From 3666e4c3320090bb4efc1bbb54ab252f2a390b57 Mon Sep 17 00:00:00 2001 From: Kian Masri Date: Tue, 10 Dec 2024 09:50:48 -0700 Subject: [PATCH 001/836] new: rank the alternate mode --- osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs index 9bf5d33d4ad7..269da46fcaf0 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs @@ -15,6 +15,7 @@ public class OsuModAlternate : InputBlockingMod public override LocalisableString Description => @"Don't use the same key twice in a row!"; public override IconUsage? Icon => FontAwesome.Solid.Keyboard; public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModSingleTap) }).ToArray(); + public override bool Ranked => true; protected override bool CheckValidNewAction(OsuAction action) => LastAcceptedAction != action; } From 6cb46106fee9c4013a8f6e2a5a3d831b36e8b815 Mon Sep 17 00:00:00 2001 From: Kian Masri Date: Tue, 10 Dec 2024 10:04:36 -0700 Subject: [PATCH 002/836] new: also the single tap mod, it's the same thing --- osu.Game.Rulesets.Osu/Mods/OsuModSingleTap.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSingleTap.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSingleTap.cs index 91731b25cf18..0d9c7d4afeea 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSingleTap.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSingleTap.cs @@ -13,6 +13,7 @@ public class OsuModSingleTap : InputBlockingMod public override string Acronym => @"SG"; public override LocalisableString Description => @"You must only use one key!"; public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAlternate) }).ToArray(); + public override bool Ranked => true; protected override bool CheckValidNewAction(OsuAction action) => LastAcceptedAction == null || LastAcceptedAction == action; } From 245ade004a7b36733ff0fbd3d7c11d4cfe43752b Mon Sep 17 00:00:00 2001 From: Kian Masri Date: Wed, 11 Dec 2024 09:47:17 -0700 Subject: [PATCH 003/836] new: rank Taiko single tap --- osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs index a5cffca06f4d..5e959387ec58 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs @@ -26,6 +26,7 @@ public partial class TaikoModSingleTap : Mod, IApplicableToDrawableRuleset @"SG"; public override LocalisableString Description => @"One key for dons, one key for kats."; + public override bool Ranked => true; public override double ScoreMultiplier => 1.0; public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModRelax), typeof(TaikoModCinema) }; public override ModType Type => ModType.Conversion; From 66eff14d2b800dcfd3d18c41dab7023e02146d49 Mon Sep 17 00:00:00 2001 From: Daniel Power Date: Mon, 16 Dec 2024 01:17:35 -0330 Subject: [PATCH 004/836] Initial proof of concept for tablet output scaling --- .../Settings/TestSceneTabletSettings.cs | 2 ++ .../Settings/Sections/Input/TabletSettings.cs | 35 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index 5ca08e0bbaa0..74578205bfd4 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -134,6 +134,8 @@ public class TestTabletHandler : ITabletHandler public Bindable AreaOffset { get; } = new Bindable(); public Bindable AreaSize { get; } = new Bindable(); + public Bindable OutputSize { get; } = new Bindable(); + public Bindable Rotation { get; } = new Bindable(); public IBindable Tablet => tablet; diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 00ffbc1120cd..22e0bc99b9f1 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -14,6 +14,7 @@ using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Framework.Threading; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -35,6 +36,7 @@ public partial class TabletSettings : SettingsSubsection private readonly Bindable areaOffset = new Bindable(); private readonly Bindable areaSize = new Bindable(); + private readonly Bindable outputSize = new Bindable(); private readonly IBindable tablet = new Bindable(); private readonly BindableNumber offsetX = new BindableNumber { MinValue = 0 }; @@ -45,6 +47,10 @@ public partial class TabletSettings : SettingsSubsection private readonly BindableNumber rotation = new BindableNumber { MinValue = 0, MaxValue = 360 }; + private Bindable scalingMode = null!; + private Bindable scalingSizeX = null!; + private Bindable scalingSizeY = null!; + [Resolved] private GameHost host { get; set; } @@ -76,8 +82,12 @@ public TabletSettings(ITabletHandler tabletHandler) } [BackgroundDependencyLoader] - private void load(OsuColour colours, LocalisationManager localisation) + private void load(OsuColour colours, LocalisationManager localisation, OsuConfigManager osuConfig) { + scalingMode = osuConfig.GetBindable(OsuSetting.Scaling); + scalingSizeX = osuConfig.GetBindable(OsuSetting.ScalingSizeX); + scalingSizeY = osuConfig.GetBindable(OsuSetting.ScalingSizeY); + Children = new Drawable[] { new SettingsCheckbox @@ -244,6 +254,8 @@ protected override void LoadComplete() sizeY.Value = val.NewValue.Y; }), true); + outputSize.BindTo(tabletHandler.OutputSize); + sizeX.BindValueChanged(val => { areaSize.Value = new Vector2(val.NewValue, areaSize.Value.Y); @@ -267,6 +279,11 @@ protected override void LoadComplete() aspectRatioApplication = Schedule(() => forceAspectRatio(aspect.NewValue)); }); + updateScaling(); + scalingSizeX.BindValueChanged(size => updateScaling()); + scalingSizeY.BindValueChanged(size => updateScaling()); + scalingMode.BindValueChanged(mode => updateScaling()); + tablet.BindTo(tabletHandler.Tablet); tablet.BindValueChanged(val => Schedule(() => { @@ -352,6 +369,22 @@ private void forceAspectRatio(float aspectRatio) aspectLock.Value = true; } + private void updateScaling() + { + switch (scalingMode.Value) + { + case ScalingMode.Everything: + outputSize.Value = new Vector2( + host.Window.ClientSize.Width * scalingSizeX.Value, + host.Window.ClientSize.Height * scalingSizeY.Value); + break; + + default: + outputSize.Value = new Vector2(host.Window.ClientSize.Width, host.Window.ClientSize.Height); + break; + } + } + private void updateAspectRatio() => aspectRatio.Value = currentAspectRatio; private float currentAspectRatio => sizeX.Value / sizeY.Value; From 4dd0672aa5a5dd0865497ceae68723e4a2f83b46 Mon Sep 17 00:00:00 2001 From: Daniel Power Date: Mon, 16 Dec 2024 21:04:08 -0330 Subject: [PATCH 005/836] Address screen scale positioning --- .../Settings/Sections/Input/TabletSettings.cs | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 22e0bc99b9f1..db670a0939ea 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -36,7 +36,8 @@ public partial class TabletSettings : SettingsSubsection private readonly Bindable areaOffset = new Bindable(); private readonly Bindable areaSize = new Bindable(); - private readonly Bindable outputSize = new Bindable(); + private readonly Bindable outputAreaSize = new Bindable(); + private readonly Bindable outputAreaPosition = new Bindable(); private readonly IBindable tablet = new Bindable(); private readonly BindableNumber offsetX = new BindableNumber { MinValue = 0 }; @@ -50,6 +51,8 @@ public partial class TabletSettings : SettingsSubsection private Bindable scalingMode = null!; private Bindable scalingSizeX = null!; private Bindable scalingSizeY = null!; + private Bindable scalingPositionX = new Bindable(); + private Bindable scalingPositionY = new Bindable(); [Resolved] private GameHost host { get; set; } @@ -87,6 +90,8 @@ private void load(OsuColour colours, LocalisationManager localisation, OsuConfig scalingMode = osuConfig.GetBindable(OsuSetting.Scaling); scalingSizeX = osuConfig.GetBindable(OsuSetting.ScalingSizeX); scalingSizeY = osuConfig.GetBindable(OsuSetting.ScalingSizeY); + scalingPositionX = osuConfig.GetBindable(OsuSetting.ScalingPositionX); + scalingPositionY = osuConfig.GetBindable(OsuSetting.ScalingPositionY); Children = new Drawable[] { @@ -254,7 +259,8 @@ protected override void LoadComplete() sizeY.Value = val.NewValue.Y; }), true); - outputSize.BindTo(tabletHandler.OutputSize); + outputAreaSize.BindTo(tabletHandler.OutputAreaSize); + outputAreaPosition.BindTo(tabletHandler.OutputAreaPosition); sizeX.BindValueChanged(val => { @@ -280,9 +286,11 @@ protected override void LoadComplete() }); updateScaling(); - scalingSizeX.BindValueChanged(size => updateScaling()); - scalingSizeY.BindValueChanged(size => updateScaling()); - scalingMode.BindValueChanged(mode => updateScaling()); + scalingMode.BindValueChanged(_ => updateScaling()); + scalingSizeX.BindValueChanged(_ => updateScaling()); + scalingSizeY.BindValueChanged(_ => updateScaling()); + scalingPositionX.BindValueChanged(_ => updateScaling()); + scalingPositionY.BindValueChanged(_ => updateScaling()); tablet.BindTo(tabletHandler.Tablet); tablet.BindValueChanged(val => Schedule(() => @@ -371,17 +379,15 @@ private void forceAspectRatio(float aspectRatio) private void updateScaling() { - switch (scalingMode.Value) + if (scalingMode.Value == ScalingMode.Everything) { - case ScalingMode.Everything: - outputSize.Value = new Vector2( - host.Window.ClientSize.Width * scalingSizeX.Value, - host.Window.ClientSize.Height * scalingSizeY.Value); - break; - - default: - outputSize.Value = new Vector2(host.Window.ClientSize.Width, host.Window.ClientSize.Height); - break; + outputAreaSize.Value = new Vector2(scalingSizeX.Value, scalingSizeY.Value); + outputAreaPosition.Value = new Vector2(scalingPositionX.Value, scalingPositionY.Value); + } + else + { + outputAreaSize.Value = new Vector2(1, 1); + outputAreaPosition.Value = new Vector2(0.5f, 0.5f); } } From 93ed0483b6a6ca70b988ed1d0623640d7a3b3559 Mon Sep 17 00:00:00 2001 From: Daniel Power Date: Mon, 16 Dec 2024 22:59:04 -0330 Subject: [PATCH 006/836] Fix TestSceneTabletSettings --- osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index 74578205bfd4..f44a08e03a64 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -134,7 +134,9 @@ public class TestTabletHandler : ITabletHandler public Bindable AreaOffset { get; } = new Bindable(); public Bindable AreaSize { get; } = new Bindable(); - public Bindable OutputSize { get; } = new Bindable(); + public Bindable OutputAreaSize { get; } = new Bindable(); + + public Bindable OutputAreaPosition { get; } = new Bindable(); public Bindable Rotation { get; } = new Bindable(); From fd504e5641c0fbd0fb46dd9d97ccf52e11c150e9 Mon Sep 17 00:00:00 2001 From: Daniel Power Date: Mon, 16 Dec 2024 23:17:22 -0330 Subject: [PATCH 007/836] Minor cleanup --- osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index f44a08e03a64..b94069aa7b55 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -135,7 +135,6 @@ public class TestTabletHandler : ITabletHandler public Bindable AreaSize { get; } = new Bindable(); public Bindable OutputAreaSize { get; } = new Bindable(); - public Bindable OutputAreaPosition { get; } = new Bindable(); public Bindable Rotation { get; } = new Bindable(); From 0b3b6468a594676b4d7da662b0aaca1768b43eec Mon Sep 17 00:00:00 2001 From: Daniel Power Date: Sat, 16 Aug 2025 23:02:28 -0230 Subject: [PATCH 008/836] Reflect tablet output area changes in osu-framework --- osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs | 2 +- .../Overlays/Settings/Sections/Input/TabletSettings.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index 1fbc395aa58e..dc9ef7439eb8 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -135,7 +135,7 @@ public class TestTabletHandler : ITabletHandler public Bindable AreaSize { get; } = new Bindable(); public Bindable OutputAreaSize { get; } = new Bindable(); - public Bindable OutputAreaPosition { get; } = new Bindable(); + public Bindable OutputAreaOffset { get; } = new Bindable(); public Bindable Rotation { get; } = new Bindable(); diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 8fd5bb7c8f4c..35304f7c34ea 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -36,7 +36,7 @@ public partial class TabletSettings : SettingsSubsection private readonly Bindable areaOffset = new Bindable(); private readonly Bindable areaSize = new Bindable(); private readonly Bindable outputAreaSize = new Bindable(); - private readonly Bindable outputAreaPosition = new Bindable(); + private readonly Bindable outputAreaOffset = new Bindable(); private readonly IBindable tablet = new Bindable(); private readonly BindableNumber offsetX = new BindableNumber { MinValue = 0, Precision = 1 }; @@ -265,7 +265,7 @@ protected override void LoadComplete() }), true); outputAreaSize.BindTo(tabletHandler.OutputAreaSize); - outputAreaPosition.BindTo(tabletHandler.OutputAreaPosition); + outputAreaOffset.BindTo(tabletHandler.OutputAreaOffset); sizeX.BindValueChanged(val => { @@ -389,12 +389,12 @@ private void updateScaling() if (scalingMode.Value == ScalingMode.Everything) { outputAreaSize.Value = new Vector2(scalingSizeX.Value, scalingSizeY.Value); - outputAreaPosition.Value = new Vector2(scalingPositionX.Value, scalingPositionY.Value); + outputAreaOffset.Value = new Vector2(scalingPositionX.Value, scalingPositionY.Value); } else { outputAreaSize.Value = new Vector2(1, 1); - outputAreaPosition.Value = new Vector2(0.5f, 0.5f); + outputAreaOffset.Value = new Vector2(0.5f, 0.5f); } } From ac21f8b9606466f6f0c1b4dda32524b59ea68617 Mon Sep 17 00:00:00 2001 From: Du Yijie Date: Wed, 27 Aug 2025 10:06:26 +0800 Subject: [PATCH 009/836] Implement "legacy" pp counter There is no pp counter in osu!(stable). However, a "legacy" pp counter allows skinners to more easily fit a pp counter into their skin's theme. --- .../Archives/modified-classic-20250827.osk | Bin 0 -> 1688 bytes .../Resources/special-skin/score-0@2x.png | Bin 0 -> 3283 bytes .../Resources/special-skin/score-1@2x.png | Bin 0 -> 1986 bytes .../Resources/special-skin/score-2@2x.png | Bin 0 -> 3302 bytes .../Resources/special-skin/score-3@2x.png | Bin 0 -> 3273 bytes .../Resources/special-skin/score-4@2x.png | Bin 0 -> 3170 bytes .../Resources/special-skin/score-5@2x.png | Bin 0 -> 3377 bytes .../Resources/special-skin/score-6@2x.png | Bin 0 -> 3305 bytes .../Resources/special-skin/score-7@2x.png | Bin 0 -> 3170 bytes .../Resources/special-skin/score-8@2x.png | Bin 0 -> 3714 bytes .../Resources/special-skin/score-9@2x.png | Bin 0 -> 3193 bytes .../Resources/special-skin/score-comma@2x.png | Bin 0 -> 1149 bytes .../Resources/special-skin/score-dot@2x.png | Bin 0 -> 930 bytes .../special-skin/score-percent@2x.png | Bin 0 -> 5397 bytes .../Resources/special-skin/score-pp@2x.png | Bin 0 -> 4777 bytes .../Resources/special-skin/score-x@2x.png | Bin 0 -> 2801 bytes .../Skins/SkinDeserialisationTest.cs | 2 + .../TestScenePerformancePointsCounter.cs | 3 +- .../LegacyPerformancePointsCounter.cs | 44 ++++++++++++++++++ osu.Game/Skinning/LegacySpriteText.cs | 10 +++- 20 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Tests/Resources/Archives/modified-classic-20250827.osk create mode 100644 osu.Game.Tests/Resources/special-skin/score-0@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-1@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-2@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-3@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-4@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-5@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-6@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-7@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-8@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-9@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-comma@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-dot@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-percent@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-pp@2x.png create mode 100644 osu.Game.Tests/Resources/special-skin/score-x@2x.png create mode 100644 osu.Game/Skinning/LegacyPerformancePointsCounter.cs diff --git a/osu.Game.Tests/Resources/Archives/modified-classic-20250827.osk b/osu.Game.Tests/Resources/Archives/modified-classic-20250827.osk new file mode 100644 index 0000000000000000000000000000000000000000..605ea60f4c74a2f72cf77d766ae5c5654a785726 GIT binary patch literal 1688 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 RO-BF#002ovPDHLkV1n-$NE847 literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/special-skin/score-1@2x.png b/osu.Game.Tests/Resources/special-skin/score-1@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..78cadf49bdf241042a4c3c5af4720e8bacddcc0b GIT binary patch literal 1986 zcmV;z2R- zmiLlK=MMw({?D0np8uTtbDkG+$RURua`-*NcV6=ak|3z+ZuWlZLCG5b&<} zV+>)%7NlDUz?%cVhxYb%J^d8$70{cBfbGCp-3ki8qD6~nZf>TwwicJm-UWT-%9V6`xh)18VgLU9DzyT@o#Hn~fVcF7%jKfJzMg&i_Ss=$ zN-SHp3{BIBMx$}65^yCG@DJ5^x7*E;BS+Y_ZJX`J8o}*$Q(9Wez`#J9Dh8e~67V|k zj-DtkF6Q|0<80ix(Gg>fFg7;E{rmUz)HpDx3fKdDpeJU}p3SLKr&zIKg(HS0LtkH? zzWV_50ulWn-XvDn$tk6%sEDSfrfD}Gpu4+UrGhB??k4@Zke{E=i4!MSvu2G`Hl{>Z zSC>ltgigQ$U}-!>(=?79J4Q`SjgvN}L}zEGO8tmVfYiBME*BLQ6;9cf5z-0h1AdOD zL?RKqUN7V0<4)R`6hlKp+`M^HPmKdtP{zRD^f|h^x;T9Juv0dsL}zEGx+CoX!YBg1 z1U}N|YH4Yqp`k(jvE#UU^{Pt!C;mm<3%v4^v%Tt*1uxexh^-nqjd!eHLiVq{3)4%E5yN z>Fw>Es?8Ga-o2|*QrFJZ2l*|q8F)r`$~sbI4uwKAH#cW%t04>oNWPYAov4?AzXQvG zS>jmtoDf#8&v@?KIit$6#=U#@RBB2sV1!YzoPQ&PH39#PCq^O>+S=Mo6#oeQ{rxIs zss&OZrmo~xtQ&T=fDwL>YPx+pdCm;sw19~85Q!wunIRrLc%V}M(?3`(K=L0I78aT= z&_IB6vbS1*WN|@3f$0K=hlf>4Qe?FN$;*+KmyPe(7(+utDka^9OxtBzrg-cHINgOT zMI;hY4^k82;%^dG3y^lKX5H>1BO@x6a0szlfHdvo=jWR$%s@cGfUsJCWU&nb5(b2= z>wsAS6B83EmEfqF@#{c3%;-U!39J?%mG?LbkS>Xfii(owvW@{HR+X4nh(ga11n*iHe zz|wVKI=Yah=Yi?yLY4~1%ge*CD_o1yDnJ>4Q-VPkvQ>a|2)3dNm6j$%H%kGkwjSyYHe*?%yu4hco|ft`UBhpX z{(Y-F5(^hDR4FNX*h&GmxKx}JAX#ih_d$d>E8dMi=?AiH0<4&U07^0Hc80y2*MhtL2gJeiByPP{y%jNkYI(W&Dek0><hYqRqFYzzd zbks)}6Sws)ED+Gs(?erpBYwYMO^N~y@dqmfAR-Bi0AjHi;cz(XQ`wa(SMd3Kw6?aY zvC;_R-w@F=V1s~PfypW3^5x5{U%x)>kAlGGuDN}!cKY>7iKp?=yix;_Z<3_r2zXSHhgI(>!pG7lEuM}2QRmHY$ z-5RT|u8x(Jm1XlP;=h5NPT!`!XY&2Y2@!<*f|Ew;p^4XU6Ivq0XH-N;zUt%~tm#k# zd?qgDRD;7}CV5u`+D_RA>BJk|9$<}FJ%1H%UfhTWZ|9Ih4msqILk>CQ@H@u;0p`6% U)kg*k{r~^~07*qoM6N<$g4w3CJpcdz literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/special-skin/score-2@2x.png b/osu.Game.Tests/Resources/special-skin/score-2@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..10dff4ccfa2637573d8e211698c9a8b69f49eacc GIT binary patch literal 3302 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 literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/special-skin/score-3@2x.png b/osu.Game.Tests/Resources/special-skin/score-3@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..89eb5d322b4805a54f2c742d58cad6bcdb7699cf GIT binary patch literal 3273 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 Hu0mjfn7}SR literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/special-skin/score-4@2x.png b/osu.Game.Tests/Resources/special-skin/score-4@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b44e9ec4602c84e77a5fdd076bda3292ccb8d5fb GIT binary patch literal 3170 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 IM6N<$g8i!gR{mkre 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 Hu0mjfcb0&K literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/special-skin/score-6@2x.png b/osu.Game.Tests/Resources/special-skin/score-6@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0e7bfc377631cde00c12db3a7008f3630522449c GIT binary patch literal 3305 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 IM6N<$g54AmHUIzs literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/special-skin/score-8@2x.png b/osu.Game.Tests/Resources/special-skin/score-8@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5726c519ae9776ee5b1c1bfc829fcd18e26a6d41 GIT binary patch literal 3714 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 P00000NkvXXu0mjf6h$Ne literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/special-skin/score-dot@2x.png b/osu.Game.Tests/Resources/special-skin/score-dot@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..58f38a22b5a0ada67b88f6b5c1d66a534a84d73a GIT binary patch literal 930 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 QR+=D9RXvqPrC0C%2T1va2><{9 literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/special-skin/score-pp@2x.png b/osu.Game.Tests/Resources/special-skin/score-pp@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e8616e72841c2590d510fd35d7257662cec508ab GIT binary patch literal 4777 zcmb7Ig;$hM8>Kr0DMdjfm6BRoLO^K+qy!e$rMs4rMjFWlX{1@w1*BOT7U^!5bPS_fUgWvTpei0 z-Cmh^;^94v`mf?A?wnWyo%g&{jlJ|;ZM=M}Jgo72e0+rLT^v2%Te(>axq8@U|B}0p zher=mS5Y$X%{j~s@G_Y7?+Q-66Gf!F%}CUv|LEy!aa3ch>33#5YSH$netd2HxAU|AqeMGtReP4V;drJ zxztBVVT@V%d>-Wss}kCaEE#$mdlhl;^6*4j^+t;L9$U7;4mEBr4|DD3Ys`z<+jCA& zJ%r4f747Yx&_wkv&%+6Wd0Qo2|8Umn2|xTGVmI-~rR@;pe|exj_~~J;M^vwpwl+0W z9C2K~vbs7stZjAKNCK}mF1tl!!b9B1&8I*k+Y*$muA@`xy57mf%}vM38i$5H27%I% zNYU8XSUv%P;^N}IAF72#MZhSV?V;r2(o#{I5thx(%|A~uC7KzyjVSh^u`!$RJo%Zq zIRsJy-!U{JRE8FOA@7!<@17bHN=Pbd*@c&ql7d}n5yNwLcb}P=d2ME<dox49w;gAe}1fqii{*VJw07O1uL|{4hyTQM)c>7LKYz_Tau%U zE4uN9_}H0>yEng&fN%|*WfD}*YUt?DTwPuLH$51vtE^05-s<%QIN15odOom=Yx6H_ z%^o`x%io;0!fBruAd!0Top_c$_|vJ=P}wZnxmxgeuFu-uSr)7|G5|T&i-6ACok_ycnJ;eoq|6dJ6bCR__8=U`5$azj!kdxsE`!f?ehA9`x$o`8e5RpP@U0hd*5J5*0zL{eF84J62& zPrUHZqqQV0I1JNq5No)gAc;;)3?13x^$L77#?1oLd$&`*UBRhT^vvXKKWU?)X zqZcar)oV}BW-R9k?>;7n6Qo|5C)O))@SOME3E`{y6IsGR#}uA9noB z27k!#4Bo!I%CfZcR8dt;PEJf6{nAhi+ev=sEWjiSXK$7@h_C1)f|Wk+s~&oPY)Ia zA@C7(uFKb>T3O;TZ;I5=o6OMAd8P+w1w{ztv3{8jyx+WmG`T7t4TW@v5d)K0X>Dvr zI(OrV*^DIdl9@%%2(@NT7QGY$$e@~!#8-_!snN$zO+rHABk}`Bna|PM3V;~4X-;#6 zRCHhbJu&Es*I}sBB&N`v&mz^q!2yTcN|g5g$zWK?m^~UfYQrfbleN(sbp~{cxo@iY zF|0sJwK99wIs)MKUnXk5dAV*N@oguPo;_lap!x}ayJL{#?^*R;sEOaK$Mo2c3N$PkBn%!bS{G5Q;!3C zBdK4k`mlmE?*=e+b@n4QJG)X#SU_MKK%Le1bipdq##mr$q=BQ&%~EQKY@^-bq>Y>C zQO1MDxVbaZ@|qf(jh>Ig!*J;jxM%e?qdhkDS0nqB^@~~#4hT{0BUao_2Kdsr#Z-Wa z(sOrYqc7%etC`Oq+zArvGx~3c@u2W)oN?f_sff@ zg+@oCiFwp5tZ_99pulg=%h1Ut#aLfwdts-d^(oNf%Gu#}t{sf$jR47+9dt%;K~`LjP4| zu|3w?WFfwzbhIJx1_rS6wkKf^R1{sSN!ELF>@^8cAChl5{KP-J&cM!&iGhg;5!4<6 zVB6?^_g+bUKP1`JlGSbH#U<6@Qd{o^=4@Pnwv{TDqBGa6(X#)czh3U$kTVF!GI|~y z{Lt&3|Lvb5}3-k zx&3=pIQ$QSC7-jRu0~&pN#J{4A=`8tEf@tB`HQ^qPs8HCNe*f3WE5rX{1KJJ02gm}--elU#lo!8%~q4+gjmMCz4cPkC$g_d(N zo(Sif^^}d=W(hS55RsyAb5fQT%Z~JC9s- zDMKKJwQJ_7<-D-3uSgznGQE*INt?S0!X0lQ28|W@%-n~`<^ztK-M6;cAH5~we{&N5 z-NVR$AyMx1)$953@89)5>0L|-i-^3r^oXaUBQ{v!p_HcmF&QS=qV1vGmk-j|^#0i@v$;m3S7Evr8At-yasN`cFqZ1%(bajnBb~LN{ZjaA=GgGO|mzpe# ztJP&tqtoe)smmH2%U8&6@%(Z9fKKw}PiaYs-{=q8#l=Oo@N#VR`cN{bNr!(U_~>A| zOxJc1X{`jVFDwiLINM%TyK8qhyv}(8V0S+NcF%Y8^sUw^UP&vRnD z#HL-aG^)qx^6$-&Eg%s_vLxanB8ZyKp9fyo`CmAs3%=W(XRi9x_Tp4Ntd+#d@tJnwof-L~ukr!`cF&Qdj5T=H}*FM_Kif_)&bjj|(@vGbbdI^WkFF2w|*`nrBl% z2EpO*s&`E~Oen#ZyVT2kGC4D|vtJ$H*$Q6iWIR7rYIl0(Fr$*|Y4b^rA^(!jR+GkT z_xAQqXSUyBxP>F#==y8S+YD;eY7qj~F3m#zKvX_l?PMT*;m?v|aIDS6#Sx7BhC`cM zT~UZXk_OCyn|o1ye+HB@gLXRRr>#E>3SVA}{?I~~$1k<-{ zG%4F}P!>aj^evu;r{`jW{asnu!7;`QbeIfHcr( z*gnMHrGh=%bJEbi{QBA-kiO`z?*|t;0-9^&CUfHKYx{+o$FJOxVK zqSMU$yywZLDv)sd`}_aOWF0bQn_W3Hnkv`i_ihxFmq!CW0#R96QBko0C|k46519ZV zYG`Qi@$;YA@@727Fdl9OY924C?yLLxNmm+HL)JS3yVX7~3#y^p-nqF9wc539RU9%sj%DN@8Xk7o z+cOG1?Ba#YYBq&^ED7`ZwQ|pH2Na!9bs1NKdzT9;rc$S@DKEDK{8eZkObz?HdVv(p zp1&EA42U?*3I6+z-rkJ@$mj%S%?L*2+`4akjOGS!G{3o@g(s;@S65UdyQcep%`R8< zy_u&7{;@7D`z@0Dev4T*%AU5kWtFLDfw4-lxi%tzWxo)dG_Ju*aeF^h8d5f6sG1iC zvv*(?!cj-+|+tET`nZRqW+4Se#e(=2zv+e}Q%+F%tq8Hpesp{5bY&pw8-*IXI zb?*mh%+;o~wY8m96_^c}7KCc>SV2yhru86w=vjVP7y)4Uswpmaf_)8damqKt-n%3B zkoEQ9*F8&1rWU>%#Bbk|36T`hlt0DkLLm5kT>Ymz-`{y<$UdO?=Cs%Y$U#0q@8v0< zqV{~t&*cmcepd~X1kakqY%zlCZxg-o$r&)^4$7TSopZguyQzg znG-O$?@u=Soz~h-B=kn<*I-|K=P#nzL#{@z=Vxc#f#*FnHT4I!(_k!6TvnC}fX{#R zDg9bXb!TH%*-|WBy@1ejZXouSYwdo3r)~ZC0B{32vOb><4xC^I3mbx$kS@n8j!kb& zenVJapGuzJ?mb{e>{NeX2-w16ESd8q@W>wX@(xaGt&?MFZ^>*~nA#-@%?kM8g+myCk=sn1pDxS7 z%aI_JrdX4*(nrr}z9!br2fDnAkveH6Q$z7g-udP1Y;8I$*pt#lS1@$}Q3*0~%{v&J_3Jnp^DcL8hqzV{JuQa$E517fMbz- z3aenp*;0({+34e6&}tTuNGQ4zjui@X7>u)ZXpFX)22r(8QBnP6KSp_0uicHXeP;;# PX2Mff)lsQYwha3pLxy)* literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/special-skin/score-x@2x.png b/osu.Game.Tests/Resources/special-skin/score-x@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c61724db1f021dc25216f444bf9b2a9551a107f5 GIT binary patch literal 2801 zcmVBd1||a&fm9$8 z2nTGy4d5nl9XJX6Q`mgL3akWv21El5z;@sO(C1^>{UiXZffIloaCrIY15N|K2Oc%} z?7eQvZUlY#$iz zx#xfkPX)?-@ZUhDdV`;zAL;4oq@|^il9IxR5hDl*31Qf;8MdAAu5g{nIIM7;x8_wpc7o zojR55>}+PunniSU^dNQmmd?&j-hKC7cJAEC)vH&vZrKYgcT<@};F2@p=jTUtbv5DP z;dFF#uxr;YcI?=}H{X1tRc~k6B{(?PD{%len~m|~$Fp?l zQo_Q*ICbh2eSI!k#*0z-J&o*zz>l1XjEoF&bMLq8pr9Z!GBU`?$>H|x+g!MCLCu>Y zM*26!TOAQZhF9oCiQ;WF+(E&2w9BR#q1K_wOeuDM`KbbKqIoAPYPL zY?Uu=+O&y|jt)JV1~6*WD9X#r2@Q3bz5;-KK%A(v9N0X3{!29pNkHg_`nnQq}h`}w-Y4rE^ zXWhDWgoK26EH@}9h|J7P4jec@Z*Q;D91Q#yIHe`<4$uqy)M+?>{=BY{)E)8h@mMSt zYHMp{^GINUJY7BW%rh)lu)ynbBO)T`>FMF*Nx4fi8h8Vxi8?6*E;sYNeo{KzF&zmMv2U!*sD$))d$yCggr1QD0BN`p2yjrHt6qKeRd=fiUD#|k%F4=k{PD+K z>=6+WtXj3oaJeH#j#N#d3?dNm7W;c{OG^tC6%~dnAQKf8#rEynS+QaTVPRn;B_;9t z>#q|N6Jxl{ufP6UHQmOG{os1BMFAi%FpziNd51?IHM$deF!c5Hk(rrES67#89s{&^ zTBfX#H?Vi_-etpv4G*lMMyac-Q^j2aTJX?B0d9#EPCo|^9^~}t(+{GahI#9)w^Y*+ z=NE4lntuW6oC$}+!7H!4GT650q0-vg%6sn(SiA3Ze(^?NpWF`t&YnHXM<0DORCV-; z($Z3ObZ-JabSAvrDjWg+AsaSt-YhS>z7vigKTcIum137-} zJ32ZjDk@U{$^Vg?CpraQ7CV4`s;jGgt*0US`uZp=ETpZiO*Y>HeyO@d^zLTgloKaT zobaWdhAA&E*LwD!flpMUH;!MK7_l3-00aaCaPs6ytX6eX^5D3B{W?!S{j@r;R027| zGvR{XH+WO{B?0K|?WMJ~b?_WROhrY7D(;%tPil^M`W-Hk=L_Jo&ptCygfScrht{s9 zNc`h9F(UADInmkKX`l#WT)uo+Z84qd^rd1%piBFZTm=uDD_5?lrX#}T;T9tTUE2D+ zd-vSmIm9$IHL0d^p7IzG7%L}y_0{M>W5fNWr#wakj*}A_KF|Lv^a>0FT%0BkQ=o>g zbhxKHdIe5%daD3pV`FulUHFQI-({?)JbDFY%ZaC+dP-+@-_UTCqoBqSurCMz&&usnJMx*U+qnKOs5 zurR%K^cjtR>a*H+-p5;k^MN_C;koCY(_6P8VeZ_ys%idUfezjX3UFzu#t^j@^8}jn< zNJ&WeOC&z-;xqFwj%;)^eS z=S@?_X0x$!4pHJ3AYTMXzJ; zTPzj}W5$e8z1#6XJ#Zckfn~storz(?hOuSK7DkO4Ww;UmhYlU0sHn&#>gmdrD|B^r zF>Ts3pURGli=)22UUh!`5GV)iauXe=P6_$>`6MSN;|nbq8Nu;?A?+6zDR0M?^#n*?Gf=5d#+bV}N6_VJO`H8V=|lB!M^Ov%ecRZt%qy zU-c<~{OkQ3dUw-M)x2nm;jT@<~tW?cg#TmNGDtXVI zJuF+cjAO@+srP%urAwF8AU_B2FO-SCUQF`wPD5*JEBp5CqpPcnsP^Lzf!EMD z038h+)^f*LtyU&YnnYGs7852+AT>3W@Nid$RzpJrYuB!&uC7kaep5vB%N=D3@HY{R zK7i2BP-e`SL1tzqlP6DR?AU=W&~xX`@$$qZsyvxYg)J668;>m^X^cwIL`BQ+8h}fNlZ)((b3UZEEcX_z3OiCtppZ&s=G7H z_;VkB6w(Sz^7Js_-+Wu=&xo`>XXMy#ZwLf_1)MeTuswPoCjJ?(0nG-Ux8K0?T!<6# z+*`#Du(W;#^p)sW1HyWB;wKi%e-LBBZ8xIsh&S(c*=2k)c7FsOBUbJKLU66tuTO>m zEAWVj@_0n}iCV?T{P2#LO-xKoOiWBnOiWBnzCZjAFh_Rf0Exov00000NkvXXu0mjf DwF+8& literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 0eafe3334371..56cdbb1e8de4 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -79,6 +79,8 @@ public class SkinDeserialisationTest "Archives/modified-argon-20250424.osk", // Covers "Argon" unstable rate counter "Archives/modified-argon-20250809.osk", + // Covers legacy style performance points counter + "Archives/modified-classic-20250827.osk", }; /// diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePerformancePointsCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePerformancePointsCounter.cs index eada72326d98..68f314d52af7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePerformancePointsCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePerformancePointsCounter.cs @@ -18,6 +18,7 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; +using osu.Game.Skinning; using osu.Game.Skinning.Triangles; using osu.Game.Tests.Gameplay; @@ -35,7 +36,7 @@ public partial class TestScenePerformancePointsCounter : SkinnableHUDComponentTe protected override Drawable CreateDefaultImplementation() => new TrianglesPerformancePointsCounter(); protected override Drawable CreateArgonImplementation() => new ArgonPerformancePointsCounter(); - protected override Drawable CreateLegacyImplementation() => Empty(); + protected override Drawable CreateLegacyImplementation() => new LegacyPerformancePointsCounter(); private Bindable lastJudgementResult => (Bindable)gameplayState.LastJudgementResult; diff --git a/osu.Game/Skinning/LegacyPerformancePointsCounter.cs b/osu.Game/Skinning/LegacyPerformancePointsCounter.cs new file mode 100644 index 000000000000..e59a4a80b4e5 --- /dev/null +++ b/osu.Game/Skinning/LegacyPerformancePointsCounter.cs @@ -0,0 +1,44 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Localisation; +using osu.Game.Graphics.Sprites; +using osu.Game.Screens.Play.HUD; +using osuTK; + +namespace osu.Game.Skinning +{ + public partial class LegacyPerformancePointsCounter : PerformancePointsCounter, ISerialisableDrawable + { + protected override double RollingDuration => 1000; + protected override Easing RollingEasing => Easing.Out; + + private const float alpha_when_invalid = 0.3f; + + public LegacyPerformancePointsCounter() + { + Anchor = Anchor.TopRight; + Origin = Anchor.TopRight; + + Scale = new Vector2(0.96f); + } + + public override bool IsValid + { + get => base.IsValid; + set + { + if (value == IsValid) + return; + + base.IsValid = value; + DrawableCount.FadeTo(value ? 1 : alpha_when_invalid, 1000, Easing.OutQuint); + } + } + + protected override LocalisableString FormatCount(int count) => count.ToString($@"0'{LegacySpriteText.PP}'"); + + protected sealed override OsuSpriteText CreateSpriteText() => new LegacySpriteText(LegacyFont.Score); + } +} diff --git a/osu.Game/Skinning/LegacySpriteText.cs b/osu.Game/Skinning/LegacySpriteText.cs index 1028b5bb9d11..dca258e6eb94 100644 --- a/osu.Game/Skinning/LegacySpriteText.cs +++ b/osu.Game/Skinning/LegacySpriteText.cs @@ -14,6 +14,11 @@ namespace osu.Game.Skinning { public sealed partial class LegacySpriteText : OsuSpriteText { + /// + /// The Private Use Area character representing performance points. + /// + public const char PP = '\uebd9'; + public Vector2? MaxSizePerGlyph { get; init; } public bool FixedWidth { get; init; } @@ -23,7 +28,7 @@ public sealed partial class LegacySpriteText : OsuSpriteText protected override char FixedWidthReferenceCharacter => '5'; - protected override char[] FixedWidthExcludeCharacters => new[] { ',', '.', '%', 'x' }; + protected override char[] FixedWidthExcludeCharacters => new[] { ',', '.', '%', 'x', PP }; // ReSharper disable once UnusedMember.Global // being unused is the point here @@ -116,6 +121,9 @@ private static string getLookupName(char character) case '%': return "percent"; + case PP: + return "pp"; + default: return character.ToString(); } From 3aad0868af6865e193df1dbd5108afb9ec9992b6 Mon Sep 17 00:00:00 2001 From: Daniel Power Date: Wed, 27 Aug 2025 19:57:58 -0230 Subject: [PATCH 010/836] Remove duplicated declarations --- osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index ee3f7805aab4..068471ae491c 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -133,9 +133,6 @@ public class TestTabletHandler : ITabletHandler { public Bindable AreaOffset { get; } = new Bindable(); public Bindable AreaSize { get; } = new Bindable(); - public Bindable OutputAreaOffset { get; } = new Bindable(); - public Bindable OutputAreaSize { get; } = new Bindable(); - public Bindable OutputAreaSize { get; } = new Bindable(); public Bindable OutputAreaOffset { get; } = new Bindable(); From 61c3aad53791c838d5d20e6f93a77d6bdb0ac9ab Mon Sep 17 00:00:00 2001 From: Daniel Power Date: Wed, 27 Aug 2025 20:00:56 -0230 Subject: [PATCH 011/836] Fix conflict --- osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index 068471ae491c..e9f70180e1a2 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -133,8 +133,8 @@ public class TestTabletHandler : ITabletHandler { public Bindable AreaOffset { get; } = new Bindable(); public Bindable AreaSize { get; } = new Bindable(); - public Bindable OutputAreaSize { get; } = new Bindable(); public Bindable OutputAreaOffset { get; } = new Bindable(); + public Bindable OutputAreaSize { get; } = new Bindable(); public Bindable Rotation { get; } = new Bindable(); From 038bf3fddaad3787749b88865a1a52d665517496 Mon Sep 17 00:00:00 2001 From: Daniel Power Date: Wed, 27 Aug 2025 20:11:28 -0230 Subject: [PATCH 012/836] "Conform to aspect ratio" uses scaled area --- .../Settings/Sections/Input/TabletSettings.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 35304f7c34ea..a355205a851c 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -167,7 +167,16 @@ private void load(OsuColour colours, LocalisationManager localisation, OsuConfig Text = TabletSettingsStrings.ConformToCurrentGameAspectRatio, Action = () => { - forceAspectRatio((float)host.Window.ClientSize.Width / host.Window.ClientSize.Height); + float gameplayWidth = host.Window.ClientSize.Width; + float gameplayHeight = host.Window.ClientSize.Height; + + if (osuConfig.Get(OsuSetting.Scaling) == ScalingMode.Everything) + { + gameplayWidth *= osuConfig.Get(OsuSetting.ScalingSizeX); + gameplayHeight *= osuConfig.Get(OsuSetting.ScalingSizeY); + } + + forceAspectRatio(gameplayWidth / gameplayHeight); }, CanBeShown = { BindTarget = enabled } }, From b4b26e3a1de490ff527e15b2a2cf7f528dc591a6 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 16 Oct 2025 17:40:19 +0900 Subject: [PATCH 013/836] Remove song select dependency from FooterButtonOptions --- .../Visual/SongSelectV2/TestSceneScreenFooter.cs | 2 +- osu.Game/Screens/OsuScreen.cs | 2 -- osu.Game/Screens/SelectV2/FooterButtonOptions.cs | 8 ++++++-- osu.Game/Screens/SelectV2/SongSelect.cs | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneScreenFooter.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneScreenFooter.cs index e247b92f528a..bb0fb16dcf5d 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneScreenFooter.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneScreenFooter.cs @@ -53,7 +53,7 @@ public void SetUp() => Schedule(() => { new FooterButtonMods(modOverlay) { Current = SelectedMods }, new FooterButtonRandom(), - new FooterButtonOptions(), + new FooterButtonOptions(null), }); }); diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 1307be64943d..ce04db0189eb 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -117,8 +117,6 @@ public abstract partial class OsuScreen : Screen, IOsuScreen, IHasDescription internal void CreateLeasedDependencies(IReadOnlyDependencyContainer dependencies) => createDependencies(dependencies); - internal void LoadComponentsAgainstScreenDependencies(IEnumerable components) => LoadComponents(components); - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { if (screenDependencies == null) diff --git a/osu.Game/Screens/SelectV2/FooterButtonOptions.cs b/osu.Game/Screens/SelectV2/FooterButtonOptions.cs index 3371785dd2de..3e08e69bf885 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonOptions.cs +++ b/osu.Game/Screens/SelectV2/FooterButtonOptions.cs @@ -23,8 +23,12 @@ public partial class FooterButtonOptions : ScreenFooterButton, IHasPopover [Resolved] private IBindable beatmap { get; set; } = null!; - [Resolved] - private ISongSelect? songSelect { get; set; } + private readonly ISongSelect? songSelect; + + public FooterButtonOptions(ISongSelect? songSelect) + { + this.songSelect = songSelect; + } [BackgroundDependencyLoader] private void load(OsuColour colour) diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index e8843876d39a..f047184d993d 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -352,7 +352,7 @@ private void requestRecommendedSelection(IEnumerable groupedBeat errorSample?.Play(); } }, - new FooterButtonOptions + new FooterButtonOptions(this) { Hotkey = GlobalAction.ToggleBeatmapOptions, } From d85c2ee623869d352f8400fecdbc727804027192 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 16 Oct 2025 17:56:15 +0900 Subject: [PATCH 014/836] Isolate footer behaviour to ScreenStackFooter, support subscreens --- osu.Game/OsuGame.cs | 69 +----- osu.Game/Screens/Footer/ScreenStackFooter.cs | 216 +++++++++++++++++++ 2 files changed, 222 insertions(+), 63 deletions(-) create mode 100644 osu.Game/Screens/Footer/ScreenStackFooter.cs diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4dd42b7fd203..4ea9fae1838b 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -189,19 +189,14 @@ public partial class OsuGame : OsuGameBase, IKeyBindingHandler, IL /// public readonly IBindable OverlayActivationMode = new Bindable(); - /// - /// Whether the back button is currently displayed. - /// - private readonly IBindable backButtonVisibility = new BindableBool(); - IBindable ILocalUserPlayInfo.PlayingState => UserPlayingState; protected readonly Bindable UserPlayingState = new Bindable(); protected OsuScreenStack ScreenStack; - protected BackButton BackButton; - protected ScreenFooter ScreenFooter; + protected BackButton BackButton => screenStackFooter.BackButton; + protected ScreenFooter ScreenFooter => screenStackFooter.Footer; protected SettingsOverlay Settings; @@ -233,6 +228,8 @@ public partial class OsuGame : OsuGameBase, IKeyBindingHandler, IL private RealmDetachedBeatmapStore detachedBeatmapStore; + private ScreenStackFooter screenStackFooter; + private readonly string[] args; private readonly List focusedOverlays = new List(); @@ -1132,12 +1129,6 @@ protected override void LoadComplete() { backReceptor = new ScreenFooter.BackReceptor(), ScreenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }, - BackButton = new BackButton(backReceptor) - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Action = handleBackButton, - }, logoContainer = new Container { RelativeSizeAxes = Axes.Both }, // TODO: what is this? why is this? // TODO: this is being screen scaled even though it's probably AN OVERLAY. @@ -1150,7 +1141,7 @@ protected override void LoadComplete() { Depth = -1, RelativeSizeAxes = Axes.Both, - Child = ScreenFooter = new ScreenFooter(backReceptor) + Child = screenStackFooter = new ScreenStackFooter(ScreenStack, backReceptor) { // TODO: this is really really weird and should not exist. RequestLogoInFront = inFront => ScreenContainer.ChangeChildDepth(logoContainer, inFront ? float.MinValue : 0), @@ -1324,14 +1315,6 @@ protected override void LoadComplete() if (mode.NewValue != OverlayActivation.All) CloseAllOverlays(); }; - backButtonVisibility.ValueChanged += visible => - { - if (visible.NewValue) - BackButton.Show(); - else - BackButton.Hide(); - }; - // Importantly, this should be run after binding PostNotification to the import handlers so they can present the import after game startup. handleStartupImport(); } @@ -1723,13 +1706,12 @@ protected virtual void ScreenChanged([CanBeNull] IOsuScreen current, [CanBeNull] if (current != null) { - backButtonVisibility.UnbindFrom(current.BackButtonVisibility); OverlayActivationMode.UnbindFrom(current.OverlayActivationMode); configUserActivity.UnbindFrom(current.Activity); } // Bind to new screen. - if (newScreen != null) + if (newScreen is OsuScreen newOsuScreen) { OverlayActivationMode.BindTo(newScreen.OverlayActivationMode); configUserActivity.BindTo(newScreen.Activity); @@ -1742,45 +1724,6 @@ protected virtual void ScreenChanged([CanBeNull] IOsuScreen current, [CanBeNull] else Toolbar.Show(); - var newOsuScreen = (OsuScreen)newScreen; - - if (newScreen.ShowFooter) - { - // the legacy back button should never display while the new footer is in use, as it - // contains its own local back button. - ((BindableBool)backButtonVisibility).Value = false; - - BackButton.Hide(); - ScreenFooter.Show(); - - if (newOsuScreen.IsLoaded) - updateFooterButtons(); - else - { - // ensure the current buttons are immediately disabled on screen change (so they can't be pressed). - ScreenFooter.SetButtons(Array.Empty()); - - newOsuScreen.OnLoadComplete += _ => updateFooterButtons(); - } - - void updateFooterButtons() - { - var buttons = newScreen.CreateFooterButtons(); - - newOsuScreen.LoadComponentsAgainstScreenDependencies(buttons); - - ScreenFooter.SetButtons(buttons); - ScreenFooter.Show(); - } - } - else - { - backButtonVisibility.BindTo(newScreen.BackButtonVisibility); - - ScreenFooter.SetButtons(Array.Empty()); - ScreenFooter.Hide(); - } - skinEditor.SetTarget(newOsuScreen); } } diff --git a/osu.Game/Screens/Footer/ScreenStackFooter.cs b/osu.Game/Screens/Footer/ScreenStackFooter.cs new file mode 100644 index 000000000000..3fb470cab0ee --- /dev/null +++ b/osu.Game/Screens/Footer/ScreenStackFooter.cs @@ -0,0 +1,216 @@ +// 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 osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Screens; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.Footer +{ + public partial class ScreenStackFooter : CompositeDrawable + { + /// + /// Called when logo tracking begins, intended to bring the osu! logo to the frontmost visually. + /// + public Action? RequestLogoInFront { private get; init; } + + /// + /// The back button was pressed. + /// + public Action? BackButtonPressed { private get; init; } + + /// + /// The (legacy) back button. + /// + public readonly BackButton BackButton; + + /// + /// The footer. + /// + public readonly ScreenFooter Footer; + + /// + /// Whether the legacy back button is currently displayed. + /// + private readonly IBindable backButtonVisibility = new BindableBool(); + + private readonly ScreenStackTracker screenTracker; + + public ScreenStackFooter(ScreenStack screenStack, ScreenFooter.BackReceptor? backReceptor = null) + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + BackButton = new BackButton(backReceptor) + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Action = () => BackButtonPressed?.Invoke(), + }, + Footer = new ScreenFooter(backReceptor) + { + RequestLogoInFront = v => RequestLogoInFront?.Invoke(v), + BackButtonPressed = () => BackButtonPressed?.Invoke() + } + }; + + screenTracker = new ScreenStackTracker(screenStack); + screenTracker.ScreenChanged += onScreenChanged; + + backButtonVisibility.ValueChanged += onBackButtonVisibilityChanged; + } + + private void onScreenChanged(IScreen lastScreen, IScreen newScreen) + { + unbindScreen(lastScreen); + bindScreen(newScreen); + } + + private void onBackButtonVisibilityChanged(ValueChangedEvent visible) + { + if (visible.NewValue) + BackButton.Show(); + else + BackButton.Hide(); + } + + private void unbindScreen(IScreen screen) + { + if (screen is not OsuScreen osuScreen) + return; + + backButtonVisibility.UnbindFrom(osuScreen.BackButtonVisibility); + } + + private void bindScreen(IScreen screen) + { + if (screen is not OsuScreen osuScreen) + { + ((BindableBool)backButtonVisibility).Value = true; + + Footer.SetButtons([]); + Footer.Hide(); + return; + } + + if (osuScreen.ShowFooter) + { + // the legacy back button should never display while the new footer is in use, as it + // contains its own local back button. + ((BindableBool)backButtonVisibility).Value = false; + + Footer.Show(); + + if (osuScreen.IsLoaded) + updateFooterButtons(); + else + { + // ensure the current buttons are immediately disabled on screen change (so they can't be pressed). + Footer.SetButtons([]); + + osuScreen.OnLoadComplete += _ => updateFooterButtons(); + } + + void updateFooterButtons() + { + Footer.SetButtons(osuScreen.CreateFooterButtons()); + Footer.Show(); + } + } + else + { + backButtonVisibility.BindTo(osuScreen.BackButtonVisibility); + + Footer.SetButtons([]); + Footer.Hide(); + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + screenTracker.Dispose(); + } + + /// + /// Recursively represents a single screen stack and any nested subscreen stack. + /// + private class ScreenStackTracker : IDisposable + { + /// + /// Invoked when the leading screen changes. + /// + /// + /// This differs from and + /// because lastScreen and newScreen may be subscreens of the current screen stack. + ///
+ /// As such, no assumptions may be made as to the relation of screens to this entry's . + ///
+ public event ScreenChangedDelegate? ScreenChanged; + + /// + /// The screen stack tracked by this entry. + /// + private readonly ScreenStack stack; + + /// + /// An entry corresponding to the subscreen stack of the current screen, if any. + /// + private ScreenStackTracker? subScreenTracker; + + /// + /// The screen which should be bound to the screen footer - the most nested subscreen. + /// + private IScreen leadingScreen => subScreenTracker?.leadingScreen ?? stack.CurrentScreen; + + public ScreenStackTracker(ScreenStack stack) + { + this.stack = stack; + + stack.ScreenPushed += onParentScreenChanged; + stack.ScreenExited += onParentScreenChanged; + } + + private void onParentScreenChanged(IScreen lastScreen, IScreen newScreen) + { + // The screen which we will be UNBINDING from the screen footer later on. + IScreen lastLeadingScreen = subScreenTracker?.leadingScreen ?? lastScreen; + + // Subscreens are attached to a parent screen, so when the parent changes the subscreen must also. + subScreenTracker?.Dispose(); + subScreenTracker = null; + + // Check if we've switched to a screen that has a subscreen. + if (newScreen is IHasSubScreenStack newStack) + { + subScreenTracker = new ScreenStackTracker(newStack.SubScreenStack); + subScreenTracker.ScreenChanged += onSubScreenScreenChanged; + } + + ScreenChanged?.Invoke(lastLeadingScreen, leadingScreen); + } + + private void onSubScreenScreenChanged(IScreen lastScreen, IScreen newScreen) + { + ScreenChanged?.Invoke(lastScreen, newScreen); + } + + public void Dispose() + { + stack.ScreenPushed -= onParentScreenChanged; + stack.ScreenExited -= onParentScreenChanged; + + if (subScreenTracker != null) + { + subScreenTracker.ScreenChanged -= onSubScreenScreenChanged; + subScreenTracker.Dispose(); + } + } + } + } +} From c80fe7ab82171159d3ebd9ddb7804fdbe75ba795 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 16 Oct 2025 18:07:57 +0900 Subject: [PATCH 015/836] Use new implementation in ScreenTestScene --- .../SongSelectV2/TestSceneSongSelect.cs | 4 +- osu.Game/Tests/Visual/ScreenTestScene.cs | 59 ++++--------------- 2 files changed, 15 insertions(+), 48 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs index 8419684b27f0..e4f05b2e495d 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs @@ -213,7 +213,7 @@ public void TestClearModsViaModButtonRightClick() AddAssert("mods selected", () => SelectedMods.Value, () => Has.Count.EqualTo(1)); AddStep("right click mod button", () => { - InputManager.MoveMouseTo(Footer.ChildrenOfType().Single()); + InputManager.MoveMouseTo(ScreenFooter.ChildrenOfType().Single()); InputManager.Click(MouseButton.Right); }); AddAssert("not mods selected", () => SelectedMods.Value, () => Has.Count.EqualTo(0)); @@ -620,7 +620,7 @@ public void TestFooterRewindViaMouseRight() AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled); } - private FooterButtonRandom randomButton => Footer.ChildrenOfType().Single(); + private FooterButtonRandom randomButton => ScreenFooter.ChildrenOfType().Single(); [Test] public void TestFooterOptions() diff --git a/osu.Game/Tests/Visual/ScreenTestScene.cs b/osu.Game/Tests/Visual/ScreenTestScene.cs index 42199faa4d01..7d28ee1d1d55 100644 --- a/osu.Game/Tests/Visual/ScreenTestScene.cs +++ b/osu.Game/Tests/Visual/ScreenTestScene.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Logging; -using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Graphics; using osu.Game.Overlays; @@ -34,12 +33,16 @@ public abstract partial class ScreenTestScene : OsuManualInputManagerTestScene, protected DialogOverlay DialogOverlay { get; private set; } [Cached] - protected ScreenFooter Footer { get; private set; } + protected ScreenFooter ScreenFooter { get; private set; } protected ScreenTestScene() { + ScreenStackFooter screenStackFooter; + ScreenFooter.BackReceptor backReceptor; + base.Content.AddRange(new Drawable[] { + backReceptor = new ScreenFooter.BackReceptor(), Stack = new OsuScreenStack { Name = nameof(ScreenTestScene), @@ -51,7 +54,10 @@ protected ScreenTestScene() Children = new Drawable[] { content = new Container { RelativeSizeAxes = Axes.Both }, - Footer = new ScreenFooter(), + screenStackFooter = new ScreenStackFooter(Stack, backReceptor) + { + BackButtonPressed = () => Stack.Exit() + } } }, overlayContent = new Container @@ -61,16 +67,10 @@ protected ScreenTestScene() }, }); - Stack.ScreenPushed += (oldScreen, newScreen) => - { - updateFooter(oldScreen, newScreen); - Logger.Log($"{nameof(ScreenTestScene)} screen changed → {newScreen}"); - }; - Stack.ScreenExited += (oldScreen, newScreen) => - { - updateFooter(oldScreen, newScreen); - Logger.Log($"{nameof(ScreenTestScene)} screen changed ← {newScreen}"); - }; + ScreenFooter = screenStackFooter.Footer; + + Stack.ScreenPushed += (_, newScreen) => Logger.Log($"{nameof(ScreenTestScene)} screen changed → {newScreen}"); + Stack.ScreenExited += (_, newScreen) => Logger.Log($"{nameof(ScreenTestScene)} screen changed ← {newScreen}"); } protected void LoadScreen(OsuScreen screen) => Stack.Push(screen); @@ -96,39 +96,6 @@ private void addExitAllScreensStep() }); } - private void updateFooter(IScreen? _, IScreen? newScreen) - { - if (newScreen is OsuScreen osuScreen && osuScreen.ShowFooter) - { - Footer.Show(); - - if (osuScreen.IsLoaded) - updateFooterButtons(); - else - { - // ensure the current buttons are immediately disabled on screen change (so they can't be pressed). - Footer.SetButtons(Array.Empty()); - - osuScreen.OnLoadComplete += _ => updateFooterButtons(); - } - - void updateFooterButtons() - { - var buttons = osuScreen.CreateFooterButtons(); - - osuScreen.LoadComponentsAgainstScreenDependencies(buttons); - - Footer.SetButtons(buttons); - Footer.Show(); - } - } - else - { - Footer.Hide(); - Footer.SetButtons(Array.Empty()); - } - } - #region IOverlayManager IBindable IOverlayManager.OverlayActivationMode { get; } = new Bindable(OverlayActivation.All); From bfa45a23ceb48bbcd58acde27475c961414fb4f6 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 11 Sep 2025 11:49:11 +0900 Subject: [PATCH 016/836] Add initial screen + test structure --- .../TestScenePlaylistsSongSelectV2.cs | 89 +++++++++++++++++++ .../Playlists/PlaylistsSongSelectV2.cs | 14 +++ .../Visual/OnlinePlay/OnlinePlayTestScene.cs | 2 +- 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/Playlists/TestScenePlaylistsSongSelectV2.cs create mode 100644 osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsSongSelectV2.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsSongSelectV2.cs new file mode 100644 index 000000000000..0bbd2f5d92a5 --- /dev/null +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsSongSelectV2.cs @@ -0,0 +1,89 @@ +// 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.Linq; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Platform; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Database; +using osu.Game.Rulesets; +using osu.Game.Scoring; +using osu.Game.Screens.OnlinePlay.Playlists; +using osu.Game.Screens.SelectV2; +using osu.Game.Tests.Resources; +using osu.Game.Tests.Visual.OnlinePlay; + +namespace osu.Game.Tests.Visual.Playlists +{ + public class TestScenePlaylistsSongSelectV2 : OnlinePlayTestScene + { + private BeatmapManager beatmaps = null!; + private RealmRulesetStore rulesets = null!; + private OsuConfigManager config = null!; + private ScoreManager scoreManager = null!; + private RealmDetachedBeatmapStore beatmapStore = null!; + + private PlaylistsSongSelectV2 songSelect = null!; + + private BeatmapCarousel Carousel => songSelect.ChildrenOfType().Single(); + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + + // These DI caches are required to ensure for interactive runs this test scene doesn't nuke all user beatmaps in the local install. + // At a point we have isolated interactive test runs enough, this can likely be removed. + dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); + dependencies.Cache(Realm); + dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, Dependencies.Get(), Resources, Dependencies.Get(), Beatmap.Default)); + dependencies.Cache(config = new OsuConfigManager(LocalStorage)); + dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmaps, LocalStorage, Realm, API, config)); + + dependencies.CacheAs(beatmapStore = new RealmDetachedBeatmapStore()); + + return dependencies; + } + + [BackgroundDependencyLoader] + private void load() + { + Add(beatmapStore); + } + + public override void SetUpSteps() + { + base.SetUpSteps(); + + ImportBeatmapForRuleset(0); + + AddStep("load screen", () => LoadScreen(songSelect = new PlaylistsSongSelectV2())); + AddUntilStep("wait for load", () => Stack.CurrentScreen == songSelect && songSelect.IsLoaded); + AddUntilStep("wait for filtering", () => !Carousel.IsFiltering); + } + + protected void ImportBeatmapForRuleset(params int[] rulesetIds) => ImportBeatmapForRuleset(_ => { }, 3, rulesetIds); + + protected void ImportBeatmapForRuleset(Action applyToBeatmap, int difficultyCount, params int[] rulesetIds) + { + int beatmapsCount = 0; + + AddStep($"import test map for ruleset {rulesetIds}", () => + { + beatmapsCount = songSelect.IsNull() ? 0 : Carousel.Filters.OfType().Single().SetItems.Count; + + var beatmapSet = TestResources.CreateTestBeatmapSetInfo(difficultyCount, rulesets.AvailableRulesets.Where(r => rulesetIds.Contains(r.OnlineID)).ToArray()); + applyToBeatmap(beatmapSet); + beatmaps.Import(beatmapSet); + }); + + // This is specifically for cases where the add is happening post song select load. + // For cases where song select is null, the assertions are provided by the load checks. + AddUntilStep("wait for imported to arrive in carousel", () => songSelect.IsNull() || Carousel.Filters.OfType().Single().SetItems.Count > beatmapsCount); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs new file mode 100644 index 000000000000..375e22cf000d --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -0,0 +1,14 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Screens.SelectV2; + +namespace osu.Game.Screens.OnlinePlay.Playlists +{ + public class PlaylistsSongSelectV2 : SongSelect + { + protected override void OnStart() + { + } + } +} diff --git a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs index 75932bbfef70..3aa126c2500c 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs @@ -46,7 +46,7 @@ protected OnlinePlayTestScene() }); } - protected sealed override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DelegatedDependencyContainer(base.CreateChildDependencies(parent)); public override void SetUpSteps() From ff6f797a3e0eef6e950b048386e72ca93598f0ae Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 11 Sep 2025 18:10:41 +0900 Subject: [PATCH 017/836] Add initial freemods button --- .../TestSceneFooterButtonFreeModsV2.cs | 44 +++++ .../OnlinePlay/FooterButtonFreeModsV2.cs | 171 ++++++++++++++++++ 2 files changed, 215 insertions(+) create mode 100644 osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreeModsV2.cs create mode 100644 osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs diff --git a/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreeModsV2.cs b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreeModsV2.cs new file mode 100644 index 000000000000..7eb82d5fd1c7 --- /dev/null +++ b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreeModsV2.cs @@ -0,0 +1,44 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Overlays; +using osu.Game.Overlays.Mods; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.OnlinePlay; + +namespace osu.Game.Tests.Visual.Playlists +{ + public partial class TestSceneFooterButtonFreeModsV2 : OsuTestScene + { + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + + public TestSceneFooterButtonFreeModsV2() + { + ModSelectOverlay modSelectOverlay; + Add(modSelectOverlay = new TestModSelectOverlay()); + + FooterButtonFreeModsV2 button; + Add(button = new FooterButtonFreeModsV2(modSelectOverlay) + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + X = -100, + }); + + button.FreeMods.Value = new OsuRuleset().CreateAllMods().ToArray(); + } + + private partial class TestModSelectOverlay : UserModSelectOverlay + { + public TestModSelectOverlay() + : base(OverlayColourScheme.Aquamarine) + { + IsValidMod = _ => true; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs new file mode 100644 index 000000000000..37755cd32659 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs @@ -0,0 +1,171 @@ +// 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.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Localisation; +using osu.Game.Overlays; +using osu.Game.Overlays.Mods; +using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Footer; +using osu.Game.Screens.Play.HUD; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay +{ + public partial class FooterButtonFreeModsV2 : ScreenFooterButton + { + private const float bar_height = 30f; + + public readonly Bindable> FreeMods = new Bindable>(); + public readonly IBindable Freestyle = new Bindable(); + + public new Action Action + { + set => throw new NotSupportedException("The click action is handled by the button itself."); + } + + [Resolved] + private OsuColour colours { get; set; } = null!; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + private ModDisplay modDisplay = null!; + private Container modContainer = null!; + private ModCountText overflowModCountDisplay = null!; + + public FooterButtonFreeModsV2(ModSelectOverlay overlay) + : base(overlay) + { + } + + [BackgroundDependencyLoader] + private void load() + { + Text = "Freemods"; + Icon = FontAwesome.Solid.ExchangeAlt; + AccentColour = colours.Lime1; + + AddRange(new[] + { + new Container + { + Y = -5f, + Depth = float.MaxValue, + Origin = Anchor.BottomLeft, + Shear = OsuGame.SHEAR, + CornerRadius = CORNER_RADIUS, + Size = new Vector2(BUTTON_WIDTH, bar_height), + Masking = true, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 4, + // Figma says 50% opacity, but it does not match up visually if taken at face value, and looks bad. + Colour = Colour4.Black.Opacity(0.25f), + Offset = new Vector2(0, 2), + }, + Children = new Drawable[] + { + new Box + { + Colour = colourProvider.Background4, + RelativeSizeAxes = Axes.Both, + }, + modContainer = new Container + { + CornerRadius = CORNER_RADIUS, + RelativeSizeAxes = Axes.Both, + Masking = true, + Children = new Drawable[] + { + new Box + { + Colour = colourProvider.Background3, + RelativeSizeAxes = Axes.Both, + }, + modDisplay = new ModDisplay(showExtendedInformation: true) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Shear = -OsuGame.SHEAR, + Scale = new Vector2(0.5f), + Current = { BindTarget = FreeMods }, + ExpansionMode = ExpansionMode.AlwaysContracted, + }, + overflowModCountDisplay = new ModCountText { Mods = { BindTarget = FreeMods }, }, + } + }, + } + }, + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Freestyle.BindValueChanged(f => Enabled.Value = !f.NewValue, true); + } + + protected override void Update() + { + base.Update(); + + if (FreeMods.Value.Count == 0) + return; + + if (modDisplay.DrawWidth * modDisplay.Scale.X > modContainer.DrawWidth) + overflowModCountDisplay.Show(); + else + overflowModCountDisplay.Hide(); + } + + private partial class ModCountText : CompositeDrawable + { + public readonly Bindable> Mods = new Bindable>(); + + private OsuSpriteText text = null!; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = colourProvider.Background3, + Alpha = 0.8f, + RelativeSizeAxes = Axes.Both, + }, + text = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.Torus.With(size: 14f, weight: FontWeight.Bold), + Shear = -OsuGame.SHEAR, + } + }; + + Mods.BindValueChanged(v => text.Text = ModSelectOverlayStrings.Mods(v.NewValue.Count).ToUpper(), true); + } + } + } +} From f1539167eb4fed9f0e1ec0433fe2b5400825af15 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 11 Sep 2025 18:24:27 +0900 Subject: [PATCH 018/836] Add initial freestyle button --- .../TestSceneFooterButtonFreestyleV2.cs | 26 ++++ .../OnlinePlay/FooterButtonFreestyleV2.cs | 121 ++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreestyleV2.cs create mode 100644 osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs diff --git a/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreestyleV2.cs b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreestyleV2.cs new file mode 100644 index 000000000000..32c2c33db108 --- /dev/null +++ b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreestyleV2.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Overlays; +using osu.Game.Screens.OnlinePlay; + +namespace osu.Game.Tests.Visual.Playlists +{ + public partial class TestSceneFooterButtonFreestyleV2 : OsuTestScene + { + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + + public TestSceneFooterButtonFreestyleV2() + { + Add(new FooterButtonFreestyleV2 + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + X = -100, + }); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs new file mode 100644 index 000000000000..5381c64cc46e --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs @@ -0,0 +1,121 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osu.Game.Screens.Footer; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay +{ + public class FooterButtonFreestyleV2 : ScreenFooterButton + { + private const float bar_height = 30f; + + public readonly Bindable Freestyle = new Bindable(); + + public new Action Action + { + set => throw new NotSupportedException("The click action is handled by the button itself."); + } + + [Resolved] + private OsuColour colours { get; set; } = null!; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + public FooterButtonFreestyleV2() + { + // Overwrite any external behaviour as we delegate the main toggle action to a sub-button. + base.Action = () => Freestyle.Value = !Freestyle.Value; + } + + [BackgroundDependencyLoader] + private void load() + { + Text = "Freestyle"; + Icon = FontAwesome.Solid.ExchangeAlt; + AccentColour = colours.Lime1; + + AddRange(new[] + { + new Container + { + Y = -5f, + Depth = float.MaxValue, + Origin = Anchor.BottomLeft, + Shear = OsuGame.SHEAR, + CornerRadius = CORNER_RADIUS, + Size = new Vector2(BUTTON_WIDTH, bar_height), + Masking = true, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 4, + // Figma says 50% opacity, but it does not match up visually if taken at face value, and looks bad. + Colour = Colour4.Black.Opacity(0.25f), + Offset = new Vector2(0, 2), + }, + Children = new Drawable[] + { + new Box + { + Colour = colourProvider.Background3, + RelativeSizeAxes = Axes.Both, + }, + new StatusText { Freestyle = { BindTarget = Freestyle } } + } + }, + }); + } + + private partial class StatusText : CompositeDrawable + { + public readonly Bindable Freestyle = new Bindable(); + + private OsuSpriteText text = null!; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = colourProvider.Background3, + Alpha = 0.8f, + RelativeSizeAxes = Axes.Both, + }, + text = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.Torus.With(size: 14f, weight: FontWeight.Bold), + Shear = -OsuGame.SHEAR, + } + }; + + Freestyle.BindValueChanged(v => + { + text.Text = v.NewValue ? "ON" : "OFF"; + }, true); + } + } + } +} From 87834d1693a4d52a5b60a728ea5dd7620866c523 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 11 Sep 2025 18:44:31 +0900 Subject: [PATCH 019/836] Add overall mods/freemods/freestyle hookups --- .../TestScenePlaylistsSongSelectV2.cs | 3 +- .../Playlists/PlaylistsSongSelectV2.cs | 138 ++++++++++++++++++ osu.Game/Screens/SelectV2/SongSelect.cs | 17 ++- 3 files changed, 149 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsSongSelectV2.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsSongSelectV2.cs index 0bbd2f5d92a5..923970e921b7 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsSongSelectV2.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsSongSelectV2.cs @@ -11,6 +11,7 @@ using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Database; +using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Playlists; @@ -61,7 +62,7 @@ public override void SetUpSteps() ImportBeatmapForRuleset(0); - AddStep("load screen", () => LoadScreen(songSelect = new PlaylistsSongSelectV2())); + AddStep("load screen", () => LoadScreen(songSelect = new PlaylistsSongSelectV2(new Room()))); AddUntilStep("wait for load", () => Stack.CurrentScreen == songSelect && songSelect.IsLoaded); AddUntilStep("wait for filtering", () => !Carousel.IsFiltering); } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index 375e22cf000d..d63c105afbc5 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -1,14 +1,152 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Localisation; +using osu.Game.Online.Rooms; +using osu.Game.Overlays; +using osu.Game.Overlays.Mods; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Footer; using osu.Game.Screens.SelectV2; +using osu.Game.Utils; namespace osu.Game.Screens.OnlinePlay.Playlists { public class PlaylistsSongSelectV2 : SongSelect { + private readonly Bindable> freeMods = new Bindable>([]); + private readonly Bindable freestyle = new Bindable(true); + + private readonly Room room; + private ModSelectOverlay modSelect = null!; + private FreeModSelectOverlay freeModSelect = null!; + + public PlaylistsSongSelectV2(Room room) + { + this.room = room; + } + + [BackgroundDependencyLoader] + private void load() + { + AddInternal(freeModSelect = new FreeModSelectOverlay + { + SelectedMods = { BindTarget = freeMods }, + IsValidMod = isValidAllowedMod, + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Mods.BindValueChanged(onGlobalModsChanged); + Ruleset.BindValueChanged(onRulesetChanged); + freestyle.BindValueChanged(onFreestyleChanged); + + updateValidMods(); + } + + private void onGlobalModsChanged(ValueChangedEvent> mods) + { + updateValidMods(); + } + + private void onRulesetChanged(ValueChangedEvent ruleset) + { + // Todo: We can probably attempt to preserve across rulesets like the global mods do. + freeMods.Value = []; + } + + private void onFreestyleChanged(ValueChangedEvent enabled) + { + updateValidMods(); + + if (enabled.NewValue) + { + freeModSelect.Hide(); + + // Freestyle allows all mods to be selected as freemods. This does not play nicely for some components: + // - We probably don't want to store a gigantic list of acronyms to the database. + // - The mod select overlay isn't built to handle duplicate mods/mods from all rulesets being shoved into it. + // Instead, freestyle inherently assumes this list is empty, and must be empty for server-side validation to pass. + freeMods.Value = []; + } + else + { + // When disabling freestyle, enable freemods by default. + freeMods.Value = freeModSelect.AllAvailableMods.Where(state => state.ValidForSelection.Value).Select(state => state.Mod).ToArray(); + } + } + + /// + /// Removes invalid mods from and , + /// and updates mod selection overlays to display the new mods valid for selection. + /// + private void updateValidMods() + { + Mod[] validMods = Mods.Value.Where(isValidRequiredMod).ToArray(); + if (!validMods.SequenceEqual(Mods.Value)) + Mods.Value = validMods; + + Mod[] validFreeMods = freeMods.Value.Where(isValidAllowedMod).ToArray(); + if (!validFreeMods.SequenceEqual(freeMods.Value)) + freeMods.Value = validFreeMods; + + modSelect.IsValidMod = isValidRequiredMod; + freeModSelect.IsValidMod = isValidAllowedMod; + } + protected override void OnStart() { } + + public override IReadOnlyList CreateFooterButtons() + { + var buttons = base.CreateFooterButtons().ToList(); + + buttons.Single(i => i is FooterButtonMods).TooltipText = MultiplayerMatchStrings.RequiredModsButtonTooltip; + + buttons.InsertRange(buttons.FindIndex(b => b is FooterButtonMods) + 1, + [ + new FooterButtonFreeModsV2(freeModSelect) + { + FreeMods = { BindTarget = freeMods }, + Freestyle = { BindTarget = freestyle } + }, + new FooterButtonFreestyleV2 + { + Freestyle = { BindTarget = freestyle } + } + ]); + + return buttons; + } + + protected override ModSelectOverlay CreateModSelectOverlay() => modSelect = new UserModSelectOverlay(OverlayColourScheme.Plum) + { + IsValidMod = isValidRequiredMod + }; + + /// + /// Checks whether a given is valid to be selected as a required mod. + /// + /// The to check. + private bool isValidRequiredMod(Mod mod) => ModUtils.IsValidModForMatch(mod, true, room.Type, freestyle.Value); + + /// + /// Checks whether a given is valid to be selected as an allowed mod. + /// + /// The to check. + private bool isValidAllowedMod(Mod mod) => ModUtils.IsValidModForMatch(mod, false, room.Type, freestyle.Value) + // Mod must not be contained in the required mods. + && Mods.Value.All(m => m.Acronym != mod.Acronym) + // Mod must be compatible with all the required mods. + && ModUtils.CheckCompatibleSet(Mods.Value.Append(mod).ToArray()); } } diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index f047184d993d..456e6b2a09e4 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -94,13 +94,7 @@ public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBind /// protected bool ControlGlobalMusic { get; init; } = true; - // Colour scheme for mod overlay is left as default (green) to match mods button. - // Not sure about this, but we'll iterate based on feedback. - private readonly ModSelectOverlay modSelectOverlay = new UserModSelectOverlay - { - ShowPresets = true, - }; - + private ModSelectOverlay modSelectOverlay = null!; private ModSpeedHotkeyHandler modSpeedHotkeyHandler = null!; // Blue is the most neutral choice, so I'm using that for now. @@ -297,7 +291,7 @@ private void load(AudioManager audio, OsuConfigManager config) RelativeSizeAxes = Axes.Both, }, modSpeedHotkeyHandler = new ModSpeedHotkeyHandler(), - modSelectOverlay, + modSelectOverlay = CreateModSelectOverlay(), }); configBackgroundBlur = config.GetBindable(OsuSetting.SongSelectBackgroundBlur); @@ -312,6 +306,13 @@ private void load(AudioManager audio, OsuConfigManager config) showConvertedBeatmaps = config.GetBindable(OsuSetting.ShowConvertedBeatmaps); } + // Colour scheme for mod overlay is left as default (green) to match mods button. + // Not sure about this, but we'll iterate based on feedback. + protected virtual ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay + { + ShowPresets = true, + }; + private void requestRecommendedSelection(IEnumerable groupedBeatmaps) { var recommendedBeatmap = difficultyRecommender?.GetRecommendedBeatmap(groupedBeatmaps.Select(gb => gb.Beatmap)) ?? groupedBeatmaps.First().Beatmap; From 259bc536999076421f0bbbbb9ad28e422e117731 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 12 Sep 2025 13:46:04 +0900 Subject: [PATCH 020/836] Add initial playlist button --- .../TestSceneFooterButtonPlaylistV2.cs | 37 ++++++ .../OnlinePlay/FooterButtonPlaylistV2.cs | 124 ++++++++++++++++++ .../Playlists/PlaylistsSongSelectV2.cs | 18 +++ 3 files changed, 179 insertions(+) create mode 100644 osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonPlaylistV2.cs create mode 100644 osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs diff --git a/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonPlaylistV2.cs b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonPlaylistV2.cs new file mode 100644 index 000000000000..dc84102aef7a --- /dev/null +++ b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonPlaylistV2.cs @@ -0,0 +1,37 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Cursor; +using osu.Game.Online.Rooms; +using osu.Game.Overlays; +using osu.Game.Screens.OnlinePlay; +using osu.Game.Tests.Visual.OnlinePlay; + +namespace osu.Game.Tests.Visual.Playlists +{ + public partial class TestSceneFooterButtonPlaylistV2 : OnlinePlayTestScene + { + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + + public TestSceneFooterButtonPlaylistV2() + { + Room room = new Room(); + + Add(new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + Child = new FooterButtonPlaylistV2(room) + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + X = -100, + CreateNewItem = () => room.Playlist = room.Playlist.Append(new PlaylistItem(CreateAPIBeatmap())).ToArray() + } + }); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs new file mode 100644 index 000000000000..0cf515c544f1 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs @@ -0,0 +1,124 @@ +// 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.ComponentModel; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Online.Rooms; +using osu.Game.Screens.Footer; +using osu.Game.Screens.OnlinePlay.Playlists; +using osuTK; +using Container = osu.Framework.Graphics.Containers.Container; + +namespace osu.Game.Screens.OnlinePlay +{ + public partial class FooterButtonPlaylistV2 : ScreenFooterButton, IHasPopover + { + public required Action? CreateNewItem { get; init; } + + private readonly Room room; + + public FooterButtonPlaylistV2(Room room) + { + this.room = room; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + Text = "Playlist"; + Icon = FontAwesome.Solid.List; + AccentColour = colour.Purple1; + + Action = this.ShowPopover; + } + + public Popover GetPopover() => new PlaylistPopover(room) + { + CreateNewItem = CreateNewItem + }; + + private partial class PlaylistPopover : OsuPopover + { + public required Action? CreateNewItem { get; init; } + + private readonly Room room; + private PlaylistsRoomSettingsPlaylist playlist = null!; + + public PlaylistPopover(Room room) + { + this.room = room; + } + + [BackgroundDependencyLoader] + private void load() + { + Content.Padding = new MarginPadding(5); + + Add(new GridContainer + { + Size = new Vector2(300, 300), + Padding = new MarginPadding { Vertical = 10 }, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Bottom = 10 }, + Child = playlist = new PlaylistsRoomSettingsPlaylist + { + RelativeSizeAxes = Axes.Both + } + } + }, + new Drawable[] + { + new RoundedButton + { + Text = "Add new playlist entry", + RelativeSizeAxes = Axes.Both, + Size = Vector2.One, + Action = () => CreateNewItem?.Invoke() + } + }, + }, + RowDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.Absolute, 50), + } + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + playlist.Items.BindCollectionChanged((_, __) => room.Playlist = playlist.Items.ToArray()); + + room.PropertyChanged += onRoomPropertyChanged; + updateRoomPlaylist(); + } + + private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(Room.Playlist)) + updateRoomPlaylist(); + } + + private void updateRoomPlaylist() + => playlist.Items.ReplaceRange(0, playlist.Items.Count, room.Playlist); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index d63c105afbc5..8e51ddb1a0c4 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -5,7 +5,9 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Screens; using osu.Game.Localisation; +using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Overlays.Mods; @@ -104,6 +106,8 @@ private void updateValidMods() protected override void OnStart() { + room.Playlist = [createNewItem()]; + this.Exit(); } public override IReadOnlyList CreateFooterButtons() @@ -112,6 +116,11 @@ public override IReadOnlyList CreateFooterButtons() buttons.Single(i => i is FooterButtonMods).TooltipText = MultiplayerMatchStrings.RequiredModsButtonTooltip; + buttons.Insert(0, new FooterButtonPlaylistV2(room) + { + CreateNewItem = () => room.Playlist = room.Playlist.Append(createNewItem()).ToArray() + }); + buttons.InsertRange(buttons.FindIndex(b => b is FooterButtonMods) + 1, [ new FooterButtonFreeModsV2(freeModSelect) @@ -133,6 +142,15 @@ public override IReadOnlyList CreateFooterButtons() IsValidMod = isValidRequiredMod }; + private PlaylistItem createNewItem() => new PlaylistItem(Beatmap.Value.BeatmapInfo) + { + ID = room.Playlist.Count == 0 ? 0 : room.Playlist.Max(p => p.ID) + 1, + RulesetID = Ruleset.Value.OnlineID, + RequiredMods = Mods.Value.Select(m => new APIMod(m)).ToArray(), + AllowedMods = freeMods.Value.Select(m => new APIMod(m)).ToArray(), + Freestyle = freestyle.Value + }; + /// /// Checks whether a given is valid to be selected as a required mod. /// From 3c1d45b8969335bee379bd935b5f1ca53c704045 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 19 Sep 2025 16:27:56 +0900 Subject: [PATCH 021/836] Integrate v2 playlists song select with game --- osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs | 4 ++++ .../Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs index 0cf515c544f1..fdf6c09e69c3 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs @@ -14,6 +14,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.Rooms; +using osu.Game.Overlays; using osu.Game.Screens.Footer; using osu.Game.Screens.OnlinePlay.Playlists; using osuTK; @@ -54,6 +55,9 @@ private partial class PlaylistPopover : OsuPopover private readonly Room room; private PlaylistsRoomSettingsPlaylist playlist = null!; + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); + public PlaylistPopover(Room room) { this.room = room; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index fdda6f6c8551..9d210e4678db 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -404,7 +404,7 @@ private void load() EditPlaylist = () => { if (this.IsCurrentScreen()) - this.Push(new PlaylistsSongSelect(room)); + this.Push(new PlaylistsSongSelectV2(room)); } } } From b663fe17aba8aa58fa59e92b6b7d92b570d17a91 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 19 Sep 2025 16:47:48 +0900 Subject: [PATCH 022/836] Fix tests --- ...t.cs => TestScenePlaylistsSongSelectV2.cs} | 44 ++++----- .../Navigation/TestSceneScreenNavigation.cs | 4 +- .../TestScenePlaylistsSongSelectV2.cs | 90 ------------------- .../Playlists/PlaylistsSongSelectV2.cs | 25 +++--- 4 files changed, 35 insertions(+), 128 deletions(-) rename osu.Game.Tests/Visual/Multiplayer/{TestScenePlaylistsSongSelect.cs => TestScenePlaylistsSongSelectV2.cs} (78%) delete mode 100644 osu.Game.Tests/Visual/Playlists/TestScenePlaylistsSongSelectV2.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs similarity index 78% rename from osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs rename to osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs index 7135ff930d8e..ec853669af75 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs @@ -9,9 +9,7 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Framework.Platform; -using osu.Framework.Screens; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps; @@ -22,7 +20,6 @@ using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.OnlinePlay; -using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual.OnlinePlay; @@ -30,7 +27,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { - public partial class TestScenePlaylistsSongSelect : OnlinePlayTestScene + public partial class TestScenePlaylistsSongSelectV2 : OnlinePlayTestScene { private RulesetStore rulesets = null!; private BeatmapManager manager = null!; @@ -69,47 +66,47 @@ public override void SetUpSteps() }); AddStep("create song select", () => LoadScreen(songSelect = new TestPlaylistsSongSelect(room))); - AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && songSelect.BeatmapSetsLoaded); + AddUntilStep("wait for song select", () => songSelect.IsLoaded && !songSelect.IsFiltering); } [Test] public void TestItemAddedIfEmptyOnStart() { - AddStep("finalise selection", () => songSelect.FinaliseSelection()); + AddStep("finalise selection", () => InputManager.Key(Key.Enter)); AddAssert("playlist has 1 item", () => room.Playlist.Count == 1); } [Test] public void TestItemAddedWhenCreateNewItemClicked() { - AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem!()); + AddStep("create new item", () => songSelect.AddNewItem()); AddAssert("playlist has 1 item", () => room.Playlist.Count == 1); } [Test] public void TestItemNotAddedIfExistingOnStart() { - AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem!()); - AddStep("finalise selection", () => songSelect.FinaliseSelection()); + AddStep("create new item", () => songSelect.AddNewItem()); + AddStep("finalise selection", () => InputManager.Key(Key.Enter)); AddAssert("playlist has 1 item", () => room.Playlist.Count == 1); } [Test] public void TestAddSameItemMultipleTimes() { - AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem!()); - AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem!()); + AddStep("create new item", () => songSelect.AddNewItem()); + AddStep("create new item", () => songSelect.AddNewItem()); AddAssert("playlist has 2 items", () => room.Playlist.Count == 2); } [Test] public void TestAddItemAfterRearrangement() { - AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem!()); - AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem!()); + AddStep("create new item", () => songSelect.AddNewItem()); + AddStep("create new item", () => songSelect.AddNewItem()); AddStep("rearrange", () => room.Playlist = room.Playlist.Skip(1).Append(room.Playlist[0]).ToArray()); - AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem!()); + AddStep("create new item", () => songSelect.AddNewItem()); AddAssert("new item has id 2", () => room.Playlist.Last().ID == 2); } @@ -120,9 +117,9 @@ public void TestAddItemAfterRearrangement() public void TestNewItemHasNewModInstances() { AddStep("set dt mod", () => SelectedMods.Value = new[] { new OsuModDoubleTime() }); - AddStep("create item", () => songSelect.BeatmapDetails.CreateNewItem!()); + AddStep("create item", () => songSelect.AddNewItem()); AddStep("change mod rate", () => ((OsuModDoubleTime)SelectedMods.Value[0]).SpeedChange.Value = 2); - AddStep("create item", () => songSelect.BeatmapDetails.CreateNewItem!()); + AddStep("create item", () => songSelect.AddNewItem()); AddAssert("item 1 has rate 1.5", () => { @@ -153,7 +150,7 @@ public void TestGlobalModInstancesNotRetained() mod = (OsuModDoubleTime)SelectedMods.Value[0]; }); - AddStep("create item", () => songSelect.BeatmapDetails.CreateNewItem!()); + AddStep("create item", () => songSelect.AddNewItem()); AddStep("change stored mod rate", () => mod.SpeedChange.Value = 2); AddAssert("item has rate 1.5", () => @@ -166,26 +163,23 @@ public void TestGlobalModInstancesNotRetained() [Test] public void TestFreeModSelectionDisable() { - FooterButtonFreeMods freeMods = null!; - AddAssert("freestyle enabled", () => songSelect.Freestyle.Value, () => Is.True); AddStep("click icon in free mods button", () => { - freeMods = this.ChildrenOfType().Single(); - InputManager.MoveMouseTo(freeMods.ChildrenOfType().Single()); + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); AddAssert("mod select not visible", () => this.ChildrenOfType().Single().State.Value, () => Is.EqualTo(Visibility.Hidden)); AddStep("toggle freestyle off", () => { - InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); AddAssert("freestyle disabled", () => songSelect.Freestyle.Value, () => Is.False); AddStep("click icon in free mods button", () => { - InputManager.MoveMouseTo(freeMods.ChildrenOfType().Single()); + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); AddAssert("mod select visible", () => this.ChildrenOfType().Single().State.Value, () => Is.EqualTo(Visibility.Visible)); @@ -199,10 +193,8 @@ protected override void Dispose(bool isDisposing) rulesets.Dispose(); } - private partial class TestPlaylistsSongSelect : PlaylistsSongSelect + private partial class TestPlaylistsSongSelect : PlaylistsSongSelectV2 { - public new MatchBeatmapDetailArea BeatmapDetails => (MatchBeatmapDetailArea)base.BeatmapDetails; - public new IBindable Freestyle => base.Freestyle; public TestPlaylistsSongSelect(Room room) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 8a0c9f561ccf..04e1da5b9b9d 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -92,7 +92,7 @@ public void TestConfirmationRequiredToDiscardPlaylist(bool withPlaylistItemAdded AddStep("edit playlist", () => InputManager.Key(Key.Enter)); - AddUntilStep("wait for song select", () => (playlistScreen.CurrentSubScreen as PlaylistsSongSelect)?.BeatmapSetsLoaded == true); + AddUntilStep("wait for song select", () => playlistScreen.CurrentSubScreen is PlaylistsSongSelectV2 songSelect && songSelect.IsLoaded && !songSelect.IsFiltering); AddUntilStep("wait for selection", () => !Game.Beatmap.IsDefault); @@ -106,7 +106,7 @@ public void TestConfirmationRequiredToDiscardPlaylist(bool withPlaylistItemAdded InputManager.Click(MouseButton.Left); }); - AddUntilStep("wait for song select", () => (playlistScreen.CurrentSubScreen as PlaylistsSongSelect)?.BeatmapSetsLoaded == true); + AddUntilStep("wait for song select", () => playlistScreen.CurrentSubScreen is PlaylistsSongSelectV2 songSelect && songSelect.IsLoaded && !songSelect.IsFiltering); AddStep("press home button", () => { diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsSongSelectV2.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsSongSelectV2.cs deleted file mode 100644 index 923970e921b7..000000000000 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsSongSelectV2.cs +++ /dev/null @@ -1,90 +0,0 @@ -// 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.Linq; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Platform; -using osu.Framework.Testing; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Database; -using osu.Game.Online.Rooms; -using osu.Game.Rulesets; -using osu.Game.Scoring; -using osu.Game.Screens.OnlinePlay.Playlists; -using osu.Game.Screens.SelectV2; -using osu.Game.Tests.Resources; -using osu.Game.Tests.Visual.OnlinePlay; - -namespace osu.Game.Tests.Visual.Playlists -{ - public class TestScenePlaylistsSongSelectV2 : OnlinePlayTestScene - { - private BeatmapManager beatmaps = null!; - private RealmRulesetStore rulesets = null!; - private OsuConfigManager config = null!; - private ScoreManager scoreManager = null!; - private RealmDetachedBeatmapStore beatmapStore = null!; - - private PlaylistsSongSelectV2 songSelect = null!; - - private BeatmapCarousel Carousel => songSelect.ChildrenOfType().Single(); - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - // These DI caches are required to ensure for interactive runs this test scene doesn't nuke all user beatmaps in the local install. - // At a point we have isolated interactive test runs enough, this can likely be removed. - dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); - dependencies.Cache(Realm); - dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, Dependencies.Get(), Resources, Dependencies.Get(), Beatmap.Default)); - dependencies.Cache(config = new OsuConfigManager(LocalStorage)); - dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmaps, LocalStorage, Realm, API, config)); - - dependencies.CacheAs(beatmapStore = new RealmDetachedBeatmapStore()); - - return dependencies; - } - - [BackgroundDependencyLoader] - private void load() - { - Add(beatmapStore); - } - - public override void SetUpSteps() - { - base.SetUpSteps(); - - ImportBeatmapForRuleset(0); - - AddStep("load screen", () => LoadScreen(songSelect = new PlaylistsSongSelectV2(new Room()))); - AddUntilStep("wait for load", () => Stack.CurrentScreen == songSelect && songSelect.IsLoaded); - AddUntilStep("wait for filtering", () => !Carousel.IsFiltering); - } - - protected void ImportBeatmapForRuleset(params int[] rulesetIds) => ImportBeatmapForRuleset(_ => { }, 3, rulesetIds); - - protected void ImportBeatmapForRuleset(Action applyToBeatmap, int difficultyCount, params int[] rulesetIds) - { - int beatmapsCount = 0; - - AddStep($"import test map for ruleset {rulesetIds}", () => - { - beatmapsCount = songSelect.IsNull() ? 0 : Carousel.Filters.OfType().Single().SetItems.Count; - - var beatmapSet = TestResources.CreateTestBeatmapSetInfo(difficultyCount, rulesets.AvailableRulesets.Where(r => rulesetIds.Contains(r.OnlineID)).ToArray()); - applyToBeatmap(beatmapSet); - beatmaps.Import(beatmapSet); - }); - - // This is specifically for cases where the add is happening post song select load. - // For cases where song select is null, the assertions are provided by the load checks. - AddUntilStep("wait for imported to arrive in carousel", () => songSelect.IsNull() || Carousel.Filters.OfType().Single().SetItems.Count > beatmapsCount); - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index 8e51ddb1a0c4..b4a644342ccf 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -21,8 +21,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { public class PlaylistsSongSelectV2 : SongSelect { + protected readonly Bindable Freestyle = new Bindable(true); private readonly Bindable> freeMods = new Bindable>([]); - private readonly Bindable freestyle = new Bindable(true); private readonly Room room; private ModSelectOverlay modSelect = null!; @@ -49,11 +49,16 @@ protected override void LoadComplete() Mods.BindValueChanged(onGlobalModsChanged); Ruleset.BindValueChanged(onRulesetChanged); - freestyle.BindValueChanged(onFreestyleChanged); + Freestyle.BindValueChanged(onFreestyleChanged); updateValidMods(); } + public void AddNewItem() + { + room.Playlist = room.Playlist.Append(createItem()).ToArray(); + } + private void onGlobalModsChanged(ValueChangedEvent> mods) { updateValidMods(); @@ -106,7 +111,7 @@ private void updateValidMods() protected override void OnStart() { - room.Playlist = [createNewItem()]; + room.Playlist = [createItem()]; this.Exit(); } @@ -118,7 +123,7 @@ public override IReadOnlyList CreateFooterButtons() buttons.Insert(0, new FooterButtonPlaylistV2(room) { - CreateNewItem = () => room.Playlist = room.Playlist.Append(createNewItem()).ToArray() + CreateNewItem = AddNewItem }); buttons.InsertRange(buttons.FindIndex(b => b is FooterButtonMods) + 1, @@ -126,11 +131,11 @@ public override IReadOnlyList CreateFooterButtons() new FooterButtonFreeModsV2(freeModSelect) { FreeMods = { BindTarget = freeMods }, - Freestyle = { BindTarget = freestyle } + Freestyle = { BindTarget = Freestyle } }, new FooterButtonFreestyleV2 { - Freestyle = { BindTarget = freestyle } + Freestyle = { BindTarget = Freestyle } } ]); @@ -142,26 +147,26 @@ public override IReadOnlyList CreateFooterButtons() IsValidMod = isValidRequiredMod }; - private PlaylistItem createNewItem() => new PlaylistItem(Beatmap.Value.BeatmapInfo) + private PlaylistItem createItem() => new PlaylistItem(Beatmap.Value.BeatmapInfo) { ID = room.Playlist.Count == 0 ? 0 : room.Playlist.Max(p => p.ID) + 1, RulesetID = Ruleset.Value.OnlineID, RequiredMods = Mods.Value.Select(m => new APIMod(m)).ToArray(), AllowedMods = freeMods.Value.Select(m => new APIMod(m)).ToArray(), - Freestyle = freestyle.Value + Freestyle = Freestyle.Value }; /// /// Checks whether a given is valid to be selected as a required mod. /// /// The to check. - private bool isValidRequiredMod(Mod mod) => ModUtils.IsValidModForMatch(mod, true, room.Type, freestyle.Value); + private bool isValidRequiredMod(Mod mod) => ModUtils.IsValidModForMatch(mod, true, room.Type, Freestyle.Value); /// /// Checks whether a given is valid to be selected as an allowed mod. /// /// The to check. - private bool isValidAllowedMod(Mod mod) => ModUtils.IsValidModForMatch(mod, false, room.Type, freestyle.Value) + private bool isValidAllowedMod(Mod mod) => ModUtils.IsValidModForMatch(mod, false, room.Type, Freestyle.Value) // Mod must not be contained in the required mods. && Mods.Value.All(m => m.Acronym != mod.Acronym) // Mod must be compatible with all the required mods. From f38162c550036ea78ed5a974d7139c2c41687272 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Sep 2025 11:10:35 +0900 Subject: [PATCH 023/836] Fix padding as subscreen --- .../Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs | 4 ++++ osu.Game/Screens/SelectV2/SongSelect.cs | 3 +++ 2 files changed, 7 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index b4a644342ccf..ea7eba23b326 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -5,6 +5,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Localisation; using osu.Game.Online.API; @@ -31,6 +32,9 @@ public class PlaylistsSongSelectV2 : SongSelect public PlaylistsSongSelectV2(Room room) { this.room = room; + + Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; + LeftPadding = new MarginPadding { Top = CORNER_RADIUS_HIDE_OFFSET + Header.HEIGHT }; } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index 456e6b2a09e4..8505bf016579 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -94,6 +94,8 @@ public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBind /// protected bool ControlGlobalMusic { get; init; } = true; + protected MarginPadding LeftPadding { get; init; } + private ModSelectOverlay modSelectOverlay = null!; private ModSpeedHotkeyHandler modSpeedHotkeyHandler = null!; @@ -222,6 +224,7 @@ private void load(AudioManager audio, OsuConfigManager config) RelativeSizeAxes = Axes.Both, Spacing = new Vector2(0f, 4f), Direction = FillDirection.Vertical, + Padding = LeftPadding, Children = new Drawable[] { new ShearAligningWrapper(titleWedge = new BeatmapTitleWedge()), From 798f6bdcc79929c8548b8a587e808d1f18dac16f Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Sep 2025 11:43:34 +0900 Subject: [PATCH 024/836] Fix padding not considered in sizing --- osu.Game/Screens/SelectV2/SongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index 8505bf016579..aaa029f684d3 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -396,7 +396,7 @@ protected override void Update() { base.Update(); - detailsArea.Height = wedgesContainer.DrawHeight - titleWedge.LayoutSize.Y - 4; + detailsArea.Height = wedgesContainer.ChildSize.Y - titleWedge.LayoutSize.Y - 4; float widescreenBonusWidth = Math.Max(0, DrawWidth / DrawHeight - 2f); From 0777bdbfc54c0166a5c496063f72366cb418411e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Sep 2025 11:11:24 +0900 Subject: [PATCH 025/836] Add screen title --- .../Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index ea7eba23b326..b0c2bda0dc33 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -20,8 +21,12 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { - public class PlaylistsSongSelectV2 : SongSelect + public class PlaylistsSongSelectV2 : SongSelect, IOnlinePlaySubScreen { + public string ShortTitle => "song selection"; + + public override string Title => ShortTitle.Humanize(); + protected readonly Bindable Freestyle = new Bindable(true); private readonly Bindable> freeMods = new Bindable>([]); From 67849ca4180924e31c26f2b511ecceb09d3f64c9 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Sep 2025 12:13:40 +0900 Subject: [PATCH 026/836] Adjust button styling --- .../TestSceneFooterButtonFreeModsV2.cs | 23 ++++++- .../OnlinePlay/FooterButtonFreeModsV2.cs | 24 +++++-- .../OnlinePlay/FooterButtonFreestyleV2.cs | 62 ++++++++----------- 3 files changed, 67 insertions(+), 42 deletions(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreeModsV2.cs b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreeModsV2.cs index 7eb82d5fd1c7..222b9a80f83d 100644 --- a/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreeModsV2.cs +++ b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreeModsV2.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Overlays; @@ -16,20 +17,36 @@ public partial class TestSceneFooterButtonFreeModsV2 : OsuTestScene [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + private readonly FooterButtonFreeModsV2 button; + public TestSceneFooterButtonFreeModsV2() { ModSelectOverlay modSelectOverlay; Add(modSelectOverlay = new TestModSelectOverlay()); - - FooterButtonFreeModsV2 button; Add(button = new FooterButtonFreeModsV2(modSelectOverlay) { Anchor = Anchor.Centre, Origin = Anchor.CentreLeft, X = -100, }); + } + + [Test] + public void TestAllMods() + { + AddStep("all mods", () => button.FreeMods.Value = new OsuRuleset().CreateAllMods().ToArray()); + } - button.FreeMods.Value = new OsuRuleset().CreateAllMods().ToArray(); + [Test] + public void TestNoMods() + { + AddStep("no mods", () => button.FreeMods.Value = []); + } + + [Test] + public void TestFreestyle() + { + AddToggleStep("toggle freestyle", v => button.Freestyle.Value = v); } private partial class TestModSelectOverlay : UserModSelectOverlay diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs index 37755cd32659..d9cb0acb4fc0 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs @@ -27,8 +27,8 @@ public partial class FooterButtonFreeModsV2 : ScreenFooterButton { private const float bar_height = 30f; - public readonly Bindable> FreeMods = new Bindable>(); - public readonly IBindable Freestyle = new Bindable(); + public readonly Bindable> FreeMods = new Bindable>([]); + public readonly Bindable Freestyle = new Bindable(); public new Action Action { @@ -104,7 +104,11 @@ private void load() Current = { BindTarget = FreeMods }, ExpansionMode = ExpansionMode.AlwaysContracted, }, - overflowModCountDisplay = new ModCountText { Mods = { BindTarget = FreeMods }, }, + overflowModCountDisplay = new ModCountText + { + Mods = { BindTarget = FreeMods }, + Freestyle = { BindTarget = Freestyle } + }, } }, } @@ -135,6 +139,7 @@ protected override void Update() private partial class ModCountText : CompositeDrawable { public readonly Bindable> Mods = new Bindable>(); + public readonly Bindable Freestyle = new Bindable(); private OsuSpriteText text = null!; @@ -164,7 +169,18 @@ protected override void LoadComplete() } }; - Mods.BindValueChanged(v => text.Text = ModSelectOverlayStrings.Mods(v.NewValue.Count).ToUpper(), true); + Mods.BindValueChanged(_ => updateText()); + Freestyle.BindValueChanged(_ => updateText()); + + updateText(); + } + + private void updateText() + { + if (Freestyle.Value) + text.Text = "ALL MODS"; + else + text.Text = ModSelectOverlayStrings.Mods(Mods.Value.Count).ToUpper(); } } } diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs index 5381c64cc46e..6d39ee92e7f6 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs @@ -14,6 +14,7 @@ using osu.Game.Overlays; using osu.Game.Screens.Footer; using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay { @@ -34,6 +35,9 @@ public class FooterButtonFreestyleV2 : ScreenFooterButton [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; + private Drawable statusBackground = null!; + private OsuSpriteText statusText = null!; + public FooterButtonFreestyleV2() { // Overwrite any external behaviour as we delegate the main toggle action to a sub-button. @@ -66,56 +70,44 @@ private void load() Colour = Colour4.Black.Opacity(0.25f), Offset = new Vector2(0, 2), }, - Children = new Drawable[] + Children = new[] { - new Box + statusBackground = new Box { Colour = colourProvider.Background3, RelativeSizeAxes = Axes.Both, }, - new StatusText { Freestyle = { BindTarget = Freestyle } } + statusText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.Torus.With(size: 14f, weight: FontWeight.Bold), + Shear = -OsuGame.SHEAR, + }, } }, }); } - private partial class StatusText : CompositeDrawable + protected override void LoadComplete() { - public readonly Bindable Freestyle = new Bindable(); + base.LoadComplete(); - private OsuSpriteText text = null!; - - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; - - protected override void LoadComplete() + Freestyle.BindValueChanged(v => { - base.LoadComplete(); - - RelativeSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] + if (v.NewValue) { - new Box - { - Colour = colourProvider.Background3, - Alpha = 0.8f, - RelativeSizeAxes = Axes.Both, - }, - text = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.Torus.With(size: 14f, weight: FontWeight.Bold), - Shear = -OsuGame.SHEAR, - } - }; - - Freestyle.BindValueChanged(v => + statusBackground.Colour = colours.Yellow; + statusText.Text = "ON"; + statusText.Colour = Color4.Black; + } + else { - text.Text = v.NewValue ? "ON" : "OFF"; - }, true); - } + statusBackground.Colour = colourProvider.Background3; + statusText.Text = "OFF"; + statusText.Colour = Color4.White; + } + }, true); } } } From 1cf9c04756974c464895c210837b53e558c3b23e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Sep 2025 12:34:34 +0900 Subject: [PATCH 027/836] Fix playlist with >1 item getting cleared --- .../Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index b0c2bda0dc33..af4476b69387 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -120,7 +120,9 @@ private void updateValidMods() protected override void OnStart() { - room.Playlist = [createItem()]; + if (room.Playlist.Count <= 1) + room.Playlist = [createItem()]; + this.Exit(); } From 9333ef361bf5017e2f45fc7f7188866998f56484 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Sep 2025 12:36:31 +0900 Subject: [PATCH 028/836] Remove old implementation --- .../Playlists/PlaylistsSongSelect.cs | 46 ------------------- 1 file changed, 46 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs deleted file mode 100644 index 84446ed0cfe3..000000000000 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Linq; -using osu.Framework.Screens; -using osu.Game.Online.API; -using osu.Game.Online.Rooms; -using osu.Game.Screens.OnlinePlay.Components; -using osu.Game.Screens.Select; - -namespace osu.Game.Screens.OnlinePlay.Playlists -{ - public partial class PlaylistsSongSelect : OnlinePlaySongSelect - { - private readonly Room room; - - public PlaylistsSongSelect(Room room) - : base(room) - { - this.room = room; - } - - protected override BeatmapDetailArea CreateBeatmapDetailArea() => new MatchBeatmapDetailArea(room) - { - CreateNewItem = () => room.Playlist = room.Playlist.Append(createNewItem()).ToArray() - }; - - protected override bool SelectItem(PlaylistItem item) - { - if (room.Playlist.Count <= 1) - room.Playlist = [createNewItem()]; - - this.Exit(); - return true; - } - - private PlaylistItem createNewItem() => new PlaylistItem(Beatmap.Value.BeatmapInfo) - { - ID = room.Playlist.Count == 0 ? 0 : room.Playlist.Max(p => p.ID) + 1, - RulesetID = Ruleset.Value.OnlineID, - RequiredMods = Mods.Value.Select(m => new APIMod(m)).ToArray(), - AllowedMods = FreeMods.Value.Select(m => new APIMod(m)).ToArray(), - Freestyle = Freestyle.Value - }; - } -} From c8762762f95b42aed9c707343a56ce6e2ad5f99c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 17 Oct 2025 09:19:27 +0900 Subject: [PATCH 029/836] Fix CI inspections --- osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs | 2 +- osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs index 6d39ee92e7f6..03d590ac6ec3 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.OnlinePlay { - public class FooterButtonFreestyleV2 : ScreenFooterButton + public partial class FooterButtonFreestyleV2 : ScreenFooterButton { private const float bar_height = 30f; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index af4476b69387..cee4e549a78b 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -21,7 +21,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { - public class PlaylistsSongSelectV2 : SongSelect, IOnlinePlaySubScreen + public partial class PlaylistsSongSelectV2 : SongSelect, IOnlinePlaySubScreen { public string ShortTitle => "song selection"; From 1ec6735a3523a24fd185b80c82ad6a1d3d26d922 Mon Sep 17 00:00:00 2001 From: Loreos7 <86934170+Loreos7@users.noreply.github.com> Date: Sat, 18 Oct 2025 19:17:08 +0300 Subject: [PATCH 030/836] Restore original delete button name --- osu.Game/Localisation/SongSelectStrings.cs | 4 ++-- osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs | 2 +- osu.Game/Screens/SelectV2/PanelBeatmapSet.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Localisation/SongSelectStrings.cs b/osu.Game/Localisation/SongSelectStrings.cs index c81cf97f09fe..5f940f8a5657 100644 --- a/osu.Game/Localisation/SongSelectStrings.cs +++ b/osu.Game/Localisation/SongSelectStrings.cs @@ -140,9 +140,9 @@ public static class SongSelectStrings public static LocalisableString ClearAllLocalScores => new TranslatableString(getKey(@"clear_all_local_scores"), @"Clear all local scores"); /// - /// "Delete beatmap" + /// "Delete..." /// - public static LocalisableString DeleteBeatmap => new TranslatableString(getKey(@"delete_beatmap"), @"Delete beatmap"); + public static LocalisableString Delete => new TranslatableString(getKey(@"delete"), @"Delete..."); /// /// "Restore all hidden" diff --git a/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs b/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs index 7e71fedfcb14..ae06522b30a2 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs +++ b/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs @@ -62,7 +62,7 @@ private void load(OsuColour colours) Debug.Assert(beatmap.BeatmapSet != null); addHeader(SongSelectStrings.ForAllDifficulties, beatmap.BeatmapSet.ToString()); - addButton(SongSelectStrings.DeleteBeatmap, FontAwesome.Solid.Trash, () => SongSelect?.Delete(beatmap.BeatmapSet), colours.Red1); + addButton(SongSelectStrings.Delete, FontAwesome.Solid.Trash, () => SongSelect?.Delete(beatmap.BeatmapSet), colours.Red1); addHeader(SongSelectStrings.ForSelectedDifficulty, beatmap.DifficultyName); diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs index a52d3fa2161a..cc552864319a 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs @@ -268,7 +268,7 @@ public override MenuItem[] ContextMenuItems if (beatmapSet.Beatmaps.Any(b => b.Hidden)) items.Add(new OsuMenuItem(SongSelectStrings.RestoreAllHidden, MenuItemType.Standard, () => songSelect?.RestoreAllHidden(beatmapSet))); - items.Add(new OsuMenuItem(SongSelectStrings.DeleteBeatmap, MenuItemType.Destructive, () => songSelect?.Delete(beatmapSet))); + items.Add(new OsuMenuItem(SongSelectStrings.Delete, MenuItemType.Destructive, () => songSelect?.Delete(beatmapSet))); return items.ToArray(); } } From fa7bd482d2d90df9a1b916a4634e324281b5eb2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 15 Oct 2025 10:04:00 +0200 Subject: [PATCH 031/836] Show sample suffix on timeline pieces --- .../Compose/Components/Timeline/SamplePointPiece.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs index cdd2f52dab5d..eaf9069431ac 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -127,7 +127,7 @@ protected override bool OnClick(ClickEvent e) private void updateText() { - Label.Text = $"{abbreviateBank(GetBankValue(GetSamples()))} {GetVolumeValue(GetSamples())}"; + Label.Text = $"{abbreviateBank(GetBankValue(GetSamples()))}{GetSuffix(GetSamples())} {GetVolumeValue(GetSamples())}"; if (!contracted.Value) LabelContainer.ResizeWidthTo(Label.Width, 200, Easing.OutQuint); @@ -149,6 +149,17 @@ private void updateText() return samples.FirstOrDefault(o => o.Name == HitSampleInfo.HIT_NORMAL)?.Bank; } + public static string GetSuffix(IEnumerable samples) + { + var suffixes = samples.Select(o => o.Suffix).Distinct().ToList(); + + // having multiple values should never happen, but just for safety... + if (suffixes.Count != 1 || suffixes.Single() is not string commonSuffix) + return string.Empty; + + return $@":{commonSuffix}"; + } + public static string? GetAdditionBankValue(IEnumerable samples) { var firstAddition = samples.FirstOrDefault(o => o.Name != HitSampleInfo.HIT_NORMAL); From 1f2f86b016d112b28c75daba59e3144ada46f2e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 15 Oct 2025 10:30:03 +0200 Subject: [PATCH 032/836] Make bank selection controls dropdowns instead of text boxes Longstanding complaint. Text boxes make no sense if anything that isn't the three legacy values gets deleted on save anyway. --- .../TestSceneLabelledDropdown.cs | 4 +-- .../Screens/Setup/SetupScreen.cs | 3 +- .../UserInterfaceV2/LabelledDropdown.cs | 11 ++++++-- .../UserInterfaceV2/LabelledEnumDropdown.cs | 5 ++++ .../Components/Timeline/SamplePointPiece.cs | 28 +++++++------------ 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDropdown.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDropdown.cs index 300b451cf500..941f6667e2c4 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDropdown.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDropdown.cs @@ -11,7 +11,7 @@ public partial class TestSceneLabelledDropdown : OsuTestScene { [Test] public void TestLabelledDropdown() - => AddStep(@"create dropdown", () => Child = new LabelledDropdown + => AddStep(@"create dropdown", () => Child = new LabelledDropdown(true) { Label = @"Countdown speed", Items = new[] @@ -25,7 +25,7 @@ public void TestLabelledDropdown() [Test] public void TestLabelledEnumDropdown() - => AddStep(@"create dropdown", () => Child = new LabelledEnumDropdown + => AddStep(@"create dropdown", () => Child = new LabelledEnumDropdown(true) { Label = @"Beatmap status", Description = @"This is a description" diff --git a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs index 536e8ba76719..bd368d88a05f 100644 --- a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs @@ -116,12 +116,13 @@ private void reload() Failing = api.IsLoggedIn != true, Description = "In order to access the API and display metadata, signing in is required." }, - new LabelledDropdown + new LabelledDropdown(padded: true) { Label = "Ruleset", Description = "Decides what stats are displayed and which ranks are retrieved for players. This requires a restart to reload data for an existing bracket.", Items = rulesets.AvailableRulesets, Current = LadderInfo.Ruleset, + DropdownWidth = 0.5f, }, new TournamentSwitcher { diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs index dbbae390a74f..a37267014f70 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs @@ -9,8 +9,8 @@ namespace osu.Game.Graphics.UserInterfaceV2 { public partial class LabelledDropdown : LabelledComponent, TItem> { - public LabelledDropdown() - : base(true) + public LabelledDropdown(bool padded) + : base(padded) { } @@ -20,10 +20,15 @@ public IEnumerable Items set => Component.Items = value; } + public float DropdownWidth + { + get => Component.Width; + set => Component.Width = value; + } + protected sealed override OsuDropdown CreateComponent() => CreateDropdown().With(d => { d.RelativeSizeAxes = Axes.X; - d.Width = 0.5f; }); protected virtual OsuDropdown CreateDropdown() => new OsuDropdown(); diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledEnumDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledEnumDropdown.cs index 9c2c8397ed71..5658175804ab 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledEnumDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledEnumDropdown.cs @@ -9,6 +9,11 @@ namespace osu.Game.Graphics.UserInterfaceV2 public partial class LabelledEnumDropdown : LabelledDropdown where TEnum : struct, Enum { + public LabelledEnumDropdown(bool padded) + : base(padded) + { + } + protected override OsuDropdown CreateDropdown() => new OsuEnumDropdown(); } } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs index eaf9069431ac..bf31ea4e2eeb 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -187,8 +187,8 @@ public partial class SampleEditPopover : OsuPopover { private readonly HitObject hitObject; - private LabelledTextBox bank = null!; - private LabelledTextBox additionBank = null!; + private LabelledDropdown bank = null!; + private LabelledDropdown additionBank = null!; private IndeterminateSliderWithTextBoxInput volume = null!; private FillFlowContainer togglesCollection = null!; @@ -240,7 +240,7 @@ private void load() { flow = new FillFlowContainer { - Width = 200, + Width = 220, Direction = FillDirection.Vertical, AutoSizeAxes = Axes.Y, Spacing = new Vector2(0, 10), @@ -253,15 +253,15 @@ private void load() Direction = FillDirection.Horizontal, Spacing = new Vector2(5, 5), }, - bank = new LabelledTextBox + bank = new LabelledDropdown(padded: false) { - Label = "Bank Name", - SelectAllOnFocus = true, + Label = "Normal Bank", + Items = HitSampleInfo.ALL_BANKS, }, - additionBank = new LabelledTextBox + additionBank = new LabelledDropdown(padded: false) { Label = "Addition Bank", - SelectAllOnFocus = true, + Items = HitSampleInfo.ALL_BANKS, }, volume = new IndeterminateSliderWithTextBoxInput("Volume", new BindableInt(100) { @@ -272,8 +272,6 @@ private void load() } }; - bank.TabbableContentContainer = flow; - additionBank.TabbableContentContainer = flow; volume.TabbableContentContainer = flow; // if the piece belongs to a currently selected object, assume that the user wants to change all selected objects. @@ -295,9 +293,6 @@ private void load() setBank(val.NewValue); updatePrimaryBankState(); }); - // on commit, ensure that the value is correct by sourcing it from the objects' samples again. - // this ensures that committing empty text causes a revert to the previous value. - bank.OnCommit += (_, _) => updatePrimaryBankState(); updateAdditionBankState(); additionBank.Current.BindValueChanged(val => @@ -308,7 +303,6 @@ private void load() setAdditionBank(val.NewValue); updateAdditionBankState(); }); - additionBank.OnCommit += (_, _) => updateAdditionBankState(); volume.Current.BindValueChanged(val => { @@ -338,15 +332,13 @@ private void load() private void updatePrimaryBankState() { string? commonBank = getCommonBank(); - bank.Current.Value = commonBank; - bank.PlaceholderText = string.IsNullOrEmpty(commonBank) ? "(multiple)" : string.Empty; + bank.Current.Value = !string.IsNullOrEmpty(commonBank) ? commonBank : "(multiple)"; } private void updateAdditionBankState() { string? commonAdditionBank = getCommonAdditionBank(); - additionBank.PlaceholderText = string.IsNullOrEmpty(commonAdditionBank) ? "(multiple)" : string.Empty; - additionBank.Current.Value = commonAdditionBank; + additionBank.Current.Value = !string.IsNullOrEmpty(commonAdditionBank) ? commonAdditionBank : "(multiple)"; bool anyAdditions = allRelevantSamples.Any(o => o.samples.Any(s => s.Name != HitSampleInfo.HIT_NORMAL)); if (anyAdditions) From e2681c416300cf079e886a1567ed5633e7c8a4cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 15 Oct 2025 11:00:57 +0200 Subject: [PATCH 033/836] Add sample set selection controls to sample popovers - Below 20 custom sample sets, they are shown as ternary buttons. - Above 20 custom sample sets, they are shown in a dropdown (yes there are actual cases of this as I've been informed by the NAT; one example being https://osu.ppy.sh/beatmapsets/1018061#osu/2197383) As a bonus, to make determining what the heck is actually changing when adjusting these controls, the full set of applicable sounds now plays on adding/removing additions, changing their banks, as well as changing the custom set (if any). For now there are no user-facing controls to add the samples to the map yourself, you have to know how to name the `.wav`s and edit-externally them in yourself. *For now.* --- .../UserInterfaceV2/LabelledDropdown.cs | 7 +- .../TernaryButtons/DrawableTernaryButton.cs | 7 +- .../TernaryButtons/SampleSetTernaryButton.cs | 85 +++++++++++++ .../Components/Timeline/SamplePointPiece.cs | 118 +++++++++++++++++- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 42 +++++++ osu.Game/Skinning/Skin.cs | 2 +- 6 files changed, 254 insertions(+), 7 deletions(-) create mode 100644 osu.Game/Screens/Edit/Components/TernaryButtons/SampleSetTernaryButton.cs diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs index a37267014f70..5dd9db750614 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs @@ -31,6 +31,11 @@ protected sealed override OsuDropdown CreateComponent() => CreateDropdown d.RelativeSizeAxes = Axes.X; }); - protected virtual OsuDropdown CreateDropdown() => new OsuDropdown(); + protected virtual OsuDropdown CreateDropdown() => new Dropdown(); + + private partial class Dropdown : OsuDropdown + { + protected override DropdownMenu CreateMenu() => base.CreateMenu().With(menu => menu.MaxHeight = 200); + } } } diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs index 7b36b5f957e1..9cc962fe8f76 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs @@ -49,7 +49,8 @@ public required LocalisableString Description public Drawable Icon { get; private set; } = null!; - public DrawableTernaryButton() + public DrawableTernaryButton(HoverSampleSet? hoverSampleSet = HoverSampleSet.Button) + : base(hoverSampleSet) { RelativeSizeAxes = Axes.X; } @@ -79,10 +80,10 @@ protected override void LoadComplete() current.BindValueChanged(_ => updateSelectionState(), true); - Action = onAction; + Action = OnAction; } - private void onAction() + protected void OnAction() { if (!Enabled.Value) return; diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/SampleSetTernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/SampleSetTernaryButton.cs new file mode 100644 index 000000000000..ae2602465059 --- /dev/null +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/SampleSetTernaryButton.cs @@ -0,0 +1,85 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Audio; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Skinning; + +namespace osu.Game.Screens.Edit.Components.TernaryButtons +{ + public partial class SampleSetTernaryButton : DrawableTernaryButton + { + public EditorBeatmapSkin.SampleSet SampleSet { get; } + + public ISampleInfo[] DemoSamples + { + get => demoSample.Samples; + set => demoSample.Samples = value; + } + + private readonly SkinnableSound demoSample; + + public SampleSetTernaryButton(EditorBeatmapSkin.SampleSet sampleSet) + : base(null) + { + SampleSet = sampleSet; + CreateIcon = () => sampleSet.SampleSetIndex == 0 + ? new SpriteIcon { Icon = OsuIcon.SkinA } + : new Container + { + Child = new OsuSpriteText + { + Text = sampleSet.SampleSetIndex.ToString(), + Font = OsuFont.Style.Body.With(weight: FontWeight.Bold), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + + switch (sampleSet.SampleSetIndex) + { + case 0: + RelativeSizeAxes = Axes.X; + Width = 1; + break; + + default: + RelativeSizeAxes = Axes.None; + Width = Height; + break; + } + + demoSample = new SkinnableSound(); + } + + [BackgroundDependencyLoader] + private void load(EditorBeatmap editorBeatmap) + { + AddRangeInternal(new Drawable[] + { + new HoverSounds(HoverSampleSet.Button), + new EditorSkinProvidingContainer(editorBeatmap) + { + Child = demoSample, + } + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Action = () => + { + OnAction(); + demoSample?.Play(); + }; + } + } +} diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs index bf31ea4e2eeb..6fd54da360d2 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -20,10 +20,11 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Rulesets.Objects; -using osu.Game.Screens.Edit.Components.TernaryButtons; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Screens.Edit.Components.TernaryButtons; using osu.Game.Screens.Edit.Timing; +using osu.Game.Skinning; using osuTK; using osuTK.Graphics; using osuTK.Input; @@ -189,7 +190,10 @@ public partial class SampleEditPopover : OsuPopover private LabelledDropdown bank = null!; private LabelledDropdown additionBank = null!; + private FillFlowContainer? sampleSetsFlow; + private LabelledDropdown? sampleSetDropdown; private IndeterminateSliderWithTextBoxInput volume = null!; + private SkinnableSound demoSample = null!; private FillFlowContainer togglesCollection = null!; @@ -244,7 +248,7 @@ private void load() Direction = FillDirection.Vertical, AutoSizeAxes = Axes.Y, Spacing = new Vector2(0, 10), - Children = new Drawable[] + Children = new[] { togglesCollection = new FillFlowContainer { @@ -263,12 +267,17 @@ private void load() Label = "Addition Bank", Items = HitSampleInfo.ALL_BANKS, }, + createSampleSetContent(), volume = new IndeterminateSliderWithTextBoxInput("Volume", new BindableInt(100) { MinValue = DrawableHitObject.MINIMUM_SAMPLE_VOLUME, MaxValue = 100, }) } + }, + new EditorSkinProvidingContainer(beatmap) + { + Child = demoSample = new SkinnableSound() } }; @@ -292,6 +301,7 @@ private void load() setBank(val.NewValue); updatePrimaryBankState(); + playDemoSample(); }); updateAdditionBankState(); @@ -302,8 +312,11 @@ private void load() setAdditionBank(val.NewValue); updateAdditionBankState(); + playDemoSample(); }); + updateSampleSetState(); + volume.Current.BindValueChanged(val => { if (val.NewValue != null) @@ -315,6 +328,58 @@ private void load() togglesCollection.AddRange(createTernaryButtons()); } + private Drawable createSampleSetContent() + { + if (beatmap.BeatmapSkin == null) + return Empty(); + + var sampleSets = beatmap.BeatmapSkin.GetAvailableSampleSets().ToList(); + + if (sampleSets.Count == 0) + return Empty(); + + sampleSets.Insert(0, new EditorBeatmapSkin.SampleSet(0, "User skin")); + + if (sampleSets.Count < 20) + { + sampleSetsFlow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(5), + ChildrenEnumerable = sampleSets.Select(set => new SampleSetTernaryButton(set) { Description = set.Name }), + }; + + foreach (var ternary in sampleSetsFlow) + { + ternary.Current.BindValueChanged(val => + { + if (val.NewValue == TernaryState.True) + setSampleSet(ternary.SampleSet); + + updateSampleSetState(); + playDemoSample(); + }); + } + + return sampleSetsFlow; + } + + sampleSetDropdown = new LabelledDropdown(padded: false) + { + Label = "Sample Set", + Items = sampleSets, + }; + sampleSetDropdown.Current.BindValueChanged(val => + { + setSampleSet(val.NewValue); + updateSampleSetState(); + playDemoSample(); + }); + + return sampleSetDropdown; + } + private string? getCommonBank() => allRelevantSamples.Select(h => GetBankValue(h.samples)).Distinct().Count() == 1 ? GetBankValue(allRelevantSamples.First().samples) : null; @@ -347,6 +412,40 @@ private void updateAdditionBankState() additionBank.Hide(); } + private void updateSampleSetState() + { + HashSet activeSets = new HashSet(); + + foreach (var sample in allRelevantSamples.SelectMany(h => h.samples)) + { + if (sample.Suffix == null) + activeSets.Add(sample.UseBeatmapSamples ? 1 : 0); + else if (int.TryParse(sample.Suffix, out int suffix)) + activeSets.Add(suffix); + } + + if (sampleSetsFlow != null) + { + var onState = activeSets.Count > 1 ? TernaryState.Indeterminate : TernaryState.True; + + foreach (var ternary in sampleSetsFlow) + ternary.Current.Value = activeSets.Contains(ternary.SampleSet.SampleSetIndex) ? onState : TernaryState.False; + } + + if (sampleSetDropdown != null) + { + sampleSetDropdown.Current.Value = activeSets.Count == 1 + ? sampleSetDropdown.Items.Single(i => i.SampleSetIndex == activeSets.Single()) + : new EditorBeatmapSkin.SampleSet(-1, "(multiple)"); + } + } + + private void playDemoSample() + { + demoSample.Samples = allRelevantSamples.First().samples.Cast().ToArray(); + demoSample.Play(); + } + /// /// Applies the given update action on all samples of /// and invokes the necessary update notifiers for the beatmap and hit objects. @@ -400,6 +499,19 @@ private void setAdditionBank(string newBank) }); } + private void setSampleSet(EditorBeatmapSkin.SampleSet newSampleSet) + { + updateAllRelevantSamples((_, relevantSamples) => + { + for (int i = 0; i < relevantSamples.Count; i++) + { + relevantSamples[i] = relevantSamples[i].With( + newSuffix: newSampleSet.SampleSetIndex >= 2 ? newSampleSet.SampleSetIndex.ToString() : null, + newUseBeatmapSamples: newSampleSet.SampleSetIndex >= 1); + } + }); + } + private void setVolume(int newVolume) { updateAllRelevantSamples((_, relevantSamples) => @@ -438,6 +550,8 @@ private void createStateBindables() addHitSample(sampleName); break; } + + playDemoSample(); }; selectionSampleStates[sampleName] = bindable; diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 07fa1cb49cd8..315ddf8f959c 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Linq; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -61,6 +63,46 @@ private void updateColours() invokeSkinChanged(); } + public record SampleSet(int SampleSetIndex, string Name) + { + public SampleSet(int sampleSetIndex) + : this(sampleSetIndex, $@"Custom #{sampleSetIndex}") + { + } + + public override string ToString() => Name; + } + + public IEnumerable GetAvailableSampleSets() + { + string[] possibleSounds = [HitSampleInfo.HIT_NORMAL, ..HitSampleInfo.ALL_ADDITIONS]; + string[] possibleBanks = HitSampleInfo.ALL_BANKS; + + string[] possiblePrefixes = possibleSounds.SelectMany(sound => possibleBanks.Select(bank => $@"{bank}-{sound}")).ToArray(); + + HashSet indices = new HashSet(); + + if (Skin.Samples != null) + { + foreach (string sample in Skin.Samples.GetAvailableResources()) + { + foreach (string possiblePrefix in possiblePrefixes) + { + if (!sample.StartsWith(possiblePrefix, StringComparison.InvariantCultureIgnoreCase)) + continue; + + string indexString = Path.GetFileNameWithoutExtension(sample)[possiblePrefix.Length..]; + if (string.IsNullOrEmpty(indexString)) + indices.Add(1); + if (int.TryParse(indexString, out int index)) + indices.Add(index); + } + } + } + + return indices.OrderBy(i => i).Select(i => new SampleSet(i)); + } + #region Delegated ISkin implementation public Drawable? GetDrawableComponent(ISkinComponentLookup lookup) => Skin.GetDrawableComponent(lookup); diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 07902106ef61..d985c33f548b 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -38,7 +38,7 @@ public abstract class Skin : IDisposable, ISkin /// /// A sample store which can be used to perform user file lookups for this skin. /// - protected ISampleStore? Samples { get; } + protected internal ISampleStore? Samples { get; } public readonly Live SkinInfo; From 511921c1f71277070ce37720a75791aec7e2dfeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 15 Oct 2025 13:41:44 +0200 Subject: [PATCH 034/836] Inherit sample set info from previous object on placement --- osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs b/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs index 6720540ec22d..2daef797f8ee 100644 --- a/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs @@ -119,8 +119,11 @@ public override SnapResult UpdateTimeAndPosition(Vector2 screenSpacePosition, do // Inherit the bank from the previous hit object HitObject.Samples = HitObject.Samples.Select(s => s.Name == HitSampleInfo.HIT_NORMAL ? s.With(newBank: lastHitNormal.Bank) : s).ToList(); - // Inherit the volume from the previous hit object - HitObject.Samples = HitObject.Samples.Select(s => s.With(newVolume: lastHitNormal.Volume)).ToList(); + // Inherit the volume and sample set info from the previous hit object + HitObject.Samples = HitObject.Samples.Select(s => s.With( + newVolume: lastHitNormal.Volume, + newSuffix: lastHitNormal.Suffix, + newUseBeatmapSamples: lastHitNormal.UseBeatmapSamples)).ToList(); } if (HitObject is IHasRepeats hasRepeats) From 78eaad13aeaa071bd4692a54782799b2e164a113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 23 Oct 2025 14:23:17 +0200 Subject: [PATCH 035/836] Fix tests --- .../TestSceneHitObjectSampleAdjustments.cs | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs index 765fe1ecf60e..082064d19866 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using Humanizer; using NUnit.Framework; -using osu.Framework.Input; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Audio; @@ -196,11 +195,6 @@ public void TestPopoverMultipleSelectionWithSameSampleBank() clickSamplePiece(1); samplePopoverHasSingleBank(HitSampleInfo.BANK_SOFT); - setBankViaPopover(string.Empty); - hitObjectHasSampleBank(0, HitSampleInfo.BANK_SOFT); - hitObjectHasSampleBank(1, HitSampleInfo.BANK_SOFT); - samplePopoverHasSingleBank(HitSampleInfo.BANK_SOFT); - setBankViaPopover(HitSampleInfo.BANK_DRUM); hitObjectHasSampleBank(0, HitSampleInfo.BANK_DRUM); hitObjectHasSampleBank(1, HitSampleInfo.BANK_DRUM); @@ -219,11 +213,6 @@ public void TestPopoverMultipleSelectionWithDifferentSampleBank() clickSamplePiece(1); samplePopoverHasIndeterminateBank(); - setBankViaPopover(string.Empty); - hitObjectHasSampleBank(0, HitSampleInfo.BANK_NORMAL); - hitObjectHasSampleBank(1, HitSampleInfo.BANK_SOFT); - samplePopoverHasIndeterminateBank(); - setBankViaPopover(HitSampleInfo.BANK_NORMAL); hitObjectHasSampleBank(0, HitSampleInfo.BANK_NORMAL); hitObjectHasSampleBank(1, HitSampleInfo.BANK_NORMAL); @@ -878,17 +867,17 @@ private void samplePopoverHasIndeterminateVolume() => AddUntilStep("sample popov private void samplePopoverHasSingleBank(string bank) => AddUntilStep($"sample popover has bank {bank}", () => { var popover = this.ChildrenOfType().SingleOrDefault(); - var textBox = popover?.ChildrenOfType().First(); + var dropdown = popover?.ChildrenOfType>().First(); - return textBox?.Current.Value == bank && string.IsNullOrEmpty(textBox.PlaceholderText.ToString()); + return dropdown?.Current.Value == bank; }); private void samplePopoverHasIndeterminateBank() => AddUntilStep("sample popover has indeterminate bank", () => { var popover = this.ChildrenOfType().SingleOrDefault(); - var textBox = popover?.ChildrenOfType().First(); + var dropdown = popover?.ChildrenOfType>().First(); - return textBox != null && string.IsNullOrEmpty(textBox.Current.Value) && !string.IsNullOrEmpty(textBox.PlaceholderText.ToString()); + return dropdown?.Current.Value == "(multiple)"; }); private void dismissPopover() @@ -920,23 +909,15 @@ private void hitObjectNodeHasSampleVolume(int objectIndex, int nodeIndex, int vo private void setBankViaPopover(string bank) => AddStep($"set bank {bank} via popover", () => { var popover = this.ChildrenOfType().Single(); - var textBox = popover.ChildrenOfType().First(); + var textBox = popover.ChildrenOfType>().First(); textBox.Current.Value = bank; - // force a commit via keyboard. - // this is needed when testing attempting to set empty bank - which should revert to the previous value, but only on commit. - ((IFocusManager)InputManager).ChangeFocus(textBox); - InputManager.Key(Key.Enter); }); private void setAdditionBankViaPopover(string bank) => AddStep($"set addition bank {bank} via popover", () => { var popover = this.ChildrenOfType().Single(); - var textBox = popover.ChildrenOfType().ToArray()[1]; + var textBox = popover.ChildrenOfType>().ToArray()[1]; textBox.Current.Value = bank; - // force a commit via keyboard. - // this is needed when testing attempting to set empty bank - which should revert to the previous value, but only on commit. - ((IFocusManager)InputManager).ChangeFocus(textBox); - InputManager.Key(Key.Enter); }); private void toggleAdditionViaPopover(int index) => AddStep($"toggle addition {index} via popover", () => From 90d1725603cd781350bbeca3558f0efd4072f5c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 24 Oct 2025 12:47:16 +0200 Subject: [PATCH 036/836] Fix code quality God does `dotnet format` make the `..` spread syntax just absolutely unusable with its stupid inspections. --- .../Edit/Components/TernaryButtons/SampleSetTernaryButton.cs | 2 +- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/SampleSetTernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/SampleSetTernaryButton.cs index ae2602465059..32ac63e17340 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/SampleSetTernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/SampleSetTernaryButton.cs @@ -78,7 +78,7 @@ protected override void LoadComplete() Action = () => { OnAction(); - demoSample?.Play(); + demoSample.Play(); }; } } diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 315ddf8f959c..ab1f5e4ad1fc 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -75,7 +75,7 @@ public SampleSet(int sampleSetIndex) public IEnumerable GetAvailableSampleSets() { - string[] possibleSounds = [HitSampleInfo.HIT_NORMAL, ..HitSampleInfo.ALL_ADDITIONS]; + string[] possibleSounds = HitSampleInfo.ALL_ADDITIONS.Prepend(HitSampleInfo.HIT_NORMAL).ToArray(); string[] possibleBanks = HitSampleInfo.ALL_BANKS; string[] possiblePrefixes = possibleSounds.SelectMany(sound => possibleBanks.Select(bank => $@"{bank}-{sound}")).ToArray(); From 0558f9f2d9a6d605df2549644a9f3fa65996bfb8 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 24 Oct 2025 22:42:28 +0900 Subject: [PATCH 037/836] Add SFX for 'jumping' in quickplay --- .../Matchmaking/Match/PlayerPanel.cs | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs index 1480e866a66a..d43863b4c0c6 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs @@ -7,6 +7,8 @@ using System.Linq; using Humanizer; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -15,6 +17,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Screens; +using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -93,6 +96,10 @@ public partial class PlayerPanel : OsuClickableContainer, IHasContextMenu private PlayerPanelDisplayMode displayMode = PlayerPanelDisplayMode.Horizontal; + private Sample? jumpSample; + private SampleChannel? jumpSampleChannel; + private double samplePitch; + public PlayerPanelDisplayMode DisplayMode { get => displayMode; @@ -128,7 +135,7 @@ public PlayerPanel(MultiplayerRoomUser user) } [BackgroundDependencyLoader] - private void load() + private void load(AudioManager audio) { Add(SolidBackgroundLayer = new Box { @@ -222,6 +229,8 @@ private void load() // Allow avatar to exist outside of masking for when it jumps around and stuff. AddInternal(avatar.CreateProxy()); + + jumpSample = audio.Samples.Get(@"Multiplayer/Matchmaking/player-jump"); } protected override void LoadComplete() @@ -238,6 +247,9 @@ protected override void LoadComplete() avatar.ScaleTo(0) .ScaleTo(1, 500, Easing.OutElasticHalf) .FadeIn(200); + + // pick a random pitch to be used by the player for duration of this session + samplePitch = 0.75f + RNG.NextDouble(0f, 0.5f); } private bool horizontal => displayMode == PlayerPanelDisplayMode.Horizontal; @@ -396,6 +408,11 @@ private void onMatchEvent(MatchServerEvent e) scale.Then().ScaleTo(new Vector2(1, 1.05f), 200, Easing.Out) .Then().ScaleTo(new Vector2(1, 0.95f), 200, Easing.In) .Then().ScaleTo(Vector2.One, 800, Easing.OutElastic); + + // only play jump sample if panel is visible + if (Alpha > 0) + playJumpSample(); + break; } @@ -403,6 +420,23 @@ private void onMatchEvent(MatchServerEvent e) } } + private void playJumpSample() + { + jumpSampleChannel?.Stop(); + jumpSampleChannel = jumpSample?.GetChannel(); + + if (jumpSampleChannel == null) + return; + + float horizontalPos = BoundingBox.Centre.X / Parent!.ToLocalSpace(Parent!.ScreenSpaceDrawQuad).Width; + // rescale balance from 0..1 to -1..1 + float balance = -1f + horizontalPos * 2f; + + jumpSampleChannel.Frequency.Value = samplePitch; + jumpSampleChannel.Balance.Value = balance * OsuGameBase.SFX_STEREO_STRENGTH; + jumpSampleChannel?.Play(); + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); From afdebcf188392efd4494661b19140bc4c9cf5946 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 22 Oct 2025 16:35:29 +0300 Subject: [PATCH 038/836] Make CursorPathContainer a smooth path --- .../UI/ReplayAnalysis/CursorPathContainer.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/ReplayAnalysis/CursorPathContainer.cs b/osu.Game.Rulesets.Osu/UI/ReplayAnalysis/CursorPathContainer.cs index 1951d467e230..f23cf5129bf2 100644 --- a/osu.Game.Rulesets.Osu/UI/ReplayAnalysis/CursorPathContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/ReplayAnalysis/CursorPathContainer.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics.Lines; using osu.Framework.Graphics.Performance; using osu.Game.Graphics; @@ -12,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.UI.ReplayAnalysis { - public partial class CursorPathContainer : Path + public partial class CursorPathContainer : SmoothPath { private readonly LifetimeEntryManager lifetimeManager = new LifetimeEntryManager(); private readonly SortedSet aliveEntries = new SortedSet(new AimLinePointComparator()); @@ -29,7 +28,6 @@ public CursorPathContainer() private void load(OsuColour colours) { Colour = colours.Pink2; - BackgroundColour = colours.Pink2.Opacity(0); } protected override void Update() From a435dfe93ed4d6971c8cf329a9777ad0d7a2045c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 29 Oct 2025 22:42:12 +0900 Subject: [PATCH 039/836] Add interop models --- osu.Game/Online/Multiplayer/IMultiplayerClient.cs | 10 ++++++++++ .../Online/Multiplayer/IMultiplayerRoomServer.cs | 5 +++++ osu.Game/Online/Multiplayer/MultiplayerClient.cs | 12 ++++++++++++ osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs | 6 ++++++ .../Online/Multiplayer/OnlineMultiplayerClient.cs | 5 +++++ .../Visual/Multiplayer/TestMultiplayerClient.cs | 5 +++++ 6 files changed, 43 insertions(+) diff --git a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs index adb9b92614a0..340fb04731d8 100644 --- a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs @@ -149,5 +149,15 @@ public interface IMultiplayerClient : IStatefulUserHubClient /// /// The changed item. Task PlaylistItemChanged(MultiplayerPlaylistItem item); + + /// + /// Signals that a user has requested to skip the beatmap intro. + /// + Task UserVotedToSkip(int userId); + + /// + /// Signals that the vote to skip the beatmap intro has passed. + /// + Task VoteToSkipPassed(); } } diff --git a/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs index 490973faa2fe..d7834427d0a7 100644 --- a/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs @@ -112,6 +112,11 @@ public interface IMultiplayerRoomServer /// The item to remove. Task RemovePlaylistItem(long playlistItemId); + /// + /// Votes to skip the beatmap intro. + /// + Task VoteToSkip(); + /// /// Invites a player to the current room. /// diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 44cbbafe72c1..04162f6b6f03 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -493,6 +493,8 @@ public async Task ToggleSpectate() public abstract Task RemovePlaylistItem(long playlistItemId); + public abstract Task VoteToSkip(); + Task IMultiplayerClient.RoomStateChanged(MultiplayerRoomState state) { handleRoomRequest(() => @@ -916,6 +918,16 @@ public Task PlaylistItemChanged(MultiplayerPlaylistItem item) return Task.CompletedTask; } + Task IMultiplayerClient.UserVotedToSkip(int userId) + { + throw new NotImplementedException(); + } + + Task IMultiplayerClient.VoteToSkipPassed() + { + throw new NotImplementedException(); + } + /// /// Populates the for a given collection of s. /// diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs index 499e84ce80d8..365a25778bf8 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs @@ -49,6 +49,12 @@ public class MultiplayerRoomUser : IEquatable [Key(6)] public int? BeatmapId; + /// + /// Whether this user voted to skip the beatmap intro. + /// + [Key(7)] + public bool VotedToSkip; + [IgnoreMember] public APIUser? User { get; set; } diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 0decff7ab3e1..e496aea7a22d 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -312,6 +312,11 @@ public override Task RemovePlaylistItem(long playlistItemId) return connection.InvokeAsync(nameof(IMultiplayerServer.RemovePlaylistItem), playlistItemId); } + public override Task VoteToSkip() + { + throw new NotImplementedException(); + } + public override Task DisconnectInternal() { if (connector == null) diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 5b2876a98977..a899912225be 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -561,6 +561,11 @@ public async Task RemoveUserPlaylistItem(int userId, long playlistItemId) public override Task RemovePlaylistItem(long playlistItemId) => RemoveUserPlaylistItem(api.LocalUser.Value.OnlineID, clone(playlistItemId)); + public override Task VoteToSkip() + { + throw new NotImplementedException(); + } + protected override Task CreateRoomInternal(MultiplayerRoom room) { Room apiRoom = new Room(room) From a8251046881481061b5d23ec337a919ea94d6729 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 30 Oct 2025 21:34:42 +0900 Subject: [PATCH 040/836] Add test scene for player jump spamming --- .../TestScenePlayerPanelOverlay.cs | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanelOverlay.cs b/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanelOverlay.cs index c2b2b95d5501..83f3aab264fa 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanelOverlay.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanelOverlay.cs @@ -8,7 +8,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Framework.Utils; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Matchmaking.Events; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; @@ -158,5 +160,64 @@ public void ChangeRankings() MultiplayerClient.ChangeMatchRoomState(state).WaitSafely(); }); } + + [Test] + public void InteractionSpam() + { + AddStep("join users", () => + { + for (int i = 0; i < 7; i++) + { + MultiplayerClient.AddUser(new MultiplayerRoomUser(i) + { + User = new APIUser + { + Username = $"User {i}" + } + }); + } + }); + AddStep("change to grid mode", () => list.DisplayStyle = PanelDisplayStyle.Grid); + AddStep("player jump", () => { MultiplayerClient.SendUserMatchRequest(1001, new MatchmakingAvatarActionRequest { Action = MatchmakingAvatarAction.Jump }).WaitSafely(); }); + AddStep("local jumping", () => jumpSpam(false)); + AddWaitStep("wait", 25); + AddStep("group jumping spam", () => jumpSpam(true)); + AddWaitStep("wait", 25); + + AddStep("change to split mode", () => list.DisplayStyle = PanelDisplayStyle.Split); + AddStep("local jumping", () => jumpSpam(false)); + AddWaitStep("wait", 25); + AddStep("group jumping spam", () => jumpSpam(true)); + AddWaitStep("wait", 25); + + AddStep("change to hidden mode", () => list.DisplayStyle = PanelDisplayStyle.Hidden); + AddStep("local jumping", () => jumpSpam(false)); + AddWaitStep("wait", 25); + AddStep("group jumping spam", () => jumpSpam(true)); + AddWaitStep("wait", 25); + } + + private void jumpSpam(bool everyone) + { + for (int i = 0; i < 30; i++) + { + Scheduler.AddDelayed(() => + { + MultiplayerClient.SendUserMatchRequest(1001, new MatchmakingAvatarActionRequest { Action = MatchmakingAvatarAction.Jump }).WaitSafely(); + }, i * 150 + RNG.NextDouble(0, 140)); + + if (!everyone) + continue; + + for (int ii = 0; ii < 7; ii++) + { + int iii = ii; + Scheduler.AddDelayed(() => + { + MultiplayerClient.SendUserMatchRequest(iii, new MatchmakingAvatarActionRequest { Action = MatchmakingAvatarAction.Jump }).WaitSafely(); + }, i * 150 + RNG.NextDouble(0, 140)); + } + } + } } } From cf0e5edf34326b2a9d198542d2748ca478de01ff Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 30 Oct 2025 21:35:19 +0900 Subject: [PATCH 041/836] Rework player jump feedback --- .../Matchmaking/Match/PlayerPanel.cs | 58 +++++++++++++++---- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs index 8f8e1430a041..92f3bd3c55c0 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs @@ -113,9 +113,17 @@ public partial class PlayerPanel : OsuClickableContainer, IHasContextMenu private PlayerPanelDisplayMode displayMode = PlayerPanelDisplayMode.Horizontal; private bool hasQuit; - private Sample? jumpSample; - private SampleChannel? jumpSampleChannel; + private enum InteractionSampleType + { + PlayerJump, + PlayerReJump, + OtherPlayerJump, + } + + private Dictionary interactionSamples = new Dictionary(); + private readonly Dictionary interactionSampleChannels = new Dictionary(); private double samplePitch; + private double? lastSamplePlayback; public PlayerPanel(MultiplayerRoomUser user) : base(HoverSampleSet.Button) @@ -248,7 +256,12 @@ private void load(AudioManager audio) // Allow avatar to exist outside of masking for when it jumps around and stuff. AddInternal(avatar.CreateProxy()); - jumpSample = audio.Samples.Get(@"Multiplayer/Matchmaking/player-jump"); + interactionSamples = new Dictionary + { + { InteractionSampleType.PlayerJump, audio.Samples.Get(@"Multiplayer/Matchmaking/player-jump") }, + { InteractionSampleType.PlayerReJump, audio.Samples.Get(@"Multiplayer/Matchmaking/player-rejump") }, + { InteractionSampleType.OtherPlayerJump, audio.Samples.Get(@"Multiplayer/Matchmaking/player-jump-other") } + }; } protected override void LoadComplete() @@ -267,7 +280,7 @@ protected override void LoadComplete() .FadeIn(200); // pick a random pitch to be used by the player for duration of this session - samplePitch = 0.75f + RNG.NextDouble(0f, 0.5f); + samplePitch = 0.75f + RNG.NextDouble(0f, 0.75f); } public PlayerPanelDisplayMode DisplayMode @@ -477,7 +490,7 @@ private void onMatchEvent(MatchServerEvent e) // only play jump sample if panel is visible if (Alpha > 0) - playJumpSample(); + playJumpSample(isConsecutive); break; } @@ -486,21 +499,42 @@ private void onMatchEvent(MatchServerEvent e) } } - private void playJumpSample() + private void playJumpSample(bool rejumping) { - jumpSampleChannel?.Stop(); - jumpSampleChannel = jumpSample?.GetChannel(); + bool isLocalUser = User.OnlineID == client.LocalUser?.UserID; + + if (isLocalUser) + playInteractionSample(rejumping ? InteractionSampleType.PlayerReJump : InteractionSampleType.PlayerJump); + else + playInteractionSample(InteractionSampleType.OtherPlayerJump); + } - if (jumpSampleChannel == null) + private void playInteractionSample(InteractionSampleType sampleType) + { + bool enoughTimePassedSinceLastPlayback = lastSamplePlayback == null || Time.Current - lastSamplePlayback.Value >= OsuGameBase.SAMPLE_DEBOUNCE_TIME; + if (!enoughTimePassedSinceLastPlayback) + return; + + Sample? targetSample = interactionSamples[sampleType]; + SampleChannel? targetChannel = interactionSampleChannels.GetValueOrDefault(sampleType); + + targetChannel?.Stop(); + targetChannel = targetSample?.GetChannel(); + + if (targetChannel == null) return; float horizontalPos = BoundingBox.Centre.X / Parent!.ToLocalSpace(Parent!.ScreenSpaceDrawQuad).Width; // rescale balance from 0..1 to -1..1 float balance = -1f + horizontalPos * 2f; - jumpSampleChannel.Frequency.Value = samplePitch; - jumpSampleChannel.Balance.Value = balance * OsuGameBase.SFX_STEREO_STRENGTH; - jumpSampleChannel?.Play(); + targetChannel.Frequency.Value = samplePitch; + targetChannel.Balance.Value = balance * OsuGameBase.SFX_STEREO_STRENGTH; + targetChannel.Play(); + + interactionSampleChannels[sampleType] = targetChannel; + + lastSamplePlayback = Time.Current; } protected override void Dispose(bool isDisposing) From 901044d6902ddd13a4027cea0a943d9393adc6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 31 Oct 2025 08:49:26 +0100 Subject: [PATCH 042/836] Remove stuff that was not even supposed to exist --- .../TernaryButtons/DrawableTernaryButton.cs | 4 +-- .../TernaryButtons/SampleSetTernaryButton.cs | 29 +------------------ 2 files changed, 3 insertions(+), 30 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs index 9cc962fe8f76..f9c6ee6b4363 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs @@ -80,10 +80,10 @@ protected override void LoadComplete() current.BindValueChanged(_ => updateSelectionState(), true); - Action = OnAction; + Action = onAction; } - protected void OnAction() + private void onAction() { if (!Enabled.Value) return; diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/SampleSetTernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/SampleSetTernaryButton.cs index 32ac63e17340..96227ec53e3a 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/SampleSetTernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/SampleSetTernaryButton.cs @@ -5,11 +5,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Game.Audio; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Skinning; namespace osu.Game.Screens.Edit.Components.TernaryButtons { @@ -17,14 +15,6 @@ public partial class SampleSetTernaryButton : DrawableTernaryButton { public EditorBeatmapSkin.SampleSet SampleSet { get; } - public ISampleInfo[] DemoSamples - { - get => demoSample.Samples; - set => demoSample.Samples = value; - } - - private readonly SkinnableSound demoSample; - public SampleSetTernaryButton(EditorBeatmapSkin.SampleSet sampleSet) : base(null) { @@ -54,32 +44,15 @@ public SampleSetTernaryButton(EditorBeatmapSkin.SampleSet sampleSet) Width = Height; break; } - - demoSample = new SkinnableSound(); } [BackgroundDependencyLoader] - private void load(EditorBeatmap editorBeatmap) + private void load() { AddRangeInternal(new Drawable[] { new HoverSounds(HoverSampleSet.Button), - new EditorSkinProvidingContainer(editorBeatmap) - { - Child = demoSample, - } }); } - - protected override void LoadComplete() - { - base.LoadComplete(); - - Action = () => - { - OnAction(); - demoSample.Play(); - }; - } } } From 8755a016229af4126d3c568d771daeda368ac4f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 31 Oct 2025 08:53:27 +0100 Subject: [PATCH 043/836] Fix playing sample multiple times --- .../Edit/Compose/Components/Timeline/SamplePointPiece.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs index 6fd54da360d2..f4242e1fe069 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -440,11 +440,11 @@ private void updateSampleSetState() } } - private void playDemoSample() + private void playDemoSample() => Scheduler.AddOnce(() => { demoSample.Samples = allRelevantSamples.First().samples.Cast().ToArray(); demoSample.Play(); - } + }); /// /// Applies the given update action on all samples of From 373162df02421cf835f2ad7ef25d98b092910cbd Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 30 Oct 2025 19:56:12 +0900 Subject: [PATCH 044/836] Add support for vote-to-skip in multiplayer --- .../Online/Multiplayer/MultiplayerClient.cs | 34 +++++++++++++++++-- .../Multiplayer/OnlineMultiplayerClient.cs | 12 +++++-- .../Multiplayer/MultiplayerPlayer.cs | 14 +++++++- osu.Game/Screens/Play/Player.cs | 9 +++-- .../Multiplayer/TestMultiplayerClient.cs | 2 +- 5 files changed, 63 insertions(+), 8 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 04162f6b6f03..9d97f0e83066 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -131,6 +131,9 @@ public abstract partial class MultiplayerClient : Component, IMultiplayerClient, public event Action? MatchmakingItemDeselected; public event Action? MatchRoomStateChanged; + public event Action? UserVotedToSkip; + public event Action? VoteToSkipPassed; + /// /// Whether the is currently connected. /// This is NOT thread safe and usage should be scheduled. @@ -521,6 +524,12 @@ Task IMultiplayerClient.RoomStateChanged(MultiplayerRoomState state) break; } + if (state == MultiplayerRoomState.Playing) + { + foreach (var user in Room.Users) + user.VotedToSkip = false; + } + RoomUpdated?.Invoke(); }); @@ -920,12 +929,33 @@ public Task PlaylistItemChanged(MultiplayerPlaylistItem item) Task IMultiplayerClient.UserVotedToSkip(int userId) { - throw new NotImplementedException(); + handleRoomRequest(() => + { + Debug.Assert(Room != null); + + var user = Room.Users.SingleOrDefault(u => u.UserID == userId); + + // TODO: user should NEVER be null here, see https://github.com/ppy/osu/issues/17713. + if (user == null) + return; + + user.VotedToSkip = true; + + UserVotedToSkip?.Invoke(userId); + }); + + return Task.CompletedTask; } Task IMultiplayerClient.VoteToSkipPassed() { - throw new NotImplementedException(); + handleRoomRequest(() => + { + Debug.Assert(Room != null); + VoteToSkipPassed?.Invoke(); + }); + + return Task.CompletedTask; } /// diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index e496aea7a22d..54811c57946c 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -70,7 +70,8 @@ private void load(IAPIProvider api) connection.On(nameof(IMultiplayerClient.PlaylistItemAdded), ((IMultiplayerClient)this).PlaylistItemAdded); connection.On(nameof(IMultiplayerClient.PlaylistItemRemoved), ((IMultiplayerClient)this).PlaylistItemRemoved); connection.On(nameof(IMultiplayerClient.PlaylistItemChanged), ((IMultiplayerClient)this).PlaylistItemChanged); - connection.On(nameof(IStatefulUserHubClient.DisconnectRequested), ((IMultiplayerClient)this).DisconnectRequested); + connection.On(nameof(IMultiplayerClient.UserVotedToSkip), ((IMultiplayerClient)this).UserVotedToSkip); + connection.On(nameof(IMultiplayerClient.VoteToSkipPassed), ((IMultiplayerClient)this).VoteToSkipPassed); connection.On(nameof(IMatchmakingClient.MatchmakingQueueJoined), ((IMatchmakingClient)this).MatchmakingQueueJoined); connection.On(nameof(IMatchmakingClient.MatchmakingQueueLeft), ((IMatchmakingClient)this).MatchmakingQueueLeft); @@ -80,6 +81,8 @@ private void load(IAPIProvider api) connection.On(nameof(IMatchmakingClient.MatchmakingQueueStatusChanged), ((IMatchmakingClient)this).MatchmakingQueueStatusChanged); connection.On(nameof(IMatchmakingClient.MatchmakingItemSelected), ((IMatchmakingClient)this).MatchmakingItemSelected); connection.On(nameof(IMatchmakingClient.MatchmakingItemDeselected), ((IMatchmakingClient)this).MatchmakingItemDeselected); + + connection.On(nameof(IStatefulUserHubClient.DisconnectRequested), ((IMultiplayerClient)this).DisconnectRequested); }; IsConnected.BindTo(connector.IsConnected); @@ -314,7 +317,12 @@ public override Task RemovePlaylistItem(long playlistItemId) public override Task VoteToSkip() { - throw new NotImplementedException(); + if (!IsConnected.Value) + return Task.CompletedTask; + + Debug.Assert(connection != null); + + return connection.InvokeAsync(nameof(IMultiplayerServer.VoteToSkip)); } public override Task DisconnectInternal() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 56120120d5b0..41b8f5f14688 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -56,7 +56,6 @@ public MultiplayerPlayer(Room room, PlaylistItem playlistItem, MultiplayerRoomUs { AllowPause = false, AllowRestart = false, - AllowSkipping = room.AutoSkip, AutomaticallySkipIntro = room.AutoSkip, ShowLeaderboard = true, }) @@ -121,6 +120,7 @@ protected override void LoadAsyncComplete() client.GameplayStarted += onGameplayStarted; client.ResultsReady += onResultsReady; + client.VoteToSkipPassed += onVoteToSkipPassed; ScoreProcessor.HasCompleted.BindValueChanged(_ => { @@ -219,6 +219,17 @@ protected override async Task PrepareScoreForResultsAsync(Score score) await Task.WhenAny(resultsReady.Task, Task.Delay(TimeSpan.FromSeconds(60))).ConfigureAwait(false); } + protected override void RequestIntroSkip() + { + // No base call because we aren't skipping yet. + client.VoteToSkip(); + } + + private void onVoteToSkipPassed() + { + Schedule(PerformIntroSkip); + } + protected override ResultsScreen CreateResults(ScoreInfo score) { Debug.Assert(Room.RoomID != null); @@ -242,6 +253,7 @@ protected override void Dispose(bool isDisposing) { client.GameplayStarted -= onGameplayStarted; client.ResultsReady -= onResultsReady; + client.VoteToSkipPassed -= onVoteToSkipPassed; } } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 22fb8a3463e3..9f40fc97daaf 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -502,7 +502,7 @@ private Drawable createOverlayComponents() DrawableRuleset.Cursor?.CreateProxy() ?? new Container(), skipIntroOverlay = new SkipOverlay(DrawableRuleset.GameplayStartTime) { - RequestSkip = performUserRequestedSkip + RequestSkip = RequestIntroSkip }, skipOutroOverlay = new SkipOverlay(GameplayState.Storyboard.LatestEventTime ?? 0) { @@ -701,7 +701,12 @@ protected bool PerformExit(bool skipTransition = false) return true; } - private void performUserRequestedSkip() + protected virtual void RequestIntroSkip() + { + PerformIntroSkip(); + } + + protected void PerformIntroSkip() { // user requested skip // disable sample playback to stop currently playing samples and perform skip diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index a899912225be..242bbe30835b 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -563,7 +563,7 @@ public async Task RemoveUserPlaylistItem(int userId, long playlistItemId) public override Task VoteToSkip() { - throw new NotImplementedException(); + return Task.CompletedTask; } protected override Task CreateRoomInternal(MultiplayerRoom room) From d0ce74063d21329f5feeaec26c1a87f6c19f12f3 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 30 Oct 2025 20:49:27 +0900 Subject: [PATCH 045/836] Skip full intro length --- osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs | 2 +- osu.Game/Screens/Play/MasterGameplayClockContainer.cs | 4 ++-- osu.Game/Screens/Play/Player.cs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 41b8f5f14688..406f38ea72ea 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -227,7 +227,7 @@ protected override void RequestIntroSkip() private void onVoteToSkipPassed() { - Schedule(PerformIntroSkip); + Schedule(() => PerformIntroSkip(true)); } protected override ResultsScreen CreateResults(ScoreInfo score) diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 07ecb5a5fbbc..abf157df43c3 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -115,14 +115,14 @@ protected override void StartGameplayClock() /// /// Skip forward to the next valid skip point. /// - public void Skip() + public void Skip(bool fullLength = false) { if (GameplayClock.CurrentTime > GameplayStartTime - MINIMUM_SKIP_TIME) return; double skipTarget = GameplayStartTime - MINIMUM_SKIP_TIME; - if (StartTime < -10000 && GameplayClock.CurrentTime < 0 && skipTarget > 6000) + if (!fullLength && StartTime < -10000 && GameplayClock.CurrentTime < 0 && skipTarget > 6000) // double skip exception for storyboards with very long intros skipTarget = 0; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 9f40fc97daaf..2927d8a720e3 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -706,13 +706,13 @@ protected virtual void RequestIntroSkip() PerformIntroSkip(); } - protected void PerformIntroSkip() + protected void PerformIntroSkip(bool fullLength = false) { // user requested skip // disable sample playback to stop currently playing samples and perform skip samplePlaybackDisabled.Value = true; - (GameplayClockContainer as MasterGameplayClockContainer)?.Skip(); + (GameplayClockContainer as MasterGameplayClockContainer)?.Skip(fullLength); // return samplePlaybackDisabled.Value to what is defined by the beatmap's current state updateSampleDisabledState(); From b20a41c1e8377271bd96fd345df1479d20fac3c2 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 31 Oct 2025 21:39:33 +0900 Subject: [PATCH 046/836] Add simple multiplayer skip overlay --- .../Visual/Gameplay/TestSceneSkipOverlay.cs | 2 +- .../TestSceneMultiplayerSkipOverlay.cs | 73 +++++++++++ .../Multiplayer/MultiplayerPlayer.cs | 2 + .../Multiplayer/MultiplayerSkipOverlay.cs | 114 ++++++++++++++++++ osu.Game/Screens/Play/Player.cs | 14 ++- osu.Game/Screens/Play/SkipOverlay.cs | 17 +-- .../Multiplayer/TestMultiplayerClient.cs | 7 +- 7 files changed, 213 insertions(+), 16 deletions(-) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSkipOverlay.cs create mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs index 276a0c3410b5..946b625608ba 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs @@ -173,7 +173,7 @@ public TestSkipOverlay(double startTime) public Drawable OverlayContent => InternalChild; - public Drawable FadingContent => (OverlayContent as Container)?.Child; + public new Drawable FadingContent => (OverlayContent as Container)?.Child; } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSkipOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSkipOverlay.cs new file mode 100644 index 000000000000..a1b28e2544f9 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSkipOverlay.cs @@ -0,0 +1,73 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.OnlinePlay.Multiplayer; +using osu.Game.Screens.Play; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public partial class TestSceneMultiplayerSkipOverlay : MultiplayerTestScene + { + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("join room", () => JoinRoom(CreateDefaultRoom())); + WaitForJoined(); + + AddStep("add skip overlay", () => + { + GameplayClockContainer gameplayClockContainer; + + var working = CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)); + + Child = gameplayClockContainer = new MasterGameplayClockContainer(working, 0) + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new MultiplayerSkipOverlay(120000) + }, + }; + + gameplayClockContainer.Start(); + }); + + AddStep("set playing state", () => MultiplayerClient.ChangeUserState(API.LocalUser.Value.OnlineID, MultiplayerUserState.Playing)); + } + + [Test] + public void TestSkip() + { + for (int i = 0; i < 4; i++) + { + int i2 = i; + + AddStep($"join user {i2}", () => + { + MultiplayerClient.AddUser(new APIUser + { + Id = i2, + Username = $"User {i2}" + }); + + MultiplayerClient.ChangeUserState(i2, MultiplayerUserState.Playing); + }); + } + + AddStep("local user votes", () => MultiplayerClient.VoteToSkip().WaitSafely()); + + for (int i = 0; i < 4; i++) + { + int i2 = i; + AddStep($"user {i2} votes", () => MultiplayerClient.UserVoteToSkip(i2).WaitSafely()); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 406f38ea72ea..24dfa59ed306 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -148,6 +148,8 @@ protected override void LoadComplete() Debug.Assert(client.Room != null); } + protected override SkipOverlay CreateSkipOverlay(double startTime) => new MultiplayerSkipOverlay(startTime); + protected override void StartGameplay() { // We can enter this screen one of two ways: diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs new file mode 100644 index 000000000000..ccda0e86904d --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs @@ -0,0 +1,114 @@ +// 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.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Multiplayer; +using osu.Game.Screens.Play; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Multiplayer +{ + public partial class MultiplayerSkipOverlay : SkipOverlay + { + [Resolved] + private MultiplayerClient client { get; set; } = null!; + + private Drawable votedIcon = null!; + private OsuSpriteText countText = null!; + + public MultiplayerSkipOverlay(double startTime) + : base(startTime) + { + } + + [BackgroundDependencyLoader] + private void load() + { + FadingContent.AddRange( + [ + votedIcon = new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Position = new Vector2(50, 0), + Size = new Vector2(20), + Alpha = 0, + Masking = true, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Green + }, + new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Scale = new Vector2(0.5f), + Icon = FontAwesome.Solid.Check + } + } + }, + countText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.Centre, + RelativePositionAxes = Axes.X, + Position = new Vector2(0.75f, 0), + Font = OsuFont.Default.With(size: 36, weight: FontWeight.Bold) + } + ]); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + client.UserStateChanged += onUserStateChanged; + client.UserVotedToSkip += onUserVotedToSkip; + + updateText(); + } + + private void onUserStateChanged(MultiplayerRoomUser user, MultiplayerUserState state) + { + Schedule(updateText); + } + + private void onUserVotedToSkip(int userId) => Schedule(() => + { + updateText(); + + countText.ScaleTo(1.5f).ScaleTo(1, 200, Easing.OutSine); + + if (userId == client.LocalUser?.UserID) + { + votedIcon.ScaleTo(1.5f).ScaleTo(1, 200, Easing.OutSine); + votedIcon.FadeInFromZero(100); + } + }); + + private void updateText() + { + if (client.Room == null) + return; + + int countTotal = client.Room.Users.Count(u => u.State == MultiplayerUserState.Playing); + int countSkipped = client.Room.Users.Count(u => u.State == MultiplayerUserState.Playing && u.VotedToSkip); + int countRequired = countTotal / 2 + 1; + + countText.Text = $"{Math.Min(countRequired, countSkipped)} / {countRequired}"; + } + } +} diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 2927d8a720e3..b712a451c5f8 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -154,7 +154,7 @@ public override bool RequiresPortraitOrientation private BreakTracker breakTracker; - private SkipOverlay skipIntroOverlay; + protected SkipOverlay SkipIntroOverlay { get; private set; } private SkipOverlay skipOutroOverlay; protected ScoreProcessor ScoreProcessor { get; private set; } @@ -500,10 +500,10 @@ private Drawable createOverlayComponents() }, // display the cursor above some HUD elements. DrawableRuleset.Cursor?.CreateProxy() ?? new Container(), - skipIntroOverlay = new SkipOverlay(DrawableRuleset.GameplayStartTime) + SkipIntroOverlay = CreateSkipOverlay(DrawableRuleset.GameplayStartTime).With(o => { - RequestSkip = RequestIntroSkip - }, + o.RequestSkip = RequestIntroSkip; + }), skipOutroOverlay = new SkipOverlay(GameplayState.Storyboard.LatestEventTime ?? 0) { RequestSkip = () => progressToResults(false), @@ -522,13 +522,15 @@ private Drawable createOverlayComponents() if (!Configuration.AllowSkipping || !DrawableRuleset.AllowGameplayOverlays) { - skipIntroOverlay.Expire(); + SkipIntroOverlay.Expire(); skipOutroOverlay.Expire(); } return container; } + protected virtual SkipOverlay CreateSkipOverlay(double startTime) => new SkipOverlay(startTime); + private void onBreakTimeChanged(ValueChangedEvent isBreakTime) { updateGameplayState(); @@ -1158,7 +1160,7 @@ protected virtual void StartGameplay() GameplayClockContainer.Reset(startClock: true); if (Configuration.AutomaticallySkipIntro) - skipIntroOverlay.SkipWhenReady(); + SkipIntroOverlay.SkipWhenReady(); } public override void OnSuspending(ScreenTransitionEvent e) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index be8517d9a009..700ea2e532b1 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -38,20 +38,21 @@ public partial class SkipOverlay : BeatSyncedContainer, IKeyBindingHandler fadeContainer.State == Visibility.Visible && buttonContainer.State.Value == Visibility.Visible; + internal bool IsButtonVisible => FadingContent.State == Visibility.Visible && buttonContainer.State.Value == Visibility.Visible; public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; /// @@ -77,7 +78,7 @@ private void load(OsuColour colours) InternalChild = buttonContainer = new ButtonContainer { RelativeSizeAxes = Axes.Both, - Child = fadeContainer = new FadeContainer + Child = FadingContent = new FadeContainer { RelativeSizeAxes = Axes.Both, Children = new Drawable[] @@ -107,13 +108,13 @@ private void load(OsuColour colours) public override void Hide() { base.Hide(); - fadeContainer.Hide(); + FadingContent.Hide(); } public override void Show() { base.Show(); - fadeContainer.TriggerShow(); + FadingContent.TriggerShow(); } protected override void LoadComplete() @@ -136,7 +137,7 @@ protected override void LoadComplete() RequestSkip?.Invoke(); }; - fadeContainer.TriggerShow(); + FadingContent.TriggerShow(); } /// @@ -183,7 +184,7 @@ protected override void Update() protected override bool OnMouseMove(MouseMoveEvent e) { if (isClickable && !e.HasAnyButtonPressed) - fadeContainer.TriggerShow(); + FadingContent.TriggerShow(); return base.OnMouseMove(e); } diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 242bbe30835b..fcee7e5b44d6 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -563,7 +563,12 @@ public async Task RemoveUserPlaylistItem(int userId, long playlistItemId) public override Task VoteToSkip() { - return Task.CompletedTask; + return UserVoteToSkip(api.LocalUser.Value.OnlineID); + } + + public async Task UserVoteToSkip(int userId) + { + await ((IMultiplayerClient)this).UserVotedToSkip(userId); } protected override Task CreateRoomInternal(MultiplayerRoom room) From 6f94b1ab6d21e0dba43c78a801624611c838981b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 31 Oct 2025 21:40:40 +0900 Subject: [PATCH 047/836] Move property reset into GameplayStarted() --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 9d97f0e83066..3df12e16eaa3 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -524,12 +524,6 @@ Task IMultiplayerClient.RoomStateChanged(MultiplayerRoomState state) break; } - if (state == MultiplayerRoomState.Playing) - { - foreach (var user in Room.Users) - user.VotedToSkip = false; - } - RoomUpdated?.Invoke(); }); @@ -857,6 +851,10 @@ Task IMultiplayerClient.GameplayStarted() handleRoomRequest(() => { Debug.Assert(Room != null); + + foreach (var user in Room.Users) + user.VotedToSkip = false; + GameplayStarted?.Invoke(); }); From bdcc0ee937113dd5a80ae6e7920688dd7a6de028 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 31 Oct 2025 21:42:29 +0900 Subject: [PATCH 048/836] Apply suggestions from review --- osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs | 2 +- osu.Game/Screens/Play/MasterGameplayClockContainer.cs | 1 + osu.Game/Screens/Play/Player.cs | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 24dfa59ed306..214a7d640304 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -224,7 +224,7 @@ protected override async Task PrepareScoreForResultsAsync(Score score) protected override void RequestIntroSkip() { // No base call because we aren't skipping yet. - client.VoteToSkip(); + client.VoteToSkip().FireAndForget(); } private void onVoteToSkipPassed() diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index abf157df43c3..c9db6009d0d1 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -115,6 +115,7 @@ protected override void StartGameplayClock() /// /// Skip forward to the next valid skip point. /// + /// true to skip as close to gameplay as possible, or false to skip only to the next valid skip point. public void Skip(bool fullLength = false) { if (GameplayClock.CurrentTime > GameplayStartTime - MINIMUM_SKIP_TIME) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index b712a451c5f8..6158118c7813 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -708,6 +708,10 @@ protected virtual void RequestIntroSkip() PerformIntroSkip(); } + /// + /// Skip forward to the next valid skip point. + /// + /// true to skip as close to gameplay as possible, or false to skip only to the next valid skip point. protected void PerformIntroSkip(bool fullLength = false) { // user requested skip From a9ca4634fc583ececc0fd3c3bbfa224c8a8daf59 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 31 Oct 2025 21:48:24 +0900 Subject: [PATCH 049/836] Resolve CI inspections --- osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index fcee7e5b44d6..83b2da000fd1 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -568,7 +568,7 @@ public override Task VoteToSkip() public async Task UserVoteToSkip(int userId) { - await ((IMultiplayerClient)this).UserVotedToSkip(userId); + await ((IMultiplayerClient)this).UserVotedToSkip(userId).ConfigureAwait(false); } protected override Task CreateRoomInternal(MultiplayerRoom room) From f4049c7ec18fa22904e7c57ce8c725f7824136bc Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 31 Oct 2025 22:48:49 +0900 Subject: [PATCH 050/836] Suffix introp methods with "Intro" --- .../Multiplayer/TestSceneMultiplayerSkipOverlay.cs | 4 ++-- osu.Game/Online/Multiplayer/IMultiplayerClient.cs | 4 ++-- .../Online/Multiplayer/IMultiplayerRoomServer.cs | 2 +- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 14 +++++++------- osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs | 2 +- .../Online/Multiplayer/OnlineMultiplayerClient.cs | 8 ++++---- .../OnlinePlay/Multiplayer/MultiplayerPlayer.cs | 8 ++++---- .../Multiplayer/MultiplayerSkipOverlay.cs | 2 +- .../Visual/Multiplayer/TestMultiplayerClient.cs | 8 ++++---- 9 files changed, 26 insertions(+), 26 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSkipOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSkipOverlay.cs index a1b28e2544f9..059af2484d8d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSkipOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSkipOverlay.cs @@ -61,12 +61,12 @@ public void TestSkip() }); } - AddStep("local user votes", () => MultiplayerClient.VoteToSkip().WaitSafely()); + AddStep("local user votes", () => MultiplayerClient.VoteToSkipIntro().WaitSafely()); for (int i = 0; i < 4; i++) { int i2 = i; - AddStep($"user {i2} votes", () => MultiplayerClient.UserVoteToSkip(i2).WaitSafely()); + AddStep($"user {i2} votes", () => MultiplayerClient.UserVoteToSkipIntro(i2).WaitSafely()); } } } diff --git a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs index 340fb04731d8..c91128401d0b 100644 --- a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs @@ -153,11 +153,11 @@ public interface IMultiplayerClient : IStatefulUserHubClient /// /// Signals that a user has requested to skip the beatmap intro. /// - Task UserVotedToSkip(int userId); + Task UserVotedToSkipIntro(int userId); /// /// Signals that the vote to skip the beatmap intro has passed. /// - Task VoteToSkipPassed(); + Task VoteToSkipIntroPassed(); } } diff --git a/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs index d7834427d0a7..169d5d1b8312 100644 --- a/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs @@ -115,7 +115,7 @@ public interface IMultiplayerRoomServer /// /// Votes to skip the beatmap intro. /// - Task VoteToSkip(); + Task VoteToSkipIntro(); /// /// Invites a player to the current room. diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 3df12e16eaa3..af2655f0f4a6 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -132,7 +132,7 @@ public abstract partial class MultiplayerClient : Component, IMultiplayerClient, public event Action? MatchRoomStateChanged; public event Action? UserVotedToSkip; - public event Action? VoteToSkipPassed; + public event Action? VoteToSkipIntroPassed; /// /// Whether the is currently connected. @@ -496,7 +496,7 @@ public async Task ToggleSpectate() public abstract Task RemovePlaylistItem(long playlistItemId); - public abstract Task VoteToSkip(); + public abstract Task VoteToSkipIntro(); Task IMultiplayerClient.RoomStateChanged(MultiplayerRoomState state) { @@ -853,7 +853,7 @@ Task IMultiplayerClient.GameplayStarted() Debug.Assert(Room != null); foreach (var user in Room.Users) - user.VotedToSkip = false; + user.VotedToSkipIntro = false; GameplayStarted?.Invoke(); }); @@ -925,7 +925,7 @@ public Task PlaylistItemChanged(MultiplayerPlaylistItem item) return Task.CompletedTask; } - Task IMultiplayerClient.UserVotedToSkip(int userId) + Task IMultiplayerClient.UserVotedToSkipIntro(int userId) { handleRoomRequest(() => { @@ -937,7 +937,7 @@ Task IMultiplayerClient.UserVotedToSkip(int userId) if (user == null) return; - user.VotedToSkip = true; + user.VotedToSkipIntro = true; UserVotedToSkip?.Invoke(userId); }); @@ -945,12 +945,12 @@ Task IMultiplayerClient.UserVotedToSkip(int userId) return Task.CompletedTask; } - Task IMultiplayerClient.VoteToSkipPassed() + Task IMultiplayerClient.VoteToSkipIntroPassed() { handleRoomRequest(() => { Debug.Assert(Room != null); - VoteToSkipPassed?.Invoke(); + VoteToSkipIntroPassed?.Invoke(); }); return Task.CompletedTask; diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs index 365a25778bf8..d19386c98d71 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs @@ -53,7 +53,7 @@ public class MultiplayerRoomUser : IEquatable /// Whether this user voted to skip the beatmap intro. /// [Key(7)] - public bool VotedToSkip; + public bool VotedToSkipIntro; [IgnoreMember] public APIUser? User { get; set; } diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 54811c57946c..1319578c0636 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -70,8 +70,8 @@ private void load(IAPIProvider api) connection.On(nameof(IMultiplayerClient.PlaylistItemAdded), ((IMultiplayerClient)this).PlaylistItemAdded); connection.On(nameof(IMultiplayerClient.PlaylistItemRemoved), ((IMultiplayerClient)this).PlaylistItemRemoved); connection.On(nameof(IMultiplayerClient.PlaylistItemChanged), ((IMultiplayerClient)this).PlaylistItemChanged); - connection.On(nameof(IMultiplayerClient.UserVotedToSkip), ((IMultiplayerClient)this).UserVotedToSkip); - connection.On(nameof(IMultiplayerClient.VoteToSkipPassed), ((IMultiplayerClient)this).VoteToSkipPassed); + connection.On(nameof(IMultiplayerClient.UserVotedToSkipIntro), ((IMultiplayerClient)this).UserVotedToSkipIntro); + connection.On(nameof(IMultiplayerClient.VoteToSkipIntroPassed), ((IMultiplayerClient)this).VoteToSkipIntroPassed); connection.On(nameof(IMatchmakingClient.MatchmakingQueueJoined), ((IMatchmakingClient)this).MatchmakingQueueJoined); connection.On(nameof(IMatchmakingClient.MatchmakingQueueLeft), ((IMatchmakingClient)this).MatchmakingQueueLeft); @@ -315,14 +315,14 @@ public override Task RemovePlaylistItem(long playlistItemId) return connection.InvokeAsync(nameof(IMultiplayerServer.RemovePlaylistItem), playlistItemId); } - public override Task VoteToSkip() + public override Task VoteToSkipIntro() { if (!IsConnected.Value) return Task.CompletedTask; Debug.Assert(connection != null); - return connection.InvokeAsync(nameof(IMultiplayerServer.VoteToSkip)); + return connection.InvokeAsync(nameof(IMultiplayerServer.VoteToSkipIntro)); } public override Task DisconnectInternal() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 214a7d640304..26535f269c06 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -120,7 +120,7 @@ protected override void LoadAsyncComplete() client.GameplayStarted += onGameplayStarted; client.ResultsReady += onResultsReady; - client.VoteToSkipPassed += onVoteToSkipPassed; + client.VoteToSkipIntroPassed += onVoteToSkipIntroPassed; ScoreProcessor.HasCompleted.BindValueChanged(_ => { @@ -224,10 +224,10 @@ protected override async Task PrepareScoreForResultsAsync(Score score) protected override void RequestIntroSkip() { // No base call because we aren't skipping yet. - client.VoteToSkip().FireAndForget(); + client.VoteToSkipIntro().FireAndForget(); } - private void onVoteToSkipPassed() + private void onVoteToSkipIntroPassed() { Schedule(() => PerformIntroSkip(true)); } @@ -255,7 +255,7 @@ protected override void Dispose(bool isDisposing) { client.GameplayStarted -= onGameplayStarted; client.ResultsReady -= onResultsReady; - client.VoteToSkipPassed -= onVoteToSkipPassed; + client.VoteToSkipIntroPassed -= onVoteToSkipIntroPassed; } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs index ccda0e86904d..68c6fbe7c573 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs @@ -105,7 +105,7 @@ private void updateText() return; int countTotal = client.Room.Users.Count(u => u.State == MultiplayerUserState.Playing); - int countSkipped = client.Room.Users.Count(u => u.State == MultiplayerUserState.Playing && u.VotedToSkip); + int countSkipped = client.Room.Users.Count(u => u.State == MultiplayerUserState.Playing && u.VotedToSkipIntro); int countRequired = countTotal / 2 + 1; countText.Text = $"{Math.Min(countRequired, countSkipped)} / {countRequired}"; diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 83b2da000fd1..38070d953ee6 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -561,14 +561,14 @@ public async Task RemoveUserPlaylistItem(int userId, long playlistItemId) public override Task RemovePlaylistItem(long playlistItemId) => RemoveUserPlaylistItem(api.LocalUser.Value.OnlineID, clone(playlistItemId)); - public override Task VoteToSkip() + public override Task VoteToSkipIntro() { - return UserVoteToSkip(api.LocalUser.Value.OnlineID); + return UserVoteToSkipIntro(api.LocalUser.Value.OnlineID); } - public async Task UserVoteToSkip(int userId) + public async Task UserVoteToSkipIntro(int userId) { - await ((IMultiplayerClient)this).UserVotedToSkip(userId).ConfigureAwait(false); + await ((IMultiplayerClient)this).UserVotedToSkipIntro(userId).ConfigureAwait(false); } protected override Task CreateRoomInternal(MultiplayerRoom room) From 4c81d661aa472d69b74af75c539a96ea66d1bee7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 4 Nov 2025 11:03:45 +0900 Subject: [PATCH 051/836] Bypass vote for auto-skip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- .../Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs | 7 +++++++ .../OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 26535f269c06..4cc6f3469d3a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -223,6 +223,13 @@ protected override async Task PrepareScoreForResultsAsync(Score score) protected override void RequestIntroSkip() { + // If the room is set up such that the intro is automatically skipped, there's no need to vote on it. + if (Configuration.AutomaticallySkipIntro) + { + base.RequestIntroSkip(); + return; + } + // No base call because we aren't skipping yet. client.VoteToSkipIntro().FireAndForget(); } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs index 68c6fbe7c573..747384b22063 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs @@ -101,7 +101,7 @@ private void onUserVotedToSkip(int userId) => Schedule(() => private void updateText() { - if (client.Room == null) + if (client.Room == null || client.Room.Settings.AutoSkip) return; int countTotal = client.Room.Users.Count(u => u.State == MultiplayerUserState.Playing); From c44f701abe08bae1439a3319654df2c9eb991c58 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 4 Nov 2025 11:06:57 +0900 Subject: [PATCH 052/836] Also update text when users leave --- .../OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs index 747384b22063..927d30398845 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs @@ -75,12 +75,18 @@ protected override void LoadComplete() { base.LoadComplete(); + client.UserLeft += onUserLeft; client.UserStateChanged += onUserStateChanged; client.UserVotedToSkip += onUserVotedToSkip; updateText(); } + private void onUserLeft(MultiplayerRoomUser user) + { + Schedule(updateText); + } + private void onUserStateChanged(MultiplayerRoomUser user, MultiplayerUserState state) { Schedule(updateText); From 4d706b12ac3b0cc13e44ce6efd8af2d971055195 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 4 Nov 2025 11:07:18 +0900 Subject: [PATCH 053/836] Fix missing disposal --- .../Multiplayer/MultiplayerSkipOverlay.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs index 927d30398845..f9d394c2b5a3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -116,5 +117,17 @@ private void updateText() countText.Text = $"{Math.Min(countRequired, countSkipped)} / {countRequired}"; } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (client.IsNotNull()) + { + client.UserLeft -= onUserLeft; + client.UserStateChanged -= onUserStateChanged; + client.UserVotedToSkip -= onUserVotedToSkip; + } + } } } From 4ea03d0e0710bb49763518de9fc09785ed0d0d8f Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 4 Nov 2025 11:21:33 +0900 Subject: [PATCH 054/836] Add history footer button to quick play rooms --- .../ScreenMatchmaking.HistoryFooterButton.cs | 40 +++++++++++++++++++ .../Matchmaking/Match/ScreenMatchmaking.cs | 11 ++++- 2 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.HistoryFooterButton.cs diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.HistoryFooterButton.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.HistoryFooterButton.cs new file mode 100644 index 000000000000..94e19ab7b93c --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.HistoryFooterButton.cs @@ -0,0 +1,40 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Online.Multiplayer; +using osu.Game.Screens.Footer; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match +{ + public partial class ScreenMatchmaking + { + private partial class HistoryFooterButton : ScreenFooterButton + { + [Resolved] + private OsuGame? game { get; set; } + + private readonly MultiplayerRoom room; + + public HistoryFooterButton(MultiplayerRoom room) + { + this.room = room; + + Action = openRoomHistory; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Text = "History"; + Icon = FontAwesome.Solid.Globe; + AccentColour = colours.Lime1; + } + + private void openRoomHistory() + => game?.OpenUrlExternally($@"/multiplayer/rooms/{room.RoomID}"); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs index 527b1ba243e4..160fdd74050f 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.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.Collections.Generic; using System.Linq; using System.Threading; using osu.Framework.Allocation; @@ -29,6 +30,7 @@ using osu.Game.Overlays; using osu.Game.Overlays.Dialog; using osu.Game.Rulesets; +using osu.Game.Screens.Footer; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.Gameplay; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Users; @@ -164,7 +166,7 @@ private void load(OverlayColourProvider colourProvider) { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Size = new Vector2(700, 130), + Size = new Vector2(600, 130), Margin = new MarginPadding { Bottom = row_padding } } ] @@ -326,6 +328,11 @@ protected override bool OnKeyDown(KeyDownEvent e) return false; } + public override IReadOnlyList CreateFooterButtons() => + [ + new HistoryFooterButton(room) + ]; + public override void OnEntering(ScreenTransitionEvent e) { base.OnEntering(e); @@ -463,7 +470,7 @@ public ChatContainer(MatchmakingChatDisplay chat) // This component is added to the screen footer which is only about 50px high. // Therefore, it's given a large absolute size to give the context menu enough space to display correctly. - Size = new Vector2(700); + Size = new Vector2(600); InternalChild = new OsuContextMenuContainer { From 78f639d7600f9bce7513494cd9854bc98ac2e17b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 4 Nov 2025 11:29:51 +0900 Subject: [PATCH 055/836] Attempt to clean up chat size definition --- .../Matchmaking/Match/ScreenMatchmaking.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs index 160fdd74050f..972f0b4adb31 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs @@ -49,6 +49,8 @@ public partial class ScreenMatchmaking : OsuScreen, IPreviewTrackOwner, IHandleP /// private const float row_padding = 10; + private static readonly Vector2 chat_size = new Vector2(550, 130); + public override bool? ApplyModTrackAdjustments => true; public override bool DisallowExternalBeatmapRulesetChanges => true; @@ -106,8 +108,12 @@ public ScreenMatchmaking(MultiplayerRoom room) { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, - Size = new Vector2(700, 130), - Margin = new MarginPadding { Bottom = 10, Right = WaveOverlayContainer.WIDTH_PADDING - HORIZONTAL_OVERFLOW_PADDING }, + Size = chat_size, + Margin = new MarginPadding + { + Right = WaveOverlayContainer.WIDTH_PADDING - HORIZONTAL_OVERFLOW_PADDING, + Bottom = row_padding + }, Alpha = 0 }; } @@ -164,9 +170,10 @@ private void load(OverlayColourProvider colourProvider) [ new Container { + Name = "Chat Area Space", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Size = new Vector2(600, 130), + Size = new Vector2(550, 130), Margin = new MarginPadding { Bottom = row_padding } } ] @@ -470,7 +477,7 @@ public ChatContainer(MatchmakingChatDisplay chat) // This component is added to the screen footer which is only about 50px high. // Therefore, it's given a large absolute size to give the context menu enough space to display correctly. - Size = new Vector2(600); + Size = new Vector2(chat_size.X); InternalChild = new OsuContextMenuContainer { From f8331e0b2859d0d849cbf9f39dfa722f7def33c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 4 Nov 2025 12:56:03 +0100 Subject: [PATCH 056/836] Apply one more missed rename --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 4 ++-- .../OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index af2655f0f4a6..6f98264d239c 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -131,7 +131,7 @@ public abstract partial class MultiplayerClient : Component, IMultiplayerClient, public event Action? MatchmakingItemDeselected; public event Action? MatchRoomStateChanged; - public event Action? UserVotedToSkip; + public event Action? UserVotedToSkipIntro; public event Action? VoteToSkipIntroPassed; /// @@ -939,7 +939,7 @@ Task IMultiplayerClient.UserVotedToSkipIntro(int userId) user.VotedToSkipIntro = true; - UserVotedToSkip?.Invoke(userId); + UserVotedToSkipIntro?.Invoke(userId); }); return Task.CompletedTask; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs index f9d394c2b5a3..35e85c327350 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs @@ -78,7 +78,7 @@ protected override void LoadComplete() client.UserLeft += onUserLeft; client.UserStateChanged += onUserStateChanged; - client.UserVotedToSkip += onUserVotedToSkip; + client.UserVotedToSkipIntro += onUserVotedToSkipIntro; updateText(); } @@ -93,7 +93,7 @@ private void onUserStateChanged(MultiplayerRoomUser user, MultiplayerUserState s Schedule(updateText); } - private void onUserVotedToSkip(int userId) => Schedule(() => + private void onUserVotedToSkipIntro(int userId) => Schedule(() => { updateText(); @@ -126,7 +126,7 @@ protected override void Dispose(bool isDisposing) { client.UserLeft -= onUserLeft; client.UserStateChanged -= onUserStateChanged; - client.UserVotedToSkip -= onUserVotedToSkip; + client.UserVotedToSkipIntro -= onUserVotedToSkipIntro; } } } From a7e4aa8b1250e7d8467f19ec99a800e6e16a0a27 Mon Sep 17 00:00:00 2001 From: StanR Date: Tue, 4 Nov 2025 21:27:07 +0500 Subject: [PATCH 057/836] Clamp notification avatar width --- osu.Game/Overlays/Notifications/UserAvatarNotification.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/UserAvatarNotification.cs b/osu.Game/Overlays/Notifications/UserAvatarNotification.cs index 7dbecbf11e2f..fcc1d59dde6b 100644 --- a/osu.Game/Overlays/Notifications/UserAvatarNotification.cs +++ b/osu.Game/Overlays/Notifications/UserAvatarNotification.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 osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; @@ -39,7 +40,7 @@ private void load() protected override void Update() { base.Update(); - IconContent.Width = IconContent.DrawHeight; + IconContent.Width = Math.Min(78, IconContent.DrawHeight); } } } From d98cb9ca45c9ac3ae1e44e9d341d66365d0c1806 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 5 Nov 2025 16:42:32 +0900 Subject: [PATCH 058/836] Correctly link to room history --- .../Matchmaking/Match/ScreenMatchmaking.HistoryFooterButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.HistoryFooterButton.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.HistoryFooterButton.cs index 94e19ab7b93c..f46c0611c5a8 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.HistoryFooterButton.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.HistoryFooterButton.cs @@ -34,7 +34,7 @@ private void load(OsuColour colours) } private void openRoomHistory() - => game?.OpenUrlExternally($@"/multiplayer/rooms/{room.RoomID}"); + => game?.OpenUrlExternally($@"/multiplayer/rooms/{room.RoomID}/events"); } } } From 6a6c7ad3ba106f06414f4ce5bba6fb6585ea1aee Mon Sep 17 00:00:00 2001 From: Loreos7 <86934170+Loreos7@users.noreply.github.com> Date: Wed, 5 Nov 2025 15:56:07 +0300 Subject: [PATCH 059/836] Move `Delete...` button to `CommonStrings` --- osu.Game/Localisation/CommonStrings.cs | 5 +++++ osu.Game/Localisation/SongSelectStrings.cs | 5 ----- osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs | 2 +- osu.Game/Screens/SelectV2/PanelBeatmapSet.cs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index c8630f933270..324cb424b5cc 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -199,6 +199,11 @@ public static class CommonStrings /// public static LocalisableString Mapper => new TranslatableString(getKey(@"mapper"), @"Mapper"); + /// + /// "Delete..." + /// + public static LocalisableString Delete => new TranslatableString(getKey(@"delete"), @"Delete..."); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/SongSelectStrings.cs b/osu.Game/Localisation/SongSelectStrings.cs index 5f940f8a5657..c20715fb4ceb 100644 --- a/osu.Game/Localisation/SongSelectStrings.cs +++ b/osu.Game/Localisation/SongSelectStrings.cs @@ -139,11 +139,6 @@ public static class SongSelectStrings /// public static LocalisableString ClearAllLocalScores => new TranslatableString(getKey(@"clear_all_local_scores"), @"Clear all local scores"); - /// - /// "Delete..." - /// - public static LocalisableString Delete => new TranslatableString(getKey(@"delete"), @"Delete..."); - /// /// "Restore all hidden" /// diff --git a/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs b/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs index ae06522b30a2..c93afe24a5d7 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs +++ b/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs @@ -62,7 +62,7 @@ private void load(OsuColour colours) Debug.Assert(beatmap.BeatmapSet != null); addHeader(SongSelectStrings.ForAllDifficulties, beatmap.BeatmapSet.ToString()); - addButton(SongSelectStrings.Delete, FontAwesome.Solid.Trash, () => SongSelect?.Delete(beatmap.BeatmapSet), colours.Red1); + addButton(CommonStrings.Delete, FontAwesome.Solid.Trash, () => SongSelect?.Delete(beatmap.BeatmapSet), colours.Red1); addHeader(SongSelectStrings.ForSelectedDifficulty, beatmap.DifficultyName); diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs index cc552864319a..3046155a5e41 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs @@ -268,7 +268,7 @@ public override MenuItem[] ContextMenuItems if (beatmapSet.Beatmaps.Any(b => b.Hidden)) items.Add(new OsuMenuItem(SongSelectStrings.RestoreAllHidden, MenuItemType.Standard, () => songSelect?.RestoreAllHidden(beatmapSet))); - items.Add(new OsuMenuItem(SongSelectStrings.Delete, MenuItemType.Destructive, () => songSelect?.Delete(beatmapSet))); + items.Add(new OsuMenuItem(CommonStrings.Delete, MenuItemType.Destructive, () => songSelect?.Delete(beatmapSet))); return items.ToArray(); } } From 20904de276d67939a339fa7b020643192c5e662a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Nov 2025 22:47:21 +0900 Subject: [PATCH 060/836] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 3ca35b958c62..1c3e1a3a9eb7 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From dbefba57ce0b890ac423ae4319873a197efb87b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 6 Nov 2025 08:06:52 +0100 Subject: [PATCH 061/836] Fix pressing Enter on song select with IME active advancing to gameplay instead of confirming choice (#35619) Closes https://github.com/ppy/osu/issues/35568. --- osu.Game/Graphics/UserInterface/SearchTextBox.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/SearchTextBox.cs b/osu.Game/Graphics/UserInterface/SearchTextBox.cs index a2e0ab648217..17d714d029cc 100644 --- a/osu.Game/Graphics/UserInterface/SearchTextBox.cs +++ b/osu.Game/Graphics/UserInterface/SearchTextBox.cs @@ -54,7 +54,13 @@ protected override bool OnKeyDown(KeyDownEvent e) { case Key.KeypadEnter: case Key.Enter: - return false; + // even if committing per se is not allowed for this textbox, + // the commit flow is also responsible for terminating any active IME. + // ensure that the Enter press terminates IME correctly + // and is also handled if it needs to be, so that it doesn't leak to some other non-focused drawable and cause breakage. + bool wasImeComposing = ImeCompositionActive; + FinalizeImeComposition(true); + return wasImeComposing; } } From 4a22ef88ce6ad68831d448047ae2b8deb44995dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 6 Nov 2025 13:14:25 +0100 Subject: [PATCH 062/836] Adjust global rank colour tiers See https://github.com/ppy/osu-web/pull/12522. --- osu.Game.Tests/Visual/Online/TestSceneGlobalRankDisplay.cs | 2 +- .../Overlays/Profile/Header/Components/GlobalRankDisplay.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneGlobalRankDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneGlobalRankDisplay.cs index 07fe8c6172cb..beabf6711c0d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneGlobalRankDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneGlobalRankDisplay.cs @@ -26,7 +26,7 @@ public TestSceneGlobalRankDisplay() Direction = FillDirection.Full, Padding = new MarginPadding(20), Spacing = new Vector2(40), - ChildrenEnumerable = new int?[] { 64, 423, 1453, 3468, 18_367, 48_342, 178_432, 375_231, 897_783, null }.Select(createDisplay) + ChildrenEnumerable = new int?[] { 64, 423, 1_453, 3_468, 8_367, 48_342, 78_432, 375_231, 897_783, null }.Select(createDisplay) }; private GlobalRankDisplay createDisplay(int? rank) => new GlobalRankDisplay diff --git a/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs b/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs index 356098692558..f48d467d8771 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs @@ -75,19 +75,19 @@ private void updateState() if (percent < 0.0005) return RankingTier.Radiant; - if (percent < 0.0025) + if (percent < 0.0015) return RankingTier.Rhodium; if (percent < 0.005) return RankingTier.Platinum; - if (percent < 0.025) + if (percent < 0.015) return RankingTier.Gold; if (percent < 0.05) return RankingTier.Silver; - if (percent < 0.25) + if (percent < 0.15) return RankingTier.Bronze; if (percent < 0.5) From 55ae7e8bb81717adcf85fe9d267cbc226090f117 Mon Sep 17 00:00:00 2001 From: "Giovanni D." <37423957+GioSDA@users.noreply.github.com> Date: Thu, 6 Nov 2025 07:01:00 -0600 Subject: [PATCH 063/836] Fix timing of beatmap break overlay (#35566) Issue was bisected to [this commit](https://github.com/ppy/osu/pull/29616/commits/6f1664f0a60fc08995d737e40272b61742fbe580) This change in the commit outlined is what caused the issue: ```diff BreakOverlay = new BreakOverlay(working.Beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) { Clock = DrawableRuleset.FrameStableClock, ProcessCustomClock = false, - Breaks = working.Beatmap.Breaks + BreakTracker = breakTracker, }, ``` `BreakTracker` always initializes breaks as `new Period(b.StartTime, b.EndTime - BreakOverlay.BREAK_FADE_DURATION);` leaving room at the end to account for the fade before resuming gameplay. Because of this, changing the `BreakOverlay` to use a `BreakTracker` instead of the original beatmap breaks caused each break to be `BREAK_FADE_DURATION` shorter than it was originally - which in this case is 325ms - leading to the discrepancy between the background fadeout and the overlay fadeout. Since the current behavior is 'correct', aligning the overlay with the rest of the beatmap such as background fadeout, I changed the timing to account for the shorter duration instead of revert the overlay initialization. --- osu.Game/Screens/Play/BreakOverlay.cs | 7 +++---- osu.Game/Screens/Play/LetterboxOverlay.cs | 4 +--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/BreakOverlay.cs b/osu.Game/Screens/Play/BreakOverlay.cs index 2ae66a6dc4ba..234daece5e89 100644 --- a/osu.Game/Screens/Play/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreakOverlay.cs @@ -165,7 +165,6 @@ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, private void updateDisplay(ValueChangedEvent period) { - FinishTransforms(true); Scheduler.CancelDelayedTasks(); if (period.NewValue == null) @@ -180,12 +179,12 @@ private void updateDisplay(ValueChangedEvent period) remainingTimeAdjustmentBox .ResizeWidthTo(remaining_time_container_max_size, BREAK_FADE_DURATION, Easing.OutQuint) - .Delay(b.Duration - BREAK_FADE_DURATION) + .Delay(b.Duration) .ResizeWidthTo(0); remainingTimeBox.ResizeWidthTo(remainingTimeForCurrentPeriod); - remainingTimeCounter.CountTo(b.Duration).CountTo(0, b.Duration); + remainingTimeCounter.CountTo(b.Duration + BREAK_FADE_DURATION).CountTo(0, b.Duration + BREAK_FADE_DURATION); remainingTimeCounter.MoveToX(-50) .MoveToX(0, BREAK_FADE_DURATION, Easing.OutQuint); @@ -193,7 +192,7 @@ private void updateDisplay(ValueChangedEvent period) info.MoveToX(50) .MoveToX(0, BREAK_FADE_DURATION, Easing.OutQuint); - using (BeginDelayedSequence(b.Duration - BREAK_FADE_DURATION)) + using (BeginDelayedSequence(b.Duration)) { fadeContainer.FadeOut(BREAK_FADE_DURATION); breakArrows.Hide(BREAK_FADE_DURATION); diff --git a/osu.Game/Screens/Play/LetterboxOverlay.cs b/osu.Game/Screens/Play/LetterboxOverlay.cs index 21fc6cf19cdd..f5c762ccf2cc 100644 --- a/osu.Game/Screens/Play/LetterboxOverlay.cs +++ b/osu.Game/Screens/Play/LetterboxOverlay.cs @@ -61,8 +61,6 @@ protected override void LoadComplete() private void updateDisplay(ValueChangedEvent period) { - FinishTransforms(true); - if (period.NewValue == null) return; @@ -71,7 +69,7 @@ private void updateDisplay(ValueChangedEvent period) using (BeginAbsoluteSequence(b.Start)) { fadeContainer.FadeInFromZero(BreakOverlay.BREAK_FADE_DURATION); - using (BeginDelayedSequence(b.Duration - BreakOverlay.BREAK_FADE_DURATION)) + using (BeginDelayedSequence(b.Duration)) fadeContainer.FadeOut(BreakOverlay.BREAK_FADE_DURATION); } } From 933fbd274d0444b843c915c0791f5032456d09c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 6 Nov 2025 15:21:26 +0100 Subject: [PATCH 064/836] Fix incorrect handling of user verification failure response (#35629) `VerificationFailureResponse.RequiredSessionVerificationMethod` not being nullable means that if it was missing in the verification response, it would not be `null` but default to `TimedOneTimePassword` instead, therefore showing TOTP-related error messages to users that never enabled it rather than the user-facing message they were supposed to. Most easily tested on a local full-stack environment with ```diff diff --git a/app/Libraries/SessionVerification/MailState.php b/app/Libraries/SessionVerification/MailState.php index 305a2794ec0..3c2d15f335b 100644 --- a/app/Libraries/SessionVerification/MailState.php +++ b/app/Libraries/SessionVerification/MailState.php @@ -14,7 +14,7 @@ use Carbon\CarbonImmutable; class MailState { - private const KEY_VALID_DURATION = 600; + private const KEY_VALID_DURATION = 10; public readonly CarbonImmutable $expiresAt; public readonly string $key; ``` applied so that you don't have to wait 10 minutes to trigger the failure. --- osu.Game/Online/API/Requests/VerifySessionRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/VerifySessionRequest.cs b/osu.Game/Online/API/Requests/VerifySessionRequest.cs index d8f622348b07..88652bce7f2f 100644 --- a/osu.Game/Online/API/Requests/VerifySessionRequest.cs +++ b/osu.Game/Online/API/Requests/VerifySessionRequest.cs @@ -44,7 +44,7 @@ protected override WebRequest CreateWebRequest() private class VerificationFailureResponse { [JsonProperty("method")] - public SessionVerificationMethod RequiredSessionVerificationMethod { get; set; } + public SessionVerificationMethod? RequiredSessionVerificationMethod { get; set; } } } } From 8c28d2613046a51286b29db73435f92f4a95fa35 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 29 Oct 2025 15:40:48 +0900 Subject: [PATCH 065/836] Document `-1` as a special "random" playlist item --- osu.Game/Online/Matchmaking/IMatchmakingClient.cs | 4 ++++ osu.Game/Online/Matchmaking/IMatchmakingServer.cs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Matchmaking/IMatchmakingClient.cs b/osu.Game/Online/Matchmaking/IMatchmakingClient.cs index 70e1ce0b5da8..be05e3ca0ddc 100644 --- a/osu.Game/Online/Matchmaking/IMatchmakingClient.cs +++ b/osu.Game/Online/Matchmaking/IMatchmakingClient.cs @@ -43,11 +43,15 @@ public interface IMatchmakingClient : IStatefulUserHubClient /// /// The user has raised a candidate playlist item to be played. /// + /// The notifying user. + /// The playlist item candidate raised, or -1 as a special value that indicates a random selection. Task MatchmakingItemSelected(int userId, long playlistItemId); /// /// The user has removed a candidate playlist item. /// + /// The notifying user. + /// The playlist item candidate removed, or -1 as a special value that indicates a random selection. Task MatchmakingItemDeselected(int userId, long playlistItemId); } } diff --git a/osu.Game/Online/Matchmaking/IMatchmakingServer.cs b/osu.Game/Online/Matchmaking/IMatchmakingServer.cs index 66fd8c36da2d..7641c57fe94c 100644 --- a/osu.Game/Online/Matchmaking/IMatchmakingServer.cs +++ b/osu.Game/Online/Matchmaking/IMatchmakingServer.cs @@ -45,7 +45,7 @@ public interface IMatchmakingServer /// /// Raise a candidate playlist item to be played in the current round. /// - /// The playlist item. + /// The playlist item, or -1 to indicate a random selection. Task MatchmakingToggleSelection(long playlistItemId); /// From 3c215f6574919573e49ff6742086bd9742c22732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 7 Nov 2025 04:01:11 +0100 Subject: [PATCH 066/836] Fix retro skin changing when creating copy for skin editor (#35630) RFC, lowest effort solution for https://github.com/ppy/osu/issues/34979. The `SkinImporter` conditional *is* hella ugly, but anything less ugly will require taking a hammer to structures. Maybe passing version via the import flow, maybe even trying to make the `EnsureMutableSkin()` flow somehow attempt to read the `skin.ini` that's in resources. No idea. Properties from `skin.ini` that were defaults or that lazer can't (won't ever?) understand snipped. --- osu.Game/Skinning/RetroSkin.cs | 18 ++++++++++++++++++ osu.Game/Skinning/SkinImporter.cs | 5 +++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/RetroSkin.cs b/osu.Game/Skinning/RetroSkin.cs index abeab9ab17a6..20214dfb6720 100644 --- a/osu.Game/Skinning/RetroSkin.cs +++ b/osu.Game/Skinning/RetroSkin.cs @@ -7,6 +7,7 @@ using osu.Framework.IO.Stores; using osu.Game.Extensions; using osu.Game.IO; +using osuTK.Graphics; namespace osu.Game.Skinning { @@ -40,6 +41,23 @@ public RetroSkin(SkinInfo skin, IStorageResourceProvider resources) new NamespacedResourceStore(resources.Resources, "Skins/Retro") ) { + Configuration.ConfigDictionary[@"SliderBallFlip"] = "0"; + Configuration.ConfigDictionary[@"SliderBallFrames"] = "10"; + Configuration.ConfigDictionary[@"AllowSliderBallTint"] = "0"; + Configuration.ConfigDictionary[@"CursorTrailRotate"] = "0"; + Configuration.ConfigDictionary[@"Version"] = "1"; + + Configuration.CustomComboColours = + [ + new Color4(255, 150, 0, 255), + new Color4(5, 240, 5, 255), + new Color4(5, 5, 240, 255), + new Color4(240, 5, 5, 255) + ]; + + Configuration.ConfigDictionary[@"HitCircleOverlap"] = "3"; + Configuration.ConfigDictionary[@"ScoreOverlap"] = "3"; + Configuration.ConfigDictionary[@"ComboOverlap"] = "3"; } public override Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs index 3a50fb9f9af7..6290e3439a2f 100644 --- a/osu.Game/Skinning/SkinImporter.cs +++ b/osu.Game/Skinning/SkinImporter.cs @@ -177,9 +177,10 @@ public void UpdateSkinIniMetadata(SkinInfo item, Realm realm) if (existingFile == null) { - // skins without a skin.ini are supposed to import using the "latest version" spec. + // skins without a skin.ini are supposed to import using the "latest version" spec, unless we're making a copy of the retro skin which specifies 1.0. // see https://github.com/peppy/osu-stable-reference/blob/1531237b63392e82c003c712faa028406073aa8f/osu!/Graphics/Skinning/SkinManager.cs#L297-L298 - newLines.Add(FormattableString.Invariant($"Version: {SkinConfiguration.LATEST_VERSION}")); + decimal version = item.InstantiationInfo == typeof(RetroSkin).GetInvariantInstantiationInfo() ? 1.0M : SkinConfiguration.LATEST_VERSION; + newLines.Add(FormattableString.Invariant($"Version: {version}")); // In the case a skin doesn't have a skin.ini yet, let's create one. writeNewSkinIni(); From 1fbe1bd6c9b1b4dae23e11378fc9edef67d89337 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 7 Nov 2025 00:38:42 +0900 Subject: [PATCH 067/836] Fix selected item callback being lost --- .../Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs index 1d3153915f44..4057f2097bc1 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs @@ -109,7 +109,7 @@ public void AddItem(MultiplayerPlaylistItem item) AllowSelection = allowSelection, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Action = ItemSelected, + Action = i => ItemSelected?.Invoke(i), }; panelGridContainer.Add(panel); From b354fa44720da3a010f138248a4d694a74658aed Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 29 Oct 2025 19:38:15 +0900 Subject: [PATCH 068/836] Implement random beatmap card --- .../Matchmaking/TestSceneBeatmapSelectGrid.cs | 17 + .../TestSceneBeatmapSelectPanel.cs | 48 +- .../BeatmapSelect/BeatmapCardMatchmaking.cs | 470 ++---------------- .../BeatmapCardMatchmakingBeatmapContent.cs | 347 +++++++++++++ .../BeatmapCardMatchmakingContent.cs | 153 ++++++ .../BeatmapCardMatchmakingRandomContent.cs | 77 +++ .../Match/BeatmapSelect/BeatmapSelectGrid.cs | 19 +- .../Match/BeatmapSelect/BeatmapSelectPanel.cs | 67 +-- .../BeatmapSelect/SubScreenBeatmapSelect.cs | 14 + 9 files changed, 739 insertions(+), 473 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingBeatmapContent.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingContent.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingRandomContent.cs diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs index 4271742b1ba3..15989dd47d8a 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs @@ -197,6 +197,23 @@ public void TestPanelArrangement(int count) }); } + [Test] + public void TestPresentRandomItem() + { + AddStep("present random item panel", () => + { + grid.TransferCandidatePanelsToRollContainer(pickRandomItems(4).candidateItems.Append(-1).ToArray(), duration: 0); + grid.ArrangeItemsForRollAnimation(duration: 0, stagger: 0); + grid.PlayRollAnimation(-1, duration: 0); + + Scheduler.AddDelayed(() => grid.PresentUnanimouslyChosenBeatmap(-1), 500); + }); + + AddWaitStep("wait for animation", 5); + + AddStep("reveal beatmap", () => grid.RevealRandomItem(new MultiplayerPlaylistItem())); + } + private (long[] candidateItems, long finalItem) pickRandomItems(int count) { long[] candidateItems = items.Select(it => it.ID).ToArray(); diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs index 01f76157f120..79eb8f4443ca 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -21,6 +22,24 @@ public partial class TestSceneBeatmapSelectPanel : MultiplayerTestScene [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("join room", () => + { + var room = CreateDefaultRoom(MatchType.Matchmaking); + room.Playlist = Enumerable.Range(1, 50).Select(i => new PlaylistItem(new MultiplayerPlaylistItem + { + ID = i, + BeatmapID = 0, + StarRating = i / 10.0, + })).ToArray(); + + JoinRoom(room); + }); + } + [Test] public void TestBeatmapPanel() { @@ -58,11 +77,7 @@ public void TestBeatmapPanel() AddStep("remove peppy", () => panel!.RemoveUser(new APIUser { Id = 2 })); AddStep("remove maarvin", () => panel!.RemoveUser(new APIUser { Id = 6411631 })); - AddToggleStep("allow selection", value => - { - if (panel != null) - panel.AllowSelection = value; - }); + AddToggleStep("allow selection", value => panel!.AllowSelection = value); } [Test] @@ -100,5 +115,28 @@ public void TestFailedBeatmapLookup() }; }); } + + [Test] + public void TestRandomPanel() + { + BeatmapSelectPanel? panel = null; + + AddStep("add panel", () => + { + Child = new OsuContextMenuContainer + { + RelativeSizeAxes = Axes.Both, + Child = panel = new BeatmapSelectPanel(new MultiplayerPlaylistItem { ID = -1 }) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + }); + + AddToggleStep("allow selection", value => panel!.AllowSelection = value); + + AddStep("reveal beatmap", () => panel!.DisplayItem(new MultiplayerPlaylistItem())); + } } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmaking.cs index 1c8194d587e0..737649a3520c 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmaking.cs @@ -2,465 +2,105 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.Linq; +using System.Threading.Tasks; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Localisation; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Beatmaps.Drawables.Cards; -using osu.Game.Graphics; +using osu.Game.Database; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; -using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Overlays; -using osu.Game.Overlays.BeatmapSet; -using osu.Game.Resources.Localisation.Web; -using osuTK; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect { - public partial class BeatmapCardMatchmaking : BeatmapCard + public partial class BeatmapCardMatchmaking : OsuClickableContainer { - private readonly APIBeatmap beatmap; - - protected override Drawable IdleContent => idleBottomContent; - protected override Drawable DownloadInProgressContent => downloadProgressBar; - + public const float WIDTH = 345; public const float HEIGHT = 80; - [Cached] - private readonly BeatmapCardContent content; - - private BeatmapCardThumbnail thumbnail = null!; - private CollapsibleButtonContainer buttonContainer = null!; - - private FillFlowContainer idleBottomContent = null!; - private BeatmapCardDownloadProgressBar downloadProgressBar = null!; - - public AvatarOverlay SelectionOverlay = null!; - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; + private BeatmapLookupCache beatmapLookupCache { get; set; } = null!; - [Resolved] - private BeatmapSetOverlay? beatmapSetOverlay { get; set; } + private readonly List users = new List(); - public BeatmapCardMatchmaking(APIBeatmap beatmap) - : base(beatmap.BeatmapSet!, false) - { - this.beatmap = beatmap; - content = new BeatmapCardContent(HEIGHT); - } + private Container contentContainer = null!; + private Drawable flashLayer = null!; + private BeatmapCardMatchmakingContent? content; - [BackgroundDependencyLoader] - private void load(OsuColour colours) + public BeatmapCardMatchmaking() { Width = WIDTH; Height = HEIGHT; + } - FillFlowContainer leftIconArea = null!; - FillFlowContainer titleBadgeArea = null!; - GridContainer artistContainer = null!; - - Child = content.With(c => - { - c.MainContent = new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - thumbnail = new BeatmapCardThumbnail(BeatmapSet, BeatmapSet, keepLoaded: true) - { - Name = @"Left (icon) area", - Size = new Vector2(HEIGHT), - Padding = new MarginPadding { Right = CORNER_RADIUS }, - Child = leftIconArea = new FillFlowContainer - { - Margin = new MarginPadding(4), - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(1) - } - }, - buttonContainer = new CollapsibleButtonContainer(BeatmapSet, allowNavigationToBeatmap: false, keepBackgroundLoaded: true) - { - X = HEIGHT - CORNER_RADIUS, - Width = WIDTH - HEIGHT + CORNER_RADIUS, - FavouriteState = { BindTarget = FavouriteState }, - ButtonsCollapsedWidth = 0, - ButtonsExpandedWidth = 24, - Children = new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.AutoSize), - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new Drawable[] - { - new TruncatingSpriteText - { - Text = new RomanisableString(BeatmapSet.TitleUnicode, BeatmapSet.Title), - Font = OsuFont.Default.With(size: 18f, weight: FontWeight.SemiBold), - RelativeSizeAxes = Axes.X, - }, - titleBadgeArea = new FillFlowContainer - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - } - } - } - }, - artistContainer = new GridContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.AutoSize) - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new[] - { - new TruncatingSpriteText - { - Text = createArtistText(), - Font = OsuFont.Default.With(size: 14f, weight: FontWeight.SemiBold), - RelativeSizeAxes = Axes.X, - }, - Empty() - }, - } - }, - new LinkFlowContainer(s => - { - s.Shadow = false; - s.Font = OsuFont.GetFont(size: 11f, weight: FontWeight.SemiBold); - }).With(d => - { - d.AutoSizeAxes = Axes.Both; - d.Margin = new MarginPadding { Top = 1 }; - d.AddText("mapped by ", t => t.Colour = colourProvider.Content2); - d.AddUserLink(BeatmapSet.Author); - }), - } - }, - new Container - { - Name = @"Bottom content", - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Children = new Drawable[] - { - idleBottomContent = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 2), - AlwaysPresent = true, - Children = new Drawable[] - { - new Container - { - Masking = true, - CornerRadius = CORNER_RADIUS, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new Box - { - Colour = colours.ForStarDifficulty(beatmap.StarRating).Darken(0.8f), - RelativeSizeAxes = Axes.Both, - }, - new FillFlowContainer - { - Padding = new MarginPadding(4), - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(6, 0), - Children = new Drawable[] - { - new StarRatingDisplay(new StarDifficulty(beatmap.StarRating, 0), StarRatingDisplaySize.Small, animated: true) - { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Scale = new Vector2(0.9f), - }, - new TruncatingSpriteText - { - Text = beatmap.DifficultyName, - Font = OsuFont.Style.Caption1.With(weight: FontWeight.Bold), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - } - } - }, - } - }, - } - }, - downloadProgressBar = new BeatmapCardDownloadProgressBar - { - RelativeSizeAxes = Axes.X, - Height = 5, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - State = { BindTarget = DownloadTracker.State }, - Progress = { BindTarget = DownloadTracker.Progress } - } - } - }, - SelectionOverlay = new AvatarOverlay - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - } - } - } - } - }; - c.Expanded.BindTarget = Expanded; - }); - - if (BeatmapSet.HasVideo) - leftIconArea.Add(new VideoIconPill { IconSize = new Vector2(16) }); - - if (BeatmapSet.HasStoryboard) - leftIconArea.Add(new StoryboardIconPill { IconSize = new Vector2(16) }); - - if (BeatmapSet.FeaturedInSpotlight) - { - titleBadgeArea.Add(new SpotlightBeatmapBadge - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Margin = new MarginPadding { Left = 4 } - }); - } - - if (BeatmapSet.HasExplicitContent) + [BackgroundDependencyLoader] + private void load() + { + Children = new[] { - titleBadgeArea.Add(new ExplicitContentBeatmapBadge + contentContainer = new Container { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Margin = new MarginPadding { Left = 4 } - }); - } - - if (BeatmapSet.TrackId != null) - { - artistContainer.Content[0][1] = new FeaturedArtistBeatmapBadge + RelativeSizeAxes = Axes.Both + }, + flashLayer = new Box { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Margin = new MarginPadding { Left = 4 } - }; - } - } - - private LocalisableString createArtistText() - { - var romanisableArtist = new RomanisableString(BeatmapSet.ArtistUnicode, BeatmapSet.Artist); - return BeatmapsetsStrings.ShowDetailsByArtist(romanisableArtist); + RelativeSizeAxes = Axes.Both, + Alpha = 0 + } + }; } - protected override void UpdateState() + public void AddUser(APIUser user) { - base.UpdateState(); - - bool showDetails = IsHovered; - - buttonContainer.ShowDetails.Value = showDetails; - thumbnail.Dimmed.Value = showDetails; + users.Add(user); + content?.SelectionOverlay.AddUser(user); } - public override MenuItem[] ContextMenuItems + public void RemoveUser(APIUser user) { - get - { - List items = new List - { - new OsuMenuItem(ContextMenuStrings.ViewBeatmap, MenuItemType.Highlighted, () => beatmapSetOverlay?.FetchAndShowBeatmap(beatmap.OnlineID)) - }; - - foreach (var button in buttonContainer.Buttons) - { - if (button.Enabled.Value) - items.Add(new OsuMenuItem(button.TooltipText.ToSentence(), MenuItemType.Standard, () => button.TriggerClick())); - } - - return items.ToArray(); - } + users.Remove(user); + content?.SelectionOverlay.RemoveUser(user.Id); } - public partial class AvatarOverlay : CompositeDrawable + public void DisplayItem(MultiplayerPlaylistItem item) { - private readonly Container avatars; - - private Sample? userAddedSample; - private double? lastSamplePlayback; - - [Resolved] - private IAPIProvider api { get; set; } = null!; + Task.Run(loadBeatmap); - public AvatarOverlay() + async Task loadBeatmap() { - AutoSizeAxes = Axes.Both; + APIBeatmap? beatmap = await beatmapLookupCache.GetBeatmapAsync(item.BeatmapID).ConfigureAwait(false); - InternalChild = avatars = new Container + beatmap ??= new APIBeatmap { - AutoSizeAxes = Axes.X, - Height = SelectionAvatar.AVATAR_SIZE, + BeatmapSet = new APIBeatmapSet + { + Title = "unknown beatmap", + TitleUnicode = "unknown beatmap", + Artist = "unknown artist", + ArtistUnicode = "unknown artist", + } }; - Padding = new MarginPadding { Vertical = 5 }; - } + beatmap.StarRating = item.StarRating; - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - userAddedSample = audio.Samples.Get(@"Multiplayer/player-ready"); + loadContent(new BeatmapCardMatchmakingBeatmapContent(beatmap)); } + } - public bool AddUser(APIUser user) - { - if (avatars.Any(a => a.User.Id == user.Id)) - return false; - - var avatar = new SelectionAvatar(user, user.Equals(api.LocalUser.Value)); - - avatars.Add(avatar); - - if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > OsuGameBase.SAMPLE_DEBOUNCE_TIME) - { - userAddedSample?.Play(); - lastSamplePlayback = Time.Current; - } - - updateAvatarLayout(); - - avatar.FinishTransforms(); - - return true; - } - - public bool RemoveUser(int id) - { - if (avatars.SingleOrDefault(a => a.User.Id == id) is not SelectionAvatar avatar) - return false; - - avatar.PopOutAndExpire(); - avatars.ChangeChildDepth(avatar, float.MaxValue); - - updateAvatarLayout(); - - return true; - } - - private void updateAvatarLayout() - { - const double stagger = 30; - const float spacing = 4; - - double delay = 0; - float x = 0; - - for (int i = avatars.Count - 1; i >= 0; i--) - { - var avatar = avatars[i]; - - if (avatar.Expired) - continue; - - avatar.Delay(delay).MoveToX(x, 500, Easing.OutElasticQuarter); - - x -= avatar.LayoutSize.X + spacing; - - delay += stagger; - } - } - - public partial class SelectionAvatar : CompositeDrawable - { - public const float AVATAR_SIZE = 30; - - public APIUser User { get; } - - public bool Expired { get; private set; } - - private readonly MatchmakingAvatar avatar; - - public SelectionAvatar(APIUser user, bool isOwnUser) - { - User = user; - Size = new Vector2(AVATAR_SIZE); - - InternalChild = avatar = new MatchmakingAvatar(user, isOwnUser) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }; - } + public void DisplayRandom() => loadContent(new BeatmapCardMatchmakingRandomContent()); - protected override void LoadComplete() - { - base.LoadComplete(); + private void loadContent(BeatmapCardMatchmakingContent newContent) => Schedule(() => + { + bool flashNewContent = content != null; - avatar.ScaleTo(0) - .ScaleTo(1, 500, Easing.OutElasticHalf) - .FadeIn(200); - } + contentContainer.Child = content = newContent; - public void PopOutAndExpire() - { - avatar.ScaleTo(0, 400, Easing.OutExpo); + foreach (var user in users) + newContent.SelectionOverlay.AddUser(user); - this.FadeOut(100).Expire(); - Expired = true; - } - } - } + if (flashNewContent) + flashLayer.FadeOutFromOne(1000, Easing.In); + }); } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingBeatmapContent.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingBeatmapContent.cs new file mode 100644 index 000000000000..a5478b503517 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingBeatmapContent.cs @@ -0,0 +1,347 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Beatmaps.Drawables.Cards; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; +using osu.Game.Online; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; +using osu.Game.Overlays.BeatmapSet; +using osu.Game.Resources.Localisation.Web; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect +{ + public partial class BeatmapCardMatchmakingBeatmapContent : BeatmapCardMatchmakingContent, IHasContextMenu + { + public override AvatarOverlay SelectionOverlay => selectionOverlay; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + [Resolved] + private BeatmapSetOverlay? beatmapSetOverlay { get; set; } + + private readonly IBindable downloadState = new Bindable(); + private readonly IBindableNumber downloadProgress = new BindableDouble(); + private readonly Bindable favouriteState = new Bindable(); + private readonly APIBeatmapSet beatmapSet; + private readonly APIBeatmap beatmap; + + private BeatmapCardThumbnail thumbnail = null!; + private CollapsibleButtonContainer buttonContainer = null!; + private FillFlowContainer idleBottomContent = null!; + private BeatmapCardDownloadProgressBar downloadProgressBar = null!; + private AvatarOverlay selectionOverlay = null!; + + public BeatmapCardMatchmakingBeatmapContent(APIBeatmap beatmap) + { + this.beatmap = beatmap; + + beatmapSet = beatmap.BeatmapSet!; + favouriteState.Value = new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + FillFlowContainer leftIconArea; + FillFlowContainer titleBadgeArea; + GridContainer artistContainer; + + InternalChildren = new Drawable[] + { + new BeatmapDownloadTracker(beatmap.BeatmapSet!) + { + State = { BindTarget = downloadState }, + Progress = { BindTarget = downloadProgress }, + }, + thumbnail = new BeatmapCardThumbnail(beatmapSet, beatmapSet, keepLoaded: true) + { + Name = @"Left (icon) area", + Size = new Vector2(BeatmapCardMatchmaking.HEIGHT), + Padding = new MarginPadding { Right = BeatmapCard.CORNER_RADIUS }, + Child = leftIconArea = new FillFlowContainer + { + Margin = new MarginPadding(4), + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(1) + } + }, + buttonContainer = new CollapsibleButtonContainer(beatmapSet, allowNavigationToBeatmap: false, keepBackgroundLoaded: true) + { + X = BeatmapCardMatchmaking.HEIGHT - BeatmapCard.CORNER_RADIUS, + Width = BeatmapCard.WIDTH - BeatmapCardMatchmaking.HEIGHT + BeatmapCard.CORNER_RADIUS, + FavouriteState = { BindTarget = favouriteState }, + ButtonsCollapsedWidth = 0, + ButtonsExpandedWidth = 24, + Children = new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] + { + new TruncatingSpriteText + { + Text = new RomanisableString(beatmapSet.TitleUnicode, beatmapSet.Title), + Font = OsuFont.Default.With(size: 18f, weight: FontWeight.SemiBold), + RelativeSizeAxes = Axes.X, + }, + titleBadgeArea = new FillFlowContainer + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + } + } + } + }, + artistContainer = new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize) + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new[] + { + new TruncatingSpriteText + { + Text = BeatmapsetsStrings.ShowDetailsByArtist(new RomanisableString(beatmapSet.ArtistUnicode, beatmapSet.Artist)), + Font = OsuFont.Default.With(size: 14f, weight: FontWeight.SemiBold), + RelativeSizeAxes = Axes.X, + }, + Empty() + }, + } + }, + new LinkFlowContainer(s => + { + s.Shadow = false; + s.Font = OsuFont.GetFont(size: 11f, weight: FontWeight.SemiBold); + }).With(d => + { + d.AutoSizeAxes = Axes.Both; + d.Margin = new MarginPadding { Top = 1 }; + d.AddText("mapped by ", t => t.Colour = colourProvider.Content2); + d.AddUserLink(beatmapSet.Author); + }), + } + }, + new Container + { + Name = @"Bottom content", + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Children = new Drawable[] + { + idleBottomContent = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 2), + AlwaysPresent = true, + Children = new Drawable[] + { + new Container + { + Masking = true, + CornerRadius = BeatmapCard.CORNER_RADIUS, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + Colour = colours.ForStarDifficulty(beatmap.StarRating).Darken(0.8f), + RelativeSizeAxes = Axes.Both, + }, + new FillFlowContainer + { + Padding = new MarginPadding(4), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(6, 0), + Children = new Drawable[] + { + new StarRatingDisplay(new StarDifficulty(beatmap.StarRating, 0), StarRatingDisplaySize.Small, animated: true) + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Scale = new Vector2(0.9f), + }, + new TruncatingSpriteText + { + Text = beatmap.DifficultyName, + Font = OsuFont.Style.Caption1.With(weight: FontWeight.Bold), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + } + } + }, + } + }, + } + }, + downloadProgressBar = new BeatmapCardDownloadProgressBar + { + RelativeSizeAxes = Axes.X, + Height = 5, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + State = { BindTarget = downloadState }, + Progress = { BindTarget = downloadProgress } + } + } + }, + selectionOverlay = new AvatarOverlay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + } + } + } + }; + + if (beatmapSet.HasVideo) + leftIconArea.Add(new VideoIconPill { IconSize = new Vector2(16) }); + + if (beatmapSet.HasStoryboard) + leftIconArea.Add(new StoryboardIconPill { IconSize = new Vector2(16) }); + + if (beatmapSet.FeaturedInSpotlight) + { + titleBadgeArea.Add(new SpotlightBeatmapBadge + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Margin = new MarginPadding { Left = 4 } + }); + } + + if (beatmapSet.HasExplicitContent) + { + titleBadgeArea.Add(new ExplicitContentBeatmapBadge + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Margin = new MarginPadding { Left = 4 } + }); + } + + if (beatmapSet.TrackId != null) + { + artistContainer.Content[0][1] = new FeaturedArtistBeatmapBadge + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Margin = new MarginPadding { Left = 4 } + }; + } + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + downloadState.BindValueChanged(_ => updateState(), true); + + FinishTransforms(true); + } + + protected override bool OnHover(HoverEvent e) + { + updateState(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateState(); + base.OnHoverLost(e); + } + + private void updateState() + { + bool showDetails = IsHovered; + + buttonContainer.ShowDetails.Value = showDetails; + thumbnail.Dimmed.Value = showDetails; + + bool showProgress = downloadState.Value == DownloadState.Downloading || downloadState.Value == DownloadState.Importing; + + idleBottomContent.FadeTo(showProgress ? 0 : 1, 340, Easing.OutQuint); + downloadProgressBar.FadeTo(showProgress ? 1 : 0, 340, Easing.OutQuint); + } + + public MenuItem[] ContextMenuItems + { + get + { + List items = new List + { + new OsuMenuItem(ContextMenuStrings.ViewBeatmap, MenuItemType.Highlighted, () => beatmapSetOverlay?.FetchAndShowBeatmap(beatmap.OnlineID)) + }; + + foreach (var button in buttonContainer.Buttons) + { + if (button.Enabled.Value) + items.Add(new OsuMenuItem(button.TooltipText.ToSentence(), MenuItemType.Standard, () => button.TriggerClick())); + } + + return items.ToArray(); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingContent.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingContent.cs new file mode 100644 index 000000000000..8314174a4cd5 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingContent.cs @@ -0,0 +1,153 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect +{ + public abstract partial class BeatmapCardMatchmakingContent : CompositeDrawable + { + public abstract AvatarOverlay SelectionOverlay { get; } + + protected BeatmapCardMatchmakingContent() + { + RelativeSizeAxes = Axes.Both; + } + + public partial class AvatarOverlay : CompositeDrawable + { + private readonly Container avatars; + + private Sample? userAddedSample; + private double? lastSamplePlayback; + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + public AvatarOverlay() + { + AutoSizeAxes = Axes.Both; + + InternalChild = avatars = new Container + { + AutoSizeAxes = Axes.X, + Height = SelectionAvatar.AVATAR_SIZE, + }; + + Padding = new MarginPadding { Vertical = 5 }; + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + userAddedSample = audio.Samples.Get(@"Multiplayer/player-ready"); + } + + public bool AddUser(APIUser user) + { + if (avatars.Any(a => a.User.Id == user.Id)) + return false; + + var avatar = new SelectionAvatar(user, user.Equals(api.LocalUser.Value)); + + avatars.Add(avatar); + + if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > OsuGameBase.SAMPLE_DEBOUNCE_TIME) + { + userAddedSample?.Play(); + lastSamplePlayback = Time.Current; + } + + updateAvatarLayout(); + + avatar.FinishTransforms(); + + return true; + } + + public bool RemoveUser(int id) + { + if (avatars.SingleOrDefault(a => a.User.Id == id) is not SelectionAvatar avatar) + return false; + + avatar.PopOutAndExpire(); + avatars.ChangeChildDepth(avatar, float.MaxValue); + + updateAvatarLayout(); + + return true; + } + + private void updateAvatarLayout() + { + const double stagger = 30; + const float spacing = 4; + + double delay = 0; + float x = 0; + + for (int i = avatars.Count - 1; i >= 0; i--) + { + var avatar = avatars[i]; + + if (avatar.Expired) + continue; + + avatar.Delay(delay).MoveToX(x, 500, Easing.OutElasticQuarter); + + x -= avatar.LayoutSize.X + spacing; + + delay += stagger; + } + } + + public partial class SelectionAvatar : CompositeDrawable + { + public const float AVATAR_SIZE = 30; + + public APIUser User { get; } + + public bool Expired { get; private set; } + + private readonly MatchmakingAvatar avatar; + + public SelectionAvatar(APIUser user, bool isOwnUser) + { + User = user; + Size = new Vector2(AVATAR_SIZE); + + InternalChild = avatar = new MatchmakingAvatar(user, isOwnUser) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + avatar.ScaleTo(0) + .ScaleTo(1, 500, Easing.OutElasticHalf) + .FadeIn(200); + } + + public void PopOutAndExpire() + { + avatar.ScaleTo(0, 400, Easing.OutExpo); + + this.FadeOut(100).Expire(); + Expired = true; + } + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingRandomContent.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingRandomContent.cs new file mode 100644 index 000000000000..515456abe197 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingRandomContent.cs @@ -0,0 +1,77 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect +{ + public partial class BeatmapCardMatchmakingRandomContent : BeatmapCardMatchmakingContent + { + public override AvatarOverlay SelectionOverlay => selectionOverlay; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + private AvatarOverlay selectionOverlay = null!; + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background2, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding + { + Horizontal = 10, + Vertical = 4 + }, + Children = new Drawable[] + { + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = + [ + new SpriteIcon + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Size = new Vector2(32), + Icon = FontAwesome.Solid.Random, + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "Random", + } + ] + }, + selectionOverlay = new AvatarOverlay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + } + } + } + }; + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs index 4057f2097bc1..cb7cfae4f61e 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs @@ -69,6 +69,9 @@ public BeatmapSelectGrid() Masking = true, }, }; + + // Special item denoting a random selection. + AddItem(new MultiplayerPlaylistItem { ID = -1 }); } [BackgroundDependencyLoader] @@ -116,14 +119,6 @@ public void AddItem(MultiplayerPlaylistItem item) panelGridContainer.SetLayoutPosition(panel, (float)item.StarRating); } - public void RemoveItem(long id) - { - if (!panelLookup.Remove(id, out var panel)) - return; - - panel.Expire(); - } - public void SetUserSelection(APIUser user, long itemId, bool selected) { if (!panelLookup.TryGetValue(itemId, out var panel)) @@ -135,6 +130,14 @@ public void SetUserSelection(APIUser user, long itemId, bool selected) panel.RemoveUser(user); } + public void RevealRandomItem(MultiplayerPlaylistItem item) + { + if (!panelLookup.TryGetValue(-1, out var panel)) + return; + + panel.DisplayItem(item); + } + public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId) { Debug.Assert(candidateItemIds.Length >= 1); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectPanel.cs index aa0329ad94d0..cbd8480da467 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectPanel.cs @@ -2,10 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; -using System.Diagnostics; using osu.Framework.Allocation; -using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -13,7 +10,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Game.Beatmaps.Drawables.Cards; -using osu.Game.Database; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Overlays; @@ -37,13 +33,8 @@ public partial class BeatmapSelectPanel : Container private Container scaleContainer = null!; private Drawable lighting = null!; - private Container border = null!; - private Container mainContent = null!; - - private readonly List users = new List(); - - private BeatmapCardMatchmaking? card; + private BeatmapCardMatchmaking card = null!; public BeatmapSelectPanel(MultiplayerPlaylistItem item) { @@ -52,7 +43,7 @@ public BeatmapSelectPanel(MultiplayerPlaylistItem item) } [BackgroundDependencyLoader] - private void load(BeatmapLookupCache lookupCache, OverlayColourProvider colourProvider) + private void load(OverlayColourProvider colourProvider) { InternalChild = scaleContainer = new Container { @@ -61,7 +52,7 @@ private void load(BeatmapLookupCache lookupCache, OverlayColourProvider colourPr Origin = Anchor.Centre, Children = new[] { - mainContent = new Container + new Container { Masking = true, CornerRadius = BeatmapCard.CORNER_RADIUS, @@ -69,6 +60,14 @@ private void load(BeatmapLookupCache lookupCache, OverlayColourProvider colourPr RelativeSizeAxes = Axes.Both, Children = new[] { + card = new BeatmapCardMatchmaking + { + Action = () => + { + if (AllowSelection) + Action?.Invoke(Item); + }, + }, lighting = new Box { Blending = BlendingParameters.Additive, @@ -107,48 +106,26 @@ private void load(BeatmapLookupCache lookupCache, OverlayColourProvider colourPr }, } }; - lookupCache.GetBeatmapAsync(Item.BeatmapID).ContinueWith(b => Schedule(() => - { - Debug.Assert(card == null); - - APIBeatmap beatmap = b.GetResultSafely() ?? new APIBeatmap - { - BeatmapSet = new APIBeatmapSet - { - Title = "unknown beatmap", - TitleUnicode = "unknown beatmap", - Artist = "unknown artist", - ArtistUnicode = "unknown artist", - } - }; - beatmap.StarRating = Item.StarRating; - - mainContent.Add(card = new BeatmapCardMatchmaking(beatmap) - { - Depth = float.MaxValue, - Action = () => - { - if (AllowSelection) - Action?.Invoke(Item); - }, - }); - - foreach (var user in users) - card.SelectionOverlay.AddUser(user); - })); + if (Item.ID == -1) + card.DisplayRandom(); + else + card.DisplayItem(Item); } public void AddUser(APIUser user) { - users.Add(user); - card?.SelectionOverlay.AddUser(user); + card.AddUser(user); } public void RemoveUser(APIUser user) { - users.Remove(user); - card?.SelectionOverlay.RemoveUser(user.Id); + card.RemoveUser(user); + } + + public void DisplayItem(MultiplayerPlaylistItem item) + { + card.DisplayItem(item); } protected override bool OnHover(HoverEvent e) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs index 4b3412551763..de832587641a 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect @@ -58,6 +59,7 @@ protected override void LoadComplete() client.MatchmakingItemSelected += onItemSelected; client.MatchmakingItemDeselected += onItemDeselected; + client.SettingsChanged += onSettingsChanged; } private void onItemAdded(MultiplayerPlaylistItem item) => Scheduler.Add(() => @@ -80,6 +82,17 @@ private void onItemDeselected(int userId, long itemId) beatmapSelectGrid.SetUserSelection(user, itemId, false); } + private void onSettingsChanged(MultiplayerRoomSettings settings) + { + if (client.Room!.MatchState is not MatchmakingRoomState matchmakingState) + return; + + if (matchmakingState.CandidateItem != -1 || client.Room!.CurrentPlaylistItem.Expired) + return; + + beatmapSelectGrid.RevealRandomItem(client.Room!.CurrentPlaylistItem); + } + public void RollFinalBeatmap(long[] candidateItems, long finalItem) => beatmapSelectGrid.RollAndDisplayFinalBeatmap(candidateItems, finalItem); protected override void Dispose(bool isDisposing) @@ -91,6 +104,7 @@ protected override void Dispose(bool isDisposing) client.ItemAdded -= onItemAdded; client.MatchmakingItemSelected -= onItemSelected; client.MatchmakingItemDeselected -= onItemDeselected; + client.SettingsChanged -= onSettingsChanged; } } } From 34a3b1ba78474ef4cf9a7ebc523ab047dbb028bc Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 7 Nov 2025 17:59:02 +0900 Subject: [PATCH 069/836] Display mods in quick play beatmap cards --- .../TestSceneBeatmapSelectPanel.cs | 29 ++++++ .../BeatmapSelect/BeatmapCardMatchmaking.cs | 15 +++- .../BeatmapCardMatchmakingBeatmapContent.cs | 89 +++++++++++++------ 3 files changed, 103 insertions(+), 30 deletions(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs index 79eb8f4443ca..023b9b9743f4 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs @@ -12,6 +12,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Overlays; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect; using osu.Game.Tests.Visual.Multiplayer; @@ -138,5 +139,33 @@ public void TestRandomPanel() AddStep("reveal beatmap", () => panel!.DisplayItem(new MultiplayerPlaylistItem())); } + + [Test] + public void TestBeatmapWithMods() + { + AddStep("add panel", () => + { + BeatmapSelectPanel? panel; + + Child = new OsuContextMenuContainer + { + RelativeSizeAxes = Axes.Both, + Child = panel = new BeatmapSelectPanel(new MultiplayerPlaylistItem + { + RequiredMods = [new APIMod(new OsuModHardRock()), new APIMod(new OsuModDoubleTime())] + }) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + + panel.AddUser(new APIUser + { + Id = 2, + Username = "peppy", + }); + }); + } } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmaking.cs index 737649a3520c..96eb9dd0da07 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmaking.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -11,6 +12,8 @@ using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect { @@ -22,6 +25,9 @@ public partial class BeatmapCardMatchmaking : OsuClickableContainer [Resolved] private BeatmapLookupCache beatmapLookupCache { get; set; } = null!; + [Resolved] + private RulesetStore rulesetStore { get; set; } = null!; + private readonly List users = new List(); private Container contentContainer = null!; @@ -65,6 +71,13 @@ public void RemoveUser(APIUser user) public void DisplayItem(MultiplayerPlaylistItem item) { + Ruleset? ruleset = rulesetStore.GetRuleset(item.RulesetID)?.CreateInstance(); + + if (ruleset == null) + return; + + Mod[] mods = item.RequiredMods.Select(m => m.ToMod(ruleset)).ToArray(); + Task.Run(loadBeatmap); async Task loadBeatmap() @@ -84,7 +97,7 @@ async Task loadBeatmap() beatmap.StarRating = item.StarRating; - loadContent(new BeatmapCardMatchmakingBeatmapContent(beatmap)); + loadContent(new BeatmapCardMatchmakingBeatmapContent(beatmap, mods)); } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingBeatmapContent.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingBeatmapContent.cs index a5478b503517..e6a2dfb0559f 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingBeatmapContent.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingBeatmapContent.cs @@ -26,6 +26,8 @@ using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; using osu.Game.Resources.Localisation.Web; +using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Play.HUD; using osuTK; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect @@ -45,6 +47,7 @@ public partial class BeatmapCardMatchmakingBeatmapContent : BeatmapCardMatchmaki private readonly Bindable favouriteState = new Bindable(); private readonly APIBeatmapSet beatmapSet; private readonly APIBeatmap beatmap; + private readonly Mod[] mods; private BeatmapCardThumbnail thumbnail = null!; private CollapsibleButtonContainer buttonContainer = null!; @@ -52,9 +55,10 @@ public partial class BeatmapCardMatchmakingBeatmapContent : BeatmapCardMatchmaki private BeatmapCardDownloadProgressBar downloadProgressBar = null!; private AvatarOverlay selectionOverlay = null!; - public BeatmapCardMatchmakingBeatmapContent(APIBeatmap beatmap) + public BeatmapCardMatchmakingBeatmapContent(APIBeatmap beatmap, Mod[] mods) { this.beatmap = beatmap; + this.mods = mods; beatmapSet = beatmap.BeatmapSet!; favouriteState.Value = new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount); @@ -193,42 +197,69 @@ private void load(OsuColour colours) AlwaysPresent = true, Children = new Drawable[] { - new Container + new GridContainer { - Masking = true, - CornerRadius = BeatmapCard.CORNER_RADIUS, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Children = new Drawable[] + ColumnDimensions = new[] { - new Box - { - Colour = colours.ForStarDifficulty(beatmap.StarRating).Darken(0.8f), - RelativeSizeAxes = Axes.Both, - }, - new FillFlowContainer + new Dimension(), + new Dimension(GridSizeMode.AutoSize) + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] { - Padding = new MarginPadding(4), - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(6, 0), - Children = new Drawable[] + new Container { - new StarRatingDisplay(new StarDifficulty(beatmap.StarRating, 0), StarRatingDisplaySize.Small, animated: true) + Masking = true, + CornerRadius = BeatmapCard.CORNER_RADIUS, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Scale = new Vector2(0.9f), - }, - new TruncatingSpriteText - { - Text = beatmap.DifficultyName, - Font = OsuFont.Style.Caption1.With(weight: FontWeight.Bold), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + new Box + { + Colour = colours.ForStarDifficulty(beatmap.StarRating).Darken(0.8f), + RelativeSizeAxes = Axes.Both, + }, + new FillFlowContainer + { + Padding = new MarginPadding(4), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(6, 0), + Children = new Drawable[] + { + new StarRatingDisplay(new StarDifficulty(beatmap.StarRating, 0), StarRatingDisplaySize.Small, animated: true) + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Scale = new Vector2(0.9f), + }, + new TruncatingSpriteText + { + Text = beatmap.DifficultyName, + Font = OsuFont.Style.Caption1.With(weight: FontWeight.Bold), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + } + }, } - } + }, + new ModFlowDisplay + { + AutoSizeAxes = Axes.Both, + Scale = new Vector2(0.5f), + Margin = new MarginPadding { Left = 5 }, + Current = { Value = mods } + }, }, } }, From 8d80e2bd2c6b023b09d315fd6c456ae926625563 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 7 Nov 2025 18:35:46 +0900 Subject: [PATCH 070/836] Adjust guard to be based on current stage --- .../Match/BeatmapSelect/SubScreenBeatmapSelect.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs index de832587641a..e0db69783c17 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs @@ -87,7 +87,10 @@ private void onSettingsChanged(MultiplayerRoomSettings settings) if (client.Room!.MatchState is not MatchmakingRoomState matchmakingState) return; - if (matchmakingState.CandidateItem != -1 || client.Room!.CurrentPlaylistItem.Expired) + if (matchmakingState.Stage != MatchmakingStage.ServerBeatmapFinalised) + return; + + if (matchmakingState.CandidateItem != -1) return; beatmapSelectGrid.RevealRandomItem(client.Room!.CurrentPlaylistItem); From 04d2ce150ad5ded53dcb67ee2654bd313829ffa8 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Fri, 7 Nov 2025 14:46:40 +0300 Subject: [PATCH 071/836] Localise `WASAPI` setting --- osu.Game/Localisation/AudioSettingsStrings.cs | 15 +++++++++++++++ .../Sections/Audio/AudioDevicesSettings.cs | 9 +++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/osu.Game/Localisation/AudioSettingsStrings.cs b/osu.Game/Localisation/AudioSettingsStrings.cs index 58caea7dd4eb..37ebdd80e062 100644 --- a/osu.Game/Localisation/AudioSettingsStrings.cs +++ b/osu.Game/Localisation/AudioSettingsStrings.cs @@ -99,6 +99,21 @@ public static class AudioSettingsStrings /// public static LocalisableString AdjustBeatmapOffsetAutomaticallyTooltip => new TranslatableString(getKey(@"adjust_beatmap_offset_automatically_tooltip"), @"If enabled, the offset suggested from last play on a beatmap is automatically applied."); + /// + /// "Use experimental audio mode" + /// + public static LocalisableString WasapiLabel => new TranslatableString(getKey(@"wasapi_label"), @"Use experimental audio mode"); + + /// + /// "This will attempt to initialise the audio engine in a lower latency mode." + /// + public static LocalisableString WasapiTooltip => new TranslatableString(getKey(@"wasapi_tooltip"), @"This will attempt to initialise the audio engine in a lower latency mode."); + + /// + /// "Due to reduced latency, your audio offset will need to be adjusted when enabling this setting. Generally expect to subtract 20 - 60 ms from your known value." + /// + public static LocalisableString WasapiNotice => new TranslatableString(getKey(@"wasapi_notice"), @"Due to reduced latency, your audio offset will need to be adjusted when enabling this setting. Generally expect to subtract 20 - 60 ms from your known value."); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs index 5b5617bae013..811f6b606ac9 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs @@ -41,8 +41,8 @@ private void load() { Add(wasapiExperimental = new SettingsCheckbox { - LabelText = "Use experimental audio mode", - TooltipText = "This will attempt to initialise the audio engine in a lower latency mode.", + LabelText = AudioSettingsStrings.WasapiLabel, + TooltipText = AudioSettingsStrings.WasapiTooltip, Current = audio.UseExperimentalWasapi, Keywords = new[] { "wasapi", "latency", "exclusive" } }); @@ -64,10 +64,7 @@ private void onDeviceChanged(string _) if (wasapiExperimental != null) { if (wasapiExperimental.Current.Value) - { - wasapiExperimental.SetNoticeText( - "Due to reduced latency, your audio offset will need to be adjusted when enabling this setting. Generally expect to subtract 20 - 60 ms from your known value.", true); - } + wasapiExperimental.SetNoticeText(AudioSettingsStrings.WasapiNotice, true); else wasapiExperimental.ClearNoticeText(); } From 680614fbeef34d5d08febd2d3b7dd077de3999d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 7 Nov 2025 15:12:12 +0100 Subject: [PATCH 072/836] Fix messages from blocked users being visible in public channels (#35645) * Add failing test coverage for blocking users not removing their messages from public channels * Fix messages from blocked users being visible in public channels Closes https://github.com/ppy/osu/issues/35633. It appears that the expectation from web here is that messages from blocked users should be excised client-side. Compare: https://github.com/ppy/osu-web/blob/12dd504255bddc0cb37701c392c460222b6825db/resources/js/chat/conversation-view.tsx#L104 This implementation won't *restore* the messages after a block and unblock, but I kind of... don't care if I'm honest with you? Making that happen will result in a bunch of complications for no reason, so I'm fine waiting for anyone to complain about it. --- .../Chat/TestSceneChannelManager.cs | 59 +++++++++++++++++++ osu.Game/Online/Chat/ChannelManager.cs | 20 ++++++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Chat/TestSceneChannelManager.cs b/osu.Game.Tests/Chat/TestSceneChannelManager.cs index ef4d4f683aa5..5c7f0b0a2fe3 100644 --- a/osu.Game.Tests/Chat/TestSceneChannelManager.cs +++ b/osu.Game.Tests/Chat/TestSceneChannelManager.cs @@ -42,6 +42,7 @@ public void SetUpSteps() sentMessages = new List(); silencedUserIds = new List(); + ((DummyAPIAccess)API).LocalUserState.Blocks.Clear(); ((DummyAPIAccess)API).HandleRequest = req => { switch (req) @@ -63,6 +64,10 @@ public void SetUpSteps() silencedUserIds.Clear(); return true; + case GetMessagesRequest getMessages: + getMessages.TriggerSuccess(sentMessages); + return true; + case GetUpdatesRequest updatesRequest: updatesRequest.TriggerSuccess(new GetUpdatesResponse { @@ -161,6 +166,60 @@ public void TestCommandNameCaseInsensitivity() AddUntilStep("/help command received", () => channel.Messages.Last().Content.Contains("Supported commands")); } + [Test] + public void TestBlockedUserMessagesAreDeletedFromInitialMessageBatch() + { + Channel channel = null; + + AddStep("create channel", () => channel = createChannel(1, ChannelType.Public)); + AddStep("post a message from blocked user", () => sentMessages.Add(new Message + { + ChannelId = channel.Id, + Content = "i am blocked", + SenderId = 1234 + })); + AddStep("mark user as blocked", () => ((DummyAPIAccess)API).LocalUserState.Blocks.Add(new APIRelation + { + TargetUser = new APIUser { Username = "blocked", Id = 1234 }, + TargetID = 1234, + })); + + AddStep("join channel and select it", () => + { + channelManager.JoinChannel(channel); + channelManager.CurrentChannel.Value = channel; + }); + AddAssert("channel has no messages", () => channel.Messages, () => Is.Empty); + } + + [Test] + public void TestBlockedUserMessagesAreDeletedImmediatelyOnBlock() + { + Channel channel = null; + + AddStep("create channel", () => channel = createChannel(1, ChannelType.Public)); + + AddStep("join channel and select it", () => + { + channelManager.JoinChannel(channel); + channelManager.CurrentChannel.Value = channel; + }); + AddStep("post a message from blocked user", () => sentMessages.Add(new Message + { + ChannelId = channel.Id, + Content = "i am blocked", + SenderId = 1234 + })); + AddUntilStep("channel has message", () => channel.Messages, () => Is.Not.Empty); + + AddStep("block user", () => ((DummyAPIAccess)API).LocalUserState.Blocks.Add(new APIRelation + { + TargetUser = new APIUser { Username = "blocked", Id = 1234 }, + TargetID = 1234, + })); + AddAssert("channel has no messages", () => channel.Messages, () => Is.Empty); + } + private void handlePostMessageRequest(PostMessageRequest request) { var message = new Message(++currentMessageId) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index fde6c4db06ce..eb5d6d1b9c8a 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -70,6 +71,7 @@ public partial class ChannelManager : CompositeComponent, IChannelPostTarget private UserLookupCache users { get; set; } private readonly IBindable apiState = new Bindable(); + private readonly IBindableList localUserBlocks = new BindableList(); private ScheduledDelegate scheduledAck; private IChatClient chatClient = null!; @@ -95,6 +97,9 @@ private void load() apiState.BindTo(api.State); apiState.BindValueChanged(_ => SendAck(), true); + + localUserBlocks.BindTo(api.LocalUserState.Blocks); + localUserBlocks.BindCollectionChanged((_, args) => Schedule(() => onBlocksChanged(args))); } /// @@ -311,8 +316,9 @@ public void PostCommand(string text, Channel target = null) private void addMessages(List messages) { var channels = JoinedChannels.ToList(); + var blockedUserIds = localUserBlocks.Select(b => b.TargetID).ToList(); - foreach (var group in messages.GroupBy(m => m.ChannelId)) + foreach (var group in messages.Where(m => !blockedUserIds.Contains(m.SenderId)).GroupBy(m => m.ChannelId)) channels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); lastSilenceMessageId ??= messages.LastOrDefault()?.Id; @@ -641,6 +647,18 @@ public void MarkChannelAsRead(Channel channel) api.Queue(req); } + private void onBlocksChanged(NotifyCollectionChangedEventArgs args) + { + if (args.Action != NotifyCollectionChangedAction.Add) + return; + + foreach (APIRelation newBlock in args.NewItems!) + { + foreach (var channel in joinedChannels) + channel.RemoveMessagesFromUser(newBlock.TargetID); + } + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); From 7b55b9e4f285483d4aa3a9563d64d6394c8ecda7 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 9 Nov 2025 02:07:13 +0300 Subject: [PATCH 073/836] Change path thickness to 1px Looks better with the new path rendering --- osu.Game.Rulesets.Osu/UI/ReplayAnalysis/CursorPathContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/ReplayAnalysis/CursorPathContainer.cs b/osu.Game.Rulesets.Osu/UI/ReplayAnalysis/CursorPathContainer.cs index f23cf5129bf2..76de6c472402 100644 --- a/osu.Game.Rulesets.Osu/UI/ReplayAnalysis/CursorPathContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/ReplayAnalysis/CursorPathContainer.cs @@ -21,7 +21,7 @@ public CursorPathContainer() lifetimeManager.EntryBecameAlive += entryBecameAlive; lifetimeManager.EntryBecameDead += entryBecameDead; - PathRadius = 0.5f; + PathRadius = 1f; } [BackgroundDependencyLoader] From 1df640898fe2a43c9e2ce5956ea1e27ee7685d9d Mon Sep 17 00:00:00 2001 From: Loreos7 <86934170+Loreos7@users.noreply.github.com> Date: Sun, 9 Nov 2025 17:48:19 +0300 Subject: [PATCH 074/836] Use proper string key --- osu.Game/Localisation/CommonStrings.cs | 2 +- osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs | 2 +- osu.Game/Screens/SelectV2/PanelBeatmapSet.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 324cb424b5cc..22fc2bb24220 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -202,7 +202,7 @@ public static class CommonStrings /// /// "Delete..." /// - public static LocalisableString Delete => new TranslatableString(getKey(@"delete"), @"Delete..."); + public static LocalisableString DeleteEllipsis => new TranslatableString(getKey(@"delete_ellipsis"), @"Delete..."); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs b/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs index c93afe24a5d7..afbe2450d668 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs +++ b/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs @@ -62,7 +62,7 @@ private void load(OsuColour colours) Debug.Assert(beatmap.BeatmapSet != null); addHeader(SongSelectStrings.ForAllDifficulties, beatmap.BeatmapSet.ToString()); - addButton(CommonStrings.Delete, FontAwesome.Solid.Trash, () => SongSelect?.Delete(beatmap.BeatmapSet), colours.Red1); + addButton(CommonStrings.DeleteEllipsis, FontAwesome.Solid.Trash, () => SongSelect?.Delete(beatmap.BeatmapSet), colours.Red1); addHeader(SongSelectStrings.ForSelectedDifficulty, beatmap.DifficultyName); diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs index 3046155a5e41..71da530e18a9 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs @@ -268,7 +268,7 @@ public override MenuItem[] ContextMenuItems if (beatmapSet.Beatmaps.Any(b => b.Hidden)) items.Add(new OsuMenuItem(SongSelectStrings.RestoreAllHidden, MenuItemType.Standard, () => songSelect?.RestoreAllHidden(beatmapSet))); - items.Add(new OsuMenuItem(CommonStrings.Delete, MenuItemType.Destructive, () => songSelect?.Delete(beatmapSet))); + items.Add(new OsuMenuItem(CommonStrings.DeleteEllipsis, MenuItemType.Destructive, () => songSelect?.Delete(beatmapSet))); return items.ToArray(); } } From cd6c9405fe0c7dfa21fa69a591a71ab75706d7b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 10 Nov 2025 07:43:59 +0100 Subject: [PATCH 075/836] Fix legacy skin drum roll head circle being underneath ticks (#35647) Closes https://github.com/ppy/osu/issues/35321. --- .../Objects/Drawables/DrawableDrumRoll.cs | 33 +++++++++++++++++-- .../Skinning/Legacy/LegacyDrumRoll.cs | 16 ++------- .../Legacy/TaikoLegacySkinTransformer.cs | 6 ++++ .../TaikoSkinComponents.cs | 1 + 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 547d0afe4afd..f4dc1f18bdfc 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -40,6 +40,7 @@ public partial class DrawableDrumRoll : DrawableTaikoStrongableHitObject new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.DrumRollBody), _ => new ElongatedCirclePiece()); + private SkinnableDrawable createHeadPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.DrumRollHead), _ => Empty()) + { + RelativeSizeAxes = Axes.Y, + Depth = -2, + }; + public override bool OnPressed(KeyBindingPressEvent e) => false; private void onNewResult(DrawableHitObject obj, JudgementResult result) @@ -174,7 +187,23 @@ protected override void Update() private void updateColour(double fadeDuration = 0) { Color4 newColour = Interpolation.ValueAt((float)rollingHits / rolling_hits_for_engaged_colour, colourIdle, colourEngaged, 0, 1); - (MainPiece.Drawable as IHasAccentColour)?.FadeAccent(newColour, fadeDuration); + + if (fadeDuration == 0) + { + // fade duration is 0 when calling via `RecreatePieces()`. + // in this case we want to apply the colour *without* using transforms. + // using transforms may result in the application of colour being undone via `DrawableHitObject.UpdateState()` clearing transforms. + if (MainPiece.Drawable is IHasAccentColour mainPieceWithAccentColour) + mainPieceWithAccentColour.AccentColour = newColour; + + if (headPiece.Drawable is IHasAccentColour headPieceWithAccentColour) + headPieceWithAccentColour.AccentColour = newColour; + } + else + { + (MainPiece.Drawable as IHasAccentColour)?.FadeAccent(newColour, fadeDuration); + (headPiece.Drawable as IHasAccentColour)?.FadeAccent(newColour, fadeDuration); + } } public partial class StrongNestedHit : DrawableStrongNestedHit diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs index 78be0ef64344..34339b185dbc 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs @@ -1,7 +1,6 @@ // 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 osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -21,14 +20,10 @@ public override Quad ScreenSpaceDrawQuad { get { - // the reason why this calculation is so involved is that the head & tail sprites have different sizes/radii. - // therefore naively taking the SSDQs of them and making a quad out of them results in a trapezoid shape and not a box. - var headCentre = headCircle.ScreenSpaceDrawQuad.Centre; + var headCentre = (body.ScreenSpaceDrawQuad.TopLeft + body.ScreenSpaceDrawQuad.BottomLeft) / 2; var tailCentre = (tailCircle.ScreenSpaceDrawQuad.TopLeft + tailCircle.ScreenSpaceDrawQuad.BottomLeft) / 2; - float headRadius = headCircle.ScreenSpaceDrawQuad.Height / 2; - float tailRadius = tailCircle.ScreenSpaceDrawQuad.Height / 2; - float radius = Math.Max(headRadius, tailRadius); + float radius = body.ScreenSpaceDrawQuad.Height / 2; var rectangle = new RectangleF(headCentre.X, headCentre.Y, tailCentre.X - headCentre.X, 0).Inflate(radius); return new Quad(rectangle.TopLeft, rectangle.TopRight, rectangle.BottomLeft, rectangle.BottomRight); @@ -37,8 +32,6 @@ public override Quad ScreenSpaceDrawQuad public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => ScreenSpaceDrawQuad.Contains(screenSpacePos); - private LegacyCirclePiece headCircle = null!; - private Sprite body = null!; private Sprite tailCircle = null!; @@ -66,10 +59,6 @@ private void load(ISkinSource skin, OsuColour colours) RelativeSizeAxes = Axes.Both, Texture = skin.GetTexture("taiko-roll-middle", WrapMode.ClampToEdge, WrapMode.ClampToEdge), }, - headCircle = new LegacyCirclePiece - { - RelativeSizeAxes = Axes.Y, - }, }; AccentColour = colours.YellowDark; @@ -101,7 +90,6 @@ private void updateAccentColour() { var colour = LegacyColourCompatibility.DisallowZeroAlpha(accentColour); - headCircle.AccentColour = colour; body.Colour = colour; tailCircle.Colour = colour; } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index b5c767c2befe..73d32a79333f 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -103,6 +103,12 @@ public TaikoLegacySkinTransformer(ISkin skin) { switch (taikoComponent.Component) { + case TaikoSkinComponents.DrumRollHead: + if (GetTexture("taiko-roll-middle") != null) + return new LegacyCirclePiece(); + + return null; + case TaikoSkinComponents.DrumRollBody: if (GetTexture("taiko-roll-middle") != null) return new LegacyDrumRoll(); diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs index 28133ffcb28e..31342b30c411 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs @@ -8,6 +8,7 @@ public enum TaikoSkinComponents InputDrum, CentreHit, RimHit, + DrumRollHead, DrumRollBody, DrumRollTick, Swell, From 013de9f85d9b7652f04f329643bbee48f1fe69b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=8D=E4=BA=88?= Date: Mon, 10 Nov 2025 17:08:00 +0800 Subject: [PATCH 076/836] Add circular progress display to back-to-top button (#35625) * Show circular progress on ScrollBackButton of OverlayScrollContainer * Adjust standardization of position progress --- osu.Game/Overlays/OverlayScrollContainer.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/OverlayScrollContainer.cs b/osu.Game/Overlays/OverlayScrollContainer.cs index 957008d823d3..a197748687ee 100644 --- a/osu.Game/Overlays/OverlayScrollContainer.cs +++ b/osu.Game/Overlays/OverlayScrollContainer.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Audio; @@ -14,6 +15,7 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -36,6 +38,7 @@ public partial class OverlayScrollContainer : UserTrackingScrollContainer public ScrollBackButton Button { get; private set; } private readonly Bindable lastScrollTarget = new Bindable(); + private readonly Bindable progress = new Bindable(); [BackgroundDependencyLoader] private void load() @@ -46,7 +49,8 @@ private void load() Origin = Anchor.BottomRight, Margin = new MarginPadding(20), Action = scrollBack, - LastScrollTarget = { BindTarget = lastScrollTarget } + LastScrollTarget = { BindTarget = lastScrollTarget }, + Progress = { BindTarget = progress }, }); } @@ -54,6 +58,10 @@ protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); + // Map current position to standardized progress + float height = AvailableContent - DrawHeight; + progress.Value = height == 0 ? 1 : Math.Round(Math.Clamp(Current / height, 0, 1), 3); + if (ScrollContent.DrawHeight + button_scroll_position < DrawHeight) { Button.State = Visibility.Hidden; @@ -110,9 +118,11 @@ public Visibility State private readonly Container content; private readonly Box background; + private readonly CircularProgress currentCircularProgress; private readonly SpriteIcon spriteIcon; public Bindable LastScrollTarget = new Bindable(); + public Bindable Progress = new Bindable(); protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds(); @@ -145,6 +155,11 @@ public ScrollBackButton() { RelativeSizeAxes = Axes.Both }, + currentCircularProgress = new CircularProgress + { + RelativeSizeAxes = Axes.Both, + InnerRadius = 0.1f, + }, spriteIcon = new SpriteIcon { Anchor = Anchor.Centre, @@ -164,6 +179,7 @@ private void load(OverlayColourProvider colourProvider, AudioManager audio) IdleColour = colourProvider.Background6; HoverColour = colourProvider.Background5; flashColour = colourProvider.Light1; + currentCircularProgress.Colour = colourProvider.Highlight1; scrollToTopSample = audio.Samples.Get(@"UI/scroll-to-top"); scrollToPreviousSample = audio.Samples.Get(@"UI/scroll-to-previous"); @@ -173,6 +189,8 @@ protected override void LoadComplete() { base.LoadComplete(); + Progress.BindValueChanged(p => currentCircularProgress.Progress = p.NewValue, true); + LastScrollTarget.BindValueChanged(target => { spriteIcon.ScaleTo(target.NewValue != null ? new Vector2(1f, -1f) : Vector2.One, fade_duration, Easing.OutQuint); From c56c52882476231eaf70512e100367bb8f9de900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 10 Nov 2025 11:24:59 +0100 Subject: [PATCH 077/836] Add button for reporting issues to general settings Clicking the button opens the browser, on the "new topic" page inside the help forum. Web can now correctly read the build number of the client since https://github.com/ppy/osu-web/pull/12478 so I see no reason not to. Minimal effort implementation. Stemmed from discussion in https://discord.com/channels/90072389919997952/299846395031060480/1437368033734561792. Not really interested in putting more effort into this at this point, if this is not considered acceptable then just close the PR and this can be revisited more properly at a later date. --- osu.Game/Localisation/GeneralSettingsStrings.cs | 10 ++++++++++ osu.Game/Overlays/Settings/Sections/GeneralSection.cs | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/osu.Game/Localisation/GeneralSettingsStrings.cs b/osu.Game/Localisation/GeneralSettingsStrings.cs index 20db5983fdeb..7e4ee942869f 100644 --- a/osu.Game/Localisation/GeneralSettingsStrings.cs +++ b/osu.Game/Localisation/GeneralSettingsStrings.cs @@ -79,6 +79,16 @@ public static class GeneralSettingsStrings /// public static LocalisableString LearnMoreAboutLazerTooltip => new TranslatableString(getKey(@"check_out_the_feature_comparison"), @"Check out the feature comparison and FAQ"); + /// + /// "Report an issue" + /// + public static LocalisableString ReportIssue => new TranslatableString(getKey(@"report_issue"), @"Report an issue"); + + /// + /// "Report a problem with the game to the developers." + /// + public static LocalisableString ReportIssueTooltip => new TranslatableString(getKey(@"report_issue_tooltip"), @"Report a problem with the game to the developers."); + /// /// "Check with your package manager / provider for other release streams." /// diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index 2aa1008b1da6..848fbd9c7a72 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -45,6 +45,12 @@ private void load(OsuColour colours) BackgroundColour = colours.YellowDark, Action = () => game?.ShowWiki(@"Help_centre/Upgrading_to_lazer") }, + new SettingsButton + { + Text = GeneralSettingsStrings.ReportIssue, + TooltipText = GeneralSettingsStrings.ReportIssueTooltip, + Action = () => game?.OpenUrlExternally(@"https://osu.ppy.sh/community/forums/topics/create?forum_id=5") + }, new LanguageSettings(), new UpdateSettings(), }; From 4c72a60ee275e281204028452fe6794dbd38dcb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 11 Nov 2025 06:18:40 +0100 Subject: [PATCH 078/836] Delay seeking the current track when dragging now playing overlay progress bar until commit (#35677) RFC. Written to address https://osu.ppy.sh/community/forums/topics/2150023. Few other things we might want to happen here: - pause the track when starting the drag - figure out what to do when a drag is held while the track changes in the background (which was impossible to happen before this) but I want to see the reaction to this first. --- .../Graphics/UserInterface/ProgressBar.cs | 14 ++++++++++- osu.Game/Overlays/NowPlayingOverlay.cs | 23 +++++++++++-------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/ProgressBar.cs b/osu.Game/Graphics/UserInterface/ProgressBar.cs index 8f383c76dbe3..dcf96f04c0cc 100644 --- a/osu.Game/Graphics/UserInterface/ProgressBar.cs +++ b/osu.Game/Graphics/UserInterface/ProgressBar.cs @@ -13,6 +13,8 @@ namespace osu.Game.Graphics.UserInterface { public partial class ProgressBar : SliderBar { + public bool Seeking { get; private set; } + public Action OnSeek; private readonly Box fill; @@ -75,6 +77,16 @@ protected override void UpdateValue(float value) fill.Width = value * UsableWidth; } - protected override void OnUserChange(double value) => OnSeek?.Invoke(value); + protected override void OnUserChange(double value) + { + Seeking = true; + } + + protected override bool Commit() + { + OnSeek?.Invoke(CurrentNumber.Value); + Seeking = false; + return base.Commit(); + } } } diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index a58aa27e2433..84c279476fb7 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -304,18 +304,21 @@ protected override void Update() var track = musicController.CurrentTrack; - if (!track.IsDummyDevice) + if (!progressBar.Seeking) { - progressBar.EndTime = track.Length; - progressBar.CurrentTime = track.CurrentTime; + if (!track.IsDummyDevice) + { + progressBar.EndTime = track.Length; + progressBar.CurrentTime = track.CurrentTime; - playButton.Icon = track.IsRunning ? FontAwesome.Regular.PauseCircle : FontAwesome.Regular.PlayCircle; - } - else - { - progressBar.CurrentTime = 0; - progressBar.EndTime = 1; - playButton.Icon = FontAwesome.Regular.PlayCircle; + playButton.Icon = track.IsRunning ? FontAwesome.Regular.PauseCircle : FontAwesome.Regular.PlayCircle; + } + else + { + progressBar.CurrentTime = 0; + progressBar.EndTime = 1; + playButton.Icon = FontAwesome.Regular.PlayCircle; + } } } From 4f783f8c41a11248b9535c80b3649349623455d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 11 Nov 2025 06:20:42 +0100 Subject: [PATCH 079/836] Fix attempting to select beatmap which was just externally edited in song select crashing (#35676) Closes https://github.com/ppy/osu/issues/35651. The reproduction steps provided in the issue are too complex even. In my testing all you need to do is go into editor, replace the background via external editing, and exit out to song select; you'll immediately see loss of selection on the carousel, the set panel still using the old background, and eventually a crash when you attempt to re-select any of the difficulties of the edited set. `HandleItemsChanged()` - an optimisation aiming to reduce the number of redundant re-filters due to minor changes to realm models that aren't visible to the user anyway - ignoring changes to `BeatmapInfo.ID` after re-entering song select post-external edit meant that song select would retain stale beatmap models that no longer existed in the realm database, thus failing refetch attempts via `GetWorkingBeatmap()` or https://github.com/ppy/osu/blob/8f6f859c15bdfc9f10d5754c254fca7b9dd9bc9b/osu.Game/Screens/SelectV2/FooterButtonOptions.cs#L56-L57 --- osu.Game/Screens/SelectV2/BeatmapCarousel.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index edee63c0fad2..ee504eefc8fb 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -459,6 +459,8 @@ protected override bool HandleItemsChanged(NotifyCollectionChangedEventArgs args // - Background user tag population runs and causes a realm update. // We don't display user tags so want to ignore this. bool equalForDisplayPurposes = + // covers import-as-update flows, such as updating the beatmap with the latest online versions, or external editing inside editor + oldBeatmap.ID == newBeatmap.ID && // covers metadata changes oldBeatmap.Hash == newBeatmap.Hash && // sanity check From e1baa0362239ae63ab1618d387f67a6355a70a3a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 11 Nov 2025 18:00:15 +0900 Subject: [PATCH 080/836] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 8917bc9339f8..6f0543935bc0 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index 7e219e4b1d44..adab5435ea76 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From 5763b7dbe96cf2ce8fcf5499d7b73eff3129c610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 11 Nov 2025 10:24:11 +0100 Subject: [PATCH 081/836] Fix skin layout deserialisation eating exceptions without logging Because I just wasted 30 minutes trying to debug why a skin provided by a user in an issue thread was failing to deserialise, only to realise halfway through that the deserialisation error I was seeing was *from the fallback path and thus a complete red herring*. --- osu.Game/Skinning/Skin.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 07902106ef61..fe0ce5afbcba 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -228,8 +228,9 @@ public void UpdateDrawableTarget(SkinnableContainer targetContainer) // First attempt to deserialise using the new SkinLayoutInfo format layout = JsonConvert.DeserializeObject(jsonContent); } - catch + catch (Exception ex) { + Logger.Log($"Deserialising skin layout to {nameof(SkinLayoutInfo)} failed. Falling back to {nameof(SerialisedDrawableInfo)}[].\nDetails: {ex}"); } // If deserialisation using SkinLayoutInfo fails, attempt to deserialise using the old naked list. From cb9d9734d692e40750c597bc5d939dabbb70a39a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 11 Nov 2025 12:29:39 +0100 Subject: [PATCH 082/836] Move realm collection writes off of update thread (#35681) Probably closes https://github.com/ppy/osu/issues/35650. Realm slow, episode 23894. I can't reproduce freezes as big as the video in the issue is showing but 'realm slow' is 99% the culprit, because affected user's database is not small. --- osu.Game/Collections/CollectionDropdown.cs | 5 +++-- osu.Game/Collections/CollectionToggleMenuItem.cs | 5 +++-- .../Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 4 ++-- osu.Game/Screens/SelectV2/CollectionDropdown.cs | 5 +++-- osu.Game/Screens/SelectV2/PanelBeatmapSet.cs | 5 +++-- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/osu.Game/Collections/CollectionDropdown.cs b/osu.Game/Collections/CollectionDropdown.cs index 1e47aff3ec17..2f9e94fef7b4 100644 --- a/osu.Game/Collections/CollectionDropdown.cs +++ b/osu.Game/Collections/CollectionDropdown.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; @@ -263,11 +264,11 @@ private void addOrRemove() { Debug.Assert(collection != null); - collection.PerformWrite(c => + Task.Run(() => collection.PerformWrite(c => { if (!c.BeatmapMD5Hashes.Remove(beatmap.Value.BeatmapInfo.MD5Hash)) c.BeatmapMD5Hashes.Add(beatmap.Value.BeatmapInfo.MD5Hash); - }); + })); } protected override Drawable CreateContent() => (Content)base.CreateContent(); diff --git a/osu.Game/Collections/CollectionToggleMenuItem.cs b/osu.Game/Collections/CollectionToggleMenuItem.cs index 5ad06a72c07d..e0e278e9a386 100644 --- a/osu.Game/Collections/CollectionToggleMenuItem.cs +++ b/osu.Game/Collections/CollectionToggleMenuItem.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.Threading.Tasks; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Graphics.UserInterface; @@ -10,7 +11,7 @@ namespace osu.Game.Collections public class CollectionToggleMenuItem : ToggleMenuItem { public CollectionToggleMenuItem(Live collection, IBeatmapInfo beatmap) - : base(collection.PerformRead(c => c.Name), MenuItemType.Standard, state => + : base(collection.PerformRead(c => c.Name), MenuItemType.Standard, state => Task.Run(() => { collection.PerformWrite(c => { @@ -19,7 +20,7 @@ public CollectionToggleMenuItem(Live collection, IBeatmapInfo else c.BeatmapMD5Hashes.Remove(beatmap.MD5Hash); }); - }) + })) { State.Value = collection.PerformRead(c => c.BeatmapMD5Hashes.Contains(beatmap.MD5Hash)); } diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index c410cb7d69af..f0e024663d2f 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -328,7 +328,7 @@ private MenuItem createCollectionMenuItem(BeatmapCollection collection) return new TernaryStateToggleMenuItem(collection.Name, MenuItemType.Standard, s => { - liveCollection.PerformWrite(c => + Task.Run(() => liveCollection.PerformWrite(c => { foreach (var b in beatmapSet.Beatmaps) { @@ -346,7 +346,7 @@ private MenuItem createCollectionMenuItem(BeatmapCollection collection) break; } } - }); + })); }) { State = { Value = state } diff --git a/osu.Game/Screens/SelectV2/CollectionDropdown.cs b/osu.Game/Screens/SelectV2/CollectionDropdown.cs index a333be57761c..9f1950ac5f42 100644 --- a/osu.Game/Screens/SelectV2/CollectionDropdown.cs +++ b/osu.Game/Screens/SelectV2/CollectionDropdown.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; @@ -237,11 +238,11 @@ private void addOrRemove() { Debug.Assert(collection != null); - collection.PerformWrite(c => + Task.Run(() => collection.PerformWrite(c => { if (!c.BeatmapMD5Hashes.Remove(beatmap.Value.BeatmapInfo.MD5Hash)) c.BeatmapMD5Hashes.Add(beatmap.Value.BeatmapInfo.MD5Hash); - }); + })); } protected override Drawable CreateContent() => (Content)base.CreateContent(); diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs index 792fa90c4eb3..91645d261cde 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.LocalisationExtensions; @@ -296,7 +297,7 @@ private MenuItem createCollectionMenuItem(BeatmapCollection collection) return new TernaryStateToggleMenuItem(collection.Name, MenuItemType.Standard, s => { - liveCollection.PerformWrite(c => + Task.Run(() => liveCollection.PerformWrite(c => { foreach (var b in beatmapSet.Beatmaps) { @@ -314,7 +315,7 @@ private MenuItem createCollectionMenuItem(BeatmapCollection collection) break; } } - }); + })); }) { State = { Value = state } From 72507b80c784d03d1a72a102e953f93d2c74e7cf Mon Sep 17 00:00:00 2001 From: Kawaritai <72053972+Kawaritai@users.noreply.github.com> Date: Wed, 12 Nov 2025 06:51:55 +1100 Subject: [PATCH 083/836] Add window sizes in dropdown menu options --- .../Sections/Graphics/LayoutSettings.cs | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index f40a4c941fa2..0028d2137677 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -36,6 +36,8 @@ public partial class LayoutSettings : SettingsSubsection private Bindable scalingMode = null!; private Bindable sizeFullscreen = null!; + private Bindable sizeWindowed = null!; + private readonly BindableWithCurrent currentResolution = new BindableWithCurrent(); private readonly BindableList resolutions = new BindableList(new[] { new Size(9999, 9999) }); private readonly IBindable fullscreenCapability = new Bindable(FullscreenCapability.Capable); @@ -70,6 +72,7 @@ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, Gam scalingMode = osuConfig.GetBindable(OsuSetting.Scaling); sizeFullscreen = config.GetBindable(FrameworkSetting.SizeFullscreen); + sizeWindowed = config.GetBindable(FrameworkSetting.WindowedSize); scalingSizeX = osuConfig.GetBindable(OsuSetting.ScalingSizeX); scalingSizeY = osuConfig.GetBindable(OsuSetting.ScalingSizeY); scalingPositionX = osuConfig.GetBindable(OsuSetting.ScalingPositionX); @@ -105,7 +108,7 @@ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, Gam LabelText = GraphicsSettingsStrings.Resolution, ShowsDefaultIndicator = false, ItemSource = resolutions, - Current = sizeFullscreen + Current = currentResolution }, minimiseOnFocusLossCheckbox = new SettingsCheckbox { @@ -196,6 +199,7 @@ protected override void LoadComplete() { updateDisplaySettingsVisibility(); updateScreenModeWarning(); + updateCurrentResolutionBinding(); }, true); currentDisplay.BindValueChanged(display => Schedule(() => @@ -206,15 +210,41 @@ protected override void LoadComplete() return; } + var buffer = new Bindable(currentResolution.Value); + currentResolution.Current = buffer; + resolutions.ReplaceRange(1, resolutions.Count - 1, display.NewValue.DisplayModes .Where(m => m.Size.Width >= 800 && m.Size.Height >= 600) .OrderByDescending(m => Math.Max(m.Size.Height, m.Size.Width)) .Select(m => m.Size) .Distinct()); + updateCurrentResolutionBinding(); + updateDisplaySettingsVisibility(); }), true); + sizeWindowed.BindValueChanged(size => + { + if (windowModeDropdown.Current.Value != WindowMode.Windowed) + return; + + if (window?.WindowState == Framework.Platform.WindowState.Normal && + size.NewValue == new Size(9999, 9999) + ) + { + window.WindowState = Framework.Platform.WindowState.Maximised; + return; + } + + if (window?.WindowState == Framework.Platform.WindowState.Maximised && + size.NewValue != new Size(9999, 9999) + ) + { + window.WindowState = Framework.Platform.WindowState.Normal; + } + }); + scalingMode.BindValueChanged(_ => { scalingSettings.ClearTransforms(); @@ -223,8 +253,6 @@ protected override void LoadComplete() updateScalingModeVisibility(); }); - - // initial update bypasses transforms updateScalingModeVisibility(); void updateScalingModeVisibility() @@ -248,6 +276,20 @@ void updateScalingModeVisibility() } } + private void updateCurrentResolutionBinding() + { + switch (windowModeDropdown.Current.Value) + { + case WindowMode.Fullscreen: + currentResolution.Current = sizeFullscreen; + break; + + case WindowMode.Windowed: + currentResolution.Current = sizeWindowed; + break; + } + } + private void onDisplaysChanged(IEnumerable displays) { Scheduler.AddOnce(d => @@ -260,7 +302,9 @@ private void onDisplaysChanged(IEnumerable displays) private void updateDisplaySettingsVisibility() { - resolutionDropdown.CanBeShown.Value = resolutions.Count > 1 && windowModeDropdown.Current.Value == WindowMode.Fullscreen; + resolutionDropdown.CanBeShown.Value = resolutions.Count > 1 + && (windowModeDropdown.Current.Value == WindowMode.Fullscreen || + windowModeDropdown.Current.Value == WindowMode.Windowed); displayDropdown.CanBeShown.Value = displayDropdown.Items.Count() > 1; minimiseOnFocusLossCheckbox.CanBeShown.Value = RuntimeInfo.IsDesktop && windowModeDropdown.Current.Value == WindowMode.Fullscreen; safeAreaConsiderationsCheckbox.CanBeShown.Value = host.Window?.SafeAreaPadding.Value.Total != Vector2.Zero; From 4265e72180785fd82af0966381000d5f1ba5dee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 13 Nov 2025 06:10:24 +0100 Subject: [PATCH 084/836] Improve loading time of collection grouping mode (#35693) Supersedes / closes https://github.com/ppy/osu/pull/35687. Implements idea from https://github.com/ppy/osu/pull/35687#issuecomment-3520613982, except without the additional record, because there's no need for it. Co-authored-by: WitherFlower --- .../SelectV2/BeatmapCarouselFilterGrouping.cs | 57 ++++++++++++++----- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs b/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs index 675bb455a554..b8dd65823f4e 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs @@ -209,7 +209,7 @@ private List getGroups(List items, FilterCriteria cr case GroupMode.Collections: { var collections = GetCollections(); - return getGroupsBy(b => defineGroupByCollection(b, collections), items); + return defineGroupsByCollection(items, collections); } case GroupMode.MyMaps: @@ -396,29 +396,56 @@ private IEnumerable defineGroupBySource(string source) return new GroupDefinition(0, source).Yield(); } - private IEnumerable defineGroupByCollection(BeatmapInfo beatmap, List collections) + private List defineGroupsByCollection(List carouselItems, List allCollections) { - bool anyCollections = false; + Dictionary groupMappings = new Dictionary(); + // this is a pre-built mapping of MD5s to a list of collections in which this MD5 is found in. + // the reason to pre-build this is that `BeatmapCollection.BeatmapMD5Hashes` is a list and therefore a naive implementation would be slow, + // particularly in edge cases where most beatmaps are in more than one collection. + Dictionary> md5ToCollectionsMap = new Dictionary>(); - for (int i = 0; i < collections.Count; i++) + for (int i = 0; i < allCollections.Count; i++) { - var collection = collections[i]; - - if (collection.BeatmapMD5Hashes.Contains(beatmap.MD5Hash)) + var collection = allCollections[i]; + // NOTE: the ordering of the incoming collection list is significant and needs to be preserved. + // the fallback to ordering by name cannot be relied on. + // see xmldoc of `BeatmapCarousel.GetAllCollections()`. + var groupDefinition = new GroupDefinition(i, collection.Name); + groupMappings[groupDefinition] = new GroupMapping(groupDefinition, []); + + foreach (string md5 in collection.BeatmapMD5Hashes) { - // NOTE: the ordering of the incoming collection list is significant and needs to be preserved. - // the fallback to ordering by name cannot be relied on. - // see xmldoc of `BeatmapCarousel.GetAllCollections()`. - yield return new GroupDefinition(i, collection.Name); + if (!md5ToCollectionsMap.TryGetValue(md5, out var collections)) + md5ToCollectionsMap[md5] = collections = new List(); - anyCollections = true; + collections.Add(groupDefinition); } } - if (anyCollections) - yield break; + var notInCollection = new GroupDefinition(int.MaxValue, "Not in collection"); + groupMappings[notInCollection] = new GroupMapping(notInCollection, []); + + foreach (var item in carouselItems) + { + var beatmap = (BeatmapInfo)item.Model; + + // as a side note, even reading the `MD5Hash` off a realm model is slow if done enough times, + // so it definitely helps that thanks to the mapping it needs to only be retrieved once + if (md5ToCollectionsMap.TryGetValue(beatmap.MD5Hash, out var collections)) + { + foreach (var collection in collections) + groupMappings[collection].ItemsInGroup.Add(item); + } + else + groupMappings[notInCollection].ItemsInGroup.Add(item); + } - yield return new GroupDefinition(int.MaxValue, "Not in collection"); + return groupMappings.Values + // safety against potentially empty eagerly-initialised groups + // (could happen if user has a collection with MD5s of maps that aren't locally available) + .Where(mapping => mapping.ItemsInGroup.Count > 0) + .OrderBy(mapping => mapping.Group!.Order) + .ToList(); } private IEnumerable defineGroupByOwnMaps(BeatmapInfo beatmap, int? localUserId, string? localUserUsername) From b64abbf1f521bb0a422b18e4193fd981b16b9a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 13 Nov 2025 15:21:14 +0100 Subject: [PATCH 085/836] Alleviate song select post-filter update thread hitches by caching a model-to-carousel-item mapping (#35628) --- osu.Game/Beatmaps/BeatmapInfo.cs | 6 +++ osu.Game/Graphics/Carousel/Carousel.cs | 49 +++++++++++-------- osu.Game/Screens/SelectV2/BeatmapCarousel.cs | 44 ++++++++++------- .../SelectV2/BeatmapCarouselFilterGrouping.cs | 6 +++ 4 files changed, 68 insertions(+), 37 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index a6b40a26de78..1f4d370d13e5 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -157,6 +157,12 @@ public bool Equals(BeatmapInfo? other) public bool Equals(IBeatmapInfo? other) => other is BeatmapInfo b && Equals(b); + public override int GetHashCode() + { + // ReSharper disable once NonReadonlyMemberInGetHashCode + return ID.GetHashCode(); + } + public bool AudioEquals(BeatmapInfo? other) => other != null && BeatmapSet != null && other.BeatmapSet != null diff --git a/osu.Game/Graphics/Carousel/Carousel.cs b/osu.Game/Graphics/Carousel/Carousel.cs index 4a40862a6f3e..be1c0134784c 100644 --- a/osu.Game/Graphics/Carousel/Carousel.cs +++ b/osu.Game/Graphics/Carousel/Carousel.cs @@ -785,31 +785,19 @@ private void refreshAfterSelection() // We are performing two important operations here: // - Update all Y positions. After a selection occurs, panels may have changed visibility state and therefore Y positions. // - Link selected models to CarouselItems. If a selection changed, this is where we find the relevant CarouselItems for further use. + FindCarouselItemsForSelection(ref currentKeyboardSelection, ref currentSelection, carouselItems); + for (int i = 0; i < count; i++) { var item = carouselItems[i]; - - bool isKeyboardSelection = CheckModelEquality(item.Model, currentKeyboardSelection.Model!); - bool isSelection = CheckModelEquality(item.Model, currentSelection.Model!); - - // while we don't know the Y position of the item yet, as it's about to be updated, - // consumers (specifically `BeatmapCarousel.GetSpacingBetweenPanels()`) benefit from `CurrentSelectionItem` already pointing - // at the correct item to avoid redundant local equality checks. - // the Y positions will be filled in after they're computed. - if (isKeyboardSelection) - currentKeyboardSelection = new Selection(currentKeyboardSelection.Model, item, null, i); - - if (isSelection) - currentSelection = new Selection(currentSelection.Model, item, null, i); - updateItemYPosition(item, ref lastVisible, ref yPos); + } - if (isKeyboardSelection) - currentKeyboardSelection = currentKeyboardSelection with { YPosition = item.CarouselYPosition + item.DrawHeight / 2 }; + if (currentKeyboardSelection.CarouselItem is CarouselItem currentKeyboardSelectionItem) + currentKeyboardSelection = currentKeyboardSelection with { YPosition = currentKeyboardSelectionItem.CarouselYPosition + currentKeyboardSelectionItem.DrawHeight / 2 }; - if (isSelection) - currentSelection = currentSelection with { YPosition = item.CarouselYPosition + item.DrawHeight / 2 }; - } + if (currentSelection.CarouselItem is CarouselItem currentSelectionItem) + currentSelection = currentSelection with { YPosition = currentSelectionItem.CarouselYPosition + currentSelectionItem.DrawHeight / 2 }; // Update the total height of all items (to make the scroll container scrollable through the full height even though // most items are not displayed / loaded). @@ -821,6 +809,27 @@ private void refreshAfterSelection() Scroll.OffsetScrollPosition((float)(currentKeyboardSelection.YPosition!.Value - prevKeyboard.YPosition.Value)); } + protected virtual void FindCarouselItemsForSelection(ref Selection keyboardSelection, ref Selection selection, IList items) + { + for (int i = 0; i < items.Count; i++) + { + var item = items[i]; + + bool isKeyboardSelection = CheckModelEquality(item.Model, keyboardSelection.Model!); + bool isSelection = CheckModelEquality(item.Model, selection.Model!); + + // while we don't know the Y position of the item yet, as it's about to be updated, + // consumers (specifically `BeatmapCarousel.GetSpacingBetweenPanels()`) benefit from `CurrentSelectionItem` already pointing + // at the correct item to avoid redundant local equality checks. + // the Y positions will be filled in after they're computed. + if (isKeyboardSelection) + keyboardSelection = new Selection(keyboardSelection.Model, item, null, i); + + if (isSelection) + selection = new Selection(selection.Model, item, null, i); + } + } + #endregion #region Display handling @@ -1081,7 +1090,7 @@ protected override bool OnInvalidate(Invalidation invalidation, InvalidationSour /// A related carousel item representation for the model. May be null if selection is not present as an item, or if has not been run yet. /// The Y position of the selection as of the last run of . May be null if selection is not present as an item, or if has not been run yet. /// The index of the selection as of the last run of . May be null if selection is not present as an item, or if has not been run yet. - private record Selection(object? Model = null, CarouselItem? CarouselItem = null, double? YPosition = null, int? Index = null); + protected record Selection(object? Model = null, CarouselItem? CarouselItem = null, double? YPosition = null, int? Index = null); private record DisplayRange(int First, int Last) { diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index ee504eefc8fb..58874e79d18b 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -485,6 +485,15 @@ protected override bool HandleItemsChanged(NotifyCollectionChangedEventArgs args } } + protected override void FindCarouselItemsForSelection(ref Selection keyboardSelection, ref Selection selection, IList items) + { + if (keyboardSelection.Model != null && grouping.ItemMap.TryGetValue(keyboardSelection.Model, out var keyboardSelectionItem)) + keyboardSelection = keyboardSelection with { CarouselItem = keyboardSelectionItem.item, Index = keyboardSelectionItem.index }; + + if (selection.Model != null && grouping.ItemMap.TryGetValue(selection.Model, out var selectionItem)) + selection = selection with { CarouselItem = selectionItem.item, Index = selectionItem.index }; + } + protected override void HandleFilterCompleted() { base.HandleFilterCompleted(); @@ -499,14 +508,7 @@ protected override void HandleFilterCompleted() // The filter might have changed the set of available groups, which means that the current selection may point to a stale group. // Check whether that is the case. bool groupingRemainsOff = currentGroupedBeatmap?.Group == null && grouping.GroupItems.Count == 0; - - bool groupStillValid = false; - - if (currentGroupedBeatmap?.Group != null) - { - groupStillValid = grouping.GroupItems.TryGetValue(currentGroupedBeatmap.Group, out var items) - && items.Any(i => CheckModelEquality(i.Model, currentGroupedBeatmap)); - } + bool groupStillValid = currentGroupedBeatmap?.Group != null && grouping.ItemMap.ContainsKey(currentGroupedBeatmap); if (groupingRemainsOff || groupStillValid) { @@ -699,9 +701,8 @@ public void ExpandGroupForCurrentSelection() if (CheckModelEquality(ExpandedGroup, CurrentGroupedBeatmap.Group)) return; - var groupItem = GetCarouselItems()?.FirstOrDefault(i => CheckModelEquality(i.Model, CurrentGroupedBeatmap.Group)); - if (groupItem != null) - Activate(groupItem); + if (grouping.ItemMap.TryGetValue(CurrentGroupedBeatmap.Group, out var groupItem)) + Activate(groupItem.item); } protected override double? GetScrollTarget() @@ -712,9 +713,13 @@ public void ExpandGroupForCurrentSelection() // attempt a fallback to other possibly expanded panels (set first, then group) if (target == null) { - var items = GetCarouselItems(); - var targetItem = items?.FirstOrDefault(i => CheckModelEquality(i.Model, ExpandedBeatmapSet)) - ?? items?.FirstOrDefault(i => CheckModelEquality(i.Model, ExpandedGroup)); + CarouselItem? targetItem = null; + + if (ExpandedBeatmapSet != null && grouping.ItemMap.TryGetValue(ExpandedBeatmapSet, out var setItem)) + targetItem = setItem.item; + + if (targetItem == null && ExpandedGroup != null && grouping.ItemMap.TryGetValue(ExpandedGroup, out var groupItem)) + targetItem = groupItem.item; target = targetItem?.CarouselYPosition; } @@ -924,9 +929,6 @@ protected override bool CheckModelEquality(object? x, object? y) if (x is BeatmapInfo beatmapInfoX && y is BeatmapInfo beatmapInfoY) return beatmapInfoX.Equals(beatmapInfoY); - if (x is GroupDefinition groupX && y is GroupDefinition groupY) - return groupX.Equals(groupY); - if (x is StarDifficultyGroupDefinition starX && y is StarDifficultyGroupDefinition starY) return starX.Equals(starY); @@ -936,6 +938,14 @@ protected override bool CheckModelEquality(object? x, object? y) if (x is RankedStatusGroupDefinition statusX && y is RankedStatusGroupDefinition statusY) return statusX.Equals(statusY); + // NOTE: this branch must be AFTER all branches that compare `GroupDefinition` subtypes! + // this is an optimisation measure. any subclass of `GroupDefinition` will pass the `is GroupDefinition` check, + // and testing a subclass of `GroupDefinition` against any other `GroupDefinition` (or subclass thereof) + // will result in a casting cascade of `Equals(GroupDefinition) -> Equals(object) -> Equals(GroupDefinitionSubClass)` + // (that last one only if the type check passes) + if (x is GroupDefinition groupX && y is GroupDefinition groupY) + return groupX.Equals(groupY); + return base.CheckModelEquality(x, y); } diff --git a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs b/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs index b8dd65823f4e..280db188efa5 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs @@ -26,6 +26,8 @@ public class BeatmapCarouselFilterGrouping : ICarouselFilter /// public int BeatmapItemsCount { get; private set; } + public IDictionary ItemMap => itemMap; + /// /// Beatmap sets contain difficulties as related panels. This dictionary holds the relationships between set-difficulties to allow expanding them on selection. /// @@ -36,6 +38,7 @@ public class BeatmapCarouselFilterGrouping : ICarouselFilter /// public IDictionary> GroupItems => groupMap; + private Dictionary itemMap = new Dictionary(); private Dictionary> setMap = new Dictionary>(); private Dictionary> groupMap = new Dictionary>(); @@ -49,6 +52,7 @@ public async Task> Run(IEnumerable items, Cance return await Task.Run(() => { // preallocate space for the new mappings using last known estimates + var newItemMap = new Dictionary(itemMap.Count); var newSetMap = new Dictionary>(setMap.Count); var newGroupMap = new Dictionary>(groupMap.Count); @@ -127,6 +131,7 @@ void addItem(CarouselItem i) { newItems.Add(i); + newItemMap[i.Model] = (i, newItems.Count - 1); currentGroupItems?.Add(i); currentSetItems?.Add(i); @@ -136,6 +141,7 @@ void addItem(CarouselItem i) cancellationToken.ThrowIfCancellationRequested(); + Interlocked.Exchange(ref itemMap, newItemMap); Interlocked.Exchange(ref setMap, newSetMap); Interlocked.Exchange(ref groupMap, newGroupMap); BeatmapItemsCount = displayedBeatmapsCount; From 435cd272eaa3f291921e804255f33a3c53d92da4 Mon Sep 17 00:00:00 2001 From: Kawaritai <72053972+Kawaritai@users.noreply.github.com> Date: Fri, 14 Nov 2025 09:48:32 +1100 Subject: [PATCH 086/836] Separate fullscreen/windowed dropdowns. Center window on size change. --- .../Sections/Graphics/LayoutSettings.cs | 83 +++++++++---------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 0028d2137677..f1211e3a6068 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -37,9 +37,9 @@ public partial class LayoutSettings : SettingsSubsection private Bindable scalingMode = null!; private Bindable sizeFullscreen = null!; private Bindable sizeWindowed = null!; - private readonly BindableWithCurrent currentResolution = new BindableWithCurrent(); - private readonly BindableList resolutions = new BindableList(new[] { new Size(9999, 9999) }); + private readonly BindableList resolutionsFullscreen = new BindableList(new[] { new Size(9999, 9999) }); + private readonly BindableList resolutionsWindowed = new BindableList(); private readonly IBindable fullscreenCapability = new Bindable(FullscreenCapability.Capable); [Resolved] @@ -50,12 +50,15 @@ public partial class LayoutSettings : SettingsSubsection private IWindow? window; - private SettingsDropdown resolutionDropdown = null!; + private SettingsDropdown resolutionFullscreenDropdown = null!; + private SettingsDropdown resolutionWindowedDropdown = null!; private SettingsDropdown displayDropdown = null!; private SettingsDropdown windowModeDropdown = null!; private SettingsCheckbox minimiseOnFocusLossCheckbox = null!; private SettingsCheckbox safeAreaConsiderationsCheckbox = null!; + private Bindable windowedPositionX = null!; + private Bindable windowedPositionY = null!; private Bindable scalingPositionX = null!; private Bindable scalingPositionY = null!; private Bindable scalingSizeX = null!; @@ -73,6 +76,8 @@ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, Gam scalingMode = osuConfig.GetBindable(OsuSetting.Scaling); sizeFullscreen = config.GetBindable(FrameworkSetting.SizeFullscreen); sizeWindowed = config.GetBindable(FrameworkSetting.WindowedSize); + windowedPositionX = config.GetBindable(FrameworkSetting.WindowedPositionX); + windowedPositionY = config.GetBindable(FrameworkSetting.WindowedPositionY); scalingSizeX = osuConfig.GetBindable(OsuSetting.ScalingSizeX); scalingSizeY = osuConfig.GetBindable(OsuSetting.ScalingSizeY); scalingPositionX = osuConfig.GetBindable(OsuSetting.ScalingPositionX); @@ -103,12 +108,19 @@ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, Gam Items = window?.Displays, Current = currentDisplay, }, - resolutionDropdown = new ResolutionSettingsDropdown + resolutionFullscreenDropdown = new ResolutionSettingsDropdown { LabelText = GraphicsSettingsStrings.Resolution, ShowsDefaultIndicator = false, - ItemSource = resolutions, - Current = currentResolution + ItemSource = resolutionsFullscreen, + Current = sizeFullscreen + }, + resolutionWindowedDropdown = new ResolutionSettingsDropdown + { + LabelText = GraphicsSettingsStrings.Resolution, + ShowsDefaultIndicator = false, + ItemSource = resolutionsWindowed, + Current = sizeWindowed }, minimiseOnFocusLossCheckbox = new SettingsCheckbox { @@ -199,27 +211,31 @@ protected override void LoadComplete() { updateDisplaySettingsVisibility(); updateScreenModeWarning(); - updateCurrentResolutionBinding(); }, true); currentDisplay.BindValueChanged(display => Schedule(() => { if (display.NewValue == null) { - resolutions.Clear(); + resolutionsFullscreen.Clear(); + resolutionsWindowed.Clear(); return; } - var buffer = new Bindable(currentResolution.Value); - currentResolution.Current = buffer; + var buffer = new Bindable(sizeWindowed.Value); + resolutionWindowedDropdown.Current = buffer; + + var newResolutions = display.NewValue.DisplayModes + .Where(m => m.Size.Width >= 800 && m.Size.Height >= 600) + .OrderByDescending(m => Math.Max(m.Size.Height, m.Size.Width)) + .Select(m => m.Size) + .Distinct() + .ToList(); - resolutions.ReplaceRange(1, resolutions.Count - 1, display.NewValue.DisplayModes - .Where(m => m.Size.Width >= 800 && m.Size.Height >= 600) - .OrderByDescending(m => Math.Max(m.Size.Height, m.Size.Width)) - .Select(m => m.Size) - .Distinct()); + resolutionsFullscreen.ReplaceRange(1, resolutionsFullscreen.Count - 1, newResolutions); + resolutionsWindowed.ReplaceRange(0, resolutionsWindowed.Count, newResolutions); - updateCurrentResolutionBinding(); + resolutionWindowedDropdown.Current = sizeWindowed; updateDisplaySettingsVisibility(); }), true); @@ -229,20 +245,13 @@ protected override void LoadComplete() if (windowModeDropdown.Current.Value != WindowMode.Windowed) return; - if (window?.WindowState == Framework.Platform.WindowState.Normal && - size.NewValue == new Size(9999, 9999) - ) - { - window.WindowState = Framework.Platform.WindowState.Maximised; - return; - } - - if (window?.WindowState == Framework.Platform.WindowState.Maximised && - size.NewValue != new Size(9999, 9999) - ) + if (window?.WindowState == Framework.Platform.WindowState.Maximised) { window.WindowState = Framework.Platform.WindowState.Normal; } + + windowedPositionX.Value = 0.5; + windowedPositionY.Value = 0.5; }); scalingMode.BindValueChanged(_ => @@ -276,20 +285,6 @@ void updateScalingModeVisibility() } } - private void updateCurrentResolutionBinding() - { - switch (windowModeDropdown.Current.Value) - { - case WindowMode.Fullscreen: - currentResolution.Current = sizeFullscreen; - break; - - case WindowMode.Windowed: - currentResolution.Current = sizeWindowed; - break; - } - } - private void onDisplaysChanged(IEnumerable displays) { Scheduler.AddOnce(d => @@ -302,9 +297,9 @@ private void onDisplaysChanged(IEnumerable displays) private void updateDisplaySettingsVisibility() { - resolutionDropdown.CanBeShown.Value = resolutions.Count > 1 - && (windowModeDropdown.Current.Value == WindowMode.Fullscreen || - windowModeDropdown.Current.Value == WindowMode.Windowed); + resolutionFullscreenDropdown.CanBeShown.Value = windowModeDropdown.Current.Value == WindowMode.Fullscreen && resolutionsFullscreen.Count > 1; + resolutionWindowedDropdown.CanBeShown.Value = windowModeDropdown.Current.Value == WindowMode.Windowed && resolutionsWindowed.Count > 1; + displayDropdown.CanBeShown.Value = displayDropdown.Items.Count() > 1; minimiseOnFocusLossCheckbox.CanBeShown.Value = RuntimeInfo.IsDesktop && windowModeDropdown.Current.Value == WindowMode.Fullscreen; safeAreaConsiderationsCheckbox.CanBeShown.Value = host.Window?.SafeAreaPadding.Value.Total != Vector2.Zero; From 02b88de76e48cc940e77456920ca6ea51e740541 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 14 Nov 2025 19:20:56 +0900 Subject: [PATCH 087/836] Add SFX to the matchmaking roulette random reveal --- .../Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs index cb7cfae4f61e..967e2777b7c9 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs @@ -43,6 +43,7 @@ public partial class BeatmapSelectGrid : CompositeDrawable private readonly Sample?[] spinSamples = new Sample?[5]; private static readonly int[] spin_sample_sequence = [0, 1, 2, 3, 4, 2, 3, 4]; + private Sample? randomRevealSample; private Sample? resultSample; private Sample? swooshSample; private double? lastSamplePlayback; @@ -80,6 +81,7 @@ private void load(AudioManager audio) for (int i = 0; i < spinSamples.Length; i++) spinSamples[i] = audio.Samples.Get($@"Multiplayer/Matchmaking/Selection/roulette-{i}"); + randomRevealSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Selection/random-reveal"); resultSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Selection/roulette-result"); swooshSample = audio.Samples.Get(@"SongSelect/options-pop-out"); } @@ -136,6 +138,7 @@ public void RevealRandomItem(MultiplayerPlaylistItem item) return; panel.DisplayItem(item); + randomRevealSample?.Play(); } public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId) From 1e91dde92ecfbe9c6c0b92ab48e9a80f149dcfcf Mon Sep 17 00:00:00 2001 From: Kawaritai <72053972+Kawaritai@users.noreply.github.com> Date: Sat, 15 Nov 2025 05:43:22 +1100 Subject: [PATCH 088/836] Separate bindables and centering logic for windowed resolution changes. --- .../Sections/Graphics/LayoutSettings.cs | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index f1211e3a6068..99d47aab1fcf 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -40,6 +40,7 @@ public partial class LayoutSettings : SettingsSubsection private readonly BindableList resolutionsFullscreen = new BindableList(new[] { new Size(9999, 9999) }); private readonly BindableList resolutionsWindowed = new BindableList(); + private readonly Bindable windowedResolution = new Bindable(); private readonly IBindable fullscreenCapability = new Bindable(FullscreenCapability.Capable); [Resolved] @@ -84,6 +85,8 @@ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, Gam scalingPositionY = osuConfig.GetBindable(OsuSetting.ScalingPositionY); scalingBackgroundDim = osuConfig.GetBindable(OsuSetting.ScalingBackgroundDim); + windowedResolution.Value = sizeWindowed.Value; + if (window != null) { currentDisplay.BindTo(window.CurrentDisplayBindable); @@ -120,7 +123,7 @@ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, Gam LabelText = GraphicsSettingsStrings.Resolution, ShowsDefaultIndicator = false, ItemSource = resolutionsWindowed, - Current = sizeWindowed + Current = windowedResolution }, minimiseOnFocusLossCheckbox = new SettingsCheckbox { @@ -222,7 +225,7 @@ protected override void LoadComplete() return; } - var buffer = new Bindable(sizeWindowed.Value); + var buffer = new Bindable(windowedResolution.Value); resolutionWindowedDropdown.Current = buffer; var newResolutions = display.NewValue.DisplayModes @@ -235,16 +238,18 @@ protected override void LoadComplete() resolutionsFullscreen.ReplaceRange(1, resolutionsFullscreen.Count - 1, newResolutions); resolutionsWindowed.ReplaceRange(0, resolutionsWindowed.Count, newResolutions); - resolutionWindowedDropdown.Current = sizeWindowed; + resolutionWindowedDropdown.Current = windowedResolution; updateDisplaySettingsVisibility(); }), true); - sizeWindowed.BindValueChanged(size => + windowedResolution.BindValueChanged(size => { - if (windowModeDropdown.Current.Value != WindowMode.Windowed) + if (size.NewValue == sizeWindowed.Value || windowModeDropdown.Current.Value != WindowMode.Windowed) return; + sizeWindowed.Value = size.NewValue; + if (window?.WindowState == Framework.Platform.WindowState.Maximised) { window.WindowState = Framework.Platform.WindowState.Normal; @@ -254,6 +259,12 @@ protected override void LoadComplete() windowedPositionY.Value = 0.5; }); + sizeWindowed.BindValueChanged(size => + { + if (size.NewValue != windowedResolution.Value) + windowedResolution.Value = size.NewValue; + }); + scalingMode.BindValueChanged(_ => { scalingSettings.ClearTransforms(); From bd4ed49c067467347429480c8ee25725bd20bff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 15 Nov 2025 08:19:08 +0100 Subject: [PATCH 089/836] Fix several issues with incorrect sample playback (#35685) * Add failing test coverage for layered hit samples not playing in mania when beatmap is converted Adding the `osu.Game.Rulesets.Osu` reference to the mania test project is required so that `HitObjectSampleTest` base logic doesn't die on https://github.com/ppy/osu/blob/f0aeeeea966f06add12cf2bca3dd48dac8573e82/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs#L88-L91 * Fix layered hit sounds not playing on converted beatmaps in mania Compare https://github.com/peppy/osu-stable-reference/blob/f9e58b4864a10f801393199e7652b2192c7342c3/osu!/GameplayElements/HitObjects/HitObject.cs#L476-L477. In case of converted beatmaps, the last condition there (`BeatmapManager.Current.PlayMode != PlayModes.OsuMania`) fails, and thus layered hitsounds are allowed to play. * Add failing test coverage for mania beatmap conversion assigning wrong samples to spinners * Fix mania beatmap conversion assigning wrong samples to spinners A spinner is never `IHasRepeats`. It was a dead condition, leading to the hitobject generating fallback `NodeSamples`, which in particular feature a silent tail which stable doesn't do. Noticeably, stable also appears to force the head of the generated hold note to have no addition sounds: https://github.com/peppy/osu-stable-reference/blob/f9e58b4864a10f801393199e7652b2192c7342c3/osu!/GameplayElements/HitObjects/Mania/SpinnerMania.cs#L86-L89 * Add failing test coverage for file hit sample not falling back to plain samples if file missing * Allow `FileHitSampleInfo` to fall back to standard samples if the file is not found (or not allowed to be looked up) I'm honestly not 100% as to how closely this matches stable because I reached the point wherein I'd rather not look at stable code anymore, so as long as this passes tests I'm fine to wait for someone else to report new breakage. * Use alternative workaround for lack of osu! ruleset assembly in mania test project * Fix encode stability test failures --- .../ManiaBeatmapSampleConversionTest.cs | 1 + .../convert-beatmap-custom-sample-bank.osu | 10 ++++++++++ ...er-convert-samples-expected-conversion.json | 16 ++++++++++++++++ .../Beatmaps/spinner-convert-samples.osu | 18 ++++++++++++++++++ .../TestSceneManiaHitObjectSamples.cs | 14 ++++++++++++++ .../Patterns/Legacy/SpinnerPatternGenerator.cs | 6 +++++- .../Legacy/ManiaLegacySkinTransformer.cs | 6 ++++-- .../Gameplay/TestSceneHitObjectSamples.cs | 16 ++++++++++++++++ .../Beatmaps/Formats/LegacyBeatmapEncoder.cs | 2 +- .../Objects/Legacy/ConvertHitObjectParser.cs | 8 +++----- osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs | 4 +--- 11 files changed, 89 insertions(+), 12 deletions(-) create mode 100644 osu.Game.Rulesets.Mania.Tests/Resources/SampleLookups/convert-beatmap-custom-sample-bank.osu create mode 100644 osu.Game.Rulesets.Mania.Tests/Resources/Testing/Beatmaps/spinner-convert-samples-expected-conversion.json create mode 100644 osu.Game.Rulesets.Mania.Tests/Resources/Testing/Beatmaps/spinner-convert-samples.osu diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapSampleConversionTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapSampleConversionTest.cs index b4f084a07c9a..823538919b60 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapSampleConversionTest.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapSampleConversionTest.cs @@ -24,6 +24,7 @@ public class ManiaBeatmapSampleConversionTest : BeatmapConversionTest base.Test(name); protected override IEnumerable CreateConvertValue(HitObject hitObject) diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/SampleLookups/convert-beatmap-custom-sample-bank.osu b/osu.Game.Rulesets.Mania.Tests/Resources/SampleLookups/convert-beatmap-custom-sample-bank.osu new file mode 100644 index 000000000000..bccaf49023bf --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/Resources/SampleLookups/convert-beatmap-custom-sample-bank.osu @@ -0,0 +1,10 @@ +osu file format v14 + +[General] +Mode: 0 + +[TimingPoints] +0,300,4,0,2,100,1,0 + +[HitObjects] +444,320,1000,5,2,0:0:0:0: diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/Testing/Beatmaps/spinner-convert-samples-expected-conversion.json b/osu.Game.Rulesets.Mania.Tests/Resources/Testing/Beatmaps/spinner-convert-samples-expected-conversion.json new file mode 100644 index 000000000000..6a4ce67ec131 --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/Resources/Testing/Beatmaps/spinner-convert-samples-expected-conversion.json @@ -0,0 +1,16 @@ +{ + "Mappings": [{ + "StartTime": 1000.0, + "Objects": [{ + "StartTime": 1000.0, + "EndTime": 8000.0, + "Column": 0, + "PlaySlidingSamples": false, + "NodeSamples": [ + ["Gameplay/soft-hitnormal"], + ["Gameplay/soft-hitnormal", "Gameplay/soft-hitfinish"] + ], + "Samples": ["Gameplay/soft-hitnormal", "Gameplay/soft-hitfinish"], + }] + }] +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/Testing/Beatmaps/spinner-convert-samples.osu b/osu.Game.Rulesets.Mania.Tests/Resources/Testing/Beatmaps/spinner-convert-samples.osu new file mode 100644 index 000000000000..b68c5cc05504 --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/Resources/Testing/Beatmaps/spinner-convert-samples.osu @@ -0,0 +1,18 @@ +osu file format v14 + +[General] +Mode: 0 + +[Difficulty] +HPDrainRate:5 +CircleSize:5 +OverallDifficulty:5 +ApproachRate:5 +SliderMultiplier:1.4 +SliderTickRate:1 + +[TimingPoints] +0,500,4,2,0,100,1,0 + +[HitObjects] +256,192,1000,8,4,8000,0:2:0:0: diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs index 36ecbdb098f6..bbac75f74fe3 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs @@ -45,5 +45,19 @@ public void TestManiaHitObjectCustomSampleBank() AssertBeatmapLookup(expected_sample); AssertNoLookup(unwanted_sample); } + + [Test] + public void TestConvertHitObjectCustomSampleBank() + { + const string beatmap_sample = "normal-hitwhistle2"; + const string user_skin_sample = "normal-hitnormal"; + + SetupSkins(beatmap_sample, user_skin_sample); + + CreateTestWithBeatmap("convert-beatmap-custom-sample-bank.osu"); + + AssertBeatmapLookup(beatmap_sample); + AssertUserLookup(user_skin_sample); + } } } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/SpinnerPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/SpinnerPatternGenerator.cs index 39896d3e13ae..f2ca2888c7fb 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/SpinnerPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/SpinnerPatternGenerator.cs @@ -85,7 +85,11 @@ private void addToPattern(Pattern pattern, int column, bool holdNote) Duration = endTime - HitObject.StartTime, Column = column, Samples = HitObject.Samples, - NodeSamples = (HitObject as IHasRepeats)?.NodeSamples + NodeSamples = + [ + HitObject.Samples.Where(s => s.Name == HitSampleInfo.HIT_NORMAL).ToList(), + HitObject.Samples + ] }; } else diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index f0d8430f71e6..addb96d2c3d7 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -64,11 +64,13 @@ private static readonly IReadOnlyDictionary default_hit_resul private readonly Lazy hasKeyTexture; private readonly ManiaBeatmap beatmap; + private readonly bool isBeatmapConverted; public ManiaLegacySkinTransformer(ISkin skin, IBeatmap beatmap) : base(skin) { this.beatmap = (ManiaBeatmap)beatmap; + isBeatmapConverted = !beatmap.BeatmapInfo.Ruleset.Equals(new ManiaRuleset().RulesetInfo); isLegacySkin = new Lazy(() => GetConfig(SkinConfiguration.LegacySetting.Version) != null); hasKeyTexture = new Lazy(() => @@ -196,8 +198,8 @@ private Drawable getResult(HitResult result) public override ISample GetSample(ISampleInfo sampleInfo) { - // layered hit sounds never play in mania - if (sampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacySample && legacySample.IsLayered) + // layered hit sounds never play in mania-native beatmaps (but do play on converts) + if (sampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacySample && legacySample.IsLayered && !isBeatmapConverted) return new SampleVirtual(); return base.GetSample(sampleInfo); diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs index c9f5f5023240..20d63b9bb471 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs @@ -126,6 +126,22 @@ public void TestFileSampleFromBeatmap() AssertBeatmapLookup(expected_sample); } + /// + /// Tests that a hitobject which specifies a specific sample file which doesn't exist (or isn't allowed to be looked up) + /// falls back to a normal sample. + /// + [Test] + public void TestFileSampleFallsBackToNormal() + { + const string expected_sample = "normal-hitnormal"; + + SetupSkins(null, expected_sample); + + CreateTestWithBeatmap("file-beatmap-sample.osu"); + + AssertUserLookup(expected_sample); + } + /// /// Tests that a default hitobject and control point causes . /// diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index cfca40104f10..24976717c1e5 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -544,7 +544,7 @@ private string getSampleBank(IList samples, bool banksOnly = fals if (!banksOnly) { int customSampleBank = toLegacyCustomSampleBank(samples.FirstOrDefault(s => !string.IsNullOrEmpty(s.Name))); - string sampleFilename = samples.FirstOrDefault(s => string.IsNullOrEmpty(s.Name))?.LookupNames.First() ?? string.Empty; + string sampleFilename = samples.FirstOrDefault(s => s is ConvertHitObjectParser.FileHitSampleInfo)?.LookupNames.First() ?? string.Empty; int volume = samples.FirstOrDefault()?.Volume ?? 100; // We want to ignore custom sample banks and volume when not encoding to the mania game mode, diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 243f79d9060d..0a6ef82b77f7 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -550,7 +550,6 @@ private List convertSoundType(LegacyHitSoundType type, SampleBank } else { - // Todo: This should set the normal SampleInfo if the specified sample file isn't found, but that's a pretty edge-case scenario soundTypes.Add(new FileHitSampleInfo(bankInfo.Filename, bankInfo.Volume)); } @@ -680,14 +679,13 @@ public override bool Equals(object? obj) public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), CustomSampleBank, IsLayered); } - private class FileHitSampleInfo : LegacyHitSampleInfo, IEquatable + public class FileHitSampleInfo : LegacyHitSampleInfo, IEquatable { public readonly string Filename; public FileHitSampleInfo(string filename, int volume) // Force CSS=1 to make sure that the LegacyBeatmapSkin does not fall back to the user skin. - // Note that this does not change the lookup names, as they are overridden locally. - : base(string.Empty, customSampleBank: 1, volume: volume) + : base(HIT_NORMAL, SampleControlPoint.DEFAULT_BANK, customSampleBank: 1, volume: volume) { Filename = filename; } @@ -696,7 +694,7 @@ public FileHitSampleInfo(string filename, int volume) { Filename, Path.ChangeExtension(Filename, null) - }; + }.Concat(base.LookupNames); public sealed override LegacyHitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newVolume = default, Optional newEditorAutoBank = default, Optional newCustomSampleBank = default, Optional newIsLayered = default) diff --git a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs index 1f491be7e3e5..85c436e9c8e5 100644 --- a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs +++ b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs @@ -86,9 +86,7 @@ protected void CreateTestWithBeatmap(string filename) currentTestBeatmap = Decoder.GetDecoder(reader).Decode(reader); // populate ruleset for beatmap converters that require it to be present. - var ruleset = rulesetStore.GetRuleset(currentTestBeatmap.BeatmapInfo.Ruleset.OnlineID); - - Debug.Assert(ruleset != null); + var ruleset = rulesetStore.GetRuleset(currentTestBeatmap.BeatmapInfo.Ruleset.OnlineID) ?? new RulesetInfo { OnlineID = currentTestBeatmap.BeatmapInfo.Ruleset.OnlineID }; currentTestBeatmap.BeatmapInfo.Ruleset = ruleset; }); From 1c30cb8371a23c40465825fc3ef6ee922e511213 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 16 Nov 2025 20:22:21 +0900 Subject: [PATCH 090/836] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6b4b91d14d80..9925cf217ea6 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From ce5e54c9d27b17d460d99e774de502f9480fb710 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 17 Nov 2025 13:33:59 +0900 Subject: [PATCH 091/836] Fix various screens not registering themselves as `IPreviewTrackOwner` --- .../Visual/Components/TestScenePreviewTrackManager.cs | 9 ++++++--- osu.Game/Audio/IPreviewTrackOwner.cs | 3 +++ .../Graphics/Containers/OsuFocusedOverlayContainer.cs | 1 - .../Screens/OnlinePlay/DailyChallenge/DailyChallenge.cs | 1 - osu.Game/Screens/Play/SoloSpectatorScreen.cs | 1 - 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs index b334616125b2..3cce3782477d 100644 --- a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs +++ b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs @@ -220,10 +220,13 @@ private void load() protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { - var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); if (registerAsOwner) - dependencies.CacheAs(this); - return dependencies; + { + // Automatically handled by interface caching. + return base.CreateChildDependencies(parent); + } + + return new DependencyContainer(); } } diff --git a/osu.Game/Audio/IPreviewTrackOwner.cs b/osu.Game/Audio/IPreviewTrackOwner.cs index 8ab93257a5fd..e9653aad225d 100644 --- a/osu.Game/Audio/IPreviewTrackOwner.cs +++ b/osu.Game/Audio/IPreviewTrackOwner.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; + namespace osu.Game.Audio { /// @@ -10,6 +12,7 @@ namespace osu.Game.Audio /// s can cancel the currently playing through the /// global if they're the owner of the playing . /// + [Cached] public interface IPreviewTrackOwner { } diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 1945b2f0dde6..3c530a3aced3 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -15,7 +15,6 @@ namespace osu.Game.Graphics.Containers { - [Cached(typeof(IPreviewTrackOwner))] public abstract partial class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner, IKeyBindingHandler { protected readonly IBindable OverlayActivationMode = new Bindable(OverlayActivation.All); diff --git a/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallenge.cs b/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallenge.cs index 893bc4eb5c90..c3648a7edfa1 100644 --- a/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallenge.cs +++ b/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallenge.cs @@ -44,7 +44,6 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge { - [Cached(typeof(IPreviewTrackOwner))] public partial class DailyChallenge : OsuScreen, IPreviewTrackOwner, IHandlePresentBeatmap { private readonly Room room; diff --git a/osu.Game/Screens/Play/SoloSpectatorScreen.cs b/osu.Game/Screens/Play/SoloSpectatorScreen.cs index 75f8da707cc4..e54cde4b0a94 100644 --- a/osu.Game/Screens/Play/SoloSpectatorScreen.cs +++ b/osu.Game/Screens/Play/SoloSpectatorScreen.cs @@ -30,7 +30,6 @@ namespace osu.Game.Screens.Play { - [Cached(typeof(IPreviewTrackOwner))] public partial class SoloSpectatorScreen : SpectatorScreen, IPreviewTrackOwner { [Resolved] From 8b778e8106b509f4affabdb6b7682bf5dbc658bc Mon Sep 17 00:00:00 2001 From: maarvin Date: Mon, 17 Nov 2025 06:11:07 +0100 Subject: [PATCH 092/836] Split quickplay beatmap & "random" panel into separate classes (V2) (#35701) * Load all beatmaps in bulk for SubScreenBeatmapSelect * Fix tests no longer working due to drawable changes * Remove test that no longer makes sense * Split matchmaking panel into subclasses for each panel type * Adjust tests to match new structure * Add `ConfigureAwait` * Display loading spinner while beatmaps are being fetched * Fix test failure * Load playlist items directly in `LoadComplete` * Convert `MatchmakingSelectPanel` card content classes into nested classes * Wait for panels to be loaded before operating on them * Add ConfigureAwait() --------- Co-authored-by: Dan Balasescu --- .../Matchmaking/TestSceneBeatmapSelectGrid.cs | 60 ++- .../TestSceneBeatmapSelectPanel.cs | 55 +-- .../BeatmapSelect/BeatmapCardMatchmaking.cs | 119 ------ .../BeatmapCardMatchmakingBeatmapContent.cs | 378 ----------------- .../BeatmapCardMatchmakingContent.cs | 153 ------- .../BeatmapCardMatchmakingRandomContent.cs | 77 ---- .../Match/BeatmapSelect/BeatmapSelectGrid.cs | 91 +++-- .../BeatmapSelect/MatchmakingPlaylistItem.cs | 14 + .../MatchmakingSelectPanel.CardContent.cs | 156 +++++++ ...tchmakingSelectPanel.CardContentBeatmap.cs | 381 ++++++++++++++++++ ...atchmakingSelectPanel.CardContentRandom.cs | 80 ++++ ...lectPanel.cs => MatchmakingSelectPanel.cs} | 134 +++--- .../MatchmakingSelectPanelBeatmap.cs | 40 ++ .../MatchmakingSelectPanelRandom.cs | 60 +++ .../BeatmapSelect/SubScreenBeatmapSelect.cs | 81 +++- 15 files changed, 963 insertions(+), 916 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmaking.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingBeatmapContent.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingContent.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingRandomContent.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingPlaylistItem.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContent.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs rename osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/{BeatmapSelectPanel.cs => MatchmakingSelectPanel.cs} (56%) create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelBeatmap.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs index 15989dd47d8a..0e5e5b8aae04 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs @@ -2,17 +2,20 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; +using osu.Game.Rulesets.Mods; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect; using osu.Game.Tests.Visual.OnlinePlay; using osuTK; @@ -21,7 +24,7 @@ namespace osu.Game.Tests.Visual.Matchmaking { public partial class TestSceneBeatmapSelectGrid : OnlinePlayTestScene { - private MultiplayerPlaylistItem[] items = null!; + private MatchmakingPlaylistItem[] items = null!; private BeatmapSelectGrid grid = null!; @@ -36,24 +39,44 @@ private void load() .Take(50) .ToArray(); + IEnumerable playlistItems; + if (beatmaps.Length > 0) { - items = Enumerable.Range(1, 50).Select(i => new MultiplayerPlaylistItem + playlistItems = Enumerable.Range(1, 50).Select(i => { - ID = i, - BeatmapID = beatmaps[i % beatmaps.Length].OnlineID, - StarRating = i / 10.0, - }).ToArray(); + var beatmap = beatmaps[i % beatmaps.Length]; + + return new MatchmakingPlaylistItem( + new MultiplayerPlaylistItem + { + ID = i, + BeatmapID = beatmap.OnlineID, + StarRating = i / 10.0, + }, + CreateAPIBeatmap(beatmap), + Array.Empty() + ); + }); } else { - items = Enumerable.Range(1, 50).Select(i => new MultiplayerPlaylistItem - { - ID = i, - BeatmapID = i, - StarRating = i / 10.0, - }).ToArray(); + playlistItems = Enumerable.Range(1, 50).Select(i => new MatchmakingPlaylistItem( + new MultiplayerPlaylistItem + { + ID = i, + BeatmapID = i, + StarRating = i / 10.0, + }, + CreateAPIBeatmap(), + Array.Empty() + )); } + + foreach (var item in playlistItems) + item.Beatmap.StarRating = item.PlaylistItem.StarRating; + + items = playlistItems.ToArray(); } public override void SetUpSteps() @@ -70,8 +93,7 @@ public override void SetUpSteps() AddStep("add items", () => { - foreach (var item in items) - grid.AddItem(item); + grid.AddItems(items); }); AddWaitStep("wait for panels", 3); @@ -85,17 +107,17 @@ public void TestBasic() // test scene is weird. }); - AddStep("add selection 1", () => grid.ChildrenOfType().First().AddUser(new APIUser + AddStep("add selection 1", () => grid.ChildrenOfType().First().AddUser(new APIUser { Id = DummyAPIAccess.DUMMY_USER_ID, Username = "Maarvin", })); - AddStep("add selection 2", () => grid.ChildrenOfType().Skip(5).First().AddUser(new APIUser + AddStep("add selection 2", () => grid.ChildrenOfType().Skip(5).First().AddUser(new APIUser { Id = 2, Username = "peppy", })); - AddStep("add selection 3", () => grid.ChildrenOfType().Skip(10).First().AddUser(new APIUser + AddStep("add selection 3", () => grid.ChildrenOfType().Skip(10).First().AddUser(new APIUser { Id = 1040328, Username = "smoogipoo", @@ -180,7 +202,7 @@ public void TestPanelArrangement(int count) AddStep("display roll order", () => { - var panels = grid.ChildrenOfType().ToArray(); + var panels = grid.ChildrenOfType().ToArray(); for (int i = 0; i < panels.Length; i++) { @@ -211,7 +233,7 @@ public void TestPresentRandomItem() AddWaitStep("wait for animation", 5); - AddStep("reveal beatmap", () => grid.RevealRandomItem(new MultiplayerPlaylistItem())); + AddStep("reveal beatmap", () => grid.RevealRandomItem(items[RNG.Next(items.Length)].PlaylistItem)); } private (long[] candidateItems, long finalItem) pickRandomItems(int count) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs index 023b9b9743f4..9ac64288ed5d 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs @@ -1,14 +1,12 @@ // 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.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics.Cursor; using osu.Game.Online.API; -using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Overlays; @@ -44,14 +42,14 @@ public override void SetUpSteps() [Test] public void TestBeatmapPanel() { - BeatmapSelectPanel? panel = null; + MatchmakingSelectPanel? panel = null; AddStep("add panel", () => { Child = new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, - Child = panel = new BeatmapSelectPanel(new MultiplayerPlaylistItem()) + Child = panel = new MatchmakingSelectPanelBeatmap(new MatchmakingPlaylistItem(new MultiplayerPlaylistItem(), CreateAPIBeatmap(), [])) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -81,53 +79,17 @@ public void TestBeatmapPanel() AddToggleStep("allow selection", value => panel!.AllowSelection = value); } - [Test] - public void TestFailedBeatmapLookup() - { - AddStep("setup request handle", () => - { - var api = (DummyAPIAccess)API; - var handler = api.HandleRequest; - api.HandleRequest = req => - { - switch (req) - { - case GetBeatmapRequest: - case GetBeatmapsRequest: - req.TriggerFailure(new InvalidOperationException()); - return false; - - default: - return handler?.Invoke(req) ?? false; - } - }; - }); - - AddStep("add panel", () => - { - Child = new OsuContextMenuContainer - { - RelativeSizeAxes = Axes.Both, - Child = new BeatmapSelectPanel(new MultiplayerPlaylistItem()) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - }; - }); - } - [Test] public void TestRandomPanel() { - BeatmapSelectPanel? panel = null; + MatchmakingSelectPanelRandom? panel = null; AddStep("add panel", () => { Child = new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, - Child = panel = new BeatmapSelectPanel(new MultiplayerPlaylistItem { ID = -1 }) + Child = panel = new MatchmakingSelectPanelRandom(new MultiplayerPlaylistItem { ID = -1 }) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -137,7 +99,7 @@ public void TestRandomPanel() AddToggleStep("allow selection", value => panel!.AllowSelection = value); - AddStep("reveal beatmap", () => panel!.DisplayItem(new MultiplayerPlaylistItem())); + AddStep("reveal beatmap", () => panel!.RevealBeatmap(CreateAPIBeatmap(), [])); } [Test] @@ -145,15 +107,12 @@ public void TestBeatmapWithMods() { AddStep("add panel", () => { - BeatmapSelectPanel? panel; + MatchmakingSelectPanel? panel; Child = new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, - Child = panel = new BeatmapSelectPanel(new MultiplayerPlaylistItem - { - RequiredMods = [new APIMod(new OsuModHardRock()), new APIMod(new OsuModDoubleTime())] - }) + Child = panel = new MatchmakingSelectPanelBeatmap(new MatchmakingPlaylistItem(new MultiplayerPlaylistItem(), CreateAPIBeatmap(), [new OsuModHardRock(), new OsuModDoubleTime()])) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmaking.cs deleted file mode 100644 index 96eb9dd0da07..000000000000 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmaking.cs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Database; -using osu.Game.Graphics.Containers; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Online.Rooms; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; - -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect -{ - public partial class BeatmapCardMatchmaking : OsuClickableContainer - { - public const float WIDTH = 345; - public const float HEIGHT = 80; - - [Resolved] - private BeatmapLookupCache beatmapLookupCache { get; set; } = null!; - - [Resolved] - private RulesetStore rulesetStore { get; set; } = null!; - - private readonly List users = new List(); - - private Container contentContainer = null!; - private Drawable flashLayer = null!; - private BeatmapCardMatchmakingContent? content; - - public BeatmapCardMatchmaking() - { - Width = WIDTH; - Height = HEIGHT; - } - - [BackgroundDependencyLoader] - private void load() - { - Children = new[] - { - contentContainer = new Container - { - RelativeSizeAxes = Axes.Both - }, - flashLayer = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0 - } - }; - } - - public void AddUser(APIUser user) - { - users.Add(user); - content?.SelectionOverlay.AddUser(user); - } - - public void RemoveUser(APIUser user) - { - users.Remove(user); - content?.SelectionOverlay.RemoveUser(user.Id); - } - - public void DisplayItem(MultiplayerPlaylistItem item) - { - Ruleset? ruleset = rulesetStore.GetRuleset(item.RulesetID)?.CreateInstance(); - - if (ruleset == null) - return; - - Mod[] mods = item.RequiredMods.Select(m => m.ToMod(ruleset)).ToArray(); - - Task.Run(loadBeatmap); - - async Task loadBeatmap() - { - APIBeatmap? beatmap = await beatmapLookupCache.GetBeatmapAsync(item.BeatmapID).ConfigureAwait(false); - - beatmap ??= new APIBeatmap - { - BeatmapSet = new APIBeatmapSet - { - Title = "unknown beatmap", - TitleUnicode = "unknown beatmap", - Artist = "unknown artist", - ArtistUnicode = "unknown artist", - } - }; - - beatmap.StarRating = item.StarRating; - - loadContent(new BeatmapCardMatchmakingBeatmapContent(beatmap, mods)); - } - } - - public void DisplayRandom() => loadContent(new BeatmapCardMatchmakingRandomContent()); - - private void loadContent(BeatmapCardMatchmakingContent newContent) => Schedule(() => - { - bool flashNewContent = content != null; - - contentContainer.Child = content = newContent; - - foreach (var user in users) - newContent.SelectionOverlay.AddUser(user); - - if (flashNewContent) - flashLayer.FadeOutFromOne(1000, Easing.In); - }); - } -} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingBeatmapContent.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingBeatmapContent.cs deleted file mode 100644 index e6a2dfb0559f..000000000000 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingBeatmapContent.cs +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Extensions.LocalisationExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Beatmaps.Drawables.Cards; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; -using osu.Game.Online; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Overlays; -using osu.Game.Overlays.BeatmapSet; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Play.HUD; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect -{ - public partial class BeatmapCardMatchmakingBeatmapContent : BeatmapCardMatchmakingContent, IHasContextMenu - { - public override AvatarOverlay SelectionOverlay => selectionOverlay; - - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; - - [Resolved] - private BeatmapSetOverlay? beatmapSetOverlay { get; set; } - - private readonly IBindable downloadState = new Bindable(); - private readonly IBindableNumber downloadProgress = new BindableDouble(); - private readonly Bindable favouriteState = new Bindable(); - private readonly APIBeatmapSet beatmapSet; - private readonly APIBeatmap beatmap; - private readonly Mod[] mods; - - private BeatmapCardThumbnail thumbnail = null!; - private CollapsibleButtonContainer buttonContainer = null!; - private FillFlowContainer idleBottomContent = null!; - private BeatmapCardDownloadProgressBar downloadProgressBar = null!; - private AvatarOverlay selectionOverlay = null!; - - public BeatmapCardMatchmakingBeatmapContent(APIBeatmap beatmap, Mod[] mods) - { - this.beatmap = beatmap; - this.mods = mods; - - beatmapSet = beatmap.BeatmapSet!; - favouriteState.Value = new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - FillFlowContainer leftIconArea; - FillFlowContainer titleBadgeArea; - GridContainer artistContainer; - - InternalChildren = new Drawable[] - { - new BeatmapDownloadTracker(beatmap.BeatmapSet!) - { - State = { BindTarget = downloadState }, - Progress = { BindTarget = downloadProgress }, - }, - thumbnail = new BeatmapCardThumbnail(beatmapSet, beatmapSet, keepLoaded: true) - { - Name = @"Left (icon) area", - Size = new Vector2(BeatmapCardMatchmaking.HEIGHT), - Padding = new MarginPadding { Right = BeatmapCard.CORNER_RADIUS }, - Child = leftIconArea = new FillFlowContainer - { - Margin = new MarginPadding(4), - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(1) - } - }, - buttonContainer = new CollapsibleButtonContainer(beatmapSet, allowNavigationToBeatmap: false, keepBackgroundLoaded: true) - { - X = BeatmapCardMatchmaking.HEIGHT - BeatmapCard.CORNER_RADIUS, - Width = BeatmapCard.WIDTH - BeatmapCardMatchmaking.HEIGHT + BeatmapCard.CORNER_RADIUS, - FavouriteState = { BindTarget = favouriteState }, - ButtonsCollapsedWidth = 0, - ButtonsExpandedWidth = 24, - Children = new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.AutoSize), - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new Drawable[] - { - new TruncatingSpriteText - { - Text = new RomanisableString(beatmapSet.TitleUnicode, beatmapSet.Title), - Font = OsuFont.Default.With(size: 18f, weight: FontWeight.SemiBold), - RelativeSizeAxes = Axes.X, - }, - titleBadgeArea = new FillFlowContainer - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - } - } - } - }, - artistContainer = new GridContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.AutoSize) - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new[] - { - new TruncatingSpriteText - { - Text = BeatmapsetsStrings.ShowDetailsByArtist(new RomanisableString(beatmapSet.ArtistUnicode, beatmapSet.Artist)), - Font = OsuFont.Default.With(size: 14f, weight: FontWeight.SemiBold), - RelativeSizeAxes = Axes.X, - }, - Empty() - }, - } - }, - new LinkFlowContainer(s => - { - s.Shadow = false; - s.Font = OsuFont.GetFont(size: 11f, weight: FontWeight.SemiBold); - }).With(d => - { - d.AutoSizeAxes = Axes.Both; - d.Margin = new MarginPadding { Top = 1 }; - d.AddText("mapped by ", t => t.Colour = colourProvider.Content2); - d.AddUserLink(beatmapSet.Author); - }), - } - }, - new Container - { - Name = @"Bottom content", - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Children = new Drawable[] - { - idleBottomContent = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 2), - AlwaysPresent = true, - Children = new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.AutoSize) - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new Drawable[] - { - new Container - { - Masking = true, - CornerRadius = BeatmapCard.CORNER_RADIUS, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new Box - { - Colour = colours.ForStarDifficulty(beatmap.StarRating).Darken(0.8f), - RelativeSizeAxes = Axes.Both, - }, - new FillFlowContainer - { - Padding = new MarginPadding(4), - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(6, 0), - Children = new Drawable[] - { - new StarRatingDisplay(new StarDifficulty(beatmap.StarRating, 0), StarRatingDisplaySize.Small, animated: true) - { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Scale = new Vector2(0.9f), - }, - new TruncatingSpriteText - { - Text = beatmap.DifficultyName, - Font = OsuFont.Style.Caption1.With(weight: FontWeight.Bold), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - } - }, - } - }, - new ModFlowDisplay - { - AutoSizeAxes = Axes.Both, - Scale = new Vector2(0.5f), - Margin = new MarginPadding { Left = 5 }, - Current = { Value = mods } - }, - }, - } - }, - } - }, - downloadProgressBar = new BeatmapCardDownloadProgressBar - { - RelativeSizeAxes = Axes.X, - Height = 5, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - State = { BindTarget = downloadState }, - Progress = { BindTarget = downloadProgress } - } - } - }, - selectionOverlay = new AvatarOverlay - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - } - } - } - }; - - if (beatmapSet.HasVideo) - leftIconArea.Add(new VideoIconPill { IconSize = new Vector2(16) }); - - if (beatmapSet.HasStoryboard) - leftIconArea.Add(new StoryboardIconPill { IconSize = new Vector2(16) }); - - if (beatmapSet.FeaturedInSpotlight) - { - titleBadgeArea.Add(new SpotlightBeatmapBadge - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Margin = new MarginPadding { Left = 4 } - }); - } - - if (beatmapSet.HasExplicitContent) - { - titleBadgeArea.Add(new ExplicitContentBeatmapBadge - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Margin = new MarginPadding { Left = 4 } - }); - } - - if (beatmapSet.TrackId != null) - { - artistContainer.Content[0][1] = new FeaturedArtistBeatmapBadge - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Margin = new MarginPadding { Left = 4 } - }; - } - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - downloadState.BindValueChanged(_ => updateState(), true); - - FinishTransforms(true); - } - - protected override bool OnHover(HoverEvent e) - { - updateState(); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - updateState(); - base.OnHoverLost(e); - } - - private void updateState() - { - bool showDetails = IsHovered; - - buttonContainer.ShowDetails.Value = showDetails; - thumbnail.Dimmed.Value = showDetails; - - bool showProgress = downloadState.Value == DownloadState.Downloading || downloadState.Value == DownloadState.Importing; - - idleBottomContent.FadeTo(showProgress ? 0 : 1, 340, Easing.OutQuint); - downloadProgressBar.FadeTo(showProgress ? 1 : 0, 340, Easing.OutQuint); - } - - public MenuItem[] ContextMenuItems - { - get - { - List items = new List - { - new OsuMenuItem(ContextMenuStrings.ViewBeatmap, MenuItemType.Highlighted, () => beatmapSetOverlay?.FetchAndShowBeatmap(beatmap.OnlineID)) - }; - - foreach (var button in buttonContainer.Buttons) - { - if (button.Enabled.Value) - items.Add(new OsuMenuItem(button.TooltipText.ToSentence(), MenuItemType.Standard, () => button.TriggerClick())); - } - - return items.ToArray(); - } - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingContent.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingContent.cs deleted file mode 100644 index 8314174a4cd5..000000000000 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingContent.cs +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests.Responses; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect -{ - public abstract partial class BeatmapCardMatchmakingContent : CompositeDrawable - { - public abstract AvatarOverlay SelectionOverlay { get; } - - protected BeatmapCardMatchmakingContent() - { - RelativeSizeAxes = Axes.Both; - } - - public partial class AvatarOverlay : CompositeDrawable - { - private readonly Container avatars; - - private Sample? userAddedSample; - private double? lastSamplePlayback; - - [Resolved] - private IAPIProvider api { get; set; } = null!; - - public AvatarOverlay() - { - AutoSizeAxes = Axes.Both; - - InternalChild = avatars = new Container - { - AutoSizeAxes = Axes.X, - Height = SelectionAvatar.AVATAR_SIZE, - }; - - Padding = new MarginPadding { Vertical = 5 }; - } - - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - userAddedSample = audio.Samples.Get(@"Multiplayer/player-ready"); - } - - public bool AddUser(APIUser user) - { - if (avatars.Any(a => a.User.Id == user.Id)) - return false; - - var avatar = new SelectionAvatar(user, user.Equals(api.LocalUser.Value)); - - avatars.Add(avatar); - - if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > OsuGameBase.SAMPLE_DEBOUNCE_TIME) - { - userAddedSample?.Play(); - lastSamplePlayback = Time.Current; - } - - updateAvatarLayout(); - - avatar.FinishTransforms(); - - return true; - } - - public bool RemoveUser(int id) - { - if (avatars.SingleOrDefault(a => a.User.Id == id) is not SelectionAvatar avatar) - return false; - - avatar.PopOutAndExpire(); - avatars.ChangeChildDepth(avatar, float.MaxValue); - - updateAvatarLayout(); - - return true; - } - - private void updateAvatarLayout() - { - const double stagger = 30; - const float spacing = 4; - - double delay = 0; - float x = 0; - - for (int i = avatars.Count - 1; i >= 0; i--) - { - var avatar = avatars[i]; - - if (avatar.Expired) - continue; - - avatar.Delay(delay).MoveToX(x, 500, Easing.OutElasticQuarter); - - x -= avatar.LayoutSize.X + spacing; - - delay += stagger; - } - } - - public partial class SelectionAvatar : CompositeDrawable - { - public const float AVATAR_SIZE = 30; - - public APIUser User { get; } - - public bool Expired { get; private set; } - - private readonly MatchmakingAvatar avatar; - - public SelectionAvatar(APIUser user, bool isOwnUser) - { - User = user; - Size = new Vector2(AVATAR_SIZE); - - InternalChild = avatar = new MatchmakingAvatar(user, isOwnUser) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - avatar.ScaleTo(0) - .ScaleTo(1, 500, Easing.OutElasticHalf) - .FadeIn(200); - } - - public void PopOutAndExpire() - { - avatar.ScaleTo(0, 400, Easing.OutExpo); - - this.FadeOut(100).Expire(); - Expired = true; - } - } - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingRandomContent.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingRandomContent.cs deleted file mode 100644 index 515456abe197..000000000000 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapCardMatchmakingRandomContent.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics.Sprites; -using osu.Game.Overlays; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect -{ - public partial class BeatmapCardMatchmakingRandomContent : BeatmapCardMatchmakingContent - { - public override AvatarOverlay SelectionOverlay => selectionOverlay; - - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; - - private AvatarOverlay selectionOverlay = null!; - - [BackgroundDependencyLoader] - private void load() - { - InternalChildren = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background2, - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding - { - Horizontal = 10, - Vertical = 4 - }, - Children = new Drawable[] - { - new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = - [ - new SpriteIcon - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Size = new Vector2(32), - Icon = FontAwesome.Solid.Random, - }, - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "Random", - } - ] - }, - selectionOverlay = new AvatarOverlay - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - } - } - } - }; - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs index 967e2777b7c9..d27b0e3818a3 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; using Microsoft.Toolkit.HighPerformance; using osu.Framework.Allocation; using osu.Framework.Audio; @@ -33,10 +34,12 @@ public partial class BeatmapSelectGrid : CompositeDrawable public event Action? ItemSelected; - private readonly Dictionary panelLookup = new Dictionary(); + private readonly Dictionary panelLookup = new Dictionary(); + private readonly Dictionary playlistItems = new Dictionary(); + private MatchmakingSelectPanelRandom randomPanel = null!; private readonly PanelGridContainer panelGridContainer; - private readonly Container rollContainer; + private readonly Container rollContainer; private readonly OsuScrollContainer scroll; private bool allowSelection = true; @@ -64,15 +67,12 @@ public BeatmapSelectGrid() Spacing = new Vector2(panel_spacing) }, }, - rollContainer = new Container + rollContainer = new Container { RelativeSizeAxes = Axes.Both, Masking = true, }, }; - - // Special item denoting a random selection. - AddItem(new MultiplayerPlaylistItem { ID = -1 }); } [BackgroundDependencyLoader] @@ -86,9 +86,33 @@ private void load(AudioManager audio) swooshSample = audio.Samples.Get(@"SongSelect/options-pop-out"); } - protected override void LoadComplete() + public void AddItems(IEnumerable items) { - base.LoadComplete(); + foreach (var item in items) + { + playlistItems[item.ID] = item; + + var panel = panelLookup[item.ID] = new MatchmakingSelectPanelBeatmap(item) + { + AllowSelection = allowSelection, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Action = i => ItemSelected?.Invoke(i), + }; + + panelGridContainer.Add(panel); + panelGridContainer.SetLayoutPosition(panel, (float)panel.Item.StarRating); + } + + panelLookup[-1] = randomPanel = new MatchmakingSelectPanelRandom(new MultiplayerPlaylistItem { ID = -1 }) + { + AllowSelection = allowSelection, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Action = i => ItemSelected?.Invoke(i), + }; + panelGridContainer.Add(randomPanel); + panelGridContainer.SetLayoutPosition(randomPanel, float.MinValue); const double enter_duration = 500; @@ -104,24 +128,12 @@ protected override void LoadComplete() panel.FadeInAndEnterFromBelow(duration: enter_duration, delay: delay); } - }); - } - public void AddItem(MultiplayerPlaylistItem item) - { - var panel = panelLookup[item.ID] = new BeatmapSelectPanel(item) - { - AllowSelection = allowSelection, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Action = i => ItemSelected?.Invoke(i), - }; - - panelGridContainer.Add(panel); - panelGridContainer.SetLayoutPosition(panel, (float)item.StarRating); + panelsLoaded.SetResult(); + }); } - public void SetUserSelection(APIUser user, long itemId, bool selected) + public void SetUserSelection(APIUser user, long itemId, bool selected) => whenPanelsLoaded(() => { if (!panelLookup.TryGetValue(itemId, out var panel)) return; @@ -130,18 +142,19 @@ public void SetUserSelection(APIUser user, long itemId, bool selected) panel.AddUser(user); else panel.RemoveUser(user); - } + }); - public void RevealRandomItem(MultiplayerPlaylistItem item) + public void RevealRandomItem(MultiplayerPlaylistItem item) => whenPanelsLoaded(() => { - if (!panelLookup.TryGetValue(-1, out var panel)) - return; + playlistItems.TryGetValue(item.ID, out var playlistItem); + + Debug.Assert(playlistItem != null); - panel.DisplayItem(item); randomRevealSample?.Play(); - } + randomPanel.RevealBeatmap(playlistItem.Beatmap, playlistItem.Mods); + }); - public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId) + public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId) => whenPanelsLoaded(() => { Debug.Assert(candidateItemIds.Length >= 1); Debug.Assert(candidateItemIds.Contains(finalItemId)); @@ -168,7 +181,7 @@ public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId .Delay(roll_duration + present_beatmap_delay) .Schedule(() => PresentRolledBeatmap(finalItemId)); } - } + }); internal void TransferCandidatePanelsToRollContainer(long[] candidateItemIds, double duration = hide_duration) { @@ -177,7 +190,7 @@ internal void TransferCandidatePanelsToRollContainer(long[] candidateItemIds, do var rng = new Random(); - var remainingPanels = new List(); + var remainingPanels = new List(); foreach (var panel in panelGridContainer.Children.ToArray()) { @@ -217,7 +230,7 @@ internal void ArrangeItemsForRollAnimation(double duration = arrange_duration, d { var panel = rollContainer.Children[i]; - var position = positions[i] * (BeatmapSelectPanel.SIZE + new Vector2(panel_spacing)); + var position = positions[i] * (MatchmakingSelectPanel.SIZE + new Vector2(panel_spacing)); panel.MoveTo(position, duration + stagger * i, new SplitEasingFunction(Easing.InCubic, Easing.OutExpo, 0.3f)); @@ -286,7 +299,7 @@ internal void PlayRollAnimation(long finalItem, double duration = roll_duration) while ((numSteps - 1) % rollContainer.Children.Count != finalItemIndex) numSteps++; - BeatmapSelectPanel? lastPanel = null; + MatchmakingSelectPanel? lastPanel = null; for (int i = 0; i < numSteps; i++) { @@ -347,7 +360,15 @@ internal void PresentUnanimouslyChosenBeatmap(long finalItem) PresentRolledBeatmap(finalItem); } - private partial class PanelGridContainer : FillFlowContainer + private readonly TaskCompletionSource panelsLoaded = new TaskCompletionSource(); + + private void whenPanelsLoaded(Action action) => Task.Run(async () => + { + await panelsLoaded.Task.ConfigureAwait(false); + Schedule(action); + }); + + private partial class PanelGridContainer : FillFlowContainer { public bool LayoutDisabled; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingPlaylistItem.cs new file mode 100644 index 000000000000..6b7fb9f21eb1 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingPlaylistItem.cs @@ -0,0 +1,14 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Rooms; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect +{ + public record MatchmakingPlaylistItem(MultiplayerPlaylistItem PlaylistItem, APIBeatmap Beatmap, Mod[] Mods) + { + public long ID => PlaylistItem.ID; + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContent.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContent.cs new file mode 100644 index 000000000000..48c64f2f6674 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContent.cs @@ -0,0 +1,156 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect +{ + public partial class MatchmakingSelectPanel + { + public abstract partial class CardContent : CompositeDrawable + { + public abstract AvatarOverlay SelectionOverlay { get; } + + protected CardContent() + { + RelativeSizeAxes = Axes.Both; + } + + public partial class AvatarOverlay : CompositeDrawable + { + private readonly Container avatars; + + private Sample? userAddedSample; + private double? lastSamplePlayback; + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + public AvatarOverlay() + { + AutoSizeAxes = Axes.Both; + + InternalChild = avatars = new Container + { + AutoSizeAxes = Axes.X, + Height = SelectionAvatar.AVATAR_SIZE, + }; + + Padding = new MarginPadding { Vertical = 5 }; + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + userAddedSample = audio.Samples.Get(@"Multiplayer/player-ready"); + } + + public bool AddUser(APIUser user) + { + if (avatars.Any(a => a.User.Id == user.Id)) + return false; + + var avatar = new SelectionAvatar(user, user.Equals(api.LocalUser.Value)); + + avatars.Add(avatar); + + if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > OsuGameBase.SAMPLE_DEBOUNCE_TIME) + { + userAddedSample?.Play(); + lastSamplePlayback = Time.Current; + } + + updateAvatarLayout(); + + avatar.FinishTransforms(); + + return true; + } + + public bool RemoveUser(int id) + { + if (avatars.SingleOrDefault(a => a.User.Id == id) is not SelectionAvatar avatar) + return false; + + avatar.PopOutAndExpire(); + avatars.ChangeChildDepth(avatar, float.MaxValue); + + updateAvatarLayout(); + + return true; + } + + private void updateAvatarLayout() + { + const double stagger = 30; + const float spacing = 4; + + double delay = 0; + float x = 0; + + for (int i = avatars.Count - 1; i >= 0; i--) + { + var avatar = avatars[i]; + + if (avatar.Expired) + continue; + + avatar.Delay(delay).MoveToX(x, 500, Easing.OutElasticQuarter); + + x -= avatar.LayoutSize.X + spacing; + + delay += stagger; + } + } + + public partial class SelectionAvatar : CompositeDrawable + { + public const float AVATAR_SIZE = 30; + + public APIUser User { get; } + + public bool Expired { get; private set; } + + private readonly MatchmakingAvatar avatar; + + public SelectionAvatar(APIUser user, bool isOwnUser) + { + User = user; + Size = new Vector2(AVATAR_SIZE); + + InternalChild = avatar = new MatchmakingAvatar(user, isOwnUser) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + avatar.ScaleTo(0) + .ScaleTo(1, 500, Easing.OutElasticHalf) + .FadeIn(200); + } + + public void PopOutAndExpire() + { + avatar.ScaleTo(0, 400, Easing.OutExpo); + + this.FadeOut(100).Expire(); + Expired = true; + } + } + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs new file mode 100644 index 000000000000..b27ab2850bbc --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs @@ -0,0 +1,381 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Beatmaps.Drawables.Cards; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; +using osu.Game.Online; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; +using osu.Game.Overlays.BeatmapSet; +using osu.Game.Resources.Localisation.Web; +using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Play.HUD; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect +{ + public partial class MatchmakingSelectPanel + { + public partial class CardContentBeatmap : CardContent, IHasContextMenu + { + public override AvatarOverlay SelectionOverlay => selectionOverlay; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + [Resolved] + private BeatmapSetOverlay? beatmapSetOverlay { get; set; } + + private readonly IBindable downloadState = new Bindable(); + private readonly IBindableNumber downloadProgress = new BindableDouble(); + private readonly Bindable favouriteState = new Bindable(); + private readonly APIBeatmapSet beatmapSet; + private readonly APIBeatmap beatmap; + private readonly Mod[] mods; + + private BeatmapCardThumbnail thumbnail = null!; + private CollapsibleButtonContainer buttonContainer = null!; + private FillFlowContainer idleBottomContent = null!; + private BeatmapCardDownloadProgressBar downloadProgressBar = null!; + private AvatarOverlay selectionOverlay = null!; + + public CardContentBeatmap(APIBeatmap beatmap, Mod[] mods) + { + this.beatmap = beatmap; + this.mods = mods; + + beatmapSet = beatmap.BeatmapSet!; + favouriteState.Value = new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + FillFlowContainer leftIconArea; + FillFlowContainer titleBadgeArea; + GridContainer artistContainer; + + InternalChildren = new Drawable[] + { + new BeatmapDownloadTracker(beatmap.BeatmapSet!) + { + State = { BindTarget = downloadState }, + Progress = { BindTarget = downloadProgress }, + }, + thumbnail = new BeatmapCardThumbnail(beatmapSet, beatmapSet, keepLoaded: true) + { + Name = @"Left (icon) area", + Size = new Vector2(MatchmakingSelectPanel.HEIGHT), + Padding = new MarginPadding { Right = BeatmapCard.CORNER_RADIUS }, + Child = leftIconArea = new FillFlowContainer + { + Margin = new MarginPadding(4), + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(1) + } + }, + buttonContainer = new CollapsibleButtonContainer(beatmapSet, allowNavigationToBeatmap: false, keepBackgroundLoaded: true) + { + X = MatchmakingSelectPanel.HEIGHT - BeatmapCard.CORNER_RADIUS, + Width = BeatmapCard.WIDTH - MatchmakingSelectPanel.HEIGHT + BeatmapCard.CORNER_RADIUS, + FavouriteState = { BindTarget = favouriteState }, + ButtonsCollapsedWidth = 0, + ButtonsExpandedWidth = 24, + Children = new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] + { + new TruncatingSpriteText + { + Text = new RomanisableString(beatmapSet.TitleUnicode, beatmapSet.Title), + Font = OsuFont.Default.With(size: 18f, weight: FontWeight.SemiBold), + RelativeSizeAxes = Axes.X, + }, + titleBadgeArea = new FillFlowContainer + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + } + } + } + }, + artistContainer = new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize) + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new[] + { + new TruncatingSpriteText + { + Text = BeatmapsetsStrings.ShowDetailsByArtist(new RomanisableString(beatmapSet.ArtistUnicode, beatmapSet.Artist)), + Font = OsuFont.Default.With(size: 14f, weight: FontWeight.SemiBold), + RelativeSizeAxes = Axes.X, + }, + Empty() + }, + } + }, + new LinkFlowContainer(s => + { + s.Shadow = false; + s.Font = OsuFont.GetFont(size: 11f, weight: FontWeight.SemiBold); + }).With(d => + { + d.AutoSizeAxes = Axes.Both; + d.Margin = new MarginPadding { Top = 1 }; + d.AddText("mapped by ", t => t.Colour = colourProvider.Content2); + d.AddUserLink(beatmapSet.Author); + }), + } + }, + new Container + { + Name = @"Bottom content", + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Children = new Drawable[] + { + idleBottomContent = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 2), + AlwaysPresent = true, + Children = new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize) + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] + { + new Container + { + Masking = true, + CornerRadius = BeatmapCard.CORNER_RADIUS, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + Colour = colours.ForStarDifficulty(beatmap.StarRating).Darken(0.8f), + RelativeSizeAxes = Axes.Both, + }, + new FillFlowContainer + { + Padding = new MarginPadding(4), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(6, 0), + Children = new Drawable[] + { + new StarRatingDisplay(new StarDifficulty(beatmap.StarRating, 0), StarRatingDisplaySize.Small, animated: true) + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Scale = new Vector2(0.9f), + }, + new TruncatingSpriteText + { + Text = beatmap.DifficultyName, + Font = OsuFont.Style.Caption1.With(weight: FontWeight.Bold), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + } + }, + } + }, + new ModFlowDisplay + { + AutoSizeAxes = Axes.Both, + Scale = new Vector2(0.5f), + Margin = new MarginPadding { Left = 5 }, + Current = { Value = mods } + }, + }, + } + }, + } + }, + downloadProgressBar = new BeatmapCardDownloadProgressBar + { + RelativeSizeAxes = Axes.X, + Height = 5, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + State = { BindTarget = downloadState }, + Progress = { BindTarget = downloadProgress } + } + } + }, + selectionOverlay = new AvatarOverlay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + } + } + } + }; + + if (beatmapSet.HasVideo) + leftIconArea.Add(new VideoIconPill { IconSize = new Vector2(16) }); + + if (beatmapSet.HasStoryboard) + leftIconArea.Add(new StoryboardIconPill { IconSize = new Vector2(16) }); + + if (beatmapSet.FeaturedInSpotlight) + { + titleBadgeArea.Add(new SpotlightBeatmapBadge + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Margin = new MarginPadding { Left = 4 } + }); + } + + if (beatmapSet.HasExplicitContent) + { + titleBadgeArea.Add(new ExplicitContentBeatmapBadge + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Margin = new MarginPadding { Left = 4 } + }); + } + + if (beatmapSet.TrackId != null) + { + artistContainer.Content[0][1] = new FeaturedArtistBeatmapBadge + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Margin = new MarginPadding { Left = 4 } + }; + } + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + downloadState.BindValueChanged(_ => updateState(), true); + + FinishTransforms(true); + } + + protected override bool OnHover(HoverEvent e) + { + updateState(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateState(); + base.OnHoverLost(e); + } + + private void updateState() + { + bool showDetails = IsHovered; + + buttonContainer.ShowDetails.Value = showDetails; + thumbnail.Dimmed.Value = showDetails; + + bool showProgress = downloadState.Value == DownloadState.Downloading || downloadState.Value == DownloadState.Importing; + + idleBottomContent.FadeTo(showProgress ? 0 : 1, 340, Easing.OutQuint); + downloadProgressBar.FadeTo(showProgress ? 1 : 0, 340, Easing.OutQuint); + } + + public MenuItem[] ContextMenuItems + { + get + { + List items = new List + { + new OsuMenuItem(ContextMenuStrings.ViewBeatmap, MenuItemType.Highlighted, () => beatmapSetOverlay?.FetchAndShowBeatmap(beatmap.OnlineID)) + }; + + foreach (var button in buttonContainer.Buttons) + { + if (button.Enabled.Value) + items.Add(new OsuMenuItem(button.TooltipText.ToSentence(), MenuItemType.Standard, () => button.TriggerClick())); + } + + return items.ToArray(); + } + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs new file mode 100644 index 000000000000..24422de1b57e --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs @@ -0,0 +1,80 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect +{ + public partial class MatchmakingSelectPanel + { + public partial class CardContentRandom : CardContent + { + public override AvatarOverlay SelectionOverlay => selectionOverlay; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + private AvatarOverlay selectionOverlay = null!; + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background2, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding + { + Horizontal = 10, + Vertical = 4 + }, + Children = new Drawable[] + { + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = + [ + new SpriteIcon + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Size = new Vector2(32), + Icon = FontAwesome.Solid.Random, + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "Random", + } + ] + }, + selectionOverlay = new AvatarOverlay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + } + } + } + }; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs similarity index 56% rename from osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectPanel.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs index cbd8480da467..ca10133a36dc 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Game.Beatmaps.Drawables.Cards; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Overlays; @@ -19,9 +20,12 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect { - public partial class BeatmapSelectPanel : Container + public abstract partial class MatchmakingSelectPanel : Container { - public static readonly Vector2 SIZE = new Vector2(BeatmapCard.WIDTH, BeatmapCardNormal.HEIGHT); + public const float WIDTH = 345; + public const float HEIGHT = 80; + + public static readonly Vector2 SIZE = new Vector2(WIDTH, HEIGHT); public bool AllowSelection { get; set; } @@ -29,14 +33,15 @@ public partial class BeatmapSelectPanel : Container public Action? Action { private get; init; } + protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; + private const float border_width = 3; private Container scaleContainer = null!; private Drawable lighting = null!; private Container border = null!; - private BeatmapCardMatchmaking card = null!; - public BeatmapSelectPanel(MultiplayerPlaylistItem item) + protected MatchmakingSelectPanel(MultiplayerPlaylistItem item) { Item = item; Size = SIZE; @@ -45,88 +50,70 @@ public BeatmapSelectPanel(MultiplayerPlaylistItem item) [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { - InternalChild = scaleContainer = new Container + InternalChildren = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Children = new[] + scaleContainer = new Container { - new Container + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = new[] { - Masking = true, - CornerRadius = BeatmapCard.CORNER_RADIUS, - CornerExponent = 10, - RelativeSizeAxes = Axes.Both, - Children = new[] + new Container { - card = new BeatmapCardMatchmaking + Masking = true, + CornerRadius = BeatmapCard.CORNER_RADIUS, + CornerExponent = 10, + RelativeSizeAxes = Axes.Both, + Children = new[] { - Action = () => + Content, + lighting = new Box { - if (AllowSelection) - Action?.Invoke(Item); + Blending = BlendingParameters.Additive, + RelativeSizeAxes = Axes.Both, + Alpha = 0, }, - }, - lighting = new Box - { - Blending = BlendingParameters.Additive, - RelativeSizeAxes = Axes.Both, - Alpha = 0, - }, - } - }, - border = new Container - { - Alpha = 0, - Masking = true, - CornerRadius = BeatmapCard.CORNER_RADIUS, - CornerExponent = 10, - Blending = BlendingParameters.Additive, - RelativeSizeAxes = Axes.Both, - BorderThickness = border_width, - BorderColour = colourProvider.Light1, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Radius = 40, - Roundness = 300, - Colour = colourProvider.Light3.Opacity(0.1f), + } }, - Children = new Drawable[] + border = new Container { - new Box + Alpha = 0, + Masking = true, + CornerRadius = BeatmapCard.CORNER_RADIUS, + CornerExponent = 10, + Blending = BlendingParameters.Additive, + RelativeSizeAxes = Axes.Both, + BorderThickness = border_width, + BorderColour = colourProvider.Light1, + EdgeEffect = new EdgeEffectParameters { - AlwaysPresent = true, - Alpha = 0, - Colour = Color4.Black, - RelativeSizeAxes = Axes.Both, + Type = EdgeEffectType.Glow, + Radius = 40, + Roundness = 300, + Colour = colourProvider.Light3.Opacity(0.1f), }, - } - }, - } + Children = new Drawable[] + { + new Box + { + AlwaysPresent = true, + Alpha = 0, + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + }, + } + }, + } + }, + new HoverClickSounds(), }; - - if (Item.ID == -1) - card.DisplayRandom(); - else - card.DisplayItem(Item); - } - - public void AddUser(APIUser user) - { - card.AddUser(user); } - public void RemoveUser(APIUser user) - { - card.RemoveUser(user); - } + // TODO: making these abstract for now but avatar overlay should really be owned by the top level class + public abstract void AddUser(APIUser user); - public void DisplayItem(MultiplayerPlaylistItem item) - { - card.DisplayItem(item); - } + public abstract void RemoveUser(APIUser user); protected override bool OnHover(HoverEvent e) { @@ -171,10 +158,11 @@ protected override bool OnClick(ClickEvent e) lighting.FadeTo(0.5f, 50) .Then() .FadeTo(0.1f, 400); + + Action?.Invoke(Item); } - // pass through to let the beatmap card handle actual click. - return false; + return true; } public void ShowChosenBorder() diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelBeatmap.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelBeatmap.cs new file mode 100644 index 000000000000..ec00ed3847dc --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelBeatmap.cs @@ -0,0 +1,40 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect +{ + public partial class MatchmakingSelectPanelBeatmap : MatchmakingSelectPanel + { + private readonly APIBeatmap beatmap; + private readonly Mod[] mods; + + public MatchmakingSelectPanelBeatmap(MatchmakingPlaylistItem item) + : base(item.PlaylistItem) + { + beatmap = item.Beatmap; + mods = item.Mods; + } + + private CardContent content = null!; + + [BackgroundDependencyLoader] + private void load() + { + Add(content = new CardContentBeatmap(beatmap, mods)); + } + + public override void AddUser(APIUser user) + { + content.SelectionOverlay.AddUser(user); + } + + public override void RemoveUser(APIUser user) + { + content.SelectionOverlay.RemoveUser(user.Id); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs new file mode 100644 index 000000000000..0c818df06be0 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs @@ -0,0 +1,60 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Rooms; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect +{ + public partial class MatchmakingSelectPanelRandom : MatchmakingSelectPanel + { + public MatchmakingSelectPanelRandom(MultiplayerPlaylistItem item) + : base(item) + { + } + + private CardContent content = null!; + private readonly List users = new List(); + + [BackgroundDependencyLoader] + private void load() + { + Add(content = new CardContentRandom()); + } + + public void RevealBeatmap(APIBeatmap beatmap, Mod[] mods) + { + content.Expire(); + + var flashLayer = new Box { RelativeSizeAxes = Axes.Both }; + + AddRange(new Drawable[] + { + content = new CardContentBeatmap(beatmap, mods), + flashLayer, + }); + + foreach (var user in users) + content.SelectionOverlay.AddUser(user); + + flashLayer.FadeOutFromOne(1000, Easing.In); + } + + public override void AddUser(APIUser user) + { + users.Add(user); + content.SelectionOverlay.AddUser(user); + } + + public override void RemoveUser(APIUser user) + { + users.Remove(user); + content.SelectionOverlay.RemoveUser(user.Id); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs index e0db69783c17..7951fc5448ec 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs @@ -1,14 +1,23 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Database; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osuTK; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect { @@ -18,10 +27,17 @@ public partial class SubScreenBeatmapSelect : MatchmakingSubScreen public override Drawable PlayersDisplayArea { get; } private readonly BeatmapSelectGrid beatmapSelectGrid; + private readonly LoadingSpinner loadingSpinner; [Resolved] private MultiplayerClient client { get; set; } = null!; + [Resolved] + private RulesetStore rulesetStore { get; set; } = null!; + + [Resolved] + private BeatmapLookupCache beatmapLookupCache { get; set; } = null!; + public SubScreenBeatmapSelect() { InternalChildren = new Drawable[] @@ -30,9 +46,19 @@ public SubScreenBeatmapSelect() { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Horizontal = 200 }, - Child = beatmapSelectGrid = new BeatmapSelectGrid + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, + beatmapSelectGrid = new BeatmapSelectGrid + { + RelativeSizeAxes = Axes.Both, + }, + loadingSpinner = new LoadingSpinner + { + Size = new Vector2(64), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + State = { Value = Visibility.Visible } + } }, }, new Container @@ -50,25 +76,53 @@ protected override void LoadComplete() { base.LoadComplete(); - client.ItemAdded += onItemAdded; - - foreach (var item in client.Room!.Playlist) - onItemAdded(item); - beatmapSelectGrid.ItemSelected += item => client.MatchmakingToggleSelection(item.ID); - client.MatchmakingItemSelected += onItemSelected; client.MatchmakingItemDeselected += onItemDeselected; client.SettingsChanged += onSettingsChanged; + + Debug.Assert(client.Room != null); + + loadItems(client.Room.Playlist.ToArray()).FireAndForget(); } - private void onItemAdded(MultiplayerPlaylistItem item) => Scheduler.Add(() => + private async Task loadItems(MultiplayerPlaylistItem[] items) { - if (item.Expired) - return; + var beatmaps = await beatmapLookupCache.GetBeatmapsAsync(items.Select(it => it.BeatmapID).ToArray()).ConfigureAwait(false); + var matchmakingItems = new List(); + + foreach (var entry in items.Zip(beatmaps)) + { + var (item, beatmap) = entry; - beatmapSelectGrid.AddItem(item); - }); + beatmap ??= new APIBeatmap + { + BeatmapSet = new APIBeatmapSet + { + Title = "unknown beatmap", + TitleUnicode = "unknown beatmap", + Artist = "unknown artist", + ArtistUnicode = "unknown artist", + } + }; + + beatmap.StarRating = item.StarRating; + + Ruleset? ruleset = rulesetStore.GetRuleset(item.RulesetID)?.CreateInstance(); + + Debug.Assert(ruleset != null); + + Mod[] mods = item.RequiredMods.Select(m => m.ToMod(ruleset)).ToArray(); + + matchmakingItems.Add(new MatchmakingPlaylistItem(item, beatmap, mods)); + } + + Scheduler.Add(() => + { + loadingSpinner.Hide(); + beatmapSelectGrid.AddItems(matchmakingItems); + }); + } private void onItemSelected(int userId, long itemId) { @@ -104,7 +158,6 @@ protected override void Dispose(bool isDisposing) if (client.IsNotNull()) { - client.ItemAdded -= onItemAdded; client.MatchmakingItemSelected -= onItemSelected; client.MatchmakingItemDeselected -= onItemDeselected; client.SettingsChanged -= onSettingsChanged; From e349a597bae4618cc474505348d00f74c3325bd6 Mon Sep 17 00:00:00 2001 From: marvin Date: Mon, 17 Nov 2025 07:29:27 +0100 Subject: [PATCH 093/836] Use dice icon for MatchmakingSelectPanelRandom --- ...atchmakingSelectPanel.CardContentRandom.cs | 79 ++++++++++--------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs index 24422de1b57e..156d21380674 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs @@ -3,9 +3,10 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Utils; +using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using osuTK; @@ -22,6 +23,7 @@ public partial class CardContentRandom : CardContent private OverlayColourProvider colourProvider { get; set; } = null!; private AvatarOverlay selectionOverlay = null!; + public SpriteIcon Dice { get; private set; } = null!; [BackgroundDependencyLoader] private void load() @@ -31,50 +33,49 @@ private void load() new Box { RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background2, + Colour = colourProvider.Dark5, }, - new Container + new TrianglesV2 { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding - { - Horizontal = 10, - Vertical = 4 - }, - Children = new Drawable[] - { - new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = - [ - new SpriteIcon - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Size = new Vector2(32), - Icon = FontAwesome.Solid.Random, - }, - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "Random", - } - ] - }, - selectionOverlay = new AvatarOverlay - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - } - } + Alpha = 0.1f, + }, + new OsuSpriteText + { + Y = 20, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "Random" + }, + Dice = new SpriteIcon + { + Y = -10, + Size = new Vector2(28), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Icon = randomDiceIcon(), + }, + selectionOverlay = new AvatarOverlay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, } }; + + Dice.Spin(10_000, RotationDirection.Clockwise); } + + private static IconUsage[] diceIcons => new[] + { + FontAwesome.Solid.DiceOne, + FontAwesome.Solid.DiceTwo, + FontAwesome.Solid.DiceThree, + FontAwesome.Solid.DiceFour, + FontAwesome.Solid.DiceFive, + FontAwesome.Solid.DiceSix, + }; + + private static IconUsage randomDiceIcon() => diceIcons[RNG.Next(diceIcons.Length)]; } } } From 32900f563c0b2b0ff5c8efc394e6f1c116a3a862 Mon Sep 17 00:00:00 2001 From: marvin Date: Mon, 17 Nov 2025 07:30:15 +0100 Subject: [PATCH 094/836] Roll dice on click --- .../MatchmakingSelectPanel.CardContentRandom.cs | 13 +++++++++++++ .../BeatmapSelect/MatchmakingSelectPanelRandom.cs | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs index 156d21380674..ad7293b8111b 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs @@ -65,6 +65,19 @@ private void load() Dice.Spin(10_000, RotationDirection.Clockwise); } + public void RollDice() + { + var icon = randomDiceIcon(); + + while (icon.Equals(Dice.Icon)) + icon = randomDiceIcon(); + + Dice.ScaleTo(0.65f, 60, Easing.Out) + .Then() + .Schedule(() => Dice.Icon = icon) + .ScaleTo(1f, 400, Easing.OutElasticHalf); + } + private static IconUsage[] diceIcons => new[] { FontAwesome.Solid.DiceOne, diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs index 0c818df06be0..4c50f4184ce6 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Mods; @@ -56,5 +57,13 @@ public override void RemoveUser(APIUser user) users.Remove(user); content.SelectionOverlay.RemoveUser(user.Id); } + + protected override bool OnClick(ClickEvent e) + { + if (AllowSelection && content is CardContentRandom randomContent) + randomContent.RollDice(); + + return base.OnClick(e); + } } } From 77963946851427d23a4c21a5d6281f5d0e6ecc33 Mon Sep 17 00:00:00 2001 From: marvin Date: Mon, 17 Nov 2025 07:31:46 +0100 Subject: [PATCH 095/836] Play roll animation when revealing random beatmap --- .../Matchmaking/TestSceneBeatmapSelectGrid.cs | 10 ++-- ...atchmakingSelectPanel.CardContentRandom.cs | 3 +- .../MatchmakingSelectPanelRandom.cs | 54 +++++++++++++++---- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs index 0e5e5b8aae04..f7efbf06487b 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs @@ -228,12 +228,12 @@ public void TestPresentRandomItem() grid.ArrangeItemsForRollAnimation(duration: 0, stagger: 0); grid.PlayRollAnimation(-1, duration: 0); - Scheduler.AddDelayed(() => grid.PresentUnanimouslyChosenBeatmap(-1), 500); + Scheduler.AddDelayed(() => + { + grid.PresentUnanimouslyChosenBeatmap(-1); + grid.RevealRandomItem(items[RNG.Next(items.Length)].PlaylistItem); + }, 500); }); - - AddWaitStep("wait for animation", 5); - - AddStep("reveal beatmap", () => grid.RevealRandomItem(items[RNG.Next(items.Length)].PlaylistItem)); } private (long[] candidateItems, long finalItem) pickRandomItems(int count) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs index ad7293b8111b..0fc5a9fa4695 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs @@ -24,6 +24,7 @@ public partial class CardContentRandom : CardContent private AvatarOverlay selectionOverlay = null!; public SpriteIcon Dice { get; private set; } = null!; + public OsuSpriteText Label { get; private set; } = null!; [BackgroundDependencyLoader] private void load() @@ -40,7 +41,7 @@ private void load() RelativeSizeAxes = Axes.Both, Alpha = 0.1f, }, - new OsuSpriteText + Label = new OsuSpriteText { Y = 20, Anchor = Anchor.Centre, diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs index 4c50f4184ce6..1c2114ad9118 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs @@ -1,10 +1,12 @@ // 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.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Transforms; using osu.Framework.Input.Events; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; @@ -19,31 +21,50 @@ public MatchmakingSelectPanelRandom(MultiplayerPlaylistItem item) { } - private CardContent content = null!; + private CardContentRandom content = null!; + private Drawable diceProxy = null!; private readonly List users = new List(); [BackgroundDependencyLoader] private void load() { Add(content = new CardContentRandom()); + + AddInternal(diceProxy = content.Dice.CreateProxy()); } public void RevealBeatmap(APIBeatmap beatmap, Mod[] mods) { - content.Expire(); + const double duration = 800; + + content.Dice.MoveToY(-200, duration * 0.55, new PowEasingFunction(2.75, easeOut: true)) + .Then() + .Schedule(() => ChangeInternalChildDepth(diceProxy, float.MaxValue)) + .MoveToY(-DrawHeight / 2, duration * 0.45, new PowEasingFunction(2.2)) + .Then() + .FadeOut() + .Expire(); - var flashLayer = new Box { RelativeSizeAxes = Axes.Both }; + content.Dice.RotateTo(content.Dice.Rotation - 360 * 5, duration * 1.3f, Easing.Out); + content.Label.FadeOut(200).Expire(); - AddRange(new Drawable[] + Scheduler.AddDelayed(() => { - content = new CardContentBeatmap(beatmap, mods), - flashLayer, - }); + content.Expire(); + + var flashLayer = new Box { RelativeSizeAxes = Axes.Both }; - foreach (var user in users) - content.SelectionOverlay.AddUser(user); + AddRange(new Drawable[] + { + new CardContentBeatmap(beatmap, mods), + flashLayer, + }); - flashLayer.FadeOutFromOne(1000, Easing.In); + foreach (var user in users) + content.SelectionOverlay.AddUser(user); + + flashLayer.FadeOutFromOne(1000, Easing.In); + }, duration); } public override void AddUser(APIUser user) @@ -65,5 +86,18 @@ protected override bool OnClick(ClickEvent e) return base.OnClick(e); } + + private readonly struct PowEasingFunction(double exponent, bool easeOut = false) : IEasingFunction + { + public double ApplyEasing(double time) + { + if (easeOut) + time = 1 - time; + + double value = Math.Pow(time, exponent); + + return easeOut ? 1 - value : value; + } + } } } From e541e917a471744d332548bf9484cc435490ed24 Mon Sep 17 00:00:00 2001 From: marvin Date: Mon, 17 Nov 2025 07:32:27 +0100 Subject: [PATCH 096/836] Change order of tests --- .../Matchmaking/TestSceneBeatmapSelectGrid.cs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs index f7efbf06487b..daf9db85be7e 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs @@ -179,6 +179,23 @@ public void TestPresentUnanimouslyChosenBeatmap() }); } + [Test] + public void TestPresentRandomItem() + { + AddStep("present random item panel", () => + { + grid.TransferCandidatePanelsToRollContainer(pickRandomItems(4).candidateItems.Append(-1).ToArray(), duration: 0); + grid.ArrangeItemsForRollAnimation(duration: 0, stagger: 0); + grid.PlayRollAnimation(-1, duration: 0); + + Scheduler.AddDelayed(() => + { + grid.PresentUnanimouslyChosenBeatmap(-1); + grid.RevealRandomItem(items[RNG.Next(items.Length)].PlaylistItem); + }, 500); + }); + } + [TestCase(1)] [TestCase(2)] [TestCase(3)] @@ -219,23 +236,6 @@ public void TestPanelArrangement(int count) }); } - [Test] - public void TestPresentRandomItem() - { - AddStep("present random item panel", () => - { - grid.TransferCandidatePanelsToRollContainer(pickRandomItems(4).candidateItems.Append(-1).ToArray(), duration: 0); - grid.ArrangeItemsForRollAnimation(duration: 0, stagger: 0); - grid.PlayRollAnimation(-1, duration: 0); - - Scheduler.AddDelayed(() => - { - grid.PresentUnanimouslyChosenBeatmap(-1); - grid.RevealRandomItem(items[RNG.Next(items.Length)].PlaylistItem); - }, 500); - }); - } - private (long[] candidateItems, long finalItem) pickRandomItems(int count) { long[] candidateItems = items.Select(it => it.ID).ToArray(); From 424ef9237faffa7808292a5e4dbe1396af9edb31 Mon Sep 17 00:00:00 2001 From: marvin Date: Fri, 14 Nov 2025 23:11:50 +0100 Subject: [PATCH 097/836] Move result animation & sample implementation into selection panels --- .../TestSceneBeatmapSelectPanel.cs | 2 +- .../Match/BeatmapSelect/BeatmapSelectGrid.cs | 14 ++++---------- .../BeatmapSelect/MatchmakingSelectPanel.cs | 2 ++ .../MatchmakingSelectPanelBeatmap.cs | 18 +++++++++++++++++- .../MatchmakingSelectPanelRandom.cs | 19 +++++++++++++++---- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs index 9ac64288ed5d..d01a0cf2f87c 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs @@ -99,7 +99,7 @@ public void TestRandomPanel() AddToggleStep("allow selection", value => panel!.AllowSelection = value); - AddStep("reveal beatmap", () => panel!.RevealBeatmap(CreateAPIBeatmap(), [])); + // AddStep("reveal beatmap", () => panel!.RevealBeatmap(CreateAPIBeatmap(), [])); } [Test] diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs index d27b0e3818a3..11b9d1bfecd2 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs @@ -46,8 +46,6 @@ public partial class BeatmapSelectGrid : CompositeDrawable private readonly Sample?[] spinSamples = new Sample?[5]; private static readonly int[] spin_sample_sequence = [0, 1, 2, 3, 4, 2, 3, 4]; - private Sample? randomRevealSample; - private Sample? resultSample; private Sample? swooshSample; private double? lastSamplePlayback; @@ -81,8 +79,6 @@ private void load(AudioManager audio) for (int i = 0; i < spinSamples.Length; i++) spinSamples[i] = audio.Samples.Get($@"Multiplayer/Matchmaking/Selection/roulette-{i}"); - randomRevealSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Selection/random-reveal"); - resultSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Selection/roulette-result"); swooshSample = audio.Samples.Get(@"SongSelect/options-pop-out"); } @@ -150,8 +146,8 @@ public void RevealRandomItem(MultiplayerPlaylistItem item) => whenPanelsLoaded(( Debug.Assert(playlistItem != null); - randomRevealSample?.Play(); - randomPanel.RevealBeatmap(playlistItem.Beatmap, playlistItem.Mods); + // TODO: make this happen via panel.PresentAsChosenBeatmap + // randomPanel.RevealBeatmap(playlistItem.Beatmap, playlistItem.Mods); }); public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId) => whenPanelsLoaded(() => @@ -344,11 +340,9 @@ internal void PresentRolledBeatmap(long finalItem) { rollContainer.ChangeChildDepth(panel, float.MinValue); - panel.ShowChosenBorder(); - panel.MoveTo(Vector2.Zero, 1000, Easing.OutExpo) - .ScaleTo(1.5f, 1000, Easing.OutExpo); + var item = playlistItems[finalItem]; - resultSample?.Play(); + panel.PresentAsChosenBeatmap(item); }); } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs index ca10133a36dc..66d8b4249228 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs @@ -182,6 +182,8 @@ public void HideBorder() border.FadeOut(500, Easing.OutQuint); } + public abstract void PresentAsChosenBeatmap(MatchmakingPlaylistItem playlistItem); + public void FadeInAndEnterFromBelow(double duration = 500, double delay = 0, float distance = 200) { scaleContainer diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelBeatmap.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelBeatmap.cs index ec00ed3847dc..0f70c1b2ed05 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelBeatmap.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelBeatmap.cs @@ -2,8 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Graphics; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mods; +using osuTK; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect { @@ -20,13 +24,25 @@ public MatchmakingSelectPanelBeatmap(MatchmakingPlaylistItem item) } private CardContent content = null!; + private Sample? resultSample; [BackgroundDependencyLoader] - private void load() + private void load(AudioManager audio) { + resultSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Selection/roulette-result"); + Add(content = new CardContentBeatmap(beatmap, mods)); } + public override void PresentAsChosenBeatmap(MatchmakingPlaylistItem playlistItem) + { + ShowChosenBorder(); + this.MoveTo(Vector2.Zero, 1000, Easing.OutExpo) + .ScaleTo(1.5f, 1000, Easing.OutExpo); + + resultSample?.Play(); + } + public override void AddUser(APIUser user) { content.SelectionOverlay.AddUser(user); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs index 1c2114ad9118..26b0e6610f39 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs @@ -4,13 +4,14 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Transforms; using osu.Framework.Input.Events; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; -using osu.Game.Rulesets.Mods; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect { @@ -25,15 +26,21 @@ public MatchmakingSelectPanelRandom(MultiplayerPlaylistItem item) private Drawable diceProxy = null!; private readonly List users = new List(); + private Sample? resultSample; + private Sample? swooshSample; + [BackgroundDependencyLoader] - private void load() + private void load(AudioManager audio) { + resultSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Selection/roulette-result"); + swooshSample = audio.Samples.Get(@"SongSelect/options-pop-out"); + Add(content = new CardContentRandom()); AddInternal(diceProxy = content.Dice.CreateProxy()); } - public void RevealBeatmap(APIBeatmap beatmap, Mod[] mods) + public override void PresentAsChosenBeatmap(MatchmakingPlaylistItem playlistItem) { const double duration = 800; @@ -48,6 +55,8 @@ public void RevealBeatmap(APIBeatmap beatmap, Mod[] mods) content.Dice.RotateTo(content.Dice.Rotation - 360 * 5, duration * 1.3f, Easing.Out); content.Label.FadeOut(200).Expire(); + swooshSample?.Play(); + Scheduler.AddDelayed(() => { content.Expire(); @@ -56,7 +65,7 @@ public void RevealBeatmap(APIBeatmap beatmap, Mod[] mods) AddRange(new Drawable[] { - new CardContentBeatmap(beatmap, mods), + new CardContentBeatmap(playlistItem.Beatmap, playlistItem.Mods), flashLayer, }); @@ -64,6 +73,8 @@ public void RevealBeatmap(APIBeatmap beatmap, Mod[] mods) content.SelectionOverlay.AddUser(user); flashLayer.FadeOutFromOne(1000, Easing.In); + + resultSample?.Play(); }, duration); } From 1e05613859562cf0211665758ef8aa4058f34c50 Mon Sep 17 00:00:00 2001 From: marvin Date: Fri, 14 Nov 2025 23:23:44 +0100 Subject: [PATCH 098/836] Combine random card reveal & panel roll animation into the same event --- .../Matchmaking/TestSceneBeatmapSelectGrid.cs | 13 ++++++----- .../TestSceneBeatmapSelectPanel.cs | 2 +- .../Visual/Matchmaking/TestScenePickScreen.cs | 3 ++- .../Matchmaking/MatchmakingRoomState.cs | 9 ++++++++ .../Match/BeatmapSelect/BeatmapSelectGrid.cs | 22 +++++++++++++------ .../MatchmakingSelectPanelRandom.cs | 4 ++++ .../BeatmapSelect/SubScreenBeatmapSelect.cs | 3 ++- .../Match/ScreenMatchmaking.ScreenStack.cs | 2 +- 8 files changed, 42 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs index daf9db85be7e..8ed595dcb9ea 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs @@ -14,6 +14,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Mods; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect; @@ -131,7 +132,7 @@ public void TestCompleteRollAnimation() { var (candidateItems, finalItem) = pickRandomItems(5); - grid.RollAndDisplayFinalBeatmap(candidateItems, finalItem); + grid.RollAndDisplayFinalBeatmap(candidateItems, finalItem, MatchmakingRoomState.CandidateType.UserSelection); }); } @@ -160,7 +161,7 @@ public void TestPresentRolledBeatmap() grid.ArrangeItemsForRollAnimation(duration: 0, stagger: 0); grid.PlayRollAnimation(finalItem, duration: 0); - Scheduler.AddDelayed(() => grid.PresentRolledBeatmap(finalItem), 500); + Scheduler.AddDelayed(() => grid.PresentRolledBeatmap(finalItem, MatchmakingRoomState.CandidateType.UserSelection), 500); }); } @@ -175,7 +176,7 @@ public void TestPresentUnanimouslyChosenBeatmap() grid.ArrangeItemsForRollAnimation(duration: 0, stagger: 0); grid.PlayRollAnimation(finalItem, duration: 0); - Scheduler.AddDelayed(() => grid.PresentUnanimouslyChosenBeatmap(finalItem), 500); + Scheduler.AddDelayed(() => grid.PresentUnanimouslyChosenBeatmap(finalItem, MatchmakingRoomState.CandidateType.UserSelection), 500); }); } @@ -184,13 +185,15 @@ public void TestPresentRandomItem() { AddStep("present random item panel", () => { - grid.TransferCandidatePanelsToRollContainer(pickRandomItems(4).candidateItems.Append(-1).ToArray(), duration: 0); + var (candidateItems, finalItem) = pickRandomItems(4); + + grid.TransferCandidatePanelsToRollContainer(candidateItems.Append(-1).ToArray(), duration: 0); grid.ArrangeItemsForRollAnimation(duration: 0, stagger: 0); grid.PlayRollAnimation(-1, duration: 0); Scheduler.AddDelayed(() => { - grid.PresentUnanimouslyChosenBeatmap(-1); + grid.PresentRolledBeatmap(finalItem, MatchmakingRoomState.CandidateType.Random); grid.RevealRandomItem(items[RNG.Next(items.Length)].PlaylistItem); }, 500); }); diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs index d01a0cf2f87c..6eebb27ef0ec 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs @@ -99,7 +99,7 @@ public void TestRandomPanel() AddToggleStep("allow selection", value => panel!.AllowSelection = value); - // AddStep("reveal beatmap", () => panel!.RevealBeatmap(CreateAPIBeatmap(), [])); + AddStep("reveal beatmap", () => panel!.PresentAsChosenBeatmap(new MatchmakingPlaylistItem(new MultiplayerPlaylistItem(), CreateAPIBeatmap(), []))); } [Test] diff --git a/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs index e894616f9e3d..e63370a01eed 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs @@ -9,6 +9,7 @@ using osu.Framework.Utils; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect; using osu.Game.Tests.Visual.Multiplayer; @@ -104,7 +105,7 @@ public void TestScreen() long[] candidateItems = selectedItems.ToArray(); long finalItem = candidateItems[Random.Shared.Next(candidateItems.Length)]; - screen.RollFinalBeatmap(candidateItems, finalItem); + screen.RollFinalBeatmap(candidateItems, finalItem, MatchmakingRoomState.CandidateType.UserSelection); }); } } diff --git a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs index b55fa638442c..9bbc8f6f158a 100644 --- a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs @@ -45,6 +45,9 @@ public class MatchmakingRoomState : MatchRoomState [Key(4)] public MatchmakingUserList Users { get; set; } = new MatchmakingUserList(); + [Key(5)] + public CandidateType CandidateItemType { get; set; } + /// /// Advances to the next round. /// @@ -97,5 +100,11 @@ public void RecordScores(SoloScoreInfo[] scores, int[] placementPoints) foreach (var user in Users.Order(new MatchmakingUserComparer(CurrentRound))) user.Placement = i++; } + + public enum CandidateType + { + UserSelection, + Random, + } } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs index 11b9d1bfecd2..687e5314df8a 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs @@ -17,6 +17,7 @@ using osu.Framework.Utils; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osuTK; @@ -150,7 +151,7 @@ public void RevealRandomItem(MultiplayerPlaylistItem item) => whenPanelsLoaded(( // randomPanel.RevealBeatmap(playlistItem.Beatmap, playlistItem.Mods); }); - public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId) => whenPanelsLoaded(() => + public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId, MatchmakingRoomState.CandidateType candidateType) => whenPanelsLoaded(() => { Debug.Assert(candidateItemIds.Length >= 1); Debug.Assert(candidateItemIds.Contains(finalItemId)); @@ -166,7 +167,7 @@ public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId this.Delay(ARRANGE_DELAY) .Schedule(() => ArrangeItemsForRollAnimation()) .Delay(arrange_duration + present_beatmap_delay) - .Schedule(() => PresentUnanimouslyChosenBeatmap(finalItemId)); + .Schedule(() => PresentUnanimouslyChosenBeatmap(finalItemId, candidateType)); } else { @@ -175,7 +176,7 @@ public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId .Delay(arrange_duration) .Schedule(() => PlayRollAnimation(finalItemId, roll_duration)) .Delay(roll_duration + present_beatmap_delay) - .Schedule(() => PresentRolledBeatmap(finalItemId)); + .Schedule(() => PresentRolledBeatmap(finalItemId, candidateType)); } }); @@ -322,13 +323,20 @@ internal void PlayRollAnimation(long finalItem, double duration = roll_duration) } } - internal void PresentRolledBeatmap(long finalItem) + internal void PresentRolledBeatmap(long finalItem, MatchmakingRoomState.CandidateType candidateType) { + long itemToReveal = candidateType switch + { + MatchmakingRoomState.CandidateType.UserSelection => finalItem, + MatchmakingRoomState.CandidateType.Random => -1, + _ => throw new ArgumentOutOfRangeException(nameof(candidateType), candidateType, null) + }; + Debug.Assert(rollContainer.Children.Any(it => it.Item.ID == finalItem)); foreach (var panel in rollContainer.Children) { - if (panel.Item.ID != finalItem) + if (panel.Item.ID != itemToReveal) { panel.FadeOut(200); panel.PopOutAndExpire(easing: Easing.InQuad); @@ -347,11 +355,11 @@ internal void PresentRolledBeatmap(long finalItem) } } - internal void PresentUnanimouslyChosenBeatmap(long finalItem) + internal void PresentUnanimouslyChosenBeatmap(long finalItem, MatchmakingRoomState.CandidateType candidateType) { // TODO: display special animation in this case - PresentRolledBeatmap(finalItem); + PresentRolledBeatmap(finalItem, candidateType); } private readonly TaskCompletionSource panelsLoaded = new TaskCompletionSource(); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs index 26b0e6610f39..6acc1e3d8ec3 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs @@ -12,6 +12,7 @@ using osu.Framework.Input.Events; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; +using osuTK; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect { @@ -44,6 +45,9 @@ public override void PresentAsChosenBeatmap(MatchmakingPlaylistItem playlistItem { const double duration = 800; + this.MoveTo(Vector2.Zero, 1000, Easing.OutExpo) + .ScaleTo(1.5f, 1000, Easing.OutExpo); + content.Dice.MoveToY(-200, duration * 0.55, new PowEasingFunction(2.75, easeOut: true)) .Then() .Schedule(() => ChangeInternalChildDepth(diceProxy, float.MaxValue)) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs index 7951fc5448ec..358033d1c8e0 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs @@ -150,7 +150,8 @@ private void onSettingsChanged(MultiplayerRoomSettings settings) beatmapSelectGrid.RevealRandomItem(client.Room!.CurrentPlaylistItem); } - public void RollFinalBeatmap(long[] candidateItems, long finalItem) => beatmapSelectGrid.RollAndDisplayFinalBeatmap(candidateItems, finalItem); + public void RollFinalBeatmap(long[] candidateItems, long finalItem, MatchmakingRoomState.CandidateType panelType) => + beatmapSelectGrid.RollAndDisplayFinalBeatmap(candidateItems, finalItem, panelType); protected override void Dispose(bool isDisposing) { diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs index 279dd98a5efe..e14434499473 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs @@ -108,7 +108,7 @@ private void onMatchRoomStateChanged(MatchRoomState? state) => Scheduler.Add(() case MatchmakingStage.ServerBeatmapFinalised: Debug.Assert(screenStack.CurrentScreen is SubScreenBeatmapSelect); - ((SubScreenBeatmapSelect)screenStack.CurrentScreen).RollFinalBeatmap(matchmakingState.CandidateItems, matchmakingState.CandidateItem); + ((SubScreenBeatmapSelect)screenStack.CurrentScreen).RollFinalBeatmap(matchmakingState.CandidateItems, matchmakingState.CandidateItem, matchmakingState.CandidateItemType); break; case MatchmakingStage.ResultsDisplaying: From 1ca4c8860baa16cfc8c5f888789331c9de81c839 Mon Sep 17 00:00:00 2001 From: marvin Date: Fri, 14 Nov 2025 23:42:45 +0100 Subject: [PATCH 099/836] Add slight wiggle when random card reveals beatmap --- .../Match/BeatmapSelect/MatchmakingSelectPanel.cs | 12 ++++++------ .../BeatmapSelect/MatchmakingSelectPanelRandom.cs | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs index 66d8b4249228..23d5f8cfb005 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs @@ -37,7 +37,7 @@ public abstract partial class MatchmakingSelectPanel : Container private const float border_width = 3; - private Container scaleContainer = null!; + protected Container ScaleContainer = null!; private Drawable lighting = null!; private Container border = null!; @@ -52,7 +52,7 @@ private void load(OverlayColourProvider colourProvider) { InternalChildren = new Drawable[] { - scaleContainer = new Container + ScaleContainer = new Container { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, @@ -138,7 +138,7 @@ protected override void OnHoverLost(HoverLostEvent e) protected override bool OnMouseDown(MouseDownEvent e) { if (AllowSelection && e.Button == MouseButton.Left) - scaleContainer.ScaleTo(0.95f, 400, Easing.OutExpo); + ScaleContainer.ScaleTo(0.95f, 400, Easing.OutExpo); return base.OnMouseDown(e); } @@ -148,7 +148,7 @@ protected override void OnMouseUp(MouseUpEvent e) base.OnMouseUp(e); if (e.Button == MouseButton.Left) - scaleContainer.ScaleTo(1f, 500, Easing.OutElasticHalf); + ScaleContainer.ScaleTo(1f, 500, Easing.OutElasticHalf); } protected override bool OnClick(ClickEvent e) @@ -186,7 +186,7 @@ public void HideBorder() public void FadeInAndEnterFromBelow(double duration = 500, double delay = 0, float distance = 200) { - scaleContainer + ScaleContainer .FadeOut() .MoveToY(distance) .Delay(delay) @@ -198,7 +198,7 @@ public void PopOutAndExpire(double duration = 400, double delay = 0, Easing easi { AllowSelection = false; - scaleContainer.Delay(delay) + ScaleContainer.Delay(delay) .ScaleTo(0, duration, easing) .FadeOut(duration); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs index 6acc1e3d8ec3..c789c3dc746e 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs @@ -78,6 +78,10 @@ public override void PresentAsChosenBeatmap(MatchmakingPlaylistItem playlistItem flashLayer.FadeOutFromOne(1000, Easing.In); + ScaleContainer.ScaleTo(0.92f, 120, Easing.Out) + .Then() + .ScaleTo(1f, 600, Easing.OutElasticHalf); + resultSample?.Play(); }, duration); } From fe56ba292174f3b5389c6b0fd1ee5e10c2eacf46 Mon Sep 17 00:00:00 2001 From: marvin Date: Mon, 17 Nov 2025 07:46:05 +0100 Subject: [PATCH 100/836] Turn MatchmakingCandidateType into top level declaration --- .../Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs | 8 ++++---- .../Visual/Matchmaking/TestScenePickScreen.cs | 2 +- .../Matchmaking/MatchmakingCandidateType.cs | 11 +++++++++++ .../MatchTypes/Matchmaking/MatchmakingRoomState.cs | 8 +------- .../Match/BeatmapSelect/BeatmapSelectGrid.cs | 10 +++++----- .../Match/BeatmapSelect/SubScreenBeatmapSelect.cs | 2 +- .../Match/ScreenMatchmaking.ScreenStack.cs | 2 +- 7 files changed, 24 insertions(+), 19 deletions(-) create mode 100644 osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingCandidateType.cs diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs index 8ed595dcb9ea..c2c4b6a797e9 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs @@ -132,7 +132,7 @@ public void TestCompleteRollAnimation() { var (candidateItems, finalItem) = pickRandomItems(5); - grid.RollAndDisplayFinalBeatmap(candidateItems, finalItem, MatchmakingRoomState.CandidateType.UserSelection); + grid.RollAndDisplayFinalBeatmap(candidateItems, finalItem, MatchmakingCandidateType.UserSelection); }); } @@ -161,7 +161,7 @@ public void TestPresentRolledBeatmap() grid.ArrangeItemsForRollAnimation(duration: 0, stagger: 0); grid.PlayRollAnimation(finalItem, duration: 0); - Scheduler.AddDelayed(() => grid.PresentRolledBeatmap(finalItem, MatchmakingRoomState.CandidateType.UserSelection), 500); + Scheduler.AddDelayed(() => grid.PresentRolledBeatmap(finalItem, MatchmakingCandidateType.UserSelection), 500); }); } @@ -176,7 +176,7 @@ public void TestPresentUnanimouslyChosenBeatmap() grid.ArrangeItemsForRollAnimation(duration: 0, stagger: 0); grid.PlayRollAnimation(finalItem, duration: 0); - Scheduler.AddDelayed(() => grid.PresentUnanimouslyChosenBeatmap(finalItem, MatchmakingRoomState.CandidateType.UserSelection), 500); + Scheduler.AddDelayed(() => grid.PresentUnanimouslyChosenBeatmap(finalItem, MatchmakingCandidateType.UserSelection), 500); }); } @@ -193,7 +193,7 @@ public void TestPresentRandomItem() Scheduler.AddDelayed(() => { - grid.PresentRolledBeatmap(finalItem, MatchmakingRoomState.CandidateType.Random); + grid.PresentRolledBeatmap(finalItem, MatchmakingCandidateType.Random); grid.RevealRandomItem(items[RNG.Next(items.Length)].PlaylistItem); }, 500); }); diff --git a/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs index e63370a01eed..1b7cc90132bd 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs @@ -105,7 +105,7 @@ public void TestScreen() long[] candidateItems = selectedItems.ToArray(); long finalItem = candidateItems[Random.Shared.Next(candidateItems.Length)]; - screen.RollFinalBeatmap(candidateItems, finalItem, MatchmakingRoomState.CandidateType.UserSelection); + screen.RollFinalBeatmap(candidateItems, finalItem, MatchmakingCandidateType.UserSelection); }); } } diff --git a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingCandidateType.cs b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingCandidateType.cs new file mode 100644 index 000000000000..91b436088b77 --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingCandidateType.cs @@ -0,0 +1,11 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Online.Multiplayer.MatchTypes.Matchmaking +{ + public enum MatchmakingCandidateType + { + UserSelection, + Random, + } +} diff --git a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs index 9bbc8f6f158a..44774c350db0 100644 --- a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs @@ -46,7 +46,7 @@ public class MatchmakingRoomState : MatchRoomState public MatchmakingUserList Users { get; set; } = new MatchmakingUserList(); [Key(5)] - public CandidateType CandidateItemType { get; set; } + public MatchmakingCandidateType CandidateType { get; set; } /// /// Advances to the next round. @@ -100,11 +100,5 @@ public void RecordScores(SoloScoreInfo[] scores, int[] placementPoints) foreach (var user in Users.Order(new MatchmakingUserComparer(CurrentRound))) user.Placement = i++; } - - public enum CandidateType - { - UserSelection, - Random, - } } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs index 687e5314df8a..5da2546745d2 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs @@ -151,7 +151,7 @@ public void RevealRandomItem(MultiplayerPlaylistItem item) => whenPanelsLoaded(( // randomPanel.RevealBeatmap(playlistItem.Beatmap, playlistItem.Mods); }); - public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId, MatchmakingRoomState.CandidateType candidateType) => whenPanelsLoaded(() => + public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId, MatchmakingCandidateType candidateType) => whenPanelsLoaded(() => { Debug.Assert(candidateItemIds.Length >= 1); Debug.Assert(candidateItemIds.Contains(finalItemId)); @@ -323,12 +323,12 @@ internal void PlayRollAnimation(long finalItem, double duration = roll_duration) } } - internal void PresentRolledBeatmap(long finalItem, MatchmakingRoomState.CandidateType candidateType) + internal void PresentRolledBeatmap(long finalItem, MatchmakingCandidateType candidateType) { long itemToReveal = candidateType switch { - MatchmakingRoomState.CandidateType.UserSelection => finalItem, - MatchmakingRoomState.CandidateType.Random => -1, + MatchmakingCandidateType.UserSelection => finalItem, + MatchmakingCandidateType.Random => -1, _ => throw new ArgumentOutOfRangeException(nameof(candidateType), candidateType, null) }; @@ -355,7 +355,7 @@ internal void PresentRolledBeatmap(long finalItem, MatchmakingRoomState.Candidat } } - internal void PresentUnanimouslyChosenBeatmap(long finalItem, MatchmakingRoomState.CandidateType candidateType) + internal void PresentUnanimouslyChosenBeatmap(long finalItem, MatchmakingCandidateType candidateType) { // TODO: display special animation in this case diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs index 358033d1c8e0..c9cfa74e3e03 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs @@ -150,7 +150,7 @@ private void onSettingsChanged(MultiplayerRoomSettings settings) beatmapSelectGrid.RevealRandomItem(client.Room!.CurrentPlaylistItem); } - public void RollFinalBeatmap(long[] candidateItems, long finalItem, MatchmakingRoomState.CandidateType panelType) => + public void RollFinalBeatmap(long[] candidateItems, long finalItem, MatchmakingCandidateType panelType) => beatmapSelectGrid.RollAndDisplayFinalBeatmap(candidateItems, finalItem, panelType); protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs index e14434499473..ad517b0de566 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs @@ -108,7 +108,7 @@ private void onMatchRoomStateChanged(MatchRoomState? state) => Scheduler.Add(() case MatchmakingStage.ServerBeatmapFinalised: Debug.Assert(screenStack.CurrentScreen is SubScreenBeatmapSelect); - ((SubScreenBeatmapSelect)screenStack.CurrentScreen).RollFinalBeatmap(matchmakingState.CandidateItems, matchmakingState.CandidateItem, matchmakingState.CandidateItemType); + ((SubScreenBeatmapSelect)screenStack.CurrentScreen).RollFinalBeatmap(matchmakingState.CandidateItems, matchmakingState.CandidateItem, matchmakingState.CandidateType); break; case MatchmakingStage.ResultsDisplaying: From 76c0bd475051e453c9a0be8be233769a9c6258c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 17 Nov 2025 11:55:28 +0100 Subject: [PATCH 101/836] Add pooling support to smoke segments - Closes https://github.com/ppy/osu/issues/35703 - Supersedes / closes https://github.com/ppy/osu/pull/35711 Can test using something dumb like diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 11b3b5c71d..e21d8389ef 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -8,6 +8,7 @@ using System.Globalization; using System.IO; using System.Linq; +using System.Threading; using JetBrains.Annotations; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; @@ -540,6 +541,10 @@ protected override void ParseConfigurationStream(Stream stream) case "Menu/fountain-star": componentName = "star2"; break; + + case "cursor-smoke": + Thread.Sleep(500); + break; } Texture? texture = null; --- .../Skinning/SmokeSegment.cs | 9 ++++++-- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 21 +++++++++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index f4fe42b8de5f..2962bce635cd 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -77,9 +77,14 @@ protected override void LoadComplete() base.LoadComplete(); RelativeSizeAxes = Axes.Both; + } - LifetimeStart = smokeStartTime = Time.Current; - + public void StartDrawing(double time) + { + LifetimeStart = smokeStartTime = time; + LifetimeEnd = smokeEndTime = double.MaxValue; + SmokePoints.Clear(); + lastPosition = null; totalDistance = pointInterval; } diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index 389440ba2dc5..ff28444e82b6 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -1,9 +1,9 @@ // 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 osu.Framework.Graphics; +using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Pooling; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; @@ -19,17 +19,24 @@ namespace osu.Game.Rulesets.Osu.UI /// public partial class SmokeContainer : Container, IRequireHighFrequencyMousePosition, IKeyBindingHandler { + private DrawablePool segmentPool = null!; private SmokeSkinnableDrawable? currentSegmentSkinnable; private Vector2 lastMousePosition; public override bool ReceivePositionalInputAt(Vector2 _) => true; + [BackgroundDependencyLoader] + private void load() + { + AddInternal(segmentPool = new DrawablePool(10)); + } + public bool OnPressed(KeyBindingPressEvent e) { if (e.Action == OsuAction.Smoke) { - AddInternal(currentSegmentSkinnable = new SmokeSkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.CursorSmoke), _ => new DefaultSmokeSegment())); + AddInternal(currentSegmentSkinnable = segmentPool.Get(segment => segment.Segment?.StartDrawing(Time.Current))); // Add initial position immediately. addPosition(); @@ -59,17 +66,19 @@ protected override bool OnMouseMove(MouseMoveEvent e) return base.OnMouseMove(e); } - private void addPosition() => (currentSegmentSkinnable?.Drawable as SmokeSegment)?.AddPosition(lastMousePosition, Time.Current); + private void addPosition() => currentSegmentSkinnable?.Segment?.AddPosition(lastMousePosition, Time.Current); private partial class SmokeSkinnableDrawable : SkinnableDrawable { + public SmokeSegment? Segment => Drawable as SmokeSegment; + public override bool RemoveWhenNotAlive => true; public override double LifetimeStart => Drawable.LifetimeStart; public override double LifetimeEnd => Drawable.LifetimeEnd; - public SmokeSkinnableDrawable(ISkinComponentLookup lookup, Func? defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) - : base(lookup, defaultImplementation, confineMode) + public SmokeSkinnableDrawable() + : base(new OsuSkinComponentLookup(OsuSkinComponents.CursorSmoke), _ => new DefaultSmokeSegment()) { } } From 214122f633f5c61260964ef076e15e25250a28bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 17 Nov 2025 12:01:27 +0100 Subject: [PATCH 102/836] Fix bad localisation reuse in pause overlay (#35717) Closes https://github.com/ppy/osu-resources/issues/393. Matches break overlay: https://github.com/ppy/osu/blob/5dc44fbdf9dfaff573f596b0085a954c6f420e07/osu.Game/Screens/Play/Break/BreakInfo.cs#L48 --- osu.Game/Screens/Play/GameplayMenuOverlay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index 7d946dc6786f..d4c40c78ae3a 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -22,6 +22,7 @@ using osuTK; using osuTK.Graphics; using osu.Game.Localisation; +using osu.Game.Resources.Localisation.Web; using osu.Game.Utils; namespace osu.Game.Screens.Play @@ -236,7 +237,7 @@ private void updateInfoText() if (gameplayState != null) { playInfoText.NewLine(); - playInfoText.AddText(SongSelectStrings.Accuracy); + playInfoText.AddText(BeatmapsetsStrings.ShowScoreboardHeadersAccuracy); playInfoText.AddText(": "); playInfoText.AddText(gameplayState!.ScoreProcessor.Accuracy.Value.FormatAccuracy(), cp => cp.Font = cp.Font.With(weight: FontWeight.Bold)); } From 7b952b83bf5f56f03aa0ee993c64a9bc446aae89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 17 Nov 2025 13:55:53 +0100 Subject: [PATCH 103/836] Fix test --- osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs index d5d3cbb146be..0e7d94cb9f3d 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Input.Events; @@ -10,6 +11,7 @@ using osu.Framework.Logging; using osu.Framework.Testing.Input; using osu.Game.Rulesets.Osu.UI; +using osu.Game.Skinning; using osuTK; namespace osu.Game.Rulesets.Osu.Tests @@ -58,7 +60,7 @@ private void addStep(string stepName, double duration) foreach (var smokeContainer in smokeContainers) { - if (smokeContainer.Children.Count != 0) + if (smokeContainer.Children.OfType().Any()) return false; } From ae5584bd88d35ff5a5e4be0708e577eadcb03838 Mon Sep 17 00:00:00 2001 From: Kawaritai <72053972+Kawaritai@users.noreply.github.com> Date: Tue, 18 Nov 2025 14:10:18 +1100 Subject: [PATCH 104/836] Center window within usable bounds --- .../Settings/Sections/Graphics/LayoutSettings.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 99d47aab1fcf..36a273f41211 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -255,8 +255,17 @@ protected override void LoadComplete() window.WindowState = Framework.Platform.WindowState.Normal; } - windowedPositionX.Value = 0.5; - windowedPositionY.Value = 0.5; + var dBounds = currentDisplay.Value.Bounds; + var dUsable = currentDisplay.Value.UsableBounds; + int w = size.NewValue.Width; + int h = size.NewValue.Height; + + float adjustedY = Math.Max( + dUsable.Y + (dUsable.Height - h) / 2f, + dUsable.Y + (host.Window?.BorderSize.Value.Top ?? 0) // titlebar adjustment + ); + windowedPositionY.Value = dBounds.Height - h != 0 ? (adjustedY - dBounds.Y) / (dBounds.Height - h) : 0; + windowedPositionX.Value = dBounds.Width - w != 0 ? (dUsable.X - dBounds.X + (dUsable.Width - w) / 2f) / (dBounds.Width - w) : 0; }); sizeWindowed.BindValueChanged(size => From 0c341c1f3e36921186b0d3fac03a20df2bf96312 Mon Sep 17 00:00:00 2001 From: Kawaritai <72053972+Kawaritai@users.noreply.github.com> Date: Tue, 18 Nov 2025 14:38:34 +1100 Subject: [PATCH 105/836] Clamp sizing --- .../Settings/Sections/Graphics/LayoutSettings.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 36a273f41211..e1b1b7ccce7f 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -248,8 +248,6 @@ protected override void LoadComplete() if (size.NewValue == sizeWindowed.Value || windowModeDropdown.Current.Value != WindowMode.Windowed) return; - sizeWindowed.Value = size.NewValue; - if (window?.WindowState == Framework.Platform.WindowState.Maximised) { window.WindowState = Framework.Platform.WindowState.Normal; @@ -257,12 +255,17 @@ protected override void LoadComplete() var dBounds = currentDisplay.Value.Bounds; var dUsable = currentDisplay.Value.UsableBounds; - int w = size.NewValue.Width; - int h = size.NewValue.Height; + float topBar = host.Window?.BorderSize.Value.Top ?? 0; + + int w = Math.Min(size.NewValue.Width, dUsable.Width); + int h = (int)Math.Min(size.NewValue.Height, dUsable.Height - topBar); + + windowedResolution.Value = new Size(w, h); + sizeWindowed.Value = windowedResolution.Value; float adjustedY = Math.Max( dUsable.Y + (dUsable.Height - h) / 2f, - dUsable.Y + (host.Window?.BorderSize.Value.Top ?? 0) // titlebar adjustment + dUsable.Y + topBar // titlebar adjustment ); windowedPositionY.Value = dBounds.Height - h != 0 ? (adjustedY - dBounds.Y) / (dBounds.Height - h) : 0; windowedPositionX.Value = dBounds.Width - w != 0 ? (dUsable.X - dBounds.X + (dUsable.Width - w) / 2f) / (dBounds.Width - w) : 0; From 96dd95940fd9da26a8205245c9f7401a7ec93a01 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 18 Nov 2025 16:08:44 +0900 Subject: [PATCH 106/836] Add simple "Add to playlist" button in the footer --- .../TestScenePlaylistsSongSelectV2.cs | 6 ++ .../TestSceneAddToPlaylistFooterButton.cs | 40 +++++++++++ .../Playlists/AddToPlaylistFooterButton.cs | 68 +++++++++++++++++++ .../Playlists/PlaylistsSongSelectV2.cs | 63 +++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 osu.Game.Tests/Visual/Playlists/TestSceneAddToPlaylistFooterButton.cs create mode 100644 osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs index ec853669af75..1d78896ce7c0 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs @@ -69,6 +69,12 @@ public override void SetUpSteps() AddUntilStep("wait for song select", () => songSelect.IsLoaded && !songSelect.IsFiltering); } + [Test] + public void TestShowScreen() + { + AddStep("show screen", () => { }); + } + [Test] public void TestItemAddedIfEmptyOnStart() { diff --git a/osu.Game.Tests/Visual/Playlists/TestSceneAddToPlaylistFooterButton.cs b/osu.Game.Tests/Visual/Playlists/TestSceneAddToPlaylistFooterButton.cs new file mode 100644 index 000000000000..a693738ad613 --- /dev/null +++ b/osu.Game.Tests/Visual/Playlists/TestSceneAddToPlaylistFooterButton.cs @@ -0,0 +1,40 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Overlays; +using osu.Game.Screens.OnlinePlay.Playlists; + +namespace osu.Game.Tests.Visual.Playlists +{ + public class TestSceneAddToPlaylistFooterButton : OsuTestScene + { + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + + private AddToPlaylistFooterButton button = null!; + + [SetUp] + public void Setup() => Schedule(() => + { + Child = button = new AddToPlaylistFooterButton + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Action = () => { } + }; + }); + + [Test] + public void TestAppearDisappear() + { + AddStep("appear", () => button.Appear()); + AddWaitStep("wait for animation", 3); + AddStep("disappear", () => button.Disappear()); + AddWaitStep("wait for animation", 3); + AddStep("appear", () => button.Appear()); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs new file mode 100644 index 000000000000..1815bd9dcba5 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs @@ -0,0 +1,68 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Transforms; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.OnlinePlay.Playlists +{ + public partial class AddToPlaylistFooterButton : ShearedButton + { + public AddToPlaylistFooterButton() + : base(width: 220) + { + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + DarkerColour = colours.Blue3; + LighterColour = colours.Blue1; + + ButtonContent.Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + X = -10, + Font = OsuFont.TorusAlternate.With(size: 17), + Text = "Add to playlist", + UseFullGlyphHeight = false, + }, + new OsuSpriteText + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + X = 35, + Font = OsuFont.TorusAlternate.With(size: 20), + Shadow = false, + Text = "+", + UseFullGlyphHeight = false, + }, + }; + } + + public void Appear() + { + FinishTransforms(); + + this.MoveToY(150f) + .FadeOut() + .MoveToY(0f, 240, Easing.OutCubic) + .FadeIn(240, Easing.OutCubic); + } + + public TransformSequence Disappear() + { + FinishTransforms(); + + return this.FadeOut(240, Easing.InOutCubic) + .MoveToY(150f, 240, Easing.InOutCubic); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index cee4e549a78b..a301f19dddab 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -16,6 +16,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Footer; +using osu.Game.Screens.Menu; using osu.Game.Screens.SelectV2; using osu.Game.Utils; @@ -30,6 +31,8 @@ public partial class PlaylistsSongSelectV2 : SongSelect, IOnlinePlaySubScreen protected readonly Bindable Freestyle = new Bindable(true); private readonly Bindable> freeMods = new Bindable>([]); + private readonly AddToPlaylistFooterButton addToPlaylistFooterButton; + private readonly Room room; private ModSelectOverlay modSelect = null!; private FreeModSelectOverlay freeModSelect = null!; @@ -40,6 +43,19 @@ public PlaylistsSongSelectV2(Room room) Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; LeftPadding = new MarginPadding { Top = CORNER_RADIUS_HIDE_OFFSET + Header.HEIGHT }; + + addToPlaylistFooterButton = new AddToPlaylistFooterButton + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Margin = new MarginPadding + { + Bottom = OsuGame.SCREEN_EDGE_MARGIN, + Right = OsuGame.SCREEN_EDGE_MARGIN * 2 + }, + Alpha = 0, + Action = AddNewItem + }; } [BackgroundDependencyLoader] @@ -61,6 +77,8 @@ protected override void LoadComplete() Freestyle.BindValueChanged(onFreestyleChanged); updateValidMods(); + + Footer?.Add(addToPlaylistFooterButton); } public void AddNewItem() @@ -126,6 +144,51 @@ protected override void OnStart() this.Exit(); } + public override void OnEntering(ScreenTransitionEvent e) + { + base.OnEntering(e); + + addToPlaylistFooterButton.Appear(); + } + + public override void OnResuming(ScreenTransitionEvent e) + { + base.OnResuming(e); + + addToPlaylistFooterButton.Appear(); + } + + public override void OnSuspending(ScreenTransitionEvent e) + { + base.OnSuspending(e); + + addToPlaylistFooterButton.Disappear(); + } + + public override bool OnExiting(ScreenExitEvent e) + { + if (base.OnExiting(e)) + return true; + + addToPlaylistFooterButton.Disappear().Expire(); + return false; + } + + protected override void LogoArriving(OsuLogo logo, bool resuming) + { + // Intentionally not calling base so the logo isn't shown. + } + + protected override void LogoExiting(OsuLogo logo) + { + // Intentionally not calling base so the logo isn't shown. + } + + protected override void LogoSuspending(OsuLogo logo) + { + // Intentionally not calling base so the logo isn't shown. + } + public override IReadOnlyList CreateFooterButtons() { var buttons = base.CreateFooterButtons().ToList(); From 549cc08bfe4cbde8180a05650fceb7974ce6bb35 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 18 Nov 2025 16:12:24 +0900 Subject: [PATCH 107/836] Remove add button from playlist popup --- .../TestSceneFooterButtonPlaylistV2.cs | 2 - .../OnlinePlay/FooterButtonPlaylistV2.cs | 51 ++----------------- .../Playlists/PlaylistsSongSelectV2.cs | 5 +- 3 files changed, 6 insertions(+), 52 deletions(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonPlaylistV2.cs b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonPlaylistV2.cs index dc84102aef7a..730696c36377 100644 --- a/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonPlaylistV2.cs +++ b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonPlaylistV2.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Cursor; @@ -29,7 +28,6 @@ public TestSceneFooterButtonPlaylistV2() Anchor = Anchor.Centre, Origin = Anchor.CentreLeft, X = -100, - CreateNewItem = () => room.Playlist = room.Playlist.Append(new PlaylistItem(CreateAPIBeatmap())).ToArray() } }); } diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs index fdf6c09e69c3..f5f5024d4f93 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs @@ -1,13 +1,11 @@ // 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.ComponentModel; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; @@ -18,14 +16,11 @@ using osu.Game.Screens.Footer; using osu.Game.Screens.OnlinePlay.Playlists; using osuTK; -using Container = osu.Framework.Graphics.Containers.Container; namespace osu.Game.Screens.OnlinePlay { public partial class FooterButtonPlaylistV2 : ScreenFooterButton, IHasPopover { - public required Action? CreateNewItem { get; init; } - private readonly Room room; public FooterButtonPlaylistV2(Room room) @@ -43,15 +38,10 @@ private void load(OsuColour colour) Action = this.ShowPopover; } - public Popover GetPopover() => new PlaylistPopover(room) - { - CreateNewItem = CreateNewItem - }; + public Popover GetPopover() => new PlaylistPopover(room); private partial class PlaylistPopover : OsuPopover { - public required Action? CreateNewItem { get; init; } - private readonly Room room; private PlaylistsRoomSettingsPlaylist playlist = null!; @@ -66,43 +56,12 @@ public PlaylistPopover(Room room) [BackgroundDependencyLoader] private void load() { - Content.Padding = new MarginPadding(5); + Content.Padding = new MarginPadding(10); - Add(new GridContainer + Child = playlist = new PlaylistsRoomSettingsPlaylist { - Size = new Vector2(300, 300), - Padding = new MarginPadding { Vertical = 10 }, - Content = new[] - { - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Bottom = 10 }, - Child = playlist = new PlaylistsRoomSettingsPlaylist - { - RelativeSizeAxes = Axes.Both - } - } - }, - new Drawable[] - { - new RoundedButton - { - Text = "Add new playlist entry", - RelativeSizeAxes = Axes.Both, - Size = Vector2.One, - Action = () => CreateNewItem?.Invoke() - } - }, - }, - RowDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.Absolute, 50), - } - }); + Size = new Vector2(300) + }; } protected override void LoadComplete() diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index a301f19dddab..ea5fc1536c4c 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -195,10 +195,7 @@ public override IReadOnlyList CreateFooterButtons() buttons.Single(i => i is FooterButtonMods).TooltipText = MultiplayerMatchStrings.RequiredModsButtonTooltip; - buttons.Insert(0, new FooterButtonPlaylistV2(room) - { - CreateNewItem = AddNewItem - }); + buttons.Insert(0, new FooterButtonPlaylistV2(room)); buttons.InsertRange(buttons.FindIndex(b => b is FooterButtonMods) + 1, [ From bb017ade649926e5846ba50cf1d22df528b79d8c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 18 Nov 2025 17:26:34 +0900 Subject: [PATCH 108/836] Add simple tray --- .../Visual/Playlists/TestScenePlaylistTray.cs | 38 ++++++ .../PlaylistsSongSelectV2.PlaylistTray.cs | 128 ++++++++++++++++++ .../Playlists/PlaylistsSongSelectV2.cs | 21 ++- 3 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs create mode 100644 osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs new file mode 100644 index 000000000000..5efb85915749 --- /dev/null +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs @@ -0,0 +1,38 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Playlists; +using osu.Game.Tests.Visual.OnlinePlay; + +namespace osu.Game.Tests.Visual.Playlists +{ + public partial class TestScenePlaylistTray : OnlinePlayTestScene + { + private Room room = null!; + private PlaylistsSongSelectV2.PlaylistTray tray = null!; + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("add tray", () => Child = tray = new PlaylistsSongSelectV2.PlaylistTray(room = new Room()) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }); + } + + [Test] + public void TestAddItem() + { + AddStep("add playlist item", () => + { + room.Playlist = room.Playlist.Append(new PlaylistItem(CreateAPIBeatmap())).ToArray(); + }); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs new file mode 100644 index 000000000000..f2c210b33bc9 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs @@ -0,0 +1,128 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.ComponentModel; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Rooms; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Playlists +{ + public partial class PlaylistsSongSelectV2 + { + public partial class PlaylistTray : CompositeDrawable + { + private readonly Room room; + + private OsuScrollContainer scroll = null!; + private FillFlowContainer flow = null!; + + public PlaylistTray(Room room) + { + this.room = room; + + Size = new Vector2(400, 75); + } + + [BackgroundDependencyLoader] + private void load() + { + Masking = true; + CornerRadius = 20; + + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.9f + }, + new GridContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Height = DrawableRoomPlaylistItem.HEIGHT, + Padding = new MarginPadding { Horizontal = 20 }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension() + }, + Content = new[] + { + new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = "Playlist", + Font = OsuFont.Default.With(size: 20) + }, + scroll = new OsuScrollContainer(Direction.Horizontal) + { + RelativeSizeAxes = Axes.Both, + Margin = new MarginPadding { Left = 10 }, + ScrollbarVisible = false, + Child = flow = new FillFlowContainer + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Direction = FillDirection.Horizontal + } + } + }, + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + room.PropertyChanged += onRoomPropertyChanged; + updateRoomPlaylist(); + } + + private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(Room.Playlist)) + updateRoomPlaylist(); + } + + private void updateRoomPlaylist() + { + if (room.Playlist.Count > 0) + { + flow.Add(new DrawableRoomPlaylistItem(room.Playlist[^1], loadImmediately: true) + { + RelativeSizeAxes = Axes.None, + Width = 250, + AllowReordering = false, + }); + } + + scroll.ScrollToStart(animated: false); + + this.FadeIn(200); + ScheduleAfterChildren(() => scroll.ScrollToEnd()); + this.Delay(1000).FadeOut(200); + } + + // Disallow the user from interacting with the scrolling elements. + public override bool PropagatePositionalInputSubTree => false; + public override bool PropagateNonPositionalInputSubTree => false; + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index ea5fc1536c4c..2ceecf69850a 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -61,10 +61,23 @@ public PlaylistsSongSelectV2(Room room) [BackgroundDependencyLoader] private void load() { - AddInternal(freeModSelect = new FreeModSelectOverlay + AddRangeInternal(new Drawable[] { - SelectedMods = { BindTarget = freeMods }, - IsValidMod = isValidAllowedMod, + freeModSelect = new FreeModSelectOverlay + { + SelectedMods = { BindTarget = freeMods }, + IsValidMod = isValidAllowedMod, + }, + new PlaylistTray(room) + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Margin = new MarginPadding + { + Bottom = ScreenFooterButton.HEIGHT, + Right = OsuGame.SCREEN_EDGE_MARGIN + } + } }); } @@ -195,8 +208,6 @@ public override IReadOnlyList CreateFooterButtons() buttons.Single(i => i is FooterButtonMods).TooltipText = MultiplayerMatchStrings.RequiredModsButtonTooltip; - buttons.Insert(0, new FooterButtonPlaylistV2(room)); - buttons.InsertRange(buttons.FindIndex(b => b is FooterButtonMods) + 1, [ new FooterButtonFreeModsV2(freeModSelect) From 19b6761697b214230a485a5c37f261903e2c7b66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 18 Nov 2025 09:39:06 +0100 Subject: [PATCH 109/836] Clarify target branch requirements in `CONTRIBUTING.md` Because it appears to be a point of confusion to new contributors (https://github.com/ppy/osu/pull/35725#issuecomment-3545734262). --- CONTRIBUTING.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ebe1e0807477..1d9861baf719 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,6 +73,9 @@ Aside from the above, below is a brief checklist of things to watch out when you After you're done with your changes and you wish to open the PR, please observe the following recommendations: - Please submit the pull request from a [topic branch](https://git-scm.com/book/en/v2/Git-Branching-Branching-Workflows#_topic_branch) (not `master`), and keep the *Allow edits from maintainers* check box selected, so that we can push fixes to your PR if necessary. +- Please pick the following target branch for your pull request: + - `pp-dev`, if the change impacts star rating or performance points calculations for any of the rulesets, + - `master`, otherwise. - Please avoid pushing untested or incomplete code. - Please do not force-push or rebase unless we ask you to. - Please do not merge `master` continually if there are no conflicts to resolve. We will do this for you when the change is ready for merge. From fbd83cb0482b9f73c8bfe20c52cbb28b21a5d2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 18 Nov 2025 09:50:42 +0100 Subject: [PATCH 110/836] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 6f0543935bc0..2df686d354c1 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index adab5435ea76..74dae877f12f 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From f0ca079fe6f0e0f2006bc44e1357475db93f28a0 Mon Sep 17 00:00:00 2001 From: Urantij Date: Tue, 18 Nov 2025 15:52:37 +0700 Subject: [PATCH 111/836] Fix cursor incorrectly flashing red after a rewind in replays with Alternate mod active (#35725) * Fix red cursor with alt mod when rewind * Change rewind detection in input blocking --- osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs b/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs index b56fdbdf74e7..34eb2be07743 100644 --- a/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs +++ b/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs @@ -67,6 +67,9 @@ public void Update(Playfield playfield) { if (LastAcceptedAction != null && nonGameplayPeriods.IsInAny(gameplayClock.CurrentTime)) LastAcceptedAction = null; + + if (LastAcceptedAction != null && gameplayClock.IsRewinding) + LastAcceptedAction = null; } protected abstract bool CheckValidNewAction(OsuAction action); From 89f2c7160d91ed991fea7db7de6b6ca425521969 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Nov 2025 18:45:38 +0900 Subject: [PATCH 112/836] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 6f0543935bc0..2df686d354c1 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index adab5435ea76..74dae877f12f 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From 9c2319b98992c5698c0b530b6a6612c00481f27e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 18 Nov 2025 14:40:47 +0100 Subject: [PATCH 113/836] Use existing bindables instead of refetching --- osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index a355205a851c..314e1a1f4cbb 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -170,10 +170,10 @@ private void load(OsuColour colours, LocalisationManager localisation, OsuConfig float gameplayWidth = host.Window.ClientSize.Width; float gameplayHeight = host.Window.ClientSize.Height; - if (osuConfig.Get(OsuSetting.Scaling) == ScalingMode.Everything) + if (scalingMode.Value == ScalingMode.Everything) { - gameplayWidth *= osuConfig.Get(OsuSetting.ScalingSizeX); - gameplayHeight *= osuConfig.Get(OsuSetting.ScalingSizeY); + gameplayWidth *= scalingSizeX.Value; + gameplayHeight *= scalingSizeY.Value; } forceAspectRatio(gameplayWidth / gameplayHeight); From 80fbcd5fbdbd46c9fa26fa0b6528f7679439b58d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 18 Nov 2025 14:41:10 +0100 Subject: [PATCH 114/836] Move application of scaling to tablet output area to scaling container It's the safest place for it to be there, really. --- .../Graphics/Containers/ScalingContainer.cs | 15 ++++++++++- .../Settings/Sections/Input/TabletSettings.cs | 25 ------------------- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/osu.Game/Graphics/Containers/ScalingContainer.cs b/osu.Game/Graphics/Containers/ScalingContainer.cs index 9d2a1c16af99..22dabc55ce09 100644 --- a/osu.Game/Graphics/Containers/ScalingContainer.cs +++ b/osu.Game/Graphics/Containers/ScalingContainer.cs @@ -1,11 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; +using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Layout; using osu.Framework.Platform; using osu.Framework.Screens; @@ -50,6 +52,8 @@ public partial class ScalingContainer : Container private RectangleF? customRect; private bool customRectIsRelativePosition; + private ITabletHandler? tabletHandler; + /// /// Set a custom position and scale which overrides any user specification. /// @@ -123,7 +127,7 @@ protected override void Update() } [BackgroundDependencyLoader] - private void load(OsuConfigManager config, ISafeArea safeArea) + private void load(GameHost host, OsuConfigManager config, ISafeArea safeArea) { scalingMode = config.GetBindable(OsuSetting.Scaling); scalingMode.ValueChanged += _ => Scheduler.AddOnce(updateSize); @@ -148,6 +152,8 @@ private void load(OsuConfigManager config, ISafeArea safeArea) scalingMenuBackgroundDim = config.GetBindable(OsuSetting.ScalingBackgroundDim); scalingMenuBackgroundDim.ValueChanged += _ => Scheduler.AddOnce(updateSize); + + tabletHandler = host.AvailableInputHandlers.OfType().SingleOrDefault(); } protected override void LoadComplete() @@ -222,6 +228,13 @@ private void updateSize() // An example of how this can occur is when the skin editor is visible and the game screen scaling is set to "Everything". sizableContainer.TransformTo(nameof(CornerRadius), requiresMasking ? corner_radius : 0, TRANSITION_DURATION, requiresMasking ? Easing.OutQuart : Easing.None) .OnComplete(_ => { sizableContainer.Masking = requiresMasking; }); + + // when "everything" scaling mode is active, tablets are expected to constrain output area to the scaled size of the game + if (tabletHandler != null) + { + tabletHandler.OutputAreaSize.Value = scalingMode.Value == ScalingMode.Everything ? new Vector2(sizeX.Value, sizeY.Value) : Vector2.One; + tabletHandler.OutputAreaOffset.Value = scalingMode.Value == ScalingMode.Everything ? new Vector2(posX.Value, posY.Value) : new Vector2(0.5f); + } } private partial class ScalingBackgroundScreen : BackgroundScreenDefault diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 314e1a1f4cbb..9ef2fc093310 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -52,8 +52,6 @@ public partial class TabletSettings : SettingsSubsection private Bindable scalingMode = null!; private Bindable scalingSizeX = null!; private Bindable scalingSizeY = null!; - private Bindable scalingPositionX = new Bindable(); - private Bindable scalingPositionY = new Bindable(); [Resolved] private GameHost host { get; set; } @@ -91,8 +89,6 @@ private void load(OsuColour colours, LocalisationManager localisation, OsuConfig scalingMode = osuConfig.GetBindable(OsuSetting.Scaling); scalingSizeX = osuConfig.GetBindable(OsuSetting.ScalingSizeX); scalingSizeY = osuConfig.GetBindable(OsuSetting.ScalingSizeY); - scalingPositionX = osuConfig.GetBindable(OsuSetting.ScalingPositionX); - scalingPositionY = osuConfig.GetBindable(OsuSetting.ScalingPositionY); Children = new Drawable[] { @@ -299,13 +295,6 @@ protected override void LoadComplete() aspectRatioApplication = Schedule(() => forceAspectRatio(aspect.NewValue)); }); - updateScaling(); - scalingMode.BindValueChanged(_ => updateScaling()); - scalingSizeX.BindValueChanged(_ => updateScaling()); - scalingSizeY.BindValueChanged(_ => updateScaling()); - scalingPositionX.BindValueChanged(_ => updateScaling()); - scalingPositionY.BindValueChanged(_ => updateScaling()); - pressureThreshold.BindTo(tabletHandler.PressureThreshold); tablet.BindTo(tabletHandler.Tablet); @@ -393,20 +382,6 @@ private void forceAspectRatio(float aspectRatio) aspectLock.Value = true; } - private void updateScaling() - { - if (scalingMode.Value == ScalingMode.Everything) - { - outputAreaSize.Value = new Vector2(scalingSizeX.Value, scalingSizeY.Value); - outputAreaOffset.Value = new Vector2(scalingPositionX.Value, scalingPositionY.Value); - } - else - { - outputAreaSize.Value = new Vector2(1, 1); - outputAreaOffset.Value = new Vector2(0.5f, 0.5f); - } - } - private void updateAspectRatio() => aspectRatio.Value = currentAspectRatio; private float currentAspectRatio => sizeX.Value / sizeY.Value; From 277f4268db271250a43cdb46bcdd45ae7bb98b9d Mon Sep 17 00:00:00 2001 From: marvin Date: Tue, 18 Nov 2025 19:33:59 +0100 Subject: [PATCH 115/836] Remove `BeatmapSelectGrid.RevealRandomItem` method --- .../Matchmaking/TestSceneBeatmapSelectGrid.cs | 2 -- .../Match/BeatmapSelect/BeatmapSelectGrid.cs | 10 ---------- .../BeatmapSelect/SubScreenBeatmapSelect.cs | 16 ---------------- 3 files changed, 28 deletions(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs index c2c4b6a797e9..f2448a5e2635 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs @@ -8,7 +8,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing; -using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -194,7 +193,6 @@ public void TestPresentRandomItem() Scheduler.AddDelayed(() => { grid.PresentRolledBeatmap(finalItem, MatchmakingCandidateType.Random); - grid.RevealRandomItem(items[RNG.Next(items.Length)].PlaylistItem); }, 500); }); } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs index 5da2546745d2..f5796fe76086 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs @@ -141,16 +141,6 @@ public void SetUserSelection(APIUser user, long itemId, bool selected) => whenPa panel.RemoveUser(user); }); - public void RevealRandomItem(MultiplayerPlaylistItem item) => whenPanelsLoaded(() => - { - playlistItems.TryGetValue(item.ID, out var playlistItem); - - Debug.Assert(playlistItem != null); - - // TODO: make this happen via panel.PresentAsChosenBeatmap - // randomPanel.RevealBeatmap(playlistItem.Beatmap, playlistItem.Mods); - }); - public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId, MatchmakingCandidateType candidateType) => whenPanelsLoaded(() => { Debug.Assert(candidateItemIds.Length >= 1); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs index c9cfa74e3e03..5f6886d23a39 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs @@ -79,7 +79,6 @@ protected override void LoadComplete() beatmapSelectGrid.ItemSelected += item => client.MatchmakingToggleSelection(item.ID); client.MatchmakingItemSelected += onItemSelected; client.MatchmakingItemDeselected += onItemDeselected; - client.SettingsChanged += onSettingsChanged; Debug.Assert(client.Room != null); @@ -136,20 +135,6 @@ private void onItemDeselected(int userId, long itemId) beatmapSelectGrid.SetUserSelection(user, itemId, false); } - private void onSettingsChanged(MultiplayerRoomSettings settings) - { - if (client.Room!.MatchState is not MatchmakingRoomState matchmakingState) - return; - - if (matchmakingState.Stage != MatchmakingStage.ServerBeatmapFinalised) - return; - - if (matchmakingState.CandidateItem != -1) - return; - - beatmapSelectGrid.RevealRandomItem(client.Room!.CurrentPlaylistItem); - } - public void RollFinalBeatmap(long[] candidateItems, long finalItem, MatchmakingCandidateType panelType) => beatmapSelectGrid.RollAndDisplayFinalBeatmap(candidateItems, finalItem, panelType); @@ -161,7 +146,6 @@ protected override void Dispose(bool isDisposing) { client.MatchmakingItemSelected -= onItemSelected; client.MatchmakingItemDeselected -= onItemDeselected; - client.SettingsChanged -= onSettingsChanged; } } } From 6f7f9802bd33676a8398a313bbaaa4237e02fec8 Mon Sep 17 00:00:00 2001 From: Kawaritai <72053972+Kawaritai@users.noreply.github.com> Date: Wed, 19 Nov 2025 09:18:07 +1100 Subject: [PATCH 116/836] Change windowed resolutions filtering. Add comment about borders logic. --- .../Sections/Graphics/LayoutSettings.cs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index e1b1b7ccce7f..cdc4f328c376 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -228,15 +228,18 @@ protected override void LoadComplete() var buffer = new Bindable(windowedResolution.Value); resolutionWindowedDropdown.Current = buffer; - var newResolutions = display.NewValue.DisplayModes - .Where(m => m.Size.Width >= 800 && m.Size.Height >= 600) - .OrderByDescending(m => Math.Max(m.Size.Height, m.Size.Width)) - .Select(m => m.Size) - .Distinct() - .ToList(); - - resolutionsFullscreen.ReplaceRange(1, resolutionsFullscreen.Count - 1, newResolutions); - resolutionsWindowed.ReplaceRange(0, resolutionsWindowed.Count, newResolutions); + var fullscreenResolutions = display.NewValue.DisplayModes + .Where(m => m.Size.Width >= 800 && m.Size.Height >= 600) + .OrderByDescending(m => Math.Max(m.Size.Height, m.Size.Width)) + .Select(m => m.Size) + .Distinct() + .ToList(); + var windowedResolutions = fullscreenResolutions + .Where(res => res.Width <= display.NewValue.UsableBounds.Width && res.Height <= display.NewValue.UsableBounds.Height) + .ToList(); + + resolutionsFullscreen.ReplaceRange(1, resolutionsFullscreen.Count - 1, fullscreenResolutions); + resolutionsWindowed.ReplaceRange(0, resolutionsWindowed.Count, windowedResolutions); resolutionWindowedDropdown.Current = windowedResolution; @@ -253,6 +256,8 @@ protected override void LoadComplete() window.WindowState = Framework.Platform.WindowState.Normal; } + // Adjust only for top decorations (assuming system titlebar). + // Bottom/left/right borders are ignored as invisible padding, which don't align with the screen. var dBounds = currentDisplay.Value.Bounds; var dUsable = currentDisplay.Value.UsableBounds; float topBar = host.Window?.BorderSize.Value.Top ?? 0; From ef4408a73e5c5c5851bdc6073f4ca09a626032f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 19 Nov 2025 08:29:55 +0100 Subject: [PATCH 117/836] Fix song select crashing when selecting random beatmap and changing star rating filter simultaneously (#35730) Closes https://github.com/ppy/osu/issues/35728. --- osu.Game/Screens/SelectV2/BeatmapCarousel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index 58874e79d18b..ae1c8eb87875 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -1035,13 +1035,13 @@ public bool NextRandom() private bool nextRandomBeatmap() { - ICollection visibleBeatmaps = ExpandedGroup != null + ICollection visibleBeatmaps = ExpandedGroup != null && grouping.GroupItems.TryGetValue(ExpandedGroup, out var groupItems) // In the case of grouping, users expect random to only operate on the expanded group. // This is going to incur some overhead as we don't have a group-beatmapset mapping currently. // // If this becomes an issue, we could either store a mapping, or run the random algorithm many times // using the `SetItems` method until we get a group HIT. - ? grouping.GroupItems[ExpandedGroup].Select(i => i.Model).OfType().ToArray() + ? groupItems.Select(i => i.Model).OfType().ToArray() : GetCarouselItems()!.Select(i => i.Model).OfType().ToArray(); GroupedBeatmap beatmap; From 603c77e3e902cd15224a0f0993b963d99000aaad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 19 Nov 2025 11:23:58 +0100 Subject: [PATCH 118/836] Avoid nuking logged in user's joined channels on showing match chat in tournament client Closes https://github.com/ppy/osu/issues/35721. I worry that straight up removing the nuke and not adding any channel leave calls in exchange is going to leave tourney client users with the *inverse* problem of being joined into a gorillion channels from multiplayer matches they broadcasted, so this attempts to strike a reasonable balance. --- .../Components/TournamentMatchChatDisplay.cs | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs index c04dbdcdd64f..761ecd4a46bf 100644 --- a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs @@ -41,30 +41,33 @@ private void load(MatchIPCInfo? ipc, IAPIProvider api) chatChannel.BindTo(ipc.ChatChannel); chatChannel.BindValueChanged(c => { - if (string.IsNullOrWhiteSpace(c.NewValue)) - return; - - int id = int.Parse(c.NewValue); - - if (id <= 0) return; - if (manager == null) { AddInternal(manager = new ChannelManager(api)); Channel.BindTo(manager.CurrentChannel); } - foreach (var ch in manager.JoinedChannels.ToList()) - manager.LeaveChannel(ch); - - var channel = new Channel + if (int.TryParse(c.OldValue, out int oldChannelId) && oldChannelId > 0) { - Id = id, - Type = ChannelType.Public - }; + var joinedChannel = manager.JoinedChannels.SingleOrDefault(ch => ch.Id == oldChannelId); + if (joinedChannel != null) + manager.LeaveChannel(joinedChannel); + } + + if (string.IsNullOrWhiteSpace(c.NewValue)) + return; - manager.JoinChannel(channel); - manager.CurrentChannel.Value = channel; + if (int.TryParse(c.NewValue, out int newChannelId) && newChannelId > 0) + { + var channel = new Channel + { + Id = newChannelId, + Type = ChannelType.Public + }; + + manager.JoinChannel(channel); + manager.CurrentChannel.Value = channel; + } }, true); } } From 02090bf6c43b921c33f7f4f3f6b1bfd76a4f2c68 Mon Sep 17 00:00:00 2001 From: marvin Date: Wed, 19 Nov 2025 13:15:53 +0100 Subject: [PATCH 119/836] Resolve candidateItem in RollAndDisplayFinalBeatmap instead of PresentRolledBeatmap --- .../Matchmaking/TestSceneBeatmapSelectGrid.cs | 6 ++-- .../Match/BeatmapSelect/BeatmapSelectGrid.cs | 31 ++++++++++--------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs index f2448a5e2635..4ca014bf2a8d 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs @@ -160,7 +160,7 @@ public void TestPresentRolledBeatmap() grid.ArrangeItemsForRollAnimation(duration: 0, stagger: 0); grid.PlayRollAnimation(finalItem, duration: 0); - Scheduler.AddDelayed(() => grid.PresentRolledBeatmap(finalItem, MatchmakingCandidateType.UserSelection), 500); + Scheduler.AddDelayed(() => grid.PresentRolledBeatmap(finalItem, finalItem, MatchmakingCandidateType.UserSelection), 500); }); } @@ -175,7 +175,7 @@ public void TestPresentUnanimouslyChosenBeatmap() grid.ArrangeItemsForRollAnimation(duration: 0, stagger: 0); grid.PlayRollAnimation(finalItem, duration: 0); - Scheduler.AddDelayed(() => grid.PresentUnanimouslyChosenBeatmap(finalItem, MatchmakingCandidateType.UserSelection), 500); + Scheduler.AddDelayed(() => grid.PresentUnanimouslyChosenBeatmap(finalItem, finalItem, MatchmakingCandidateType.UserSelection), 500); }); } @@ -192,7 +192,7 @@ public void TestPresentRandomItem() Scheduler.AddDelayed(() => { - grid.PresentRolledBeatmap(finalItem, MatchmakingCandidateType.Random); + grid.PresentRolledBeatmap(-1, finalItem, MatchmakingCandidateType.Random); }, 500); }); } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs index f5796fe76086..137f7712e01c 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs @@ -143,8 +143,15 @@ public void SetUserSelection(APIUser user, long itemId, bool selected) => whenPa public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId, MatchmakingCandidateType candidateType) => whenPanelsLoaded(() => { + long candidateItemId = candidateType switch + { + MatchmakingCandidateType.UserSelection => finalItemId, + MatchmakingCandidateType.Random => -1, + _ => throw new ArgumentOutOfRangeException(nameof(candidateType), candidateType, null) + }; + Debug.Assert(candidateItemIds.Length >= 1); - Debug.Assert(candidateItemIds.Contains(finalItemId)); + Debug.Assert(candidateItemIds.Contains(candidateItemId)); Debug.Assert(panelLookup.ContainsKey(finalItemId)); Debug.Assert(candidateItemIds.All(id => panelLookup.ContainsKey(id))); @@ -157,7 +164,7 @@ public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId this.Delay(ARRANGE_DELAY) .Schedule(() => ArrangeItemsForRollAnimation()) .Delay(arrange_duration + present_beatmap_delay) - .Schedule(() => PresentUnanimouslyChosenBeatmap(finalItemId, candidateType)); + .Schedule(() => PresentUnanimouslyChosenBeatmap(candidateItemId, finalItemId, candidateType)); } else { @@ -166,7 +173,7 @@ public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId .Delay(arrange_duration) .Schedule(() => PlayRollAnimation(finalItemId, roll_duration)) .Delay(roll_duration + present_beatmap_delay) - .Schedule(() => PresentRolledBeatmap(finalItemId, candidateType)); + .Schedule(() => PresentRolledBeatmap(candidateItemId, finalItemId, candidateType)); } }); @@ -313,20 +320,14 @@ internal void PlayRollAnimation(long finalItem, double duration = roll_duration) } } - internal void PresentRolledBeatmap(long finalItem, MatchmakingCandidateType candidateType) + internal void PresentRolledBeatmap(long candidateItem, long finalItem, MatchmakingCandidateType candidateType) { - long itemToReveal = candidateType switch - { - MatchmakingCandidateType.UserSelection => finalItem, - MatchmakingCandidateType.Random => -1, - _ => throw new ArgumentOutOfRangeException(nameof(candidateType), candidateType, null) - }; - - Debug.Assert(rollContainer.Children.Any(it => it.Item.ID == finalItem)); + Debug.Assert(rollContainer.Children.Any(it => it.Item.ID == candidateItem)); + Debug.Assert(playlistItems.ContainsKey(finalItem)); foreach (var panel in rollContainer.Children) { - if (panel.Item.ID != itemToReveal) + if (panel.Item.ID != candidateItem) { panel.FadeOut(200); panel.PopOutAndExpire(easing: Easing.InQuad); @@ -345,11 +346,11 @@ internal void PresentRolledBeatmap(long finalItem, MatchmakingCandidateType cand } } - internal void PresentUnanimouslyChosenBeatmap(long finalItem, MatchmakingCandidateType candidateType) + internal void PresentUnanimouslyChosenBeatmap(long candidateItem, long finalItem, MatchmakingCandidateType candidateType) { // TODO: display special animation in this case - PresentRolledBeatmap(finalItem, candidateType); + PresentRolledBeatmap(candidateItem, finalItem, candidateType); } private readonly TaskCompletionSource panelsLoaded = new TaskCompletionSource(); From 4b59a4657f8a1cd5ebee6d284a9e873c4db23522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 19 Nov 2025 13:22:07 +0100 Subject: [PATCH 120/836] Use new sliders-with-text-input in editor toolboxes Addresses https://github.com/ppy/osu/discussions/35732. And yes, I renamed "perfect curve threshold" to "bias" so that the text can fit. Sue me. --- .../Edit/FreehandSliderToolboxGroup.cs | 19 ++++----- .../Edit/OsuGridToolboxGroup.cs | 8 ++-- .../TestSceneExpandingContainer.cs | 9 ++-- .../Graphics/Containers/ExpandingContainer.cs | 34 +++++++-------- .../UserInterface/ExpandableSlider.cs | 42 +++++-------------- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 38 +++++++++++++---- .../Edit/ComposerDistanceSnapProvider.cs | 7 ++-- 7 files changed, 78 insertions(+), 79 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/FreehandSliderToolboxGroup.cs b/osu.Game.Rulesets.Osu/Edit/FreehandSliderToolboxGroup.cs index f17118ba349d..43bc4420f3e0 100644 --- a/osu.Game.Rulesets.Osu/Edit/FreehandSliderToolboxGroup.cs +++ b/osu.Game.Rulesets.Osu/Edit/FreehandSliderToolboxGroup.cs @@ -68,15 +68,18 @@ private void load() { toleranceSlider = new ExpandableSlider { - Current = displayTolerance + Current = displayTolerance, + ExpandedLabelText = "Control point spacing", }, cornerThresholdSlider = new ExpandableSlider { - Current = displayCornerThreshold + Current = displayCornerThreshold, + ExpandedLabelText = "Corner bias", }, circleThresholdSlider = new ExpandableSlider { - Current = displayCircleThreshold + Current = displayCircleThreshold, + ExpandedLabelText = "Perfect curve bias" } }; } @@ -88,24 +91,18 @@ protected override void LoadComplete() displayTolerance.BindValueChanged(tolerance => { toleranceSlider.ContractedLabelText = $"C. P. S.: {tolerance.NewValue:N0}"; - toleranceSlider.ExpandedLabelText = $"Control Point Spacing: {tolerance.NewValue:N0}"; - Tolerance.Value = displayToInternalTolerance(tolerance.NewValue); }, true); displayCornerThreshold.BindValueChanged(threshold => { - cornerThresholdSlider.ContractedLabelText = $"C. T.: {threshold.NewValue:N0}"; - cornerThresholdSlider.ExpandedLabelText = $"Corner Threshold: {threshold.NewValue:N0}"; - + cornerThresholdSlider.ContractedLabelText = $"C. B.: {threshold.NewValue:N0}"; CornerThreshold.Value = displayToInternalCornerThreshold(threshold.NewValue); }, true); displayCircleThreshold.BindValueChanged(threshold => { - circleThresholdSlider.ContractedLabelText = $"P. C. T.: {threshold.NewValue:N0}"; - circleThresholdSlider.ExpandedLabelText = $"Perfect Curve Threshold: {threshold.NewValue:N0}"; - + circleThresholdSlider.ContractedLabelText = $"P. C. B.: {threshold.NewValue:N0}"; CircleThreshold.Value = displayToInternalCircleThreshold(threshold.NewValue); }, true); diff --git a/osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs b/osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs index 991d42c7b4c3..5bd5b54f39ae 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs @@ -127,21 +127,25 @@ private void load() { Current = StartPositionX, KeyboardStep = 1, + ExpandedLabelText = "X offset", }, startPositionYSlider = new ExpandableSlider { Current = StartPositionY, KeyboardStep = 1, + ExpandedLabelText = "Y offset", }, spacingSlider = new ExpandableSlider { Current = Spacing, KeyboardStep = 1, + ExpandedLabelText = "Spacing", }, gridLinesRotationSlider = new ExpandableSlider { Current = GridLinesRotation, KeyboardStep = 1, + ExpandedLabelText = "Rotation", }, new FillFlowContainer { @@ -182,14 +186,12 @@ protected override void LoadComplete() StartPositionX.BindValueChanged(x => { startPositionXSlider.ContractedLabelText = $"X: {x.NewValue:#,0.##}"; - startPositionXSlider.ExpandedLabelText = $"X Offset: {x.NewValue:#,0.##}"; StartPosition.Value = new Vector2(x.NewValue, StartPosition.Value.Y); }, true); StartPositionY.BindValueChanged(y => { startPositionYSlider.ContractedLabelText = $"Y: {y.NewValue:#,0.##}"; - startPositionYSlider.ExpandedLabelText = $"Y Offset: {y.NewValue:#,0.##}"; StartPosition.Value = new Vector2(StartPosition.Value.X, y.NewValue); }, true); @@ -202,7 +204,6 @@ protected override void LoadComplete() Spacing.BindValueChanged(spacing => { spacingSlider.ContractedLabelText = $"S: {spacing.NewValue:#,0.##}"; - spacingSlider.ExpandedLabelText = $"Spacing: {spacing.NewValue:#,0.##}"; SpacingVector.Value = new Vector2(spacing.NewValue); editorBeatmap.GridSize = (int)spacing.NewValue; }, true); @@ -210,7 +211,6 @@ protected override void LoadComplete() GridLinesRotation.BindValueChanged(rotation => { gridLinesRotationSlider.ContractedLabelText = $"R: {rotation.NewValue:#,0.##}"; - gridLinesRotationSlider.ExpandedLabelText = $"Rotation: {rotation.NewValue:#,0.##}"; }, true); GridType.BindValueChanged(v => diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs index 3f4f86e42444..44998e6fa204 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs @@ -9,7 +9,6 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; -using osu.Game.Overlays.Settings.Sections; using osuTK; namespace osu.Game.Tests.Visual.UserInterface @@ -19,7 +18,7 @@ public partial class TestSceneExpandingContainer : OsuManualInputManagerTestScen private TestExpandingContainer container; private SettingsToolboxGroup toolboxGroup; - private ExpandableSlider> slider1; + private ExpandableSlider slider1; private ExpandableSlider slider2; [SetUp] @@ -36,7 +35,7 @@ public void SetUp() => Schedule(() => Width = 1, Children = new Drawable[] { - slider1 = new ExpandableSlider> + slider1 = new ExpandableSlider { Current = new BindableFloat { @@ -62,13 +61,13 @@ public void SetUp() => Schedule(() => slider1.Current.BindValueChanged(v => { - slider1.ExpandedLabelText = $"Slider One ({v.NewValue:0.##x})"; + slider1.ExpandedLabelText = "Slider One"; slider1.ContractedLabelText = $"S. 1. ({v.NewValue:0.##x})"; }, true); slider2.Current.BindValueChanged(v => { - slider2.ExpandedLabelText = $"Slider Two ({v.NewValue:N2})"; + slider2.ExpandedLabelText = "Slider Two"; slider2.ContractedLabelText = $"S. 2. ({v.NewValue:N2})"; }, true); }); diff --git a/osu.Game/Graphics/Containers/ExpandingContainer.cs b/osu.Game/Graphics/Containers/ExpandingContainer.cs index 65a00b725c23..7cce49fb8157 100644 --- a/osu.Game/Graphics/Containers/ExpandingContainer.cs +++ b/osu.Game/Graphics/Containers/ExpandingContainer.cs @@ -4,7 +4,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Events; +using osu.Framework.Input; using osu.Framework.Threading; namespace osu.Game.Graphics.Containers @@ -58,6 +58,8 @@ protected ExpandingContainer(float contractedWidth, float expandedWidth) protected virtual OsuScrollContainer CreateScrollContainer() => new OsuScrollContainer(); + private InputManager inputManager = null!; + private bool? lastMouseInBounds; private ScheduledDelegate? hoverExpandEvent; protected override void LoadComplete() @@ -68,37 +70,35 @@ protected override void LoadComplete() { this.ResizeWidthTo(v.NewValue ? expandedWidth : contractedWidth, TRANSITION_DURATION, Easing.OutQuint); }, true); - } - protected override bool OnHover(HoverEvent e) - { - updateHoverExpansion(); - return true; + inputManager = GetContainingInputManager()!; } - protected override void OnHoverLost(HoverLostEvent e) + protected override void Update() { - if (hoverExpandEvent != null) - { - hoverExpandEvent?.Cancel(); - hoverExpandEvent = null; + base.Update(); - Expanded.Value = false; - return; - } + bool mouseInBounds = Contains(inputManager.CurrentState.Mouse.Position); + + if (lastMouseInBounds != mouseInBounds) + updateExpansionState(mouseInBounds); - base.OnHoverLost(e); + lastMouseInBounds = mouseInBounds; } - private void updateHoverExpansion() + private void updateExpansionState(bool mouseInBounds) { if (!ExpandOnHover) return; hoverExpandEvent?.Cancel(); + hoverExpandEvent = null; - if (IsHovered && !Expanded.Value) + if (mouseInBounds && !Expanded.Value) hoverExpandEvent = Scheduler.AddDelayed(() => Expanded.Value = true, HoverExpansionDelay); + + if (!mouseInBounds && Expanded.Value) + Expanded.Value = false; } } } diff --git a/osu.Game/Graphics/UserInterface/ExpandableSlider.cs b/osu.Game/Graphics/UserInterface/ExpandableSlider.cs index 4cc77e218fd0..addf4c91102b 100644 --- a/osu.Game/Graphics/UserInterface/ExpandableSlider.cs +++ b/osu.Game/Graphics/UserInterface/ExpandableSlider.cs @@ -10,6 +10,7 @@ using osu.Framework.Localisation; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterfaceV2; using Vector2 = osuTK.Vector2; namespace osu.Game.Graphics.UserInterface @@ -19,49 +20,27 @@ namespace osu.Game.Graphics.UserInterface /// public partial class ExpandableSlider : CompositeDrawable, IExpandable, IHasCurrentValue where T : struct, INumber, IMinMaxValue - where TSlider : RoundedSliderBar, new() + where TSlider : FormSliderBar, new() { - private readonly OsuSpriteText label; + private readonly OsuSpriteText contractedLabel; private readonly TSlider slider; - private LocalisableString contractedLabelText; - /// /// The label text to display when this slider is in a contracted state. /// public LocalisableString ContractedLabelText { - get => contractedLabelText; - set - { - if (value == contractedLabelText) - return; - - contractedLabelText = value; - - if (!Expanded.Value) - label.Text = value; - } + get => contractedLabel.Text; + set => contractedLabel.Text = value; } - private LocalisableString expandedLabelText; - /// /// The label text to display when this slider is in an expanded state. /// public LocalisableString ExpandedLabelText { - get => expandedLabelText; - set - { - if (value == expandedLabelText) - return; - - expandedLabelText = value; - - if (Expanded.Value) - label.Text = value; - } + get => slider.Caption; + set => slider.Caption = value; } public Bindable Current @@ -95,7 +74,7 @@ public ExpandableSlider() Spacing = new Vector2(0f, 10f), Children = new Drawable[] { - label = new OsuSpriteText(), + contractedLabel = new OsuSpriteText(), slider = new TSlider { RelativeSizeAxes = Axes.X, @@ -118,7 +97,8 @@ protected override void LoadComplete() Expanded.BindValueChanged(v => { - label.Text = v.NewValue ? expandedLabelText : contractedLabelText; + contractedLabel.FadeTo(v.NewValue ? 0 : 1); + slider.FadeTo(v.NewValue ? Current.Disabled ? 0.3f : 1f : 0f, 500, Easing.OutQuint); slider.BypassAutoSizeAxes = !v.NewValue ? Axes.Y : Axes.None; }, true); @@ -133,7 +113,7 @@ protected override void LoadComplete() /// /// An implementation for the UI slider bar control. /// - public partial class ExpandableSlider : ExpandableSlider> + public partial class ExpandableSlider : ExpandableSlider> where T : struct, INumber, IMinMaxValue { } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 1304c298fb8c..59217f64abd1 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -58,26 +58,49 @@ public CompositeDrawable? TabbableContentContainer } } + private LocalisableString caption; + /// /// Caption describing this slider bar, displayed on top of the controls. /// - public LocalisableString Caption { get; init; } + public LocalisableString Caption + { + get => caption; + set + { + caption = value; + + if (IsLoaded) + captionText.Caption = value; + } + } /// /// Hint text containing an extended description of this slider bar, displayed in a tooltip when hovering the caption. /// public LocalisableString HintText { get; init; } + private float keyboardStep; + /// /// A custom step value for each key press which actuates a change on this control. /// - public float KeyboardStep { get; init; } + public float KeyboardStep + { + get => keyboardStep; + set + { + keyboardStep = value; + if (IsLoaded) + slider.KeyboardStep = value; + } + } private Box background = null!; private Box flashLayer = null!; private FormTextBox.InnerTextBox textBox = null!; private InnerSlider slider = null!; - private FormFieldCaption caption = null!; + private FormFieldCaption captionText = null!; private IFocusManager focusManager = null!; [Resolved] @@ -117,11 +140,10 @@ private void load(OsuColour colours, OsuGame? game) }, Children = new Drawable[] { - caption = new FormFieldCaption + captionText = new FormFieldCaption { Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft, - Caption = Caption, TooltipText = HintText, }, textBox = new FormNumberBox.InnerNumberBox(allowDecimals: true) @@ -145,7 +167,6 @@ private void load(OsuColour colours, OsuGame? game) Origin = Anchor.CentreRight, RelativeSizeAxes = Axes.X, Width = 0.5f, - KeyboardStep = KeyboardStep, Current = currentNumberInstantaneous, OnCommit = () => current.Value = currentNumberInstantaneous.Value, } @@ -161,6 +182,9 @@ protected override void LoadComplete() { base.LoadComplete(); + slider.KeyboardStep = keyboardStep; + captionText.Caption = caption; + focusManager = GetContainingFocusManager()!; textBox.Focused.BindValueChanged(_ => updateState()); @@ -270,7 +294,7 @@ private void updateState() textBox.Alpha = 1; background.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background4 : colourProvider.Background5; - caption.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Foreground1 : colourProvider.Content2; + captionText.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Foreground1 : colourProvider.Content2; textBox.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Foreground1 : colourProvider.Content1; BorderThickness = childHasFocus || IsHovered || slider.IsDragging.Value ? 2 : 0; diff --git a/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs b/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs index 2d6e09b3fdcd..d2f402a6fa23 100644 --- a/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs +++ b/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs @@ -20,7 +20,6 @@ using osu.Game.Input.Bindings; using osu.Game.Overlays; using osu.Game.Overlays.OSD; -using osu.Game.Overlays.Settings.Sections; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.UI; @@ -42,7 +41,7 @@ public abstract partial class ComposerDistanceSnapProvider : Component, IDistanc Bindable IDistanceSnapProvider.DistanceSpacingMultiplier => DistanceSpacingMultiplier; - private ExpandableSlider> distanceSpacingSlider = null!; + private ExpandableSlider distanceSpacingSlider = null!; private ExpandableButton currentDistanceSpacingButton = null!; [Resolved] @@ -78,11 +77,12 @@ public void AttachToToolbox(ExpandingToolboxContainer toolboxContainer) Alpha = DistanceSpacingMultiplier.Disabled ? 0 : 1, Children = new Drawable[] { - distanceSpacingSlider = new ExpandableSlider> + distanceSpacingSlider = new ExpandableSlider { KeyboardStep = adjust_step, // Manual binding in LoadComplete to handle one-way event flow. Current = DistanceSpacingMultiplier.GetUnboundCopy(), + ExpandedLabelText = "Distance spacing", }, currentDistanceSpacingButton = new ExpandableButton { @@ -104,7 +104,6 @@ public void AttachToToolbox(ExpandingToolboxContainer toolboxContainer) DistanceSpacingMultiplier.BindValueChanged(multiplier => { distanceSpacingSlider.ContractedLabelText = $"D. S. ({multiplier.NewValue:0.##x})"; - distanceSpacingSlider.ExpandedLabelText = $"Distance Spacing ({multiplier.NewValue:0.##x})"; if (multiplier.NewValue != multiplier.OldValue) onScreenDisplay?.Display(new DistanceSpacingToast(multiplier.NewValue.ToLocalisableString(@"0.##x"), multiplier)); From 397041099e27551e2f782a5fd6adf6e216b45872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 19 Nov 2025 13:38:31 +0100 Subject: [PATCH 121/836] Adjust element spacing in editor toolboxes --- .../Edit/Blueprints/GridPlacementBlueprint.cs | 8 ++++---- .../Edit/FreehandSliderToolboxGroup.cs | 10 ++++++++++ osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs | 14 ++++++++------ osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 4 ++-- osu.Game/Overlays/SettingsToolboxGroup.cs | 6 ++++++ .../Rulesets/Edit/ComposerDistanceSnapProvider.cs | 3 +++ 6 files changed, 33 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/GridPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/GridPlacementBlueprint.cs index f54dc2c85b88..07856f11e0af 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/GridPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/GridPlacementBlueprint.cs @@ -25,7 +25,7 @@ private void load(OsuGridToolboxGroup gridToolboxGroup) { this.gridToolboxGroup = gridToolboxGroup; originalOrigin = gridToolboxGroup.StartPosition.Value; - originalSpacing = gridToolboxGroup.Spacing.Value; + originalSpacing = gridToolboxGroup.GridLineSpacing.Value; originalRotation = gridToolboxGroup.GridLinesRotation.Value; } @@ -67,7 +67,7 @@ protected override bool OnMouseDown(MouseDownEvent e) { // Reset the grid to the default values. gridToolboxGroup.StartPosition.Value = gridToolboxGroup.StartPosition.Default; - gridToolboxGroup.Spacing.Value = gridToolboxGroup.Spacing.Default; + gridToolboxGroup.GridLineSpacing.Value = gridToolboxGroup.GridLineSpacing.Default; if (!gridToolboxGroup.GridLinesRotation.Disabled) gridToolboxGroup.GridLinesRotation.Value = gridToolboxGroup.GridLinesRotation.Default; EndPlacement(true); @@ -112,7 +112,7 @@ public override SnapResult UpdateTimeAndPosition(Vector2 screenSpacePosition, do // Default to the original spacing and rotation if the distance is too small. if (Vector2.Distance(gridToolboxGroup.StartPosition.Value, pos) < 2) { - gridToolboxGroup.Spacing.Value = originalSpacing; + gridToolboxGroup.GridLineSpacing.Value = originalSpacing; if (!gridToolboxGroup.GridLinesRotation.Disabled) gridToolboxGroup.GridLinesRotation.Value = originalRotation; } @@ -134,7 +134,7 @@ protected override void PopOut() private void resetGridState() { gridToolboxGroup.StartPosition.Value = originalOrigin; - gridToolboxGroup.Spacing.Value = originalSpacing; + gridToolboxGroup.GridLineSpacing.Value = originalSpacing; if (!gridToolboxGroup.GridLinesRotation.Disabled) gridToolboxGroup.GridLinesRotation.Value = originalRotation; } diff --git a/osu.Game.Rulesets.Osu/Edit/FreehandSliderToolboxGroup.cs b/osu.Game.Rulesets.Osu/Edit/FreehandSliderToolboxGroup.cs index 43bc4420f3e0..79090443610c 100644 --- a/osu.Game.Rulesets.Osu/Edit/FreehandSliderToolboxGroup.cs +++ b/osu.Game.Rulesets.Osu/Edit/FreehandSliderToolboxGroup.cs @@ -5,8 +5,10 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; +using osuTK; namespace osu.Game.Rulesets.Osu.Edit { @@ -61,6 +63,9 @@ public FreehandSliderToolboxGroup() private ExpandableSlider cornerThresholdSlider = null!; private ExpandableSlider circleThresholdSlider = null!; + [Resolved] + private IExpandingContainer? expandingContainer { get; set; } + [BackgroundDependencyLoader] private void load() { @@ -116,6 +121,11 @@ protected override void LoadComplete() displayCircleThreshold.Value = internalToDisplayCircleThreshold(threshold.NewValue) ); + expandingContainer?.Expanded.BindValueChanged(v => + { + Spacing = v.NewValue ? new Vector2(5) : new Vector2(15); + }, true); + float displayToInternalTolerance(float v) => v / 50f; int internalToDisplayTolerance(float v) => (int)Math.Round(v * 50f); diff --git a/osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs b/osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs index 5bd5b54f39ae..e0c486a68839 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs @@ -54,7 +54,7 @@ public partial class OsuGridToolboxGroup : EditorToolboxGroup, IKeyBindingHandle /// /// The spacing between grid lines. /// - public BindableFloat Spacing { get; } = new BindableFloat(4f) + public BindableFloat GridLineSpacing { get; } = new BindableFloat(4f) { MinValue = 4f, MaxValue = 256f, @@ -115,7 +115,7 @@ public void SetGridFromPoints(Vector2 point1, Vector2 point2) float dist = Vector2.Distance(point1, point2); while (dist >= max_automatic_spacing) dist /= 2; - Spacing.Value = dist; + GridLineSpacing.Value = dist; } [BackgroundDependencyLoader] @@ -137,7 +137,7 @@ private void load() }, spacingSlider = new ExpandableSlider { - Current = Spacing, + Current = GridLineSpacing, KeyboardStep = 1, ExpandedLabelText = "Spacing", }, @@ -174,7 +174,7 @@ private void load() }, }; - Spacing.Value = editorBeatmap.GridSize; + GridLineSpacing.Value = editorBeatmap.GridSize; } protected override void LoadComplete() @@ -201,7 +201,7 @@ protected override void LoadComplete() StartPositionY.Value = pos.NewValue.Y; }); - Spacing.BindValueChanged(spacing => + GridLineSpacing.BindValueChanged(spacing => { spacingSlider.ContractedLabelText = $"S: {spacing.NewValue:#,0.##}"; SpacingVector.Value = new Vector2(spacing.NewValue); @@ -239,6 +239,8 @@ protected override void LoadComplete() { gridTypeButtons.FadeTo(v.NewValue ? 1f : 0f, 500, Easing.OutQuint); gridTypeButtons.BypassAutoSizeAxes = !v.NewValue ? Axes.Y : Axes.None; + + Spacing = v.NewValue ? new Vector2(5) : new Vector2(15); }, true); } @@ -252,7 +254,7 @@ public bool OnPressed(KeyBindingPressEvent e) switch (e.Action) { case GlobalAction.EditorCycleGridSpacing: - Spacing.Value = Spacing.Value * 2 >= max_automatic_spacing ? Spacing.Value / 8 : Spacing.Value * 2; + GridLineSpacing.Value = GridLineSpacing.Value * 2 >= max_automatic_spacing ? GridLineSpacing.Value / 8 : GridLineSpacing.Value * 2; return true; case GlobalAction.EditorCycleGridType: diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index e4f8ee5b6d09..0dac4cb2dfeb 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -142,7 +142,7 @@ private void updatePositionSnapGrid(ValueChangedEvent obj) case PositionSnapGridType.Triangle: var triangularPositionSnapGrid = new TriangularPositionSnapGrid(); - triangularPositionSnapGrid.Spacing.BindTo(OsuGridToolboxGroup.Spacing); + triangularPositionSnapGrid.Spacing.BindTo(OsuGridToolboxGroup.GridLineSpacing); triangularPositionSnapGrid.GridLineRotation.BindTo(OsuGridToolboxGroup.GridLinesRotation); positionSnapGrid = triangularPositionSnapGrid; @@ -151,7 +151,7 @@ private void updatePositionSnapGrid(ValueChangedEvent obj) case PositionSnapGridType.Circle: var circularPositionSnapGrid = new CircularPositionSnapGrid(); - circularPositionSnapGrid.Spacing.BindTo(OsuGridToolboxGroup.Spacing); + circularPositionSnapGrid.Spacing.BindTo(OsuGridToolboxGroup.GridLineSpacing); positionSnapGrid = circularPositionSnapGrid; break; diff --git a/osu.Game/Overlays/SettingsToolboxGroup.cs b/osu.Game/Overlays/SettingsToolboxGroup.cs index d82118fa1a5d..f26ed962cb2b 100644 --- a/osu.Game/Overlays/SettingsToolboxGroup.cs +++ b/osu.Game/Overlays/SettingsToolboxGroup.cs @@ -46,6 +46,12 @@ public partial class SettingsToolboxGroup : Container, IExpandable public BindableBool Expanded { get; } = new BindableBool(true); + public Vector2 Spacing + { + get => content.Spacing; + set => content.Spacing = value; + } + private OsuSpriteText headerText = null!; private Container headerContent = null!; diff --git a/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs b/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs index d2f402a6fa23..64f938ba6c35 100644 --- a/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs +++ b/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs @@ -25,6 +25,7 @@ using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components.TernaryButtons; +using osuTK; namespace osu.Game.Rulesets.Edit { @@ -74,6 +75,7 @@ public void AttachToToolbox(ExpandingToolboxContainer toolboxContainer) toolboxContainer.Add(toolboxGroup = new EditorToolboxGroup("snapping") { Name = "snapping", + Spacing = new Vector2(5), Alpha = DistanceSpacingMultiplier.Disabled ? 0 : 1, Children = new Drawable[] { @@ -104,6 +106,7 @@ public void AttachToToolbox(ExpandingToolboxContainer toolboxContainer) DistanceSpacingMultiplier.BindValueChanged(multiplier => { distanceSpacingSlider.ContractedLabelText = $"D. S. ({multiplier.NewValue:0.##x})"; + distanceSpacingSlider.Current.Value = multiplier.NewValue; if (multiplier.NewValue != multiplier.OldValue) onScreenDisplay?.Display(new DistanceSpacingToast(multiplier.NewValue.ToLocalisableString(@"0.##x"), multiplier)); From be77257ddb4d819001e999be20962d99fed4ae88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 20 Nov 2025 03:10:12 +0100 Subject: [PATCH 122/836] Do not overwrite website state of 'hide online presence' toggle (#35741) Closes https://github.com/ppy/osu/issues/35735. --- osu.Game/Online/API/LocalUserState.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Online/API/LocalUserState.cs b/osu.Game/Online/API/LocalUserState.cs index 1359d62ae746..94b298fdb4a4 100644 --- a/osu.Game/Online/API/LocalUserState.cs +++ b/osu.Game/Online/API/LocalUserState.cs @@ -62,6 +62,10 @@ public void SetLocalUser(APIMe me) localUser.Value = me; configSupporter.Value = me.IsSupporter; + // `last_visit` is assumed to be `null` if and only if the web-side "hide online presence toggle" is enabled + if (me.LastVisit == null) + configStatus.Value = UserStatus.Offline; + UpdateFriends(); UpdateBlocks(); UpdateFavouriteBeatmapSets(); From 47faf774b04072f3ebd5d158005028960a3dfa1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 20 Nov 2025 10:12:43 +0100 Subject: [PATCH 123/836] Fix tests --- .../TestSceneExpandingContainer.cs | 4 ++++ .../Graphics/Containers/ExpandingContainer.cs | 21 ++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs index 44998e6fa204..db949c6754d9 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs @@ -4,6 +4,7 @@ #nullable disable using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Graphics.Containers; @@ -21,6 +22,9 @@ public partial class TestSceneExpandingContainer : OsuManualInputManagerTestScen private ExpandableSlider slider1; private ExpandableSlider slider2; + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + [SetUp] public void SetUp() => Schedule(() => { diff --git a/osu.Game/Graphics/Containers/ExpandingContainer.cs b/osu.Game/Graphics/Containers/ExpandingContainer.cs index 7cce49fb8157..90322e92bc80 100644 --- a/osu.Game/Graphics/Containers/ExpandingContainer.cs +++ b/osu.Game/Graphics/Containers/ExpandingContainer.cs @@ -59,7 +59,18 @@ protected ExpandingContainer(float contractedWidth, float expandedWidth) protected virtual OsuScrollContainer CreateScrollContainer() => new OsuScrollContainer(); private InputManager inputManager = null!; + + /// + /// Tracks whether the mouse was in bounds of this expanding container in the last frame. + /// private bool? lastMouseInBounds; + + /// + /// Tracks whether the last expansion of the container was caused by the mouse moving into its bounds + /// (as opposed to an external set of `Expanded`, in which case moving the mouse outside of its bounds should not contract). + /// + private bool? expandedByMouse; + private ScheduledDelegate? hoverExpandEvent; protected override void LoadComplete() @@ -95,10 +106,18 @@ private void updateExpansionState(bool mouseInBounds) hoverExpandEvent = null; if (mouseInBounds && !Expanded.Value) + { hoverExpandEvent = Scheduler.AddDelayed(() => Expanded.Value = true, HoverExpansionDelay); + expandedByMouse = true; + } if (!mouseInBounds && Expanded.Value) - Expanded.Value = false; + { + if (expandedByMouse == true) + Expanded.Value = false; + + expandedByMouse = false; + } } } } From a8ac82aa1f3da33a9b8d9ac06617f5ecb4597ccb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Nov 2025 18:19:30 +0900 Subject: [PATCH 124/836] Fix test failure due to channel not being joined --- .../TestSceneTournamentMatchChatDisplay.cs | 25 +++++++++++++++++-- osu.Game/Properties/AssemblyInfo.cs | 1 + 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs index 231bd776554a..4b1d56dea22b 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs @@ -6,6 +6,8 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Overlays.Chat; @@ -61,14 +63,33 @@ public TestSceneTournamentMatchChatDisplay() Anchor = Anchor.Centre, Origin = Anchor.Centre, }); - - chatDisplay.Channel.Value = testChannel; } protected override void LoadComplete() { base.LoadComplete(); + AddStep("set up API", () => + { + ((DummyAPIAccess)API).HandleRequest = req => + { + switch (req) + { + case JoinChannelRequest joinChannelRequest: + joinChannelRequest.TriggerSuccess(); + return true; + + case LeaveChannelRequest leaveChannelRequest: + leaveChannelRequest.TriggerSuccess(); + return true; + + default: + return false; + } + }; + }); + AddStep("set channel", () => chatDisplay.Channel.Value = testChannel); + AddStep("message from admin", () => testChannel.AddNewMessages(new Message(nextMessageId()) { Sender = admin, diff --git a/osu.Game/Properties/AssemblyInfo.cs b/osu.Game/Properties/AssemblyInfo.cs index be430a0fe4f2..75e3ff8fd0ee 100644 --- a/osu.Game/Properties/AssemblyInfo.cs +++ b/osu.Game/Properties/AssemblyInfo.cs @@ -11,6 +11,7 @@ [assembly: InternalsVisibleTo("osu.Game.Tests.Dynamic")] [assembly: InternalsVisibleTo("osu.Game.Tests.iOS")] [assembly: InternalsVisibleTo("osu.Game.Tests.Android")] +[assembly: InternalsVisibleTo("osu.Game.Tournament.Tests")] // intended for Moq usage [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] From c7e1a5770d4d95ee9c0fd0a01556e4dd3ff3beb1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Nov 2025 18:22:16 +0900 Subject: [PATCH 125/836] Adjust code structure slightly to simplify logic --- .../Components/TournamentMatchChatDisplay.cs | 53 ++++++++----------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs index 761ecd4a46bf..02fb5a7ae007 100644 --- a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs @@ -16,7 +16,7 @@ namespace osu.Game.Tournament.Components { public partial class TournamentMatchChatDisplay : StandAloneChatDisplay { - private readonly Bindable chatChannel = new Bindable(); + private readonly Bindable channelName = new Bindable(); private ChannelManager? manager; @@ -34,42 +34,33 @@ public TournamentMatchChatDisplay() } [BackgroundDependencyLoader] - private void load(MatchIPCInfo? ipc, IAPIProvider api) + private void load(MatchIPCInfo ipc, IAPIProvider api) { - if (ipc != null) + AddInternal(manager = new ChannelManager(api)); + Channel.BindTo(manager.CurrentChannel); + + channelName.BindTo(ipc.ChatChannel); + channelName.BindValueChanged(c => { - chatChannel.BindTo(ipc.ChatChannel); - chatChannel.BindValueChanged(c => + if (int.TryParse(c.OldValue, out int oldChannelId) && oldChannelId > 0) { - if (manager == null) - { - AddInternal(manager = new ChannelManager(api)); - Channel.BindTo(manager.CurrentChannel); - } + var joinedChannel = manager.JoinedChannels.SingleOrDefault(ch => ch.Id == oldChannelId); + if (joinedChannel != null) + manager.LeaveChannel(joinedChannel); + } - if (int.TryParse(c.OldValue, out int oldChannelId) && oldChannelId > 0) + if (int.TryParse(c.NewValue, out int newChannelId) && newChannelId > 0) + { + var channel = new Channel { - var joinedChannel = manager.JoinedChannels.SingleOrDefault(ch => ch.Id == oldChannelId); - if (joinedChannel != null) - manager.LeaveChannel(joinedChannel); - } + Id = newChannelId, + Type = ChannelType.Public + }; - if (string.IsNullOrWhiteSpace(c.NewValue)) - return; - - if (int.TryParse(c.NewValue, out int newChannelId) && newChannelId > 0) - { - var channel = new Channel - { - Id = newChannelId, - Type = ChannelType.Public - }; - - manager.JoinChannel(channel); - manager.CurrentChannel.Value = channel; - } - }, true); - } + manager.JoinChannel(channel); + manager.CurrentChannel.Value = channel; + } + }, true); } public void Expand() => this.FadeIn(300); From 094454499ca04ad4d6e1138615dc8a6773b04a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 20 Nov 2025 11:51:28 +0100 Subject: [PATCH 126/836] Add `created` alias for `submitted` song select filter Symmetrical change to https://github.com/ppy/osu-web/pull/12561 (can probably wait until that one is reviewed to be legitimate). --- .../NonVisual/Filtering/FilterQueryParserTest.cs | 10 ++++++++++ osu.Game/Screens/Select/FilterQueryParser.cs | 1 + 2 files changed, 11 insertions(+) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 8bef6b04a7a7..87e439534bbd 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -738,6 +738,16 @@ public void TestInvalidRankedDateQueries(string query) new object[] { "submitted=99999", false }, new object[] { "submitted>=2012-03-05-04", false }, new object[] { "submitted>=2012/03.05-04", false }, + + new object[] { "created<2012", true }, + new object[] { "created<2012.03", true }, + new object[] { "created<2012/03/05", true }, + new object[] { "created<2012-3-5", true }, + + new object[] { "created<0", false }, + new object[] { "created=99999", false }, + new object[] { "created>=2012-03-05-04", false }, + new object[] { "created>=2012/03.05-04", false }, }; [Test] diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 8cf3bda1c55e..0adcf5d45421 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -68,6 +68,7 @@ private static bool tryParseKeywordCriteria(FilterCriteria criteria, string key, case "ranked": return tryUpdateRankedDateRange(ref criteria.DateRanked, op, value); + case "created": case "submitted": return tryUpdateRankedDateRange(ref criteria.DateSubmitted, op, value); From aba567d258734e6ce058f2248ebcd16dfa066f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Sch=C3=BCrz?= Date: Thu, 20 Nov 2025 11:16:05 +0100 Subject: [PATCH 127/836] Add background screen --- .../Match/MatchmakingBackgroundScreen.cs | 56 +++++++++++++++++++ .../Matchmaking/Match/ScreenMatchmaking.cs | 2 + 2 files changed, 58 insertions(+) create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingBackgroundScreen.cs diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingBackgroundScreen.cs new file mode 100644 index 000000000000..cfb3f2e6c424 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingBackgroundScreen.cs @@ -0,0 +1,56 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Overlays; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match +{ + public partial class MatchmakingBackgroundScreen : BackgroundScreen + { + public MatchmakingBackgroundScreen() + { + InternalChild = new Content + { + RelativeSizeAxes = Axes.Both + }; + } + + public partial class Content : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load(TextureStore textures, OverlayColourProvider colourProvider) + { + AddRangeInternal(new Drawable[] + { + new Sprite + { + RelativeSizeAxes = Axes.Both, + Texture = textures.Get("Backgrounds/bg1"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + FillMode = FillMode.Fill, + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Colour4, + Alpha = 0.5f, + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.6f, + } + }); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs index 972f0b4adb31..8a48a089b46d 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs @@ -57,6 +57,8 @@ public partial class ScreenMatchmaking : OsuScreen, IPreviewTrackOwner, IHandleP public override bool ShowFooter => true; + protected override BackgroundScreen CreateBackground() => new MatchmakingBackgroundScreen(); + [Cached(typeof(OnlinePlayBeatmapAvailabilityTracker))] private readonly OnlinePlayBeatmapAvailabilityTracker beatmapAvailabilityTracker = new MultiplayerBeatmapAvailabilityTracker(); From 107c481fb96522e5d65cc41266bc13802ac2d1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Sch=C3=BCrz?= Date: Thu, 20 Nov 2025 12:03:42 +0100 Subject: [PATCH 128/836] Use new background in all matchmaking test scenes --- .../Matchmaking/MatchmakingTestScene.cs | 32 +++++++++++++++++++ .../Matchmaking/TestSceneBeatmapSelectGrid.cs | 3 +- .../TestSceneBeatmapSelectPanel.cs | 3 +- .../TestSceneMatchmakingChatDisplay.cs | 2 +- .../Matchmaking/TestScenePanelRoomAward.cs | 3 +- .../Visual/Matchmaking/TestScenePickScreen.cs | 3 +- .../Matchmaking/TestScenePlayerPanel.cs | 3 +- .../TestScenePlayerPanelOverlay.cs | 3 +- .../Matchmaking/TestSceneResultsScreen.cs | 3 +- .../TestSceneRoundResultsScreen.cs | 3 +- .../Matchmaking/TestSceneStageDisplay.cs | 3 +- 11 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 osu.Game.Tests/Visual/Matchmaking/MatchmakingTestScene.cs diff --git a/osu.Game.Tests/Visual/Matchmaking/MatchmakingTestScene.cs b/osu.Game.Tests/Visual/Matchmaking/MatchmakingTestScene.cs new file mode 100644 index 000000000000..8c01083b12c9 --- /dev/null +++ b/osu.Game.Tests/Visual/Matchmaking/MatchmakingTestScene.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Overlays; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match; +using osu.Game.Tests.Visual.Multiplayer; + +namespace osu.Game.Tests.Visual.Matchmaking +{ + public abstract partial class MatchmakingTestScene : MultiplayerTestScene + { + protected override Container Content { get; } + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); + + protected MatchmakingTestScene() + { + base.Content.AddRange(new Drawable[] + { + new MatchmakingBackgroundScreen.Content + { + RelativeSizeAxes = Axes.Both, + }, + Content = new Container { RelativeSizeAxes = Axes.Both } + }); + } + } +} diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs index 0e5e5b8aae04..cf98a785f1a3 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs @@ -17,12 +17,11 @@ using osu.Game.Online.Rooms; using osu.Game.Rulesets.Mods; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect; -using osu.Game.Tests.Visual.OnlinePlay; using osuTK; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestSceneBeatmapSelectGrid : OnlinePlayTestScene + public partial class TestSceneBeatmapSelectGrid : MatchmakingTestScene { private MatchmakingPlaylistItem[] items = null!; diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs index 9ac64288ed5d..cd1d8297da97 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs @@ -12,11 +12,10 @@ using osu.Game.Overlays; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect; -using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestSceneBeatmapSelectPanel : MultiplayerTestScene + public partial class TestSceneBeatmapSelectPanel : MatchmakingTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingChatDisplay.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingChatDisplay.cs index d8e42cd94699..b22c4dd74ac5 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingChatDisplay.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingChatDisplay.cs @@ -11,7 +11,7 @@ namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestSceneMatchmakingChatDisplay : ScreenTestScene + public partial class TestSceneMatchmakingChatDisplay : MatchmakingTestScene { private MatchmakingChatDisplay? chat; diff --git a/osu.Game.Tests/Visual/Matchmaking/TestScenePanelRoomAward.cs b/osu.Game.Tests/Visual/Matchmaking/TestScenePanelRoomAward.cs index bdae6568555a..f03af8b8f5cb 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestScenePanelRoomAward.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestScenePanelRoomAward.cs @@ -3,11 +3,10 @@ using osu.Framework.Graphics; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.Results; -using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestScenePanelRoomAward : MultiplayerTestScene + public partial class TestScenePanelRoomAward : MatchmakingTestScene { public override void SetUpSteps() { diff --git a/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs index e894616f9e3d..6f281fd6b3b1 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs @@ -11,11 +11,10 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect; -using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestScenePickScreen : MultiplayerTestScene + public partial class TestScenePickScreen : MatchmakingTestScene { private readonly IReadOnlyList users = new[] { diff --git a/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanel.cs index 0c78038179ac..897d59657c80 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanel.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanel.cs @@ -11,12 +11,11 @@ using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Matchmaking.Match; -using osu.Game.Tests.Visual.Multiplayer; using osu.Game.Users; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestScenePlayerPanel : MultiplayerTestScene + public partial class TestScenePlayerPanel : MatchmakingTestScene { private PlayerPanel panel = null!; diff --git a/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanelOverlay.cs b/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanelOverlay.cs index cdc0c93d118a..f41416925115 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanelOverlay.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanelOverlay.cs @@ -15,12 +15,11 @@ using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Matchmaking.Match; -using osu.Game.Tests.Visual.Multiplayer; using osuTK; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestScenePlayerPanelOverlay : MultiplayerTestScene + public partial class TestScenePlayerPanelOverlay : MatchmakingTestScene { private PlayerPanelOverlay list = null!; diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneResultsScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneResultsScreen.cs index 843c20b1e58b..f717849a2a37 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneResultsScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneResultsScreen.cs @@ -11,12 +11,11 @@ using osu.Game.Online.Rooms; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.Results; -using osu.Game.Tests.Visual.Multiplayer; using osuTK; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestSceneResultsScreen : MultiplayerTestScene + public partial class TestSceneResultsScreen : MatchmakingTestScene { public override void SetUpSteps() { diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneRoundResultsScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneRoundResultsScreen.cs index cbdbd3315843..ff4e2c1932b1 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneRoundResultsScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneRoundResultsScreen.cs @@ -14,12 +14,11 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundResults; -using osu.Game.Tests.Visual.Multiplayer; using osuTK; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestSceneRoundResultsScreen : MultiplayerTestScene + public partial class TestSceneRoundResultsScreen : MatchmakingTestScene { public override void SetUpSteps() { diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneStageDisplay.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneStageDisplay.cs index dc4f09c55514..a4aa4e2cebc7 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneStageDisplay.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneStageDisplay.cs @@ -9,11 +9,10 @@ using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Screens.OnlinePlay.Matchmaking.Match; -using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestSceneStageDisplay : MultiplayerTestScene + public partial class TestSceneStageDisplay : MatchmakingTestScene { [Cached] protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); From 6052ed790d70a5c552e5360c68d90dd289129eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 20 Nov 2025 12:23:31 +0100 Subject: [PATCH 129/836] Debounce continuous track seeks to at most one every 500ms See https://github.com/ppy/osu/pull/35677#issuecomment-3555903209. --- .../Graphics/UserInterface/ProgressBar.cs | 5 ++- osu.Game/Overlays/NowPlayingOverlay.cs | 20 +++++++++- .../Timelines/Summary/Parts/MarkerPart.cs | 39 ++++++++++++------- 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/ProgressBar.cs b/osu.Game/Graphics/UserInterface/ProgressBar.cs index dcf96f04c0cc..1169d4ca8818 100644 --- a/osu.Game/Graphics/UserInterface/ProgressBar.cs +++ b/osu.Game/Graphics/UserInterface/ProgressBar.cs @@ -16,6 +16,7 @@ public partial class ProgressBar : SliderBar public bool Seeking { get; private set; } public Action OnSeek; + public Action OnCommit; private readonly Box fill; private readonly Box background; @@ -80,12 +81,14 @@ protected override void UpdateValue(float value) protected override void OnUserChange(double value) { Seeking = true; + OnSeek?.Invoke(value); + base.OnUserChange(value); } protected override bool Commit() { - OnSeek?.Invoke(CurrentNumber.Value); Seeking = false; + OnCommit?.Invoke(CurrentNumber.Value); return base.Commit(); } } diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index 84c279476fb7..9f9f57336c1a 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -207,7 +207,8 @@ private void load() Height = progress_height / 2, FillColour = colours.Yellow, BackgroundColour = colours.YellowDarker.Opacity(0.5f), - OnSeek = musicController.SeekTo + OnSeek = onSeek, + OnCommit = onCommit, } }, }, @@ -221,6 +222,23 @@ private void load() }; } + private double? lastSeekTime; + + private void onSeek(double progress) + { + if (lastSeekTime == null || Time.Current - lastSeekTime > 500) + { + musicController.SeekTo(progress); + lastSeekTime = Time.Current; + } + } + + private void onCommit(double progress) + { + musicController.SeekTo(progress); + lastSeekTime = null; + } + private void togglePlaylist() { if (playlist == null) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs index afe14de3eab2..c9a44eab4a63 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Input.Events; -using osu.Framework.Threading; using osu.Game.Screens.Edit.Compose.Components.Timeline; using osuTK; @@ -34,39 +33,53 @@ private void load() }); } + private double? lastSeekTime; + protected override bool OnDragStart(DragStartEvent e) => true; protected override void OnDrag(DragEvent e) { - seekToPosition(e.ScreenSpaceMousePosition); + base.OnDrag(e); + seekToPosition(e.ScreenSpaceMousePosition, instant: false); + } + + protected override void OnDragEnd(DragEndEvent e) + { + base.OnDragEnd(e); + seekToPosition(e.ScreenSpaceMousePosition, instant: true); } protected override bool OnMouseDown(MouseDownEvent e) { - seekToPosition(e.ScreenSpaceMousePosition); + seekToPosition(e.ScreenSpaceMousePosition, instant: true); return true; } - private ScheduledDelegate? scheduledSeek; - /// /// Seeks the to the time closest to a position on the screen relative to the . /// /// The position in screen coordinates. - private void seekToPosition(Vector2 screenPosition) + /// Whether the seek should be instant (drag end, mouse button press) or debounced (drag in progress). + private void seekToPosition(Vector2 screenPosition, bool instant) { - scheduledSeek?.Cancel(); - scheduledSeek = Schedule(() => - { - float markerPos = Math.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth); - editorClock.SeekSmoothlyTo(markerPos / DrawWidth * editorClock.TrackLength); - }); + float markerPos = Math.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth); + double seekDestination = markerPos / DrawWidth * editorClock.TrackLength; + marker.X = (float)seekDestination; + + if (!instant && lastSeekTime != null && Time.Current - lastSeekTime < 500) + return; + + editorClock.SeekSmoothlyTo(seekDestination); + + lastSeekTime = instant ? null : Time.Current; } protected override void Update() { base.Update(); - marker.X = (float)editorClock.CurrentTime; + + if (!IsDragged) + marker.X = (float)editorClock.CurrentTime; } protected override void LoadBeatmap(EditorBeatmap beatmap) From f0f33b6df443ce34662f8da7c999081b939788ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 20 Nov 2025 10:29:15 +0100 Subject: [PATCH 130/836] Adjust precisions to be less weird In a perfect world you could specify different precisions for the slider and the text box but let's start here and see if we get complaints first. --- .../Editor/TestSceneOsuEditorGrids.cs | 8 ++++---- osu.Game.Rulesets.Osu/Edit/FreehandSliderToolboxGroup.cs | 9 ++++++--- osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs | 8 ++++---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs index c6893a5bdfb4..b9258f0053ca 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs @@ -245,13 +245,13 @@ public void TestGridPlacementTool() AddAssert("grid spacing is distance to slider tail", () => { var composer = Editor.ChildrenOfType().Single(); - return Precision.AlmostEquals(composer.Spacing.Value.X, 32.05, 0.01) + return Precision.AlmostEquals(composer.Spacing.Value.X, 32.05, 0.1) && Precision.AlmostEquals(composer.Spacing.Value.X, composer.Spacing.Value.Y); }); AddAssert("grid rotation points to slider tail", () => { var composer = Editor.ChildrenOfType().Single(); - return Precision.AlmostEquals(composer.GridLineRotation.Value, 0.09, 0.01); + return Precision.AlmostEquals(composer.GridLineRotation.Value, 0.09, 0.1); }); AddStep("start grid placement", () => InputManager.Key(Key.Number5)); @@ -280,9 +280,9 @@ public void TestGridPlacementTool() AddAssert("grid spacing and rotation unchanged", () => { var composer = Editor.ChildrenOfType().Single(); - return Precision.AlmostEquals(composer.Spacing.Value.X, 32.05, 0.01) + return Precision.AlmostEquals(composer.Spacing.Value.X, 32.05, 0.1) && Precision.AlmostEquals(composer.Spacing.Value.X, composer.Spacing.Value.Y) - && Precision.AlmostEquals(composer.GridLineRotation.Value, 0.09, 0.01); + && Precision.AlmostEquals(composer.GridLineRotation.Value, 0.09, 0.1); }); } diff --git a/osu.Game.Rulesets.Osu/Edit/FreehandSliderToolboxGroup.cs b/osu.Game.Rulesets.Osu/Edit/FreehandSliderToolboxGroup.cs index 79090443610c..6f8c58e1e45e 100644 --- a/osu.Game.Rulesets.Osu/Edit/FreehandSliderToolboxGroup.cs +++ b/osu.Game.Rulesets.Osu/Edit/FreehandSliderToolboxGroup.cs @@ -44,19 +44,22 @@ public FreehandSliderToolboxGroup() private readonly BindableInt displayTolerance = new BindableInt(90) { MinValue = 5, - MaxValue = 100 + MaxValue = 100, + Precision = 1, }; private readonly BindableInt displayCornerThreshold = new BindableInt(40) { MinValue = 5, - MaxValue = 100 + MaxValue = 100, + Precision = 1, }; private readonly BindableInt displayCircleThreshold = new BindableInt(30) { MinValue = 0, - MaxValue = 100 + MaxValue = 100, + Precision = 1, }; private ExpandableSlider toleranceSlider = null!; diff --git a/osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs b/osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs index e0c486a68839..5cc25630aaca 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuGridToolboxGroup.cs @@ -38,7 +38,7 @@ public partial class OsuGridToolboxGroup : EditorToolboxGroup, IKeyBindingHandle { MinValue = 0f, MaxValue = OsuPlayfield.BASE_SIZE.X, - Precision = 0.01f, + Precision = 0.1f, }; /// @@ -48,7 +48,7 @@ public partial class OsuGridToolboxGroup : EditorToolboxGroup, IKeyBindingHandle { MinValue = 0f, MaxValue = OsuPlayfield.BASE_SIZE.Y, - Precision = 0.01f, + Precision = 0.1f, }; /// @@ -58,7 +58,7 @@ public partial class OsuGridToolboxGroup : EditorToolboxGroup, IKeyBindingHandle { MinValue = 4f, MaxValue = 256f, - Precision = 0.01f, + Precision = 0.1f, }; /// @@ -68,7 +68,7 @@ public partial class OsuGridToolboxGroup : EditorToolboxGroup, IKeyBindingHandle { MinValue = -180f, MaxValue = 180f, - Precision = 0.01f, + Precision = 0.1f, }; /// From edf7a126c8afcae3a0da9713a980a0c944a03f85 Mon Sep 17 00:00:00 2001 From: marvin Date: Fri, 21 Nov 2025 01:32:11 +0100 Subject: [PATCH 131/836] Use single drawable for background --- .../Match/MatchmakingBackgroundScreen.cs | 32 +++++-------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingBackgroundScreen.cs index cfb3f2e6c424..89a404faaaeb 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingBackgroundScreen.cs @@ -4,11 +4,9 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Overlays; -using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match { @@ -27,29 +25,15 @@ public partial class Content : CompositeDrawable [BackgroundDependencyLoader] private void load(TextureStore textures, OverlayColourProvider colourProvider) { - AddRangeInternal(new Drawable[] + InternalChild = new Sprite { - new Sprite - { - RelativeSizeAxes = Axes.Both, - Texture = textures.Get("Backgrounds/bg1"), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Colour4, - Alpha = 0.5f, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.6f, - } - }); + RelativeSizeAxes = Axes.Both, + Texture = textures.Get("Backgrounds/bg1"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + FillMode = FillMode.Fill, + Colour = colourProvider.Dark2 + }; } } } From 1dd026c0f096e7e34a10110fbdb55f3eeb46ac07 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 13:55:01 +0900 Subject: [PATCH 132/836] Fix everything crashing --- .../Matchmaking/MatchmakingTestScene.cs | 10 +++--- .../Matchmaking/Intro/ScreenIntro.cs | 27 ++------------- .../Match/MatchmakingBackgroundScreen.cs | 33 ++++++++----------- .../Matchmaking/Match/ScreenMatchmaking.cs | 5 ++- 4 files changed, 26 insertions(+), 49 deletions(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/MatchmakingTestScene.cs b/osu.Game.Tests/Visual/Matchmaking/MatchmakingTestScene.cs index 8c01083b12c9..ebfe79502889 100644 --- a/osu.Game.Tests/Visual/Matchmaking/MatchmakingTestScene.cs +++ b/osu.Game.Tests/Visual/Matchmaking/MatchmakingTestScene.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Overlays; +using osu.Game.Screens; using osu.Game.Screens.OnlinePlay.Matchmaking.Match; using osu.Game.Tests.Visual.Multiplayer; @@ -19,14 +20,15 @@ public abstract partial class MatchmakingTestScene : MultiplayerTestScene protected MatchmakingTestScene() { + BackgroundScreenStack backgroundStack; + base.Content.AddRange(new Drawable[] { - new MatchmakingBackgroundScreen.Content - { - RelativeSizeAxes = Axes.Both, - }, + backgroundStack = new BackgroundScreenStack(), Content = new Container { RelativeSizeAxes = Axes.Both } }); + + backgroundStack.Push(new MatchmakingBackgroundScreen(colourProvider)); } } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Intro/ScreenIntro.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Intro/ScreenIntro.cs index 093d9f611751..7d630ff986ef 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Intro/ScreenIntro.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Intro/ScreenIntro.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -13,7 +12,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; -using osu.Game.Screens.OnlinePlay.Match; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match; using osu.Game.Screens.OnlinePlay.Matchmaking.Queue; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Intro @@ -53,7 +52,7 @@ public partial class ScreenIntro : OsuScreen private IDisposable? duckOperation; - protected override BackgroundScreen CreateBackground() => new MatchmakingIntroBackgroundScreen(colourProvider); + protected override BackgroundScreen CreateBackground() => new MatchmakingBackgroundScreen(colourProvider); public ScreenIntro() { @@ -240,27 +239,5 @@ private void resetAudio() beatmapImpactChannel?.Stop(); duckOperation?.Dispose(); } - - private partial class MatchmakingIntroBackgroundScreen : RoomBackgroundScreen - { - private readonly OverlayColourProvider colourProvider; - - public MatchmakingIntroBackgroundScreen(OverlayColourProvider colourProvider) - : base(null) - { - this.colourProvider = colourProvider; - } - - [BackgroundDependencyLoader] - private void load() - { - AddInternal(new Box - { - Depth = float.MinValue, - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5.Opacity(0.6f), - }); - } - } } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingBackgroundScreen.cs index 89a404faaaeb..bc832a934672 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingBackgroundScreen.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Overlays; @@ -12,29 +11,25 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match { public partial class MatchmakingBackgroundScreen : BackgroundScreen { - public MatchmakingBackgroundScreen() + private readonly OverlayColourProvider colourProvider; + + public MatchmakingBackgroundScreen(OverlayColourProvider colourProvider) { - InternalChild = new Content - { - RelativeSizeAxes = Axes.Both - }; + this.colourProvider = colourProvider; } - public partial class Content : CompositeDrawable + [BackgroundDependencyLoader] + private void load(TextureStore textures) { - [BackgroundDependencyLoader] - private void load(TextureStore textures, OverlayColourProvider colourProvider) + InternalChild = new Sprite { - InternalChild = new Sprite - { - RelativeSizeAxes = Axes.Both, - Texture = textures.Get("Backgrounds/bg1"), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill, - Colour = colourProvider.Dark2 - }; - } + RelativeSizeAxes = Axes.Both, + Texture = textures.Get("Backgrounds/bg1"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + FillMode = FillMode.Fill, + Colour = colourProvider.Dark2 + }; } } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs index 8a48a089b46d..a8092705744f 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs @@ -57,7 +57,10 @@ public partial class ScreenMatchmaking : OsuScreen, IPreviewTrackOwner, IHandleP public override bool ShowFooter => true; - protected override BackgroundScreen CreateBackground() => new MatchmakingBackgroundScreen(); + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + protected override BackgroundScreen CreateBackground() => new MatchmakingBackgroundScreen(colourProvider); [Cached(typeof(OnlinePlayBeatmapAvailabilityTracker))] private readonly OnlinePlayBeatmapAvailabilityTracker beatmapAvailabilityTracker = new MultiplayerBeatmapAvailabilityTracker(); From fa8d303922d3fec0ec6910cf895c8619a5490dce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 14:54:25 +0900 Subject: [PATCH 133/836] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 2df686d354c1..98d4ebc31636 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index 74dae877f12f..4a5919d16dc9 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From 8e78f4dac4fb1975eb48da6d767bbf9edfd43079 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 15:33:14 +0900 Subject: [PATCH 134/836] Adjust button colour and don't show warning --- osu.Game/Overlays/Settings/Sections/GeneralSection.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index 848fbd9c7a72..b3ef1b924297 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -7,6 +7,7 @@ using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Localisation; +using osu.Game.Online.Chat; using osu.Game.Overlays.Settings.Sections.General; namespace osu.Game.Overlays.Settings.Sections @@ -49,7 +50,8 @@ private void load(OsuColour colours) { Text = GeneralSettingsStrings.ReportIssue, TooltipText = GeneralSettingsStrings.ReportIssueTooltip, - Action = () => game?.OpenUrlExternally(@"https://osu.ppy.sh/community/forums/topics/create?forum_id=5") + BackgroundColour = colours.DarkOrange2, + Action = () => game?.OpenUrlExternally(@"https://osu.ppy.sh/community/forums/topics/create?forum_id=5", LinkWarnMode.NeverWarn) }, new LanguageSettings(), new UpdateSettings(), From 6362cdb6755509395dcc7618a7594d6dd566f15f Mon Sep 17 00:00:00 2001 From: marvin Date: Thu, 20 Nov 2025 18:45:40 +0100 Subject: [PATCH 135/836] Replace `MatchmakingRoomState.CandidateType` with `MatchmakingRoomState.FinalItem` --- .../Matchmaking/TestSceneBeatmapSelectGrid.cs | 9 ++++---- .../Matchmaking/TestSceneMatchmakingScreen.cs | 1 + .../Visual/Matchmaking/TestScenePickScreen.cs | 3 +-- .../Matchmaking/MatchmakingCandidateType.cs | 11 ---------- .../Matchmaking/MatchmakingRoomState.cs | 2 +- .../Match/BeatmapSelect/BeatmapSelectGrid.cs | 22 ++++++------------- .../BeatmapSelect/SubScreenBeatmapSelect.cs | 5 ++--- .../Match/ScreenMatchmaking.ScreenStack.cs | 2 +- 8 files changed, 17 insertions(+), 38 deletions(-) delete mode 100644 osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingCandidateType.cs diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs index 4ca014bf2a8d..3bbf001b6413 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs @@ -13,7 +13,6 @@ using osu.Game.Graphics.Sprites; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Mods; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect; @@ -131,7 +130,7 @@ public void TestCompleteRollAnimation() { var (candidateItems, finalItem) = pickRandomItems(5); - grid.RollAndDisplayFinalBeatmap(candidateItems, finalItem, MatchmakingCandidateType.UserSelection); + grid.RollAndDisplayFinalBeatmap(candidateItems, finalItem, finalItem); }); } @@ -160,7 +159,7 @@ public void TestPresentRolledBeatmap() grid.ArrangeItemsForRollAnimation(duration: 0, stagger: 0); grid.PlayRollAnimation(finalItem, duration: 0); - Scheduler.AddDelayed(() => grid.PresentRolledBeatmap(finalItem, finalItem, MatchmakingCandidateType.UserSelection), 500); + Scheduler.AddDelayed(() => grid.PresentRolledBeatmap(finalItem, finalItem), 500); }); } @@ -175,7 +174,7 @@ public void TestPresentUnanimouslyChosenBeatmap() grid.ArrangeItemsForRollAnimation(duration: 0, stagger: 0); grid.PlayRollAnimation(finalItem, duration: 0); - Scheduler.AddDelayed(() => grid.PresentUnanimouslyChosenBeatmap(finalItem, finalItem, MatchmakingCandidateType.UserSelection), 500); + Scheduler.AddDelayed(() => grid.PresentUnanimouslyChosenBeatmap(finalItem, finalItem), 500); }); } @@ -192,7 +191,7 @@ public void TestPresentRandomItem() Scheduler.AddDelayed(() => { - grid.PresentRolledBeatmap(-1, finalItem, MatchmakingCandidateType.Random); + grid.PresentRolledBeatmap(-1, finalItem); }, 500); }); } diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreen.cs index e88b10d30de7..642e9926c33f 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreen.cs @@ -110,6 +110,7 @@ public void TestGameplayFlow() state.CandidateItems = beatmaps.Select(b => b.ID).ToArray(); state.CandidateItem = beatmaps[0].ID; + state.FinalItem = beatmaps[0].ID; }, waitTime: 35); changeStage(MatchmakingStage.WaitingForClientsBeatmapDownload); diff --git a/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs index 1b7cc90132bd..5bb6ab2c447b 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs @@ -9,7 +9,6 @@ using osu.Framework.Utils; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect; using osu.Game.Tests.Visual.Multiplayer; @@ -105,7 +104,7 @@ public void TestScreen() long[] candidateItems = selectedItems.ToArray(); long finalItem = candidateItems[Random.Shared.Next(candidateItems.Length)]; - screen.RollFinalBeatmap(candidateItems, finalItem, MatchmakingCandidateType.UserSelection); + screen.RollFinalBeatmap(candidateItems, finalItem, finalItem); }); } } diff --git a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingCandidateType.cs b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingCandidateType.cs deleted file mode 100644 index 91b436088b77..000000000000 --- a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingCandidateType.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -namespace osu.Game.Online.Multiplayer.MatchTypes.Matchmaking -{ - public enum MatchmakingCandidateType - { - UserSelection, - Random, - } -} diff --git a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs index 44774c350db0..2901074fb008 100644 --- a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs @@ -46,7 +46,7 @@ public class MatchmakingRoomState : MatchRoomState public MatchmakingUserList Users { get; set; } = new MatchmakingUserList(); [Key(5)] - public MatchmakingCandidateType CandidateType { get; set; } + public long FinalItem { get; set; } /// /// Advances to the next round. diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs index 137f7712e01c..eb2bb37482fb 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs @@ -17,7 +17,6 @@ using osu.Framework.Utils; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osuTK; @@ -141,18 +140,11 @@ public void SetUserSelection(APIUser user, long itemId, bool selected) => whenPa panel.RemoveUser(user); }); - public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId, MatchmakingCandidateType candidateType) => whenPanelsLoaded(() => + public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long candidateItemId, long finalItemId) => whenPanelsLoaded(() => { - long candidateItemId = candidateType switch - { - MatchmakingCandidateType.UserSelection => finalItemId, - MatchmakingCandidateType.Random => -1, - _ => throw new ArgumentOutOfRangeException(nameof(candidateType), candidateType, null) - }; - Debug.Assert(candidateItemIds.Length >= 1); Debug.Assert(candidateItemIds.Contains(candidateItemId)); - Debug.Assert(panelLookup.ContainsKey(finalItemId)); + Debug.Assert(panelLookup.ContainsKey(candidateItemId)); Debug.Assert(candidateItemIds.All(id => panelLookup.ContainsKey(id))); allowSelection = false; @@ -164,7 +156,7 @@ public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId this.Delay(ARRANGE_DELAY) .Schedule(() => ArrangeItemsForRollAnimation()) .Delay(arrange_duration + present_beatmap_delay) - .Schedule(() => PresentUnanimouslyChosenBeatmap(candidateItemId, finalItemId, candidateType)); + .Schedule(() => PresentUnanimouslyChosenBeatmap(candidateItemId, finalItemId)); } else { @@ -173,7 +165,7 @@ public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId .Delay(arrange_duration) .Schedule(() => PlayRollAnimation(finalItemId, roll_duration)) .Delay(roll_duration + present_beatmap_delay) - .Schedule(() => PresentRolledBeatmap(candidateItemId, finalItemId, candidateType)); + .Schedule(() => PresentRolledBeatmap(candidateItemId, finalItemId)); } }); @@ -320,7 +312,7 @@ internal void PlayRollAnimation(long finalItem, double duration = roll_duration) } } - internal void PresentRolledBeatmap(long candidateItem, long finalItem, MatchmakingCandidateType candidateType) + internal void PresentRolledBeatmap(long candidateItem, long finalItem) { Debug.Assert(rollContainer.Children.Any(it => it.Item.ID == candidateItem)); Debug.Assert(playlistItems.ContainsKey(finalItem)); @@ -346,11 +338,11 @@ internal void PresentRolledBeatmap(long candidateItem, long finalItem, Matchmaki } } - internal void PresentUnanimouslyChosenBeatmap(long candidateItem, long finalItem, MatchmakingCandidateType candidateType) + internal void PresentUnanimouslyChosenBeatmap(long candidateItem, long finalItem) { // TODO: display special animation in this case - PresentRolledBeatmap(candidateItem, finalItem, candidateType); + PresentRolledBeatmap(candidateItem, finalItem); } private readonly TaskCompletionSource panelsLoaded = new TaskCompletionSource(); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs index 5f6886d23a39..607a8e47f0b0 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs @@ -13,7 +13,6 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -135,8 +134,8 @@ private void onItemDeselected(int userId, long itemId) beatmapSelectGrid.SetUserSelection(user, itemId, false); } - public void RollFinalBeatmap(long[] candidateItems, long finalItem, MatchmakingCandidateType panelType) => - beatmapSelectGrid.RollAndDisplayFinalBeatmap(candidateItems, finalItem, panelType); + public void RollFinalBeatmap(long[] candidateItems, long candidateItem, long finalItem) => + beatmapSelectGrid.RollAndDisplayFinalBeatmap(candidateItems, candidateItem, finalItem); protected override void Dispose(bool isDisposing) { diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs index ad517b0de566..4aee7e8a211f 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs @@ -108,7 +108,7 @@ private void onMatchRoomStateChanged(MatchRoomState? state) => Scheduler.Add(() case MatchmakingStage.ServerBeatmapFinalised: Debug.Assert(screenStack.CurrentScreen is SubScreenBeatmapSelect); - ((SubScreenBeatmapSelect)screenStack.CurrentScreen).RollFinalBeatmap(matchmakingState.CandidateItems, matchmakingState.CandidateItem, matchmakingState.CandidateType); + ((SubScreenBeatmapSelect)screenStack.CurrentScreen).RollFinalBeatmap(matchmakingState.CandidateItems, matchmakingState.CandidateItem, matchmakingState.FinalItem); break; case MatchmakingStage.ResultsDisplaying: From 871c0ebe3d7a75fa8a21c27eb3f333a37d10442a Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 21 Nov 2025 15:34:30 +0900 Subject: [PATCH 136/836] Rename to `GameplayItem` + adjust documentation --- .../Matchmaking/TestSceneMatchmakingScreen.cs | 2 +- .../Matchmaking/MatchmakingRoomState.cs | 18 +++++++++++++++--- .../Match/BeatmapSelect/BeatmapSelectGrid.cs | 18 +++++++++--------- .../BeatmapSelect/SubScreenBeatmapSelect.cs | 4 ++-- .../Match/ScreenMatchmaking.ScreenStack.cs | 2 +- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreen.cs index 642e9926c33f..5b60f1e7a1bc 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreen.cs @@ -110,7 +110,7 @@ public void TestGameplayFlow() state.CandidateItems = beatmaps.Select(b => b.ID).ToArray(); state.CandidateItem = beatmaps[0].ID; - state.FinalItem = beatmaps[0].ID; + state.GameplayItem = beatmaps[0].ID; }, waitTime: 35); changeStage(MatchmakingStage.WaitingForClientsBeatmapDownload); diff --git a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs index 2901074fb008..0c4106ae2b21 100644 --- a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingRoomState.cs @@ -28,14 +28,20 @@ public class MatchmakingRoomState : MatchRoomState public int CurrentRound { get; set; } /// - /// The playlist items that were picked as gameplay candidates. + /// The playlist items that were picked as candidates by user. /// + /// + /// May contain -1 when any users picked the "random" playlist item. + /// [Key(2)] public long[] CandidateItems { get; set; } = []; /// - /// The final gameplay candidate. + /// A playlist item from that was randomly picked by the server. /// + /// + /// May be -1 to indicate the "random" playlist item was chosen. + /// [Key(3)] public long CandidateItem { get; set; } @@ -45,8 +51,14 @@ public class MatchmakingRoomState : MatchRoomState [Key(4)] public MatchmakingUserList Users { get; set; } = new MatchmakingUserList(); + /// + /// A playlist item from the room's playlist that will be played in the current round. + /// + /// + /// The value of this property may not equal or exist in . + /// [Key(5)] - public long FinalItem { get; set; } + public long GameplayItem { get; set; } /// /// Advances to the next round. diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs index eb2bb37482fb..5e8975410fed 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs @@ -140,7 +140,7 @@ public void SetUserSelection(APIUser user, long itemId, bool selected) => whenPa panel.RemoveUser(user); }); - public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long candidateItemId, long finalItemId) => whenPanelsLoaded(() => + public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long candidateItemId, long gameplayItemId) => whenPanelsLoaded(() => { Debug.Assert(candidateItemIds.Length >= 1); Debug.Assert(candidateItemIds.Contains(candidateItemId)); @@ -156,16 +156,16 @@ public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long candidateIt this.Delay(ARRANGE_DELAY) .Schedule(() => ArrangeItemsForRollAnimation()) .Delay(arrange_duration + present_beatmap_delay) - .Schedule(() => PresentUnanimouslyChosenBeatmap(candidateItemId, finalItemId)); + .Schedule(() => PresentUnanimouslyChosenBeatmap(candidateItemId, gameplayItemId)); } else { this.Delay(ARRANGE_DELAY) .Schedule(() => ArrangeItemsForRollAnimation()) .Delay(arrange_duration) - .Schedule(() => PlayRollAnimation(finalItemId, roll_duration)) + .Schedule(() => PlayRollAnimation(gameplayItemId, roll_duration)) .Delay(roll_duration + present_beatmap_delay) - .Schedule(() => PresentRolledBeatmap(candidateItemId, finalItemId)); + .Schedule(() => PresentRolledBeatmap(candidateItemId, gameplayItemId)); } }); @@ -312,10 +312,10 @@ internal void PlayRollAnimation(long finalItem, double duration = roll_duration) } } - internal void PresentRolledBeatmap(long candidateItem, long finalItem) + internal void PresentRolledBeatmap(long candidateItem, long gameplayItem) { Debug.Assert(rollContainer.Children.Any(it => it.Item.ID == candidateItem)); - Debug.Assert(playlistItems.ContainsKey(finalItem)); + Debug.Assert(playlistItems.ContainsKey(gameplayItem)); foreach (var panel in rollContainer.Children) { @@ -331,18 +331,18 @@ internal void PresentRolledBeatmap(long candidateItem, long finalItem) { rollContainer.ChangeChildDepth(panel, float.MinValue); - var item = playlistItems[finalItem]; + var item = playlistItems[gameplayItem]; panel.PresentAsChosenBeatmap(item); }); } } - internal void PresentUnanimouslyChosenBeatmap(long candidateItem, long finalItem) + internal void PresentUnanimouslyChosenBeatmap(long candidateItem, long gameplayItem) { // TODO: display special animation in this case - PresentRolledBeatmap(candidateItem, finalItem); + PresentRolledBeatmap(candidateItem, gameplayItem); } private readonly TaskCompletionSource panelsLoaded = new TaskCompletionSource(); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs index 607a8e47f0b0..9262e105264d 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs @@ -134,8 +134,8 @@ private void onItemDeselected(int userId, long itemId) beatmapSelectGrid.SetUserSelection(user, itemId, false); } - public void RollFinalBeatmap(long[] candidateItems, long candidateItem, long finalItem) => - beatmapSelectGrid.RollAndDisplayFinalBeatmap(candidateItems, candidateItem, finalItem); + public void RollFinalBeatmap(long[] candidateItems, long candidateItem, long gameplayItem) => + beatmapSelectGrid.RollAndDisplayFinalBeatmap(candidateItems, candidateItem, gameplayItem); protected override void Dispose(bool isDisposing) { diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs index 4aee7e8a211f..4d5a7099c460 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs @@ -108,7 +108,7 @@ private void onMatchRoomStateChanged(MatchRoomState? state) => Scheduler.Add(() case MatchmakingStage.ServerBeatmapFinalised: Debug.Assert(screenStack.CurrentScreen is SubScreenBeatmapSelect); - ((SubScreenBeatmapSelect)screenStack.CurrentScreen).RollFinalBeatmap(matchmakingState.CandidateItems, matchmakingState.CandidateItem, matchmakingState.FinalItem); + ((SubScreenBeatmapSelect)screenStack.CurrentScreen).RollFinalBeatmap(matchmakingState.CandidateItems, matchmakingState.CandidateItem, matchmakingState.GameplayItem); break; case MatchmakingStage.ResultsDisplaying: From 34146b8bcbaa2bf3adb77390e67c303c81e82e83 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 16:23:53 +0900 Subject: [PATCH 137/836] Update rounded button to be less rounded Intended to match the rest of the UI which is less rounded these days. See inline comment for reason for not matching `FormControl` corner radius just yet. --- .../Graphics/UserInterfaceV2/RoundedButton.cs | 18 +++--------------- osu.Game/Overlays/Settings/SettingsButton.cs | 7 ++++++- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs index bf92f20526a3..01c495ae30ba 100644 --- a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs @@ -26,18 +26,6 @@ public partial class RoundedButton : OsuButton, IFilterable, IHasTooltip private Color4? triangleGradientSecondColour; - public override float Height - { - get => base.Height; - set - { - base.Height = value; - - if (IsLoaded) - updateCornerRadius(); - } - } - public override Color4 BackgroundColour { get => base.BackgroundColour; @@ -61,7 +49,9 @@ protected override void LoadComplete() { base.LoadComplete(); - updateCornerRadius(); + // This doesn't match the latest design spec (should be 5) but is an in-between that feels right to the eye + // until we move everything over to Form controls. + Content.CornerRadius = 10; Add(Triangles = new TrianglesV2 { @@ -98,8 +88,6 @@ protected override void OnHoverLost(HoverLostEvent e) base.OnHoverLost(e); } - private void updateCornerRadius() => Content.CornerRadius = DrawHeight / 2; - public virtual IEnumerable FilterTerms => new[] { Text }; public bool MatchingFilter diff --git a/osu.Game/Overlays/Settings/SettingsButton.cs b/osu.Game/Overlays/Settings/SettingsButton.cs index 196ddca95307..0033543fdb13 100644 --- a/osu.Game/Overlays/Settings/SettingsButton.cs +++ b/osu.Game/Overlays/Settings/SettingsButton.cs @@ -16,7 +16,12 @@ public partial class SettingsButton : RoundedButton, IConditionalFilterable public SettingsButton() { RelativeSizeAxes = Axes.X; - Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS }; + Margin = new MarginPadding { Vertical = -5 }; + Padding = new MarginPadding + { + Left = SettingsPanel.CONTENT_MARGINS, + Right = SettingsPanel.CONTENT_MARGINS, + }; } public IEnumerable Keywords { get; set; } = Array.Empty(); From df79269e6fa409cf7340de5553fb332f3ef57f9b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 16:24:10 +0900 Subject: [PATCH 138/836] Adjust tablet settings layout to feel a touch nicer --- .../Overlays/Settings/Sections/Input/TabletAreaSelection.cs | 2 +- osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs index 33f4f49173bf..b3fdd534666d 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs @@ -137,7 +137,7 @@ protected override void LoadComplete() rotation.BindValueChanged(val => { usableAreaContainer.RotateTo(val.NewValue, 100, Easing.OutQuint); - tabletContainer.RotateTo(-val.NewValue, 800, Easing.OutQuint); + tabletContainer.RotateTo(-val.NewValue, 400, Easing.OutQuint); checkBounds(); }, true); diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 6aebec88a989..86b52328b204 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -126,7 +126,7 @@ private void load(OsuColour colours, LocalisationManager localisation) Alpha = 0, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Spacing = new Vector2(0, 8), + Spacing = new Vector2(0, SettingsSection.ITEM_SPACING), Direction = FillDirection.Vertical, Children = new Drawable[] { From 908a950cd2431ed2dbed1a763101a709859dbf4a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 16:25:04 +0900 Subject: [PATCH 139/836] Move quick action settings into own subsection --- .../Localisation/GeneralSettingsStrings.cs | 5 ++ .../Sections/General/QuickActionSettings.cs | 52 +++++++++++++++++++ .../Settings/Sections/GeneralSection.cs | 31 +---------- 3 files changed, 59 insertions(+), 29 deletions(-) create mode 100644 osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs diff --git a/osu.Game/Localisation/GeneralSettingsStrings.cs b/osu.Game/Localisation/GeneralSettingsStrings.cs index 7e4ee942869f..d1e22c197e0d 100644 --- a/osu.Game/Localisation/GeneralSettingsStrings.cs +++ b/osu.Game/Localisation/GeneralSettingsStrings.cs @@ -29,6 +29,11 @@ public static class GeneralSettingsStrings /// public static LocalisableString Prefer24HourTimeDisplay => new TranslatableString(getKey(@"prefer_24_hour_time_display"), @"Prefer 24-hour time display"); + /// + /// "Quick Actions" + /// + public static LocalisableString QuickActionsHeader => new TranslatableString(getKey(@"quick_actions_header"), @"Quick Actions"); + /// /// "Updates" /// diff --git a/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs new file mode 100644 index 000000000000..94f0e7a7d1d0 --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs @@ -0,0 +1,52 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Localisation; +using osu.Game.Online.Chat; + +namespace osu.Game.Overlays.Settings.Sections.General +{ + public partial class QuickActionSettings : SettingsSubsection + { + [Resolved(CanBeNull = true)] + private FirstRunSetupOverlay? firstRunSetupOverlay { get; set; } + + [Resolved(CanBeNull = true)] + private OsuGame? game { get; set; } + + protected override LocalisableString Header => GeneralSettingsStrings.QuickActionsHeader; + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + AddRange(new Drawable[] + { + new SettingsButton + { + Text = GeneralSettingsStrings.RunSetupWizard, + Keywords = new[] { @"first run", @"initial", @"getting started", @"import", @"tutorial", @"recommended beatmaps" }, + TooltipText = FirstRunSetupOverlayStrings.FirstRunSetupDescription, + Action = () => firstRunSetupOverlay?.Show(), + }, + new SettingsButton + { + Text = GeneralSettingsStrings.LearnMoreAboutLazer, + TooltipText = GeneralSettingsStrings.LearnMoreAboutLazerTooltip, + BackgroundColour = colours.YellowDark, + Action = () => game?.ShowWiki(@"Help_centre/Upgrading_to_lazer") + }, + new SettingsButton + { + Text = GeneralSettingsStrings.ReportIssue, + TooltipText = GeneralSettingsStrings.ReportIssueTooltip, + BackgroundColour = colours.YellowDarker, + Action = () => game?.OpenUrlExternally(@"https://osu.ppy.sh/community/forums/topics/create?forum_id=5", LinkWarnMode.NeverWarn) + }, + }); + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index b3ef1b924297..a8acbb6bbb21 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -7,19 +7,12 @@ using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Localisation; -using osu.Game.Online.Chat; using osu.Game.Overlays.Settings.Sections.General; namespace osu.Game.Overlays.Settings.Sections { public partial class GeneralSection : SettingsSection { - [Resolved(CanBeNull = true)] - private FirstRunSetupOverlay? firstRunSetupOverlay { get; set; } - - [Resolved(CanBeNull = true)] - private OsuGame? game { get; set; } - public override LocalisableString Header => CommonStrings.General; public override Drawable CreateIcon() => new SpriteIcon @@ -28,33 +21,13 @@ public partial class GeneralSection : SettingsSection }; [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { Children = new Drawable[] { - new SettingsButton - { - Text = GeneralSettingsStrings.RunSetupWizard, - Keywords = new[] { @"first run", @"initial", @"getting started", @"import", @"tutorial", @"recommended beatmaps" }, - TooltipText = FirstRunSetupOverlayStrings.FirstRunSetupDescription, - Action = () => firstRunSetupOverlay?.Show(), - }, - new SettingsButton - { - Text = GeneralSettingsStrings.LearnMoreAboutLazer, - TooltipText = GeneralSettingsStrings.LearnMoreAboutLazerTooltip, - BackgroundColour = colours.YellowDark, - Action = () => game?.ShowWiki(@"Help_centre/Upgrading_to_lazer") - }, - new SettingsButton - { - Text = GeneralSettingsStrings.ReportIssue, - TooltipText = GeneralSettingsStrings.ReportIssueTooltip, - BackgroundColour = colours.DarkOrange2, - Action = () => game?.OpenUrlExternally(@"https://osu.ppy.sh/community/forums/topics/create?forum_id=5", LinkWarnMode.NeverWarn) - }, new LanguageSettings(), new UpdateSettings(), + new QuickActionSettings(), }; } } From 15ee49348d9506cb21ce50eefcdb45a06cc5ed2d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 21 Nov 2025 16:24:08 +0900 Subject: [PATCH 140/836] Add failing test --- .../Visual/Matchmaking/TestScenePickScreen.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs index e894616f9e3d..53db8efaf2e8 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs @@ -6,6 +6,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Screens; +using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; @@ -107,5 +108,25 @@ public void TestScreen() screen.RollFinalBeatmap(candidateItems, finalItem); }); } + + [Test] + public void TestExpiredBeatmapNotShown() + { + SubScreenBeatmapSelect screen = null!; + + AddStep("add screen with expired items", () => + { + MultiplayerClient.ClientRoom!.Playlist = + [ + new MultiplayerPlaylistItem(items[0]) { Expired = true }, + new MultiplayerPlaylistItem(items[1]) + ]; + + Child = new ScreenStack(screen = new SubScreenBeatmapSelect()); + }); + + AddUntilStep("items displayed", () => screen.ChildrenOfType().Any()); + AddAssert("expired item not shown", () => screen.ChildrenOfType().Count(), () => Is.EqualTo(1)); + } } } From d3860f1630d9bb56363c5f437e57997bb8173db5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 21 Nov 2025 14:58:22 +0900 Subject: [PATCH 141/836] Fix quick play showing expired playlist items --- .../Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs index 7951fc5448ec..8b11e84437e3 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs @@ -83,7 +83,7 @@ protected override void LoadComplete() Debug.Assert(client.Room != null); - loadItems(client.Room.Playlist.ToArray()).FireAndForget(); + loadItems(client.Room.Playlist.Where(item => !item.Expired).ToArray()).FireAndForget(); } private async Task loadItems(MultiplayerPlaylistItem[] items) From a8594f1c08dae7d72c91e25c32737132744f0e20 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 16:25:13 +0900 Subject: [PATCH 142/836] Move installation settings into own subsection --- .../Localisation/GeneralSettingsStrings.cs | 5 + .../Sections/General/InstallationSettings.cs | 114 ++++++++++++++++++ .../Sections/General/UpdateSettings.cs | 88 +------------- .../Settings/Sections/GeneralSection.cs | 1 + 4 files changed, 121 insertions(+), 87 deletions(-) create mode 100644 osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs diff --git a/osu.Game/Localisation/GeneralSettingsStrings.cs b/osu.Game/Localisation/GeneralSettingsStrings.cs index d1e22c197e0d..9b6276781ad2 100644 --- a/osu.Game/Localisation/GeneralSettingsStrings.cs +++ b/osu.Game/Localisation/GeneralSettingsStrings.cs @@ -29,6 +29,11 @@ public static class GeneralSettingsStrings /// public static LocalisableString Prefer24HourTimeDisplay => new TranslatableString(getKey(@"prefer_24_hour_time_display"), @"Prefer 24-hour time display"); + /// + /// "Installation" + /// + public static LocalisableString InstallationHeader => new TranslatableString(getKey(@"installation_header"), @"Installation"); + /// /// "Quick Actions" /// diff --git a/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs b/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs new file mode 100644 index 000000000000..92f6c5e3b094 --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs @@ -0,0 +1,114 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading.Tasks; +using osu.Framework; +using osu.Framework.Allocation; +using osu.Framework.Localisation; +using osu.Framework.Logging; +using osu.Framework.Platform; +using osu.Framework.Screens; +using osu.Framework.Statistics; +using osu.Game.Graphics; +using osu.Game.IO; +using osu.Game.Localisation; +using osu.Game.Overlays.Notifications; +using osu.Game.Overlays.Settings.Sections.Maintenance; +using osu.Game.Utils; +using SharpCompress.Archives.Zip; + +namespace osu.Game.Overlays.Settings.Sections.General +{ + public partial class InstallationSettings : SettingsSubsection + { + protected override LocalisableString Header => GeneralSettingsStrings.InstallationHeader; + + [Resolved] + private INotificationOverlay? notifications { get; set; } + + [Resolved] + private OsuGame? game { get; set; } + + private Storage exportStorage = null!; + + [BackgroundDependencyLoader] + private void load(Storage storage, OsuColour colours) + { + bool isDesktop = RuntimeInfo.IsDesktop; + bool supportsExport = RuntimeInfo.OS != RuntimeInfo.Platform.Android; + + // Loosely update-related maintenance buttons. + if (isDesktop) + { + Add(new SettingsButton + { + Text = GeneralSettingsStrings.OpenOsuFolder, + Keywords = new[] { @"logs", @"files", @"access", "directory" }, + Action = () => storage.PresentExternally(), + }); + + Add(new DangerousSettingsButton + { + Text = GeneralSettingsStrings.ChangeFolderLocation, + Action = () => game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen())) + }); + } + + if (supportsExport) + { + Add(new SettingsButton + { + Text = GeneralSettingsStrings.ExportLogs, + BackgroundColour = colours.YellowDarker, + Keywords = new[] { @"bug", "report", "logs", "files" }, + Action = () => Task.Run(exportLogs), + }); + + exportStorage = (storage as OsuStorage)?.GetExportStorage() ?? storage.GetStorageForDirectory(@"exports"); + } + } + + private void exportLogs() + { + ProgressNotification notification = new ProgressNotification + { + State = ProgressNotificationState.Active, + Text = "Exporting logs...", + }; + + notifications?.Post(notification); + + const string archive_filename = "compressed-logs.zip"; + + try + { + GlobalStatistics.OutputToLog(); + Logger.Flush(); + + var logStorage = Logger.Storage; + + using (var outStream = exportStorage.CreateFileSafely(archive_filename)) + using (var zip = ZipArchive.Create()) + { + foreach (string? f in logStorage.GetFiles(string.Empty, "*.log")) + FileUtils.AttemptOperation(z => z.AddEntry(f, logStorage.GetStream(f), true), zip); + + zip.SaveTo(outStream); + } + } + catch + { + notification.State = ProgressNotificationState.Cancelled; + + // cleanup if export is failed or canceled. + exportStorage.Delete(archive_filename); + throw; + } + + notification.CompletionText = "Exported logs! Click to view."; + notification.CompletionClickAction = () => exportStorage.PresentFileExternally(archive_filename); + + notification.State = ProgressNotificationState.Completed; + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs index 596e4b2589f9..04dec0539942 100644 --- a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs @@ -7,20 +7,12 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Framework.Logging; -using osu.Framework.Platform; -using osu.Framework.Screens; -using osu.Framework.Statistics; using osu.Game.Configuration; -using osu.Game.IO; using osu.Game.Localisation; using osu.Game.Online.Multiplayer; using osu.Game.Overlays.Dialog; using osu.Game.Overlays.Notifications; -using osu.Game.Overlays.Settings.Sections.Maintenance; using osu.Game.Updater; -using osu.Game.Utils; -using SharpCompress.Archives.Zip; namespace osu.Game.Overlays.Settings.Sections.General { @@ -45,15 +37,12 @@ public partial class UpdateSettings : SettingsSubsection [Resolved] private IDialogOverlay? dialogOverlay { get; set; } - private Storage exportStorage = null!; - [BackgroundDependencyLoader] - private void load(OsuConfigManager config, Storage storage) + private void load(OsuConfigManager config) { config.BindWith(OsuSetting.ReleaseStream, configReleaseStream); bool isDesktop = RuntimeInfo.IsDesktop; - bool supportsExport = RuntimeInfo.OS != RuntimeInfo.Platform.Android; bool canCheckUpdates = updateManager?.CanCheckForUpdate == true; if (canCheckUpdates) @@ -86,38 +75,6 @@ private void load(OsuConfigManager config, Storage storage) Action = () => checkForUpdates().FireAndForget() }); } - - // Loosely update-related maintenance buttons. - if (isDesktop) - { - Add(new SettingsButton - { - Text = GeneralSettingsStrings.OpenOsuFolder, - Keywords = new[] { @"logs", @"files", @"access", "directory" }, - Action = () => storage.PresentExternally(), - }); - } - - if (supportsExport) - { - Add(new SettingsButton - { - Text = GeneralSettingsStrings.ExportLogs, - Keywords = new[] { @"bug", "report", "logs", "files" }, - Action = () => Task.Run(exportLogs), - }); - } - - if (isDesktop) - { - Add(new SettingsButton - { - Text = GeneralSettingsStrings.ChangeFolderLocation, - Action = () => game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen())) - }); - } - - exportStorage = (storage as OsuStorage)?.GetExportStorage() ?? storage.GetStorageForDirectory(@"exports"); } private void releaseStreamChanged(ValueChangedEvent stream) @@ -176,48 +133,5 @@ private async Task checkForUpdates() checkForUpdatesButton.Enabled.Value = true; } } - - private void exportLogs() - { - ProgressNotification notification = new ProgressNotification - { - State = ProgressNotificationState.Active, - Text = "Exporting logs...", - }; - - notifications?.Post(notification); - - const string archive_filename = "compressed-logs.zip"; - - try - { - GlobalStatistics.OutputToLog(); - Logger.Flush(); - - var logStorage = Logger.Storage; - - using (var outStream = exportStorage.CreateFileSafely(archive_filename)) - using (var zip = ZipArchive.Create()) - { - foreach (string? f in logStorage.GetFiles(string.Empty, "*.log")) - FileUtils.AttemptOperation(z => z.AddEntry(f, logStorage.GetStream(f), true), zip); - - zip.SaveTo(outStream); - } - } - catch - { - notification.State = ProgressNotificationState.Cancelled; - - // cleanup if export is failed or canceled. - exportStorage.Delete(archive_filename); - throw; - } - - notification.CompletionText = "Exported logs! Click to view."; - notification.CompletionClickAction = () => exportStorage.PresentFileExternally(archive_filename); - - notification.State = ProgressNotificationState.Completed; - } } } diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index a8acbb6bbb21..7124d9a37d20 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -27,6 +27,7 @@ private void load() { new LanguageSettings(), new UpdateSettings(), + new InstallationSettings(), new QuickActionSettings(), }; } From a6a98fc078049e42680eb2d463c6a3a6f8d46d4e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 16:30:24 +0900 Subject: [PATCH 143/836] Only show update settings if the game can be updated --- .../Sections/General/UpdateSettings.cs | 44 +++++++++---------- .../Settings/Sections/GeneralSection.cs | 15 +++---- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs index 04dec0539942..87b1acc23a83 100644 --- a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs @@ -43,38 +43,34 @@ private void load(OsuConfigManager config) config.BindWith(OsuSetting.ReleaseStream, configReleaseStream); bool isDesktop = RuntimeInfo.IsDesktop; - bool canCheckUpdates = updateManager?.CanCheckForUpdate == true; - if (canCheckUpdates) + // For simplicity, hide the concept of release streams from mobile users. + if (isDesktop) { - // For simplicity, hide the concept of release streams from mobile users. - if (isDesktop) + Add(releaseStreamDropdown = new SettingsEnumDropdown { - Add(releaseStreamDropdown = new SettingsEnumDropdown - { - LabelText = GeneralSettingsStrings.ReleaseStream, - Current = { Value = configReleaseStream.Value }, - Keywords = new[] { @"version" }, - }); - - if (updateManager!.FixedReleaseStream != null) - { - configReleaseStream.Value = updateManager.FixedReleaseStream.Value; + LabelText = GeneralSettingsStrings.ReleaseStream, + Current = { Value = configReleaseStream.Value }, + Keywords = new[] { @"version" }, + }); - releaseStreamDropdown.ShowsDefaultIndicator = false; - releaseStreamDropdown.Items = [updateManager.FixedReleaseStream.Value]; - releaseStreamDropdown.SetNoticeText(GeneralSettingsStrings.ChangeReleaseStreamPackageManagerWarning); - } + if (updateManager!.FixedReleaseStream != null) + { + configReleaseStream.Value = updateManager.FixedReleaseStream.Value; - releaseStreamDropdown.Current.BindValueChanged(releaseStreamChanged); + releaseStreamDropdown.ShowsDefaultIndicator = false; + releaseStreamDropdown.Items = [updateManager.FixedReleaseStream.Value]; + releaseStreamDropdown.SetNoticeText(GeneralSettingsStrings.ChangeReleaseStreamPackageManagerWarning); } - Add(checkForUpdatesButton = new SettingsButton - { - Text = GeneralSettingsStrings.CheckUpdate, - Action = () => checkForUpdates().FireAndForget() - }); + releaseStreamDropdown.Current.BindValueChanged(releaseStreamChanged); } + + Add(checkForUpdatesButton = new SettingsButton + { + Text = GeneralSettingsStrings.CheckUpdate, + Action = () => checkForUpdates().FireAndForget() + }); } private void releaseStreamChanged(ValueChangedEvent stream) diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index 7124d9a37d20..1243887386ae 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -8,6 +8,7 @@ using osu.Game.Graphics; using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.General; +using osu.Game.Updater; namespace osu.Game.Overlays.Settings.Sections { @@ -21,15 +22,13 @@ public partial class GeneralSection : SettingsSection }; [BackgroundDependencyLoader] - private void load() + private void load(UpdateManager? updateManager) { - Children = new Drawable[] - { - new LanguageSettings(), - new UpdateSettings(), - new InstallationSettings(), - new QuickActionSettings(), - }; + Add(new LanguageSettings()); + if (updateManager?.CanCheckForUpdate == true) + Add(new UpdateSettings()); + Add(new InstallationSettings()); + Add(new QuickActionSettings()); } } } From 73349ab1825e449a8833f46ad19b3abf9dd5294c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 16:34:53 +0900 Subject: [PATCH 144/836] Move quick actions to top --- osu.Game/Overlays/Settings/Sections/GeneralSection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index 1243887386ae..18e650d70d28 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -24,11 +24,11 @@ public partial class GeneralSection : SettingsSection [BackgroundDependencyLoader] private void load(UpdateManager? updateManager) { + Add(new QuickActionSettings()); Add(new LanguageSettings()); if (updateManager?.CanCheckForUpdate == true) Add(new UpdateSettings()); Add(new InstallationSettings()); - Add(new QuickActionSettings()); } } } From 56ce955e0c3d16c26fabc4cc75e371b801dd98f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 16:40:38 +0900 Subject: [PATCH 145/836] Move export logs to quick actions (to sit with report issue button) --- .../Sections/General/InstallationSettings.cs | 72 +----------------- .../Sections/General/QuickActionSettings.cs | 75 ++++++++++++++++++- 2 files changed, 75 insertions(+), 72 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs b/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs index 92f6c5e3b094..3aaeadd1580a 100644 --- a/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs @@ -1,21 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Threading.Tasks; using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Localisation; -using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Screens; -using osu.Framework.Statistics; -using osu.Game.Graphics; -using osu.Game.IO; using osu.Game.Localisation; -using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Settings.Sections.Maintenance; -using osu.Game.Utils; -using SharpCompress.Archives.Zip; namespace osu.Game.Overlays.Settings.Sections.General { @@ -23,19 +15,13 @@ public partial class InstallationSettings : SettingsSubsection { protected override LocalisableString Header => GeneralSettingsStrings.InstallationHeader; - [Resolved] - private INotificationOverlay? notifications { get; set; } - [Resolved] private OsuGame? game { get; set; } - private Storage exportStorage = null!; - [BackgroundDependencyLoader] - private void load(Storage storage, OsuColour colours) + private void load(Storage storage) { bool isDesktop = RuntimeInfo.IsDesktop; - bool supportsExport = RuntimeInfo.OS != RuntimeInfo.Platform.Android; // Loosely update-related maintenance buttons. if (isDesktop) @@ -53,62 +39,6 @@ private void load(Storage storage, OsuColour colours) Action = () => game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen())) }); } - - if (supportsExport) - { - Add(new SettingsButton - { - Text = GeneralSettingsStrings.ExportLogs, - BackgroundColour = colours.YellowDarker, - Keywords = new[] { @"bug", "report", "logs", "files" }, - Action = () => Task.Run(exportLogs), - }); - - exportStorage = (storage as OsuStorage)?.GetExportStorage() ?? storage.GetStorageForDirectory(@"exports"); - } - } - - private void exportLogs() - { - ProgressNotification notification = new ProgressNotification - { - State = ProgressNotificationState.Active, - Text = "Exporting logs...", - }; - - notifications?.Post(notification); - - const string archive_filename = "compressed-logs.zip"; - - try - { - GlobalStatistics.OutputToLog(); - Logger.Flush(); - - var logStorage = Logger.Storage; - - using (var outStream = exportStorage.CreateFileSafely(archive_filename)) - using (var zip = ZipArchive.Create()) - { - foreach (string? f in logStorage.GetFiles(string.Empty, "*.log")) - FileUtils.AttemptOperation(z => z.AddEntry(f, logStorage.GetStream(f), true), zip); - - zip.SaveTo(outStream); - } - } - catch - { - notification.State = ProgressNotificationState.Cancelled; - - // cleanup if export is failed or canceled. - exportStorage.Delete(archive_filename); - throw; - } - - notification.CompletionText = "Exported logs! Click to view."; - notification.CompletionClickAction = () => exportStorage.PresentFileExternally(archive_filename); - - notification.State = ProgressNotificationState.Completed; } } } diff --git a/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs index 94f0e7a7d1d0..b6b78a6d00f4 100644 --- a/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs @@ -1,12 +1,22 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Threading.Tasks; +using osu.Framework; using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Localisation; +using osu.Framework.Logging; +using osu.Framework.Platform; +using osu.Framework.Statistics; using osu.Game.Graphics; +using osu.Game.IO; using osu.Game.Localisation; using osu.Game.Online.Chat; +using osu.Game.Overlays.Notifications; +using osu.Game.Utils; +using SharpCompress.Archives.Zip; namespace osu.Game.Overlays.Settings.Sections.General { @@ -21,7 +31,7 @@ public partial class QuickActionSettings : SettingsSubsection protected override LocalisableString Header => GeneralSettingsStrings.QuickActionsHeader; [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, Storage storage) { AddRange(new Drawable[] { @@ -47,6 +57,69 @@ private void load(OsuColour colours) Action = () => game?.OpenUrlExternally(@"https://osu.ppy.sh/community/forums/topics/create?forum_id=5", LinkWarnMode.NeverWarn) }, }); + + bool supportsExport = RuntimeInfo.OS != RuntimeInfo.Platform.Android; + + if (supportsExport) + { + Add(new SettingsButton + { + Text = GeneralSettingsStrings.ExportLogs, + BackgroundColour = colours.YellowDarker.Darken(0.5f), + Keywords = new[] { @"bug", "report", "logs", "files" }, + Action = () => Task.Run(exportLogs), + }); + + exportStorage = (storage as OsuStorage)?.GetExportStorage() ?? storage.GetStorageForDirectory(@"exports"); + } + } + + [Resolved] + private INotificationOverlay? notifications { get; set; } + + private Storage exportStorage = null!; + + private void exportLogs() + { + ProgressNotification notification = new ProgressNotification + { + State = ProgressNotificationState.Active, + Text = "Exporting logs...", + }; + + notifications?.Post(notification); + + const string archive_filename = "compressed-logs.zip"; + + try + { + GlobalStatistics.OutputToLog(); + Logger.Flush(); + + var logStorage = Logger.Storage; + + using (var outStream = exportStorage.CreateFileSafely(archive_filename)) + using (var zip = ZipArchive.Create()) + { + foreach (string? f in logStorage.GetFiles(string.Empty, "*.log")) + FileUtils.AttemptOperation(z => z.AddEntry(f, logStorage.GetStream(f), true), zip); + + zip.SaveTo(outStream); + } + } + catch + { + notification.State = ProgressNotificationState.Cancelled; + + // cleanup if export is failed or canceled. + exportStorage.Delete(archive_filename); + throw; + } + + notification.CompletionText = "Exported logs! Click to view."; + notification.CompletionClickAction = () => exportStorage.PresentFileExternally(archive_filename); + + notification.State = ProgressNotificationState.Completed; } } } From 13dab24d418eebad5c4884ccc4e61837b8729c38 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 16:56:58 +0900 Subject: [PATCH 146/836] Adjust to 200 ms debounce This [matches stable](https://github.com/peppy/osu-stable-reference/blob/52f3f75ed7efd7b9eb56e1e45c95bb91504337be/osu!/Audio/AudioEngine.cs#L1295) and feels somewhat better. --- osu.Game/Overlays/NowPlayingOverlay.cs | 4 +++- .../Edit/Components/Timelines/Summary/Parts/MarkerPart.cs | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index 9f9f57336c1a..28119615f364 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -29,6 +29,8 @@ namespace osu.Game.Overlays { public partial class NowPlayingOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent { + public const double TRACK_DRAG_SEEK_DEBOUNCE = 200; + public IconUsage Icon => OsuIcon.Music; public LocalisableString Title => NowPlayingStrings.HeaderTitle; public LocalisableString Description => NowPlayingStrings.HeaderDescription; @@ -226,7 +228,7 @@ private void load() private void onSeek(double progress) { - if (lastSeekTime == null || Time.Current - lastSeekTime > 500) + if (lastSeekTime == null || Time.Current - lastSeekTime > TRACK_DRAG_SEEK_DEBOUNCE) { musicController.SeekTo(progress); lastSeekTime = Time.Current; diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs index c9a44eab4a63..b7453bf7f63b 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Input.Events; +using osu.Game.Overlays; using osu.Game.Screens.Edit.Compose.Components.Timeline; using osuTK; @@ -66,7 +67,7 @@ private void seekToPosition(Vector2 screenPosition, bool instant) double seekDestination = markerPos / DrawWidth * editorClock.TrackLength; marker.X = (float)seekDestination; - if (!instant && lastSeekTime != null && Time.Current - lastSeekTime < 500) + if (!instant && lastSeekTime != null && Time.Current - lastSeekTime < NowPlayingOverlay.TRACK_DRAG_SEEK_DEBOUNCE) return; editorClock.SeekSmoothlyTo(seekDestination); From 98e7a10e1e7b2514a64c7a423c44c96fd60d3320 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 17:13:44 +0900 Subject: [PATCH 147/836] Rename localised string --- osu.Game/Localisation/CommonStrings.cs | 2 +- osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs | 2 +- osu.Game/Screens/SelectV2/PanelBeatmapSet.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 22fc2bb24220..d72257f43804 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -202,7 +202,7 @@ public static class CommonStrings /// /// "Delete..." /// - public static LocalisableString DeleteEllipsis => new TranslatableString(getKey(@"delete_ellipsis"), @"Delete..."); + public static LocalisableString DeleteWithConfirmation => new TranslatableString(getKey(@"delete_with_confrmation"), @"Delete..."); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs b/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs index afbe2450d668..2f0f36c99c64 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs +++ b/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs @@ -62,7 +62,7 @@ private void load(OsuColour colours) Debug.Assert(beatmap.BeatmapSet != null); addHeader(SongSelectStrings.ForAllDifficulties, beatmap.BeatmapSet.ToString()); - addButton(CommonStrings.DeleteEllipsis, FontAwesome.Solid.Trash, () => SongSelect?.Delete(beatmap.BeatmapSet), colours.Red1); + addButton(CommonStrings.DeleteWithConfirmation, FontAwesome.Solid.Trash, () => SongSelect?.Delete(beatmap.BeatmapSet), colours.Red1); addHeader(SongSelectStrings.ForSelectedDifficulty, beatmap.DifficultyName); diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs index f8459bfedb78..befdba1b2b13 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs @@ -273,7 +273,7 @@ public override MenuItem[] ContextMenuItems if (beatmapSet.Beatmaps.Any(b => b.Hidden)) items.Add(new OsuMenuItem(SongSelectStrings.RestoreAllHidden, MenuItemType.Standard, () => songSelect?.RestoreAllHidden(beatmapSet))); - items.Add(new OsuMenuItem(CommonStrings.DeleteEllipsis, MenuItemType.Destructive, () => songSelect?.Delete(beatmapSet))); + items.Add(new OsuMenuItem(CommonStrings.DeleteWithConfirmation, MenuItemType.Destructive, () => songSelect?.Delete(beatmapSet))); return items.ToArray(); } } From fc74726d114f97fd8f885d2ddb42c4bf1bb7b91e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 17:25:40 +0900 Subject: [PATCH 148/836] Ensure the skip overlay shows when someone votes to skip --- .../Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs index 35e85c327350..79fd0eb8d127 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs @@ -95,6 +95,8 @@ private void onUserStateChanged(MultiplayerRoomUser user, MultiplayerUserState s private void onUserVotedToSkipIntro(int userId) => Schedule(() => { + FadingContent.TriggerShow(); + updateText(); countText.ScaleTo(1.5f).ScaleTo(1, 200, Easing.OutSine); From 90e7faf271806bb465d9ac1f6190443b5b8716ff Mon Sep 17 00:00:00 2001 From: marvin Date: Fri, 21 Nov 2025 09:57:14 +0100 Subject: [PATCH 149/836] Replace PowEasingFunction with CubicBezieEasingFunction --- .../MatchmakingSelectPanelRandom.cs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs index c789c3dc746e..6389766b4684 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs @@ -1,7 +1,6 @@ // 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.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Audio; @@ -48,10 +47,10 @@ public override void PresentAsChosenBeatmap(MatchmakingPlaylistItem playlistItem this.MoveTo(Vector2.Zero, 1000, Easing.OutExpo) .ScaleTo(1.5f, 1000, Easing.OutExpo); - content.Dice.MoveToY(-200, duration * 0.55, new PowEasingFunction(2.75, easeOut: true)) + content.Dice.MoveToY(-200, duration * 0.55, new CubicBezierEasingFunction(0.33, 1, 0.8, 1)) .Then() .Schedule(() => ChangeInternalChildDepth(diceProxy, float.MaxValue)) - .MoveToY(-DrawHeight / 2, duration * 0.45, new PowEasingFunction(2.2)) + .MoveToY(-DrawHeight / 2, duration * 0.45, new CubicBezierEasingFunction(0.2, 0, 0.55, 0)) .Then() .FadeOut() .Expire(); @@ -105,18 +104,5 @@ protected override bool OnClick(ClickEvent e) return base.OnClick(e); } - - private readonly struct PowEasingFunction(double exponent, bool easeOut = false) : IEasingFunction - { - public double ApplyEasing(double time) - { - if (easeOut) - time = 1 - time; - - double value = Math.Pow(time, exponent); - - return easeOut ? 1 - value : value; - } - } } } From d8b71423b0a1bb7d546a9c1a2fa4ccc5b120db85 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Nov 2025 19:33:38 +0900 Subject: [PATCH 150/836] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 98d4ebc31636..20c0f7cec573 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index 4a5919d16dc9..c2796cf00006 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From a2bfb409d2c8edad8f3935a917faaf4f2c590b31 Mon Sep 17 00:00:00 2001 From: StanR Date: Sat, 22 Nov 2025 03:16:36 +0500 Subject: [PATCH 151/836] Use actual mod-adjusted map difficulty settings in the `SongBar` --- .../Components/TestSceneSongBar.cs | 1 + osu.Game.Tournament/Components/SongBar.cs | 42 ++++++++----------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs b/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs index 95d6b6d107fd..285937ef03a3 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs @@ -61,6 +61,7 @@ public void TestSongBar() AddStep("set mods to HR", () => songBar.Mods = LegacyMods.HardRock); AddStep("set mods to DT", () => songBar.Mods = LegacyMods.DoubleTime); + AddStep("set mods to HDHRDT", () => songBar.Mods = LegacyMods.Hidden | LegacyMods.HardRock | LegacyMods.DoubleTime); AddStep("unset mods", () => songBar.Mods = LegacyMods.None); AddToggleStep("toggle expanded", expanded => songBar.Expanded = expanded); diff --git a/osu.Game.Tournament/Components/SongBar.cs b/osu.Game.Tournament/Components/SongBar.cs index cff86cf0a11b..11cb04e5405a 100644 --- a/osu.Game.Tournament/Components/SongBar.cs +++ b/osu.Game.Tournament/Components/SongBar.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.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -14,6 +15,7 @@ using osu.Game.Graphics; using osu.Game.Models; using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Screens.Menu; using osu.Game.Utils; using osuTK; @@ -123,27 +125,19 @@ private void refreshContent() }, }; - double bpm = beatmap.BPM; - double length = beatmap.Length; - string hardRockExtra = ""; - string srExtra = ""; + var rulesetInstance = ruleset.Value.CreateInstance(); - float ar = beatmap.Difficulty.ApproachRate; + var convertedMods = rulesetInstance.ConvertFromLegacyMods(mods).ToList(); + var adjustedDifficulty = rulesetInstance.GetAdjustedDisplayDifficulty(beatmap, convertedMods); - if ((mods & LegacyMods.HardRock) > 0) - { - hardRockExtra = "*"; - srExtra = "*"; - } + double rate = ModUtils.CalculateRateWithMods(convertedMods); + double bpm = FormatUtils.RoundBPM(beatmap.BPM, rate); + double length = beatmap.Length / rate; - if ((mods & LegacyMods.DoubleTime) > 0) - { - // temporary local calculation (taken from OsuDifficultyCalculator) - double preempt = (int)IBeatmapDifficultyInfo.DifficultyRange(ar, 1800, 1200, 450) / 1.5; - ar = (float)(preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5); + string srExtra = ""; - bpm *= 1.5f; - length /= 1.5f; + if (convertedMods.Any(x => x is ModHardRock) || convertedMods.Any(x => x is ModDoubleTime)) + { srExtra = "*"; } @@ -154,9 +148,9 @@ private void refreshContent() default: stats = new (string heading, string content)[] { - ("CS", $"{beatmap.Difficulty.CircleSize:0.#}{hardRockExtra}"), - ("AR", $"{ar:0.#}{hardRockExtra}"), - ("OD", $"{beatmap.Difficulty.OverallDifficulty:0.#}{hardRockExtra}"), + ("CS", $"{adjustedDifficulty.CircleSize:0.#}"), + ("AR", $"{adjustedDifficulty.ApproachRate:0.#}"), + ("OD", $"{adjustedDifficulty.OverallDifficulty:0.#}"), }; break; @@ -164,16 +158,16 @@ private void refreshContent() case 3: stats = new (string heading, string content)[] { - ("OD", $"{beatmap.Difficulty.OverallDifficulty:0.#}{hardRockExtra}"), - ("HP", $"{beatmap.Difficulty.DrainRate:0.#}{hardRockExtra}") + ("OD", $"{adjustedDifficulty.OverallDifficulty:0.#}"), + ("HP", $"{adjustedDifficulty.DrainRate:0.#}") }; break; case 2: stats = new (string heading, string content)[] { - ("CS", $"{beatmap.Difficulty.CircleSize:0.#}{hardRockExtra}"), - ("AR", $"{ar:0.#}"), + ("CS", $"{adjustedDifficulty.CircleSize:0.#}"), + ("AR", $"{adjustedDifficulty.ApproachRate:0.#}"), }; break; } From fd652982ceded9fca5bf57e7ee35c3d0358d05c0 Mon Sep 17 00:00:00 2001 From: StanR Date: Sat, 22 Nov 2025 03:29:39 +0500 Subject: [PATCH 152/836] Add ruleset tests --- .../Components/TestSceneSongBar.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs b/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs index 285937ef03a3..28ced3e0ad57 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs @@ -5,6 +5,10 @@ using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Beatmaps.Legacy; +using osu.Game.Rulesets.Catch; +using osu.Game.Rulesets.Mania; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Taiko; using osu.Game.Tournament.Components; using osu.Game.Tournament.Models; @@ -52,6 +56,7 @@ public void TestSongBar() beatmap.ApproachRate = 6.8f; beatmap.OverallDifficulty = 5.5f; beatmap.StarRating = 4.56f; + beatmap.DrainRate = 1.23f; beatmap.Length = 123456; beatmap.BPM = 133; beatmap.OnlineID = ladderBeatmap.OnlineID; @@ -62,11 +67,17 @@ public void TestSongBar() AddStep("set mods to HR", () => songBar.Mods = LegacyMods.HardRock); AddStep("set mods to DT", () => songBar.Mods = LegacyMods.DoubleTime); AddStep("set mods to HDHRDT", () => songBar.Mods = LegacyMods.Hidden | LegacyMods.HardRock | LegacyMods.DoubleTime); + AddStep("unset mods", () => songBar.Mods = LegacyMods.None); AddToggleStep("toggle expanded", expanded => songBar.Expanded = expanded); AddStep("set null beatmap", () => songBar.Beatmap = null); + + AddStep("set ruleset to osu", () => Ruleset.Value = new OsuRuleset().RulesetInfo); + AddStep("set ruleset to taiko", () => Ruleset.Value = new TaikoRuleset().RulesetInfo); + AddStep("set ruleset to catch", () => Ruleset.Value = new CatchRuleset().RulesetInfo); + AddStep("set ruleset to mania", () => Ruleset.Value = new ManiaRuleset().RulesetInfo); } } } From 8900c79758f576bd441d3f246bb6fe4f3046cf4f Mon Sep 17 00:00:00 2001 From: StanR Date: Sat, 22 Nov 2025 03:35:10 +0500 Subject: [PATCH 153/836] Set `TournamentBeatmap`'s `IBeatmapInfo.Ruleset` to a dummy ruleset. This is being queried by the https://github.com/ppy/osu/blob/master/osu.Game.Rulesets.Mania/ManiaRuleset.cs#L442 but since we don't actually draw column count anywhere nor are we supposed to be running converts in tournaments it should be safe to populate it with nothing. --- osu.Game.Tournament/Models/TournamentBeatmap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Models/TournamentBeatmap.cs b/osu.Game.Tournament/Models/TournamentBeatmap.cs index a7ba5b7db11c..79dbb680d7de 100644 --- a/osu.Game.Tournament/Models/TournamentBeatmap.cs +++ b/osu.Game.Tournament/Models/TournamentBeatmap.cs @@ -83,7 +83,7 @@ public TournamentBeatmap(APIBeatmap beatmap) string IBeatmapInfo.MD5Hash => throw new NotImplementedException(); - IRulesetInfo IBeatmapInfo.Ruleset => throw new NotImplementedException(); + IRulesetInfo IBeatmapInfo.Ruleset => new RulesetInfo(); DateTimeOffset IBeatmapSetOnlineInfo.Submitted => throw new NotImplementedException(); From d0e09e5b5c31c432f5fa80980fd77ce7e4fc74dc Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 22 Nov 2025 17:03:04 -0800 Subject: [PATCH 154/836] Fix one remaining case of "copy link" not using existing localisation --- osu.Game/Screens/OnlinePlay/Lounge/Components/RoomPanel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomPanel.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomPanel.cs index fe03fca4b8c8..84b420d79114 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomPanel.cs @@ -25,6 +25,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.Chat; using osu.Game.Online.Rooms; @@ -430,7 +431,7 @@ public virtual MenuItem[] ContextMenuItems { items.AddRange([ new OsuMenuItem("View in browser", MenuItemType.Standard, () => game?.OpenUrlExternally(url)), - new OsuMenuItem("Copy link", MenuItemType.Standard, () => game?.CopyToClipboard(url)) + new OsuMenuItem(CommonStrings.CopyLink, MenuItemType.Standard, () => game?.CopyToClipboard(url)) ]); } From b6ccc8cae42d51cd424c5fe0c61dd9e95a051ca5 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 22 Nov 2025 17:06:04 -0800 Subject: [PATCH 155/836] Replace local osd and clipboard method with existing game method --- osu.Game/Overlays/Comments/DrawableComment.cs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 805d99799805..33f09b762206 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -20,13 +20,11 @@ using System.Diagnostics; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Logging; -using osu.Framework.Platform; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Comments.Buttons; using osu.Game.Overlays.Dialog; -using osu.Game.Overlays.OSD; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments @@ -83,10 +81,7 @@ public partial class DrawableComment : CompositeDrawable private IAPIProvider api { get; set; } = null!; [Resolved] - private Clipboard clipboard { get; set; } = null!; - - [Resolved] - private OnScreenDisplay? onScreenDisplay { get; set; } + private OsuGame? game { get; set; } public DrawableComment(Comment comment, IReadOnlyList meta) { @@ -329,7 +324,7 @@ private void load(OverlayColourProvider colourProvider, DrawableComment? parentC if (WasDeleted) makeDeleted(); - actionsContainer.AddLink(CommonStrings.ButtonsPermalink, copyUrl); + actionsContainer.AddLink(CommonStrings.ButtonsPermalink, () => game?.CopyToClipboard($@"{api.Endpoints.APIUrl}/comments/{Comment.Id}")); actionsContainer.AddArbitraryDrawable(Empty().With(d => d.Width = 10)); actionsContainer.AddLink(CommonStrings.ButtonsReply.ToLower(), toggleReply); actionsContainer.AddArbitraryDrawable(Empty().With(d => d.Width = 10)); @@ -417,12 +412,6 @@ private void deleteCommentRequest() api.Queue(request); } - private void copyUrl() - { - clipboard.SetText($@"{api.Endpoints.APIUrl}/comments/{Comment.Id}"); - onScreenDisplay?.Display(new CopiedToClipboardToast()); - } - private void toggleReply() { if (replyEditorContainer.Count == 0) From 49eb013967e0e7f5802742e504f8f3047aa89b83 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 22 Nov 2025 17:06:34 -0800 Subject: [PATCH 156/836] Fix some copy link actions/buttons not showing copied toast --- osu.Game/Online/Chat/ExternalLinkOpener.cs | 4 ++-- osu.Game/Online/Leaderboards/LeaderboardScore.cs | 5 ++--- osu.Game/Screens/Edit/Compose/ComposeScreen.cs | 7 +++---- osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs | 5 ++--- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/osu.Game/Online/Chat/ExternalLinkOpener.cs b/osu.Game/Online/Chat/ExternalLinkOpener.cs index 258cca2ad577..53faafcf3661 100644 --- a/osu.Game/Online/Chat/ExternalLinkOpener.cs +++ b/osu.Game/Online/Chat/ExternalLinkOpener.cs @@ -24,7 +24,7 @@ public partial class ExternalLinkOpener : Component private GameHost host { get; set; } = null!; [Resolved] - private Clipboard clipboard { get; set; } = null!; + private OsuGame? game { get; set; } [Resolved] private IDialogOverlay? dialogOverlay { get; set; } @@ -88,7 +88,7 @@ public void OpenUrlExternally(string url, LinkWarnMode warnMode = LinkWarnMode.D } if (dialogOverlay != null && shouldWarn) - dialogOverlay.Push(new ExternalLinkDialog(url, () => host.OpenUrlExternally(url), () => clipboard.SetText(url))); + dialogOverlay.Push(new ExternalLinkDialog(url, () => host.OpenUrlExternally(url), () => game?.CopyToClipboard(url))); else host.OpenUrlExternally(url); } diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index bc617cae8033..e5aac279fba4 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -17,7 +17,6 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Localisation; -using osu.Framework.Platform; using osu.Game.Extensions; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -76,7 +75,7 @@ public partial class LeaderboardScore : OsuClickableContainer, IHasContextMenu, private SongSelect songSelect { get; set; } [Resolved(canBeNull: true)] - private Clipboard clipboard { get; set; } + private OsuGame game { get; set; } [Resolved] private IAPIProvider api { get; set; } @@ -459,7 +458,7 @@ public MenuItem[] ContextMenuItems items.Add(new OsuMenuItem("Use these mods", MenuItemType.Highlighted, () => songSelect.Mods.Value = copyableMods)); if (Score.OnlineID > 0) - items.Add(new OsuMenuItem(CommonStrings.CopyLink, MenuItemType.Standard, () => clipboard?.SetText($@"{api.Endpoints.WebsiteUrl}/scores/{Score.OnlineID}"))); + items.Add(new OsuMenuItem(CommonStrings.CopyLink, MenuItemType.Standard, () => game?.CopyToClipboard($@"{api.Endpoints.WebsiteUrl}/scores/{Score.OnlineID}"))); if (Score.Files.Count > 0) { diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index 195625dcdece..7f6ddcd54cd1 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -9,7 +9,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Extensions; @@ -22,8 +21,8 @@ namespace osu.Game.Screens.Edit.Compose { public partial class ComposeScreen : EditorScreenWithTimeline, IGameplaySettings { - [Resolved] - private Clipboard hostClipboard { get; set; } = null!; + [Resolved(canBeNull: true)] + private OsuGame game { get; set; } [Resolved] private EditorClock clock { get; set; } @@ -138,7 +137,7 @@ public override void Copy() // regardless of whether anything was even selected at all. // UX-wise this is generally strange and unexpected, but make it work anyways to preserve muscle memory. // note that this means that `getTimestamp()` must handle no-selection case, too. - hostClipboard.SetText(getTimestamp()); + game?.CopyToClipboard(getTimestamp()); if (CanCopy.Value) clipboard.Value = new ClipboardContent(EditorBeatmap).Serialize(); diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs b/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs index 5013150f05c5..16c9ed64f6ca 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs +++ b/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs @@ -16,7 +16,6 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Localisation; -using osu.Framework.Platform; using osu.Game.Configuration; using osu.Game.Extensions; using osu.Game.Graphics; @@ -77,7 +76,7 @@ public sealed partial class BeatmapLeaderboardScore : OsuClickableContainer, IHa private OsuConfigManager config { get; set; } = null!; [Resolved] - private Clipboard? clipboard { get; set; } + private OsuGame? game { get; set; } [Resolved] private IAPIProvider api { get; set; } = null!; @@ -625,7 +624,7 @@ MenuItem[] IHasContextMenu.ContextMenuItems items.Add(new OsuMenuItem(SongSelectStrings.UseTheseMods, MenuItemType.Highlighted, () => SelectedMods.Value = copyableMods)); if (Score.OnlineID > 0) - items.Add(new OsuMenuItem(CommonStrings.CopyLink, MenuItemType.Standard, () => clipboard?.SetText($@"{api.Endpoints.WebsiteUrl}/scores/{Score.OnlineID}"))); + items.Add(new OsuMenuItem(CommonStrings.CopyLink, MenuItemType.Standard, () => game?.CopyToClipboard($@"{api.Endpoints.WebsiteUrl}/scores/{Score.OnlineID}"))); if (Score.Files.Count <= 0) return items.ToArray(); From 9d88c761d3414d3e4353bd0a66f2faac2630c83e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 24 Nov 2025 10:32:42 +0100 Subject: [PATCH 157/836] Add double-click-nub-to-reset function to form slider bars See https://github.com/ppy/osu/pull/35742#issuecomment-3561517030. --- .../UserInterface/TestSceneFormSliderBar.cs | 50 ++++++++++++++++++- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 39 ++++++++++++--- 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs index 97835a993d60..d25ef3a88971 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs @@ -1,20 +1,24 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Overlays; using osuTK; +using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public partial class TestSceneFormSliderBar : OsuTestScene + public partial class TestSceneFormSliderBar : OsuManualInputManagerTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); @@ -59,5 +63,49 @@ public void TestTransferValueOnCommit() slider.TransferValueOnCommit = b; }); } + + [Test] + public void TestNubDoubleClickRevertToDefault() + { + FormSliderBar slider = null!; + + AddStep("create content", () => + { + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.5f, + Direction = FillDirection.Vertical, + Spacing = new Vector2(10), + Children = new Drawable[] + { + slider = new FormSliderBar + { + Caption = "Slider", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Precision = 0.1f, + Default = 5f, + } + }, + } + }; + }); + AddStep("set slider to 1", () => slider.Current.Value = 1); + + AddStep("move mouse to nub", () => InputManager.MoveMouseTo(slider.ChildrenOfType().Single())); + + AddStep("double click nub", () => + { + InputManager.Click(MouseButton.Left); + InputManager.Click(MouseButton.Left); + }); + + AddAssert("slider is default", () => slider.Current.IsDefault); + } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 59217f64abd1..8ebaf48ed6af 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -324,8 +324,8 @@ private partial class InnerSlider : OsuSliderBar private Box leftBox = null!; private Box rightBox = null!; - private Circle nub = null!; - private const float nub_width = 10; + private InnerSliderNub nub = null!; + public const float NUB_WIDTH = 10; [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -335,7 +335,7 @@ private void load() { Height = 40; RelativeSizeAxes = Axes.X; - RangePadding = nub_width / 2; + RangePadding = NUB_WIDTH / 2; Children = new Drawable[] { @@ -364,12 +364,13 @@ private void load() { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Horizontal = RangePadding, }, - Child = nub = new Circle + Child = nub = new InnerSliderNub { - Width = nub_width, - RelativeSizeAxes = Axes.Y, - RelativePositionAxes = Axes.X, - Origin = Anchor.TopCentre, + ResetToDefault = () => + { + if (!Current.Disabled) + Current.SetDefault(); + } } }, new HoverClickSounds() @@ -452,5 +453,27 @@ protected override bool Commit() return result; } } + + private partial class InnerSliderNub : Circle + { + public Action? ResetToDefault { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + Width = InnerSlider.NUB_WIDTH; + RelativeSizeAxes = Axes.Y; + RelativePositionAxes = Axes.X; + Origin = Anchor.TopCentre; + } + + protected override bool OnClick(ClickEvent e) => true; // must be handled for double click handler to ever fire + + protected override bool OnDoubleClick(DoubleClickEvent e) + { + ResetToDefault?.Invoke(); + return true; + } + } } } From 83ce56b7183916a1f4f7c5ad3a96a51f3b5d8c40 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 24 Nov 2025 15:11:47 +0500 Subject: [PATCH 158/836] Use `APIRuleset` instead of a blank `RulesetInfo` --- osu.Game.Tournament/Models/TournamentBeatmap.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Models/TournamentBeatmap.cs b/osu.Game.Tournament/Models/TournamentBeatmap.cs index 79dbb680d7de..83c42b793dbc 100644 --- a/osu.Game.Tournament/Models/TournamentBeatmap.cs +++ b/osu.Game.Tournament/Models/TournamentBeatmap.cs @@ -6,6 +6,7 @@ using osu.Game.Extensions; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; +using static osu.Game.Online.API.Requests.Responses.APIBeatmap; namespace osu.Game.Tournament.Models { @@ -31,6 +32,8 @@ public class TournamentBeatmap : IBeatmapInfo, IBeatmapSetOnlineInfo public BeatmapSetOnlineCovers Covers { get; set; } + public APIRuleset Ruleset { get; set; } = new APIRuleset(); + public TournamentBeatmap() { } @@ -47,6 +50,7 @@ public TournamentBeatmap(APIBeatmap beatmap) Covers = beatmap.BeatmapSet?.Covers ?? new BeatmapSetOnlineCovers(); EndTimeObjectCount = beatmap.EndTimeObjectCount; TotalObjectCount = beatmap.TotalObjectCount; + Ruleset = (APIRuleset)beatmap.Ruleset; } public bool Equals(IBeatmapInfo? other) => other is TournamentBeatmap b && this.MatchesOnlineID(b); @@ -83,7 +87,7 @@ public TournamentBeatmap(APIBeatmap beatmap) string IBeatmapInfo.MD5Hash => throw new NotImplementedException(); - IRulesetInfo IBeatmapInfo.Ruleset => new RulesetInfo(); + IRulesetInfo IBeatmapInfo.Ruleset => Ruleset; DateTimeOffset IBeatmapSetOnlineInfo.Submitted => throw new NotImplementedException(); From 33c8c4d639f1213bdbc35fca6a54d28a1f6546d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 24 Nov 2025 11:07:29 +0100 Subject: [PATCH 159/836] Add failing test --- .../Chat/TestSceneChannelManager.cs | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Chat/TestSceneChannelManager.cs b/osu.Game.Tests/Chat/TestSceneChannelManager.cs index 5c7f0b0a2fe3..768137b0cff0 100644 --- a/osu.Game.Tests/Chat/TestSceneChannelManager.cs +++ b/osu.Game.Tests/Chat/TestSceneChannelManager.cs @@ -220,6 +220,31 @@ public void TestBlockedUserMessagesAreDeletedImmediatelyOnBlock() AddAssert("channel has no messages", () => channel.Messages, () => Is.Empty); } + [Test] + public void TestPrivateChannelsPurgedOnUserChange() + { + var pmChannel = createChannel(1002, ChannelType.PM); + AddStep("join a few private channels", () => + { + channelManager.JoinChannel(createChannel(1001, ChannelType.PM)); + channelManager.JoinChannel(createChannel(1003, ChannelType.Team)); + channelManager.JoinChannel(pmChannel); + }); + AddStep("close a PM channel", () => channelManager.LeaveChannel(pmChannel)); + + AddStep("switch user", () => + { + ((DummyAPIAccess.DummyLocalUserState)API.LocalUserState).User.Value = new APIUser + { + Id = 9009, + Username = "someone_else" + }; + }); + + AddAssert("not joined to private channels of previous user", + () => !channelManager.JoinedChannels.Select(ch => ch.Id).Any(id => id >= 1001 && id <= 1003)); + } + private void handlePostMessageRequest(PostMessageRequest request) { var message = new Message(++currentMessageId) @@ -250,7 +275,7 @@ private void handleMarkChannelAsReadRequest(MarkChannelAsReadRequest request) } } - private Channel createChannel(int id, ChannelType type) => new Channel(new APIUser()) + private Channel createChannel(int id, ChannelType type) => new Channel(new APIUser { Id = id }) { Id = id, Name = $"Channel {id}", From ec890cd459ce8f5d48470b37e67cbda562e4787e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 24 Nov 2025 11:33:43 +0100 Subject: [PATCH 160/836] Clear chat state when local user changes Closes https://github.com/ppy/osu/issues/35081. --- osu.Game/Online/Chat/ChannelManager.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index eb5d6d1b9c8a..aec7928ba8b0 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -70,6 +70,7 @@ public partial class ChannelManager : CompositeComponent, IChannelPostTarget [Resolved] private UserLookupCache users { get; set; } + private readonly IBindable localUser = new Bindable(); private readonly IBindable apiState = new Bindable(); private readonly IBindableList localUserBlocks = new BindableList(); private ScheduledDelegate scheduledAck; @@ -95,6 +96,9 @@ private void load() chatClient.PresenceReceived += () => Schedule(initializeChannels); chatClient.RequestPresence(); + localUser.BindTo(api.LocalUser); + localUser.BindValueChanged(userChanged); + apiState.BindTo(api.State); apiState.BindValueChanged(_ => SendAck(), true); @@ -102,6 +106,22 @@ private void load() localUserBlocks.BindCollectionChanged((_, args) => Schedule(() => onBlocksChanged(args))); } + private void userChanged(ValueChangedEvent userChange) + { + if (userChange.OldValue?.Equals(userChange.NewValue) == true) + return; + + CurrentChannel.Value = null; + + foreach (var joinedChannel in joinedChannels) + joinedChannel.Joined.Value = false; + + joinedChannels.Clear(); + // additionally clear the history of last joined channels so that the new user can't reopen the old user's channels + // (would likely fail web-side on perms anyway, but why even get that far) + closedChannels.Clear(); + } + /// /// Opens a channel or switches to the channel if already opened. /// From e4975e8d3b33e00dc10196b0ef709381984855f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 24 Nov 2025 12:00:33 +0100 Subject: [PATCH 161/836] Remove unnecessary cast --- osu.Game.Tournament/Models/TournamentBeatmap.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tournament/Models/TournamentBeatmap.cs b/osu.Game.Tournament/Models/TournamentBeatmap.cs index 83c42b793dbc..72669c0ca7e4 100644 --- a/osu.Game.Tournament/Models/TournamentBeatmap.cs +++ b/osu.Game.Tournament/Models/TournamentBeatmap.cs @@ -32,7 +32,7 @@ public class TournamentBeatmap : IBeatmapInfo, IBeatmapSetOnlineInfo public BeatmapSetOnlineCovers Covers { get; set; } - public APIRuleset Ruleset { get; set; } = new APIRuleset(); + public IRulesetInfo Ruleset { get; set; } = new APIRuleset(); public TournamentBeatmap() { @@ -50,7 +50,7 @@ public TournamentBeatmap(APIBeatmap beatmap) Covers = beatmap.BeatmapSet?.Covers ?? new BeatmapSetOnlineCovers(); EndTimeObjectCount = beatmap.EndTimeObjectCount; TotalObjectCount = beatmap.TotalObjectCount; - Ruleset = (APIRuleset)beatmap.Ruleset; + Ruleset = beatmap.Ruleset; } public bool Equals(IBeatmapInfo? other) => other is TournamentBeatmap b && this.MatchesOnlineID(b); From 8fb402665e6ff35d706181b866e9060f876c5a8b Mon Sep 17 00:00:00 2001 From: Arpa Date: Mon, 24 Nov 2025 13:08:50 +0200 Subject: [PATCH 162/836] Merge pull request #35698 from ArpaDeveloper/master Fix editor test play autoplay / quick play toggles being usable while pause or resume overlays were showing --- osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs index eedde8b7a435..2c9b97114d35 100644 --- a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs +++ b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Screens; @@ -180,10 +181,16 @@ public bool OnPressed(KeyBindingPressEvent e) switch (e.Action) { case GlobalAction.EditorTestPlayToggleAutoplay: + if (PauseOverlay?.State.Value == Visibility.Visible || DrawableRuleset.ResumeOverlay?.State.Value == Visibility.Visible) + return true; + toggleAutoplay(); return true; case GlobalAction.EditorTestPlayToggleQuickPause: + if (PauseOverlay?.State.Value == Visibility.Visible || DrawableRuleset.ResumeOverlay?.State.Value == Visibility.Visible) + return true; + toggleQuickPause(); return true; From 96de47ac4f8c8e4410cc9f9a58a0f78e8b77ecd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 24 Nov 2025 12:46:30 +0100 Subject: [PATCH 163/836] Fix hover fighting when a `SettingsToolboxGroup`'s child handles hover Addresses https://github.com/ppy/osu/discussions/35772. --- osu.Game/Overlays/SettingsToolboxGroup.cs | 34 ++++++++++------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/SettingsToolboxGroup.cs b/osu.Game/Overlays/SettingsToolboxGroup.cs index f26ed962cb2b..9090a294b5d5 100644 --- a/osu.Game/Overlays/SettingsToolboxGroup.cs +++ b/osu.Game/Overlays/SettingsToolboxGroup.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input; -using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Graphics; @@ -64,6 +63,9 @@ public Vector2 Spacing private Drawable? draggedChild; + private bool? lastMouseInBounds; + private bool mouseInBounds => Contains(inputManager.CurrentState.Mouse.Position); + /// /// Create a new instance. /// @@ -143,20 +145,6 @@ protected override void LoadComplete() this.Delay(600).Schedule(updateFadeState); } - protected override bool OnHover(HoverEvent e) - { - updateFadeState(); - updateExpandedState(true); - return false; - } - - protected override void OnHoverLost(HoverLostEvent e) - { - updateFadeState(); - updateExpandedState(true); - base.OnHoverLost(e); - } - protected override void Update() { base.Update(); @@ -166,10 +154,16 @@ protected override void Update() headerText.Alpha = (float)Interpolation.DampContinuously(headerText.Alpha, headerText.DrawWidth < DrawWidth ? 1 : 0, 40, Time.Elapsed); // Dragged child finished its drag operation. - if (draggedChild != null && inputManager.DraggedDrawable != draggedChild) - { + bool childDragFinished = draggedChild != null && inputManager.DraggedDrawable != draggedChild; + + if (childDragFinished) draggedChild = null; + + if (childDragFinished || lastMouseInBounds != mouseInBounds) + { updateExpandedState(true); + updateFadeState(); + lastMouseInBounds = mouseInBounds; } } @@ -185,7 +179,7 @@ private void updateExpandedState(bool animate) // potentially continuing to get processed while content has changed to autosize. content.ClearTransforms(); - if (Expanded.Value || IsHovered || draggedChild != null) + if (Expanded.Value || mouseInBounds || draggedChild != null) { content.AutoSizeAxes = Axes.Y; content.AutoSizeDuration = animate ? transition_duration : 0; @@ -204,8 +198,8 @@ private void updateFadeState() { const float fade_duration = 500; - background.FadeTo(IsHovered ? 1 : 0.1f, fade_duration, Easing.OutQuint); - expandButton.FadeTo(IsHovered ? 1 : 0, fade_duration, Easing.OutQuint); + background.FadeTo(mouseInBounds ? 1 : 0.1f, fade_duration, Easing.OutQuint); + expandButton.FadeTo(mouseInBounds ? 1 : 0, fade_duration, Easing.OutQuint); } } } From 9c981a52f865b611530db7318256c696b836ead0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 24 Nov 2025 12:52:57 +0100 Subject: [PATCH 164/836] Fix test failures This is dodgy as hell but `ShortName` is completely derived from `OnlineID` anyway so there should be no valid reason to ever attempt to serialise it anyway. --- osu.Game/Online/API/Requests/Responses/APIBeatmap.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index 20494a1cbfab..cbd8833fe874 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -146,6 +146,7 @@ public class APIRuleset : IRulesetInfo public string Name => $@"{nameof(APIRuleset)} (ID: {OnlineID})"; + [JsonIgnore] public string ShortName { get From 855d5dba3cfee04d9e506ca51359a1925e30f066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 24 Nov 2025 13:20:39 +0100 Subject: [PATCH 165/836] Bypass 300ms debounce when requesting local leaderboards in song select RFC. Would probably close https://github.com/ppy/osu/issues/35773. --- osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs b/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs index 8aa3a0516fc7..6e0ffafa63c3 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs +++ b/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs @@ -237,17 +237,19 @@ public void RefetchScores() SetState(LeaderboardState.Retrieving); + var fetchScope = Scope.Value; + refetchOperation?.Cancel(); refetchOperation = Scheduler.AddDelayed(() => { var fetchBeatmapInfo = beatmap.Value.BeatmapInfo; var fetchRuleset = ruleset.Value ?? fetchBeatmapInfo.Ruleset; - var fetchSorting = Scope.Value == BeatmapLeaderboardScope.Local ? Sorting.Value : LeaderboardSortMode.Score; + var fetchSorting = fetchScope == BeatmapLeaderboardScope.Local ? Sorting.Value : LeaderboardSortMode.Score; // For now, we forcefully refresh to keep things simple. // In the future, removing this requirement may be deemed useful, but will need ample testing of edge case scenarios // (like returning from gameplay after setting a new score, returning to song select after main menu). - leaderboardManager.FetchWithCriteria(new LeaderboardCriteria(fetchBeatmapInfo, fetchRuleset, Scope.Value, FilterBySelectedMods.Value ? mods.Value.ToArray() : null, fetchSorting), + leaderboardManager.FetchWithCriteria(new LeaderboardCriteria(fetchBeatmapInfo, fetchRuleset, fetchScope, FilterBySelectedMods.Value ? mods.Value.ToArray() : null, fetchSorting), forceRefresh: true); if (!initialFetchComplete) @@ -257,7 +259,7 @@ public void RefetchScores() fetchedScores.BindValueChanged(_ => updateScores(), true); initialFetchComplete = true; } - }, initialFetchComplete ? 300 : 0); + }, initialFetchComplete && fetchScope != BeatmapLeaderboardScope.Local ? 300 : 0); } private void updateScores() From a69b2cd80395cfee1dc99c6d06a7c5388e4780bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 24 Nov 2025 13:38:53 +0100 Subject: [PATCH 166/836] Revert "Expand group that current selection resides in when moving mouse to left side of song select" Reverts https://github.com/ppy/osu/pull/35184 as per https://github.com/ppy/osu/discussions/35683#discussioncomment-15034835. --- .../SongSelectV2/TestSceneSongSelect.cs | 36 ------------------- osu.Game/Screens/SelectV2/BeatmapCarousel.cs | 12 ------- osu.Game/Screens/SelectV2/SongSelect.cs | 6 +--- 3 files changed, 1 insertion(+), 53 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs index e4f05b2e495d..a480e51adf14 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs @@ -22,7 +22,6 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Filter; using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; @@ -144,41 +143,6 @@ public void TestInvalidRulesetDoesNotEnterGameplay() void onScreenPushed(IScreen lastScreen, IScreen newScreen) => screensPushed.Add(lastScreen); } - [TestCase(true)] - [TestCase(false)] - public void TestHoveringLeftSideReexpandsGroupSelectionIsIn(bool mouseOverPanel) - { - ImportBeatmapForRuleset(0); - - LoadSongSelect(); - SortAndGroupBy(SortMode.Difficulty, GroupMode.Difficulty); - - AddStep("move mouse to carousel", () => InputManager.MoveMouseTo(Carousel)); - - AddUntilStep("expanded group is below 1 star", - () => (Carousel.ChildrenOfType().SingleOrDefault(p => p.Expanded.Value)?.Item?.Model as StarDifficultyGroupDefinition)?.Difficulty.Stars, - () => Is.EqualTo(0)); - - AddStep("select next group", () => - { - InputManager.PressKey(Key.ShiftLeft); - InputManager.Key(Key.Right); - InputManager.ReleaseKey(Key.ShiftLeft); - }); - AddUntilStep("expanded group is 3 star", - () => (Carousel.ChildrenOfType().SingleOrDefault(p => p.Expanded.Value)?.Item?.Model as StarDifficultyGroupDefinition)?.Difficulty.Stars, - () => Is.EqualTo(3)); - - if (mouseOverPanel) - AddStep("move mouse over left panel", () => InputManager.MoveMouseTo(this.ChildrenOfType().Single())); - else - AddStep("move mouse to left side container", () => InputManager.MoveMouseTo(this.ChildrenOfType().Single())); - - AddUntilStep("expanded group is below 1 star", - () => (Carousel.ChildrenOfType().Single(p => p.Expanded.Value).Item?.Model as StarDifficultyGroupDefinition)?.Difficulty.Stars, - () => Is.EqualTo(0)); - } - #region Hotkeys [Test] diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index ae1c8eb87875..aacebe4e8867 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -693,18 +693,6 @@ private void setExpansionStateOfSetItems(GroupedBeatmapSet set, bool expanded) } } - public void ExpandGroupForCurrentSelection() - { - if (CurrentGroupedBeatmap?.Group == null) - return; - - if (CheckModelEquality(ExpandedGroup, CurrentGroupedBeatmap.Group)) - return; - - if (grouping.ItemMap.TryGetValue(CurrentGroupedBeatmap.Group, out var groupItem)) - Activate(groupItem.item); - } - protected override double? GetScrollTarget() { double? target = base.GetScrollTarget(); diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index e8843876d39a..1b66bd560094 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -214,11 +214,7 @@ private void load(AudioManager audio, OsuConfigManager config) // Pad enough to only reset scroll when well into the left wedge areas. Padding = new MarginPadding { Right = 40 }, RelativeSizeAxes = Axes.Both, - Child = new Select.SongSelect.LeftSideInteractionContainer(() => - { - carousel.ExpandGroupForCurrentSelection(); - carousel.ScrollToSelection(); - }) + Child = new Select.SongSelect.LeftSideInteractionContainer(() => carousel.ScrollToSelection()) { RelativeSizeAxes = Axes.Both, }, From d59e9572d2f075c5c4e063ff0dc7aa5bd04d4130 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Nov 2025 00:55:22 +0900 Subject: [PATCH 167/836] Add missing padding around countdown settings button --- .../Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs index a91b84490006..f73983217f5f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs @@ -50,11 +50,12 @@ public MatchStartControl() ColumnDimensions = new[] { new Dimension(), + new Dimension(GridSizeMode.Absolute, 5), new Dimension(GridSizeMode.AutoSize) }, Content = new[] { - new Drawable[] + new Drawable?[] { readyButton = new MultiplayerReadyButton { @@ -62,6 +63,7 @@ public MatchStartControl() Size = Vector2.One, Action = onReadyButtonClick, }, + null, countdownButton = new MultiplayerCountdownButton { RelativeSizeAxes = Axes.Y, From b0762fc8ec2f3bf4c3fd983d7964aecb34b48e9d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Nov 2025 00:55:42 +0900 Subject: [PATCH 168/836] Reduce abstractions of rounded button --- .../UserInterface/DangerousRoundedButton.cs | 2 +- .../Settings/Sections/Input/KeyBindingRow.cs | 32 +++++++------------ osu.Game/Rulesets/Edit/ExpandableButton.cs | 2 +- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/DangerousRoundedButton.cs b/osu.Game/Graphics/UserInterface/DangerousRoundedButton.cs index 39ef7924b9ca..cb9250c15c06 100644 --- a/osu.Game/Graphics/UserInterface/DangerousRoundedButton.cs +++ b/osu.Game/Graphics/UserInterface/DangerousRoundedButton.cs @@ -6,7 +6,7 @@ namespace osu.Game.Graphics.UserInterface { - public partial class DangerousRoundedButton : RoundedButton + public sealed partial class DangerousRoundedButton : RoundedButton { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index 083c67817610..c9ef6ef891ca 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -191,8 +191,18 @@ private void load(OverlayColourProvider colourProvider, AudioManager audioManage Spacing = new Vector2(5), Children = new Drawable[] { - new CancelButton { Action = () => finalise(false) }, - new ClearButton { Action = clear }, + new RoundedButton + { + Text = CommonStrings.ButtonsCancel, + Size = new Vector2(80, 20), + Action = () => finalise(false) + }, + new DangerousRoundedButton + { + Text = CommonStrings.ButtonsClear, + Size = new Vector2(80, 20), + Action = clear + }, }, }, new HoverClickSounds() @@ -538,23 +548,5 @@ private void updateIsDefaultValue() { isDefault.Value = KeyBindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); } - - private partial class CancelButton : RoundedButton - { - public CancelButton() - { - Text = CommonStrings.ButtonsCancel; - Size = new Vector2(80, 20); - } - } - - public partial class ClearButton : DangerousRoundedButton - { - public ClearButton() - { - Text = CommonStrings.ButtonsClear; - Size = new Vector2(80, 20); - } - } } } diff --git a/osu.Game/Rulesets/Edit/ExpandableButton.cs b/osu.Game/Rulesets/Edit/ExpandableButton.cs index 9139802d68c1..d1f855a8ad7c 100644 --- a/osu.Game/Rulesets/Edit/ExpandableButton.cs +++ b/osu.Game/Rulesets/Edit/ExpandableButton.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Edit { - public partial class ExpandableButton : RoundedButton, IExpandable + public sealed partial class ExpandableButton : RoundedButton, IExpandable { private float actualHeight; From 64668eafb96c08dcfad1f02e50053b688613eb6a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Nov 2025 00:55:53 +0900 Subject: [PATCH 169/836] Adjust some more visual metrics to feel better --- osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs | 3 ++- osu.Game/Graphics/UserInterface/OsuDropdown.cs | 3 ++- osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs | 3 ++- osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs index 48d225de416d..67a4cf689044 100644 --- a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs @@ -56,7 +56,8 @@ public OsuAnimatedButton(HoverSampleSet sampleSet = HoverSampleSet.Button) Origin = Anchor.Centre, Anchor = Anchor.Centre, RelativeSizeAxes = Axes.Both, - CornerRadius = 5, + CornerRadius = 10, + CornerExponent = 2.5f, Masking = true, EdgeEffect = new EdgeEffectParameters { diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index e0179f8bc428..ae5501a3dd7d 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -357,7 +357,8 @@ public OsuDropdownHeader() Icon = FontAwesome.Solid.ChevronDown, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Size = new Vector2(16), + Size = new Vector2(10), + Margin = new MarginPadding { Right = 2 }, }, } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs index a0348fa27a62..90e12b128c44 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs @@ -178,7 +178,8 @@ private void load() Size = new Vector2(70); Masking = true; - CornerRadius = 35; + CornerRadius = 10; + CornerExponent = 2.5f; Action = this.ShowPopover; Children = new Drawable[] diff --git a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs index 01c495ae30ba..faabb8029903 100644 --- a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs @@ -52,6 +52,7 @@ protected override void LoadComplete() // This doesn't match the latest design spec (should be 5) but is an in-between that feels right to the eye // until we move everything over to Form controls. Content.CornerRadius = 10; + Content.CornerExponent = 2.5f; Add(Triangles = new TrianglesV2 { From 52af905237562a3ea9d88017cba0a90d3289d46a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Nov 2025 01:06:29 +0900 Subject: [PATCH 170/836] Hide full installation section on non-desktop platforms --- .../Sections/General/InstallationSettings.cs | 27 +++++++------------ .../Settings/Sections/GeneralSection.cs | 4 ++- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs b/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs index 3aaeadd1580a..68f3ba9b1722 100644 --- a/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Localisation; using osu.Framework.Platform; @@ -21,24 +20,18 @@ public partial class InstallationSettings : SettingsSubsection [BackgroundDependencyLoader] private void load(Storage storage) { - bool isDesktop = RuntimeInfo.IsDesktop; - - // Loosely update-related maintenance buttons. - if (isDesktop) + Add(new SettingsButton { - Add(new SettingsButton - { - Text = GeneralSettingsStrings.OpenOsuFolder, - Keywords = new[] { @"logs", @"files", @"access", "directory" }, - Action = () => storage.PresentExternally(), - }); + Text = GeneralSettingsStrings.OpenOsuFolder, + Keywords = new[] { @"logs", @"files", @"access", "directory" }, + Action = () => storage.PresentExternally(), + }); - Add(new DangerousSettingsButton - { - Text = GeneralSettingsStrings.ChangeFolderLocation, - Action = () => game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen())) - }); - } + Add(new DangerousSettingsButton + { + Text = GeneralSettingsStrings.ChangeFolderLocation, + Action = () => game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen())) + }); } } } diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index 18e650d70d28..7136de13276e 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.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 osu.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; @@ -28,7 +29,8 @@ private void load(UpdateManager? updateManager) Add(new LanguageSettings()); if (updateManager?.CanCheckForUpdate == true) Add(new UpdateSettings()); - Add(new InstallationSettings()); + if (RuntimeInfo.IsDesktop) + Add(new InstallationSettings()); } } } From 1d353ef63777f2e3983691d88db11a26cc7a0a90 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 24 Nov 2025 11:06:01 -0800 Subject: [PATCH 171/836] Revert showing toast on editor timestamp clipboard --- osu.Game/Screens/Edit/Compose/ComposeScreen.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index 7f6ddcd54cd1..195625dcdece 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -9,6 +9,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Extensions; @@ -21,8 +22,8 @@ namespace osu.Game.Screens.Edit.Compose { public partial class ComposeScreen : EditorScreenWithTimeline, IGameplaySettings { - [Resolved(canBeNull: true)] - private OsuGame game { get; set; } + [Resolved] + private Clipboard hostClipboard { get; set; } = null!; [Resolved] private EditorClock clock { get; set; } @@ -137,7 +138,7 @@ public override void Copy() // regardless of whether anything was even selected at all. // UX-wise this is generally strange and unexpected, but make it work anyways to preserve muscle memory. // note that this means that `getTimestamp()` must handle no-selection case, too. - game?.CopyToClipboard(getTimestamp()); + hostClipboard.SetText(getTimestamp()); if (CanCopy.Value) clipboard.Value = new ClipboardContent(EditorBeatmap).Serialize(); From f0f4e7c7a549288fa56ec57e690aa27b631c7b8c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Nov 2025 14:50:25 +0900 Subject: [PATCH 172/836] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index da412f270999..aa6666788786 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From 45567f19b72cc12a0461f6c379730be4fc44d60e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 25 Nov 2025 07:46:29 +0100 Subject: [PATCH 173/836] Fix test not compiling --- .../Visual/Settings/TestSceneKeyBindingPanel.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 4cad283833aa..8e671f331dd9 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -121,7 +121,7 @@ public void TestClickTwiceOnClearButton() AddStep("schedule button clicks", () => { - var clearButton = firstRow.ChildrenOfType().Single(); + var clearButton = firstRow.ChildrenOfType().Single(); InputManager.MoveMouseTo(clearButton); @@ -179,7 +179,7 @@ void clickClearButton() { AddStep("click clear button", () => { - var clearButton = multiBindingRow.ChildrenOfType().Single(); + var clearButton = multiBindingRow.ChildrenOfType().Single(); InputManager.MoveMouseTo(clearButton); InputManager.Click(MouseButton.Left); @@ -386,7 +386,7 @@ public void TestBindingConflictCausedByResetToDefaultOfSingleRow() AddStep("clear binding", () => { var row = panel.ChildrenOfType().First(r => r.ChildrenOfType().Any(s => s.Text.ToString() == "Left (centre)")); - row.ChildrenOfType().Single().TriggerClick(); + row.ChildrenOfType().Single().TriggerClick(); }); scrollToAndStartBinding("Left (rim)"); AddStep("bind M1", () => InputManager.Click(MouseButton.Left)); @@ -462,7 +462,7 @@ private void clearBinding() AddStep("clear binding", () => { var row = panel.ChildrenOfType().First(r => r.ChildrenOfType().Any(s => s.Text.ToString() == "Left (centre)")); - row.ChildrenOfType().Single().TriggerClick(); + row.ChildrenOfType().Single().TriggerClick(); }); } From c968981697e74826682ac868e737daf4f8e9a476 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Nov 2025 15:51:47 +0900 Subject: [PATCH 174/836] Fix quick retry/exit overlay volume dimming potentially sticking at results Closes #35737. --- osu.Game/Screens/Play/Player.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 6158118c7813..38e3fcd38d7e 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -320,7 +320,7 @@ private void load(OsuConfigManager config, OsuGameBase game, CancellationToken c OnRetry = Configuration.AllowUserInteraction ? () => Restart() : null, OnQuit = () => PerformExitWithConfirmation(), }, - new HotkeyExitOverlay + exitOverlay = new HotkeyExitOverlay { Action = () => { @@ -338,7 +338,7 @@ private void load(OsuConfigManager config, OsuGameBase game, CancellationToken c { rulesetSkinProvider.AddRange(new Drawable[] { - new HotkeyRetryOverlay + retryOverlay = new HotkeyRetryOverlay { Action = () => { @@ -1033,6 +1033,9 @@ private void onFailComplete() private double? lastPauseActionTime; + private HotkeyRetryOverlay retryOverlay; + private HotkeyExitOverlay exitOverlay; + protected bool PauseCooldownActive => PlayingState.Value == LocalUserPlayingState.Playing && lastPauseActionTime.HasValue && GameplayClockContainer.CurrentTime < lastPauseActionTime + PauseCooldownDuration; @@ -1171,6 +1174,10 @@ public override void OnSuspending(ScreenTransitionEvent e) { screenSuspension?.RemoveAndDisposeImmediately(); + // If these are not disposed, audio volume dimming can get stuck. + retryOverlay?.RemoveAndDisposeImmediately(); + exitOverlay?.RemoveAndDisposeImmediately(); + fadeOut(); base.OnSuspending(e); } From 0786e619f1fccebbf99204ac8d94afb99361bbd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 25 Nov 2025 07:51:43 +0100 Subject: [PATCH 175/836] Leave note about lack of toast for posterity --- osu.Game/Screens/Edit/Compose/ComposeScreen.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index 195625dcdece..00690c617e01 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -138,6 +138,8 @@ public override void Copy() // regardless of whether anything was even selected at all. // UX-wise this is generally strange and unexpected, but make it work anyways to preserve muscle memory. // note that this means that `getTimestamp()` must handle no-selection case, too. + // additionally, note we're intentionally not using `OsuGame.CopyToClipboard()` + // because we do not want toasts to pop up on every Ctrl-C press - it'd be disruptive to mappers. hostClipboard.SetText(getTimestamp()); if (CanCopy.Value) From 79bfe7880af8243b4d5c7c83d81236c872a17314 Mon Sep 17 00:00:00 2001 From: Chirag Mahesh Date: Tue, 25 Nov 2025 06:56:18 +0000 Subject: [PATCH 176/836] Move LocalSpacePosition calculation until the time of render Would address #35734 --- .../UI/Cursor/CursorTrail.cs | 34 ++++---- .../TestSceneGameplayCursorSizeChange.cs | 85 +++++++++++++++++++ 2 files changed, 102 insertions(+), 17 deletions(-) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneGameplayCursorSizeChange.cs diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 1c2d69fa00e4..8a45475f0fc2 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -164,20 +164,18 @@ protected override bool OnMouseMove(MouseMoveEvent e) return base.OnMouseMove(e); } - protected void AddTrail(Vector2 position) + protected void AddTrail(Vector2 screenSpacePosition) { - position = ToLocalSpace(position); - if (InterpolateMovements) { if (!lastPosition.HasValue) { - lastPosition = position; + lastPosition = screenSpacePosition; resampler.AddPosition(lastPosition.Value); return; } - foreach (Vector2 pos2 in resampler.AddPosition(position)) + foreach (Vector2 pos2 in resampler.AddPosition(screenSpacePosition)) { Trace.Assert(lastPosition.HasValue); @@ -198,14 +196,14 @@ protected void AddTrail(Vector2 position) } else { - lastPosition = position; + lastPosition = screenSpacePosition; addPart(lastPosition.Value); } } - private void addPart(Vector2 localSpacePosition) + private void addPart(Vector2 screenSpacePosition) { - parts[currentIndex].Position = localSpacePosition; + parts[currentIndex].ScreenSpacePosition = screenSpacePosition; parts[currentIndex].Time = time + 1; parts[currentIndex].Scale = NewPartScale; ++parts[currentIndex].InvalidationID; @@ -217,7 +215,7 @@ private void addPart(Vector2 localSpacePosition) private struct TrailPart { - public Vector2 Position; + public Vector2 ScreenSpacePosition; public float Time; public Vector2 Scale; public long InvalidationID; @@ -304,11 +302,13 @@ protected override void Draw(IRenderer renderer) if (time - part.Time >= 1) continue; + Vector2 localSpacePosition = Vector2Extensions.Transform(part.ScreenSpacePosition, DrawInfo.MatrixInverse); + vertexBatch.Add(new TexturedTrailVertex { Position = rotateAround( - new Vector2(part.Position.X - texture.DisplayWidth * originPosition.X * part.Scale.X, part.Position.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y), - part.Position, sin, cos), + new Vector2(localSpacePosition.X - texture.DisplayWidth * originPosition.X * part.Scale.X, localSpacePosition.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y), + localSpacePosition, sin, cos), TexturePosition = textureRect.BottomLeft, TextureRect = new Vector4(0, 0, 1, 1), Colour = DrawColourInfo.Colour.BottomLeft.Linear, @@ -318,8 +318,8 @@ protected override void Draw(IRenderer renderer) vertexBatch.Add(new TexturedTrailVertex { Position = rotateAround( - new Vector2(part.Position.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X, - part.Position.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y), part.Position, sin, cos), + new Vector2(localSpacePosition.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X, + localSpacePosition.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y), localSpacePosition, sin, cos), TexturePosition = textureRect.BottomRight, TextureRect = new Vector4(0, 0, 1, 1), Colour = DrawColourInfo.Colour.BottomRight.Linear, @@ -329,8 +329,8 @@ protected override void Draw(IRenderer renderer) vertexBatch.Add(new TexturedTrailVertex { Position = rotateAround( - new Vector2(part.Position.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X, part.Position.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y), - part.Position, sin, cos), + new Vector2(localSpacePosition.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X, localSpacePosition.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y), + localSpacePosition, sin, cos), TexturePosition = textureRect.TopRight, TextureRect = new Vector4(0, 0, 1, 1), Colour = DrawColourInfo.Colour.TopRight.Linear, @@ -340,8 +340,8 @@ protected override void Draw(IRenderer renderer) vertexBatch.Add(new TexturedTrailVertex { Position = rotateAround( - new Vector2(part.Position.X - texture.DisplayWidth * originPosition.X * part.Scale.X, part.Position.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y), - part.Position, sin, cos), + new Vector2(localSpacePosition.X - texture.DisplayWidth * originPosition.X * part.Scale.X, localSpacePosition.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y), + localSpacePosition, sin, cos), TexturePosition = textureRect.TopLeft, TextureRect = new Vector4(0, 0, 1, 1), Colour = DrawColourInfo.Colour.TopLeft.Linear, diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayCursorSizeChange.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayCursorSizeChange.cs new file mode 100644 index 000000000000..22b3a8e3788c --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayCursorSizeChange.cs @@ -0,0 +1,85 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Screens; +using osu.Framework.Testing; +using osu.Game.Configuration; +using osu.Game.Rulesets; +using osu.Game.Skinning; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public partial class TestSceneGameplayCursorSizeChange : OsuPlayerTestScene + { + [Resolved] + private SkinManager? skins { get; set; } + + protected new PausePlayer Player => (PausePlayer)base.Player; + + [BackgroundDependencyLoader] + private void load() + { + if (skins != null) skins.CurrentSkinInfo.Value = skins.DefaultClassicSkin.SkinInfo; + } + + [SetUpSteps] + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("resume player", () => Player.GameplayClockContainer.Start()); + AddUntilStep("clock running", () => Player.GameplayClockContainer.IsRunning); + } + + [Test] + public void TestChangeCursorSize() + { + AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre)); + AddStep("move cursor to top left", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.TopLeft)); + AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre)); + AddStep("move cursor to top right", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.TopRight)); + AddStep("press escape", () => InputManager.Key(Key.Escape)); + + for (float cursorSize = 0.4f; cursorSize <= 1.6f + 0.001f; cursorSize += 0.4f) + { + AddWaitStep("wait 2 seconds", 2); + float newCursorSize = cursorSize; + AddStep($"gameplay cursor size: {newCursorSize:F1}", () => LocalConfig.SetValue(OsuSetting.GameplayCursorSize, newCursorSize)); + } + } + + protected override TestPlayer CreatePlayer(Ruleset ruleset) => new PausePlayer(); + + protected partial class PausePlayer : TestPlayer + { + public double LastPauseTime { get; private set; } + public double LastResumeTime { get; private set; } + + public override void OnEntering(ScreenTransitionEvent e) + { + base.OnEntering(e); + GameplayClockContainer.Stop(); + } + + private bool? isRunning; + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + if (GameplayClockContainer.IsRunning != isRunning) + { + isRunning = GameplayClockContainer.IsRunning; + + if (isRunning.Value) + LastResumeTime = GameplayClockContainer.CurrentTime; + else + LastPauseTime = GameplayClockContainer.CurrentTime; + } + } + } + } +} From 2c9fc32756e543113f72042e6eb9ec454c43541c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Nov 2025 16:39:39 +0900 Subject: [PATCH 177/836] Assert that player suspension is final --- osu.Game/Screens/Play/Player.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 38e3fcd38d7e..9988bbcd9311 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -1172,6 +1172,8 @@ protected virtual void StartGameplay() public override void OnSuspending(ScreenTransitionEvent e) { + Debug.Assert(!ValidForResume); + screenSuspension?.RemoveAndDisposeImmediately(); // If these are not disposed, audio volume dimming can get stuck. From 545b13c3fb72a9e4f10bbcee9f3fbda7bf58e6d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Nov 2025 16:45:52 +0900 Subject: [PATCH 178/836] Show self in online users I don't see a reason to hide self. I kinda expect to be able to see that I'm online. --- osu.Game/Online/Metadata/OnlineMetadataClient.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Metadata/OnlineMetadataClient.cs b/osu.Game/Online/Metadata/OnlineMetadataClient.cs index 75b01873889d..052b742beb2a 100644 --- a/osu.Game/Online/Metadata/OnlineMetadataClient.cs +++ b/osu.Game/Online/Metadata/OnlineMetadataClient.cs @@ -235,15 +235,13 @@ public override Task UserPresenceUpdated(int userId, UserPresence? presence) { if (userId == api.LocalUser.Value.OnlineID) localUserPresence = presence.Value; - else - userPresences[userId] = presence.Value; + userPresences[userId] = presence.Value; } else { if (userId == api.LocalUser.Value.OnlineID) localUserPresence = default; - else - userPresences.Remove(userId); + userPresences.Remove(userId); } }); From 26c50b874cb782090eba5c197a03a4004f9cdcf1 Mon Sep 17 00:00:00 2001 From: Hiviexd Date: Tue, 25 Nov 2025 09:31:41 +0100 Subject: [PATCH 179/836] update osu!taiko drain thresholds see change in https://github.com/ppy/osu-wiki/pull/13958/commits/25169ccbe6f5b399a8a659623d622b1332d043db --- .../Edit/Checks/CheckTaikoLowestDiffDrainTime.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Edit/Checks/CheckTaikoLowestDiffDrainTime.cs b/osu.Game.Rulesets.Taiko/Edit/Checks/CheckTaikoLowestDiffDrainTime.cs index 8ef911c18e9f..30717d7ee90f 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Checks/CheckTaikoLowestDiffDrainTime.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Checks/CheckTaikoLowestDiffDrainTime.cs @@ -13,9 +13,9 @@ public class CheckTaikoLowestDiffDrainTime : CheckLowestDiffDrainTime protected override IEnumerable<(DifficultyRating rating, double thresholdMs, string name)> GetThresholds() { // See lowest difficulty requirements in https://osu.ppy.sh/wiki/en/Ranking_criteria/osu%21taiko#general - yield return (DifficultyRating.Hard, new TimeSpan(0, 3, 30).TotalMilliseconds, "Muzukashii"); - yield return (DifficultyRating.Insane, new TimeSpan(0, 4, 15).TotalMilliseconds, "Oni"); - yield return (DifficultyRating.Expert, new TimeSpan(0, 5, 0).TotalMilliseconds, "Inner Oni"); + yield return (DifficultyRating.Hard, new TimeSpan(0, 2, 30).TotalMilliseconds, "Muzukashii"); + yield return (DifficultyRating.Insane, new TimeSpan(0, 3, 15).TotalMilliseconds, "Oni"); + yield return (DifficultyRating.Expert, new TimeSpan(0, 4, 0).TotalMilliseconds, "Inner Oni"); } } } From f6a6c9f8859205b1caa19fc4fc1f39f42cceb9e4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Nov 2025 18:48:03 +0900 Subject: [PATCH 180/836] Fix failing test --- .../Visual/Background/TestSceneUserDimBackgrounds.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs index 3021589cdb86..1365d95a55bd 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs @@ -266,7 +266,11 @@ public void TestTransition() FadeAccessibleResults results = null; - AddStep("Transition to Results", () => player.Push(results = new FadeAccessibleResults(TestResources.CreateTestScoreInfo()))); + AddStep("Transition to Results", () => + { + player.ValidForResume = false; + player.Push(results = new FadeAccessibleResults(TestResources.CreateTestScoreInfo())); + }); AddUntilStep("Wait for results is current", () => results.IsCurrentScreen()); From 0d9a50e839ce8e8adab969112cca162a4e72bcaf Mon Sep 17 00:00:00 2001 From: maarvin Date: Wed, 26 Nov 2025 14:11:40 +0100 Subject: [PATCH 181/836] Quickplay: Update top level layout to match designs (#35791) * Adjust top level matchmaking screen layout * Adjust colours in StageDisplay * Fix flipped animation in StageDisplay * Adjust colours in CurrentRoundDisplay * Fade out stage segments as they approach the left screen border * Remove redundant `OfType()` call * Soften banner shadow Co-authored-by: marvin --------- Co-authored-by: Dan Balasescu --- .../Match/ScreenMatchmaking.ScreenStack.cs | 7 +- .../Matchmaking/Match/ScreenMatchmaking.cs | 26 ++---- .../Match/StageDisplay.StageSegment.cs | 9 +- .../Matchmaking/Match/StageDisplay.cs | 89 ++++++++++++------- 4 files changed, 64 insertions(+), 67 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs index 4d5a7099c460..55bbcf7ce57c 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs @@ -36,10 +36,7 @@ private void load() new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(6) - { - Bottom = StageDisplay.HEIGHT + 6, - }, + Padding = new MarginPadding { Top = StageDisplay.HEIGHT, Bottom = 6 }, Children = new Drawable[] { screenStack = new Framework.Screens.ScreenStack(), @@ -51,8 +48,6 @@ private void load() }, new StageDisplay { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.X } }; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs index a8092705744f..e3319d4c9405 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs @@ -13,7 +13,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Logging; using osu.Framework.Screens; @@ -57,8 +56,8 @@ public partial class ScreenMatchmaking : OsuScreen, IPreviewTrackOwner, IHandleP public override bool ShowFooter => true; - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); protected override BackgroundScreen CreateBackground() => new MatchmakingBackgroundScreen(colourProvider); @@ -124,7 +123,7 @@ public ScreenMatchmaking(MultiplayerRoom room) } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load() { sampleStart = audio.Samples.Get(@"SongSelect/confirm-selection"); @@ -143,8 +142,7 @@ private void load(OverlayColourProvider colourProvider) RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { - Horizontal = WaveOverlayContainer.WIDTH_PADDING, - Top = row_padding, + Horizontal = HORIZONTAL_OVERFLOW_PADDING, }, RowDimensions = new[] { @@ -155,21 +153,7 @@ private void load(OverlayColourProvider colourProvider) Content = new Drawable[]?[] { [ - new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 10, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background6, - }, - new ScreenStack(), - } - } + new ScreenStack(), ], null, [ diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.StageSegment.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.StageSegment.cs index 7e3b7d446867..50806e6b270c 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.StageSegment.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.StageSegment.cs @@ -7,7 +7,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; @@ -92,11 +91,7 @@ private void load(AudioManager audio, OverlayColourProvider colourProvider) new Box { RelativeSizeAxes = Axes.Both, - Colour = - ColourInfo.GradientVertical( - colourProvider.Dark2, - colourProvider.Dark1 - ), + Colour = colourProvider.Dark3, }, progressBar = new Box { @@ -104,7 +99,7 @@ private void load(AudioManager audio, OverlayColourProvider colourProvider) EdgeSmoothness = new Vector2(1), RelativeSizeAxes = Axes.Both, Width = 0, - Colour = colourProvider.Dark3, + Colour = colourProvider.Colour3, }, new OsuSpriteText { diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.cs index b45e8054a020..53cdc6d85e97 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.cs @@ -9,7 +9,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Transforms; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -17,6 +19,7 @@ using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Overlays; using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match { @@ -31,7 +34,7 @@ public partial class StageDisplay : CompositeDrawable private const int round_count = 5; private OsuScrollContainer scroll = null!; - private FillFlowContainer flow = null!; + private FillFlowContainer flow = null!; private CurrentRoundDisplay roundDisplay = null!; @@ -46,10 +49,16 @@ private void load(OverlayColourProvider colourProvider) { InternalChildren = new Drawable[] { - new Box + new BufferedContainer(cachedFrameBuffer: true) { - Colour = colourProvider.Dark6, RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(Color4.White, Color4.Transparent), + Alpha = 0.8f, + Child = new Box + { + Colour = ColourInfo.GradientHorizontal(colourProvider.Dark6, colourProvider.Dark6.Opacity(0.5f)), + RelativeSizeAxes = Axes.Both, + } }, new Container { @@ -63,7 +72,7 @@ private void load(OverlayColourProvider colourProvider) ClampExtension = 0, RelativeSizeAxes = Axes.X, Height = HEIGHT, - Child = flow = new FillFlowContainer + Child = flow = new FillFlowContainer { Padding = new MarginPadding { Horizontal = 2000 }, AutoSizeAxes = Axes.Both, @@ -84,15 +93,6 @@ private void load(OverlayColourProvider colourProvider) Anchor = Anchor.Centre, Origin = Anchor.Centre }, - new Box - { - Colour = ColourInfo.GradientHorizontal( - colourProvider.Dark4, - colourProvider.Dark5.Opacity(0) - ), - RelativeSizeAxes = Axes.Y, - Width = 240, - }, roundDisplay = new CurrentRoundDisplay { X = 12, @@ -119,7 +119,7 @@ private void load(OverlayColourProvider colourProvider) protected override void Update() { base.Update(); - var bubble = flow.OfType().FirstOrDefault(b => b.Active); + var bubble = flow.FirstOrDefault(b => b.Active); if (bubble != null) { @@ -128,6 +128,21 @@ protected override void Update() } } + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + foreach (var segment in flow) + { + if (segment.Active) + return; + + float offset = segment.ToSpaceOfOtherDrawable(Vector2.Zero, this).X; + + segment.Alpha = float.Clamp(offset / 300, 0.1f, 0.5f); + } + } + private partial class StageScrollContainer : OsuScrollContainer { public override bool HandlePositionalInput => false; @@ -158,47 +173,55 @@ private void load(OverlayColourProvider colours, AudioManager audio) { Size = new Vector2(76); + progress = new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = colours.Colour2, + InnerRadius = 0.1f, + RelativeSizeAxes = Axes.Both, + RoundedCaps = true, + }; InternalChildren = new Drawable[] { new Circle { - Colour = ColourInfo.GradientVertical( - colours.Dark2, - colours.Dark4 - ), + Colour = colours.Dark4, RelativeSizeAxes = Axes.Both, }, - progress = new CircularProgress + (progress = new CircularProgress { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Colour = ColourInfo.GradientVertical( - colours.Light1, - colours.Dark2 - ), + Colour = colours.Colour2, InnerRadius = 0.1f, - RelativeSizeAxes = Axes.Both, - }, + Size = Size, + }).WithEffect(new GlowEffect + { + Colour = colours.Colour2, + BlurSigma = new Vector2(10), + Strength = 2f, + Placement = EffectPlacement.Behind, + PadExtent = true, + }), innerCircle = new Circle { Alpha = 0.2f, Blending = BlendingParameters.Additive, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Colour = ColourInfo.GradientVertical( - colours.Dark1, - colours.Dark2 - ), + Colour = colours.Dark1, Scale = new Vector2(0.9f), RelativeSizeAxes = Axes.Both, }, new OsuSpriteText { - Y = 10, + Y = 13, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Font = OsuFont.Style.Caption2, Text = "Round", + Colour = colours.Content2 }, text = new OsuSpriteText { @@ -245,10 +268,10 @@ public int? Round round = value.Value; this.ScaleTo(6, 1000, Easing.OutPow10) - .MoveToY(-300, 1000, Easing.OutPow10) + .MoveToY(300, 1000, Easing.OutPow10) .Then() - .MoveToY(0, 500, Easing.InQuart) - .ScaleTo(1, 500, Easing.InQuart); + .MoveToY(0, 500, new CubicBezierEasingFunction(0.8, 0, 0.6, 1)) + .ScaleTo(1, 500, new CubicBezierEasingFunction(0.8, 0, 0.6, 1)); swishChannel = swishSample?.GetChannel(); From 75df8e363903a2886acddfc6743cac00c9145771 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 27 Nov 2025 15:00:14 +0900 Subject: [PATCH 182/836] Add failing tests --- .../Visual/Online/TestSceneDrawableChannel.cs | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs index 6a077708e325..7c6cbb66cb6e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs @@ -146,5 +146,164 @@ public void TestBackgroundAlternating() checkCount++; }, 10); } + + [Test] + public void TestAlternatingBackgroundDoesNotChangeAtMaxHistory() + { + AddStep("fill up the channel", () => + { + for (int i = 0; i < Channel.MAX_HISTORY; i++) + { + channel.AddNewMessages(new Message + { + ChannelId = channel.Id, + Content = $"Message {i}", + Timestamp = DateTimeOffset.Now, + Sender = new APIUser + { + Id = 3, + Username = "LocalUser " + RNG.Next(0, int.MaxValue - 100).ToString("N") + } + }); + } + }); + + AddUntilStep($"{Channel.MAX_HISTORY} messages present", () => drawableChannel.ChildrenOfType().Count(), () => Is.EqualTo(Channel.MAX_HISTORY)); + + ChatLine? lastLine = null; + bool lastLineAlternatingBackground = false; + + AddStep("grab last line", () => + { + lastLine = drawableChannel.ChildrenOfType().Last(); + lastLineAlternatingBackground = lastLine.AlternatingBackground; + }); + + AddStep("add another message", () => channel.AddNewMessages(new Message + { + ChannelId = channel.Id, + Content = "One final message", + Timestamp = DateTimeOffset.Now, + Sender = new APIUser + { + Id = 3, + Username = "LocalUser " + RNG.Next(0, int.MaxValue - 100).ToString("N") + } + })); + + AddAssert("second-last message has same background", () => lastLine!.AlternatingBackground, () => Is.EqualTo(lastLineAlternatingBackground)); + } + + [Test] + public void TestAlternatingBackgroundUpdatedOnRemoval() + { + AddStep("add 3 messages", () => + { + for (int i = 0; i < 3; i++) + { + channel.AddNewMessages(new Message + { + ChannelId = channel.Id, + Content = $"Message {i}", + Timestamp = DateTimeOffset.Now, + Sender = new APIUser + { + Id = i, + Username = "LocalUser " + RNG.Next(0, int.MaxValue - 100).ToString("N") + } + }); + } + }); + + AddUntilStep("3 messages present", () => drawableChannel.ChildrenOfType().Count(), () => Is.EqualTo(3)); + assertAlternatingBackground(0, false); + assertAlternatingBackground(1, true); + assertAlternatingBackground(2, false); + + AddStep("remove middle message", () => channel.RemoveMessagesFromUser(1)); + AddUntilStep("2 messages present", () => drawableChannel.ChildrenOfType().Count(), () => Is.EqualTo(2)); + assertAlternatingBackground(0, true); + assertAlternatingBackground(1, false); + + void assertAlternatingBackground(int lineIndex, bool shouldBeAlternating) + => AddAssert($"line {lineIndex} {(shouldBeAlternating ? "has" : "does not have")} alternating background", + () => drawableChannel.ChildrenOfType().ElementAt(lineIndex).AlternatingBackground, + () => Is.EqualTo(shouldBeAlternating)); + } + + [Test] + public void TestTimestampsUpdateOnRemoval() + { + AddStep("add 3 messages", () => + { + channel.AddNewMessages(new Message + { + ChannelId = channel.Id, + Content = "Message 0", + Timestamp = new DateTimeOffset(2022, 11, 21, 20, 0, 0, TimeSpan.Zero), + Sender = new APIUser + { + Id = 0, + Username = "LocalUser " + RNG.Next(0, int.MaxValue - 100).ToString("N") + } + }, + new Message + { + ChannelId = channel.Id, + Content = "Message 1", + Timestamp = new DateTimeOffset(2022, 11, 21, 20, 0, 0, TimeSpan.Zero).AddSeconds(1), + Sender = new APIUser + { + Id = 1, + Username = "LocalUser " + RNG.Next(0, int.MaxValue - 100).ToString("N") + } + }, + new Message + { + ChannelId = channel.Id, + Content = "Message 2", + Timestamp = new DateTimeOffset(2022, 11, 21, 20, 0, 0, TimeSpan.Zero).AddMinutes(1), + Sender = new APIUser + { + Id = 2, + Username = "LocalUser " + RNG.Next(0, int.MaxValue - 100).ToString("N") + } + }, + new Message + { + ChannelId = channel.Id, + Content = "Message 3", + Timestamp = new DateTimeOffset(2022, 11, 21, 20, 0, 0, TimeSpan.Zero).AddMinutes(1).AddSeconds(1), + Sender = new APIUser + { + Id = 3, + Username = "LocalUser " + RNG.Next(0, int.MaxValue - 100).ToString("N") + } + } + ); + }); + + AddUntilStep("4 messages present", () => drawableChannel.ChildrenOfType().Count(), () => Is.EqualTo(4)); + assertTimestamp(0, true); + assertTimestamp(1, false); + assertTimestamp(2, true); + assertTimestamp(3, false); + + AddStep("remove message 0", () => channel.RemoveMessagesFromUser(0)); + AddUntilStep("3 messages present", () => drawableChannel.ChildrenOfType().Count(), () => Is.EqualTo(3)); + assertTimestamp(0, true); + assertTimestamp(1, true); + assertTimestamp(2, false); + + AddStep("remove message 2", () => channel.RemoveMessagesFromUser(2)); + AddUntilStep("2 messages present", () => drawableChannel.ChildrenOfType().Count(), () => Is.EqualTo(2)); + assertTimestamp(0, true); + assertTimestamp(1, true); + + void assertTimestamp(int lineIndex, bool shouldHaveTimestamp) + => AddAssert($"line {lineIndex} {(shouldHaveTimestamp ? "has" : "does not have")} timestamp", + () => drawableChannel.ChildrenOfType().ElementAt(lineIndex).RequiresTimestamp, + () => Is.EqualTo(shouldHaveTimestamp)); + } } } From ded8aaecfdd82430781d3f9f6094df9e636710c4 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 27 Nov 2025 15:13:25 +0900 Subject: [PATCH 183/836] Fix chat lines flipping colours at maximum history --- osu.Game/Overlays/Chat/DrawableChannel.cs | 72 ++++++++++++++++++----- 1 file changed, 56 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index ad327f4b2825..92b5b4b0827d 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -85,16 +85,13 @@ protected override void Update() long? lastMinutes = null; - for (int i = 0; i < ChatLineFlow.Count; i++) + foreach (var line in chatLines) { - if (ChatLineFlow[i] is ChatLine chatline) - { - long minutes = chatline.Message.Timestamp.ToUnixTimeSeconds() / 60; + long minutes = line.Message.Timestamp.ToUnixTimeSeconds() / 60; - chatline.AlternatingBackground = i % 2 == 0; - chatline.RequiresTimestamp = minutes != lastMinutes; - lastMinutes = minutes; - } + line.RequiresTimestamp = minutes != lastMinutes; + + lastMinutes = minutes; } } @@ -145,19 +142,28 @@ private void newMessagesArrived(IEnumerable newMessages) => Schedule(() // Add up to last Channel.MAX_HISTORY messages var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY)); - Message lastMessage = chatLines.LastOrDefault()?.Message; + ChatLine lastLine = chatLines.LastOrDefault(); + Message lastMessage = lastLine?.Message; foreach (var message in displayMessages) { addDaySeparatorIfRequired(lastMessage, message); - var chatLine = CreateChatLine(message); + ChatLine line = CreateChatLine(message); - if (chatLine != null) - { - ChatLineFlow.Add(chatLine); - lastMessage = message; - } + if (line == null) + continue; + + long minutes = line.Message.Timestamp.ToUnixTimeSeconds() / 60; + long? lastMinutes = lastLine?.Message.Timestamp.ToUnixTimeSeconds() / 60; + + line.AlternatingBackground = lastLine?.AlternatingBackground == false; + line.RequiresTimestamp = minutes != lastMinutes; + + ChatLineFlow.Add(line); + + lastMessage = message; + lastLine = line; } var staleMessages = chatLines.Where(c => c.LifetimeEnd == double.MaxValue).ToArray(); @@ -232,7 +238,41 @@ private void expireAndAdjustScroll(Drawable d) private void messageRemoved(Message removed) => Schedule(() => { - chatLines.FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); + const double fade_time = 600; + + ChatLine removedLine = chatLines.FirstOrDefault(c => c.Message == removed); + + if (removedLine == null) + return; + + removedLine.FadeColour(Color4.Red, 400).FadeOut(fade_time).Expire(); + + // Resolve new colours and timestamps resulting from the removal. + this.Delay(fade_time).Schedule(() => + { + ChatLine lastLine = null; + + // Preserve the colours of most-recent messages while updating the ones upwards in the list. + foreach (var line in chatLines.Reverse().Except([removedLine])) + { + if (lastLine != null) + line.AlternatingBackground = !lastLine.AlternatingBackground; + + lastLine = line; + } + + lastLine = null; + + // Timestamps may migrate to more recent messages. + foreach (var line in chatLines.Except([removedLine])) + { + long minutes = line.Message.Timestamp.ToUnixTimeSeconds() / 60; + long? lastMinutes = lastLine?.Message.Timestamp.ToUnixTimeSeconds() / 60; + line.RequiresTimestamp = minutes != lastMinutes; + + lastLine = line; + } + }); }); private IEnumerable chatLines => ChatLineFlow.Children.OfType(); From 1e43509e4a3594f24e441efa8a04971de062f091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 27 Nov 2025 09:37:40 +0100 Subject: [PATCH 184/836] Fix formatting --- osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs index 7c6cbb66cb6e..b475071f6eb0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs @@ -236,7 +236,8 @@ public void TestTimestampsUpdateOnRemoval() { AddStep("add 3 messages", () => { - channel.AddNewMessages(new Message + channel.AddNewMessages( + new Message { ChannelId = channel.Id, Content = "Message 0", From db50019f3118ba034da1ed6d2163cf64c6fa3680 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 27 Nov 2025 18:25:32 +0900 Subject: [PATCH 185/836] Display quick play pool name as sub-heading --- .../TestSceneMatchmakingPoolSelector.cs | 10 ++--- .../Matchmaking/Queue/PoolSelector.cs | 39 +++++++++++++------ 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingPoolSelector.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingPoolSelector.cs index c05614e9a49f..bd3b75f1b812 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingPoolSelector.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingPoolSelector.cs @@ -22,11 +22,11 @@ public override void SetUpSteps() { Value = [ - new MatchmakingPool { Id = 0, RulesetId = 0, Name = "osu!" }, - new MatchmakingPool { Id = 1, RulesetId = 1, Name = "osu!taiko" }, - new MatchmakingPool { Id = 2, RulesetId = 2, Name = "osu!catch" }, - new MatchmakingPool { Id = 3, RulesetId = 3, Variant = 4, Name = "osu!mania (4k)" }, - new MatchmakingPool { Id = 4, RulesetId = 3, Variant = 7, Name = "osu!mania (7k)" }, + new MatchmakingPool { Id = 0, RulesetId = 0, Name = "Free-for-all" }, + new MatchmakingPool { Id = 1, RulesetId = 1, Name = "1v1" }, + new MatchmakingPool { Id = 2, RulesetId = 2, Name = "1v1" }, + new MatchmakingPool { Id = 3, RulesetId = 3, Variant = 4, Name = "1v1" }, + new MatchmakingPool { Id = 4, RulesetId = 3, Variant = 7, Name = "1v1" }, ] } }); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/PoolSelector.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/PoolSelector.cs index 1e6dd0f23185..a89700ffe320 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/PoolSelector.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/PoolSelector.cs @@ -92,7 +92,7 @@ protected override bool OnKeyDown(KeyDownEvent e) private partial class SelectorButton : OsuAnimatedButton { - public static readonly Vector2 SIZE = new Vector2(84, 64); + public static readonly Vector2 SIZE = new Vector2(84, 78); public bool IsSelected => SelectedPool.Value?.Equals(pool) == true; @@ -106,8 +106,6 @@ private partial class SelectorButton : OsuAnimatedButton private Box flashLayer = null!; - private OsuSpriteText text = null!; - public SelectorButton(MatchmakingPool pool) : base(HoverSampleSet.ButtonSidebar) { @@ -123,6 +121,12 @@ private void load(OverlayColourProvider colourProvider) Content.CornerRadius = 16; Content.CornerExponent = 10; + Ruleset? rulesetInstance = rulesetStore.GetRuleset(pool.RulesetId)?.CreateInstance(); + + string rulesetName = rulesetInstance?.Description ?? string.Empty; + if (pool.Variant != 0) + rulesetName += $" {pool.Variant}K"; + Children = new Drawable[] { new Box @@ -156,13 +160,28 @@ private void load(OverlayColourProvider colourProvider) iconSprite = createIcon(), } }, - text = new OsuSpriteText + new FillFlowContainer { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Font = OsuFont.Style.Caption2, - Text = pool.Name, - }, + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Font = OsuFont.Style.Caption1.With(weight: FontWeight.Bold), + Text = rulesetName, + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Font = OsuFont.Style.Caption2, + Text = pool.Name + } + } + } } }, }; @@ -198,14 +217,12 @@ private void onSelectionChanged(ValueChangedEvent selection) { this.ScaleTo(1.2f, 200, Easing.OutQuint); iconSprite.FadeColour(Color4.Gold, 100, Easing.OutQuint); - text.Font = text.Font.With(weight: FontWeight.Bold); flashLayer.FadeTo(0.1f, 200, Easing.OutQuint); } else { this.ScaleTo(1f, 200, Easing.OutQuint); iconSprite.FadeColour(OsuColour.Gray(0.5f), 100); - text.Font = text.Font.With(weight: FontWeight.Regular); flashLayer.FadeOut(200, Easing.OutQuint); } } From 5a865476cec807fc61afca1b242abb88d6bdb0eb Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 27 Nov 2025 18:42:45 +0900 Subject: [PATCH 186/836] Remove now-unnecessary timestamp updates Since #35820, this is now handled when messages are added and removed. --- osu.Game/Overlays/Chat/DrawableChannel.cs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 92b5b4b0827d..05bafae6a103 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -79,22 +79,6 @@ protected override void LoadComplete() highlightedMessage.BindValueChanged(_ => processMessageHighlighting(), true); } - protected override void Update() - { - base.Update(); - - long? lastMinutes = null; - - foreach (var line in chatLines) - { - long minutes = line.Message.Timestamp.ToUnixTimeSeconds() / 60; - - line.RequiresTimestamp = minutes != lastMinutes; - - lastMinutes = minutes; - } - } - /// /// Processes any pending message in . /// From 6244617e5eb8d2feb5a6781793647ba8de48bbec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 27 Nov 2025 12:58:47 +0100 Subject: [PATCH 187/836] Attempt to prevent main menu osu! logo being triggered by media keys (#35825) Maybe addresses https://github.com/ppy/osu/discussions/35813. I can't reproduce on macOS, may be a $USER_OS idiosyncrasy. --- osu.Game/Screens/Menu/ButtonSystem.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index a73fafcffdc2..da78ea337105 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -286,6 +286,9 @@ protected override bool OnKeyDown(KeyDownEvent e) if (e.Key >= Key.F1 && e.Key <= Key.F35) return false; + if (e.Key >= Key.Mute && e.Key <= Key.TrackNext) + return false; + switch (e.Key) { case Key.Escape: From 037743e0028d15dfd403c2026c5390a41744ca93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 27 Nov 2025 13:10:46 +0100 Subject: [PATCH 188/836] Add context menu shortcut to watch local replays from song select (#35823) Addresses https://github.com/ppy/osu/discussions/35811 I guess. Will only work for local leaderboards for now but maybe good enough for what is essentially a 5 minute job? Can be made to work with online leaderboards too I guess if need be. --- osu.Game/Localisation/SongSelectStrings.cs | 5 +++++ osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs | 2 ++ 2 files changed, 7 insertions(+) diff --git a/osu.Game/Localisation/SongSelectStrings.cs b/osu.Game/Localisation/SongSelectStrings.cs index c20715fb4ceb..f84683ac63dc 100644 --- a/osu.Game/Localisation/SongSelectStrings.cs +++ b/osu.Game/Localisation/SongSelectStrings.cs @@ -109,6 +109,11 @@ public static class SongSelectStrings /// public static LocalisableString UseTheseMods => new TranslatableString(getKey(@"use_these_mods"), @"Use these mods"); + /// + /// "Watch replay" + /// + public static LocalisableString WatchReplay => new TranslatableString(getKey(@"watch_replay"), @"Watch replay"); + /// /// "For all difficulties" /// diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs b/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs index 16c9ed64f6ca..079f4192e04f 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs +++ b/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs @@ -628,6 +628,8 @@ MenuItem[] IHasContextMenu.ContextMenuItems if (Score.Files.Count <= 0) return items.ToArray(); + items.Add(new OsuMenuItemSpacer()); + items.Add(new OsuMenuItem(SongSelectStrings.WatchReplay, MenuItemType.Standard, () => game?.PresentScore(Score, ScorePresentType.Gameplay))); items.Add(new OsuMenuItem(CommonStrings.Export, MenuItemType.Standard, () => scoreManager.Export(Score))); items.Add(new OsuMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score)))); From 6bb25b2abe09cadf61ae2c25e496a23b2827776e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 27 Nov 2025 13:22:06 +0100 Subject: [PATCH 189/836] Fix gameplay leaderboard tracked player not using team colour (#35826) * Demonstrate colour problem in test * Fix gameplay leaderboard tracked player not using team colour Closes https://github.com/ppy/osu/issues/35806. --- ...stSceneDrawableGameplayLeaderboardScore.cs | 71 +++++++++++++++++++ .../HUD/DrawableGameplayLeaderboardScore.cs | 10 +-- 2 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneDrawableGameplayLeaderboardScore.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableGameplayLeaderboardScore.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableGameplayLeaderboardScore.cs new file mode 100644 index 000000000000..1363ef12a9f1 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableGameplayLeaderboardScore.cs @@ -0,0 +1,71 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Select.Leaderboards; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public partial class TestSceneDrawableGameplayLeaderboardScore : OsuTestScene + { + private readonly APIUser user = new APIUser { Username = "user" }; + private readonly BindableLong totalScore = new BindableLong(); + private readonly Bindable position = new Bindable(); + private readonly BindableBool quit = new BindableBool(); + private readonly BindableBool expanded = new BindableBool(); + + public TestSceneDrawableGameplayLeaderboardScore() + { + AddSliderStep("total score", 0, 1_000_000, 500_000, s => totalScore.Value = s); + AddSliderStep("position", 1, 100, 5, s => position.Value = s); + AddToggleStep("toggle quit", q => quit.Value = q); + AddToggleStep("toggle expanded", e => expanded.Value = e); + } + + private static readonly OsuColour osu_colour = new OsuColour(); + + private static readonly object?[][] leaderboard_variants = + { + new object?[] { false, null }, + new object?[] { true, null }, + new object?[] { false, osu_colour.TeamColourRed }, + new object?[] { true, osu_colour.TeamColourRed }, + new object?[] { false, osu_colour.TeamColourBlue }, + new object?[] { true, osu_colour.TeamColourBlue }, + }; + + [TestCaseSource(nameof(leaderboard_variants))] + public void TestVariants(bool tracked, Color4? teamColour) + { + AddStep("show", () => + { + GameplayLeaderboardScore score = new GameplayLeaderboardScore(user, tracked, totalScore) + { + Position = { BindTarget = position }, + HasQuit = { BindTarget = quit }, + TeamColour = teamColour, + }; + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + Width = 250, + Child = new DrawableGameplayLeaderboardScore(score) + { + Expanded = { BindTarget = expanded }, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + }); + } + } +} diff --git a/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs index 339488e5d07d..df81afed5b8a 100644 --- a/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs @@ -357,7 +357,7 @@ private void updatePanelState() else if (Tracked) { widthExtension = true; - setPanelColourAsTracked(); + setTrackedPanelColour(BackgroundColour); } else if (isFriend) { @@ -380,11 +380,11 @@ private void setPanelColour(Color4 baseColour) scorePanel.BorderColour = ColourInfo.GradientVertical(baseColour.Opacity(0.2f), baseColour); } - private void setPanelColourAsTracked() + private void setTrackedPanelColour(Color4? backgroundColour) { - leftLayerGradient.Colour = ColourInfo.GradientVertical(colours.Blue2.Opacity(0.3f), colours.Blue2); - rightLayerGradient.Colour = ColourInfo.GradientVertical(colours.Blue4.Opacity(0.25f), colours.Blue3.Opacity(0.6f)); - scorePanel.BorderColour = ColourInfo.GradientVertical(colours.Blue1.Opacity(0.2f), colours.Blue1); + leftLayerGradient.Colour = ColourInfo.GradientVertical((backgroundColour ?? colours.Blue2).Opacity(0.3f), backgroundColour ?? colours.Blue2); + rightLayerGradient.Colour = ColourInfo.GradientVertical((backgroundColour ?? colours.Blue4).Opacity(0.25f), (backgroundColour ?? colours.Blue3).Opacity(0.6f)); + scorePanel.BorderColour = ColourInfo.GradientVertical((backgroundColour ?? colours.Blue1).Opacity(0.2f), backgroundColour ?? colours.Blue1); } protected override void Update() From 9e2ea63e7092e8563ea8d7e0542d0535cbf7a2e9 Mon Sep 17 00:00:00 2001 From: Chirag Mahesh Date: Thu, 27 Nov 2025 14:52:57 +0000 Subject: [PATCH 190/836] Revert Changes to Trail Position Calculation - Revert changes to CursorTrail.cs made during 79bfe7880af8243b4d5c7c83d81236c872a17314 --- .../UI/Cursor/CursorTrail.cs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 8a45475f0fc2..1c2d69fa00e4 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -164,18 +164,20 @@ protected override bool OnMouseMove(MouseMoveEvent e) return base.OnMouseMove(e); } - protected void AddTrail(Vector2 screenSpacePosition) + protected void AddTrail(Vector2 position) { + position = ToLocalSpace(position); + if (InterpolateMovements) { if (!lastPosition.HasValue) { - lastPosition = screenSpacePosition; + lastPosition = position; resampler.AddPosition(lastPosition.Value); return; } - foreach (Vector2 pos2 in resampler.AddPosition(screenSpacePosition)) + foreach (Vector2 pos2 in resampler.AddPosition(position)) { Trace.Assert(lastPosition.HasValue); @@ -196,14 +198,14 @@ protected void AddTrail(Vector2 screenSpacePosition) } else { - lastPosition = screenSpacePosition; + lastPosition = position; addPart(lastPosition.Value); } } - private void addPart(Vector2 screenSpacePosition) + private void addPart(Vector2 localSpacePosition) { - parts[currentIndex].ScreenSpacePosition = screenSpacePosition; + parts[currentIndex].Position = localSpacePosition; parts[currentIndex].Time = time + 1; parts[currentIndex].Scale = NewPartScale; ++parts[currentIndex].InvalidationID; @@ -215,7 +217,7 @@ private void addPart(Vector2 screenSpacePosition) private struct TrailPart { - public Vector2 ScreenSpacePosition; + public Vector2 Position; public float Time; public Vector2 Scale; public long InvalidationID; @@ -302,13 +304,11 @@ protected override void Draw(IRenderer renderer) if (time - part.Time >= 1) continue; - Vector2 localSpacePosition = Vector2Extensions.Transform(part.ScreenSpacePosition, DrawInfo.MatrixInverse); - vertexBatch.Add(new TexturedTrailVertex { Position = rotateAround( - new Vector2(localSpacePosition.X - texture.DisplayWidth * originPosition.X * part.Scale.X, localSpacePosition.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y), - localSpacePosition, sin, cos), + new Vector2(part.Position.X - texture.DisplayWidth * originPosition.X * part.Scale.X, part.Position.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y), + part.Position, sin, cos), TexturePosition = textureRect.BottomLeft, TextureRect = new Vector4(0, 0, 1, 1), Colour = DrawColourInfo.Colour.BottomLeft.Linear, @@ -318,8 +318,8 @@ protected override void Draw(IRenderer renderer) vertexBatch.Add(new TexturedTrailVertex { Position = rotateAround( - new Vector2(localSpacePosition.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X, - localSpacePosition.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y), localSpacePosition, sin, cos), + new Vector2(part.Position.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X, + part.Position.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y), part.Position, sin, cos), TexturePosition = textureRect.BottomRight, TextureRect = new Vector4(0, 0, 1, 1), Colour = DrawColourInfo.Colour.BottomRight.Linear, @@ -329,8 +329,8 @@ protected override void Draw(IRenderer renderer) vertexBatch.Add(new TexturedTrailVertex { Position = rotateAround( - new Vector2(localSpacePosition.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X, localSpacePosition.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y), - localSpacePosition, sin, cos), + new Vector2(part.Position.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X, part.Position.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y), + part.Position, sin, cos), TexturePosition = textureRect.TopRight, TextureRect = new Vector4(0, 0, 1, 1), Colour = DrawColourInfo.Colour.TopRight.Linear, @@ -340,8 +340,8 @@ protected override void Draw(IRenderer renderer) vertexBatch.Add(new TexturedTrailVertex { Position = rotateAround( - new Vector2(localSpacePosition.X - texture.DisplayWidth * originPosition.X * part.Scale.X, localSpacePosition.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y), - localSpacePosition, sin, cos), + new Vector2(part.Position.X - texture.DisplayWidth * originPosition.X * part.Scale.X, part.Position.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y), + part.Position, sin, cos), TexturePosition = textureRect.TopLeft, TextureRect = new Vector4(0, 0, 1, 1), Colour = DrawColourInfo.Colour.TopLeft.Linear, From ae33690632821391593315d52a868d571920d335 Mon Sep 17 00:00:00 2001 From: Chirag Mahesh Date: Thu, 27 Nov 2025 14:59:08 +0000 Subject: [PATCH 191/836] Implement CursorTrail Scaling - Add CursorScale property to CursorTrail and adjust for scaling --- .../UI/Cursor/CursorTrail.cs | 32 ++++++++++++++++--- .../UI/Cursor/OsuCursorContainer.cs | 2 +- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 1c2d69fa00e4..fc5ad2d955f3 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -49,6 +49,18 @@ public partial class CursorTrail : Drawable, IRequireHighFrequencyMousePosition /// protected bool AllowPartRotation { get; set; } + private Vector2 cursorScale; + + public Vector2 CursorScale + { + get => cursorScale; + set + { + cursorScale = value; + Invalidate(Invalidation.DrawNode); + } + } + /// /// The trail part texture origin. /// @@ -233,6 +245,7 @@ private class TrailDrawNode : DrawNode private float time; private float fadeExponent; private float angle; + private Vector2 cursorScale; private readonly TrailPart[] parts = new TrailPart[max_sprites]; private Vector2 originPosition; @@ -253,6 +266,7 @@ public override void ApplyState() time = Source.time; fadeExponent = Source.FadeExponent; angle = Source.AllowPartRotation ? float.DegreesToRadians(Source.PartRotation) : 0; + cursorScale = Source.cursorScale; originPosition = Vector2.Zero; @@ -307,7 +321,9 @@ protected override void Draw(IRenderer renderer) vertexBatch.Add(new TexturedTrailVertex { Position = rotateAround( - new Vector2(part.Position.X - texture.DisplayWidth * originPosition.X * part.Scale.X, part.Position.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y), + new Vector2( + part.Position.X - texture.DisplayWidth * originPosition.X * part.Scale.X * cursorScale.X, + part.Position.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y * cursorScale.Y), part.Position, sin, cos), TexturePosition = textureRect.BottomLeft, TextureRect = new Vector4(0, 0, 1, 1), @@ -318,8 +334,10 @@ protected override void Draw(IRenderer renderer) vertexBatch.Add(new TexturedTrailVertex { Position = rotateAround( - new Vector2(part.Position.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X, - part.Position.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y), part.Position, sin, cos), + new Vector2( + part.Position.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X * cursorScale.X, + part.Position.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y * cursorScale.Y), + part.Position, sin, cos), TexturePosition = textureRect.BottomRight, TextureRect = new Vector4(0, 0, 1, 1), Colour = DrawColourInfo.Colour.BottomRight.Linear, @@ -329,7 +347,9 @@ protected override void Draw(IRenderer renderer) vertexBatch.Add(new TexturedTrailVertex { Position = rotateAround( - new Vector2(part.Position.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X, part.Position.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y), + new Vector2( + part.Position.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X * cursorScale.X, + part.Position.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y * cursorScale.Y), part.Position, sin, cos), TexturePosition = textureRect.TopRight, TextureRect = new Vector4(0, 0, 1, 1), @@ -340,7 +360,9 @@ protected override void Draw(IRenderer renderer) vertexBatch.Add(new TexturedTrailVertex { Position = rotateAround( - new Vector2(part.Position.X - texture.DisplayWidth * originPosition.X * part.Scale.X, part.Position.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y), + new Vector2( + part.Position.X - texture.DisplayWidth * originPosition.X * part.Scale.X * cursorScale.X, + part.Position.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y * cursorScale.Y), part.Position, sin, cos), TexturePosition = textureRect.TopLeft, TextureRect = new Vector4(0, 0, 1, 1), diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 974d99d7c868..bf0ed528fb73 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -64,7 +64,7 @@ protected override void LoadComplete() var newScale = new Vector2(e.NewValue); rippleVisualiser.CursorScale = newScale; - cursorTrail.Scale = newScale; + if (cursorTrail.Drawable is CursorTrail trail) trail.CursorScale = newScale; }, true); } From d8d7c808328f31a306dc0136c3e148a9c2c6e078 Mon Sep 17 00:00:00 2001 From: Chirag Mahesh Date: Thu, 27 Nov 2025 16:08:11 +0000 Subject: [PATCH 192/836] Persist cursorScale on skin refresh --- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index bf0ed528fb73..0044cf26dd8b 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -31,6 +31,8 @@ public partial class OsuCursorContainer : GameplayCursorContainer, IKeyBindingHa private readonly SkinnableDrawable cursorTrail; + private Vector2 cursorScale; + private readonly CursorRippleVisualiser rippleVisualiser; public OsuCursorContainer() @@ -61,10 +63,10 @@ protected override void LoadComplete() ActiveCursor.CursorScale.BindValueChanged(e => { - var newScale = new Vector2(e.NewValue); + cursorScale = new Vector2(e.NewValue); - rippleVisualiser.CursorScale = newScale; - if (cursorTrail.Drawable is CursorTrail trail) trail.CursorScale = newScale; + rippleVisualiser.CursorScale = cursorScale; + if (cursorTrail.Drawable is CursorTrail trail) trail.CursorScale = cursorScale; }, true); } @@ -86,6 +88,7 @@ protected override void Update() { trail.NewPartScale = ActiveCursor.CurrentExpandedScale; trail.PartRotation = ActiveCursor.CurrentRotation; + trail.CursorScale = cursorScale; } } From 78c6973298f038cf1609f9e48ee90ff648d5b931 Mon Sep 17 00:00:00 2001 From: Chirag Mahesh Date: Thu, 27 Nov 2025 16:38:19 +0000 Subject: [PATCH 193/836] move cursorScale persistance into OsuCursor and use skinnableCursorScale --- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs | 2 ++ osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs | 10 ++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs index e84fb9e2d667..37ceb296b8b5 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs @@ -36,6 +36,8 @@ public partial class OsuCursor : SkinReloadableDrawable /// public Vector2 CurrentExpandedScale => skinnableCursor.ExpandTarget?.Scale ?? Vector2.One; + public Vector2 CurrentCursorScale => skinnableCursor.Scale; + /// /// The current rotation of the cursor. /// diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 0044cf26dd8b..df72f8be97f5 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -31,8 +31,6 @@ public partial class OsuCursorContainer : GameplayCursorContainer, IKeyBindingHa private readonly SkinnableDrawable cursorTrail; - private Vector2 cursorScale; - private readonly CursorRippleVisualiser rippleVisualiser; public OsuCursorContainer() @@ -63,10 +61,10 @@ protected override void LoadComplete() ActiveCursor.CursorScale.BindValueChanged(e => { - cursorScale = new Vector2(e.NewValue); + var newScale = new Vector2(e.NewValue); - rippleVisualiser.CursorScale = cursorScale; - if (cursorTrail.Drawable is CursorTrail trail) trail.CursorScale = cursorScale; + rippleVisualiser.CursorScale = newScale; + if (cursorTrail.Drawable is CursorTrail trail) trail.CursorScale = newScale; }, true); } @@ -88,7 +86,7 @@ protected override void Update() { trail.NewPartScale = ActiveCursor.CurrentExpandedScale; trail.PartRotation = ActiveCursor.CurrentRotation; - trail.CursorScale = cursorScale; + trail.CursorScale = ActiveCursor.CurrentCursorScale; } } From a8f058141b4e4bdf69c0d49c0c0b4f35e6d9971a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 28 Nov 2025 00:21:13 +0100 Subject: [PATCH 194/836] Fix several issues with editor timestamps for objects with fractional start times in osu!mania (#35829) * Fix mania editor timestamp generation being culture-dependent Mostly closes https://github.com/ppy/osu/issues/35809. * Add failing test for notes with fractions * Round note time when copying out timestamp & apply half-millisecond tolerance when parsing Closes the rest of https://github.com/ppy/osu/issues/35809. One issue here was that while the timestamp generation would allow fractional object timestamps to be output, the parsing (via `selection_regex`) would *reject* fractional timestamps, therefore making lazer incompatible even with itself. The other is that rounding is probably fine to do anyway for interoperability with stable. I'd hope nobody actually *needs* sub-millisecond precision but I'm ready to be proven wrong by some aspire jokester. * Specify invariant culture when writing out combo indices to editor timestamp in other rulesets Pretty sure this is just a much-of-muchness because it's integers but might as well if I'm spending time here already. --- .../Edit/CatchHitObjectComposer.cs | 4 ++- .../TestSceneOpenEditorTimestampInMania.cs | 27 ++++++++++--------- .../Edit/ManiaHitObjectComposer.cs | 9 ++++--- .../Edit/OsuHitObjectComposer.cs | 4 ++- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index 370eb37d16bb..be9685ce9af8 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using osu.Framework.Allocation; @@ -224,7 +225,8 @@ private void updateDistanceSnapGrid() #region Clipboard handling public override string ConvertSelectionToString() - => string.Join(',', EditorBeatmap.SelectedHitObjects.Cast().OrderBy(h => h.StartTime).Select(h => (h.IndexInCurrentCombo + 1).ToString())); + => string.Join(',', EditorBeatmap.SelectedHitObjects.Cast().OrderBy(h => h.StartTime) + .Select(h => (h.IndexInCurrentCombo + 1).ToString(CultureInfo.InvariantCulture))); // 1,2,3,4 ... private static readonly Regex selection_regex = new Regex(@"^\d+(,\d+)*$", RegexOptions.Compiled); diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneOpenEditorTimestampInMania.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneOpenEditorTimestampInMania.cs index 05c881d284e9..ad41ad9be470 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneOpenEditorTimestampInMania.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneOpenEditorTimestampInMania.cs @@ -18,15 +18,11 @@ public partial class TestSceneOpenEditorTimestampInMania : EditorTestScene public void TestNormalSelection() { addStepClickLink("00:05:920 (5920|3,6623|3,6857|2,7326|1)"); - AddAssert("selected group", () => checkSnapAndSelectColumn(5_920, new List<(int, int)> - { (5_920, 3), (6_623, 3), (6_857, 2), (7_326, 1) } - )); + AddAssert("selected group", () => checkSnapAndSelectColumn(5_920, [(5_920, 3), (6_623, 3), (6_857, 2), (7_326, 1)])); addReset(); addStepClickLink("00:42:716 (42716|3,43420|2,44123|0,44357|1,45295|1)"); - AddAssert("selected ungrouped", () => checkSnapAndSelectColumn(42_716, new List<(int, int)> - { (42_716, 3), (43_420, 2), (44_123, 0), (44_357, 1), (45_295, 1) } - )); + AddAssert("selected ungrouped", () => checkSnapAndSelectColumn(42_716, [(42_716, 3), (43_420, 2), (44_123, 0), (44_357, 1), (45_295, 1)])); addReset(); AddStep("add notes to row", () => @@ -41,15 +37,20 @@ public void TestNormalSelection() EditorBeatmap.AddRange(new[] { second, third, forth }); }); addStepClickLink("00:11:545 (11545|0,11545|1,11545|2,11545|3)"); - AddAssert("selected in row", () => checkSnapAndSelectColumn(11_545, new List<(int, int)> - { (11_545, 0), (11_545, 1), (11_545, 2), (11_545, 3) } - )); + AddAssert("selected in row", () => checkSnapAndSelectColumn(11_545, [(11_545, 0), (11_545, 1), (11_545, 2), (11_545, 3)])); addReset(); addStepClickLink("01:36:623 (96623|1,97560|1,97677|1,97795|1,98966|1)"); - AddAssert("selected in column", () => checkSnapAndSelectColumn(96_623, new List<(int, int)> - { (96_623, 1), (97_560, 1), (97_677, 1), (97_795, 1), (98_966, 1) } - )); + AddAssert("selected in column", () => checkSnapAndSelectColumn(96_623, [(96_623, 1), (97_560, 1), (97_677, 1), (97_795, 1), (98_966, 1)])); + } + + [Test] + public void TestRoundingToNearestMillisecondApplied() + { + AddStep("resnap note to have fractional coordinates", + () => EditorBeatmap.HitObjects.OfType().Single(ho => ho.StartTime == 85_373 && ho.Column == 1).StartTime = 85_373.125); + addStepClickLink("01:25:373 (85373|1)"); + AddAssert("selected note", () => checkSnapAndSelectColumn(85_373.125, [(85_373.125, 1)])); } [Test] @@ -75,7 +76,7 @@ private void addStepClickLink(string timestamp, string step = "", bool displayTi private void addReset() => addStepClickLink("00:00:000", "reset", false); - private bool checkSnapAndSelectColumn(double startTime, IReadOnlyCollection<(int, int)>? columnPairs = null) + private bool checkSnapAndSelectColumn(double startTime, IReadOnlyCollection<(double, int)>? columnPairs = null) { bool checkColumns = columnPairs != null ? EditorBeatmap.SelectedHitObjects.All(x => columnPairs.Any(col => isNoteAt(x, col.Item1, col.Item2))) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index bc20456722b4..7da501063dfe 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -1,10 +1,12 @@ // 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.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using osu.Framework.Allocation; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; @@ -54,7 +56,8 @@ protected override ComposeBlueprintContainer CreateBlueprintContainer() }; public override string ConvertSelectionToString() - => string.Join(',', EditorBeatmap.SelectedHitObjects.Cast().OrderBy(h => h.StartTime).Select(h => $"{h.StartTime}|{h.Column}")); + => string.Join(',', EditorBeatmap.SelectedHitObjects.Cast().OrderBy(h => h.StartTime) + .Select(h => FormattableString.Invariant($"{Math.Round(h.StartTime)}|{h.Column}"))); // 123|0,456|1,789|2 ... private static readonly Regex selection_regex = new Regex(@"^\d+\|\d+(,\d+\|\d+)*$", RegexOptions.Compiled); @@ -73,10 +76,10 @@ public override void SelectFromTimestamp(double timestamp, string objectDescript if (split.Length != 2) continue; - if (!double.TryParse(split[0], out double time) || !int.TryParse(split[1], out int column)) + if (!int.TryParse(split[0], out int time) || !int.TryParse(split[1], out int column)) continue; - ManiaHitObject? current = remainingHitObjects.FirstOrDefault(h => h.StartTime == time && h.Column == column); + ManiaHitObject? current = remainingHitObjects.FirstOrDefault(h => Precision.AlmostEquals(h.StartTime, time, 0.5) && h.Column == column); if (current == null) continue; diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 0dac4cb2dfeb..6ff762b82f06 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using JetBrains.Annotations; @@ -171,7 +172,8 @@ protected override ComposeBlueprintContainer CreateBlueprintContainer() => new OsuBlueprintContainer(this); public override string ConvertSelectionToString() - => string.Join(',', selectedHitObjects.Cast().OrderBy(h => h.StartTime).Select(h => (h.IndexInCurrentCombo + 1).ToString())); + => string.Join(',', selectedHitObjects.Cast().OrderBy(h => h.StartTime) + .Select(h => (h.IndexInCurrentCombo + 1).ToString(CultureInfo.InvariantCulture))); // 1,2,3,4 ... private static readonly Regex selection_regex = new Regex(@"^\d+(,\d+)*$", RegexOptions.Compiled); From 8f927ea7b5eeb70686e14c5332205c81d050a92b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 28 Nov 2025 00:25:47 +0100 Subject: [PATCH 195/836] Fix `Beatmap.GetMostCommonBeatLength()` potentially returning a beat length smaller or larger than the actual limits (#35827) Closes https://github.com/ppy/osu/issues/35807. The reason this closes the aforementioned issue is as follows: Taking https://osu.ppy.sh/beatmapsets/1236180#osu/4650477 as the example, we have: ``` minBeatLength = 342.857142857143 maxBeatLength = 419.58041958042003 mostCommonBeatLength = 342.85700000000003 ``` Note that `mostCommonBeatLength < minBeatLength` here. Taking the inverse of that to compute BPM, we get ``` minBpm = 174.99999999999991 maxBpm = 142.99999999999986 mostCommonBpm = 175.00007291669704 ``` which without DT present doesn't do anything bad, but when DT is engaged (and thus BPM is multiplied by 1.5), midpoint rounding causes the min BPM to become 262, and the most common BPM to become 263. --- osu.Game/Beatmaps/Beatmap.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 155ded5747d7..c728f243684c 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -105,6 +105,7 @@ public double GetMostCommonBeatLength() return (beatLength: t.BeatLength, duration: nextTime - currentTime); }) // Aggregate durations into a set of (beatLength, duration) tuples for each beat length + // Rounding is applied here (to 1e-3 milliseconds) to neutralise potential effects of floating point inaccuracies .GroupBy(t => Math.Round(t.beatLength * 1000) / 1000) .Select(g => (beatLength: g.Key, duration: g.Sum(t => t.duration))) // Get the most common one, or 0 as a suitable default (see handling below) @@ -113,7 +114,12 @@ public double GetMostCommonBeatLength() if (mostCommon.beatLength == 0) return TimingControlPoint.DEFAULT_BEAT_LENGTH; - return mostCommon.beatLength; + // Because of the rounding applied to the beat length above, it is possible for the "most common" beat length as determined by the linq query above + // to actually be less or more than the raw range of unrounded beat lengths present in the map + // To ensure this does not become a problem anywhere else further, clamp the result to the known raw range + double minBeatLength = ControlPointInfo.TimingPoints.Min(t => t.BeatLength); + double maxBeatLength = ControlPointInfo.TimingPoints.Max(t => t.BeatLength); + return Math.Clamp(mostCommon.beatLength, minBeatLength, maxBeatLength); } public double AudioLeadIn { get; set; } From c6eba26a67732fdeb579eacb4d083cd7d4958a90 Mon Sep 17 00:00:00 2001 From: Hivie Date: Fri, 28 Nov 2025 01:40:07 +0100 Subject: [PATCH 196/836] trim timestamp when pasting into `TimeInfoContainer` --- osu.Game/Screens/Edit/Components/TimeInfoContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs index d17f9011f4e1..7de94cd22e80 100644 --- a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs +++ b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs @@ -151,7 +151,7 @@ private void load() }); }; - inputTextBox.Current.BindValueChanged(val => editor?.HandleTimestamp(val.NewValue)); + inputTextBox.Current.BindValueChanged(val => editor?.HandleTimestamp(val.NewValue.Trim())); inputTextBox.OnCommit += (_, __) => { From 92e9a367448c5740ed4fcb69602898ebcea129a5 Mon Sep 17 00:00:00 2001 From: Vanni <103026931+imvanni@users.noreply.github.com> Date: Fri, 28 Nov 2025 03:25:43 +0100 Subject: [PATCH 197/836] Force exit to menu on quick play disonnection (#35793) --- .../Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs index e3319d4c9405..753b8a90aa29 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs @@ -192,6 +192,7 @@ private void onRoomUpdated() if (this.IsCurrentScreen() && client.Room == null) { Logger.Log($"{this} exiting due to loss of room or connection"); + exitConfirmed = true; this.Exit(); } } From 0b4f96efc82994773f19383aee5f0758b2e85835 Mon Sep 17 00:00:00 2001 From: SollyBunny Date: Sat, 29 Nov 2025 03:21:19 +0000 Subject: [PATCH 198/836] Make tracked leaderboard score yellow again --- .../Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs index df81afed5b8a..ef27d027c201 100644 --- a/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs @@ -357,7 +357,7 @@ private void updatePanelState() else if (Tracked) { widthExtension = true; - setTrackedPanelColour(BackgroundColour); + setPanelColour(BackgroundColour ?? colours.Orange2); } else if (isFriend) { @@ -380,13 +380,6 @@ private void setPanelColour(Color4 baseColour) scorePanel.BorderColour = ColourInfo.GradientVertical(baseColour.Opacity(0.2f), baseColour); } - private void setTrackedPanelColour(Color4? backgroundColour) - { - leftLayerGradient.Colour = ColourInfo.GradientVertical((backgroundColour ?? colours.Blue2).Opacity(0.3f), backgroundColour ?? colours.Blue2); - rightLayerGradient.Colour = ColourInfo.GradientVertical((backgroundColour ?? colours.Blue4).Opacity(0.25f), (backgroundColour ?? colours.Blue3).Opacity(0.6f)); - scorePanel.BorderColour = ColourInfo.GradientVertical((backgroundColour ?? colours.Blue1).Opacity(0.2f), backgroundColour ?? colours.Blue1); - } - protected override void Update() { base.Update(); From 1b230b3fdd0eb984768618c2e79956f094c797ab Mon Sep 17 00:00:00 2001 From: Givy120 <89256026+Givikap120@users.noreply.github.com> Date: Sat, 29 Nov 2025 21:01:15 +0200 Subject: [PATCH 199/836] Remove drain rate attribute (#35817) --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs | 6 ------ osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 3 --- .../Difficulty/OsuPerformanceCalculator.cs | 5 ++++- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 9cab45414266..be5e0385ee1f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -84,11 +84,6 @@ public class OsuDifficultyAttributes : DifficultyAttributes [JsonProperty("maximum_legacy_combo_score")] public double MaximumLegacyComboScore { get; set; } - /// - /// The beatmap's drain rate. This doesn't scale with rate-adjusting mods. - /// - public double DrainRate { get; set; } - /// /// The number of hitcircles in the beatmap. /// @@ -147,7 +142,6 @@ public override void FromDatabaseAttributes(IReadOnlyDictionary val NestedScorePerObject = values[ATTRIB_ID_NESTED_SCORE_PER_OBJECT]; LegacyScoreBaseMultiplier = values[ATTRIB_ID_LEGACY_SCORE_BASE_MULTIPLIER]; MaximumLegacyComboScore = values[ATTRIB_ID_MAXIMUM_LEGACY_COMBO_SCORE]; - DrainRate = onlineInfo.DrainRate; HitCircleCount = onlineInfo.CircleCount; SliderCount = onlineInfo.SliderCount; SpinnerCount = onlineInfo.SpinnerCount; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index d7fa159d10cc..8c78008bcb02 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -80,8 +80,6 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat int totalHits = beatmap.HitObjects.Count; - double drainRate = beatmap.Difficulty.DrainRate; - double aimDifficultyValue = aim.DifficultyValue(); double aimNoSlidersDifficultyValue = aimWithoutSliders.DifficultyValue(); double speedDifficultyValue = speed.DifficultyValue(); @@ -132,7 +130,6 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat SpeedDifficultStrainCount = speedDifficultStrainCount, AimTopWeightedSliderFactor = aimTopWeightedSliderFactor, SpeedTopWeightedSliderFactor = speedTopWeightedSliderFactor, - DrainRate = drainRate, MaxCombo = beatmap.GetMaxCombo(), HitCircleCount = hitCircleCount, SliderCount = sliderCount, diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 741ddb3d4fdd..b2ffc5aa0eab 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -50,8 +50,10 @@ public class OsuPerformanceCalculator : PerformanceCalculator private double greatHitWindow; private double okHitWindow; private double mehHitWindow; + private double overallDifficulty; private double approachRate; + private double drainRate; private double? speedDeviation; @@ -95,6 +97,7 @@ protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo s approachRate = OsuDifficultyCalculator.CalculateRateAdjustedApproachRate(difficulty.ApproachRate, clockRate); overallDifficulty = OsuDifficultyCalculator.CalculateRateAdjustedOverallDifficulty(difficulty.OverallDifficulty, clockRate); + drainRate = difficulty.DrainRate; double comboBasedEstimatedMissCount = calculateComboBasedEstimatedMissCount(osuAttributes); double? scoreBasedEstimatedMissCount = null; @@ -211,7 +214,7 @@ private double computeAimValue(ScoreInfo score, OsuDifficultyAttributes attribut // TC bonuses are excluded when blinds is present as the increased visual difficulty is unimportant when notes cannot be seen. if (score.Mods.Any(m => m is OsuModBlinds)) - aimValue *= 1.3 + (totalHits * (0.0016 / (1 + 2 * effectiveMissCount)) * Math.Pow(accuracy, 16)) * (1 - 0.003 * attributes.DrainRate * attributes.DrainRate); + aimValue *= 1.3 + (totalHits * (0.0016 / (1 + 2 * effectiveMissCount)) * Math.Pow(accuracy, 16)) * (1 - 0.003 * drainRate * drainRate); else if (score.Mods.Any(m => m is OsuModTraceable)) { aimValue *= 1.0 + OsuRatingCalculator.CalculateVisibilityBonus(score.Mods, approachRate, sliderFactor: attributes.SliderFactor); From 82f4406c7972e7de01b06ea89a91034da02838ef Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Sun, 30 Nov 2025 05:14:02 -0500 Subject: [PATCH 200/836] Allow resizing osu! on iPadOS --- osu.iOS/Info.plist | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.iOS/Info.plist b/osu.iOS/Info.plist index 120e8caecc63..e00294917791 100644 --- a/osu.iOS/Info.plist +++ b/osu.iOS/Info.plist @@ -25,8 +25,6 @@ armv7 - UIRequiresFullScreen - UIStatusBarHidden UIApplicationSupportsIndirectInputEvents From fe5cbc493237fb7152d15b599024ed02f435a066 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 4 Dec 2025 14:20:04 +0900 Subject: [PATCH 201/836] Add remaining two locus winners as bundled beatmaps --- osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs b/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs index 96838bb1ba8b..b61b2358b09b 100644 --- a/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs +++ b/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs @@ -192,6 +192,8 @@ public BundledBeatmapDownloadRequest(IBeatmapSetInfo beatmapSetInfo, bool minimi "2412260 Koto Spirit - Locus of Hexagram.osz", "2412232 Will Stetson - Of Our Time.osz", "2412292 ArXe - Locus Amoenus (feat. Megurine Luka).osz", + "2412328 Akiri - Vespera Stella.osz", + "2412331 takehirotei - Haiboku no Altra Vita.osz", }; private static readonly string[] bundled_osu = From ca8247c667c12364bd73066d942fca79f01d06d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 4 Dec 2025 10:43:18 +0100 Subject: [PATCH 202/836] Fix welcome intro skin not being looked up from user skin for supporters Closes https://github.com/ppy/osu/issues/35833. --- osu.Game/Skinning/LegacySkin.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 11b3b5c71d1c..6ff569869af6 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -540,6 +540,10 @@ protected override void ParseConfigurationStream(Stream stream) case "Menu/fountain-star": componentName = "star2"; break; + + case @"Intro/Welcome/welcome_text": + componentName = @"welcome_text"; + break; } Texture? texture = null; From 043a1c27935510eab8e8c9e7d5950e7a0e01f13e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 4 Dec 2025 11:17:44 +0100 Subject: [PATCH 203/836] Disable quick retry binding in solo spectator (#35873) Closes https://github.com/ppy/osu/issues/35870? For some definition of "closes", I guess? Why would you ever do this, unless on purpose just to break stuff? Don't answer that. A side effect of setting this flag is that the hold-to-exit menu button that's there on devices that support touch will slightly change behaviour to the behaviour multiplayer play has: https://github.com/ppy/osu/blob/e3ea38a366601df01f045f4f111765c34d041145/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs#L67 https://github.com/ppy/osu/blob/8d9245c1d4f72db4307da7492d65bd09fc48bc02/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs#L79-L82 but upon thinking about it for three minutes I decided I don't care and it's probably fine because all of this was already racking up to fifteen minutes that I shouldn't have had to spend on any of this. Notably this shouldn't affect the actual spectated user retrying, because all of that is handled elsewhere via https://github.com/ppy/osu/blob/2f90bb4d6793475835d1d51bef92b2c40f69112c/osu.Game/Screens/Spectate/SpectatorScreen.cs#L138-L154 --- osu.Game/Screens/Play/SoloSpectatorPlayer.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs index 16b1ff7ccc9c..d635fa9fe989 100644 --- a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs @@ -21,7 +21,12 @@ public partial class SoloSpectatorPlayer : SpectatorPlayer protected override UserActivity InitialActivity => new UserActivity.SpectatingUser(Score.ScoreInfo); public SoloSpectatorPlayer(Score score) - : base(score, new PlayerConfiguration { AllowUserInteraction = false, ShowLeaderboard = true }) + : base(score, new PlayerConfiguration + { + AllowUserInteraction = false, + ShowLeaderboard = true, + AllowRestart = false + }) { this.score = score; } From 0b3ec3f1e1982a77355c69298e5a292c9f24ece2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 4 Dec 2025 11:23:32 +0100 Subject: [PATCH 204/836] Fix changing beatmap during hold-to-reveal-background delay turning off blur (#35867) Closes https://github.com/ppy/osu/issues/35864. --- osu.Game/Screens/SelectV2/SongSelect.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index 1b66bd560094..ab3375e23e25 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -811,7 +811,8 @@ private void updateBackgroundDim() => ApplyToBackground(backgroundModeBeatmap => // Probably needs more thought because this needs to be in every `ApplyToBackground` currently to restore sane defaults. backgroundModeBeatmap.FadeColour(Color4.White, 250); - backgroundModeBeatmap.BlurAmount.Value = revealingBackground == null && configBackgroundBlur.Value ? 20 : 0f; + bool backgroundRevealActive = revealingBackground?.State == ScheduledDelegate.RunState.Running || revealingBackground?.State == ScheduledDelegate.RunState.Complete; + backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value && !backgroundRevealActive ? 20 : 0f; }); #endregion From 3e4c038a376bc8998c17baed66fd5ad6cc8029a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 4 Dec 2025 11:58:27 +0100 Subject: [PATCH 205/836] Do not distinguish between left/right modifiers when assigning new key combinations Addresses https://github.com/ppy/osu/discussions/35851. And no I'm not making it "you have to press both modifiers for it to become any of the two" because that's ultra weird. --- .../Sections/Input/KeyBindingRow.KeyButton.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.KeyButton.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.KeyButton.cs index adf05a71b9b5..2eb900207a11 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.KeyButton.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.KeyButton.cs @@ -5,6 +5,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -139,9 +140,14 @@ private void updateHoverState() /// /// A generated from the full input state. /// The key which triggered this update, and should be used as the binding. - public void UpdateKeyCombination(KeyCombination fullState, InputKey triggerKey) => - // TODO: Distinct() can be removed after https://github.com/ppy/osu-framework/pull/6130 is merged. - UpdateKeyCombination(new KeyCombination(fullState.Keys.Where(KeyCombination.IsModifierKey).Append(triggerKey).Distinct().ToArray())); + public void UpdateKeyCombination(KeyCombination fullState, InputKey triggerKey) + { + var combination = fullState.Keys.Where(KeyCombination.IsModifierKey) + .Append(triggerKey) + .Select(k => k.GetVirtualKey() ?? k) + .ToArray(); + UpdateKeyCombination(new KeyCombination(combination)); + } public void UpdateKeyCombination(KeyCombination newCombination) { From 12170df80add87e8f292545f67566f8d25465efc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 4 Dec 2025 14:15:52 +0100 Subject: [PATCH 206/836] Disallow placing hit objects before first timing point Because they can break stable. See https://github.com/ppy/osu/issues/31591#issuecomment-3575270120 for detailed rationale. --- .../Edit/Blueprints/BananaShowerPlacementBlueprint.cs | 2 +- .../Edit/Blueprints/JuiceStreamPlacementBlueprint.cs | 2 +- .../Edit/Blueprints/HoldNotePlacementBlueprint.cs | 2 +- .../Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs | 2 +- .../Edit/Blueprints/TaikoSpanPlacementBlueprint.cs | 2 +- osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs | 2 ++ 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs index 971c98cafd69..bb71da12ce82 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs @@ -19,7 +19,7 @@ public partial class BananaShowerPlacementBlueprint : CatchPlacementBlueprint Precision.DefinitelyBigger(HitObject.Duration, 0); + protected override bool IsValidForPlacement => base.IsValidForPlacement && Precision.DefinitelyBigger(HitObject.Duration, 0); public BananaShowerPlacementBlueprint() { diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs index 292175353a33..650bdf79949c 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs @@ -25,7 +25,7 @@ public partial class JuiceStreamPlacementBlueprint : CatchPlacementBlueprint Precision.DefinitelyBigger(HitObject.Duration, 0); + protected override bool IsValidForPlacement => base.IsValidForPlacement && Precision.DefinitelyBigger(HitObject.Duration, 0); public JuiceStreamPlacementBlueprint() { diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs index 094c59da4637..85496b42b406 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs @@ -26,7 +26,7 @@ public partial class HoldNotePlacementBlueprint : ManiaPlacementBlueprint Precision.DefinitelyBigger(HitObject.Duration, 0); + protected override bool IsValidForPlacement => base.IsValidForPlacement && Precision.DefinitelyBigger(HitObject.Duration, 0); public HoldNotePlacementBlueprint() : base(new HoldNote()) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index d934eb5a9e9f..ed0df96a2755 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -58,7 +58,7 @@ public partial class SliderPlacementBlueprint : HitObjectPlacementBlueprint private readonly IncrementalBSplineBuilder bSplineBuilder = new IncrementalBSplineBuilder { Degree = 4 }; - protected override bool IsValidForPlacement => HitObject.Path.HasValidLengthForPlacement; + protected override bool IsValidForPlacement => base.IsValidForPlacement && HitObject.Path.HasValidLengthForPlacement; public SliderPlacementBlueprint() : base(new Slider()) diff --git a/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs b/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs index 3d5c95e1e8b6..291dd3bdf1ef 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs @@ -28,7 +28,7 @@ public partial class TaikoSpanPlacementBlueprint : HitObjectPlacementBlueprint [Resolved] private TaikoHitObjectComposer? composer { get; set; } - protected override bool IsValidForPlacement => Precision.DefinitelyBigger(spanPlacementObject.Duration, 0); + protected override bool IsValidForPlacement => base.IsValidForPlacement && Precision.DefinitelyBigger(spanPlacementObject.Duration, 0); public TaikoSpanPlacementBlueprint(HitObject hitObject) : base(hitObject) diff --git a/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs b/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs index 6720540ec22d..7e9ece559168 100644 --- a/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs @@ -47,6 +47,8 @@ public abstract partial class HitObjectPlacementBlueprint : PlacementBlueprint private HitObject? getPreviousHitObject() => beatmap.HitObjects.TakeWhile(h => h.StartTime <= startTimeBindable.Value).LastOrDefault(); + protected override bool IsValidForPlacement => HitObject.StartTime >= beatmap.ControlPointInfo.TimingPoints[0].Time; + [Resolved] private IPlacementHandler placementHandler { get; set; } = null!; From c6cc92315c82454dc3b3ae70c28f1783a7ef359f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 4 Dec 2025 14:30:18 +0100 Subject: [PATCH 207/836] Add basic colour indication as to when placements are valid Unsure about this one, but I find the preceding commit to be very lacking in explaining to the user why the editor don't work. Shining some things red may help aid understanding. --- .../Edit/Blueprints/BananaShowerPlacementBlueprint.cs | 2 +- .../Edit/Blueprints/JuiceStreamPlacementBlueprint.cs | 2 +- .../Edit/Blueprints/HoldNotePlacementBlueprint.cs | 2 +- .../Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs | 2 +- .../Edit/Blueprints/TaikoSpanPlacementBlueprint.cs | 2 +- osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs | 8 ++++++++ 6 files changed, 13 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs index bb71da12ce82..bd5886cb8289 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs @@ -19,7 +19,7 @@ public partial class BananaShowerPlacementBlueprint : CatchPlacementBlueprint base.IsValidForPlacement && Precision.DefinitelyBigger(HitObject.Duration, 0); + protected override bool IsValidForPlacement => base.IsValidForPlacement && (PlacementActive == PlacementState.Waiting || Precision.DefinitelyBigger(HitObject.Duration, 0)); public BananaShowerPlacementBlueprint() { diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs index 650bdf79949c..cce3b93d902d 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs @@ -25,7 +25,7 @@ public partial class JuiceStreamPlacementBlueprint : CatchPlacementBlueprint base.IsValidForPlacement && Precision.DefinitelyBigger(HitObject.Duration, 0); + protected override bool IsValidForPlacement => base.IsValidForPlacement && (PlacementActive == PlacementState.Waiting || Precision.DefinitelyBigger(HitObject.Duration, 0)); public JuiceStreamPlacementBlueprint() { diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs index 85496b42b406..2674ab4d7502 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs @@ -26,7 +26,7 @@ public partial class HoldNotePlacementBlueprint : ManiaPlacementBlueprint base.IsValidForPlacement && Precision.DefinitelyBigger(HitObject.Duration, 0); + protected override bool IsValidForPlacement => base.IsValidForPlacement && (PlacementActive == PlacementState.Waiting || Precision.DefinitelyBigger(HitObject.Duration, 0)); public HoldNotePlacementBlueprint() : base(new HoldNote()) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index ed0df96a2755..b5b4c8c87d5c 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -58,7 +58,7 @@ public partial class SliderPlacementBlueprint : HitObjectPlacementBlueprint private readonly IncrementalBSplineBuilder bSplineBuilder = new IncrementalBSplineBuilder { Degree = 4 }; - protected override bool IsValidForPlacement => base.IsValidForPlacement && HitObject.Path.HasValidLengthForPlacement; + protected override bool IsValidForPlacement => base.IsValidForPlacement && (PlacementActive == PlacementState.Waiting || HitObject.Path.HasValidLengthForPlacement); public SliderPlacementBlueprint() : base(new Slider()) diff --git a/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs b/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs index 291dd3bdf1ef..6073dc791204 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs @@ -28,7 +28,7 @@ public partial class TaikoSpanPlacementBlueprint : HitObjectPlacementBlueprint [Resolved] private TaikoHitObjectComposer? composer { get; set; } - protected override bool IsValidForPlacement => base.IsValidForPlacement && Precision.DefinitelyBigger(spanPlacementObject.Duration, 0); + protected override bool IsValidForPlacement => base.IsValidForPlacement && (PlacementActive == PlacementState.Waiting || Precision.DefinitelyBigger(spanPlacementObject.Duration, 0)); public TaikoSpanPlacementBlueprint(HitObject hitObject) : base(hitObject) diff --git a/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs b/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs index 7e9ece559168..ea5f69be7b1a 100644 --- a/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs @@ -5,6 +5,7 @@ using System.Threading; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -89,6 +90,13 @@ public override void EndPlacement(bool commit) placementHandler.HidePlacement(); } + protected override void Update() + { + base.Update(); + + Colour = IsValidForPlacement ? Colour4.White : Colour4.Red; + } + /// /// Updates the time and position of this . /// From 1c33291b3f041fabc5faf342bcf2b57e7bee042c Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 4 Dec 2025 13:38:28 -0500 Subject: [PATCH 208/836] Adjust skip button colour and add triangles --- osu.Game/Screens/Play/SkipOverlay.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 700ea2e532b1..1d7961093ad5 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -93,7 +93,7 @@ private void load(OsuColour colours) Height = 5, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - Colour = colours.Yellow, + Colour = colours.Orange3, RelativeSizeAxes = Axes.X } } @@ -328,8 +328,8 @@ public Button() [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audio) { - colourNormal = colours.Yellow; - colourHover = colours.YellowDark; + colourNormal = colours.Orange3; + colourHover = colours.Orange4; sampleConfirm = audio.Samples.Get(@"UI/submit-select"); @@ -356,6 +356,11 @@ private void load(OsuColour colours, AudioManager audio) RelativeSizeAxes = Axes.Both, Colour = colourNormal, }, + new TrianglesV2 + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(colourNormal.Lighten(0.2f), colourNormal) + }, flow = new FillFlowContainer { Anchor = Anchor.TopCentre, From 99da986e0265379c6ba050c0da9f9b74bd8a62c5 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 4 Dec 2025 13:00:47 -0500 Subject: [PATCH 209/836] Implement redesigned multiplayer vote-to-skip button --- .../Multiplayer/MultiplayerSkipOverlay.cs | 297 ++++++++++++++---- osu.Game/Screens/Play/SkipOverlay.cs | 31 +- 2 files changed, 255 insertions(+), 73 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs index 79fd0eb8d127..5c2cc25157d3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs @@ -4,15 +4,24 @@ using System; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Play; +using osu.Game.Screens.Ranking; using osuTK; using osuTK.Graphics; @@ -23,92 +32,49 @@ public partial class MultiplayerSkipOverlay : SkipOverlay [Resolved] private MultiplayerClient client { get; set; } = null!; - private Drawable votedIcon = null!; - private OsuSpriteText countText = null!; + [Resolved] + private OsuColour colours { get; set; } = null!; + + private Button skipButton = null!; public MultiplayerSkipOverlay(double startTime) : base(startTime) { } - [BackgroundDependencyLoader] - private void load() + protected override OsuClickableContainer CreateButton() => skipButton = new Button { - FadingContent.AddRange( - [ - votedIcon = new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Position = new Vector2(50, 0), - Size = new Vector2(20), - Alpha = 0, - Masking = true, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Green - }, - new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Scale = new Vector2(0.5f), - Icon = FontAwesome.Solid.Check - } - } - }, - countText = new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.Centre, - RelativePositionAxes = Axes.X, - Position = new Vector2(0.75f, 0), - Font = OsuFont.Default.With(size: 36, weight: FontWeight.Bold) - } - ]); - } + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; protected override void LoadComplete() { base.LoadComplete(); + skipButton.Enabled.BindValueChanged(e => + { + RemainingTimeBox.Colour = e.NewValue ? colours.Orange3 : Button.COLOUR_GRAY; + }, true); + client.UserLeft += onUserLeft; client.UserStateChanged += onUserStateChanged; client.UserVotedToSkipIntro += onUserVotedToSkipIntro; - updateText(); + updateCount(); } - private void onUserLeft(MultiplayerRoomUser user) - { - Schedule(updateText); - } + private void onUserLeft(MultiplayerRoomUser user) => Schedule(updateCount); - private void onUserStateChanged(MultiplayerRoomUser user, MultiplayerUserState state) - { - Schedule(updateText); - } + private void onUserStateChanged(MultiplayerRoomUser user, MultiplayerUserState state) => Schedule(updateCount); private void onUserVotedToSkipIntro(int userId) => Schedule(() => { FadingContent.TriggerShow(); - - updateText(); - - countText.ScaleTo(1.5f).ScaleTo(1, 200, Easing.OutSine); - - if (userId == client.LocalUser?.UserID) - { - votedIcon.ScaleTo(1.5f).ScaleTo(1, 200, Easing.OutSine); - votedIcon.FadeInFromZero(100); - } + updateCount(); }); - private void updateText() + private void updateCount() { if (client.Room == null || client.Room.Settings.AutoSkip) return; @@ -117,7 +83,8 @@ private void updateText() int countSkipped = client.Room.Users.Count(u => u.State == MultiplayerUserState.Playing && u.VotedToSkipIntro); int countRequired = countTotal / 2 + 1; - countText.Text = $"{Math.Min(countRequired, countSkipped)} / {countRequired}"; + skipButton.SkippedCount.Value = Math.Min(countRequired, countSkipped); + skipButton.RequiredCount.Value = countRequired; } protected override void Dispose(bool isDisposing) @@ -131,5 +98,211 @@ protected override void Dispose(bool isDisposing) client.UserVotedToSkipIntro -= onUserVotedToSkipIntro; } } + + public partial class Button : OsuClickableContainer + { + private const float chevron_y = 0.4f; + private const float secondary_y = 0.7f; + + public static readonly Color4 COLOUR_GRAY = OsuColour.Gray(0.4f); + + private Box background = null!; + private Box box = null!; + private TrianglesV2 triangles = null!; + private OsuSpriteText countText = null!; + private OsuSpriteText skipText = null!; + private AspectContainer aspect = null!; + + private FillFlowContainer chevrons = null!; + + private Sample sampleConfirm = null!; + + public readonly BindableInt SkippedCount = new BindableInt(); + public readonly BindableInt RequiredCount = new BindableInt(); + + [Resolved] + private OsuColour colours { get; set; } = null!; + + public Button() + { + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sampleConfirm = audio.Samples.Get(@"UI/submit-select"); + + Children = new Drawable[] + { + background = new Box + { + Alpha = 0.2f, + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + }, + aspect = new AspectContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + Height = 0.6f, + Masking = true, + CornerRadius = 15, + Children = new Drawable[] + { + box = new Box + { + RelativeSizeAxes = Axes.Both, + }, + triangles = new TrianglesV2 + { + RelativeSizeAxes = Axes.Both, + }, + countText = new OsuSpriteText + { + Anchor = Anchor.TopCentre, + RelativePositionAxes = Axes.Y, + Y = 0.35f, + Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 24), + Origin = Anchor.Centre, + }, + chevrons = new FillFlowContainer + { + Anchor = Anchor.TopCentre, + RelativePositionAxes = Axes.Y, + AutoSizeAxes = Axes.Both, + Origin = Anchor.Centre, + Direction = FillDirection.Horizontal, + Children = new[] + { + new SpriteIcon { Size = new Vector2(15), Shadow = true, Icon = FontAwesome.Solid.ChevronRight }, + new SpriteIcon { Size = new Vector2(15), Shadow = true, Icon = FontAwesome.Solid.ChevronRight }, + new SpriteIcon { Size = new Vector2(15), Shadow = true, Icon = FontAwesome.Solid.ChevronRight }, + } + }, + skipText = new OsuSpriteText + { + Anchor = Anchor.TopCentre, + RelativePositionAxes = Axes.Y, + Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 12), + Origin = Anchor.Centre, + Text = @"SKIP", + Y = secondary_y, + }, + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + SkippedCount.BindValueChanged(_ => updateCount()); + RequiredCount.BindValueChanged(_ => updateCount(), true); + Enabled.BindValueChanged(_ => updateColours(), true); + + FinishTransforms(true); + } + + private void updateChevronsSpacing() + { + if (SkippedCount.Value > 0 && RequiredCount.Value > 1) + chevrons.TransformSpacingTo(new Vector2(-5f), 500, Easing.OutQuint); + else + chevrons.TransformSpacingTo(IsHovered ? new Vector2(5f) : new Vector2(0f), 500, Easing.OutQuint); + } + + private void updateCount() + { + if (SkippedCount.Value > 0 && RequiredCount.Value > 1) + { + countText.FadeIn(300, Easing.OutQuint); + countText.Text = $"{SkippedCount.Value} / {RequiredCount.Value}"; + + chevrons.ScaleTo(0.5f, 300, Easing.OutQuint) + .MoveTo(new Vector2(-11, secondary_y), 300, Easing.OutQuint); + + skipText.MoveToX(11f, 300, Easing.OutQuint); + } + else + { + countText.FadeOut(300, Easing.OutQuint); + + chevrons.ScaleTo(1f, 300, Easing.OutQuint) + .MoveTo(new Vector2(0, chevron_y), 300, Easing.OutQuint); + + skipText.MoveToX(0f, 300, Easing.OutQuint); + } + + updateChevronsSpacing(); + updateColours(); + } + + private void updateColours() + { + if (!Enabled.Value) + { + box.FadeColour(COLOUR_GRAY, 500, Easing.OutQuint); + triangles.FadeColour(ColourInfo.GradientVertical(COLOUR_GRAY.Lighten(0.2f), COLOUR_GRAY), 500, Easing.OutQuint); + } + else + { + box.FadeColour(IsHovered ? colours.Orange4 : colours.Orange3, 500, Easing.OutQuint); + triangles.FadeColour(ColourInfo.GradientVertical(colours.Orange3.Lighten(0.2f), colours.Orange3), 500, Easing.OutQuint); + } + } + + protected override bool OnHover(HoverEvent e) + { + if (Enabled.Value) + { + updateChevronsSpacing(); + updateColours(); + background.FadeTo(0.4f, 500, Easing.OutQuint); + } + + return true; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateChevronsSpacing(); + updateColours(); + background.FadeTo(0.2f, 500, Easing.OutQuint); + base.OnHoverLost(e); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (Enabled.Value) + aspect.ScaleTo(0.75f, 2000, Easing.OutQuint); + return base.OnMouseDown(e); + } + + protected override void OnMouseUp(MouseUpEvent e) + { + if (Enabled.Value) + aspect.ScaleTo(1, 1000, Easing.OutElastic); + base.OnMouseUp(e); + } + + protected override bool OnClick(ClickEvent e) + { + if (!Enabled.Value) + return false; + + sampleConfirm.Play(); + + box.FlashColour(Color4.White, 500, Easing.OutQuint); + aspect.ScaleTo(1.2f, 2000, Easing.OutQuint); + + base.OnClick(e); + + Enabled.Value = false; + return true; + } + } } } diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 1d7961093ad5..305117283d41 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -10,7 +10,9 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Audio.Track; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; @@ -19,6 +21,7 @@ using osu.Framework.Utils; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Input.Bindings; @@ -41,9 +44,10 @@ public partial class SkipOverlay : BeatSyncedContainer, IKeyBindingHandler new Button + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + private const double fade_time = 300; private double fadeOutBeginTime => startTime - MasterGameplayClockContainer.MINIMUM_SKIP_TIME; @@ -174,10 +180,13 @@ protected override void Update() double progress = Math.Max(0, 1 - (gameplayClock.CurrentTime - displayTime) / (fadeOutBeginTime - displayTime)); - remainingTimeBox.Width = (float)Interpolation.Lerp(remainingTimeBox.Width, progress, Math.Clamp(Time.Elapsed / 40, 0, 1)); + RemainingTimeBox.Width = (float)Interpolation.Lerp(RemainingTimeBox.Width, progress, Math.Clamp(Time.Elapsed / 40, 0, 1)); isClickable = progress > 0; - button.Enabled.Value = isClickable; + + if (!isClickable) + button.Enabled.Value = false; + buttonContainer.State.Value = isClickable ? Visibility.Visible : Visibility.Hidden; } @@ -220,7 +229,7 @@ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, float progress = (float)(gameplayClock.CurrentTime - displayTime) / (float)(fadeOutBeginTime - displayTime); float newWidth = 1 - Math.Clamp(progress, 0, 1); - remainingTimeBox.ResizeWidthTo(newWidth, timingPoint.BeatLength * 3.5, Easing.OutQuint); + RemainingTimeBox.ResizeWidthTo(newWidth, timingPoint.BeatLength * 3.5, Easing.OutQuint); } public partial class FadeContainer : Container, IStateful From fef8117b5cd5c497d49cc93e99417f6abade30e5 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 4 Dec 2025 13:00:55 -0500 Subject: [PATCH 210/836] Add test coverage for players leaving during intro --- .../TestSceneMultiplayerSkipOverlay.cs | 78 +++++++++++++++++-- 1 file changed, 70 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSkipOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSkipOverlay.cs index 059af2484d8d..c7ce67d16823 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSkipOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSkipOverlay.cs @@ -1,9 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using NUnit.Framework; using osu.Framework.Extensions; using osu.Framework.Graphics; +using osu.Framework.Testing; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets.Osu; @@ -33,6 +35,9 @@ public override void SetUpSteps() Children = new Drawable[] { new MultiplayerSkipOverlay(120000) + { + RequestSkip = () => MultiplayerClient.VoteToSkipIntro().WaitSafely(), + } }, }; @@ -47,26 +52,83 @@ public void TestSkip() { for (int i = 0; i < 4; i++) { - int i2 = i; + int userId = i; - AddStep($"join user {i2}", () => + AddStep($"join user {userId}", () => { MultiplayerClient.AddUser(new APIUser { - Id = i2, - Username = $"User {i2}" + Id = userId, + Username = $"User {userId}" }); - MultiplayerClient.ChangeUserState(i2, MultiplayerUserState.Playing); + MultiplayerClient.ChangeUserState(userId, MultiplayerUserState.Playing); }); } - AddStep("local user votes", () => MultiplayerClient.VoteToSkipIntro().WaitSafely()); + AddStep("user 0 votes", () => MultiplayerClient.UserVoteToSkipIntro(0).WaitSafely()); + AddStep("local user votes", () => this.ChildrenOfType().Single().TriggerClick()); + AddStep("user 1 votes", () => MultiplayerClient.UserVoteToSkipIntro(1).WaitSafely()); + } + [Test] + public void TestLeavingBeforeLocalVote() + { for (int i = 0; i < 4; i++) { - int i2 = i; - AddStep($"user {i2} votes", () => MultiplayerClient.UserVoteToSkipIntro(i2).WaitSafely()); + int userId = i; + + AddStep($"join user {userId}", () => + { + MultiplayerClient.AddUser(new APIUser + { + Id = userId, + Username = $"User {userId}" + }); + + MultiplayerClient.ChangeUserState(userId, MultiplayerUserState.Playing); + }); + } + + AddStep("user 0 votes", () => MultiplayerClient.UserVoteToSkipIntro(0).WaitSafely()); + AddStep("user 1 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 1 })); + AddStep("user 2 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 2 })); + AddStep("user 3 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 3 })); + AddStep("user 0 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 0 })); + } + + [Test] + public void TestLeavingAfterLocalVote() + { + for (int i = 0; i < 4; i++) + { + int userId = i; + + AddStep($"join user {userId}", () => + { + MultiplayerClient.AddUser(new APIUser + { + Id = userId, + Username = $"User {userId}" + }); + + MultiplayerClient.ChangeUserState(userId, MultiplayerUserState.Playing); + }); + } + + AddStep("local user votes", () => this.ChildrenOfType().Single().TriggerClick()); + AddStep("user 0 votes", () => MultiplayerClient.UserVoteToSkipIntro(0).WaitSafely()); + AddStep("user 1 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 1 })); + AddStep("user 2 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 2 })); + AddStep("user 3 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 3 })); + AddStep("user 0 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 0 })); + } + + public partial class TestMultiplayerSkipOverlay : MultiplayerSkipOverlay + { + public TestMultiplayerSkipOverlay() + : base(120000) + { } } } From 2d8b1e71526f471919447a5a51965ecfc9d48da0 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 4 Dec 2025 13:58:41 -0500 Subject: [PATCH 211/836] Make button brighter on hover --- .../Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs | 2 +- osu.Game/Screens/Play/SkipOverlay.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs index 5c2cc25157d3..02f28c2c4592 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs @@ -249,7 +249,7 @@ private void updateColours() } else { - box.FadeColour(IsHovered ? colours.Orange4 : colours.Orange3, 500, Easing.OutQuint); + box.FadeColour(IsHovered ? colours.Orange3.Lighten(0.2f) : colours.Orange3, 500, Easing.OutQuint); triangles.FadeColour(ColourInfo.GradientVertical(colours.Orange3.Lighten(0.2f), colours.Orange3), 500, Easing.OutQuint); } } diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 305117283d41..e17d639a1b7b 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -338,7 +338,7 @@ public Button() private void load(OsuColour colours, AudioManager audio) { colourNormal = colours.Orange3; - colourHover = colours.Orange4; + colourHover = colours.Orange3.Lighten(0.2f); sampleConfirm = audio.Samples.Get(@"UI/submit-select"); From 8a9f60df68d2d32a6b61985af57ee54876a1348c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 5 Dec 2025 16:45:37 +0900 Subject: [PATCH 212/836] Add failing test --- .../Matchmaking/TestSceneBeatmapSelectGrid.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs index 4759275efc1d..79ee4886a9d5 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectGrid.cs @@ -235,6 +235,22 @@ public void TestPanelArrangement(int count) }); } + [Test] + public void TestRollAnimationFinalRandom() + { + AddStep("play animation", () => + { + (long[] candidateItems, _) = pickRandomItems(5); + + candidateItems = candidateItems.Append(-1).ToArray(); + long finalItem = items.First(i => !candidateItems.Contains(i.ID)).ID; + + grid.RollAndDisplayFinalBeatmap(candidateItems, -1, finalItem); + }); + + AddWaitStep("wait for animation", 10); + } + private (long[] candidateItems, long finalItem) pickRandomItems(int count) { long[] candidateItems = items.Select(it => it.ID).ToArray(); From f595a470596adb8e83c97ab74777034d945919b5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 5 Dec 2025 16:50:33 +0900 Subject: [PATCH 213/836] Fix quick play crash when presenting random selection --- .../Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs index 5e8975410fed..a3ee24d479c8 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs @@ -163,7 +163,7 @@ public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long candidateIt this.Delay(ARRANGE_DELAY) .Schedule(() => ArrangeItemsForRollAnimation()) .Delay(arrange_duration) - .Schedule(() => PlayRollAnimation(gameplayItemId, roll_duration)) + .Schedule(() => PlayRollAnimation(candidateItemId, roll_duration)) .Delay(roll_duration + present_beatmap_delay) .Schedule(() => PresentRolledBeatmap(candidateItemId, gameplayItemId)); } From fed9564b4077ef3b5ee43142b8b54f253994a0d7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 5 Dec 2025 17:26:55 +0900 Subject: [PATCH 214/836] Fix "kicked" users not being marked as quit --- .../Screens/OnlinePlay/Matchmaking/Match/PlayerPanelOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanelOverlay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanelOverlay.cs index 4b97400ebe15..ce14d0bb19c0 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanelOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanelOverlay.cs @@ -78,6 +78,7 @@ protected override void LoadComplete() client.MatchRoomStateChanged += onRoomStateChanged; client.UserJoined += onUserJoined; client.UserLeft += onUserLeft; + client.UserKicked += onUserLeft; if (client.Room != null) { @@ -207,6 +208,7 @@ protected override void Dispose(bool isDisposing) client.MatchRoomStateChanged -= onRoomStateChanged; client.UserJoined -= onUserJoined; client.UserLeft -= onUserLeft; + client.UserKicked -= onUserLeft; } } From 66ebce8c120affd2ee54b8c4b8d7e45a2e722b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 4 Dec 2025 15:04:59 +0100 Subject: [PATCH 215/836] Fix failing tests after disallowing object placements before first timing point --- .../Editor/TestSceneNotePlacementBlueprint.cs | 12 ++++++++---- .../Editor/TestSceneSliderDrawing.cs | 8 +++++++- .../Visual/Editing/TestSceneEditorSaving.cs | 2 +- .../Visual/Editing/TestScenePlacementBlueprint.cs | 8 +++++++- .../Visual/Editing/TestSceneTimelineSelection.cs | 10 ++++++++-- osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs | 2 ++ 6 files changed, 33 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNotePlacementBlueprint.cs index 0cb9639cd177..a18b7652337f 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNotePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNotePlacementBlueprint.cs @@ -5,6 +5,7 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Testing; using osu.Game.Rulesets.Edit; @@ -16,6 +17,7 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Screens.Edit; using osu.Game.Tests.Visual; using osuTK.Input; @@ -36,29 +38,31 @@ public void Setup() => Schedule(() => [Test] public void TestPlaceBeforeCurrentTimeDownwards() { + AddStep("seek to 200", () => HitObjectContainer.Dependencies.Get().Seek(200)); AddStep("move mouse before current time", () => { var column = this.ChildrenOfType().Single(); - InputManager.MoveMouseTo(column.ScreenSpacePositionAtTime(-100)); + InputManager.MoveMouseTo(column.ScreenSpacePositionAtTime(100)); }); AddStep("click", () => InputManager.Click(MouseButton.Left)); - AddAssert("note start time < 0", () => getNote().StartTime < 0); + AddAssert("note start time < 200", () => getNote().StartTime < 200); } [Test] public void TestPlaceAfterCurrentTimeDownwards() { + AddStep("seek to 200", () => HitObjectContainer.Dependencies.Get().Seek(200)); AddStep("move mouse after current time", () => { var column = this.ChildrenOfType().Single(); - InputManager.MoveMouseTo(column.ScreenSpacePositionAtTime(100)); + InputManager.MoveMouseTo(column.ScreenSpacePositionAtTime(300)); }); AddStep("click", () => InputManager.Click(MouseButton.Left)); - AddAssert("note start time > 0", () => getNote().StartTime > 0); + AddAssert("note start time > 200", () => getNote().StartTime > 200); } private Note getNote() => this.ChildrenOfType().FirstOrDefault()?.HitObject; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderDrawing.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderDrawing.cs index 0e36c1dc4582..74474c0b6ecd 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderDrawing.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderDrawing.cs @@ -8,6 +8,7 @@ using osu.Framework.Input; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.UI; @@ -22,7 +23,12 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor [TestFixture] public partial class TestSceneSliderDrawing : TestSceneOsuEditor { - protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false); + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) + { + var beatmap = new TestBeatmap(ruleset, false); + beatmap.ControlPointInfo.Add(0, new TimingControlPoint()); + return beatmap; + } [Test] public void TestTouchInputPlaceHitCircleDirectly() diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs index 7f40da5babef..66a039f36e87 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs @@ -134,7 +134,7 @@ public void TestLengthAndStarRatingUpdated() double lastStarRating = 0; double lastLength = 0; - AddStep("Add timing point", () => EditorBeatmap.ControlPointInfo.Add(200, new TimingControlPoint { BeatLength = 600 })); + AddStep("Add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 600 })); AddStep("Change to placement mode", () => InputManager.Key(Key.Number2)); AddStep("Move to playfield", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.Centre)); AddStep("Place single hitcircle", () => InputManager.Click(MouseButton.Left)); diff --git a/osu.Game.Tests/Visual/Editing/TestScenePlacementBlueprint.cs b/osu.Game.Tests/Visual/Editing/TestScenePlacementBlueprint.cs index ae20f5e5cf59..822c04535574 100644 --- a/osu.Game.Tests/Visual/Editing/TestScenePlacementBlueprint.cs +++ b/osu.Game.Tests/Visual/Editing/TestScenePlacementBlueprint.cs @@ -7,6 +7,7 @@ using osu.Framework.Testing; using osu.Game.Audio; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Rulesets; @@ -27,7 +28,12 @@ public partial class TestScenePlacementBlueprint : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); - protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false); + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) + { + var beatmap = new TestBeatmap(ruleset, false); + beatmap.ControlPointInfo.Add(0, new TimingControlPoint()); + return beatmap; + } private GlobalActionContainer globalActionContainer => this.ChildrenOfType().Single(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs index 229cb995d8be..1915c00eb458 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; using osu.Game.Rulesets.Objects; @@ -27,7 +28,12 @@ public partial class TestSceneTimelineSelection : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); - protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false); + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) + { + var beatmap = new TestBeatmap(ruleset, false); + beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 }); + return beatmap; + } private TimelineBlueprintContainer blueprintContainer => Editor.ChildrenOfType().First(); @@ -80,7 +86,7 @@ public void TestContextMenuWithObjectBehind() { InputManager.Key(Key.Number1); blueprint = this.ChildrenOfType().First(); - InputManager.MoveMouseTo(blueprint); + InputManager.MoveMouseTo(blueprint, new Vector2(-1, 0)); InputManager.Click(MouseButton.Left); }); diff --git a/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs b/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs index a644936a169f..b23fda81906c 100644 --- a/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs @@ -10,6 +10,7 @@ using osu.Framework.Input.Events; using osu.Framework.Timing; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; @@ -55,6 +56,7 @@ protected virtual IBeatmap GetPlayableBeatmap() var playable = Beatmap.Value.GetPlayableBeatmap(rulesetInfo); playable.BeatmapInfo.Ruleset = rulesetInfo; playable.Difficulty.CircleSize = 2; + playable.ControlPointInfo.Add(0, new TimingControlPoint()); return playable; } From b1e27d842b99188a6e4337f8c3cc881cc8b96fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 5 Dec 2025 12:34:18 +0100 Subject: [PATCH 216/836] Ensure skip counter doesn't overflow the button --- .../OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs index 02f28c2c4592..9e237483feaf 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs @@ -303,6 +303,13 @@ protected override bool OnClick(ClickEvent e) Enabled.Value = false; return true; } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + countText.Scale = new Vector2(Math.Min(0.85f * aspect.DrawWidth / countText.DrawWidth, 1)); + } } } } From 6343bf7d298887daaedc16cd77c4eae476656a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 5 Dec 2025 12:35:26 +0100 Subject: [PATCH 217/836] Privatise setter --- osu.Game/Screens/Play/SkipOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index e17d639a1b7b..0509c845f876 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -47,7 +47,7 @@ public partial class SkipOverlay : BeatSyncedContainer, IKeyBindingHandler Date: Fri, 5 Dec 2025 20:50:07 +0900 Subject: [PATCH 218/836] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 20c0f7cec573..cf8b91595fd3 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index c2796cf00006..108d5760d50c 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From 8e2230d14912fb9af70d1066213bd44fcf170302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 5 Dec 2025 13:05:51 +0100 Subject: [PATCH 219/836] Add xmldoc to confusing field I don't have any better ideas at this time. --- osu.Game/Screens/Play/SkipOverlay.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 0509c845f876..361de7110326 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -50,7 +50,12 @@ public partial class SkipOverlay : BeatSyncedContainer, IKeyBindingHandler + /// Becomes when the overlay starts fading out. + /// private bool isClickable; + private bool skipQueued; [Resolved] From 1db4b897eb5f94ddae030f9e5ad89ecc90ea6d36 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Dec 2025 21:27:11 +0900 Subject: [PATCH 220/836] Update tests to match new behaviour --- osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 8e671f331dd9..287b678b07de 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -67,7 +67,7 @@ public void TestBindingSingleModifier() scrollToAndStartBinding("Increase volume"); AddStep("press shift", () => InputManager.PressKey(Key.ShiftLeft)); AddStep("release shift", () => InputManager.ReleaseKey(Key.ShiftLeft)); - checkBinding("Increase volume", "LShift"); + checkBinding("Increase volume", "Shift"); } [Test] @@ -77,7 +77,7 @@ public void TestBindingSingleKeyWithModifier() AddStep("press shift", () => InputManager.PressKey(Key.ShiftLeft)); AddStep("press k", () => InputManager.Key(Key.K)); AddStep("release shift", () => InputManager.ReleaseKey(Key.ShiftLeft)); - checkBinding("Increase volume", "LShift-K"); + checkBinding("Increase volume", "Shift-K"); } [Test] From fbac5db964def0b076161f3fe35dc1949ec5b0eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Dec 2025 22:28:55 +0900 Subject: [PATCH 221/836] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index cf8b91595fd3..fe5d204ceb7a 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index 108d5760d50c..58b0aa1c2548 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From d1d76a76ba19eaa8ea1aac6b4a0bebae294f6079 Mon Sep 17 00:00:00 2001 From: Chirag Mahesh Date: Thu, 4 Dec 2025 16:40:58 +0000 Subject: [PATCH 222/836] Refactor trail scale update logic into a dedicated method --- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs | 2 -- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs | 9 +++++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs index 37ceb296b8b5..e84fb9e2d667 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs @@ -36,8 +36,6 @@ public partial class OsuCursor : SkinReloadableDrawable /// public Vector2 CurrentExpandedScale => skinnableCursor.ExpandTarget?.Scale ?? Vector2.One; - public Vector2 CurrentCursorScale => skinnableCursor.Scale; - /// /// The current rotation of the cursor. /// diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index df72f8be97f5..e04382d194d4 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -64,8 +64,14 @@ protected override void LoadComplete() var newScale = new Vector2(e.NewValue); rippleVisualiser.CursorScale = newScale; - if (cursorTrail.Drawable is CursorTrail trail) trail.CursorScale = newScale; + updateTrailScale(); }, true); + cursorTrail.OnSkinChanged += updateTrailScale; + } + + private void updateTrailScale() + { + if (cursorTrail.Drawable is CursorTrail trail) trail.CursorScale = new Vector2(ActiveCursor.CursorScale.Value); } private int downCount; @@ -86,7 +92,6 @@ protected override void Update() { trail.NewPartScale = ActiveCursor.CurrentExpandedScale; trail.PartRotation = ActiveCursor.CurrentRotation; - trail.CursorScale = ActiveCursor.CurrentCursorScale; } } From 107098314a486ce8959020dd822223eab5ed5094 Mon Sep 17 00:00:00 2001 From: Chirag Mahesh Date: Fri, 5 Dec 2025 17:22:10 +0000 Subject: [PATCH 223/836] Move and refactor TestSceneGameplayCursorSizeChange into Ruleset Osu Tests --- .../TestSceneGameplayCursorSizeChange.cs | 52 ++++++++++++ .../TestSceneGameplayCursorSizeChange.cs | 85 ------------------- 2 files changed, 52 insertions(+), 85 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursorSizeChange.cs delete mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneGameplayCursorSizeChange.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursorSizeChange.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursorSizeChange.cs new file mode 100644 index 000000000000..27a83887dd6e --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursorSizeChange.cs @@ -0,0 +1,52 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Testing; +using osu.Game.Configuration; +using osu.Game.Skinning; +using osu.Game.Tests.Visual; +using osuTK.Input; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public partial class TestSceneGameplayCursorSizeChange : PlayerTestScene + { + private const float initial_cursor_size = 1f; + protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); + + [Resolved] + private SkinManager? skins { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + if (skins != null) skins.CurrentSkinInfo.Value = skins.DefaultClassicSkin.SkinInfo; + } + + [SetUpSteps] + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep($"Set gameplay cursor size: 1", () => LocalConfig.SetValue(OsuSetting.GameplayCursorSize, initial_cursor_size)); + AddStep("resume player", () => Player.GameplayClockContainer.Start()); + AddUntilStep("clock running", () => Player.GameplayClockContainer.IsRunning); + } + + [Test] + public void TestPausedChangeCursorSize() + { + AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre)); + AddStep("move cursor to top left", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.TopLeft)); + AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre)); + AddStep("move cursor to top right", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.TopRight)); + AddStep("press escape", () => InputManager.Key(Key.Escape)); + + AddSliderStep("cursor size", 0.1f, 2f, 1f, v => LocalConfig.SetValue(OsuSetting.GameplayCursorSize, v)); + } + + protected override TestPlayer CreatePlayer(Ruleset ruleset) => new TestPlayer(true, false); + } +} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayCursorSizeChange.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayCursorSizeChange.cs deleted file mode 100644 index 22b3a8e3788c..000000000000 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayCursorSizeChange.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Screens; -using osu.Framework.Testing; -using osu.Game.Configuration; -using osu.Game.Rulesets; -using osu.Game.Skinning; -using osuTK.Input; - -namespace osu.Game.Tests.Visual.Gameplay -{ - public partial class TestSceneGameplayCursorSizeChange : OsuPlayerTestScene - { - [Resolved] - private SkinManager? skins { get; set; } - - protected new PausePlayer Player => (PausePlayer)base.Player; - - [BackgroundDependencyLoader] - private void load() - { - if (skins != null) skins.CurrentSkinInfo.Value = skins.DefaultClassicSkin.SkinInfo; - } - - [SetUpSteps] - public override void SetUpSteps() - { - base.SetUpSteps(); - - AddStep("resume player", () => Player.GameplayClockContainer.Start()); - AddUntilStep("clock running", () => Player.GameplayClockContainer.IsRunning); - } - - [Test] - public void TestChangeCursorSize() - { - AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre)); - AddStep("move cursor to top left", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.TopLeft)); - AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre)); - AddStep("move cursor to top right", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.TopRight)); - AddStep("press escape", () => InputManager.Key(Key.Escape)); - - for (float cursorSize = 0.4f; cursorSize <= 1.6f + 0.001f; cursorSize += 0.4f) - { - AddWaitStep("wait 2 seconds", 2); - float newCursorSize = cursorSize; - AddStep($"gameplay cursor size: {newCursorSize:F1}", () => LocalConfig.SetValue(OsuSetting.GameplayCursorSize, newCursorSize)); - } - } - - protected override TestPlayer CreatePlayer(Ruleset ruleset) => new PausePlayer(); - - protected partial class PausePlayer : TestPlayer - { - public double LastPauseTime { get; private set; } - public double LastResumeTime { get; private set; } - - public override void OnEntering(ScreenTransitionEvent e) - { - base.OnEntering(e); - GameplayClockContainer.Stop(); - } - - private bool? isRunning; - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - if (GameplayClockContainer.IsRunning != isRunning) - { - isRunning = GameplayClockContainer.IsRunning; - - if (isRunning.Value) - LastResumeTime = GameplayClockContainer.CurrentTime; - else - LastPauseTime = GameplayClockContainer.CurrentTime; - } - } - } - } -} From d04029bcc7a0616c018ca0cf579866c6e53f48b7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 6 Dec 2025 03:24:17 +0900 Subject: [PATCH 224/836] Fix incorrect quick play download progress --- osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs index 0940fbdabb41..9f3509951692 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs @@ -520,6 +520,9 @@ private void onMatchEvent(MatchServerEvent e) private void onBeatmapAvailabilityChanged(MultiplayerRoomUser user, BeatmapAvailability availability) => Scheduler.Add(() => { + if (!user.Equals(RoomUser)) + return; + if (availability.State == DownloadState.Downloading) downloadProgressBar.FadeIn(200, Easing.OutPow10); else From 35fdc6f8b94784c83cd4d7040193c19810ed84bf Mon Sep 17 00:00:00 2001 From: Natelytle Date: Fri, 5 Dec 2025 22:51:00 -0500 Subject: [PATCH 225/836] Rank swap mod --- osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs index f1feb8153a6b..9af3eedf9343 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs @@ -22,6 +22,7 @@ public class TaikoModSwap : Mod, IApplicableToBeatmap public override ModType Type => ModType.Conversion; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModRandom)).ToArray(); + public override bool Ranked => true; public void ApplyToBeatmap(IBeatmap beatmap) { From 2be50d917ac1fd47f8907a50817a45e13ae7d751 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 6 Dec 2025 13:23:16 +0900 Subject: [PATCH 226/836] Adjust vote-to-skip to be explicit about states --- osu.Game/Online/Multiplayer/IMultiplayerClient.cs | 2 +- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 13 ++++--------- .../Online/Multiplayer/OnlineMultiplayerClient.cs | 2 +- .../Multiplayer/MultiplayerSkipOverlay.cs | 2 +- .../Visual/Multiplayer/TestMultiplayerClient.cs | 2 +- 5 files changed, 8 insertions(+), 13 deletions(-) diff --git a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs index c91128401d0b..c94faf173c82 100644 --- a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs @@ -153,7 +153,7 @@ public interface IMultiplayerClient : IStatefulUserHubClient /// /// Signals that a user has requested to skip the beatmap intro. /// - Task UserVotedToSkipIntro(int userId); + Task UserVotedToSkipIntro(int userId, bool voted); /// /// Signals that the vote to skip the beatmap intro has passed. diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 8a41c11ae6d8..209753ccd37a 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -131,7 +131,7 @@ public abstract partial class MultiplayerClient : Component, IMultiplayerClient, public event Action? MatchmakingItemDeselected; public event Action? MatchRoomStateChanged; - public event Action? UserVotedToSkipIntro; + public event Action? UserVotedToSkipIntro; public event Action? VoteToSkipIntroPassed; public event Action? BeatmapAvailabilityChanged; @@ -854,10 +854,6 @@ Task IMultiplayerClient.GameplayStarted() handleRoomRequest(() => { Debug.Assert(Room != null); - - foreach (var user in Room.Users) - user.VotedToSkipIntro = false; - GameplayStarted?.Invoke(); }); @@ -928,7 +924,7 @@ public Task PlaylistItemChanged(MultiplayerPlaylistItem item) return Task.CompletedTask; } - Task IMultiplayerClient.UserVotedToSkipIntro(int userId) + Task IMultiplayerClient.UserVotedToSkipIntro(int userId, bool voted) { handleRoomRequest(() => { @@ -940,9 +936,8 @@ Task IMultiplayerClient.UserVotedToSkipIntro(int userId) if (user == null) return; - user.VotedToSkipIntro = true; - - UserVotedToSkipIntro?.Invoke(userId); + user.VotedToSkipIntro = voted; + UserVotedToSkipIntro?.Invoke(userId, voted); }); return Task.CompletedTask; diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 1319578c0636..7cfa036dcdd0 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -70,7 +70,7 @@ private void load(IAPIProvider api) connection.On(nameof(IMultiplayerClient.PlaylistItemAdded), ((IMultiplayerClient)this).PlaylistItemAdded); connection.On(nameof(IMultiplayerClient.PlaylistItemRemoved), ((IMultiplayerClient)this).PlaylistItemRemoved); connection.On(nameof(IMultiplayerClient.PlaylistItemChanged), ((IMultiplayerClient)this).PlaylistItemChanged); - connection.On(nameof(IMultiplayerClient.UserVotedToSkipIntro), ((IMultiplayerClient)this).UserVotedToSkipIntro); + connection.On(nameof(IMultiplayerClient.UserVotedToSkipIntro), ((IMultiplayerClient)this).UserVotedToSkipIntro); connection.On(nameof(IMultiplayerClient.VoteToSkipIntroPassed), ((IMultiplayerClient)this).VoteToSkipIntroPassed); connection.On(nameof(IMatchmakingClient.MatchmakingQueueJoined), ((IMatchmakingClient)this).MatchmakingQueueJoined); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs index 9e237483feaf..5a9c31b88923 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs @@ -68,7 +68,7 @@ protected override void LoadComplete() private void onUserStateChanged(MultiplayerRoomUser user, MultiplayerUserState state) => Schedule(updateCount); - private void onUserVotedToSkipIntro(int userId) => Schedule(() => + private void onUserVotedToSkipIntro(int userId, bool voted) => Schedule(() => { FadingContent.TriggerShow(); updateCount(); diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 38070d953ee6..2f8a3dc7a8f0 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -568,7 +568,7 @@ public override Task VoteToSkipIntro() public async Task UserVoteToSkipIntro(int userId) { - await ((IMultiplayerClient)this).UserVotedToSkipIntro(userId).ConfigureAwait(false); + await ((IMultiplayerClient)this).UserVotedToSkipIntro(userId, true).ConfigureAwait(false); } protected override Task CreateRoomInternal(MultiplayerRoom room) From 4ae4c700ae3c1aafa02f1bc00f3a0d539728278c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 6 Dec 2025 17:36:16 +0900 Subject: [PATCH 227/836] Remove quick play round results scroll animation --- .../TestSceneRoundResultsScreen.cs | 14 +++- .../RoundResults/SubScreenRoundResults.cs | 66 ++++++++----------- 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneRoundResultsScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneRoundResultsScreen.cs index ff4e2c1932b1..d1800aca3f7e 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneRoundResultsScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneRoundResultsScreen.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Framework.Utils; @@ -26,8 +27,15 @@ public override void SetUpSteps() AddStep("join room", () => JoinRoom(CreateDefaultRoom(MatchType.Matchmaking))); WaitForJoined(); + } - setupRequestHandler(); + [TestCase(2)] + [TestCase(4)] + [TestCase(8)] + [TestCase(16)] + public void TestDisplayScores(int scoreCount) + { + setupRequestHandler(scoreCount); AddStep("load screen", () => { @@ -40,7 +48,7 @@ public override void SetUpSteps() }); } - private void setupRequestHandler() + private void setupRequestHandler(int scoreCount) { AddStep("setup request handler", () => { @@ -71,7 +79,7 @@ private void setupRequestHandler() case IndexPlaylistScoresRequest index: var result = new IndexedMultiplayerScores(); - for (int i = 0; i < 8; ++i) + for (int i = 0; i < scoreCount; ++i) { result.Scores.Add(new MultiplayerScore { diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs index 580d157a8bad..d363be6cfbf8 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs @@ -31,8 +31,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundResults /// public partial class SubScreenRoundResults : MatchmakingSubScreen { - private const int panel_spacing = 5; - public override PanelDisplayStyle PlayersDisplayStyle => PanelDisplayStyle.Hidden; public override Drawable? PlayersDisplayArea => null; @@ -51,7 +49,7 @@ public partial class SubScreenRoundResults : MatchmakingSubScreen [Resolved] private RulesetStore rulesets { get; set; } = null!; - private AutoScrollContainer scrollContainer = null!; + private PanelContainer panelContainer = null!; private LoadingSpinner loadingSpinner = null!; [BackgroundDependencyLoader] @@ -59,7 +57,7 @@ private void load() { InternalChildren = new Drawable[] { - scrollContainer = new AutoScrollContainer + panelContainer = new PanelContainer { RelativeSizeAxes = Axes.Both }, @@ -136,25 +134,11 @@ private async Task queryScores() private void setScores(ScoreInfo[] scores) => Scheduler.Add(() => { - Container panels; - - scrollContainer.Child = panels = new Container - { - RelativeSizeAxes = Axes.Y, - Width = scores.Length * (ScorePanel.CONTRACTED_WIDTH + panel_spacing), - ChildrenEnumerable = scores.Select(s => new RoundResultsScorePanel(s) - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft - }) - }; - - for (int i = 0; i < panels.Count; i++) + panelContainer.ChildrenEnumerable = scores.Select(s => new RoundResultsScorePanel(s) { - panels[i].MoveToX(panels.DrawWidth * 2) - .Delay(i * 100) - .MoveToX((ScorePanel.CONTRACTED_WIDTH + panel_spacing) * i, 500, Easing.OutQuint); - } + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }); }); private partial class RoundResultsScorePanel : CompositeDrawable @@ -183,31 +167,37 @@ protected override void LoadComplete() } } - private partial class AutoScrollContainer : UserTrackingScrollContainer + private partial class PanelContainer : Container { - private const float initial_offset = -0.5f; - private const double scroll_duration = 20000; + protected override Container Content => flowContainer; - private double? scrollStartTime; + private readonly Container centreingContainer; + private readonly Container flowContainer; - public AutoScrollContainer() - : base(Direction.Horizontal) + public PanelContainer() { + InternalChild = new OsuScrollContainer(Direction.Horizontal) + { + RelativeSizeAxes = Axes.Both, + Child = centreingContainer = new Container + { + RelativeSizeAxes = Axes.Y, + Child = flowContainer = new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Spacing = new Vector2(5) + } + } + }; } protected override void Update() { base.Update(); - - if (!UserScrolling && Children.Count > 0) - { - scrollStartTime ??= Time.Current; - - double scrollOffset = (Time.Current - scrollStartTime.Value) / scroll_duration; - - if (scrollOffset < 1) - ScrollTo(DrawWidth * (initial_offset + scrollOffset), false); - } + centreingContainer.Width = Math.Max(DrawWidth, flowContainer.DrawWidth); } } } From 1c10acba7662b6a64549e5c830d3ac57bac878fa Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 6 Dec 2025 17:40:17 +0900 Subject: [PATCH 228/836] Allow score panel to animate --- .../RoundResults/SubScreenRoundResults.cs | 20 ++++--------------- osu.Game/Screens/Ranking/ScorePanel.cs | 4 ++-- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs index d363be6cfbf8..9dc283780a58 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs @@ -23,6 +23,7 @@ using osu.Game.Rulesets; using osu.Game.Scoring; using osu.Game.Screens.Ranking; +using osuTK; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundResults { @@ -145,26 +146,13 @@ private partial class RoundResultsScorePanel : CompositeDrawable { public RoundResultsScorePanel(ScoreInfo score) { - AutoSizeAxes = Axes.Both; - InternalChild = new InstantSizingScorePanel(score); + Size = new Vector2(ScorePanel.CONTRACTED_WIDTH, ScorePanel.CONTRACTED_HEIGHT); + + InternalChild = new ScorePanel(score); } public override bool PropagateNonPositionalInputSubTree => false; public override bool PropagatePositionalInputSubTree => false; - - private partial class InstantSizingScorePanel : ScorePanel - { - public InstantSizingScorePanel(ScoreInfo score, bool isNewLocalScore = false) - : base(score, isNewLocalScore) - { - } - - protected override void LoadComplete() - { - base.LoadComplete(); - FinishTransforms(true); - } - } } private partial class PanelContainer : Container diff --git a/osu.Game/Screens/Ranking/ScorePanel.cs b/osu.Game/Screens/Ranking/ScorePanel.cs index 85da1afe7b67..72927ee6ebc5 100644 --- a/osu.Game/Screens/Ranking/ScorePanel.cs +++ b/osu.Game/Screens/Ranking/ScorePanel.cs @@ -33,7 +33,7 @@ public partial class ScorePanel : CompositeDrawable, IStateful /// /// Height of the panel when contracted. /// - private const float contracted_height = 385; + public const float CONTRACTED_HEIGHT = 385; /// /// Width of the panel when expanded. @@ -259,7 +259,7 @@ private void updateState() break; case PanelState.Contracted: - Size = new Vector2(CONTRACTED_WIDTH, contracted_height); + Size = new Vector2(CONTRACTED_WIDTH, CONTRACTED_HEIGHT); topLayerBackground.FadeColour(contracted_top_layer_colour, RESIZE_DURATION, Easing.OutQuint); middleLayerBackground.FadeColour(contracted_middle_layer_colour, RESIZE_DURATION, Easing.OutQuint); From a96b024ac5780257f54539fa9a468684771c37bb Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 6 Dec 2025 17:50:43 +0900 Subject: [PATCH 229/836] Make quick play chat retain focus after posting --- .../OnlinePlay/Matchmaking/Match/MatchmakingChatDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingChatDisplay.cs index 6a0164290704..98a08d6b17b8 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingChatDisplay.cs @@ -29,7 +29,7 @@ private void load(RealmKeyBindingStore keyBindingStore) resetPlaceholderText(); TextBox.HoldFocus = false; - TextBox.ReleaseFocusOnCommit = true; + TextBox.ReleaseFocusOnCommit = false; TextBox.Focus = () => TextBox.PlaceholderText = ChatStrings.InputPlaceholder; TextBox.FocusLost = resetPlaceholderText; From a6c001244ff44e140cfd1f5006fd370f4e2a20bd Mon Sep 17 00:00:00 2001 From: Chirag Mahesh Date: Sat, 6 Dec 2025 11:18:18 +0000 Subject: [PATCH 230/836] Redundant string interpolation --- .../TestSceneGameplayCursorSizeChange.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursorSizeChange.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursorSizeChange.cs index 27a83887dd6e..c94e575032bb 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursorSizeChange.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursorSizeChange.cs @@ -30,7 +30,7 @@ public override void SetUpSteps() { base.SetUpSteps(); - AddStep($"Set gameplay cursor size: 1", () => LocalConfig.SetValue(OsuSetting.GameplayCursorSize, initial_cursor_size)); + AddStep("Set gameplay cursor size: 1", () => LocalConfig.SetValue(OsuSetting.GameplayCursorSize, initial_cursor_size)); AddStep("resume player", () => Player.GameplayClockContainer.Start()); AddUntilStep("clock running", () => Player.GameplayClockContainer.IsRunning); } From c23d6b7fd12bdc942408916163b6074e61489151 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sun, 7 Dec 2025 02:11:26 +0900 Subject: [PATCH 231/836] Fix potentially unsafe quick play event handling --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 8a41c11ae6d8..9fca1d57808e 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -1117,7 +1117,7 @@ Task IMatchmakingClient.MatchmakingQueueStatusChanged(MatchmakingQueueStatus sta Task IMatchmakingClient.MatchmakingItemSelected(int userId, long playlistItemId) { - Scheduler.Add(() => + handleRoomRequest(() => { MatchmakingItemSelected?.Invoke(userId, playlistItemId); RoomUpdated?.Invoke(); @@ -1128,7 +1128,7 @@ Task IMatchmakingClient.MatchmakingItemSelected(int userId, long playlistItemId) Task IMatchmakingClient.MatchmakingItemDeselected(int userId, long playlistItemId) { - Scheduler.Add(() => + handleRoomRequest(() => { MatchmakingItemDeselected?.Invoke(userId, playlistItemId); RoomUpdated?.Invoke(); From d6cd748d2ac6723b6653ee103a31060cc6c6f00e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sun, 7 Dec 2025 23:26:40 +0900 Subject: [PATCH 232/836] Consider abandon time for user placements --- .../Matchmaking/MatchmakingRoomStateTest.cs | 29 +++++++++ .../MatchTypes/Matchmaking/MatchmakingUser.cs | 6 ++ .../Matchmaking/MatchmakingUserComparer.cs | 61 +++++++++++-------- 3 files changed, 71 insertions(+), 25 deletions(-) diff --git a/osu.Game.Tests/Online/Matchmaking/MatchmakingRoomStateTest.cs b/osu.Game.Tests/Online/Matchmaking/MatchmakingRoomStateTest.cs index 5f82d22ae836..25766d46458e 100644 --- a/osu.Game.Tests/Online/Matchmaking/MatchmakingRoomStateTest.cs +++ b/osu.Game.Tests/Online/Matchmaking/MatchmakingRoomStateTest.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 NUnit.Framework; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; @@ -149,5 +150,33 @@ public void UserIdTieBreaker() Assert.AreEqual(5, state.Users.GetOrAdd(5).Placement); Assert.AreEqual(6, state.Users.GetOrAdd(6).Placement); } + + [Test] + public void AbandonOrder() + { + var state = new MatchmakingRoomState(); + + state.AdvanceRound(); + state.RecordScores( + [ + new SoloScoreInfo { UserID = 1, TotalScore = 1000 }, + new SoloScoreInfo { UserID = 2, TotalScore = 500 }, + ], placement_points); + + Assert.AreEqual(1, state.Users.GetOrAdd(1).Placement); + Assert.AreEqual(2, state.Users.GetOrAdd(2).Placement); + + state.Users.GetOrAdd(1).AbandonedAt = DateTimeOffset.Now; + state.RecordScores([], placement_points); + + Assert.AreEqual(2, state.Users.GetOrAdd(1).Placement); + Assert.AreEqual(1, state.Users.GetOrAdd(2).Placement); + + state.Users.GetOrAdd(2).AbandonedAt = DateTimeOffset.Now - TimeSpan.FromMinutes(1); + state.RecordScores([], placement_points); + + Assert.AreEqual(1, state.Users.GetOrAdd(1).Placement); + Assert.AreEqual(2, state.Users.GetOrAdd(2).Placement); + } } } diff --git a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingUser.cs b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingUser.cs index ac97b114d807..94062d6024a0 100644 --- a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingUser.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingUser.cs @@ -36,5 +36,11 @@ public class MatchmakingUser /// [Key(3)] public MatchmakingRoundList Rounds { get; set; } = new MatchmakingRoundList(); + + /// + /// The time at which this user abandoned the match. + /// + [Key(4)] + public DateTimeOffset? AbandonedAt { get; set; } } } diff --git a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingUserComparer.cs b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingUserComparer.cs index 74da6a9b2acb..a81c49fe97db 100644 --- a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingUserComparer.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingUserComparer.cs @@ -23,42 +23,53 @@ public override int Compare(MatchmakingUser? x, MatchmakingUser? y) ArgumentNullException.ThrowIfNull(x); ArgumentNullException.ThrowIfNull(y); - // X appears earlier in the list if it has more points. - if (x.Points > y.Points) - return -1; + int compare = compareAbandonedAt(x, y); + if (compare != 0) + return compare; - // Y appears earlier in the list if it has more points. - if (y.Points > x.Points) - return 1; + compare = comparePoints(x, y); + if (compare != 0) + return compare; - // Tiebreaker 1 (likely): From each user's point-of-view, their earliest and best placement. - for (int r = 1; r <= rounds; r++) - { - MatchmakingRound? xRound; - x.Rounds.RoundsDictionary.TryGetValue(r, out xRound); + compare = compareRoundPlacements(x, y); + if (compare != 0) + return compare; - MatchmakingRound? yRound; - y.Rounds.RoundsDictionary.TryGetValue(r, out yRound); + return compareUserIds(x, y); + } - // Nothing to do if both players haven't played this round. - if (xRound == null && yRound == null) - continue; + private int compareAbandonedAt(MatchmakingUser x, MatchmakingUser y) + { + DateTimeOffset xAbandonedAt = x.AbandonedAt ?? DateTimeOffset.MaxValue; + DateTimeOffset yAbandonedAt = y.AbandonedAt ?? DateTimeOffset.MaxValue; + return -xAbandonedAt.CompareTo(yAbandonedAt); + } + + private int comparePoints(MatchmakingUser x, MatchmakingUser y) + { + return -x.Points.CompareTo(y.Points); + } - // X appears later in the list if it hasn't played this round. - if (xRound == null) - return 1; + private int compareRoundPlacements(MatchmakingUser x, MatchmakingUser y) + { + for (int r = 1; r <= rounds; r++) + { + x.Rounds.RoundsDictionary.TryGetValue(r, out var xRound); + y.Rounds.RoundsDictionary.TryGetValue(r, out var yRound); - // Y appears later in the list if it hasn't played this round. - if (yRound == null) - return -1; + int xPlacement = xRound?.Placement ?? int.MaxValue; + int yPlacement = yRound?.Placement ?? int.MaxValue; - // X appears earlier in the list if it has a better placement in the round. - int compare = xRound.Placement.CompareTo(yRound.Placement); + int compare = xPlacement.CompareTo(yPlacement); if (compare != 0) return compare; } - // Tiebreaker 2 (unlikely): User ID. + return 0; + } + + private int compareUserIds(MatchmakingUser x, MatchmakingUser y) + { return x.UserId.CompareTo(y.UserId); } } From 4e4aa44a026ba2992f193e77b2e4f5b463788c2e Mon Sep 17 00:00:00 2001 From: rrex971 <75212090+rrex971@users.noreply.github.com> Date: Mon, 8 Dec 2025 02:17:35 +0530 Subject: [PATCH 233/836] Override sprite update method to handle alpha values > 1 like stable. If alpha exceeds 1 during a sprite's alpha transform like in a FadeTo(), it will set it to 0 mimicking stable's behavior. --- osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index e25c915d8b6c..69b49ba8197c 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -74,6 +74,13 @@ protected override Vector2 DrawScale public override bool IsPresent => !float.IsNaN(DrawPosition.X) && !float.IsNaN(DrawPosition.Y) && base.IsPresent; + // Match stable behavior with alpha values > 1 during interpolation (eg. overshoot easings like InOutElastic etc.) + protected override void Update() + { + base.Update(); + if (Alpha > 1) Alpha = 0; + } + [Resolved] private ISkinSource skin { get; set; } = null!; From f73307876e34d3a8da86c98d0eae3ddee52ae506 Mon Sep 17 00:00:00 2001 From: rrex971 <75212090+rrex971@users.noreply.github.com> Date: Mon, 8 Dec 2025 02:19:29 +0530 Subject: [PATCH 234/836] Also apply alpha logic to StoryboardAnimation sprites too. --- .../Storyboards/Drawables/DrawableStoryboardAnimation.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index f66f84af7a58..3895101a5100 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -89,6 +89,13 @@ public DrawableStoryboardAnimation(StoryboardAnimation animation) LifetimeEnd = animation.EndTimeForDisplay; } + // Match stable behavior with alpha values > 1 during interpolation (eg. overshoot easings like InOutElastic etc.) + protected override void Update() + { + base.Update(); + if (Alpha > 1) Alpha = 0; + } + [Resolved] private ISkinSource skin { get; set; } From 4b0017dfea7ac7560b3f8ab068f10c2d14fcac18 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 8 Dec 2025 16:33:53 +0900 Subject: [PATCH 235/836] Require hold-to-exit during multiplayer load --- .../Multiplayer/MultiplayerPlayerLoader.cs | 26 +++++++++++++++++++ .../Screens/Play/HUD/HoldForMenuButton.cs | 8 ++++-- osu.Game/Screens/Play/PlayerLoader.cs | 4 +-- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayerLoader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayerLoader.cs index dd9cb568628f..4e8a2e08ce74 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayerLoader.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayerLoader.cs @@ -4,10 +4,13 @@ using System; using System.Threading.Tasks; using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD; namespace osu.Game.Screens.OnlinePlay.Multiplayer { @@ -15,6 +18,8 @@ public partial class MultiplayerPlayerLoader : PlayerLoader { public bool GameplayPassed => player?.GameplayState.HasPassed == true; + public override bool AllowUserExit => false; + [Resolved] private MultiplayerClient multiplayerClient { get; set; } = null!; @@ -28,6 +33,27 @@ public MultiplayerPlayerLoader(Func createPlayer) { } + [BackgroundDependencyLoader] + private void load() + { + PlayerSettings.Add(new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = new HoldForMenuButton(true) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Margin = new MarginPadding(10), + Action = () => + { + if (this.IsCurrentScreen()) + this.Exit(); + } + } + }); + } + protected override bool ReadyForGameplay => ( // The user is ready to enter gameplay. diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 96e937fda77d..c271adc057d2 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -44,8 +44,12 @@ public partial class HoldForMenuButton : FillFlowContainer private Bindable alwaysShow; - public HoldForMenuButton() + private readonly bool isDangerousAction; + + public HoldForMenuButton(bool isDangerousAction = false) { + this.isDangerousAction = isDangerousAction; + Direction = FillDirection.Horizontal; Spacing = new Vector2(20, 0); Margin = new MarginPadding(10); @@ -64,7 +68,7 @@ private void load(Player player, OsuConfigManager config) Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft }, - button = new HoldButton(player?.Configuration.AllowRestart == false) + button = new HoldButton(isDangerousAction || player?.Configuration.AllowRestart == false) { HoverGained = () => text.FadeIn(500, Easing.OutQuint), HoverLost = () => text.FadeOut(500, Easing.OutQuint), diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 57159afd22e7..3209ee21fea0 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -72,7 +72,7 @@ public partial class PlayerLoader : ScreenWithBeatmapBackground /// /// A fill flow containing the player settings groups, exposed for the ability to hide it from inheritors of the player loader. /// - protected FillFlowContainer PlayerSettings { get; private set; } = null!; + protected FillFlowContainer PlayerSettings { get; private set; } = null!; protected VisualSettings VisualSettings { get; private set; } = null!; @@ -233,7 +233,7 @@ private void load(SessionStatics sessionStatics, OsuConfigManager config) Width = SettingsToolboxGroup.CONTAINER_WIDTH + padding * 2, Padding = new MarginPadding { Vertical = padding }, Masking = false, - Child = PlayerSettings = new FillFlowContainer + Child = PlayerSettings = new FillFlowContainer { AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, From 8bb885a0dca60753b333f4c259a3af66f9f7bb4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 9 Dec 2025 09:54:46 +0100 Subject: [PATCH 236/836] Filter out more exceptions from being sent to sentry More or less covers the first page of client sentry issues sorted by volume, all of which is pretty much useless for anything because it's client-specific-failure noise. --- osu.Game/Online/API/APIAccess.cs | 2 +- osu.Game/Utils/SentryLogger.cs | 40 ++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 6694003b31d9..6fc897a8ffd1 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -603,7 +603,7 @@ protected override void Dispose(bool isDisposing) cancellationToken.Cancel(); } - private class WebRequestFlushedException : Exception + internal class WebRequestFlushedException : Exception { public WebRequestFlushedException(APIState state) : base($@"Request failed from flush operation (state {state})") diff --git a/osu.Game/Utils/SentryLogger.cs b/osu.Game/Utils/SentryLogger.cs index 4f916f810e15..aa1fd429a74c 100644 --- a/osu.Game/Utils/SentryLogger.cs +++ b/osu.Game/Utils/SentryLogger.cs @@ -2,10 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; +using System.Net.Sockets; +using System.Net.WebSockets; +using System.Threading.Tasks; using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -17,6 +21,7 @@ using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Models; +using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Rulesets; @@ -220,20 +225,35 @@ private SentryLevel getSentryLevel(LogLevel entryLevel) } } + private static readonly HashSet ignored_io_exception_hresults = + [ + // see https://stackoverflow.com/a/9294382 for how these are synthesised + unchecked((int)0x80070020), // ERROR_SHARING_VIOLATION + unchecked((int)0x80070027), // ERROR_HANDLE_DISK_FULL + unchecked((int)0x80070070), // ERROR_DISK_FULL + ]; + private bool shouldSubmitException(Exception exception) { switch (exception) { - case IOException ioe: - // disk full exceptions, see https://stackoverflow.com/a/9294382 - const int hr_error_handle_disk_full = unchecked((int)0x80070027); - const int hr_error_disk_full = unchecked((int)0x80070070); + // disk I/O failures, invalid formats, etc. - if (ioe.HResult == hr_error_handle_disk_full || ioe.HResult == hr_error_disk_full) + case IOException ioe: + if (ignored_io_exception_hresults.Contains(ioe.HResult)) return false; break; + case UnauthorizedAccessException: + case SharpCompress.Common.InvalidFormatException: + return false; + + // connectivity failures + + case TimeoutException te: + return !te.Message.Contains(@"elapsed without receiving a message from the server"); + case WebException we: switch (we.Status) { @@ -243,6 +263,16 @@ private bool shouldSubmitException(Exception exception) } break; + + case WebSocketException: + case SocketException: + return false; + + // stuff that should really never make it to sentry + + case APIAccess.WebRequestFlushedException: + case TaskCanceledException: + return false; } return true; From 4c0522b7956ba14a7ab207f19661c6eea2a9c6cc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Dec 2025 18:00:32 +0900 Subject: [PATCH 237/836] Update comment and fix formatting --- .../Drawables/DrawableStoryboardAnimation.cs | 10 ++++++++-- .../Storyboards/Drawables/DrawableStoryboardSprite.cs | 8 +++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index 3895101a5100..41d5b768f3e6 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -89,13 +89,19 @@ public DrawableStoryboardAnimation(StoryboardAnimation animation) LifetimeEnd = animation.EndTimeForDisplay; } - // Match stable behavior with alpha values > 1 during interpolation (eg. overshoot easings like InOutElastic etc.) protected override void Update() { base.Update(); + + // In stable, alpha transforms exceeding values of 1 would result in sprites disappearing from view. + // Over the years, storyboard(ers) have taken advantage of this to create "flicker" patterns. + // This is quite a common technique, so we are reproducing it here for now. + // + // NOTE TO FUTURE VISTIORS: If we do ever update the storyboard spec, we may want to move such flicker effects to their + // own transform type, and make this a legacy behaviour. It feels very flimsy. if (Alpha > 1) Alpha = 0; } - + [Resolved] private ISkinSource skin { get; set; } diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index 69b49ba8197c..9d2e7110da17 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -74,10 +74,16 @@ protected override Vector2 DrawScale public override bool IsPresent => !float.IsNaN(DrawPosition.X) && !float.IsNaN(DrawPosition.Y) && base.IsPresent; - // Match stable behavior with alpha values > 1 during interpolation (eg. overshoot easings like InOutElastic etc.) protected override void Update() { base.Update(); + + // In stable, alpha transforms exceeding values of 1 would result in sprites disappearing from view. + // Over the years, storyboard(ers) have taken advantage of this to create "flicker" patterns. + // This is quite a common technique, so we are reproducing it here for now. + // + // NOTE TO FUTURE VISTIORS: If we do ever update the storyboard spec, we may want to move such flicker effects to their + // own transform type, and make this a legacy behaviour. It feels very flimsy. if (Alpha > 1) Alpha = 0; } From 84db28977970c5fec819290b225711e9c8b1d221 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Dec 2025 18:57:49 +0900 Subject: [PATCH 238/836] Use modulus instead of previous solution to match stable more closely --- .../Storyboards/Drawables/DrawableStoryboardAnimation.cs | 4 +++- osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index 41d5b768f3e6..4a61bf16fc31 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -94,12 +94,14 @@ protected override void Update() base.Update(); // In stable, alpha transforms exceeding values of 1 would result in sprites disappearing from view. + // See https://github.com/peppy/osu-stable-reference/blob/08e3dafd525934cf48880b08e91c24ce4ad8b761/osu!/Graphics/Sprites/pSprite.cs#L413-L414 + // // Over the years, storyboard(ers) have taken advantage of this to create "flicker" patterns. // This is quite a common technique, so we are reproducing it here for now. // // NOTE TO FUTURE VISTIORS: If we do ever update the storyboard spec, we may want to move such flicker effects to their // own transform type, and make this a legacy behaviour. It feels very flimsy. - if (Alpha > 1) Alpha = 0; + if (Alpha > 1) Alpha %= 1; } [Resolved] diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index 9d2e7110da17..03138710cccc 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -79,12 +79,14 @@ protected override void Update() base.Update(); // In stable, alpha transforms exceeding values of 1 would result in sprites disappearing from view. + // See https://github.com/peppy/osu-stable-reference/blob/08e3dafd525934cf48880b08e91c24ce4ad8b761/osu!/Graphics/Sprites/pSprite.cs#L413-L414 + // // Over the years, storyboard(ers) have taken advantage of this to create "flicker" patterns. // This is quite a common technique, so we are reproducing it here for now. // - // NOTE TO FUTURE VISTIORS: If we do ever update the storyboard spec, we may want to move such flicker effects to their + // NOTE TO FUTURE VISITORS: If we do ever update the storyboard spec, we may want to move such flicker effects to their // own transform type, and make this a legacy behaviour. It feels very flimsy. - if (Alpha > 1) Alpha = 0; + if (Alpha > 1) Alpha %= 1; } [Resolved] From 42b184f167724af9fa10be2079096dccb1338d7f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Dec 2025 19:20:29 +0900 Subject: [PATCH 239/836] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index fe5d204ceb7a..09c83cf37bb0 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index 58b0aa1c2548..aa5f4de8c947 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From 5c2df507141aa00af9a75516fda179b62b89d7f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Dec 2025 19:53:02 +0900 Subject: [PATCH 240/836] Add test coverage of weird storyboard sprite behaviour --- .../TestSceneDrawableStoryboardSprite.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs index 800857c97376..494365a2053b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs @@ -50,6 +50,34 @@ public void TestSkinSpriteDisallowedByDefault() sprites.All(sprite => sprite.ChildrenOfType().All(s => s.Texture == null))); } + [Test] + public void TestSpriteFadeOverflowBehaviour() + { + AddStep("create sprite", () => SetContents(_ => + { + var layer = storyboard.GetLayer("Background"); + + var sprite = new StoryboardSprite(lookup_name, Anchor.TopLeft, new Vector2(256, 192)); + sprite.Commands.AddAlpha(Easing.None, Time.Current, Time.Current + 2000, 0, 2); + + layer.Elements.Clear(); + layer.Add(sprite); + + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + storyboard.CreateDrawable() + } + }; + })); + + AddUntilStep("sprite reached high opacity once", () => sprites.All(sprite => sprite.ChildrenOfType().All(s => s.Alpha > 0.8f))); + AddUntilStep("sprite reset to low opacity", () => sprites.All(sprite => sprite.ChildrenOfType().All(s => s.Alpha < 0.2f))); + AddUntilStep("sprite reached high opacity twice", () => sprites.All(sprite => sprite.ChildrenOfType().All(s => s.Alpha > 0.8f))); + } + [Test] public void TestLookupFromStoryboard() { From 691e8bcd05865a5bd877cb8199ef97da039c20ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 10 Dec 2025 11:14:56 +0100 Subject: [PATCH 241/836] Fix storyboard samples not playing in editor Closes https://github.com/ppy/osu/issues/35954. --- osu.Game/Screens/Backgrounds/EditorBackgroundScreen.cs | 10 +++++++--- osu.Game/Screens/Edit/Editor.cs | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Backgrounds/EditorBackgroundScreen.cs b/osu.Game/Screens/Backgrounds/EditorBackgroundScreen.cs index 24b582b71b5d..07cb9f5be576 100644 --- a/osu.Game/Screens/Backgrounds/EditorBackgroundScreen.cs +++ b/osu.Game/Screens/Backgrounds/EditorBackgroundScreen.cs @@ -13,12 +13,14 @@ using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; +using osu.Game.Screens.Edit; using osu.Game.Storyboards.Drawables; namespace osu.Game.Screens.Backgrounds { public partial class EditorBackgroundScreen : BackgroundScreen { + private readonly EditorBeatmap editorBeatmap; private readonly Container dimContainer; private CancellationTokenSource? cancellationTokenSource; @@ -36,8 +38,9 @@ public partial class EditorBackgroundScreen : BackgroundScreen [Resolved] private IBindable beatmap { get; set; } = null!; - public EditorBackgroundScreen() + public EditorBackgroundScreen(EditorBeatmap editorBeatmap) { + this.editorBeatmap = editorBeatmap; InternalChild = dimContainer = new Container { RelativeSizeAxes = Axes.Both, @@ -58,10 +61,11 @@ private void load(OsuConfigManager config) private IEnumerable createContent() => [ new BeatmapBackground(beatmap.Value) { RelativeSizeAxes = Axes.Both, }, - // this kooky container nesting is here because the storyboard needs a custom clock + // one reason for this kooky container nesting being here is that the storyboard needs a custom clock // but also needs it on an isolated-enough level that doesn't break screen stack expiry logic (which happens if the clock was put on `this`), // or doesn't make it literally impossible to fade the storyboard in/out in real time (which happens if the fade transforms were to be applied directly to the storyboard). - new Container + // another is that we need `EditorSkinProvidingContainer` so that storyboard sample lookups succeed. + new EditorSkinProvidingContainer(editorBeatmap) { RelativeSizeAxes = Axes.Both, Child = new DrawableStoryboard(beatmap.Value.Storyboard) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 05f74c851461..d40d36530aeb 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -480,7 +480,7 @@ private void load(OsuConfigManager config) [Resolved] private MusicController musicController { get; set; } - protected override BackgroundScreen CreateBackground() => new EditorBackgroundScreen(); + protected override BackgroundScreen CreateBackground() => new EditorBackgroundScreen(editorBeatmap); protected override void LoadComplete() { From c4f7dee82bec2e7f7d7339ffc2fe2b22cc5e3f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 11 Dec 2025 05:40:48 +0100 Subject: [PATCH 242/836] Fix skin editor sometimes dropping anchor/origin specification on paste (#35957) * Add failing test for copy->paste not being idempotent * Ensure all elements on default skins use fixed anchors `UsesFixedAnchor` defaults to false, i.e. closest anchors. Combined with manual anchor / origin specs on some drawables, this would get default skins into impossible states wherein a drawable would use "closest anchor" but also explicitly specify anchor / origin that aren't closest, which horribly fails on attempting to copy and paste. Frankly shocked this has gone unnoticed for this long, and I regret not vetoing this "feature" more every time I see its tentacles spread to produce breakage of levels yet unseen. Does this commit contain major levels of suck? For sure. Do I have any better ideas that wouldn't consist of a multi-day rewrite or deletion of this "feature"? No. * Fix skin editor always applying closest anchor / origin on paste regardless of whether the component uses fixed anchor Self-explanatory. Should close https://github.com/ppy/osu/issues/29111 along with previous commit. --- .../Legacy/CatchLegacySkinTransformer.cs | 3 +++ .../Argon/ManiaArgonSkinTransformer.cs | 3 +++ .../Legacy/ManiaLegacySkinTransformer.cs | 3 +++ .../Legacy/OsuLegacySkinTransformer.cs | 3 +++ .../Argon/TaikoArgonSkinTransformer.cs | 3 +++ .../Default/TaikoTrianglesSkinTransformer.cs | 3 +++ .../Legacy/TaikoLegacySkinTransformer.cs | 3 +++ .../Visual/Gameplay/TestSceneSkinEditor.cs | 18 ++++++++++++++++++ osu.Game/Overlays/SkinEditor/SkinEditor.cs | 4 +++- osu.Game/Skinning/ArgonSkin.cs | 6 ++++++ osu.Game/Skinning/LegacySkin.cs | 6 ++++++ osu.Game/Skinning/TrianglesSkin.cs | 6 ++++++ 12 files changed, 60 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 4f9048b988b1..4704e83b7684 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -72,6 +72,9 @@ public CatchLegacySkinTransformer(ISkin skin) leaderboard.Origin = Anchor.CentreLeft; leaderboard.X = 10; } + + foreach (var d in container.OfType()) + d.UsesFixedAnchor = true; }) { Children = new Drawable[] diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index a71b8aa98267..81cc52e9259b 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -57,6 +57,9 @@ public ManiaArgonSkinTransformer(ISkin skin, IBeatmap beatmap) if (spectatorList != null) spectatorList.Position = new Vector2(36, -66); + + foreach (var d in container.OfType()) + d.UsesFixedAnchor = true; }) { new DrawableGameplayLeaderboard(), diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index addb96d2c3d7..690705664d2f 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -122,6 +122,9 @@ public override Drawable GetDrawableComponent(ISkinComponentLookup lookup) leaderboard.Origin = Anchor.CentreLeft; leaderboard.X = 10; } + + foreach (var d in container.OfType()) + d.UsesFixedAnchor = true; }) { new LegacyManiaComboCounter(), diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 7118b6f95e1b..219e754dccd7 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -103,6 +103,9 @@ public OsuLegacySkinTransformer(ISkin skin) leaderboard.Origin = Anchor.BottomLeft; leaderboard.Position = pos; } + + foreach (var d in container.OfType()) + d.UsesFixedAnchor = true; }) { Children = new Drawable[] diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index b0a1c5d3f7f6..820af4ce54f8 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -51,6 +51,9 @@ public TaikoArgonSkinTransformer(ISkin skin) spectatorList.Anchor = Anchor.BottomLeft; spectatorList.Origin = Anchor.TopLeft; } + + foreach (var d in container.OfType()) + d.UsesFixedAnchor = true; }) { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/TaikoTrianglesSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/TaikoTrianglesSkinTransformer.cs index f6274178893e..1a73457c67e7 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/TaikoTrianglesSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/TaikoTrianglesSkinTransformer.cs @@ -51,6 +51,9 @@ public TaikoTrianglesSkinTransformer(ISkin skin) spectatorList.Origin = Anchor.TopLeft; spectatorList.Position = new Vector2(320, -280); } + + foreach (var d in container.OfType()) + d.UsesFixedAnchor = true; }) { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 73d32a79333f..a985bd362e4e 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -79,6 +79,9 @@ public TaikoLegacySkinTransformer(ISkin skin) spectatorList.Origin = Anchor.TopLeft; spectatorList.Position = pos; } + + foreach (var d in container.OfType()) + d.UsesFixedAnchor = true; }) { new LegacyDefaultComboCounter(), diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index 97889eea4d34..3b8e63c5966c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Text; +using Newtonsoft.Json; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions; @@ -378,6 +379,23 @@ public void TestCopyPaste() () => Is.EqualTo(3)); } + [Test] + public void TestCopyPasteIdempotency() + { + string state = null!; + AddStep("select everything", () => InputManager.Keys(PlatformAction.SelectAll)); + AddStep("dump state", () => + { + state = JsonConvert.SerializeObject(skinEditor.SelectedComponents.Cast().Select(s => s.CreateSerialisedInfo()).ToArray()); + }); + AddStep("copy", () => InputManager.Keys(PlatformAction.Copy)); + AddStep("delete", () => InputManager.Keys(PlatformAction.Delete)); + AddStep("paste", () => InputManager.Keys(PlatformAction.Paste)); + AddAssert("pasted state equals dumped", + () => JsonConvert.SerializeObject(skinEditor.SelectedComponents.Cast().Select(s => s.CreateSerialisedInfo()).ToArray()), + () => Is.EqualTo(state)); + } + private SkinnableContainer globalHUDTarget => Player.ChildrenOfType() .Single(c => c.Lookup.Lookup == GlobalSkinnableContainers.MainHUDComponents && c.Lookup.Ruleset == null); diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 823456dddd81..2903c867f7a4 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -529,7 +529,9 @@ private bool placeComponent(ISerialisableDrawable component, bool applyDefaults } SelectedComponents.Add(component); - SkinSelectionHandler.ApplyClosestAnchorOrigin(drawableComponent); + + if (!component.UsesFixedAnchor) + SkinSelectionHandler.ApplyClosestAnchorOrigin(drawableComponent); return true; } diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index 9e8fe4f617b4..6d922e14028d 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -128,6 +128,9 @@ public ArgonSkin(SkinInfo skin, IStorageResourceProvider resources) if (spectatorList != null) spectatorList.Position = pos; + + foreach (var d in container.OfType()) + d.UsesFixedAnchor = true; }) { RelativeSizeAxes = Axes.Both, @@ -238,6 +241,9 @@ public ArgonSkin(SkinInfo skin, IStorageResourceProvider resources) keyCounter.Position = new Vector2(-(hitError.Width + padding), -(padding * 2 + song_progress_offset_height)); } } + + foreach (var d in container.OfType()) + d.UsesFixedAnchor = true; } }) { diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 6ff569869af6..74b404a578bf 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -412,6 +412,9 @@ protected override void ParseConfigurationStream(Stream stream) leaderboard.Origin = Anchor.CentreLeft; leaderboard.X = 10; } + + foreach (var d in container.OfType()) + d.UsesFixedAnchor = true; }) { new LegacyDefaultComboCounter(), @@ -448,6 +451,9 @@ protected override void ParseConfigurationStream(Stream stream) hitError.Origin = Anchor.CentreLeft; hitError.Rotation = -90; } + + foreach (var d in container.OfType()) + d.UsesFixedAnchor = true; }) { Children = new Drawable[] diff --git a/osu.Game/Skinning/TrianglesSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs index 3881a5e97081..ae3df35383b5 100644 --- a/osu.Game/Skinning/TrianglesSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -106,6 +106,9 @@ public TrianglesSkin(SkinInfo skin, IStorageResourceProvider resources) spectatorList.Origin = Anchor.BottomLeft; spectatorList.Position = new Vector2(screen_edge_padding, -(song_progress_offset_height + screen_edge_padding)); } + + foreach (var d in container.OfType()) + d.UsesFixedAnchor = true; }) { RelativeSizeAxes = Axes.Both, @@ -178,6 +181,9 @@ public TrianglesSkin(SkinInfo skin, IStorageResourceProvider resources) keyCounter.Origin = Anchor.BottomRight; keyCounter.Position = new Vector2(-screen_edge_padding, -(song_progress_offset_height + screen_edge_padding)); } + + foreach (var d in container.OfType()) + d.UsesFixedAnchor = true; }) { Children = new Drawable[] From 86054497d0322f6fef04dc0a12b6b0f9b8cc1d6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 11 Dec 2025 05:42:15 +0100 Subject: [PATCH 243/836] Disable save replay on fail overlay when spectating (#35942) "Closes" https://github.com/ppy/osu/issues/35920. The button can't easily work anyway since it's not guaranteed that the spectating user has all of the frames of the replay (think entering spectate midway through a play). This matches the results screen in spectator too. --- osu.Game/Screens/Play/FailOverlay.cs | 2 +- osu.Game/Screens/Play/Player.cs | 2 +- osu.Game/Screens/Play/SaveFailedScoreButton.cs | 13 +++++++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/FailOverlay.cs b/osu.Game/Screens/Play/FailOverlay.cs index 4a0a6f573cf9..f5f1bf37e679 100644 --- a/osu.Game/Screens/Play/FailOverlay.cs +++ b/osu.Game/Screens/Play/FailOverlay.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Play { public partial class FailOverlay : GameplayMenuOverlay { - public Func>? SaveReplay; + public Func>? SaveReplay { get; init; } public override LocalisableString Header => GameplayMenuOverlayStrings.FailedHeader; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 9988bbcd9311..21e0d3c8b95f 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -316,7 +316,7 @@ private void load(OsuConfigManager config, OsuGameBase game, CancellationToken c }, FailOverlay = new FailOverlay { - SaveReplay = async () => await prepareAndImportScoreAsync(true).ConfigureAwait(false), + SaveReplay = Configuration.AllowUserInteraction ? async () => await prepareAndImportScoreAsync(true).ConfigureAwait(false) : null, OnRetry = Configuration.AllowUserInteraction ? () => Restart() : null, OnQuit = () => PerformExitWithConfirmation(), }, diff --git a/osu.Game/Screens/Play/SaveFailedScoreButton.cs b/osu.Game/Screens/Play/SaveFailedScoreButton.cs index e5c9e115d133..af323281bdc3 100644 --- a/osu.Game/Screens/Play/SaveFailedScoreButton.cs +++ b/osu.Game/Screens/Play/SaveFailedScoreButton.cs @@ -96,8 +96,17 @@ private void load(OsuGame? game, Player? player) break; default: - button.TooltipText = @"save score"; - button.Enabled.Value = true; + if (importFailedScore != null) + { + button.TooltipText = @"save score"; + button.Enabled.Value = true; + } + else + { + button.TooltipText = @"replay unavailable"; + button.Enabled.Value = false; + } + break; } }, true); From 095a67c24e57922f5e3c9190cc50d641f45ca1e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 11 Dec 2025 05:47:08 +0100 Subject: [PATCH 244/836] Fix dragging volume meter to adjust volume closing overlays if mouse is released outside of overlay content (#35940) * Add failing test * Fix dragging volume meter to adjust volume closing overlays if mouse is released outside of overlay content Fixes https://osu.ppy.sh/community/forums/topics/2159553. --- .../Navigation/TestSceneScreenNavigation.cs | 30 +++++++++++++++++++ osu.Game/Overlays/Volume/VolumeMeter.cs | 2 ++ 2 files changed, 32 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 8a0c9f561ccf..ac6352753f40 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -24,6 +24,7 @@ using osu.Game.Extensions; using osu.Game.Graphics.Carousel; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.Notifications.WebSocket; @@ -33,6 +34,7 @@ using osu.Game.Overlays.Mods; using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Toolbar; +using osu.Game.Overlays.Volume; using osu.Game.Rulesets; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Mania.Configuration; @@ -1331,6 +1333,34 @@ public void TestPresentBeatmapAfterDeletion() AddAssert("still nothing selected", () => Game.Beatmap.IsDefault); } + [Test] + public void TestVolumeMeterDragDoesNotDismissFocusedOverlay() + { + AddStep("show beatmap overlay", () => Game.ShowBeatmapSet(1)); + AddUntilStep("beatmap overlay still visible", + () => Game.ChildrenOfType().SingleOrDefault()?.State.Value, + () => Is.EqualTo(Visibility.Visible)); + AddStep("set game volume to max", () => Game.Dependencies.Get().SetValue(FrameworkSetting.VolumeUniversal, 1d)); + AddStep("move to centre", () => InputManager.MoveMouseTo(Game)); + AddStep("alt-scroll down", () => + { + InputManager.PressKey(Key.AltLeft); + InputManager.ScrollVerticalBy(-1); + InputManager.ReleaseKey(Key.AltLeft); + }); + AddUntilStep("wait for volume overlay to show", () => Game.ChildrenOfType().SingleOrDefault()?.State.Value, () => Is.EqualTo(Visibility.Visible)); + AddStep("start dragging meter", () => + { + InputManager.MoveMouseTo(Game.ChildrenOfType().First().ChildrenOfType().First()); + InputManager.PressButton(MouseButton.Left); + }); + AddStep("drag away", () => InputManager.MoveMouseTo(Game.ChildrenOfType().First().ChildrenOfType().First(), new Vector2(0, -100))); + AddStep("release mouse", () => InputManager.ReleaseButton(MouseButton.Left)); + AddAssert("beatmap overlay still visible", + () => Game.ChildrenOfType().SingleOrDefault()?.State.Value, + () => Is.EqualTo(Visibility.Visible)); + } + private Func playToResults() { var player = playToCompletion(); diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 9e0c59938606..ed9c5c13efd2 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -321,6 +321,8 @@ public double Volume private float dragDelta; + protected override bool OnMouseDown(MouseDownEvent e) => true; // handle to prevent drawables behind from potentially receiving the mouse down + protected override bool OnDragStart(DragStartEvent e) { dragDelta = 0; From 1faf02e8604a2d40e9a0cd2c2f0e9042046fd3cc Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 11 Dec 2025 13:53:09 +0900 Subject: [PATCH 245/836] Update localisation analyser packages --- .config/dotnet-tools.json | 2 +- osu.Game/osu.Game.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 6ec071be2fc9..17a371079ad3 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -21,7 +21,7 @@ ] }, "ppy.localisationanalyser.tools": { - "version": "2024.802.0", + "version": "2025.1208.0", "commands": [ "localisation" ] diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ee23bc7f72df..ab2304dcfb29 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -30,7 +30,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From f71eb4b9801e8792d61f59ff9c44b0cf22103691 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 11 Dec 2025 16:00:13 +0900 Subject: [PATCH 246/836] Debounce track seeks only when track is playing This fixes the editor no longer seeking smoothly when paused. Closes https://github.com/ppy/osu/issues/35963. --- osu.Game/Overlays/NowPlayingOverlay.cs | 2 +- .../Edit/Components/Timelines/Summary/Parts/MarkerPart.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index 28119615f364..eb4e2db5d1e1 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -228,7 +228,7 @@ private void load() private void onSeek(double progress) { - if (lastSeekTime == null || Time.Current - lastSeekTime > TRACK_DRAG_SEEK_DEBOUNCE) + if (!musicController.IsPlaying || lastSeekTime == null || Time.Current - lastSeekTime > TRACK_DRAG_SEEK_DEBOUNCE) { musicController.SeekTo(progress); lastSeekTime = Time.Current; diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs index b7453bf7f63b..1783bfb1e5e4 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -67,7 +67,7 @@ private void seekToPosition(Vector2 screenPosition, bool instant) double seekDestination = markerPos / DrawWidth * editorClock.TrackLength; marker.X = (float)seekDestination; - if (!instant && lastSeekTime != null && Time.Current - lastSeekTime < NowPlayingOverlay.TRACK_DRAG_SEEK_DEBOUNCE) + if (editorClock.IsRunning && !instant && lastSeekTime != null && Time.Current - lastSeekTime < NowPlayingOverlay.TRACK_DRAG_SEEK_DEBOUNCE) return; editorClock.SeekSmoothlyTo(seekDestination); From b30047def626257c1e6e4d336ef51b5a90f48c66 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 11 Dec 2025 17:55:12 +0900 Subject: [PATCH 247/836] Remove audio adjustments immediately on gameplay hotkey overlays Closes #22164. --- osu.Game/Overlays/HoldToConfirmOverlay.cs | 7 ++++++- osu.Game/Screens/Play/HotkeyExitOverlay.cs | 9 +++++++++ osu.Game/Screens/Play/HotkeyRetryOverlay.cs | 9 +++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/HoldToConfirmOverlay.cs b/osu.Game/Overlays/HoldToConfirmOverlay.cs index 6cdbc6450db7..b9c32f9f8c47 100644 --- a/osu.Game/Overlays/HoldToConfirmOverlay.cs +++ b/osu.Game/Overlays/HoldToConfirmOverlay.cs @@ -61,10 +61,15 @@ private void load() audio.Samples.AddAdjustment(AdjustableProperty.Volume, audioVolume); } - protected override void Dispose(bool isDisposing) + protected void RemoveAudioAdjustments() { audio?.Tracks.RemoveAdjustment(AdjustableProperty.Volume, audioVolume); audio?.Samples.RemoveAdjustment(AdjustableProperty.Volume, audioVolume); + } + + protected override void Dispose(bool isDisposing) + { + RemoveAudioAdjustments(); base.Dispose(isDisposing); } } diff --git a/osu.Game/Screens/Play/HotkeyExitOverlay.cs b/osu.Game/Screens/Play/HotkeyExitOverlay.cs index bcd9bd7cd614..0908e044d027 100644 --- a/osu.Game/Screens/Play/HotkeyExitOverlay.cs +++ b/osu.Game/Screens/Play/HotkeyExitOverlay.cs @@ -27,5 +27,14 @@ public void OnReleased(KeyBindingReleaseEvent e) AbortConfirm(); } + + protected override void Confirm() + { + base.Confirm(); + + // Not removing immediately can lead to delays due to async disposal. + // This is done here rather than in `Player` because it's simpler to handle. + RemoveAudioAdjustments(); + } } } diff --git a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs index 11d0b4f84f40..044aab7021ad 100644 --- a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs +++ b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs @@ -27,5 +27,14 @@ public void OnReleased(KeyBindingReleaseEvent e) AbortConfirm(); } + + protected override void Confirm() + { + base.Confirm(); + + // Not removing immediately can lead to delays due to async disposal. + // This is done here rather than in `Player` because it's simpler to handle. + RemoveAudioAdjustments(); + } } } From 6ce8b0a4bc7194286badb5d5f5d79c8445159620 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 11 Dec 2025 18:54:38 +0900 Subject: [PATCH 248/836] Slightly delay song select leaderboard's loading placeholder to avoid flashing during local score retrieval Closes #35893. --- .../Screens/SelectV2/BeatmapLeaderboardWedge.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs b/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs index 6e0ffafa63c3..af41a528b303 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs +++ b/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs @@ -407,15 +407,27 @@ private void clearScores() private LeaderboardState displayedState; + private ScheduledDelegate? loadingShowDelegate; + protected void SetState(LeaderboardState state) { if (state == displayedState) return; if (state == LeaderboardState.Retrieving) - loading.Show(); + { + // Slight delay so this doesn't display for a few silly frames for local score retrievals. + loadingShowDelegate ??= Scheduler.AddDelayed(() => loading.Show(), 200); + } else + { + loadingShowDelegate?.Cancel(); + loadingShowDelegate = null; + loading.Hide(); + } + + loading.Hide(); displayedState = state; From bbdd70c8431b1c95f4f7cd8bfad0414ffd82d1ab Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 11 Dec 2025 20:07:36 +0900 Subject: [PATCH 249/836] Always perform leave room sequence --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 4f223cc1ab80..59a26d5ba748 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -319,9 +319,6 @@ protected virtual void OnRoomJoined() public Task LeaveRoom() { - if (Room == null) - return Task.CompletedTask; - // The join may have not completed yet, so certain tasks that either update the room or reference the room should be cancelled. // This includes the setting of Room itself along with the initial update of the room settings on join. joinCancellationSource?.Cancel(); From c17db2cdd0c3ce81a3648fe5a12e32ec88f4ed7b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 11 Dec 2025 20:07:44 +0900 Subject: [PATCH 250/836] Forcefully leave room on multiplayer exit --- osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs index eb387b2664fa..b58041aa6fbc 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs @@ -90,6 +90,15 @@ private void transitionFromResults() client.ChangeState(MultiplayerUserState.Idle).FireAndForget(); } + public override bool OnExiting(ScreenExitEvent e) + { + if (base.OnExiting(e)) + return true; + + client.LeaveRoom().FireAndForget(); + return false; + } + protected override string ScreenTitle => "Multiplayer"; protected override LoungeSubScreen CreateLounge() => new MultiplayerLoungeSubScreen(); From 79151ae5b4fb12249e850cb10baddb3f625a067d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 12 Dec 2025 15:46:00 +0900 Subject: [PATCH 251/836] Remove mention of exception that doesn't exist --- osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs index 169d5d1b8312..836b9efb1037 100644 --- a/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs @@ -16,7 +16,6 @@ public interface IMultiplayerRoomServer /// /// Request to leave the currently joined room. /// - /// If the user is not in a room. Task LeaveRoom(); /// From 1aff418981353f35dca3059b6a4179f7897ab005 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 12 Dec 2025 17:57:50 +0900 Subject: [PATCH 252/836] Reword waiting text --- osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs index 8eaa28079403..19b75cecd7c3 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs @@ -403,7 +403,7 @@ public void SetState(MatchmakingScreenState newState) { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = "Waiting for all players...", + Text = "Waiting for opponents...", Font = OsuFont.GetFont(size: 32, weight: FontWeight.Light, typeface: Typeface.TorusAlternate), }, new LoadingSpinner From 7853abe8aa9b79504ebc0b1eb709737624ec2282 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 12 Dec 2025 18:02:20 +0900 Subject: [PATCH 253/836] Move to queue screen when clicking notification --- .../Matchmaking/Queue/QueueController.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs index f72f26f26e28..6d23dd4eb114 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs @@ -169,6 +169,20 @@ private void load(AudioManager audio) { Text = "Searching for opponents..."; + Activated = () => + { + performer?.PerformFromScreen(s => + { + if (s is ScreenIntro || s is ScreenQueue) + return; + + s.Push(new ScreenIntro()); + }, [typeof(ScreenIntro), typeof(ScreenQueue)]); + + // Closed when appropriate by SearchInForeground(). + return false; + }; + CompletionClickAction = () => { client.MatchmakingAcceptInvitation().FireAndForget(); From 1c463aa06045af1b2e4af82444e26034b292f54e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 12 Dec 2025 18:26:50 +0900 Subject: [PATCH 254/836] Automatically accept invitation in queue screen --- .../Matchmaking/Queue/ScreenQueue.cs | 34 ++----------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs index 19b75cecd7c3..e446a8534465 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs @@ -354,37 +354,9 @@ public void SetState(MatchmakingScreenState newState) break; case MatchmakingScreenState.PendingAccept: - mainContent.Child = new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(20), - Children = new Drawable[] - { - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "Found a match!", - Font = OsuFont.GetFont(size: 32, weight: FontWeight.Regular, typeface: Typeface.TorusAlternate), - }, - new SelectionButton(200) - { - DarkerColour = colours.YellowDark, - LighterColour = colours.YellowLight, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Action = () => - { - client.MatchmakingAcceptInvitation().FireAndForget(); - SetState(MatchmakingScreenState.AcceptedWaitingForRoom); - }, - Text = "Join match!", - } - } - }; + client.MatchmakingAcceptInvitation().FireAndForget(); + SetState(MatchmakingScreenState.AcceptedWaitingForRoom); + matchFoundSample?.Play(); musicController.DuckMomentarily(1250); break; From 346461ffdc24f9ae0e05c824271eba347062bb79 Mon Sep 17 00:00:00 2001 From: Givy120 <89256026+Givikap120@users.noreply.github.com> Date: Sat, 13 Dec 2025 14:29:20 +0200 Subject: [PATCH 255/836] Skip score-based miss count estimation for ScoreV2 (#35962) * Add basic scorev2 support * Revert unnecessary score statistic changes * Fix CI * Revert changes * Disable score-based misscount for scoreV2 --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index b2ffc5aa0eab..3bc486d7e663 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -102,7 +102,7 @@ protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo s double comboBasedEstimatedMissCount = calculateComboBasedEstimatedMissCount(osuAttributes); double? scoreBasedEstimatedMissCount = null; - if (usingClassicSliderAccuracy && score.LegacyTotalScore != null) + if (usingClassicSliderAccuracy && !usingScoreV2 && score.LegacyTotalScore != null) { var legacyScoreMissCalculator = new OsuLegacyScoreMissCalculator(score, osuAttributes); scoreBasedEstimatedMissCount = legacyScoreMissCalculator.Calculate(); From 881a35b3824e5620c293d7240cf5e288da91dbb4 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Mon, 15 Dec 2025 03:54:09 -0500 Subject: [PATCH 256/836] Fix skip overlay potentially not allowing skipping --- .../Multiplayer/MultiplayerSkipOverlay.cs | 14 +++++++++-- osu.Game/Screens/Play/SkipOverlay.cs | 24 ++++++++++--------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs index 5a9c31b88923..e44cb16f8ef0 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerSkipOverlay.cs @@ -42,10 +42,11 @@ public MultiplayerSkipOverlay(double startTime) { } - protected override OsuClickableContainer CreateButton() => skipButton = new Button + protected override OsuClickableContainer CreateButton(IBindable inSkipPeriod) => skipButton = new Button { Anchor = Anchor.Centre, Origin = Anchor.Centre, + InSkipPeriod = { BindTarget = inSkipPeriod }, }; protected override void LoadComplete() @@ -119,6 +120,9 @@ public partial class Button : OsuClickableContainer public readonly BindableInt SkippedCount = new BindableInt(); public readonly BindableInt RequiredCount = new BindableInt(); + public readonly BindableBool InSkipPeriod = new BindableBool(); + + private readonly BindableBool clicked = new BindableBool(); [Resolved] private OsuColour colours { get; set; } = null!; @@ -201,11 +205,17 @@ protected override void LoadComplete() SkippedCount.BindValueChanged(_ => updateCount()); RequiredCount.BindValueChanged(_ => updateCount(), true); + + InSkipPeriod.BindValueChanged(_ => updateEnabledState()); + clicked.BindValueChanged(_ => updateEnabledState(), true); + Enabled.BindValueChanged(_ => updateColours(), true); FinishTransforms(true); } + private void updateEnabledState() => Enabled.Value = InSkipPeriod.Value && !clicked.Value; + private void updateChevronsSpacing() { if (SkippedCount.Value > 0 && RequiredCount.Value > 1) @@ -300,7 +310,7 @@ protected override bool OnClick(ClickEvent e) base.OnClick(e); - Enabled.Value = false; + clicked.Value = true; return true; } diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 361de7110326..f9752706ade5 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -10,6 +10,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Audio.Track; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -52,9 +53,9 @@ public partial class SkipOverlay : BeatSyncedContainer, IKeyBindingHandler - /// Becomes when the overlay starts fading out. + /// Whether the gameplay clock is currently at the skippable period. /// - private bool isClickable; + private readonly BindableBool inSkipPeriod = new BindableBool(); private bool skipQueued; @@ -92,7 +93,7 @@ private void load(OsuColour colours) RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - button = CreateButton(), + button = CreateButton(inSkipPeriod), RemainingTimeBox = new Circle { Height = 5, @@ -106,10 +107,15 @@ private void load(OsuColour colours) }; } - protected virtual OsuClickableContainer CreateButton() => new Button + /// + /// Creates a skip button. + /// + /// Whether the gameplay clock is currently at the skippable period. + protected virtual OsuClickableContainer CreateButton(IBindable inSkipPeriod) => new Button { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Enabled = { BindTarget = inSkipPeriod }, }; private const double fade_time = 300; @@ -187,17 +193,13 @@ protected override void Update() RemainingTimeBox.Width = (float)Interpolation.Lerp(RemainingTimeBox.Width, progress, Math.Clamp(Time.Elapsed / 40, 0, 1)); - isClickable = progress > 0; - - if (!isClickable) - button.Enabled.Value = false; - - buttonContainer.State.Value = isClickable ? Visibility.Visible : Visibility.Hidden; + inSkipPeriod.Value = progress > 0; + buttonContainer.State.Value = inSkipPeriod.Value ? Visibility.Visible : Visibility.Hidden; } protected override bool OnMouseMove(MouseMoveEvent e) { - if (isClickable && !e.HasAnyButtonPressed) + if (inSkipPeriod.Value && !e.HasAnyButtonPressed) FadingContent.TriggerShow(); return base.OnMouseMove(e); From dcb6d712870c86956a21fbf4d788e0b51df20e59 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Dec 2025 19:07:46 +0900 Subject: [PATCH 257/836] Adjust constant and documentation slightly --- osu.Game/Skinning/LegacyPerformancePointsCounter.cs | 2 +- osu.Game/Skinning/LegacySpriteText.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Skinning/LegacyPerformancePointsCounter.cs b/osu.Game/Skinning/LegacyPerformancePointsCounter.cs index e59a4a80b4e5..a71ecaabde70 100644 --- a/osu.Game/Skinning/LegacyPerformancePointsCounter.cs +++ b/osu.Game/Skinning/LegacyPerformancePointsCounter.cs @@ -37,7 +37,7 @@ public override bool IsValid } } - protected override LocalisableString FormatCount(int count) => count.ToString($@"0'{LegacySpriteText.PP}'"); + protected override LocalisableString FormatCount(int count) => count.ToString($@"0'{LegacySpriteText.PP_SUFFIX_CHAR}'"); protected sealed override OsuSpriteText CreateSpriteText() => new LegacySpriteText(LegacyFont.Score); } diff --git a/osu.Game/Skinning/LegacySpriteText.cs b/osu.Game/Skinning/LegacySpriteText.cs index dca258e6eb94..e307577c2f10 100644 --- a/osu.Game/Skinning/LegacySpriteText.cs +++ b/osu.Game/Skinning/LegacySpriteText.cs @@ -15,9 +15,9 @@ namespace osu.Game.Skinning public sealed partial class LegacySpriteText : OsuSpriteText { /// - /// The Private Use Area character representing performance points. + /// The Private Use Area character for internally representing the "pp" suffix for performance counters. /// - public const char PP = '\uebd9'; + public const char PP_SUFFIX_CHAR = '\uebd9'; public Vector2? MaxSizePerGlyph { get; init; } public bool FixedWidth { get; init; } @@ -28,7 +28,7 @@ public sealed partial class LegacySpriteText : OsuSpriteText protected override char FixedWidthReferenceCharacter => '5'; - protected override char[] FixedWidthExcludeCharacters => new[] { ',', '.', '%', 'x', PP }; + protected override char[] FixedWidthExcludeCharacters => new[] { ',', '.', '%', 'x', PP_SUFFIX_CHAR }; // ReSharper disable once UnusedMember.Global // being unused is the point here @@ -121,7 +121,7 @@ private static string getLookupName(char character) case '%': return "percent"; - case PP: + case PP_SUFFIX_CHAR: return "pp"; default: From 1142be45ec7a7527020c9ff82cc2d791b9064b94 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Dec 2025 19:07:59 +0900 Subject: [PATCH 258/836] Update resources --- osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs | 2 +- osu.Game/Overlays/Rankings/RankingsScope.cs | 4 ++-- osu.Game/Overlays/RankingsOverlay.cs | 4 ++-- osu.Game/osu.Game.csproj | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 0eaa6ce82780..63f0d5eb766d 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -54,7 +54,7 @@ bool showRulesetSelector(RankingsScope scope) case RankingsScope.Performance: case RankingsScope.Score: case RankingsScope.Country: - case RankingsScope.Spotlights: + case RankingsScope.Playlists: return true; default: diff --git a/osu.Game/Overlays/Rankings/RankingsScope.cs b/osu.Game/Overlays/Rankings/RankingsScope.cs index 658732a1b154..6822783b0412 100644 --- a/osu.Game/Overlays/Rankings/RankingsScope.cs +++ b/osu.Game/Overlays/Rankings/RankingsScope.cs @@ -17,8 +17,8 @@ public enum RankingsScope [LocalisableDescription(typeof(RankingsStrings), nameof(RankingsStrings.TypeCountry))] Country, - [LocalisableDescription(typeof(RankingsStrings), nameof(RankingsStrings.TypeCharts))] - Spotlights, + [LocalisableDescription(typeof(RankingsStrings), nameof(RankingsStrings.TypePlaylists))] + Playlists, [LocalisableDescription(typeof(RankingsStrings), nameof(RankingsStrings.TypeKudosu))] Kudosu, diff --git a/osu.Game/Overlays/RankingsOverlay.cs b/osu.Game/Overlays/RankingsOverlay.cs index 6a32515cbc1e..71f0010d42e1 100644 --- a/osu.Game/Overlays/RankingsOverlay.cs +++ b/osu.Game/Overlays/RankingsOverlay.cs @@ -52,7 +52,7 @@ protected override void LoadComplete() ruleset.BindValueChanged(_ => { - if (Header.Current.Value == RankingsScope.Spotlights) + if (Header.Current.Value == RankingsScope.Playlists) return; Scheduler.AddOnce(triggerTabChanged); @@ -99,7 +99,7 @@ protected override void CreateDisplayToLoad(RankingsScope tab) { lastRequest?.Cancel(); - if (Header.Current.Value == RankingsScope.Spotlights) + if (Header.Current.Value == RankingsScope.Playlists) { LoadDisplay(new SpotlightsLayout { diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ab2304dcfb29..a2dabe7a9ff0 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From 1e79c562403cf5a32e1ee6d31b2c9c7d95488b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 16 Dec 2025 09:48:10 +0100 Subject: [PATCH 259/836] Fix replay fail indicator not using fail sample from beatmap skin Closes https://github.com/ppy/osu/issues/36003. The duplicated `RulesetSkinProvidingContainer` is unfortunate but it's either this or I start doing proxy shenanigans. --- osu.Game/Screens/Play/ReplayPlayer.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 1c583609d938..7fec8d63325d 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -18,6 +18,7 @@ using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Screens.Ranking; using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Skinning; using osu.Game.Users; namespace osu.Game.Screens.Play @@ -100,15 +101,18 @@ private void load(OsuConfigManager config) playbackSettings.UserPlaybackRate.BindTo(master.UserPlaybackRate); HUDOverlay.PlayerSettingsOverlay.AddAtStart(playbackSettings); - AddInternal(failIndicator = new ReplayFailIndicator(GameplayClockContainer) + AddInternal(new RulesetSkinProvidingContainer(GameplayState.Ruleset, GameplayState.Beatmap, Beatmap.Value.Skin) { - GoToResults = () => + Child = failIndicator = new ReplayFailIndicator(GameplayClockContainer) { - if (!this.IsCurrentScreen()) - return; - - ValidForResume = false; - this.Push(new SoloResultsScreen(Score.ScoreInfo)); + GoToResults = () => + { + if (!this.IsCurrentScreen()) + return; + + ValidForResume = false; + this.Push(new SoloResultsScreen(Score.ScoreInfo)); + } } }); } From 83f9eba1d1d491efbd32630e55ec4cb4a9e70ced Mon Sep 17 00:00:00 2001 From: James Wilson Date: Tue, 16 Dec 2025 09:28:30 +0000 Subject: [PATCH 260/836] Set `Ranked` to `true` for `ManiaModCover` --- osu.Game.Rulesets.Mania/Mods/ManiaModCover.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModCover.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModCover.cs index 3ebfcedfd107..f51a7774a582 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModCover.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModCover.cs @@ -30,7 +30,7 @@ public class ManiaModCover : ManiaModWithPlayfieldCover typeof(ManiaModFadeIn) }).ToArray(); - public override bool Ranked => false; + public override bool Ranked => true; public override bool ValidForFreestyleAsRequiredMod => false; From 032912e62b1400570e493df5f8725fd52450d491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 16 Dec 2025 11:16:13 +0100 Subject: [PATCH 261/836] Adjust message on successful report to match bancho Addresses https://github.com/ppy/osu/discussions/36004. Not adding localisation because the previous implementation was `.ToString()`ing anyway. Would have made the abuse e-mail a link but `mailto:` doesn't work with `MessageFormatter` and I don't want to go into that right now. The message *almost* matches stable. The "almost" is because it doesn't mention the `/ignore` chat command. I was just going to implement the command, but I went to check what it does, and backed away slowly because it has like weird scoping to chat, highlights, and PMs, so `nope.avi`. --- osu.Game/Overlays/Chat/ReportChatPopover.cs | 22 ++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ReportChatPopover.cs b/osu.Game/Overlays/Chat/ReportChatPopover.cs index 265a17c7992f..42aa92f5c2da 100644 --- a/osu.Game/Overlays/Chat/ReportChatPopover.cs +++ b/osu.Game/Overlays/Chat/ReportChatPopover.cs @@ -33,7 +33,27 @@ private void report(ChatReportReason reason, string comments) { var request = new ChatReportRequest(message.Id, reason, comments); - request.Success += () => channelManager.CurrentChannel.Value.AddNewMessages(new InfoMessage(UsersStrings.ReportThanks.ToString())); + request.Success += () => + { + string thanksMessage; + + switch (channelManager.CurrentChannel.Value.Type) + { + case ChannelType.PM: + thanksMessage = """ + Chat moderators have been alerted. You have reported a private message so they will not be able to read history to maintain your privacy. Please make sure to include as much details as you can. + You can submit a second report with more details if required, or contact abuse@ppy.sh if a user is being extremely offensive. + You can also block a user via the block button on their user profile, or by right-clicking on their name in the chat and selecting "Block". + """; + break; + + default: + thanksMessage = @"Chat moderators have been alerted. Thanks for your help."; + break; + } + + channelManager.CurrentChannel.Value.AddNewMessages(new InfoMessage(thanksMessage)); + }; api.Queue(request); } From 190b5535d7fb0b63df32b38ac806638d68f163df Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 16 Dec 2025 19:49:45 +0900 Subject: [PATCH 262/836] Remove UI scaling in quick play --- .../Matchmaking/Match/ScreenMatchmaking.cs | 71 +++++++++++++------ 1 file changed, 50 insertions(+), 21 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs index 753b8a90aa29..84af33c2ba6b 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs @@ -20,6 +20,7 @@ using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Database; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; @@ -137,35 +138,44 @@ private void load() { beatmapAvailabilityTracker, new MultiplayerRoomSounds(), - new GridContainer + new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING, }, - RowDimensions = new[] + Child = new InverseScalingDrawSizePreservingFillContainer { - new Dimension(), - new Dimension(GridSizeMode.Absolute, row_padding), - new Dimension(GridSizeMode.AutoSize), - }, - Content = new Drawable[]?[] - { - [ - new ScreenStack(), - ], - null, - [ - new Container + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] { - Name = "Chat Area Space", - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Size = new Vector2(550, 130), - Margin = new MarginPadding { Bottom = row_padding } + new Dimension(), + new Dimension(GridSizeMode.Absolute, row_padding), + new Dimension(GridSizeMode.AutoSize), + }, + Content = new Drawable[]?[] + { + [ + new ScreenStack(), + ], + null, + [ + new Container + { + Name = "Chat Area Space", + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Size = new Vector2(550, 130), + Margin = new MarginPadding { Bottom = row_padding } + } + ] } - ] + } } } } @@ -472,9 +482,28 @@ public ChatContainer(MatchmakingChatDisplay chat) InternalChild = new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, - Child = chat + Child = new InverseScalingDrawSizePreservingFillContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Child = chat + } }; } } + + private partial class InverseScalingDrawSizePreservingFillContainer : ScalingContainer.ScalingDrawSizePreservingFillContainer + { + public InverseScalingDrawSizePreservingFillContainer() + : base(true) + { + } + + protected override void Update() + { + Size = new Vector2(CurrentScale); + Scale = new Vector2(1 / CurrentScale); + } + } } } From 07817dce70e8251e2ccfe73c2965c424a3eb42b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Dec 2025 14:28:08 +0900 Subject: [PATCH 263/836] Expose notification main content for external use --- osu.Game/Overlays/Notifications/Notification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 8a2a7cee8127..dd4e1cb3b0de 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -76,7 +76,7 @@ public abstract partial class Notification : Container protected override Container Content => content; - protected Container MainContent; + public Container MainContent; private readonly DragContainer dragContainer; From 3b635f691958ebbceecbf5e07c6805a23b56feab Mon Sep 17 00:00:00 2001 From: AV <66049742+aviollaz@users.noreply.github.com> Date: Wed, 17 Dec 2025 02:40:08 -0300 Subject: [PATCH 264/836] Prevent mod track adjustments from modifying BGM speed in queue (#36027) * Fix(Matchmaking): Prevent mod track adjustments from applying BGM speed in queue * replaced modification of MusicController directly with a property change. * formatted --- osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs index e446a8534465..8dcd8f58f55a 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs @@ -43,6 +43,8 @@ public partial class ScreenQueue : OsuScreen { public override bool ShowFooter => true; + public override bool? ApplyModTrackAdjustments => false; + private Container mainContent = null!; private MatchmakingScreenState state; From b07cd2daa4de24100d7097eb107006d57536e27b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Dec 2025 16:38:46 +0900 Subject: [PATCH 265/836] Remove beat sync from skip / break overlay This didn't end up feeling as good as I hoped. Will revise at a later stage, adding beat sync in another way that isn't jank transforms on the progress bars. Also closes https://github.com/ppy/osu/issues/35972. --- osu.Game/Screens/Play/BreakOverlay.cs | 33 +++------------------------ osu.Game/Screens/Play/SkipOverlay.cs | 18 ++------------- 2 files changed, 5 insertions(+), 46 deletions(-) diff --git a/osu.Game/Screens/Play/BreakOverlay.cs b/osu.Game/Screens/Play/BreakOverlay.cs index 234daece5e89..73f887bfe6e0 100644 --- a/osu.Game/Screens/Play/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreakOverlay.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -10,10 +9,9 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; -using osu.Game.Beatmaps.ControlPoints; +using osu.Framework.Utils; using osu.Game.Beatmaps.Timing; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play.Break; @@ -21,7 +19,7 @@ namespace osu.Game.Screens.Play { - public partial class BreakOverlay : BeatSyncedContainer + public partial class BreakOverlay : Container { /// /// The duration of the break overlay fading. @@ -51,12 +49,6 @@ public BreakOverlay(ScoreProcessor scoreProcessor) this.scoreProcessor = scoreProcessor; RelativeSizeAxes = Axes.Both; - MinimumBeatLength = 200; - - // Doesn't play well with pause/unpause. - // This might mean that some beats don't animate if the user is running <60fps, but we'll deal with that if anyone notices. - AllowMistimedEventFiring = false; - Child = fadeContainer = new Container { Alpha = 0, @@ -142,25 +134,8 @@ protected override void Update() { base.Update(); + remainingTimeBox.Width = (float)Interpolation.DampContinuously(remainingTimeBox.Width, remainingTimeForCurrentPeriod, 40, Math.Abs(Time.Elapsed)); remainingTimeBox.Height = Math.Min(8, remainingTimeBox.DrawWidth); - - // Keep things simple by resetting beat synced transforms on a rewind. - if (Clock.ElapsedFrameTime < 0) - { - remainingTimeBox.ClearTransforms(targetMember: nameof(Width)); - remainingTimeBox.Width = remainingTimeForCurrentPeriod; - } - } - - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) - { - base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); - - if (currentPeriod.Value == null) - return; - - float timeBoxTargetWidth = (float)Math.Max(0, remainingTimeForCurrentPeriod - timingPoint.BeatLength / currentPeriod.Value.Value.Duration); - remainingTimeBox.ResizeWidthTo(timeBoxTargetWidth, timingPoint.BeatLength * 3.5, Easing.OutQuint); } private void updateDisplay(ValueChangedEvent period) @@ -182,8 +157,6 @@ private void updateDisplay(ValueChangedEvent period) .Delay(b.Duration) .ResizeWidthTo(0); - remainingTimeBox.ResizeWidthTo(remainingTimeForCurrentPeriod); - remainingTimeCounter.CountTo(b.Duration + BREAK_FADE_DURATION).CountTo(0, b.Duration + BREAK_FADE_DURATION); remainingTimeCounter.MoveToX(-50) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index f9752706ade5..a7cea71142a0 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -9,7 +9,6 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; -using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -20,7 +19,6 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Utils; -using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Containers; @@ -32,7 +30,7 @@ namespace osu.Game.Screens.Play { - public partial class SkipOverlay : BeatSyncedContainer, IKeyBindingHandler + public partial class SkipOverlay : Container, IKeyBindingHandler { /// /// The total number of successful skips performed by this overlay. @@ -191,7 +189,7 @@ protected override void Update() double progress = Math.Max(0, 1 - (gameplayClock.CurrentTime - displayTime) / (fadeOutBeginTime - displayTime)); - RemainingTimeBox.Width = (float)Interpolation.Lerp(RemainingTimeBox.Width, progress, Math.Clamp(Time.Elapsed / 40, 0, 1)); + RemainingTimeBox.Width = (float)Interpolation.DampContinuously(RemainingTimeBox.Width, progress, 40, Math.Abs(Time.Elapsed)); inSkipPeriod.Value = progress > 0; buttonContainer.State.Value = inSkipPeriod.Value ? Visibility.Visible : Visibility.Hidden; @@ -227,18 +225,6 @@ public void OnReleased(KeyBindingReleaseEvent e) { } - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) - { - base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); - - if (fadeOutBeginTime <= gameplayClock.CurrentTime) - return; - - float progress = (float)(gameplayClock.CurrentTime - displayTime) / (float)(fadeOutBeginTime - displayTime); - float newWidth = 1 - Math.Clamp(progress, 0, 1); - RemainingTimeBox.ResizeWidthTo(newWidth, timingPoint.BeatLength * 3.5, Easing.OutQuint); - } - public partial class FadeContainer : Container, IStateful { [CanBeNull] From f581f85eb20a1b26680ede6bbeae103d878abeb9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Dec 2025 18:47:52 +0900 Subject: [PATCH 266/836] Adjust editor seeking to be fairer when track is playing The previous multiplier was supposed to account for seeking backwards being "slower" because the track is playing forwards, but it really didn't work amazingly. Rather than trying to pull off some magic, let's just ensure that seeks in both directions feel correct, even if that means that time gradually moves forwards. Closes https://github.com/ppy/osu/issues/35998 (mostly). Of note, this still doesn't match stable completely. I attempted to implement the full stable seeking algorithm but it's objectively worse in other scenarios, so I'd rather just tweak what we have until the majority of users are happy. --- osu.Game/Screens/Edit/EditorClock.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index 8b9bdb595d78..4f700f2316f3 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -96,7 +96,7 @@ public bool SeekSnapped(double position) /// /// Whether to snap to the closest beat after seeking. /// The relative amount (magnitude) which should be seeked. - public void SeekBackward(bool snapped = false, double amount = 1) => seek(-1, snapped, amount + (IsRunning ? 1.5 : 0)); + public void SeekBackward(bool snapped = false, double amount = 1) => seek(-1, snapped, amount); /// /// Seeks forwards by one beat length. @@ -113,6 +113,16 @@ private void seek(int direction, bool snapped, double amount = 1) var timingPoint = ControlPointInfo.TimingPointAt(current); + if (IsRunning) + { + // when track is playing, seek a bit more than usual. + // the amount adjusted matches stable, because don't-break-what-works. + // https://github.com/peppy/osu-stable-reference/blob/7519cafd1823f1879c0d9c991ba0e5c7fd3bfa02/osu!/GameModes/Edit/Editor.cs#L1639-L1640 + // + // ReSharper disable once PossibleLossOfFraction + amount *= 1 + 250 / (int)timingPoint.BeatLength; + } + if (direction < 0 && timingPoint.Time == current) // When going backwards and we're at the boundary of two timing points, we compute the seek distance with the timing point which we are seeking into timingPoint = ControlPointInfo.TimingPointAt(current - 1); From 5f9639fc3f9f8c2aa0a8ee96cb50379a0639367b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Dec 2025 19:32:07 +0900 Subject: [PATCH 267/836] Fix inspections --- .../Visual/Playlists/TestSceneAddToPlaylistFooterButton.cs | 2 +- osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs | 3 +-- .../OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestSceneAddToPlaylistFooterButton.cs b/osu.Game.Tests/Visual/Playlists/TestSceneAddToPlaylistFooterButton.cs index a693738ad613..b504671c9928 100644 --- a/osu.Game.Tests/Visual/Playlists/TestSceneAddToPlaylistFooterButton.cs +++ b/osu.Game.Tests/Visual/Playlists/TestSceneAddToPlaylistFooterButton.cs @@ -9,7 +9,7 @@ namespace osu.Game.Tests.Visual.Playlists { - public class TestSceneAddToPlaylistFooterButton : OsuTestScene + public partial class TestSceneAddToPlaylistFooterButton : OsuTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs index 5efb85915749..e64d74ecba42 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs @@ -13,13 +13,12 @@ namespace osu.Game.Tests.Visual.Playlists public partial class TestScenePlaylistTray : OnlinePlayTestScene { private Room room = null!; - private PlaylistsSongSelectV2.PlaylistTray tray = null!; public override void SetUpSteps() { base.SetUpSteps(); - AddStep("add tray", () => Child = tray = new PlaylistsSongSelectV2.PlaylistTray(room = new Room()) + AddStep("add tray", () => Child = new PlaylistsSongSelectV2.PlaylistTray(room = new Room()) { Anchor = Anchor.Centre, Origin = Anchor.Centre diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs index f2c210b33bc9..b237e707f890 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.ComponentModel; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; From b71a26fcecf3fa70d7b2743c47a75bcedd91b199 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Dec 2025 19:51:42 +0900 Subject: [PATCH 268/836] Adjust tray to feel better --- .../Playlists/PlaylistsRoomSettingsOverlay.cs | 2 +- .../PlaylistsSongSelectV2.PlaylistTray.cs | 145 ++++++++++++------ .../Playlists/PlaylistsSongSelectV2.cs | 8 +- 3 files changed, 100 insertions(+), 55 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index 9c0363f40ed1..378410d77df0 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -241,7 +241,7 @@ private void load(OverlayColourProvider colourProvider, OsuColour colours) { RelativeSizeAxes = Axes.X, Height = 40, - Text = "Edit playlist", + Text = "+ Add more beatmaps", Action = () => EditPlaylist?.Invoke() } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs index b237e707f890..1b44106e36b2 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs @@ -3,15 +3,19 @@ using System.ComponentModel; using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online.Rooms; +using osu.Game.Overlays; using osuTK; -using osuTK.Graphics; +using Container = osu.Framework.Graphics.Containers.Container; namespace osu.Game.Screens.OnlinePlay.Playlists { @@ -23,64 +27,101 @@ public partial class PlaylistTray : CompositeDrawable private OsuScrollContainer scroll = null!; private FillFlowContainer flow = null!; + private OsuSpriteText text = null!; public PlaylistTray(Room room) { this.room = room; - - Size = new Vector2(400, 75); } [BackgroundDependencyLoader] - private void load() + private void load(OverlayColourProvider colourProvider) { + Size = new Vector2(500, 75); + Masking = true; CornerRadius = 20; + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = colourProvider.Background6.Opacity(0.2f), + Offset = new Vector2(2), + Radius = 8, + }; - InternalChildren = new Drawable[] + InternalChild = new BufferedContainer(pixelSnapping: true) { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.9f - }, - new GridContainer + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.X, - Height = DrawableRoomPlaylistItem.HEIGHT, - Padding = new MarginPadding { Horizontal = 20 }, - ColumnDimensions = new[] + new Box { - new Dimension(GridSizeMode.AutoSize), - new Dimension() + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background3, }, - Content = new[] + new GridContainer { - new Drawable[] + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Height = DrawableRoomPlaylistItem.HEIGHT, + Padding = new MarginPadding { Horizontal = 10 }, + ColumnDimensions = new[] { - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Text = "Playlist", - Font = OsuFont.Default.With(size: 20) - }, - scroll = new OsuScrollContainer(Direction.Horizontal) + new Dimension(GridSizeMode.AutoSize), + new Dimension() + }, + Content = new[] + { + new Drawable[] { - RelativeSizeAxes = Axes.Both, - Margin = new MarginPadding { Left = 10 }, - ScrollbarVisible = false, - Child = flow = new FillFlowContainer + new Container { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Direction = FillDirection.Horizontal - } - } - }, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + text = new OsuSpriteText + { + Font = OsuFont.Style.Heading2, + }, + new OsuSpriteText + { + Y = 20, + Font = OsuFont.Style.Caption2, + Text = "Manage items on previous screen" + }, + } + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + scroll = new OsuScrollContainer(Direction.Horizontal) + { + RelativeSizeAxes = Axes.Both, + ScrollbarVisible = false, + Child = flow = new FillFlowContainer + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Spacing = new Vector2(5), + Direction = FillDirection.Horizontal + } + }, + new Box + { + Colour = ColourInfo.GradientHorizontal(colourProvider.Background3, colourProvider.Background3.Opacity(0)), + RelativeSizeAxes = Axes.Y, + X = -1, + Width = 60, + }, + } + }, + }, + } } } }; @@ -92,6 +133,8 @@ protected override void LoadComplete() room.PropertyChanged += onRoomPropertyChanged; updateRoomPlaylist(); + + this.FadeOut(); } private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e) @@ -104,19 +147,27 @@ private void updateRoomPlaylist() { if (room.Playlist.Count > 0) { - flow.Add(new DrawableRoomPlaylistItem(room.Playlist[^1], loadImmediately: true) + var newItem = new DrawableRoomPlaylistItem(room.Playlist[^1], loadImmediately: true) { RelativeSizeAxes = Axes.None, Width = 250, AllowReordering = false, - }); - } + }; - scroll.ScrollToStart(animated: false); + if (flow.Count > 1) + flow[0].Expire(); + + flow.Add(newItem); + + scroll.ScrollToStart(animated: false); + ScheduleAfterChildren(() => scroll.ScrollToEnd()); + + Scheduler.AddDelayed(() => text.Text = $"{room.Playlist.Count} item(s)", 100); + } - this.FadeIn(200); - ScheduleAfterChildren(() => scroll.ScrollToEnd()); - this.Delay(1000).FadeOut(200); + this.FadeIn(200) + .Delay(2000) + .FadeOut(200); } // Disallow the user from interacting with the scrolling elements. diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index 2ceecf69850a..b1adcadbc0c8 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -149,13 +149,7 @@ private void updateValidMods() freeModSelect.IsValidMod = isValidAllowedMod; } - protected override void OnStart() - { - if (room.Playlist.Count <= 1) - room.Playlist = [createItem()]; - - this.Exit(); - } + protected override void OnStart() => AddNewItem(); public override void OnEntering(ScreenTransitionEvent e) { From 5bf6a75b50527edfe97b9e1705b7dd9a04e1c02e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 17 Dec 2025 11:21:50 +0100 Subject: [PATCH 269/836] Add ability to view other beatmaps in set when difficulties are split apart First part of https://github.com/ppy/osu/issues/36039, see also https://github.com/ppy/osu/discussions/33784. The goal is to add this back to the set panels too, but that one is more complicated than this if you can believe it (because it requires being able to tell which other difficulties of the set are filtered out to fade them out). I also foresee the display logic to vary significantly there. Of note, for this to work in beatmaps-split-apart mode, this requires a change of behaviour in the filtering logic. Old song select when given a "selected beatmap set" would *include* that in results regardless of the filter, but that doesn't work for beatmaps-split-apart for reasons that are hopefully obvious, so this changes the behaviour to *entirely bypass* the filter and just show the set. Unsure how angry will people be with that. Also of note, when in the scoped mode, altering any filter criteria will dismiss the scope. --- .../TestSceneSongSelectFiltering.cs | 25 ++ osu.Game/Localisation/SongSelectStrings.cs | 5 + .../SelectV2/BeatmapCarouselFilterMatching.cs | 4 +- .../FilterControl.ScopedBeatmapSetDisplay.cs | 124 +++++++++ osu.Game/Screens/SelectV2/FilterControl.cs | 20 +- osu.Game/Screens/SelectV2/ISongSelect.cs | 6 + .../PanelBeatmapStandalone.SpreadDisplay.cs | 255 ++++++++++++++++++ .../SelectV2/PanelBeatmapStandalone.cs | 15 +- osu.Game/Screens/SelectV2/SongSelect.cs | 2 + 9 files changed, 446 insertions(+), 10 deletions(-) create mode 100644 osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs create mode 100644 osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs index eeeb6f72975c..e5d537d84e87 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs @@ -17,6 +17,7 @@ using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.Select.Filter; using osu.Game.Screens.SelectV2; +using osuTK.Input; using FilterControl = osu.Game.Screens.SelectV2.FilterControl; using NoResultsPlaceholder = osu.Game.Screens.SelectV2.NoResultsPlaceholder; @@ -354,6 +355,30 @@ public void TestCantHideAllBeatmaps() checkMatchedBeatmaps(1); } + [Test] + public void TestScopeToBeatmapWhenDifficultiesSplitApart() + { + ImportBeatmapForRuleset(0); + ImportBeatmapForRuleset(0); + + LoadSongSelect(); + SortBy(SortMode.Difficulty); + checkMatchedBeatmaps(6); + + AddUntilStep("wait for spread indicator", () => this.ChildrenOfType().Any(d => d.Enabled.Value)); + AddStep("click spread indicator", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single(d => d.Enabled.Value)); + InputManager.Click(MouseButton.Left); + }); + WaitForFiltering(); + checkMatchedBeatmaps(3); + + AddStep("press Escape", () => InputManager.Key(Key.Escape)); + WaitForFiltering(); + checkMatchedBeatmaps(6); + } + private NoResultsPlaceholder? getPlaceholder() => SongSelect.ChildrenOfType().FirstOrDefault(); private void checkMatchedBeatmaps(int expected) => AddUntilStep($"{expected} matching shown", () => Carousel.MatchedBeatmapsCount, () => Is.EqualTo(expected)); diff --git a/osu.Game/Localisation/SongSelectStrings.cs b/osu.Game/Localisation/SongSelectStrings.cs index f84683ac63dc..e963b5a85ab5 100644 --- a/osu.Game/Localisation/SongSelectStrings.cs +++ b/osu.Game/Localisation/SongSelectStrings.cs @@ -259,6 +259,11 @@ public static class SongSelectStrings /// public static LocalisableString NoMatchingBeatmapsDescription => new TranslatableString(getKey(@"no_matching_beatmaps_description"), @"No beatmaps match your filter criteria!"); + /// + /// "Temporarily showing all beatmaps in" + /// + public static LocalisableString TemporarilyShowingAllBeatmapsIn => new TranslatableString(getKey(@"temporarily_showing_all_beatmaps_in"), @"Temporarily showing all beatmaps in"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs b/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs index 2a132a8a4524..31e6c790f2e7 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs @@ -56,10 +56,10 @@ private static bool checkCriteriaMatch(BeatmapInfo beatmap, FilterCriteria crite { bool match = criteria.Ruleset == null || beatmap.AllowGameplayWithRuleset(criteria.Ruleset!, criteria.AllowConvertedBeatmaps); - if (beatmap.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true) + if (criteria.SelectedBeatmapSet != null) { // only check ruleset equality or convertability for selected beatmap - return match; + return beatmap.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true && match; } if (!match) return false; diff --git a/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs b/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs new file mode 100644 index 000000000000..a3ec9c0ff7b9 --- /dev/null +++ b/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs @@ -0,0 +1,124 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Input.Bindings; +using osu.Game.Localisation; +using osu.Game.Overlays; + +namespace osu.Game.Screens.SelectV2 +{ + public partial class FilterControl + { + public partial class ScopedBeatmapSetDisplay : CompositeDrawable, IKeyBindingHandler + { + public Bindable ScopedBeatmapSet + { + get => scopedBeatmapSet.Current; + set => scopedBeatmapSet.Current = value; + } + + private readonly BindableWithCurrent scopedBeatmapSet = new BindableWithCurrent(); + private Container content = null!; + private OsuTextFlowContainer text = null!; + private ShearedButton goBackButton = null!; + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + AutoSizeEasing = Easing.OutQuint; + AutoSizeDuration = 200; + CornerRadius = 8f; + Masking = true; + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Highlight1, + }, + content = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + BypassAutoSizeAxes = Axes.Y, + Shear = -OsuGame.SHEAR, + Padding = new MarginPadding + { + Horizontal = 6, + Vertical = 2, + }, + Children = new Drawable[] + { + text = new OsuTextFlowContainer(t => t.Font = OsuFont.Style.Body) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Colour = colourProvider.Background6, + Padding = new MarginPadding { Right = 80, Vertical = 5 } + }, + goBackButton = new ShearedButton(80) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Text = CommonStrings.Back, + RelativeSizeAxes = Axes.Y, + Height = 1, + Action = () => scopedBeatmapSet.Value = null, + } + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + scopedBeatmapSet.BindValueChanged(_ => updateState(), true); + } + + private void updateState() + { + content.BypassAutoSizeAxes = scopedBeatmapSet.Value != null ? Axes.None : Axes.Y; + + if (scopedBeatmapSet.Value != null) + { + text.Clear(); + text.AddText(SongSelectStrings.TemporarilyShowingAllBeatmapsIn); + text.AddText(@" "); + text.AddText(scopedBeatmapSet.Value.Metadata.GetDisplayTitleRomanisable(), t => t.Font = OsuFont.Style.Body.With(weight: FontWeight.Bold)); + } + } + + public bool OnPressed(KeyBindingPressEvent e) + { + if (scopedBeatmapSet.Value != null && e.Action == GlobalAction.Back && !e.Repeat) + { + goBackButton.TriggerClick(); + return true; + } + + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + } + } + } +} diff --git a/osu.Game/Screens/SelectV2/FilterControl.cs b/osu.Game/Screens/SelectV2/FilterControl.cs index a90ac3a4e865..2df2dcdc131c 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.cs +++ b/osu.Game/Screens/SelectV2/FilterControl.cs @@ -12,6 +12,7 @@ using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Game.Beatmaps; using osu.Game.Collections; using osu.Game.Configuration; using osu.Game.Database; @@ -37,6 +38,8 @@ public partial class FilterControl : OverlayContainer private const float corner_radius = 10; + public Bindable ScopedBeatmapSet { get; } = new Bindable(); + private SongSelectSearchTextBox searchTextBox = null!; private ShearedToggleButton showConvertedBeatmapsButton = null!; private DifficultyRangeSlider difficultyRangeSlider = null!; @@ -158,6 +161,7 @@ private void load(IAPIProvider api) new Dimension(maxSize: 180), new Dimension(GridSizeMode.Absolute, 5), new Dimension(), + new Dimension(GridSizeMode.AutoSize), }, Content = new[] { @@ -182,6 +186,10 @@ private void load(IAPIProvider api) } } }, + new ScopedBeatmapSetDisplay + { + ScopedBeatmapSet = ScopedBeatmapSet, + } }, } }; @@ -240,6 +248,7 @@ protected override void LoadComplete() localUser.BindValueChanged(_ => updateCriteria()); localUserFavouriteBeatmapSets.BindCollectionChanged((_, _) => updateCriteria()); + ScopedBeatmapSet.BindValueChanged(_ => updateCriteria(clearScopedSet: false)); updateCriteria(); } @@ -260,6 +269,7 @@ public FilterCriteria CreateCriteria() var criteria = new FilterCriteria { + SelectedBeatmapSet = ScopedBeatmapSet.Value, Sort = sortDropdown.Current.Value, Group = groupDropdown.Current.Value, AllowConvertedBeatmaps = showConvertedBeatmapsButton.Active.Value, @@ -282,8 +292,16 @@ public FilterCriteria CreateCriteria() return criteria; } - private void updateCriteria() + private void updateCriteria(bool clearScopedSet = true) { + if (clearScopedSet && ScopedBeatmapSet.Value != null) + { + ScopedBeatmapSet.Value = null; + // because `ScopedBeatmapSet` has a value change callback bound to it that calls `updateCriteria()` again, + // we can just do nothing other than clear it to avoid extra work and duplicated `CriteriaChanged` invocations + return; + } + currentCriteria = CreateCriteria(); CriteriaChanged?.Invoke(currentCriteria); } diff --git a/osu.Game/Screens/SelectV2/ISongSelect.cs b/osu.Game/Screens/SelectV2/ISongSelect.cs index e39f74c01876..3fede4401f79 100644 --- a/osu.Game/Screens/SelectV2/ISongSelect.cs +++ b/osu.Game/Screens/SelectV2/ISongSelect.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; using osu.Game.Scoring; @@ -43,5 +44,10 @@ public interface ISongSelect /// Gets relevant actionable items for beatmap context menus, based on the type of song select. /// IEnumerable GetForwardActions(BeatmapInfo beatmap); + + /// + /// Set this to a non- value in order to temporarily bypass filter and show all difficulties of the given beatmap set. + /// + Bindable ScopedBeatmapSet { get; } } } diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs new file mode 100644 index 000000000000..faa5ee5f05d8 --- /dev/null +++ b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs @@ -0,0 +1,255 @@ +// 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.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets; +using osuTK; + +namespace osu.Game.Screens.SelectV2 +{ + public partial class PanelBeatmapStandalone + { + public partial class SpreadDisplay : OsuAnimatedButton + { + public Bindable Beatmap { get; } = new Bindable(); + public Bindable StarDifficulty { get; } = new Bindable(); + + private readonly Bindable scopedBeatmapSet = new Bindable(); + private readonly Bindable showConvertedBeatmaps = new Bindable(); + + private const double transition_duration = 200; + + [Resolved] + private Bindable ruleset { get; set; } = null!; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + private FillFlowContainer preceding = null!; + public Circle Current { get; private set; } = null!; + private FillFlowContainer succeeding = null!; + + private OsuSpriteText countText = null!; + private SpriteIcon icon = null!; + + public SpreadDisplay() + { + AutoSizeAxes = Axes.Both; + Content.CornerRadius = 5; + } + + [BackgroundDependencyLoader] + private void load(ISongSelect? songSelect, OsuConfigManager configManager) + { + Add(new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5), + Padding = new MarginPadding { Horizontal = 5 }, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(2), + Children = new Drawable[] + { + preceding = new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(1), + Alpha = 0.5f, + }, + Current = new Circle + { + Size = new Vector2(7, 12), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + succeeding = new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(1), + Alpha = 0.5f, + } + } + }, + countText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.Style.Caption2, + }, + icon = new SpriteIcon + { + Size = new Vector2(12), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Icon = FontAwesome.Solid.Eye, + Alpha = 0, + } + } + }); + + if (songSelect != null) + scopedBeatmapSet.BindTo(songSelect.ScopedBeatmapSet); + + configManager.BindWith(OsuSetting.ShowConvertedBeatmaps, showConvertedBeatmaps); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Beatmap.BindValueChanged(_ => updateBeatmap()); + StarDifficulty.BindValueChanged(_ => updateBeatmap()); + showConvertedBeatmaps.BindValueChanged(_ => updateBeatmap()); + scopedBeatmapSet.BindValueChanged(_ => updateBeatmap(), true); + Enabled.BindValueChanged(_ => updateAppearance(), true); + FinishTransforms(true); + } + + private void updateBeatmap() + { + preceding.Clear(); + succeeding.Clear(); + + if (Beatmap.Value == null || scopedBeatmapSet.Value != null) + { + this.FadeOut(transition_duration, Easing.OutQuint); + return; + } + + var otherStarDifficulties = Beatmap.Value.BeatmapSet!.Beatmaps + .Except([Beatmap.Value]) + .Where(b => b.AllowGameplayWithRuleset(ruleset.Value, showConvertedBeatmaps.Value)) + .OrderBy(b => b.StarRating) + .Select(b => b.StarRating) + .ToList(); + this.FadeTo(otherStarDifficulties.Count > 0 ? 1 : 0, transition_duration, Easing.OutQuint); + + if (otherStarDifficulties.Count == 0) + return; + + const int max_difficulties_total = 11; + + int startIndex; + int endIndex; + + if (otherStarDifficulties.Count <= max_difficulties_total) + { + startIndex = 0; + endIndex = otherStarDifficulties.Count - 1; + } + else + { + startIndex = otherStarDifficulties.BinarySearch(StarDifficulty.Value.Stars); + if (startIndex < 0) + startIndex = ~startIndex - 1; + + startIndex = Math.Clamp(startIndex - max_difficulties_total / 2, 0, otherStarDifficulties.Count - 1); + endIndex = Math.Clamp(startIndex + max_difficulties_total, 0, otherStarDifficulties.Count - 1); + } + + for (int i = startIndex; i <= endIndex; i++) + { + double otherStarDifficulty = otherStarDifficulties[i]; + var target = otherStarDifficulty < StarDifficulty.Value.Stars ? preceding : succeeding; + + var circle = new Circle + { + Size = new Vector2(5, 10), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Colour = colours.ForStarDifficulty(otherStarDifficulty) + }; + target.Add(circle); + target.SetLayoutPosition(circle, (float)otherStarDifficulty); + } + + int countNotShown = otherStarDifficulties.Count - (preceding.Count + succeeding.Count); + countText.Alpha = countNotShown > 0 ? 1 : 0; + countText.Text = $@"+{countNotShown}"; + + if (startIndex > 0) + { + for (int i = 0; i < preceding.Count; ++i) + { + var dot = preceding[i]; + dot.Alpha = (1 + 4 * (float)(i + 1) / preceding.Count) / 5; + } + } + + if (endIndex < otherStarDifficulties.Count - 1) + { + for (int i = 0; i < succeeding.Count; ++i) + { + var dot = succeeding[i]; + dot.Alpha = (1 + 4 * (float)(succeeding.Count - i) / succeeding.Count) / 5; + } + } + + Action = () => scopedBeatmapSet.Value = Beatmap.Value.BeatmapSet!; + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (!Enabled.Value) + return false; + + return base.OnMouseDown(e); + } + + protected override bool OnClick(ClickEvent e) + { + if (!Enabled.Value) + return false; + + return base.OnClick(e); + } + + protected override bool OnHover(HoverEvent e) + { + updateAppearance(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateAppearance(); + base.OnHoverLost(e); + } + + private void updateAppearance() + { + bool isInteractable = Enabled.Value && IsHovered; + + HoverColour = isInteractable ? Colour4.White.Opacity(0.1f) : Colour4.Transparent; + preceding.FadeTo(isInteractable ? 1 : 0.5f, transition_duration, Easing.OutQuint); + succeeding.FadeTo(isInteractable ? 1 : 0.5f, transition_duration, Easing.OutQuint); + icon.FadeTo(isInteractable ? 1 : 0, transition_duration, Easing.OutQuint); + } + } + } +} diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs index 53ade139e224..fdea4575511d 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs @@ -18,7 +18,6 @@ using osu.Game.Graphics.Carousel; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; @@ -65,7 +64,7 @@ public partial class PanelBeatmapStandalone : Panel private ConstrainedIconContainer difficultyIcon = null!; private StarRatingDisplay starRatingDisplay = null!; - private StarCounter starCounter = null!; + private SpreadDisplay spreadDisplay = null!; private PanelLocalRankDisplay localRank = null!; private OsuSpriteText keyCountText = null!; private OsuSpriteText difficultyText = null!; @@ -193,11 +192,11 @@ private void load() Anchor = Anchor.CentreLeft, Scale = new Vector2(0.875f), }, - starCounter = new StarCounter + spreadDisplay = new SpreadDisplay { - Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Scale = new Vector2(0.4f) + Anchor = Anchor.CentreLeft, + Enabled = { BindTarget = Selected } } }, } @@ -239,6 +238,7 @@ protected override void PrepareForUse() authorText.Text = BeatmapsetsStrings.ShowDetailsMappedBy(beatmap.Metadata.Author.Username); computeStarRating(); + spreadDisplay.Beatmap.Value = beatmap; updateKeyCount(); } @@ -252,6 +252,7 @@ protected override void FreeAfterUse() updateButton.BeatmapSet = null; localRank.Beatmap = null; starDifficultyBindable = null; + spreadDisplay.Beatmap.Value = null; starDifficultyCancellationSource?.Cancel(); } @@ -268,7 +269,7 @@ private void computeStarRating() starDifficultyBindable.BindValueChanged(starDifficulty => { starRatingDisplay.Current.Value = starDifficulty.NewValue; - starCounter.Current = (float)starDifficulty.NewValue.Stars; + spreadDisplay.StarDifficulty.Value = starDifficulty.NewValue; }, true); } @@ -289,7 +290,7 @@ protected override void Update() var diffColour = starRatingDisplay.DisplayedDifficultyColour; AccentColour = diffColour; - starCounter.Colour = diffColour; + spreadDisplay.Current.Colour = diffColour; backgroundBorder.Colour = diffColour; difficultyIcon.Colour = starRatingDisplay.DisplayedStars.Value > OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF ? colours.Orange1 : colourProvider.Background5; diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index ab3375e23e25..944c93bd5f60 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -1204,6 +1204,8 @@ public void RestoreAllHidden(BeatmapSetInfo beatmapSet) beatmaps.Restore(b); } + public Bindable ScopedBeatmapSet => filterControl.ScopedBeatmapSet; + #endregion } } From c120f0ebab63d8c68a2ce2bac6359908f2b09987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 17 Dec 2025 13:20:51 +0100 Subject: [PATCH 270/836] Fix license header --- .../Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs b/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs index a3ec9c0ff7b9..d09c0ff3e312 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs +++ b/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; From 61ecd18d2491697c77ef73f47d02472c6b7ed5a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Dec 2025 02:20:10 +0900 Subject: [PATCH 271/836] Merry christmas --- osu.Game/Seasonal/SeasonalUIConfig.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Seasonal/SeasonalUIConfig.cs b/osu.Game/Seasonal/SeasonalUIConfig.cs index b894a42108c1..060913a8bf0b 100644 --- a/osu.Game/Seasonal/SeasonalUIConfig.cs +++ b/osu.Game/Seasonal/SeasonalUIConfig.cs @@ -11,7 +11,7 @@ namespace osu.Game.Seasonal /// public static class SeasonalUIConfig { - public static readonly bool ENABLED = false; + public static readonly bool ENABLED = true; public static readonly Color4 PRIMARY_COLOUR_1 = Color4Extensions.FromHex(@"D32F2F"); From 2e7edf8c1f84bdde00e8986307e89e303646063d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 18 Dec 2025 14:07:58 +0900 Subject: [PATCH 272/836] Also apply to queue screen --- ...eScalingDrawSizePreservingFillContainer.cs | 22 +++++ .../Matchmaking/Match/ScreenMatchmaking.cs | 15 ---- .../Matchmaking/Queue/ScreenQueue.cs | 86 ++++++++++--------- 3 files changed, 67 insertions(+), 56 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/InverseScalingDrawSizePreservingFillContainer.cs diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/InverseScalingDrawSizePreservingFillContainer.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/InverseScalingDrawSizePreservingFillContainer.cs new file mode 100644 index 000000000000..8e151021104f --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/InverseScalingDrawSizePreservingFillContainer.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Graphics.Containers; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking +{ + public partial class InverseScalingDrawSizePreservingFillContainer : ScalingContainer.ScalingDrawSizePreservingFillContainer + { + public InverseScalingDrawSizePreservingFillContainer() + : base(true) + { + } + + protected override void Update() + { + Size = new Vector2(CurrentScale); + Scale = new Vector2(1 / CurrentScale); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs index 84af33c2ba6b..a689ac85eece 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs @@ -20,7 +20,6 @@ using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Database; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; @@ -491,19 +490,5 @@ public ChatContainer(MatchmakingChatDisplay chat) }; } } - - private partial class InverseScalingDrawSizePreservingFillContainer : ScalingContainer.ScalingDrawSizePreservingFillContainer - { - public InverseScalingDrawSizePreservingFillContainer() - : base(true) - { - } - - protected override void Update() - { - Size = new Vector2(CurrentScale); - Scale = new Vector2(1 / CurrentScale); - } - } } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs index e446a8534465..27c3fe9978df 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs @@ -93,51 +93,55 @@ protected override void LoadComplete() { base.LoadComplete(); - InternalChildren = new Drawable[] + InternalChild = new InverseScalingDrawSizePreservingFillContainer { - cloud = new CloudVisualisation + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - Y = -100, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.6f) - }, - new MatchmakingAvatar(api.LocalUser.Value, true) - { - Y = -100, - Scale = new Vector2(3), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - new Container - { - RelativePositionAxes = Axes.Y, - Y = 0.25f, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - CornerRadius = 10f, - Masking = true, - Children = new Drawable[] + cloud = new CloudVisualisation { - new Box - { - Colour = colourProvider.Background3, - RelativeSizeAxes = Axes.Both, - }, - mainContent = new Container + Y = -100, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.6f) + }, + new MatchmakingAvatar(api.LocalUser.Value, true) + { + Y = -100, + Scale = new Vector2(3), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new Container + { + RelativePositionAxes = Axes.Y, + Y = 0.25f, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + CornerRadius = 10f, + Masking = true, + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Alpha = 0, - AutoSizeAxes = Axes.Both, - AutoSizeDuration = 300, - AutoSizeEasing = Easing.OutQuint, - Padding = new MarginPadding(20), - }, - } - }, + new Box + { + Colour = colourProvider.Background3, + RelativeSizeAxes = Axes.Both, + }, + mainContent = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + AutoSizeAxes = Axes.Both, + AutoSizeDuration = 300, + AutoSizeEasing = Easing.OutQuint, + Padding = new MarginPadding(20), + }, + } + }, + } }; currentState.BindTo(controller.CurrentState); From 83ddcf7b029d98d566a4810d953997d991bdbd97 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Dec 2025 16:00:23 +0900 Subject: [PATCH 273/836] Fix github side inspection --- osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs index 27c3fe9978df..a4bee1a0ad0f 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs @@ -478,7 +478,7 @@ protected override void LoadComplete() private partial class SelectionButton : ShearedButton, IKeyBindingHandler { - public SelectionButton(float? width = null, float height = DEFAULT_HEIGHT) + protected SelectionButton(float? width = null, float height = DEFAULT_HEIGHT) : base(width, height) { } From 8da1fde981953f286a044db71eafb005da83f8e2 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 18 Dec 2025 04:08:13 -0500 Subject: [PATCH 274/836] Add osu!-style undo icon --- osu.Game/Graphics/OsuIcon.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Graphics/OsuIcon.cs b/osu.Game/Graphics/OsuIcon.cs index 0cf2acadda63..a02c61128528 100644 --- a/osu.Game/Graphics/OsuIcon.cs +++ b/osu.Game/Graphics/OsuIcon.cs @@ -28,6 +28,7 @@ public static class OsuIcon public static IconUsage EditCircle => get(OsuIconMapping.EditCircle); public static IconUsage LeftCircle => get(OsuIconMapping.LeftCircle); public static IconUsage RightCircle => get(OsuIconMapping.RightCircle); + public static IconUsage Undo => get(OsuIconMapping.Undo); public static IconUsage Audio => get(OsuIconMapping.Audio); public static IconUsage Beatmap => get(OsuIconMapping.Beatmap); @@ -386,6 +387,9 @@ private enum OsuIconMapping [Description(@"twitter")] Twitter, + [Description(@"undo")] + Undo, + [Description(@"user-interface")] UserInterface, From 729cd722bde881a0d5184d4cb155089560b779ee Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 18 Dec 2025 04:08:01 -0500 Subject: [PATCH 275/836] Expose common interface for form controls --- .../Graphics/UserInterfaceV2/FormCheckBox.cs | 17 ++++++++- .../Graphics/UserInterfaceV2/FormDropdown.cs | 32 ++++++++++++++++- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 20 +++++++++-- .../Graphics/UserInterfaceV2/FormTextBox.cs | 16 ++++++++- .../Graphics/UserInterfaceV2/IFormControl.cs | 35 +++++++++++++++++++ 5 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 osu.Game/Graphics/UserInterfaceV2/IFormControl.cs diff --git a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs index d4cd86010fc2..471168a17f76 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs @@ -1,10 +1,13 @@ // 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.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; @@ -19,7 +22,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { - public partial class FormCheckBox : CompositeDrawable, IHasCurrentValue + public partial class FormCheckBox : CompositeDrawable, IHasCurrentValue, IFormControl { public Bindable Current { @@ -109,6 +112,8 @@ protected override void LoadComplete() updateState(); playSamples(); background.FlashColour(ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark2), 800, Easing.OutQuint); + + ValueChanged?.Invoke(); }); current.BindDisabledChanged(_ => updateState(), true); } @@ -157,5 +162,15 @@ private void updateState() BorderColour = colourProvider.Light4; } } + + public IEnumerable FilterTerms => Caption.Yield(); + + public event Action? ValueChanged; + + public bool IsValueDefault => Current.IsDefault; + + public void SetValueDefault() => Current.SetDefault(); + + public bool IsDisabled => Current.Disabled; } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index d47b9ac73de1..7d21db1455c4 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -2,7 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Extensions; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -17,7 +20,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { - public partial class FormDropdown : OsuDropdown + public partial class FormDropdown : OsuDropdown, IFormControl { /// /// Caption describing this slider bar, displayed on top of the controls. @@ -40,6 +43,31 @@ private void load() header.HintText = HintText; } + protected override void LoadComplete() + { + base.LoadComplete(); + Current.BindValueChanged(_ => ValueChanged?.Invoke()); + } + + public virtual IEnumerable FilterTerms + { + get + { + yield return Caption; + + foreach (var item in Items) + yield return item?.ToString() ?? string.Empty; + } + } + + public event Action? ValueChanged; + + public bool IsValueDefault => Current.IsDefault; + + public void SetValueDefault() => Current.SetDefault(); + + public bool IsDisabled => Current.Disabled; + protected override DropdownHeader CreateHeader() => header = new FormDropdownHeader { Dropdown = this, @@ -243,6 +271,8 @@ private void load(OverlayColourProvider colourProvider) public partial class FormEnumDropdown : FormDropdown where T : struct, Enum { + public override IEnumerable FilterTerms => base.FilterTerms.Concat(Items.Select(i => i.GetLocalisableDescription())); + public FormEnumDropdown() { Items = Enum.GetValues(); diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 8ebaf48ed6af..ef8227c12ed2 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Globalization; using System.Numerics; using osu.Framework.Allocation; @@ -22,7 +23,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { - public partial class FormSliderBar : CompositeDrawable, IHasCurrentValue + public partial class FormSliderBar : CompositeDrawable, IHasCurrentValue, IFormControl where T : struct, INumber, IMinMaxValue { public Bindable Current @@ -194,7 +195,12 @@ protected override void LoadComplete() slider.IsDragging.BindValueChanged(_ => updateState()); slider.Focused.BindValueChanged(_ => updateState()); - current.ValueChanged += e => currentNumberInstantaneous.Value = e.NewValue; + current.ValueChanged += e => + { + currentNumberInstantaneous.Value = e.NewValue; + ValueChanged?.Invoke(); + }; + current.MinValueChanged += v => currentNumberInstantaneous.MinValue = v; current.MaxValueChanged += v => currentNumberInstantaneous.MaxValue = v; current.PrecisionChanged += v => currentNumberInstantaneous.Precision = v; @@ -475,5 +481,15 @@ protected override bool OnDoubleClick(DoubleClickEvent e) return true; } } + + public IEnumerable FilterTerms => new[] { Caption, HintText }; + + public event Action? ValueChanged; + + public bool IsValueDefault => Current.IsDefault; + + public void SetValueDefault() => Current.SetDefault(); + + public bool IsDisabled => Current.Disabled; } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs index 973419310c0c..41ea5242bd05 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs @@ -2,9 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -20,7 +22,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { - public partial class FormTextBox : CompositeDrawable, IHasCurrentValue + public partial class FormTextBox : CompositeDrawable, IHasCurrentValue, IFormControl { public Bindable Current { @@ -157,6 +159,8 @@ protected override void LoadComplete() focusManager = GetContainingFocusManager()!; textBox.Focused.BindValueChanged(_ => updateState()); + + current.BindValueChanged(_ => ValueChanged?.Invoke()); current.BindDisabledChanged(_ => updateState(), true); } @@ -247,5 +251,15 @@ protected override void NotifyInputError() OnInputError?.Invoke(); } } + + public event Action? ValueChanged; + + public bool IsValueDefault => current.IsDefault; + + public void SetValueDefault() => current.SetDefault(); + + public bool IsDisabled => current.Disabled; + + public IEnumerable FilterTerms => Caption.Yield(); } } diff --git a/osu.Game/Graphics/UserInterfaceV2/IFormControl.cs b/osu.Game/Graphics/UserInterfaceV2/IFormControl.cs new file mode 100644 index 000000000000..c967ac76b025 --- /dev/null +++ b/osu.Game/Graphics/UserInterfaceV2/IFormControl.cs @@ -0,0 +1,35 @@ +// 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 osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Graphics.UserInterfaceV2 +{ + /// + /// Represents an interface for all form controls. + /// + public interface IFormControl : IDrawable, IHasFilterTerms + { + /// + /// Invoked when the value of the control has changed. + /// + event Action ValueChanged; + + /// + /// Whether the value of this control is in a default state. + /// + bool IsValueDefault { get; } + + /// + /// If enabled, resets the control to its default state. + /// + void SetValueDefault(); + + /// + /// Whether the control is currently disabled. + /// + bool IsDisabled { get; } + } +} From 78043fa78237fb05ee40c85ce5b9bdc9c60fad80 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 18 Dec 2025 04:09:02 -0500 Subject: [PATCH 276/836] Implement new settings item component --- osu.Game/Overlays/Settings/SettingsItemV2.cs | 176 ++++++++++++++++++ osu.Game/Overlays/Settings/SettingsNote.cs | 117 ++++++++++++ .../Settings/SettingsRevertToDefaultButton.cs | 95 ++++++++++ osu.Game/Overlays/SettingsPanel.cs | 3 + 4 files changed, 391 insertions(+) create mode 100644 osu.Game/Overlays/Settings/SettingsItemV2.cs create mode 100644 osu.Game/Overlays/Settings/SettingsNote.cs create mode 100644 osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs diff --git a/osu.Game/Overlays/Settings/SettingsItemV2.cs b/osu.Game/Overlays/Settings/SettingsItemV2.cs new file mode 100644 index 000000000000..21df39df3834 --- /dev/null +++ b/osu.Game/Overlays/Settings/SettingsItemV2.cs @@ -0,0 +1,176 @@ +// 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.Collections.Generic; +using System.Linq; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Game.Graphics.UserInterfaceV2; + +namespace osu.Game.Overlays.Settings +{ + public sealed partial class SettingsItemV2 : CompositeDrawable, ISettingsItem, IConditionalFilterable + { + private readonly IFormControl control; + private readonly SettingsRevertToDefaultButton revertButton; + + private readonly BindableBool controlDefault = new BindableBool(true); + private readonly BindableBool controlEnabled = new BindableBool(true); + + /// + /// Whether a revert-to-default button should be displayed. + /// + public bool ShowDefaultRevertButton { get; init; } = true; + + /// + /// A note to display underneath the setting. + /// + public readonly Bindable Note = new Bindable(); + + public SettingsItemV2(IFormControl control) + { + this.control = control; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS_RIGHT }, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new[] + { + revertButton = new SettingsRevertToDefaultButton + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Action = ApplyDefault, + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = (Drawable)control, + } + } + }, + new SettingsNote + { + RelativeSizeAxes = Axes.X, + Current = { BindTarget = Note }, + }, + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + controlDefault.Value = control.IsValueDefault; + controlEnabled.Value = !control.IsDisabled; + + controlDefault.BindValueChanged(_ => updateDefaultState()); + controlEnabled.BindValueChanged(_ => updateDefaultState(), true); + FinishTransforms(true); + } + + private void updateDefaultState() + { + bool showRevertButton = !controlDefault.Value && controlEnabled.Value && ShowDefaultRevertButton; + + if (showRevertButton) + revertButton.Show(); + else + revertButton.Hide(); + } + + protected override void Update() + { + base.Update(); + controlDefault.Value = control.IsValueDefault; + controlEnabled.Value = !control.IsDisabled; + } + + #region ISettingsItem + + public bool HasClassicDefault { get; init; } + + public void ApplyClassicDefault() + { + // will be removed soon. + throw new NotSupportedException(); + } + + public void ApplyDefault() + { + if (!control.IsDisabled) + control.SetValueDefault(); + } + + public event Action SettingChanged + { + add => control.ValueChanged += value; + remove => control.ValueChanged -= value; + } + + #endregion + + #region Filtering + + public const string CLASSIC_DEFAULT_SEARCH_TERM = @"has-classic-default"; + + public IEnumerable Keywords { get; init; } = Enumerable.Empty(); + + public IEnumerable FilterTerms + { + get + { + var filterTerms = new List(Keywords.Select(k => (LocalisableString)k)); + filterTerms.AddRange(control.FilterTerms); + + if (HasClassicDefault) + filterTerms.Add(CLASSIC_DEFAULT_SEARCH_TERM); + + return filterTerms; + } + } + + private bool matchingFilter = true; + + public bool MatchingFilter + { + get => matchingFilter; + set + { + bool wasPresent = IsPresent; + + matchingFilter = value; + + if (IsPresent != wasPresent) + Invalidate(Invalidation.Presence); + } + } + + public override bool IsPresent => base.IsPresent && MatchingFilter; + + public bool FilteringActive { get; set; } + + public BindableBool CanBeShown { get; } = new BindableBool(true); + + IBindable IConditionalFilterable.CanBeShown => CanBeShown; + + #endregion + } +} diff --git a/osu.Game/Overlays/Settings/SettingsNote.cs b/osu.Game/Overlays/Settings/SettingsNote.cs new file mode 100644 index 000000000000..5ddbfa9fcd94 --- /dev/null +++ b/osu.Game/Overlays/Settings/SettingsNote.cs @@ -0,0 +1,117 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Settings +{ + public sealed partial class SettingsNote : CompositeDrawable + { + public readonly Bindable Current = new Bindable(); + + private Box background = null!; + private OsuTextFlowContainer text = null!; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeDuration = 300; + AutoSizeEasing = Easing.OutQuint; + + InternalChild = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Top = 5, Bottom = 5 }, + Child = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + CornerRadius = 5, + CornerExponent = 2.5f, + Masking = true, + Children = new Drawable[] + { + background = new Box + { + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + }, + text = new OsuTextFlowContainer(s => s.Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold)) + { + Padding = new MarginPadding(8), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }, + } + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + Current.BindValueChanged(_ => updateDisplay(), true); + FinishTransforms(true); + } + + private void updateDisplay() + { + ClearTransforms(); + + if (Current.Value == null) + { + AutoSizeAxes = Axes.None; + this.ResizeHeightTo(0, 300, Easing.OutQuint); + this.FadeOut(250, Easing.OutQuint); + return; + } + + AutoSizeAxes = Axes.Y; + this.FadeIn(250, Easing.OutQuint); + + switch (Current.Value.Type) + { + case Type.Informational: + background.Colour = colourProvider.Dark2; + text.Colour = colourProvider.Content2; + break; + + case Type.Warning: + background.Colour = colours.Orange1; + text.Colour = colourProvider.Background5; + break; + + case Type.Critical: + background.Colour = colours.Red1; + text.Colour = colourProvider.Background5; + break; + } + + text.Text = Current.Value.Text; + } + + public record Data(LocalisableString Text, Type Type); + + public enum Type + { + Informational, + Warning, + Critical, + } + } +} diff --git a/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs b/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs new file mode 100644 index 000000000000..305a30a2f5fc --- /dev/null +++ b/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs @@ -0,0 +1,95 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osuTK; + +namespace osu.Game.Overlays.Settings +{ + public partial class SettingsRevertToDefaultButton : OsuClickableContainer + { + public const float WIDTH = 32; + + public float IconSize { get; init; } = 14; + + private Box background = null!; + private SpriteIcon spriteIcon = null!; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + // this is done to ensure a click on this button doesn't trigger focus on a parent element which contains the button. + public override bool AcceptsFocus => true; + + public SettingsRevertToDefaultButton() + { + Size = new Vector2(WIDTH, 50); + } + + [BackgroundDependencyLoader] + private void load() + { + Masking = true; + CornerRadius = 5; + CornerExponent = 2.5f; + + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background3, + }, + spriteIcon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = colourProvider.Light1, + Icon = OsuIcon.Undo, + Margin = new MarginPadding { Left = 12, Right = 5 }, + Size = new Vector2(IconSize), + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + Enabled.BindValueChanged(_ => updateDisplay(), true); + } + + protected override bool OnHover(HoverEvent e) + { + updateDisplay(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateDisplay(); + base.OnHoverLost(e); + } + + public override void Show() + { + this.FadeIn().MoveToX(WIDTH - 10, 300, Easing.OutQuint); + } + + public override void Hide() + { + this.MoveToX(0, 300, Easing.OutQuint).Then().FadeOut(); + } + + private void updateDisplay() + { + spriteIcon.FadeColour(IsHovered ? colourProvider.Content2 : colourProvider.Light1, 300, Easing.OutQuint); + background.FadeColour(IsHovered ? colourProvider.Background2 : colourProvider.Background3, 300, Easing.OutQuint); + } + } +} diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index 9b268c573f40..8fd12e1e13b2 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -31,6 +31,9 @@ public abstract partial class SettingsPanel : OsuFocusedOverlayContainer { public const float CONTENT_MARGINS = 20; + // extra margin to give room to the revert-to-default button in settings controls. + public const float CONTENT_MARGINS_RIGHT = 30; + public const float TRANSITION_LENGTH = 600; private const float sidebar_width = SettingsSidebar.EXPANDED_WIDTH; From 7a32e0eebf74b8e84a48193d9e600f6d3566499d Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 18 Dec 2025 04:09:06 -0500 Subject: [PATCH 277/836] Add test coverage --- .../Settings/TestSceneSettingsItemV2.cs | 263 ++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs new file mode 100644 index 000000000000..4476c32e9d06 --- /dev/null +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs @@ -0,0 +1,263 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Cursor; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Localisation; +using osu.Game.Overlays; +using osu.Game.Overlays.Settings; +using osu.Game.Tests.Visual.UserInterface; +using osuTK; + +namespace osu.Game.Tests.Visual.Settings +{ + public partial class TestSceneSettingsItemV2 : ThemeComparisonTestScene + { + private readonly Bindable note = new Bindable(); + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + + private FormSliderBar sliderBar = null!; + + private SearchContainer searchContainer = null!; + + public TestSceneSettingsItemV2() + : base(false) + { + } + + protected override Drawable CreateContent() + { + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new BackgroundBox + { + RelativeSizeAxes = Axes.Both, + }, + new OsuContextMenuContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 400, + RelativeSizeAxes = Axes.Y, + Child = new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + Child = new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both, + ScrollbarVisible = false, + Child = searchContainer = new SearchContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Direction = FillDirection.Vertical, + Spacing = new Vector2(7), + Padding = new MarginPadding { Vertical = 10 }, + Children = new[] + { + new SettingsItemV2(new FormTextBox + { + Caption = "Artist", + HintText = "Poot artist here!", + PlaceholderText = "Here is an artist", + Current = { Value = string.Empty, Default = string.Empty } + }), + new SettingsItemV2(new FormTextBox + { + Caption = "Artist", + HintText = "Poot artist here!", + PlaceholderText = "Here is an artist", + Current = { Value = string.Empty, Default = string.Empty, Disabled = true } + }), + new SettingsItemV2(new FormNumberBox(allowDecimals: true) + { + Caption = "Number", + HintText = "Insert your favourite number", + PlaceholderText = "Mine is 42!", + Current = { Value = string.Empty, Default = string.Empty } + }), + new SettingsItemV2(new FormCheckBox + { + Caption = EditorSetupStrings.LetterboxDuringBreaks, + HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, + }) + { + Note = { BindTarget = note }, + }, + new SettingsItemV2(new FormCheckBox + { + Caption = EditorSetupStrings.LetterboxDuringBreaks, + HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, + Current = { Disabled = true }, + }), + new SettingsItemV2(new FormCheckBox + { + Caption = EditorSetupStrings.LetterboxDuringBreaks, + HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, + Current = { Value = true, Disabled = true }, + }), + new SettingsItemV2(new FormEnumDropdown + { + Caption = EditorSetupStrings.EnableCountdown, + HintText = EditorSetupStrings.CountdownDescription, + }), + new SettingsItemV2(new FormEnumDropdown + { + Caption = EditorSetupStrings.EnableCountdown, + HintText = EditorSetupStrings.CountdownDescription, + Current = { Disabled = true }, + }), + new SettingsItemV2(new FormEnumDropdown + { + Caption = "Dropdown with many items", + HintText = EditorSetupStrings.CountdownDescription, + }) + { + Note = { BindTarget = note }, + }, + new SettingsItemV2(sliderBar = new FormSliderBar + { + Caption = "Slider", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Value = 5, + Precision = 0.1f, + }, + }), + new SettingsItemV2(new FormSliderBar + { + Caption = "Slider", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Value = 5, + Precision = 0.1f, + Disabled = true, + }, + TransferValueOnCommit = true, + }), + new SettingsItemV2(new FormSliderBar + { + Caption = "Slider without revert button", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Value = 5, + Precision = 0.1f, + }, + }) + { + ShowDefaultRevertButton = false + }, + new SettingsItemV2(new FormSliderBar + { + Caption = "Slider with classic default", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Value = 5, + Precision = 0.1f, + }, + }) + { + HasClassicDefault = true, + }, + }, + }, + }, + } + }, + }, + }; + } + + [Test] + public void TestDisplay() + { + AddStep("display", () => CreateThemedContent(OverlayColourScheme.Purple)); + } + + [Test] + public void TestNote() + { + AddStep("set informational note", () => note.Value = new SettingsNote.Data(LayoutSettingsStrings.OsuIsRunningExclusiveFullscreen.ToString(), SettingsNote.Type.Informational)); + AddStep("set warning note", + () => note.Value = new SettingsNote.Data( + "Using unlimited frame limiter can lead to stutters, bad performance and overheating. It will not improve perceived latency. “2x refresh rate” is recommended.", + SettingsNote.Type.Warning)); + AddStep("set critical note", + () => note.Value = new SettingsNote.Data( + "You have done something so horrible in the game settings to the point we have invented a new note type for this. Look at it, it's in red. It's worse than yellow.", + SettingsNote.Type.Critical)); + AddStep("clear note", () => note.Value = null); + } + + [Test] + public void TestFilter() + { + AddStep("set classic filter", () => searchContainer.SearchTerm = SettingsItemV2.CLASSIC_DEFAULT_SEARCH_TERM); + AddStep("set no filter", () => searchContainer.SearchTerm = string.Empty); + } + + /// + /// Ensures that the reset to default button uses the correct implementation of IsDefault to determine whether it should be shown or not. + /// Values have been chosen so that after being set, Value != Default (but they are close enough that the difference is negligible compared to Precision). + /// + [TestCase(4.2f)] + [TestCase(9.9f)] + public void TestRestoreDefaultValueButtonPrecision(float initialValue) + { + BindableFloat current = null!; + SettingsRevertToDefaultButton revertToDefaultButton = null!; + + AddStep("set current bindable", () => sliderBar.Current = current = new BindableFloat(initialValue) + { + MinValue = 0, + MaxValue = 10, + Precision = 0.1f, + }); + + AddStep("retrieve restore default button", () => revertToDefaultButton = sliderBar.FindClosestParent().ChildrenOfType().Single()); + + AddAssert("restore button hidden", () => revertToDefaultButton.X == 0); + + AddStep("change value to next closest", () => sliderBar.Current.Value += current.Precision * 0.6f); + AddUntilStep("restore button shown", () => revertToDefaultButton.X > 0); + + AddStep("restore default", () => sliderBar.Current.SetDefault()); + AddUntilStep("restore button hidden", () => revertToDefaultButton.X == 0); + } + + private partial class BackgroundBox : Box + { + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Colour = colourProvider.Background4; + } + } + } +} From 90d76154328883b40f8d670589a35f4bc0175064 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 18 Dec 2025 04:11:59 -0500 Subject: [PATCH 278/836] Limit form dropdown height by default --- osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index 7d21db1455c4..021df4c2c958 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -32,6 +32,12 @@ public partial class FormDropdown : OsuDropdown, IFormControl /// public LocalisableString HintText { get; init; } + /// + /// The maximum height of the dropdown's menu. + /// By default, this is set to 200px high. Set to to remove such limit. + /// + public float MaxHeight { get; set; } = 200; + private FormDropdownHeader header = null!; [BackgroundDependencyLoader] @@ -73,7 +79,10 @@ public virtual IEnumerable FilterTerms Dropdown = this, }; - protected override DropdownMenu CreateMenu() => new FormDropdownMenu(); + protected override DropdownMenu CreateMenu() => new FormDropdownMenu + { + MaxHeight = MaxHeight, + }; private partial class FormDropdownHeader : DropdownHeader { From f5bd888078f63383d94cee3363be010de39f1750 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 18 Dec 2025 05:50:35 -0500 Subject: [PATCH 279/836] Remove `Value` from `{Is,Set}ValueDefault` --- osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs | 4 ++-- osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs | 4 ++-- osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs | 4 ++-- osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs | 4 ++-- osu.Game/Graphics/UserInterfaceV2/IFormControl.cs | 4 ++-- osu.Game/Overlays/Settings/SettingsItemV2.cs | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs index 471168a17f76..586f6546ab19 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs @@ -167,9 +167,9 @@ private void updateState() public event Action? ValueChanged; - public bool IsValueDefault => Current.IsDefault; + public bool IsDefault => Current.IsDefault; - public void SetValueDefault() => Current.SetDefault(); + public void SetDefault() => Current.SetDefault(); public bool IsDisabled => Current.Disabled; } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index 021df4c2c958..852ff4bbad38 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -68,9 +68,9 @@ public virtual IEnumerable FilterTerms public event Action? ValueChanged; - public bool IsValueDefault => Current.IsDefault; + public bool IsDefault => Current.IsDefault; - public void SetValueDefault() => Current.SetDefault(); + public void SetDefault() => Current.SetDefault(); public bool IsDisabled => Current.Disabled; diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index ef8227c12ed2..5e843fd75188 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -486,9 +486,9 @@ protected override bool OnDoubleClick(DoubleClickEvent e) public event Action? ValueChanged; - public bool IsValueDefault => Current.IsDefault; + public bool IsDefault => Current.IsDefault; - public void SetValueDefault() => Current.SetDefault(); + public void SetDefault() => Current.SetDefault(); public bool IsDisabled => Current.Disabled; } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs index 41ea5242bd05..4981557e3712 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs @@ -254,9 +254,9 @@ protected override void NotifyInputError() public event Action? ValueChanged; - public bool IsValueDefault => current.IsDefault; + public bool IsDefault => current.IsDefault; - public void SetValueDefault() => current.SetDefault(); + public void SetDefault() => current.SetDefault(); public bool IsDisabled => current.Disabled; diff --git a/osu.Game/Graphics/UserInterfaceV2/IFormControl.cs b/osu.Game/Graphics/UserInterfaceV2/IFormControl.cs index c967ac76b025..97630a649a3b 100644 --- a/osu.Game/Graphics/UserInterfaceV2/IFormControl.cs +++ b/osu.Game/Graphics/UserInterfaceV2/IFormControl.cs @@ -20,12 +20,12 @@ public interface IFormControl : IDrawable, IHasFilterTerms /// /// Whether the value of this control is in a default state. /// - bool IsValueDefault { get; } + bool IsDefault { get; } /// /// If enabled, resets the control to its default state. /// - void SetValueDefault(); + void SetDefault(); /// /// Whether the control is currently disabled. diff --git a/osu.Game/Overlays/Settings/SettingsItemV2.cs b/osu.Game/Overlays/Settings/SettingsItemV2.cs index 21df39df3834..622df50b91ec 100644 --- a/osu.Game/Overlays/Settings/SettingsItemV2.cs +++ b/osu.Game/Overlays/Settings/SettingsItemV2.cs @@ -78,7 +78,7 @@ protected override void LoadComplete() { base.LoadComplete(); - controlDefault.Value = control.IsValueDefault; + controlDefault.Value = control.IsDefault; controlEnabled.Value = !control.IsDisabled; controlDefault.BindValueChanged(_ => updateDefaultState()); @@ -99,7 +99,7 @@ private void updateDefaultState() protected override void Update() { base.Update(); - controlDefault.Value = control.IsValueDefault; + controlDefault.Value = control.IsDefault; controlEnabled.Value = !control.IsDisabled; } @@ -116,7 +116,7 @@ public void ApplyClassicDefault() public void ApplyDefault() { if (!control.IsDisabled) - control.SetValueDefault(); + control.SetDefault(); } public event Action SettingChanged From 44f535dcefce34ac5daa70bf12e52a1a9c332870 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Dec 2025 20:08:56 +0900 Subject: [PATCH 280/836] Fix osu! stacking not matching stable in very specific edge case Closes https://github.com/ppy/osu/issues/36052. Not much more to say here. Until now the `PreEmpt` typing discrepancy has likely gone unnoticed since it's usually only used in visual usages. --- osu.Game.Rulesets.Osu.Tests/StackingTest.cs | 80 ++++++++++++++----- osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs | 2 +- 2 files changed, 63 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/StackingTest.cs b/osu.Game.Rulesets.Osu.Tests/StackingTest.cs index e370807bca33..f9b4dcad52a8 100644 --- a/osu.Game.Rulesets.Osu.Tests/StackingTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/StackingTest.cs @@ -4,7 +4,6 @@ using System; using System.IO; using System.Linq; -using System.Text; using NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.IO; @@ -19,23 +18,9 @@ namespace osu.Game.Rulesets.Osu.Tests public class StackingTest { [Test] - public void TestStacking() + public void TestStackingEdgeCaseOne() { - using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(beatmap_data))) - using (var reader = new LineBufferedReader(stream)) - { - var beatmap = Decoder.GetDecoder(reader).Decode(reader); - var converted = new TestWorkingBeatmap(beatmap).GetPlayableBeatmap(new OsuRuleset().RulesetInfo, Array.Empty()); - - var objects = converted.HitObjects.ToList(); - - // The last hitobject triggers the stacking - for (int i = 0; i < objects.Count - 1; i++) - Assert.AreEqual(0, ((OsuHitObject)objects[i]).StackHeight); - } - } - - private const string beatmap_data = @" + using (var stream = new MemoryStream(@" osu file format v14 [General] @@ -62,6 +47,65 @@ osu file format v14 311,185,218471,2,0,L|325:209,1,25 311,185,218671,2,0,L|304:212,1,25 311,185,240271,5,0,0:0:0:0: -"; +"u8.ToArray())) + using (var reader = new LineBufferedReader(stream)) + { + var beatmap = Decoder.GetDecoder(reader).Decode(reader); + var converted = new TestWorkingBeatmap(beatmap).GetPlayableBeatmap(new OsuRuleset().RulesetInfo, Array.Empty()); + + var objects = converted.HitObjects.ToList(); + + // The last hitobject triggers the stacking + for (int i = 0; i < objects.Count - 1; i++) + Assert.AreEqual(0, ((OsuHitObject)objects[i]).StackHeight); + } + } + + [Test] + public void TestStackingEdgeCaseTwo() + { + using (var stream = new MemoryStream(@" +osu file format v14 +// extracted from https://osu.ppy.sh/beatmapsets/365006#osu/801165 + +[General] +StackLeniency: 0.2 + +[Difficulty] +HPDrainRate:6 +CircleSize:4 +OverallDifficulty:8 +ApproachRate:9.3 +SliderMultiplier:2 +SliderTickRate:1 + +[TimingPoints] +5338,444.444444444444,4,2,0,50,1,0 +82893,-76.9230769230769,4,2,8,50,0,0 +85115,-76.9230769230769,4,2,0,50,0,0 +85337,-100,4,2,8,60,0,0 +85893,-100,4,2,7,60,0,0 +86226,-100,4,2,8,60,0,0 +88893,-58.8235294117647,4,1,8,70,0,1 + +[HitObjects] +427,124,84226,1,0,3:0:0:0: +427,124,84337,1,0,3:0:0:0: +427,124,84449,1,8,0:0:0:0: +"u8.ToArray())) + using (var reader = new LineBufferedReader(stream)) + { + var beatmap = Decoder.GetDecoder(reader).Decode(reader); + var converted = new TestWorkingBeatmap(beatmap).GetPlayableBeatmap(new OsuRuleset().RulesetInfo, Array.Empty()); + + var objects = converted.HitObjects.ToList(); + + Assert.That(objects, Has.Count.EqualTo(3)); + + // The last hitobject triggers the stacking + for (int i = 0; i < objects.Count - 1; i++) + Assert.AreEqual(0, ((OsuHitObject)objects[i]).StackHeight); + } + } } } diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index 01309c68f62b..d623a98950f4 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -171,7 +171,7 @@ protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, I { base.ApplyDefaultsToSelf(controlPointInfo, difficulty); - TimePreempt = (float)IBeatmapDifficultyInfo.DifficultyRange(difficulty.ApproachRate, PREEMPT_RANGE); + TimePreempt = (int)IBeatmapDifficultyInfo.DifficultyRange(difficulty.ApproachRate, PREEMPT_RANGE); // Preempt time can go below 450ms. Normally, this is achieved via the DT mod which uniformly speeds up all animations game wide regardless of AR. // This uniform speedup is hard to match 1:1, however we can at least make AR>10 (via mods) feel good by extending the upper linear function above. From 094860bfea380eec0ce876dc0339e906cc142bb2 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 18 Dec 2025 06:17:07 -0500 Subject: [PATCH 281/836] Define delegate for applying classic defaults --- osu.Game/Overlays/Settings/SettingsItemV2.cs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsItemV2.cs b/osu.Game/Overlays/Settings/SettingsItemV2.cs index 622df50b91ec..bd246211b633 100644 --- a/osu.Game/Overlays/Settings/SettingsItemV2.cs +++ b/osu.Game/Overlays/Settings/SettingsItemV2.cs @@ -105,14 +105,26 @@ protected override void Update() #region ISettingsItem - public bool HasClassicDefault { get; init; } + public bool HasClassicDefault { get; private set; } - public void ApplyClassicDefault() + private Action? applyClassicDefault; + + /// + /// If set, this setting is considered as having a "classic" default value, + /// and this is the function for overwriting the control with that value. + /// + public Action? ApplyClassicDefault { - // will be removed soon. - throw new NotSupportedException(); + get => applyClassicDefault; + set + { + applyClassicDefault = value; + HasClassicDefault = true; + } } + void ISettingsItem.ApplyClassicDefault() => ApplyClassicDefault?.Invoke(); + public void ApplyDefault() { if (!control.IsDisabled) From 13aeed15f95fa6585ff01eedaccc43b28ff656cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Dec 2025 20:17:46 +0900 Subject: [PATCH 282/836] Remove button sound from sample toggle buttons The new ones added in this change don't play the UI sounds, likely because they make it nigh impossible to actually hear what the gameplay samples will sound like. This removes the same sounds from the existing buttons to match. --- .../Edit/Compose/Components/Timeline/SamplePointPiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs index f4242e1fe069..7f7f749c44f4 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -572,7 +572,7 @@ private IEnumerable createTernaryButtons() { foreach ((string sampleName, var bindable) in selectionSampleStates) { - yield return new DrawableTernaryButton + yield return new DrawableTernaryButton(null) { Current = bindable, Description = string.Empty, From 61874e59e03f7c393a13435534a336b618e39aa4 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 18 Dec 2025 06:17:48 -0500 Subject: [PATCH 283/836] Extend classic default test coverage --- .../Visual/Settings/TestSceneSettingsItemV2.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs index 4476c32e9d06..bdfe8019bc3e 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; @@ -30,6 +31,7 @@ public partial class TestSceneSettingsItemV2 : ThemeComparisonTestScene private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); private FormSliderBar sliderBar = null!; + private FormSliderBar classicSliderBar = null!; private SearchContainer searchContainer = null!; @@ -171,7 +173,7 @@ protected override Drawable CreateContent() { ShowDefaultRevertButton = false }, - new SettingsItemV2(new FormSliderBar + new SettingsItemV2(classicSliderBar = new FormSliderBar { Caption = "Slider with classic default", Current = new BindableFloat @@ -183,7 +185,7 @@ protected override Drawable CreateContent() }, }) { - HasClassicDefault = true, + ApplyClassicDefault = () => classicSliderBar.Current.Value = 2, }, }, }, @@ -216,10 +218,16 @@ public void TestNote() } [Test] - public void TestFilter() + public void TestClassicDefault() { + AddStep("modify irrelevant setting", () => sliderBar.Current.Value = 4); + AddStep("apply classic defaults", () => this.ChildrenOfType().Where(i => i.HasClassicDefault).ForEach(s => s.ApplyClassicDefault())); + AddStep("apply regular defaults", () => this.ChildrenOfType().Where(i => i.HasClassicDefault).ForEach(s => s.ApplyDefault())); AddStep("set classic filter", () => searchContainer.SearchTerm = SettingsItemV2.CLASSIC_DEFAULT_SEARCH_TERM); + AddStep("apply classic defaults", () => this.ChildrenOfType().Where(i => i.HasClassicDefault).ForEach(s => s.ApplyClassicDefault())); + AddStep("apply regular defaults", () => this.ChildrenOfType().Where(i => i.HasClassicDefault).ForEach(s => s.ApplyDefault())); AddStep("set no filter", () => searchContainer.SearchTerm = string.Empty); + AddAssert("irrelevant setting left out", () => sliderBar.Current.Value, () => Is.EqualTo(4)); } /// From de0c191c475a0a8c5a05337556a3636a532a3a70 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Dec 2025 20:53:42 +0900 Subject: [PATCH 284/836] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a2dabe7a9ff0..749afd8d5ece 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From 93a64dad8941aa088ffca80538855a2461cf8242 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Dec 2025 21:39:10 +0900 Subject: [PATCH 285/836] Adjust corner radius and design slightly --- osu.Game/Collections/DrawableCollectionListItem.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Collections/DrawableCollectionListItem.cs b/osu.Game/Collections/DrawableCollectionListItem.cs index 3031112333c8..5df746459cbd 100644 --- a/osu.Game/Collections/DrawableCollectionListItem.cs +++ b/osu.Game/Collections/DrawableCollectionListItem.cs @@ -53,7 +53,11 @@ public DrawableCollectionListItem(Live item, bool isCreated) ShowDragHandle.Value = false; Masking = true; - CornerRadius = item_height / 2; + + // This doesn't match the latest design spec (should be 5) but is an in-between that feels right to the eye + // until we move everything over to Form controls. + CornerRadius = 10; + CornerExponent = 2.5f; } protected override Drawable CreateContent() => content = new ItemContent(Model); @@ -135,7 +139,8 @@ public ItemTextBox(Live collection) { this.collection = collection; - CornerRadius = item_height / 2; + CornerRadius = 10; + CornerExponent = 2.5f; } [BackgroundDependencyLoader] From e526de7f40c4eb729dc012497c7c772a0dbce909 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Dec 2025 21:56:55 +0900 Subject: [PATCH 286/836] Move "Create new collection" out of scroll content --- .../Collections/DrawableCollectionList.cs | 80 +------------------ .../Collections/ManageCollectionsDialog.cs | 50 ++++++++++-- 2 files changed, 46 insertions(+), 84 deletions(-) diff --git a/osu.Game/Collections/DrawableCollectionList.cs b/osu.Game/Collections/DrawableCollectionList.cs index c494b830d1b7..fe9080161701 100644 --- a/osu.Game/Collections/DrawableCollectionList.cs +++ b/osu.Game/Collections/DrawableCollectionList.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -104,13 +103,8 @@ private void collectionsChanged(IRealmCollection collections, } } - protected override OsuRearrangeableListItem> CreateOsuDrawable(Live item) - { - if (item.ID == scroll.PlaceholderItem.Model.ID) - return scroll.ReplacePlaceholder(); - - return new DrawableCollectionListItem(item, true); - } + protected override OsuRearrangeableListItem> CreateOsuDrawable(Live item) => + new DrawableCollectionListItem(item, true); protected override void Dispose(bool isDisposing) { @@ -127,86 +121,20 @@ protected override void Dispose(bool isDisposing) /// private partial class Scroll : OsuScrollContainer { - /// - /// The currently-displayed placeholder item. - /// - public DrawableCollectionListItem PlaceholderItem { get; private set; } = null!; - protected override Container Content => content; - private readonly Container content; - - private readonly Container placeholderContainer; + private readonly FillFlowContainer content; public Scroll() { ScrollbarOverlapsContent = false; - base.Content.Add(new FillFlowContainer + base.Content.Add(content = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, LayoutDuration = 200, LayoutEasing = Easing.OutQuint, - Children = new Drawable[] - { - content = new Container { RelativeSizeAxes = Axes.X }, - placeholderContainer = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y - } - } }); - - ReplacePlaceholder(); - Debug.Assert(PlaceholderItem != null); - } - - protected override void Update() - { - base.Update(); - - // AutoSizeAxes cannot be used as the height should represent the post-layout-transform height at all times, so that the placeholder doesn't bounce around. - content.Height = ((Flow)Child).Children.Sum(c => c.IsPresent ? c.DrawHeight + 5 : 0); - } - - /// - /// Replaces the current with a new one, and returns the previous. - /// - /// The current . - public DrawableCollectionListItem ReplacePlaceholder() - { - var previous = PlaceholderItem; - - placeholderContainer.Clear(false); - placeholderContainer.Add(PlaceholderItem = new NewCollectionEntryItem()); - - return previous; - } - } - - private partial class NewCollectionEntryItem : DrawableCollectionListItem - { - [Resolved] - private RealmAccess realm { get; set; } = null!; - - public NewCollectionEntryItem() - : base(new BeatmapCollection().ToLiveUnmanaged(), false) - { - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - TextBox.OnCommit += (sender, newText) => - { - if (string.IsNullOrEmpty(TextBox.Text)) - return; - - realm.Write(r => r.Add(new BeatmapCollection(TextBox.Text))); - TextBox.Text = string.Empty; - }; } } diff --git a/osu.Game/Collections/ManageCollectionsDialog.cs b/osu.Game/Collections/ManageCollectionsDialog.cs index 79166840f9cf..958e16954292 100644 --- a/osu.Game/Collections/ManageCollectionsDialog.cs +++ b/osu.Game/Collections/ManageCollectionsDialog.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -102,12 +103,13 @@ private void load(OsuColour colours) new Container { RelativeSizeAxes = Axes.Both, + Masking = true, Children = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, - Colour = colours.GreySeaFoamDarker + Colour = colours.GreySeaFoamDarker, }, new Container { @@ -115,23 +117,30 @@ private void load(OsuColour colours) Padding = new MarginPadding(10), Children = new Drawable[] { + list = new DrawableCollectionList + { + Padding = new MarginPadding { Vertical = 50 }, + RelativeSizeAxes = Axes.Both, + }, searchTextBox = new BasicSearchTextBox { RelativeSizeAxes = Axes.X, - Y = 10, Height = 40, ReleaseFocusOnCommit = false, HoldFocus = true, PlaceholderText = HomeStrings.SearchPlaceholder, }, - list = new DrawableCollectionList + new Container { - Padding = new MarginPadding + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Children = new Drawable[] { - Top = 60, - }, - RelativeSizeAxes = Axes.Both, - } + new NewCollectionEntryItem() + } + }, } }, } @@ -184,5 +193,30 @@ protected override void PopOut() // Ensure that textboxes commit GetContainingFocusManager()?.TriggerFocusContention(this); } + + private partial class NewCollectionEntryItem : DrawableCollectionListItem + { + [Resolved] + private RealmAccess realm { get; set; } = null!; + + public NewCollectionEntryItem() + : base(new BeatmapCollection().ToLiveUnmanaged(), false) + { + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + TextBox.OnCommit += (_, _) => + { + if (string.IsNullOrEmpty(TextBox.Text)) + return; + + realm.Write(r => r.Add(new BeatmapCollection(TextBox.Text))); + TextBox.Text = string.Empty; + }; + } + } } } From 16c4967ee444466061e8bf06840d4a4ac9cf7fb7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Dec 2025 22:02:04 +0900 Subject: [PATCH 287/836] Fix added item not scrolling into view immediately --- osu.Game/Collections/DrawableCollectionList.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Collections/DrawableCollectionList.cs b/osu.Game/Collections/DrawableCollectionList.cs index fe9080161701..12fe40725a23 100644 --- a/osu.Game/Collections/DrawableCollectionList.cs +++ b/osu.Game/Collections/DrawableCollectionList.cs @@ -71,7 +71,9 @@ protected override void OnItemsChanged() var createdItem = flow.Children.SingleOrDefault(item => item.Model.Value.ID == lastCreated); if (createdItem != null) - scroll.ScrollTo(createdItem); + { + ScheduleAfterChildren(() => scroll.ScrollIntoView(createdItem)); + } lastCreated = null; } From 09178b5dc408357ba54efbe0c8b99730552d2271 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Dec 2025 22:28:50 +0900 Subject: [PATCH 288/836] Add helper method and update some other similar preempt calculations --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- .../Objects/CatchHitObject.cs | 2 +- osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 3 ++- osu.Game/Beatmaps/IBeatmapDifficultyInfo.cs | 25 +++++++++++++++++++ 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 02d266228ad7..dc163ed77e1f 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -300,7 +300,7 @@ public override IEnumerable GetBeatmapAttributesForDisp Description = "Affects how early fruits fade in on the screen.", AdditionalMetrics = [ - new RulesetBeatmapAttribute.AdditionalMetric("Fade-in time", LocalisableString.Interpolate($@"{IBeatmapDifficultyInfo.DifficultyRange(effectiveDifficulty.ApproachRate, CatchHitObject.PREEMPT_RANGE):#,0.##} ms")) + new RulesetBeatmapAttribute.AdditionalMetric("Fade-in time", LocalisableString.Interpolate($@"{IBeatmapDifficultyInfo.DifficultyRangeInt(effectiveDifficulty.ApproachRate, CatchHitObject.PREEMPT_RANGE):#,0.##} ms")) ] }; yield return new RulesetBeatmapAttribute(SongSelectStrings.HPDrain, @"HP", originalDifficulty.DrainRate, effectiveDifficulty.DrainRate, 10) diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index 41deaa0d82f4..2f186f5ab4ce 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -150,7 +150,7 @@ protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, I { base.ApplyDefaultsToSelf(controlPointInfo, difficulty); - TimePreempt = (float)IBeatmapDifficultyInfo.DifficultyRange(difficulty.ApproachRate, PREEMPT_RANGE); + TimePreempt = IBeatmapDifficultyInfo.DifficultyRangeInt(difficulty.ApproachRate, PREEMPT_RANGE); Scale = LegacyRulesetExtensions.CalculateScaleFromCircleSize(difficulty.CircleSize); } diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index d623a98950f4..0a5365e652eb 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -171,7 +171,7 @@ protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, I { base.ApplyDefaultsToSelf(controlPointInfo, difficulty); - TimePreempt = (int)IBeatmapDifficultyInfo.DifficultyRange(difficulty.ApproachRate, PREEMPT_RANGE); + TimePreempt = IBeatmapDifficultyInfo.DifficultyRangeInt(difficulty.ApproachRate, PREEMPT_RANGE); // Preempt time can go below 450ms. Normally, this is achieved via the DT mod which uniformly speeds up all animations game wide regardless of AR. // This uniform speedup is hard to match 1:1, however we can at least make AR>10 (via mods) feel good by extending the upper linear function above. diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 49d945e0aa39..6bb8a187e32c 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -412,7 +412,8 @@ public override IEnumerable GetBeatmapAttributesForDisp Description = "Affects how early objects appear on screen relative to their hit time.", AdditionalMetrics = [ - new RulesetBeatmapAttribute.AdditionalMetric("Approach time", LocalisableString.Interpolate($@"{IBeatmapDifficultyInfo.DifficultyRange(effectiveDifficulty.ApproachRate, OsuHitObject.PREEMPT_RANGE):#,0.##} ms")) + new RulesetBeatmapAttribute.AdditionalMetric("Approach time", + LocalisableString.Interpolate($@"{IBeatmapDifficultyInfo.DifficultyRangeInt(effectiveDifficulty.ApproachRate, OsuHitObject.PREEMPT_RANGE):#,0.##} ms")) ] }; diff --git a/osu.Game/Beatmaps/IBeatmapDifficultyInfo.cs b/osu.Game/Beatmaps/IBeatmapDifficultyInfo.cs index 2dd73a254186..0875a60d7510 100644 --- a/osu.Game/Beatmaps/IBeatmapDifficultyInfo.cs +++ b/osu.Game/Beatmaps/IBeatmapDifficultyInfo.cs @@ -95,6 +95,31 @@ static double DifficultyRange(double difficulty, double min, double mid, double static double DifficultyRange(double difficulty, DifficultyRange range) => DifficultyRange(difficulty, range.Min, range.Mid, range.Max); + /// + /// Maps a difficulty value [0, 10] to a two-piece linear range of values. + /// Floors the value to `int`, usually to match osu!stable spec. + /// + /// The difficulty value to be mapped. + /// The values that define the two linear ranges. + /// + /// + /// od0 + /// Minimum of the resulting range which will be achieved by a difficulty value of 0. + /// + /// + /// od5 + /// Midpoint of the resulting range which will be achieved by a difficulty value of 5. + /// + /// + /// od10 + /// Maximum of the resulting range which will be achieved by a difficulty value of 10. + /// + /// + /// + /// Value to which the difficulty value maps in the specified range. + static int DifficultyRangeInt(double difficulty, DifficultyRange range) + => (int)DifficultyRange(difficulty, range.Min, range.Mid, range.Max); + /// /// Inverse function to . /// Maps a value returned by the function above back to the difficulty that produced it. From 577cf7d1e7a97a62db8216cc00e2de6214cf2a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 18 Dec 2025 14:49:30 +0100 Subject: [PATCH 289/836] Remove invalid xmldoc reference --- osu.Game/Collections/DrawableCollectionList.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Collections/DrawableCollectionList.cs b/osu.Game/Collections/DrawableCollectionList.cs index 12fe40725a23..5c79549c0a80 100644 --- a/osu.Game/Collections/DrawableCollectionList.cs +++ b/osu.Game/Collections/DrawableCollectionList.cs @@ -118,9 +118,6 @@ protected override void Dispose(bool isDisposing) /// The scroll container for this . /// Contains the main flow of and attaches a placeholder item to the end of the list. /// - /// - /// Use to transfer the placeholder into the main list. - /// private partial class Scroll : OsuScrollContainer { protected override Container Content => content; From 16c1adf0f73b1063828c7daf5b66da61cf9228bc Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Thu, 18 Dec 2025 23:19:16 +0500 Subject: [PATCH 290/836] Use `DifficultyCalculationUtils.Norm` (#36064) --- .../Difficulty/OsuDifficultyCalculator.cs | 10 +++------- .../Difficulty/OsuPerformanceCalculator.cs | 9 ++------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 8c78008bcb02..509619df4c6c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -8,6 +8,7 @@ using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; +using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Skills; @@ -107,12 +108,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat double baseSpeedPerformance = OsuStrainSkill.DifficultyToPerformance(speedRating); double baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating); - double basePerformance = - Math.Pow( - Math.Pow(baseAimPerformance, 1.1) + - Math.Pow(baseSpeedPerformance, 1.1) + - Math.Pow(baseFlashlightPerformance, 1.1), 1.0 / 1.1 - ); + double basePerformance = DifficultyCalculationUtils.Norm(OsuPerformanceCalculator.PERFORMANCE_NORM_EXPONENT, baseAimPerformance, baseSpeedPerformance, baseFlashlightPerformance); double starRating = calculateStarRating(basePerformance); @@ -147,7 +143,7 @@ private double calculateMechanicalDifficultyRating(double aimDifficultyValue, do double aimValue = OsuStrainSkill.DifficultyToPerformance(OsuRatingCalculator.CalculateDifficultyRating(aimDifficultyValue)); double speedValue = OsuStrainSkill.DifficultyToPerformance(OsuRatingCalculator.CalculateDifficultyRating(speedDifficultyValue)); - double totalValue = Math.Pow(Math.Pow(aimValue, 1.1) + Math.Pow(speedValue, 1.1), 1 / 1.1); + double totalValue = DifficultyCalculationUtils.Norm(OsuPerformanceCalculator.PERFORMANCE_NORM_EXPONENT, aimValue, speedValue); return calculateStarRating(totalValue); } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 3bc486d7e663..66d6cc32cd94 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty public class OsuPerformanceCalculator : PerformanceCalculator { public const double PERFORMANCE_BASE_MULTIPLIER = 1.14; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. + public const double PERFORMANCE_NORM_EXPONENT = 1.1; private bool usingClassicSliderAccuracy; private bool usingScoreV2; @@ -145,13 +146,7 @@ protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo s double accuracyValue = computeAccuracyValue(score, osuAttributes); double flashlightValue = computeFlashlightValue(score, osuAttributes); - double totalValue = - Math.Pow( - Math.Pow(aimValue, 1.1) + - Math.Pow(speedValue, 1.1) + - Math.Pow(accuracyValue, 1.1) + - Math.Pow(flashlightValue, 1.1), 1.0 / 1.1 - ) * multiplier; + double totalValue = DifficultyCalculationUtils.Norm(PERFORMANCE_NORM_EXPONENT, aimValue, speedValue, accuracyValue, flashlightValue) * multiplier; return new OsuPerformanceAttributes { From a4215e044206c0f67ed5cce09d1268a71c8dfa2e Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 18 Dec 2025 18:56:18 -0500 Subject: [PATCH 291/836] Add tooltip to revert-to-default button --- osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs b/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs index 305a30a2f5fc..58e511341bc0 100644 --- a/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs +++ b/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs @@ -6,8 +6,10 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Localisation; using osuTK; namespace osu.Game.Overlays.Settings @@ -64,6 +66,8 @@ protected override void LoadComplete() Enabled.BindValueChanged(_ => updateDisplay(), true); } + public override LocalisableString TooltipText => CommonStrings.RevertToDefault; + protected override bool OnHover(HoverEvent e) { updateDisplay(); From 4fee1547e328884aa991b6539b8e60c27594055c Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 18 Dec 2025 19:48:42 -0500 Subject: [PATCH 292/836] Use menu item labels as filter terms instead --- osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index 852ff4bbad38..a12d166f5620 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -3,9 +3,7 @@ using System; using System.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Extensions; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -61,8 +59,8 @@ public virtual IEnumerable FilterTerms { yield return Caption; - foreach (var item in Items) - yield return item?.ToString() ?? string.Empty; + foreach (var item in MenuItems) + yield return item.Text.Value; } } @@ -280,8 +278,6 @@ private void load(OverlayColourProvider colourProvider) public partial class FormEnumDropdown : FormDropdown where T : struct, Enum { - public override IEnumerable FilterTerms => base.FilterTerms.Concat(Items.Select(i => i.GetLocalisableDescription())); - public FormEnumDropdown() { Items = Enum.GetValues(); From a82d0c3b5142cfad8a49780a47c1e608eefa133e Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 18 Dec 2025 20:01:36 -0500 Subject: [PATCH 293/836] Rename property to have consistent name --- osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs | 2 +- osu.Game/Overlays/Settings/SettingsItemV2.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs index bdfe8019bc3e..043eadf370cc 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs @@ -171,7 +171,7 @@ protected override Drawable CreateContent() }, }) { - ShowDefaultRevertButton = false + ShowRevertToDefaultButton = false }, new SettingsItemV2(classicSliderBar = new FormSliderBar { diff --git a/osu.Game/Overlays/Settings/SettingsItemV2.cs b/osu.Game/Overlays/Settings/SettingsItemV2.cs index bd246211b633..1f947d2898fc 100644 --- a/osu.Game/Overlays/Settings/SettingsItemV2.cs +++ b/osu.Game/Overlays/Settings/SettingsItemV2.cs @@ -21,9 +21,9 @@ public sealed partial class SettingsItemV2 : CompositeDrawable, ISettingsItem, I private readonly BindableBool controlEnabled = new BindableBool(true); /// - /// Whether a revert-to-default button should be displayed. + /// Whether a revert button should be displayed when the control is modified away from default state. /// - public bool ShowDefaultRevertButton { get; init; } = true; + public bool ShowRevertToDefaultButton { get; init; } = true; /// /// A note to display underneath the setting. @@ -88,7 +88,7 @@ protected override void LoadComplete() private void updateDefaultState() { - bool showRevertButton = !controlDefault.Value && controlEnabled.Value && ShowDefaultRevertButton; + bool showRevertButton = !controlDefault.Value && controlEnabled.Value && ShowRevertToDefaultButton; if (showRevertButton) revertButton.Show(); From 276757315f0197cdf418ba35cd26237974fa511e Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 18 Dec 2025 20:03:38 -0500 Subject: [PATCH 294/836] Simplify classic default flow --- osu.Game/Overlays/Settings/SettingsItemV2.cs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsItemV2.cs b/osu.Game/Overlays/Settings/SettingsItemV2.cs index 1f947d2898fc..084aa1ad1fd8 100644 --- a/osu.Game/Overlays/Settings/SettingsItemV2.cs +++ b/osu.Game/Overlays/Settings/SettingsItemV2.cs @@ -105,23 +105,13 @@ protected override void Update() #region ISettingsItem - public bool HasClassicDefault { get; private set; } - - private Action? applyClassicDefault; + public bool HasClassicDefault => ApplyClassicDefault != null; /// /// If set, this setting is considered as having a "classic" default value, /// and this is the function for overwriting the control with that value. /// - public Action? ApplyClassicDefault - { - get => applyClassicDefault; - set - { - applyClassicDefault = value; - HasClassicDefault = true; - } - } + public Action? ApplyClassicDefault { get; set; } void ISettingsItem.ApplyClassicDefault() => ApplyClassicDefault?.Invoke(); From c475b4bc4bf3e319c48d3f569737693da0c21e9e Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 18 Dec 2025 20:04:02 -0500 Subject: [PATCH 295/836] Add explanatory note for `ClearTransforms` usage --- osu.Game/Overlays/Settings/SettingsNote.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Settings/SettingsNote.cs b/osu.Game/Overlays/Settings/SettingsNote.cs index 5ddbfa9fcd94..3552e32d4e18 100644 --- a/osu.Game/Overlays/Settings/SettingsNote.cs +++ b/osu.Game/Overlays/Settings/SettingsNote.cs @@ -71,6 +71,7 @@ protected override void LoadComplete() private void updateDisplay() { + // Explicitly use ClearTransforms to clear any existing auto-size transform before modifying size / flag. ClearTransforms(); if (Current.Value == null) From f273163e58053a21c21ece9ecf8866ca7b764880 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Fri, 19 Dec 2025 02:24:42 -0500 Subject: [PATCH 296/836] Improve revert button animation --- osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs b/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs index 58e511341bc0..fd95277446a6 100644 --- a/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs +++ b/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs @@ -82,12 +82,12 @@ protected override void OnHoverLost(HoverLostEvent e) public override void Show() { - this.FadeIn().MoveToX(WIDTH - 10, 300, Easing.OutQuint); + this.FadeIn().MoveToX(WIDTH - 10, 200, Easing.OutElasticQuarter); } public override void Hide() { - this.MoveToX(0, 300, Easing.OutQuint).Then().FadeOut(); + this.MoveToX(0, 120, Easing.OutExpo).Then().FadeOut(); } private void updateDisplay() From f598d8b1088620f32e6e5c9fcdbeedf2b795a270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 19 Dec 2025 09:55:56 +0100 Subject: [PATCH 297/836] Add extended conversion mapping coverage for more failing cases Some are not immediately relevant to the stacking issue because they fail both before and after it, just less so after the stacking issue (half-)fix, and as such have been commented out for the time being. --- .../OsuBeatmapConversionTest.cs | 5 + .../Beatmaps/1341554-expected-conversion.json | 1 + .../Resources/Testing/Beatmaps/1341554.osu | 941 +++++++++ .../Beatmaps/2593923-expected-conversion.json | 1 + .../Resources/Testing/Beatmaps/2593923.osu | 1213 +++++++++++ .../Beatmaps/2730824-expected-conversion.json | 1 + .../Resources/Testing/Beatmaps/2730824.osu | 1140 +++++++++++ .../Beatmaps/4235513-expected-conversion.json | 1 + .../Resources/Testing/Beatmaps/4235513.osu | 825 ++++++++ .../Beatmaps/801165-expected-conversion.json | 1 + .../Resources/Testing/Beatmaps/801165.osu | 1768 +++++++++++++++++ 11 files changed, 5897 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/1341554-expected-conversion.json create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/1341554.osu create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2593923-expected-conversion.json create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2593923.osu create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824-expected-conversion.json create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824.osu create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513-expected-conversion.json create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513.osu create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/801165-expected-conversion.json create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/801165.osu diff --git a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs index 838bd35dd446..aaff1a2554c5 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs @@ -27,6 +27,11 @@ public class OsuBeatmapConversionTest : BeatmapConversionTest [TestCase("multi-segment-slider")] [TestCase("nan-slider")] [TestCase("1124896")] + // [TestCase("1341554")] TODO: investigate later + [TestCase("2593923")] + // [TestCase("2730824")] TODO: investigate later + // [TestCase("4235513")] TODO: investigate later + [TestCase("801165")] public void Test(string name) => base.Test(name); protected override IEnumerable CreateConvertValue(HitObject hitObject) diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/1341554-expected-conversion.json b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/1341554-expected-conversion.json new file mode 100644 index 000000000000..687676ff091c --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/1341554-expected-conversion.json @@ -0,0 +1 @@ +{"Mappings":[{"StartTime":763.0,"Objects":[{"StartTime":763.0,"EndTime":763.0,"X":309.0,"Y":230.0}]},{"StartTime":985.0,"Objects":[{"StartTime":985.0,"EndTime":985.0,"X":485.0,"Y":146.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":1060.0,"EndTime":1060.0,"X":419.765442,"Y":163.340836,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":1207.0,"Objects":[{"StartTime":1207.0,"EndTime":1207.0,"X":374.0,"Y":249.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":1282.0,"EndTime":1282.0,"X":309.2291,"Y":230.000534,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":1429.0,"Objects":[{"StartTime":1429.0,"EndTime":1429.0,"X":196.0,"Y":91.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":1484.0,"EndTime":1484.0,"X":192.451233,"Y":57.64155,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":1540.0,"EndTime":1540.0,"X":195.978485,"Y":90.79783,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":1559.0,"EndTime":1559.0,"X":192.429718,"Y":57.439373,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":1651.0,"Objects":[{"StartTime":1651.0,"EndTime":1651.0,"X":124.0,"Y":173.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":1725.0,"EndTime":1725.0,"X":130.363968,"Y":217.547729,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":1763.0,"EndTime":1763.0,"X":124.0,"Y":173.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":1874.0,"Objects":[{"StartTime":1874.0,"EndTime":1874.0,"X":221.0,"Y":284.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":1949.0,"EndTime":1949.0,"X":213.933777,"Y":216.87088,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":2096.0,"Objects":[{"StartTime":2096.0,"EndTime":2096.0,"X":292.0,"Y":86.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":2393.0,"EndTime":2393.0,"X":309.657043,"Y":231.180191,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":2540.0,"Objects":[{"StartTime":2540.0,"EndTime":2540.0,"X":314.0,"Y":328.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":2726.0,"EndTime":2726.0,"X":309.559021,"Y":230.758438,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":2874.0,"Objects":[{"StartTime":2874.0,"EndTime":2874.0,"X":421.0,"Y":300.0}]},{"StartTime":2985.0,"Objects":[{"StartTime":2985.0,"EndTime":2985.0,"X":421.0,"Y":300.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":3060.0,"EndTime":3060.0,"X":484.22522,"Y":265.267273,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":3207.0,"Objects":[{"StartTime":3207.0,"EndTime":3207.0,"X":309.0,"Y":231.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":3282.0,"EndTime":3282.0,"X":302.5318,"Y":158.8925,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":3429.0,"Objects":[{"StartTime":3429.0,"EndTime":3429.0,"X":394.0,"Y":22.0}]},{"StartTime":3540.0,"Objects":[{"StartTime":3540.0,"EndTime":3540.0,"X":461.0,"Y":72.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":3615.0,"EndTime":3615.0,"X":463.561279,"Y":140.796448,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":3762.0,"Objects":[{"StartTime":3762.0,"EndTime":3762.0,"X":378.0,"Y":183.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":3948.0,"EndTime":3948.0,"X":229.684937,"Y":160.580276,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":4096.0,"Objects":[{"StartTime":4096.0,"EndTime":4096.0,"X":229.0,"Y":161.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":4171.0,"EndTime":4171.0,"X":217.931763,"Y":234.559952,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":4318.0,"Objects":[{"StartTime":4318.0,"EndTime":4318.0,"X":61.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":4393.0,"EndTime":4393.0,"X":120.672028,"Y":339.566,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":4540.0,"Objects":[{"StartTime":4540.0,"EndTime":4540.0,"X":317.0,"Y":310.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":4615.0,"EndTime":4615.0,"X":243.821945,"Y":296.973145,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":4762.0,"Objects":[{"StartTime":4762.0,"EndTime":4762.0,"X":141.0,"Y":110.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":4948.0,"EndTime":4948.0,"X":155.885971,"Y":196.653961,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":5096.0,"Objects":[{"StartTime":5096.0,"EndTime":5096.0,"X":155.0,"Y":196.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":5282.0,"EndTime":5282.0,"X":76.3823242,"Y":283.3981,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":5429.0,"Objects":[{"StartTime":5429.0,"EndTime":5429.0,"X":212.0,"Y":366.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":5504.0,"EndTime":5504.0,"X":197.554764,"Y":312.149841,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":5651.0,"Objects":[{"StartTime":5651.0,"EndTime":5651.0,"X":206.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":5726.0,"EndTime":5726.0,"X":259.9921,"Y":299.971252,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":5874.0,"Objects":[{"StartTime":5874.0,"EndTime":5874.0,"X":281.0,"Y":321.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":5949.0,"EndTime":5949.0,"X":241.450119,"Y":360.213837,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":6096.0,"Objects":[{"StartTime":6096.0,"EndTime":6096.0,"X":124.0,"Y":246.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":6282.0,"EndTime":6282.0,"X":253.519653,"Y":211.447388,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":6429.0,"Objects":[{"StartTime":6429.0,"EndTime":6429.0,"X":253.0,"Y":211.0}]},{"StartTime":6540.0,"Objects":[{"StartTime":6540.0,"EndTime":6540.0,"X":276.0,"Y":99.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":6726.0,"EndTime":6726.0,"X":368.0168,"Y":208.521942,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":6874.0,"Objects":[{"StartTime":6874.0,"EndTime":6874.0,"X":368.0,"Y":208.0}]},{"StartTime":6985.0,"Objects":[{"StartTime":6985.0,"EndTime":6985.0,"X":430.0,"Y":96.0}]},{"StartTime":7096.0,"Objects":[{"StartTime":7096.0,"EndTime":7096.0,"X":497.0,"Y":147.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":7171.0,"EndTime":7171.0,"X":501.344818,"Y":219.752075,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7318.0,"Objects":[{"StartTime":7318.0,"EndTime":7318.0,"X":414.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":7504.0,"EndTime":7504.0,"X":421.0,"Y":298.0719,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7651.0,"Objects":[{"StartTime":7651.0,"EndTime":7651.0,"X":421.0,"Y":298.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":7726.0,"EndTime":7726.0,"X":349.034271,"Y":308.736725,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7874.0,"Objects":[{"StartTime":7874.0,"EndTime":7874.0,"X":270.0,"Y":170.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":7949.0,"EndTime":7949.0,"X":269.442352,"Y":242.5049,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":8096.0,"Objects":[{"StartTime":8096.0,"EndTime":8096.0,"X":94.0,"Y":300.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":8171.0,"EndTime":8171.0,"X":152.3368,"Y":258.00412,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":8318.0,"Objects":[{"StartTime":8318.0,"EndTime":8318.0,"X":261.0,"Y":374.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":8393.0,"EndTime":8393.0,"X":186.416916,"Y":366.102966,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":8540.0,"Objects":[{"StartTime":8540.0,"EndTime":8540.0,"X":38.0,"Y":377.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":8837.0,"EndTime":8837.0,"X":53.8668938,"Y":208.9976,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":8985.0,"Objects":[{"StartTime":8985.0,"EndTime":8985.0,"X":123.0,"Y":25.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":9060.0,"EndTime":9060.0,"X":130.897034,"Y":99.5830841,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":9207.0,"Objects":[{"StartTime":9207.0,"EndTime":9207.0,"X":217.0,"Y":242.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":9282.0,"EndTime":9282.0,"X":236.568176,"Y":169.597748,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":9429.0,"Objects":[{"StartTime":9429.0,"EndTime":9429.0,"X":48.0,"Y":92.0}]},{"StartTime":9540.0,"Objects":[{"StartTime":9540.0,"EndTime":9540.0,"X":63.0,"Y":176.0}]},{"StartTime":9651.0,"Objects":[{"StartTime":9651.0,"EndTime":9651.0,"X":83.0,"Y":259.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":9837.0,"EndTime":9837.0,"X":217.469971,"Y":242.57399,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":9985.0,"Objects":[{"StartTime":9985.0,"EndTime":9985.0,"X":274.0,"Y":312.0}]},{"StartTime":10096.0,"Objects":[{"StartTime":10096.0,"EndTime":10096.0,"X":274.0,"Y":312.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":10171.0,"EndTime":10171.0,"X":346.760681,"Y":293.8098,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":10318.0,"Objects":[{"StartTime":10318.0,"EndTime":10318.0,"X":459.0,"Y":225.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":10393.0,"EndTime":10393.0,"X":386.239319,"Y":206.80983,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":10540.0,"Objects":[{"StartTime":10540.0,"EndTime":10540.0,"X":269.0,"Y":107.0}]},{"StartTime":10651.0,"Objects":[{"StartTime":10651.0,"EndTime":10651.0,"X":276.0,"Y":54.0}]},{"StartTime":10762.0,"Objects":[{"StartTime":10762.0,"EndTime":10762.0,"X":313.0,"Y":17.0}]},{"StartTime":10874.0,"Objects":[{"StartTime":10874.0,"EndTime":10874.0,"X":363.0,"Y":9.0}]},{"StartTime":11096.0,"Objects":[{"StartTime":11096.0,"EndTime":11096.0,"X":363.0,"Y":9.0}]},{"StartTime":11207.0,"Objects":[{"StartTime":11207.0,"EndTime":11207.0,"X":432.0,"Y":68.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":11282.0,"EndTime":11282.0,"X":435.697968,"Y":139.207626,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":11429.0,"Objects":[{"StartTime":11429.0,"EndTime":11429.0,"X":309.0,"Y":252.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":11504.0,"EndTime":11504.0,"X":302.164825,"Y":181.178833,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":11651.0,"Objects":[{"StartTime":11651.0,"EndTime":11651.0,"X":450.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":11726.0,"EndTime":11726.0,"X":375.075623,"Y":312.6326,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":11874.0,"Objects":[{"StartTime":11874.0,"EndTime":11874.0,"X":160.0,"Y":341.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":12060.0,"EndTime":12060.0,"X":186.339523,"Y":248.443192,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":12207.0,"Objects":[{"StartTime":12207.0,"EndTime":12207.0,"X":116.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":12504.0,"EndTime":12504.0,"X":104.929565,"Y":274.1413,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":12762.0,"Objects":[{"StartTime":12762.0,"EndTime":12762.0,"X":297.0,"Y":91.0}]},{"StartTime":12874.0,"Objects":[{"StartTime":12874.0,"EndTime":12874.0,"X":276.0,"Y":44.0}]},{"StartTime":12985.0,"Objects":[{"StartTime":12985.0,"EndTime":12985.0,"X":226.0,"Y":27.0}]},{"StartTime":13096.0,"Objects":[{"StartTime":13096.0,"EndTime":13096.0,"X":187.0,"Y":63.0}]},{"StartTime":13207.0,"Objects":[{"StartTime":13207.0,"EndTime":13207.0,"X":196.0,"Y":115.0}]},{"StartTime":13429.0,"Objects":[{"StartTime":13429.0,"EndTime":13429.0,"X":376.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":13503.0,"EndTime":13503.0,"X":377.443817,"Y":127.395988,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":13541.0,"EndTime":13541.0,"X":376.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":13651.0,"Objects":[{"StartTime":13651.0,"EndTime":13651.0,"X":436.0,"Y":220.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":13837.0,"EndTime":13837.0,"X":288.903961,"Y":191.322586,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":13985.0,"Objects":[{"StartTime":13985.0,"EndTime":13985.0,"X":276.0,"Y":44.0}]},{"StartTime":14096.0,"Objects":[{"StartTime":14096.0,"EndTime":14096.0,"X":196.0,"Y":115.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":14151.0,"EndTime":14151.0,"X":159.292587,"Y":120.795906,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":14207.0,"EndTime":14207.0,"X":196.0,"Y":115.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":14262.0,"EndTime":14262.0,"X":159.292587,"Y":120.795906,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":14282.0,"EndTime":14282.0,"X":196.0,"Y":115.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":14429.0,"Objects":[{"StartTime":14429.0,"EndTime":14429.0,"X":82.0,"Y":69.0}]},{"StartTime":14540.0,"Objects":[{"StartTime":14540.0,"EndTime":14540.0,"X":106.0,"Y":190.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":14615.0,"EndTime":14615.0,"X":122.98851,"Y":263.0506,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":14762.0,"Objects":[{"StartTime":14762.0,"EndTime":14762.0,"X":218.0,"Y":383.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":14837.0,"EndTime":14837.0,"X":233.84996,"Y":309.693939,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":14985.0,"Objects":[{"StartTime":14985.0,"EndTime":14985.0,"X":26.0,"Y":231.0}]},{"StartTime":15207.0,"Objects":[{"StartTime":15207.0,"EndTime":15207.0,"X":253.0,"Y":202.0}]},{"StartTime":15318.0,"Objects":[{"StartTime":15318.0,"EndTime":15318.0,"X":331.0,"Y":271.0}]},{"StartTime":15429.0,"Objects":[{"StartTime":15429.0,"EndTime":15429.0,"X":233.0,"Y":309.0}]},{"StartTime":15651.0,"Objects":[{"StartTime":15651.0,"EndTime":15651.0,"X":389.0,"Y":73.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":15948.0,"EndTime":15948.0,"X":455.8205,"Y":109.365822,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":16096.0,"Objects":[{"StartTime":16096.0,"EndTime":16096.0,"X":391.0,"Y":165.0}]},{"StartTime":16207.0,"Objects":[{"StartTime":16207.0,"EndTime":16207.0,"X":377.0,"Y":177.0}]},{"StartTime":16318.0,"Objects":[{"StartTime":16318.0,"EndTime":16318.0,"X":365.0,"Y":187.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":16615.0,"EndTime":16615.0,"X":108.454308,"Y":184.412933,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":16762.0,"Objects":[{"StartTime":16762.0,"EndTime":16762.0,"X":73.0,"Y":319.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":17059.0,"EndTime":17059.0,"X":151.4236,"Y":251.735245,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":17207.0,"Objects":[{"StartTime":17207.0,"EndTime":17207.0,"X":139.0,"Y":258.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":17504.0,"EndTime":17504.0,"X":92.1605453,"Y":322.692932,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":17762.0,"Objects":[{"StartTime":17762.0,"EndTime":17762.0,"X":92.0,"Y":323.0}]},{"StartTime":17874.0,"Objects":[{"StartTime":17874.0,"EndTime":17874.0,"X":43.0,"Y":245.0}]},{"StartTime":17985.0,"Objects":[{"StartTime":17985.0,"EndTime":17985.0,"X":4.0,"Y":322.0}]},{"StartTime":18096.0,"Objects":[{"StartTime":18096.0,"EndTime":18096.0,"X":133.0,"Y":245.0}]},{"StartTime":18318.0,"Objects":[{"StartTime":18318.0,"EndTime":18318.0,"X":29.0,"Y":105.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18373.0,"EndTime":18373.0,"X":36.6683846,"Y":49.6172256,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18429.0,"EndTime":18429.0,"X":29.0464745,"Y":104.664345,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18448.0,"EndTime":18448.0,"X":36.71486,"Y":49.28157,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18540.0,"Objects":[{"StartTime":18540.0,"EndTime":18540.0,"X":50.0,"Y":30.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18726.0,"EndTime":18726.0,"X":187.203888,"Y":30.4987259,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18985.0,"Objects":[{"StartTime":18985.0,"EndTime":18985.0,"X":240.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19171.0,"EndTime":19171.0,"X":377.9097,"Y":110.78511,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19318.0,"Objects":[{"StartTime":19318.0,"EndTime":19318.0,"X":409.0,"Y":213.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19504.0,"EndTime":19504.0,"X":263.653748,"Y":204.007446,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19651.0,"Objects":[{"StartTime":19651.0,"EndTime":19651.0,"X":119.0,"Y":187.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19726.0,"EndTime":19726.0,"X":125.040916,"Y":261.756317,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19874.0,"Objects":[{"StartTime":19874.0,"EndTime":19874.0,"X":179.0,"Y":338.0}]},{"StartTime":19985.0,"Objects":[{"StartTime":19985.0,"EndTime":19985.0,"X":45.0,"Y":307.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20040.0,"EndTime":20040.0,"X":8.848415,"Y":298.3925,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20060.0,"EndTime":20060.0,"X":45.0,"Y":307.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20207.0,"Objects":[{"StartTime":20207.0,"EndTime":20207.0,"X":103.0,"Y":380.0}]},{"StartTime":20318.0,"Objects":[{"StartTime":20318.0,"EndTime":20318.0,"X":212.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20393.0,"EndTime":20393.0,"X":234.732208,"Y":187.976425,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20540.0,"Objects":[{"StartTime":20540.0,"EndTime":20540.0,"X":111.0,"Y":118.0}]},{"StartTime":20762.0,"Objects":[{"StartTime":20762.0,"EndTime":20762.0,"X":111.0,"Y":118.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20948.0,"EndTime":20948.0,"X":185.592651,"Y":110.193794,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21096.0,"Objects":[{"StartTime":21096.0,"EndTime":21096.0,"X":256.0,"Y":18.0}]},{"StartTime":21207.0,"Objects":[{"StartTime":21207.0,"EndTime":21207.0,"X":337.0,"Y":121.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21337.0,"EndTime":21337.0,"X":383.95816,"Y":25.23836,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21429.0,"Objects":[{"StartTime":21429.0,"EndTime":21429.0,"X":384.0,"Y":26.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21559.0,"EndTime":21559.0,"X":443.158325,"Y":114.866982,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21651.0,"Objects":[{"StartTime":21651.0,"EndTime":21651.0,"X":443.0,"Y":114.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21781.0,"EndTime":21781.0,"X":336.563934,"Y":123.06649,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21874.0,"Objects":[{"StartTime":21874.0,"EndTime":21874.0,"X":352.0,"Y":223.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21949.0,"EndTime":21949.0,"X":458.863068,"Y":242.7167,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22096.0,"Objects":[{"StartTime":22096.0,"EndTime":22096.0,"X":322.0,"Y":343.0}]},{"StartTime":22207.0,"Objects":[{"StartTime":22207.0,"EndTime":22207.0,"X":259.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22318.0,"EndTime":22318.0,"X":186.556473,"Y":265.58252,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22393.0,"EndTime":22393.0,"X":259.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22540.0,"Objects":[{"StartTime":22540.0,"EndTime":22540.0,"X":86.0,"Y":360.0}]},{"StartTime":22651.0,"Objects":[{"StartTime":22651.0,"EndTime":22651.0,"X":15.0,"Y":295.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22762.0,"EndTime":22762.0,"X":3.18144321,"Y":220.937042,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22837.0,"EndTime":22837.0,"X":15.0,"Y":295.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22985.0,"Objects":[{"StartTime":22985.0,"EndTime":22985.0,"X":94.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23282.0,"EndTime":23282.0,"X":112.333351,"Y":278.012543,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23429.0,"Objects":[{"StartTime":23429.0,"EndTime":23429.0,"X":0.0,"Y":211.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23504.0,"EndTime":23504.0,"X":73.58056,"Y":196.477524,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23651.0,"Objects":[{"StartTime":23651.0,"EndTime":23651.0,"X":215.0,"Y":134.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23726.0,"EndTime":23726.0,"X":142.0318,"Y":116.661018,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23874.0,"Objects":[{"StartTime":23874.0,"EndTime":23874.0,"X":33.0,"Y":124.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":24060.0,"EndTime":24060.0,"X":42.19049,"Y":11.8760223,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":24318.0,"Objects":[{"StartTime":24318.0,"EndTime":24318.0,"X":150.0,"Y":269.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":24504.0,"EndTime":24504.0,"X":161.849289,"Y":194.941956,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":24651.0,"Objects":[{"StartTime":24651.0,"EndTime":24651.0,"X":229.0,"Y":134.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":24726.0,"EndTime":24726.0,"X":339.500732,"Y":155.114792,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":24874.0,"Objects":[{"StartTime":24874.0,"EndTime":24874.0,"X":486.0,"Y":268.0}]},{"StartTime":24985.0,"Objects":[{"StartTime":24985.0,"EndTime":24985.0,"X":410.0,"Y":119.0}]},{"StartTime":25096.0,"Objects":[{"StartTime":25096.0,"EndTime":25096.0,"X":381.0,"Y":213.0}]},{"StartTime":25207.0,"Objects":[{"StartTime":25207.0,"EndTime":25207.0,"X":512.0,"Y":120.0}]},{"StartTime":25429.0,"Objects":[{"StartTime":25429.0,"EndTime":25429.0,"X":247.0,"Y":36.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25484.0,"EndTime":25484.0,"X":210.424835,"Y":28.8155918,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25540.0,"EndTime":25540.0,"X":246.778336,"Y":35.95646,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25559.0,"EndTime":25559.0,"X":210.203171,"Y":28.77205,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25651.0,"Objects":[{"StartTime":25651.0,"EndTime":25651.0,"X":185.0,"Y":24.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25837.0,"EndTime":25837.0,"X":171.310989,"Y":155.469345,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26096.0,"Objects":[{"StartTime":26096.0,"EndTime":26096.0,"X":253.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26282.0,"EndTime":26282.0,"X":248.797211,"Y":354.1396,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26429.0,"Objects":[{"StartTime":26429.0,"EndTime":26429.0,"X":100.0,"Y":363.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26615.0,"EndTime":26615.0,"X":249.760269,"Y":354.523,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26762.0,"Objects":[{"StartTime":26762.0,"EndTime":26762.0,"X":404.0,"Y":262.0}]},{"StartTime":26874.0,"Objects":[{"StartTime":26874.0,"EndTime":26874.0,"X":390.0,"Y":352.0}]},{"StartTime":26985.0,"Objects":[{"StartTime":26985.0,"EndTime":26985.0,"X":314.0,"Y":295.0}]},{"StartTime":27096.0,"Objects":[{"StartTime":27096.0,"EndTime":27096.0,"X":425.0,"Y":256.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27151.0,"EndTime":27151.0,"X":461.755035,"Y":250.514175,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27171.0,"EndTime":27171.0,"X":425.0,"Y":256.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27318.0,"Objects":[{"StartTime":27318.0,"EndTime":27318.0,"X":329.0,"Y":216.0}]},{"StartTime":27429.0,"Objects":[{"StartTime":27429.0,"EndTime":27429.0,"X":193.0,"Y":177.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27504.0,"EndTime":27504.0,"X":266.260956,"Y":160.94281,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27651.0,"Objects":[{"StartTime":27651.0,"EndTime":27651.0,"X":322.0,"Y":107.0}]},{"StartTime":27874.0,"Objects":[{"StartTime":27874.0,"EndTime":27874.0,"X":322.0,"Y":107.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":28060.0,"EndTime":28060.0,"X":311.7376,"Y":219.030945,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":28207.0,"Objects":[{"StartTime":28207.0,"EndTime":28207.0,"X":110.0,"Y":299.0}]},{"StartTime":28318.0,"Objects":[{"StartTime":28318.0,"EndTime":28318.0,"X":164.0,"Y":231.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":28448.0,"EndTime":28448.0,"X":135.6063,"Y":327.122955,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":28540.0,"Objects":[{"StartTime":28540.0,"EndTime":28540.0,"X":30.0,"Y":284.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":28670.0,"EndTime":28670.0,"X":127.158829,"Y":259.8269,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":28762.0,"Objects":[{"StartTime":28762.0,"EndTime":28762.0,"X":148.0,"Y":371.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":28892.0,"EndTime":28892.0,"X":78.25478,"Y":298.6825,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":28985.0,"Objects":[{"StartTime":28985.0,"EndTime":28985.0,"X":194.0,"Y":201.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29060.0,"EndTime":29060.0,"X":299.8987,"Y":225.443588,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":29207.0,"Objects":[{"StartTime":29207.0,"EndTime":29207.0,"X":492.0,"Y":114.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29282.0,"EndTime":29282.0,"X":422.503,"Y":138.437851,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":29429.0,"Objects":[{"StartTime":29429.0,"EndTime":29429.0,"X":324.0,"Y":102.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29504.0,"EndTime":29504.0,"X":281.7771,"Y":42.667614,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":29651.0,"Objects":[{"StartTime":29651.0,"EndTime":29651.0,"X":418.0,"Y":17.0}]},{"StartTime":29874.0,"Objects":[{"StartTime":29874.0,"EndTime":29874.0,"X":495.0,"Y":201.0}]},{"StartTime":30096.0,"Objects":[{"StartTime":30096.0,"EndTime":30096.0,"X":221.0,"Y":136.0}]},{"StartTime":30207.0,"Objects":[{"StartTime":30207.0,"EndTime":30207.0,"X":299.0,"Y":188.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30393.0,"EndTime":30393.0,"X":281.51004,"Y":328.410828,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30540.0,"Objects":[{"StartTime":30540.0,"EndTime":30540.0,"X":115.0,"Y":334.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30837.0,"EndTime":30837.0,"X":166.044785,"Y":247.203171,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30985.0,"Objects":[{"StartTime":30985.0,"EndTime":30985.0,"X":216.0,"Y":326.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31012.0,"EndTime":31012.0,"X":279.647339,"Y":329.616333,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31429.0,"Objects":[{"StartTime":31429.0,"EndTime":31429.0,"X":280.0,"Y":330.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31504.0,"EndTime":31504.0,"X":290.840027,"Y":255.7875,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31651.0,"Objects":[{"StartTime":31651.0,"EndTime":31651.0,"X":426.0,"Y":252.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31726.0,"EndTime":31726.0,"X":436.840027,"Y":177.7875,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31874.0,"Objects":[{"StartTime":31874.0,"EndTime":31874.0,"X":253.0,"Y":158.0}]},{"StartTime":31985.0,"Objects":[{"StartTime":31985.0,"EndTime":31985.0,"X":258.0,"Y":132.0}]},{"StartTime":32096.0,"Objects":[{"StartTime":32096.0,"EndTime":32096.0,"X":337.0,"Y":111.0}]},{"StartTime":32207.0,"Objects":[{"StartTime":32207.0,"EndTime":32207.0,"X":341.0,"Y":85.0}]},{"StartTime":32318.0,"Objects":[{"StartTime":32318.0,"EndTime":32318.0,"X":271.0,"Y":30.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32448.0,"EndTime":32448.0,"X":162.253082,"Y":25.8848,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32540.0,"Objects":[{"StartTime":32540.0,"EndTime":32540.0,"X":163.0,"Y":26.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32726.0,"EndTime":32726.0,"X":144.749512,"Y":174.88559,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32985.0,"Objects":[{"StartTime":32985.0,"EndTime":32985.0,"X":445.0,"Y":343.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33171.0,"EndTime":33171.0,"X":404.5491,"Y":255.923309,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33429.0,"Objects":[{"StartTime":33429.0,"EndTime":33429.0,"X":240.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33615.0,"EndTime":33615.0,"X":280.0188,"Y":182.645447,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33874.0,"Objects":[{"StartTime":33874.0,"EndTime":33874.0,"X":68.0,"Y":333.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34060.0,"EndTime":34060.0,"X":40.12644,"Y":256.4784,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34318.0,"Objects":[{"StartTime":34318.0,"EndTime":34318.0,"X":344.0,"Y":347.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34393.0,"EndTime":34393.0,"X":464.08136,"Y":329.892731,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34540.0,"Objects":[{"StartTime":34540.0,"EndTime":34540.0,"X":452.0,"Y":255.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34726.0,"EndTime":34726.0,"X":338.6652,"Y":265.867065,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34874.0,"Objects":[{"StartTime":34874.0,"EndTime":34874.0,"X":256.0,"Y":220.0}]},{"StartTime":34985.0,"Objects":[{"StartTime":34985.0,"EndTime":34985.0,"X":256.0,"Y":220.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35060.0,"EndTime":35060.0,"X":256.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35207.0,"Objects":[{"StartTime":35207.0,"EndTime":35207.0,"X":256.0,"Y":70.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35282.0,"EndTime":35282.0,"X":256.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35429.0,"Objects":[{"StartTime":35429.0,"EndTime":35429.0,"X":112.0,"Y":312.0}]},{"StartTime":35540.0,"Objects":[{"StartTime":35540.0,"EndTime":35540.0,"X":60.0,"Y":255.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35726.0,"EndTime":35726.0,"X":173.334808,"Y":265.867065,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35874.0,"Objects":[{"StartTime":35874.0,"EndTime":35874.0,"X":169.0,"Y":350.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36282.0,"EndTime":36282.0,"X":48.1567,"Y":333.550873,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36429.0,"Objects":[{"StartTime":36429.0,"EndTime":36429.0,"X":62.0,"Y":169.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36540.0,"EndTime":36540.0,"X":72.6066055,"Y":243.246216,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36615.0,"EndTime":36615.0,"X":62.0,"Y":169.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36762.0,"Objects":[{"StartTime":36762.0,"EndTime":36762.0,"X":134.0,"Y":61.0}]},{"StartTime":36874.0,"Objects":[{"StartTime":36874.0,"EndTime":36874.0,"X":201.0,"Y":113.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36985.0,"EndTime":36985.0,"X":211.6066,"Y":187.246216,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37060.0,"EndTime":37060.0,"X":201.0,"Y":113.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":37207.0,"Objects":[{"StartTime":37207.0,"EndTime":37207.0,"X":298.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37282.0,"EndTime":37282.0,"X":312.225616,"Y":198.361481,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":37429.0,"Objects":[{"StartTime":37429.0,"EndTime":37429.0,"X":330.0,"Y":114.0}]},{"StartTime":37540.0,"Objects":[{"StartTime":37540.0,"EndTime":37540.0,"X":446.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37726.0,"EndTime":37726.0,"X":312.0408,"Y":197.883438,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":37874.0,"Objects":[{"StartTime":37874.0,"EndTime":37874.0,"X":231.0,"Y":240.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37949.0,"EndTime":37949.0,"X":229.158188,"Y":166.818878,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38096.0,"Objects":[{"StartTime":38096.0,"EndTime":38096.0,"X":325.0,"Y":285.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38171.0,"EndTime":38171.0,"X":175.573792,"Y":298.107574,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38540.0,"Objects":[{"StartTime":38540.0,"EndTime":38540.0,"X":175.0,"Y":298.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38615.0,"EndTime":38615.0,"X":165.884415,"Y":372.44397,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38762.0,"Objects":[{"StartTime":38762.0,"EndTime":38762.0,"X":75.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38837.0,"EndTime":38837.0,"X":65.8844147,"Y":282.44397,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38985.0,"Objects":[{"StartTime":38985.0,"EndTime":38985.0,"X":233.0,"Y":74.0}]},{"StartTime":39096.0,"Objects":[{"StartTime":39096.0,"EndTime":39096.0,"X":231.0,"Y":98.0}]},{"StartTime":39207.0,"Objects":[{"StartTime":39207.0,"EndTime":39207.0,"X":156.0,"Y":139.0}]},{"StartTime":39318.0,"Objects":[{"StartTime":39318.0,"EndTime":39318.0,"X":155.0,"Y":165.0}]},{"StartTime":39429.0,"Objects":[{"StartTime":39429.0,"EndTime":39429.0,"X":227.0,"Y":215.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":39559.0,"EndTime":39559.0,"X":336.996735,"Y":222.441727,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":39651.0,"Objects":[{"StartTime":39651.0,"EndTime":39651.0,"X":336.0,"Y":222.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":39837.0,"EndTime":39837.0,"X":364.5033,"Y":74.73303,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":40096.0,"Objects":[{"StartTime":40096.0,"EndTime":40096.0,"X":81.0,"Y":35.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":40282.0,"EndTime":40282.0,"X":127.2737,"Y":104.866875,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":40540.0,"Objects":[{"StartTime":40540.0,"EndTime":40540.0,"X":272.0,"Y":158.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":40726.0,"EndTime":40726.0,"X":224.732422,"Y":227.8874,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":40985.0,"Objects":[{"StartTime":40985.0,"EndTime":40985.0,"X":423.0,"Y":36.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41171.0,"EndTime":41171.0,"X":443.179352,"Y":116.766846,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41429.0,"Objects":[{"StartTime":41429.0,"EndTime":41429.0,"X":512.0,"Y":278.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41504.0,"EndTime":41504.0,"X":373.7834,"Y":280.097351,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41651.0,"Objects":[{"StartTime":41651.0,"EndTime":41651.0,"X":359.0,"Y":302.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41781.0,"EndTime":41781.0,"X":312.524048,"Y":206.435242,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41874.0,"Objects":[{"StartTime":41874.0,"EndTime":41874.0,"X":322.0,"Y":190.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42004.0,"EndTime":42004.0,"X":433.261749,"Y":173.354538,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42096.0,"Objects":[{"StartTime":42096.0,"EndTime":42096.0,"X":443.0,"Y":159.0}]},{"StartTime":42318.0,"Objects":[{"StartTime":42318.0,"EndTime":42318.0,"X":240.0,"Y":52.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42393.0,"EndTime":42393.0,"X":244.301,"Y":121.796005,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42540.0,"Objects":[{"StartTime":42540.0,"EndTime":42540.0,"X":177.0,"Y":166.0}]},{"StartTime":42651.0,"Objects":[{"StartTime":42651.0,"EndTime":42651.0,"X":163.0,"Y":151.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42837.0,"EndTime":42837.0,"X":189.527557,"Y":288.624542,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42985.0,"Objects":[{"StartTime":42985.0,"EndTime":42985.0,"X":131.0,"Y":365.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43171.0,"EndTime":43171.0,"X":263.826355,"Y":333.7347,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":43318.0,"Objects":[{"StartTime":43318.0,"EndTime":43318.0,"X":335.0,"Y":377.0}]},{"StartTime":43429.0,"Objects":[{"StartTime":43429.0,"EndTime":43429.0,"X":442.0,"Y":239.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43726.0,"EndTime":43726.0,"X":444.975067,"Y":103.950119,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":43874.0,"Objects":[{"StartTime":43874.0,"EndTime":43874.0,"X":444.0,"Y":103.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43949.0,"EndTime":43949.0,"X":371.940247,"Y":120.881523,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44096.0,"Objects":[{"StartTime":44096.0,"EndTime":44096.0,"X":249.0,"Y":28.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44171.0,"EndTime":44171.0,"X":320.874725,"Y":46.2887573,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44318.0,"Objects":[{"StartTime":44318.0,"EndTime":44318.0,"X":364.0,"Y":201.0}]},{"StartTime":44429.0,"Objects":[{"StartTime":44429.0,"EndTime":44429.0,"X":332.0,"Y":195.0}]},{"StartTime":44540.0,"Objects":[{"StartTime":44540.0,"EndTime":44540.0,"X":251.0,"Y":135.0}]},{"StartTime":44651.0,"Objects":[{"StartTime":44651.0,"EndTime":44651.0,"X":281.0,"Y":123.0}]},{"StartTime":44762.0,"Objects":[{"StartTime":44762.0,"EndTime":44762.0,"X":332.0,"Y":195.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44948.0,"EndTime":44948.0,"X":306.331055,"Y":299.344849,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":45207.0,"Objects":[{"StartTime":45207.0,"EndTime":45207.0,"X":61.0,"Y":25.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":45282.0,"EndTime":45282.0,"X":83.3818054,"Y":135.2511,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":45651.0,"Objects":[{"StartTime":45651.0,"EndTime":45651.0,"X":84.0,"Y":136.0}]},{"StartTime":46096.0,"Objects":[{"StartTime":46096.0,"EndTime":46096.0,"X":84.0,"Y":136.0}]},{"StartTime":46207.0,"Objects":[{"StartTime":46207.0,"EndTime":46207.0,"X":176.0,"Y":33.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":46282.0,"EndTime":46282.0,"X":166.495789,"Y":88.44125,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":46429.0,"Objects":[{"StartTime":46429.0,"EndTime":46429.0,"X":219.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":46504.0,"EndTime":46504.0,"X":231.938934,"Y":152.258362,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":46651.0,"Objects":[{"StartTime":46651.0,"EndTime":46651.0,"X":312.0,"Y":65.0}]},{"StartTime":46762.0,"Objects":[{"StartTime":46762.0,"EndTime":46762.0,"X":312.0,"Y":65.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":46837.0,"EndTime":46837.0,"X":365.301147,"Y":82.97364,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":46985.0,"Objects":[{"StartTime":46985.0,"EndTime":46985.0,"X":512.0,"Y":176.0}]},{"StartTime":47096.0,"Objects":[{"StartTime":47096.0,"EndTime":47096.0,"X":421.0,"Y":192.0}]},{"StartTime":47429.0,"Objects":[{"StartTime":47429.0,"EndTime":47429.0,"X":421.0,"Y":192.0}]},{"StartTime":47651.0,"Objects":[{"StartTime":47651.0,"EndTime":47651.0,"X":402.0,"Y":357.0}]},{"StartTime":47762.0,"Objects":[{"StartTime":47762.0,"EndTime":47762.0,"X":394.0,"Y":277.0}]},{"StartTime":47874.0,"Objects":[{"StartTime":47874.0,"EndTime":47874.0,"X":328.0,"Y":324.0}]},{"StartTime":48318.0,"Objects":[{"StartTime":48318.0,"EndTime":48318.0,"X":328.0,"Y":324.0}]},{"StartTime":48540.0,"Objects":[{"StartTime":48540.0,"EndTime":48540.0,"X":110.0,"Y":357.0}]},{"StartTime":48651.0,"Objects":[{"StartTime":48651.0,"EndTime":48651.0,"X":118.0,"Y":277.0}]},{"StartTime":48763.0,"Objects":[{"StartTime":48763.0,"EndTime":48763.0,"X":184.0,"Y":324.0}]},{"StartTime":48874.0,"Objects":[{"StartTime":48874.0,"EndTime":48874.0,"X":110.0,"Y":357.0}]},{"StartTime":49207.0,"Objects":[{"StartTime":49207.0,"EndTime":49207.0,"X":110.0,"Y":357.0}]},{"StartTime":49651.0,"Objects":[{"StartTime":49651.0,"EndTime":49651.0,"X":110.0,"Y":357.0}]},{"StartTime":49762.0,"Objects":[{"StartTime":49762.0,"EndTime":49762.0,"X":0.0,"Y":283.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49837.0,"EndTime":49837.0,"X":52.00481,"Y":302.320679,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49985.0,"Objects":[{"StartTime":49985.0,"EndTime":49985.0,"X":188.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50060.0,"EndTime":50060.0,"X":139.90033,"Y":245.560135,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50207.0,"Objects":[{"StartTime":50207.0,"EndTime":50207.0,"X":49.0,"Y":137.0}]},{"StartTime":50318.0,"Objects":[{"StartTime":50318.0,"EndTime":50318.0,"X":49.0,"Y":137.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50393.0,"EndTime":50393.0,"X":68.7774048,"Y":188.112656,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50540.0,"Objects":[{"StartTime":50540.0,"EndTime":50540.0,"X":107.0,"Y":67.0}]},{"StartTime":50651.0,"Objects":[{"StartTime":50651.0,"EndTime":50651.0,"X":32.0,"Y":15.0}]},{"StartTime":50985.0,"Objects":[{"StartTime":50985.0,"EndTime":50985.0,"X":32.0,"Y":15.0}]},{"StartTime":51207.0,"Objects":[{"StartTime":51207.0,"EndTime":51207.0,"X":265.0,"Y":114.0}]},{"StartTime":51318.0,"Objects":[{"StartTime":51318.0,"EndTime":51318.0,"X":254.0,"Y":196.0}]},{"StartTime":51429.0,"Objects":[{"StartTime":51429.0,"EndTime":51429.0,"X":241.0,"Y":279.0}]},{"StartTime":51651.0,"Objects":[{"StartTime":51651.0,"EndTime":51651.0,"X":241.0,"Y":279.0}]},{"StartTime":51762.0,"Objects":[{"StartTime":51762.0,"EndTime":51762.0,"X":336.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":52059.0,"EndTime":52059.0,"X":391.603638,"Y":270.527466,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":52318.0,"Objects":[{"StartTime":52318.0,"EndTime":52318.0,"X":83.0,"Y":206.0}]},{"StartTime":52429.0,"Objects":[{"StartTime":52429.0,"EndTime":52429.0,"X":83.0,"Y":206.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":52504.0,"EndTime":52504.0,"X":100.787811,"Y":259.363434,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":52651.0,"Objects":[{"StartTime":52651.0,"EndTime":52651.0,"X":40.0,"Y":383.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":52726.0,"EndTime":52726.0,"X":78.99291,"Y":342.874847,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":52874.0,"Objects":[{"StartTime":52874.0,"EndTime":52874.0,"X":214.0,"Y":334.0}]},{"StartTime":52985.0,"Objects":[{"StartTime":52985.0,"EndTime":52985.0,"X":214.0,"Y":334.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":53060.0,"EndTime":53060.0,"X":160.677017,"Y":317.0179,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":53207.0,"Objects":[{"StartTime":53207.0,"EndTime":53207.0,"X":151.0,"Y":160.0}]},{"StartTime":53318.0,"Objects":[{"StartTime":53318.0,"EndTime":53318.0,"X":188.0,"Y":135.0}]},{"StartTime":53429.0,"Objects":[{"StartTime":53429.0,"EndTime":53429.0,"X":232.0,"Y":129.0}]},{"StartTime":53540.0,"Objects":[{"StartTime":53540.0,"EndTime":53540.0,"X":273.0,"Y":146.0}]},{"StartTime":53651.0,"Objects":[{"StartTime":53651.0,"EndTime":53651.0,"X":339.0,"Y":198.0}]},{"StartTime":53762.0,"Objects":[{"StartTime":53762.0,"EndTime":53762.0,"X":383.0,"Y":199.0}]},{"StartTime":53874.0,"Objects":[{"StartTime":53874.0,"EndTime":53874.0,"X":426.0,"Y":185.0}]},{"StartTime":53985.0,"Objects":[{"StartTime":53985.0,"EndTime":53985.0,"X":450.0,"Y":147.0}]},{"StartTime":54096.0,"Objects":[{"StartTime":54096.0,"EndTime":54096.0,"X":444.0,"Y":61.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54171.0,"EndTime":54171.0,"X":404.198761,"Y":22.7040062,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54318.0,"Objects":[{"StartTime":54318.0,"EndTime":54318.0,"X":301.0,"Y":28.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54393.0,"EndTime":54393.0,"X":259.281525,"Y":62.49509,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54540.0,"Objects":[{"StartTime":54540.0,"EndTime":54540.0,"X":189.0,"Y":271.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54615.0,"EndTime":54615.0,"X":208.7961,"Y":220.140625,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54762.0,"Objects":[{"StartTime":54762.0,"EndTime":54762.0,"X":186.0,"Y":114.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54837.0,"EndTime":54837.0,"X":149.98996,"Y":73.19951,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54985.0,"Objects":[{"StartTime":54985.0,"EndTime":54985.0,"X":27.0,"Y":137.0}]},{"StartTime":55096.0,"Objects":[{"StartTime":55096.0,"EndTime":55096.0,"X":34.0,"Y":167.0}]},{"StartTime":55207.0,"Objects":[{"StartTime":55207.0,"EndTime":55207.0,"X":122.0,"Y":204.0}]},{"StartTime":55318.0,"Objects":[{"StartTime":55318.0,"EndTime":55318.0,"X":116.0,"Y":178.0}]},{"StartTime":55429.0,"Objects":[{"StartTime":55429.0,"EndTime":55429.0,"X":48.0,"Y":249.0}]},{"StartTime":55540.0,"Objects":[{"StartTime":55540.0,"EndTime":55540.0,"X":54.0,"Y":274.0}]},{"StartTime":55651.0,"Objects":[{"StartTime":55651.0,"EndTime":55651.0,"X":124.0,"Y":329.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":55726.0,"EndTime":55726.0,"X":179.117538,"Y":319.596771,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":55874.0,"Objects":[{"StartTime":55874.0,"EndTime":55874.0,"X":320.0,"Y":185.0}]},{"StartTime":55985.0,"Objects":[{"StartTime":55985.0,"EndTime":55985.0,"X":287.0,"Y":175.0}]},{"StartTime":56096.0,"Objects":[{"StartTime":56096.0,"EndTime":56096.0,"X":254.0,"Y":181.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56171.0,"EndTime":56171.0,"X":262.399933,"Y":236.321579,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56318.0,"Objects":[{"StartTime":56318.0,"EndTime":56318.0,"X":337.0,"Y":347.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56393.0,"EndTime":56393.0,"X":350.0131,"Y":293.286041,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56540.0,"Objects":[{"StartTime":56540.0,"EndTime":56540.0,"X":418.0,"Y":197.0}]},{"StartTime":56651.0,"Objects":[{"StartTime":56651.0,"EndTime":56651.0,"X":418.0,"Y":197.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56726.0,"EndTime":56726.0,"X":472.82196,"Y":184.405762,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56874.0,"Objects":[{"StartTime":56874.0,"EndTime":56874.0,"X":329.0,"Y":114.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56949.0,"EndTime":56949.0,"X":275.1002,"Y":97.91051,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57096.0,"Objects":[{"StartTime":57096.0,"EndTime":57096.0,"X":436.0,"Y":59.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57171.0,"EndTime":57171.0,"X":417.73645,"Y":112.2025,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57318.0,"Objects":[{"StartTime":57318.0,"EndTime":57318.0,"X":332.0,"Y":194.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57429.0,"EndTime":57429.0,"X":349.292969,"Y":247.525848,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57504.0,"EndTime":57504.0,"X":332.0,"Y":194.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57651.0,"Objects":[{"StartTime":57651.0,"EndTime":57651.0,"X":202.0,"Y":194.0}]},{"StartTime":57762.0,"Objects":[{"StartTime":57762.0,"EndTime":57762.0,"X":224.0,"Y":233.0}]},{"StartTime":57874.0,"Objects":[{"StartTime":57874.0,"EndTime":57874.0,"X":222.0,"Y":279.0}]},{"StartTime":57985.0,"Objects":[{"StartTime":57985.0,"EndTime":57985.0,"X":193.0,"Y":314.0}]},{"StartTime":58096.0,"Objects":[{"StartTime":58096.0,"EndTime":58096.0,"X":144.0,"Y":244.0}]},{"StartTime":58207.0,"Objects":[{"StartTime":58207.0,"EndTime":58207.0,"X":127.0,"Y":214.0}]},{"StartTime":58318.0,"Objects":[{"StartTime":58318.0,"EndTime":58318.0,"X":126.0,"Y":180.0}]},{"StartTime":58429.0,"Objects":[{"StartTime":58429.0,"EndTime":58429.0,"X":139.0,"Y":149.0}]},{"StartTime":58540.0,"Objects":[{"StartTime":58540.0,"EndTime":58540.0,"X":224.0,"Y":113.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58726.0,"EndTime":58726.0,"X":198.29718,"Y":184.3571,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58874.0,"Objects":[{"StartTime":58874.0,"EndTime":58874.0,"X":299.0,"Y":319.0}]},{"StartTime":58985.0,"Objects":[{"StartTime":58985.0,"EndTime":58985.0,"X":299.0,"Y":319.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59282.0,"EndTime":59282.0,"X":356.653656,"Y":227.930466,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59429.0,"Objects":[{"StartTime":59429.0,"EndTime":59429.0,"X":428.0,"Y":181.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59615.0,"EndTime":59615.0,"X":418.7787,"Y":18.6044426,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59874.0,"Objects":[{"StartTime":59874.0,"EndTime":59874.0,"X":418.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59911.0,"EndTime":59911.0,"X":393.055359,"Y":16.3370247,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59948.0,"EndTime":59948.0,"X":418.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59985.0,"EndTime":59985.0,"X":393.055359,"Y":16.3370247,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60022.0,"EndTime":60022.0,"X":418.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60059.0,"EndTime":60059.0,"X":393.055359,"Y":16.3370247,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60060.0,"EndTime":60060.0,"X":418.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60207.0,"Objects":[{"StartTime":60207.0,"EndTime":60207.0,"X":428.0,"Y":181.0}]},{"StartTime":60318.0,"Objects":[{"StartTime":60318.0,"EndTime":60318.0,"X":352.0,"Y":209.0}]},{"StartTime":60429.0,"Objects":[{"StartTime":60429.0,"EndTime":60429.0,"X":278.0,"Y":177.0}]},{"StartTime":60540.0,"Objects":[{"StartTime":60540.0,"EndTime":60540.0,"X":208.0,"Y":225.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60595.0,"EndTime":60595.0,"X":219.751709,"Y":260.255127,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60615.0,"EndTime":60615.0,"X":208.0,"Y":225.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60762.0,"Objects":[{"StartTime":60762.0,"EndTime":60762.0,"X":71.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60799.0,"EndTime":60799.0,"X":66.7759,"Y":119.359444,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60836.0,"EndTime":60836.0,"X":71.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60837.0,"EndTime":60837.0,"X":66.7759,"Y":119.359444,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60985.0,"Objects":[{"StartTime":60985.0,"EndTime":60985.0,"X":145.0,"Y":86.0}]},{"StartTime":61096.0,"Objects":[{"StartTime":61096.0,"EndTime":61096.0,"X":163.0,"Y":127.0}]},{"StartTime":61207.0,"Objects":[{"StartTime":61207.0,"EndTime":61207.0,"X":161.0,"Y":171.0}]},{"StartTime":61318.0,"Objects":[{"StartTime":61318.0,"EndTime":61318.0,"X":136.0,"Y":208.0}]},{"StartTime":61429.0,"Objects":[{"StartTime":61429.0,"EndTime":61429.0,"X":99.0,"Y":231.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61504.0,"EndTime":61504.0,"X":106.705917,"Y":300.142578,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61651.0,"Objects":[{"StartTime":61651.0,"EndTime":61651.0,"X":177.0,"Y":378.0}]},{"StartTime":61762.0,"Objects":[{"StartTime":61762.0,"EndTime":61762.0,"X":177.0,"Y":378.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61948.0,"EndTime":61948.0,"X":336.375977,"Y":319.826965,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62096.0,"Objects":[{"StartTime":62096.0,"EndTime":62096.0,"X":417.0,"Y":293.0}]},{"StartTime":62207.0,"Objects":[{"StartTime":62207.0,"EndTime":62207.0,"X":438.0,"Y":263.0}]},{"StartTime":62318.0,"Objects":[{"StartTime":62318.0,"EndTime":62318.0,"X":436.0,"Y":225.0}]},{"StartTime":62429.0,"Objects":[{"StartTime":62429.0,"EndTime":62429.0,"X":412.0,"Y":196.0}]},{"StartTime":62540.0,"Objects":[{"StartTime":62540.0,"EndTime":62540.0,"X":320.0,"Y":172.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62567.0,"EndTime":62567.0,"X":296.5699,"Y":200.555862,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62651.0,"Objects":[{"StartTime":62651.0,"EndTime":62651.0,"X":291.0,"Y":147.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62678.0,"EndTime":62678.0,"X":256.037964,"Y":156.462814,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62762.0,"Objects":[{"StartTime":62762.0,"EndTime":62762.0,"X":276.0,"Y":114.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62789.0,"EndTime":62789.0,"X":241.446152,"Y":101.1804,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62874.0,"Objects":[{"StartTime":62874.0,"EndTime":62874.0,"X":283.0,"Y":81.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62901.0,"EndTime":62901.0,"X":261.449921,"Y":51.34725,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62985.0,"Objects":[{"StartTime":62985.0,"EndTime":62985.0,"X":365.0,"Y":31.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63060.0,"EndTime":63060.0,"X":437.0226,"Y":49.0166931,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63207.0,"Objects":[{"StartTime":63207.0,"EndTime":63207.0,"X":512.0,"Y":169.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63282.0,"EndTime":63282.0,"X":438.3405,"Y":168.621353,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63429.0,"Objects":[{"StartTime":63429.0,"EndTime":63429.0,"X":350.0,"Y":107.0}]},{"StartTime":63540.0,"Objects":[{"StartTime":63540.0,"EndTime":63540.0,"X":293.0,"Y":237.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63615.0,"EndTime":63615.0,"X":277.221954,"Y":163.678436,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63762.0,"Objects":[{"StartTime":63762.0,"EndTime":63762.0,"X":428.0,"Y":269.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63948.0,"EndTime":63948.0,"X":287.108154,"Y":253.30072,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64096.0,"Objects":[{"StartTime":64096.0,"EndTime":64096.0,"X":191.0,"Y":318.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64171.0,"EndTime":64171.0,"X":204.152679,"Y":384.5369,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64318.0,"Objects":[{"StartTime":64318.0,"EndTime":64318.0,"X":192.0,"Y":186.0}]},{"StartTime":64429.0,"Objects":[{"StartTime":64429.0,"EndTime":64429.0,"X":135.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64540.0,"EndTime":64540.0,"X":61.6784363,"Y":268.778046,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64615.0,"EndTime":64615.0,"X":135.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64762.0,"Objects":[{"StartTime":64762.0,"EndTime":64762.0,"X":24.0,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64892.0,"EndTime":64892.0,"X":146.587021,"Y":69.97707,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64985.0,"Objects":[{"StartTime":64985.0,"EndTime":64985.0,"X":160.0,"Y":80.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65115.0,"EndTime":65115.0,"X":236.668945,"Y":106.661751,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65207.0,"Objects":[{"StartTime":65207.0,"EndTime":65207.0,"X":276.0,"Y":34.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65337.0,"EndTime":65337.0,"X":288.3495,"Y":191.015091,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65429.0,"Objects":[{"StartTime":65429.0,"EndTime":65429.0,"X":291.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65559.0,"EndTime":65559.0,"X":309.903473,"Y":136.769836,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65651.0,"Objects":[{"StartTime":65651.0,"EndTime":65651.0,"X":381.0,"Y":111.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65726.0,"EndTime":65726.0,"X":453.075073,"Y":126.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65874.0,"Objects":[{"StartTime":65874.0,"EndTime":65874.0,"X":221.0,"Y":163.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65949.0,"EndTime":65949.0,"X":152.07077,"Y":150.219,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66096.0,"Objects":[{"StartTime":66096.0,"EndTime":66096.0,"X":41.0,"Y":231.0}]},{"StartTime":66207.0,"Objects":[{"StartTime":66207.0,"EndTime":66207.0,"X":49.0,"Y":267.0}]},{"StartTime":66318.0,"Objects":[{"StartTime":66318.0,"EndTime":66318.0,"X":56.0,"Y":303.0}]},{"StartTime":66429.0,"Objects":[{"StartTime":66429.0,"EndTime":66429.0,"X":67.0,"Y":288.0}]},{"StartTime":66540.0,"Objects":[{"StartTime":66540.0,"EndTime":66540.0,"X":77.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66837.0,"EndTime":66837.0,"X":83.81238,"Y":364.51593,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66985.0,"Objects":[{"StartTime":66985.0,"EndTime":66985.0,"X":95.0,"Y":356.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67171.0,"EndTime":67171.0,"X":169.229614,"Y":345.277954,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":67318.0,"Objects":[{"StartTime":67318.0,"EndTime":67318.0,"X":274.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67393.0,"EndTime":67393.0,"X":276.6237,"Y":355.8248,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":67540.0,"Objects":[{"StartTime":67540.0,"EndTime":67540.0,"X":191.0,"Y":227.0}]},{"StartTime":67651.0,"Objects":[{"StartTime":67651.0,"EndTime":67651.0,"X":255.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67706.0,"EndTime":67706.0,"X":261.337677,"Y":131.382233,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67726.0,"EndTime":67726.0,"X":255.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":67874.0,"Objects":[{"StartTime":67874.0,"EndTime":67874.0,"X":147.0,"Y":83.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67911.0,"EndTime":67911.0,"X":153.740753,"Y":107.0741,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67948.0,"EndTime":67948.0,"X":147.0,"Y":83.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67949.0,"EndTime":67949.0,"X":153.740753,"Y":107.0741,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68096.0,"Objects":[{"StartTime":68096.0,"EndTime":68096.0,"X":80.0,"Y":148.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":68171.0,"EndTime":68171.0,"X":97.28498,"Y":220.981018,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68318.0,"Objects":[{"StartTime":68318.0,"EndTime":68318.0,"X":125.0,"Y":356.0}]},{"StartTime":68429.0,"Objects":[{"StartTime":68429.0,"EndTime":68429.0,"X":0.0,"Y":319.0}]},{"StartTime":68540.0,"Objects":[{"StartTime":68540.0,"EndTime":68540.0,"X":0.0,"Y":319.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":68615.0,"EndTime":68615.0,"X":71.24443,"Y":295.564331,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68762.0,"Objects":[{"StartTime":68762.0,"EndTime":68762.0,"X":277.0,"Y":219.0}]},{"StartTime":68874.0,"Objects":[{"StartTime":68874.0,"EndTime":68874.0,"X":277.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69060.0,"EndTime":69060.0,"X":216.0241,"Y":166.850388,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":69207.0,"Objects":[{"StartTime":69207.0,"EndTime":69207.0,"X":157.0,"Y":273.0}]},{"StartTime":69318.0,"Objects":[{"StartTime":69318.0,"EndTime":69318.0,"X":175.0,"Y":316.0}]},{"StartTime":69429.0,"Objects":[{"StartTime":69429.0,"EndTime":69429.0,"X":212.0,"Y":334.0}]},{"StartTime":69540.0,"Objects":[{"StartTime":69540.0,"EndTime":69540.0,"X":254.0,"Y":333.0}]},{"StartTime":69651.0,"Objects":[{"StartTime":69651.0,"EndTime":69651.0,"X":332.0,"Y":268.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69678.0,"EndTime":69678.0,"X":334.774872,"Y":230.961487,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":69762.0,"Objects":[{"StartTime":69762.0,"EndTime":69762.0,"X":373.0,"Y":265.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69789.0,"EndTime":69789.0,"X":392.524567,"Y":235.296951,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":69874.0,"Objects":[{"StartTime":69874.0,"EndTime":69874.0,"X":413.0,"Y":284.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69901.0,"EndTime":69901.0,"X":444.2059,"Y":266.886841,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":69985.0,"Objects":[{"StartTime":69985.0,"EndTime":69985.0,"X":433.0,"Y":318.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":70012.0,"EndTime":70012.0,"X":467.539429,"Y":329.4084,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70096.0,"Objects":[{"StartTime":70096.0,"EndTime":70096.0,"X":401.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":70171.0,"EndTime":70171.0,"X":332.06134,"Y":363.130951,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70318.0,"Objects":[{"StartTime":70318.0,"EndTime":70318.0,"X":251.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":70393.0,"EndTime":70393.0,"X":244.703979,"Y":178.914719,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70540.0,"Objects":[{"StartTime":70540.0,"EndTime":70540.0,"X":401.0,"Y":18.0}]},{"StartTime":70651.0,"Objects":[{"StartTime":70651.0,"EndTime":70651.0,"X":401.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":70726.0,"EndTime":70726.0,"X":398.149,"Y":89.727005,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70874.0,"Objects":[{"StartTime":70874.0,"EndTime":70874.0,"X":327.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":71060.0,"EndTime":71060.0,"X":303.965668,"Y":44.77916,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":71207.0,"Objects":[{"StartTime":71207.0,"EndTime":71207.0,"X":290.0,"Y":26.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":71282.0,"EndTime":71282.0,"X":305.8338,"Y":129.799271,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":71429.0,"Objects":[{"StartTime":71429.0,"EndTime":71429.0,"X":272.0,"Y":302.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":71504.0,"EndTime":71504.0,"X":197.997055,"Y":289.811279,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":71651.0,"Objects":[{"StartTime":71651.0,"EndTime":71651.0,"X":33.0,"Y":217.0}]},{"StartTime":71762.0,"Objects":[{"StartTime":71762.0,"EndTime":71762.0,"X":27.0,"Y":187.0}]},{"StartTime":71874.0,"Objects":[{"StartTime":71874.0,"EndTime":71874.0,"X":20.0,"Y":157.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":72004.0,"EndTime":72004.0,"X":145.504913,"Y":80.92537,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":72096.0,"Objects":[{"StartTime":72096.0,"EndTime":72096.0,"X":145.0,"Y":82.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":72171.0,"EndTime":72171.0,"X":200.993164,"Y":76.63079,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":72318.0,"Objects":[{"StartTime":72318.0,"EndTime":72318.0,"X":336.0,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":72448.0,"EndTime":72448.0,"X":263.034,"Y":231.6351,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":72540.0,"Objects":[{"StartTime":72540.0,"EndTime":72540.0,"X":263.0,"Y":232.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":72615.0,"EndTime":72615.0,"X":275.1168,"Y":286.929474,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":72762.0,"Objects":[{"StartTime":72762.0,"EndTime":72762.0,"X":183.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":72837.0,"EndTime":72837.0,"X":175.045044,"Y":328.315338,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":72985.0,"Objects":[{"StartTime":72985.0,"EndTime":72985.0,"X":37.0,"Y":140.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":73171.0,"EndTime":73171.0,"X":63.65956,"Y":142.217728,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":73651.0,"Objects":[{"StartTime":73651.0,"EndTime":73651.0,"X":275.0,"Y":372.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":73837.0,"EndTime":73837.0,"X":380.158661,"Y":364.386444,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":74096.0,"Objects":[{"StartTime":74096.0,"EndTime":74096.0,"X":380.0,"Y":364.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":74171.0,"EndTime":74171.0,"X":435.9299,"Y":358.0075,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":74318.0,"Objects":[{"StartTime":74318.0,"EndTime":74318.0,"X":495.0,"Y":271.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":74393.0,"EndTime":74393.0,"X":439.413177,"Y":279.61203,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":74540.0,"Objects":[{"StartTime":74540.0,"EndTime":74540.0,"X":339.0,"Y":270.0}]},{"StartTime":74651.0,"Objects":[{"StartTime":74651.0,"EndTime":74651.0,"X":339.0,"Y":270.0}]},{"StartTime":74762.0,"Objects":[{"StartTime":74762.0,"EndTime":74762.0,"X":339.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":74837.0,"EndTime":74837.0,"X":331.467133,"Y":214.256668,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":74985.0,"Objects":[{"StartTime":74985.0,"EndTime":74985.0,"X":408.0,"Y":46.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":75060.0,"EndTime":75060.0,"X":396.112518,"Y":100.979546,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":75207.0,"Objects":[{"StartTime":75207.0,"EndTime":75207.0,"X":220.0,"Y":230.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":75282.0,"EndTime":75282.0,"X":211.729385,"Y":174.361359,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":75429.0,"Objects":[{"StartTime":75429.0,"EndTime":75429.0,"X":282.0,"Y":7.0}]},{"StartTime":75540.0,"Objects":[{"StartTime":75540.0,"EndTime":75540.0,"X":300.0,"Y":98.0}]},{"StartTime":75651.0,"Objects":[{"StartTime":75651.0,"EndTime":75651.0,"X":197.0,"Y":25.0}]},{"StartTime":75762.0,"Objects":[{"StartTime":75762.0,"EndTime":75762.0,"X":222.0,"Y":103.0}]},{"StartTime":75874.0,"Objects":[{"StartTime":75874.0,"EndTime":75874.0,"X":126.0,"Y":69.0}]},{"StartTime":75985.0,"Objects":[{"StartTime":75985.0,"EndTime":75985.0,"X":153.0,"Y":134.0}]},{"StartTime":76096.0,"Objects":[{"StartTime":76096.0,"EndTime":76096.0,"X":76.0,"Y":145.0}]},{"StartTime":76207.0,"Objects":[{"StartTime":76207.0,"EndTime":76207.0,"X":116.0,"Y":179.0}]},{"StartTime":76318.0,"Objects":[{"StartTime":76318.0,"EndTime":76318.0,"X":70.0,"Y":222.0}]},{"StartTime":76429.0,"Objects":[{"StartTime":76429.0,"EndTime":76429.0,"X":111.0,"Y":222.0}]},{"StartTime":76540.0,"Objects":[{"StartTime":76540.0,"EndTime":76540.0,"X":134.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":76615.0,"EndTime":76615.0,"X":130.626953,"Y":307.164856,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":76762.0,"Objects":[{"StartTime":76762.0,"EndTime":76762.0,"X":21.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77059.0,"EndTime":77059.0,"X":236.973511,"Y":377.8362,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77207.0,"Objects":[{"StartTime":77207.0,"EndTime":77207.0,"X":384.0,"Y":366.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77282.0,"EndTime":77282.0,"X":391.613525,"Y":291.387451,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77429.0,"Objects":[{"StartTime":77429.0,"EndTime":77429.0,"X":499.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77504.0,"EndTime":77504.0,"X":485.8507,"Y":135.838318,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77651.0,"Objects":[{"StartTime":77651.0,"EndTime":77651.0,"X":507.0,"Y":237.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77781.0,"EndTime":77781.0,"X":403.789581,"Y":202.548569,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77874.0,"Objects":[{"StartTime":77874.0,"EndTime":77874.0,"X":404.0,"Y":203.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77949.0,"EndTime":77949.0,"X":329.872131,"Y":214.4043,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78096.0,"Objects":[{"StartTime":78096.0,"EndTime":78096.0,"X":113.0,"Y":212.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78226.0,"EndTime":78226.0,"X":115.534233,"Y":319.9018,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78318.0,"Objects":[{"StartTime":78318.0,"EndTime":78318.0,"X":115.0,"Y":319.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78393.0,"EndTime":78393.0,"X":188.335175,"Y":334.7147,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78540.0,"Objects":[{"StartTime":78540.0,"EndTime":78540.0,"X":274.0,"Y":371.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78726.0,"EndTime":78726.0,"X":257.52887,"Y":191.7552,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78874.0,"Objects":[{"StartTime":78874.0,"EndTime":78874.0,"X":128.0,"Y":139.0}]},{"StartTime":78985.0,"Objects":[{"StartTime":78985.0,"EndTime":78985.0,"X":128.0,"Y":139.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":79060.0,"EndTime":79060.0,"X":202.567627,"Y":130.958389,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":79207.0,"Objects":[{"StartTime":79207.0,"EndTime":79207.0,"X":365.0,"Y":34.0}]},{"StartTime":79318.0,"Objects":[{"StartTime":79318.0,"EndTime":79318.0,"X":430.0,"Y":114.0}]},{"StartTime":79429.0,"Objects":[{"StartTime":79429.0,"EndTime":79429.0,"X":361.0,"Y":184.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":79559.0,"EndTime":79559.0,"X":277.9352,"Y":126.286682,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":79651.0,"Objects":[{"StartTime":79651.0,"EndTime":79651.0,"X":278.0,"Y":126.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":79726.0,"EndTime":79726.0,"X":203.2309,"Y":131.880722,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":79874.0,"Objects":[{"StartTime":79874.0,"EndTime":79874.0,"X":64.0,"Y":263.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":80004.0,"EndTime":80004.0,"X":47.32452,"Y":160.905121,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":80096.0,"Objects":[{"StartTime":80096.0,"EndTime":80096.0,"X":66.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":80171.0,"EndTime":80171.0,"X":77.40429,"Y":193.127869,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":80318.0,"Objects":[{"StartTime":80318.0,"EndTime":80318.0,"X":71.0,"Y":361.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":80504.0,"EndTime":80504.0,"X":231.5679,"Y":298.4993,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":80651.0,"Objects":[{"StartTime":80651.0,"EndTime":80651.0,"X":302.0,"Y":247.0}]},{"StartTime":80762.0,"Objects":[{"StartTime":80762.0,"EndTime":80762.0,"X":222.0,"Y":211.0}]},{"StartTime":80985.0,"Objects":[{"StartTime":80985.0,"EndTime":80985.0,"X":478.0,"Y":344.0}]},{"StartTime":81096.0,"Objects":[{"StartTime":81096.0,"EndTime":81096.0,"X":491.0,"Y":309.0}]},{"StartTime":81207.0,"Objects":[{"StartTime":81207.0,"EndTime":81207.0,"X":498.0,"Y":265.0}]},{"StartTime":81318.0,"Objects":[{"StartTime":81318.0,"EndTime":81318.0,"X":485.0,"Y":223.0}]},{"StartTime":81429.0,"Objects":[{"StartTime":81429.0,"EndTime":81429.0,"X":458.0,"Y":179.0}]},{"StartTime":81540.0,"Objects":[{"StartTime":81540.0,"EndTime":81540.0,"X":418.0,"Y":147.0}]},{"StartTime":81651.0,"Objects":[{"StartTime":81651.0,"EndTime":81651.0,"X":352.0,"Y":126.0}]},{"StartTime":81762.0,"Objects":[{"StartTime":81762.0,"EndTime":81762.0,"X":281.0,"Y":149.0}]},{"StartTime":81874.0,"Objects":[{"StartTime":81874.0,"EndTime":81874.0,"X":239.0,"Y":221.0}]},{"StartTime":81985.0,"Objects":[{"StartTime":81985.0,"EndTime":81985.0,"X":159.0,"Y":262.0}]},{"StartTime":82096.0,"Objects":[{"StartTime":82096.0,"EndTime":82096.0,"X":66.0,"Y":234.0}]},{"StartTime":82207.0,"Objects":[{"StartTime":82207.0,"EndTime":82207.0,"X":11.0,"Y":145.0}]},{"StartTime":82318.0,"Objects":[{"StartTime":82318.0,"EndTime":82318.0,"X":55.0,"Y":33.0}]},{"StartTime":82540.0,"Objects":[{"StartTime":82540.0,"EndTime":82540.0,"X":273.0,"Y":44.0}]},{"StartTime":82651.0,"Objects":[{"StartTime":82651.0,"EndTime":82651.0,"X":320.0,"Y":103.0}]},{"StartTime":82762.0,"Objects":[{"StartTime":82762.0,"EndTime":82762.0,"X":394.0,"Y":118.0}]},{"StartTime":82874.0,"Objects":[{"StartTime":82874.0,"EndTime":82874.0,"X":468.0,"Y":100.0}]},{"StartTime":82985.0,"Objects":[{"StartTime":82985.0,"EndTime":82985.0,"X":507.0,"Y":36.0}]},{"StartTime":83207.0,"Objects":[{"StartTime":83207.0,"EndTime":83207.0,"X":495.0,"Y":19.0}]},{"StartTime":83318.0,"Objects":[{"StartTime":83318.0,"EndTime":83318.0,"X":335.0,"Y":83.0}]},{"StartTime":83429.0,"Objects":[{"StartTime":83429.0,"EndTime":83429.0,"X":453.0,"Y":81.0}]},{"StartTime":83540.0,"Objects":[{"StartTime":83540.0,"EndTime":83540.0,"X":283.0,"Y":24.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":83689.0,"EndTime":83689.0,"X":154.807114,"Y":79.37676,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":83874.0,"Objects":[{"StartTime":83874.0,"EndTime":83874.0,"X":60.0,"Y":238.0}]},{"StartTime":83985.0,"Objects":[{"StartTime":83985.0,"EndTime":83985.0,"X":21.0,"Y":164.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84134.0,"EndTime":84134.0,"X":160.221619,"Y":176.913727,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84318.0,"Objects":[{"StartTime":84318.0,"EndTime":84318.0,"X":252.0,"Y":206.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84393.0,"EndTime":84393.0,"X":268.054169,"Y":136.0318,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84540.0,"Objects":[{"StartTime":84540.0,"EndTime":84540.0,"X":139.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84615.0,"EndTime":84615.0,"X":140.643234,"Y":328.635956,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84762.0,"Objects":[{"StartTime":84762.0,"EndTime":84762.0,"X":240.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84892.0,"EndTime":84892.0,"X":311.649658,"Y":350.824829,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84985.0,"Objects":[{"StartTime":84985.0,"EndTime":84985.0,"X":312.0,"Y":351.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":85060.0,"EndTime":85060.0,"X":270.3759,"Y":292.868469,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":85207.0,"Objects":[{"StartTime":85207.0,"EndTime":85207.0,"X":359.0,"Y":165.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":85337.0,"EndTime":85337.0,"X":372.53064,"Y":264.7404,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":85429.0,"Objects":[{"StartTime":85429.0,"EndTime":85429.0,"X":373.0,"Y":265.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":85504.0,"EndTime":85504.0,"X":446.400818,"Y":280.405121,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":85651.0,"Objects":[{"StartTime":85651.0,"EndTime":85651.0,"X":498.0,"Y":139.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":85837.0,"EndTime":85837.0,"X":394.23114,"Y":13.5172443,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":85985.0,"Objects":[{"StartTime":85985.0,"EndTime":85985.0,"X":394.0,"Y":13.0}]},{"StartTime":86096.0,"Objects":[{"StartTime":86096.0,"EndTime":86096.0,"X":301.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86171.0,"EndTime":86171.0,"X":226.398117,"Y":84.28256,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":86318.0,"Objects":[{"StartTime":86318.0,"EndTime":86318.0,"X":66.0,"Y":66.0}]},{"StartTime":86429.0,"Objects":[{"StartTime":86429.0,"EndTime":86429.0,"X":13.0,"Y":136.0}]},{"StartTime":86540.0,"Objects":[{"StartTime":86540.0,"EndTime":86540.0,"X":72.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86670.0,"EndTime":86670.0,"X":176.5301,"Y":191.3274,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":86762.0,"Objects":[{"StartTime":86762.0,"EndTime":86762.0,"X":176.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86837.0,"EndTime":86837.0,"X":153.167648,"Y":261.1704,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":86985.0,"Objects":[{"StartTime":86985.0,"EndTime":86985.0,"X":309.0,"Y":370.0}]},{"StartTime":87096.0,"Objects":[{"StartTime":87096.0,"EndTime":87096.0,"X":359.0,"Y":310.0}]},{"StartTime":87207.0,"Objects":[{"StartTime":87207.0,"EndTime":87207.0,"X":283.0,"Y":297.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87282.0,"EndTime":87282.0,"X":210.457672,"Y":316.042358,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":87429.0,"Objects":[{"StartTime":87429.0,"EndTime":87429.0,"X":4.0,"Y":203.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87615.0,"EndTime":87615.0,"X":127.740509,"Y":264.675873,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":87762.0,"Objects":[{"StartTime":87762.0,"EndTime":87762.0,"X":238.0,"Y":217.0}]},{"StartTime":87874.0,"Objects":[{"StartTime":87874.0,"EndTime":87874.0,"X":183.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87949.0,"EndTime":87949.0,"X":108.341415,"Y":112.851837,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88096.0,"Objects":[{"StartTime":88096.0,"EndTime":88096.0,"X":98.0,"Y":33.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88171.0,"EndTime":88171.0,"X":23.3245468,"Y":26.03029,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88318.0,"Objects":[{"StartTime":88318.0,"EndTime":88318.0,"X":306.0,"Y":182.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88393.0,"EndTime":88393.0,"X":380.658569,"Y":174.851837,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88540.0,"Objects":[{"StartTime":88540.0,"EndTime":88540.0,"X":391.0,"Y":95.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88615.0,"EndTime":88615.0,"X":465.6667,"Y":87.9369354,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88762.0,"Objects":[{"StartTime":88762.0,"EndTime":88762.0,"X":232.0,"Y":28.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88789.0,"EndTime":88789.0,"X":225.089172,"Y":64.85771,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88874.0,"Objects":[{"StartTime":88874.0,"EndTime":88874.0,"X":243.0,"Y":39.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88901.0,"EndTime":88901.0,"X":236.089172,"Y":75.85771,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88985.0,"Objects":[{"StartTime":88985.0,"EndTime":88985.0,"X":256.0,"Y":50.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89012.0,"EndTime":89012.0,"X":250.978073,"Y":87.16222,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":89207.0,"Objects":[{"StartTime":89207.0,"EndTime":89207.0,"X":485.0,"Y":87.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89262.0,"EndTime":89262.0,"X":493.085876,"Y":50.6135063,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89318.0,"EndTime":89318.0,"X":485.049,"Y":86.77947,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89337.0,"EndTime":89337.0,"X":493.1349,"Y":50.3929863,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":89429.0,"Objects":[{"StartTime":89429.0,"EndTime":89429.0,"X":396.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89504.0,"EndTime":89504.0,"X":410.34082,"Y":193.61618,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":89651.0,"Objects":[{"StartTime":89651.0,"EndTime":89651.0,"X":471.0,"Y":317.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89837.0,"EndTime":89837.0,"X":330.6769,"Y":326.25708,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":90096.0,"Objects":[{"StartTime":90096.0,"EndTime":90096.0,"X":61.0,"Y":239.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":90282.0,"EndTime":90282.0,"X":201.32309,"Y":248.2571,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":90540.0,"Objects":[{"StartTime":90540.0,"EndTime":90540.0,"X":367.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":90615.0,"EndTime":90615.0,"X":328.4434,"Y":82.729866,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":90762.0,"Objects":[{"StartTime":90762.0,"EndTime":90762.0,"X":163.0,"Y":96.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":90837.0,"EndTime":90837.0,"X":201.556625,"Y":157.729874,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":90985.0,"Objects":[{"StartTime":90985.0,"EndTime":90985.0,"X":190.0,"Y":346.0}]},{"StartTime":91096.0,"Objects":[{"StartTime":91096.0,"EndTime":91096.0,"X":328.0,"Y":272.0}]},{"StartTime":91207.0,"Objects":[{"StartTime":91207.0,"EndTime":91207.0,"X":154.0,"Y":272.0}]},{"StartTime":91318.0,"Objects":[{"StartTime":91318.0,"EndTime":91318.0,"X":365.0,"Y":338.0}]},{"StartTime":91429.0,"Objects":[{"StartTime":91429.0,"EndTime":91429.0,"X":257.0,"Y":382.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":91615.0,"EndTime":91615.0,"X":259.5329,"Y":236.323334,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":91762.0,"Objects":[{"StartTime":91762.0,"EndTime":91762.0,"X":325.0,"Y":196.0}]},{"StartTime":91874.0,"Objects":[{"StartTime":91874.0,"EndTime":91874.0,"X":325.0,"Y":196.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92004.0,"EndTime":92004.0,"X":429.818634,"Y":189.708939,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":92096.0,"Objects":[{"StartTime":92096.0,"EndTime":92096.0,"X":430.0,"Y":190.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92171.0,"EndTime":92171.0,"X":418.874451,"Y":115.829781,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":92318.0,"Objects":[{"StartTime":92318.0,"EndTime":92318.0,"X":313.0,"Y":19.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92448.0,"EndTime":92448.0,"X":201.559357,"Y":34.4023666,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":92540.0,"Objects":[{"StartTime":92540.0,"EndTime":92540.0,"X":201.0,"Y":34.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92615.0,"EndTime":92615.0,"X":212.6055,"Y":108.096649,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":92762.0,"Objects":[{"StartTime":92762.0,"EndTime":92762.0,"X":209.0,"Y":252.0}]},{"StartTime":92874.0,"Objects":[{"StartTime":92874.0,"EndTime":92874.0,"X":156.0,"Y":261.0}]},{"StartTime":92985.0,"Objects":[{"StartTime":92985.0,"EndTime":92985.0,"X":112.0,"Y":231.0}]},{"StartTime":93096.0,"Objects":[{"StartTime":93096.0,"EndTime":93096.0,"X":60.0,"Y":222.0}]},{"StartTime":93207.0,"Objects":[{"StartTime":93207.0,"EndTime":93207.0,"X":13.0,"Y":247.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93282.0,"EndTime":93282.0,"X":13.18664,"Y":318.8803,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93429.0,"Objects":[{"StartTime":93429.0,"EndTime":93429.0,"X":173.0,"Y":186.0}]},{"StartTime":93540.0,"Objects":[{"StartTime":93540.0,"EndTime":93540.0,"X":215.0,"Y":120.0}]},{"StartTime":93651.0,"Objects":[{"StartTime":93651.0,"EndTime":93651.0,"X":162.0,"Y":49.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93726.0,"EndTime":93726.0,"X":90.69035,"Y":49.0886574,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93874.0,"Objects":[{"StartTime":93874.0,"EndTime":93874.0,"X":234.0,"Y":138.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93949.0,"EndTime":93949.0,"X":303.1729,"Y":152.77562,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94096.0,"Objects":[{"StartTime":94096.0,"EndTime":94096.0,"X":385.0,"Y":39.0}]},{"StartTime":94318.0,"Objects":[{"StartTime":94318.0,"EndTime":94318.0,"X":337.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":94393.0,"EndTime":94393.0,"X":324.257,"Y":359.909515,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94540.0,"Objects":[{"StartTime":94540.0,"EndTime":94540.0,"X":409.0,"Y":327.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":94837.0,"EndTime":94837.0,"X":285.0893,"Y":225.489716,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94985.0,"Objects":[{"StartTime":94985.0,"EndTime":94985.0,"X":239.0,"Y":319.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95060.0,"EndTime":95060.0,"X":190.987534,"Y":371.081482,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":95207.0,"Objects":[{"StartTime":95207.0,"EndTime":95207.0,"X":34.0,"Y":344.0}]},{"StartTime":95318.0,"Objects":[{"StartTime":95318.0,"EndTime":95318.0,"X":21.0,"Y":309.0}]},{"StartTime":95429.0,"Objects":[{"StartTime":95429.0,"EndTime":95429.0,"X":14.0,"Y":265.0}]},{"StartTime":95540.0,"Objects":[{"StartTime":95540.0,"EndTime":95540.0,"X":27.0,"Y":223.0}]},{"StartTime":95651.0,"Objects":[{"StartTime":95651.0,"EndTime":95651.0,"X":54.0,"Y":179.0}]},{"StartTime":95762.0,"Objects":[{"StartTime":95762.0,"EndTime":95762.0,"X":94.0,"Y":147.0}]},{"StartTime":95873.0,"Objects":[{"StartTime":95873.0,"EndTime":95873.0,"X":160.0,"Y":126.0}]},{"StartTime":95984.0,"Objects":[{"StartTime":95984.0,"EndTime":95984.0,"X":231.0,"Y":149.0}]},{"StartTime":96096.0,"Objects":[{"StartTime":96096.0,"EndTime":96096.0,"X":273.0,"Y":221.0}]},{"StartTime":96207.0,"Objects":[{"StartTime":96207.0,"EndTime":96207.0,"X":353.0,"Y":262.0}]},{"StartTime":96318.0,"Objects":[{"StartTime":96318.0,"EndTime":96318.0,"X":446.0,"Y":234.0}]},{"StartTime":96429.0,"Objects":[{"StartTime":96429.0,"EndTime":96429.0,"X":501.0,"Y":145.0}]},{"StartTime":96540.0,"Objects":[{"StartTime":96540.0,"EndTime":96540.0,"X":450.0,"Y":36.0}]},{"StartTime":96762.0,"Objects":[{"StartTime":96762.0,"EndTime":96762.0,"X":239.0,"Y":44.0}]},{"StartTime":96873.0,"Objects":[{"StartTime":96873.0,"EndTime":96873.0,"X":192.0,"Y":103.0}]},{"StartTime":96984.0,"Objects":[{"StartTime":96984.0,"EndTime":96984.0,"X":118.0,"Y":118.0}]},{"StartTime":97096.0,"Objects":[{"StartTime":97096.0,"EndTime":97096.0,"X":44.0,"Y":100.0}]},{"StartTime":97207.0,"Objects":[{"StartTime":97207.0,"EndTime":97207.0,"X":5.0,"Y":36.0}]},{"StartTime":97429.0,"Objects":[{"StartTime":97429.0,"EndTime":97429.0,"X":17.0,"Y":19.0}]},{"StartTime":97540.0,"Objects":[{"StartTime":97540.0,"EndTime":97540.0,"X":146.0,"Y":51.0}]},{"StartTime":97651.0,"Objects":[{"StartTime":97651.0,"EndTime":97651.0,"X":29.0,"Y":122.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97781.0,"EndTime":97781.0,"X":36.8451042,"Y":177.700241,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":97874.0,"Objects":[{"StartTime":97874.0,"EndTime":97874.0,"X":44.0,"Y":197.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97949.0,"EndTime":97949.0,"X":144.239655,"Y":225.070267,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98096.0,"Objects":[{"StartTime":98096.0,"EndTime":98096.0,"X":301.0,"Y":160.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98226.0,"EndTime":98226.0,"X":377.703552,"Y":135.967728,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98318.0,"Objects":[{"StartTime":98318.0,"EndTime":98318.0,"X":398.0,"Y":147.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98393.0,"EndTime":98393.0,"X":420.6091,"Y":246.7476,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98540.0,"Objects":[{"StartTime":98540.0,"EndTime":98540.0,"X":265.0,"Y":371.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98615.0,"EndTime":98615.0,"X":190.5137,"Y":362.2369,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98762.0,"Objects":[{"StartTime":98762.0,"EndTime":98762.0,"X":127.0,"Y":202.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98837.0,"EndTime":98837.0,"X":138.654449,"Y":127.911041,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98985.0,"Objects":[{"StartTime":98985.0,"EndTime":98985.0,"X":193.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":99115.0,"EndTime":99115.0,"X":91.16292,"Y":289.2349,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":99207.0,"Objects":[{"StartTime":99207.0,"EndTime":99207.0,"X":91.0,"Y":290.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":99282.0,"EndTime":99282.0,"X":80.26821,"Y":364.2282,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":99429.0,"Objects":[{"StartTime":99429.0,"EndTime":99429.0,"X":20.0,"Y":184.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":99559.0,"EndTime":99559.0,"X":23.5322342,"Y":77.30794,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":99651.0,"Objects":[{"StartTime":99651.0,"EndTime":99651.0,"X":23.0,"Y":78.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":99726.0,"EndTime":99726.0,"X":97.15753,"Y":89.20986,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":99874.0,"Objects":[{"StartTime":99874.0,"EndTime":99874.0,"X":271.0,"Y":74.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":99949.0,"EndTime":99949.0,"X":231.432739,"Y":15.2187185,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100096.0,"Objects":[{"StartTime":100096.0,"EndTime":100096.0,"X":186.0,"Y":180.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100171.0,"EndTime":100171.0,"X":253.138412,"Y":157.416565,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100318.0,"Objects":[{"StartTime":100318.0,"EndTime":100318.0,"X":132.0,"Y":63.0}]},{"StartTime":100540.0,"Objects":[{"StartTime":100540.0,"EndTime":100540.0,"X":253.0,"Y":157.0}]},{"StartTime":100651.0,"Objects":[{"StartTime":100651.0,"EndTime":100651.0,"X":285.0,"Y":167.0}]},{"StartTime":100762.0,"Objects":[{"StartTime":100762.0,"EndTime":100762.0,"X":357.0,"Y":129.0}]},{"StartTime":100873.0,"Objects":[{"StartTime":100873.0,"EndTime":100873.0,"X":389.0,"Y":139.0}]},{"StartTime":100985.0,"Objects":[{"StartTime":100985.0,"EndTime":100985.0,"X":422.0,"Y":148.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101060.0,"EndTime":101060.0,"X":410.5588,"Y":219.494064,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101207.0,"Objects":[{"StartTime":101207.0,"EndTime":101207.0,"X":459.0,"Y":377.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101282.0,"EndTime":101282.0,"X":465.133026,"Y":305.73877,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101429.0,"Objects":[{"StartTime":101429.0,"EndTime":101429.0,"X":398.0,"Y":242.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101504.0,"EndTime":101504.0,"X":324.167938,"Y":255.1843,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101651.0,"Objects":[{"StartTime":101651.0,"EndTime":101651.0,"X":165.0,"Y":354.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101948.0,"EndTime":101948.0,"X":197.2489,"Y":249.27066,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102096.0,"Objects":[{"StartTime":102096.0,"EndTime":102096.0,"X":302.0,"Y":165.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102171.0,"EndTime":102171.0,"X":292.2159,"Y":90.64093,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102318.0,"Objects":[{"StartTime":102318.0,"EndTime":102318.0,"X":392.0,"Y":91.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102393.0,"EndTime":102393.0,"X":382.340851,"Y":16.6245956,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102540.0,"Objects":[{"StartTime":102540.0,"EndTime":102540.0,"X":192.0,"Y":229.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102615.0,"EndTime":102615.0,"X":207.768524,"Y":155.676361,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102762.0,"Objects":[{"StartTime":102762.0,"EndTime":102762.0,"X":107.0,"Y":172.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102837.0,"EndTime":102837.0,"X":122.768524,"Y":98.67637,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102985.0,"Objects":[{"StartTime":102985.0,"EndTime":102985.0,"X":314.0,"Y":332.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103012.0,"EndTime":103012.0,"X":307.835052,"Y":295.010223,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103096.0,"Objects":[{"StartTime":103096.0,"EndTime":103096.0,"X":343.0,"Y":345.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103123.0,"EndTime":103123.0,"X":336.835052,"Y":308.010223,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103207.0,"Objects":[{"StartTime":103207.0,"EndTime":103207.0,"X":370.0,"Y":358.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103234.0,"EndTime":103234.0,"X":363.835052,"Y":321.010223,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103429.0,"Objects":[{"StartTime":103429.0,"EndTime":103429.0,"X":380.0,"Y":117.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103484.0,"EndTime":103484.0,"X":374.728638,"Y":80.1005249,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103540.0,"EndTime":103540.0,"X":379.968048,"Y":116.776367,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103559.0,"EndTime":103559.0,"X":374.6967,"Y":79.87689,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103651.0,"Objects":[{"StartTime":103651.0,"EndTime":103651.0,"X":444.0,"Y":166.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103726.0,"EndTime":103726.0,"X":378.552429,"Y":197.3988,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103874.0,"Objects":[{"StartTime":103874.0,"EndTime":103874.0,"X":392.0,"Y":2.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103949.0,"EndTime":103949.0,"X":451.723328,"Y":43.11612,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104096.0,"Objects":[{"StartTime":104096.0,"EndTime":104096.0,"X":271.0,"Y":129.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104171.0,"EndTime":104171.0,"X":275.70752,"Y":56.6180077,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104318.0,"Objects":[{"StartTime":104318.0,"EndTime":104318.0,"X":505.0,"Y":113.0}]},{"StartTime":104540.0,"Objects":[{"StartTime":104540.0,"EndTime":104540.0,"X":269.0,"Y":217.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104595.0,"EndTime":104595.0,"X":231.732529,"Y":216.296829,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104651.0,"EndTime":104651.0,"X":268.774139,"Y":216.995743,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104670.0,"EndTime":104670.0,"X":231.506683,"Y":216.292572,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104762.0,"Objects":[{"StartTime":104762.0,"EndTime":104762.0,"X":360.0,"Y":220.0}]},{"StartTime":104874.0,"Objects":[{"StartTime":104874.0,"EndTime":104874.0,"X":296.0,"Y":384.0}]},{"StartTime":105096.0,"Objects":[{"StartTime":105096.0,"EndTime":105096.0,"X":102.0,"Y":307.0}]},{"StartTime":105207.0,"Objects":[{"StartTime":105207.0,"EndTime":105207.0,"X":102.0,"Y":307.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105504.0,"EndTime":105504.0,"X":359.15506,"Y":319.9753,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105651.0,"Objects":[{"StartTime":105651.0,"EndTime":105651.0,"X":439.0,"Y":319.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105948.0,"EndTime":105948.0,"X":360.576447,"Y":251.735214,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106096.0,"Objects":[{"StartTime":106096.0,"EndTime":106096.0,"X":373.0,"Y":258.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106393.0,"EndTime":106393.0,"X":419.839447,"Y":322.692932,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106651.0,"Objects":[{"StartTime":106651.0,"EndTime":106651.0,"X":420.0,"Y":323.0}]},{"StartTime":106763.0,"Objects":[{"StartTime":106763.0,"EndTime":106763.0,"X":469.0,"Y":245.0}]},{"StartTime":106874.0,"Objects":[{"StartTime":106874.0,"EndTime":106874.0,"X":508.0,"Y":322.0}]},{"StartTime":106985.0,"Objects":[{"StartTime":106985.0,"EndTime":106985.0,"X":379.0,"Y":245.0}]},{"StartTime":107207.0,"Objects":[{"StartTime":107207.0,"EndTime":107207.0,"X":483.0,"Y":105.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107262.0,"EndTime":107262.0,"X":475.3316,"Y":49.6172256,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107318.0,"EndTime":107318.0,"X":482.953522,"Y":104.664345,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107337.0,"EndTime":107337.0,"X":475.285126,"Y":49.28157,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107429.0,"Objects":[{"StartTime":107429.0,"EndTime":107429.0,"X":462.0,"Y":30.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107615.0,"EndTime":107615.0,"X":324.7961,"Y":30.4987278,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107874.0,"Objects":[{"StartTime":107874.0,"EndTime":107874.0,"X":272.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108060.0,"EndTime":108060.0,"X":134.090317,"Y":110.785133,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108207.0,"Objects":[{"StartTime":108207.0,"EndTime":108207.0,"X":103.0,"Y":213.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108393.0,"EndTime":108393.0,"X":243.658188,"Y":205.751328,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108540.0,"Objects":[{"StartTime":108540.0,"EndTime":108540.0,"X":393.0,"Y":187.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108615.0,"EndTime":108615.0,"X":386.959076,"Y":261.756317,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108763.0,"Objects":[{"StartTime":108763.0,"EndTime":108763.0,"X":333.0,"Y":338.0}]},{"StartTime":108874.0,"Objects":[{"StartTime":108874.0,"EndTime":108874.0,"X":467.0,"Y":307.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108929.0,"EndTime":108929.0,"X":503.151581,"Y":298.3925,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108949.0,"EndTime":108949.0,"X":467.0,"Y":307.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109096.0,"Objects":[{"StartTime":109096.0,"EndTime":109096.0,"X":409.0,"Y":380.0}]},{"StartTime":109207.0,"Objects":[{"StartTime":109207.0,"EndTime":109207.0,"X":300.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109282.0,"EndTime":109282.0,"X":277.2678,"Y":187.976425,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109429.0,"Objects":[{"StartTime":109429.0,"EndTime":109429.0,"X":401.0,"Y":118.0}]},{"StartTime":109651.0,"Objects":[{"StartTime":109651.0,"EndTime":109651.0,"X":401.0,"Y":118.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109837.0,"EndTime":109837.0,"X":326.407349,"Y":110.193794,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109985.0,"Objects":[{"StartTime":109985.0,"EndTime":109985.0,"X":256.0,"Y":15.0}]},{"StartTime":110096.0,"Objects":[{"StartTime":110096.0,"EndTime":110096.0,"X":175.0,"Y":121.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110226.0,"EndTime":110226.0,"X":128.04184,"Y":25.2383614,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110318.0,"Objects":[{"StartTime":110318.0,"EndTime":110318.0,"X":128.0,"Y":26.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110448.0,"EndTime":110448.0,"X":68.84166,"Y":114.866982,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110540.0,"Objects":[{"StartTime":110540.0,"EndTime":110540.0,"X":69.0,"Y":114.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110670.0,"EndTime":110670.0,"X":175.436081,"Y":123.06649,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110762.0,"Objects":[{"StartTime":110762.0,"EndTime":110762.0,"X":160.0,"Y":223.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110837.0,"EndTime":110837.0,"X":52.99624,"Y":242.365173,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110985.0,"Objects":[{"StartTime":110985.0,"EndTime":110985.0,"X":193.0,"Y":334.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111060.0,"EndTime":111060.0,"X":237.04248,"Y":301.937531,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111207.0,"Objects":[{"StartTime":111207.0,"EndTime":111207.0,"X":335.0,"Y":325.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111282.0,"EndTime":111282.0,"X":372.85437,"Y":365.2907,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111429.0,"Objects":[{"StartTime":111429.0,"EndTime":111429.0,"X":273.0,"Y":383.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111726.0,"EndTime":111726.0,"X":303.272858,"Y":216.98761,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111874.0,"Objects":[{"StartTime":111874.0,"EndTime":111874.0,"X":383.0,"Y":255.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111949.0,"EndTime":111949.0,"X":454.046539,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112096.0,"Objects":[{"StartTime":112096.0,"EndTime":112096.0,"X":209.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112171.0,"EndTime":112171.0,"X":136.491043,"Y":208.167511,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112318.0,"Objects":[{"StartTime":112318.0,"EndTime":112318.0,"X":403.0,"Y":147.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112615.0,"EndTime":112615.0,"X":236.823761,"Y":114.722252,"StackOffset":{"X":0.0,"Y":0.0}}]}]} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/1341554.osu b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/1341554.osu new file mode 100644 index 000000000000..e118bc2db2db --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/1341554.osu @@ -0,0 +1,941 @@ +osu file format v14 + +[General] +AudioLeadIn: 0 +PreviewTime: 76429 +Countdown: 0 +SampleSet: Soft +StackLeniency: 0.2 +Mode: 0 +LetterboxInBreaks: 0 +WidescreenStoryboard: 1 + +[Difficulty] +HPDrainRate:5 +CircleSize:4.3 +OverallDifficulty:8 +ApproachRate:9.3 +SliderMultiplier:2.99999995231628 +SliderTickRate:1 + +[Events] +//Background and Video events +//Break Periods +//Storyboard Layer 0 (Background) +//Storyboard Layer 1 (Fail) +//Storyboard Layer 2 (Pass) +//Storyboard Layer 3 (Foreground) +//Storyboard Sound Samples + +[TimingPoints] +763,444.444444444444,4,2,1,60,1,0 +763,-111.111111111111,4,2,1,60,0,0 +1929,-100,4,2,1,5,0,0 +1985,-100,4,2,1,60,0,0 +2040,-100,4,2,1,5,0,0 +2096,-153.846153846153,4,2,1,60,0,0 +2429,-133.333333333333,4,2,1,5,0,0 +2540,-71.4285714285714,4,2,1,70,0,1 +2985,-100,4,2,1,70,0,1 +4485,-100,4,2,1,5,0,1 +4540,-100,4,2,1,70,0,1 +4707,-100,4,2,1,5,0,1 +4762,-100,4,2,1,70,0,1 +4929,-100,4,2,1,5,0,1 +4985,-100,4,2,1,70,0,1 +5096,-83.3333333333333,4,2,1,70,0,1 +5429,-133.333333333333,4,2,1,70,0,1 +5596,-133.333333333333,4,2,1,70,0,1 +5652,-133.333333333333,4,2,1,70,0,1 +5818,-133.333333333333,4,2,1,70,0,1 +5874,-133.333333333333,4,2,1,70,0,1 +6040,-133.333333333333,4,2,1,70,0,1 +6096,-100,4,2,1,70,0,1 +6540,-100,4,2,1,70,0,1 +8040,-100,4,2,1,5,0,1 +8096,-100,4,2,1,70,0,1 +8262,-100,4,2,1,5,0,1 +8318,-100,4,2,1,70,0,1 +8485,-100,4,2,1,5,0,1 +8540,-133.333333333333,4,2,1,70,0,1 +8874,-100,4,2,1,5,0,1 +8985,-100,4,2,1,70,0,1 +9651,-100,4,2,1,70,0,1 +10096,-100,4,2,1,70,0,1 +11596,-100,4,2,1,5,0,1 +11651,-100,4,2,1,70,0,1 +11818,-100,4,2,1,5,0,1 +11873,-100,4,2,1,70,0,1 +11874,-80,4,2,1,70,0,1 +12040,-80,4,2,1,5,0,1 +12096,-80,4,2,1,70,0,1 +12207,-133.333333333333,4,2,1,70,0,1 +12429,-100,4,2,1,5,0,1 +12540,-100,4,2,1,70,0,1 +12707,-100,4,2,1,70,0,1 +12763,-100,4,2,1,70,0,1 +12929,-100,4,2,1,70,0,1 +12985,-100,4,2,1,70,0,1 +13429,-300,4,2,1,70,0,1 +13651,-83.3333333333333,4,2,1,70,0,1 +13874,-100,4,2,1,70,0,1 +15151,-100,4,2,1,5,0,1 +15207,-100,4,2,1,70,0,1 +15373,-100,4,2,1,5,0,1 +15429,-100,4,2,1,70,0,1 +15596,-100,4,2,1,5,0,1 +15651,-100,4,2,1,70,0,1 +15985,-100,4,2,1,5,0,1 +16096,-100,4,2,1,70,0,1 +16262,-100,4,2,1,70,0,1 +16318,-83.3333333333333,4,2,1,70,0,1 +16651,-100,4,2,1,70,0,1 +16762,-133.333333333333,4,2,1,60,0,0 +17096,-133.333333333333,4,2,1,5,0,0 +17207,-200,4,2,1,60,0,0 +18096,-66.6666666666667,4,2,1,60,0,0 +18262,-66.6666666666667,4,2,1,5,0,0 +18318,-66.6666666666667,4,2,1,60,0,0 +18540,-100,4,2,1,60,0,0 +18874,-100,4,2,1,5,0,0 +18985,-100,4,2,1,60,0,0 +19985,-100,4,2,1,60,0,0 +20485,-100,4,2,1,5,0,0 +20540,-100,4,2,1,60,0,0 +20707,-100,4,2,1,5,0,0 +20762,-200,4,2,1,60,0,0 +20985,-100,4,2,1,60,0,0 +21095,-100,4,2,1,60,0,0 +21374,-100,4,2,1,5,0,0 +21429,-100,4,2,1,60,0,0 +21596,-100,4,2,1,5,0,0 +21651,-100,4,2,1,60,0,0 +21818,-100,4,2,1,5,0,0 +21874,-66.6666666666667,4,2,1,60,0,0 +21985,-100,4,2,1,60,0,0 +22096,-100,4,2,1,60,0,0 +22985,-200,4,2,1,60,0,0 +23318,-100,4,2,1,60,0,0 +23429,-100,4,2,1,60,0,0 +23540,-100,4,2,1,60,0,0 +23651,-100,4,2,1,60,0,0 +23762,-100,4,2,1,60,0,0 +23874,-133.333333333333,4,2,1,60,0,0 +24208,-133.333333333333,4,2,1,5,0,0 +24318,-200,4,2,1,5,0,0 +24319,-200,4,2,1,60,0,0 +24540,-100,4,2,1,60,0,0 +24651,-66.6666666666667,4,2,1,60,0,0 +24874,-100,4,2,1,60,0,0 +25374,-100,4,2,1,5,0,0 +25429,-100,4,2,1,60,0,0 +27096,-100,4,2,1,60,0,0 +27596,-100,4,2,1,5,0,0 +27651,-100,4,2,1,60,0,0 +27818,-100,4,2,1,5,0,0 +27873,-133.333333333333,4,2,1,60,0,0 +28096,-100,4,2,1,60,0,0 +28206,-100,4,2,1,60,0,0 +28485,-100,4,2,1,5,0,0 +28540,-100,4,2,1,60,0,0 +28707,-100,4,2,1,5,0,0 +28762,-100,4,2,1,60,0,0 +28929,-100,4,2,1,5,0,0 +28985,-66.6666666666667,4,2,1,60,0,0 +29151,-100,4,2,1,60,0,0 +29207,-100,4,2,1,60,0,0 +29651,-100,4,2,1,60,0,0 +30429,-100,4,2,1,60,0,0 +30540,-58.8235294117647,4,2,1,60,0,0 +30874,-58.8235294117647,4,2,1,5,0,0 +30985,-58.8235294117647,4,2,1,60,0,0 +31040,-100,4,2,1,5,0,0 +31429,-100,4,2,1,60,0,0 +32485,-100,4,2,1,60,0,0 +32540,-100,4,2,1,60,0,0 +32707,-100,4,2,1,60,0,0 +32762,-100,4,2,1,60,0,0 +32985,-100,4,2,1,60,0,0 +34318,-50,4,2,1,60,0,0 +34485,-100,4,2,1,5,0,0 +34540,-100,4,2,1,60,0,0 +35151,-100,4,2,1,5,0,0 +35207,-100,4,2,1,60,0,0 +35374,-100,4,2,1,5,0,0 +35430,-100,4,2,1,60,0,0 +35818,-100,4,2,1,5,0,0 +35874,-200,4,2,1,60,0,0 +36429,-100,4,2,1,60,0,0 +37818,-100,4,2,1,5,0,0 +37874,-100,4,2,1,60,0,0 +38040,-100,4,2,1,5,0,0 +38096,-50,4,2,1,60,0,0 +38151,-100,4,2,1,5,0,0 +38540,-100,4,2,1,60,0,0 +39596,-100,4,2,1,5,0,0 +39651,-100,4,2,1,60,0,0 +39818,-100,4,2,1,60,0,0 +39873,-100,4,2,1,60,0,0 +40096,-100,4,2,1,60,0,0 +41429,-50,4,2,1,60,0,0 +41596,-100,4,2,1,5,0,0 +41651,-100,4,2,1,60,0,0 +41818,-100,4,2,1,5,0,0 +41874,-100,4,2,1,60,0,0 +42040,-100,4,2,1,5,0,0 +42096,-100,4,2,1,60,0,0 +44318,-100,4,2,1,60,0,0 +44762,-83.3333333333333,4,2,1,60,0,0 +45207,-66.6666666666667,4,2,1,45,0,0 +45651,-133.333333333333,4,2,1,45,0,0 +51540,-133.333333333333,4,2,1,50,0,0 +51651,-133.333333333333,4,2,1,45,0,0 +52318,-133.333333333333,4,2,1,45,0,0 +58540,-76.9230769230769,4,2,1,45,0,0 +58818,-100,4,2,1,45,0,0 +58874,-111.111111111111,4,2,1,45,0,0 +59318,-111.111111111111,4,2,1,45,0,0 +59429,-83.3333333333333,4,2,1,60,0,0 +59540,-83.3333333333333,4,2,1,5,0,0 +59874,-100,4,2,1,60,0,0 +60096,-100,4,2,1,5,0,0 +60207,-100,4,2,1,60,0,0 +60707,-100,4,2,1,5,0,0 +60763,-100,4,2,1,60,0,0 +60818,-100,4,2,1,5,0,0 +60874,-100,4,2,1,60,0,0 +60929,-100,4,2,1,5,0,0 +60985,-100,4,2,1,60,0,0 +61040,-100,4,2,1,5,0,0 +61096,-100,4,2,1,60,0,0 +61151,-100,4,2,1,5,0,0 +61207,-100,4,2,1,60,0,0 +61596,-100,4,2,1,5,0,0 +61651,-100,4,2,1,60,0,0 +61762,-83.3333333333333,4,2,1,60,0,0 +61985,-100,4,2,1,5,0,0 +62096,-100,4,2,1,60,0,0 +62151,-100,4,2,1,5,0,0 +62207,-100,4,2,1,60,0,0 +62262,-100,4,2,1,5,0,0 +62318,-100,4,2,1,60,0,0 +62374,-100,4,2,1,5,0,0 +62430,-100,4,2,1,60,0,0 +62485,-100,4,2,1,5,0,0 +62540,-100,4,2,1,60,0,0 +62596,-100,4,2,1,5,0,0 +62651,-100,4,2,1,60,0,0 +62707,-100,4,2,1,5,0,0 +62762,-100,4,2,1,60,0,0 +62818,-100,4,2,1,5,0,0 +62874,-100,4,2,1,60,0,0 +62929,-100,4,2,1,60,0,0 +62930,-100,4,2,1,5,0,0 +62985,-100,4,2,1,60,0,0 +63707,-100,4,2,1,5,0,0 +63762,-100,4,2,1,60,0,0 +64262,-100,4,2,1,5,0,0 +64318,-100,4,2,1,60,0,0 +64485,-100,4,2,1,5,0,0 +64540,-100,4,2,1,60,0,0 +64596,-100,4,2,1,5,0,0 +64651,-100,4,2,1,60,0,0 +64707,-100,4,2,1,5,0,0 +64762,-71.4285714285714,4,2,1,60,0,0 +64929,-71.4285714285714,4,2,1,5,0,0 +64984,-133.333333333333,4,2,1,60,0,0 +65151,-133.333333333333,4,2,1,5,0,0 +65206,-71.4285714285714,4,2,1,60,0,0 +65374,-71.4285714285714,4,2,1,5,0,0 +65429,-133.333333333333,4,2,1,60,0,0 +65596,-133.333333333333,4,2,1,5,0,0 +65651,-100,4,2,1,60,0,0 +66540,-66.6666666666667,4,2,1,60,0,0 +66596,-66.6666666666667,4,2,1,5,0,0 +66929,-100,4,2,1,5,0,0 +66985,-200,4,2,1,60,0,0 +67207,-200,4,2,1,5,0,0 +67318,-100,4,2,1,60,0,0 +67818,-100,4,2,1,5,0,0 +67874,-100,4,2,1,60,0,0 +67929,-100,4,2,1,5,0,0 +67985,-100,4,2,1,60,0,0 +68040,-100,4,2,1,5,0,0 +68096,-100,4,2,1,60,0,0 +68151,-100,4,2,1,5,0,0 +68207,-100,4,2,1,60,0,0 +68262,-100,4,2,1,5,0,0 +68318,-100,4,2,1,60,0,0 +68874,-83.3333333333333,4,2,1,60,0,0 +69096,-100,4,2,1,60,0,0 +69097,-100,4,2,1,5,0,0 +69207,-100,4,2,1,60,0,0 +69263,-100,4,2,1,5,0,0 +69319,-100,4,2,1,60,0,0 +69374,-100,4,2,1,5,0,0 +69430,-100,4,2,1,60,0,0 +69486,-100,4,2,1,5,0,0 +69542,-100,4,2,1,60,0,0 +69597,-100,4,2,1,5,0,0 +69651,-100,4,2,1,60,0,0 +69707,-100,4,2,1,5,0,0 +69762,-100,4,2,1,60,0,0 +69818,-100,4,2,1,5,0,0 +69874,-100,4,2,1,60,0,0 +69929,-100,4,2,1,5,0,0 +69985,-100,4,2,1,60,0,0 +70040,-100,4,2,1,60,0,0 +70041,-100,4,2,1,5,0,0 +70096,-100,4,2,1,60,0,0 +70818,-100,4,2,1,5,0,0 +70873,-100,4,2,1,60,0,0 +71207,-71.4285714285714,4,2,1,60,0,0 +71429,-100,4,2,1,60,0,0 +71874,-71.4285714285714,4,2,1,60,0,0 +72041,-71.4285714285714,4,2,1,5,0,0 +72096,-133.333333333333,4,2,1,60,0,0 +72263,-133.333333333333,4,2,1,5,0,0 +72318,-71.4285714285714,4,2,1,60,0,0 +72485,-71.4285714285714,4,2,1,5,0,0 +72540,-133.333333333333,4,2,1,60,0,0 +72985,-66.6666666666667,4,2,1,60,0,0 +73207,-100,4,2,1,60,0,0 +73651,-133.333333333333,4,2,1,45,0,0 +75318,-133.333333333333,4,2,1,5,0,0 +75429,-133.333333333333,4,2,1,45,0,0 +76762,-100,4,2,1,45,0,0 +77096,-100,4,2,1,5,0,0 +77207,-100,4,2,1,70,0,1 +77818,-100,4,2,1,5,0,1 +77874,-100,4,2,1,70,0,1 +78262,-100,4,2,1,5,0,1 +78318,-100,4,2,1,70,0,1 +78540,-83.3333333333333,4,2,1,70,0,1 +78985,-100,4,2,1,70,0,1 +79596,-100,4,2,1,5,0,1 +79651,-100,4,2,1,70,0,1 +80040,-100,4,2,1,5,0,1 +80096,-100,4,2,1,70,0,1 +80318,-83.3333333333333,4,2,1,70,0,1 +84318,-100,4,2,1,70,0,1 +84929,-100,4,2,1,5,0,1 +84985,-100,4,2,1,70,0,1 +85207,-100,4,2,1,70,0,1 +85374,-100,4,2,1,5,0,1 +85429,-100,4,2,1,70,0,1 +85651,-83.3333333333333,4,2,1,70,0,1 +86096,-100,4,2,1,70,0,1 +86707,-100,4,2,1,5,0,1 +86762,-100,4,2,1,70,0,1 +88818,-100,4,2,1,5,0,1 +88874,-100,4,2,1,70,0,1 +88929,-100,4,2,1,5,0,1 +88985,-100,4,2,1,70,0,1 +89040,-100,4,2,1,5,0,1 +89096,-100,4,2,1,70,0,1 +92040,-100,4,2,1,5,0,1 +92096,-100,4,2,1,70,0,1 +92485,-100,4,2,1,5,0,1 +92540,-100,4,2,1,70,0,1 +97651,-200,4,2,1,70,0,1 +97818,-200,4,2,1,5,0,1 +97874,-66.6666666666667,4,2,1,70,0,1 +97985,-66.6666666666667,4,2,1,70,0,1 +98040,-66.6666666666667,4,2,1,5,0,1 +98096,-133.333333333333,4,2,1,70,0,1 +98262,-133.333333333333,4,2,1,5,0,1 +98318,-66.6666666666667,4,2,1,70,0,1 +98540,-100,4,2,1,70,0,1 +99151,-100,4,2,1,5,0,1 +99207,-100,4,2,1,70,0,1 +99596,-100,4,2,1,5,0,1 +99651,-100,4,2,1,70,0,1 +103040,-100,4,2,1,5,0,1 +103096,-100,4,2,1,70,0,1 +103151,-100,4,2,1,5,0,1 +103207,-100,4,2,1,70,0,1 +103262,-100,4,2,1,5,0,1 +103318,-100,4,2,1,70,0,1 +105207,-83.3333333333333,4,2,1,70,0,1 +105540,-83.3333333333333,4,2,1,70,0,1 +105651,-133.333333333333,4,2,1,60,0,0 +105985,-133.333333333333,4,2,1,5,0,0 +106096,-200,4,2,1,60,0,0 +106985,-66.6666666666667,4,2,1,60,0,0 +107151,-66.6666666666667,4,2,1,5,0,0 +107207,-66.6666666666667,4,2,1,60,0,0 +107429,-100,4,2,1,60,0,0 +107763,-100,4,2,1,5,0,0 +107874,-100,4,2,1,60,0,0 +108874,-100,4,2,1,60,0,0 +109374,-100,4,2,1,5,0,0 +109429,-100,4,2,1,60,0,0 +109596,-100,4,2,1,5,0,0 +109651,-200,4,2,1,60,0,0 +109929,-100,4,2,1,60,0,0 +109984,-100,4,2,1,60,0,0 +110262,-100,4,2,1,5,0,0 +110318,-100,4,2,1,60,0,0 +110485,-100,4,2,1,5,0,0 +110540,-100,4,2,1,60,0,0 +110707,-100,4,2,1,5,0,0 +110762,-66.6666666666667,4,2,1,60,0,0 +110929,-100,4,2,1,60,0,0 +110985,-133.333333333333,4,2,1,60,0,0 +111429,-133.333333333333,4,2,1,60,0,0 +111596,-133.333333333333,4,2,1,60,0,0 +111651,-133.333333333333,4,2,1,60,0,0 +111818,-133.333333333333,4,2,1,60,0,0 +111874,-100,4,2,1,60,0,1 +112318,-83.3333333333333,4,2,1,60,0,1 +112429,-100,4,2,1,5,0,0 + + +[Colours] +Combo1 : 112,75,180 +Combo2 : 0,255,255 +Combo3 : 255,15,117 +Combo4 : 255,135,15 + +[HitObjects] +309,230,763,37,0,3:0:0:0: +485,146,985,2,0,L|406:167,1,67.4999968671799,8|0,3:0|0:0,0:0:0:0: +374,249,1207,2,0,L|299:227,1,67.4999968671799,8|0,3:0|0:0,0:0:0:0: +196,91,1429,2,0,L|191:44,3,33.7499984335899,0|0|0|0,3:0|3:0|3:0|3:0,0:0:0:0: +124,173,1651,2,0,L|131:222,2,44.9999979114532,0|0|0,3:0|3:0|3:0,0:0:0:0: +221,284,1874,2,0,L|213:208,1,67.4999968671799,0|0,3:0|3:0,0:0:0:0: +292,86,2096,38,0,L|310:234,1,146.249990980625,12|0,3:0|0:0,0:0:0:0: +314,328,2540,38,0,B|280:359|280:359|230:320|252:242|313:230,1,209.999990253448,0|0,3:0|0:0,0:0:0:0: +421,300,2874,1,0,0:0:0:0: +421,300,2985,2,0,P|461:288|491:253,1,74.999998807907,8|0,3:0|0:0,0:0:0:0: +309,231,3207,2,0,P|297:190|305:153,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +394,22,3429,5,0,3:0:0:0: +461,72,3540,2,0,B|477:103|477:103|461:148,1,74.999998807907,0|4,0:0|0:0,0:0:0:0: +378,183,3762,2,0,L|206:157,1,149.999997615814,0|0,0:0|0:0,0:0:0:0: +229,161,4096,2,0,P|227:202|211:250,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +61,384,4318,38,0,P|101:359|134:322,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +317,310,4540,2,0,P|267:305|226:288,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +141,110,4762,2,0,B|121:175|152:226|152:226|152:202|161:183,1,149.999997615814,8|4,3:0|0:0,0:0:0:0: +155,196,5096,6,0,P|67:211|79:286,1,179.999991645813,0|0,0:0|0:0,0:0:0:0: +212,366,5429,38,0,P|207:335|174:281,1,56.2500012516975,4|0,0:0|0:0,0:0:0:0: +206,286,5651,2,0,P|236:297|299:295,1,56.2500012516975,8|0,3:0|0:0,0:0:0:0: +281,321,5874,2,0,P|257:340|227:396,1,56.2500012516975,4|0,0:0|0:0,0:0:0:0: +124,246,6096,6,0,P|198:198|277:232,1,149.999997615814,0|0,3:0|0:0,0:0:0:0: +253,211,6429,1,0,0:0:0:0: +276,99,6540,2,0,P|335:139|369:215,1,149.999997615814,8|4,3:0|0:0,0:0:0:0: +368,208,6874,1,0,0:0:0:0: +430,96,6985,37,0,3:0:0:0: +497,147,7096,2,0,P|507:189|488:244,1,74.999998807907,0|4,0:0|0:0,0:0:0:0: +414,379,7318,2,0,B|383:322|421:267|421:267|421:308,1,149.999997615814,0|0,0:0|0:0,0:0:0:0: +421,298,7651,2,0,P|378:312|336:304,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +270,170,7874,6,0,P|275:228|236:278,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +94,300,8096,2,0,P|133:263|208:274,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +261,374,8318,2,0,L|176:365,1,74.999998807907,8|0,3:0|0:0,0:0:0:0: +38,377,8540,2,0,L|55:197,1,168.750003755093,4|0,0:0|0:0,0:0:0:0: +123,25,8985,38,0,L|132:110,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +217,242,9207,2,0,L|237:168,1,74.999998807907,8|0,3:0|0:0,0:0:0:0: +48,92,9429,5,4,0:0:0:0: +63,176,9540,1,0,0:0:0:0: +83,259,9651,38,0,P|167:223|231:255,1,149.999997615814,0|0,3:0|0:0,0:0:0:0: +274,312,9985,1,0,0:0:0:0: +274,312,10096,2,0,L|354:292,1,74.999998807907,8|0,3:0|0:0,0:0:0:0: +459,225,10318,2,0,L|375:204,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +269,107,10540,1,0,3:0:0:0: +276,54,10651,1,0,0:0:0:0: +313,17,10762,1,4,0:0:0:0: +363,9,10874,1,0,0:0:0:0: +363,9,11096,5,0,0:0:0:0: +432,68,11207,2,0,P|444:107|425:154,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +309,252,11429,38,0,P|297:195|321:158,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +450,316,11651,2,0,L|361:312,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +160,341,11874,2,0,B|187:380|187:380|233:309|177:235,1,187.499997019767,8|4,3:0|0:0,0:0:0:0: +116,200,12207,6,0,P|52:224|122:264,1,168.750003755093,0|4,0:0|0:0,0:0:0:0: +297,91,12762,37,8,3:0:0:0: +276,44,12874,1,0,0:0:0:0: +226,27,12985,1,4,0:0:0:0: +187,63,13096,1,0,0:0:0:0: +196,115,13207,1,0,0:0:0:0: +376,144,13429,2,0,L|378:121,2,16.6666664017571,0|0|0,0:0|0:0|0:0,0:0:0:0: +436,220,13651,6,0,B|395:211|373:164|373:164|332:208|264:185,1,179.999991645813,8|4,3:0|0:0,0:0:0:0: +276,44,13985,1,0,0:0:0:0: +196,115,14096,38,0,L|139:124,4,37.4999994039535,0|0|0|0|4,3:0|0:0|0:0|0:0|0:0,0:0:0:0: +82,69,14429,1,0,0:0:0:0: +106,190,14540,2,0,L|126:276,1,74.999998807907,8|0,3:0|0:0,0:0:0:0: +218,383,14762,2,0,L|234:309,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +26,231,14985,5,0,3:0:0:0: +253,202,15207,37,0,0:0:0:0: +331,271,15318,1,0,0:0:0:0: +233,309,15429,1,8,3:0:0:0: +389,73,15651,6,0,P|410:22|447:112,1,224.999996423721,4|0,3:0|0:0,0:0:0:0: +391,165,16096,1,0,0:0:0:0: +377,177,16207,1,0,0:0:0:0: +365,187,16318,38,0,B|253:261|221:119|94:192,1,269.999987468719,0|0,0:0|0:0,0:0:0:0: +73,319,16762,22,0,P|133:336|116:236,1,168.750003755093,4|0,3:0|0:0,0:0:0:0: +139,258,17207,6,0,P|138:315|69:283,1,112.500002503395,8|0,3:0|0:0,0:0:0:0: +92,323,17762,37,0,0:0:0:0: +43,245,17874,1,4,0:0:0:0: +4,322,17985,1,0,0:0:0:0: +133,245,18096,1,0,3:0:0:0: +29,105,18318,6,0,L|38:40,3,56.2500012516975,4|0|0|0,3:0|0:0|0:0|0:0,0:0:0:0: +50,30,18540,38,0,P|111:56|193:25,1,149.999997615814,0|0,3:0|0:0,0:0:0:0: +240,120,18985,2,0,P|328:91|394:125,1,149.999997615814,8|4,3:0|0:0,0:0:0:0: +409,213,19318,2,0,B|377:226|377:226|243:200,1,149.999997615814,0|0,0:0|0:0,0:0:0:0: +119,187,19651,2,0,L|127:286,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +179,338,19874,1,8,3:0:0:0: +45,307,19985,6,0,L|3:297,2,37.4999994039535,0|0|4,0:0|0:0|0:0,0:0:0:0: +103,380,20207,1,0,3:0:0:0: +212,257,20318,38,0,P|233:218|231:171,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +111,118,20540,1,4,0:0:0:0: +111,118,20762,6,0,L|197:109,1,74.999998807907,8|4,3:0|0:0,0:0:0:0: +256,18,21096,37,0,0:0:0:0: +337,121,21207,2,0,P|350:60|403:16,1,112.49999821186,0|0,3:0|0:0,0:0:0:0: +384,26,21429,2,0,P|406:86|465:122,1,112.49999821186,0|0,0:0|0:0,0:0:0:0: +443,114,21651,2,0,P|377:105|327:131,1,112.49999821186,8|0,3:0|0:0,0:0:0:0: +352,223,21874,6,0,B|369:230|369:230|391:228|391:228|416:239|416:239|440:235|440:235|462:244|462:244|489:249,1,112.500002503395,4|0,0:0|0:0,0:0:0:0: +322,343,22096,37,0,3:0:0:0: +259,270,22207,2,0,P|223:276|182:263,2,74.999998807907,0|4|0,0:0|0:0|0:0,0:0:0:0: +86,360,22540,5,8,3:0:0:0: +15,295,22651,2,0,L|0:201,2,74.999998807907,0|4|0,0:0|0:0|0:0,0:0:0:0: +94,384,22985,38,0,P|118:328|112:277,1,112.49999821186,0|0,3:0|0:0,0:0:0:0: +0,211,23429,22,0,L|76:196,1,74.999998807907,12|0,3:0|0:0,0:0:0:0: +215,134,23651,2,0,L|114:110,1,74.999998807907,12|0,3:0|0:0,0:0:0:0: +33,124,23874,22,0,L|43:2,1,112.49999821186,0|0,3:0|0:0,0:0:0:0: +150,269,24318,2,0,L|162:194,1,74.999998807907,0|4,3:0|0:0,0:0:0:0: +229,134,24651,6,0,L|386:164,1,112.500002503395,12|0,3:0|0:0,0:0:0:0: +486,268,24874,37,0,0:0:0:0: +410,119,24985,1,4,0:0:0:0: +381,213,25096,1,0,0:0:0:0: +512,120,25207,1,0,3:0:0:0: +247,36,25429,6,0,L|191:25,3,37.4999994039535,4|0|0|0,3:0|0:0|0:0|0:0,0:0:0:0: +185,24,25651,2,0,B|145:72|145:72|174:164,1,149.999997615814,0|0,3:0|0:0,0:0:0:0: +253,219,26096,2,0,B|281:311|281:311|228:382,1,149.999997615814,8|4,3:0|0:0,0:0:0:0: +100,363,26429,38,0,L|259:354,1,149.999997615814,0|0,0:0|0:0,0:0:0:0: +404,262,26762,1,4,0:0:0:0: +390,352,26874,1,0,0:0:0:0: +314,295,26985,1,8,3:0:0:0: +425,256,27096,6,0,L|492:246,2,37.4999994039535,0|0|4,0:0|0:0|0:0,0:0:0:0: +329,216,27318,1,0,3:0:0:0: +193,177,27429,38,0,L|266:161,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +322,107,27651,1,4,0:0:0:0: +322,107,27874,2,0,L|310:238,1,112.500002503395,8|4,3:0|0:0,0:0:0:0: +110,299,28207,5,0,0:0:0:0: +164,231,28318,2,0,B|168:303|168:303|121:338,1,112.49999821186,0|0,3:0|0:0,0:0:0:0: +30,284,28540,2,0,B|90:244|90:244|144:267,1,112.49999821186,0|0,0:0|0:0,0:0:0:0: +148,371,28762,2,0,B|83:338|83:338|76:280,1,112.49999821186,8|0,3:0|0:0,0:0:0:0: +194,201,28985,38,0,B|207:210|207:210|227:210|227:210|243:217|243:217|265:218|265:218|282:227|282:227|305:225|305:225|325:238,1,112.500002503395,4|0,0:0|0:0,0:0:0:0: +492,114,29207,6,0,P|445:136|410:138,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +324,102,29429,2,0,P|291:68|280:29,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +418,17,29651,1,8,3:0:0:0: +495,201,29874,1,4,3:2:0:0: +221,136,30096,37,0,3:0:0:0: +299,188,30207,2,0,B|316:251|316:251|271:352,1,149.999997615814,4|0,3:0|0:0,0:0:0:0: +115,334,30540,6,0,P|11:252|167:266,1,382.500001215934,0|0,0:0|0:0,0:0:0:0: +216,326,30985,38,0,L|304:331,1,63.7500002026557,4|0,3:0|0:0,0:0:0:0: +280,330,31429,6,0,L|293:241,1,74.999998807907,8|0,3:0|0:0,0:0:0:0: +426,252,31651,2,0,L|439:163,1,74.999998807907,0|0,0:0|0:0,0:0:0:0: +253,158,31874,37,0,3:0:0:0: +258,132,31985,1,0,0:0:0:0: +337,111,32096,5,4,0:0:0:0: +341,85,32207,1,0,0:0:0:0: +271,30,32318,38,0,B|212:42|212:42|141:19,1,112.49999821186,8|0,3:0|0:0,0:0:0:0: +163,26,32540,2,0,L|144:181,1,149.999997615814,4|0,0:0|3:0,0:0:0:0: +445,343,32985,22,0,B|439:234|439:234|384:269,1,149.999997615814,4|8,0:0|3:0,0:0:0:0: +240,257,33429,2,0,B|263:148|263:148|291:205,1,149.999997615814,4|0,0:0|3:0,0:0:0:0: +68,333,33874,2,0,B|83:233|83:233|41:256,1,149.999997615814,4|8,0:0|3:0,0:0:0:0: +344,347,34318,22,0,B|368:372|368:372|455:355|455:355|472:308,1,149.999997615814,4|0,0:0|0:0,0:0:0:0: +452,255,34540,2,0,B|389:212|389:212|332:273,1,149.999997615814,0|4,3:0|0:0,0:0:0:0: +256,220,34874,5,0,0:0:0:0: +256,220,34985,2,0,B|256:128,1,74.999998807907,8|0,3:0|0:0,0:0:0:0: +256,70,35207,2,0,B|256:162,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +112,312,35429,37,0,3:0:0:0: +60,255,35540,2,0,B|123:212|123:212|180:273,1,149.999997615814,0|0,0:0|0:0,0:0:0:0: +169,350,35874,6,0,B|144:375|144:375|57:358|57:358|40:311,1,149.999997615814,8|0,3:0|3:0,0:0:0:0: +62,169,36429,6,0,L|76:267,2,74.999998807907,0|4|0,0:0|0:0|0:0,0:0:0:0: +134,61,36762,1,8,3:0:0:0: +201,113,36874,2,0,L|215:211,2,74.999998807907,0|4|0,0:0|0:0|0:0,0:0:0:0: +298,272,37207,6,0,L|315:184,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +330,114,37429,1,4,0:0:0:0: +446,176,37540,2,0,B|404:214|404:214|307:197,1,149.999997615814,4|0,3:0|0:0,0:0:0:0: +231,240,37874,2,0,P|223:199|231:162,1,74.999998807907,4|0,3:0|0:0,0:0:0:0: +325,285,38096,6,0,L|154:300,1,149.999997615814,4|0,3:0|0:0,0:0:0:0: +175,298,38540,6,0,L|163:396,1,74.999998807907,8|0,3:0|0:0,0:0:0:0: +75,208,38762,2,0,L|63:306,1,74.999998807907,0|0,0:0|0:0,0:0:0:0: +233,74,38985,37,0,3:0:0:0: +231,98,39096,1,0,0:0:0:0: +156,139,39207,5,4,0:0:0:0: +155,165,39318,1,0,0:0:0:0: +227,215,39429,38,0,P|282:209|352:230,1,112.49999821186,8|0,3:0|0:0,0:0:0:0: +336,222,39651,2,0,L|366:67,1,149.999997615814,4|0,0:0|3:0,0:0:0:0: +81,35,40096,22,0,B|82:105|82:105|118:136|118:136|132:89,1,149.999997615814,4|8,0:0|3:0,0:0:0:0: +272,158,40540,2,0,B|270:228|270:228|234:259|234:259|220:212,1,149.999997615814,4|0,0:0|3:0,0:0:0:0: +423,36,40985,2,0,B|400:102|400:102|423:143|423:143|453:104,1,149.999997615814,4|8,0:0|3:0,0:0:0:0: +512,278,41429,6,0,P|415:258|361:293,1,149.999997615814,4|0,0:0|0:0,0:0:0:0: +359,302,41651,6,0,B|320:264|320:264|310:187,1,112.49999821186,0|0,3:0|0:0,0:0:0:0: +322,190,41874,2,0,L|449:171,1,112.49999821186,4|0,0:0|0:0,0:0:0:0: +443,159,42096,1,8,3:0:0:0: +240,52,42318,6,0,B|255:79|255:79|241:135,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +177,166,42540,1,0,3:0:0:0: +163,151,42651,2,0,B|161:207|161:207|192:240|192:240|189:299,1,149.999997615814,0|0,0:0|0:0,0:0:0:0: +131,365,42985,2,0,P|198:322|280:345,1,149.999997615814,8|4,3:0|0:0,0:0:0:0: +335,377,43318,1,0,0:0:0:0: +442,239,43429,38,0,B|456:178|456:178|422:136|422:136|427:68|427:68|449:112,1,224.999996423721,0|0,3:0|0:0,0:0:0:0: +444,103,43874,2,0,P|402:118|356:120,1,74.999998807907,0|0,0:0|0:0,0:0:0:0: +249,28,44096,2,0,P|295:35|324:48,1,74.999998807907,0|0,0:0|0:0,0:0:0:0: +364,201,44318,5,0,0:0:0:0: +332,195,44429,1,0,0:0:0:0: +251,135,44540,37,0,0:0:0:0: +281,123,44651,1,0,0:0:0:0: +332,195,44762,6,0,B|356:269|324:333|324:333|303:293,1,179.999991645813,4|0,0:3|0:0,0:0:0:0: +61,25,45207,38,0,L|88:158,1,112.500002503395,0|0,3:0|0:0,0:0:0:0: +84,136,45651,1,8,3:0:0:0: +84,136,46096,1,0,3:0:0:0: +176,33,46207,2,0,L|164:103,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +219,207,46429,2,0,L|232:152,1,56.2500012516975,0|8,0:0|3:0,0:0:0:0: +312,65,46651,1,0,0:0:0:0: +312,65,46762,2,0,L|398:94,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +512,176,46985,5,0,3:0:0:0: +421,192,47096,1,0,0:0:0:0: +421,192,47429,1,8,3:0:0:0: +402,357,47651,37,0,0:0:0:0: +394,277,47762,1,0,0:0:0:0: +328,324,47874,1,0,3:0:0:0: +328,324,48318,1,8,3:0:0:0: +110,357,48540,5,0,0:0:0:0: +118,277,48651,1,0,0:0:0:0: +184,324,48763,1,0,3:0:0:0: +110,357,48874,1,0,0:0:0:0: +110,357,49207,1,8,3:0:0:0: +110,357,49651,1,0,3:0:0:0: +0,283,49762,38,0,P|41:301|97:295,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +188,219,49985,2,0,P|168:236|137:246,1,56.2500012516975,0|8,0:0|3:0,0:0:0:0: +49,137,50207,1,0,0:0:0:0: +49,137,50318,2,0,P|65:184|93:205,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +107,67,50540,5,0,3:0:0:0: +32,15,50651,1,0,0:0:0:0: +32,15,50985,1,8,3:0:0:0: +265,114,51207,37,0,0:0:0:0: +254,196,51318,1,0,0:0:0:0: +241,279,51429,1,0,3:0:0:0: +241,279,51651,1,0,0:0:0:0: +336,207,51762,6,0,P|397:191|371:274,1,168.750003755093,0|0,0:0|0:0,0:0:0:0: +83,206,52318,5,0,3:0:0:0: +83,206,52429,2,0,L|101:260,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +40,383,52651,2,0,P|70:355|90:324,1,56.2500012516975,0|8,0:0|3:0,0:0:0:0: +214,334,52874,1,0,0:0:0:0: +214,334,52985,2,0,P|171:322|140:304,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +151,160,53207,5,0,3:0:0:0: +188,135,53318,1,0,0:0:0:0: +232,129,53429,1,0,0:0:0:0: +273,146,53540,1,0,0:0:0:0: +339,198,53651,37,8,3:0:0:0: +383,199,53762,1,0,0:0:0:0: +426,185,53874,1,0,0:0:0:0: +450,147,53985,1,0,0:0:0:0: +444,61,54096,6,0,P|414:28|377:15,1,56.2500012516975,0|0,3:0|0:0,0:0:0:0: +301,28,54318,2,0,P|268:48|255:77,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +189,271,54540,38,0,P|209:222|204:198,1,56.2500012516975,8|0,3:0|0:0,0:0:0:0: +186,114,54762,2,0,P|152:74|124:68,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +27,137,54985,5,0,3:0:0:0: +34,167,55096,1,0,0:0:0:0: +122,204,55207,37,0,0:0:0:0: +116,178,55318,1,0,0:0:0:0: +48,249,55429,5,8,3:0:0:0: +54,274,55540,1,0,0:0:0:0: +124,329,55651,38,0,P|157:326|200:310,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +320,185,55874,5,0,3:0:0:0: +287,175,55985,1,0,0:0:0:0: +254,181,56096,2,0,P|258:221|264:241,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +337,347,56318,2,0,P|348:321|350:293,1,56.2500012516975,8|0,3:0|0:0,0:0:0:0: +418,197,56540,37,0,0:0:0:0: +418,197,56651,2,0,L|492:180,1,56.2500012516975,0|0,0:0|3:0,0:0:0:0: +329,114,56874,2,0,L|262:94,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +436,59,57096,6,0,L|413:126,1,56.2500012516975,0|8,0:0|3:0,0:0:0:0: +332,194,57318,2,0,L|353:259,2,56.2500012516975,0|0|0,0:0|0:0|0:0,0:0:0:0: +202,194,57651,37,0,3:0:0:0: +224,233,57762,1,0,0:0:0:0: +222,279,57874,1,0,0:0:0:0: +193,314,57985,1,0,0:0:0:0: +144,244,58096,5,0,0:0:0:0: +127,214,58207,1,0,0:0:0:0: +126,180,58318,1,0,0:0:0:0: +139,149,58429,1,0,0:0:0:0: +224,113,58540,38,0,B|262:88|235:70|189:83|189:83|224:138|194:193,1,194.999987974167 +299,319,58874,1,0,0:0:0:0: +299,319,58985,2,0,B|316:283|314:237|314:237|278:226|278:226|320:243|359:227,1,202.49999060154,4|0,0:0|0:0,0:0:0:0: +428,181,59429,22,0,P|454:129|399:4,1,179.999991645813,0|0,3:0|0:0,0:0:0:0: +418,18,59874,2,0,L|373:15,6,24.9999996026357,8|0|0|0|0|0|4,3:0|0:0|0:0|0:0|0:0|0:0|0:0,0:0:0:0: +428,181,60207,5,0,0:0:0:0: +352,209,60318,1,0,3:0:0:0: +278,177,60429,1,0,0:0:0:0: +208,225,60540,2,0,L|222:267,2,37.4999994039535,4|0|0,0:0|0:0|0:0,0:0:0:0: +71,144,60762,38,0,L|65:109,3,24.9999996026357,8|0|0|0,3:0|0:0|0:0|0:0,0:0:0:0: +145,86,60985,1,4,0:0:0:0: +163,127,61096,1,0,0:0:0:0: +161,171,61207,1,0,3:0:0:0: +136,208,61318,1,0,0:0:0:0: +99,231,61429,2,0,B|91:279|91:279|117:314,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +177,378,61651,5,8,3:0:0:0: +177,378,61762,2,0,B|231:371|231:371|272:326|272:326|345:319,1,179.999991645813 +417,293,62096,1,0,3:0:0:0: +438,263,62207,1,0,0:0:0:0: +436,225,62318,1,4,0:0:0:0: +412,196,62429,1,0,0:0:0:0: +320,172,62540,6,0,P|307:192|291:204,1,37.4999994039535,8|0,3:0|0:0,0:0:0:0: +291,147,62651,2,0,P|274:156|245:153,1,37.4999994039535,0|0,0:0|0:0,0:0:0:0: +276,114,62762,2,0,P|250:107|234:94,1,37.4999994039535,4|0,0:0|0:0,0:0:0:0: +283,81,62874,2,0,P|265:61|260:45,1,37.4999994039535,0|0,0:0|0:0,0:0:0:0: +365,31,62985,38,0,P|398:44|442:49,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +512,169,63207,2,0,P|466:163|421:176,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +350,107,63429,1,8,3:0:0:0: +293,237,63540,38,0,L|276:158,1,74.999998807907,0|0,0:0|0:0,0:0:0:0: +428,269,63762,2,0,B|373:275|373:275|338:249|338:249|267:255,1,149.999997615814,0|0,0:0|0:0,0:0:0:0: +191,318,64096,2,0,B|182:355|182:355|212:395,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +192,186,64318,5,8,3:0:0:0: +135,253,64429,2,0,L|56:270,2,74.999998807907,0|4|0,0:0|0:0|0:0,0:0:0:0: +24,136,64762,38,0,P|69:76|158:75,1,157.499992690086,0|0,3:0|0:0,0:0:0:0: +160,80,64985,6,0,P|193:102|255:102,1,84.3750018775463,4|0,0:0|0:0,0:0:0:0: +276,34,65207,38,0,L|290:212,1,157.499992690086,8|0,3:0|0:0,0:0:0:0: +291,219,65429,6,0,L|311:132,1,84.3750018775463,4|0,0:0|0:0,0:0:0:0: +381,111,65651,38,0,B|418:126|418:126|460:126,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +221,163,65874,2,0,B|186:143|186:143|139:153,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +41,231,66096,1,8,3:0:0:0: +49,267,66207,1,0,0:0:0:0: +56,303,66318,1,4,0:0:0:0: +67,288,66429,1,4,0:0:0:0: +77,270,66540,6,0,P|171:255|72:350,1,337.500007510185,0|0,0:0|0:0,0:0:0:0: +95,356,66985,38,0,L|185:343,1,74.999998807907,8|4,3:0|0:0,0:0:0:0: +274,286,67318,6,0,B|289:324|289:324|268:378,1,74.999998807907,0|0,0:0|3:0,0:0:0:0: +191,227,67540,1,0,0:0:0:0: +255,168,67651,2,0,L|264:116,2,37.4999994039535,4|0|0,0:0|0:0|0:0,0:0:0:0: +147,83,67874,2,0,L|154:108,3,24.9999996026357,8|0|0|0,3:0|0:0|0:0|0:0,0:0:0:0: +80,148,68096,38,0,L|98:224,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +125,356,68318,1,0,3:0:0:0: +0,319,68429,1,0,0:0:0:0: +0,319,68540,2,0,L|76:294,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +277,219,68762,5,8,3:0:0:0: +277,219,68874,2,0,B|327:199|327:199|293:138|197:173,1,179.999991645813,0|0,0:0|0:0,0:0:0:0: +157,273,69207,37,0,3:0:0:0: +175,316,69318,1,0,0:0:0:0: +212,334,69429,1,4,0:0:0:0: +254,333,69540,1,0,0:0:0:0: +332,268,69651,38,0,P|333:237|343:213,1,37.4999994039535,8|0,3:0|0:0,0:0:0:0: +373,265,69762,2,0,P|386:239|404:232,1,37.4999994039535,0|0,0:0|0:0,0:0:0:0: +413,284,69874,2,0,P|430:269|454:269,1,37.4999994039535,4|0,0:0|0:0,0:0:0:0: +433,318,69985,2,0,P|452:320|474:337,1,37.4999994039535,4|0,0:0|0:0,0:0:0:0: +401,384,70096,6,0,P|353:378|319:346,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +251,251,70318,2,0,P|240:196|260:154,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +401,18,70540,1,8,3:0:0:0: +401,18,70651,2,0,P|409:54|398:90,1,74.999998807907,0|0,0:0|0:0,0:0:0:0: +327,193,70874,2,0,L|304:45,1,149.999997615814,0|0,0:0|0:0,0:0:0:0: +290,26,71207,6,0,L|308:144,1,104.999995126724,0|0,0:0|0:0,0:0:0:0: +272,302,71429,2,0,L|187:288,1,74.999998807907,8|0,3:0|0:0,0:0:0:0: +33,217,71651,37,4,0:0:0:0: +27,187,71762,1,4,0:0:0:0: +20,157,71874,2,0,B|103:140|103:140|162:58,1,157.499992690086,0|0,3:0|0:0,0:0:0:0: +145,82,72096,6,0,L|218:75,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +336,136,72318,38,0,P|331:213|231:208,1,157.499992690086 +263,232,72540,6,0,L|278:300,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +183,384,72762,2,0,L|172:307,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +37,140,72985,38,0,B|10:168|10:168|17:204|17:204|54:220|54:220|89:196|89:196|87:157|87:157|57:138,1,225.00000500679 +275,372,73651,6,0,P|320:352|387:369,1,112.500002503395 +380,364,74096,2,0,L|436:358,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +495,271,74318,2,0,L|424:282,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +339,270,74540,1,0,0:0:0:0: +339,270,74651,1,0,0:0:0:0: +339,270,74762,2,0,L|329:196,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +408,46,74985,38,0,L|392:120,1,56.2500012516975 +220,230,75207,2,0,L|209:156,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +282,7,75429,37,0,0:0:0:0: +300,98,75540,1,0,0:0:0:0: +197,25,75651,5,0,0:0:0:0: +222,103,75762,1,0,0:0:0:0: +126,69,75874,5,0,0:0:0:0: +153,134,75985,1,0,0:0:0:0: +76,145,76096,5,0,0:0:0:0: +116,179,76207,1,0,0:0:0:0: +70,222,76318,5,0,0:0:0:0: +111,222,76429,1,0,0:0:0:0: +134,253,76540,6,0,P|135:298|126:314,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +21,384,76762,2,0,P|124:354|260:391,1,224.999996423721,0|0,0:0|0:0,0:0:0:0: +384,366,77207,22,0,L|394:268,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +499,62,77429,2,0,L|486:135,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +507,237,77651,2,0,P|450:231|388:184,1,112.49999821186,8|0,3:0|0:0,0:0:0:0: +404,203,77874,2,0,L|313:217,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +113,212,78096,6,0,P|128:267|111:328,1,112.49999821186,0|0,3:0|0:0,0:0:0:0: +115,319,78318,2,0,L|213:340,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +274,371,78540,38,0,L|257:186,1,179.999991645813,8|0,3:0|0:0,0:0:0:0: +128,139,78874,1,0,0:0:0:0: +128,139,78985,6,0,L|230:128,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +365,34,79207,37,4,0:0:0:0: +430,114,79318,1,0,0:0:0:0: +361,184,79429,2,0,P|304:170|277:110,1,112.49999821186,8|0,3:0|0:0,0:0:0:0: +278,126,79651,2,0,L|189:133,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +64,263,79874,6,0,B|37:230|37:230|50:143,1,112.49999821186,0|0,3:0|0:0,0:0:0:0: +66,119,80096,2,0,L|80:210,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +71,361,80318,38,0,B|135:350|135:350|182:305|182:305|243:297,1,179.999991645813,8|0,3:0|0:0,0:0:0:0: +302,247,80651,1,0,0:0:0:0: +222,211,80762,1,0,3:0:0:0: +478,344,80985,5,4,0:0:0:0: +491,309,81096,5,0,0:0:0:0: +498,265,81207,5,8,3:0:0:0: +485,223,81318,5,0,0:0:0:0: +458,179,81429,5,4,0:0:0:0: +418,147,81540,5,0,0:0:0:0: +352,126,81651,5,0,3:0:0:0: +281,149,81762,5,0,0:0:0:0: +239,221,81874,5,4,0:0:0:0: +159,262,81985,5,0,0:0:0:0: +66,234,82096,5,8,3:0:0:0: +11,145,82207,5,0,0:0:0:0: +55,33,82318,5,4,0:0:0:0: +273,44,82540,37,0,3:0:0:0: +320,103,82651,1,0,0:0:0:0: +394,118,82762,1,4,0:0:0:0: +468,100,82874,1,0,0:0:0:0: +507,36,82985,1,8,3:0:0:0: +495,19,83207,5,4,0:0:0:0: +335,83,83318,1,0,0:0:0:0: +453,81,83429,1,0,3:0:0:0: +283,24,83540,2,0,P|196:37|141:120,1,149.999997615814,0|0,0:0|0:0,0:0:0:0: +60,238,83874,1,8,3:0:0:0: +21,164,83985,2,0,P|59:149|175:193,1,149.999997615814,0|8,0:0|3:0,0:0:0:0: +252,206,84318,38,0,P|271:160|264:125,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +139,257,84540,2,0,P|131:302|149:340,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +240,379,84762,2,0,B|330:360|330:360|298:344,1,112.49999821186,8|0,3:0|0:0,0:0:0:0: +312,351,84985,2,0,P|279:321|270:287,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +359,165,85207,6,0,B|389:202|389:202|368:282,1,112.49999821186,0|0,3:0|0:0,0:0:0:0: +373,265,85429,2,0,L|454:282,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +498,139,85651,38,0,P|446:120|396:0,1,179.999991645813,8|0,3:0|0:0,0:0:0:0: +394,13,85985,1,0,0:0:0:0: +301,92,86096,6,0,L|214:83,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +66,66,86318,1,4,0:0:0:0: +13,136,86429,1,0,0:0:0:0: +72,193,86540,2,0,P|120:210|190:178,1,112.49999821186,8|0,3:0|0:0,0:0:0:0: +176,192,86762,2,0,P|154:237|160:288,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +309,370,86985,37,0,3:0:0:0: +359,310,87096,1,0,0:0:0:0: +283,297,87207,2,0,L|203:318,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +4,203,87429,2,0,B|55:211|55:211|82:255|82:255|134:266,1,149.999997615814,8|0,3:0|0:0,0:0:0:0: +238,217,87762,1,0,0:0:0:0: +183,120,87874,6,0,L|89:111,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +98,33,88096,2,0,L|23:26,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +306,182,88318,38,0,L|400:173,1,74.999998807907,8|0,3:0|0:0,0:0:0:0: +391,95,88540,2,0,L|465:88,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +232,28,88762,2,0,L|220:92,1,37.4999994039535,0|0,3:0|0:0,0:0:0:0: +243,39,88874,2,0,L|231:103,1,37.4999994039535,0|0,0:0|0:0,0:0:0:0: +256,50,88985,2,0,L|251:87,1,37.4999994039535,4|0,0:0|0:0,0:0:0:0: +485,87,89207,6,0,L|493:51,3,37.4999994039535,8|0|0|0,3:0|0:0|0:0|0:0,0:0:0:0: +396,120,89429,2,0,L|411:197,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +471,317,89651,38,0,P|411:299|320:336,1,149.999997615814,0|4,3:0|0:0,0:0:0:0: +61,239,90096,2,0,P|121:221|212:258,1,149.999997615814,8|4,3:0|0:0,0:0:0:0: +367,21,90540,6,0,P|336:57|328:104,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +163,96,90762,2,0,P|194:132|202:179,1,74.999998807907,0|0,0:0|0:0,0:0:0:0: +190,346,90985,37,8,3:0:0:0: +328,272,91096,1,0,0:0:0:0: +154,272,91207,5,8,3:0:0:0: +365,338,91318,1,0,0:0:0:0: +257,382,91429,38,0,B|290:333|224:286|269:219,1,149.999997615814,4|4,3:0|0:0,0:0:0:0: +325,196,91762,1,0,0:0:0:0: +325,196,91874,2,0,P|365:210|436:184,1,112.49999821186,8|0,3:0|0:0,0:0:0:0: +430,190,92096,2,0,B|418:110,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +313,19,92318,2,0,L|190:36,1,112.49999821186,0|0,3:0|0:0,0:0:0:0: +201,34,92540,2,0,B|214:117,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +209,252,92762,5,8,3:0:0:0: +156,261,92874,1,0,0:0:0:0: +112,231,92985,1,4,0:0:0:0: +60,222,93096,1,0,0:0:0:0: +13,247,93207,38,0,P|4:288|19:328,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +173,186,93429,1,4,0:0:0:0: +215,120,93540,1,0,0:0:0:0: +162,49,93651,2,0,P|125:39|76:61,1,74.999998807907,8|0,3:0|0:0,0:0:0:0: +234,138,93874,2,0,P|273:157|313:148,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +385,39,94096,5,0,3:0:0:0: +337,286,94318,2,0,L|322:373,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +409,327,94540,2,0,P|418:277|280:230,1,224.999996423721,8|0,3:0|0:0,0:0:0:0: +239,319,94985,2,0,P|218:357|173:373,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +34,344,95207,37,4,0:0:0:0: +21,309,95318,5,0,0:0:0:0: +14,265,95429,5,8,3:0:0:0: +27,223,95540,5,0,0:0:0:0: +54,179,95651,5,4,0:0:0:0: +94,147,95762,5,0,0:0:0:0: +160,126,95873,5,0,3:0:0:0: +231,149,95984,5,0,0:0:0:0: +273,221,96096,5,4,0:0:0:0: +353,262,96207,5,0,0:0:0:0: +446,234,96318,5,8,3:0:0:0: +501,145,96429,5,0,0:0:0:0: +450,36,96540,5,4,0:0:0:0: +239,44,96762,5,0,3:0:0:0: +192,103,96873,1,0,0:0:0:0: +118,118,96984,1,4,0:0:0:0: +44,100,97096,1,0,0:0:0:0: +5,36,97207,1,8,3:0:0:0: +17,19,97429,37,4,0:0:0:0: +146,51,97540,1,0,0:0:0:0: +29,122,97651,2,0,L|39:193,1,56.2499991059302,0|0,3:0|0:0,0:0:0:0: +44,197,97874,6,0,P|100:231|176:201,1,112.500002503395,4|0,0:0|0:0,0:0:0:0: +301,160,98096,38,0,P|329:140|382:137,1,84.3750018775463,8|0,3:0|0:0,0:0:0:0: +398,147,98318,6,0,B|431:187|431:187|415:279,1,112.500002503395,4|0,0:0|0:0,0:0:0:0: +265,371,98540,38,0,L|180:361,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +127,202,98762,2,0,L|141:113,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +193,260,98985,2,0,P|144:291|68:278,1,112.49999821186,8|0,3:0|0:0,0:0:0:0: +91,290,99207,2,0,L|79:373,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +20,184,99429,6,0,B|4:141|4:141|27:66,1,112.49999821186,0|0,3:0|0:0,0:0:0:0: +23,78,99651,2,0,L|109:91,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +271,74,99874,2,0,P|254:31|222:12,1,74.999998807907,8|0,3:0|0:0,0:0:0:0: +186,180,100096,2,0,P|232:175|260:147,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +132,63,100318,37,0,3:0:0:0: +253,157,100540,1,4,0:0:0:0: +285,167,100651,1,0,0:0:0:0: +357,129,100762,5,8,3:0:0:0: +389,139,100873,1,0,0:0:0:0: +422,148,100985,2,0,P|407:200|416:233,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +459,377,101207,38,0,P|472:333|459:295,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +398,242,101429,2,0,L|314:257,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +165,354,101651,2,0,P|116:332|211:264,1,224.999996423721,8|0,3:0|0:0,0:0:0:0: +302,165,102096,6,0,L|292:89,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +392,91,102318,2,0,L|382:14,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +192,229,102540,38,0,L|212:136,1,74.999998807907,8|0,3:0|0:0,0:0:0:0: +107,172,102762,2,0,L|127:79,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +314,332,102985,6,0,L|305:278,1,37.4999994039535,0|0,3:0|0:0,0:0:0:0: +343,345,103096,2,0,L|334:291,1,37.4999994039535,0|0,0:0|0:0,0:0:0:0: +370,358,103207,2,0,L|361:304,1,37.4999994039535,4|0,0:0|0:0,0:0:0:0: +380,117,103429,38,0,L|374:75,3,37.4999994039535,8|0|0|0,3:0|0:0|0:0|0:0,0:0:0:0: +444,166,103651,2,0,P|417:188|346:191,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +392,2,103874,2,0,P|424:14|462:74,1,74.999998807907,4|0,3:0|0:0,0:0:0:0: +271,129,104096,2,0,P|265:94|298:31,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +505,113,104318,5,8,3:0:0:0: +269,217,104540,38,0,L|216:216,3,37.4999994039535,0|0|0|0,3:0|3:0|3:0|3:0,0:0:0:0: +360,220,104762,1,0,3:0:0:0: +296,384,104874,1,4,3:0:0:0: +102,307,105096,5,0,0:0:0:0: +102,307,105207,2,0,B|206:381|258:244|374:330,1,269.999987468719,12|0,3:0|0:0,0:0:0:0: +439,319,105651,6,0,P|379:336|396:236,1,168.750003755093,0|0,3:0|0:0,0:0:0:0: +373,258,106096,6,0,P|374:315|443:283,1,112.500002503395,8|0,3:0|0:0,0:0:0:0: +420,323,106651,37,0,0:0:0:0: +469,245,106763,1,4,0:0:0:0: +508,322,106874,1,0,0:0:0:0: +379,245,106985,1,8,3:0:0:0: +483,105,107207,6,0,L|474:40,3,56.2500012516975,4|0|0|0,3:0|0:0|0:0|0:0,0:0:0:0: +462,30,107429,38,0,P|401:56|319:25,1,149.999997615814,0|0,3:0|0:0,0:0:0:0: +272,120,107874,2,0,P|184:91|118:125,1,149.999997615814,8|4,3:0|0:0,0:0:0:0: +103,213,108207,2,0,B|128:232|128:232|269:200,1,149.999997615814,0|0,0:0|0:0,0:0:0:0: +393,187,108540,2,0,L|385:286,1,74.999998807907,4|0,0:0|0:0,0:0:0:0: +333,338,108763,1,8,3:0:0:0: +467,307,108874,6,0,L|509:297,2,37.4999994039535,0|0|4,0:0|0:0|0:0,0:0:0:0: +409,380,109096,1,0,0:0:0:0: +300,257,109207,38,0,P|279:218|281:171,1,74.999998807907,0|0,3:0|0:0,0:0:0:0: +401,118,109429,1,4,0:0:0:0: +401,118,109651,6,0,L|315:109,1,74.999998807907,8|4,3:0|0:0,0:0:0:0: +256,15,109985,37,0,0:0:0:0: +175,121,110096,2,0,P|162:60|109:16,1,112.49999821186,0|0,3:0|0:0,0:0:0:0: +128,26,110318,2,0,P|106:86|47:122,1,112.49999821186,0|0,0:0|0:0,0:0:0:0: +69,114,110540,2,0,P|135:105|185:131,1,112.49999821186,8|0,3:0|0:0,0:0:0:0: +160,223,110762,6,0,B|142:230|142:230|120:228|120:228|95:239|95:239|71:235|71:235|49:244|49:244|22:249,1,112.500002503395,4|0,0:0|0:0,0:0:0:0: +193,334,110985,38,0,P|216:310|242:301,1,56.2500012516975,0|0,3:0|0:0,0:0:0:0: +335,325,111207,2,0,P|366:353|378:379,1,56.2500012516975,0|0,0:0|0:0,0:0:0:0: +273,383,111429,2,0,L|304:213,1,168.750003755093,0|0,0:0|0:0,0:0:0:0: +383,255,111874,22,0,B|422:273|422:273|476:273,1,74.999998807907,8|0,3:0|3:0,0:0:0:0: +209,219,112096,2,0,B|169:221|169:221|131:206,1,74.999998807907,0|0,0:0|0:0,0:0:0:0: +403,147,112318,2,0,B|352:114|352:114|337:43|337:43|295:109|295:109|234:115,1,269.999987468719,8|0,3:0|0:0,0:0:0:0: diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2593923-expected-conversion.json b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2593923-expected-conversion.json new file mode 100644 index 000000000000..4eb70e836b90 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2593923-expected-conversion.json @@ -0,0 +1 @@ +{"Mappings":[{"StartTime":1433.0,"Objects":[{"StartTime":1433.0,"EndTime":1433.0,"X":493.0,"Y":304.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":1595.0,"EndTime":1595.0,"X":482.0946,"Y":367.449646,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":1721.0,"EndTime":1721.0,"X":493.0,"Y":304.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":1919.0,"Objects":[{"StartTime":1919.0,"EndTime":1919.0,"X":442.0,"Y":244.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":2081.0,"EndTime":2081.0,"X":431.959137,"Y":180.4078,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":2207.0,"EndTime":2207.0,"X":442.0,"Y":244.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":2405.0,"Objects":[{"StartTime":2405.0,"EndTime":2405.0,"X":394.0,"Y":304.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":2531.0,"EndTime":2531.0,"X":335.6331,"Y":323.993469,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":2730.0,"Objects":[{"StartTime":2730.0,"EndTime":2730.0,"X":277.0,"Y":272.0}]},{"StartTime":2892.0,"Objects":[{"StartTime":2892.0,"EndTime":2892.0,"X":183.0,"Y":169.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":3018.0,"EndTime":3018.0,"X":194.8645,"Y":105.722687,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":3216.0,"Objects":[{"StartTime":3216.0,"EndTime":3216.0,"X":257.0,"Y":66.0}]},{"StartTime":3378.0,"Objects":[{"StartTime":3378.0,"EndTime":3378.0,"X":178.0,"Y":178.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":3666.0,"EndTime":3666.0,"X":63.2089653,"Y":223.380814,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":3865.0,"Objects":[{"StartTime":3865.0,"EndTime":3865.0,"X":196.0,"Y":303.0}]},{"StartTime":4027.0,"Objects":[{"StartTime":4027.0,"EndTime":4027.0,"X":53.0,"Y":214.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":4351.0,"EndTime":4351.0,"X":168.013245,"Y":216.502319,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":4513.0,"EndTime":4513.0,"X":188.218781,"Y":275.762878,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":4675.0,"EndTime":4675.0,"X":168.013245,"Y":216.502319,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":4963.0,"EndTime":4963.0,"X":53.0,"Y":214.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":5162.0,"Objects":[{"StartTime":5162.0,"EndTime":5162.0,"X":194.0,"Y":105.0}]},{"StartTime":5324.0,"Objects":[{"StartTime":5324.0,"EndTime":5324.0,"X":31.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":5612.0,"EndTime":5612.0,"X":133.993271,"Y":43.15782,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":5811.0,"Objects":[{"StartTime":5811.0,"EndTime":5811.0,"X":257.0,"Y":153.0}]},{"StartTime":5973.0,"Objects":[{"StartTime":5973.0,"EndTime":5973.0,"X":311.0,"Y":30.0}]},{"StartTime":6135.0,"Objects":[{"StartTime":6135.0,"EndTime":6135.0,"X":146.0,"Y":171.0}]},{"StartTime":6297.0,"Objects":[{"StartTime":6297.0,"EndTime":6297.0,"X":320.0,"Y":103.0}]},{"StartTime":6460.0,"Objects":[{"StartTime":6460.0,"EndTime":6460.0,"X":428.0,"Y":231.0}]},{"StartTime":6622.0,"Objects":[{"StartTime":6622.0,"EndTime":6622.0,"X":469.0,"Y":166.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":6946.0,"EndTime":6946.0,"X":351.395355,"Y":178.384933,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":7072.0,"EndTime":7072.0,"X":326.584534,"Y":236.296982,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7270.0,"Objects":[{"StartTime":7270.0,"EndTime":7270.0,"X":234.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":7396.0,"EndTime":7396.0,"X":295.6874,"Y":361.119446,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7595.0,"Objects":[{"StartTime":7595.0,"EndTime":7595.0,"X":155.0,"Y":291.0}]},{"StartTime":7757.0,"Objects":[{"StartTime":7757.0,"EndTime":7757.0,"X":326.88028,"Y":236.88028}]},{"StartTime":7838.0,"Objects":[{"StartTime":7838.0,"EndTime":7838.0,"X":330.440155,"Y":240.44014}]},{"StartTime":7919.0,"Objects":[{"StartTime":7919.0,"EndTime":7919.0,"X":334.0,"Y":244.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":8243.0,"EndTime":8243.0,"X":217.1122,"Y":283.230347,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":8369.0,"EndTime":8369.0,"X":154.385681,"Y":290.712372,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":8568.0,"Objects":[{"StartTime":8568.0,"EndTime":8568.0,"X":43.0,"Y":93.0}]},{"StartTime":8730.0,"Objects":[{"StartTime":8730.0,"EndTime":8730.0,"X":213.0,"Y":180.0}]},{"StartTime":8892.0,"Objects":[{"StartTime":8892.0,"EndTime":8892.0,"X":50.0,"Y":278.0}]},{"StartTime":9054.0,"Objects":[{"StartTime":9054.0,"EndTime":9054.0,"X":179.0,"Y":92.0}]},{"StartTime":9216.0,"Objects":[{"StartTime":9216.0,"EndTime":9216.0,"X":298.440155,"Y":318.440155}]},{"StartTime":9541.0,"Objects":[{"StartTime":9541.0,"EndTime":9541.0,"X":302.0,"Y":322.0}]},{"StartTime":9703.0,"Objects":[{"StartTime":9703.0,"EndTime":9703.0,"X":213.0,"Y":180.0}]},{"StartTime":9865.0,"Objects":[{"StartTime":9865.0,"EndTime":9865.0,"X":156.0,"Y":290.0}]},{"StartTime":10027.0,"Objects":[{"StartTime":10027.0,"EndTime":10027.0,"X":276.0,"Y":88.0}]},{"StartTime":10189.0,"Objects":[{"StartTime":10189.0,"EndTime":10189.0,"X":370.0,"Y":237.0}]},{"StartTime":10351.0,"Objects":[{"StartTime":10351.0,"EndTime":10351.0,"X":179.0,"Y":92.0}]},{"StartTime":10514.0,"Objects":[{"StartTime":10514.0,"EndTime":10514.0,"X":327.0,"Y":10.0}]},{"StartTime":10676.0,"Objects":[{"StartTime":10676.0,"EndTime":10676.0,"X":239.0,"Y":267.0}]},{"StartTime":10838.0,"Objects":[{"StartTime":10838.0,"EndTime":10838.0,"X":92.0,"Y":0.0}]},{"StartTime":11000.0,"Objects":[{"StartTime":11000.0,"EndTime":11000.0,"X":360.0,"Y":142.0}]},{"StartTime":11162.0,"Objects":[{"StartTime":11162.0,"EndTime":11162.0,"X":17.0,"Y":198.0}]},{"StartTime":11324.0,"Objects":[{"StartTime":11324.0,"EndTime":11324.0,"X":327.0,"Y":10.0}]},{"StartTime":11487.0,"Objects":[{"StartTime":11487.0,"EndTime":11487.0,"X":213.0,"Y":180.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":11694.0,"EndTime":11694.0,"X":203.7394,"Y":124.416283,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":11811.0,"Objects":[{"StartTime":11811.0,"EndTime":11811.0,"X":179.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":12099.0,"EndTime":12099.0,"X":360.0068,"Y":142.989914,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":12297.0,"Objects":[{"StartTime":12297.0,"EndTime":12297.0,"X":161.0,"Y":247.0}]},{"StartTime":12460.0,"Objects":[{"StartTime":12460.0,"EndTime":12460.0,"X":333.0,"Y":351.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":12586.0,"EndTime":12586.0,"X":237.9624,"Y":377.402344,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":12784.0,"Objects":[{"StartTime":12784.0,"EndTime":12784.0,"X":355.440155,"Y":230.44014,"StackOffset":{"X":-3.559845,"Y":-3.55986023}},{"StartTime":12991.0,"EndTime":12991.0,"X":475.1857,"Y":275.841736,"StackOffset":{"X":-3.559845,"Y":-3.55986023}}]},{"StartTime":13108.0,"Objects":[{"StartTime":13108.0,"EndTime":13108.0,"X":478.0,"Y":279.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":13234.0,"EndTime":13234.0,"X":465.9604,"Y":377.18808,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":13432.0,"Objects":[{"StartTime":13432.0,"EndTime":13432.0,"X":262.0,"Y":177.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":13558.0,"EndTime":13558.0,"X":276.4605,"Y":275.036957,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":13757.0,"Objects":[{"StartTime":13757.0,"EndTime":13757.0,"X":462.0,"Y":114.0}]},{"StartTime":13919.0,"Objects":[{"StartTime":13919.0,"EndTime":13919.0,"X":330.0,"Y":16.0}]},{"StartTime":14081.0,"Objects":[{"StartTime":14081.0,"EndTime":14081.0,"X":424.0,"Y":194.0}]},{"StartTime":14243.0,"Objects":[{"StartTime":14243.0,"EndTime":14243.0,"X":492.88028,"Y":18.8802814}]},{"StartTime":14324.0,"Objects":[{"StartTime":14324.0,"EndTime":14324.0,"X":496.440155,"Y":22.4401417}]},{"StartTime":14405.0,"Objects":[{"StartTime":14405.0,"EndTime":14405.0,"X":500.0,"Y":26.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":14693.0,"EndTime":14693.0,"X":329.573761,"Y":91.81665,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":14892.0,"Objects":[{"StartTime":14892.0,"EndTime":14892.0,"X":194.0,"Y":239.0}]},{"StartTime":15054.0,"Objects":[{"StartTime":15054.0,"EndTime":15054.0,"X":145.0,"Y":179.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":15180.0,"EndTime":15180.0,"X":162.32164,"Y":81.54735,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":15378.0,"Objects":[{"StartTime":15378.0,"EndTime":15378.0,"X":334.0,"Y":205.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":15585.0,"EndTime":15585.0,"X":351.839874,"Y":352.5982,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":15703.0,"Objects":[{"StartTime":15703.0,"EndTime":15703.0,"X":280.0,"Y":384.0}]},{"StartTime":15865.0,"Objects":[{"StartTime":15865.0,"EndTime":15865.0,"X":428.0,"Y":267.0}]},{"StartTime":16027.0,"Objects":[{"StartTime":16027.0,"EndTime":16027.0,"X":267.0,"Y":152.0}]},{"StartTime":16189.0,"Objects":[{"StartTime":16189.0,"EndTime":16189.0,"X":435.0,"Y":350.0}]},{"StartTime":16351.0,"Objects":[{"StartTime":16351.0,"EndTime":16351.0,"X":512.0,"Y":117.0}]},{"StartTime":16514.0,"Objects":[{"StartTime":16514.0,"EndTime":16514.0,"X":317.0,"Y":254.0}]},{"StartTime":16595.0,"Objects":[{"StartTime":16595.0,"EndTime":16595.0,"X":274.0,"Y":268.0}]},{"StartTime":16676.0,"Objects":[{"StartTime":16676.0,"EndTime":16676.0,"X":231.0,"Y":240.0}]},{"StartTime":16757.0,"Objects":[{"StartTime":16757.0,"EndTime":16757.0,"X":225.0,"Y":184.0}]},{"StartTime":16838.0,"Objects":[{"StartTime":16838.0,"EndTime":16838.0,"X":267.0,"Y":152.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":16883.0,"EndTime":16883.0,"X":314.118317,"Y":167.4607,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":17000.0,"Objects":[{"StartTime":17000.0,"EndTime":17000.0,"X":163.0,"Y":356.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":17288.0,"EndTime":17288.0,"X":90.0459442,"Y":235.082169,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":17487.0,"Objects":[{"StartTime":17487.0,"EndTime":17487.0,"X":267.0,"Y":152.0}]},{"StartTime":17649.0,"Objects":[{"StartTime":17649.0,"EndTime":17649.0,"X":133.0,"Y":23.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":17775.0,"EndTime":17775.0,"X":149.881119,"Y":120.732796,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":17973.0,"Objects":[{"StartTime":17973.0,"EndTime":17973.0,"X":355.0,"Y":312.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18180.0,"EndTime":18180.0,"X":388.59436,"Y":206.28183,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18297.0,"Objects":[{"StartTime":18297.0,"EndTime":18297.0,"X":345.0,"Y":146.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18585.0,"EndTime":18585.0,"X":167.093735,"Y":210.64801,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18784.0,"Objects":[{"StartTime":18784.0,"EndTime":18784.0,"X":381.0,"Y":76.0}]},{"StartTime":18946.0,"Objects":[{"StartTime":18946.0,"EndTime":18946.0,"X":234.0,"Y":23.0}]},{"StartTime":19108.0,"Objects":[{"StartTime":19108.0,"EndTime":19108.0,"X":316.0,"Y":229.0}]},{"StartTime":19270.0,"Objects":[{"StartTime":19270.0,"EndTime":19270.0,"X":456.0,"Y":47.0}]},{"StartTime":19432.0,"Objects":[{"StartTime":19432.0,"EndTime":19432.0,"X":243.0,"Y":135.0}]},{"StartTime":19514.0,"Objects":[{"StartTime":19514.0,"EndTime":19514.0,"X":247.0,"Y":124.0}]},{"StartTime":19595.0,"Objects":[{"StartTime":19595.0,"EndTime":19595.0,"X":252.0,"Y":115.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19721.0,"EndTime":19721.0,"X":345.13028,"Y":145.5859,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19919.0,"Objects":[{"StartTime":19919.0,"EndTime":19919.0,"X":477.0,"Y":348.0}]},{"StartTime":20081.0,"Objects":[{"StartTime":20081.0,"EndTime":20081.0,"X":316.0,"Y":229.0}]},{"StartTime":20243.0,"Objects":[{"StartTime":20243.0,"EndTime":20243.0,"X":490.0,"Y":131.0}]},{"StartTime":20405.0,"Objects":[{"StartTime":20405.0,"EndTime":20405.0,"X":350.0,"Y":315.0}]},{"StartTime":20487.0,"Objects":[{"StartTime":20487.0,"EndTime":20487.0,"X":331.0,"Y":326.0}]},{"StartTime":20568.0,"Objects":[{"StartTime":20568.0,"EndTime":20568.0,"X":307.0,"Y":324.0}]},{"StartTime":20730.0,"Objects":[{"StartTime":20730.0,"EndTime":20730.0,"X":149.44014,"Y":172.44014}]},{"StartTime":21054.0,"Objects":[{"StartTime":21054.0,"EndTime":21054.0,"X":153.0,"Y":176.0}]},{"StartTime":21216.0,"Objects":[{"StartTime":21216.0,"EndTime":21216.0,"X":216.0,"Y":241.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21504.0,"EndTime":21504.0,"X":195.1709,"Y":367.652924,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21703.0,"Objects":[{"StartTime":21703.0,"EndTime":21703.0,"X":69.0,"Y":222.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21829.0,"EndTime":21829.0,"X":81.0571747,"Y":285.124634,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22189.0,"Objects":[{"StartTime":22189.0,"EndTime":22189.0,"X":109.0,"Y":82.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22513.0,"EndTime":22513.0,"X":4.257408,"Y":47.9354248,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22801.0,"EndTime":22801.0,"X":109.0,"Y":82.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23000.0,"Objects":[{"StartTime":23000.0,"EndTime":23000.0,"X":172.0,"Y":127.0}]},{"StartTime":23162.0,"Objects":[{"StartTime":23162.0,"EndTime":23162.0,"X":277.0,"Y":0.0}]},{"StartTime":23324.0,"Objects":[{"StartTime":23324.0,"EndTime":23324.0,"X":209.0,"Y":33.0}]},{"StartTime":23487.0,"Objects":[{"StartTime":23487.0,"EndTime":23487.0,"X":330.0,"Y":148.0}]},{"StartTime":23649.0,"Objects":[{"StartTime":23649.0,"EndTime":23649.0,"X":379.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23775.0,"EndTime":23775.0,"X":361.026459,"Y":30.37888,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23973.0,"Objects":[{"StartTime":23973.0,"EndTime":23973.0,"X":230.0,"Y":185.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":24261.0,"EndTime":24261.0,"X":211.478638,"Y":312.3779,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":24460.0,"Objects":[{"StartTime":24460.0,"EndTime":24460.0,"X":57.0,"Y":132.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":24586.0,"EndTime":24586.0,"X":67.68643,"Y":195.35968,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":24784.0,"Objects":[{"StartTime":24784.0,"EndTime":24784.0,"X":0.0,"Y":365.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25072.0,"EndTime":25072.0,"X":104.24324,"Y":330.343933,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25432.0,"Objects":[{"StartTime":25432.0,"EndTime":25432.0,"X":352.0,"Y":146.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25720.0,"EndTime":25720.0,"X":229.388351,"Y":184.353943,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25919.0,"Objects":[{"StartTime":25919.0,"EndTime":25919.0,"X":346.0,"Y":306.0}]},{"StartTime":26081.0,"Objects":[{"StartTime":26081.0,"EndTime":26081.0,"X":283.0,"Y":346.0}]},{"StartTime":26243.0,"Objects":[{"StartTime":26243.0,"EndTime":26243.0,"X":352.0,"Y":229.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26369.0,"EndTime":26369.0,"X":412.114777,"Y":251.14682,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26568.0,"Objects":[{"StartTime":26568.0,"EndTime":26568.0,"X":257.0,"Y":75.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26856.0,"EndTime":26856.0,"X":229.16745,"Y":182.521591,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27054.0,"Objects":[{"StartTime":27054.0,"EndTime":27054.0,"X":401.0,"Y":73.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27180.0,"EndTime":27180.0,"X":389.483368,"Y":9.658455,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27378.0,"Objects":[{"StartTime":27378.0,"EndTime":27378.0,"X":486.0,"Y":170.0}]},{"StartTime":27541.0,"Objects":[{"StartTime":27541.0,"EndTime":27541.0,"X":291.88028,"Y":67.88028}]},{"StartTime":27622.0,"Objects":[{"StartTime":27622.0,"EndTime":27622.0,"X":295.440155,"Y":71.44014}]},{"StartTime":27703.0,"Objects":[{"StartTime":27703.0,"EndTime":27703.0,"X":299.0,"Y":75.0}]},{"StartTime":27865.0,"Objects":[{"StartTime":27865.0,"EndTime":27865.0,"X":352.0,"Y":229.0}]},{"StartTime":28027.0,"Objects":[{"StartTime":28027.0,"EndTime":28027.0,"X":480.88028,"Y":83.88028}]},{"StartTime":28108.0,"Objects":[{"StartTime":28108.0,"EndTime":28108.0,"X":484.440155,"Y":87.44014}]},{"StartTime":28189.0,"Objects":[{"StartTime":28189.0,"EndTime":28189.0,"X":488.0,"Y":91.0}]},{"StartTime":28351.0,"Objects":[{"StartTime":28351.0,"EndTime":28351.0,"X":302.0,"Y":157.0}]},{"StartTime":28514.0,"Objects":[{"StartTime":28514.0,"EndTime":28514.0,"X":492.0,"Y":249.0}]},{"StartTime":28676.0,"Objects":[{"StartTime":28676.0,"EndTime":28676.0,"X":249.0,"Y":350.0}]},{"StartTime":28838.0,"Objects":[{"StartTime":28838.0,"EndTime":28838.0,"X":351.88028,"Y":230.88028}]},{"StartTime":28919.0,"Objects":[{"StartTime":28919.0,"EndTime":28919.0,"X":355.440155,"Y":234.44014}]},{"StartTime":29000.0,"Objects":[{"StartTime":29000.0,"EndTime":29000.0,"X":359.0,"Y":238.0}]},{"StartTime":29162.0,"Objects":[{"StartTime":29162.0,"EndTime":29162.0,"X":399.0,"Y":383.0}]},{"StartTime":29324.0,"Objects":[{"StartTime":29324.0,"EndTime":29324.0,"X":216.88028,"Y":239.88028}]},{"StartTime":29405.0,"Objects":[{"StartTime":29405.0,"EndTime":29405.0,"X":220.44014,"Y":243.44014}]},{"StartTime":29487.0,"Objects":[{"StartTime":29487.0,"EndTime":29487.0,"X":224.0,"Y":247.0}]},{"StartTime":29649.0,"Objects":[{"StartTime":29649.0,"EndTime":29649.0,"X":370.0,"Y":257.0}]},{"StartTime":29811.0,"Objects":[{"StartTime":29811.0,"EndTime":29811.0,"X":159.0,"Y":384.0}]},{"StartTime":29973.0,"Objects":[{"StartTime":29973.0,"EndTime":29973.0,"X":329.0,"Y":329.0}]},{"StartTime":30135.0,"Objects":[{"StartTime":30135.0,"EndTime":30135.0,"X":217.0,"Y":278.0}]},{"StartTime":30297.0,"Objects":[{"StartTime":30297.0,"EndTime":30297.0,"X":254.0,"Y":376.0}]},{"StartTime":30460.0,"Objects":[{"StartTime":30460.0,"EndTime":30460.0,"X":340.0,"Y":232.0}]},{"StartTime":30622.0,"Objects":[{"StartTime":30622.0,"EndTime":30622.0,"X":176.0,"Y":159.0}]},{"StartTime":30784.0,"Objects":[{"StartTime":30784.0,"EndTime":30784.0,"X":329.0,"Y":329.0}]},{"StartTime":30946.0,"Objects":[{"StartTime":30946.0,"EndTime":30946.0,"X":124.0,"Y":235.0}]},{"StartTime":31108.0,"Objects":[{"StartTime":31108.0,"EndTime":31108.0,"X":390.0,"Y":102.0}]},{"StartTime":31270.0,"Objects":[{"StartTime":31270.0,"EndTime":31270.0,"X":254.0,"Y":376.0}]},{"StartTime":31432.0,"Objects":[{"StartTime":31432.0,"EndTime":31432.0,"X":176.0,"Y":36.0}]},{"StartTime":32081.0,"Objects":[{"StartTime":32081.0,"EndTime":32081.0,"X":11.0,"Y":207.0}]},{"StartTime":32162.0,"Objects":[{"StartTime":32162.0,"EndTime":32162.0,"X":9.0,"Y":195.0}]},{"StartTime":32243.0,"Objects":[{"StartTime":32243.0,"EndTime":32243.0,"X":12.0,"Y":183.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32450.0,"EndTime":32450.0,"X":165.248047,"Y":205.856049,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32568.0,"Objects":[{"StartTime":32568.0,"EndTime":32568.0,"X":230.0,"Y":258.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32694.0,"EndTime":32694.0,"X":241.458481,"Y":338.973267,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32892.0,"Objects":[{"StartTime":32892.0,"EndTime":32892.0,"X":412.0,"Y":228.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33018.0,"EndTime":33018.0,"X":427.511627,"Y":147.704559,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33216.0,"Objects":[{"StartTime":33216.0,"EndTime":33216.0,"X":289.0,"Y":55.0}]},{"StartTime":33378.0,"Objects":[{"StartTime":33378.0,"EndTime":33378.0,"X":307.0,"Y":126.0}]},{"StartTime":33541.0,"Objects":[{"StartTime":33541.0,"EndTime":33541.0,"X":420.0,"Y":29.0}]},{"StartTime":33703.0,"Objects":[{"StartTime":33703.0,"EndTime":33703.0,"X":356.0,"Y":0.0}]},{"StartTime":33865.0,"Objects":[{"StartTime":33865.0,"EndTime":33865.0,"X":228.0,"Y":103.0}]},{"StartTime":34027.0,"Objects":[{"StartTime":34027.0,"EndTime":34027.0,"X":169.0,"Y":156.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34153.0,"EndTime":34153.0,"X":89.55082,"Y":173.8051,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34351.0,"Objects":[{"StartTime":34351.0,"EndTime":34351.0,"X":225.0,"Y":321.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34558.0,"EndTime":34558.0,"X":330.9766,"Y":360.775024,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34676.0,"Objects":[{"StartTime":34676.0,"EndTime":34676.0,"X":394.0,"Y":318.0}]},{"StartTime":34838.0,"Objects":[{"StartTime":34838.0,"EndTime":34838.0,"X":456.0,"Y":156.0}]},{"StartTime":35000.0,"Objects":[{"StartTime":35000.0,"EndTime":35000.0,"X":387.0,"Y":182.0}]},{"StartTime":35162.0,"Objects":[{"StartTime":35162.0,"EndTime":35162.0,"X":491.0,"Y":363.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35288.0,"EndTime":35288.0,"X":500.417938,"Y":282.124268,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35487.0,"Objects":[{"StartTime":35487.0,"EndTime":35487.0,"X":302.0,"Y":149.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35613.0,"EndTime":35613.0,"X":313.509155,"Y":229.585571,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35811.0,"Objects":[{"StartTime":35811.0,"EndTime":35811.0,"X":456.0,"Y":63.0}]},{"StartTime":35973.0,"Objects":[{"StartTime":35973.0,"EndTime":35973.0,"X":386.0,"Y":37.0}]},{"StartTime":36135.0,"Objects":[{"StartTime":36135.0,"EndTime":36135.0,"X":456.0,"Y":156.0}]},{"StartTime":36297.0,"Objects":[{"StartTime":36297.0,"EndTime":36297.0,"X":387.0,"Y":182.0}]},{"StartTime":36460.0,"Objects":[{"StartTime":36460.0,"EndTime":36460.0,"X":456.0,"Y":63.0}]},{"StartTime":36622.0,"Objects":[{"StartTime":36622.0,"EndTime":36622.0,"X":302.0,"Y":149.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36748.0,"EndTime":36748.0,"X":231.357132,"Y":120.073067,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36946.0,"Objects":[{"StartTime":36946.0,"EndTime":36946.0,"X":127.0,"Y":34.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37234.0,"EndTime":37234.0,"X":104.682526,"Y":195.795059,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":37432.0,"Objects":[{"StartTime":37432.0,"EndTime":37432.0,"X":229.0,"Y":33.0}]},{"StartTime":37595.0,"Objects":[{"StartTime":37595.0,"EndTime":37595.0,"X":-7.119718,"Y":148.88028}]},{"StartTime":37676.0,"Objects":[{"StartTime":37676.0,"EndTime":37676.0,"X":-3.559859,"Y":152.44014}]},{"StartTime":37757.0,"Objects":[{"StartTime":37757.0,"EndTime":37757.0,"X":0.0,"Y":156.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38045.0,"EndTime":38045.0,"X":105.247383,"Y":196.403824,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38243.0,"Objects":[{"StartTime":38243.0,"EndTime":38243.0,"X":223.0,"Y":324.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38369.0,"EndTime":38369.0,"X":145.465851,"Y":298.830627,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38568.0,"Objects":[{"StartTime":38568.0,"EndTime":38568.0,"X":261.0,"Y":217.0}]},{"StartTime":38730.0,"Objects":[{"StartTime":38730.0,"EndTime":38730.0,"X":105.0,"Y":196.0}]},{"StartTime":38892.0,"Objects":[{"StartTime":38892.0,"EndTime":38892.0,"X":159.0,"Y":384.0}]},{"StartTime":39054.0,"Objects":[{"StartTime":39054.0,"EndTime":39054.0,"X":57.0,"Y":263.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":39180.0,"EndTime":39180.0,"X":44.4304,"Y":343.747,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":39378.0,"Objects":[{"StartTime":39378.0,"EndTime":39378.0,"X":185.0,"Y":183.0}]},{"StartTime":39541.0,"Objects":[{"StartTime":39541.0,"EndTime":39541.0,"X":344.0,"Y":308.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":39829.0,"EndTime":39829.0,"X":326.713867,"Y":145.787735,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":40027.0,"Objects":[{"StartTime":40027.0,"EndTime":40027.0,"X":223.0,"Y":324.0}]},{"StartTime":40189.0,"Objects":[{"StartTime":40189.0,"EndTime":40189.0,"X":436.0,"Y":193.0}]},{"StartTime":40351.0,"Objects":[{"StartTime":40351.0,"EndTime":40351.0,"X":244.0,"Y":93.0}]},{"StartTime":40514.0,"Objects":[{"StartTime":40514.0,"EndTime":40514.0,"X":413.88028,"Y":280.88028}]},{"StartTime":40595.0,"Objects":[{"StartTime":40595.0,"EndTime":40595.0,"X":417.440155,"Y":284.440155}]},{"StartTime":40676.0,"Objects":[{"StartTime":40676.0,"EndTime":40676.0,"X":421.0,"Y":288.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":40883.0,"EndTime":40883.0,"X":343.534119,"Y":307.5015,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41000.0,"Objects":[{"StartTime":41000.0,"EndTime":41000.0,"X":103.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41288.0,"EndTime":41288.0,"X":199.702286,"Y":178.3348,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41487.0,"Objects":[{"StartTime":41487.0,"EndTime":41487.0,"X":410.88028,"Y":12.8802814}]},{"StartTime":41568.0,"Objects":[{"StartTime":41568.0,"EndTime":41568.0,"X":414.440155,"Y":16.4401417}]},{"StartTime":41649.0,"Objects":[{"StartTime":41649.0,"EndTime":41649.0,"X":418.0,"Y":20.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41856.0,"EndTime":41856.0,"X":316.865723,"Y":65.63147,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41973.0,"Objects":[{"StartTime":41973.0,"EndTime":41973.0,"X":375.0,"Y":116.0}]},{"StartTime":42135.0,"Objects":[{"StartTime":42135.0,"EndTime":42135.0,"X":181.0,"Y":32.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42261.0,"EndTime":42261.0,"X":80.84002,"Y":-0.0190725327,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42460.0,"Objects":[{"StartTime":42460.0,"EndTime":42460.0,"X":280.0,"Y":169.0}]},{"StartTime":42622.0,"Objects":[{"StartTime":42622.0,"EndTime":42622.0,"X":78.0,"Y":332.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42829.0,"EndTime":42829.0,"X":123.77272,"Y":225.780655,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42946.0,"Objects":[{"StartTime":42946.0,"EndTime":42946.0,"X":189.0,"Y":264.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42991.0,"EndTime":42991.0,"X":240.3147,"Y":280.623077,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":43108.0,"Objects":[{"StartTime":43108.0,"EndTime":43108.0,"X":381.0,"Y":384.0}]},{"StartTime":43270.0,"Objects":[{"StartTime":43270.0,"EndTime":43270.0,"X":444.0,"Y":339.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43396.0,"EndTime":43396.0,"X":455.20694,"Y":284.4595,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":43595.0,"Objects":[{"StartTime":43595.0,"EndTime":43595.0,"X":280.0,"Y":169.0}]},{"StartTime":43757.0,"Objects":[{"StartTime":43757.0,"EndTime":43757.0,"X":397.440155,"Y":165.44014}]},{"StartTime":43919.0,"Objects":[{"StartTime":43919.0,"EndTime":43919.0,"X":240.0,"Y":280.0}]},{"StartTime":44081.0,"Objects":[{"StartTime":44081.0,"EndTime":44081.0,"X":401.0,"Y":169.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44369.0,"EndTime":44369.0,"X":323.41684,"Y":41.0436325,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44568.0,"Objects":[{"StartTime":44568.0,"EndTime":44568.0,"X":455.0,"Y":284.0}]},{"StartTime":44730.0,"Objects":[{"StartTime":44730.0,"EndTime":44730.0,"X":280.0,"Y":169.0}]},{"StartTime":44892.0,"Objects":[{"StartTime":44892.0,"EndTime":44892.0,"X":446.0,"Y":58.0}]},{"StartTime":45054.0,"Objects":[{"StartTime":45054.0,"EndTime":45054.0,"X":313.88028,"Y":237.88028}]},{"StartTime":45135.0,"Objects":[{"StartTime":45135.0,"EndTime":45135.0,"X":317.440155,"Y":241.44014}]},{"StartTime":45216.0,"Objects":[{"StartTime":45216.0,"EndTime":45216.0,"X":321.0,"Y":245.0}]},{"StartTime":45378.0,"Objects":[{"StartTime":45378.0,"EndTime":45378.0,"X":224.0,"Y":19.0}]},{"StartTime":45541.0,"Objects":[{"StartTime":45541.0,"EndTime":45541.0,"X":401.0,"Y":169.0}]},{"StartTime":45703.0,"Objects":[{"StartTime":45703.0,"EndTime":45703.0,"X":144.0,"Y":285.0}]},{"StartTime":45865.0,"Objects":[{"StartTime":45865.0,"EndTime":45865.0,"X":98.0,"Y":221.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":45991.0,"EndTime":45991.0,"X":108.747459,"Y":166.3671,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":46108.0,"Objects":[{"StartTime":46108.0,"EndTime":46108.0,"X":127.0,"Y":95.0}]},{"StartTime":46189.0,"Objects":[{"StartTime":46189.0,"EndTime":46189.0,"X":130.0,"Y":81.0}]},{"StartTime":46351.0,"Objects":[{"StartTime":46351.0,"EndTime":46351.0,"X":0.0,"Y":173.0}]},{"StartTime":46514.0,"Objects":[{"StartTime":46514.0,"EndTime":46514.0,"X":133.0,"Y":68.0}]},{"StartTime":46676.0,"Objects":[{"StartTime":46676.0,"EndTime":46676.0,"X":273.0,"Y":240.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":46883.0,"EndTime":46883.0,"X":143.723663,"Y":284.335815,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":47000.0,"Objects":[{"StartTime":47000.0,"EndTime":47000.0,"X":98.0,"Y":221.0}]},{"StartTime":47162.0,"Objects":[{"StartTime":47162.0,"EndTime":47162.0,"X":278.0,"Y":94.0}]},{"StartTime":47324.0,"Objects":[{"StartTime":47324.0,"EndTime":47324.0,"X":216.0,"Y":52.0}]},{"StartTime":47487.0,"Objects":[{"StartTime":47487.0,"EndTime":47487.0,"X":325.0,"Y":319.0}]},{"StartTime":47649.0,"Objects":[{"StartTime":47649.0,"EndTime":47649.0,"X":193.0,"Y":209.0}]},{"StartTime":47730.0,"Objects":[{"StartTime":47730.0,"EndTime":47730.0,"X":195.0,"Y":195.0}]},{"StartTime":47811.0,"Objects":[{"StartTime":47811.0,"EndTime":47811.0,"X":198.0,"Y":180.0}]},{"StartTime":47973.0,"Objects":[{"StartTime":47973.0,"EndTime":47973.0,"X":356.0,"Y":70.0}]},{"StartTime":48135.0,"Objects":[{"StartTime":48135.0,"EndTime":48135.0,"X":424.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48261.0,"EndTime":48261.0,"X":437.1501,"Y":190.887146,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":48378.0,"Objects":[{"StartTime":48378.0,"EndTime":48378.0,"X":452.0,"Y":263.0}]},{"StartTime":48460.0,"Objects":[{"StartTime":48460.0,"EndTime":48460.0,"X":455.0,"Y":283.0}]},{"StartTime":48622.0,"Objects":[{"StartTime":48622.0,"EndTime":48622.0,"X":338.0,"Y":197.0}]},{"StartTime":48784.0,"Objects":[{"StartTime":48784.0,"EndTime":48784.0,"X":235.0,"Y":343.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48946.0,"EndTime":48946.0,"X":249.644958,"Y":271.402435,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49072.0,"EndTime":49072.0,"X":235.0,"Y":343.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49270.0,"Objects":[{"StartTime":49270.0,"EndTime":49270.0,"X":48.8802834,"Y":199.88028}]},{"StartTime":49351.0,"Objects":[{"StartTime":49351.0,"EndTime":49351.0,"X":52.44014,"Y":203.44014}]},{"StartTime":49432.0,"Objects":[{"StartTime":49432.0,"EndTime":49432.0,"X":56.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49558.0,"EndTime":49558.0,"X":127.47998,"Y":191.791489,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49676.0,"Objects":[{"StartTime":49676.0,"EndTime":49676.0,"X":198.0,"Y":180.0}]},{"StartTime":49757.0,"Objects":[{"StartTime":49757.0,"EndTime":49757.0,"X":222.0,"Y":175.0}]},{"StartTime":49919.0,"Objects":[{"StartTime":49919.0,"EndTime":49919.0,"X":344.0,"Y":84.0}]},{"StartTime":50081.0,"Objects":[{"StartTime":50081.0,"EndTime":50081.0,"X":239.0,"Y":6.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50207.0,"EndTime":50207.0,"X":249.335068,"Y":78.34551,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50405.0,"Objects":[{"StartTime":50405.0,"EndTime":50405.0,"X":385.0,"Y":177.0}]},{"StartTime":50568.0,"Objects":[{"StartTime":50568.0,"EndTime":50568.0,"X":465.88028,"Y":67.88028}]},{"StartTime":50649.0,"Objects":[{"StartTime":50649.0,"EndTime":50649.0,"X":469.440155,"Y":71.44014}]},{"StartTime":50730.0,"Objects":[{"StartTime":50730.0,"EndTime":50730.0,"X":473.0,"Y":75.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50856.0,"EndTime":50856.0,"X":464.6807,"Y":147.604919,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50973.0,"Objects":[{"StartTime":50973.0,"EndTime":50973.0,"X":453.0,"Y":220.0}]},{"StartTime":51054.0,"Objects":[{"StartTime":51054.0,"EndTime":51054.0,"X":451.0,"Y":236.0}]},{"StartTime":51216.0,"Objects":[{"StartTime":51216.0,"EndTime":51216.0,"X":321.0,"Y":132.0}]},{"StartTime":51378.0,"Objects":[{"StartTime":51378.0,"EndTime":51378.0,"X":218.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51504.0,"EndTime":51504.0,"X":289.1127,"Y":263.157532,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":51703.0,"Objects":[{"StartTime":51703.0,"EndTime":51703.0,"X":198.0,"Y":180.0}]},{"StartTime":51865.0,"Objects":[{"StartTime":51865.0,"EndTime":51865.0,"X":289.88028,"Y":264.88028}]},{"StartTime":51946.0,"Objects":[{"StartTime":51946.0,"EndTime":51946.0,"X":293.440155,"Y":268.440155}]},{"StartTime":52027.0,"Objects":[{"StartTime":52027.0,"EndTime":52027.0,"X":297.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":52153.0,"EndTime":52153.0,"X":287.091919,"Y":344.4052,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":52270.0,"Objects":[{"StartTime":52270.0,"EndTime":52270.0,"X":223.44014,"Y":380.440155}]},{"StartTime":52351.0,"Objects":[{"StartTime":52351.0,"EndTime":52351.0,"X":227.0,"Y":384.0}]},{"StartTime":52514.0,"Objects":[{"StartTime":52514.0,"EndTime":52514.0,"X":55.8802834,"Y":234.88028}]},{"StartTime":52595.0,"Objects":[{"StartTime":52595.0,"EndTime":52595.0,"X":59.44014,"Y":238.44014}]},{"StartTime":52676.0,"Objects":[{"StartTime":52676.0,"EndTime":52676.0,"X":63.0,"Y":242.0}]},{"StartTime":52757.0,"Objects":[{"StartTime":52757.0,"EndTime":52757.0,"X":91.0,"Y":196.0}]},{"StartTime":52838.0,"Objects":[{"StartTime":52838.0,"EndTime":52838.0,"X":138.0,"Y":186.0}]},{"StartTime":52919.0,"Objects":[{"StartTime":52919.0,"EndTime":52919.0,"X":186.0,"Y":209.0}]},{"StartTime":53000.0,"Objects":[{"StartTime":53000.0,"EndTime":53000.0,"X":187.0,"Y":230.0}]},{"StartTime":53081.0,"Objects":[{"StartTime":53081.0,"EndTime":53081.0,"X":234.0,"Y":278.0}]},{"StartTime":53162.0,"Objects":[{"StartTime":53162.0,"EndTime":53162.0,"X":297.0,"Y":272.0}]},{"StartTime":53243.0,"Objects":[{"StartTime":53243.0,"EndTime":53243.0,"X":330.0,"Y":217.0}]},{"StartTime":53324.0,"Objects":[{"StartTime":53324.0,"EndTime":53324.0,"X":291.440155,"Y":157.44014}]},{"StartTime":53649.0,"Objects":[{"StartTime":53649.0,"EndTime":53649.0,"X":295.0,"Y":161.0}]},{"StartTime":53811.0,"Objects":[{"StartTime":53811.0,"EndTime":53811.0,"X":401.0,"Y":308.0}]},{"StartTime":53973.0,"Objects":[{"StartTime":53973.0,"EndTime":53973.0,"X":187.0,"Y":230.0}]},{"StartTime":54135.0,"Objects":[{"StartTime":54135.0,"EndTime":54135.0,"X":383.0,"Y":113.0}]},{"StartTime":54297.0,"Objects":[{"StartTime":54297.0,"EndTime":54297.0,"X":268.0,"Y":345.0}]},{"StartTime":54460.0,"Objects":[{"StartTime":54460.0,"EndTime":54460.0,"X":181.0,"Y":103.0}]},{"StartTime":54622.0,"Objects":[{"StartTime":54622.0,"EndTime":54622.0,"X":353.0,"Y":192.0}]},{"StartTime":54784.0,"Objects":[{"StartTime":54784.0,"EndTime":54784.0,"X":125.0,"Y":325.0}]},{"StartTime":54946.0,"Objects":[{"StartTime":54946.0,"EndTime":54946.0,"X":253.0,"Y":53.0}]},{"StartTime":55108.0,"Objects":[{"StartTime":55108.0,"EndTime":55108.0,"X":349.0,"Y":356.0}]},{"StartTime":55270.0,"Objects":[{"StartTime":55270.0,"EndTime":55270.0,"X":107.0,"Y":207.0}]},{"StartTime":55432.0,"Objects":[{"StartTime":55432.0,"EndTime":55432.0,"X":408.0,"Y":39.0}]},{"StartTime":55595.0,"Objects":[{"StartTime":55595.0,"EndTime":55595.0,"X":93.0,"Y":84.0}]},{"StartTime":55757.0,"Objects":[{"StartTime":55757.0,"EndTime":55757.0,"X":434.0,"Y":284.0}]},{"StartTime":55919.0,"Objects":[{"StartTime":55919.0,"EndTime":55919.0,"X":189.0,"Y":384.0}]},{"StartTime":56081.0,"Objects":[{"StartTime":56081.0,"EndTime":56081.0,"X":261.0,"Y":22.0}]},{"StartTime":56730.0,"Objects":[{"StartTime":56730.0,"EndTime":56730.0,"X":261.0,"Y":22.0}]},{"StartTime":56892.0,"Objects":[{"StartTime":56892.0,"EndTime":56892.0,"X":349.0,"Y":270.0}]},{"StartTime":57054.0,"Objects":[{"StartTime":57054.0,"EndTime":57054.0,"X":403.0,"Y":210.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57261.0,"EndTime":57261.0,"X":266.4971,"Y":168.565536,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57378.0,"Objects":[{"StartTime":57378.0,"EndTime":57378.0,"X":192.0,"Y":141.0}]},{"StartTime":57541.0,"Objects":[{"StartTime":57541.0,"EndTime":57541.0,"X":0.0,"Y":284.0}]},{"StartTime":57703.0,"Objects":[{"StartTime":57703.0,"EndTime":57703.0,"X":94.0,"Y":384.0}]},{"StartTime":57865.0,"Objects":[{"StartTime":57865.0,"EndTime":57865.0,"X":3.880282,"Y":172.88028}]},{"StartTime":57946.0,"Objects":[{"StartTime":57946.0,"EndTime":57946.0,"X":7.44014072,"Y":176.44014}]},{"StartTime":58027.0,"Objects":[{"StartTime":58027.0,"EndTime":58027.0,"X":11.0,"Y":180.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58072.0,"EndTime":58072.0,"X":60.9864349,"Y":199.046555,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58189.0,"Objects":[{"StartTime":58189.0,"EndTime":58189.0,"X":227.0,"Y":293.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58396.0,"EndTime":58396.0,"X":176.743668,"Y":315.771759,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58514.0,"Objects":[{"StartTime":58514.0,"EndTime":58514.0,"X":117.0,"Y":261.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58802.0,"EndTime":58802.0,"X":290.002,"Y":336.26297,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59000.0,"Objects":[{"StartTime":59000.0,"EndTime":59000.0,"X":403.0,"Y":210.0}]},{"StartTime":59162.0,"Objects":[{"StartTime":59162.0,"EndTime":59162.0,"X":512.0,"Y":346.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59288.0,"EndTime":59288.0,"X":419.275238,"Y":315.02655,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59487.0,"Objects":[{"StartTime":59487.0,"EndTime":59487.0,"X":292.0,"Y":168.0}]},{"StartTime":59649.0,"Objects":[{"StartTime":59649.0,"EndTime":59649.0,"X":438.88028,"Y":99.88028}]},{"StartTime":59730.0,"Objects":[{"StartTime":59730.0,"EndTime":59730.0,"X":442.440155,"Y":103.44014}]},{"StartTime":59811.0,"Objects":[{"StartTime":59811.0,"EndTime":59811.0,"X":446.0,"Y":107.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60099.0,"EndTime":60099.0,"X":291.098572,"Y":167.505417,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60297.0,"Objects":[{"StartTime":60297.0,"EndTime":60297.0,"X":117.0,"Y":261.0}]},{"StartTime":60460.0,"Objects":[{"StartTime":60460.0,"EndTime":60460.0,"X":38.0,"Y":79.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60586.0,"EndTime":60586.0,"X":130.721649,"Y":113.926353,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60784.0,"Objects":[{"StartTime":60784.0,"EndTime":60784.0,"X":249.0,"Y":284.0}]},{"StartTime":60946.0,"Objects":[{"StartTime":60946.0,"EndTime":60946.0,"X":43.8802834,"Y":358.88028}]},{"StartTime":61027.0,"Objects":[{"StartTime":61027.0,"EndTime":61027.0,"X":47.44014,"Y":362.440155}]},{"StartTime":61108.0,"Objects":[{"StartTime":61108.0,"EndTime":61108.0,"X":51.0,"Y":366.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61396.0,"EndTime":61396.0,"X":53.8655739,"Y":214.24295,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61595.0,"Objects":[{"StartTime":61595.0,"EndTime":61595.0,"X":189.0,"Y":366.0}]},{"StartTime":61757.0,"Objects":[{"StartTime":61757.0,"EndTime":61757.0,"X":197.0,"Y":181.0}]},{"StartTime":61919.0,"Objects":[{"StartTime":61919.0,"EndTime":61919.0,"X":25.0,"Y":290.0}]},{"StartTime":62081.0,"Objects":[{"StartTime":62081.0,"EndTime":62081.0,"X":130.0,"Y":113.0}]},{"StartTime":62243.0,"Objects":[{"StartTime":62243.0,"EndTime":62243.0,"X":247.88028,"Y":282.88028}]},{"StartTime":62324.0,"Objects":[{"StartTime":62324.0,"EndTime":62324.0,"X":251.44014,"Y":286.440155}]},{"StartTime":62405.0,"Objects":[{"StartTime":62405.0,"EndTime":62405.0,"X":255.0,"Y":290.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62612.0,"EndTime":62612.0,"X":387.1793,"Y":342.8401,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62730.0,"Objects":[{"StartTime":62730.0,"EndTime":62730.0,"X":448.0,"Y":294.0}]},{"StartTime":62892.0,"Objects":[{"StartTime":62892.0,"EndTime":62892.0,"X":266.0,"Y":384.0}]},{"StartTime":63054.0,"Objects":[{"StartTime":63054.0,"EndTime":63054.0,"X":330.0,"Y":157.0}]},{"StartTime":63216.0,"Objects":[{"StartTime":63216.0,"EndTime":63216.0,"X":464.0,"Y":369.0}]},{"StartTime":63297.0,"Objects":[{"StartTime":63297.0,"EndTime":63297.0,"X":476.0,"Y":372.0}]},{"StartTime":63378.0,"Objects":[{"StartTime":63378.0,"EndTime":63378.0,"X":486.0,"Y":376.0}]},{"StartTime":63541.0,"Objects":[{"StartTime":63541.0,"EndTime":63541.0,"X":332.88028,"Y":236.88028}]},{"StartTime":63622.0,"Objects":[{"StartTime":63622.0,"EndTime":63622.0,"X":336.440155,"Y":240.44014}]},{"StartTime":63703.0,"Objects":[{"StartTime":63703.0,"EndTime":63703.0,"X":340.0,"Y":244.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63991.0,"EndTime":63991.0,"X":159.834656,"Y":305.091217,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64189.0,"Objects":[{"StartTime":64189.0,"EndTime":64189.0,"X":330.0,"Y":157.0}]},{"StartTime":64351.0,"Objects":[{"StartTime":64351.0,"EndTime":64351.0,"X":191.0,"Y":35.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64477.0,"EndTime":64477.0,"X":277.459381,"Y":65.24982,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64676.0,"Objects":[{"StartTime":64676.0,"EndTime":64676.0,"X":114.0,"Y":169.0}]},{"StartTime":64838.0,"Objects":[{"StartTime":64838.0,"EndTime":64838.0,"X":276.0,"Y":284.0}]},{"StartTime":65000.0,"Objects":[{"StartTime":65000.0,"EndTime":65000.0,"X":191.0,"Y":35.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65126.0,"EndTime":65126.0,"X":203.19455,"Y":133.42746,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65324.0,"Objects":[{"StartTime":65324.0,"EndTime":65324.0,"X":69.0,"Y":328.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65531.0,"EndTime":65531.0,"X":50.3194847,"Y":213.134308,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65649.0,"Objects":[{"StartTime":65649.0,"EndTime":65649.0,"X":114.0,"Y":169.0}]},{"StartTime":65811.0,"Objects":[{"StartTime":65811.0,"EndTime":65811.0,"X":276.0,"Y":284.0}]},{"StartTime":65973.0,"Objects":[{"StartTime":65973.0,"EndTime":65973.0,"X":385.0,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66099.0,"EndTime":66099.0,"X":291.745331,"Y":168.527618,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66297.0,"Objects":[{"StartTime":66297.0,"EndTime":66297.0,"X":426.0,"Y":382.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66585.0,"EndTime":66585.0,"X":449.0037,"Y":226.493729,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66784.0,"Objects":[{"StartTime":66784.0,"EndTime":66784.0,"X":277.0,"Y":65.0}]},{"StartTime":66946.0,"Objects":[{"StartTime":66946.0,"EndTime":66946.0,"X":466.0,"Y":140.0}]},{"StartTime":67108.0,"Objects":[{"StartTime":67108.0,"EndTime":67108.0,"X":276.0,"Y":284.0}]},{"StartTime":67270.0,"Objects":[{"StartTime":67270.0,"EndTime":67270.0,"X":370.0,"Y":44.0}]},{"StartTime":67432.0,"Objects":[{"StartTime":67432.0,"EndTime":67432.0,"X":449.0,"Y":226.0}]},{"StartTime":67595.0,"Objects":[{"StartTime":67595.0,"EndTime":67595.0,"X":218.0,"Y":127.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67802.0,"EndTime":67802.0,"X":78.44003,"Y":170.844543,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":67919.0,"Objects":[{"StartTime":67919.0,"EndTime":67919.0,"X":17.0,"Y":215.0}]},{"StartTime":68000.0,"Objects":[{"StartTime":68000.0,"EndTime":68000.0,"X":0.0,"Y":184.0}]},{"StartTime":68081.0,"Objects":[{"StartTime":68081.0,"EndTime":68081.0,"X":12.0,"Y":147.0}]},{"StartTime":68243.0,"Objects":[{"StartTime":68243.0,"EndTime":68243.0,"X":178.44014,"Y":264.440155}]},{"StartTime":68405.0,"Objects":[{"StartTime":68405.0,"EndTime":68405.0,"X":5.0,"Y":376.0}]},{"StartTime":68568.0,"Objects":[{"StartTime":68568.0,"EndTime":68568.0,"X":182.0,"Y":268.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":68775.0,"EndTime":68775.0,"X":308.081726,"Y":309.018158,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68892.0,"Objects":[{"StartTime":68892.0,"EndTime":68892.0,"X":352.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69180.0,"EndTime":69180.0,"X":322.055725,"Y":182.913208,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":69378.0,"Objects":[{"StartTime":69378.0,"EndTime":69378.0,"X":452.0,"Y":288.0}]},{"StartTime":69541.0,"Objects":[{"StartTime":69541.0,"EndTime":69541.0,"X":236.0,"Y":384.0}]},{"StartTime":69703.0,"Objects":[{"StartTime":69703.0,"EndTime":69703.0,"X":428.0,"Y":187.0}]},{"StartTime":69865.0,"Objects":[{"StartTime":69865.0,"EndTime":69865.0,"X":449.0,"Y":384.0}]},{"StartTime":70027.0,"Objects":[{"StartTime":70027.0,"EndTime":70027.0,"X":229.88028,"Y":175.88028}]},{"StartTime":70108.0,"Objects":[{"StartTime":70108.0,"EndTime":70108.0,"X":233.44014,"Y":179.44014}]},{"StartTime":70189.0,"Objects":[{"StartTime":70189.0,"EndTime":70189.0,"X":237.0,"Y":183.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":70396.0,"EndTime":70396.0,"X":311.577423,"Y":106.287315,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70514.0,"Objects":[{"StartTime":70514.0,"EndTime":70514.0,"X":302.0,"Y":117.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":70640.0,"EndTime":70640.0,"X":210.930847,"Y":150.767288,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70838.0,"Objects":[{"StartTime":70838.0,"EndTime":70838.0,"X":335.0,"Y":2.0}]},{"StartTime":71000.0,"Objects":[{"StartTime":71000.0,"EndTime":71000.0,"X":428.88028,"Y":187.88028}]},{"StartTime":71081.0,"Objects":[{"StartTime":71081.0,"EndTime":71081.0,"X":432.440155,"Y":191.44014}]},{"StartTime":71162.0,"Objects":[{"StartTime":71162.0,"EndTime":71162.0,"X":436.0,"Y":195.0}]},{"StartTime":71324.0,"Objects":[{"StartTime":71324.0,"EndTime":71324.0,"X":311.0,"Y":106.0}]},{"StartTime":71487.0,"Objects":[{"StartTime":71487.0,"EndTime":71487.0,"X":224.0,"Y":322.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":71775.0,"EndTime":71775.0,"X":95.6513062,"Y":234.867325,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":71973.0,"Objects":[{"StartTime":71973.0,"EndTime":71973.0,"X":49.0,"Y":175.0}]},{"StartTime":72135.0,"Objects":[{"StartTime":72135.0,"EndTime":72135.0,"X":177.0,"Y":84.0}]},{"StartTime":72297.0,"Objects":[{"StartTime":72297.0,"EndTime":72297.0,"X":20.0,"Y":260.0}]},{"StartTime":72460.0,"Objects":[{"StartTime":72460.0,"EndTime":72460.0,"X":86.0,"Y":94.0}]},{"StartTime":72622.0,"Objects":[{"StartTime":72622.0,"EndTime":72622.0,"X":241.0,"Y":246.0}]},{"StartTime":72784.0,"Objects":[{"StartTime":72784.0,"EndTime":72784.0,"X":80.0,"Y":332.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":72910.0,"EndTime":72910.0,"X":95.6374,"Y":234.060516,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":73108.0,"Objects":[{"StartTime":73108.0,"EndTime":73108.0,"X":306.0,"Y":124.0}]},{"StartTime":73270.0,"Objects":[{"StartTime":73270.0,"EndTime":73270.0,"X":154.0,"Y":169.0}]},{"StartTime":73432.0,"Objects":[{"StartTime":73432.0,"EndTime":73432.0,"X":342.0,"Y":313.0}]},{"StartTime":73595.0,"Objects":[{"StartTime":73595.0,"EndTime":73595.0,"X":215.0,"Y":354.0}]},{"StartTime":73676.0,"Objects":[{"StartTime":73676.0,"EndTime":73676.0,"X":199.0,"Y":318.0}]},{"StartTime":73757.0,"Objects":[{"StartTime":73757.0,"EndTime":73757.0,"X":214.0,"Y":277.0}]},{"StartTime":73919.0,"Objects":[{"StartTime":73919.0,"EndTime":73919.0,"X":417.0,"Y":248.0}]},{"StartTime":74000.0,"Objects":[{"StartTime":74000.0,"EndTime":74000.0,"X":428.0,"Y":270.0}]},{"StartTime":74081.0,"Objects":[{"StartTime":74081.0,"EndTime":74081.0,"X":413.0,"Y":298.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":74207.0,"EndTime":74207.0,"X":341.732971,"Y":312.8005,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":74405.0,"Objects":[{"StartTime":74405.0,"EndTime":74405.0,"X":464.0,"Y":175.0}]},{"StartTime":74568.0,"Objects":[{"StartTime":74568.0,"EndTime":74568.0,"X":395.0,"Y":145.0}]},{"StartTime":74730.0,"Objects":[{"StartTime":74730.0,"EndTime":74730.0,"X":498.0,"Y":35.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":74856.0,"EndTime":74856.0,"X":506.846649,"Y":107.542564,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":75054.0,"Objects":[{"StartTime":75054.0,"EndTime":75054.0,"X":378.0,"Y":40.0}]},{"StartTime":75216.0,"Objects":[{"StartTime":75216.0,"EndTime":75216.0,"X":278.88028,"Y":141.88028}]},{"StartTime":75297.0,"Objects":[{"StartTime":75297.0,"EndTime":75297.0,"X":282.440155,"Y":145.44014}]},{"StartTime":75378.0,"Objects":[{"StartTime":75378.0,"EndTime":75378.0,"X":286.0,"Y":149.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":75504.0,"EndTime":75504.0,"X":300.0564,"Y":77.30375,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":75703.0,"Objects":[{"StartTime":75703.0,"EndTime":75703.0,"X":436.0,"Y":241.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":75829.0,"EndTime":75829.0,"X":367.113739,"Y":265.2332,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":76027.0,"Objects":[{"StartTime":76027.0,"EndTime":76027.0,"X":241.0,"Y":384.0}]},{"StartTime":76270.0,"Objects":[{"StartTime":76270.0,"EndTime":76270.0,"X":464.0,"Y":175.0}]},{"StartTime":76514.0,"Objects":[{"StartTime":76514.0,"EndTime":76514.0,"X":210.0,"Y":32.0}]},{"StartTime":76676.0,"Objects":[{"StartTime":76676.0,"EndTime":76676.0,"X":280.0,"Y":204.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":76964.0,"EndTime":76964.0,"X":235.7542,"Y":130.475433,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77162.0,"Objects":[{"StartTime":77162.0,"EndTime":77162.0,"X":367.0,"Y":265.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77369.0,"EndTime":77369.0,"X":496.5096,"Y":318.670868,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77487.0,"Objects":[{"StartTime":77487.0,"EndTime":77487.0,"X":501.88028,"Y":239.88028}]},{"StartTime":77568.0,"Objects":[{"StartTime":77568.0,"EndTime":77568.0,"X":505.440155,"Y":243.44014}]},{"StartTime":77649.0,"Objects":[{"StartTime":77649.0,"EndTime":77649.0,"X":509.0,"Y":247.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77856.0,"EndTime":77856.0,"X":488.1183,"Y":99.71859,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77973.0,"Objects":[{"StartTime":77973.0,"EndTime":77973.0,"X":428.0,"Y":51.0}]},{"StartTime":78135.0,"Objects":[{"StartTime":78135.0,"EndTime":78135.0,"X":280.0,"Y":204.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78342.0,"EndTime":78342.0,"X":297.461823,"Y":56.3390465,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78460.0,"Objects":[{"StartTime":78460.0,"EndTime":78460.0,"X":353.0,"Y":6.0}]},{"StartTime":78622.0,"Objects":[{"StartTime":78622.0,"EndTime":78622.0,"X":175.0,"Y":118.0}]},{"StartTime":78784.0,"Objects":[{"StartTime":78784.0,"EndTime":78784.0,"X":367.0,"Y":265.0}]},{"StartTime":78946.0,"Objects":[{"StartTime":78946.0,"EndTime":78946.0,"X":301.0,"Y":135.0}]},{"StartTime":79108.0,"Objects":[{"StartTime":79108.0,"EndTime":79108.0,"X":131.88028,"Y":228.88028}]},{"StartTime":79189.0,"Objects":[{"StartTime":79189.0,"EndTime":79189.0,"X":135.44014,"Y":232.44014}]},{"StartTime":79270.0,"Objects":[{"StartTime":79270.0,"EndTime":79270.0,"X":139.0,"Y":236.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":79477.0,"EndTime":79477.0,"X":261.5925,"Y":303.983337,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":79595.0,"Objects":[{"StartTime":79595.0,"EndTime":79595.0,"X":330.0,"Y":335.0}]},{"StartTime":79757.0,"Objects":[{"StartTime":79757.0,"EndTime":79757.0,"X":231.0,"Y":178.0}]},{"StartTime":79919.0,"Objects":[{"StartTime":79919.0,"EndTime":79919.0,"X":391.0,"Y":241.0}]},{"StartTime":80081.0,"Objects":[{"StartTime":80081.0,"EndTime":80081.0,"X":228.0,"Y":375.0}]},{"StartTime":80243.0,"Objects":[{"StartTime":80243.0,"EndTime":80243.0,"X":311.0,"Y":114.0}]},{"StartTime":80405.0,"Objects":[{"StartTime":80405.0,"EndTime":80405.0,"X":442.0,"Y":339.0}]},{"StartTime":80568.0,"Objects":[{"StartTime":80568.0,"EndTime":80568.0,"X":386.0,"Y":52.0}]},{"StartTime":80730.0,"Objects":[{"StartTime":80730.0,"EndTime":80730.0,"X":327.0,"Y":359.0}]},{"StartTime":81541.0,"Objects":[{"StartTime":81541.0,"EndTime":81541.0,"X":62.0,"Y":133.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":81748.0,"EndTime":81748.0,"X":206.079437,"Y":76.30348,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":81865.0,"Objects":[{"StartTime":81865.0,"EndTime":81865.0,"X":256.0,"Y":133.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":81991.0,"EndTime":81991.0,"X":238.8628,"Y":204.038742,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82189.0,"Objects":[{"StartTime":82189.0,"EndTime":82189.0,"X":399.0,"Y":329.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":82315.0,"EndTime":82315.0,"X":391.4031,"Y":256.37088,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82514.0,"Objects":[{"StartTime":82514.0,"EndTime":82514.0,"X":203.0,"Y":313.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":82640.0,"EndTime":82640.0,"X":271.74295,"Y":337.270447,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82838.0,"Objects":[{"StartTime":82838.0,"EndTime":82838.0,"X":406.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":82964.0,"EndTime":82964.0,"X":337.526459,"Y":192.858139,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":83162.0,"Objects":[{"StartTime":83162.0,"EndTime":83162.0,"X":209.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":83450.0,"EndTime":83450.0,"X":328.328674,"Y":92.72046,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":83649.0,"Objects":[{"StartTime":83649.0,"EndTime":83649.0,"X":239.0,"Y":204.0}]},{"StartTime":83811.0,"Objects":[{"StartTime":83811.0,"EndTime":83811.0,"X":328.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":83937.0,"EndTime":83937.0,"X":395.987061,"Y":65.98791,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84135.0,"Objects":[{"StartTime":84135.0,"EndTime":84135.0,"X":507.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84261.0,"EndTime":84261.0,"X":438.416,"Y":169.361435,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84460.0,"Objects":[{"StartTime":84460.0,"EndTime":84460.0,"X":274.0,"Y":337.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84748.0,"EndTime":84748.0,"X":385.897217,"Y":352.294159,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84946.0,"Objects":[{"StartTime":84946.0,"EndTime":84946.0,"X":239.0,"Y":204.0}]},{"StartTime":85108.0,"Objects":[{"StartTime":85108.0,"EndTime":85108.0,"X":186.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":85234.0,"EndTime":85234.0,"X":115.1999,"Y":278.111664,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":85432.0,"Objects":[{"StartTime":85432.0,"EndTime":85432.0,"X":281.0,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":85558.0,"EndTime":85558.0,"X":352.092682,"Y":152.926834,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":85757.0,"Objects":[{"StartTime":85757.0,"EndTime":85757.0,"X":161.0,"Y":5.0}]},{"StartTime":85919.0,"Objects":[{"StartTime":85919.0,"EndTime":85919.0,"X":239.0,"Y":204.0}]},{"StartTime":86081.0,"Objects":[{"StartTime":86081.0,"EndTime":86081.0,"X":273.0,"Y":44.0}]},{"StartTime":86243.0,"Objects":[{"StartTime":86243.0,"EndTime":86243.0,"X":124.0,"Y":190.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86531.0,"EndTime":86531.0,"X":303.0346,"Y":255.0868,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":86730.0,"Objects":[{"StartTime":86730.0,"EndTime":86730.0,"X":161.0,"Y":5.0}]},{"StartTime":86811.0,"Objects":[{"StartTime":86811.0,"EndTime":86811.0,"X":138.0,"Y":37.0}]},{"StartTime":86892.0,"Objects":[{"StartTime":86892.0,"EndTime":86892.0,"X":147.0,"Y":70.0}]},{"StartTime":87054.0,"Objects":[{"StartTime":87054.0,"EndTime":87054.0,"X":352.0,"Y":152.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87342.0,"EndTime":87342.0,"X":403.287628,"Y":316.874359,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":87541.0,"Objects":[{"StartTime":87541.0,"EndTime":87541.0,"X":239.0,"Y":204.0}]},{"StartTime":87703.0,"Objects":[{"StartTime":87703.0,"EndTime":87703.0,"X":183.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87829.0,"EndTime":87829.0,"X":200.273987,"Y":350.475433,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88027.0,"Objects":[{"StartTime":88027.0,"EndTime":88027.0,"X":303.440155,"Y":252.44014}]},{"StartTime":88189.0,"Objects":[{"StartTime":88189.0,"EndTime":88189.0,"X":193.0,"Y":142.0}]},{"StartTime":88351.0,"Objects":[{"StartTime":88351.0,"EndTime":88351.0,"X":307.0,"Y":256.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88639.0,"EndTime":88639.0,"X":126.771782,"Y":318.279968,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88838.0,"Objects":[{"StartTime":88838.0,"EndTime":88838.0,"X":323.0,"Y":165.0}]},{"StartTime":89000.0,"Objects":[{"StartTime":89000.0,"EndTime":89000.0,"X":171.0,"Y":32.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89126.0,"EndTime":89126.0,"X":258.739349,"Y":64.95778,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":89324.0,"Objects":[{"StartTime":89324.0,"EndTime":89324.0,"X":166.0,"Y":153.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89531.0,"EndTime":89531.0,"X":84.73328,"Y":172.269424,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":89649.0,"Objects":[{"StartTime":89649.0,"EndTime":89649.0,"X":54.0,"Y":183.0}]},{"StartTime":89811.0,"Objects":[{"StartTime":89811.0,"EndTime":89811.0,"X":282.0,"Y":51.0}]},{"StartTime":89973.0,"Objects":[{"StartTime":89973.0,"EndTime":89973.0,"X":153.0,"Y":20.0}]},{"StartTime":90135.0,"Objects":[{"StartTime":90135.0,"EndTime":90135.0,"X":339.0,"Y":174.0}]},{"StartTime":90297.0,"Objects":[{"StartTime":90297.0,"EndTime":90297.0,"X":126.0,"Y":318.0}]},{"StartTime":90460.0,"Objects":[{"StartTime":90460.0,"EndTime":90460.0,"X":238.0,"Y":125.0}]},{"StartTime":90541.0,"Objects":[{"StartTime":90541.0,"EndTime":90541.0,"X":242.0,"Y":141.0}]},{"StartTime":90622.0,"Objects":[{"StartTime":90622.0,"EndTime":90622.0,"X":244.0,"Y":158.0}]},{"StartTime":90784.0,"Objects":[{"StartTime":90784.0,"EndTime":90784.0,"X":338.0,"Y":281.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":91072.0,"EndTime":91072.0,"X":438.117,"Y":323.4276,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":91270.0,"Objects":[{"StartTime":91270.0,"EndTime":91270.0,"X":481.0,"Y":138.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":91396.0,"EndTime":91396.0,"X":427.0648,"Y":151.829544,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":91514.0,"Objects":[{"StartTime":91514.0,"EndTime":91514.0,"X":356.0,"Y":170.0}]},{"StartTime":91595.0,"Objects":[{"StartTime":91595.0,"EndTime":91595.0,"X":339.0,"Y":174.0}]},{"StartTime":91757.0,"Objects":[{"StartTime":91757.0,"EndTime":91757.0,"X":463.0,"Y":235.0}]},{"StartTime":91919.0,"Objects":[{"StartTime":91919.0,"EndTime":91919.0,"X":369.440155,"Y":91.44014,"StackOffset":{"X":-3.559845,"Y":-3.55986023}},{"StartTime":92126.0,"EndTime":92126.0,"X":385.6048,"Y":9.84262,"StackOffset":{"X":-3.559845,"Y":-3.55986023}}]},{"StartTime":92243.0,"Objects":[{"StartTime":92243.0,"EndTime":92243.0,"X":389.0,"Y":13.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92531.0,"EndTime":92531.0,"X":270.5224,"Y":51.6697578,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":92892.0,"Objects":[{"StartTime":92892.0,"EndTime":92892.0,"X":126.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93018.0,"EndTime":93018.0,"X":196.3784,"Y":187.659012,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93216.0,"Objects":[{"StartTime":93216.0,"EndTime":93216.0,"X":75.0,"Y":40.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93342.0,"EndTime":93342.0,"X":145.749725,"Y":57.7823524,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93541.0,"Objects":[{"StartTime":93541.0,"EndTime":93541.0,"X":42.0,"Y":128.0}]},{"StartTime":93703.0,"Objects":[{"StartTime":93703.0,"EndTime":93703.0,"X":126.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93991.0,"EndTime":93991.0,"X":102.604004,"Y":351.27533,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94189.0,"Objects":[{"StartTime":94189.0,"EndTime":94189.0,"X":260.0,"Y":235.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":94315.0,"EndTime":94315.0,"X":271.253265,"Y":307.208374,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94514.0,"Objects":[{"StartTime":94514.0,"EndTime":94514.0,"X":404.0,"Y":168.0}]},{"StartTime":94676.0,"Objects":[{"StartTime":94676.0,"EndTime":94676.0,"X":329.0,"Y":138.0}]},{"StartTime":94838.0,"Objects":[{"StartTime":94838.0,"EndTime":94838.0,"X":389.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95126.0,"EndTime":95126.0,"X":512.510864,"Y":209.161926,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":95487.0,"Objects":[{"StartTime":95487.0,"EndTime":95487.0,"X":512.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95613.0,"EndTime":95613.0,"X":443.248566,"Y":185.697754,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":95811.0,"Objects":[{"StartTime":95811.0,"EndTime":95811.0,"X":306.0,"Y":51.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95937.0,"EndTime":95937.0,"X":375.1769,"Y":29.8420277,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96135.0,"Objects":[{"StartTime":96135.0,"EndTime":96135.0,"X":265.0,"Y":196.0}]},{"StartTime":96297.0,"Objects":[{"StartTime":96297.0,"EndTime":96297.0,"X":169.0,"Y":81.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96423.0,"EndTime":96423.0,"X":237.498428,"Y":105.515129,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96622.0,"Objects":[{"StartTime":96622.0,"EndTime":96622.0,"X":106.0,"Y":191.0}]},{"StartTime":96784.0,"Objects":[{"StartTime":96784.0,"EndTime":96784.0,"X":220.0,"Y":333.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96946.0,"EndTime":96946.0,"X":210.935547,"Y":260.484344,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97072.0,"EndTime":97072.0,"X":220.0,"Y":333.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":97432.0,"Objects":[{"StartTime":97432.0,"EndTime":97432.0,"X":208.0,"Y":345.0}]},{"StartTime":97595.0,"Objects":[{"StartTime":97595.0,"EndTime":97595.0,"X":365.88028,"Y":250.88028}]},{"StartTime":97676.0,"Objects":[{"StartTime":97676.0,"EndTime":97676.0,"X":369.440155,"Y":254.44014}]},{"StartTime":97757.0,"Objects":[{"StartTime":97757.0,"EndTime":97757.0,"X":373.0,"Y":258.0}]},{"StartTime":97919.0,"Objects":[{"StartTime":97919.0,"EndTime":97919.0,"X":286.0,"Y":206.0}]},{"StartTime":98081.0,"Objects":[{"StartTime":98081.0,"EndTime":98081.0,"X":396.88028,"Y":337.88028}]},{"StartTime":98162.0,"Objects":[{"StartTime":98162.0,"EndTime":98162.0,"X":400.440155,"Y":341.440155}]},{"StartTime":98243.0,"Objects":[{"StartTime":98243.0,"EndTime":98243.0,"X":404.0,"Y":345.0}]},{"StartTime":98405.0,"Objects":[{"StartTime":98405.0,"EndTime":98405.0,"X":295.0,"Y":285.0}]},{"StartTime":98568.0,"Objects":[{"StartTime":98568.0,"EndTime":98568.0,"X":447.88028,"Y":183.88028}]},{"StartTime":98649.0,"Objects":[{"StartTime":98649.0,"EndTime":98649.0,"X":451.440155,"Y":187.44014}]},{"StartTime":98730.0,"Objects":[{"StartTime":98730.0,"EndTime":98730.0,"X":455.0,"Y":191.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98856.0,"EndTime":98856.0,"X":444.882874,"Y":118.623688,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98973.0,"Objects":[{"StartTime":98973.0,"EndTime":98973.0,"X":433.0,"Y":49.0}]},{"StartTime":99054.0,"Objects":[{"StartTime":99054.0,"EndTime":99054.0,"X":430.0,"Y":33.0}]},{"StartTime":99216.0,"Objects":[{"StartTime":99216.0,"EndTime":99216.0,"X":322.0,"Y":120.0}]},{"StartTime":99378.0,"Objects":[{"StartTime":99378.0,"EndTime":99378.0,"X":236.0,"Y":48.0}]},{"StartTime":99460.0,"Objects":[{"StartTime":99460.0,"EndTime":99460.0,"X":237.0,"Y":36.0}]},{"StartTime":99541.0,"Objects":[{"StartTime":99541.0,"EndTime":99541.0,"X":239.0,"Y":20.0}]},{"StartTime":99703.0,"Objects":[{"StartTime":99703.0,"EndTime":99703.0,"X":322.0,"Y":120.0}]},{"StartTime":99865.0,"Objects":[{"StartTime":99865.0,"EndTime":99865.0,"X":166.0,"Y":190.0}]},{"StartTime":99946.0,"Objects":[{"StartTime":99946.0,"EndTime":99946.0,"X":165.0,"Y":177.0}]},{"StartTime":100027.0,"Objects":[{"StartTime":100027.0,"EndTime":100027.0,"X":163.0,"Y":166.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100315.0,"EndTime":100315.0,"X":311.452423,"Y":199.964645,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100514.0,"Objects":[{"StartTime":100514.0,"EndTime":100514.0,"X":136.0,"Y":71.0}]},{"StartTime":100676.0,"Objects":[{"StartTime":100676.0,"EndTime":100676.0,"X":322.0,"Y":120.0}]},{"StartTime":100838.0,"Objects":[{"StartTime":100838.0,"EndTime":100838.0,"X":119.0,"Y":280.0}]},{"StartTime":101000.0,"Objects":[{"StartTime":101000.0,"EndTime":101000.0,"X":236.0,"Y":48.0}]},{"StartTime":101162.0,"Objects":[{"StartTime":101162.0,"EndTime":101162.0,"X":346.0,"Y":315.0}]},{"StartTime":101324.0,"Objects":[{"StartTime":101324.0,"EndTime":101324.0,"X":47.0,"Y":167.0}]},{"StartTime":101487.0,"Objects":[{"StartTime":101487.0,"EndTime":101487.0,"X":384.0,"Y":47.0}]},{"StartTime":102135.0,"Objects":[{"StartTime":102135.0,"EndTime":102135.0,"X":384.88028,"Y":45.8802834}]},{"StartTime":102216.0,"Objects":[{"StartTime":102216.0,"EndTime":102216.0,"X":388.440155,"Y":49.44014}]},{"StartTime":102297.0,"Objects":[{"StartTime":102297.0,"EndTime":102297.0,"X":392.0,"Y":53.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102504.0,"EndTime":102504.0,"X":287.890961,"Y":117.336929,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102622.0,"Objects":[{"StartTime":102622.0,"EndTime":102622.0,"X":229.0,"Y":189.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102910.0,"EndTime":102910.0,"X":382.2425,"Y":229.177368,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103108.0,"Objects":[{"StartTime":103108.0,"EndTime":103108.0,"X":438.0,"Y":175.0}]},{"StartTime":103270.0,"Objects":[{"StartTime":103270.0,"EndTime":103270.0,"X":285.0,"Y":287.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103396.0,"EndTime":103396.0,"X":204.35733,"Y":300.591461,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103595.0,"Objects":[{"StartTime":103595.0,"EndTime":103595.0,"X":343.0,"Y":378.0}]},{"StartTime":103757.0,"Objects":[{"StartTime":103757.0,"EndTime":103757.0,"X":363.0,"Y":307.0}]},{"StartTime":103919.0,"Objects":[{"StartTime":103919.0,"EndTime":103919.0,"X":194.0,"Y":121.0}]},{"StartTime":104081.0,"Objects":[{"StartTime":104081.0,"EndTime":104081.0,"X":229.0,"Y":189.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104207.0,"EndTime":104207.0,"X":308.993835,"Y":205.998688,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104405.0,"Objects":[{"StartTime":104405.0,"EndTime":104405.0,"X":146.0,"Y":366.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104612.0,"EndTime":104612.0,"X":122.078148,"Y":267.7327,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104730.0,"Objects":[{"StartTime":104730.0,"EndTime":104730.0,"X":95.0,"Y":201.0}]},{"StartTime":104892.0,"Objects":[{"StartTime":104892.0,"EndTime":104892.0,"X":272.0,"Y":122.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105099.0,"EndTime":105099.0,"X":284.801727,"Y":18.6999683,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105216.0,"Objects":[{"StartTime":105216.0,"EndTime":105216.0,"X":214.0,"Y":1.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105504.0,"EndTime":105504.0,"X":60.34272,"Y":42.0378342,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105703.0,"Objects":[{"StartTime":105703.0,"EndTime":105703.0,"X":194.0,"Y":121.0}]},{"StartTime":105865.0,"Objects":[{"StartTime":105865.0,"EndTime":105865.0,"X":95.0,"Y":201.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105991.0,"EndTime":105991.0,"X":108.977585,"Y":120.423355,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106189.0,"Objects":[{"StartTime":106189.0,"EndTime":106189.0,"X":279.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106396.0,"EndTime":106396.0,"X":293.2297,"Y":340.8419,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106514.0,"Objects":[{"StartTime":106514.0,"EndTime":106514.0,"X":231.0,"Y":382.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106640.0,"EndTime":106640.0,"X":205.732849,"Y":318.131958,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106838.0,"Objects":[{"StartTime":106838.0,"EndTime":106838.0,"X":369.0,"Y":185.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106964.0,"EndTime":106964.0,"X":447.2368,"Y":208.8112,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107162.0,"Objects":[{"StartTime":107162.0,"EndTime":107162.0,"X":310.0,"Y":88.0}]},{"StartTime":107324.0,"Objects":[{"StartTime":107324.0,"EndTime":107324.0,"X":300.0,"Y":16.0}]},{"StartTime":107487.0,"Objects":[{"StartTime":107487.0,"EndTime":107487.0,"X":194.0,"Y":121.0}]},{"StartTime":107649.0,"Objects":[{"StartTime":107649.0,"EndTime":107649.0,"X":370.88028,"Y":187.88028}]},{"StartTime":107730.0,"Objects":[{"StartTime":107730.0,"EndTime":107730.0,"X":374.440155,"Y":191.44014}]},{"StartTime":107811.0,"Objects":[{"StartTime":107811.0,"EndTime":107811.0,"X":378.0,"Y":195.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108099.0,"EndTime":108099.0,"X":228.641785,"Y":248.379822,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108297.0,"Objects":[{"StartTime":108297.0,"EndTime":108297.0,"X":122.0,"Y":87.0}]},{"StartTime":108460.0,"Objects":[{"StartTime":108460.0,"EndTime":108460.0,"X":194.0,"Y":121.0}]},{"StartTime":108622.0,"Objects":[{"StartTime":108622.0,"EndTime":108622.0,"X":48.0,"Y":214.0}]},{"StartTime":108784.0,"Objects":[{"StartTime":108784.0,"EndTime":108784.0,"X":37.0,"Y":137.0}]},{"StartTime":108946.0,"Objects":[{"StartTime":108946.0,"EndTime":108946.0,"X":136.88028,"Y":200.88028}]},{"StartTime":109027.0,"Objects":[{"StartTime":109027.0,"EndTime":109027.0,"X":140.44014,"Y":204.44014}]},{"StartTime":109108.0,"Objects":[{"StartTime":109108.0,"EndTime":109108.0,"X":144.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109315.0,"EndTime":109315.0,"X":124.652115,"Y":329.134583,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109432.0,"Objects":[{"StartTime":109432.0,"EndTime":109432.0,"X":58.0,"Y":361.0}]},{"StartTime":109595.0,"Objects":[{"StartTime":109595.0,"EndTime":109595.0,"X":244.0,"Y":241.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109883.0,"EndTime":109883.0,"X":372.25354,"Y":294.5455,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110081.0,"Objects":[{"StartTime":110081.0,"EndTime":110081.0,"X":194.0,"Y":121.0}]},{"StartTime":110243.0,"Objects":[{"StartTime":110243.0,"EndTime":110243.0,"X":354.0,"Y":43.0}]},{"StartTime":110405.0,"Objects":[{"StartTime":110405.0,"EndTime":110405.0,"X":290.0,"Y":0.0}]},{"StartTime":110568.0,"Objects":[{"StartTime":110568.0,"EndTime":110568.0,"X":394.88028,"Y":124.88028}]},{"StartTime":110649.0,"Objects":[{"StartTime":110649.0,"EndTime":110649.0,"X":398.440155,"Y":128.44014}]},{"StartTime":110730.0,"Objects":[{"StartTime":110730.0,"EndTime":110730.0,"X":402.0,"Y":132.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110937.0,"EndTime":110937.0,"X":321.508484,"Y":160.5931,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111054.0,"Objects":[{"StartTime":111054.0,"EndTime":111054.0,"X":117.0,"Y":295.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111342.0,"EndTime":111342.0,"X":293.832336,"Y":321.662231,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111541.0,"Objects":[{"StartTime":111541.0,"EndTime":111541.0,"X":101.88028,"Y":156.88028}]},{"StartTime":111622.0,"Objects":[{"StartTime":111622.0,"EndTime":111622.0,"X":105.44014,"Y":160.44014}]},{"StartTime":111703.0,"Objects":[{"StartTime":111703.0,"EndTime":111703.0,"X":109.0,"Y":164.0}]},{"StartTime":111865.0,"Objects":[{"StartTime":111865.0,"EndTime":111865.0,"X":279.0,"Y":95.0}]},{"StartTime":112027.0,"Objects":[{"StartTime":112027.0,"EndTime":112027.0,"X":99.0,"Y":38.0}]},{"StartTime":112189.0,"Objects":[{"StartTime":112189.0,"EndTime":112189.0,"X":216.0,"Y":244.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112396.0,"EndTime":112396.0,"X":195.586136,"Y":83.47279,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112514.0,"Objects":[{"StartTime":112514.0,"EndTime":112514.0,"X":245.0,"Y":28.0}]},{"StartTime":112676.0,"Objects":[{"StartTime":112676.0,"EndTime":112676.0,"X":23.0,"Y":186.0}]},{"StartTime":112838.0,"Objects":[{"StartTime":112838.0,"EndTime":112838.0,"X":179.0,"Y":352.0}]},{"StartTime":112919.0,"Objects":[{"StartTime":112919.0,"EndTime":112919.0,"X":159.0,"Y":363.0}]},{"StartTime":113000.0,"Objects":[{"StartTime":113000.0,"EndTime":113000.0,"X":138.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":113045.0,"EndTime":113045.0,"X":149.7844,"Y":302.363037,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":113162.0,"Objects":[{"StartTime":113162.0,"EndTime":113162.0,"X":331.0,"Y":171.0}]},{"StartTime":113324.0,"Objects":[{"StartTime":113324.0,"EndTime":113324.0,"X":397.0,"Y":215.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":113450.0,"EndTime":113450.0,"X":406.577026,"Y":269.8502,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":113649.0,"Objects":[{"StartTime":113649.0,"EndTime":113649.0,"X":252.0,"Y":149.0}]},{"StartTime":113811.0,"Objects":[{"StartTime":113811.0,"EndTime":113811.0,"X":411.0,"Y":51.0}]},{"StartTime":113973.0,"Objects":[{"StartTime":113973.0,"EndTime":113973.0,"X":347.0,"Y":16.0}]},{"StartTime":114135.0,"Objects":[{"StartTime":114135.0,"EndTime":114135.0,"X":457.0,"Y":161.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114423.0,"EndTime":114423.0,"X":272.994629,"Y":240.572388,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114622.0,"Objects":[{"StartTime":114622.0,"EndTime":114622.0,"X":126.0,"Y":120.0}]},{"StartTime":114784.0,"Objects":[{"StartTime":114784.0,"EndTime":114784.0,"X":267.0,"Y":55.0}]},{"StartTime":114946.0,"Objects":[{"StartTime":114946.0,"EndTime":114946.0,"X":130.0,"Y":257.0}]},{"StartTime":115108.0,"Objects":[{"StartTime":115108.0,"EndTime":115108.0,"X":171.88028,"Y":28.8802814}]},{"StartTime":115189.0,"Objects":[{"StartTime":115189.0,"EndTime":115189.0,"X":175.44014,"Y":32.44014}]},{"StartTime":115270.0,"Objects":[{"StartTime":115270.0,"EndTime":115270.0,"X":179.0,"Y":36.0}]},{"StartTime":115432.0,"Objects":[{"StartTime":115432.0,"EndTime":115432.0,"X":353.0,"Y":157.0}]},{"StartTime":115595.0,"Objects":[{"StartTime":115595.0,"EndTime":115595.0,"X":130.0,"Y":257.0}]},{"StartTime":115757.0,"Objects":[{"StartTime":115757.0,"EndTime":115757.0,"X":353.0,"Y":74.0}]},{"StartTime":115919.0,"Objects":[{"StartTime":115919.0,"EndTime":115919.0,"X":259.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":116045.0,"EndTime":116045.0,"X":267.296478,"Y":55.0584335,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":116162.0,"Objects":[{"StartTime":116162.0,"EndTime":116162.0,"X":280.0,"Y":124.0}]},{"StartTime":116243.0,"Objects":[{"StartTime":116243.0,"EndTime":116243.0,"X":283.0,"Y":135.0}]},{"StartTime":116405.0,"Objects":[{"StartTime":116405.0,"EndTime":116405.0,"X":441.0,"Y":224.0}]},{"StartTime":116568.0,"Objects":[{"StartTime":116568.0,"EndTime":116568.0,"X":353.0,"Y":74.0}]},{"StartTime":116730.0,"Objects":[{"StartTime":116730.0,"EndTime":116730.0,"X":203.0,"Y":217.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117018.0,"EndTime":117018.0,"X":301.176636,"Y":253.817078,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":117216.0,"Objects":[{"StartTime":117216.0,"EndTime":117216.0,"X":180.0,"Y":111.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117342.0,"EndTime":117342.0,"X":74.6470947,"Y":87.78665,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":117541.0,"Objects":[{"StartTime":117541.0,"EndTime":117541.0,"X":241.0,"Y":8.0}]},{"StartTime":117703.0,"Objects":[{"StartTime":117703.0,"EndTime":117703.0,"X":76.0,"Y":228.0}]},{"StartTime":117784.0,"Objects":[{"StartTime":117784.0,"EndTime":117784.0,"X":80.0,"Y":217.0}]},{"StartTime":117865.0,"Objects":[{"StartTime":117865.0,"EndTime":117865.0,"X":85.0,"Y":205.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117910.0,"EndTime":117910.0,"X":136.95993,"Y":219.480637,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118027.0,"Objects":[{"StartTime":118027.0,"EndTime":118027.0,"X":334.0,"Y":361.0}]},{"StartTime":118108.0,"Objects":[{"StartTime":118108.0,"EndTime":118108.0,"X":328.0,"Y":344.0}]},{"StartTime":118189.0,"Objects":[{"StartTime":118189.0,"EndTime":118189.0,"X":321.0,"Y":329.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118315.0,"EndTime":118315.0,"X":249.125366,"Y":342.218323,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118432.0,"Objects":[{"StartTime":118432.0,"EndTime":118432.0,"X":180.0,"Y":358.0}]},{"StartTime":118514.0,"Objects":[{"StartTime":118514.0,"EndTime":118514.0,"X":164.0,"Y":362.0}]},{"StartTime":118676.0,"Objects":[{"StartTime":118676.0,"EndTime":118676.0,"X":301.0,"Y":253.0}]},{"StartTime":118838.0,"Objects":[{"StartTime":118838.0,"EndTime":118838.0,"X":407.0,"Y":282.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118964.0,"EndTime":118964.0,"X":478.0228,"Y":299.217651,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":119162.0,"Objects":[{"StartTime":119162.0,"EndTime":119162.0,"X":321.0,"Y":172.0}]},{"StartTime":119324.0,"Objects":[{"StartTime":119324.0,"EndTime":119324.0,"X":445.0,"Y":94.0}]},{"StartTime":119405.0,"Objects":[{"StartTime":119405.0,"EndTime":119405.0,"X":431.0,"Y":98.0}]},{"StartTime":119487.0,"Objects":[{"StartTime":119487.0,"EndTime":119487.0,"X":416.0,"Y":103.0}]},{"StartTime":119649.0,"Objects":[{"StartTime":119649.0,"EndTime":119649.0,"X":316.0,"Y":12.0}]},{"StartTime":119730.0,"Objects":[{"StartTime":119730.0,"EndTime":119730.0,"X":331.0,"Y":16.0}]},{"StartTime":119811.0,"Objects":[{"StartTime":119811.0,"EndTime":119811.0,"X":342.0,"Y":22.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119937.0,"EndTime":119937.0,"X":325.503876,"Y":93.19385,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":120135.0,"Objects":[{"StartTime":120135.0,"EndTime":120135.0,"X":194.0,"Y":229.0}]},{"StartTime":120216.0,"Objects":[{"StartTime":120216.0,"EndTime":120216.0,"X":150.0,"Y":214.0}]},{"StartTime":120297.0,"Objects":[{"StartTime":120297.0,"EndTime":120297.0,"X":132.0,"Y":178.0}]},{"StartTime":120378.0,"Objects":[{"StartTime":120378.0,"EndTime":120378.0,"X":143.0,"Y":139.0}]},{"StartTime":120460.0,"Objects":[{"StartTime":120460.0,"EndTime":120460.0,"X":175.0,"Y":120.0}]},{"StartTime":120622.0,"Objects":[{"StartTime":120622.0,"EndTime":120622.0,"X":323.88028,"Y":265.88028}]},{"StartTime":120703.0,"Objects":[{"StartTime":120703.0,"EndTime":120703.0,"X":327.440155,"Y":269.440155}]},{"StartTime":120784.0,"Objects":[{"StartTime":120784.0,"EndTime":120784.0,"X":331.0,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":120910.0,"EndTime":120910.0,"X":260.102,"Y":290.724518,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":121027.0,"Objects":[{"StartTime":121027.0,"EndTime":121027.0,"X":189.0,"Y":306.0}]},{"StartTime":121108.0,"Objects":[{"StartTime":121108.0,"EndTime":121108.0,"X":172.0,"Y":311.0}]},{"StartTime":121270.0,"Objects":[{"StartTime":121270.0,"EndTime":121270.0,"X":278.0,"Y":193.0}]},{"StartTime":121432.0,"Objects":[{"StartTime":121432.0,"EndTime":121432.0,"X":175.0,"Y":120.0}]},{"StartTime":121514.0,"Objects":[{"StartTime":121514.0,"EndTime":121514.0,"X":174.0,"Y":109.0}]},{"StartTime":121595.0,"Objects":[{"StartTime":121595.0,"EndTime":121595.0,"X":173.0,"Y":98.0}]},{"StartTime":121757.0,"Objects":[{"StartTime":121757.0,"EndTime":121757.0,"X":276.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121883.0,"EndTime":121883.0,"X":263.553436,"Y":72.01228,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122000.0,"Objects":[{"StartTime":122000.0,"EndTime":122000.0,"X":311.440155,"Y":122.44014}]},{"StartTime":122081.0,"Objects":[{"StartTime":122081.0,"EndTime":122081.0,"X":315.0,"Y":126.0}]},{"StartTime":122243.0,"Objects":[{"StartTime":122243.0,"EndTime":122243.0,"X":177.0,"Y":210.0}]},{"StartTime":122324.0,"Objects":[{"StartTime":122324.0,"EndTime":122324.0,"X":162.0,"Y":214.0}]},{"StartTime":122405.0,"Objects":[{"StartTime":122405.0,"EndTime":122405.0,"X":150.0,"Y":217.0}]},{"StartTime":122568.0,"Objects":[{"StartTime":122568.0,"EndTime":122568.0,"X":260.0,"Y":290.0}]},{"StartTime":122730.0,"Objects":[{"StartTime":122730.0,"EndTime":122730.0,"X":312.0,"Y":208.0}]},{"StartTime":122811.0,"Objects":[{"StartTime":122811.0,"EndTime":122811.0,"X":346.0,"Y":188.0}]},{"StartTime":122892.0,"Objects":[{"StartTime":122892.0,"EndTime":122892.0,"X":384.0,"Y":199.0}]},{"StartTime":122973.0,"Objects":[{"StartTime":122973.0,"EndTime":122973.0,"X":406.0,"Y":233.0}]},{"StartTime":123054.0,"Objects":[{"StartTime":123054.0,"EndTime":123054.0,"X":391.0,"Y":250.0}]},{"StartTime":123135.0,"Objects":[{"StartTime":123135.0,"EndTime":123135.0,"X":413.0,"Y":304.0}]},{"StartTime":123216.0,"Objects":[{"StartTime":123216.0,"EndTime":123216.0,"X":474.0,"Y":312.0}]},{"StartTime":123297.0,"Objects":[{"StartTime":123297.0,"EndTime":123297.0,"X":512.0,"Y":266.0}]},{"StartTime":123378.0,"Objects":[{"StartTime":123378.0,"EndTime":123378.0,"X":512.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":123504.0,"EndTime":123504.0,"X":499.302948,"Y":161.415314,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":123703.0,"Objects":[{"StartTime":123703.0,"EndTime":123703.0,"X":260.0,"Y":290.0}]},{"StartTime":123865.0,"Objects":[{"StartTime":123865.0,"EndTime":123865.0,"X":324.0,"Y":73.0}]},{"StartTime":124027.0,"Objects":[{"StartTime":124027.0,"EndTime":124027.0,"X":413.0,"Y":304.0}]},{"StartTime":124189.0,"Objects":[{"StartTime":124189.0,"EndTime":124189.0,"X":222.0,"Y":147.0}]},{"StartTime":124351.0,"Objects":[{"StartTime":124351.0,"EndTime":124351.0,"X":437.0,"Y":36.0}]},{"StartTime":124514.0,"Objects":[{"StartTime":124514.0,"EndTime":124514.0,"X":346.0,"Y":188.0}]},{"StartTime":124676.0,"Objects":[{"StartTime":124676.0,"EndTime":124676.0,"X":192.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":124802.0,"EndTime":124802.0,"X":104.078423,"Y":-0.3641224,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125000.0,"Objects":[{"StartTime":125000.0,"EndTime":125000.0,"X":222.0,"Y":147.0}]},{"StartTime":125162.0,"Objects":[{"StartTime":125162.0,"EndTime":125162.0,"X":22.0,"Y":215.0}]},{"StartTime":125324.0,"Objects":[{"StartTime":125324.0,"EndTime":125324.0,"X":107.55986,"Y":3.559859}]},{"StartTime":125487.0,"Objects":[{"StartTime":125487.0,"EndTime":125487.0,"X":240.0,"Y":244.0}]},{"StartTime":125568.0,"Objects":[{"StartTime":125568.0,"EndTime":125568.0,"X":238.0,"Y":231.0}]},{"StartTime":125649.0,"Objects":[{"StartTime":125649.0,"EndTime":125649.0,"X":235.0,"Y":218.0}]},{"StartTime":125811.0,"Objects":[{"StartTime":125811.0,"EndTime":125811.0,"X":59.0,"Y":133.0}]},{"StartTime":125892.0,"Objects":[{"StartTime":125892.0,"EndTime":125892.0,"X":62.0,"Y":122.0}]},{"StartTime":125973.0,"Objects":[{"StartTime":125973.0,"EndTime":125973.0,"X":64.0,"Y":111.0}]},{"StartTime":126135.0,"Objects":[{"StartTime":126135.0,"EndTime":126135.0,"X":22.0,"Y":215.0}]},{"StartTime":126297.0,"Objects":[{"StartTime":126297.0,"EndTime":126297.0,"X":157.0,"Y":96.0}]},{"StartTime":126460.0,"Objects":[{"StartTime":126460.0,"EndTime":126460.0,"X":104.0,"Y":270.0}]},{"StartTime":126622.0,"Objects":[{"StartTime":126622.0,"EndTime":126622.0,"X":241.0,"Y":72.0}]},{"StartTime":126784.0,"Objects":[{"StartTime":126784.0,"EndTime":126784.0,"X":198.0,"Y":320.0}]},{"StartTime":126946.0,"Objects":[{"StartTime":126946.0,"EndTime":126946.0,"X":330.0,"Y":46.0}]},{"StartTime":127108.0,"Objects":[{"StartTime":127108.0,"EndTime":127108.0,"X":294.0,"Y":371.0}]},{"StartTime":127270.0,"Objects":[{"StartTime":127270.0,"EndTime":127270.0,"X":436.0,"Y":24.0}]},{"StartTime":127432.0,"Objects":[{"StartTime":127432.0,"EndTime":127432.0,"X":128.0,"Y":184.0}]},{"StartTime":127595.0,"Objects":[{"StartTime":127595.0,"EndTime":127595.0,"X":446.0,"Y":344.0}]},{"StartTime":127757.0,"Objects":[{"StartTime":127757.0,"EndTime":127757.0,"X":262.440155,"Y":-3.559859}]},{"StartTime":127919.0,"Objects":[{"StartTime":127919.0,"EndTime":127919.0,"X":152.0,"Y":384.0}]},{"StartTime":128081.0,"Objects":[{"StartTime":128081.0,"EndTime":128081.0,"X":512.0,"Y":170.0}]},{"StartTime":128243.0,"Objects":[{"StartTime":128243.0,"EndTime":128243.0,"X":266.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":128369.0,"EndTime":128369.0,"X":278.288239,"Y":133.415283,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":128487.0,"Objects":[{"StartTime":128487.0,"EndTime":128487.0,"X":378.0,"Y":196.0}]},{"StartTime":128568.0,"Objects":[{"StartTime":128568.0,"EndTime":128568.0,"X":396.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":128856.0,"EndTime":128856.0,"X":218.724335,"Y":206.941788,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":129054.0,"Objects":[{"StartTime":129054.0,"EndTime":129054.0,"X":365.0,"Y":56.0}]},{"StartTime":129216.0,"Objects":[{"StartTime":129216.0,"EndTime":129216.0,"X":312.0,"Y":299.0}]},{"StartTime":129378.0,"Objects":[{"StartTime":129378.0,"EndTime":129378.0,"X":196.0,"Y":119.0}]},{"StartTime":129541.0,"Objects":[{"StartTime":129541.0,"EndTime":129541.0,"X":396.0,"Y":176.0}]},{"StartTime":129703.0,"Objects":[{"StartTime":129703.0,"EndTime":129703.0,"X":208.0,"Y":302.0}]},{"StartTime":129865.0,"Objects":[{"StartTime":129865.0,"EndTime":129865.0,"X":298.0,"Y":190.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130153.0,"EndTime":130153.0,"X":491.098358,"Y":263.395782,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130351.0,"Objects":[{"StartTime":130351.0,"EndTime":130351.0,"X":281.0,"Y":90.0}]},{"StartTime":130514.0,"Objects":[{"StartTime":130514.0,"EndTime":130514.0,"X":484.0,"Y":174.0}]},{"StartTime":130676.0,"Objects":[{"StartTime":130676.0,"EndTime":130676.0,"X":312.0,"Y":299.0}]},{"StartTime":130838.0,"Objects":[{"StartTime":130838.0,"EndTime":130838.0,"X":504.0,"Y":380.0}]},{"StartTime":131000.0,"Objects":[{"StartTime":131000.0,"EndTime":131000.0,"X":299.88028,"Y":190.88028}]},{"StartTime":131081.0,"Objects":[{"StartTime":131081.0,"EndTime":131081.0,"X":303.440155,"Y":194.44014}]},{"StartTime":131162.0,"Objects":[{"StartTime":131162.0,"EndTime":131162.0,"X":307.0,"Y":198.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":131369.0,"EndTime":131369.0,"X":166.610275,"Y":253.783371,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":131487.0,"Objects":[{"StartTime":131487.0,"EndTime":131487.0,"X":110.0,"Y":300.0}]},{"StartTime":131649.0,"Objects":[{"StartTime":131649.0,"EndTime":131649.0,"X":0.0,"Y":176.0}]},{"StartTime":131811.0,"Objects":[{"StartTime":131811.0,"EndTime":131811.0,"X":144.0,"Y":107.0}]},{"StartTime":131973.0,"Objects":[{"StartTime":131973.0,"EndTime":131973.0,"X":3.0,"Y":282.0}]},{"StartTime":132135.0,"Objects":[{"StartTime":132135.0,"EndTime":132135.0,"X":208.44014,"Y":182.44014}]},{"StartTime":132297.0,"Objects":[{"StartTime":132297.0,"EndTime":132297.0,"X":77.0,"Y":31.0}]},{"StartTime":132460.0,"Objects":[{"StartTime":132460.0,"EndTime":132460.0,"X":212.0,"Y":186.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":132586.0,"EndTime":132586.0,"X":307.203156,"Y":207.722458,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":132784.0,"Objects":[{"StartTime":132784.0,"EndTime":132784.0,"X":455.0,"Y":384.0}]},{"StartTime":132946.0,"Objects":[{"StartTime":132946.0,"EndTime":132946.0,"X":297.0,"Y":290.0}]},{"StartTime":133108.0,"Objects":[{"StartTime":133108.0,"EndTime":133108.0,"X":430.0,"Y":145.0}]},{"StartTime":133270.0,"Objects":[{"StartTime":133270.0,"EndTime":133270.0,"X":339.0,"Y":362.0}]},{"StartTime":133432.0,"Objects":[{"StartTime":133432.0,"EndTime":133432.0,"X":512.0,"Y":239.0}]},{"StartTime":133595.0,"Objects":[{"StartTime":133595.0,"EndTime":133595.0,"X":336.88028,"Y":84.88028}]},{"StartTime":133676.0,"Objects":[{"StartTime":133676.0,"EndTime":133676.0,"X":340.440155,"Y":88.44014}]},{"StartTime":133757.0,"Objects":[{"StartTime":133757.0,"EndTime":133757.0,"X":344.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":133964.0,"EndTime":133964.0,"X":366.340729,"Y":252.2704,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":134081.0,"Objects":[{"StartTime":134081.0,"EndTime":134081.0,"X":297.0,"Y":290.0}]},{"StartTime":134243.0,"Objects":[{"StartTime":134243.0,"EndTime":134243.0,"X":430.0,"Y":145.0}]},{"StartTime":134405.0,"Objects":[{"StartTime":134405.0,"EndTime":134405.0,"X":277.0,"Y":8.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":134531.0,"EndTime":134531.0,"X":249.166824,"Y":99.0191956,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":134730.0,"Objects":[{"StartTime":134730.0,"EndTime":134730.0,"X":442.0,"Y":257.0}]},{"StartTime":134892.0,"Objects":[{"StartTime":134892.0,"EndTime":134892.0,"X":344.0,"Y":92.0}]},{"StartTime":135054.0,"Objects":[{"StartTime":135054.0,"EndTime":135054.0,"X":205.0,"Y":225.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":135180.0,"EndTime":135180.0,"X":100.106705,"Y":249.039276,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":135378.0,"Objects":[{"StartTime":135378.0,"EndTime":135378.0,"X":268.0,"Y":363.0}]},{"StartTime":135541.0,"Objects":[{"StartTime":135541.0,"EndTime":135541.0,"X":91.0,"Y":241.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":135829.0,"EndTime":135829.0,"X":170.039261,"Y":105.009521,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":136027.0,"Objects":[{"StartTime":136027.0,"EndTime":136027.0,"X":331.0,"Y":242.0}]},{"StartTime":136189.0,"Objects":[{"StartTime":136189.0,"EndTime":136189.0,"X":128.0,"Y":372.0}]},{"StartTime":136351.0,"Objects":[{"StartTime":136351.0,"EndTime":136351.0,"X":223.0,"Y":299.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":136558.0,"EndTime":136558.0,"X":360.467651,"Y":366.594482,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":136676.0,"Objects":[{"StartTime":136676.0,"EndTime":136676.0,"X":433.0,"Y":383.0}]},{"StartTime":136838.0,"Objects":[{"StartTime":136838.0,"EndTime":136838.0,"X":257.0,"Y":167.0}]},{"StartTime":137000.0,"Objects":[{"StartTime":137000.0,"EndTime":137000.0,"X":491.0,"Y":120.0}]},{"StartTime":137162.0,"Objects":[{"StartTime":137162.0,"EndTime":137162.0,"X":330.88028,"Y":240.88028}]},{"StartTime":137243.0,"Objects":[{"StartTime":137243.0,"EndTime":137243.0,"X":334.440155,"Y":244.44014}]},{"StartTime":137324.0,"Objects":[{"StartTime":137324.0,"EndTime":137324.0,"X":338.0,"Y":248.0}]},{"StartTime":137487.0,"Objects":[{"StartTime":137487.0,"EndTime":137487.0,"X":198.0,"Y":103.0}]},{"StartTime":137649.0,"Objects":[{"StartTime":137649.0,"EndTime":137649.0,"X":435.0,"Y":212.0}]},{"StartTime":137811.0,"Objects":[{"StartTime":137811.0,"EndTime":137811.0,"X":208.0,"Y":351.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":137856.0,"EndTime":137856.0,"X":222.192551,"Y":298.960632,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":137973.0,"Objects":[{"StartTime":137973.0,"EndTime":137973.0,"X":69.0,"Y":173.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":138054.0,"EndTime":138054.0,"X":79.83893,"Y":225.839767,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":138099.0,"EndTime":138099.0,"X":69.0,"Y":173.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":138297.0,"Objects":[{"StartTime":138297.0,"EndTime":138297.0,"X":208.0,"Y":50.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":138342.0,"EndTime":138342.0,"X":197.973,"Y":102.999832,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":138460.0,"Objects":[{"StartTime":138460.0,"EndTime":138460.0,"X":46.0,"Y":24.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":138505.0,"EndTime":138505.0,"X":95.8045349,"Y":3.86346078,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":138622.0,"Objects":[{"StartTime":138622.0,"EndTime":138622.0,"X":256.440155,"Y":201.44014,"StackOffset":{"X":-3.559845,"Y":-3.55986023}},{"StartTime":138667.0,"EndTime":138667.0,"X":206.76033,"Y":180.891571,"StackOffset":{"X":-3.559845,"Y":-3.55986023}}]},{"StartTime":138784.0,"Objects":[{"StartTime":138784.0,"EndTime":138784.0,"X":343.0,"Y":15.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":138829.0,"EndTime":138829.0,"X":355.401733,"Y":65.85758,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":138946.0,"Objects":[{"StartTime":138946.0,"EndTime":138946.0,"X":210.0,"Y":184.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":139234.0,"EndTime":139234.0,"X":362.085327,"Y":234.37854,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":139432.0,"Objects":[{"StartTime":139432.0,"EndTime":139432.0,"X":512.0,"Y":353.0}]},{"StartTime":139595.0,"Objects":[{"StartTime":139595.0,"EndTime":139595.0,"X":435.0,"Y":378.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":139721.0,"EndTime":139721.0,"X":455.4719,"Y":272.080231,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":139919.0,"Objects":[{"StartTime":139919.0,"EndTime":139919.0,"X":274.0,"Y":125.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":140126.0,"EndTime":140126.0,"X":280.4883,"Y":280.441528,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":140243.0,"Objects":[{"StartTime":140243.0,"EndTime":140243.0,"X":289.0,"Y":361.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":140531.0,"EndTime":140531.0,"X":208.826126,"Y":293.6522,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":140730.0,"Objects":[{"StartTime":140730.0,"EndTime":140730.0,"X":387.0,"Y":151.0}]},{"StartTime":140892.0,"Objects":[{"StartTime":140892.0,"EndTime":140892.0,"X":187.0,"Y":95.0}]},{"StartTime":141054.0,"Objects":[{"StartTime":141054.0,"EndTime":141054.0,"X":368.0,"Y":321.0}]},{"StartTime":141216.0,"Objects":[{"StartTime":141216.0,"EndTime":141216.0,"X":287.0,"Y":41.0}]},{"StartTime":141378.0,"Objects":[{"StartTime":141378.0,"EndTime":141378.0,"X":101.0,"Y":196.0}]},{"StartTime":141541.0,"Objects":[{"StartTime":141541.0,"EndTime":141541.0,"X":308.0,"Y":124.0}]},{"StartTime":141703.0,"Objects":[{"StartTime":141703.0,"EndTime":141703.0,"X":107.0,"Y":7.0}]},{"StartTime":141865.0,"Objects":[{"StartTime":141865.0,"EndTime":141865.0,"X":226.0,"Y":219.0}]},{"StartTime":142027.0,"Objects":[{"StartTime":142027.0,"EndTime":142027.0,"X":374.0,"Y":40.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":142315.0,"EndTime":142315.0,"X":508.23288,"Y":152.034592,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":142514.0,"Objects":[{"StartTime":142514.0,"EndTime":142514.0,"X":287.0,"Y":41.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":142640.0,"EndTime":142640.0,"X":181.518585,"Y":18.5109634,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":142838.0,"Objects":[{"StartTime":142838.0,"EndTime":142838.0,"X":29.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":143045.0,"EndTime":143045.0,"X":167.568069,"Y":175.772644,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":143162.0,"Objects":[{"StartTime":143162.0,"EndTime":143162.0,"X":226.0,"Y":219.0}]},{"StartTime":143324.0,"Objects":[{"StartTime":143324.0,"EndTime":143324.0,"X":356.88028,"Y":340.88028}]},{"StartTime":143405.0,"Objects":[{"StartTime":143405.0,"EndTime":143405.0,"X":360.440155,"Y":344.440155}]},{"StartTime":143487.0,"Objects":[{"StartTime":143487.0,"EndTime":143487.0,"X":364.0,"Y":348.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":143532.0,"EndTime":143532.0,"X":311.31073,"Y":359.54834,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":143649.0,"Objects":[{"StartTime":143649.0,"EndTime":143649.0,"X":429.0,"Y":222.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":143694.0,"EndTime":143694.0,"X":480.925385,"Y":236.604019,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":143811.0,"Objects":[{"StartTime":143811.0,"EndTime":143811.0,"X":344.0,"Y":142.0}]},{"StartTime":143892.0,"Objects":[{"StartTime":143892.0,"EndTime":143892.0,"X":313.0,"Y":113.0}]},{"StartTime":143973.0,"Objects":[{"StartTime":143973.0,"EndTime":143973.0,"X":311.0,"Y":72.0}]},{"StartTime":144054.0,"Objects":[{"StartTime":144054.0,"EndTime":144054.0,"X":342.0,"Y":40.0}]},{"StartTime":144135.0,"Objects":[{"StartTime":144135.0,"EndTime":144135.0,"X":403.0,"Y":74.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":144423.0,"EndTime":144423.0,"X":204.603455,"Y":131.8075,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":144622.0,"Objects":[{"StartTime":144622.0,"EndTime":144622.0,"X":365.0,"Y":267.0}]},{"StartTime":144784.0,"Objects":[{"StartTime":144784.0,"EndTime":144784.0,"X":232.0,"Y":48.0}]},{"StartTime":144946.0,"Objects":[{"StartTime":144946.0,"EndTime":144946.0,"X":106.0,"Y":218.0}]},{"StartTime":145108.0,"Objects":[{"StartTime":145108.0,"EndTime":145108.0,"X":313.0,"Y":113.0}]},{"StartTime":145270.0,"Objects":[{"StartTime":145270.0,"EndTime":145270.0,"X":99.88028,"Y":-7.119718}]},{"StartTime":145351.0,"Objects":[{"StartTime":145351.0,"EndTime":145351.0,"X":103.44014,"Y":-3.559859}]},{"StartTime":145432.0,"Objects":[{"StartTime":145432.0,"EndTime":145432.0,"X":107.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":145558.0,"EndTime":145558.0,"X":122.551392,"Y":106.59304,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":145757.0,"Objects":[{"StartTime":145757.0,"EndTime":145757.0,"X":325.0,"Y":27.0}]},{"StartTime":145919.0,"Objects":[{"StartTime":145919.0,"EndTime":145919.0,"X":256.0,"Y":238.0}]},{"StartTime":146081.0,"Objects":[{"StartTime":146081.0,"EndTime":146081.0,"X":149.0,"Y":107.0}]},{"StartTime":146243.0,"Objects":[{"StartTime":146243.0,"EndTime":146243.0,"X":368.0,"Y":228.0}]},{"StartTime":146405.0,"Objects":[{"StartTime":146405.0,"EndTime":146405.0,"X":120.0,"Y":384.0}]},{"StartTime":146568.0,"Objects":[{"StartTime":146568.0,"EndTime":146568.0,"X":329.0,"Y":316.0}]},{"StartTime":146730.0,"Objects":[{"StartTime":146730.0,"EndTime":146730.0,"X":149.0,"Y":107.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":147018.0,"EndTime":147018.0,"X":166.077515,"Y":252.1589,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":147216.0,"Objects":[{"StartTime":147216.0,"EndTime":147216.0,"X":113.0,"Y":306.0}]},{"StartTime":147378.0,"Objects":[{"StartTime":147378.0,"EndTime":147378.0,"X":318.0,"Y":147.0}]},{"StartTime":147541.0,"Objects":[{"StartTime":147541.0,"EndTime":147541.0,"X":145.44014,"Y":67.44014}]},{"StartTime":147703.0,"Objects":[{"StartTime":147703.0,"EndTime":147703.0,"X":149.0,"Y":71.0}]},{"StartTime":147865.0,"Objects":[{"StartTime":147865.0,"EndTime":147865.0,"X":246.0,"Y":15.0}]},{"StartTime":148027.0,"Objects":[{"StartTime":148027.0,"EndTime":148027.0,"X":199.0,"Y":171.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148153.0,"EndTime":148153.0,"X":128.68573,"Y":190.439545,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":148351.0,"Objects":[{"StartTime":148351.0,"EndTime":148351.0,"X":256.0,"Y":101.0}]},{"StartTime":148514.0,"Objects":[{"StartTime":148514.0,"EndTime":148514.0,"X":356.0,"Y":225.0}]},{"StartTime":148676.0,"Objects":[{"StartTime":148676.0,"EndTime":148676.0,"X":424.0,"Y":185.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148802.0,"EndTime":148802.0,"X":436.841553,"Y":113.358727,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149000.0,"Objects":[{"StartTime":149000.0,"EndTime":149000.0,"X":270.0,"Y":245.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":149126.0,"EndTime":149126.0,"X":283.376617,"Y":316.208832,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149324.0,"Objects":[{"StartTime":149324.0,"EndTime":149324.0,"X":360.0,"Y":339.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":149612.0,"EndTime":149612.0,"X":221.613678,"Y":376.0835,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149811.0,"Objects":[{"StartTime":149811.0,"EndTime":149811.0,"X":356.0,"Y":225.0}]},{"StartTime":149973.0,"Objects":[{"StartTime":149973.0,"EndTime":149973.0,"X":168.0,"Y":96.0}]},{"StartTime":150216.0,"Objects":[{"StartTime":150216.0,"EndTime":150216.0,"X":360.0,"Y":339.0}]},{"StartTime":150460.0,"Objects":[{"StartTime":150460.0,"EndTime":150460.0,"X":242.0,"Y":25.0}]},{"StartTime":150622.0,"Objects":[{"StartTime":150622.0,"EndTime":150622.0,"X":86.0,"Y":185.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":150784.0,"EndTime":150784.0,"X":22.42053,"Y":160.525543,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":150910.0,"EndTime":150910.0,"X":86.0,"Y":185.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":151108.0,"Objects":[{"StartTime":151108.0,"EndTime":151108.0,"X":140.0,"Y":240.0}]},{"StartTime":151270.0,"Objects":[{"StartTime":151270.0,"EndTime":151270.0,"X":256.0,"Y":131.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":151396.0,"EndTime":151396.0,"X":327.1842,"Y":114.462257,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":151514.0,"Objects":[{"StartTime":151514.0,"EndTime":151514.0,"X":399.0,"Y":95.0}]},{"StartTime":151595.0,"Objects":[{"StartTime":151595.0,"EndTime":151595.0,"X":419.0,"Y":89.0}]},{"StartTime":151757.0,"Objects":[{"StartTime":151757.0,"EndTime":151757.0,"X":319.0,"Y":36.0}]},{"StartTime":151919.0,"Objects":[{"StartTime":151919.0,"EndTime":151919.0,"X":416.0,"Y":229.0}]},{"StartTime":152081.0,"Objects":[{"StartTime":152081.0,"EndTime":152081.0,"X":489.0,"Y":32.0}]},{"StartTime":152243.0,"Objects":[{"StartTime":152243.0,"EndTime":152243.0,"X":327.0,"Y":114.0}]},{"StartTime":152568.0,"Objects":[{"StartTime":152568.0,"EndTime":152568.0,"X":331.0,"Y":126.0}]},{"StartTime":152892.0,"Objects":[{"StartTime":152892.0,"EndTime":152892.0,"X":335.0,"Y":138.0}]},{"StartTime":153216.0,"Objects":[{"StartTime":153216.0,"EndTime":153216.0,"X":488.0,"Y":256.0}]},{"StartTime":153541.0,"Objects":[{"StartTime":153541.0,"EndTime":153541.0,"X":488.0,"Y":244.0}]},{"StartTime":153865.0,"Objects":[{"StartTime":153865.0,"EndTime":153865.0,"X":489.0,"Y":228.0}]},{"StartTime":154027.0,"Objects":[{"StartTime":154027.0,"EndTime":154027.0,"X":315.0,"Y":330.0}]},{"StartTime":154189.0,"Objects":[{"StartTime":154189.0,"EndTime":154189.0,"X":426.0,"Y":384.0}]},{"StartTime":154351.0,"Objects":[{"StartTime":154351.0,"EndTime":154351.0,"X":328.88028,"Y":225.88028}]},{"StartTime":154432.0,"Objects":[{"StartTime":154432.0,"EndTime":154432.0,"X":332.440155,"Y":229.44014}]},{"StartTime":154514.0,"Objects":[{"StartTime":154514.0,"EndTime":154514.0,"X":336.0,"Y":233.0}]},{"StartTime":154676.0,"Objects":[{"StartTime":154676.0,"EndTime":154676.0,"X":137.0,"Y":361.0}]},{"StartTime":154838.0,"Objects":[{"StartTime":154838.0,"EndTime":154838.0,"X":202.0,"Y":170.0}]},{"StartTime":155162.0,"Objects":[{"StartTime":155162.0,"EndTime":155162.0,"X":205.0,"Y":190.0}]},{"StartTime":155487.0,"Objects":[{"StartTime":155487.0,"EndTime":155487.0,"X":208.0,"Y":209.0}]},{"StartTime":155811.0,"Objects":[{"StartTime":155811.0,"EndTime":155811.0,"X":80.0,"Y":122.0}]},{"StartTime":155973.0,"Objects":[{"StartTime":155973.0,"EndTime":155973.0,"X":230.0,"Y":48.0}]},{"StartTime":156135.0,"Objects":[{"StartTime":156135.0,"EndTime":156135.0,"X":61.0,"Y":0.0}]},{"StartTime":156297.0,"Objects":[{"StartTime":156297.0,"EndTime":156297.0,"X":193.0,"Y":148.0}]},{"StartTime":156378.0,"Objects":[{"StartTime":156378.0,"EndTime":156378.0,"X":217.0,"Y":158.0}]},{"StartTime":156460.0,"Objects":[{"StartTime":156460.0,"EndTime":156460.0,"X":244.0,"Y":152.0}]},{"StartTime":156622.0,"Objects":[{"StartTime":156622.0,"EndTime":156622.0,"X":120.0,"Y":246.0}]},{"StartTime":156784.0,"Objects":[{"StartTime":156784.0,"EndTime":156784.0,"X":294.0,"Y":99.0}]},{"StartTime":156865.0,"Objects":[{"StartTime":156865.0,"EndTime":156865.0,"X":318.0,"Y":82.0}]},{"StartTime":156946.0,"Objects":[{"StartTime":156946.0,"EndTime":156946.0,"X":351.0,"Y":87.0}]},{"StartTime":157108.0,"Objects":[{"StartTime":157108.0,"EndTime":157108.0,"X":428.0,"Y":207.0}]},{"StartTime":157270.0,"Objects":[{"StartTime":157270.0,"EndTime":157270.0,"X":230.0,"Y":48.0}]},{"StartTime":157432.0,"Objects":[{"StartTime":157432.0,"EndTime":157432.0,"X":120.0,"Y":246.0}]},{"StartTime":157757.0,"Objects":[{"StartTime":157757.0,"EndTime":157757.0,"X":122.0,"Y":229.0}]},{"StartTime":158081.0,"Objects":[{"StartTime":158081.0,"EndTime":158081.0,"X":124.0,"Y":213.0}]},{"StartTime":158243.0,"Objects":[{"StartTime":158243.0,"EndTime":158243.0,"X":295.0,"Y":314.0}]},{"StartTime":158405.0,"Objects":[{"StartTime":158405.0,"EndTime":158405.0,"X":122.0,"Y":384.0}]},{"StartTime":158568.0,"Objects":[{"StartTime":158568.0,"EndTime":158568.0,"X":324.0,"Y":222.0}]},{"StartTime":158730.0,"Objects":[{"StartTime":158730.0,"EndTime":158730.0,"X":428.0,"Y":368.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":158856.0,"EndTime":158856.0,"X":358.3122,"Y":345.993317,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":159054.0,"Objects":[{"StartTime":159054.0,"EndTime":159054.0,"X":380.0,"Y":162.0}]},{"StartTime":159216.0,"Objects":[{"StartTime":159216.0,"EndTime":159216.0,"X":242.0,"Y":215.0}]},{"StartTime":159378.0,"Objects":[{"StartTime":159378.0,"EndTime":159378.0,"X":428.0,"Y":368.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":159585.0,"EndTime":159585.0,"X":447.453766,"Y":260.12,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":159703.0,"Objects":[{"StartTime":159703.0,"EndTime":159703.0,"X":380.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":159910.0,"EndTime":159910.0,"X":426.5376,"Y":66.61574,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":160027.0,"Objects":[{"StartTime":160027.0,"EndTime":160027.0,"X":484.0,"Y":116.0}]},{"StartTime":160189.0,"Objects":[{"StartTime":160189.0,"EndTime":160189.0,"X":242.0,"Y":215.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":160477.0,"EndTime":160477.0,"X":143.721771,"Y":108.139114,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":160676.0,"Objects":[{"StartTime":160676.0,"EndTime":160676.0,"X":327.0,"Y":235.0}]},{"StartTime":160838.0,"Objects":[{"StartTime":160838.0,"EndTime":160838.0,"X":167.88028,"Y":369.88028}]},{"StartTime":160919.0,"Objects":[{"StartTime":160919.0,"EndTime":160919.0,"X":171.44014,"Y":373.440155}]},{"StartTime":161000.0,"Objects":[{"StartTime":161000.0,"EndTime":161000.0,"X":175.0,"Y":377.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":161126.0,"EndTime":161126.0,"X":150.120163,"Y":290.917664,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":161324.0,"Objects":[{"StartTime":161324.0,"EndTime":161324.0,"X":330.0,"Y":156.0}]},{"StartTime":161487.0,"Objects":[{"StartTime":161487.0,"EndTime":161487.0,"X":471.0,"Y":341.0}]},{"StartTime":161568.0,"Objects":[{"StartTime":161568.0,"EndTime":161568.0,"X":434.0,"Y":364.0}]},{"StartTime":161649.0,"Objects":[{"StartTime":161649.0,"EndTime":161649.0,"X":399.0,"Y":355.0}]},{"StartTime":161811.0,"Objects":[{"StartTime":161811.0,"EndTime":161811.0,"X":328.0,"Y":258.0}]},{"StartTime":161973.0,"Objects":[{"StartTime":161973.0,"EndTime":161973.0,"X":474.0,"Y":149.0}]},{"StartTime":162054.0,"Objects":[{"StartTime":162054.0,"EndTime":162054.0,"X":466.0,"Y":186.0}]},{"StartTime":162135.0,"Objects":[{"StartTime":162135.0,"EndTime":162135.0,"X":458.0,"Y":219.0}]},{"StartTime":162297.0,"Objects":[{"StartTime":162297.0,"EndTime":162297.0,"X":363.0,"Y":82.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":162585.0,"EndTime":162585.0,"X":195.744888,"Y":149.32608,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":162784.0,"Objects":[{"StartTime":162784.0,"EndTime":162784.0,"X":139.0,"Y":96.0}]},{"StartTime":162946.0,"Objects":[{"StartTime":162946.0,"EndTime":162946.0,"X":35.0,"Y":225.0}]},{"StartTime":163108.0,"Objects":[{"StartTime":163108.0,"EndTime":163108.0,"X":60.0,"Y":152.0}]},{"StartTime":163270.0,"Objects":[{"StartTime":163270.0,"EndTime":163270.0,"X":223.0,"Y":298.0}]},{"StartTime":163432.0,"Objects":[{"StartTime":163432.0,"EndTime":163432.0,"X":210.0,"Y":223.0}]},{"StartTime":163595.0,"Objects":[{"StartTime":163595.0,"EndTime":163595.0,"X":45.0,"Y":321.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":163721.0,"EndTime":163721.0,"X":137.6757,"Y":355.2489,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":163919.0,"Objects":[{"StartTime":163919.0,"EndTime":163919.0,"X":283.440155,"Y":242.44014}]},{"StartTime":164081.0,"Objects":[{"StartTime":164081.0,"EndTime":164081.0,"X":139.0,"Y":96.0}]},{"StartTime":164243.0,"Objects":[{"StartTime":164243.0,"EndTime":164243.0,"X":287.0,"Y":246.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":164369.0,"EndTime":164369.0,"X":381.60495,"Y":218.029053,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":164568.0,"Objects":[{"StartTime":164568.0,"EndTime":164568.0,"X":228.0,"Y":64.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":164775.0,"EndTime":164775.0,"X":178.179764,"Y":177.656937,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":164892.0,"Objects":[{"StartTime":164892.0,"EndTime":164892.0,"X":187.0,"Y":251.0}]},{"StartTime":165054.0,"Objects":[{"StartTime":165054.0,"EndTime":165054.0,"X":362.0,"Y":95.0}]},{"StartTime":165216.0,"Objects":[{"StartTime":165216.0,"EndTime":165216.0,"X":181.55986,"Y":180.55986}]},{"StartTime":165378.0,"Objects":[{"StartTime":165378.0,"EndTime":165378.0,"X":393.0,"Y":331.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":165504.0,"EndTime":165504.0,"X":406.0307,"Y":240.255035,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":165703.0,"Objects":[{"StartTime":165703.0,"EndTime":165703.0,"X":224.0,"Y":352.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":165829.0,"EndTime":165829.0,"X":127.282745,"Y":373.0001,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166027.0,"Objects":[{"StartTime":166027.0,"EndTime":166027.0,"X":38.0,"Y":139.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":166315.0,"EndTime":166315.0,"X":94.76893,"Y":202.286728,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166514.0,"Objects":[{"StartTime":166514.0,"EndTime":166514.0,"X":224.0,"Y":352.0}]},{"StartTime":166676.0,"Objects":[{"StartTime":166676.0,"EndTime":166676.0,"X":312.88028,"Y":211.88028}]},{"StartTime":166757.0,"Objects":[{"StartTime":166757.0,"EndTime":166757.0,"X":316.440155,"Y":215.44014}]},{"StartTime":166838.0,"Objects":[{"StartTime":166838.0,"EndTime":166838.0,"X":320.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":166964.0,"EndTime":166964.0,"X":335.705536,"Y":316.9286,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":167162.0,"Objects":[{"StartTime":167162.0,"EndTime":167162.0,"X":208.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":167369.0,"EndTime":167369.0,"X":314.63,"Y":110.89566,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":167487.0,"Objects":[{"StartTime":167487.0,"EndTime":167487.0,"X":383.440155,"Y":81.44014}]},{"StartTime":167811.0,"Objects":[{"StartTime":167811.0,"EndTime":167811.0,"X":387.0,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":167937.0,"EndTime":167937.0,"X":402.5302,"Y":182.887451,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":168135.0,"Objects":[{"StartTime":168135.0,"EndTime":168135.0,"X":247.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":168261.0,"EndTime":168261.0,"X":227.808548,"Y":96.07656,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":168460.0,"Objects":[{"StartTime":168460.0,"EndTime":168460.0,"X":51.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":168667.0,"EndTime":168667.0,"X":160.370071,"Y":209.627731,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":168784.0,"Objects":[{"StartTime":168784.0,"EndTime":168784.0,"X":184.0,"Y":282.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":168910.0,"EndTime":168910.0,"X":277.386383,"Y":312.846649,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":169108.0,"Objects":[{"StartTime":169108.0,"EndTime":169108.0,"X":402.0,"Y":182.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":169234.0,"EndTime":169234.0,"X":307.239227,"Y":209.268143,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":169432.0,"Objects":[{"StartTime":169432.0,"EndTime":169432.0,"X":414.0,"Y":367.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":169558.0,"EndTime":169558.0,"X":429.1886,"Y":278.648743,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":169757.0,"Objects":[{"StartTime":169757.0,"EndTime":169757.0,"X":223.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":169883.0,"EndTime":169883.0,"X":233.536072,"Y":214.5363,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":170081.0,"Objects":[{"StartTime":170081.0,"EndTime":170081.0,"X":488.0,"Y":67.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":170288.0,"EndTime":170288.0,"X":367.508942,"Y":32.84226,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":170405.0,"Objects":[{"StartTime":170405.0,"EndTime":170405.0,"X":319.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":170531.0,"EndTime":170531.0,"X":222.873062,"Y":115.492477,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":170730.0,"Objects":[{"StartTime":170730.0,"EndTime":170730.0,"X":393.0,"Y":237.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":170856.0,"EndTime":170856.0,"X":487.852,"Y":265.337646,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":171054.0,"Objects":[{"StartTime":171054.0,"EndTime":171054.0,"X":308.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":171180.0,"EndTime":171180.0,"X":293.36615,"Y":298.094452,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":171378.0,"Objects":[{"StartTime":171378.0,"EndTime":171378.0,"X":195.0,"Y":44.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":171585.0,"EndTime":171585.0,"X":177.52536,"Y":191.740128,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":171703.0,"Objects":[{"StartTime":171703.0,"EndTime":171703.0,"X":230.0,"Y":247.0}]},{"StartTime":171865.0,"Objects":[{"StartTime":171865.0,"EndTime":171865.0,"X":31.0,"Y":366.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":172153.0,"EndTime":172153.0,"X":98.42071,"Y":234.214081,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":172351.0,"Objects":[{"StartTime":172351.0,"EndTime":172351.0,"X":204.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":172558.0,"EndTime":172558.0,"X":71.31268,"Y":15.4140854,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":172676.0,"Objects":[{"StartTime":172676.0,"EndTime":172676.0,"X":14.0,"Y":62.0}]},{"StartTime":172838.0,"Objects":[{"StartTime":172838.0,"EndTime":172838.0,"X":161.0,"Y":175.0}]},{"StartTime":173000.0,"Objects":[{"StartTime":173000.0,"EndTime":173000.0,"X":35.0,"Y":149.0}]},{"StartTime":173162.0,"Objects":[{"StartTime":173162.0,"EndTime":173162.0,"X":204.0,"Y":62.0}]},{"StartTime":173324.0,"Objects":[{"StartTime":173324.0,"EndTime":173324.0,"X":262.0,"Y":266.0}]},{"StartTime":173487.0,"Objects":[{"StartTime":173487.0,"EndTime":173487.0,"X":124.0,"Y":91.0}]},{"StartTime":173649.0,"Objects":[{"StartTime":173649.0,"EndTime":173649.0,"X":123.0,"Y":310.0}]},{"StartTime":173811.0,"Objects":[{"StartTime":173811.0,"EndTime":173811.0,"X":265.0,"Y":107.0}]},{"StartTime":173973.0,"Objects":[{"StartTime":173973.0,"EndTime":173973.0,"X":319.0,"Y":381.0}]},{"StartTime":174135.0,"Objects":[{"StartTime":174135.0,"EndTime":174135.0,"X":161.0,"Y":175.0}]},{"StartTime":174297.0,"Objects":[{"StartTime":174297.0,"EndTime":174297.0,"X":363.0,"Y":258.0}]},{"StartTime":174460.0,"Objects":[{"StartTime":174460.0,"EndTime":174460.0,"X":155.0,"Y":384.0}]},{"StartTime":174622.0,"Objects":[{"StartTime":174622.0,"EndTime":174622.0,"X":364.0,"Y":59.0}]},{"StartTime":174784.0,"Objects":[{"StartTime":174784.0,"EndTime":174784.0,"X":410.0,"Y":341.0}]},{"StartTime":174946.0,"Objects":[{"StartTime":174946.0,"EndTime":174946.0,"X":205.0,"Y":35.0}]},{"StartTime":175108.0,"Objects":[{"StartTime":175108.0,"EndTime":175108.0,"X":123.0,"Y":310.0}]},{"StartTime":175270.0,"Objects":[{"StartTime":175270.0,"EndTime":175270.0,"X":411.0,"Y":183.0}]},{"StartTime":175432.0,"Objects":[{"StartTime":175432.0,"EndTime":175432.0,"X":80.0,"Y":49.0}]},{"StartTime":176081.0,"Objects":[{"StartTime":176081.0,"EndTime":176081.0,"X":67.0,"Y":42.0}]},{"StartTime":176243.0,"Objects":[{"StartTime":176243.0,"EndTime":176243.0,"X":231.0,"Y":249.0}]},{"StartTime":176405.0,"Objects":[{"StartTime":176405.0,"EndTime":176405.0,"X":433.0,"Y":101.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":176612.0,"EndTime":176612.0,"X":374.4514,"Y":152.1901,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":176730.0,"Objects":[{"StartTime":176730.0,"EndTime":176730.0,"X":427.0,"Y":207.0}]},{"StartTime":176892.0,"Objects":[{"StartTime":176892.0,"EndTime":176892.0,"X":281.0,"Y":95.0}]},{"StartTime":177054.0,"Objects":[{"StartTime":177054.0,"EndTime":177054.0,"X":471.0,"Y":27.0}]},{"StartTime":177216.0,"Objects":[{"StartTime":177216.0,"EndTime":177216.0,"X":265.88028,"Y":211.88028}]},{"StartTime":177297.0,"Objects":[{"StartTime":177297.0,"EndTime":177297.0,"X":269.440155,"Y":215.44014}]},{"StartTime":177378.0,"Objects":[{"StartTime":177378.0,"EndTime":177378.0,"X":273.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":177423.0,"EndTime":177423.0,"X":221.380753,"Y":195.4054,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":177541.0,"Objects":[{"StartTime":177541.0,"EndTime":177541.0,"X":377.0,"Y":361.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":177748.0,"EndTime":177748.0,"X":429.262421,"Y":340.613739,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":177865.0,"Objects":[{"StartTime":177865.0,"EndTime":177865.0,"X":465.0,"Y":274.0}]},{"StartTime":182892.0,"Objects":[{"StartTime":182892.0,"EndTime":182892.0,"X":100.0,"Y":334.0}]},{"StartTime":183054.0,"Objects":[{"StartTime":183054.0,"EndTime":183054.0,"X":72.0,"Y":268.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":183378.0,"EndTime":183378.0,"X":176.303543,"Y":275.243622,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":183504.0,"EndTime":183504.0,"X":206.569153,"Y":320.91394,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":183703.0,"Objects":[{"StartTime":183703.0,"EndTime":183703.0,"X":328.0,"Y":140.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":183991.0,"EndTime":183991.0,"X":219.648621,"Y":165.7105,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":184189.0,"Objects":[{"StartTime":184189.0,"EndTime":184189.0,"X":341.88028,"Y":296.88028}]},{"StartTime":184270.0,"Objects":[{"StartTime":184270.0,"EndTime":184270.0,"X":345.440155,"Y":300.440155}]},{"StartTime":184351.0,"Objects":[{"StartTime":184351.0,"EndTime":184351.0,"X":349.0,"Y":304.0}]},{"StartTime":184838.0,"Objects":[{"StartTime":184838.0,"EndTime":184838.0,"X":349.0,"Y":304.0}]},{"StartTime":185000.0,"Objects":[{"StartTime":185000.0,"EndTime":185000.0,"X":219.0,"Y":165.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":185126.0,"EndTime":185126.0,"X":230.723755,"Y":110.568245,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":185324.0,"Objects":[{"StartTime":185324.0,"EndTime":185324.0,"X":353.0,"Y":62.0}]},{"StartTime":185568.0,"Objects":[{"StartTime":185568.0,"EndTime":185568.0,"X":121.0,"Y":275.0}]},{"StartTime":185649.0,"Objects":[{"StartTime":185649.0,"EndTime":185649.0,"X":129.0,"Y":262.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":185775.0,"EndTime":185775.0,"X":200.858246,"Y":248.692917,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":185892.0,"Objects":[{"StartTime":185892.0,"EndTime":185892.0,"X":272.0,"Y":234.0}]},{"StartTime":185973.0,"Objects":[{"StartTime":185973.0,"EndTime":185973.0,"X":295.0,"Y":231.0}]},{"StartTime":186135.0,"Objects":[{"StartTime":186135.0,"EndTime":186135.0,"X":219.0,"Y":165.0}]},{"StartTime":186297.0,"Objects":[{"StartTime":186297.0,"EndTime":186297.0,"X":349.0,"Y":304.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":186423.0,"EndTime":186423.0,"X":334.49353,"Y":375.625732,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":186622.0,"Objects":[{"StartTime":186622.0,"EndTime":186622.0,"X":468.0,"Y":214.0}]},{"StartTime":186784.0,"Objects":[{"StartTime":186784.0,"EndTime":186784.0,"X":398.0,"Y":238.0}]},{"StartTime":186946.0,"Objects":[{"StartTime":186946.0,"EndTime":186946.0,"X":432.0,"Y":55.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":187072.0,"EndTime":187072.0,"X":446.1718,"Y":126.692726,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":187189.0,"Objects":[{"StartTime":187189.0,"EndTime":187189.0,"X":464.0,"Y":196.0}]},{"StartTime":187270.0,"Objects":[{"StartTime":187270.0,"EndTime":187270.0,"X":468.0,"Y":214.0}]},{"StartTime":187432.0,"Objects":[{"StartTime":187432.0,"EndTime":187432.0,"X":338.0,"Y":93.0}]},{"StartTime":187595.0,"Objects":[{"StartTime":187595.0,"EndTime":187595.0,"X":219.0,"Y":165.0}]},{"StartTime":187676.0,"Objects":[{"StartTime":187676.0,"EndTime":187676.0,"X":187.0,"Y":181.0}]},{"StartTime":187757.0,"Objects":[{"StartTime":187757.0,"EndTime":187757.0,"X":157.0,"Y":164.0}]},{"StartTime":187838.0,"Objects":[{"StartTime":187838.0,"EndTime":187838.0,"X":152.0,"Y":127.0}]},{"StartTime":187919.0,"Objects":[{"StartTime":187919.0,"EndTime":187919.0,"X":177.0,"Y":105.0}]},{"StartTime":188081.0,"Objects":[{"StartTime":188081.0,"EndTime":188081.0,"X":309.88028,"Y":225.88028}]},{"StartTime":188162.0,"Objects":[{"StartTime":188162.0,"EndTime":188162.0,"X":313.440155,"Y":229.44014}]},{"StartTime":188243.0,"Objects":[{"StartTime":188243.0,"EndTime":188243.0,"X":317.0,"Y":233.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":188450.0,"EndTime":188450.0,"X":296.006622,"Y":340.591,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":188568.0,"Objects":[{"StartTime":188568.0,"EndTime":188568.0,"X":353.0,"Y":384.0}]},{"StartTime":188730.0,"Objects":[{"StartTime":188730.0,"EndTime":188730.0,"X":216.0,"Y":275.0}]},{"StartTime":188892.0,"Objects":[{"StartTime":188892.0,"EndTime":188892.0,"X":385.0,"Y":171.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":189018.0,"EndTime":189018.0,"X":398.602173,"Y":242.736786,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":189216.0,"Objects":[{"StartTime":189216.0,"EndTime":189216.0,"X":194.0,"Y":34.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":189342.0,"EndTime":189342.0,"X":176.858063,"Y":104.771019,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":189460.0,"Objects":[{"StartTime":189460.0,"EndTime":189460.0,"X":118.44014,"Y":152.44014}]},{"StartTime":189541.0,"Objects":[{"StartTime":189541.0,"EndTime":189541.0,"X":122.0,"Y":156.0}]},{"StartTime":189703.0,"Objects":[{"StartTime":189703.0,"EndTime":189703.0,"X":293.88028,"Y":37.8802834}]},{"StartTime":189784.0,"Objects":[{"StartTime":189784.0,"EndTime":189784.0,"X":297.440155,"Y":41.44014}]},{"StartTime":189865.0,"Objects":[{"StartTime":189865.0,"EndTime":189865.0,"X":301.0,"Y":45.0}]},{"StartTime":190027.0,"Objects":[{"StartTime":190027.0,"EndTime":190027.0,"X":385.0,"Y":171.0}]},{"StartTime":190189.0,"Objects":[{"StartTime":190189.0,"EndTime":190189.0,"X":186.88028,"Y":26.8802814}]},{"StartTime":190270.0,"Objects":[{"StartTime":190270.0,"EndTime":190270.0,"X":190.44014,"Y":30.4401417}]},{"StartTime":190351.0,"Objects":[{"StartTime":190351.0,"EndTime":190351.0,"X":194.0,"Y":34.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":190396.0,"EndTime":190396.0,"X":199.64093,"Y":70.10196,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":190514.0,"Objects":[{"StartTime":190514.0,"EndTime":190514.0,"X":34.8802834,"Y":240.88028}]},{"StartTime":190595.0,"Objects":[{"StartTime":190595.0,"EndTime":190595.0,"X":38.44014,"Y":244.44014}]},{"StartTime":190676.0,"Objects":[{"StartTime":190676.0,"EndTime":190676.0,"X":42.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":190721.0,"EndTime":190721.0,"X":47.64093,"Y":211.898041,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":190838.0,"Objects":[{"StartTime":190838.0,"EndTime":190838.0,"X":16.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":191162.0,"EndTime":191162.0,"X":119.469978,"Y":147.29715,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":191288.0,"EndTime":191288.0,"X":148.708221,"Y":193.475845,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":191487.0,"Objects":[{"StartTime":191487.0,"EndTime":191487.0,"X":296.0,"Y":345.0}]},{"StartTime":191568.0,"Objects":[{"StartTime":191568.0,"EndTime":191568.0,"X":261.0,"Y":370.0}]},{"StartTime":191649.0,"Objects":[{"StartTime":191649.0,"EndTime":191649.0,"X":221.0,"Y":354.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":191694.0,"EndTime":191694.0,"X":213.887466,"Y":298.299835,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":191811.0,"Objects":[{"StartTime":191811.0,"EndTime":191811.0,"X":378.0,"Y":138.0}]},{"StartTime":191892.0,"Objects":[{"StartTime":191892.0,"EndTime":191892.0,"X":343.0,"Y":113.0}]},{"StartTime":191973.0,"Objects":[{"StartTime":191973.0,"EndTime":191973.0,"X":303.0,"Y":129.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":192018.0,"EndTime":192018.0,"X":295.887482,"Y":184.700165,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":192135.0,"Objects":[{"StartTime":192135.0,"EndTime":192135.0,"X":352.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":192423.0,"EndTime":192423.0,"X":169.461578,"Y":325.467743,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":192622.0,"Objects":[{"StartTime":192622.0,"EndTime":192622.0,"X":295.0,"Y":184.0}]},{"StartTime":192784.0,"Objects":[{"StartTime":192784.0,"EndTime":192784.0,"X":129.0,"Y":67.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":192910.0,"EndTime":192910.0,"X":214.250961,"Y":97.42061,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":193108.0,"Objects":[{"StartTime":193108.0,"EndTime":193108.0,"X":87.0,"Y":223.0}]},{"StartTime":193270.0,"Objects":[{"StartTime":193270.0,"EndTime":193270.0,"X":223.88028,"Y":72.88028}]},{"StartTime":193351.0,"Objects":[{"StartTime":193351.0,"EndTime":193351.0,"X":227.44014,"Y":76.44014}]},{"StartTime":193432.0,"Objects":[{"StartTime":193432.0,"EndTime":193432.0,"X":231.0,"Y":80.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":193639.0,"EndTime":193639.0,"X":355.849518,"Y":39.56346,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":193757.0,"Objects":[{"StartTime":193757.0,"EndTime":193757.0,"X":414.0,"Y":88.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":193883.0,"EndTime":193883.0,"X":393.473846,"Y":185.032715,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":194081.0,"Objects":[{"StartTime":194081.0,"EndTime":194081.0,"X":273.0,"Y":328.0}]},{"StartTime":194243.0,"Objects":[{"StartTime":194243.0,"EndTime":194243.0,"X":486.0,"Y":204.0}]},{"StartTime":194405.0,"Objects":[{"StartTime":194405.0,"EndTime":194405.0,"X":307.0,"Y":111.0}]},{"StartTime":194568.0,"Objects":[{"StartTime":194568.0,"EndTime":194568.0,"X":431.0,"Y":324.0}]},{"StartTime":194649.0,"Objects":[{"StartTime":194649.0,"EndTime":194649.0,"X":434.0,"Y":307.0}]},{"StartTime":194730.0,"Objects":[{"StartTime":194730.0,"EndTime":194730.0,"X":437.0,"Y":293.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":195018.0,"EndTime":195018.0,"X":272.098663,"Y":327.366364,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":195216.0,"Objects":[{"StartTime":195216.0,"EndTime":195216.0,"X":119.0,"Y":181.0}]},{"StartTime":195378.0,"Objects":[{"StartTime":195378.0,"EndTime":195378.0,"X":30.0,"Y":306.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":195504.0,"EndTime":195504.0,"X":126.266693,"Y":283.16925,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":195703.0,"Objects":[{"StartTime":195703.0,"EndTime":195703.0,"X":231.0,"Y":143.0}]},{"StartTime":195865.0,"Objects":[{"StartTime":195865.0,"EndTime":195865.0,"X":94.88028,"Y":25.8802814}]},{"StartTime":195946.0,"Objects":[{"StartTime":195946.0,"EndTime":195946.0,"X":98.44014,"Y":29.4401417}]},{"StartTime":196027.0,"Objects":[{"StartTime":196027.0,"EndTime":196027.0,"X":102.0,"Y":33.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":196153.0,"EndTime":196153.0,"X":197.922256,"Y":56.95418,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":196351.0,"Objects":[{"StartTime":196351.0,"EndTime":196351.0,"X":89.0,"Y":175.0}]},{"StartTime":196514.0,"Objects":[{"StartTime":196514.0,"EndTime":196514.0,"X":260.0,"Y":250.0}]},{"StartTime":196676.0,"Objects":[{"StartTime":196676.0,"EndTime":196676.0,"X":97.0,"Y":370.0}]},{"StartTime":196838.0,"Objects":[{"StartTime":196838.0,"EndTime":196838.0,"X":239.88028,"Y":155.88028}]},{"StartTime":196919.0,"Objects":[{"StartTime":196919.0,"EndTime":196919.0,"X":243.44014,"Y":159.44014}]},{"StartTime":197000.0,"Objects":[{"StartTime":197000.0,"EndTime":197000.0,"X":247.0,"Y":163.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":197045.0,"EndTime":197045.0,"X":295.152618,"Y":174.852951,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":197162.0,"Objects":[{"StartTime":197162.0,"EndTime":197162.0,"X":473.0,"Y":339.0}]},{"StartTime":197243.0,"Objects":[{"StartTime":197243.0,"EndTime":197243.0,"X":441.0,"Y":363.0}]},{"StartTime":197324.0,"Objects":[{"StartTime":197324.0,"EndTime":197324.0,"X":403.0,"Y":349.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":197531.0,"EndTime":197531.0,"X":422.4077,"Y":201.501343,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":197649.0,"Objects":[{"StartTime":197649.0,"EndTime":197649.0,"X":472.0,"Y":140.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":197775.0,"EndTime":197775.0,"X":497.565216,"Y":225.263321,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":197973.0,"Objects":[{"StartTime":197973.0,"EndTime":197973.0,"X":344.0,"Y":101.0}]},{"StartTime":198135.0,"Objects":[{"StartTime":198135.0,"EndTime":198135.0,"X":470.0,"Y":38.0}]},{"StartTime":198297.0,"Objects":[{"StartTime":198297.0,"EndTime":198297.0,"X":347.0,"Y":231.0}]},{"StartTime":198460.0,"Objects":[{"StartTime":198460.0,"EndTime":198460.0,"X":200.88028,"Y":1.88028193}]},{"StartTime":198541.0,"Objects":[{"StartTime":198541.0,"EndTime":198541.0,"X":204.44014,"Y":5.44014072}]},{"StartTime":198622.0,"Objects":[{"StartTime":198622.0,"EndTime":198622.0,"X":208.0,"Y":9.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":198748.0,"EndTime":198748.0,"X":301.888275,"Y":39.795578,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":198946.0,"Objects":[{"StartTime":198946.0,"EndTime":198946.0,"X":189.0,"Y":186.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":199153.0,"EndTime":199153.0,"X":49.7648544,"Y":228.957153,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":199270.0,"Objects":[{"StartTime":199270.0,"EndTime":199270.0,"X":-3.559859,"Y":171.44014}]},{"StartTime":199432.0,"Objects":[{"StartTime":199432.0,"EndTime":199432.0,"X":192.0,"Y":352.0}]},{"StartTime":199595.0,"Objects":[{"StartTime":199595.0,"EndTime":199595.0,"X":0.0,"Y":175.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":199721.0,"EndTime":199721.0,"X":22.2606564,"Y":78.42636,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":199919.0,"Objects":[{"StartTime":199919.0,"EndTime":199919.0,"X":244.0,"Y":262.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":200126.0,"EndTime":200126.0,"X":227.027512,"Y":114.432533,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":200243.0,"Objects":[{"StartTime":200243.0,"EndTime":200243.0,"X":174.0,"Y":61.0}]},{"StartTime":200405.0,"Objects":[{"StartTime":200405.0,"EndTime":200405.0,"X":49.0,"Y":228.0}]},{"StartTime":200568.0,"Objects":[{"StartTime":200568.0,"EndTime":200568.0,"X":259.0,"Y":127.0}]},{"StartTime":200730.0,"Objects":[{"StartTime":200730.0,"EndTime":200730.0,"X":78.88028,"Y":-5.119718}]},{"StartTime":200811.0,"Objects":[{"StartTime":200811.0,"EndTime":200811.0,"X":82.44014,"Y":-1.559859}]},{"StartTime":200892.0,"Objects":[{"StartTime":200892.0,"EndTime":200892.0,"X":86.0,"Y":2.0}]},{"StartTime":201054.0,"Objects":[{"StartTime":201054.0,"EndTime":201054.0,"X":244.0,"Y":262.0}]},{"StartTime":201216.0,"Objects":[{"StartTime":201216.0,"EndTime":201216.0,"X":23.0,"Y":124.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201342.0,"EndTime":201342.0,"X":118.862045,"Y":99.96171,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201541.0,"Objects":[{"StartTime":201541.0,"EndTime":201541.0,"X":293.0,"Y":0.0}]},{"StartTime":201703.0,"Objects":[{"StartTime":201703.0,"EndTime":201703.0,"X":447.0,"Y":147.0}]},{"StartTime":201784.0,"Objects":[{"StartTime":201784.0,"EndTime":201784.0,"X":428.0,"Y":166.0}]},{"StartTime":201865.0,"Objects":[{"StartTime":201865.0,"EndTime":201865.0,"X":397.0,"Y":165.0}]},{"StartTime":202027.0,"Objects":[{"StartTime":202027.0,"EndTime":202027.0,"X":483.0,"Y":51.0}]},{"StartTime":202189.0,"Objects":[{"StartTime":202189.0,"EndTime":202189.0,"X":380.0,"Y":149.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202396.0,"EndTime":202396.0,"X":257.8795,"Y":176.7536,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202514.0,"Objects":[{"StartTime":202514.0,"EndTime":202514.0,"X":186.0,"Y":215.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202802.0,"EndTime":202802.0,"X":368.3096,"Y":273.459625,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":203000.0,"Objects":[{"StartTime":203000.0,"EndTime":203000.0,"X":208.0,"Y":96.0}]},{"StartTime":203162.0,"Objects":[{"StartTime":203162.0,"EndTime":203162.0,"X":261.0,"Y":329.0}]},{"StartTime":203324.0,"Objects":[{"StartTime":203324.0,"EndTime":203324.0,"X":380.0,"Y":149.0}]},{"StartTime":203487.0,"Objects":[{"StartTime":203487.0,"EndTime":203487.0,"X":186.0,"Y":215.0}]},{"StartTime":203649.0,"Objects":[{"StartTime":203649.0,"EndTime":203649.0,"X":378.0,"Y":364.0}]},{"StartTime":203811.0,"Objects":[{"StartTime":203811.0,"EndTime":203811.0,"X":279.0,"Y":239.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":204099.0,"EndTime":204099.0,"X":98.91592,"Y":298.552063,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":204297.0,"Objects":[{"StartTime":204297.0,"EndTime":204297.0,"X":281.0,"Y":153.0}]},{"StartTime":204460.0,"Objects":[{"StartTime":204460.0,"EndTime":204460.0,"X":110.0,"Y":46.0}]},{"StartTime":204622.0,"Objects":[{"StartTime":204622.0,"EndTime":204622.0,"X":186.0,"Y":215.0}]},{"StartTime":204784.0,"Objects":[{"StartTime":204784.0,"EndTime":204784.0,"X":315.0,"Y":72.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":204991.0,"EndTime":204991.0,"X":435.8663,"Y":118.276,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":205108.0,"Objects":[{"StartTime":205108.0,"EndTime":205108.0,"X":512.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":205396.0,"EndTime":205396.0,"X":380.2276,"Y":228.202179,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":205595.0,"Objects":[{"StartTime":205595.0,"EndTime":205595.0,"X":512.0,"Y":96.0}]},{"StartTime":205757.0,"Objects":[{"StartTime":205757.0,"EndTime":205757.0,"X":302.0,"Y":224.0}]},{"StartTime":205919.0,"Objects":[{"StartTime":205919.0,"EndTime":205919.0,"X":496.0,"Y":334.0}]},{"StartTime":206081.0,"Objects":[{"StartTime":206081.0,"EndTime":206081.0,"X":363.0,"Y":152.0}]},{"StartTime":206243.0,"Objects":[{"StartTime":206243.0,"EndTime":206243.0,"X":226.0,"Y":365.0}]},{"StartTime":206405.0,"Objects":[{"StartTime":206405.0,"EndTime":206405.0,"X":377.0,"Y":226.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":206693.0,"EndTime":206693.0,"X":208.3632,"Y":146.109634,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":206892.0,"Objects":[{"StartTime":206892.0,"EndTime":206892.0,"X":317.0,"Y":310.0}]},{"StartTime":207054.0,"Objects":[{"StartTime":207054.0,"EndTime":207054.0,"X":282.0,"Y":65.0}]},{"StartTime":207216.0,"Objects":[{"StartTime":207216.0,"EndTime":207216.0,"X":108.0,"Y":232.0}]},{"StartTime":207378.0,"Objects":[{"StartTime":207378.0,"EndTime":207378.0,"X":0.0,"Y":163.0}]},{"StartTime":207460.0,"Objects":[{"StartTime":207460.0,"EndTime":207460.0,"X":21.0,"Y":119.0}]},{"StartTime":207541.0,"Objects":[{"StartTime":207541.0,"EndTime":207541.0,"X":65.0,"Y":101.0}]},{"StartTime":207622.0,"Objects":[{"StartTime":207622.0,"EndTime":207622.0,"X":116.0,"Y":115.0}]},{"StartTime":207703.0,"Objects":[{"StartTime":207703.0,"EndTime":207703.0,"X":131.0,"Y":132.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":207829.0,"EndTime":207829.0,"X":113.029633,"Y":202.713181,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":208027.0,"Objects":[{"StartTime":208027.0,"EndTime":208027.0,"X":209.0,"Y":284.0}]},{"StartTime":208189.0,"Objects":[{"StartTime":208189.0,"EndTime":208189.0,"X":87.0,"Y":342.0}]},{"StartTime":208351.0,"Objects":[{"StartTime":208351.0,"EndTime":208351.0,"X":228.0,"Y":206.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":208477.0,"EndTime":208477.0,"X":295.507141,"Y":233.443161,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":208676.0,"Objects":[{"StartTime":208676.0,"EndTime":208676.0,"X":317.0,"Y":310.0}]},{"StartTime":208838.0,"Objects":[{"StartTime":208838.0,"EndTime":208838.0,"X":468.0,"Y":196.0}]},{"StartTime":208919.0,"Objects":[{"StartTime":208919.0,"EndTime":208919.0,"X":457.0,"Y":192.0}]},{"StartTime":209000.0,"Objects":[{"StartTime":209000.0,"EndTime":209000.0,"X":444.0,"Y":186.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":209126.0,"EndTime":209126.0,"X":451.721558,"Y":258.535278,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":209324.0,"Objects":[{"StartTime":209324.0,"EndTime":209324.0,"X":302.0,"Y":84.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":209450.0,"EndTime":209450.0,"X":286.32312,"Y":155.0472,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":209649.0,"Objects":[{"StartTime":209649.0,"EndTime":209649.0,"X":445.0,"Y":43.0}]},{"StartTime":209892.0,"Objects":[{"StartTime":209892.0,"EndTime":209892.0,"X":228.0,"Y":206.0}]},{"StartTime":210135.0,"Objects":[{"StartTime":210135.0,"EndTime":210135.0,"X":447.0,"Y":384.0}]},{"StartTime":210297.0,"Objects":[{"StartTime":210297.0,"EndTime":210297.0,"X":313.0,"Y":229.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":210504.0,"EndTime":210504.0,"X":172.0766,"Y":265.49353,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":210622.0,"Objects":[{"StartTime":210622.0,"EndTime":210622.0,"X":138.0,"Y":334.0}]},{"StartTime":210784.0,"Objects":[{"StartTime":210784.0,"EndTime":210784.0,"X":6.0,"Y":131.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":211072.0,"EndTime":211072.0,"X":112.5638,"Y":170.578735,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":211189.0,"Objects":[{"StartTime":211189.0,"EndTime":211189.0,"X":52.0,"Y":220.0}]},{"StartTime":211270.0,"Objects":[{"StartTime":211270.0,"EndTime":211270.0,"X":47.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":211477.0,"EndTime":211477.0,"X":171.609314,"Y":265.431152,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":211595.0,"Objects":[{"StartTime":211595.0,"EndTime":211595.0,"X":226.0,"Y":322.0}]},{"StartTime":211757.0,"Objects":[{"StartTime":211757.0,"EndTime":211757.0,"X":381.0,"Y":194.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":212045.0,"EndTime":212045.0,"X":275.428528,"Y":97.02175,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":212162.0,"Objects":[{"StartTime":212162.0,"EndTime":212162.0,"X":233.44014,"Y":157.44014}]},{"StartTime":212243.0,"Objects":[{"StartTime":212243.0,"EndTime":212243.0,"X":237.0,"Y":161.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":212288.0,"EndTime":212288.0,"X":284.574951,"Y":174.99263,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":212405.0,"Objects":[{"StartTime":212405.0,"EndTime":212405.0,"X":422.0,"Y":292.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":212450.0,"EndTime":212450.0,"X":374.446442,"Y":306.065125,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":212568.0,"Objects":[{"StartTime":212568.0,"EndTime":212568.0,"X":451.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":212613.0,"EndTime":212613.0,"X":458.834747,"Y":176.967178,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":212730.0,"Objects":[{"StartTime":212730.0,"EndTime":212730.0,"X":263.0,"Y":324.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":212775.0,"EndTime":212775.0,"X":272.138855,"Y":275.259369,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":212892.0,"Objects":[{"StartTime":212892.0,"EndTime":212892.0,"X":455.0,"Y":384.0}]},{"StartTime":213054.0,"Objects":[{"StartTime":213054.0,"EndTime":213054.0,"X":422.0,"Y":292.0}]},{"StartTime":213216.0,"Objects":[{"StartTime":213216.0,"EndTime":213216.0,"X":321.0,"Y":384.0}]},{"StartTime":213378.0,"Objects":[{"StartTime":213378.0,"EndTime":213378.0,"X":378.0,"Y":188.0}]},{"StartTime":213541.0,"Objects":[{"StartTime":213541.0,"EndTime":213541.0,"X":194.0,"Y":379.0}]},{"StartTime":213703.0,"Objects":[{"StartTime":213703.0,"EndTime":213703.0,"X":130.0,"Y":108.0}]},{"StartTime":213865.0,"Objects":[{"StartTime":213865.0,"EndTime":213865.0,"X":341.0,"Y":272.0}]},{"StartTime":214027.0,"Objects":[{"StartTime":214027.0,"EndTime":214027.0,"X":63.0,"Y":384.0}]},{"StartTime":214189.0,"Objects":[{"StartTime":214189.0,"EndTime":214189.0,"X":243.0,"Y":34.0}]},{"StartTime":214351.0,"Objects":[{"StartTime":214351.0,"EndTime":214351.0,"X":321.0,"Y":384.0}]},{"StartTime":215162.0,"Objects":[{"StartTime":215162.0,"EndTime":215162.0,"X":15.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":215369.0,"EndTime":215369.0,"X":94.9599457,"Y":184.9499,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":215487.0,"Objects":[{"StartTime":215487.0,"EndTime":215487.0,"X":172.0,"Y":178.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":215775.0,"EndTime":215775.0,"X":352.33728,"Y":238.509,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":215973.0,"Objects":[{"StartTime":215973.0,"EndTime":215973.0,"X":233.0,"Y":321.0}]},{"StartTime":216135.0,"Objects":[{"StartTime":216135.0,"EndTime":216135.0,"X":406.0,"Y":180.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":216261.0,"EndTime":216261.0,"X":429.166473,"Y":265.959167,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":216460.0,"Objects":[{"StartTime":216460.0,"EndTime":216460.0,"X":261.0,"Y":148.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":216667.0,"EndTime":216667.0,"X":384.301575,"Y":70.8233643,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":216784.0,"Objects":[{"StartTime":216784.0,"EndTime":216784.0,"X":461.0,"Y":67.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":217072.0,"EndTime":217072.0,"X":285.659058,"Y":-0.6762123,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":217270.0,"Objects":[{"StartTime":217270.0,"EndTime":217270.0,"X":406.0,"Y":180.0}]},{"StartTime":217432.0,"Objects":[{"StartTime":217432.0,"EndTime":217432.0,"X":277.0,"Y":7.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":217558.0,"EndTime":217558.0,"X":180.3599,"Y":29.3015652,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":217757.0,"Objects":[{"StartTime":217757.0,"EndTime":217757.0,"X":23.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":217964.0,"EndTime":217964.0,"X":148.637451,"Y":187.654114,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":218081.0,"Objects":[{"StartTime":218081.0,"EndTime":218081.0,"X":231.0,"Y":234.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":218369.0,"EndTime":218369.0,"X":104.144432,"Y":308.3843,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":218568.0,"Objects":[{"StartTime":218568.0,"EndTime":218568.0,"X":278.0,"Y":165.0}]},{"StartTime":218730.0,"Objects":[{"StartTime":218730.0,"EndTime":218730.0,"X":348.0,"Y":279.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":218856.0,"EndTime":218856.0,"X":436.208221,"Y":306.333,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":219054.0,"Objects":[{"StartTime":219054.0,"EndTime":219054.0,"X":299.0,"Y":68.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219180.0,"EndTime":219180.0,"X":277.9312,"Y":164.916351,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":219378.0,"Objects":[{"StartTime":219378.0,"EndTime":219378.0,"X":376.0,"Y":7.0}]},{"StartTime":219541.0,"Objects":[{"StartTime":219541.0,"EndTime":219541.0,"X":204.0,"Y":94.0}]},{"StartTime":219703.0,"Objects":[{"StartTime":219703.0,"EndTime":219703.0,"X":361.0,"Y":202.0}]},{"StartTime":219865.0,"Objects":[{"StartTime":219865.0,"EndTime":219865.0,"X":185.0,"Y":326.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219991.0,"EndTime":219991.0,"X":205.094421,"Y":228.876953,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":220189.0,"Objects":[{"StartTime":220189.0,"EndTime":220189.0,"X":389.0,"Y":313.0}]},{"StartTime":220271.0,"Objects":[{"StartTime":220271.0,"EndTime":220271.0,"X":388.0,"Y":356.0}]},{"StartTime":220352.0,"Objects":[{"StartTime":220352.0,"EndTime":220352.0,"X":354.0,"Y":384.0}]},{"StartTime":220433.0,"Objects":[{"StartTime":220433.0,"EndTime":220433.0,"X":313.0,"Y":384.0}]},{"StartTime":220514.0,"Objects":[{"StartTime":220514.0,"EndTime":220514.0,"X":285.0,"Y":353.0}]},{"StartTime":220676.0,"Objects":[{"StartTime":220676.0,"EndTime":220676.0,"X":205.0,"Y":228.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":220964.0,"EndTime":220964.0,"X":45.86247,"Y":183.3497,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":221162.0,"Objects":[{"StartTime":221162.0,"EndTime":221162.0,"X":202.0,"Y":91.0}]},{"StartTime":221324.0,"Objects":[{"StartTime":221324.0,"EndTime":221324.0,"X":44.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":221450.0,"EndTime":221450.0,"X":131.2635,"Y":30.0638027,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":221649.0,"Objects":[{"StartTime":221649.0,"EndTime":221649.0,"X":45.0,"Y":183.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":221775.0,"EndTime":221775.0,"X":25.2771187,"Y":280.18396,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":221892.0,"Objects":[{"StartTime":221892.0,"EndTime":221892.0,"X":74.44014,"Y":329.440155}]},{"StartTime":221973.0,"Objects":[{"StartTime":221973.0,"EndTime":221973.0,"X":78.0,"Y":333.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":222180.0,"EndTime":222180.0,"X":218.276413,"Y":372.293671,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":222297.0,"Objects":[{"StartTime":222297.0,"EndTime":222297.0,"X":285.0,"Y":341.0}]},{"StartTime":222460.0,"Objects":[{"StartTime":222460.0,"EndTime":222460.0,"X":184.0,"Y":211.0}]},{"StartTime":222622.0,"Objects":[{"StartTime":222622.0,"EndTime":222622.0,"X":306.440155,"Y":160.44014}]},{"StartTime":222784.0,"Objects":[{"StartTime":222784.0,"EndTime":222784.0,"X":163.0,"Y":325.0}]},{"StartTime":222946.0,"Objects":[{"StartTime":222946.0,"EndTime":222946.0,"X":310.0,"Y":164.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":223072.0,"EndTime":223072.0,"X":322.5219,"Y":65.61365,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":223189.0,"Objects":[{"StartTime":223189.0,"EndTime":223189.0,"X":264.440155,"Y":9.440141}]},{"StartTime":223270.0,"Objects":[{"StartTime":223270.0,"EndTime":223270.0,"X":268.0,"Y":13.0}]},{"StartTime":223432.0,"Objects":[{"StartTime":223432.0,"EndTime":223432.0,"X":406.0,"Y":106.0}]},{"StartTime":223595.0,"Objects":[{"StartTime":223595.0,"EndTime":223595.0,"X":184.0,"Y":211.0}]},{"StartTime":223757.0,"Objects":[{"StartTime":223757.0,"EndTime":223757.0,"X":292.0,"Y":88.0}]},{"StartTime":223919.0,"Objects":[{"StartTime":223919.0,"EndTime":223919.0,"X":361.0,"Y":307.0}]},{"StartTime":224081.0,"Objects":[{"StartTime":224081.0,"EndTime":224081.0,"X":206.88028,"Y":111.88028}]},{"StartTime":224162.0,"Objects":[{"StartTime":224162.0,"EndTime":224162.0,"X":210.44014,"Y":115.44014}]},{"StartTime":224243.0,"Objects":[{"StartTime":224243.0,"EndTime":224243.0,"X":214.0,"Y":119.0}]},{"StartTime":224405.0,"Objects":[{"StartTime":224405.0,"EndTime":224405.0,"X":125.44014,"Y":286.440155}]},{"StartTime":224730.0,"Objects":[{"StartTime":224730.0,"EndTime":224730.0,"X":129.0,"Y":290.0}]},{"StartTime":224892.0,"Objects":[{"StartTime":224892.0,"EndTime":224892.0,"X":86.0,"Y":152.0}]},{"StartTime":225054.0,"Objects":[{"StartTime":225054.0,"EndTime":225054.0,"X":155.0,"Y":177.0}]},{"StartTime":225216.0,"Objects":[{"StartTime":225216.0,"EndTime":225216.0,"X":31.0,"Y":270.0}]},{"StartTime":225378.0,"Objects":[{"StartTime":225378.0,"EndTime":225378.0,"X":186.0,"Y":353.0}]},{"StartTime":225541.0,"Objects":[{"StartTime":225541.0,"EndTime":225541.0,"X":112.0,"Y":377.0}]},{"StartTime":225865.0,"Objects":[{"StartTime":225865.0,"EndTime":225865.0,"X":410.0,"Y":158.0}]},{"StartTime":226027.0,"Objects":[{"StartTime":226027.0,"EndTime":226027.0,"X":350.0,"Y":203.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":226153.0,"EndTime":226153.0,"X":358.2194,"Y":258.07,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":226351.0,"Objects":[{"StartTime":226351.0,"EndTime":226351.0,"X":193.0,"Y":83.0}]},{"StartTime":226514.0,"Objects":[{"StartTime":226514.0,"EndTime":226514.0,"X":246.0,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":226640.0,"EndTime":226640.0,"X":235.239471,"Y":190.630341,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":226838.0,"Objects":[{"StartTime":226838.0,"EndTime":226838.0,"X":394.0,"Y":25.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":226964.0,"EndTime":226964.0,"X":340.226776,"Y":39.44654,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":227162.0,"Objects":[{"StartTime":227162.0,"EndTime":227162.0,"X":269.0,"Y":59.0}]},{"StartTime":227324.0,"Objects":[{"StartTime":227324.0,"EndTime":227324.0,"X":109.0,"Y":153.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":227450.0,"EndTime":227450.0,"X":162.537659,"Y":168.296478,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":227649.0,"Objects":[{"StartTime":227649.0,"EndTime":227649.0,"X":235.0,"Y":190.0}]},{"StartTime":227811.0,"Objects":[{"StartTime":227811.0,"EndTime":227811.0,"X":107.0,"Y":348.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":227973.0,"EndTime":227973.0,"X":98.98543,"Y":292.899841,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":228099.0,"EndTime":228099.0,"X":107.0,"Y":348.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":228297.0,"Objects":[{"StartTime":228297.0,"EndTime":228297.0,"X":176.0,"Y":384.0}]},{"StartTime":228460.0,"Objects":[{"StartTime":228460.0,"EndTime":228460.0,"X":321.0,"Y":307.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":228586.0,"EndTime":228586.0,"X":330.4079,"Y":252.12056,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":228784.0,"Objects":[{"StartTime":228784.0,"EndTime":228784.0,"X":271.0,"Y":203.0}]},{"StartTime":228946.0,"Objects":[{"StartTime":228946.0,"EndTime":228946.0,"X":437.0,"Y":70.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":229072.0,"EndTime":229072.0,"X":444.753723,"Y":125.137482,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":229270.0,"Objects":[{"StartTime":229270.0,"EndTime":229270.0,"X":394.0,"Y":174.0}]},{"StartTime":229432.0,"Objects":[{"StartTime":229432.0,"EndTime":229432.0,"X":291.0,"Y":42.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":229558.0,"EndTime":229558.0,"X":238.1773,"Y":24.3924389,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":229757.0,"Objects":[{"StartTime":229757.0,"EndTime":229757.0,"X":288.0,"Y":119.0}]},{"StartTime":229919.0,"Objects":[{"StartTime":229919.0,"EndTime":229919.0,"X":150.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":230081.0,"EndTime":230081.0,"X":204.107239,"Y":195.859665,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":230207.0,"EndTime":230207.0,"X":150.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":230405.0,"Objects":[{"StartTime":230405.0,"EndTime":230405.0,"X":88.0,"Y":167.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":230531.0,"EndTime":230531.0,"X":98.91975,"Y":112.401268,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":230730.0,"Objects":[{"StartTime":230730.0,"EndTime":230730.0,"X":274.0,"Y":285.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":230838.0,"EndTime":230838.0,"X":279.0154,"Y":321.7796,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":230910.0,"EndTime":230910.0,"X":274.0,"Y":285.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":231054.0,"Objects":[{"StartTime":231054.0,"EndTime":231054.0,"X":314.0,"Y":217.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":231342.0,"EndTime":231342.0,"X":406.0158,"Y":249.631241,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":231541.0,"Objects":[{"StartTime":231541.0,"EndTime":231541.0,"X":512.0,"Y":130.0}]},{"StartTime":231703.0,"Objects":[{"StartTime":231703.0,"EndTime":231703.0,"X":452.0,"Y":88.0}]},{"StartTime":231865.0,"Objects":[{"StartTime":231865.0,"EndTime":231865.0,"X":406.0,"Y":143.0}]},{"StartTime":232027.0,"Objects":[{"StartTime":232027.0,"EndTime":232027.0,"X":280.0,"Y":54.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":232153.0,"EndTime":232153.0,"X":289.960327,"Y":-0.7818756,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":232351.0,"Objects":[{"StartTime":232351.0,"EndTime":232351.0,"X":348.0,"Y":89.0}]},{"StartTime":232514.0,"Objects":[{"StartTime":232514.0,"EndTime":232514.0,"X":186.0,"Y":175.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":232640.0,"EndTime":232640.0,"X":179.09375,"Y":119.749969,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":232838.0,"Objects":[{"StartTime":232838.0,"EndTime":232838.0,"X":120.0,"Y":222.0}]},{"StartTime":233000.0,"Objects":[{"StartTime":233000.0,"EndTime":233000.0,"X":224.0,"Y":364.0}]},{"StartTime":233162.0,"Objects":[{"StartTime":233162.0,"EndTime":233162.0,"X":157.0,"Y":342.0}]},{"StartTime":233324.0,"Objects":[{"StartTime":233324.0,"EndTime":233324.0,"X":293.0,"Y":248.0}]},{"StartTime":233487.0,"Objects":[{"StartTime":233487.0,"EndTime":233487.0,"X":384.0,"Y":221.0}]}]} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2593923.osu b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2593923.osu new file mode 100644 index 000000000000..49ac05b253f8 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2593923.osu @@ -0,0 +1,1213 @@ +osu file format v14 + +[General] +AudioLeadIn: 0 +PreviewTime: 175189 +Countdown: 0 +SampleSet: Soft +StackLeniency: 0.9 +Mode: 0 +LetterboxInBreaks: 0 +WidescreenStoryboard: 1 + +[Difficulty] +HPDrainRate:6 +CircleSize:4.2 +OverallDifficulty:8.7 +ApproachRate:9.4 +SliderMultiplier:1.74 +SliderTickRate:1 + +[Events] +//Background and Video events +//Break Periods +2,178065,182352 +//Storyboard Layer 0 (Background) +//Storyboard Layer 1 (Fail) +//Storyboard Layer 2 (Pass) +//Storyboard Layer 3 (Foreground) +//Storyboard Layer 4 (Overlay) +//Storyboard Sound Samples + +[TimingPoints] +1433,324.324324324324,4,2,4,54,1,0 +1433,-135.135135135135,4,2,4,54,0,0 +6622,-135.135135135135,4,2,4,64,0,0 +10514,-135.135135135135,4,2,4,74,0,0 +11487,-227.272727272727,4,2,4,74,0,0 +11811,-87.719298245614,4,2,4,84,0,0 +21216,-135.135135135135,4,2,7,54,0,0 +22189,-135.135135135135,4,2,4,64,0,0 +32243,-69.4444444444444,4,2,4,74,0,0 +32568,-106.382978723404,4,2,4,74,0,0 +40676,-80.6451612903224,4,2,4,74,0,0 +43270,-156.25,4,2,4,74,0,0 +44081,-80.6451612903226,4,2,4,74,0,0 +45865,-156.25,4,2,4,74,0,0 +46676,-80.6451612903226,4,2,4,74,0,0 +48135,-119.047619047619,4,2,4,74,0,0 +56730,-80.6451612903226,4,2,4,74,0,0 +57865,-80.6451612903226,4,2,4,74,0,0 +58189,-227.272727272727,4,2,4,94,0,1 +58514,-87.719298245614,4,2,4,84,0,0 +68892,-87.719298245614,4,2,4,84,0,1 +74081,-119.047619047619,4,2,4,74,0,0 +76676,-87.719298245614,4,2,4,74,0,0 +81541,-69.4444444444444,4,2,4,74,0,0 +81865,-119.047619047619,4,2,4,74,0,0 +85757,-87.719298245614,4,2,4,74,0,0 +89324,-156.25,4,2,4,74,0,0 +92243,-119.047619047619,4,2,7,64,0,0 +96784,-119.047619047619,4,2,4,74,0,0 +100027,-96.1538461538461,4,2,4,74,0,0 +102297,-69.4444444444444,4,2,4,74,0,0 +102621,-106.382978723404,4,2,4,74,0,0 +110730,-80.6451612903224,4,2,4,74,0,0 +113324,-156.25,4,2,4,74,0,0 +114135,-80.6451612903226,4,2,4,74,0,0 +115919,-156.25,4,2,4,74,0,0 +116730,-80.6451612903226,4,2,4,74,0,0 +118189,-119.047619047619,4,2,4,74,0,0 +123378,-96.1538461538461,4,2,4,74,0,0 +126784,-80.6451612903226,4,2,4,74,0,0 +128243,-64.9350649350649,4,2,4,74,0,0 +128568,-80.6451612903226,4,2,4,90,0,1 +146730,-119.047619047619,4,2,4,80,0,0 +159703,-87.719298245614,4,2,4,80,0,0 +173973,-87.719298245614,4,2,4,90,0,0 +175270,-87.719298245614,4,2,4,84,0,0 +176081,-87.719298245614,4,2,4,84,0,0 +176405,-74.6268656716418,4,2,4,84,0,0 +177541,-227.272727272727,4,2,4,84,0,1 +177865,-227.272727272727,4,2,4,84,0,0 +182892,-227.272727272727,4,2,4,64,0,0 +183054,-156.25,4,2,4,64,0,0 +185649,-119.047619047619,4,2,4,74,0,0 +190838,-156.25,4,2,4,74,0,0 +191487,-74.6268656716418,4,2,4,90,0,1 +192135,-87.719298245614,4,2,4,84,0,0 +202514,-87.719298245614,4,2,4,84,0,1 +207703,-119.047619047619,4,2,4,74,0,0 +210297,-87.719298245614,4,2,4,74,0,0 +215162,-74.6268656716418,4,2,4,74,0,0 +215487,-87.719298245614,4,2,4,74,0,0 +224892,-156.25,4,2,4,54,0,0 + + +[Colours] +Combo1 : 89,244,183 +Combo2 : 249,188,87 +Combo3 : 108,197,249 +Combo4 : 197,137,137 + +[HitObjects] +493,304,1433,6,0,L|482:368,2,64.3800015717774,2|0|0,0:0|0:0|0:0,0:0:0:0: +442,244,1919,2,0,L|430:168,2,64.3800015717774,2|0|0,0:0|0:0|0:0,0:0:0:0: +394,304,2405,6,0,P|366:322|324:321,1,64.3800015717774,2|0,0:0|0:0,0:0:0:0: +277,272,2730,1,0,0:0:0:0: +183,169,2892,6,0,L|198:89,1,64.3800015717774,2|0,0:0|0:0,0:0:0:0: +257,66,3216,1,0,0:0:0:0: +178,178,3378,6,0,B|132:188|132:188|113:212|113:212|43:228,1,128.760003143555,2|2,0:0|0:0,0:0:0:0: +196,303,3865,1,0,3:2:0:0: +53,214,4027,6,0,P|125:192|187:285,2,193.140004715332,2|0|8,3:2|3:2|0:1,0:0:0:0: +194,105,5162,1,2,3:2:0:0: +31,0,5324,6,0,P|70:46|150:31,1,128.760003143555,2|0,3:2|0:0,0:0:0:0: +257,153,5811,1,0,3:2:0:0: +311,30,5973,5,8,0:0:0:0: +146,171,6135,1,0,3:2:0:0: +320,103,6297,5,8,3:0:0:0: +428,231,6460,1,8,3:0:0:0: +469,166,6622,6,0,P|421:150|328:258,1,193.140004715332,6|0,3:2|3:2,0:0:0:0: +234,379,7270,2,0,P|265:368|303:360,1,64.3800015717774,8|0,0:0|0:0,0:0:0:0: +155,291,7595,1,0,0:0:0:0: +334,244,7757,1,8,0:1:0:0: +334,244,7838,1,8,0:1:0:0: +334,244,7919,6,0,B|225:226|252:311|145:289,1,193.140004715332,2|0,3:2|0:0,0:0:0:0: +43,93,8568,1,8,0:0:0:0: +213,180,8730,1,0,3:2:0:0: +50,278,8892,1,8,3:1:0:0: +179,92,9054,1,0,3:2:0:0: +302,322,9216,5,4,3:2:0:0: +302,322,9541,5,10,0:1:0:0: +213,180,9703,1,8,0:1:0:0: +156,290,9865,5,8,0:1:0:0: +276,88,10027,1,8,0:1:0:0: +370,237,10189,5,8,0:0:0:0: +179,92,10351,1,8,0:0:0:0: +327,10,10514,5,10,0:0:0:0: +239,267,10676,1,8,0:0:0:0: +92,0,10838,5,8,0:0:0:0: +360,142,11000,1,8,0:0:0:0: +17,198,11162,5,4,3:2:0:0: +327,10,11324,1,8,0:0:0:0: +213,180,11487,6,0,P|204:155|207:111,1,57.4200017523194,6|0,0:2|0:0,0:0:0:0: +179,92,11811,6,0,B|283:67|257:165|365:142,1,198.359997578613,4|8,3:1|0:0,0:0:0:0: +161,247,12297,1,2,0:0:0:0: +333,351,12460,2,0,P|285:369|230:378,1,99.1799987893067,0|0,3:2|3:2,0:0:0:0: +359,234,12784,2,0,P|429:226|480:284,1,148.76999818396,8|0,0:0|0:0,0:0:0:0: +478,279,13108,6,0,P|469:327|466:383,1,99.1799987893067,2|0,3:2|0:0,0:0:0:0: +262,177,13432,2,0,P|271:226|278:302,1,99.1799987893067,8|0,0:0|0:0,0:0:0:0: +462,114,13757,1,0,3:2:0:0: +330,16,13919,1,0,3:2:0:0: +424,194,14081,1,8,0:0:0:0: +500,26,14243,1,2,0:0:0:0: +500,26,14324,1,2,0:0:0:0: +500,26,14405,6,0,B|448:7|406:42|406:42|379:102|315:90,1,198.359997578613,4|8,3:2|0:0,0:0:0:0: +194,239,14892,1,2,0:0:0:0: +145,179,15054,2,0,P|157:127|163:69,1,99.1799987893067,0|0,3:2|3:2,0:0:0:0: +334,205,15378,2,0,P|340:274|354:364,1,148.76999818396,8|0,0:0|0:0,0:0:0:0: +280,384,15703,5,2,3:2:0:0: +428,267,15865,1,2,0:0:0:0: +267,152,16027,1,10,0:0:0:0: +435,350,16189,1,2,0:2:0:0: +512,117,16351,1,4,3:2:0:0: +317,254,16514,5,8,0:0:0:0: +274,268,16595,1,8,0:0:0:0: +231,240,16676,1,8,0:0:0:0: +225,184,16757,1,8,0:0:0:0: +267,152,16838,2,0,L|331:173,1,49.5899993946533,0|0,3:2|0:0,0:0:0:0: +163,356,17000,6,0,B|69:319|69:319|40:257|100:230,1,198.359997578613,6|8,3:2|0:0,0:0:0:0: +267,152,17487,1,2,0:0:0:0: +133,23,17649,2,0,L|152:133,1,99.1799987893067,0|0,3:2|3:2,0:0:0:0: +355,312,17973,2,0,B|385:297|413:289|413:289|398:248|385:191,1,148.76999818396,8|0,0:0|0:0,0:0:0:0: +345,146,18297,6,0,B|235:134|269:232|151:208,1,198.359997578613,2|8,3:2|0:0,0:0:0:0: +381,76,18784,1,0,0:0:0:0: +234,23,18946,5,0,3:2:0:0: +316,229,19108,1,0,3:2:0:0: +456,47,19270,5,8,0:0:0:0: +243,135,19432,1,8,0:1:0:0: +247,124,19514,1,8,0:1:0:0: +252,115,19595,6,0,B|285:125|285:125|294:133|294:133|359:149,1,99.1799987893067,6|2,3:2|0:0,0:0:0:0: +477,348,19919,1,10,0:0:0:0: +316,229,20081,1,2,0:0:0:0: +490,131,20243,5,10,0:0:0:0: +350,315,20405,1,0,3:2:0:0: +331,326,20487,1,0,3:2:0:0: +307,324,20568,1,0,3:2:0:0: +153,176,20730,1,2,3:2:0:0: +153,176,21054,5,2,0:0:0:0: +216,241,21216,2,0,P|202:299|195:379,1,128.760003143555,0|2,3:0|0:0,0:0:0:0: +69,222,21703,2,0,P|77:255|82:301,1,64.3800015717774,0|0,3:0|0:0,0:0:0:0: +109,82,22189,6,0,P|71:40|-4:55,2,128.760003143555,4|2|2,3:2|3:2|3:2,0:0:0:0: +172,127,23000,1,0,0:1:0:0: +277,0,23162,1,0,3:2:0:0: +209,33,23324,1,2,0:0:0:0: +330,148,23487,5,2,3:2:0:0: +379,92,23649,2,0,P|368:62|360:23,1,64.3800015717774,2|0,0:0|3:2,0:0:0:0: +230,185,23973,2,0,P|222:250|210:320,1,128.760003143555,2|0,0:0|0:0,0:0:0:0: +57,132,24460,2,0,P|64:163|68:201,1,64.3800015717774,2|0,3:2|0:0,0:0:0:0: +0,365,24784,6,0,P|39:322|114:339,1,128.760003143555,4|2,3:2|3:2,0:0:0:0: +352,146,25432,2,0,P|291:169|226:185,1,128.760003143555,2|0,3:2|3:2,0:0:0:0: +346,306,25919,1,2,0:0:0:0: +283,346,26081,5,2,3:2:0:0: +352,229,26243,2,0,P|382:243|424:253,1,64.3800015717774,2|0,0:0|3:2,0:0:0:0: +257,75,26568,2,0,P|215:127|234:188,1,128.760003143555,2|0,0:0|0:0,0:0:0:0: +401,73,27054,2,0,L|387:-4,1,64.3800015717774,10|2,0:1|0:0,0:0:0:0: +486,170,27378,5,12,0:0:0:0: +299,75,27541,1,8,0:1:0:0: +299,75,27622,1,8,0:1:0:0: +299,75,27703,1,8,0:1:0:0: +352,229,27865,5,8,0:0:0:0: +488,91,28027,1,8,0:1:0:0: +488,91,28108,1,8,0:1:0:0: +488,91,28189,1,8,0:1:0:0: +302,157,28351,5,10,0:0:0:0: +492,249,28514,1,2,0:0:0:0: +249,350,28676,5,8,3:2:0:0: +359,238,28838,1,8,0:1:0:0: +359,238,28919,1,8,0:1:0:0: +359,238,29000,1,8,0:1:0:0: +399,383,29162,5,2,3:2:0:0: +224,247,29324,1,8,0:1:0:0: +224,247,29405,1,8,0:1:0:0: +224,247,29487,1,8,0:1:0:0: +370,257,29649,5,0,3:2:0:0: +159,384,29811,1,2,0:0:0:0: +329,329,29973,5,8,0:0:0:0: +217,278,30135,1,2,0:0:0:0: +254,376,30297,5,0,3:2:0:0: +340,232,30460,1,0,3:2:0:0: +176,159,30622,5,8,0:0:0:0: +329,329,30784,1,8,0:0:0:0: +124,235,30946,5,8,0:0:0:0: +390,102,31108,1,8,0:0:0:0: +254,376,31270,5,4,3:2:0:0: +176,36,31432,1,0,3:2:0:0: +11,207,32081,5,10,0:1:0:0: +9,195,32162,1,10,0:1:0:0: +12,183,32243,2,0,B|48:137|107:154|107:154|127:207|190:209,1,187.920004587891,10|0,0:0|0:0,0:0:0:0: +230,258,32568,6,0,L|245:364,1,81.7799987521363,4|0,3:2|0:0,0:0:0:0: +412,228,32892,2,0,L|429:140,1,81.7799987521363,10|0,0:0|0:0,0:0:0:0: +289,55,33216,1,2,3:2:0:0: +307,126,33378,1,0,3:2:0:0: +420,29,33541,1,8,0:0:0:0: +356,0,33703,1,2,0:0:0:0: +228,103,33865,5,2,3:2:0:0: +169,156,34027,2,0,P|127:162|82:177,1,81.7799987521363,2|8,0:0|0:0,0:0:0:0: +225,321,34351,2,0,P|277:362|346:354,1,122.669998128204,2|0,3:2|0:0,0:0:0:0: +394,318,34676,1,0,3:2:0:0: +456,156,34838,1,10,0:0:0:0: +387,182,35000,1,0,0:0:0:0: +491,363,35162,6,0,P|499:323|500:275,1,81.7799987521363,4|0,3:2|0:0,0:0:0:0: +302,149,35487,2,0,P|304:187|316:237,1,81.7799987521363,8|0,0:0|0:0,0:0:0:0: +456,63,35811,1,0,3:2:0:0: +386,37,35973,1,0,3:2:0:0: +456,156,36135,1,8,0:0:0:0: +387,182,36297,1,2,0:0:0:0: +456,63,36460,5,2,3:2:0:0: +302,149,36622,2,0,P|259:145|225:106,1,81.7799987521363,2|8,0:0|0:0,0:0:0:0: +127,34,36946,2,0,P|113:108|104:216,1,163.559997504273,2|0,3:2|3:2,0:0:0:0: +229,33,37432,1,10,0:0:0:0: +0,156,37595,1,8,0:0:0:0: +0,156,37676,1,8,0:0:0:0: +0,156,37757,6,0,B|91:134|91:134|126:164|101:204,1,163.559997504273,4|8,3:2|0:0,0:0:0:0: +223,324,38243,2,0,P|186:309|134:297,1,81.7799987521363,0|0,0:0|3:2,0:0:0:0: +261,217,38568,1,0,3:2:0:0: +105,196,38730,5,8,0:0:0:0: +159,384,38892,1,2,0:0:0:0: +57,263,39054,6,0,P|52:304|43:350,1,81.7799987521363,0|0,3:2|0:0,0:0:0:0: +185,183,39378,1,8,0:0:0:0: +344,308,39541,2,0,P|330:225|327:135,1,163.559997504273,0|2,3:2|3:2,0:0:0:0: +223,324,40027,5,8,0:0:0:0: +436,193,40189,1,2,0:0:0:0: +244,93,40351,5,2,3:2:0:0: +421,288,40514,1,2,0:0:0:0: +421,288,40595,1,2,0:0:0:0: +421,288,40676,6,0,B|325:252|325:252|344:278|344:320,1,161.819993580139,14|0,0:0|0:0,0:0:0:0: +103,145,41000,6,0,B|230:105|230:105|190:141|202:192,1,215.759991440186,12|8,0:0|0:0,0:0:0:0: +418,20,41487,1,8,0:1:0:0: +418,20,41568,1,8,0:1:0:0: +418,20,41649,6,0,B|339:0|339:0|284:35|326:76,1,161.819993580139,4|0,3:2|0:0,0:0:0:0: +375,116,41973,1,8,0:0:0:0: +181,32,42135,6,0,B|144:24|144:24|132:11|132:11|67:-3,1,107.879995720093,4|8,3:2|0:1,0:0:0:0: +280,169,42460,1,0,3:2:0:0: +78,332,42622,6,0,B|53:248|53:248|139:221,1,161.819993580139,12|0,0:0|0:0,0:0:0:0: +189,264,42946,6,0,L|260:287,1,53.9399978600465,4|0,3:2|0:0,0:0:0:0: +381,384,43108,1,8,0:0:0:0: +444,339,43270,6,0,L|459:266,1,55.68,2|0,0:0|0:0,0:0:0:0: +280,169,43595,1,2,3:2:0:0: +401,169,43757,5,8,3:0:0:0: +240,280,43919,1,8,3:0:0:0: +401,169,44081,6,0,B|423:68|423:68|384:16|321:42,1,215.759991440186,6|2,3:2|3:2,0:0:0:0: +455,284,44568,1,10,0:0:0:0: +280,169,44730,1,0,3:2:0:0: +446,58,44892,1,8,0:0:0:0: +321,245,45054,1,0,3:2:0:0: +321,245,45135,1,0,3:2:0:0: +321,245,45216,5,8,0:2:0:0: +224,19,45378,1,0,3:2:0:0: +401,169,45541,5,4,3:2:0:0: +144,285,45703,1,8,3:2:0:0: +98,221,45865,6,0,L|110:160,1,55.68,2|8,0:0|3:0,0:0:0:0: +127,95,46108,1,8,3:0:0:0: +130,81,46189,1,2,3:2:0:0: +0,173,46351,1,0,3:2:0:0: +133,68,46514,5,8,0:0:0:0: +273,240,46676,2,0,P|228:294|130:271,1,161.819993580139,4|0,3:2|0:0,0:0:0:0: +98,221,47000,1,2,3:2:0:0: +278,94,47162,1,10,0:0:0:0: +216,52,47324,1,0,3:2:0:0: +325,319,47487,1,8,0:0:0:0: +193,209,47649,5,8,0:0:0:0: +195,195,47730,1,8,0:0:0:0: +198,180,47811,1,8,0:0:0:0: +356,70,47973,1,0,3:2:0:0: +424,119,48135,6,0,L|439:201,1,73.0799977697755,4|8,3:2|0:1,0:0:0:0: +452,263,48378,1,8,0:1:0:0: +455,283,48460,1,2,3:2:0:0: +338,197,48622,1,8,0:1:0:0: +235,343,48784,2,0,L|253:255,2,73.0799977697755,2|8|10,3:2|0:1|0:0,0:0:0:0: +56,207,49270,1,8,0:1:0:0: +56,207,49351,1,8,0:1:0:0: +56,207,49432,6,0,L|150:187,1,73.0799977697755,0|8,3:2|0:1,0:0:0:0: +198,180,49676,1,8,0:1:0:0: +222,175,49757,1,2,3:2:0:0: +344,84,49919,1,8,0:1:0:0: +239,6,50081,2,0,L|252:97,1,73.0799977697755,2|8,3:2|0:1,0:0:0:0: +385,177,50405,1,10,0:0:0:0: +473,75,50568,1,8,0:1:0:0: +473,75,50649,1,8,0:1:0:0: +473,75,50730,6,0,L|462:171,1,73.0799977697755,0|8,3:2|0:1,0:0:0:0: +453,220,50973,1,8,0:1:0:0: +451,236,51054,1,2,3:2:0:0: +321,132,51216,1,8,0:1:0:0: +218,280,51378,2,0,L|294:262,1,73.0799977697755,2|8,3:2|0:1,0:0:0:0: +198,180,51703,1,10,0:0:0:0: +297,272,51865,1,8,0:1:0:0: +297,272,51946,1,8,0:1:0:0: +297,272,52027,6,0,L|284:367,1,73.0799977697755,2|8,3:2|0:1,0:0:0:0: +227,384,52270,1,8,0:1:0:0: +227,384,52351,1,0,3:2:0:0: +63,242,52514,1,10,0:0:0:0: +63,242,52595,1,8,0:1:0:0: +63,242,52676,5,8,3:1:0:0: +91,196,52757,1,8,0:1:0:0: +138,186,52838,1,8,0:1:0:0: +186,209,52919,1,8,0:1:0:0: +187,230,53000,5,10,3:2:0:0: +234,278,53081,1,8,0:0:0:0: +297,272,53162,1,8,0:0:0:0: +330,217,53243,1,8,0:0:0:0: +295,161,53324,5,4,3:2:0:0: +295,161,53649,5,2,3:2:0:0: +401,308,53811,1,2,0:0:0:0: +187,230,53973,5,10,3:1:0:0: +383,113,54135,1,8,0:1:0:0: +268,345,54297,5,8,0:0:0:0: +181,103,54460,1,8,0:1:0:0: +353,192,54622,5,8,0:0:0:0: +125,325,54784,1,8,0:0:0:0: +253,53,54946,5,8,0:0:0:0: +349,356,55108,1,8,0:0:0:0: +107,207,55270,5,8,3:2:0:0: +408,39,55432,1,8,0:0:0:0: +93,84,55595,5,8,0:0:0:0: +434,284,55757,1,8,0:0:0:0: +189,384,55919,5,8,0:2:0:0: +261,22,56081,1,6,3:2:0:0: +261,22,56730,5,2,3:2:0:0: +349,270,56892,1,8,0:0:0:0: +403,210,57054,6,0,P|363:166|254:178,1,161.819993580139,4|0,3:2|0:0,0:0:0:0: +192,141,57378,1,0,3:2:0:0: +0,284,57541,1,8,0:0:0:0: +94,384,57703,5,2,0:0:0:0: +11,180,57865,1,10,0:0:0:0: +11,180,57946,1,8,0:0:0:0: +11,180,58027,2,0,P|34:192|86:200,1,53.9399978600465,0|0,3:2|0:0,0:0:0:0: +227,293,58189,6,0,P|204:311|162:313,1,57.4200017523194,4|0,3:2|0:0,0:0:0:0: +117,261,58514,6,0,B|228:246|185:353|319:334,1,198.359997578613,6|8,3:1|0:0,0:0:0:0: +403,210,59000,1,2,0:0:0:0: +512,346,59162,6,0,P|466:323|411:315,1,99.1799987893067,2|0,3:2|3:2,0:0:0:0: +292,168,59487,1,10,0:0:0:0: +446,107,59649,1,2,0:0:0:0: +446,107,59730,1,2,0:0:0:0: +446,107,59811,6,0,P|388:179|280:158,1,198.359997578613,2|8,3:2|0:0,0:0:0:0: +117,261,60297,1,0,0:0:0:0: +38,79,60460,6,0,P|83:98|138:116,1,99.1799987893067,2|0,3:2|3:2,0:0:0:0: +249,284,60784,1,8,0:0:0:0: +51,366,60946,1,2,0:0:0:0: +51,366,61027,1,2,0:0:0:0: +51,366,61108,6,0,P|1:310|67:211,1,198.359997578613,2|8,3:2|0:0,0:0:0:0: +189,366,61595,1,2,0:0:0:0: +197,181,61757,5,2,3:2:0:0: +25,290,61919,1,0,3:2:0:0: +130,113,62081,5,10,0:0:0:0: +255,290,62243,1,2,0:0:0:0: +255,290,62324,1,2,0:0:0:0: +255,290,62405,6,0,B|303:301|303:301|326:330|326:330|407:347,1,148.76999818396,2|0,3:2|0:0,0:0:0:0: +448,294,62730,1,8,0:0:0:0: +266,384,62892,1,2,0:0:0:0: +330,157,63054,5,6,3:2:0:0: +464,369,63216,1,8,0:0:0:0: +476,372,63297,1,8,0:1:0:0: +486,376,63378,1,10,0:1:0:0: +340,244,63541,5,8,0:0:0:0: +340,244,63622,1,8,0:0:0:0: +340,244,63703,2,0,B|236:226|264:317|146:304,1,198.359997578613,6|8,3:2|0:0,0:0:0:0: +330,157,64189,1,0,0:0:0:0: +191,35,64351,2,0,P|230:66|292:58,1,99.1799987893067,2|0,3:2|3:2,0:0:0:0: +114,169,64676,1,8,0:0:0:0: +276,284,64838,1,2,0:0:0:0: +191,35,65000,6,0,L|205:148,1,99.1799987893067,2|0,3:2|0:0,0:0:0:0: +69,328,65324,2,0,B|19:298|19:298|50:214,1,148.76999818396,8|0,0:0|0:0,0:0:0:0: +114,169,65649,1,0,3:2:0:0: +276,284,65811,1,0,3:2:0:0: +385,136,65973,2,0,P|333:150|277:177,1,99.1799987893067,10|0,0:0|0:0,0:0:0:0: +426,382,66297,6,0,P|477:343|445:224,1,198.359997578613,4|8,3:2|0:0,0:0:0:0: +277,65,66784,1,2,3:2:0:0: +466,140,66946,5,8,0:0:0:0: +276,284,67108,1,0,3:2:0:0: +370,44,67270,5,8,0:0:0:0: +449,226,67432,1,0,3:2:0:0: +218,127,67595,6,0,B|138:125|157:176|48:171,1,148.76999818396,4|0,3:2|0:0,0:0:0:0: +17,215,67919,1,8,0:0:0:0: +0,184,68000,1,8,0:0:0:0: +12,147,68081,1,8,0:0:0:0: +182,268,68243,1,2,3:2:0:0: +5,376,68405,1,0,3:2:0:0: +182,268,68568,6,0,P|242:258|311:316,1,148.76999818396,10|0,0:0|0:0,0:0:0:0: +352,379,68892,6,0,L|321:176,1,198.359997578613,6|8,3:1|0:0,0:0:0:0: +452,288,69378,1,0,3:2:0:0: +236,384,69541,5,8,0:0:0:0: +428,187,69703,1,0,3:2:0:0: +449,384,69865,5,10,0:0:0:0: +237,183,70027,1,2,3:2:0:0: +237,183,70108,1,2,3:2:0:0: +237,183,70189,6,0,B|249:103|249:103|281:79|320:113,1,148.76999818396,4|0,3:2|0:0,0:0:0:0: +302,117,70514,2,0,B|267:127|267:127|254:140|254:140|186:157,1,99.1799987893067,8|0,0:0|0:0,0:0:0:0: +335,2,70838,5,8,0:0:0:0: +436,195,71000,1,0,3:2:0:0: +436,195,71081,1,0,3:2:0:0: +436,195,71162,1,8,0:0:0:0: +311,106,71324,5,0,3:2:0:0: +224,322,71487,2,0,P|174:336|96:233,1,198.359997578613,6|8,3:2|0:0,0:0:0:0: +49,175,71973,1,2,0:0:0:0: +177,84,72135,5,10,0:0:0:0: +20,260,72297,1,0,3:2:0:0: +86,94,72460,5,10,0:0:0:0: +241,246,72622,1,0,3:2:0:0: +80,332,72784,6,0,L|99:213,1,99.1799987893067,6|2,3:2|0:0,0:0:0:0: +306,124,73108,1,8,0:0:0:0: +154,169,73270,5,0,3:2:0:0: +342,313,73432,1,4,3:2:0:0: +215,354,73595,5,2,3:2:0:0: +199,318,73676,1,8,0:0:0:0: +214,277,73757,1,10,0:0:0:0: +417,248,73919,5,8,0:0:0:0: +428,270,74000,1,8,0:0:0:0: +413,298,74081,2,0,P|375:303|336:315,1,73.0799977697755,6|0,3:2|0:0,0:0:0:0: +464,175,74405,1,0,0:0:0:0: +395,145,74568,1,0,3:2:0:0: +498,35,74730,6,0,L|508:117,1,73.0799977697755,8|2,0:0|0:0,0:0:0:0: +378,40,75054,1,10,0:1:0:0: +286,149,75216,1,10,0:1:0:0: +286,149,75297,1,8,0:1:0:0: +286,149,75378,6,0,P|293:117|303:57,1,73.0799977697755,2|0,3:2|0:0,0:0:0:0: +436,241,75703,2,0,P|401:252|363:267,1,73.0799977697755,0|2,3:2|0:0,0:0:0:0: +241,384,76027,5,8,0:0:0:0: +464,175,76270,5,2,0:0:0:0: +210,32,76514,5,2,0:0:0:0: +280,204,76676,6,0,B|300:87|300:87|276:124|228:132,1,198.359997578613,4|0,3:2|3:2,0:0:0:0: +367,265,77162,2,0,B|406:255|436:276|436:276|462:321|522:321,1,148.76999818396,8|0,0:0|0:0,0:0:0:0: +509,247,77487,1,8,0:0:0:0: +509,247,77568,1,8,0:0:0:0: +509,247,77649,6,0,P|497:169|486:81,1,148.76999818396,4|0,3:2|0:0,0:0:0:0: +428,51,77973,1,0,3:2:0:0: +280,204,78135,6,0,P|291:129|298:47,1,148.76999818396,8|0,0:0|0:0,0:0:0:0: +353,6,78460,1,10,0:0:0:0: +175,118,78622,1,10,0:0:0:0: +367,265,78784,1,8,0:0:0:0: +301,135,78946,1,0,3:2:0:0: +139,236,79108,1,8,0:1:0:0: +139,236,79189,1,8,0:1:0:0: +139,236,79270,6,0,B|182:250|182:250|203:287|203:287|272:307,1,148.76999818396,4|0,3:2|0:0,0:0:0:0: +330,335,79595,1,10,0:1:0:0: +231,178,79757,1,2,0:0:0:0: +391,241,79919,5,8,0:0:0:0: +228,375,80081,1,8,0:1:0:0: +311,114,80243,5,8,0:0:0:0: +442,339,80405,1,8,0:0:0:0: +386,52,80568,5,4,3:2:0:0: +327,359,80730,1,4,3:2:0:0: +62,133,81541,6,0,P|114:64|218:88,1,187.920004587891,4|0,3:2|0:0,0:0:0:0: +256,133,81865,6,0,P|247:169|236:217,1,73.0799977697755,4|0,3:1|0:0,0:0:0:0: +399,329,82189,2,0,P|394:293|391:236,1,73.0799977697755,0|0,3:2|0:0,0:0:0:0: +203,313,82514,6,0,P|238:323|279:341,1,73.0799977697755,0|0,3:2|0:0,0:0:0:0: +406,168,82838,2,0,P|371:178|330:197,1,73.0799977697755,0|0,3:2|0:0,0:0:0:0: +209,56,83162,6,0,P|268:41|332:111,1,146.159995539551,2|2,3:2|3:2,0:0:0:0: +239,204,83649,1,2,0:0:0:0: +328,92,83811,2,0,P|362:82|409:58,1,73.0799977697755,2|0,3:2|0:0,0:0:0:0: +507,193,84135,2,0,P|472:185|430:164,1,73.0799977697755,2|8,3:2|0:1,0:0:0:0: +274,337,84460,6,0,B|346:308|346:308|405:324|381:362,1,146.159995539551,4|0,3:2|3:2,0:0:0:0: +239,204,84946,1,2,0:0:0:0: +186,260,85108,2,0,L|100:282,1,73.0799977697755,0|0,3:2|0:0,0:0:0:0: +281,136,85432,2,0,L|365:156,1,73.0799977697755,0|0,3:2|0:0,0:0:0:0: +161,5,85757,5,6,3:2:0:0: +239,204,85919,1,2,0:0:0:0: +273,44,86081,5,10,0:1:0:0: +124,190,86243,2,0,B|226:178|199:272|321:253,1,198.359997578613,4|0,3:2|3:2,0:0:0:0: +161,5,86730,1,8,0:0:0:0: +138,37,86811,1,8,0:1:0:0: +147,70,86892,1,0,3:2:0:0: +352,152,87054,6,0,P|421:237|391:332,1,198.359997578613,2|0,3:2|3:2,0:0:0:0: +239,204,87541,1,0,0:0:0:0: +183,253,87703,2,0,P|194:300|201:363,1,99.1799987893067,0|0,3:2|0:0,0:0:0:0: +307,256,88027,1,0,3:2:0:0: +193,142,88189,5,8,0:0:0:0: +307,256,88351,2,0,B|201:239|236:343|86:313,1,198.359997578613,2|0,3:2|3:2,0:0:0:0: +323,165,88838,1,0,0:0:0:0: +171,32,89000,2,0,P|206:60|274:60,1,99.1799987893067,0|8,3:2|0:0,0:0:0:0: +166,153,89324,6,0,L|69:176,1,83.52,4|0,3:0|0:0,0:0:0:0: +54,183,89649,5,4,3:2:0:0: +282,51,89811,1,2,0:0:0:0: +153,20,89973,5,10,0:0:0:0: +339,174,90135,1,0,3:2:0:0: +126,318,90297,1,0,3:2:0:0: +238,125,90460,1,0,3:2:0:0: +242,141,90541,1,0,3:2:0:0: +244,158,90622,1,0,3:2:0:0: +338,281,90784,6,0,B|374:293|374:293|388:309|388:309|454:328,1,111.36,4|0,3:2|3:2,0:0:0:0: +481,138,91270,2,0,L|403:158,1,55.68,8|0,0:0|0:0,0:0:0:0: +356,170,91514,1,8,3:0:0:0: +339,174,91595,1,0,3:2:0:0: +463,235,91757,1,8,3:0:0:0: +373,95,91919,2,0,P|378:53|392:6,1,83.52,8|0,3:0|0:0,0:0:0:0: +389,13,92243,6,0,P|354:57|267:49,1,146.159995539551,4|2,1:2|3:2,0:0:0:0: +126,207,92892,2,0,P|160:196|206:186,1,73.0799977697755,2|0,3:2|0:3,0:3:0:0: +75,40,93216,2,0,P|111:51|155:59,1,73.0799977697755,2|2,3:2|0:0,0:0:0:0: +42,128,93541,5,2,1:2:0:0: +126,207,93703,2,0,L|102:355,1,146.159995539551,2|2,0:0|0:0,0:0:0:0: +260,235,94189,2,0,L|272:312,1,73.0799977697755,2|0,3:2|0:0,0:0:0:0: +404,168,94514,1,2,3:2:0:0: +329,138,94676,1,0,1:2:0:0: +389,280,94838,6,0,B|467:265|433:222|519:208,1,146.159995539551,2|2,1:2|3:2,0:0:0:0: +512,209,95487,6,0,P|477:201|434:180,1,73.0799977697755,2|0,3:2|0:0,0:0:0:0: +306,51,95811,2,0,P|341:45|387:22,1,73.0799977697755,0|2,3:2|1:2,0:0:0:0: +265,196,96135,5,2,1:2:0:0: +169,81,96297,2,0,P|202:96|255:108,1,73.0799977697755,2|0,0:0|3:2,0:0:0:0: +106,191,96622,1,2,1:2:0:0: +220,333,96784,2,0,L|208:237,2,73.0799977697755,10|0|0,0:0|3:2|3:2,0:0:0:0: +208,345,97432,5,4,3:2:0:0: +373,258,97595,1,8,0:1:0:0: +373,258,97676,1,8,0:1:0:0: +373,258,97757,1,0,3:2:0:0: +286,206,97919,5,8,0:0:0:0: +404,345,98081,1,8,3:1:0:0: +404,345,98162,1,8,0:1:0:0: +404,345,98243,1,8,0:1:0:0: +295,285,98405,5,10,0:0:0:0: +455,191,98568,1,8,0:1:0:0: +455,191,98649,1,8,0:1:0:0: +455,191,98730,6,0,L|442:98,1,73.0799977697755,8|8,0:0|0:1,0:0:0:0: +433,49,98973,1,8,0:1:0:0: +430,33,99054,1,0,3:2:0:0: +322,120,99216,1,8,0:1:0:0: +236,48,99378,1,0,3:2:0:0: +237,36,99460,1,8,0:1:0:0: +239,20,99541,1,8,0:1:0:0: +322,120,99703,5,8,3:2:0:0: +166,190,99865,1,8,0:1:0:0: +165,177,99946,1,8,0:1:0:0: +163,166,100027,6,0,B|195:129|243:146|243:146|267:202|319:200,1,180.959998895508,4|8,3:2|0:1,0:0:0:0: +136,71,100514,1,8,0:1:0:0: +322,120,100676,5,10,0:0:0:0: +119,280,100838,1,8,0:1:0:0: +236,48,101000,5,8,0:0:0:0: +346,315,101162,1,8,0:0:0:0: +47,167,101324,5,4,3:2:0:0: +384,47,101487,1,4,3:2:0:0: +392,53,102135,5,8,0:1:0:0: +392,53,102216,5,8,0:1:0:0: +392,53,102297,6,0,B|325:31|325:31|270:44|248:110|311:129,1,187.920004587891,8|0,0:0|0:0,0:0:0:0: +229,189,102622,6,0,B|322:178|287:244|401:227,1,163.559997504273,4|10,3:2|0:0,0:0:0:0: +438,175,103108,1,0,0:0:0:0: +285,287,103270,2,0,L|196:302,1,81.7799987521363,2|0,3:2|3:2,0:0:0:0: +343,378,103595,1,8,0:0:0:0: +363,307,103757,1,2,0:0:0:0: +194,121,103919,5,2,3:2:0:0: +229,189,104081,2,0,L|309:206,1,81.7799987521363,2|8,0:0|0:0,0:0:0:0: +146,366,104405,2,0,P|108:332|134:259,1,122.669998128204,2|0,3:2|0:0,0:0:0:0: +95,201,104730,1,0,3:2:0:0: +272,122,104892,2,0,P|305:79|270:9,1,122.669998128204,8|0,0:0|0:0,0:0:0:0: +214,1,105216,6,0,B|117:-5|149:53|50:41,1,163.559997504273,4|10,3:2|0:0,0:0:0:0: +194,121,105703,1,0,0:0:0:0: +95,201,105865,2,0,L|112:103,1,81.7799987521363,2|2,3:2|3:2,0:0:0:0: +279,219,106189,2,0,L|295:356,1,122.669998128204,8|0,0:0|0:0,0:0:0:0: +231,382,106514,6,0,P|200:355|210:313,1,81.7799987521363,2|0,3:2|0:0,0:0:0:0: +369,185,106838,2,0,L|461:213,1,81.7799987521363,10|2,0:0|3:2,0:0:0:0: +310,88,107162,1,2,0:0:0:0: +300,16,107324,1,0,3:2:0:0: +194,121,107487,1,8,0:0:0:0: +378,195,107649,1,8,0:1:0:0: +378,195,107730,1,8,0:1:0:0: +378,195,107811,6,0,B|289:190|315:259|208:247,1,163.559997504273,2|8,3:2|0:0,0:0:0:0: +122,87,108297,1,0,0:0:0:0: +194,121,108460,1,0,3:2:0:0: +48,214,108622,1,0,3:2:0:0: +37,137,108784,1,10,0:0:0:0: +144,208,108946,1,8,0:1:0:0: +144,208,109027,1,8,0:1:0:0: +144,208,109108,6,0,L|121:352,1,122.669998128204,0|0,3:2|0:0,0:0:0:0: +58,361,109432,1,8,0:0:0:0: +244,241,109595,6,0,P|327:236|374:308,1,163.559997504273,0|2,3:2|3:2,0:0:0:0: +194,121,110081,1,10,0:0:0:0: +354,43,110243,1,2,0:0:0:0: +290,0,110405,5,0,3:2:0:0: +402,132,110568,1,8,3:1:0:0: +402,132,110649,1,8,0:1:0:0: +402,132,110730,6,0,B|301:107|301:107|319:135|323:171,1,161.819993580139,4|0,3:2|0:0,0:0:0:0: +117,295,111054,2,0,B|157:241|217:263|217:263|246:327|317:322,1,215.759991440186,4|8,3:2|0:0,0:0:0:0: +109,164,111541,1,8,0:1:0:0: +109,164,111622,1,8,0:1:0:0: +109,164,111703,5,2,3:2:0:0: +279,95,111865,1,0,3:2:0:0: +99,38,112027,5,8,0:0:0:0: +216,244,112189,2,0,L|194:71,1,161.819993580139,4|0,3:2|0:0,0:0:0:0: +245,28,112514,1,0,3:2:0:0: +23,186,112676,1,8,0:0:0:0: +179,352,112838,1,8,3:1:0:0: +159,363,112919,1,8,3:1:0:0: +138,355,113000,6,0,L|153:288,1,53.9399978600465,0|0,3:2|0:0,0:0:0:0: +331,171,113162,1,4,3:2:0:0: +397,215,113324,6,0,L|408:278,1,55.68,2|0,0:0|0:0,0:0:0:0: +252,149,113649,1,0,3:2:0:0: +411,51,113811,1,8,3:0:0:0: +347,16,113973,1,0,3:2:0:0: +457,161,114135,6,0,B|382:174|382:174|349:227|349:227|265:242,1,215.759991440186,6|2,3:2|3:2,0:0:0:0: +126,120,114622,1,10,0:0:0:0: +267,55,114784,1,0,3:2:0:0: +130,257,114946,5,10,0:0:0:0: +179,36,115108,1,0,3:2:0:0: +179,36,115189,1,0,3:2:0:0: +179,36,115270,5,8,0:0:0:0: +353,157,115432,1,0,3:2:0:0: +130,257,115595,5,8,0:0:0:0: +353,74,115757,1,12,0:0:0:0: +259,0,115919,2,0,L|270:73,1,55.68,2|8,0:0|0:3,0:0:0:0: +280,124,116162,1,8,0:3:0:0: +283,135,116243,5,0,3:2:0:0: +441,224,116405,1,0,3:2:0:0: +353,74,116568,5,8,0:0:0:0: +203,217,116730,6,0,B|264:204|281:151|281:151|268:218|308:262,1,215.759991440186,4|2,3:2|3:2,0:0:0:0: +180,111,117216,2,0,L|62:85,1,107.879995720093,10|0,0:0|3:2,0:0:0:0: +241,8,117541,1,10,0:0:0:0: +76,228,117703,1,8,0:1:0:0: +80,217,117784,1,8,0:1:0:0: +85,205,117865,2,0,L|146:222,1,53.9399978600465,8|0,0:1|0:0,0:0:0:0: +334,361,118027,1,8,0:1:0:0: +328,344,118108,1,8,0:1:0:0: +321,329,118189,6,0,L|234:345,1,73.0799977697755,4|8,3:2|0:1,0:0:0:0: +180,358,118432,1,8,0:1:0:0: +164,362,118514,1,2,3:2:0:0: +301,253,118676,1,8,0:1:0:0: +407,282,118838,6,0,L|506:306,1,73.0799977697755,2|8,3:2|0:1,0:0:0:0: +321,172,119162,1,2,3:1:0:0: +445,94,119324,1,8,0:1:0:0: +431,98,119405,1,8,0:1:0:0: +416,103,119487,5,0,3:2:0:0: +316,12,119649,1,8,0:1:0:0: +331,16,119730,1,8,0:1:0:0: +342,22,119811,2,0,L|323:104,1,73.0799977697755,2|8,3:2|0:1,0:0:0:0: +194,229,120135,1,10,3:1:0:0: +150,214,120216,1,8,0:1:0:0: +132,178,120297,1,8,0:1:0:0: +143,139,120378,1,8,0:1:0:0: +175,120,120460,5,10,3:1:0:0: +331,273,120622,1,8,0:1:0:0: +331,273,120703,1,8,0:1:0:0: +331,273,120784,6,0,L|251:293,1,73.0799977697755,0|8,3:2|0:1,0:0:0:0: +189,306,121027,1,8,0:1:0:0: +172,311,121108,1,2,3:2:0:0: +278,193,121270,1,8,0:0:0:0: +175,120,121432,5,10,3:1:0:0: +174,109,121514,1,8,0:1:0:0: +173,98,121595,1,8,0:1:0:0: +276,0,121757,2,0,L|262:81,1,73.0799977697755,2|8,3:2|0:1,0:0:0:0: +315,126,122000,1,8,0:1:0:0: +315,126,122081,5,10,3:1:0:0: +177,210,122243,1,8,0:1:0:0: +162,214,122324,1,8,0:1:0:0: +150,217,122405,1,8,3:1:0:0: +260,290,122568,1,10,0:0:0:0: +312,208,122730,5,8,3:1:0:0: +346,188,122811,1,8,0:1:0:0: +384,199,122892,1,8,0:1:0:0: +406,233,122973,1,8,0:1:0:0: +391,250,123054,5,10,3:2:0:0: +413,304,123135,1,8,0:0:0:0: +474,312,123216,1,8,0:0:0:0: +512,266,123297,1,8,0:0:0:0: +512,251,123378,6,0,L|494:124,1,90.4799994477539,4|0,3:2|0:0,0:0:0:0: +260,290,123703,5,10,0:0:0:0: +324,73,123865,1,0,3:2:0:0: +413,304,124027,5,10,0:0:0:0: +222,147,124189,1,2,3:2:0:0: +437,36,124351,1,10,0:0:0:0: +346,188,124514,1,0,3:2:0:0: +192,21,124676,6,0,L|85:-5,1,90.4799994477539,8|0,0:0|0:0,0:0:0:0: +222,147,125000,5,10,0:0:0:0: +22,215,125162,1,0,3:2:0:0: +104,0,125324,5,8,0:0:0:0: +240,244,125487,1,0,3:2:0:0: +238,231,125568,1,0,3:2:0:0: +235,218,125649,1,8,0:0:0:0: +59,133,125811,1,8,0:1:0:0: +62,122,125892,1,8,0:1:0:0: +64,111,125973,5,4,3:2:0:0: +22,215,126135,1,0,3:2:0:0: +157,96,126297,5,0,3:2:0:0: +104,270,126460,1,0,3:2:0:0: +241,72,126622,5,0,3:2:0:0: +198,320,126784,1,0,3:2:0:0: +330,46,126946,5,10,0:0:0:0: +294,371,127108,1,8,0:0:0:0: +436,24,127270,5,8,3:2:0:0: +128,184,127432,1,8,0:0:0:0: +446,344,127595,1,8,0:0:0:0: +266,0,127757,1,8,0:0:0:0: +152,384,127919,1,8,0:0:0:0: +512,170,128081,1,0,3:2:0:0: +266,0,128243,6,0,L|280:152,1,133.979997342316,6|0,3:2|0:0,0:0:0:0: +378,196,128487,5,2,0:0:0:0: +396,176,128568,6,0,B|357:124|293:152|293:152|277:210|204:207,1,215.759991440186,6|8,3:1|0:0,0:0:0:0: +365,56,129054,1,2,0:0:0:0: +312,299,129216,5,0,3:2:0:0: +196,119,129378,1,0,3:2:0:0: +396,176,129541,1,8,0:0:0:0: +208,302,129703,1,2,0:0:0:0: +298,190,129865,6,0,B|410:171|384:285|519:260,1,215.759991440186,2|8,3:2|0:0,0:0:0:0: +281,90,130351,1,2,0:0:0:0: +484,174,130514,5,0,3:2:0:0: +312,299,130676,1,0,3:2:0:0: +504,380,130838,5,8,0:0:0:0: +307,198,131000,1,2,0:0:0:0: +307,198,131081,1,2,0:0:0:0: +307,198,131162,6,0,B|264:187|228:210|228:210|207:260|137:254,1,161.819993580139,4|0,3:2|0:0,0:0:0:0: +110,300,131487,1,8,0:0:0:0: +0,176,131649,1,2,0:0:0:0: +144,107,131811,5,0,3:2:0:0: +3,282,131973,1,0,3:2:0:0: +212,186,132135,5,8,0:0:0:0: +77,31,132297,1,2,0:0:0:0: +212,186,132460,6,0,P|255:216|323:195,1,107.879995720093,2|2,3:2|0:0,0:0:0:0: +455,384,132784,1,10,0:0:0:0: +297,290,132946,1,2,0:0:0:0: +430,145,133108,5,4,3:2:0:0: +339,362,133270,1,0,3:2:0:0: +512,239,133432,1,8,0:0:0:0: +344,92,133595,1,8,0:0:0:0: +344,92,133676,1,8,0:0:0:0: +344,92,133757,6,0,L|367:257,1,161.819993580139,2|0,3:2|0:0,0:0:0:0: +297,290,134081,1,10,0:0:0:0: +430,145,134243,1,2,0:0:0:0: +277,8,134405,2,0,P|241:52|262:114,1,107.879995720093,0|2,3:2|3:2,0:0:0:0: +442,257,134730,1,8,0:0:0:0: +344,92,134892,5,2,0:0:0:0: +205,225,135054,2,0,P|151:234|87:254,1,107.879995720093,2|2,3:2|0:0,0:0:0:0: +268,363,135378,1,10,0:0:0:0: +91,241,135541,2,0,P|67:170|170:105,1,215.759991440186,2|2,0:0|3:2,0:0:0:0: +331,242,136027,1,8,0:0:0:0: +128,372,136189,1,2,0:0:0:0: +223,299,136351,6,0,B|278:315|278:315|303:353|303:353|396:375,1,161.819993580139,4|0,3:2|0:0,0:0:0:0: +433,383,136676,1,10,0:0:0:0: +257,167,136838,1,0,3:2:0:0: +491,120,137000,5,8,0:0:0:0: +338,248,137162,1,0,3:2:0:0: +338,248,137243,1,0,3:2:0:0: +338,248,137324,1,8,0:0:0:0: +198,103,137487,1,0,3:2:0:0: +435,212,137649,5,10,0:0:0:0: +208,351,137811,2,0,L|223:296,1,53.9399978600465,10|0,0:0|0:0,0:0:0:0: +69,173,137973,2,0,L|85:251,2,53.9399978600465,10|8|10,0:0|0:0|0:1,0:0:0:0: +208,50,138297,6,0,L|194:124,1,53.9399978600465,10|0,3:2|0:0,0:0:0:0: +46,24,138460,2,0,P|70:12|105:2,1,53.9399978600465,8|0,3:0|0:0,0:0:0:0: +260,205,138622,2,0,P|236:193|194:181,1,53.9399978600465,10|0,0:0|0:0,0:0:0:0: +343,15,138784,2,0,P|356:46|347:88,1,53.9399978600465,2|0,0:0|0:0,0:0:0:0: +210,184,138946,6,0,B|328:154|328:154|384:193|355:253,1,215.759991440186,6|10,3:1|0:0,0:0:0:0: +512,353,139432,1,0,0:0:0:0: +435,378,139595,2,0,L|458:259,1,107.879995720093,0|0,3:2|3:2,0:0:0:0: +274,125,139919,2,0,B|287:182|287:182|269:223|269:223|282:288,1,161.819993580139,10|0,0:0|0:0,0:0:0:0: +289,361,140243,6,0,B|310:330|349:326|349:326|206:293,1,215.759991440186,4|8,3:2|0:0,0:0:0:0: +387,151,140730,1,2,0:0:0:0: +187,95,140892,5,2,3:2:0:0: +368,321,141054,1,2,3:2:0:0: +287,41,141216,1,10,0:0:0:0: +101,196,141378,1,2,0:0:0:0: +308,124,141541,5,2,3:2:0:0: +107,7,141703,1,2,3:2:0:0: +226,219,141865,5,8,0:0:0:0: +374,40,142027,2,0,P|440:36|504:166,1,215.759991440186,2|2,0:0|3:2,0:0:0:0: +287,41,142514,2,0,P|235:31|168:15,1,107.879995720093,8|0,0:0|0:0,0:0:0:0: +29,243,142838,6,0,B|78:249|106:205|92:210|120:161|186:179,1,161.819993580139,2|0,3:2|0:0,0:0:0:0: +226,219,143162,1,8,0:0:0:0: +364,348,143324,1,2,0:0:0:0: +364,348,143405,1,2,0:0:0:0: +364,348,143487,6,0,L|291:364,1,53.9399978600465,4|0,3:2|0:0,0:0:0:0: +429,222,143649,2,0,L|493:240,1,53.9399978600465,0|0,3:2|0:0,0:0:0:0: +344,142,143811,1,8,3:2:0:0: +313,113,143892,1,8,0:0:0:0: +311,72,143973,1,8,0:0:0:0: +342,40,144054,1,8,0:0:0:0: +403,74,144135,6,0,B|283:53|324:157|181:128,1,215.759991440186,4|8,3:2|0:0,0:0:0:0: +365,267,144622,1,2,0:0:0:0: +232,48,144784,1,10,0:0:0:0: +106,218,144946,1,0,3:2:0:0: +313,113,145108,1,8,0:0:0:0: +107,0,145270,1,2,0:0:0:0: +107,0,145351,1,2,0:0:0:0: +107,0,145432,6,0,P|117:51|123:117,1,107.879995720093,4|0,3:2|3:2,0:0:0:0: +325,27,145757,1,8,0:0:0:0: +256,238,145919,1,2,3:2:0:0: +149,107,146081,5,10,0:0:0:0: +368,228,146243,1,0,3:2:0:0: +120,384,146405,5,10,0:0:0:0: +329,316,146568,1,0,3:2:0:0: +149,107,146730,6,0,L|169:277,1,146.159995539551,6|2,3:2|0:0,0:0:0:0: +113,306,147216,1,2,3:2:0:0: +318,147,147378,5,8,0:0:0:0: +149,71,147541,1,2,0:0:0:0: +149,71,147703,1,2,0:0:0:0: +246,15,147865,1,2,0:0:0:0: +199,171,148027,6,0,P|163:179|113:197,1,73.0799977697755,2|0,3:2|0:0,0:0:0:0: +256,101,148351,1,2,0:0:0:0: +356,225,148514,1,0,3:2:0:0: +424,185,148676,2,0,P|433:151|436:88,1,73.0799977697755,8|0,0:0|0:0,0:0:0:0: +270,245,149000,2,0,P|274:288|288:326,1,73.0799977697755 +360,339,149324,6,0,B|275:331|301:385|187:375,1,146.159995539551,4|2,3:2|3:2,0:0:0:0: +356,225,149811,1,2,3:2:0:0: +168,96,149973,5,8,0:0:0:0: +360,339,150216,5,2,0:0:0:0: +242,25,150460,5,2,0:0:0:0: +86,185,150622,6,0,P|49:183|16:146,2,73.0799977697755,2|0|2,3:2|0:0|0:0,0:0:0:0: +140,240,151108,1,0,3:2:0:0: +256,131,151270,2,0,L|355:108,1,73.0799977697755,10|0,0:0|0:0,0:0:0:0: +399,95,151514,1,8,0:1:0:0: +419,89,151595,1,2,3:2:0:0: +319,36,151757,1,2,0:0:0:0: +416,229,151919,5,6,3:2:0:0: +489,32,152081,1,0,3:2:0:0: +327,114,152243,5,0,3:2:0:0: +331,126,152568,1,0,3:2:0:0: +335,138,152892,1,2,3:2:0:0: +488,256,153216,5,0,3:2:0:0: +488,244,153541,1,0,3:2:0:0: +489,228,153865,5,0,3:2:0:0: +315,330,154027,1,8,0:0:0:0: +426,384,154189,1,2,3:2:0:0: +336,233,154351,1,2,0:0:0:0: +336,233,154432,1,2,0:0:0:0: +336,233,154514,5,4,3:2:0:0: +137,361,154676,1,0,3:2:0:0: +202,170,154838,5,0,3:2:0:0: +205,190,155162,1,0,3:2:0:0: +208,209,155487,1,0,3:2:0:0: +80,122,155811,5,0,3:2:0:0: +230,48,155973,1,0,3:2:0:0: +61,0,156135,5,8,0:0:0:0: +193,148,156297,1,8,0:1:0:0: +217,158,156378,1,8,0:1:0:0: +244,152,156460,1,2,3:2:0:0: +120,246,156622,1,0,3:2:0:0: +294,99,156784,1,8,3:1:0:0: +318,82,156865,1,8,0:1:0:0: +351,87,156946,1,8,0:1:0:0: +428,207,157108,5,4,3:2:0:0: +230,48,157270,1,0,3:2:0:0: +120,246,157432,5,0,3:2:0:0: +122,229,157757,1,0,3:2:0:0: +124,213,158081,5,2,3:2:0:0: +295,314,158243,1,10,0:0:0:0: +122,384,158405,5,4,3:2:0:0: +324,222,158568,1,0,3:2:0:0: +428,368,158730,2,0,L|352:344,1,73.0799977697755,2|0,3:2|0:0,0:0:0:0: +380,162,159054,5,8,3:0:0:0: +242,215,159216,1,8,3:0:0:0: +428,368,159378,6,0,L|450:246,1,109.619996654663,10|0,0:0|0:0,0:0:0:0: +380,162,159703,6,0,B|379:125|363:88|363:88|385:53|435:69,1,148.76999818396,4|0,3:2|0:0,0:0:0:0: +484,116,160027,1,10,0:0:0:0: +242,215,160189,6,0,B|196:192|139:188|139:188|98:137|156:99,1,198.359997578613,4|0,3:2|3:2,0:0:0:0: +327,235,160676,1,8,0:0:0:0: +175,377,160838,1,2,0:0:0:0: +175,377,160919,1,2,0:0:0:0: +175,377,161000,6,0,P|145:339|161:276,1,99.1799987893067,2|0,3:2|3:2,0:0:0:0: +330,156,161324,1,8,0:0:0:0: +471,341,161487,1,8,0:1:0:0: +434,364,161568,1,8,0:1:0:0: +399,355,161649,5,10,0:0:0:0: +328,258,161811,1,0,3:2:0:0: +474,149,161973,5,10,0:0:0:0: +466,186,162054,1,8,0:0:0:0: +458,219,162135,1,8,0:0:0:0: +363,82,162297,6,0,B|306:61|268:101|268:101|247:159|186:148,1,198.359997578613,4|8,3:2|0:0,0:0:0:0: +139,96,162784,1,0,0:0:0:0: +35,225,162946,5,2,0:0:0:0: +60,152,163108,1,0,3:2:0:0: +223,298,163270,1,8,0:0:0:0: +210,223,163432,1,2,0:0:0:0: +45,321,163595,6,0,P|91:334|146:360,1,99.1799987893067,0|0,3:2|0:0,0:0:0:0: +287,246,163919,1,8,0:0:0:0: +139,96,164081,1,2,0:0:0:0: +287,246,164243,6,0,P|333:237|393:212,1,99.1799987893067,2|0,0:0|3:2,0:0:0:0: +228,64,164568,2,0,P|167:119|184:185,1,148.76999818396,8|0,0:0|0:0,0:0:0:0: +187,251,164892,5,4,3:2:0:0: +362,95,165054,1,0,3:2:0:0: +178,177,165216,5,8,0:0:0:0: +393,331,165378,2,0,P|416:285|393:224,1,99.1799987893067,2|0,3:2|0:0,0:0:0:0: +224,352,165703,2,0,P|174:360|108:380,1,99.1799987893067,2|8,3:2|0:0,0:0:0:0: +38,139,166027,6,0,B|90:140|125:108|125:108|80:150|98:217,1,198.359997578613,2|2,3:2|3:2,0:0:0:0: +224,352,166514,1,8,0:0:0:0: +320,219,166676,1,2,0:0:0:0: +320,219,166757,1,2,0:0:0:0: +320,219,166838,2,0,L|337:325,1,99.1799987893067,0|0,3:2|3:2,0:0:0:0: +208,168,167162,2,0,P|239:110|319:114,1,148.76999818396,8|8,0:0|0:1,0:0:0:0: +387,85,167487,5,4,3:2:0:0: +387,85,167811,6,0,P|393:133|403:185,1,99.1799987893067,2|0,3:2|0:0,0:0:0:0: +247,0,168135,2,0,P|231:46|228:99,1,99.1799987893067,0|0,3:2|0:0,0:0:0:0: +51,253,168460,2,0,P|86:198|169:220,1,148.76999818396,2|0,3:2|0:0,0:0:0:0: +184,282,168784,6,0,P|232:292|284:317,1,99.1799987893067,10|0,3:1|0:0,0:0:0:0: +402,182,169108,2,0,P|354:191|293:217,1,99.1799987893067,2|0,3:2|0:0,0:0:0:0: +414,367,169432,2,0,P|440:323|419:267,1,99.1799987893067,2|0,3:2|0:0,0:0:0:0: +223,116,169757,2,0,P|230:165|234:241,1,99.1799987893067,2|0,3:2|0:0,0:0:0:0: +488,67,170081,6,0,P|450:22|352:52,1,148.76999818396,10|0,3:1|0:0,0:0:0:0: +319,92,170405,2,0,P|270:101|204:123,1,99.1799987893067,2|0,3:2|0:0,0:0:0:0: +393,237,170730,2,0,P|439:248|503:272,1,99.1799987893067,2|0,3:2|0:0,0:0:0:0: +308,384,171054,2,0,P|280:339|306:287,1,99.1799987893067,2|0,3:2|0:0,0:0:0:0: +195,44,171378,6,0,L|173:230,1,148.76999818396,2|0,3:2|0:0,0:0:0:0: +230,247,171703,1,0,3:2:0:0: +31,366,171865,2,0,B|7:268|7:268|99:234,1,198.359997578613,2|2,0:0|0:0,0:0:0:0: +204,62,172351,6,0,B|147:52|147:52|124:22|124:22|52:13,1,148.76999818396,10|0,0:0|0:0,0:0:0:0: +14,62,172676,5,4,3:2:0:0: +161,175,172838,1,0,3:2:0:0: +35,149,173000,5,0,3:2:0:0: +204,62,173162,1,0,3:2:0:0: +262,266,173324,5,8,3:1:0:0: +124,91,173487,1,8,3:1:0:0: +123,310,173649,5,8,3:1:0:0: +265,107,173811,1,8,3:1:0:0: +319,381,173973,5,8,3:2:0:0: +161,175,174135,1,8,3:2:0:0: +363,258,174297,1,8,3:2:0:0: +155,384,174460,1,8,3:2:0:0: +364,59,174622,5,8,0:0:0:0: +410,341,174784,1,8,0:0:0:0: +205,35,174946,1,8,0:0:0:0: +123,310,175108,1,8,0:0:0:0: +411,183,175270,5,4,3:2:0:0: +80,49,175432,1,4,3:2:0:0: +67,42,176081,5,0,3:2:0:0: +231,249,176243,1,8,0:0:0:0: +433,101,176405,6,0,B|406:83|394:47|394:47|373:160,1,174.869991728257,4|0,3:2|0:0,0:0:0:0: +427,207,176730,1,0,3:2:0:0: +281,95,176892,1,8,0:0:0:0: +471,27,177054,1,2,0:0:0:0: +273,219,177216,5,10,0:0:0:0: +273,219,177297,1,8,0:0:0:0: +273,219,177378,2,0,P|246:213|220:194,1,58.2899972427522,8|8,0:0|0:0,0:0:0:0: +377,361,177541,6,0,P|407:355|441:327,1,57.4200017523194,6|0,3:2|0:0,0:0:0:0: +465,274,177865,5,6,3:1:0:0: +100,334,182892,5,0,3:2:0:0: +72,268,183054,2,0,P|133:256|210:340,1,167.04,2|0,3:2|3:2,0:0:0:0: +328,140,183703,2,0,L|210:168,1,111.36,10|0,0:0|0:0,0:0:0:0: +349,304,184189,1,8,0:1:0:0: +349,304,184270,1,8,0:1:0:0: +349,304,184351,5,0,3:2:0:0: +349,304,184838,5,0,3:2:0:0: +219,165,185000,2,0,L|233:100,1,55.68,8|0,0:0|0:0,0:0:0:0: +353,62,185324,1,2,0:0:0:0: +121,275,185568,5,8,0:1:0:0: +129,262,185649,2,0,L|210:247,1,73.0799977697755,4|8,3:1|0:1,0:0:0:0: +272,234,185892,1,8,0:1:0:0: +295,231,185973,1,2,3:2:0:0: +219,165,186135,1,8,0:0:0:0: +349,304,186297,2,0,L|333:383,1,73.0799977697755,2|8,3:2|0:1,0:0:0:0: +468,214,186622,1,8,0:0:0:0: +398,238,186784,1,8,0:1:0:0: +432,55,186946,6,0,L|449:141,1,73.0799977697755,2|8,3:2|0:1,0:0:0:0: +464,196,187189,1,8,0:1:0:0: +468,214,187270,1,0,3:2:0:0: +338,93,187432,1,8,0:0:0:0: +219,165,187595,5,8,3:1:0:0: +187,181,187676,1,8,0:1:0:0: +157,164,187757,1,8,0:1:0:0: +152,127,187838,1,8,0:1:0:0: +177,105,187919,1,10,3:1:0:0: +317,233,188081,1,8,0:1:0:0: +317,233,188162,1,8,0:1:0:0: +317,233,188243,6,0,L|293:356,1,109.619996654663,2|8,3:2|0:1,0:0:0:0: +353,384,188568,1,2,3:2:0:0: +216,275,188730,1,8,0:0:0:0: +385,171,188892,6,0,P|393:206|401:270,1,73.0799977697755,2|8,3:2|0:1,0:0:0:0: +194,34,189216,2,0,P|183:68|176:117,1,73.0799977697755,8|8,0:0|0:1,0:0:0:0: +122,156,189460,1,8,0:1:0:0: +122,156,189541,5,10,0:0:0:0: +301,45,189703,1,8,0:0:0:0: +301,45,189784,1,8,0:0:0:0: +301,45,189865,1,8,0:0:0:0: +385,171,190027,5,8,0:0:0:0: +194,34,190189,1,8,3:2:0:0: +194,34,190270,1,8,0:0:0:0: +194,34,190351,6,0,L|204:98,1,36.5399988848877,8|0,0:0|0:0,0:0:0:0: +42,248,190514,1,8,3:2:0:0: +42,248,190595,1,8,0:0:0:0: +42,248,190676,2,0,L|52:184,1,36.5399988848877,8|8,0:0|0:0,0:0:0:0: +16,145,190838,6,0,P|87:131|151:217,1,167.04,2|0,3:2|3:2,0:0:0:0: +296,345,191487,5,8,3:2:0:0: +261,370,191568,1,8,0:0:0:0: +221,354,191649,2,0,P|211:329|215:295,1,58.2899972427522,8|0,0:0|0:0,0:0:0:0: +378,138,191811,5,4,3:2:0:0: +343,113,191892,1,8,0:0:0:0: +303,129,191973,2,0,P|293:154|297:188,1,58.2899972427522,8|0,0:0|0:0,0:0:0:0: +352,270,192135,6,0,B|243:247|274:348|133:321,1,198.359997578613,6|8,3:1|0:0,0:0:0:0: +295,184,192622,1,2,0:0:0:0: +129,67,192784,2,0,P|174:101|225:92,1,99.1799987893067,2|0,3:2|3:2,0:0:0:0: +87,223,193108,1,10,0:0:0:0: +231,80,193270,1,2,0:0:0:0: +231,80,193351,1,2,0:0:0:0: +231,80,193432,6,0,P|282:32|373:53,1,148.76999818396,2|0,3:2|0:0,0:0:0:0: +414,88,193757,2,0,L|392:192,1,99.1799987893067,8|0,0:0|0:0,0:0:0:0: +273,328,194081,1,0,3:2:0:0: +486,204,194243,1,0,3:2:0:0: +307,111,194405,1,8,0:0:0:0: +431,324,194568,1,2,0:0:0:0: +434,307,194649,1,2,0:0:0:0: +437,293,194730,6,0,B|395:250|342:273|342:273|316:332|262:327,1,198.359997578613,2|8,3:2|0:0,0:0:0:0: +119,181,195216,1,2,0:0:0:0: +30,306,195378,2,0,P|76:292|138:282,1,99.1799987893067,2|0,3:2|3:2,0:0:0:0: +231,143,195703,1,10,0:0:0:0: +102,33,195865,1,2,0:0:0:0: +102,33,195946,1,2,0:0:0:0: +102,33,196027,6,0,P|148:48|209:58,1,99.1799987893067,2|0,3:2|3:2,0:0:0:0: +89,175,196351,1,8,0:0:0:0: +260,250,196514,1,2,0:0:0:0: +97,370,196676,5,4,3:2:0:0: +247,163,196838,1,8,0:0:0:0: +247,163,196919,1,8,0:0:0:0: +247,163,197000,2,0,L|312:179,1,49.5899993946533,0|0,3:2|0:0,0:0:0:0: +473,339,197162,1,8,0:0:0:0: +441,363,197243,1,8,0:0:0:0: +403,349,197324,6,0,L|423:197,1,148.76999818396,6|0,3:2|0:0,0:0:0:0: +472,140,197649,2,0,P|504:182|483:243,1,99.1799987893067,8|0,0:0|0:0,0:0:0:0: +344,101,197973,1,2,3:2:0:0: +470,38,198135,1,0,3:2:0:0: +347,231,198297,1,8,0:0:0:0: +208,9,198460,1,2,0:0:0:0: +208,9,198541,1,2,0:0:0:0: +208,9,198622,6,0,P|251:27|317:42,1,99.1799987893067,4|2,3:2|0:0,0:0:0:0: +189,186,198946,2,0,B|102:182|137:235|14:229,1,148.76999818396,10|0,0:0|0:0,0:0:0:0: +0,175,199270,1,2,3:2:0:0: +192,352,199432,1,0,3:2:0:0: +0,175,199595,2,0,P|13:126|25:60,1,99.1799987893067,10|0,0:0|0:0,0:0:0:0: +244,262,199919,6,0,P|232:189|227:87,1,148.76999818396,2|0,3:2|0:0,0:0:0:0: +174,61,200243,1,8,0:0:0:0: +49,228,200405,1,2,3:2:0:0: +259,127,200568,5,8,0:0:0:0: +86,2,200730,1,0,3:2:0:0: +86,2,200811,1,0,3:2:0:0: +86,2,200892,5,8,0:0:0:0: +244,262,201054,1,0,3:2:0:0: +23,124,201216,6,0,P|68:109|130:99,1,99.1799987893067,4|0,3:2|3:2,0:0:0:0: +293,0,201541,1,8,0:0:0:0: +447,147,201703,1,8,0:1:0:0: +428,166,201784,1,8,0:1:0:0: +397,165,201865,1,8,0:0:0:0: +483,51,202027,1,0,3:2:0:0: +380,149,202189,6,0,P|321:128|257:179,1,148.76999818396,2|0,3:2|0:0,0:0:0:0: +186,215,202514,6,0,B|288:193|266:293|408:270,1,198.359997578613,4|8,3:1|0:0,0:0:0:0: +208,96,203000,1,0,3:2:0:0: +261,329,203162,1,10,0:0:0:0: +380,149,203324,1,0,3:2:0:0: +186,215,203487,1,10,0:0:0:0: +378,364,203649,1,0,3:2:0:0: +279,239,203811,6,0,B|200:252|200:252|165:290|165:290|80:301,1,198.359997578613,4|8,3:2|0:0,0:0:0:0: +281,153,204297,1,2,0:0:0:0: +110,46,204460,1,8,0:0:0:0: +186,215,204622,1,0,3:2:0:0: +315,72,204784,2,0,P|387:66|439:132,1,148.76999818396,10|2,0:0|0:0,0:0:0:0: +512,176,205108,6,0,B|434:143|434:143|349:175|390:251,1,198.359997578613,6|8,3:2|0:0,0:0:0:0: +512,96,205595,1,2,0:0:0:0: +302,224,205757,5,8,0:0:0:0: +496,334,205919,1,0,3:2:0:0: +363,152,206081,1,10,0:0:0:0: +226,365,206243,1,0,3:2:0:0: +377,226,206405,6,0,B|315:233|279:184|296:182|266:125|194:150,1,198.359997578613,4|8,3:2|0:0,0:0:0:0: +317,310,206892,1,0,3:2:0:0: +282,65,207054,1,4,3:2:0:0: +108,232,207216,1,2,3:2:0:0: +0,163,207378,5,10,0:0:0:0: +21,119,207460,1,8,0:0:0:0: +65,101,207541,1,10,0:0:0:0: +116,115,207622,1,8,0:0:0:0: +131,132,207703,6,0,P|119:172|110:229,1,73.0799977697755,2|0,3:2|0:0,0:0:0:0: +209,284,208027,1,2,0:0:0:0: +87,342,208189,5,0,3:2:0:0: +228,206,208351,2,0,P|261:222|306:236,1,73.0799977697755,8|2,0:0|0:0,0:0:0:0: +317,310,208676,1,2,0:0:0:0: +468,196,208838,5,2,0:0:0:0: +457,192,208919,1,2,0:0:0:0: +444,186,209000,2,0,P|446:223|457:280,1,73.0799977697755,0|0,3:2|0:0,0:0:0:0: +302,84,209324,2,0,P|291:120|286:170,1,73.0799977697755,0|0,3:2|0:0,0:0:0:0: +445,43,209649,5,8,0:0:0:0: +228,206,209892,5,2,0:0:0:0: +447,384,210135,5,2,0:0:0:0: +313,229,210297,6,0,B|231:226|256:272|164:265,1,148.76999818396,4|0,3:2|0:0,0:0:0:0: +138,334,210622,1,0,3:2:0:0: +6,131,210784,6,0,B|116:94|116:94|148:155|89:189,1,198.359997578613,10|8,0:0|0:1,0:0:0:0: +52,220,211189,1,8,0:1:0:0: +47,207,211270,6,0,B|103:220|103:220|118:253|118:253|187:269,1,148.76999818396,4|0,3:2|0:0,0:0:0:0: +226,322,211595,1,0,3:2:0:0: +381,194,211757,6,0,B|361:84|361:84|269:98,1,198.359997578613,8|8,0:0|0:1,0:0:0:0: +237,161,212162,1,8,0:1:0:0: +237,161,212243,6,0,L|305:181,1,49.5899993946533,2|0,3:2|0:0,0:0:0:0: +422,292,212405,2,0,L|351:313,1,49.5899993946533,0|0,3:2|0:0,0:0:0:0: +451,128,212568,6,0,L|463:203,1,49.5899993946533,0|0,3:2|0:0,0:0:0:0: +263,324,212730,2,0,L|275:260,1,49.5899993946533,0|0,3:2|0:0,0:0:0:0: +455,384,212892,5,4,3:2:0:0: +422,292,213054,1,0,3:2:0:0: +321,384,213216,5,0,3:2:0:0: +378,188,213378,1,0,3:2:0:0: +194,379,213541,5,8,0:0:0:0: +130,108,213703,1,8,0:0:0:0: +341,272,213865,1,8,0:0:0:0: +63,384,214027,1,8,0:0:0:0: +243,34,214189,5,4,3:2:0:0: +321,384,214351,1,4,3:2:0:0: +15,145,215162,6,0,B|117:120|117:120|92:149|95:208,1,174.869991728257,6|0,3:2|0:0,0:0:0:0: +172,178,215487,6,0,B|276:158|248:252|371:237,1,198.359997578613,4|8,3:1|0:0,0:0:0:0: +233,321,215973,1,2,0:0:0:0: +406,180,216135,2,0,P|437:224|420:278,1,99.1799987893067,0|0,3:2|3:2,0:0:0:0: +261,148,216460,2,0,B|336:128|295:94|391:69,1,148.76999818396,8|2,0:0|0:0,0:0:0:0: +461,67,216784,6,0,B|388:52|388:52|359:12|359:12|278:-2,1,198.359997578613,2|10,3:2|0:0,0:0:0:0: +406,180,217270,1,2,0:0:0:0: +277,7,217432,6,0,L|173:31,1,99.1799987893067,0|0,3:2|3:2,0:0:0:0: +23,168,217757,2,0,B|55:139|97:145|97:145|115:179|162:192,1,148.76999818396,8|2,0:0|0:0,0:0:0:0: +231,234,218081,6,0,B|163:209|163:209|64:266|123:343,1,198.359997578613,4|8,3:2|0:0,0:0:0:0: +278,165,218568,1,0,0:0:0:0: +348,279,218730,2,0,P|389:308|448:301,1,99.1799987893067,2|0,3:2|3:2,0:0:0:0: +299,68,219054,2,0,L|274:183,1,99.1799987893067,8|0,0:0|0:0,0:0:0:0: +376,7,219378,5,2,3:2:0:0: +204,94,219541,1,2,0:0:0:0: +361,202,219703,1,10,0:0:0:0: +185,326,219865,2,0,L|209:210,1,99.1799987893067,2|4,0:0|3:2,0:0:0:0: +389,313,220189,1,8,0:1:0:0: +388,356,220271,1,8,0:1:0:0: +354,384,220352,1,8,3:1:0:0: +313,384,220433,1,8,0:1:0:0: +285,353,220514,1,8,0:1:0:0: +205,228,220676,6,0,P|150:165|31:201,1,198.359997578613,6|8,3:2|0:0,0:0:0:0: +202,91,221162,1,2,0:0:0:0: +44,0,221324,2,0,P|83:30|139:27,1,99.1799987893067,0|0,3:2|3:2,0:0:0:0: +45,183,221649,6,0,P|35:236|21:298,1,99.1799987893067,8|2,0:0|0:0,0:0:0:0: +78,333,221892,1,2,0:0:0:0: +78,333,221973,2,0,B|159:326|131:378|246:372,1,148.76999818396,2|0,3:2|0:0,0:0:0:0: +285,341,222297,5,8,0:0:0:0: +184,211,222460,1,2,0:0:0:0: +310,164,222622,5,0,3:2:0:0: +163,325,222784,1,0,3:2:0:0: +310,164,222946,2,0,L|324:54,1,99.1799987893067,8|8,0:0|0:1,0:0:0:0: +268,13,223189,1,8,0:1:0:0: +268,13,223270,5,4,3:2:0:0: +406,106,223432,1,2,0:0:0:0: +184,211,223595,1,8,0:0:0:0: +292,88,223757,1,2,0:0:0:0: +361,307,223919,5,10,0:0:0:0: +214,119,224081,1,0,3:2:0:0: +214,119,224162,1,0,3:2:0:0: +214,119,224243,1,0,3:2:0:0: +129,290,224405,5,4,3:2:0:0: +129,290,224730,5,2,0:0:0:0: +86,152,224892,1,8,3:0:0:0: +155,177,225054,1,4,3:0:0:0: +31,270,225216,1,0,3:0:0:0: +186,353,225378,1,8,3:0:0:0: +112,377,225541,1,4,3:0:0:0: +410,158,225865,5,6,3:1:0:0: +350,203,226027,2,0,L|360:270,1,55.68,2|0,0:0|0:0,0:0:0:0: +193,83,226351,5,2,0:0:0:0: +246,136,226514,2,0,L|233:202,1,55.68,2|0,0:0|0:0,0:0:0:0: +394,25,226838,6,0,L|327:43,1,55.68,2|0,0:0|0:0,0:0:0:0: +269,59,227162,1,2,0:0:0:0: +109,153,227324,6,0,L|172:171,1,55.68,2|0,0:0|0:0,0:0:0:0: +235,190,227649,1,2,0:0:0:0: +107,348,227811,6,0,L|99:293,2,55.68,2|0|0,0:0|0:0|0:0,0:0:0:0: +176,384,228297,1,2,0:0:0:0: +321,307,228460,6,0,L|333:237,1,55.68,2|0,0:0|0:0,0:0:0:0: +271,203,228784,1,2,0:0:0:0: +437,70,228946,6,0,L|446:134,1,55.68,2|0,0:0|0:0,0:0:0:0: +394,174,229270,1,2,0:0:0:0: +291,42,229432,6,0,L|231:22,1,55.68,2|0,0:0|0:0,0:0:0:0: +288,119,229757,1,2,0:0:0:0: +150,209,229919,6,0,L|220:192,2,55.68,2|0|0,0:0|0:0|0:0,0:0:0:0: +88,167,230405,2,0,L|100:107,1,55.68,2|0,0:0|0:0,0:0:0:0: +274,285,230730,6,0,L|280:329,2,37.12,2|2|2,0:0|0:0|0:0,0:0:0:0: +314,217,231054,6,0,P|362:210|409:260,1,111.36,2|0,0:0|0:0,0:0:0:0: +512,130,231541,1,2,0:0:0:0: +452,88,231703,1,2,0:0:0:0: +406,143,231865,1,2,0:0:0:0: +280,54,232027,6,0,L|292:-12,1,55.68,2|0,0:0|0:0,0:0:0:0: +348,89,232351,1,2,0:0:0:0: +186,175,232514,6,0,L|177:103,1,55.68,2|0,0:0|0:0,0:0:0:0: +120,222,232838,1,2,0:0:0:0: +224,364,233000,5,2,0:0:0:0: +157,342,233162,1,2,0:0:0:0: +293,248,233324,5,2,0:0:0:0: +384,221,233487,1,2,0:0:0:0: diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824-expected-conversion.json b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824-expected-conversion.json new file mode 100644 index 000000000000..4c196a182c18 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824-expected-conversion.json @@ -0,0 +1 @@ +{"Mappings":[{"StartTime":3135.0,"Objects":[{"StartTime":3135.0,"EndTime":3135.0,"X":31.0,"Y":114.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":3321.0,"EndTime":3321.0,"X":121.109383,"Y":118.3692,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":3468.0,"Objects":[{"StartTime":3468.0,"EndTime":3468.0,"X":183.0,"Y":39.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":3654.0,"EndTime":3654.0,"X":273.109375,"Y":34.6308022,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":3801.0,"Objects":[{"StartTime":3801.0,"EndTime":3801.0,"X":358.0,"Y":104.0}]},{"StartTime":4023.0,"Objects":[{"StartTime":4023.0,"EndTime":4023.0,"X":274.0,"Y":180.0}]},{"StartTime":4246.0,"Objects":[{"StartTime":4246.0,"EndTime":4246.0,"X":367.0,"Y":238.0}]},{"StartTime":4468.0,"Objects":[{"StartTime":4468.0,"EndTime":4468.0,"X":273.0,"Y":34.0}]},{"StartTime":4690.0,"Objects":[{"StartTime":4690.0,"EndTime":4690.0,"X":209.0,"Y":249.0}]},{"StartTime":4912.0,"Objects":[{"StartTime":4912.0,"EndTime":4912.0,"X":413.0,"Y":99.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":5245.0,"EndTime":5245.0,"X":281.78244,"Y":149.250275,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":5542.0,"EndTime":5542.0,"X":413.0,"Y":99.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":5801.0,"Objects":[{"StartTime":5801.0,"EndTime":5801.0,"X":504.0,"Y":157.0}]},{"StartTime":6023.0,"Objects":[{"StartTime":6023.0,"EndTime":6023.0,"X":429.0,"Y":235.0}]},{"StartTime":6246.0,"Objects":[{"StartTime":6246.0,"EndTime":6246.0,"X":498.0,"Y":324.0}]},{"StartTime":6468.0,"Objects":[{"StartTime":6468.0,"EndTime":6468.0,"X":331.0,"Y":232.0}]},{"StartTime":6579.0,"Objects":[{"StartTime":6579.0,"EndTime":6579.0,"X":321.0,"Y":232.0}]},{"StartTime":6690.0,"Objects":[{"StartTime":6690.0,"EndTime":6690.0,"X":311.0,"Y":233.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":6876.0,"EndTime":6876.0,"X":304.188019,"Y":322.47525,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7023.0,"Objects":[{"StartTime":7023.0,"EndTime":7023.0,"X":160.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":7209.0,"EndTime":7209.0,"X":166.811981,"Y":294.52475,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7357.0,"Objects":[{"StartTime":7357.0,"EndTime":7357.0,"X":78.0,"Y":237.0}]},{"StartTime":7579.0,"Objects":[{"StartTime":7579.0,"EndTime":7579.0,"X":14.0,"Y":325.0}]},{"StartTime":7801.0,"Objects":[{"StartTime":7801.0,"EndTime":7801.0,"X":190.0,"Y":197.0}]},{"StartTime":8023.0,"Objects":[{"StartTime":8023.0,"EndTime":8023.0,"X":0.0,"Y":74.0}]},{"StartTime":8134.0,"Objects":[{"StartTime":8134.0,"EndTime":8134.0,"X":25.0,"Y":114.0}]},{"StartTime":8245.0,"Objects":[{"StartTime":8245.0,"EndTime":8245.0,"X":70.0,"Y":131.0}]},{"StartTime":8356.0,"Objects":[{"StartTime":8356.0,"EndTime":8356.0,"X":116.0,"Y":117.0}]},{"StartTime":8468.0,"Objects":[{"StartTime":8468.0,"EndTime":8468.0,"X":143.0,"Y":78.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":8801.0,"EndTime":8801.0,"X":256.694672,"Y":40.1920738,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":9098.0,"EndTime":9098.0,"X":143.0,"Y":78.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":9357.0,"Objects":[{"StartTime":9357.0,"EndTime":9357.0,"X":69.0,"Y":241.0}]},{"StartTime":9579.0,"Objects":[{"StartTime":9579.0,"EndTime":9579.0,"X":48.0,"Y":132.0}]},{"StartTime":9801.0,"Objects":[{"StartTime":9801.0,"EndTime":9801.0,"X":191.0,"Y":187.0}]},{"StartTime":10023.0,"Objects":[{"StartTime":10023.0,"EndTime":10023.0,"X":173.0,"Y":308.0}]},{"StartTime":10246.0,"Objects":[{"StartTime":10246.0,"EndTime":10246.0,"X":0.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":10432.0,"EndTime":10432.0,"X":90.3386841,"Y":374.001251,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":10579.0,"Objects":[{"StartTime":10579.0,"EndTime":10579.0,"X":179.0,"Y":287.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":10765.0,"EndTime":10765.0,"X":269.338684,"Y":296.998749,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":10912.0,"Objects":[{"StartTime":10912.0,"EndTime":10912.0,"X":363.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":10987.0,"EndTime":10987.0,"X":355.587219,"Y":224.183121,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":11134.0,"Objects":[{"StartTime":11134.0,"EndTime":11134.0,"X":415.0,"Y":327.0}]},{"StartTime":11579.0,"Objects":[{"StartTime":11579.0,"EndTime":11579.0,"X":267.0,"Y":121.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":11654.0,"EndTime":11654.0,"X":259.587219,"Y":169.183121,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":11801.0,"Objects":[{"StartTime":11801.0,"EndTime":11801.0,"X":503.983917,"Y":122.983917}]},{"StartTime":11912.0,"Objects":[{"StartTime":11912.0,"EndTime":11912.0,"X":507.991943,"Y":126.991959}]},{"StartTime":12023.0,"Objects":[{"StartTime":12023.0,"EndTime":12023.0,"X":512.0,"Y":131.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":12356.0,"EndTime":12356.0,"X":369.271851,"Y":134.8306,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":12653.0,"EndTime":12653.0,"X":512.0,"Y":131.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":12912.0,"Objects":[{"StartTime":12912.0,"EndTime":12912.0,"X":275.0,"Y":68.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":13098.0,"EndTime":13098.0,"X":345.202454,"Y":16.3424149,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":13357.0,"Objects":[{"StartTime":13357.0,"EndTime":13357.0,"X":276.0,"Y":180.0}]},{"StartTime":13579.0,"Objects":[{"StartTime":13579.0,"EndTime":13579.0,"X":121.0,"Y":111.0}]},{"StartTime":13690.0,"Objects":[{"StartTime":13690.0,"EndTime":13690.0,"X":72.0,"Y":116.0}]},{"StartTime":13801.0,"Objects":[{"StartTime":13801.0,"EndTime":13801.0,"X":24.0,"Y":122.0}]},{"StartTime":14023.0,"Objects":[{"StartTime":14023.0,"EndTime":14023.0,"X":188.0,"Y":13.0}]},{"StartTime":14246.0,"Objects":[{"StartTime":14246.0,"EndTime":14246.0,"X":86.0,"Y":226.0}]},{"StartTime":14468.0,"Objects":[{"StartTime":14468.0,"EndTime":14468.0,"X":235.0,"Y":139.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":14876.0,"EndTime":14876.0,"X":243.728867,"Y":327.927429,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":15134.0,"Objects":[{"StartTime":15134.0,"EndTime":15134.0,"X":23.0,"Y":350.0}]},{"StartTime":15245.0,"Objects":[{"StartTime":15245.0,"EndTime":15245.0,"X":21.0,"Y":302.0}]},{"StartTime":15356.0,"Objects":[{"StartTime":15356.0,"EndTime":15356.0,"X":52.0,"Y":265.0}]},{"StartTime":15467.0,"Objects":[{"StartTime":15467.0,"EndTime":15467.0,"X":99.0,"Y":257.0}]},{"StartTime":15579.0,"Objects":[{"StartTime":15579.0,"EndTime":15579.0,"X":140.0,"Y":281.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":15765.0,"EndTime":15765.0,"X":236.782974,"Y":269.1972,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":15912.0,"Objects":[{"StartTime":15912.0,"EndTime":15912.0,"X":184.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":16098.0,"EndTime":16098.0,"X":280.782959,"Y":150.1972,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":16246.0,"Objects":[{"StartTime":16246.0,"EndTime":16246.0,"X":412.0,"Y":135.0}]},{"StartTime":16468.0,"Objects":[{"StartTime":16468.0,"EndTime":16468.0,"X":394.0,"Y":22.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":16765.0,"EndTime":16765.0,"X":382.8766,"Y":156.34137,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":16912.0,"Objects":[{"StartTime":16912.0,"EndTime":16912.0,"X":487.0,"Y":220.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":16987.0,"EndTime":16987.0,"X":477.05722,"Y":267.725281,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":17134.0,"Objects":[{"StartTime":17134.0,"EndTime":17134.0,"X":380.0,"Y":382.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":17209.0,"EndTime":17209.0,"X":370.05722,"Y":334.274719,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":17357.0,"Objects":[{"StartTime":17357.0,"EndTime":17357.0,"X":264.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":17543.0,"EndTime":17543.0,"X":137.27359,"Y":327.860168,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":17690.0,"Objects":[{"StartTime":17690.0,"EndTime":17690.0,"X":26.0,"Y":244.0}]},{"StartTime":17801.0,"Objects":[{"StartTime":17801.0,"EndTime":17801.0,"X":56.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":17987.0,"EndTime":17987.0,"X":130.303314,"Y":232.876617,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18134.0,"Objects":[{"StartTime":18134.0,"EndTime":18134.0,"X":43.99196,"Y":356.991943}]},{"StartTime":18246.0,"Objects":[{"StartTime":18246.0,"EndTime":18246.0,"X":48.0,"Y":361.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18321.0,"EndTime":18321.0,"X":29.613245,"Y":288.288757,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18468.0,"Objects":[{"StartTime":18468.0,"EndTime":18468.0,"X":130.0,"Y":232.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18543.0,"EndTime":18543.0,"X":146.027267,"Y":158.7325,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18690.0,"Objects":[{"StartTime":18690.0,"EndTime":18690.0,"X":231.0,"Y":7.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18876.0,"EndTime":18876.0,"X":308.9407,"Y":100.850838,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19023.0,"Objects":[{"StartTime":19023.0,"EndTime":19023.0,"X":257.991943,"Y":218.991959}]},{"StartTime":19134.0,"Objects":[{"StartTime":19134.0,"EndTime":19134.0,"X":262.0,"Y":223.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19320.0,"EndTime":19320.0,"X":406.117065,"Y":241.147919,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19468.0,"Objects":[{"StartTime":19468.0,"EndTime":19468.0,"X":487.991943,"Y":161.991959}]},{"StartTime":19579.0,"Objects":[{"StartTime":19579.0,"EndTime":19579.0,"X":492.0,"Y":166.0}]},{"StartTime":19801.0,"Objects":[{"StartTime":19801.0,"EndTime":19801.0,"X":411.0,"Y":310.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19876.0,"EndTime":19876.0,"X":405.865967,"Y":240.440765,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20023.0,"Objects":[{"StartTime":20023.0,"EndTime":20023.0,"X":372.0,"Y":6.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20209.0,"EndTime":20209.0,"X":395.446167,"Y":136.246689,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20357.0,"Objects":[{"StartTime":20357.0,"EndTime":20357.0,"X":257.991943,"Y":142.991959}]},{"StartTime":20468.0,"Objects":[{"StartTime":20468.0,"EndTime":20468.0,"X":262.0,"Y":147.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20543.0,"EndTime":20543.0,"X":305.505249,"Y":85.90751,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20690.0,"Objects":[{"StartTime":20690.0,"EndTime":20690.0,"X":160.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20765.0,"EndTime":20765.0,"X":193.541016,"Y":67.08204,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20912.0,"Objects":[{"StartTime":20912.0,"EndTime":20912.0,"X":306.0,"Y":220.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21098.0,"EndTime":21098.0,"X":183.694366,"Y":194.6086,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21246.0,"Objects":[{"StartTime":21246.0,"EndTime":21246.0,"X":27.9919586,"Y":175.991959}]},{"StartTime":21357.0,"Objects":[{"StartTime":21357.0,"EndTime":21357.0,"X":32.0,"Y":180.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21543.0,"EndTime":21543.0,"X":85.78159,"Y":113.576027,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21690.0,"Objects":[{"StartTime":21690.0,"EndTime":21690.0,"X":113.0,"Y":363.0}]},{"StartTime":21801.0,"Objects":[{"StartTime":21801.0,"EndTime":21801.0,"X":43.0,"Y":305.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21876.0,"EndTime":21876.0,"X":103.223976,"Y":267.573425,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22023.0,"Objects":[{"StartTime":22023.0,"EndTime":22023.0,"X":209.0,"Y":310.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22098.0,"EndTime":22098.0,"X":198.14006,"Y":384.2096,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22246.0,"Objects":[{"StartTime":22246.0,"EndTime":22246.0,"X":102.0,"Y":166.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22321.0,"EndTime":22321.0,"X":170.558487,"Y":184.751465,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22468.0,"Objects":[{"StartTime":22468.0,"EndTime":22468.0,"X":249.0,"Y":121.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22543.0,"EndTime":22543.0,"X":280.5543,"Y":184.69635,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22690.0,"Objects":[{"StartTime":22690.0,"EndTime":22690.0,"X":209.0,"Y":310.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22876.0,"EndTime":22876.0,"X":350.500458,"Y":343.22287,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23023.0,"Objects":[{"StartTime":23023.0,"EndTime":23023.0,"X":437.991943,"Y":255.991959}]},{"StartTime":23134.0,"Objects":[{"StartTime":23134.0,"EndTime":23134.0,"X":442.0,"Y":260.0}]},{"StartTime":23357.0,"Objects":[{"StartTime":23357.0,"EndTime":23357.0,"X":250.0,"Y":201.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23432.0,"EndTime":23432.0,"X":325.0,"Y":201.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23579.0,"Objects":[{"StartTime":23579.0,"EndTime":23579.0,"X":442.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23654.0,"EndTime":23654.0,"X":446.8069,"Y":191.50061,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23801.0,"Objects":[{"StartTime":23801.0,"EndTime":23801.0,"X":343.0,"Y":301.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23876.0,"EndTime":23876.0,"X":335.715149,"Y":371.783661,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":24023.0,"Objects":[{"StartTime":24023.0,"EndTime":24023.0,"X":442.0,"Y":260.0}]},{"StartTime":24134.0,"Objects":[{"StartTime":24134.0,"EndTime":24134.0,"X":397.0,"Y":202.0}]},{"StartTime":24245.0,"Objects":[{"StartTime":24245.0,"EndTime":24245.0,"X":325.0,"Y":202.0}]},{"StartTime":24357.0,"Objects":[{"StartTime":24357.0,"EndTime":24357.0,"X":246.0,"Y":274.0}]},{"StartTime":24468.0,"Objects":[{"StartTime":24468.0,"EndTime":24468.0,"X":153.0,"Y":226.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":24654.0,"EndTime":24654.0,"X":147.008972,"Y":368.243042,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":24801.0,"Objects":[{"StartTime":24801.0,"EndTime":24801.0,"X":18.9919586,"Y":65.99196}]},{"StartTime":24912.0,"Objects":[{"StartTime":24912.0,"EndTime":24912.0,"X":23.0,"Y":70.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25098.0,"EndTime":25098.0,"X":28.99103,"Y":212.243042,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25246.0,"Objects":[{"StartTime":25246.0,"EndTime":25246.0,"X":211.991959,"Y":139.991959}]},{"StartTime":25357.0,"Objects":[{"StartTime":25357.0,"EndTime":25357.0,"X":216.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25432.0,"EndTime":25432.0,"X":141.9953,"Y":131.822,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25579.0,"Objects":[{"StartTime":25579.0,"EndTime":25579.0,"X":105.0,"Y":32.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25654.0,"EndTime":25654.0,"X":179.0047,"Y":44.17799,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25801.0,"Objects":[{"StartTime":25801.0,"EndTime":25801.0,"X":328.0,"Y":246.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25876.0,"EndTime":25876.0,"X":253.9953,"Y":233.822,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26023.0,"Objects":[{"StartTime":26023.0,"EndTime":26023.0,"X":270.0,"Y":66.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26098.0,"EndTime":26098.0,"X":303.2081,"Y":129.55838,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26246.0,"Objects":[{"StartTime":26246.0,"EndTime":26246.0,"X":162.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26432.0,"EndTime":26432.0,"X":207.819519,"Y":145.865692,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26579.0,"Objects":[{"StartTime":26579.0,"EndTime":26579.0,"X":206.991959,"Y":368.991943}]},{"StartTime":26690.0,"Objects":[{"StartTime":26690.0,"EndTime":26690.0,"X":211.0,"Y":373.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26876.0,"EndTime":26876.0,"X":91.82551,"Y":333.5027,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27023.0,"Objects":[{"StartTime":27023.0,"EndTime":27023.0,"X":295.991943,"Y":195.991959}]},{"StartTime":27134.0,"Objects":[{"StartTime":27134.0,"EndTime":27134.0,"X":300.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27209.0,"EndTime":27209.0,"X":267.82074,"Y":267.745819,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27357.0,"Objects":[{"StartTime":27357.0,"EndTime":27357.0,"X":402.0,"Y":363.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27432.0,"EndTime":27432.0,"X":373.273865,"Y":293.71936,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27579.0,"Objects":[{"StartTime":27579.0,"EndTime":27579.0,"X":178.0,"Y":44.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27765.0,"EndTime":27765.0,"X":183.8688,"Y":176.813446,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27912.0,"Objects":[{"StartTime":27912.0,"EndTime":27912.0,"X":324.991943,"Y":84.99196}]},{"StartTime":28023.0,"Objects":[{"StartTime":28023.0,"EndTime":28023.0,"X":329.0,"Y":89.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":28098.0,"EndTime":28098.0,"X":255.973389,"Y":106.091339,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":28246.0,"Objects":[{"StartTime":28246.0,"EndTime":28246.0,"X":103.0,"Y":268.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":28432.0,"EndTime":28432.0,"X":183.533081,"Y":176.552429,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":28690.0,"Objects":[{"StartTime":28690.0,"EndTime":28690.0,"X":360.0,"Y":217.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":28765.0,"EndTime":28765.0,"X":286.9734,"Y":234.091339,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":28912.0,"Objects":[{"StartTime":28912.0,"EndTime":28912.0,"X":178.0,"Y":44.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29098.0,"EndTime":29098.0,"X":183.8688,"Y":176.813446,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":29357.0,"Objects":[{"StartTime":29357.0,"EndTime":29357.0,"X":247.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29432.0,"EndTime":29432.0,"X":229.52034,"Y":316.708374,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":29579.0,"Objects":[{"StartTime":29579.0,"EndTime":29579.0,"X":26.0,"Y":254.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29654.0,"EndTime":29654.0,"X":93.5281143,"Y":271.24292,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":29801.0,"Objects":[{"StartTime":29801.0,"EndTime":29801.0,"X":233.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29876.0,"EndTime":29876.0,"X":182.988586,"Y":176.208755,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30023.0,"Objects":[{"StartTime":30023.0,"EndTime":30023.0,"X":173.0,"Y":257.0}]},{"StartTime":30246.0,"Objects":[{"StartTime":30246.0,"EndTime":30246.0,"X":173.0,"Y":257.0}]},{"StartTime":30690.0,"Objects":[{"StartTime":30690.0,"EndTime":30690.0,"X":173.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30765.0,"EndTime":30765.0,"X":230.78125,"Y":218.994263,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30912.0,"Objects":[{"StartTime":30912.0,"EndTime":30912.0,"X":173.0,"Y":42.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30987.0,"EndTime":30987.0,"X":176.039978,"Y":111.164528,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31134.0,"Objects":[{"StartTime":31134.0,"EndTime":31134.0,"X":353.0,"Y":122.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31209.0,"EndTime":31209.0,"X":290.774017,"Y":91.4817657,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31357.0,"Objects":[{"StartTime":31357.0,"EndTime":31357.0,"X":173.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31432.0,"EndTime":31432.0,"X":230.78125,"Y":218.994263,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31579.0,"Objects":[{"StartTime":31579.0,"EndTime":31579.0,"X":331.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31765.0,"EndTime":31765.0,"X":339.830933,"Y":355.1529,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31912.0,"Objects":[{"StartTime":31912.0,"EndTime":31912.0,"X":433.0,"Y":278.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32098.0,"EndTime":32098.0,"X":424.9847,"Y":165.785889,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32246.0,"Objects":[{"StartTime":32246.0,"EndTime":32246.0,"X":510.0,"Y":105.0}]},{"StartTime":32468.0,"Objects":[{"StartTime":32468.0,"EndTime":32468.0,"X":510.0,"Y":105.0}]},{"StartTime":32690.0,"Objects":[{"StartTime":32690.0,"EndTime":32690.0,"X":235.0,"Y":27.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32765.0,"EndTime":32765.0,"X":226.30426,"Y":90.74597,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32912.0,"Objects":[{"StartTime":32912.0,"EndTime":32912.0,"X":350.0,"Y":138.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32987.0,"EndTime":32987.0,"X":319.980743,"Y":86.37892,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33134.0,"Objects":[{"StartTime":33134.0,"EndTime":33134.0,"X":183.0,"Y":198.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33209.0,"EndTime":33209.0,"X":257.0822,"Y":186.302811,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33357.0,"Objects":[{"StartTime":33357.0,"EndTime":33357.0,"X":384.0,"Y":39.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33543.0,"EndTime":33543.0,"X":349.632935,"Y":137.788986,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33690.0,"Objects":[{"StartTime":33690.0,"EndTime":33690.0,"X":501.0,"Y":181.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33876.0,"EndTime":33876.0,"X":454.8317,"Y":124.837044,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34023.0,"Objects":[{"StartTime":34023.0,"EndTime":34023.0,"X":388.0,"Y":225.0}]},{"StartTime":34246.0,"Objects":[{"StartTime":34246.0,"EndTime":34246.0,"X":388.0,"Y":225.0}]},{"StartTime":34468.0,"Objects":[{"StartTime":34468.0,"EndTime":34468.0,"X":512.0,"Y":329.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34543.0,"EndTime":34543.0,"X":471.919983,"Y":272.1336,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34690.0,"Objects":[{"StartTime":34690.0,"EndTime":34690.0,"X":382.0,"Y":326.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34876.0,"EndTime":34876.0,"X":240.883636,"Y":335.966736,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35023.0,"Objects":[{"StartTime":35023.0,"EndTime":35023.0,"X":135.991959,"Y":292.991943}]},{"StartTime":35134.0,"Objects":[{"StartTime":35134.0,"EndTime":35134.0,"X":140.0,"Y":297.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35209.0,"EndTime":35209.0,"X":187.189865,"Y":238.706635,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35357.0,"Objects":[{"StartTime":35357.0,"EndTime":35357.0,"X":322.0,"Y":42.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35543.0,"EndTime":35543.0,"X":274.3119,"Y":151.136856,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35801.0,"Objects":[{"StartTime":35801.0,"EndTime":35801.0,"X":121.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35876.0,"EndTime":35876.0,"X":168.189865,"Y":135.293365,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36024.0,"Objects":[{"StartTime":36024.0,"EndTime":36024.0,"X":299.0,"Y":267.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36210.0,"EndTime":36210.0,"X":274.15448,"Y":150.210541,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36468.0,"Objects":[{"StartTime":36468.0,"EndTime":36468.0,"X":197.0,"Y":292.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36543.0,"EndTime":36543.0,"X":220.717087,"Y":363.151245,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36690.0,"Objects":[{"StartTime":36690.0,"EndTime":36690.0,"X":105.0,"Y":216.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36765.0,"EndTime":36765.0,"X":90.92856,"Y":289.668152,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36912.0,"Objects":[{"StartTime":36912.0,"EndTime":36912.0,"X":325.0,"Y":312.0}]},{"StartTime":37134.0,"Objects":[{"StartTime":37134.0,"EndTime":37134.0,"X":207.0,"Y":192.0}]},{"StartTime":37357.0,"Objects":[{"StartTime":37357.0,"EndTime":37357.0,"X":478.0,"Y":185.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37543.0,"EndTime":37543.0,"X":338.679565,"Y":200.801971,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":37801.0,"Objects":[{"StartTime":37801.0,"EndTime":37801.0,"X":409.0,"Y":38.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37876.0,"EndTime":37876.0,"X":397.115051,"Y":112.052338,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38023.0,"Objects":[{"StartTime":38023.0,"EndTime":38023.0,"X":218.0,"Y":266.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38098.0,"EndTime":38098.0,"X":206.115051,"Y":191.947662,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38246.0,"Objects":[{"StartTime":38246.0,"EndTime":38246.0,"X":299.0,"Y":30.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38432.0,"EndTime":38432.0,"X":188.825577,"Y":79.8648148,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38579.0,"Objects":[{"StartTime":38579.0,"EndTime":38579.0,"X":74.99196,"Y":28.9919586}]},{"StartTime":38690.0,"Objects":[{"StartTime":38690.0,"EndTime":38690.0,"X":79.0,"Y":33.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38876.0,"EndTime":38876.0,"X":72.29509,"Y":141.819641,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":39023.0,"Objects":[{"StartTime":39023.0,"EndTime":39023.0,"X":182.0,"Y":295.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":39209.0,"EndTime":39209.0,"X":175.535126,"Y":186.1405,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":39357.0,"Objects":[{"StartTime":39357.0,"EndTime":39357.0,"X":69.0,"Y":244.0}]},{"StartTime":39579.0,"Objects":[{"StartTime":39579.0,"EndTime":39579.0,"X":69.0,"Y":244.0}]},{"StartTime":39801.0,"Objects":[{"StartTime":39801.0,"EndTime":39801.0,"X":257.0,"Y":133.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":39876.0,"EndTime":39876.0,"X":204.156845,"Y":89.1012344,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":40023.0,"Objects":[{"StartTime":40023.0,"EndTime":40023.0,"X":179.0,"Y":216.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":40209.0,"EndTime":40209.0,"X":318.21756,"Y":227.418915,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":40468.0,"Objects":[{"StartTime":40468.0,"EndTime":40468.0,"X":492.0,"Y":74.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":40912.0,"EndTime":40912.0,"X":383.634857,"Y":63.100235,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41209.0,"EndTime":41209.0,"X":407.914,"Y":149.609482,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41357.0,"Objects":[{"StartTime":41357.0,"EndTime":41357.0,"X":492.0,"Y":74.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41801.0,"EndTime":41801.0,"X":380.8066,"Y":100.582275,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42098.0,"EndTime":42098.0,"X":294.218781,"Y":115.022942,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42246.0,"Objects":[{"StartTime":42246.0,"EndTime":42246.0,"X":202.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42432.0,"EndTime":42432.0,"X":194.000076,"Y":168.117783,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42690.0,"Objects":[{"StartTime":42690.0,"EndTime":42690.0,"X":294.0,"Y":115.0}]},{"StartTime":42912.0,"Objects":[{"StartTime":42912.0,"EndTime":42912.0,"X":98.0,"Y":226.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43098.0,"EndTime":43098.0,"X":193.181259,"Y":167.556946,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":43357.0,"Objects":[{"StartTime":43357.0,"EndTime":43357.0,"X":212.0,"Y":338.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43432.0,"EndTime":43432.0,"X":191.175934,"Y":273.79245,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":43579.0,"Objects":[{"StartTime":43579.0,"EndTime":43579.0,"X":289.0,"Y":235.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43654.0,"EndTime":43654.0,"X":310.0445,"Y":170.864365,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":43801.0,"Objects":[{"StartTime":43801.0,"EndTime":43801.0,"X":417.0,"Y":146.0}]},{"StartTime":44023.0,"Objects":[{"StartTime":44023.0,"EndTime":44023.0,"X":417.0,"Y":146.0}]},{"StartTime":44246.0,"Objects":[{"StartTime":44246.0,"EndTime":44246.0,"X":212.0,"Y":338.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44321.0,"EndTime":44321.0,"X":184.7824,"Y":277.928528,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44468.0,"Objects":[{"StartTime":44468.0,"EndTime":44468.0,"X":289.0,"Y":235.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44543.0,"EndTime":44543.0,"X":290.496,"Y":172.141,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44690.0,"Objects":[{"StartTime":44690.0,"EndTime":44690.0,"X":417.0,"Y":146.0}]},{"StartTime":44912.0,"Objects":[{"StartTime":44912.0,"EndTime":44912.0,"X":417.0,"Y":146.0}]},{"StartTime":45134.0,"Objects":[{"StartTime":45134.0,"EndTime":45134.0,"X":192.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":45209.0,"EndTime":45209.0,"X":211.809387,"Y":102.229622,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":45357.0,"Objects":[{"StartTime":45357.0,"EndTime":45357.0,"X":427.0,"Y":40.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":45543.0,"EndTime":45543.0,"X":303.3012,"Y":45.94596,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":45690.0,"Objects":[{"StartTime":45690.0,"EndTime":45690.0,"X":215.991959,"Y":4.99195766}]},{"StartTime":45801.0,"Objects":[{"StartTime":45801.0,"EndTime":45801.0,"X":220.0,"Y":9.0}]},{"StartTime":46023.0,"Objects":[{"StartTime":46023.0,"EndTime":46023.0,"X":301.0,"Y":160.0}]},{"StartTime":46246.0,"Objects":[{"StartTime":46246.0,"EndTime":46246.0,"X":129.0,"Y":125.0}]},{"StartTime":46468.0,"Objects":[{"StartTime":46468.0,"EndTime":46468.0,"X":310.983917,"Y":37.9839172}]},{"StartTime":46579.0,"Objects":[{"StartTime":46579.0,"EndTime":46579.0,"X":314.991943,"Y":41.99196}]},{"StartTime":46690.0,"Objects":[{"StartTime":46690.0,"EndTime":46690.0,"X":319.0,"Y":46.0}]},{"StartTime":46912.0,"Objects":[{"StartTime":46912.0,"EndTime":46912.0,"X":184.0,"Y":235.0}]},{"StartTime":47134.0,"Objects":[{"StartTime":47134.0,"EndTime":47134.0,"X":424.0,"Y":203.0}]},{"StartTime":47357.0,"Objects":[{"StartTime":47357.0,"EndTime":47357.0,"X":222.0,"Y":101.0}]},{"StartTime":47579.0,"Objects":[{"StartTime":47579.0,"EndTime":47579.0,"X":317.0,"Y":195.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":47765.0,"EndTime":47765.0,"X":311.3081,"Y":318.992,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":47912.0,"Objects":[{"StartTime":47912.0,"EndTime":47912.0,"X":405.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48098.0,"EndTime":48098.0,"X":398.957825,"Y":254.92,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":48246.0,"Objects":[{"StartTime":48246.0,"EndTime":48246.0,"X":311.0,"Y":318.0}]},{"StartTime":48468.0,"Objects":[{"StartTime":48468.0,"EndTime":48468.0,"X":477.0,"Y":199.0}]},{"StartTime":48690.0,"Objects":[{"StartTime":48690.0,"EndTime":48690.0,"X":195.0,"Y":231.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48765.0,"EndTime":48765.0,"X":262.158875,"Y":224.2225,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":48912.0,"Objects":[{"StartTime":48912.0,"EndTime":48912.0,"X":246.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48987.0,"EndTime":48987.0,"X":313.158875,"Y":121.222496,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49134.0,"Objects":[{"StartTime":49134.0,"EndTime":49134.0,"X":468.0,"Y":54.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49320.0,"EndTime":49320.0,"X":368.604065,"Y":25.4110832,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49579.0,"Objects":[{"StartTime":49579.0,"EndTime":49579.0,"X":195.0,"Y":231.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49654.0,"EndTime":49654.0,"X":262.158875,"Y":224.2225,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49801.0,"Objects":[{"StartTime":49801.0,"EndTime":49801.0,"X":246.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49876.0,"EndTime":49876.0,"X":313.158875,"Y":121.222496,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50023.0,"Objects":[{"StartTime":50023.0,"EndTime":50023.0,"X":468.0,"Y":54.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50209.0,"EndTime":50209.0,"X":422.311432,"Y":155.298447,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50468.0,"Objects":[{"StartTime":50468.0,"EndTime":50468.0,"X":195.0,"Y":231.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50543.0,"EndTime":50543.0,"X":262.158875,"Y":224.2225,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50690.0,"Objects":[{"StartTime":50690.0,"EndTime":50690.0,"X":246.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50765.0,"EndTime":50765.0,"X":313.158875,"Y":121.222496,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50912.0,"Objects":[{"StartTime":50912.0,"EndTime":50912.0,"X":483.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51098.0,"EndTime":51098.0,"X":421.906952,"Y":154.214828,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":51357.0,"Objects":[{"StartTime":51357.0,"EndTime":51357.0,"X":375.0,"Y":361.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51432.0,"EndTime":51432.0,"X":379.676239,"Y":293.66217,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":51579.0,"Objects":[{"StartTime":51579.0,"EndTime":51579.0,"X":314.0,"Y":122.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51654.0,"EndTime":51654.0,"X":309.323761,"Y":189.33783,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":51801.0,"Objects":[{"StartTime":51801.0,"EndTime":51801.0,"X":379.0,"Y":293.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51987.0,"EndTime":51987.0,"X":248.055283,"Y":303.25946,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":52246.0,"Objects":[{"StartTime":52246.0,"EndTime":52246.0,"X":22.0,"Y":215.0}]},{"StartTime":52357.0,"Objects":[{"StartTime":52357.0,"EndTime":52357.0,"X":55.0,"Y":212.0}]},{"StartTime":52468.0,"Objects":[{"StartTime":52468.0,"EndTime":52468.0,"X":89.0,"Y":209.0}]},{"StartTime":52690.0,"Objects":[{"StartTime":52690.0,"EndTime":52690.0,"X":229.0,"Y":127.0}]},{"StartTime":52912.0,"Objects":[{"StartTime":52912.0,"EndTime":52912.0,"X":152.0,"Y":6.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":53098.0,"EndTime":53098.0,"X":130.962738,"Y":121.142517,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":53357.0,"Objects":[{"StartTime":53357.0,"EndTime":53357.0,"X":240.0,"Y":226.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":53432.0,"EndTime":53432.0,"X":253.058411,"Y":159.775177,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":53579.0,"Objects":[{"StartTime":53579.0,"EndTime":53579.0,"X":31.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":53765.0,"EndTime":53765.0,"X":103.393211,"Y":213.200455,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54023.0,"Objects":[{"StartTime":54023.0,"EndTime":54023.0,"X":260.0,"Y":41.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54098.0,"EndTime":54098.0,"X":206.719482,"Y":69.47305,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54246.0,"Objects":[{"StartTime":54246.0,"EndTime":54246.0,"X":306.0,"Y":188.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54321.0,"EndTime":54321.0,"X":252.739288,"Y":158.844131,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54468.0,"Objects":[{"StartTime":54468.0,"EndTime":54468.0,"X":71.98392,"Y":285.983917}]},{"StartTime":54579.0,"Objects":[{"StartTime":54579.0,"EndTime":54579.0,"X":75.99196,"Y":289.991943}]},{"StartTime":54690.0,"Objects":[{"StartTime":54690.0,"EndTime":54690.0,"X":80.0,"Y":294.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54876.0,"EndTime":54876.0,"X":192.993744,"Y":272.5478,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":55023.0,"Objects":[{"StartTime":55023.0,"EndTime":55023.0,"X":306.0,"Y":294.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":55209.0,"EndTime":55209.0,"X":192.104675,"Y":272.193573,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":55357.0,"Objects":[{"StartTime":55357.0,"EndTime":55357.0,"X":202.0,"Y":155.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":55432.0,"EndTime":55432.0,"X":257.5735,"Y":189.935318,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":55579.0,"Objects":[{"StartTime":55579.0,"EndTime":55579.0,"X":148.0,"Y":372.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":55765.0,"EndTime":55765.0,"X":192.697815,"Y":272.199921,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":55912.0,"Objects":[{"StartTime":55912.0,"EndTime":55912.0,"X":281.991943,"Y":124.991959}]},{"StartTime":56023.0,"Objects":[{"StartTime":56023.0,"EndTime":56023.0,"X":286.0,"Y":129.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56098.0,"EndTime":56098.0,"X":256.8464,"Y":189.879547,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56246.0,"Objects":[{"StartTime":56246.0,"EndTime":56246.0,"X":383.0,"Y":267.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56321.0,"EndTime":56321.0,"X":353.210938,"Y":206.428879,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56468.0,"Objects":[{"StartTime":56468.0,"EndTime":56468.0,"X":164.0,"Y":44.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56654.0,"EndTime":56654.0,"X":147.254028,"Y":186.346436,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56801.0,"Objects":[{"StartTime":56801.0,"EndTime":56801.0,"X":367.0,"Y":78.0}]},{"StartTime":56912.0,"Objects":[{"StartTime":56912.0,"EndTime":56912.0,"X":283.0,"Y":29.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56987.0,"EndTime":56987.0,"X":273.013336,"Y":109.284035,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57134.0,"Objects":[{"StartTime":57134.0,"EndTime":57134.0,"X":237.0,"Y":264.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57320.0,"EndTime":57320.0,"X":90.27847,"Y":356.257324,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57579.0,"Objects":[{"StartTime":57579.0,"EndTime":57579.0,"X":342.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57654.0,"EndTime":57654.0,"X":345.1496,"Y":303.2366,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57801.0,"Objects":[{"StartTime":57801.0,"EndTime":57801.0,"X":509.0,"Y":173.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57987.0,"EndTime":57987.0,"X":347.468536,"Y":192.426285,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58134.0,"Objects":[{"StartTime":58134.0,"EndTime":58134.0,"X":243.991959,"Y":146.991959}]},{"StartTime":58246.0,"Objects":[{"StartTime":58246.0,"EndTime":58246.0,"X":248.0,"Y":151.0}]},{"StartTime":58468.0,"Objects":[{"StartTime":58468.0,"EndTime":58468.0,"X":386.0,"Y":20.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58543.0,"EndTime":58543.0,"X":338.760651,"Y":91.60191,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58690.0,"Objects":[{"StartTime":58690.0,"EndTime":58690.0,"X":157.0,"Y":70.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58765.0,"EndTime":58765.0,"X":241.659058,"Y":52.80721,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58912.0,"Objects":[{"StartTime":58912.0,"EndTime":58912.0,"X":348.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59098.0,"EndTime":59098.0,"X":193.521332,"Y":272.03418,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59357.0,"Objects":[{"StartTime":59357.0,"EndTime":59357.0,"X":15.0,"Y":170.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59432.0,"EndTime":59432.0,"X":88.98373,"Y":211.08371,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59579.0,"Objects":[{"StartTime":59579.0,"EndTime":59579.0,"X":21.0,"Y":297.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59765.0,"EndTime":59765.0,"X":192.964737,"Y":271.068176,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59912.0,"Objects":[{"StartTime":59912.0,"EndTime":59912.0,"X":264.991943,"Y":85.99196}]},{"StartTime":60023.0,"Objects":[{"StartTime":60023.0,"EndTime":60023.0,"X":269.0,"Y":90.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60098.0,"EndTime":60098.0,"X":224.308014,"Y":165.543427,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60246.0,"Objects":[{"StartTime":60246.0,"EndTime":60246.0,"X":124.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60321.0,"EndTime":60321.0,"X":160.52005,"Y":76.5283051,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60468.0,"Objects":[{"StartTime":60468.0,"EndTime":60468.0,"X":110.0,"Y":347.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60543.0,"EndTime":60543.0,"X":89.8069153,"Y":263.089447,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60690.0,"Objects":[{"StartTime":60690.0,"EndTime":60690.0,"X":192.0,"Y":271.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60765.0,"EndTime":60765.0,"X":246.522369,"Y":205.4,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60912.0,"Objects":[{"StartTime":60912.0,"EndTime":60912.0,"X":358.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61098.0,"EndTime":61098.0,"X":373.250122,"Y":217.322479,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61246.0,"Objects":[{"StartTime":61246.0,"EndTime":61246.0,"X":430.0,"Y":30.0}]},{"StartTime":61357.0,"Objects":[{"StartTime":61357.0,"EndTime":61357.0,"X":505.0,"Y":82.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61432.0,"EndTime":61432.0,"X":431.744324,"Y":122.383575,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61579.0,"Objects":[{"StartTime":61579.0,"EndTime":61579.0,"X":291.0,"Y":5.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61654.0,"EndTime":61654.0,"X":323.602966,"Y":81.7476959,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61801.0,"Objects":[{"StartTime":61801.0,"EndTime":61801.0,"X":241.0,"Y":182.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61876.0,"EndTime":61876.0,"X":152.224548,"Y":196.795914,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62023.0,"Objects":[{"StartTime":62023.0,"EndTime":62023.0,"X":4.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62209.0,"EndTime":62209.0,"X":173.169617,"Y":74.65553,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62468.0,"Objects":[{"StartTime":62468.0,"EndTime":62468.0,"X":118.0,"Y":348.0}]},{"StartTime":62579.0,"Objects":[{"StartTime":62579.0,"EndTime":62579.0,"X":68.0,"Y":264.0}]},{"StartTime":62690.0,"Objects":[{"StartTime":62690.0,"EndTime":62690.0,"X":134.0,"Y":181.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62765.0,"EndTime":62765.0,"X":160.78125,"Y":258.295074,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62912.0,"Objects":[{"StartTime":62912.0,"EndTime":62912.0,"X":264.0,"Y":364.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62987.0,"EndTime":62987.0,"X":272.42923,"Y":281.0493,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63134.0,"Objects":[{"StartTime":63134.0,"EndTime":63134.0,"X":79.0,"Y":96.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63320.0,"EndTime":63320.0,"X":225.852829,"Y":152.494583,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63468.0,"Objects":[{"StartTime":63468.0,"EndTime":63468.0,"X":295.991943,"Y":67.99196}]},{"StartTime":63579.0,"Objects":[{"StartTime":63579.0,"EndTime":63579.0,"X":300.0,"Y":72.0}]},{"StartTime":63801.0,"Objects":[{"StartTime":63801.0,"EndTime":63801.0,"X":188.0,"Y":7.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63876.0,"EndTime":63876.0,"X":179.597717,"Y":72.3198853,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64023.0,"Objects":[{"StartTime":64023.0,"EndTime":64023.0,"X":376.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64209.0,"EndTime":64209.0,"X":299.1473,"Y":71.53191,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64357.0,"Objects":[{"StartTime":64357.0,"EndTime":64357.0,"X":272.991943,"Y":171.991959}]},{"StartTime":64468.0,"Objects":[{"StartTime":64468.0,"EndTime":64468.0,"X":277.0,"Y":176.0}]},{"StartTime":64690.0,"Objects":[{"StartTime":64690.0,"EndTime":64690.0,"X":474.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64765.0,"EndTime":64765.0,"X":414.378662,"Y":73.66836,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64912.0,"Objects":[{"StartTime":64912.0,"EndTime":64912.0,"X":494.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65098.0,"EndTime":65098.0,"X":375.9208,"Y":207.62468,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65246.0,"Objects":[{"StartTime":65246.0,"EndTime":65246.0,"X":311.991943,"Y":367.991943}]},{"StartTime":65357.0,"Objects":[{"StartTime":65357.0,"EndTime":65357.0,"X":316.0,"Y":372.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65432.0,"EndTime":65432.0,"X":310.725769,"Y":296.927643,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65579.0,"Objects":[{"StartTime":65579.0,"EndTime":65579.0,"X":188.0,"Y":163.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65654.0,"EndTime":65654.0,"X":191.017456,"Y":246.244186,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65801.0,"Objects":[{"StartTime":65801.0,"EndTime":65801.0,"X":449.0,"Y":141.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65987.0,"EndTime":65987.0,"X":294.266144,"Y":193.555252,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66134.0,"Objects":[{"StartTime":66134.0,"EndTime":66134.0,"X":246.991959,"Y":22.9919586}]},{"StartTime":66246.0,"Objects":[{"StartTime":66246.0,"EndTime":66246.0,"X":251.0,"Y":27.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66321.0,"EndTime":66321.0,"X":280.9946,"Y":103.377113,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66468.0,"Objects":[{"StartTime":66468.0,"EndTime":66468.0,"X":131.0,"Y":223.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66543.0,"EndTime":66543.0,"X":186.999573,"Y":162.000076,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66690.0,"Objects":[{"StartTime":66690.0,"EndTime":66690.0,"X":292.0,"Y":356.0}]},{"StartTime":66801.0,"Objects":[{"StartTime":66801.0,"EndTime":66801.0,"X":233.0,"Y":273.0}]},{"StartTime":66912.0,"Objects":[{"StartTime":66912.0,"EndTime":66912.0,"X":283.0,"Y":188.0}]},{"StartTime":67023.0,"Objects":[{"StartTime":67023.0,"EndTime":67023.0,"X":387.0,"Y":198.0}]},{"StartTime":67134.0,"Objects":[{"StartTime":67134.0,"EndTime":67134.0,"X":327.0,"Y":275.0}]},{"StartTime":77357.0,"Objects":[{"StartTime":77357.0,"EndTime":77357.0,"X":22.0,"Y":236.0}]},{"StartTime":77468.0,"Objects":[{"StartTime":77468.0,"EndTime":77468.0,"X":28.0,"Y":134.0}]},{"StartTime":77579.0,"Objects":[{"StartTime":77579.0,"EndTime":77579.0,"X":127.0,"Y":121.0}]},{"StartTime":77690.0,"Objects":[{"StartTime":77690.0,"EndTime":77690.0,"X":193.0,"Y":191.0}]},{"StartTime":77801.0,"Objects":[{"StartTime":77801.0,"EndTime":77801.0,"X":272.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77987.0,"EndTime":77987.0,"X":235.886368,"Y":42.98614,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78134.0,"Objects":[{"StartTime":78134.0,"EndTime":78134.0,"X":153.991959,"Y":261.991943}]},{"StartTime":78246.0,"Objects":[{"StartTime":78246.0,"EndTime":78246.0,"X":158.0,"Y":266.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78432.0,"EndTime":78432.0,"X":193.2372,"Y":191.506226,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78579.0,"Objects":[{"StartTime":78579.0,"EndTime":78579.0,"X":263.991943,"Y":281.991943}]},{"StartTime":78690.0,"Objects":[{"StartTime":78690.0,"EndTime":78690.0,"X":268.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78765.0,"EndTime":78765.0,"X":269.681641,"Y":341.7793,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78912.0,"Objects":[{"StartTime":78912.0,"EndTime":78912.0,"X":472.0,"Y":268.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78987.0,"EndTime":78987.0,"X":470.318359,"Y":323.7793,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":79134.0,"Objects":[{"StartTime":79134.0,"EndTime":79134.0,"X":382.0,"Y":379.0}]},{"StartTime":79245.0,"Objects":[{"StartTime":79245.0,"EndTime":79245.0,"X":361.0,"Y":323.0}]},{"StartTime":79356.0,"Objects":[{"StartTime":79356.0,"EndTime":79356.0,"X":369.0,"Y":264.0}]},{"StartTime":79579.0,"Objects":[{"StartTime":79579.0,"EndTime":79579.0,"X":341.0,"Y":102.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":79765.0,"EndTime":79765.0,"X":191.770432,"Y":106.0115,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":79912.0,"Objects":[{"StartTime":79912.0,"EndTime":79912.0,"X":13.9919577,"Y":77.99196}]},{"StartTime":80023.0,"Objects":[{"StartTime":80023.0,"EndTime":80023.0,"X":18.0,"Y":82.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":80209.0,"EndTime":80209.0,"X":112.42717,"Y":24.9309063,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":80357.0,"Objects":[{"StartTime":80357.0,"EndTime":80357.0,"X":44.0,"Y":222.0}]},{"StartTime":80468.0,"Objects":[{"StartTime":80468.0,"EndTime":80468.0,"X":31.0,"Y":206.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":80543.0,"EndTime":80543.0,"X":87.72538,"Y":166.579071,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":80690.0,"Objects":[{"StartTime":80690.0,"EndTime":80690.0,"X":191.0,"Y":106.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":80765.0,"EndTime":80765.0,"X":236.460342,"Y":159.530334,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":80912.0,"Objects":[{"StartTime":80912.0,"EndTime":80912.0,"X":125.0,"Y":355.0}]},{"StartTime":81023.0,"Objects":[{"StartTime":81023.0,"EndTime":81023.0,"X":100.0,"Y":316.0}]},{"StartTime":81134.0,"Objects":[{"StartTime":81134.0,"EndTime":81134.0,"X":122.0,"Y":267.0}]},{"StartTime":81357.0,"Objects":[{"StartTime":81357.0,"EndTime":81357.0,"X":253.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":81543.0,"EndTime":81543.0,"X":395.074554,"Y":351.882355,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":81690.0,"Objects":[{"StartTime":81690.0,"EndTime":81690.0,"X":512.0,"Y":190.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":81876.0,"EndTime":81876.0,"X":369.925446,"Y":225.88237,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82023.0,"Objects":[{"StartTime":82023.0,"EndTime":82023.0,"X":328.0,"Y":71.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":82098.0,"EndTime":82098.0,"X":383.893555,"Y":101.619812,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82246.0,"Objects":[{"StartTime":82246.0,"EndTime":82246.0,"X":257.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":82432.0,"EndTime":82432.0,"X":237.943909,"Y":158.504913,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82579.0,"Objects":[{"StartTime":82579.0,"EndTime":82579.0,"X":163.0,"Y":99.0}]},{"StartTime":82690.0,"Objects":[{"StartTime":82690.0,"EndTime":82690.0,"X":111.0,"Y":178.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":82765.0,"EndTime":82765.0,"X":59.71753,"Y":227.345261,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82912.0,"Objects":[{"StartTime":82912.0,"EndTime":82912.0,"X":81.0,"Y":47.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":82987.0,"EndTime":82987.0,"X":135.614578,"Y":4.255745,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":83134.0,"Objects":[{"StartTime":83134.0,"EndTime":83134.0,"X":0.0,"Y":177.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":83320.0,"EndTime":83320.0,"X":43.84988,"Y":309.314972,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":83468.0,"Objects":[{"StartTime":83468.0,"EndTime":83468.0,"X":47.00804,"Y":313.008057}]},{"StartTime":83579.0,"Objects":[{"StartTime":83579.0,"EndTime":83579.0,"X":51.0160828,"Y":317.016083}]},{"StartTime":83801.0,"Objects":[{"StartTime":83801.0,"EndTime":83801.0,"X":139.0,"Y":384.0}]},{"StartTime":84023.0,"Objects":[{"StartTime":84023.0,"EndTime":84023.0,"X":188.0,"Y":280.0}]},{"StartTime":84246.0,"Objects":[{"StartTime":84246.0,"EndTime":84246.0,"X":103.0,"Y":89.0}]},{"StartTime":84468.0,"Objects":[{"StartTime":84468.0,"EndTime":84468.0,"X":224.0,"Y":144.0}]},{"StartTime":84579.0,"Objects":[{"StartTime":84579.0,"EndTime":84579.0,"X":290.0,"Y":148.0}]},{"StartTime":84690.0,"Objects":[{"StartTime":84690.0,"EndTime":84690.0,"X":337.0,"Y":103.0}]},{"StartTime":84801.0,"Objects":[{"StartTime":84801.0,"EndTime":84801.0,"X":339.0,"Y":38.0}]},{"StartTime":84912.0,"Objects":[{"StartTime":84912.0,"EndTime":84912.0,"X":295.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":85098.0,"EndTime":85098.0,"X":290.461456,"Y":146.231247,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":85246.0,"Objects":[{"StartTime":85246.0,"EndTime":85246.0,"X":220.991959,"Y":231.991959}]},{"StartTime":85357.0,"Objects":[{"StartTime":85357.0,"EndTime":85357.0,"X":225.0,"Y":236.0}]},{"StartTime":85579.0,"Objects":[{"StartTime":85579.0,"EndTime":85579.0,"X":398.0,"Y":86.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":85654.0,"EndTime":85654.0,"X":390.427429,"Y":126.911087,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":85801.0,"Objects":[{"StartTime":85801.0,"EndTime":85801.0,"X":115.0,"Y":294.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":85987.0,"EndTime":85987.0,"X":224.971466,"Y":235.134537,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":86246.0,"Objects":[{"StartTime":86246.0,"EndTime":86246.0,"X":115.0,"Y":294.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86321.0,"EndTime":86321.0,"X":115.371964,"Y":222.39064,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":86468.0,"Objects":[{"StartTime":86468.0,"EndTime":86468.0,"X":22.0,"Y":157.0}]},{"StartTime":86579.0,"Objects":[{"StartTime":86579.0,"EndTime":86579.0,"X":55.0,"Y":100.0}]},{"StartTime":86690.0,"Objects":[{"StartTime":86690.0,"EndTime":86690.0,"X":119.0,"Y":90.0}]},{"StartTime":86912.0,"Objects":[{"StartTime":86912.0,"EndTime":86912.0,"X":308.0,"Y":247.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86987.0,"EndTime":86987.0,"X":233.004623,"Y":247.833282,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":87134.0,"Objects":[{"StartTime":87134.0,"EndTime":87134.0,"X":228.0,"Y":131.0}]},{"StartTime":87357.0,"Objects":[{"StartTime":87357.0,"EndTime":87357.0,"X":177.0,"Y":357.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87432.0,"EndTime":87432.0,"X":117.9708,"Y":310.7339,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":87579.0,"Objects":[{"StartTime":87579.0,"EndTime":87579.0,"X":233.0,"Y":249.0}]},{"StartTime":87801.0,"Objects":[{"StartTime":87801.0,"EndTime":87801.0,"X":15.0,"Y":324.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87876.0,"EndTime":87876.0,"X":38.60399,"Y":258.514923,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88023.0,"Objects":[{"StartTime":88023.0,"EndTime":88023.0,"X":224.0,"Y":165.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88098.0,"EndTime":88098.0,"X":149.013092,"Y":166.401627,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88246.0,"Objects":[{"StartTime":88246.0,"EndTime":88246.0,"X":258.0,"Y":70.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88321.0,"EndTime":88321.0,"X":183.013092,"Y":71.40163,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88468.0,"Objects":[{"StartTime":88468.0,"EndTime":88468.0,"X":5.0,"Y":16.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88654.0,"EndTime":88654.0,"X":43.598732,"Y":145.0479,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88912.0,"Objects":[{"StartTime":88912.0,"EndTime":88912.0,"X":273.0,"Y":256.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88987.0,"EndTime":88987.0,"X":198.00383,"Y":255.242462,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":89134.0,"Objects":[{"StartTime":89134.0,"EndTime":89134.0,"X":3.0,"Y":269.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89320.0,"EndTime":89320.0,"X":42.83066,"Y":145.045731,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":89579.0,"Objects":[{"StartTime":89579.0,"EndTime":89579.0,"X":124.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89654.0,"EndTime":89654.0,"X":114.932907,"Y":317.385345,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":89801.0,"Objects":[{"StartTime":89801.0,"EndTime":89801.0,"X":208.0,"Y":188.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89876.0,"EndTime":89876.0,"X":197.526962,"Y":254.4049,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":90023.0,"Objects":[{"StartTime":90023.0,"EndTime":90023.0,"X":3.0,"Y":269.0}]},{"StartTime":90134.0,"Objects":[{"StartTime":90134.0,"EndTime":90134.0,"X":49.0,"Y":218.0}]},{"StartTime":90246.0,"Objects":[{"StartTime":90246.0,"EndTime":90246.0,"X":115.0,"Y":225.0}]},{"StartTime":90468.0,"Objects":[{"StartTime":90468.0,"EndTime":90468.0,"X":0.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":90543.0,"EndTime":90543.0,"X":55.339325,"Y":99.68659,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":90690.0,"Objects":[{"StartTime":90690.0,"EndTime":90690.0,"X":218.0,"Y":6.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":90876.0,"EndTime":90876.0,"X":195.563538,"Y":127.699821,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":91134.0,"Objects":[{"StartTime":91134.0,"EndTime":91134.0,"X":419.0,"Y":145.0}]},{"StartTime":91246.0,"Objects":[{"StartTime":91246.0,"EndTime":91246.0,"X":479.0,"Y":56.0}]},{"StartTime":91357.0,"Objects":[{"StartTime":91357.0,"EndTime":91357.0,"X":379.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":91432.0,"EndTime":91432.0,"X":367.074463,"Y":67.35657,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":91579.0,"Objects":[{"StartTime":91579.0,"EndTime":91579.0,"X":512.0,"Y":276.0}]},{"StartTime":91690.0,"Objects":[{"StartTime":91690.0,"EndTime":91690.0,"X":468.0,"Y":233.0}]},{"StartTime":91801.0,"Objects":[{"StartTime":91801.0,"EndTime":91801.0,"X":406.0,"Y":261.0}]},{"StartTime":91912.0,"Objects":[{"StartTime":91912.0,"EndTime":91912.0,"X":318.0,"Y":330.0}]},{"StartTime":92023.0,"Objects":[{"StartTime":92023.0,"EndTime":92023.0,"X":224.0,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92209.0,"EndTime":92209.0,"X":226.0476,"Y":150.599991,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":92357.0,"Objects":[{"StartTime":92357.0,"EndTime":92357.0,"X":313.991943,"Y":212.991959}]},{"StartTime":92468.0,"Objects":[{"StartTime":92468.0,"EndTime":92468.0,"X":318.0,"Y":217.0}]},{"StartTime":92690.0,"Objects":[{"StartTime":92690.0,"EndTime":92690.0,"X":149.0,"Y":15.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92765.0,"EndTime":92765.0,"X":131.775192,"Y":83.55616,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":92912.0,"Objects":[{"StartTime":92912.0,"EndTime":92912.0,"X":342.0,"Y":63.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92987.0,"EndTime":92987.0,"X":267.0478,"Y":60.3231354,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93134.0,"Objects":[{"StartTime":93134.0,"EndTime":93134.0,"X":170.0,"Y":201.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93209.0,"EndTime":93209.0,"X":244.952209,"Y":203.676865,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93357.0,"Objects":[{"StartTime":93357.0,"EndTime":93357.0,"X":472.0,"Y":64.0}]},{"StartTime":93468.0,"Objects":[{"StartTime":93468.0,"EndTime":93468.0,"X":506.0,"Y":125.0}]},{"StartTime":93579.0,"Objects":[{"StartTime":93579.0,"EndTime":93579.0,"X":462.0,"Y":179.0}]},{"StartTime":93690.0,"Objects":[{"StartTime":93690.0,"EndTime":93690.0,"X":366.0,"Y":146.0}]},{"StartTime":93801.0,"Objects":[{"StartTime":93801.0,"EndTime":93801.0,"X":285.0,"Y":212.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93987.0,"EndTime":93987.0,"X":272.6529,"Y":342.357147,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94134.0,"Objects":[{"StartTime":94134.0,"EndTime":94134.0,"X":364.991943,"Y":282.991943}]},{"StartTime":94246.0,"Objects":[{"StartTime":94246.0,"EndTime":94246.0,"X":369.0,"Y":287.0}]},{"StartTime":94468.0,"Objects":[{"StartTime":94468.0,"EndTime":94468.0,"X":219.0,"Y":185.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":94543.0,"EndTime":94543.0,"X":284.25824,"Y":211.452911,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94690.0,"Objects":[{"StartTime":94690.0,"EndTime":94690.0,"X":336.0,"Y":23.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":94765.0,"EndTime":94765.0,"X":347.338745,"Y":97.13793,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94912.0,"Objects":[{"StartTime":94912.0,"EndTime":94912.0,"X":433.0,"Y":84.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":94987.0,"EndTime":94987.0,"X":444.338745,"Y":158.137939,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":95134.0,"Objects":[{"StartTime":95134.0,"EndTime":95134.0,"X":284.0,"Y":211.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95209.0,"EndTime":95209.0,"X":272.661255,"Y":285.137939,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":95356.0,"Objects":[{"StartTime":95356.0,"EndTime":95356.0,"X":187.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95431.0,"EndTime":95431.0,"X":175.661255,"Y":346.137939,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":95579.0,"Objects":[{"StartTime":95579.0,"EndTime":95579.0,"X":356.0,"Y":383.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95765.0,"EndTime":95765.0,"X":488.053619,"Y":358.016022,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96023.0,"Objects":[{"StartTime":96023.0,"EndTime":96023.0,"X":272.0,"Y":285.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96209.0,"EndTime":96209.0,"X":139.5626,"Y":259.780029,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96357.0,"Objects":[{"StartTime":96357.0,"EndTime":96357.0,"X":196.991959,"Y":120.991959}]},{"StartTime":96468.0,"Objects":[{"StartTime":96468.0,"EndTime":96468.0,"X":201.0,"Y":125.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96543.0,"EndTime":96543.0,"X":216.962341,"Y":198.281677,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96690.0,"Objects":[{"StartTime":96690.0,"EndTime":96690.0,"X":271.0,"Y":284.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96765.0,"EndTime":96765.0,"X":256.1003,"Y":357.5051,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96912.0,"Objects":[{"StartTime":96912.0,"EndTime":96912.0,"X":84.0,"Y":186.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97098.0,"EndTime":97098.0,"X":216.1286,"Y":197.325577,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":97246.0,"Objects":[{"StartTime":97246.0,"EndTime":97246.0,"X":142.991959,"Y":263.991943}]},{"StartTime":97357.0,"Objects":[{"StartTime":97357.0,"EndTime":97357.0,"X":147.0,"Y":268.0}]},{"StartTime":97579.0,"Objects":[{"StartTime":97579.0,"EndTime":97579.0,"X":357.0,"Y":138.0}]},{"StartTime":97801.0,"Objects":[{"StartTime":97801.0,"EndTime":97801.0,"X":176.0,"Y":7.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97987.0,"EndTime":97987.0,"X":155.1887,"Y":93.60436,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98134.0,"Objects":[{"StartTime":98134.0,"EndTime":98134.0,"X":202.991959,"Y":265.991943}]},{"StartTime":98246.0,"Objects":[{"StartTime":98246.0,"EndTime":98246.0,"X":207.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98321.0,"EndTime":98321.0,"X":224.953857,"Y":204.034622,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98468.0,"Objects":[{"StartTime":98468.0,"EndTime":98468.0,"X":247.0,"Y":69.0}]},{"StartTime":98579.0,"Objects":[{"StartTime":98579.0,"EndTime":98579.0,"X":294.0,"Y":108.0}]},{"StartTime":98690.0,"Objects":[{"StartTime":98690.0,"EndTime":98690.0,"X":353.0,"Y":100.0}]},{"StartTime":98801.0,"Objects":[{"StartTime":98801.0,"EndTime":98801.0,"X":397.0,"Y":60.0}]},{"StartTime":98912.0,"Objects":[{"StartTime":98912.0,"EndTime":98912.0,"X":496.0,"Y":86.0}]},{"StartTime":99023.0,"Objects":[{"StartTime":99023.0,"EndTime":99023.0,"X":491.0,"Y":189.0}]},{"StartTime":99134.0,"Objects":[{"StartTime":99134.0,"EndTime":99134.0,"X":389.0,"Y":228.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":99320.0,"EndTime":99320.0,"X":379.916351,"Y":364.565735,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":99468.0,"Objects":[{"StartTime":99468.0,"EndTime":99468.0,"X":266.991943,"Y":53.99196}]},{"StartTime":99579.0,"Objects":[{"StartTime":99579.0,"EndTime":99579.0,"X":271.0,"Y":58.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":99765.0,"EndTime":99765.0,"X":280.083649,"Y":194.56575,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":99912.0,"Objects":[{"StartTime":99912.0,"EndTime":99912.0,"X":185.991959,"Y":347.991943}]},{"StartTime":100023.0,"Objects":[{"StartTime":100023.0,"EndTime":100023.0,"X":190.0,"Y":352.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100098.0,"EndTime":100098.0,"X":237.068085,"Y":307.034576,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100246.0,"Objects":[{"StartTime":100246.0,"EndTime":100246.0,"X":347.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100321.0,"EndTime":100321.0,"X":278.9459,"Y":193.096,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100468.0,"Objects":[{"StartTime":100468.0,"EndTime":100468.0,"X":84.0,"Y":306.0}]},{"StartTime":100579.0,"Objects":[{"StartTime":100579.0,"EndTime":100579.0,"X":105.0,"Y":243.0}]},{"StartTime":100690.0,"Objects":[{"StartTime":100690.0,"EndTime":100690.0,"X":170.0,"Y":218.0}]},{"StartTime":100912.0,"Objects":[{"StartTime":100912.0,"EndTime":100912.0,"X":231.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101098.0,"EndTime":101098.0,"X":278.354858,"Y":193.081116,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101246.0,"Objects":[{"StartTime":101246.0,"EndTime":101246.0,"X":344.0,"Y":370.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101432.0,"EndTime":101432.0,"X":391.354858,"Y":232.918884,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101579.0,"Objects":[{"StartTime":101579.0,"EndTime":101579.0,"X":448.0,"Y":146.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101654.0,"EndTime":101654.0,"X":378.303619,"Y":128.719528,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101801.0,"Objects":[{"StartTime":101801.0,"EndTime":101801.0,"X":205.0,"Y":282.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101876.0,"EndTime":101876.0,"X":270.360626,"Y":249.990387,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102023.0,"Objects":[{"StartTime":102023.0,"EndTime":102023.0,"X":197.0,"Y":178.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102098.0,"EndTime":102098.0,"X":237.161285,"Y":117.944107,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102246.0,"Objects":[{"StartTime":102246.0,"EndTime":102246.0,"X":70.0,"Y":284.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102321.0,"EndTime":102321.0,"X":4.63935757,"Y":251.990387,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102468.0,"Objects":[{"StartTime":102468.0,"EndTime":102468.0,"X":78.0,"Y":180.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102543.0,"EndTime":102543.0,"X":37.8387,"Y":119.944115,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102690.0,"Objects":[{"StartTime":102690.0,"EndTime":102690.0,"X":178.0,"Y":15.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102876.0,"EndTime":102876.0,"X":104.018806,"Y":12.1474352,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103023.0,"Objects":[{"StartTime":103023.0,"EndTime":103023.0,"X":281.0,"Y":207.0}]},{"StartTime":103134.0,"Objects":[{"StartTime":103134.0,"EndTime":103134.0,"X":260.0,"Y":203.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103209.0,"EndTime":103209.0,"X":251.868073,"Y":136.364059,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103357.0,"Objects":[{"StartTime":103357.0,"EndTime":103357.0,"X":354.0,"Y":14.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103432.0,"EndTime":103432.0,"X":344.82843,"Y":80.1442642,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103579.0,"Objects":[{"StartTime":103579.0,"EndTime":103579.0,"X":178.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103765.0,"EndTime":103765.0,"X":157.606537,"Y":114.033684,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103912.0,"Objects":[{"StartTime":103912.0,"EndTime":103912.0,"X":379.0,"Y":203.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104098.0,"EndTime":104098.0,"X":259.0721,"Y":202.865311,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104246.0,"Objects":[{"StartTime":104246.0,"EndTime":104246.0,"X":168.0,"Y":324.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104321.0,"EndTime":104321.0,"X":177.0319,"Y":252.65538,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104468.0,"Objects":[{"StartTime":104468.0,"EndTime":104468.0,"X":304.0,"Y":76.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104654.0,"EndTime":104654.0,"X":258.715973,"Y":202.396683,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104801.0,"Objects":[{"StartTime":104801.0,"EndTime":104801.0,"X":464.0,"Y":172.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104987.0,"EndTime":104987.0,"X":360.003235,"Y":162.668,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105134.0,"Objects":[{"StartTime":105134.0,"EndTime":105134.0,"X":253.0,"Y":328.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105209.0,"EndTime":105209.0,"X":310.076935,"Y":287.604034,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105357.0,"Objects":[{"StartTime":105357.0,"EndTime":105357.0,"X":360.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105432.0,"EndTime":105432.0,"X":285.5137,"Y":170.763092,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105579.0,"Objects":[{"StartTime":105579.0,"EndTime":105579.0,"X":166.0,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105654.0,"EndTime":105654.0,"X":240.4863,"Y":76.23691,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105801.0,"Objects":[{"StartTime":105801.0,"EndTime":105801.0,"X":166.0,"Y":271.0}]},{"StartTime":105912.0,"Objects":[{"StartTime":105912.0,"EndTime":105912.0,"X":164.0,"Y":228.0}]},{"StartTime":106023.0,"Objects":[{"StartTime":106023.0,"EndTime":106023.0,"X":60.0,"Y":177.0}]},{"StartTime":106134.0,"Objects":[{"StartTime":106134.0,"EndTime":106134.0,"X":59.0,"Y":134.0}]},{"StartTime":106246.0,"Objects":[{"StartTime":106246.0,"EndTime":106246.0,"X":226.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106432.0,"EndTime":106432.0,"X":165.177826,"Y":84.50453,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106690.0,"Objects":[{"StartTime":106690.0,"EndTime":106690.0,"X":323.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106765.0,"EndTime":106765.0,"X":330.090057,"Y":124.520119,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106912.0,"Objects":[{"StartTime":106912.0,"EndTime":106912.0,"X":166.0,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107098.0,"EndTime":107098.0,"X":202.6605,"Y":243.165527,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107246.0,"Objects":[{"StartTime":107246.0,"EndTime":107246.0,"X":42.0,"Y":125.0}]},{"StartTime":107357.0,"Objects":[{"StartTime":107357.0,"EndTime":107357.0,"X":20.0,"Y":228.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107432.0,"EndTime":107432.0,"X":106.100655,"Y":201.795456,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107579.0,"Objects":[{"StartTime":107579.0,"EndTime":107579.0,"X":225.0,"Y":148.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107654.0,"EndTime":107654.0,"X":165.022446,"Y":84.57403,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107801.0,"Objects":[{"StartTime":107801.0,"EndTime":107801.0,"X":176.0,"Y":305.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107876.0,"EndTime":107876.0,"X":235.406113,"Y":241.261124,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108023.0,"Objects":[{"StartTime":108023.0,"EndTime":108023.0,"X":106.0,"Y":201.0}]},{"StartTime":108246.0,"Objects":[{"StartTime":108246.0,"EndTime":108246.0,"X":323.0,"Y":179.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108321.0,"EndTime":108321.0,"X":325.87088,"Y":89.0458,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108468.0,"Objects":[{"StartTime":108468.0,"EndTime":108468.0,"X":426.0,"Y":19.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108543.0,"EndTime":108543.0,"X":423.12912,"Y":108.9542,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108690.0,"Objects":[{"StartTime":108690.0,"EndTime":108690.0,"X":371.0,"Y":297.0}]},{"StartTime":108801.0,"Objects":[{"StartTime":108801.0,"EndTime":108801.0,"X":427.0,"Y":211.0}]},{"StartTime":108912.0,"Objects":[{"StartTime":108912.0,"EndTime":108912.0,"X":508.0,"Y":272.0}]},{"StartTime":109134.0,"Objects":[{"StartTime":109134.0,"EndTime":109134.0,"X":302.0,"Y":358.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109209.0,"EndTime":109209.0,"X":278.45575,"Y":279.0938,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109357.0,"Objects":[{"StartTime":109357.0,"EndTime":109357.0,"X":169.0,"Y":263.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109432.0,"EndTime":109432.0,"X":209.881577,"Y":190.538345,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109579.0,"Objects":[{"StartTime":109579.0,"EndTime":109579.0,"X":418.0,"Y":133.0}]},{"StartTime":109690.0,"Objects":[{"StartTime":109690.0,"EndTime":109690.0,"X":326.0,"Y":187.0}]},{"StartTime":109801.0,"Objects":[{"StartTime":109801.0,"EndTime":109801.0,"X":264.0,"Y":99.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109987.0,"EndTime":109987.0,"X":125.060516,"Y":76.14555,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110134.0,"Objects":[{"StartTime":110134.0,"EndTime":110134.0,"X":-4.00804234,"Y":238.991959}]},{"StartTime":110246.0,"Objects":[{"StartTime":110246.0,"EndTime":110246.0,"X":0.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110321.0,"EndTime":110321.0,"X":60.9713249,"Y":186.021042,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110468.0,"Objects":[{"StartTime":110468.0,"EndTime":110468.0,"X":203.0,"Y":40.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110654.0,"EndTime":110654.0,"X":168.509491,"Y":196.267059,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110801.0,"Objects":[{"StartTime":110801.0,"EndTime":110801.0,"X":141.991959,"Y":369.991943}]},{"StartTime":110912.0,"Objects":[{"StartTime":110912.0,"EndTime":110912.0,"X":146.0,"Y":374.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110987.0,"EndTime":110987.0,"X":105.254768,"Y":302.029266,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111134.0,"Objects":[{"StartTime":111134.0,"EndTime":111134.0,"X":271.0,"Y":133.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111320.0,"EndTime":111320.0,"X":230.608124,"Y":291.669281,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111468.0,"Objects":[{"StartTime":111468.0,"EndTime":111468.0,"X":398.0,"Y":293.0}]},{"StartTime":111579.0,"Objects":[{"StartTime":111579.0,"EndTime":111579.0,"X":402.0,"Y":194.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111654.0,"EndTime":111654.0,"X":319.0025,"Y":228.8054,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111801.0,"Objects":[{"StartTime":111801.0,"EndTime":111801.0,"X":153.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111876.0,"EndTime":111876.0,"X":164.993683,"Y":196.600021,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112023.0,"Objects":[{"StartTime":112023.0,"EndTime":112023.0,"X":436.0,"Y":63.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112209.0,"EndTime":112209.0,"X":270.123169,"Y":132.891922,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112357.0,"Objects":[{"StartTime":112357.0,"EndTime":112357.0,"X":296.991943,"Y":13.9919577}]},{"StartTime":112468.0,"Objects":[{"StartTime":112468.0,"EndTime":112468.0,"X":301.0,"Y":18.0}]},{"StartTime":112690.0,"Objects":[{"StartTime":112690.0,"EndTime":112690.0,"X":153.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112765.0,"EndTime":112765.0,"X":142.674759,"Y":35.2563171,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112912.0,"Objects":[{"StartTime":112912.0,"EndTime":112912.0,"X":335.0,"Y":186.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112987.0,"EndTime":112987.0,"X":270.000671,"Y":132.817719,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":113134.0,"Objects":[{"StartTime":113134.0,"EndTime":113134.0,"X":197.0,"Y":215.0}]},{"StartTime":113357.0,"Objects":[{"StartTime":113357.0,"EndTime":113357.0,"X":197.0,"Y":215.0}]},{"StartTime":113579.0,"Objects":[{"StartTime":113579.0,"EndTime":113579.0,"X":246.0,"Y":30.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":113654.0,"EndTime":113654.0,"X":322.939545,"Y":22.0649261,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":113801.0,"Objects":[{"StartTime":113801.0,"EndTime":113801.0,"X":487.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":113876.0,"EndTime":113876.0,"X":410.060455,"Y":120.064926,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114023.0,"Objects":[{"StartTime":114023.0,"EndTime":114023.0,"X":307.0,"Y":215.0}]},{"StartTime":114246.0,"Objects":[{"StartTime":114246.0,"EndTime":114246.0,"X":307.0,"Y":215.0}]},{"StartTime":114468.0,"Objects":[{"StartTime":114468.0,"EndTime":114468.0,"X":306.0,"Y":214.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114543.0,"EndTime":114543.0,"X":299.8086,"Y":294.7465,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114690.0,"Objects":[{"StartTime":114690.0,"EndTime":114690.0,"X":420.0,"Y":354.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114765.0,"EndTime":114765.0,"X":411.106842,"Y":271.121,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114912.0,"Objects":[{"StartTime":114912.0,"EndTime":114912.0,"X":232.0,"Y":153.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115098.0,"EndTime":115098.0,"X":200.770355,"Y":314.7974,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115357.0,"Objects":[{"StartTime":115357.0,"EndTime":115357.0,"X":232.0,"Y":153.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115432.0,"EndTime":115432.0,"X":262.242279,"Y":76.66023,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115579.0,"Objects":[{"StartTime":115579.0,"EndTime":115579.0,"X":134.0,"Y":49.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115654.0,"EndTime":115654.0,"X":113.259193,"Y":127.8234,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115801.0,"Objects":[{"StartTime":115801.0,"EndTime":115801.0,"X":379.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115987.0,"EndTime":115987.0,"X":231.178818,"Y":152.268,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":116246.0,"Objects":[{"StartTime":116246.0,"EndTime":116246.0,"X":291.0,"Y":331.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":116321.0,"EndTime":116321.0,"X":277.160767,"Y":273.2597,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":116468.0,"Objects":[{"StartTime":116468.0,"EndTime":116468.0,"X":98.0,"Y":122.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":116543.0,"EndTime":116543.0,"X":110.779022,"Y":204.751175,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":116690.0,"Objects":[{"StartTime":116690.0,"EndTime":116690.0,"X":303.0,"Y":183.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":116765.0,"EndTime":116765.0,"X":219.3649,"Y":196.415344,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":116912.0,"Objects":[{"StartTime":116912.0,"EndTime":116912.0,"X":120.0,"Y":366.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117209.0,"EndTime":117209.0,"X":24.3464966,"Y":257.467133,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":117357.0,"Objects":[{"StartTime":117357.0,"EndTime":117357.0,"X":24.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117432.0,"EndTime":117432.0,"X":99.04936,"Y":214.926025,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":117579.0,"Objects":[{"StartTime":117579.0,"EndTime":117579.0,"X":171.0,"Y":32.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117876.0,"EndTime":117876.0,"X":227.881714,"Y":272.095856,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118023.0,"Objects":[{"StartTime":118023.0,"EndTime":118023.0,"X":228.0,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118098.0,"EndTime":118098.0,"X":236.877625,"Y":190.670639,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118246.0,"Objects":[{"StartTime":118246.0,"EndTime":118246.0,"X":341.0,"Y":196.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118321.0,"EndTime":118321.0,"X":348.764679,"Y":278.39035,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118468.0,"Objects":[{"StartTime":118468.0,"EndTime":118468.0,"X":211.0,"Y":45.0}]},{"StartTime":118579.0,"Objects":[{"StartTime":118579.0,"EndTime":118579.0,"X":283.0,"Y":109.0}]},{"StartTime":118690.0,"Objects":[{"StartTime":118690.0,"EndTime":118690.0,"X":349.0,"Y":39.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118765.0,"EndTime":118765.0,"X":428.230774,"Y":20.6932182,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118912.0,"Objects":[{"StartTime":118912.0,"EndTime":118912.0,"X":512.0,"Y":138.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118987.0,"EndTime":118987.0,"X":432.769226,"Y":156.306778,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":119134.0,"Objects":[{"StartTime":119134.0,"EndTime":119134.0,"X":305.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119320.0,"EndTime":119320.0,"X":317.103851,"Y":213.768875,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":119468.0,"Objects":[{"StartTime":119468.0,"EndTime":119468.0,"X":145.0,"Y":89.0}]},{"StartTime":119579.0,"Objects":[{"StartTime":119579.0,"EndTime":119579.0,"X":236.0,"Y":33.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119654.0,"EndTime":119654.0,"X":247.9182,"Y":116.346733,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":119801.0,"Objects":[{"StartTime":119801.0,"EndTime":119801.0,"X":98.0,"Y":245.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119876.0,"EndTime":119876.0,"X":180.54184,"Y":225.650055,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":120023.0,"Objects":[{"StartTime":120023.0,"EndTime":120023.0,"X":357.0,"Y":302.0}]},{"StartTime":120134.0,"Objects":[{"StartTime":120134.0,"EndTime":120134.0,"X":317.0,"Y":213.0}]},{"StartTime":120246.0,"Objects":[{"StartTime":120246.0,"EndTime":120246.0,"X":379.0,"Y":134.0}]},{"StartTime":120357.0,"Objects":[{"StartTime":120357.0,"EndTime":120357.0,"X":475.0,"Y":159.0}]},{"StartTime":120468.0,"Objects":[{"StartTime":120468.0,"EndTime":120468.0,"X":412.0,"Y":227.0}]},{"StartTime":120690.0,"Objects":[{"StartTime":120690.0,"EndTime":120690.0,"X":507.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":120765.0,"EndTime":120765.0,"X":452.0761,"Y":60.7611046,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":120912.0,"Objects":[{"StartTime":120912.0,"EndTime":120912.0,"X":205.0,"Y":127.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":120987.0,"EndTime":120987.0,"X":203.958939,"Y":41.8644447,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":121134.0,"Objects":[{"StartTime":121134.0,"EndTime":121134.0,"X":317.0,"Y":15.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121320.0,"EndTime":121320.0,"X":319.1678,"Y":185.7771,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":121468.0,"Objects":[{"StartTime":121468.0,"EndTime":121468.0,"X":206.991959,"Y":248.991959}]},{"StartTime":121579.0,"Objects":[{"StartTime":121579.0,"EndTime":121579.0,"X":211.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121654.0,"EndTime":121654.0,"X":121.147781,"Y":247.844543,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":121801.0,"Objects":[{"StartTime":121801.0,"EndTime":121801.0,"X":117.0,"Y":78.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121876.0,"EndTime":121876.0,"X":206.852219,"Y":72.84454,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122023.0,"Objects":[{"StartTime":122023.0,"EndTime":122023.0,"X":319.0,"Y":185.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":122209.0,"EndTime":122209.0,"X":291.38446,"Y":345.232025,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122357.0,"Objects":[{"StartTime":122357.0,"EndTime":122357.0,"X":511.0,"Y":320.0}]},{"StartTime":122468.0,"Objects":[{"StartTime":122468.0,"EndTime":122468.0,"X":436.0,"Y":249.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":122543.0,"EndTime":122543.0,"X":382.6199,"Y":296.860382,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122690.0,"Objects":[{"StartTime":122690.0,"EndTime":122690.0,"X":312.0,"Y":102.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":122765.0,"EndTime":122765.0,"X":318.238678,"Y":185.758011,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122912.0,"Objects":[{"StartTime":122912.0,"EndTime":122912.0,"X":411.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":123098.0,"EndTime":123098.0,"X":261.447,"Y":321.2776,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":123246.0,"Objects":[{"StartTime":123246.0,"EndTime":123246.0,"X":115.991959,"Y":227.991959}]},{"StartTime":123357.0,"Objects":[{"StartTime":123357.0,"EndTime":123357.0,"X":120.0,"Y":232.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":123432.0,"EndTime":123432.0,"X":129.313568,"Y":276.144958,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":123579.0,"Objects":[{"StartTime":123579.0,"EndTime":123579.0,"X":185.0,"Y":60.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":123654.0,"EndTime":123654.0,"X":175.686432,"Y":104.144951,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":123801.0,"Objects":[{"StartTime":123801.0,"EndTime":123801.0,"X":0.0,"Y":305.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":123876.0,"EndTime":123876.0,"X":-0.89471674,"Y":221.483368,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124023.0,"Objects":[{"StartTime":124023.0,"EndTime":124023.0,"X":175.0,"Y":104.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":124209.0,"EndTime":124209.0,"X":16.7900982,"Y":103.414063,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124357.0,"Objects":[{"StartTime":124357.0,"EndTime":124357.0,"X":201.991959,"Y":278.991943}]},{"StartTime":124468.0,"Objects":[{"StartTime":124468.0,"EndTime":124468.0,"X":206.0,"Y":283.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":124543.0,"EndTime":124543.0,"X":172.017578,"Y":199.66217,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124690.0,"Objects":[{"StartTime":124690.0,"EndTime":124690.0,"X":288.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":124765.0,"EndTime":124765.0,"X":305.650452,"Y":104.747742,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124912.0,"Objects":[{"StartTime":124912.0,"EndTime":124912.0,"X":358.0,"Y":14.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125098.0,"EndTime":125098.0,"X":464.55777,"Y":99.8785,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125246.0,"Objects":[{"StartTime":125246.0,"EndTime":125246.0,"X":363.0,"Y":246.0}]},{"StartTime":125357.0,"Objects":[{"StartTime":125357.0,"EndTime":125357.0,"X":288.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125432.0,"EndTime":125432.0,"X":360.534882,"Y":151.889328,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125579.0,"Objects":[{"StartTime":125579.0,"EndTime":125579.0,"X":477.0,"Y":281.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125654.0,"EndTime":125654.0,"X":458.6441,"Y":369.108246,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125801.0,"Objects":[{"StartTime":125801.0,"EndTime":125801.0,"X":224.0,"Y":50.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125987.0,"EndTime":125987.0,"X":287.6426,"Y":192.975677,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":126134.0,"Objects":[{"StartTime":126134.0,"EndTime":126134.0,"X":216.0,"Y":266.0}]},{"StartTime":126246.0,"Objects":[{"StartTime":126246.0,"EndTime":126246.0,"X":261.0,"Y":353.0}]},{"StartTime":126468.0,"Objects":[{"StartTime":126468.0,"EndTime":126468.0,"X":158.0,"Y":188.0}]},{"StartTime":126579.0,"Objects":[{"StartTime":126579.0,"EndTime":126579.0,"X":105.0,"Y":268.0}]},{"StartTime":126690.0,"Objects":[{"StartTime":126690.0,"EndTime":126690.0,"X":147.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":126765.0,"EndTime":126765.0,"X":236.8718,"Y":359.8023,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":126912.0,"Objects":[{"StartTime":126912.0,"EndTime":126912.0,"X":305.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":126987.0,"EndTime":126987.0,"X":215.1282,"Y":265.1977,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":127134.0,"Objects":[{"StartTime":127134.0,"EndTime":127134.0,"X":71.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":127320.0,"EndTime":127320.0,"X":39.2628021,"Y":188.96315,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":127468.0,"Objects":[{"StartTime":127468.0,"EndTime":127468.0,"X":145.0,"Y":172.0}]},{"StartTime":127579.0,"Objects":[{"StartTime":127579.0,"EndTime":127579.0,"X":105.0,"Y":268.0}]},{"StartTime":127801.0,"Objects":[{"StartTime":127801.0,"EndTime":127801.0,"X":167.0,"Y":76.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":127876.0,"EndTime":127876.0,"X":228.04187,"Y":133.115982,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":128023.0,"Objects":[{"StartTime":128023.0,"EndTime":128023.0,"X":210.0,"Y":346.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":128098.0,"EndTime":128098.0,"X":214.49173,"Y":264.965332,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":128246.0,"Objects":[{"StartTime":128246.0,"EndTime":128246.0,"X":493.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":128432.0,"EndTime":128432.0,"X":316.4311,"Y":212.7431,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":128690.0,"Objects":[{"StartTime":128690.0,"EndTime":128690.0,"X":404.0,"Y":107.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":128765.0,"EndTime":128765.0,"X":470.7821,"Y":102.797379,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":128912.0,"Objects":[{"StartTime":128912.0,"EndTime":128912.0,"X":332.0,"Y":362.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":129098.0,"EndTime":129098.0,"X":315.634277,"Y":212.514771,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":129246.0,"Objects":[{"StartTime":129246.0,"EndTime":129246.0,"X":118.0,"Y":206.0}]},{"StartTime":129357.0,"Objects":[{"StartTime":129357.0,"EndTime":129357.0,"X":185.0,"Y":135.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":129432.0,"EndTime":129432.0,"X":210.139664,"Y":221.417572,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":129579.0,"Objects":[{"StartTime":129579.0,"EndTime":129579.0,"X":381.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":129654.0,"EndTime":129654.0,"X":298.13324,"Y":97.3488159,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":129801.0,"Objects":[{"StartTime":129801.0,"EndTime":129801.0,"X":130.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":129876.0,"EndTime":129876.0,"X":86.73138,"Y":121.130447,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130023.0,"Objects":[{"StartTime":130023.0,"EndTime":130023.0,"X":363.0,"Y":274.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130098.0,"EndTime":130098.0,"X":317.3323,"Y":210.8698,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130246.0,"Objects":[{"StartTime":130246.0,"EndTime":130246.0,"X":121.0,"Y":364.0}]},{"StartTime":130468.0,"Objects":[{"StartTime":130468.0,"EndTime":130468.0,"X":199.0,"Y":178.0}]},{"StartTime":130690.0,"Objects":[{"StartTime":130690.0,"EndTime":130690.0,"X":71.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130987.0,"EndTime":130987.0,"X":237.43425,"Y":296.5649,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":131134.0,"Objects":[{"StartTime":131134.0,"EndTime":131134.0,"X":350.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":131209.0,"EndTime":131209.0,"X":351.217255,"Y":306.720581,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":131357.0,"Objects":[{"StartTime":131357.0,"EndTime":131357.0,"X":512.0,"Y":189.0}]},{"StartTime":131468.0,"Objects":[{"StartTime":131468.0,"EndTime":131468.0,"X":418.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":131543.0,"EndTime":131543.0,"X":418.495758,"Y":222.902069,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":131690.0,"Objects":[{"StartTime":131690.0,"EndTime":131690.0,"X":258.0,"Y":98.0}]},{"StartTime":131801.0,"Objects":[{"StartTime":131801.0,"EndTime":131801.0,"X":322.0,"Y":184.0}]},{"StartTime":131912.0,"Objects":[{"StartTime":131912.0,"EndTime":131912.0,"X":259.0,"Y":270.0}]},{"StartTime":132023.0,"Objects":[{"StartTime":132023.0,"EndTime":132023.0,"X":197.0,"Y":184.0}]},{"StartTime":132468.0,"Objects":[{"StartTime":132468.0,"EndTime":132468.0,"X":400.0,"Y":134.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":132543.0,"EndTime":132543.0,"X":405.635132,"Y":210.747955,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":132690.0,"Objects":[{"StartTime":132690.0,"EndTime":132690.0,"X":110.0,"Y":214.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":132765.0,"EndTime":132765.0,"X":104.364876,"Y":137.252045,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":132912.0,"Objects":[{"StartTime":132912.0,"EndTime":132912.0,"X":259.0,"Y":270.0}]},{"StartTime":133134.0,"Objects":[{"StartTime":133134.0,"EndTime":133134.0,"X":191.991959,"Y":48.99196}]},{"StartTime":133246.0,"Objects":[{"StartTime":133246.0,"EndTime":133246.0,"X":196.0,"Y":53.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":133321.0,"EndTime":133321.0,"X":197.738525,"Y":129.95166,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":133468.0,"Objects":[{"StartTime":133468.0,"EndTime":133468.0,"X":313.991943,"Y":46.99196}]},{"StartTime":133580.0,"Objects":[{"StartTime":133580.0,"EndTime":133580.0,"X":318.0,"Y":51.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":133655.0,"EndTime":133655.0,"X":316.261475,"Y":127.95166,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":133801.0,"Objects":[{"StartTime":133801.0,"EndTime":133801.0,"X":259.0,"Y":270.0}]},{"StartTime":134246.0,"Objects":[{"StartTime":134246.0,"EndTime":134246.0,"X":259.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":134321.0,"EndTime":134321.0,"X":255.945129,"Y":347.246368,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":134468.0,"Objects":[{"StartTime":134468.0,"EndTime":134468.0,"X":45.0,"Y":203.0}]},{"StartTime":134579.0,"Objects":[{"StartTime":134579.0,"EndTime":134579.0,"X":78.0,"Y":202.0}]},{"StartTime":134690.0,"Objects":[{"StartTime":134690.0,"EndTime":134690.0,"X":166.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":134765.0,"EndTime":134765.0,"X":169.054871,"Y":173.753632,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":134912.0,"Objects":[{"StartTime":134912.0,"EndTime":134912.0,"X":85.0,"Y":27.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":134987.0,"EndTime":134987.0,"X":88.07755,"Y":104.19873,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":135134.0,"Objects":[{"StartTime":135134.0,"EndTime":135134.0,"X":0.0,"Y":226.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":135209.0,"EndTime":135209.0,"X":77.76112,"Y":202.808533,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":135357.0,"Objects":[{"StartTime":135357.0,"EndTime":135357.0,"X":266.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":135432.0,"EndTime":135432.0,"X":188.238876,"Y":68.80853,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":135579.0,"Objects":[{"StartTime":135579.0,"EndTime":135579.0,"X":130.0,"Y":373.0}]},{"StartTime":135690.0,"Objects":[{"StartTime":135690.0,"EndTime":135690.0,"X":108.0,"Y":310.0}]},{"StartTime":135801.0,"Objects":[{"StartTime":135801.0,"EndTime":135801.0,"X":159.0,"Y":262.0}]},{"StartTime":135912.0,"Objects":[{"StartTime":135912.0,"EndTime":135912.0,"X":250.0,"Y":304.0}]},{"StartTime":136023.0,"Objects":[{"StartTime":136023.0,"EndTime":136023.0,"X":341.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":136098.0,"EndTime":136098.0,"X":339.675476,"Y":173.298676,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":136246.0,"Objects":[{"StartTime":136246.0,"EndTime":136246.0,"X":442.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":136321.0,"EndTime":136321.0,"X":391.297943,"Y":58.8912926,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":136468.0,"Objects":[{"StartTime":136468.0,"EndTime":136468.0,"X":250.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":136543.0,"EndTime":136543.0,"X":255.012466,"Y":103.347588,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":136690.0,"Objects":[{"StartTime":136690.0,"EndTime":136690.0,"X":107.0,"Y":212.0}]},{"StartTime":136801.0,"Objects":[{"StartTime":136801.0,"EndTime":136801.0,"X":23.0,"Y":181.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":136987.0,"EndTime":136987.0,"X":154.333725,"Y":133.844666,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":137134.0,"Objects":[{"StartTime":137134.0,"EndTime":137134.0,"X":229.0,"Y":189.0}]},{"StartTime":137246.0,"Objects":[{"StartTime":137246.0,"EndTime":137246.0,"X":224.0,"Y":287.0}]},{"StartTime":137357.0,"Objects":[{"StartTime":137357.0,"EndTime":137357.0,"X":220.0,"Y":384.0}]},{"StartTime":137579.0,"Objects":[{"StartTime":137579.0,"EndTime":137579.0,"X":220.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":137654.0,"EndTime":137654.0,"X":286.980377,"Y":346.6252,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":137801.0,"Objects":[{"StartTime":137801.0,"EndTime":137801.0,"X":505.0,"Y":241.0}]},{"StartTime":137912.0,"Objects":[{"StartTime":137912.0,"EndTime":137912.0,"X":442.0,"Y":269.0}]},{"StartTime":138023.0,"Objects":[{"StartTime":138023.0,"EndTime":138023.0,"X":382.0,"Y":242.0}]},{"StartTime":138134.0,"Objects":[{"StartTime":138134.0,"EndTime":138134.0,"X":307.0,"Y":183.0}]},{"StartTime":138246.0,"Objects":[{"StartTime":138246.0,"EndTime":138246.0,"X":222.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":138432.0,"EndTime":138432.0,"X":71.38295,"Y":275.653046,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":138579.0,"Objects":[{"StartTime":138579.0,"EndTime":138579.0,"X":71.0,"Y":171.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":138765.0,"EndTime":138765.0,"X":221.926514,"Y":223.005737,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":138912.0,"Objects":[{"StartTime":138912.0,"EndTime":138912.0,"X":343.0,"Y":94.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":138987.0,"EndTime":138987.0,"X":260.5,"Y":94.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":139134.0,"Objects":[{"StartTime":139134.0,"EndTime":139134.0,"X":134.0,"Y":26.0}]},{"StartTime":139357.0,"Objects":[{"StartTime":139357.0,"EndTime":139357.0,"X":134.0,"Y":26.0}]},{"StartTime":139468.0,"Objects":[{"StartTime":139468.0,"EndTime":139468.0,"X":104.0,"Y":77.0}]},{"StartTime":139579.0,"Objects":[{"StartTime":139579.0,"EndTime":139579.0,"X":129.0,"Y":129.0}]},{"StartTime":139690.0,"Objects":[{"StartTime":139690.0,"EndTime":139690.0,"X":188.0,"Y":207.0}]},{"StartTime":139801.0,"Objects":[{"StartTime":139801.0,"EndTime":139801.0,"X":114.0,"Y":291.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":139876.0,"EndTime":139876.0,"X":99.4008255,"Y":215.296585,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":140023.0,"Objects":[{"StartTime":140023.0,"EndTime":140023.0,"X":216.0,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":140098.0,"EndTime":140098.0,"X":298.5,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":140246.0,"Objects":[{"StartTime":140246.0,"EndTime":140246.0,"X":432.0,"Y":90.0}]},{"StartTime":140357.0,"Objects":[{"StartTime":140357.0,"EndTime":140357.0,"X":347.0,"Y":152.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":140543.0,"EndTime":140543.0,"X":357.324921,"Y":10.7098618,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":140690.0,"Objects":[{"StartTime":140690.0,"EndTime":140690.0,"X":512.0,"Y":253.0}]},{"StartTime":140801.0,"Objects":[{"StartTime":140801.0,"EndTime":140801.0,"X":441.0,"Y":179.0}]},{"StartTime":140912.0,"Objects":[{"StartTime":140912.0,"EndTime":140912.0,"X":376.0,"Y":255.0}]},{"StartTime":141357.0,"Objects":[{"StartTime":141357.0,"EndTime":141357.0,"X":376.0,"Y":255.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":141432.0,"EndTime":141432.0,"X":382.0538,"Y":332.489,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":141579.0,"Objects":[{"StartTime":141579.0,"EndTime":141579.0,"X":245.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":141654.0,"EndTime":141654.0,"X":250.6925,"Y":141.435944,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":141801.0,"Objects":[{"StartTime":141801.0,"EndTime":141801.0,"X":179.0,"Y":302.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":141876.0,"EndTime":141876.0,"X":141.112991,"Y":232.186615,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":142023.0,"Objects":[{"StartTime":142023.0,"EndTime":142023.0,"X":368.0,"Y":164.0}]},{"StartTime":142134.0,"Objects":[{"StartTime":142134.0,"EndTime":142134.0,"X":342.0,"Y":166.0}]},{"StartTime":142246.0,"Objects":[{"StartTime":142246.0,"EndTime":142246.0,"X":177.0,"Y":98.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":142321.0,"EndTime":142321.0,"X":259.205322,"Y":91.03345,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":142468.0,"Objects":[{"StartTime":142468.0,"EndTime":142468.0,"X":341.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":142543.0,"EndTime":142543.0,"X":361.5398,"Y":72.01209,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":142690.0,"Objects":[{"StartTime":142690.0,"EndTime":142690.0,"X":245.0,"Y":219.0}]},{"StartTime":142912.0,"Objects":[{"StartTime":142912.0,"EndTime":142912.0,"X":456.991943,"Y":107.991959}]},{"StartTime":143023.0,"Objects":[{"StartTime":143023.0,"EndTime":143023.0,"X":461.0,"Y":112.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":143098.0,"EndTime":143098.0,"X":455.83255,"Y":188.940552,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":143246.0,"Objects":[{"StartTime":143246.0,"EndTime":143246.0,"X":368.0,"Y":371.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":143321.0,"EndTime":143321.0,"X":361.7833,"Y":293.69873,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":143468.0,"Objects":[{"StartTime":143468.0,"EndTime":143468.0,"X":192.0,"Y":166.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":143654.0,"EndTime":143654.0,"X":331.016968,"Y":191.846024,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":143801.0,"Objects":[{"StartTime":143801.0,"EndTime":143801.0,"X":315.0,"Y":32.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":143876.0,"EndTime":143876.0,"X":274.3848,"Y":93.43054,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":144023.0,"Objects":[{"StartTime":144023.0,"EndTime":144023.0,"X":268.0,"Y":351.0}]},{"StartTime":144134.0,"Objects":[{"StartTime":144134.0,"EndTime":144134.0,"X":282.0,"Y":287.0}]},{"StartTime":144246.0,"Objects":[{"StartTime":144246.0,"EndTime":144246.0,"X":230.0,"Y":251.0}]},{"StartTime":144357.0,"Objects":[{"StartTime":144357.0,"EndTime":144357.0,"X":138.0,"Y":305.0}]},{"StartTime":144468.0,"Objects":[{"StartTime":144468.0,"EndTime":144468.0,"X":59.0,"Y":249.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":144543.0,"EndTime":144543.0,"X":56.647377,"Y":173.0617,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":144690.0,"Objects":[{"StartTime":144690.0,"EndTime":144690.0,"X":144.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":144765.0,"EndTime":144765.0,"X":146.352631,"Y":203.9383,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":144912.0,"Objects":[{"StartTime":144912.0,"EndTime":144912.0,"X":18.0,"Y":81.0}]},{"StartTime":145023.0,"Objects":[{"StartTime":145023.0,"EndTime":145023.0,"X":69.0,"Y":1.0}]},{"StartTime":145134.0,"Objects":[{"StartTime":145134.0,"EndTime":145134.0,"X":172.0,"Y":11.0}]},{"StartTime":145246.0,"Objects":[{"StartTime":145246.0,"EndTime":145246.0,"X":231.0,"Y":98.0}]},{"StartTime":145357.0,"Objects":[{"StartTime":145357.0,"EndTime":145357.0,"X":303.0,"Y":28.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":145432.0,"EndTime":145432.0,"X":374.9048,"Y":-0.0191259384,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":145579.0,"Objects":[{"StartTime":145579.0,"EndTime":145579.0,"X":384.0,"Y":220.0}]},{"StartTime":145690.0,"Objects":[{"StartTime":145690.0,"EndTime":145690.0,"X":285.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":145765.0,"EndTime":145765.0,"X":336.018738,"Y":135.212479,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":145912.0,"Objects":[{"StartTime":145912.0,"EndTime":145912.0,"X":507.0,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":145987.0,"EndTime":145987.0,"X":442.2237,"Y":76.94097,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":146134.0,"Objects":[{"StartTime":146134.0,"EndTime":146134.0,"X":504.991943,"Y":238.991959}]},{"StartTime":146246.0,"Objects":[{"StartTime":146246.0,"EndTime":146246.0,"X":509.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":146321.0,"EndTime":146321.0,"X":447.662445,"Y":200.745743,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":146468.0,"Objects":[{"StartTime":146468.0,"EndTime":146468.0,"X":270.0,"Y":374.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":146543.0,"EndTime":146543.0,"X":286.513733,"Y":293.169647,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":146690.0,"Objects":[{"StartTime":146690.0,"EndTime":146690.0,"X":168.0,"Y":143.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":146765.0,"EndTime":146765.0,"X":184.513733,"Y":223.830353,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":146912.0,"Objects":[{"StartTime":146912.0,"EndTime":146912.0,"X":401.0,"Y":283.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":146987.0,"EndTime":146987.0,"X":365.557617,"Y":213.172012,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":147134.0,"Objects":[{"StartTime":147134.0,"EndTime":147134.0,"X":50.0,"Y":214.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":147320.0,"EndTime":147320.0,"X":183.730637,"Y":223.72197,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":147468.0,"Objects":[{"StartTime":147468.0,"EndTime":147468.0,"X":306.0,"Y":64.0}]},{"StartTime":147579.0,"Objects":[{"StartTime":147579.0,"EndTime":147579.0,"X":204.0,"Y":48.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":147690.0,"EndTime":147690.0,"X":220.76535,"Y":128.778534,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":147765.0,"EndTime":147765.0,"X":204.0,"Y":48.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":147912.0,"Objects":[{"StartTime":147912.0,"EndTime":147912.0,"X":360.0,"Y":154.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148098.0,"EndTime":148098.0,"X":345.995636,"Y":303.007568,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":148246.0,"Objects":[{"StartTime":148246.0,"EndTime":148246.0,"X":208.0,"Y":368.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148321.0,"EndTime":148321.0,"X":230.968475,"Y":316.226654,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":148468.0,"Objects":[{"StartTime":148468.0,"EndTime":148468.0,"X":106.0,"Y":264.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148543.0,"EndTime":148543.0,"X":169.758072,"Y":216.935791,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":148690.0,"Objects":[{"StartTime":148690.0,"EndTime":148690.0,"X":399.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148765.0,"EndTime":148765.0,"X":323.475,"Y":223.086472,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":148912.0,"Objects":[{"StartTime":148912.0,"EndTime":148912.0,"X":126.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148987.0,"EndTime":148987.0,"X":203.621765,"Y":125.594574,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149134.0,"Objects":[{"StartTime":149134.0,"EndTime":149134.0,"X":249.0,"Y":36.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":149209.0,"EndTime":149209.0,"X":300.844055,"Y":95.0325,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149357.0,"Objects":[{"StartTime":149357.0,"EndTime":149357.0,"X":388.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":149432.0,"EndTime":149432.0,"X":460.192932,"Y":248.763474,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149579.0,"Objects":[{"StartTime":149579.0,"EndTime":149579.0,"X":390.0,"Y":178.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":149654.0,"EndTime":149654.0,"X":411.7897,"Y":103.093239,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149801.0,"Objects":[{"StartTime":149801.0,"EndTime":149801.0,"X":272.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":149876.0,"EndTime":149876.0,"X":278.945923,"Y":361.0271,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":150023.0,"Objects":[{"StartTime":150023.0,"EndTime":150023.0,"X":161.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":150098.0,"EndTime":150098.0,"X":166.382416,"Y":195.049881,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":150246.0,"Objects":[{"StartTime":150246.0,"EndTime":150246.0,"X":390.0,"Y":178.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":150321.0,"EndTime":150321.0,"X":307.832764,"Y":185.402451,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":150468.0,"Objects":[{"StartTime":150468.0,"EndTime":150468.0,"X":55.0,"Y":95.0}]},{"StartTime":150579.0,"Objects":[{"StartTime":150579.0,"EndTime":150579.0,"X":20.0,"Y":98.0}]},{"StartTime":150690.0,"Objects":[{"StartTime":150690.0,"EndTime":150690.0,"X":119.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":150876.0,"EndTime":150876.0,"X":229.438019,"Y":88.46765,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":151023.0,"Objects":[{"StartTime":151023.0,"EndTime":151023.0,"X":68.0,"Y":214.0}]},{"StartTime":151134.0,"Objects":[{"StartTime":151134.0,"EndTime":151134.0,"X":170.0,"Y":229.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":151209.0,"EndTime":151209.0,"X":147.563553,"Y":149.609467,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":151357.0,"Objects":[{"StartTime":151357.0,"EndTime":151357.0,"X":263.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":151432.0,"EndTime":151432.0,"X":239.9385,"Y":365.211243,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":151579.0,"Objects":[{"StartTime":151579.0,"EndTime":151579.0,"X":94.0,"Y":322.0}]},{"StartTime":151801.0,"Objects":[{"StartTime":151801.0,"EndTime":151801.0,"X":394.0,"Y":216.0}]},{"StartTime":152023.0,"Objects":[{"StartTime":152023.0,"EndTime":152023.0,"X":370.0,"Y":57.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":152320.0,"EndTime":152320.0,"X":253.870209,"Y":172.60585,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":152468.0,"Objects":[{"StartTime":152468.0,"EndTime":152468.0,"X":317.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":152654.0,"EndTime":152654.0,"X":158.693573,"Y":141.477356,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":152912.0,"Objects":[{"StartTime":152912.0,"EndTime":152912.0,"X":8.0,"Y":52.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":152987.0,"EndTime":152987.0,"X":41.25625,"Y":44.6429024,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":153134.0,"Objects":[{"StartTime":153134.0,"EndTime":153134.0,"X":317.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":153320.0,"EndTime":153320.0,"X":158.693573,"Y":141.477356,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":153579.0,"Objects":[{"StartTime":153579.0,"EndTime":153579.0,"X":71.0,"Y":190.0}]},{"StartTime":153690.0,"Objects":[{"StartTime":153690.0,"EndTime":153690.0,"X":38.0,"Y":191.0}]},{"StartTime":153801.0,"Objects":[{"StartTime":153801.0,"EndTime":153801.0,"X":158.0,"Y":141.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":153876.0,"EndTime":153876.0,"X":168.284653,"Y":218.124176,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":154023.0,"Objects":[{"StartTime":154023.0,"EndTime":154023.0,"X":93.0,"Y":372.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":154098.0,"EndTime":154098.0,"X":82.7153549,"Y":294.875824,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":154246.0,"Objects":[{"StartTime":154246.0,"EndTime":154246.0,"X":255.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":154432.0,"EndTime":154432.0,"X":284.45993,"Y":213.542831,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":154690.0,"Objects":[{"StartTime":154690.0,"EndTime":154690.0,"X":202.0,"Y":347.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":154765.0,"EndTime":154765.0,"X":212.29007,"Y":315.725861,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":154912.0,"Objects":[{"StartTime":154912.0,"EndTime":154912.0,"X":255.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":155098.0,"EndTime":155098.0,"X":284.45993,"Y":213.542831,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":155357.0,"Objects":[{"StartTime":155357.0,"EndTime":155357.0,"X":488.0,"Y":313.0}]},{"StartTime":155468.0,"Objects":[{"StartTime":155468.0,"EndTime":155468.0,"X":454.0,"Y":314.0}]},{"StartTime":155579.0,"Objects":[{"StartTime":155579.0,"EndTime":155579.0,"X":367.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":155654.0,"EndTime":155654.0,"X":364.4232,"Y":278.617371,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":155801.0,"Objects":[{"StartTime":155801.0,"EndTime":155801.0,"X":503.0,"Y":146.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":155876.0,"EndTime":155876.0,"X":445.314484,"Y":195.759918,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":156023.0,"Objects":[{"StartTime":156023.0,"EndTime":156023.0,"X":220.0,"Y":123.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":156209.0,"EndTime":156209.0,"X":289.916,"Y":201.523849,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":156357.0,"Objects":[{"StartTime":156357.0,"EndTime":156357.0,"X":111.0,"Y":158.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":156543.0,"EndTime":156543.0,"X":142.369736,"Y":56.6978226,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":156690.0,"Objects":[{"StartTime":156690.0,"EndTime":156690.0,"X":186.0,"Y":229.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":156765.0,"EndTime":156765.0,"X":135.32048,"Y":252.494751,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":156912.0,"Objects":[{"StartTime":156912.0,"EndTime":156912.0,"X":220.0,"Y":123.0}]},{"StartTime":157060.0,"Objects":[{"StartTime":157060.0,"EndTime":157060.0,"X":186.0,"Y":229.0}]},{"StartTime":157209.0,"Objects":[{"StartTime":157209.0,"EndTime":157209.0,"X":111.0,"Y":158.0}]},{"StartTime":157357.0,"Objects":[{"StartTime":157357.0,"EndTime":157357.0,"X":288.0,"Y":199.0}]},{"StartTime":157505.0,"Objects":[{"StartTime":157505.0,"EndTime":157505.0,"X":94.0,"Y":258.0}]},{"StartTime":157653.0,"Objects":[{"StartTime":157653.0,"EndTime":157653.0,"X":144.0,"Y":56.0}]},{"StartTime":157801.0,"Objects":[{"StartTime":157801.0,"EndTime":157801.0,"X":150.0,"Y":383.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":157987.0,"EndTime":157987.0,"X":236.781082,"Y":319.1922,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":158246.0,"Objects":[{"StartTime":158246.0,"EndTime":158246.0,"X":359.0,"Y":145.0}]},{"StartTime":158468.0,"Objects":[{"StartTime":158468.0,"EndTime":158468.0,"X":270.0,"Y":182.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":158654.0,"EndTime":158654.0,"X":369.479736,"Y":249.689819,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":158912.0,"Objects":[{"StartTime":158912.0,"EndTime":158912.0,"X":359.0,"Y":145.0}]},{"StartTime":159134.0,"Objects":[{"StartTime":159134.0,"EndTime":159134.0,"X":236.0,"Y":319.0}]},{"StartTime":159357.0,"Objects":[{"StartTime":159357.0,"EndTime":159357.0,"X":460.0,"Y":160.0}]},{"StartTime":159579.0,"Objects":[{"StartTime":159579.0,"EndTime":159579.0,"X":233.0,"Y":22.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":159912.0,"EndTime":159912.0,"X":268.943939,"Y":181.561172,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":160209.0,"EndTime":160209.0,"X":233.0,"Y":22.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":160468.0,"Objects":[{"StartTime":160468.0,"EndTime":160468.0,"X":454.0,"Y":29.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":160654.0,"EndTime":160654.0,"X":345.565582,"Y":31.0499535,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":160912.0,"Objects":[{"StartTime":160912.0,"EndTime":160912.0,"X":173.0,"Y":216.0}]},{"StartTime":161134.0,"Objects":[{"StartTime":161134.0,"EndTime":161134.0,"X":424.983917,"Y":195.983917}]},{"StartTime":161246.0,"Objects":[{"StartTime":161246.0,"EndTime":161246.0,"X":428.991943,"Y":199.991959}]},{"StartTime":161357.0,"Objects":[{"StartTime":161357.0,"EndTime":161357.0,"X":433.0,"Y":204.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":161765.0,"EndTime":161765.0,"X":269.099426,"Y":180.445,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":162023.0,"Objects":[{"StartTime":162023.0,"EndTime":162023.0,"X":268.0,"Y":79.0}]},{"StartTime":162246.0,"Objects":[{"StartTime":162246.0,"EndTime":162246.0,"X":344.0,"Y":362.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":162432.0,"EndTime":162432.0,"X":293.673523,"Y":285.970734,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":162690.0,"Objects":[{"StartTime":162690.0,"EndTime":162690.0,"X":159.0,"Y":224.0}]},{"StartTime":162912.0,"Objects":[{"StartTime":162912.0,"EndTime":162912.0,"X":316.0,"Y":154.0}]},{"StartTime":163134.0,"Objects":[{"StartTime":163134.0,"EndTime":163134.0,"X":213.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":163467.0,"EndTime":163467.0,"X":205.7877,"Y":92.723114,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":163764.0,"EndTime":163764.0,"X":213.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":164023.0,"Objects":[{"StartTime":164023.0,"EndTime":164023.0,"X":337.0,"Y":271.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":164209.0,"EndTime":164209.0,"X":298.85553,"Y":168.804764,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":164468.0,"Objects":[{"StartTime":164468.0,"EndTime":164468.0,"X":99.0,"Y":334.0}]},{"StartTime":164579.0,"Objects":[{"StartTime":164579.0,"EndTime":164579.0,"X":133.0,"Y":332.0}]},{"StartTime":164690.0,"Objects":[{"StartTime":164690.0,"EndTime":164690.0,"X":166.0,"Y":329.0}]},{"StartTime":164801.0,"Objects":[{"StartTime":164801.0,"EndTime":164801.0,"X":200.0,"Y":326.0}]},{"StartTime":164912.0,"Objects":[{"StartTime":164912.0,"EndTime":164912.0,"X":234.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":165098.0,"EndTime":165098.0,"X":130.22879,"Y":254.891266,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":165357.0,"Objects":[{"StartTime":165357.0,"EndTime":165357.0,"X":67.0,"Y":174.0}]},{"StartTime":165579.0,"Objects":[{"StartTime":165579.0,"EndTime":165579.0,"X":234.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":165765.0,"EndTime":165765.0,"X":227.521072,"Y":127.2661,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166023.0,"Objects":[{"StartTime":166023.0,"EndTime":166023.0,"X":391.0,"Y":159.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":166098.0,"EndTime":166098.0,"X":323.841736,"Y":165.783661,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166246.0,"Objects":[{"StartTime":166246.0,"EndTime":166246.0,"X":253.0,"Y":28.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":166321.0,"EndTime":166321.0,"X":305.653931,"Y":61.37197,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166468.0,"Objects":[{"StartTime":166468.0,"EndTime":166468.0,"X":209.0,"Y":188.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":166543.0,"EndTime":166543.0,"X":226.751892,"Y":127.185547,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166690.0,"Objects":[{"StartTime":166690.0,"EndTime":166690.0,"X":444.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":167023.0,"EndTime":167023.0,"X":283.719574,"Y":276.808929,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":167320.0,"EndTime":167320.0,"X":444.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":167579.0,"Objects":[{"StartTime":167579.0,"EndTime":167579.0,"X":216.0,"Y":360.0}]},{"StartTime":167801.0,"Objects":[{"StartTime":167801.0,"EndTime":167801.0,"X":177.0,"Y":264.0}]},{"StartTime":168023.0,"Objects":[{"StartTime":168023.0,"EndTime":168023.0,"X":312.0,"Y":162.0}]},{"StartTime":168134.0,"Objects":[{"StartTime":168134.0,"EndTime":168134.0,"X":266.0,"Y":190.0}]},{"StartTime":168245.0,"Objects":[{"StartTime":168245.0,"EndTime":168245.0,"X":218.0,"Y":166.0}]},{"StartTime":168356.0,"Objects":[{"StartTime":168356.0,"EndTime":168356.0,"X":213.0,"Y":112.0}]},{"StartTime":168468.0,"Objects":[{"StartTime":168468.0,"EndTime":168468.0,"X":287.0,"Y":65.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":168876.0,"EndTime":168876.0,"X":167.100861,"Y":18.7974186,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":169134.0,"Objects":[{"StartTime":169134.0,"EndTime":169134.0,"X":0.0,"Y":205.0}]},{"StartTime":169357.0,"Objects":[{"StartTime":169357.0,"EndTime":169357.0,"X":54.0,"Y":125.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":169543.0,"EndTime":169543.0,"X":88.6647,"Y":218.9704,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":169801.0,"Objects":[{"StartTime":169801.0,"EndTime":169801.0,"X":254.0,"Y":281.0}]},{"StartTime":170023.0,"Objects":[{"StartTime":170023.0,"EndTime":170023.0,"X":192.0,"Y":190.0}]},{"StartTime":170246.0,"Objects":[{"StartTime":170246.0,"EndTime":170246.0,"X":0.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":170579.0,"EndTime":170579.0,"X":149.732025,"Y":293.5072,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":170876.0,"EndTime":170876.0,"X":0.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":171134.0,"Objects":[{"StartTime":171134.0,"EndTime":171134.0,"X":0.0,"Y":355.0}]},{"StartTime":171357.0,"Objects":[{"StartTime":171357.0,"EndTime":171357.0,"X":219.0,"Y":363.0}]},{"StartTime":171579.0,"Objects":[{"StartTime":171579.0,"EndTime":171579.0,"X":120.0,"Y":195.0}]},{"StartTime":171690.0,"Objects":[{"StartTime":171690.0,"EndTime":171690.0,"X":153.0,"Y":196.0}]},{"StartTime":171801.0,"Objects":[{"StartTime":171801.0,"EndTime":171801.0,"X":187.0,"Y":198.0}]},{"StartTime":171912.0,"Objects":[{"StartTime":171912.0,"EndTime":171912.0,"X":221.0,"Y":200.0}]},{"StartTime":172023.0,"Objects":[{"StartTime":172023.0,"EndTime":172023.0,"X":297.0,"Y":155.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":172209.0,"EndTime":172209.0,"X":286.743378,"Y":280.805,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":172357.0,"Objects":[{"StartTime":172357.0,"EndTime":172357.0,"X":450.991943,"Y":233.991959}]},{"StartTime":172468.0,"Objects":[{"StartTime":172468.0,"EndTime":172468.0,"X":455.0,"Y":238.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":172543.0,"EndTime":172543.0,"X":388.201447,"Y":228.29422,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":172690.0,"Objects":[{"StartTime":172690.0,"EndTime":172690.0,"X":307.0,"Y":52.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":172876.0,"EndTime":172876.0,"X":399.912659,"Y":120.163414,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":173134.0,"Objects":[{"StartTime":173134.0,"EndTime":173134.0,"X":182.0,"Y":98.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":173209.0,"EndTime":173209.0,"X":170.090744,"Y":31.5588989,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":173357.0,"Objects":[{"StartTime":173357.0,"EndTime":173357.0,"X":281.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":173432.0,"EndTime":173432.0,"X":268.925232,"Y":228.411224,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":173579.0,"Objects":[{"StartTime":173579.0,"EndTime":173579.0,"X":36.9839172,"Y":287.983917}]},{"StartTime":173690.0,"Objects":[{"StartTime":173690.0,"EndTime":173690.0,"X":40.99196,"Y":291.991943}]},{"StartTime":173801.0,"Objects":[{"StartTime":173801.0,"EndTime":173801.0,"X":45.0,"Y":296.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":173987.0,"EndTime":173987.0,"X":129.058121,"Y":220.794525,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":174134.0,"Objects":[{"StartTime":174134.0,"EndTime":174134.0,"X":217.991959,"Y":361.991943}]},{"StartTime":174246.0,"Objects":[{"StartTime":174246.0,"EndTime":174246.0,"X":222.0,"Y":366.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":174321.0,"EndTime":174321.0,"X":198.07811,"Y":307.061584,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":174468.0,"Objects":[{"StartTime":174468.0,"EndTime":174468.0,"X":287.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":174543.0,"EndTime":174543.0,"X":326.644043,"Y":204.022247,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":174690.0,"Objects":[{"StartTime":174690.0,"EndTime":174690.0,"X":506.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":174876.0,"EndTime":174876.0,"X":386.5124,"Y":106.955444,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":175023.0,"Objects":[{"StartTime":175023.0,"EndTime":175023.0,"X":224.991959,"Y":67.99196}]},{"StartTime":175134.0,"Objects":[{"StartTime":175134.0,"EndTime":175134.0,"X":229.0,"Y":72.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":175209.0,"EndTime":175209.0,"X":243.306,"Y":137.966568,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":175357.0,"Objects":[{"StartTime":175357.0,"EndTime":175357.0,"X":312.0,"Y":269.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":175432.0,"EndTime":175432.0,"X":326.306,"Y":203.033432,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":175579.0,"Objects":[{"StartTime":175579.0,"EndTime":175579.0,"X":146.0,"Y":16.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":175765.0,"EndTime":175765.0,"X":139.074585,"Y":137.318375,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":175912.0,"Objects":[{"StartTime":175912.0,"EndTime":175912.0,"X":243.991959,"Y":224.991959}]},{"StartTime":176023.0,"Objects":[{"StartTime":176023.0,"EndTime":176023.0,"X":248.0,"Y":229.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":176098.0,"EndTime":176098.0,"X":180.809891,"Y":222.539413,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":176246.0,"Objects":[{"StartTime":176246.0,"EndTime":176246.0,"X":36.0,"Y":384.0}]},{"StartTime":176357.0,"Objects":[{"StartTime":176357.0,"EndTime":176357.0,"X":20.0,"Y":335.0}]},{"StartTime":176468.0,"Objects":[{"StartTime":176468.0,"EndTime":176468.0,"X":64.0,"Y":300.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":176654.0,"EndTime":176654.0,"X":190.327454,"Y":337.0614,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":176801.0,"Objects":[{"StartTime":176801.0,"EndTime":176801.0,"X":293.991943,"Y":379.991943}]},{"StartTime":176912.0,"Objects":[{"StartTime":176912.0,"EndTime":176912.0,"X":298.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":176987.0,"EndTime":176987.0,"X":300.6823,"Y":322.70462,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":177134.0,"Objects":[{"StartTime":177134.0,"EndTime":177134.0,"X":423.0,"Y":236.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":177209.0,"EndTime":177209.0,"X":419.9614,"Y":297.0566,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":177357.0,"Objects":[{"StartTime":177357.0,"EndTime":177357.0,"X":217.0,"Y":241.0}]},{"StartTime":177579.0,"Objects":[{"StartTime":177579.0,"EndTime":177579.0,"X":300.0,"Y":31.0}]},{"StartTime":177690.0,"Objects":[{"StartTime":177690.0,"EndTime":177690.0,"X":343.0,"Y":86.0}]},{"StartTime":177801.0,"Objects":[{"StartTime":177801.0,"EndTime":177801.0,"X":314.0,"Y":148.0}]},{"StartTime":178023.0,"Objects":[{"StartTime":178023.0,"EndTime":178023.0,"X":74.98392,"Y":70.98392}]},{"StartTime":178134.0,"Objects":[{"StartTime":178134.0,"EndTime":178134.0,"X":78.99196,"Y":74.99196}]},{"StartTime":178246.0,"Objects":[{"StartTime":178246.0,"EndTime":178246.0,"X":83.0,"Y":79.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":178432.0,"EndTime":178432.0,"X":205.811111,"Y":97.7642059,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":178579.0,"Objects":[{"StartTime":178579.0,"EndTime":178579.0,"X":332.991943,"Y":15.9919577}]},{"StartTime":178690.0,"Objects":[{"StartTime":178690.0,"EndTime":178690.0,"X":337.0,"Y":20.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":178765.0,"EndTime":178765.0,"X":318.676453,"Y":84.9653549,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":178912.0,"Objects":[{"StartTime":178912.0,"EndTime":178912.0,"X":214.0,"Y":239.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":178987.0,"EndTime":178987.0,"X":258.598236,"Y":196.108292,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":179134.0,"Objects":[{"StartTime":179134.0,"EndTime":179134.0,"X":435.0,"Y":127.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":179320.0,"EndTime":179320.0,"X":410.495239,"Y":246.099274,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":179468.0,"Objects":[{"StartTime":179468.0,"EndTime":179468.0,"X":470.991943,"Y":351.991943}]},{"StartTime":179579.0,"Objects":[{"StartTime":179579.0,"EndTime":179579.0,"X":475.0,"Y":356.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":179654.0,"EndTime":179654.0,"X":506.7647,"Y":296.441162,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":179801.0,"Objects":[{"StartTime":179801.0,"EndTime":179801.0,"X":278.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":179876.0,"EndTime":179876.0,"X":299.962067,"Y":231.827255,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":180023.0,"Objects":[{"StartTime":180023.0,"EndTime":180023.0,"X":351.0,"Y":348.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":180209.0,"EndTime":180209.0,"X":220.201462,"Y":363.836945,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":180357.0,"Objects":[{"StartTime":180357.0,"EndTime":180357.0,"X":99.99196,"Y":348.991943}]},{"StartTime":180468.0,"Objects":[{"StartTime":180468.0,"EndTime":180468.0,"X":104.0,"Y":353.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":180543.0,"EndTime":180543.0,"X":141.955933,"Y":297.182465,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":180690.0,"Objects":[{"StartTime":180690.0,"EndTime":180690.0,"X":0.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":180765.0,"EndTime":180765.0,"X":47.40831,"Y":267.04895,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":180912.0,"Objects":[{"StartTime":180912.0,"EndTime":180912.0,"X":245.0,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":180987.0,"EndTime":180987.0,"X":223.346817,"Y":212.329941,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":181134.0,"Objects":[{"StartTime":181134.0,"EndTime":181134.0,"X":352.0,"Y":194.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":181209.0,"EndTime":181209.0,"X":323.133057,"Y":136.271255,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":181357.0,"Objects":[{"StartTime":181357.0,"EndTime":181357.0,"X":37.0,"Y":82.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":181432.0,"EndTime":181432.0,"X":72.12841,"Y":135.108,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":181579.0,"Objects":[{"StartTime":181579.0,"EndTime":181579.0,"X":188.0,"Y":19.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":181654.0,"EndTime":181654.0,"X":167.375656,"Y":81.45676,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":181801.0,"Objects":[{"StartTime":181801.0,"EndTime":181801.0,"X":342.0,"Y":220.0}]},{"StartTime":182023.0,"Objects":[{"StartTime":182023.0,"EndTime":182023.0,"X":268.0,"Y":81.0}]},{"StartTime":182246.0,"Objects":[{"StartTime":182246.0,"EndTime":182246.0,"X":158.0,"Y":195.0}]},{"StartTime":182690.0,"Objects":[{"StartTime":182690.0,"EndTime":182690.0,"X":309.0,"Y":231.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":182765.0,"EndTime":182765.0,"X":287.637878,"Y":291.5341,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":182912.0,"Objects":[{"StartTime":182912.0,"EndTime":182912.0,"X":388.0,"Y":302.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":182987.0,"EndTime":182987.0,"X":396.8215,"Y":376.820435,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":183134.0,"Objects":[{"StartTime":183134.0,"EndTime":183134.0,"X":490.0,"Y":52.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":183209.0,"EndTime":183209.0,"X":511.362122,"Y":112.534065,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":183357.0,"Objects":[{"StartTime":183357.0,"EndTime":183357.0,"X":414.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":183432.0,"EndTime":183432.0,"X":403.953461,"Y":195.117416,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":183579.0,"Objects":[{"StartTime":183579.0,"EndTime":183579.0,"X":269.0,"Y":0.0}]},{"StartTime":183690.0,"Objects":[{"StartTime":183690.0,"EndTime":183690.0,"X":320.0,"Y":15.0}]},{"StartTime":183801.0,"Objects":[{"StartTime":183801.0,"EndTime":183801.0,"X":340.0,"Y":64.0}]},{"StartTime":183912.0,"Objects":[{"StartTime":183912.0,"EndTime":183912.0,"X":311.0,"Y":124.0}]},{"StartTime":184023.0,"Objects":[{"StartTime":184023.0,"EndTime":184023.0,"X":225.0,"Y":160.0}]},{"StartTime":184134.0,"Objects":[{"StartTime":184134.0,"EndTime":184134.0,"X":160.0,"Y":95.0}]},{"StartTime":184246.0,"Objects":[{"StartTime":184246.0,"EndTime":184246.0,"X":79.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":184543.0,"EndTime":184543.0,"X":133.33046,"Y":376.409332,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":184690.0,"Objects":[{"StartTime":184690.0,"EndTime":184690.0,"X":137.008041,"Y":380.008057}]},{"StartTime":184912.0,"Objects":[{"StartTime":184912.0,"EndTime":184912.0,"X":169.0,"Y":151.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":185098.0,"EndTime":185098.0,"X":25.66817,"Y":349.460663,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":185357.0,"Objects":[{"StartTime":185357.0,"EndTime":185357.0,"X":26.0,"Y":350.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":185801.0,"EndTime":185801.0,"X":67.54302,"Y":333.1509,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":186098.0,"EndTime":186098.0,"X":100.962524,"Y":328.956482,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":186246.0,"Objects":[{"StartTime":186246.0,"EndTime":186246.0,"X":205.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":186432.0,"EndTime":186432.0,"X":283.367523,"Y":261.024628,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":186579.0,"Objects":[{"StartTime":186579.0,"EndTime":186579.0,"X":410.0,"Y":99.0}]},{"StartTime":186690.0,"Objects":[{"StartTime":186690.0,"EndTime":186690.0,"X":471.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":186765.0,"EndTime":186765.0,"X":380.588684,"Y":194.399445,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":186912.0,"Objects":[{"StartTime":186912.0,"EndTime":186912.0,"X":242.0,"Y":64.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":186987.0,"EndTime":186987.0,"X":288.7081,"Y":142.4731,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":187134.0,"Objects":[{"StartTime":187134.0,"EndTime":187134.0,"X":283.0,"Y":261.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":187320.0,"EndTime":187320.0,"X":104.302727,"Y":321.47583,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":187468.0,"Objects":[{"StartTime":187468.0,"EndTime":187468.0,"X":107.991959,"Y":212.991959}]},{"StartTime":187579.0,"Objects":[{"StartTime":187579.0,"EndTime":187579.0,"X":112.0,"Y":217.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":187654.0,"EndTime":187654.0,"X":88.1223145,"Y":144.955582,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":187801.0,"Objects":[{"StartTime":187801.0,"EndTime":187801.0,"X":0.0,"Y":293.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":187876.0,"EndTime":187876.0,"X":34.3335266,"Y":384.254883,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":188023.0,"Objects":[{"StartTime":188023.0,"EndTime":188023.0,"X":220.0,"Y":151.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":188209.0,"EndTime":188209.0,"X":89.1849747,"Y":38.11739,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":188357.0,"Objects":[{"StartTime":188357.0,"EndTime":188357.0,"X":193.991959,"Y":281.991943}]},{"StartTime":188468.0,"Objects":[{"StartTime":188468.0,"EndTime":188468.0,"X":198.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":188543.0,"EndTime":188543.0,"X":115.5115,"Y":246.779144,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":188690.0,"Objects":[{"StartTime":188690.0,"EndTime":188690.0,"X":328.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":188765.0,"EndTime":188765.0,"X":323.656677,"Y":293.825745,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":188912.0,"Objects":[{"StartTime":188912.0,"EndTime":188912.0,"X":506.0,"Y":165.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":189098.0,"EndTime":189098.0,"X":325.711121,"Y":174.086273,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":189246.0,"Objects":[{"StartTime":189246.0,"EndTime":189246.0,"X":136.0,"Y":81.0}]},{"StartTime":189357.0,"Objects":[{"StartTime":189357.0,"EndTime":189357.0,"X":219.0,"Y":40.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":189432.0,"EndTime":189432.0,"X":264.425018,"Y":22.49165,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":189579.0,"Objects":[{"StartTime":189579.0,"EndTime":189579.0,"X":333.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":189654.0,"EndTime":189654.0,"X":287.444427,"Y":234.581711,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":189801.0,"Objects":[{"StartTime":189801.0,"EndTime":189801.0,"X":78.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":189987.0,"EndTime":189987.0,"X":215.659058,"Y":383.269257,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":190134.0,"Objects":[{"StartTime":190134.0,"EndTime":190134.0,"X":240.991959,"Y":156.991959}]},{"StartTime":190246.0,"Objects":[{"StartTime":190246.0,"EndTime":190246.0,"X":245.0,"Y":161.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":190321.0,"EndTime":190321.0,"X":177.97789,"Y":216.226547,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":190468.0,"Objects":[{"StartTime":190468.0,"EndTime":190468.0,"X":11.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":190543.0,"EndTime":190543.0,"X":97.85994,"Y":143.0787,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":190690.0,"Objects":[{"StartTime":190690.0,"EndTime":190690.0,"X":55.0,"Y":345.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":190876.0,"EndTime":190876.0,"X":245.305511,"Y":318.198578,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":191023.0,"Objects":[{"StartTime":191023.0,"EndTime":191023.0,"X":400.991943,"Y":189.991959}]},{"StartTime":191134.0,"Objects":[{"StartTime":191134.0,"EndTime":191134.0,"X":405.0,"Y":194.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":191209.0,"EndTime":191209.0,"X":361.7055,"Y":274.186035,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":191357.0,"Objects":[{"StartTime":191357.0,"EndTime":191357.0,"X":498.0,"Y":363.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":191432.0,"EndTime":191432.0,"X":480.31192,"Y":278.6314,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":191579.0,"Objects":[{"StartTime":191579.0,"EndTime":191579.0,"X":468.0,"Y":72.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":191765.0,"EndTime":191765.0,"X":306.435425,"Y":130.6289,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":191912.0,"Objects":[{"StartTime":191912.0,"EndTime":191912.0,"X":101.0,"Y":81.0}]},{"StartTime":192023.0,"Objects":[{"StartTime":192023.0,"EndTime":192023.0,"X":182.0,"Y":24.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":192098.0,"EndTime":192098.0,"X":199.58197,"Y":119.901642,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":192246.0,"Objects":[{"StartTime":192246.0,"EndTime":192246.0,"X":302.0,"Y":384.0}]},{"StartTime":192357.0,"Objects":[{"StartTime":192357.0,"EndTime":192357.0,"X":355.0,"Y":305.0}]},{"StartTime":192468.0,"Objects":[{"StartTime":192468.0,"EndTime":192468.0,"X":281.0,"Y":239.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":192543.0,"EndTime":192543.0,"X":194.7636,"Y":248.249023,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":192690.0,"Objects":[{"StartTime":192690.0,"EndTime":192690.0,"X":18.0,"Y":347.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":192765.0,"EndTime":192765.0,"X":71.3199844,"Y":326.631134,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":192912.0,"Objects":[{"StartTime":192912.0,"EndTime":192912.0,"X":89.0,"Y":106.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":192987.0,"EndTime":192987.0,"X":71.78304,"Y":160.039886,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":193134.0,"Objects":[{"StartTime":193134.0,"EndTime":193134.0,"X":252.0,"Y":287.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":193209.0,"EndTime":193209.0,"X":212.6236,"Y":244.7909,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":193357.0,"Objects":[{"StartTime":193357.0,"EndTime":193357.0,"X":111.0,"Y":244.0}]},{"StartTime":193579.0,"Objects":[{"StartTime":193579.0,"EndTime":193579.0,"X":215.0,"Y":37.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":193654.0,"EndTime":193654.0,"X":200.609528,"Y":126.211754,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":193801.0,"Objects":[{"StartTime":193801.0,"EndTime":193801.0,"X":371.0,"Y":126.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":193876.0,"EndTime":193876.0,"X":356.564331,"Y":36.5752678,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":194023.0,"Objects":[{"StartTime":194023.0,"EndTime":194023.0,"X":282.0,"Y":276.0}]},{"StartTime":194246.0,"Objects":[{"StartTime":194246.0,"EndTime":194246.0,"X":282.0,"Y":276.0}]},{"StartTime":194468.0,"Objects":[{"StartTime":194468.0,"EndTime":194468.0,"X":239.0,"Y":195.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":194543.0,"EndTime":194543.0,"X":328.394379,"Y":191.421982,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":194690.0,"Objects":[{"StartTime":194690.0,"EndTime":194690.0,"X":508.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":194765.0,"EndTime":194765.0,"X":418.383057,"Y":244.1962,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":194912.0,"Objects":[{"StartTime":194912.0,"EndTime":194912.0,"X":334.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":195098.0,"EndTime":195098.0,"X":463.9035,"Y":157.835983,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":195357.0,"Objects":[{"StartTime":195357.0,"EndTime":195357.0,"X":316.0,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":195432.0,"EndTime":195432.0,"X":327.604462,"Y":190.84021,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":195579.0,"Objects":[{"StartTime":195579.0,"EndTime":195579.0,"X":253.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":195654.0,"EndTime":195654.0,"X":333.9576,"Y":55.0459251,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":195801.0,"Objects":[{"StartTime":195801.0,"EndTime":195801.0,"X":418.0,"Y":244.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":195987.0,"EndTime":195987.0,"X":232.039337,"Y":278.23053,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":196246.0,"Objects":[{"StartTime":196246.0,"EndTime":196246.0,"X":96.0,"Y":93.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":196321.0,"EndTime":196321.0,"X":158.051941,"Y":152.6015,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":196468.0,"Objects":[{"StartTime":196468.0,"EndTime":196468.0,"X":36.0,"Y":291.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":196543.0,"EndTime":196543.0,"X":43.7772751,"Y":205.244049,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":196690.0,"Objects":[{"StartTime":196690.0,"EndTime":196690.0,"X":316.0,"Y":108.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":196765.0,"EndTime":196765.0,"X":258.890442,"Y":187.023712,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":196912.0,"Objects":[{"StartTime":196912.0,"EndTime":196912.0,"X":158.0,"Y":342.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":197209.0,"EndTime":197209.0,"X":381.5317,"Y":332.94693,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":197357.0,"Objects":[{"StartTime":197357.0,"EndTime":197357.0,"X":381.0,"Y":332.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":197432.0,"EndTime":197432.0,"X":388.862427,"Y":243.495224,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":197579.0,"Objects":[{"StartTime":197579.0,"EndTime":197579.0,"X":512.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":197876.0,"EndTime":197876.0,"X":285.27533,"Y":102.821617,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":198023.0,"Objects":[{"StartTime":198023.0,"EndTime":198023.0,"X":285.0,"Y":102.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":198098.0,"EndTime":198098.0,"X":308.620453,"Y":188.817657,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":198246.0,"Objects":[{"StartTime":198246.0,"EndTime":198246.0,"X":139.0,"Y":368.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":198321.0,"EndTime":198321.0,"X":161.313477,"Y":281.518036,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":198468.0,"Objects":[{"StartTime":198468.0,"EndTime":198468.0,"X":202.0,"Y":186.0}]},{"StartTime":198579.0,"Objects":[{"StartTime":198579.0,"EndTime":198579.0,"X":116.0,"Y":180.0}]},{"StartTime":198690.0,"Objects":[{"StartTime":198690.0,"EndTime":198690.0,"X":60.0,"Y":113.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":198765.0,"EndTime":198765.0,"X":143.467941,"Y":93.9362,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":198912.0,"Objects":[{"StartTime":198912.0,"EndTime":198912.0,"X":259.0,"Y":291.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":198987.0,"EndTime":198987.0,"X":162.120941,"Y":280.0137,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":199134.0,"Objects":[{"StartTime":199134.0,"EndTime":199134.0,"X":187.0,"Y":7.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":199320.0,"EndTime":199320.0,"X":229.512268,"Y":159.866241,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":199468.0,"Objects":[{"StartTime":199468.0,"EndTime":199468.0,"X":72.0,"Y":342.0}]},{"StartTime":199579.0,"Objects":[{"StartTime":199579.0,"EndTime":199579.0,"X":0.0,"Y":282.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":199654.0,"EndTime":199654.0,"X":78.95528,"Y":246.232529,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":199801.0,"Objects":[{"StartTime":199801.0,"EndTime":199801.0,"X":173.0,"Y":337.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":199876.0,"EndTime":199876.0,"X":257.654663,"Y":349.431061,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":200023.0,"Objects":[{"StartTime":200023.0,"EndTime":200023.0,"X":494.0,"Y":181.0}]},{"StartTime":200134.0,"Objects":[{"StartTime":200134.0,"EndTime":200134.0,"X":402.0,"Y":122.0}]},{"StartTime":200246.0,"Objects":[{"StartTime":200246.0,"EndTime":200246.0,"X":323.0,"Y":194.0}]},{"StartTime":200357.0,"Objects":[{"StartTime":200357.0,"EndTime":200357.0,"X":371.0,"Y":288.0}]},{"StartTime":200468.0,"Objects":[{"StartTime":200468.0,"EndTime":200468.0,"X":414.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":200654.0,"EndTime":200654.0,"X":236.752914,"Y":258.171417,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":200801.0,"Objects":[{"StartTime":200801.0,"EndTime":200801.0,"X":127.991959,"Y":157.991959}]},{"StartTime":200912.0,"Objects":[{"StartTime":200912.0,"EndTime":200912.0,"X":132.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":200987.0,"EndTime":200987.0,"X":184.15062,"Y":152.335556,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201134.0,"Objects":[{"StartTime":201134.0,"EndTime":201134.0,"X":236.0,"Y":258.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201209.0,"EndTime":201209.0,"X":220.839447,"Y":354.314117,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201357.0,"Objects":[{"StartTime":201357.0,"EndTime":201357.0,"X":58.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201543.0,"EndTime":201543.0,"X":35.1479073,"Y":86.65965,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201690.0,"Objects":[{"StartTime":201690.0,"EndTime":201690.0,"X":190.0,"Y":71.0}]},{"StartTime":201801.0,"Objects":[{"StartTime":201801.0,"EndTime":201801.0,"X":229.0,"Y":171.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201876.0,"EndTime":201876.0,"X":131.975967,"Y":161.377777,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202023.0,"Objects":[{"StartTime":202023.0,"EndTime":202023.0,"X":63.0,"Y":335.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202098.0,"EndTime":202098.0,"X":134.2772,"Y":290.463074,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202246.0,"Objects":[{"StartTime":202246.0,"EndTime":202246.0,"X":408.0,"Y":277.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202432.0,"EndTime":202432.0,"X":244.544388,"Y":290.6308,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202579.0,"Objects":[{"StartTime":202579.0,"EndTime":202579.0,"X":208.991959,"Y":80.99196}]},{"StartTime":202690.0,"Objects":[{"StartTime":202690.0,"EndTime":202690.0,"X":213.0,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202765.0,"EndTime":202765.0,"X":228.79689,"Y":170.052963,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202912.0,"Objects":[{"StartTime":202912.0,"EndTime":202912.0,"X":49.0,"Y":312.0}]},{"StartTime":203023.0,"Objects":[{"StartTime":203023.0,"EndTime":203023.0,"X":24.0,"Y":224.0}]},{"StartTime":203134.0,"Objects":[{"StartTime":203134.0,"EndTime":203134.0,"X":122.0,"Y":233.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":203320.0,"EndTime":203320.0,"X":191.638641,"Y":368.68396,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":203468.0,"Objects":[{"StartTime":203468.0,"EndTime":203468.0,"X":141.991959,"Y":66.99196}]},{"StartTime":203579.0,"Objects":[{"StartTime":203579.0,"EndTime":203579.0,"X":146.0,"Y":71.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":203654.0,"EndTime":203654.0,"X":199.075058,"Y":144.244308,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":203801.0,"Objects":[{"StartTime":203801.0,"EndTime":203801.0,"X":307.0,"Y":98.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":203876.0,"EndTime":203876.0,"X":306.357178,"Y":192.275589,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":204023.0,"Objects":[{"StartTime":204023.0,"EndTime":204023.0,"X":148.0,"Y":315.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":204209.0,"EndTime":204209.0,"X":338.9172,"Y":312.6326,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":204357.0,"Objects":[{"StartTime":204357.0,"EndTime":204357.0,"X":476.991943,"Y":265.991943}]},{"StartTime":204468.0,"Objects":[{"StartTime":204468.0,"EndTime":204468.0,"X":481.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":204543.0,"EndTime":204543.0,"X":484.560455,"Y":339.2592,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":204690.0,"Objects":[{"StartTime":204690.0,"EndTime":204690.0,"X":374.0,"Y":187.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":204765.0,"EndTime":204765.0,"X":439.03717,"Y":114.361069,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":204912.0,"Objects":[{"StartTime":204912.0,"EndTime":204912.0,"X":246.0,"Y":22.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":205098.0,"EndTime":205098.0,"X":242.783752,"Y":185.724686,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":205246.0,"Objects":[{"StartTime":205246.0,"EndTime":205246.0,"X":284.0,"Y":353.0}]},{"StartTime":205357.0,"Objects":[{"StartTime":205357.0,"EndTime":205357.0,"X":377.0,"Y":329.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":205432.0,"EndTime":205432.0,"X":310.678467,"Y":265.608063,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":205579.0,"Objects":[{"StartTime":205579.0,"EndTime":205579.0,"X":140.0,"Y":351.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":205654.0,"EndTime":205654.0,"X":198.56424,"Y":287.309631,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":205801.0,"Objects":[{"StartTime":205801.0,"EndTime":205801.0,"X":71.0,"Y":229.0}]},{"StartTime":206023.0,"Objects":[{"StartTime":206023.0,"EndTime":206023.0,"X":284.0,"Y":353.0}]},{"StartTime":206134.0,"Objects":[{"StartTime":206134.0,"EndTime":206134.0,"X":310.0,"Y":265.0}]},{"StartTime":206246.0,"Objects":[{"StartTime":206246.0,"EndTime":206246.0,"X":270.0,"Y":189.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":206321.0,"EndTime":206321.0,"X":172.514236,"Y":190.666428,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":206468.0,"Objects":[{"StartTime":206468.0,"EndTime":206468.0,"X":0.0,"Y":130.0}]},{"StartTime":206579.0,"Objects":[{"StartTime":206579.0,"EndTime":206579.0,"X":21.0,"Y":49.0}]},{"StartTime":206690.0,"Objects":[{"StartTime":206690.0,"EndTime":206690.0,"X":108.0,"Y":42.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":206876.0,"EndTime":206876.0,"X":171.950943,"Y":190.486923,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":207023.0,"Objects":[{"StartTime":207023.0,"EndTime":207023.0,"X":15.9919577,"Y":318.991943}]},{"StartTime":207134.0,"Objects":[{"StartTime":207134.0,"EndTime":207134.0,"X":20.0,"Y":323.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":207209.0,"EndTime":207209.0,"X":102.738419,"Y":285.6162,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":207357.0,"Objects":[{"StartTime":207357.0,"EndTime":207357.0,"X":251.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":207432.0,"EndTime":207432.0,"X":234.77272,"Y":297.868958,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":207579.0,"Objects":[{"StartTime":207579.0,"EndTime":207579.0,"X":480.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":207765.0,"EndTime":207765.0,"X":303.419739,"Y":213.402771,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":207912.0,"Objects":[{"StartTime":207912.0,"EndTime":207912.0,"X":125.991959,"Y":118.991959}]},{"StartTime":208023.0,"Objects":[{"StartTime":208023.0,"EndTime":208023.0,"X":130.0,"Y":123.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":208098.0,"EndTime":208098.0,"X":171.601212,"Y":189.693237,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":208246.0,"Objects":[{"StartTime":208246.0,"EndTime":208246.0,"X":368.0,"Y":138.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":208321.0,"EndTime":208321.0,"X":280.454285,"Y":113.3478,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":208468.0,"Objects":[{"StartTime":208468.0,"EndTime":208468.0,"X":133.0,"Y":360.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":208654.0,"EndTime":208654.0,"X":287.511,"Y":308.130524,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":208801.0,"Objects":[{"StartTime":208801.0,"EndTime":208801.0,"X":437.991943,"Y":301.991943}]},{"StartTime":208912.0,"Objects":[{"StartTime":208912.0,"EndTime":208912.0,"X":442.0,"Y":306.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":208987.0,"EndTime":208987.0,"X":387.819427,"Y":378.516083,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":209134.0,"Objects":[{"StartTime":209134.0,"EndTime":209134.0,"X":512.0,"Y":182.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":209209.0,"EndTime":209209.0,"X":419.7707,"Y":188.271652,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":209357.0,"Objects":[{"StartTime":209357.0,"EndTime":209357.0,"X":275.0,"Y":16.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":209543.0,"EndTime":209543.0,"X":298.5103,"Y":195.631866,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":209690.0,"Objects":[{"StartTime":209690.0,"EndTime":209690.0,"X":136.991959,"Y":190.991959}]},{"StartTime":209801.0,"Objects":[{"StartTime":209801.0,"EndTime":209801.0,"X":141.0,"Y":195.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":209876.0,"EndTime":209876.0,"X":191.738983,"Y":133.100525,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":210023.0,"Objects":[{"StartTime":210023.0,"EndTime":210023.0,"X":55.0,"Y":267.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":210098.0,"EndTime":210098.0,"X":29.103653,"Y":182.072876,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":210246.0,"Objects":[{"StartTime":210246.0,"EndTime":210246.0,"X":223.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":210321.0,"EndTime":210321.0,"X":213.5535,"Y":357.041321,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":210468.0,"Objects":[{"StartTime":210468.0,"EndTime":210468.0,"X":327.0,"Y":210.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":210543.0,"EndTime":210543.0,"X":317.5535,"Y":307.041321,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":210690.0,"Objects":[{"StartTime":210690.0,"EndTime":210690.0,"X":104.0,"Y":111.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":210765.0,"EndTime":210765.0,"X":140.630753,"Y":194.91655,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":210912.0,"Objects":[{"StartTime":210912.0,"EndTime":210912.0,"X":253.0,"Y":11.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":210987.0,"EndTime":210987.0,"X":235.838547,"Y":96.9594955,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":211134.0,"Objects":[{"StartTime":211134.0,"EndTime":211134.0,"X":29.0,"Y":278.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":211320.0,"EndTime":211320.0,"X":222.616745,"Y":259.101837,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":211468.0,"Objects":[{"StartTime":211468.0,"EndTime":211468.0,"X":394.991943,"Y":183.991959}]},{"StartTime":211579.0,"Objects":[{"StartTime":211579.0,"EndTime":211579.0,"X":399.0,"Y":188.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":211654.0,"EndTime":211654.0,"X":303.68924,"Y":168.970551,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":211801.0,"Objects":[{"StartTime":211801.0,"EndTime":211801.0,"X":316.0,"Y":367.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":211876.0,"EndTime":211876.0,"X":329.0899,"Y":271.836945,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":212023.0,"Objects":[{"StartTime":212023.0,"EndTime":212023.0,"X":191.0,"Y":159.0}]},{"StartTime":212246.0,"Objects":[{"StartTime":212246.0,"EndTime":212246.0,"X":379.991943,"Y":78.99196}]},{"StartTime":212357.0,"Objects":[{"StartTime":212357.0,"EndTime":212357.0,"X":384.0,"Y":83.0}]},{"StartTime":212579.0,"Objects":[{"StartTime":212579.0,"EndTime":212579.0,"X":251.991959,"Y":-4.00804234}]},{"StartTime":212690.0,"Objects":[{"StartTime":212690.0,"EndTime":212690.0,"X":256.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":212765.0,"EndTime":212765.0,"X":274.741,"Y":95.5859146,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":212912.0,"Objects":[{"StartTime":212912.0,"EndTime":212912.0,"X":370.0,"Y":188.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":213098.0,"EndTime":213098.0,"X":336.668121,"Y":378.5493,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":213246.0,"Objects":[{"StartTime":213246.0,"EndTime":213246.0,"X":106.991959,"Y":164.991959}]},{"StartTime":213357.0,"Objects":[{"StartTime":213357.0,"EndTime":213357.0,"X":111.0,"Y":169.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":213432.0,"EndTime":213432.0,"X":139.0973,"Y":261.838654,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":213579.0,"Objects":[{"StartTime":213579.0,"EndTime":213579.0,"X":254.0,"Y":288.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":213654.0,"EndTime":213654.0,"X":224.939835,"Y":380.4556,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":213801.0,"Objects":[{"StartTime":213801.0,"EndTime":213801.0,"X":36.0,"Y":223.0}]},{"StartTime":213912.0,"Objects":[{"StartTime":213912.0,"EndTime":213912.0,"X":2.0,"Y":171.0}]},{"StartTime":214023.0,"Objects":[{"StartTime":214023.0,"EndTime":214023.0,"X":19.0,"Y":113.0}]},{"StartTime":214134.0,"Objects":[{"StartTime":214134.0,"EndTime":214134.0,"X":92.0,"Y":47.0}]},{"StartTime":214246.0,"Objects":[{"StartTime":214246.0,"EndTime":214246.0,"X":189.0,"Y":76.0}]},{"StartTime":214357.0,"Objects":[{"StartTime":214357.0,"EndTime":214357.0,"X":205.0,"Y":179.0}]},{"StartTime":214468.0,"Objects":[{"StartTime":214468.0,"EndTime":214468.0,"X":305.0,"Y":229.0}]},{"StartTime":214579.0,"Objects":[{"StartTime":214579.0,"EndTime":214579.0,"X":395.0,"Y":167.0}]},{"StartTime":214690.0,"Objects":[{"StartTime":214690.0,"EndTime":214690.0,"X":306.0,"Y":121.0}]},{"StartTime":215134.0,"Objects":[{"StartTime":215134.0,"EndTime":215134.0,"X":306.0,"Y":149.0}]},{"StartTime":215579.0,"Objects":[{"StartTime":215579.0,"EndTime":215579.0,"X":302.0,"Y":179.0}]},{"StartTime":216023.0,"Objects":[{"StartTime":216023.0,"EndTime":216023.0,"X":299.0,"Y":214.0}]},{"StartTime":216468.0,"Objects":[{"StartTime":216468.0,"EndTime":216468.0,"X":295.0,"Y":261.0}]},{"StartTime":216690.0,"Objects":[{"StartTime":216690.0,"EndTime":216690.0,"X":206.0,"Y":318.0}]},{"StartTime":216912.0,"Objects":[{"StartTime":216912.0,"EndTime":216912.0,"X":128.0,"Y":248.0}]},{"StartTime":217134.0,"Objects":[{"StartTime":217134.0,"EndTime":217134.0,"X":177.0,"Y":139.0}]},{"StartTime":217357.0,"Objects":[{"StartTime":217357.0,"EndTime":217357.0,"X":289.0,"Y":164.0}]},{"StartTime":217579.0,"Objects":[{"StartTime":217579.0,"EndTime":217579.0,"X":358.0,"Y":74.0}]},{"StartTime":217801.0,"Objects":[{"StartTime":217801.0,"EndTime":217801.0,"X":243.0,"Y":22.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":218098.0,"EndTime":218098.0,"X":259.170074,"Y":239.193665,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":218246.0,"Objects":[{"StartTime":218246.0,"EndTime":218246.0,"X":99.0,"Y":350.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":218321.0,"EndTime":218321.0,"X":189.276535,"Y":334.704254,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":218468.0,"Objects":[{"StartTime":218468.0,"EndTime":218468.0,"X":316.0,"Y":338.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":218654.0,"EndTime":218654.0,"X":190.048248,"Y":335.3634,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":218912.0,"Objects":[{"StartTime":218912.0,"EndTime":218912.0,"X":188.0,"Y":186.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":218987.0,"EndTime":218987.0,"X":258.7948,"Y":238.577835,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":219134.0,"Objects":[{"StartTime":219134.0,"EndTime":219134.0,"X":77.0,"Y":265.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219320.0,"EndTime":219320.0,"X":69.94787,"Y":134.962021,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":219468.0,"Objects":[{"StartTime":219468.0,"EndTime":219468.0,"X":199.991959,"Y":39.99196}]},{"StartTime":219579.0,"Objects":[{"StartTime":219579.0,"EndTime":219579.0,"X":204.0,"Y":44.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219654.0,"EndTime":219654.0,"X":140.776764,"Y":17.8049469,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":219801.0,"Objects":[{"StartTime":219801.0,"EndTime":219801.0,"X":272.0,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219876.0,"EndTime":219876.0,"X":184.1349,"Y":160.285843,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":220023.0,"Objects":[{"StartTime":220023.0,"EndTime":220023.0,"X":345.0,"Y":38.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":220098.0,"EndTime":220098.0,"X":425.9743,"Y":-2.0466094,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":220246.0,"Objects":[{"StartTime":220246.0,"EndTime":220246.0,"X":293.0,"Y":246.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":220321.0,"EndTime":220321.0,"X":284.1332,"Y":153.632828,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":220468.0,"Objects":[{"StartTime":220468.0,"EndTime":220468.0,"X":454.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":220654.0,"EndTime":220654.0,"X":442.845032,"Y":293.1156,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":220801.0,"Objects":[{"StartTime":220801.0,"EndTime":220801.0,"X":267.0,"Y":384.0}]},{"StartTime":220912.0,"Objects":[{"StartTime":220912.0,"EndTime":220912.0,"X":330.0,"Y":303.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":220987.0,"EndTime":220987.0,"X":256.6342,"Y":277.682,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":221134.0,"Objects":[{"StartTime":221134.0,"EndTime":221134.0,"X":122.0,"Y":252.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":221209.0,"EndTime":221209.0,"X":77.28965,"Y":302.866638,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":221357.0,"Objects":[{"StartTime":221357.0,"EndTime":221357.0,"X":358.0,"Y":189.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":221432.0,"EndTime":221432.0,"X":291.6313,"Y":167.885254,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":221579.0,"Objects":[{"StartTime":221579.0,"EndTime":221579.0,"X":122.0,"Y":252.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":221654.0,"EndTime":221654.0,"X":144.643356,"Y":362.1977,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":221801.0,"Objects":[{"StartTime":221801.0,"EndTime":221801.0,"X":180.0,"Y":89.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":221987.0,"EndTime":221987.0,"X":-0.212159589,"Y":155.517212,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":222134.0,"Objects":[{"StartTime":222134.0,"EndTime":222134.0,"X":2.0,"Y":52.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":222320.0,"EndTime":222320.0,"X":179.106552,"Y":118.010155,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":222468.0,"Objects":[{"StartTime":222468.0,"EndTime":222468.0,"X":310.0,"Y":3.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":222543.0,"EndTime":222543.0,"X":314.75592,"Y":71.55705,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":222690.0,"Objects":[{"StartTime":222690.0,"EndTime":222690.0,"X":86.0,"Y":282.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":222876.0,"EndTime":222876.0,"X":247.322327,"Y":250.250336,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":223023.0,"Objects":[{"StartTime":223023.0,"EndTime":223023.0,"X":385.991943,"Y":130.991959}]},{"StartTime":223134.0,"Objects":[{"StartTime":223134.0,"EndTime":223134.0,"X":390.0,"Y":135.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":223209.0,"EndTime":223209.0,"X":404.3002,"Y":216.25119,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":223357.0,"Objects":[{"StartTime":223357.0,"EndTime":223357.0,"X":503.0,"Y":302.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":223432.0,"EndTime":223432.0,"X":487.977631,"Y":383.120758,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":223579.0,"Objects":[{"StartTime":223579.0,"EndTime":223579.0,"X":272.0,"Y":306.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":223765.0,"EndTime":223765.0,"X":403.882141,"Y":215.343521,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":223912.0,"Objects":[{"StartTime":223912.0,"EndTime":223912.0,"X":368.0,"Y":309.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":224098.0,"EndTime":224098.0,"X":235.15654,"Y":204.242447,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":224246.0,"Objects":[{"StartTime":224246.0,"EndTime":224246.0,"X":131.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":224321.0,"EndTime":224321.0,"X":144.1626,"Y":297.576355,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":224468.0,"Objects":[{"StartTime":224468.0,"EndTime":224468.0,"X":95.0,"Y":94.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":224543.0,"EndTime":224543.0,"X":110.714821,"Y":179.094528,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":224690.0,"Objects":[{"StartTime":224690.0,"EndTime":224690.0,"X":18.0,"Y":376.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":224765.0,"EndTime":224765.0,"X":32.05672,"Y":287.904755,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":224912.0,"Objects":[{"StartTime":224912.0,"EndTime":224912.0,"X":221.0,"Y":91.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":224987.0,"EndTime":224987.0,"X":170.667969,"Y":-0.700416565,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":225134.0,"Objects":[{"StartTime":225134.0,"EndTime":225134.0,"X":0.0,"Y":195.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":225209.0,"EndTime":225209.0,"X":110.847977,"Y":179.233826,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":225357.0,"Objects":[{"StartTime":225357.0,"EndTime":225357.0,"X":225.0,"Y":279.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":225432.0,"EndTime":225432.0,"X":250.488,"Y":373.109558,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":225579.0,"Objects":[{"StartTime":225579.0,"EndTime":225579.0,"X":303.0,"Y":187.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":225765.0,"EndTime":225765.0,"X":302.1273,"Y":313.028442,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":226023.0,"Objects":[{"StartTime":226023.0,"EndTime":226023.0,"X":7.0,"Y":167.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":226098.0,"EndTime":226098.0,"X":85.87472,"Y":124.424934,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":226246.0,"Objects":[{"StartTime":226246.0,"EndTime":226246.0,"X":256.0,"Y":71.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":226432.0,"EndTime":226432.0,"X":145.4533,"Y":3.64019942,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":226579.0,"Objects":[{"StartTime":226579.0,"EndTime":226579.0,"X":176.991959,"Y":204.991959}]},{"StartTime":226690.0,"Objects":[{"StartTime":226690.0,"EndTime":226690.0,"X":181.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":226765.0,"EndTime":226765.0,"X":136.537048,"Y":259.55426,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":226912.0,"Objects":[{"StartTime":226912.0,"EndTime":226912.0,"X":259.0,"Y":383.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":226987.0,"EndTime":226987.0,"X":251.052277,"Y":292.364258,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":227134.0,"Objects":[{"StartTime":227134.0,"EndTime":227134.0,"X":479.0,"Y":317.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":227209.0,"EndTime":227209.0,"X":382.294434,"Y":329.4209,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":227357.0,"Objects":[{"StartTime":227357.0,"EndTime":227357.0,"X":181.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":227432.0,"EndTime":227432.0,"X":254.120087,"Y":153.375763,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":227579.0,"Objects":[{"StartTime":227579.0,"EndTime":227579.0,"X":510.0,"Y":38.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":227765.0,"EndTime":227765.0,"X":354.12912,"Y":1.18961823,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":227912.0,"Objects":[{"StartTime":227912.0,"EndTime":227912.0,"X":254.0,"Y":153.0}]},{"StartTime":228023.0,"Objects":[{"StartTime":228023.0,"EndTime":228023.0,"X":327.0,"Y":97.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":228098.0,"EndTime":228098.0,"X":345.770142,"Y":185.498367,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":228246.0,"Objects":[{"StartTime":228246.0,"EndTime":228246.0,"X":160.0,"Y":133.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":228321.0,"EndTime":228321.0,"X":223.510559,"Y":56.254303,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":228468.0,"Objects":[{"StartTime":228468.0,"EndTime":228468.0,"X":59.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":228543.0,"EndTime":228543.0,"X":23.5169945,"Y":163.594849,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":228690.0,"Objects":[{"StartTime":228690.0,"EndTime":228690.0,"X":210.0,"Y":274.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":228765.0,"EndTime":228765.0,"X":169.413956,"Y":371.345062,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":228912.0,"Objects":[{"StartTime":228912.0,"EndTime":228912.0,"X":124.0,"Y":143.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":229098.0,"EndTime":229098.0,"X":287.543579,"Y":107.639671,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":229246.0,"Objects":[{"StartTime":229246.0,"EndTime":229246.0,"X":436.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":229432.0,"EndTime":229432.0,"X":272.456421,"Y":295.360321,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":229579.0,"Objects":[{"StartTime":229579.0,"EndTime":229579.0,"X":392.0,"Y":42.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":229654.0,"EndTime":229654.0,"X":425.099121,"Y":124.701683,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":229801.0,"Objects":[{"StartTime":229801.0,"EndTime":229801.0,"X":164.0,"Y":360.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":229987.0,"EndTime":229987.0,"X":271.6051,"Y":295.145325,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":230134.0,"Objects":[{"StartTime":230134.0,"EndTime":230134.0,"X":234.0,"Y":80.0}]},{"StartTime":230246.0,"Objects":[{"StartTime":230246.0,"EndTime":230246.0,"X":331.0,"Y":158.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":230321.0,"EndTime":230321.0,"X":239.261871,"Y":182.147629,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":230468.0,"Objects":[{"StartTime":230468.0,"EndTime":230468.0,"X":114.0,"Y":95.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":230543.0,"EndTime":230543.0,"X":22.4259262,"Y":70.0677643,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":230690.0,"Objects":[{"StartTime":230690.0,"EndTime":230690.0,"X":68.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":230876.0,"EndTime":230876.0,"X":77.38308,"Y":207.233841,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":231023.0,"Objects":[{"StartTime":231023.0,"EndTime":231023.0,"X":194.0,"Y":44.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":231209.0,"EndTime":231209.0,"X":197.103,"Y":193.028,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":231357.0,"Objects":[{"StartTime":231357.0,"EndTime":231357.0,"X":246.0,"Y":376.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":231432.0,"EndTime":231432.0,"X":183.012833,"Y":319.709869,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":231579.0,"Objects":[{"StartTime":231579.0,"EndTime":231579.0,"X":351.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":231654.0,"EndTime":231654.0,"X":302.545776,"Y":223.952576,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":231801.0,"Objects":[{"StartTime":231801.0,"EndTime":231801.0,"X":439.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":231876.0,"EndTime":231876.0,"X":405.727173,"Y":301.005463,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":232023.0,"Objects":[{"StartTime":232023.0,"EndTime":232023.0,"X":464.0,"Y":28.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":232098.0,"EndTime":232098.0,"X":511.817963,"Y":101.332527,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":232246.0,"Objects":[{"StartTime":232246.0,"EndTime":232246.0,"X":404.0,"Y":300.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":232321.0,"EndTime":232321.0,"X":419.2058,"Y":214.033356,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":232468.0,"Objects":[{"StartTime":232468.0,"EndTime":232468.0,"X":219.0,"Y":236.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":232543.0,"EndTime":232543.0,"X":282.5849,"Y":174.9625,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":232690.0,"Objects":[{"StartTime":232690.0,"EndTime":232690.0,"X":342.0,"Y":39.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":232876.0,"EndTime":232876.0,"X":324.964325,"Y":159.368423,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":233134.0,"Objects":[{"StartTime":233134.0,"EndTime":233134.0,"X":126.0,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":233209.0,"EndTime":233209.0,"X":198.389069,"Y":83.24417,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":233357.0,"Objects":[{"StartTime":233357.0,"EndTime":233357.0,"X":443.0,"Y":238.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":233543.0,"EndTime":233543.0,"X":303.395447,"Y":265.311,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":233690.0,"Objects":[{"StartTime":233690.0,"EndTime":233690.0,"X":173.991959,"Y":277.991943}]},{"StartTime":233801.0,"Objects":[{"StartTime":233801.0,"EndTime":233801.0,"X":178.0,"Y":282.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":233876.0,"EndTime":233876.0,"X":162.8839,"Y":345.9473,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":234023.0,"Objects":[{"StartTime":234023.0,"EndTime":234023.0,"X":85.0,"Y":181.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":234098.0,"EndTime":234098.0,"X":33.3551064,"Y":255.5539,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":234246.0,"Objects":[{"StartTime":234246.0,"EndTime":234246.0,"X":347.0,"Y":157.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":234321.0,"EndTime":234321.0,"X":265.2607,"Y":189.827148,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":234468.0,"Objects":[{"StartTime":234468.0,"EndTime":234468.0,"X":158.0,"Y":87.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":234543.0,"EndTime":234543.0,"X":69.60225,"Y":68.49895,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":234690.0,"Objects":[{"StartTime":234690.0,"EndTime":234690.0,"X":242.0,"Y":11.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":234876.0,"EndTime":234876.0,"X":264.992859,"Y":188.8681,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":235023.0,"Objects":[{"StartTime":235023.0,"EndTime":235023.0,"X":149.991959,"Y":366.991943}]},{"StartTime":235134.0,"Objects":[{"StartTime":235134.0,"EndTime":235134.0,"X":154.0,"Y":371.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":235209.0,"EndTime":235209.0,"X":117.766327,"Y":311.878845,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":235357.0,"Objects":[{"StartTime":235357.0,"EndTime":235357.0,"X":352.0,"Y":150.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":235432.0,"EndTime":235432.0,"X":316.041229,"Y":233.2105,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":235579.0,"Objects":[{"StartTime":235579.0,"EndTime":235579.0,"X":214.0,"Y":285.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":235654.0,"EndTime":235654.0,"X":203.611847,"Y":217.484741,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":235801.0,"Objects":[{"StartTime":235801.0,"EndTime":235801.0,"X":437.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":235876.0,"EndTime":235876.0,"X":351.636444,"Y":149.2189,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":236023.0,"Objects":[{"StartTime":236023.0,"EndTime":236023.0,"X":458.0,"Y":323.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":236209.0,"EndTime":236209.0,"X":423.702148,"Y":240.080933,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":236357.0,"Objects":[{"StartTime":236357.0,"EndTime":236357.0,"X":329.0,"Y":261.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":236543.0,"EndTime":236543.0,"X":203.401733,"Y":267.2608,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":236690.0,"Objects":[{"StartTime":236690.0,"EndTime":236690.0,"X":35.0,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":236765.0,"EndTime":236765.0,"X":35.1037254,"Y":356.016968,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":236912.0,"Objects":[{"StartTime":236912.0,"EndTime":236912.0,"X":130.0,"Y":357.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":237098.0,"EndTime":237098.0,"X":87.5048752,"Y":200.5525,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":237246.0,"Objects":[{"StartTime":237246.0,"EndTime":237246.0,"X":16.9919586,"Y":51.99196}]},{"StartTime":237357.0,"Objects":[{"StartTime":237357.0,"EndTime":237357.0,"X":21.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":237432.0,"EndTime":237432.0,"X":101.406532,"Y":89.1720352,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":237579.0,"Objects":[{"StartTime":237579.0,"EndTime":237579.0,"X":230.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":237654.0,"EndTime":237654.0,"X":208.203568,"Y":95.03244,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":237801.0,"Objects":[{"StartTime":237801.0,"EndTime":237801.0,"X":44.0,"Y":226.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":237987.0,"EndTime":237987.0,"X":70.47167,"Y":311.8084,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":238134.0,"Objects":[{"StartTime":238134.0,"EndTime":238134.0,"X":207.0,"Y":190.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":238320.0,"EndTime":238320.0,"X":331.306183,"Y":171.1106,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":238468.0,"Objects":[{"StartTime":238468.0,"EndTime":238468.0,"X":501.0,"Y":143.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":238543.0,"EndTime":238543.0,"X":509.553375,"Y":231.402039,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":238690.0,"Objects":[{"StartTime":238690.0,"EndTime":238690.0,"X":411.0,"Y":240.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":238765.0,"EndTime":238765.0,"X":408.77948,"Y":148.338074,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":238912.0,"Objects":[{"StartTime":238912.0,"EndTime":238912.0,"X":496.0,"Y":14.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":238987.0,"EndTime":238987.0,"X":414.912842,"Y":53.2139854,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":239134.0,"Objects":[{"StartTime":239134.0,"EndTime":239134.0,"X":204.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":239209.0,"EndTime":239209.0,"X":283.579468,"Y":30.7221928,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":239357.0,"Objects":[{"StartTime":239357.0,"EndTime":239357.0,"X":299.0,"Y":259.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":239432.0,"EndTime":239432.0,"X":219.272232,"Y":212.447662,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":239579.0,"Objects":[{"StartTime":239579.0,"EndTime":239579.0,"X":0.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":239654.0,"EndTime":239654.0,"X":87.22065,"Y":41.1654,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":239801.0,"Objects":[{"StartTime":239801.0,"EndTime":239801.0,"X":89.0,"Y":177.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":239987.0,"EndTime":239987.0,"X":86.67163,"Y":40.7199364,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":240246.0,"Objects":[{"StartTime":240246.0,"EndTime":240246.0,"X":310.0,"Y":181.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":240321.0,"EndTime":240321.0,"X":222.779343,"Y":145.1654,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":240468.0,"Objects":[{"StartTime":240468.0,"EndTime":240468.0,"X":36.0,"Y":338.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":240654.0,"EndTime":240654.0,"X":160.513031,"Y":285.858368,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":240801.0,"Objects":[{"StartTime":240801.0,"EndTime":240801.0,"X":268.991943,"Y":319.991943}]},{"StartTime":240912.0,"Objects":[{"StartTime":240912.0,"EndTime":240912.0,"X":273.0,"Y":324.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":240987.0,"EndTime":240987.0,"X":240.250153,"Y":383.3273,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":241134.0,"Objects":[{"StartTime":241134.0,"EndTime":241134.0,"X":454.0,"Y":329.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":241209.0,"EndTime":241209.0,"X":421.2658,"Y":242.324371,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":241357.0,"Objects":[{"StartTime":241357.0,"EndTime":241357.0,"X":270.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":241432.0,"EndTime":241432.0,"X":314.621155,"Y":127.794777,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":241579.0,"Objects":[{"StartTime":241579.0,"EndTime":241579.0,"X":512.0,"Y":65.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":241654.0,"EndTime":241654.0,"X":442.488647,"Y":119.759155,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":241801.0,"Objects":[{"StartTime":241801.0,"EndTime":241801.0,"X":197.0,"Y":29.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":241987.0,"EndTime":241987.0,"X":314.3943,"Y":126.814934,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":242134.0,"Objects":[{"StartTime":242134.0,"EndTime":242134.0,"X":122.0,"Y":235.0}]},{"StartTime":242246.0,"Objects":[{"StartTime":242246.0,"EndTime":242246.0,"X":223.0,"Y":265.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":242321.0,"EndTime":242321.0,"X":215.238159,"Y":199.806656,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":242468.0,"Objects":[{"StartTime":242468.0,"EndTime":242468.0,"X":97.0,"Y":19.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":242543.0,"EndTime":242543.0,"X":99.42523,"Y":106.645737,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":242690.0,"Objects":[{"StartTime":242690.0,"EndTime":242690.0,"X":314.0,"Y":127.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":242765.0,"EndTime":242765.0,"X":250.80098,"Y":68.37848,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":242912.0,"Objects":[{"StartTime":242912.0,"EndTime":242912.0,"X":14.0,"Y":268.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":242987.0,"EndTime":242987.0,"X":121.45948,"Y":234.7027,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":243134.0,"Objects":[{"StartTime":243134.0,"EndTime":243134.0,"X":354.0,"Y":245.0}]},{"StartTime":243468.0,"Objects":[{"StartTime":243468.0,"EndTime":243468.0,"X":158.0,"Y":49.0}]},{"StartTime":243801.0,"Objects":[{"StartTime":243801.0,"EndTime":243801.0,"X":121.0,"Y":331.0}]},{"StartTime":244246.0,"Objects":[{"StartTime":244246.0,"EndTime":244246.0,"X":291.0,"Y":99.0}]},{"StartTime":244469.0,"Objects":[{"StartTime":244469.0,"EndTime":244469.0,"X":270.0,"Y":314.0}]},{"StartTime":244691.0,"Objects":[{"StartTime":244691.0,"EndTime":244691.0,"X":91.0,"Y":198.0}]},{"StartTime":244912.0,"Objects":[{"StartTime":244912.0,"EndTime":244912.0,"X":244.0,"Y":208.0}]},{"StartTime":245246.0,"Objects":[{"StartTime":245246.0,"EndTime":245246.0,"X":192.0,"Y":228.0}]},{"StartTime":245579.0,"Objects":[{"StartTime":245579.0,"EndTime":245579.0,"X":199.0,"Y":179.0}]}]} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824.osu b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824.osu new file mode 100644 index 000000000000..7b53a82b51b3 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824.osu @@ -0,0 +1,1140 @@ +osu file format v14 + +[General] +AudioLeadIn: 0 +PreviewTime: 27912 +Countdown: 0 +SampleSet: Soft +StackLeniency: 0.4 +Mode: 0 +LetterboxInBreaks: 0 +WidescreenStoryboard: 1 + +[Difficulty] +HPDrainRate:5.5 +CircleSize:3.2 +OverallDifficulty:8.7 +ApproachRate:9.3 +SliderMultiplier:3 +SliderTickRate:1 + +[Events] +//Background and Video events +//Break Periods +2,67334,76803 +//Storyboard Layer 0 (Background) +//Storyboard Layer 1 (Fail) +//Storyboard Layer 2 (Pass) +//Storyboard Layer 3 (Foreground) +//Storyboard Layer 4 (Overlay) +//Storyboard Sound Samples + +[TimingPoints] +3135,444.444444444444,4,2,1,60,1,0 +3135,-153.846153846153,4,2,1,60,0,0 +17357,-100,4,2,1,65,0,0 +28023,-100,4,2,1,70,0,0 +31579,-133.333333333333,4,2,1,70,0,0 +32690,-100,4,2,1,70,0,0 +33357,-133.333333333333,4,2,1,70,0,0 +34468,-100,4,2,1,70,0,0 +38690,-133.333333333333,4,2,1,70,0,0 +39801,-100,4,2,1,70,0,0 +40468,-222.222222222221,4,2,1,70,0,0 +41246,-222.222222222221,4,2,1,5,0,0 +41357,-250,4,2,1,80,0,0 +42134,-222.222222222221,4,2,1,5,0,0 +42246,-111.111111111111,4,2,1,75,0,0 +56468,-83.3333333333333,4,2,1,80,0,1 +67134,-100,4,2,1,85,0,0 +77801,-100,4,2,1,70,0,0 +92023,-100,4,2,1,75,0,0 +106246,-83.3333333333333,4,2,1,90,0,1 +129801,-90.9090909090909,4,2,1,90,0,1 +130246,-125,4,2,1,90,0,1 +131134,-90.9090909090909,4,2,1,80,0,0 +145357,-90.9090909090909,4,2,1,85,0,0 +152357,-222.222222222221,4,2,1,5,0,0 +152468,-90.9090909090909,4,2,1,85,0,0 +156023,-76.9230769230769,4,2,1,85,0,0 +157801,-111.111111111111,4,2,1,70,0,0 +159579,-133.333333333333,4,2,1,70,0,0 +160468,-111.111111111111,4,2,1,70,0,0 +161357,-133.333333333333,4,2,1,70,0,0 +162246,-111.111111111111,4,2,1,70,0,0 +166690,-133.333333333333,4,2,1,70,0,0 +172023,-111.111111111111,4,2,1,75,0,0 +182690,-111.111111111111,4,2,1,70,0,0 +182912,-90.9090909090908,4,2,1,70,0,0 +183134,-111.111111111111,4,2,1,80,0,0 +183357,-90.9090909090908,4,2,1,80,0,0 +183579,-90.9090909090908,4,2,1,90,0,0 +184912,-58.8235294117647,4,2,1,90,0,0 +185134,-111.111111111111,4,2,1,5,0,0 +185357,-666.666666666658,4,2,1,90,0,0 +186246,-76.9230769230769,4,2,1,95,0,1 +214690,-100,4,2,1,80,0,0 +218246,-76.9230769230769,4,2,1,85,0,1 +218468,-105.263157894737,4,2,1,85,0,1 +218912,-76.9230769230769,4,2,1,85,0,1 +219134,-105.263157894737,4,2,1,85,0,1 +219801,-76.9230769230769,4,2,1,85,0,1 +221134,-105.263157894737,4,2,1,85,0,1 +221367,-76.9230769230769,4,2,1,85,0,1 +221579,-66.6666666666667,4,2,1,85,0,1 +221801,-76.9230769230769,4,2,1,85,0,1 +223023,-90.9090909090909,4,2,1,85,0,1 +223579,-76.9230769230769,4,2,1,85,0,1 +224912,-66.6666666666667,4,2,1,85,0,1 +225357,-76.9230769230769,4,2,1,85,0,1 +225579,-105.263157894737,4,2,1,85,0,1 +226023,-76.9230769230769,4,2,1,85,0,1 +226246,-105.263157894737,4,2,1,85,0,1 +226912,-76.9230769230769,4,2,1,85,0,1 +228244,-66.6666666666667,4,2,1,85,0,1 +228468,-76.9230769230769,4,2,1,85,0,1 +228690,-66.6666666666667,4,2,1,85,0,1 +228912,-76.9230769230769,4,2,1,85,0,1 +230690,-66.6666666666667,4,2,1,85,0,1 +231357,-76.9230769230769,4,2,1,85,0,1 +232690,-105.263157894737,4,2,1,85,0,1 +233134,-76.9230769230769,4,2,1,85,0,1 +233357,-105.263157894737,4,2,1,85,0,1 +234023,-76.9230769230769,4,2,1,85,0,1 +235023,-105.263157894737,4,2,1,85,0,1 +235357,-76.9230769230769,4,2,1,85,0,1 +235579,-105.263157894737,4,2,1,85,0,1 +235801,-76.9230769230769,4,2,1,85,0,1 +236357,-55.5555555555556,4,2,1,85,0,1 +236690,-76.9230769230769,4,2,1,85,0,1 +238134,-55.5555555555556,4,2,1,85,0,1 +238468,-76.9230769230769,4,2,1,85,0,1 +239134,-55.5555555555556,4,2,1,85,0,1 +239579,-76.9230769230769,4,2,1,85,0,1 +239801,-105.263157894737,4,2,1,85,0,1 +240246,-76.9230769230769,4,2,1,85,0,1 +240468,-105.263157894737,4,2,1,85,0,1 +241134,-76.9230769230769,4,2,1,85,0,1 +242246,-105.263157894737,4,2,1,85,0,1 +242468,-76.9230769230769,4,2,1,85,0,1 +242690,-80.0000000000001,4,2,1,85,0,1 +242912,-66.6666666666667,4,2,1,85,0,1 +243134,-66.6666666666667,4,2,1,85,0,0 + + +[Colours] +Combo1 : 234,69,21 +Combo2 : 46,46,199 +Combo3 : 74,85,217 +Combo4 : 82,49,168 + +[HitObjects] +31,114,3135,6,0,B|55:132|55:132|152:112,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +183,39,3468,2,0,B|207:21|207:21|304:41,1,97.4999955368044,0|0,3:2|0:0,0:0:0:0: +358,104,3801,1,2,3:2:0:0: +274,180,4023,1,2,1:2:0:0: +367,238,4246,1,2,0:0:0:0: +273,34,4468,1,2,0:0:0:0: +209,249,4690,1,2,0:0:0:0: +413,99,4912,6,0,B|318:97|380:159|248:148,2,146.249993305207,2|0|2,3:2|3:2|3:2,0:0:0:0: +504,157,5801,1,2,1:2:0:0: +429,235,6023,1,2,0:0:0:0: +498,324,6246,1,2,3:2:0:0: +331,232,6468,5,2,3:2:0:0: +321,232,6579,1,0,3:2:0:0: +311,233,6690,2,0,P|295:305|321:339,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +160,384,7023,2,0,P|176:312|150:278,1,97.4999955368044,0|0,3:2|0:0,0:0:0:0: +78,237,7357,1,2,3:2:0:0: +14,325,7579,1,2,1:2:0:0: +190,197,7801,1,2,0:0:0:0: +0,74,8023,1,2,3:2:0:0: +25,114,8134,1,0,3:2:0:0: +70,131,8245,1,2,3:2:0:0: +116,117,8356,1,0,3:2:0:0: +143,78,8468,6,0,P|193:24|264:48,2,146.249993305207,2|0|0,3:2|3:2|3:2,0:0:0:0: +69,241,9357,1,2,1:2:0:0: +48,132,9579,1,2,0:0:0:0: +191,187,9801,1,2,0:0:0:0: +173,308,10023,1,2,0:0:0:0: +0,384,10246,6,0,B|39:362|39:362|116:380,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +179,287,10579,2,0,B|218:309|218:309|295:291,1,97.4999955368044,0|0,3:2|0:0,0:0:0:0: +363,176,10912,2,0,L|353:241,1,48.7499977684022,2|0,3:2|0:0,0:0:0:0: +415,327,11134,1,2,1:2:0:0: +267,121,11579,2,0,L|257:186,1,48.7499977684022,2|0,0:0|0:0,0:0:0:0: +512,131,11801,1,2,0:0:0:0: +512,131,11912,1,0,0:0:0:0: +512,131,12023,6,0,B|459:125|459:125|414:141|414:141|356:133,2,146.249993305207,0|0|2,3:2|3:2|3:2,0:0:0:0: +275,68,12912,2,0,P|314:19|360:21,1,97.4999955368044,0|2,1:2|0:0,0:0:0:0: +276,180,13357,1,2,3:2:0:0: +121,111,13579,1,2,3:2:0:0: +72,116,13690,1,0,3:2:0:0: +24,122,13801,5,2,3:2:0:0: +188,13,14023,1,2,0:0:0:0: +86,226,14246,1,2,0:0:0:0: +235,139,14468,2,0,B|197:247|276:206|239:348,1,194.999991073609,2|2,3:2|0:0,0:0:0:0: +23,350,15134,1,2,3:2:0:0: +21,302,15245,1,0,3:2:0:0: +52,265,15356,1,2,3:2:0:0: +99,257,15467,1,0,3:2:0:0: +140,281,15579,6,0,B|263:266,1,97.4999955368044,0|2,3:2|0:0,0:0:0:0: +184,162,15912,2,0,B|307:147,1,97.4999955368044,0|0,3:2|0:0,0:0:0:0: +412,135,16246,1,0,3:2:0:0: +394,22,16468,2,0,B|362:72|362:72|387:173,1,146.249993305207,0|0,1:2|0:0,0:0:0:0: +487,220,16912,2,0,L|472:292,1,48.7499977684022,2|0,3:2|0:0,0:0:0:0: +380,382,17134,2,0,L|370:334,1,48.7499977684022,2|0,3:2|3:2,0:0:0:0: +264,260,17357,6,0,B|171:266|230:323|116:330,1,150,2|0,3:2|0:0,0:0:0:0: +26,244,17690,1,0,0:0:0:0: +56,145,17801,2,0,P|115:154|117:249,1,150,0|2,3:2|0:0,0:0:0:0: +48,361,18134,1,0,0:0:0:0: +48,361,18246,6,0,L|26:274,1,75,2|0,3:2|0:0,0:0:0:0: +130,232,18468,2,0,L|151:136,1,75,2|0,0:0|0:0,0:0:0:0: +231,7,18690,2,0,P|311:53|295:122,1,150,2|2,3:2|0:0,0:0:0:0: +262,223,19023,1,0,0:0:0:0: +262,223,19134,6,0,B|367:199|316:270|444:232,1,150,2|0,3:2|0:0,0:0:0:0: +492,166,19468,1,0,0:0:0:0: +492,166,19579,1,0,3:2:0:0: +411,310,19801,2,0,P|406:240|427:221,1,75,2|0,0:0|0:0,0:0:0:0: +372,6,20023,6,0,P|414:69|384:148,1,150,2|2,3:2|0:0,0:0:0:0: +262,147,20357,1,0,0:0:0:0: +262,147,20468,2,0,L|309:81,1,75,2|0,3:2|0:0,0:0:0:0: +160,0,20690,2,0,L|193:66,1,75,2|0,0:0|0:0,0:0:0:0: +306,220,20912,6,0,P|248:172|165:233,1,150,2|0,3:2|0:0,0:0:0:0: +32,180,21246,1,0,0:0:0:0: +32,180,21357,2,0,P|77:106|93:160,1,150,0|2,3:2|0:0,0:0:0:0: +113,363,21690,1,0,0:0:0:0: +43,305,21801,6,0,P|120:270|139:279,1,75,2|0,3:2|0:0,0:0:0:0: +209,310,22023,2,0,L|197:392,1,75,2|0,0:0|0:0,0:0:0:0: +102,166,22246,2,0,P|175:190|188:227,1,75,2|0,3:2|0:0,0:0:0:0: +249,121,22468,2,0,P|281:178|271:213,1,75,2|0,0:0|0:0,0:0:0:0: +209,310,22690,6,0,B|300:297|261:364|383:338,1,150,2|0,3:2|0:0,0:0:0:0: +442,260,23023,1,0,0:0:0:0: +442,260,23134,1,0,3:2:0:0: +250,201,23357,6,0,L|337:201,1,75,2|0,0:0|0:0,0:0:0:0: +442,260,23579,2,0,P|450:196|430:177,1,75,2|0,3:2|0:0,0:0:0:0: +343,301,23801,2,0,P|330:355|353:394,1,75,2|0,0:0|0:0,0:0:0:0: +442,260,24023,5,2,3:2:0:0: +397,202,24134,1,0,0:0:0:0: +325,202,24245,1,2,0:0:0:0: +246,274,24357,1,0,0:0:0:0: +153,226,24468,6,0,B|128:277|128:277|148:373,1,150,2|0,3:2|0:0,0:0:0:0: +23,70,24801,1,0,0:0:0:0: +23,70,24912,2,0,B|48:121|48:121|28:217,1,150,0|2,3:2|0:0,0:0:0:0: +216,144,25246,1,0,0:0:0:0: +216,144,25357,6,0,L|137:131,1,75,2|0,3:2|0:0,0:0:0:0: +105,32,25579,2,0,L|184:45,1,75,2|0,0:0|0:0,0:0:0:0: +328,246,25801,2,0,L|249:233,1,75,2|0,3:2|0:0,0:0:0:0: +270,66,26023,2,0,P|303:120|300:149,1,75,2|0,0:0|0:0,0:0:0:0: +162,270,26246,6,0,B|154:193|154:193|171:162|220:140,1,150,2|0,3:2|0:0,0:0:0:0: +211,373,26579,1,0,0:0:0:0: +211,373,26690,2,0,P|165:321|67:374,1,150,0|2,3:2|0:0,0:0:0:0: +300,200,27023,1,0,0:0:0:0: +300,200,27134,6,0,L|262:280,1,75,2|0,3:2|0:0,0:0:0:0: +402,363,27357,2,0,L|368:281,1,75,2|0,0:0|0:0,0:0:0:0: +178,44,27579,2,0,P|164:154|217:194,1,150,2|0,3:2|0:0,0:0:0:0: +329,89,27912,1,0,0:0:0:0: +329,89,28023,6,0,L|235:111,1,75,6|0,3:2|0:0,0:0:0:0: +103,268,28246,2,0,P|126:188|208:188,1,150,2|0,0:0|1:2,0:0:0:0: +360,217,28690,6,0,L|266:239,1,75,2|0,0:0|0:0,0:0:0:0: +178,44,28912,2,0,P|164:154|217:194,1,150,2|0,1:2|0:0,0:0:0:0: +247,384,29357,6,0,P|216:309|186:306,1,75,2|0,1:2|0:0,0:0:0:0: +26,254,29579,2,0,P|106:264|124:240,1,75,2|0,0:0|0:0,0:0:0:0: +233,128,29801,2,0,P|183:192|195:219,1,75,2|0,1:2|0:0,0:0:0:0: +173,257,30023,1,2,0:0:0:0: +173,257,30246,1,2,1:2:0:0: +173,257,30690,6,0,P|218:219|241:221,1,75,2|0,1:2|0:0,0:0:0:0: +173,42,30912,2,0,P|183:99|170:118,1,75,2|0,0:0|0:0,0:0:0:0: +353,122,31134,2,0,P|297:102|287:81,1,75,2|0,1:2|0:0,0:0:0:0: +173,257,31357,2,0,P|218:219|241:221,1,75,2|0,0:0|0:0,0:0:0:0: +331,243,31579,6,0,L|341:370,1,112.500004291535,2|0,1:2|0:0,0:0:0:0: +433,278,31912,2,0,L|425:166,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: +510,105,32246,1,2,0:0:0:0: +510,105,32468,1,0,1:2:0:0: +235,27,32690,6,0,P|215:53|245:101,1,75,2|0,0:0|0:0,0:0:0:0: +350,138,32912,2,0,P|331:87|303:93,1,75,2|0,1:2|0:0,0:0:0:0: +183,198,33134,2,0,L|259:186,1,75,2|0,0:0|0:0,0:0:0:0: +384,39,33357,6,0,P|346:99|372:173,1,112.500004291535,2|0,1:2|0:0,0:0:0:0: +501,181,33690,2,0,P|500:125|447:174,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: +388,225,34023,1,2,0:0:0:0: +388,225,34246,1,0,1:2:0:0: +512,329,34468,6,0,P|468:271|434:274,1,75,2|0,0:0|0:0,0:0:0:0: +382,326,34690,2,0,B|311:356|311:356|234:334,1,150,2|0,1:2|0:0,0:0:0:0: +140,297,35023,1,0,0:0:0:0: +140,297,35134,6,0,L|191:234,1,75,2|0,1:2|0:0,0:0:0:0: +322,42,35357,2,0,P|261:129|296:167,1,150,2|0,0:0|1:2,0:0:0:0: +121,77,35801,6,0,L|172:140,1,75,2|0,0:0|0:0,0:0:0:0: +299,267,36024,2,0,P|297:160|246:150,1,150,2|0,1:2|0:0,0:0:0:0: +197,292,36468,6,0,L|225:376,1,75,2|0,1:2|0:0,0:0:0:0: +105,216,36690,2,0,L|88:305,1,75,2|0,0:0|0:0,0:0:0:0: +325,312,36912,1,2,1:2:0:0: +207,192,37134,1,2,0:0:0:0: +478,185,37357,2,0,B|405:220|405:220|329:198,1,150,2|0,1:2|0:0,0:0:0:0: +409,38,37801,6,0,L|396:119,1,75,2|0,1:2|0:0,0:0:0:0: +218,266,38023,2,0,L|205:185,1,75,2|0,0:0|0:0,0:0:0:0: +299,30,38246,2,0,P|273:81|174:63,1,150,2|2,1:2|0:0,0:0:0:0: +79,33,38579,1,0,0:0:0:0: +79,33,38690,6,0,B|73:74|73:74|83:99|83:99|71:147,1,112.500004291535,2|0,1:2|0:0,0:0:0:0: +182,295,39023,2,0,B|176:253|176:253|186:228|186:228|174:180,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: +69,244,39357,1,2,0:0:0:0: +69,244,39579,1,0,1:2:0:0: +257,133,39801,6,0,P|195:90|176:98,1,75,2|0,0:0|0:0,0:0:0:0: +179,216,40023,2,0,B|247:249|247:249|346:219,1,150,2|0,1:2|0:0,0:0:0:0: +492,74,40468,6,0,P|422:36|419:154,1,236.249992790222,2|0,0:0|0:0,0:0:0:0: +492,74,41357,6,2,B|361:53|421:129|294:115,1,210,0|0,0:0|0:0,0:0:0:0: +202,56,42246,6,0,B|161:106|161:106|195:170,1,134.999995880127,6|2,3:2|0:0,0:0:0:0: +294,115,42690,1,2,0:0:0:0: +98,226,42912,2,0,P|137:165|213:184,1,134.999995880127,2|8,3:2|0:0,0:0:0:0: +212,338,43357,6,0,L|188:264,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +289,235,43579,2,0,L|310:171,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +417,146,43801,1,2,0:0:0:0: +417,146,44023,1,0,3:2:0:0: +212,338,44246,6,0,P|189:301|187:253,1,67.4999979400635,2|0,0:0|3:2,0:0:0:0: +289,235,44468,2,0,P|280:195|301:162,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +417,146,44690,1,2,3:2:0:0: +417,146,44912,1,8,0:0:0:0: +192,162,45134,6,0,P|254:94|272:102,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +427,40,45357,2,0,B|360:70|360:70|294:42,1,134.999995880127,2|2,0:0|0:0,0:0:0:0: +220,9,45690,1,0,0:0:0:0: +220,9,45801,5,0,3:2:0:0: +301,160,46023,1,2,0:0:0:0: +129,125,46246,1,2,0:0:0:0: +319,46,46468,5,2,3:2:0:0: +319,46,46579,1,0,0:0:0:0: +319,46,46690,1,8,0:0:0:0: +184,235,46912,1,2,0:0:0:0: +424,203,47134,1,2,0:0:0:0: +222,101,47357,1,2,0:0:0:0: +317,195,47579,6,0,B|288:250|288:250|313:324,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: +405,379,47912,2,0,B|428:310|428:310|399:255,1,134.999995880127,0|0,3:2|0:0,0:0:0:0: +311,318,48246,1,2,3:2:0:0: +477,199,48468,1,8,0:0:0:0: +195,231,48690,6,0,L|304:220,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +246,128,48912,2,0,L|355:117,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +468,54,49134,2,0,P|405:3|364:33,1,134.999995880127,2|0,0:0|3:2,0:0:0:0: +195,231,49579,6,0,L|304:220,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +246,128,49801,2,0,L|355:117,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +468,54,50023,2,0,P|431:70|428:162,1,134.999995880127,2|8,3:2|0:0,0:0:0:0: +195,231,50468,6,0,L|304:220,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +246,128,50690,2,0,L|355:117,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +483,257,50912,2,0,P|475:191|421:154,1,134.999995880127,2|0,0:0|3:2,0:0:0:0: +375,361,51357,6,0,L|380:289,1,67.4999979400635,2|0,0:0|3:2,0:0:0:0: +314,122,51579,2,0,L|309:194,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +379,293,51801,2,0,B|329:289|329:289|293:306|293:306|211:301,1,134.999995880127,2|8,3:2|0:0,0:0:0:0: +22,215,52246,5,2,0:0:0:0: +55,212,52357,1,0,0:0:0:0: +89,209,52468,1,2,0:0:0:0: +229,127,52690,1,2,0:0:0:0: +152,6,52912,6,0,P|112:71|139:129,1,134.999995880127,2|0,3:2|0:0,0:0:0:0: +240,226,53357,6,0,L|254:155,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +31,120,53579,2,0,P|80:209|140:205,1,134.999995880127,2|8,3:2|0:0,0:0:0:0: +260,41,54023,6,0,P|210:100|222:114,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +306,188,54246,2,0,P|285:162|252:159,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +80,294,54468,1,2,0:0:0:0: +80,294,54579,1,0,0:0:0:0: +80,294,54690,6,0,P|135:253|205:288,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: +306,294,55023,2,0,P|243:312|192:272,1,134.999995880127,0|0,3:2|0:0,0:0:0:0: +202,155,55357,2,0,P|257:189|271:223,1,67.4999979400635,0|0,3:2|0:0,0:0:0:0: +148,372,55579,6,0,P|196:272|236:287,1,134.999995880127,8|2,0:0|0:0,0:0:0:0: +286,129,55912,1,0,0:0:0:0: +286,129,56023,2,0,L|252:200,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +383,267,56246,2,0,L|353:206,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +164,44,56468,6,0,P|117:153|167:195,1,179.999994506836,4|2,3:2|0:0,0:0:0:0: +367,78,56801,1,0,0:0:0:0: +283,29,56912,2,0,B|258:71|258:71|278:122,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: +237,264,57134,2,0,B|134:289|203:339|80:358,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: +342,384,57579,6,0,P|338:311|359:294,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +509,173,57801,2,0,B|427:220|427:220|396:193|324:191,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: +248,151,58134,1,0,0:0:0:0: +248,151,58246,1,0,3:2:0:0: +386,20,58468,6,0,P|377:54|336:93,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +157,70,58690,2,0,P|255:58|282:78,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: +348,193,58912,2,0,B|239:203|292:268|180:273,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: +15,170,59357,6,0,P|83:201|96:234,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +21,297,59579,2,0,P|131:262|196:272,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: +269,90,59912,1,0,0:0:0:0: +269,90,60023,6,0,P|221:168|197:181,1,89.9999972534181,0|0,3:2|0:0,0:0:0:0: +124,0,60246,2,0,P|154:98|137:121,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +110,347,60468,6,0,P|90:262|102:236,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: +192,271,60690,2,0,P|242:207|279:202,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +358,379,60912,6,0,P|338:269|386:208,1,179.999994506836,0|2,3:2|0:0,0:0:0:0: +430,30,61246,1,0,0:0:0:0: +505,82,61357,2,0,P|448:123|408:114,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: +291,5,61579,2,0,P|322:87|300:117,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +241,182,61801,2,0,L|151:197,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: +4,119,62023,2,0,B|69:108|69:108|93:85|93:85|186:73,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: +118,348,62468,5,2,0:0:0:0: +68,264,62579,1,0,0:0:0:0: +134,181,62690,2,0,P|165:245|150:275,1,89.9999972534181,0|0,3:2|0:0,0:0:0:0: +264,364,62912,2,0,P|265:290|290:268,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +79,96,63134,2,0,P|195:164|261:119,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: +300,72,63468,1,0,0:0:0:0: +300,72,63579,1,0,3:2:0:0: +188,7,63801,6,0,P|162:57|184:74,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +376,208,64023,2,0,P|375:130|296:71,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: +277,176,64357,1,0,0:0:0:0: +277,176,64468,1,0,3:2:0:0: +474,21,64690,6,0,P|419:95|436:116,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +494,270,64912,2,0,P|423:186|369:216,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: +316,372,65246,1,0,0:0:0:0: +316,372,65357,6,0,B|338:333|338:333|307:292,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: +188,163,65579,2,0,P|211:262|235:269,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +449,141,65801,2,0,P|352:204|277:184,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: +251,27,66134,1,0,0:0:0:0: +251,27,66246,6,0,P|285:84|242:140,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: +131,223,66468,2,0,P|148:182|187:162,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +292,356,66690,1,8,0:1:0:0: +233,273,66801,1,0,3:0:0:0: +283,188,66912,1,8,0:1:0:0: +387,198,67023,1,8,0:1:0:0: +327,275,67134,5,6,3:2:0:0: +22,236,77357,5,8,0:1:0:0: +28,134,77468,1,8,0:1:0:0: +127,121,77579,1,8,0:1:0:0: +193,191,77690,1,8,0:1:0:0: +272,116,77801,6,0,P|290:44|223:90,1,150,6|0,3:2|0:0,0:0:0:0: +158,266,78134,1,0,0:0:0:0: +158,266,78246,2,0,P|130:206|194:192,1,150,8|2,0:0|0:0,0:0:0:0: +268,286,78579,1,0,0:0:0:0: +268,286,78690,6,0,B|244:318|244:318|271:343,1,75,2|0,3:2|0:0,0:0:0:0: +472,268,78912,2,0,B|496:300|496:300|469:325,1,75,2|0,0:0|0:0,0:0:0:0: +382,379,79134,1,10,0:0:0:0: +361,323,79245,1,0,0:0:0:0: +369,264,79356,1,2,0:0:0:0: +341,102,79579,6,0,B|274:102|274:102|258:107|258:107|191:106,1,150,2|0,3:2|0:0,0:0:0:0: +18,82,79912,1,0,0:0:0:0: +18,82,80023,2,0,P|51:13|129:56,1,150,8|2,0:0|0:0,0:0:0:0: +44,222,80357,1,0,0:0:0:0: +31,206,80468,6,0,P|74:167|114:176,1,75,2|0,3:2|0:0,0:0:0:0: +191,106,80690,2,0,P|236:155|231:190,1,75,2|0,0:0|0:0,0:0:0:0: +125,355,80912,1,10,0:0:0:0: +100,316,81023,1,0,0:0:0:0: +122,267,81134,1,2,0:0:0:0: +253,316,81357,6,0,B|353:309|301:365|437:349,1,150,2|0,3:2|0:0,0:0:0:0: +512,190,81690,2,0,B|412:183|464:239|328:223,1,150 +328,71,82023,2,0,P|384:108|378:126,1,75,2|0,0:0|0:0,0:0:0:0: +257,286,82246,6,0,P|263:179|225:153,1,150,2|2,3:2|0:0,0:0:0:0: +163,99,82579,1,0,0:0:0:0: +111,178,82690,2,0,P|88:214|19:223,1,75,10|0,0:0|0:0,0:0:0:0: +81,47,82912,2,0,P|144:5|166:14,1,75,2|0,0:0|0:0,0:0:0:0: +0,177,83134,6,0,P|49:289|19:350,1,150,2|0,3:2|0:0,0:0:0:0: +43,309,83468,1,0,0:0:0:0: +43,309,83579,1,8,0:0:0:0: +139,384,83801,1,0,0:0:0:0: +188,280,84023,5,2,3:2:0:0: +103,89,84246,1,2,0:0:0:0: +224,144,84468,1,10,0:0:0:0: +290,148,84579,1,0,0:0:0:0: +337,103,84690,1,2,0:0:0:0: +339,38,84801,1,0,0:0:0:0: +295,0,84912,6,0,B|287:55|287:55|300:89|300:89|288:161,1,150,2|0,3:2|0:0,0:0:0:0: +225,236,85246,1,0,0:0:0:0: +225,236,85357,1,8,0:0:0:0: +398,86,85579,6,0,B|424:116|424:116|384:129,1,75,2|0,0:0|0:0,0:0:0:0: +115,294,85801,2,0,P|181:225|250:260,1,150,2|0,3:2|0:0,0:0:0:0: +115,294,86246,6,0,P|111:231|142:196,1,75,10|0,0:0|0:0,0:0:0:0: +22,157,86468,1,2,0:0:0:0: +55,100,86579,1,0,0:0:0:0: +119,90,86690,1,0,3:2:0:0: +308,247,86912,6,0,L|218:248,1,75,2|0,0:0|0:0,0:0:0:0: +228,131,87134,1,8,0:0:0:0: +177,357,87357,6,0,L|103:299,1,75,2|0,0:0|0:0,0:0:0:0: +233,249,87579,1,0,3:2:0:0: +15,324,87801,6,0,P|43:256|71:250,1,75,2|0,0:0|0:0,0:0:0:0: +224,165,88023,2,0,L|117:167,1,75,10|0,0:0|0:0,0:0:0:0: +258,70,88246,2,0,L|151:72,1,75,2|0,0:0|0:0,0:0:0:0: +5,16,88468,6,0,P|55:108|28:166,1,150,2|2,3:2|0:0,0:0:0:0: +273,256,88912,6,0,L|174:255,1,75,10|0,0:0|0:0,0:0:0:0: +3,269,89134,2,0,P|14:163|74:140,1,150,2|0,0:0|3:2,0:0:0:0: +124,384,89579,6,0,P|116:316|134:303,1,75,2|0,0:0|0:0,0:0:0:0: +208,188,89801,2,0,P|217:223|198:254,1,75,10|0,0:0|0:0,0:0:0:0: +3,269,90023,1,2,0:0:0:0: +49,218,90134,1,0,0:0:0:0: +115,225,90246,5,0,3:2:0:0: +0,145,90468,2,0,P|79:100|95:105,1,75,2|0,0:0|0:0,0:0:0:0: +218,6,90690,2,0,P|181:111|249:144,1,150,10|0,0:0|0:0,0:0:0:0: +419,145,91134,5,0,3:2:0:0: +479,56,91246,1,0,0:0:0:0: +379,0,91357,2,0,P|363:21|368:69,1,75,8|0,1:2|0:0,0:0:0:0: +512,276,91579,5,10,1:2:0:0: +468,233,91690,1,2,0:0:0:0: +406,261,91801,1,2,0:0:0:0: +318,330,91912,1,2,0:0:0:0: +224,273,92023,6,0,P|193:187|241:145,1,150,6|0,3:2|0:0,0:0:0:0: +318,217,92357,1,0,0:0:0:0: +318,217,92468,1,8,0:0:0:0: +149,15,92690,2,0,P|150:110|166:120,1,75,2|0,0:0|0:0,0:0:0:0: +342,63,92912,6,0,L|230:59,1,75,2|0,3:2|0:0,0:0:0:0: +170,201,93134,2,0,L|282:205,1,75,2|0,0:0|0:0,0:0:0:0: +472,64,93357,1,10,0:0:0:0: +506,125,93468,1,0,0:0:0:0: +462,179,93579,1,2,0:0:0:0: +366,146,93690,1,0,0:0:0:0: +285,212,93801,6,0,P|250:261|286:353,1,150,2|0,3:2|0:0,0:0:0:0: +369,287,94134,1,0,0:0:0:0: +369,287,94246,1,8,0:0:0:0: +219,185,94468,2,0,P|304:203|319:189,1,75,2|0,0:0|0:0,0:0:0:0: +336,23,94690,6,0,L|349:108,1,75,2|0,3:2|0:0,0:0:0:0: +433,84,94912,2,0,L|446:169,1,75,2|0,0:0|0:0,0:0:0:0: +284,211,95134,6,0,L|271:296,1,75,10|0,0:0|0:0,0:0:0:0: +187,272,95356,2,0,L|174:357,1,75,2|0,0:0|0:0,0:0:0:0: +356,383,95579,6,0,P|440:341|498:366,1,150,2|0,3:2|0:0,0:0:0:0: +272,285,96023,2,0,P|200:300|139:259,1,150,8|2,0:0|0:0,0:0:0:0: +201,125,96357,1,0,0:0:0:0: +201,125,96468,6,0,L|223:226,1,75,2|0,3:2|0:0,0:0:0:0: +271,284,96690,2,0,L|256:358,1,75,2|0,0:0|0:0,0:0:0:0: +84,186,96912,2,0,P|155:162|224:210,1,150,10|2,0:0|0:0,0:0:0:0: +147,268,97246,1,0,0:0:0:0: +147,268,97357,5,2,3:2:0:0: +357,138,97579,1,0,0:0:0:0: +176,7,97801,2,0,P|117:41|182:89,1,150,8|2,0:0|0:0,0:0:0:0: +207,270,98134,1,0,0:0:0:0: +207,270,98246,2,0,P|203:234|225:204,1,75,2|0,3:2|0:0,0:0:0:0: +247,69,98468,5,2,0:0:0:0: +294,108,98579,1,0,0:0:0:0: +353,100,98690,1,10,0:0:0:0: +397,60,98801,1,0,0:0:0:0: +496,86,98912,1,2,0:0:0:0: +491,189,99023,1,0,0:0:0:0: +389,228,99134,6,0,B|354:292|354:292|384:376,1,150,2|0,3:2|0:0,0:0:0:0: +271,58,99468,1,0,0:0:0:0: +271,58,99579,2,0,B|306:122|306:122|276:206,1,150,8|2,0:0|0:0,0:0:0:0: +190,352,99912,1,0,0:0:0:0: +190,352,100023,6,0,P|242:308|264:323,1,75,2|0,3:2|0:0,0:0:0:0: +347,176,100246,2,0,P|274:191|256:177,1,75,2|0,0:0|0:0,0:0:0:0: +84,306,100468,1,10,0:0:0:0: +105,243,100579,1,0,0:0:0:0: +170,218,100690,1,2,0:0:0:0: +231,56,100912,6,0,B|226:145|275:94|279:205,1,150,2|0,3:2|0:0,0:0:0:0: +344,370,101246,2,0,B|339:281|388:332|392:221,1,150 +448,146,101579,2,0,P|371:131|346:147,1,75,2|0,0:0|0:0,0:0:0:0: +205,282,101801,6,0,P|272:248|286:222,1,75,2|0,3:2|0:0,0:0:0:0: +197,178,102023,2,0,P|237:97|230:74,1,75,2|0,0:0|0:0,0:0:0:0: +70,284,102246,6,0,P|3:250|-11:224,1,75,10|0,0:0|0:0,0:0:0:0: +78,180,102468,2,0,P|38:99|45:76,1,75,2|0,0:0|0:0,0:0:0:0: +178,15,102690,6,0,P|149:65|148:-12,1,150,2|0,3:2|0:0,0:0:0:0: +281,207,103023,1,0,0:0:0:0: +260,203,103134,2,0,P|249:140|267:124,1,75,8|0,0:0|0:0,0:0:0:0: +354,14,103357,2,0,P|364:49|345:80,1,75 +178,253,103579,6,0,P|147:143|164:103,1,150,2|0,3:2|0:0,0:0:0:0: +379,203,103912,2,0,P|299:238|253:180,1,150,2|0,0:0|0:0,0:0:0:0: +168,324,104246,2,0,P|198:233|219:224,1,75,2|0,0:0|0:0,0:0:0:0: +304,76,104468,6,0,P|249:165|267:216,1,150,2|0,3:2|0:0,0:0:0:0: +464,172,104801,2,0,P|380:201|364:139,1,150,2|0,0:0|0:0,0:0:0:0: +253,328,105134,2,0,P|301:288|335:294,1,75,2|0,0:0|0:0,0:0:0:0: +360,162,105357,6,0,L|275:172,1,75,2|0,3:1|0:0,0:0:0:0: +166,85,105579,2,0,L|251:75,1,75 +166,271,105801,5,10,0:0:0:0: +164,228,105912,1,2,0:0:0:0: +60,177,106023,5,2,0:0:0:0: +59,134,106134,1,2,0:0:0:0: +226,0,106246,6,0,P|147:7|166:85,1,179.999994506836,6|2,3:2|0:0,0:0:0:0: +323,209,106690,2,0,P|335:135|308:100,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +166,85,106912,2,0,P|212:141|196:253,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: +42,125,107246,1,0,0:0:0:0: +20,228,107357,6,0,B|112:200,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +225,148,107579,2,0,P|167:90|160:63,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +176,305,107801,2,0,P|199:266|236:241,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +106,201,108023,1,0,3:2:0:0: +323,179,108246,6,0,L|326:85,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +426,19,108468,2,0,L|423:113,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +371,297,108690,1,2,0:0:0:0: +427,211,108801,1,0,0:0:0:0: +508,272,108912,1,0,3:2:0:0: +302,358,109134,6,0,P|289:263|310:248,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: +169,263,109357,2,0,P|234:186|250:188,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: +418,133,109579,1,2,0:0:0:0: +326,187,109690,1,0,0:0:0:0: +264,99,109801,6,0,P|195:40|115:102,1,179.999994506836,0|2,3:2|0:0,0:0:0:0: +0,243,110134,1,0,0:0:0:0: +0,243,110246,6,0,P|59:195|58:154,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +203,40,110468,2,0,P|153:164|178:208,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: +146,374,110801,1,0,0:0:0:0: +146,374,110912,6,0,P|116:307|85:298,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +271,133,111134,2,0,P|216:237|233:296,1,179.999994506836,10|2,0:0|0:0,0:0:0:0: +398,293,111468,1,0,0:0:0:0: +402,194,111579,6,0,L|309:233,1,89.9999972534181,0|0,3:2|0:0,0:0:0:0: +153,116,111801,2,0,P|175:203|198:209,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +436,63,112023,2,0,L|258:138,1,179.999994506836,10|2,0:0|0:0,0:0:0:0: +301,18,112357,1,2,0:0:0:0: +301,18,112468,1,2,3:2:0:0: +153,116,112690,6,0,P|131:69|147:30,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: +335,186,112912,2,0,P|291:137|238:139,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: +197,215,113134,1,2,0:0:0:0: +197,215,113357,1,0,3:2:0:0: +246,30,113579,6,0,B|286:49|286:49|334:14,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +487,128,113801,2,0,B|447:147|447:147|399:112,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +307,215,114023,1,2,0:0:0:0: +307,215,114246,1,0,3:2:0:0: +306,214,114468,6,0,P|286:254|300:295,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: +420,354,114690,2,0,P|430:310|411:271,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: +232,153,114912,2,0,P|184:262|212:331,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: +232,153,115357,6,0,P|257:66|229:42,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +134,49,115579,2,0,P|106:104|129:146,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +379,208,115801,2,0,P|284:139|210:168,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: +291,331,116246,6,0,P|263:280|254:311,1,89.9999972534181,8|0,1:2|0:0,0:0:0:0: +98,122,116468,2,0,P|107:201|135:220,1,89.9999972534181,8|0,1:2|0:0,0:0:0:0: +303,183,116690,2,0,P|227:190|210:207,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +120,366,116912,6,0,P|145:255|12:288,1,269.999991760254,2|0,3:2|0:0,0:0:0:0: +24,257,117357,6,0,P|67:246|99:215,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +171,32,117579,2,0,B|136:90|150:180|246:133|269:227|205:313,1,269.999991760254,2|0,0:0|0:0,0:0:0:0: +228,273,118023,6,0,P|231:197|256:178,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +341,196,118246,2,0,P|360:235|349:278,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +211,45,118468,5,2,0:0:0:0: +283,109,118579,1,0,0:0:0:0: +349,39,118690,2,0,P|429:21|452:48,1,89.9999972534181,0|0,3:2|0:0,0:0:0:0: +512,138,118912,2,0,P|432:156|409:129,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +305,379,119134,6,0,P|285:270|329:203,1,179.999994506836,10|2,0:0|0:0,0:0:0:0: +145,89,119468,1,2,0:0:0:0: +236,33,119579,2,0,P|251:110|236:133,1,89.9999972534181,0|0,3:2|0:0,0:0:0:0: +98,245,119801,2,0,P|146:221|203:239,1,89.9999972534181,10|2,1:2|0:0,0:0:0:0: +357,302,120023,1,10,1:2:0:0: +317,213,120134,1,2,0:0:0:0: +379,134,120246,1,2,0:0:0:0: +475,159,120357,1,2,0:0:0:0: +412,227,120468,5,4,3:2:0:0: +507,0,120690,2,0,P|435:60|399:38,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +205,127,120912,2,0,P|202:45|236:13,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +317,15,121134,2,0,P|339:136|311:198,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: +211,253,121468,1,0,0:0:0:0: +211,253,121579,6,0,L|89:246,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +117,78,121801,2,0,L|239:71,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +319,185,122023,2,0,P|271:285|294:349,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: +511,320,122357,1,0,0:0:0:0: +436,249,122468,6,0,P|389:261|393:314,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +312,102,122690,2,0,P|304:160|337:201,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +411,384,122912,2,0,P|288:314|219:351,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: +120,232,123246,1,0,0:0:0:0: +120,232,123357,6,0,B|86:259|86:259|134:278,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: +185,60,123579,2,0,B|219:87|219:87|171:106,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: +0,305,123801,2,0,P|-9:235|25:201,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +175,104,124023,6,0,B|127:105|92:141|92:141|60:100|-7:103,1,179.999994506836,0|2,3:2|0:0,0:0:0:0: +206,283,124357,1,0,0:0:0:0: +206,283,124468,2,0,L|164:180,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +288,193,124690,2,0,L|309:88,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +358,14,124912,6,0,P|459:38|428:140,1,179.999994506836,0|2,3:2|0:0,0:0:0:0: +363,246,125246,1,0,0:0:0:0: +288,193,125357,2,0,P|366:153|402:176,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +477,281,125579,2,0,L|452:401,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +224,50,125801,2,0,P|291:186|234:240,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: +216,266,126134,1,0,0:0:0:0: +261,353,126246,1,8,0:0:0:0: +158,188,126468,5,2,0:0:0:0: +105,268,126579,1,2,0:0:0:0: +147,355,126690,2,0,L|278:362,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: +305,270,126912,2,0,L|174:263,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: +71,77,127134,2,0,P|39:189|74:189,1,179.999994506836,10|2,1:2|0:0,0:0:0:0: +145,172,127468,1,0,0:0:0:0: +105,268,127579,1,0,3:2:0:0: +167,76,127801,6,0,P|229:145|221:176,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +210,346,128023,2,0,P|218:262|235:253,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: +493,209,128246,2,0,B|443:201|443:201|379:219|379:219|279:209,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: +404,107,128690,6,0,P|464:91|472:123,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +332,362,128912,2,0,B|373:282|373:282|302:196,1,179.999994506836,10|2,0:0|0:0,0:0:0:0: +118,206,129246,1,0,0:0:0:0: +185,135,129357,6,0,L|217:245,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: +381,119,129579,2,0,P|299:97|280:105,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +130,56,129801,6,0,P|90:145|95:157,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: +363,274,130023,2,0,P|303:207|264:212,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +121,364,130246,5,2,3:2:0:0: +199,178,130468,1,0,0:0:0:0: +71,243,130690,2,0,B|159:307|137:227|247:303,1,180,10|0,0:0|0:0,0:0:0:0: +350,384,131134,6,0,P|347:313|381:284,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +512,189,131357,1,0,0:0:0:0: +418,145,131468,2,0,P|430:183|419:222,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +258,98,131690,1,0,0:0:0:0: +322,184,131801,1,2,3:2:0:0: +259,270,131912,1,0,0:0:0:0: +197,184,132023,5,10,1:2:0:0: +400,134,132468,6,0,P|409:205|391:227,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +110,214,132690,2,0,P|101:143|119:121,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +259,270,132912,5,2,0:0:0:0: +196,53,133134,1,0,3:2:0:0: +196,53,133246,2,0,B|182:90|182:90|208:156,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +318,51,133468,1,0,3:2:0:0: +318,51,133580,2,0,B|332:88|332:88|306:154,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +259,270,133801,1,10,1:2:0:0: +259,270,134246,6,0,B|243:311|243:311|263:367,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +45,203,134468,1,2,3:2:0:0: +78,202,134579,1,0,3:2:0:0: +166,251,134690,6,0,B|182:210|182:210|162:154,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +85,27,134912,2,0,B|72:63|72:63|88:104,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +0,226,135134,6,0,B|32:220|32:220|45:210|45:210|86:201,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +266,92,135357,2,0,B|234:86|234:86|221:76|221:76|180:67,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +130,373,135579,1,10,1:2:0:0: +108,310,135690,1,0,0:0:0:0: +159,262,135801,1,2,3:2:0:0: +250,304,135912,1,0,0:0:0:0: +341,248,136023,6,0,P|321:161|293:158,1,82.5000025177003,2|0,0:0|3:2,0:0:0:0: +442,119,136246,2,0,P|401:63|358:55,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +250,21,136468,6,0,L|257:136,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +107,212,136690,1,0,0:0:0:0: +23,181,136801,2,0,P|69:125|175:156,1,165.000005035401,2|0,3:2|0:0,0:0:0:0: +229,189,137134,1,2,3:2:0:0: +224,287,137246,1,0,0:0:0:0: +220,384,137357,1,10,1:2:0:0: +220,384,137579,6,0,P|282:346|321:363,1,82.5000025177003,0|0,3:2|0:0,0:0:0:0: +505,241,137801,1,2,3:2:0:0: +442,269,137912,1,0,3:2:0:0: +382,242,138023,1,0,3:2:0:0: +307,183,138134,1,0,3:2:0:0: +222,224,138246,6,0,B|121:224|174:283|58:275,1,165.000005035401,2|0,3:2|0:0,0:0:0:0: +71,171,138579,2,0,B|164:167|132:223|221:223,1,165.000005035401,2|0,3:2|0:0,0:0:0:0: +343,94,138912,2,0,L|250:94,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +134,26,139134,1,10,1:2:0:0: +134,26,139357,5,2,0:0:0:0: +104,77,139468,1,2,0:0:0:0: +129,129,139579,1,2,0:0:0:0: +188,207,139690,1,2,0:0:0:0: +114,291,139801,2,0,P|94:232|106:204,1,82.5000025177003,2|2,0:0|0:0,0:0:0:0: +216,85,140023,6,0,L|315:85,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +432,90,140246,1,0,3:2:0:0: +347,152,140357,2,0,B|310:78|310:78|374:-13,1,165.000005035401,2|0,0:0|3:2,0:0:0:0: +512,253,140690,1,2,0:0:0:0: +441,179,140801,1,0,0:0:0:0: +376,255,140912,1,10,1:2:0:0: +376,255,141357,6,0,P|391:303|372:346,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +245,219,141579,2,0,P|236:179|251:141,1,82.5000025177003,2|0,3:2|3:2,0:0:0:0: +179,302,141801,2,0,P|141:229|145:204,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +368,164,142023,5,2,3:2:0:0: +342,166,142134,1,0,0:0:0:0: +177,98,142246,2,0,L|295:88,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +341,0,142468,2,0,P|365:64|341:94,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +245,219,142690,1,10,1:2:0:0: +461,112,142912,5,2,3:2:0:0: +461,112,143023,2,0,P|451:180|470:205,1,82.5000025177003,2|2,0:0|0:0,0:0:0:0: +368,371,143246,2,0,P|377:331|362:294,1,82.5000025177003,0|0,3:2|0:0,0:0:0:0: +192,166,143468,2,0,B|244:218|244:218|299:189|360:191,1,165.000005035401,2|0,3:2|0:0,0:0:0:0: +315,32,143801,2,0,P|282:53|279:106,1,82.5000025177003,0|0,3:2|0:0,0:0:0:0: +268,351,144023,5,2,0:0:0:0: +282,287,144134,1,0,0:0:0:0: +230,251,144246,1,2,3:2:0:0: +138,305,144357,1,0,0:0:0:0: +59,249,144468,2,0,P|44:207|61:168,1,82.5000025177003,10|2,1:2|0:0,0:0:0:0: +144,128,144690,2,0,P|159:170|142:209,1,82.5000025177003,2|2,3:2|0:0,0:0:0:0: +18,81,144912,5,2,3:2:0:0: +69,1,145023,1,2,3:2:0:0: +172,11,145134,1,2,3:2:0:0: +231,98,145246,1,2,3:2:0:0: +303,28,145357,6,0,P|335:2|375:0,1,82.5000025177003,6|0,3:2|0:0,0:0:0:0: +384,220,145579,1,2,0:0:0:0: +285,192,145690,2,0,P|301:154|337:135,1,82.5000025177003,0|10,0:0|0:0,0:0:0:0: +507,85,145912,2,0,P|459:98|453:40,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +509,243,146134,1,2,0:0:0:0: +509,243,146246,2,0,P|453:200|415:220,1,82.5000025177003,0|0,3:2|0:0,0:0:0:0: +270,374,146468,6,0,L|289:281,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +168,143,146690,2,0,L|187:236,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: +401,283,146912,2,0,P|370:216|337:203,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +50,214,147134,6,0,P|130:259|186:220,1,165.000005035401,2|2,3:2|0:3,0:0:0:0: +306,64,147468,1,0,0:0:0:0: +204,48,147579,2,0,L|226:154,2,82.5000025177003,10|2|0,0:0|0:0|0:0,0:0:0:0: +360,154,147912,2,0,B|321:223|321:223|351:257|345:323,1,165.000005035401,2|0,0:0|0:0,0:0:0:0: +208,368,148246,6,0,P|205:321|242:322,1,82.5000025177003,10|0,1:2|0:0,0:0:0:0: +106,264,148468,2,0,P|180:216|220:225,1,82.5000025177003,10|0,1:2|0:0,0:0:0:0: +399,200,148690,2,0,P|310:219|283:201,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +126,128,148912,6,0,P|223:144|235:175,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +249,36,149134,2,0,P|299:87|299:131,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +388,280,149357,6,0,P|429:274|460:249,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: +390,178,149579,2,0,P|412:144|412:104,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +272,286,149801,6,0,B|292:320|292:320|271:386,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: +161,270,150023,2,0,B|147:228|147:228|167:194,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +390,178,150246,6,0,L|279:188,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: +55,95,150468,1,2,0:0:0:0: +20,98,150579,1,0,0:0:0:0: +119,18,150690,2,0,P|210:28|208:130,1,165.000005035401,0|2,3:2|0:0,0:0:0:0: +68,214,151023,1,0,0:0:0:0: +170,229,151134,6,0,L|144:137,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: +263,286,151357,2,0,L|240:365,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +94,322,151579,1,2,3:2:0:0: +394,216,151801,1,8,1:2:0:0: +370,57,152023,6,0,P|256:62|299:199,1,247.500007553101,10|0,1:2|0:0,0:0:0:0: +317,120,152468,6,0,B|213:98|254:179|118:129,1,165.000005035401,2|0,3:2|0:0,0:0:0:0: +8,52,152912,6,0,B|15:12|15:12|52:58,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: +317,120,153134,2,0,B|213:98|254:179|118:129,1,165.000005035401,2|0,0:0|3:2,0:0:0:0: +71,190,153579,5,2,0:0:0:0: +38,191,153690,1,0,0:0:0:0: +158,141,153801,2,0,P|171:212|142:247,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: +93,372,154023,2,0,P|80:301|109:266,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +255,62,154246,6,0,P|296:144|264:245,1,165.000005035401,2|2,3:2|0:3,0:0:0:0: +202,347,154690,6,0,B|170:324|170:324|216:315,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: +255,62,154912,2,0,P|296:144|264:245,1,165.000005035401,2|0,0:0|3:2,0:0:0:0: +488,313,155357,5,2,0:0:0:0: +454,314,155468,1,0,0:0:0:0: +367,355,155579,2,0,P|355:297|373:269,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: +503,146,155801,2,0,P|465:192|425:193,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +220,123,156023,6,0,B|288:121|341:175|341:175|303:177|278:218,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: +111,158,156357,2,0,B|75:99|95:26|95:26|116:58|164:59,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: +186,229,156690,2,0,B|173:263|137:278|137:278|143:259|127:239,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +220,123,156912,5,2,0:0:0:0: +186,229,157060,1,2,0:0:0:0: +111,158,157209,1,2,0:0:0:0: +288,199,157357,5,2,0:0:0:0: +94,258,157505,1,2,0:0:0:0: +144,56,157653,1,2,0:0:0:0: +150,383,157801,6,0,P|192:314|249:328,1,134.999995880127,6|2,3:2|0:0,0:0:0:0: +359,145,158246,1,2,0:0:0:0: +270,182,158468,2,0,P|330:249|412:225,1,134.999995880127,2|8,3:2|0:0,0:0:0:0: +359,145,158912,1,2,0:0:0:0: +236,319,159134,1,2,0:0:0:0: +460,160,159357,1,2,0:0:0:0: +233,22,159579,6,0,B|218:118|280:81|268:192,2,168.750006437302,0|0|2,3:2|3:2|3:2,0:0:0:0: +454,29,160468,2,0,P|363:52|339:6,1,134.999995880127,8|2,0:0|0:0,0:0:0:0: +173,216,160912,1,2,0:0:0:0: +433,204,161134,1,2,3:2:0:0: +433,204,161246,1,0,3:2:0:0: +433,204,161357,6,0,B|380:169|363:120|363:120|318:175|246:185,1,225.000008583069,2|0,3:2|0:0,0:0:0:0: +268,79,162023,1,2,3:2:0:0: +344,362,162246,2,0,P|330:283|279:298,1,134.999995880127,10|2,0:0|0:0,0:0:0:0: +159,224,162690,1,2,0:0:0:0: +316,154,162912,1,2,0:0:0:0: +213,21,163134,6,0,P|174:99|217:83,2,202.499993820191,0|0|2,3:2|3:2|3:2,0:0:0:0: +337,271,164023,2,0,P|332:183|278:170,1,134.999995880127,10|2,0:0|0:0,0:0:0:0: +99,334,164468,1,8,3:0:0:0: +133,332,164579,1,8,3:0:0:0: +166,329,164690,1,2,3:2:0:0: +200,326,164801,1,0,3:2:0:0: +234,251,164912,6,0,P|161:221|133:296,1,134.999995880127,2|0,3:2|0:0,0:0:0:0: +67,174,165357,1,2,0:0:0:0: +234,251,165579,2,0,P|224:132|257:102,1,134.999995880127,2|8,3:2|0:0,0:0:0:0: +391,159,166023,6,0,L|292:169,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +253,28,166246,2,0,P|307:88|298:107,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +209,188,166468,2,0,P|215:140|241:119,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +444,248,166690,6,0,B|365:259|365:259|363:268|363:268|273:278,2,168.750006437302,0|0|2,3:2|3:2|3:2,0:0:0:0: +216,360,167579,1,10,0:0:0:0: +177,264,167801,1,2,0:0:0:0: +312,162,168023,1,2,0:0:0:0: +266,190,168134,1,0,0:0:0:0: +218,166,168245,1,2,3:2:0:0: +213,112,168356,1,0,3:2:0:0: +287,65,168468,6,0,P|209:115|167:19,1,225.000008583069,2|0,3:2|0:0,0:0:0:0: +0,205,169134,1,2,3:2:0:0: +54,125,169357,2,0,P|96:193|81:231,1,112.500004291535,10|2,0:0|0:0,0:0:0:0: +254,281,169801,1,2,0:0:0:0: +192,190,170023,1,2,0:0:0:0: +0,355,170246,6,0,B|101:354|39:279|186:296,2,168.750006437302,0|0|0,3:2|3:2|3:2,0:0:0:0: +0,355,171134,1,8,0:0:0:0: +219,363,171357,1,2,0:0:0:0: +120,195,171579,5,8,3:0:0:0: +153,196,171690,1,8,3:0:0:0: +187,198,171801,1,2,3:2:0:0: +221,200,171912,1,0,3:2:0:0: +297,155,172023,6,0,B|270:200|270:200|293:311,1,134.999995880127,4|2,3:2|0:0,0:0:0:0: +455,238,172357,1,0,0:0:0:0: +455,238,172468,2,0,L|338:221,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: +307,52,172690,6,0,P|384:74|380:168,1,134.999995880127,2|0,0:0|3:2,0:0:0:0: +182,98,173134,2,0,L|163:-8,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +281,162,173357,2,0,L|269:228,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: +45,296,173579,1,2,0:0:0:0: +45,296,173690,1,0,0:0:0:0: +45,296,173801,6,0,P|130:221|171:258,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: +222,366,174134,1,0,0:0:0:0: +222,366,174246,2,0,P|197:314|208:285,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: +287,253,174468,2,0,P|314:209|353:204,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +506,116,174690,6,0,B|447:141|447:141|420:105|345:102,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: +229,72,175023,1,0,0:0:0:0: +229,72,175134,2,0,L|247:155,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: +312,269,175357,2,0,L|330:186,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +146,16,175579,6,0,P|127:120|174:161,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: +248,229,175912,1,0,0:0:0:0: +248,229,176023,2,0,L|144:219,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: +36,384,176246,1,2,0:0:0:0: +20,335,176357,1,0,0:0:0:0: +64,300,176468,6,0,B|118:308|118:308|142:328|142:328|238:346,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: +298,384,176801,1,0,0:0:0:0: +298,384,176912,2,0,B|286:345|286:345|313:304,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: +423,236,177134,2,0,B|435:275|435:275|420:297,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +217,241,177357,5,2,3:2:0:0: +300,31,177579,1,2,0:0:0:0: +343,86,177690,1,0,0:0:0:0: +314,148,177801,1,0,3:2:0:0: +83,79,178023,1,2,0:0:0:0: +83,79,178134,1,0,0:0:0:0: +83,79,178246,6,0,B|144:115|144:115|248:86,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: +337,20,178579,1,0,0:0:0:0: +337,20,178690,2,0,L|315:98,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: +214,239,178912,2,0,P|262:196|282:201,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +435,127,179134,6,0,B|392:193|392:193|423:282,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: +475,356,179468,1,0,0:0:0:0: +475,356,179579,2,0,L|515:281,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: +278,168,179801,2,0,L|310:261,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +351,348,180023,6,0,B|256:331|314:385|179:357,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: +104,353,180357,1,0,0:0:0:0: +104,353,180468,2,0,L|155:278,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: +0,219,180690,2,0,L|74:294,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +245,273,180912,6,0,P|204:201|163:200,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: +352,194,181134,2,0,P|297:126|268:128,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +37,82,181357,2,0,P|74:136|85:139,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: +188,19,181579,2,0,P|169:93|177:115,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: +342,220,181801,5,2,3:2:0:0: +268,81,182023,1,2,0:0:0:0: +158,195,182246,1,2,0:0:0:0: +309,231,182690,6,0,P|290:300|302:320,1,67.4999979400635,6|0,3:1|0:0,0:0:0:0: +388,302,182912,2,0,P|378:341|397:377,1,82.5000025177003,10|0,3:2|0:0,0:0:0:0: +490,52,183134,6,0,P|509:121|497:141,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: +414,120,183357,2,0,P|423:159|405:194,1,82.5000025177003,10|0,3:2|0:0,0:0:0:0: +269,0,183579,5,2,3:2:0:0: +320,15,183690,1,0,3:2:0:0: +340,64,183801,1,2,3:2:0:0: +311,124,183912,1,0,3:2:0:0: +225,160,184023,1,2,3:2:0:0: +160,95,184134,1,0,3:2:0:0: +79,145,184246,6,0,B|51:288|151:224|132:390,1,247.500007553101,6|0,3:1|0:0,0:0:0:0: +133,376,184690,1,2,3:2:0:0: +169,151,184912,6,0,B|138:293|71:195|24:355,1,255.000004863739,2|0,3:2|0:0,0:0:0:0: +26,350,185357,6,2,P|85:330|100:329,1,78.7499975967408,2|0,0:0|0:0,0:0:0:0: +205,384,186246,6,0,P|209:280|316:280,1,194.999991073609,6|2,3:2|0:0,0:0:0:0: +410,99,186579,1,0,0:0:0:0: +471,176,186690,2,0,P|405:200|366:187,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +242,64,186912,2,0,P|287:118|279:174,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +283,261,187134,6,0,B|168:256|219:328|88:321,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +112,217,187468,1,0,0:0:0:0: +112,217,187579,2,0,P|115:157|45:187,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +0,293,187801,2,0,L|38:394,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +220,151,188023,6,0,P|151:47|55:48,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +198,286,188357,1,0,0:0:0:0: +198,286,188468,2,0,P|120:246|81:262,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +328,384,188690,2,0,P|316:307|345:274,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +506,165,188912,6,0,B|412:205|412:205|376:177|313:173,1,194.999991073609,0|10,3:2|1:2,0:0:0:0: +136,81,189246,1,0,0:0:0:0: +219,40,189357,2,0,B|253:72|253:72|265:20,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +333,253,189579,2,0,B|321:203|321:203|287:235,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +78,253,189801,6,0,B|130:342|170:284|216:384,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +245,161,190134,1,0,0:0:0:0: +245,161,190246,2,0,P|196:216|158:210,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +11,128,190468,2,0,P|92:136|110:176,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +55,345,190690,6,0,B|164:350|137:295|272:323,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +405,194,191023,1,0,0:0:0:0: +405,194,191134,2,0,P|361:268|371:302,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +498,363,191357,2,0,P|475:287|487:271,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +468,72,191579,6,0,P|411:134|277:107,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +101,81,191912,1,0,0:0:0:0: +182,24,192023,2,0,L|204:144,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +302,384,192246,1,2,0:0:0:0: +355,305,192357,1,2,0:0:0:0: +281,239,192468,2,0,P|228:226|184:273,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +18,347,192690,6,0,B|15:372|15:372|87:314,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +89,106,192912,2,0,B|71:88|71:88|72:180,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +252,287,193134,2,0,B|276:280|276:280|195:235,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +111,244,193357,1,0,3:2:0:0: +215,37,193579,6,0,P|207:136|219:148,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +371,126,193801,2,0,P|379:78|356:36,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +282,276,194023,1,2,0:0:0:0: +282,276,194246,1,0,3:2:0:0: +239,195,194468,6,0,B|280:174|280:174|355:201,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +508,248,194690,2,0,B|459:265|459:265|418:244,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +334,56,194912,2,0,P|399:57|460:179,1,194.999991073609,2|0,0:0|3:2,0:0:0:0: +316,273,195357,6,0,P|334:188|363:187,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +253,92,195579,2,0,P|318:52|346:60,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +418,244,195801,2,0,B|299:221|358:308|183:270,1,194.999991073609,2|0,0:0|3:2,0:0:0:0: +96,93,196246,6,0,P|153:126|137:194,1,97.4999955368044,8|0,1:2|0:0,0:0:0:0: +36,291,196468,2,0,B|18:239|18:239|60:184,1,97.4999955368044,8|0,1:2|0:0,0:0:0:0: +316,108,196690,2,0,L|230:227,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +158,342,196912,6,0,B|175:373|214:367|214:367|215:374|215:374|214:367|214:367|246:362|265:336|265:336|286:310|318:301|318:301|318:295|318:295|318:301|318:301|386:305|389:362,1,292.499986610413,2|0,3:2|0:0,0:0:0:0: +381,332,197357,6,0,P|381:252|411:230,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +512,116,197579,2,0,B|495:147|456:141|456:141|455:148|455:148|456:141|456:141|424:136|405:110|405:110|384:84|352:75|352:75|352:69|352:69|352:75|352:75|284:79|272:131,1,292.499986610413,2|0,0:0|0:0,0:0:0:0: +285,102,198023,6,0,P|312:180|272:225,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +139,368,198246,2,0,P|134:320|162:281,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +202,186,198468,5,2,0:0:0:0: +116,180,198579,1,0,0:0:0:0: +60,113,198690,2,0,P|141:92|164:124,1,97.4999955368044,0|0,3:2|0:0,0:0:0:0: +259,291,198912,2,0,L|162:280,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +187,7,199134,6,0,P|257:107|215:171,1,194.999991073609,10|2,0:0|0:0,0:0:0:0: +72,342,199468,1,2,0:0:0:0: +0,282,199579,2,0,P|81:247|110:277,1,97.4999955368044,0|0,3:2|0:0,0:0:0:0: +173,337,199801,2,0,P|229:363|267:339,1,97.4999955368044,10|2,1:2|0:0,0:0:0:0: +494,181,200023,1,10,1:2:0:0: +402,122,200134,1,2,0:0:0:0: +323,194,200246,1,2,0:0:0:0: +371,288,200357,1,2,0:0:0:0: +414,207,200468,6,0,B|280:178|340:289|201:251,1,194.999991073609,4|2,3:2|0:0,0:0:0:0: +132,162,200801,1,0,0:0:0:0: +132,162,200912,2,0,B|146:118|146:118|196:163,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +236,258,201134,2,0,L|219:366,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +58,251,201357,6,0,P|9:125|49:76,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +190,71,201690,1,0,0:0:0:0: +229,171,201801,2,0,L|108:159,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +63,335,202023,2,0,P|142:294|162:315,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +408,277,202246,6,0,B|354:286|319:240|319:240|294:290|202:297,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +213,85,202579,1,0,0:0:0:0: +213,85,202690,2,0,P|236:158|201:190,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +49,312,202912,1,2,0:0:0:0: +24,224,203023,1,0,0:0:0:0: +122,233,203134,6,0,P|208:291|149:395,1,194.999991073609,0|10,3:2|1:2,0:0:0:0: +146,71,203468,1,0,0:0:0:0: +146,71,203579,2,0,P|196:120|196:163,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +307,98,203801,2,0,P|297:208|287:220,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +148,315,204023,6,0,B|228:306|228:306|270:322|270:322|373:308,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +481,270,204357,1,0,0:0:0:0: +481,270,204468,2,0,B|517:310|517:310|466:356,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +374,187,204690,2,0,L|451:101,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +246,22,204912,6,0,P|208:145|273:199,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +284,353,205246,1,0,0:0:0:0: +377,329,205357,2,0,P|327:270|268:270,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +140,351,205579,2,0,P|187:328|197:278,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +71,229,205801,5,2,3:2:0:0: +284,353,206023,1,2,0:0:0:0: +310,265,206134,1,0,0:0:0:0: +270,189,206246,2,0,L|153:191,1,97.4999955368044,8|0,0:0|0:0,0:0:0:0: +0,130,206468,1,2,0:0:0:0: +21,49,206579,1,2,0:0:0:0: +108,42,206690,6,0,P|190:129|154:209,1,194.999991073609,2|10,3:2|1:2,0:0:0:0: +20,323,207023,1,0,0:0:0:0: +20,323,207134,2,0,P|93:284|124:294,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +251,384,207357,2,0,P|232:302|257:278,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +480,209,207579,6,0,B|370:251|370:251|335:217|279:208,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +130,123,207912,1,0,0:0:0:0: +130,123,208023,2,0,P|204:170|211:144,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +368,138,208246,2,0,P|284:112|264:122,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +133,360,208468,6,0,P|222:286|302:323,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +442,306,208801,1,0,0:0:0:0: +442,306,208912,2,0,P|389:391|391:399,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +512,182,209134,2,0,P|421:189|393:166,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +275,16,209357,6,0,B|325:101|322:148|322:148|286:221,1,194.999991073609,2|2,3:2|0:0,0:0:0:0: +141,195,209690,1,0,0:0:0:0: +141,195,209801,2,0,P|196:134|218:148,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +55,267,210023,2,0,P|30:180|46:160,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +223,260,210246,6,0,L|212:373,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +327,210,210468,2,0,L|316:323,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +104,111,210690,6,0,P|142:186|125:229,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +253,11,210912,2,0,P|263:54|207:107,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +29,278,211134,6,0,P|146:261|263:261,1,194.999991073609,2|2,3:2|0:0,0:0:0:0: +399,188,211468,1,0,0:0:0:0: +399,188,211579,2,0,P|317:170|261:169,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +316,367,211801,2,0,P|331:289|327:261,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +191,159,212023,5,2,3:2:0:0: +384,83,212246,1,0,0:0:0:0: +384,83,212357,1,2,0:0:0:0: +256,0,212579,1,0,0:0:0:0: +256,0,212690,2,0,P|273:82|276:107,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +370,188,212912,6,0,P|340:300|337:385,1,194.999991073609,2|2,3:2|0:0,0:0:0:0: +111,169,213246,1,0,0:0:0:0: +111,169,213357,2,0,P|139:261|141:294,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: +254,288,213579,2,0,P|235:333|225:380,1,97.4999955368044,2|2,0:0|0:0,0:0:0:0: +36,223,213801,5,2,3:2:0:0: +2,171,213912,1,0,0:0:0:0: +19,113,214023,1,10,1:2:0:0: +92,47,214134,1,2,0:0:0:0: +189,76,214246,1,10,1:2:0:0: +205,179,214357,1,2,0:0:0:0: +305,229,214468,1,2,0:0:0:0: +395,167,214579,1,2,0:0:0:0: +306,121,214690,5,0,3:2:0:0: +306,149,215134,5,10,3:2:0:0: +302,179,215579,5,0,3:2:0:0: +299,214,216023,5,10,3:2:0:0: +295,261,216468,5,2,3:2:0:0: +206,318,216690,1,2,0:3:0:0: +128,248,216912,1,10,0:0:0:0: +177,139,217134,1,2,0:3:0:0: +289,164,217357,1,2,3:2:0:0: +358,74,217579,1,2,0:0:0:0: +243,22,217801,6,0,B|202:147|303:106|250:272,1,225,2|0,0:0|0:0,0:0:0:0: +99,350,218246,6,0,P|168:328|194:337,1,97.4999955368044,6|0,3:2|0:0,0:0:0:0: +316,338,218468,2,0,P|240:364|173:303,1,142.49999619484,2|8,0:0|0:2,0:0:0:0: +188,186,218912,6,0,P|239:202|256:270,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +77,265,219134,2,0,P|60:150|116:103,1,142.49999619484,2|0,3:2|0:0,0:0:0:0: +204,44,219468,1,0,0:0:0:0: +204,44,219579,6,0,P|137:13|129:-2,1,71.2499980974198,10|0,0:2|0:0,0:0:0:0: +272,136,219801,2,0,P|197:164|159:145,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +345,38,220023,2,0,P|456:12|474:33,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +293,246,220246,2,0,P|276:181|290:143,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +454,119,220468,6,0,P|416:246|453:303,1,194.999991073609,10|0,0:2|0:0,0:0:0:0: +267,384,220801,1,0,0:0:0:0: +330,303,220912,6,0,P|268:269|245:302,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +122,252,221134,2,0,P|79:333|84:345,1,71.2499980974198,10|0,1:2|0:0,0:0:0:0: +358,189,221357,6,0,P|289:168|250:180,1,71.2499980974198,10|0,1:2|0:0,0:0:0:0: +122,252,221579,2,0,L|152:398,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: +180,89,221801,6,0,B|55:104|133:146|-49:161,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: +2,52,222134,2,0,B|117:58|67:119|182:118,1,194.999991073609,2|0,0:0|0:0,0:0:0:0: +310,3,222468,2,0,B|347:42|347:42|311:75,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +86,282,222690,2,0,B|155:215|155:215|265:257,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +390,135,223023,1,0,0:0:0:0: +390,135,223134,2,0,L|412:260,1,82.5000025177003,10|0,1:2|0:0,0:0:0:0: +503,302,223357,2,0,L|488:383,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: +272,306,223579,6,0,P|347:207|430:235,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: +368,309,223912,2,0,P|296:207|218:210,1,194.999991073609,2|0,0:0|0:0,0:0:0:0: +131,384,224246,2,0,P|129:313|161:289,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +95,94,224468,2,0,P|116:171|94:194,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +18,376,224690,6,0,P|67:273|120:290,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +221,91,224912,2,0,P|210:34|162:-4,1,112.500004291535,10|0,1:2|0:0,0:0:0:0: +0,195,225134,2,0,P|77:180|169:186,1,112.500004291535 +225,279,225357,6,0,L|251:375,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +303,187,225579,2,0,P|331:252|280:327,1,142.49999619484,2|8,0:0|1:2,0:0:0:0: +7,167,226023,6,0,P|67:123|100:129,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +256,71,226246,2,0,P|176:51|142:-21,1,142.49999619484,2|0,3:2|0:0,0:0:0:0: +181,209,226579,1,0,0:0:0:0: +181,209,226690,6,0,P|138:285|147:304,1,71.2499980974198,10|0,1:2|0:0,0:0:0:0: +259,383,226912,2,0,P|246:302|267:274,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +479,317,227134,2,0,L|370:331,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +181,209,227357,2,0,P|247:154|298:163,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +510,38,227579,6,0,B|435:75|435:75|415:32|348:-2,1,194.999991073609,10|0,1:2|0:0,0:0:0:0: +254,153,227912,1,0,0:0:0:0: +327,97,228023,6,0,P|353:160|325:211,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +160,133,228246,2,0,P|215:57|261:66,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: +59,248,228468,6,0,P|24:161|35:136,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +210,274,228690,2,0,P|168:364|174:386,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: +124,143,228912,6,0,B|182:129|219:166|219:166|250:107|325:100,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: +436,260,229246,2,0,B|378:274|341:237|341:237|310:296|235:303,1,194.999991073609,2|0,0:0|0:0,0:0:0:0: +392,42,229579,2,0,P|429:107|421:134,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +164,360,229801,2,0,P|253:276|274:299,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +234,80,230134,1,0,0:0:0:0: +331,158,230246,6,0,B|287:165|287:165|280:174|280:174|220:186,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +114,95,230468,2,0,B|73:86|73:86|66:77|66:77|22:70,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +68,355,230690,6,0,B|21:369|21:369|49:289|49:289|43:276|43:276|82:198,1,225.000008583069,2|0,3:2|0:0,0:0:0:0: +194,44,231023,2,0,B|148:28|148:28|172:108|172:108|166:121|166:121|204:209,1,225.000008583069,2|0,0:0|0:0,0:0:0:0: +246,376,231357,2,0,P|233:337|148:343,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +351,144,231579,2,0,P|305:206|303:239,1,97.4999955368044,0|0,3:2|0:2,0:0:0:0: +439,384,231801,6,0,P|427:318|383:294,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +464,28,232023,2,0,P|503:54|512:100,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +404,300,232246,2,0,P|393:255|418:215,1,97.4999955368044,2|0,1:2|0:0,0:0:0:0: +219,236,232468,6,0,P|245:187|282:175,1,97.4999955368044,6|0,3:2|0:0,0:0:0:0: +342,39,232690,2,0,P|358:126|314:164,1,142.49999619484,2|8,0:0|0:2,0:0:0:0: +126,136,233134,6,0,P|190:83|210:85,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +443,238,233357,2,0,P|363:250|255:282,1,142.49999619484,2|0,3:2|0:0,0:0:0:0: +178,282,233690,1,0,0:0:0:0: +178,282,233801,6,0,P|185:369|208:375,1,71.2499980974198,10|0,0:2|0:0,0:0:0:0: +85,181,234023,2,0,P|34:263|43:289,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +347,157,234246,2,0,P|280:194|254:184,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +158,87,234468,2,0,P|75:66|44:90,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +242,11,234690,6,0,P|287:122|252:206,1,194.999991073609,10|0,0:2|0:0,0:0:0:0: +154,371,235023,1,0,0:0:0:0: +154,371,235134,6,0,P|117:291|126:259,1,71.2499980974198,2|0,3:2|0:0,0:0:0:0: +352,150,235357,2,0,P|320:185|316:233,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +214,285,235579,6,0,P|210:204|245:175,1,71.2499980974198,10|0,1:2|0:0,0:0:0:0: +437,116,235801,2,0,P|348:155|338:190,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +458,323,236023,6,0,P|505:256|425:239,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: +329,261,236357,2,0,B|306:302|302:337|302:337|268:296|268:296|236:340|236:340|236:304|194:256,1,269.999991760254,2|0,0:0|0:0,0:0:0:0: +35,273,236690,2,0,P|16:298|64:365,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +130,357,236912,2,0,P|154:313|61:197,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: +21,56,237246,1,0,0:0:0:0: +21,56,237357,6,0,P|104:88|125:70,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +230,0,237579,2,0,B|205:109,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +44,226,237801,6,0,B|108:259|144:265|144:265|109:281|36:338,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: +207,190,238134,2,0,B|237:225|248:259|248:259|273:212|273:212|313:249|313:249|306:214|338:159,1,269.999991760254,2|0,0:0|0:0,0:0:0:0: +501,143,238468,2,0,P|519:214|503:239,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +411,240,238690,2,0,P|407:151|450:116,1,97.4999955368044,0|2,3:2|0:2,0:0:0:0: +496,14,238912,6,0,P|426:55|385:38,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: +204,77,239134,2,0,P|222:19|292:49,1,134.999995880127,10|0,1:2|0:0,0:0:0:0: +299,259,239357,2,0,P|281:201|214:221,1,134.999995880127 +0,77,239579,6,0,P|76:52|94:33,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +89,177,239801,2,0,P|76:66|102:18,1,142.49999619484,2|8,0:0|1:2,0:0:0:0: +310,181,240246,6,0,P|234:156|216:137,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +36,338,240468,2,0,P|140:284|186:293,1,142.49999619484,2|0,3:2|0:0,0:0:0:0: +273,324,240801,1,0,0:0:0:0: +273,324,240912,6,0,P|246:408|251:417,1,71.2499980974198,10|0,1:2|0:0,0:0:0:0: +454,329,241134,2,0,P|420:267|444:198,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +270,208,241357,2,0,P|326:123|350:119,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: +512,65,241579,2,0,P|452:120|409:107,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +197,29,241801,6,0,P|317:88|299:155,1,194.999991073609,10|0,1:2|0:0,0:0:0:0: +122,235,242134,1,0,0:0:0:0: +223,265,242246,6,0,B|233:232|233:232|201:174,1,71.2499980974198,2|0,3:2|0:0,0:0:0:0: +97,19,242468,2,0,B|77:66|77:66|109:124,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: +314,127,242690,6,0,P|258:69|213:78,1,93.75,10|0,1:2|0:0,0:0:0:0: +14,268,242912,2,0,L|156:224,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: +354,245,243134,5,2,0:0:0:0: +158,49,243468,1,2,0:0:0:0: +121,331,243801,1,2,0:0:0:0: +291,99,244246,5,2,0:0:0:0: +270,314,244469,1,2,0:0:0:0: +91,198,244691,1,2,0:0:0:0: +244,208,244912,5,2,0:0:0:0: +192,228,245246,1,2,0:0:0:0: +199,179,245579,1,2,0:0:0:0: diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513-expected-conversion.json b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513-expected-conversion.json new file mode 100644 index 000000000000..a7a2ba4e24c7 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513-expected-conversion.json @@ -0,0 +1 @@ +{"Mappings":[{"StartTime":14554.0,"Objects":[{"StartTime":14554.0,"EndTime":14554.0,"X":140.0,"Y":242.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":14776.0,"EndTime":14776.0,"X":159.385574,"Y":334.6728,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":14962.0,"EndTime":14962.0,"X":140.0,"Y":242.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":15146.0,"Objects":[{"StartTime":15146.0,"EndTime":15146.0,"X":98.0,"Y":147.0}]},{"StartTime":15220.0,"Objects":[{"StartTime":15220.0,"EndTime":15220.0,"X":90.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":15332.0,"EndTime":15332.0,"X":30.0399876,"Y":180.1521,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":15665.0,"Objects":[{"StartTime":15665.0,"EndTime":15665.0,"X":30.0,"Y":180.0}]},{"StartTime":15887.0,"Objects":[{"StartTime":15887.0,"EndTime":15887.0,"X":252.0,"Y":94.0}]},{"StartTime":16109.0,"Objects":[{"StartTime":16109.0,"EndTime":16109.0,"X":453.0,"Y":164.0}]},{"StartTime":18109.0,"Objects":[{"StartTime":18109.0,"EndTime":18109.0,"X":462.0,"Y":154.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18295.0,"EndTime":18295.0,"X":370.388947,"Y":94.52616,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18480.0,"Objects":[{"StartTime":18480.0,"EndTime":18480.0,"X":331.260864,"Y":20.2608681}]},{"StartTime":18554.0,"Objects":[{"StartTime":18554.0,"EndTime":18554.0,"X":335.0,"Y":24.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18666.0,"EndTime":18666.0,"X":258.2912,"Y":40.5695877,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18776.0,"Objects":[{"StartTime":18776.0,"EndTime":18776.0,"X":168.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18888.0,"EndTime":18888.0,"X":246.032837,"Y":126.069855,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19220.0,"Objects":[{"StartTime":19220.0,"EndTime":19220.0,"X":246.0,"Y":126.0}]},{"StartTime":19443.0,"Objects":[{"StartTime":19443.0,"EndTime":19443.0,"X":115.0,"Y":44.0}]},{"StartTime":19665.0,"Objects":[{"StartTime":19665.0,"EndTime":19665.0,"X":104.0,"Y":194.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19777.0,"EndTime":19777.0,"X":120.877777,"Y":270.869843,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19887.0,"Objects":[{"StartTime":19887.0,"EndTime":19887.0,"X":48.0,"Y":124.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20221.0,"EndTime":20221.0,"X":68.6317749,"Y":334.704071,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20331.0,"Objects":[{"StartTime":20331.0,"EndTime":20331.0,"X":153.0,"Y":346.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20443.0,"EndTime":20443.0,"X":246.364746,"Y":329.347076,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20554.0,"Objects":[{"StartTime":20554.0,"EndTime":20554.0,"X":246.0,"Y":329.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20666.0,"EndTime":20666.0,"X":223.447632,"Y":245.661713,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20776.0,"Objects":[{"StartTime":20776.0,"EndTime":20776.0,"X":226.739136,"Y":248.739136}]},{"StartTime":20924.0,"Objects":[{"StartTime":20924.0,"EndTime":20924.0,"X":351.260864,"Y":380.260864}]},{"StartTime":20998.0,"Objects":[{"StartTime":20998.0,"EndTime":20998.0,"X":355.0,"Y":384.0}]},{"StartTime":21220.0,"Objects":[{"StartTime":21220.0,"EndTime":21220.0,"X":505.0,"Y":303.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21554.0,"EndTime":21554.0,"X":390.768066,"Y":271.293854,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21665.0,"Objects":[{"StartTime":21665.0,"EndTime":21665.0,"X":375.0,"Y":269.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21851.0,"EndTime":21851.0,"X":350.468628,"Y":379.1108,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21998.0,"Objects":[{"StartTime":21998.0,"EndTime":21998.0,"X":309.0,"Y":215.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22184.0,"EndTime":22184.0,"X":226.02095,"Y":138.321442,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22331.0,"Objects":[{"StartTime":22331.0,"EndTime":22331.0,"X":389.0,"Y":184.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22443.0,"EndTime":22443.0,"X":463.616272,"Y":174.1903,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22776.0,"Objects":[{"StartTime":22776.0,"EndTime":22776.0,"X":463.0,"Y":174.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22888.0,"EndTime":22888.0,"X":483.131836,"Y":100.896431,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22998.0,"Objects":[{"StartTime":22998.0,"EndTime":22998.0,"X":330.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23184.0,"EndTime":23184.0,"X":341.2172,"Y":118.004745,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23443.0,"Objects":[{"StartTime":23443.0,"EndTime":23443.0,"X":341.0,"Y":118.0}]},{"StartTime":23665.0,"Objects":[{"StartTime":23665.0,"EndTime":23665.0,"X":417.0,"Y":37.0}]},{"StartTime":23887.0,"Objects":[{"StartTime":23887.0,"EndTime":23887.0,"X":384.0,"Y":274.0}]},{"StartTime":24109.0,"Objects":[{"StartTime":24109.0,"EndTime":24109.0,"X":189.0,"Y":125.0}]},{"StartTime":24257.0,"Objects":[{"StartTime":24257.0,"EndTime":24257.0,"X":160.260864,"Y":46.2608681}]},{"StartTime":24331.0,"Objects":[{"StartTime":24331.0,"EndTime":24331.0,"X":164.0,"Y":50.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":24517.0,"EndTime":24517.0,"X":258.715332,"Y":57.3486023,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":24776.0,"Objects":[{"StartTime":24776.0,"EndTime":24776.0,"X":259.0,"Y":59.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25110.0,"EndTime":25110.0,"X":87.62962,"Y":-0.2703557,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25220.0,"Objects":[{"StartTime":25220.0,"EndTime":25220.0,"X":39.0,"Y":64.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25406.0,"EndTime":25406.0,"X":28.9925976,"Y":182.287445,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25554.0,"Objects":[{"StartTime":25554.0,"EndTime":25554.0,"X":145.0,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25740.0,"EndTime":25740.0,"X":26.8029518,"Y":262.037933,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25887.0,"Objects":[{"StartTime":25887.0,"EndTime":25887.0,"X":234.0,"Y":202.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25999.0,"EndTime":25999.0,"X":230.918243,"Y":280.907837,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26331.0,"Objects":[{"StartTime":26331.0,"EndTime":26331.0,"X":231.0,"Y":282.0}]},{"StartTime":26554.0,"Objects":[{"StartTime":26554.0,"EndTime":26554.0,"X":12.0,"Y":377.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26740.0,"EndTime":26740.0,"X":25.7964287,"Y":262.9408,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26998.0,"Objects":[{"StartTime":26998.0,"EndTime":26998.0,"X":234.0,"Y":202.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27258.0,"EndTime":27258.0,"X":422.545441,"Y":184.940186,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27369.0,"Objects":[{"StartTime":27369.0,"EndTime":27369.0,"X":487.260864,"Y":234.260864}]},{"StartTime":27443.0,"Objects":[{"StartTime":27443.0,"EndTime":27443.0,"X":491.0,"Y":238.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27555.0,"EndTime":27555.0,"X":407.885376,"Y":272.836151,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27665.0,"Objects":[{"StartTime":27665.0,"EndTime":27665.0,"X":407.0,"Y":100.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27777.0,"EndTime":27777.0,"X":490.3403,"Y":134.4242,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27887.0,"Objects":[{"StartTime":27887.0,"EndTime":27887.0,"X":491.0,"Y":238.0}]},{"StartTime":28109.0,"Objects":[{"StartTime":28109.0,"EndTime":28109.0,"X":338.260864,"Y":153.260864}]},{"StartTime":28183.0,"Objects":[{"StartTime":28183.0,"EndTime":28183.0,"X":342.0,"Y":157.0}]},{"StartTime":28443.0,"Objects":[{"StartTime":28443.0,"EndTime":28443.0,"X":300.0,"Y":343.0}]},{"StartTime":28776.0,"Objects":[{"StartTime":28776.0,"EndTime":28776.0,"X":300.0,"Y":343.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29109.0,"EndTime":29109.0,"X":494.547028,"Y":370.47995,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29406.0,"EndTime":29406.0,"X":300.0,"Y":343.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":29887.0,"Objects":[{"StartTime":29887.0,"EndTime":29887.0,"X":285.0,"Y":110.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29999.0,"EndTime":29999.0,"X":374.669769,"Y":90.45255,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30109.0,"Objects":[{"StartTime":30109.0,"EndTime":30109.0,"X":474.0,"Y":9.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30295.0,"EndTime":30295.0,"X":380.0077,"Y":103.602509,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30554.0,"Objects":[{"StartTime":30554.0,"EndTime":30554.0,"X":194.0,"Y":141.0}]},{"StartTime":30776.0,"Objects":[{"StartTime":30776.0,"EndTime":30776.0,"X":220.0,"Y":46.0}]},{"StartTime":30998.0,"Objects":[{"StartTime":30998.0,"EndTime":30998.0,"X":153.0,"Y":228.0}]},{"StartTime":31220.0,"Objects":[{"StartTime":31220.0,"EndTime":31220.0,"X":46.0,"Y":31.0}]},{"StartTime":31369.0,"Objects":[{"StartTime":31369.0,"EndTime":31369.0,"X":58.0,"Y":210.0}]},{"StartTime":31443.0,"Objects":[{"StartTime":31443.0,"EndTime":31443.0,"X":63.0,"Y":213.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31573.0,"EndTime":31573.0,"X":151.282684,"Y":204.9826,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31665.0,"Objects":[{"StartTime":31665.0,"EndTime":31665.0,"X":245.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31777.0,"EndTime":31777.0,"X":150.780273,"Y":232.175674,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31887.0,"Objects":[{"StartTime":31887.0,"EndTime":31887.0,"X":83.2608643,"Y":288.260864}]},{"StartTime":31961.0,"Objects":[{"StartTime":31961.0,"EndTime":31961.0,"X":87.0,"Y":292.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32035.0,"EndTime":32035.0,"X":89.47952,"Y":339.199554,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32073.0,"EndTime":32073.0,"X":87.0,"Y":292.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32331.0,"Objects":[{"StartTime":32331.0,"EndTime":32331.0,"X":40.0,"Y":20.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32517.0,"EndTime":32517.0,"X":27.954195,"Y":147.40477,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32665.0,"Objects":[{"StartTime":32665.0,"EndTime":32665.0,"X":138.0,"Y":81.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32851.0,"EndTime":32851.0,"X":33.6966553,"Y":6.6338315,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32998.0,"Objects":[{"StartTime":32998.0,"EndTime":32998.0,"X":38.0,"Y":140.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33184.0,"EndTime":33184.0,"X":154.183746,"Y":85.22502,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33443.0,"Objects":[{"StartTime":33443.0,"EndTime":33443.0,"X":154.0,"Y":86.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33629.0,"EndTime":33629.0,"X":247.144852,"Y":69.95044,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33776.0,"Objects":[{"StartTime":33776.0,"EndTime":33776.0,"X":286.0,"Y":0.0}]},{"StartTime":33887.0,"Objects":[{"StartTime":33887.0,"EndTime":33887.0,"X":286.0,"Y":0.0}]},{"StartTime":34109.0,"Objects":[{"StartTime":34109.0,"EndTime":34109.0,"X":258.0,"Y":218.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34331.0,"EndTime":34331.0,"X":271.6775,"Y":359.204651,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34517.0,"EndTime":34517.0,"X":258.0,"Y":218.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34776.0,"Objects":[{"StartTime":34776.0,"EndTime":34776.0,"X":380.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34851.0,"EndTime":34851.0,"X":367.713348,"Y":320.938263,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34998.0,"Objects":[{"StartTime":34998.0,"EndTime":34998.0,"X":471.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35184.0,"EndTime":35184.0,"X":458.353516,"Y":266.323029,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35443.0,"Objects":[{"StartTime":35443.0,"EndTime":35443.0,"X":260.0,"Y":217.0}]},{"StartTime":35591.0,"Objects":[{"StartTime":35591.0,"EndTime":35591.0,"X":157.260864,"Y":294.260864}]},{"StartTime":35665.0,"Objects":[{"StartTime":35665.0,"EndTime":35665.0,"X":161.0,"Y":298.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35777.0,"EndTime":35777.0,"X":184.057953,"Y":373.6862,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35887.0,"Objects":[{"StartTime":35887.0,"EndTime":35887.0,"X":46.0,"Y":246.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36073.0,"EndTime":36073.0,"X":42.9525223,"Y":383.886,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36220.0,"Objects":[{"StartTime":36220.0,"EndTime":36220.0,"X":256.0,"Y":216.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36406.0,"EndTime":36406.0,"X":120.48381,"Y":204.784927,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36554.0,"Objects":[{"StartTime":36554.0,"EndTime":36554.0,"X":371.0,"Y":232.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36740.0,"EndTime":36740.0,"X":511.9474,"Y":213.112839,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36998.0,"Objects":[{"StartTime":36998.0,"EndTime":36998.0,"X":511.0,"Y":213.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37110.0,"EndTime":37110.0,"X":495.4303,"Y":136.39592,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":37220.0,"Objects":[{"StartTime":37220.0,"EndTime":37220.0,"X":381.0,"Y":36.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37406.0,"EndTime":37406.0,"X":411.975159,"Y":142.76506,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":37665.0,"Objects":[{"StartTime":37665.0,"EndTime":37665.0,"X":472.0,"Y":55.0}]},{"StartTime":37887.0,"Objects":[{"StartTime":37887.0,"EndTime":37887.0,"X":368.0,"Y":17.0}]},{"StartTime":38109.0,"Objects":[{"StartTime":38109.0,"EndTime":38109.0,"X":114.0,"Y":109.0}]},{"StartTime":38331.0,"Objects":[{"StartTime":38331.0,"EndTime":38331.0,"X":269.0,"Y":65.0}]},{"StartTime":38554.0,"Objects":[{"StartTime":38554.0,"EndTime":38554.0,"X":12.0,"Y":84.0}]},{"StartTime":38998.0,"Objects":[{"StartTime":38998.0,"EndTime":38998.0,"X":482.0,"Y":60.0}]},{"StartTime":39443.0,"Objects":[{"StartTime":39443.0,"EndTime":39443.0,"X":225.0,"Y":293.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":39776.0,"EndTime":39776.0,"X":34.1912575,"Y":339.044769,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":40073.0,"EndTime":40073.0,"X":225.0,"Y":293.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":40554.0,"Objects":[{"StartTime":40554.0,"EndTime":40554.0,"X":511.0,"Y":364.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":40666.0,"EndTime":40666.0,"X":419.3407,"Y":364.803,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":40776.0,"Objects":[{"StartTime":40776.0,"EndTime":40776.0,"X":322.0,"Y":284.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":40962.0,"EndTime":40962.0,"X":415.9923,"Y":378.6025,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41146.0,"Objects":[{"StartTime":41146.0,"EndTime":41146.0,"X":466.260864,"Y":279.260864}]},{"StartTime":41220.0,"Objects":[{"StartTime":41220.0,"EndTime":41220.0,"X":470.0,"Y":283.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41332.0,"EndTime":41332.0,"X":449.4545,"Y":190.666824,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41443.0,"Objects":[{"StartTime":41443.0,"EndTime":41443.0,"X":445.0,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41555.0,"EndTime":41555.0,"X":383.091278,"Y":96.9536362,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41665.0,"Objects":[{"StartTime":41665.0,"EndTime":41665.0,"X":316.0,"Y":47.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41777.0,"EndTime":41777.0,"X":273.3131,"Y":0.42472744,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41887.0,"Objects":[{"StartTime":41887.0,"EndTime":41887.0,"X":306.0,"Y":124.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41999.0,"EndTime":41999.0,"X":290.485779,"Y":201.456039,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42109.0,"Objects":[{"StartTime":42109.0,"EndTime":42109.0,"X":307.0,"Y":335.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42406.0,"EndTime":42406.0,"X":357.6962,"Y":245.541336,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42554.0,"Objects":[{"StartTime":42554.0,"EndTime":42554.0,"X":231.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42851.0,"EndTime":42851.0,"X":65.17772,"Y":71.38798,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42998.0,"Objects":[{"StartTime":42998.0,"EndTime":42998.0,"X":0.0,"Y":28.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43442.0,"EndTime":43442.0,"X":141.066589,"Y":14.2687416,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43850.0,"EndTime":43850.0,"X":0.0,"Y":28.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44109.0,"Objects":[{"StartTime":44109.0,"EndTime":44109.0,"X":192.0,"Y":75.0}]},{"StartTime":44331.0,"Objects":[{"StartTime":44331.0,"EndTime":44331.0,"X":257.0,"Y":35.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44628.0,"EndTime":44628.0,"X":361.660645,"Y":20.101881,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44776.0,"Objects":[{"StartTime":44776.0,"EndTime":44776.0,"X":361.0,"Y":20.0}]},{"StartTime":44998.0,"Objects":[{"StartTime":44998.0,"EndTime":44998.0,"X":453.0,"Y":10.0}]},{"StartTime":45220.0,"Objects":[{"StartTime":45220.0,"EndTime":45220.0,"X":512.0,"Y":73.0}]},{"StartTime":45665.0,"Objects":[{"StartTime":45665.0,"EndTime":45665.0,"X":0.0,"Y":12.0}]},{"StartTime":45887.0,"Objects":[{"StartTime":45887.0,"EndTime":45887.0,"X":0.0,"Y":12.0}]},{"StartTime":46109.0,"Objects":[{"StartTime":46109.0,"EndTime":46109.0,"X":0.0,"Y":12.0}]},{"StartTime":46554.0,"Objects":[{"StartTime":46554.0,"EndTime":46554.0,"X":0.0,"Y":12.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":46851.0,"EndTime":46851.0,"X":101.499535,"Y":43.66694,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":46998.0,"Objects":[{"StartTime":46998.0,"EndTime":46998.0,"X":169.0,"Y":0.0}]},{"StartTime":47220.0,"Objects":[{"StartTime":47220.0,"EndTime":47220.0,"X":375.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":47554.0,"EndTime":47554.0,"X":485.153961,"Y":74.49411,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":47665.0,"Objects":[{"StartTime":47665.0,"EndTime":47665.0,"X":501.0,"Y":55.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":47851.0,"EndTime":47851.0,"X":462.965179,"Y":-0.772694349,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":48109.0,"Objects":[{"StartTime":48109.0,"EndTime":48109.0,"X":188.0,"Y":77.0}]},{"StartTime":48331.0,"Objects":[{"StartTime":48331.0,"EndTime":48331.0,"X":188.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48553.0,"EndTime":48553.0,"X":199.2907,"Y":147.349716,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48739.0,"EndTime":48739.0,"X":188.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":48998.0,"Objects":[{"StartTime":48998.0,"EndTime":48998.0,"X":307.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49184.0,"EndTime":49184.0,"X":297.639069,"Y":70.63239,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49665.0,"Objects":[{"StartTime":49665.0,"EndTime":49665.0,"X":297.0,"Y":70.0}]},{"StartTime":49887.0,"Objects":[{"StartTime":49887.0,"EndTime":49887.0,"X":380.0,"Y":57.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49999.0,"EndTime":49999.0,"X":401.888733,"Y":14.8439369,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50109.0,"Objects":[{"StartTime":50109.0,"EndTime":50109.0,"X":188.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50442.0,"EndTime":50442.0,"X":83.18368,"Y":56.6891975,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50739.0,"EndTime":50739.0,"X":188.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":51220.0,"Objects":[{"StartTime":51220.0,"EndTime":51220.0,"X":188.0,"Y":77.0}]},{"StartTime":51442.0,"Objects":[{"StartTime":51442.0,"EndTime":51442.0,"X":33.0,"Y":125.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51776.0,"EndTime":51776.0,"X":12.38936,"Y":16.1852417,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":51887.0,"Objects":[{"StartTime":51887.0,"EndTime":51887.0,"X":15.7391319,"Y":19.7391319}]},{"StartTime":52109.0,"Objects":[{"StartTime":52109.0,"EndTime":52109.0,"X":90.0,"Y":59.0}]},{"StartTime":52331.0,"Objects":[{"StartTime":52331.0,"EndTime":52331.0,"X":189.0,"Y":63.0}]},{"StartTime":52776.0,"Objects":[{"StartTime":52776.0,"EndTime":52776.0,"X":512.0,"Y":0.0}]},{"StartTime":52998.0,"Objects":[{"StartTime":52998.0,"EndTime":52998.0,"X":512.0,"Y":0.0}]},{"StartTime":53220.0,"Objects":[{"StartTime":53220.0,"EndTime":53220.0,"X":512.0,"Y":0.0}]},{"StartTime":53665.0,"Objects":[{"StartTime":53665.0,"EndTime":53665.0,"X":512.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":53962.0,"EndTime":53962.0,"X":410.500458,"Y":31.6669388,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54109.0,"Objects":[{"StartTime":54109.0,"EndTime":54109.0,"X":410.0,"Y":31.0}]},{"StartTime":54331.0,"Objects":[{"StartTime":54331.0,"EndTime":54331.0,"X":359.0,"Y":110.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54665.0,"EndTime":54665.0,"X":340.5059,"Y":-0.153986454,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54776.0,"Objects":[{"StartTime":54776.0,"EndTime":54776.0,"X":492.0,"Y":96.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54962.0,"EndTime":54962.0,"X":436.244843,"Y":134.083344,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":55220.0,"Objects":[{"StartTime":55220.0,"EndTime":55220.0,"X":256.0,"Y":75.0}]},{"StartTime":55442.0,"Objects":[{"StartTime":55442.0,"EndTime":55442.0,"X":256.0,"Y":75.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":55664.0,"EndTime":55664.0,"X":185.613754,"Y":63.9393044,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":55850.0,"EndTime":55850.0,"X":256.0,"Y":75.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56331.0,"Objects":[{"StartTime":56331.0,"EndTime":56331.0,"X":359.0,"Y":110.0}]},{"StartTime":56554.0,"Objects":[{"StartTime":56554.0,"EndTime":56554.0,"X":256.0,"Y":384.0}]},{"StartTime":56776.0,"Objects":[{"StartTime":56776.0,"EndTime":56776.0,"X":135.0,"Y":352.0}]},{"StartTime":57220.0,"Objects":[{"StartTime":57220.0,"EndTime":57220.0,"X":135.0,"Y":352.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57332.0,"EndTime":57332.0,"X":56.703907,"Y":179.021271,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57443.0,"Objects":[{"StartTime":57443.0,"EndTime":57443.0,"X":214.0,"Y":2.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57555.0,"EndTime":57555.0,"X":157.702835,"Y":166.508469,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57665.0,"Objects":[{"StartTime":57665.0,"EndTime":57665.0,"X":63.0,"Y":39.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57777.0,"EndTime":57777.0,"X":216.202484,"Y":76.36667,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57887.0,"Objects":[{"StartTime":57887.0,"EndTime":57887.0,"X":256.0,"Y":370.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57999.0,"EndTime":57999.0,"X":236.6084,"Y":229.30957,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58109.0,"Objects":[{"StartTime":58109.0,"EndTime":58109.0,"X":494.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58221.0,"EndTime":58221.0,"X":380.0297,"Y":273.818848,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58332.0,"Objects":[{"StartTime":58332.0,"EndTime":58332.0,"X":322.0,"Y":67.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58444.0,"EndTime":58444.0,"X":361.137817,"Y":169.606186,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58554.0,"Objects":[{"StartTime":58554.0,"EndTime":58554.0,"X":242.0,"Y":377.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58666.0,"EndTime":58666.0,"X":154.118546,"Y":343.403931,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58776.0,"Objects":[{"StartTime":58776.0,"EndTime":58776.0,"X":22.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58962.0,"EndTime":58962.0,"X":139.243927,"Y":189.986084,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59220.0,"Objects":[{"StartTime":59220.0,"EndTime":59220.0,"X":491.0,"Y":202.0}]},{"StartTime":59331.0,"Objects":[{"StartTime":59331.0,"EndTime":59331.0,"X":370.0,"Y":162.0}]},{"StartTime":59443.0,"Objects":[{"StartTime":59443.0,"EndTime":59443.0,"X":442.0,"Y":76.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59518.0,"EndTime":59518.0,"X":454.5813,"Y":132.28093,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59665.0,"Objects":[{"StartTime":59665.0,"EndTime":59665.0,"X":362.0,"Y":170.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59851.0,"EndTime":59851.0,"X":365.3222,"Y":-0.135499477,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60109.0,"Objects":[{"StartTime":60109.0,"EndTime":60109.0,"X":266.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60239.0,"EndTime":60239.0,"X":250.3682,"Y":240.412949,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60331.0,"Objects":[{"StartTime":60331.0,"EndTime":60331.0,"X":250.0,"Y":240.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60628.0,"EndTime":60628.0,"X":261.902863,"Y":346.2101,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60776.0,"Objects":[{"StartTime":60776.0,"EndTime":60776.0,"X":243.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60888.0,"EndTime":60888.0,"X":414.964264,"Y":64.90915,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60998.0,"Objects":[{"StartTime":60998.0,"EndTime":60998.0,"X":108.0,"Y":108.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61110.0,"EndTime":61110.0,"X":51.0426025,"Y":272.124146,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61221.0,"Objects":[{"StartTime":61221.0,"EndTime":61221.0,"X":422.0,"Y":317.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61333.0,"EndTime":61333.0,"X":461.749878,"Y":163.95488,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61443.0,"Objects":[{"StartTime":61443.0,"EndTime":61443.0,"X":188.0,"Y":69.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61555.0,"EndTime":61555.0,"X":47.2970963,"Y":49.65848,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61665.0,"Objects":[{"StartTime":61665.0,"EndTime":61665.0,"X":2.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61777.0,"EndTime":61777.0,"X":117.986351,"Y":306.8477,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61888.0,"Objects":[{"StartTime":61888.0,"EndTime":61888.0,"X":155.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62000.0,"EndTime":62000.0,"X":52.2578239,"Y":206.931015,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62110.0,"Objects":[{"StartTime":62110.0,"EndTime":62110.0,"X":328.0,"Y":287.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62222.0,"EndTime":62222.0,"X":415.8731,"Y":320.639221,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62332.0,"Objects":[{"StartTime":62332.0,"EndTime":62332.0,"X":259.0,"Y":156.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62444.0,"EndTime":62444.0,"X":250.142136,"Y":234.555649,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62554.0,"Objects":[{"StartTime":62554.0,"EndTime":62554.0,"X":439.0,"Y":37.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62814.0,"EndTime":62814.0,"X":327.925018,"Y":286.186462,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62924.0,"Objects":[{"StartTime":62924.0,"EndTime":62924.0,"X":271.0,"Y":154.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63036.0,"EndTime":63036.0,"X":296.7042,"Y":99.75176,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63220.0,"Objects":[{"StartTime":63220.0,"EndTime":63220.0,"X":327.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63480.0,"EndTime":63480.0,"X":217.666336,"Y":18.1386681,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63591.0,"Objects":[{"StartTime":63591.0,"EndTime":63591.0,"X":158.260864,"Y":79.2608643}]},{"StartTime":63665.0,"Objects":[{"StartTime":63665.0,"EndTime":63665.0,"X":162.0,"Y":83.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63740.0,"EndTime":63740.0,"X":115.196854,"Y":78.46499,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63887.0,"Objects":[{"StartTime":63887.0,"EndTime":63887.0,"X":63.0,"Y":227.0}]},{"StartTime":63998.0,"Objects":[{"StartTime":63998.0,"EndTime":63998.0,"X":40.0,"Y":145.0}]},{"StartTime":64109.0,"Objects":[{"StartTime":64109.0,"EndTime":64109.0,"X":20.0,"Y":64.0}]},{"StartTime":64331.0,"Objects":[{"StartTime":64331.0,"EndTime":64331.0,"X":30.0,"Y":67.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64443.0,"EndTime":64443.0,"X":215.669785,"Y":30.3937016,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64554.0,"Objects":[{"StartTime":64554.0,"EndTime":64554.0,"X":184.0,"Y":369.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64666.0,"EndTime":64666.0,"X":20.7301826,"Y":309.824158,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64776.0,"Objects":[{"StartTime":64776.0,"EndTime":64776.0,"X":425.0,"Y":32.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64888.0,"EndTime":64888.0,"X":402.833282,"Y":188.61615,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64998.0,"Objects":[{"StartTime":64998.0,"EndTime":64998.0,"X":100.0,"Y":370.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65110.0,"EndTime":65110.0,"X":77.70479,"Y":229.476547,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65220.0,"Objects":[{"StartTime":65220.0,"EndTime":65220.0,"X":387.0,"Y":107.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65350.0,"EndTime":65350.0,"X":512.8505,"Y":172.545654,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65443.0,"Objects":[{"StartTime":65443.0,"EndTime":65443.0,"X":203.0,"Y":269.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65555.0,"EndTime":65555.0,"X":239.321548,"Y":164.535965,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65665.0,"Objects":[{"StartTime":65665.0,"EndTime":65665.0,"X":483.0,"Y":277.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65777.0,"EndTime":65777.0,"X":494.957733,"Y":370.8416,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65887.0,"Objects":[{"StartTime":65887.0,"EndTime":65887.0,"X":400.0,"Y":205.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66073.0,"EndTime":66073.0,"X":512.1871,"Y":172.1586,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66331.0,"Objects":[{"StartTime":66331.0,"EndTime":66331.0,"X":372.0,"Y":357.0}]},{"StartTime":66442.0,"Objects":[{"StartTime":66442.0,"EndTime":66442.0,"X":287.0,"Y":283.0}]},{"StartTime":66554.0,"Objects":[{"StartTime":66554.0,"EndTime":66554.0,"X":175.0,"Y":345.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66666.0,"EndTime":66666.0,"X":97.7213,"Y":359.975983,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66776.0,"Objects":[{"StartTime":66776.0,"EndTime":66776.0,"X":28.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66962.0,"EndTime":66962.0,"X":198.1355,"Y":260.3222,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":67221.0,"Objects":[{"StartTime":67221.0,"EndTime":67221.0,"X":0.0,"Y":117.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67351.0,"EndTime":67351.0,"X":139.735031,"Y":90.25935,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":67443.0,"Objects":[{"StartTime":67443.0,"EndTime":67443.0,"X":125.0,"Y":113.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67740.0,"EndTime":67740.0,"X":18.8577633,"Y":101.148491,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":67887.0,"Objects":[{"StartTime":67887.0,"EndTime":67887.0,"X":194.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67999.0,"EndTime":67999.0,"X":274.090851,"Y":171.964279,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68109.0,"Objects":[{"StartTime":68109.0,"EndTime":68109.0,"X":10.0,"Y":350.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":68221.0,"EndTime":68221.0,"X":67.05159,"Y":185.783691,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68332.0,"Objects":[{"StartTime":68332.0,"EndTime":68332.0,"X":412.0,"Y":34.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":68444.0,"EndTime":68444.0,"X":372.017242,"Y":186.88884,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68554.0,"Objects":[{"StartTime":68554.0,"EndTime":68554.0,"X":194.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":68666.0,"EndTime":68666.0,"X":313.206573,"Y":77.26558,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68776.0,"Objects":[{"StartTime":68776.0,"EndTime":68776.0,"X":197.0,"Y":271.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":68888.0,"EndTime":68888.0,"X":272.742371,"Y":170.890579,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68999.0,"Objects":[{"StartTime":68999.0,"EndTime":68999.0,"X":448.0,"Y":305.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69111.0,"EndTime":69111.0,"X":338.401917,"Y":298.116425,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":69220.0,"Objects":[{"StartTime":69220.0,"EndTime":69220.0,"X":409.0,"Y":117.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69332.0,"EndTime":69332.0,"X":496.88147,"Y":150.596054,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":69443.0,"Objects":[{"StartTime":69443.0,"EndTime":69443.0,"X":225.0,"Y":349.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69555.0,"EndTime":69555.0,"X":146.244675,"Y":355.206116,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":69665.0,"Objects":[{"StartTime":69665.0,"EndTime":69665.0,"X":198.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69925.0,"EndTime":69925.0,"X":447.4509,"Y":310.416962,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70035.0,"Objects":[{"StartTime":70035.0,"EndTime":70035.0,"X":445.0,"Y":334.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":70147.0,"EndTime":70147.0,"X":393.847443,"Y":369.199432,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70331.0,"Objects":[{"StartTime":70331.0,"EndTime":70331.0,"X":188.0,"Y":271.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":70591.0,"EndTime":70591.0,"X":415.634369,"Y":92.77198,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70776.0,"Objects":[{"StartTime":70776.0,"EndTime":70776.0,"X":341.0,"Y":222.0}]},{"StartTime":70887.0,"Objects":[{"StartTime":70887.0,"EndTime":70887.0,"X":341.0,"Y":222.0}]},{"StartTime":70998.0,"Objects":[{"StartTime":70998.0,"EndTime":70998.0,"X":134.0,"Y":157.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":71073.0,"EndTime":71073.0,"X":2.40367842,"Y":143.132309,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":71220.0,"Objects":[{"StartTime":71220.0,"EndTime":71220.0,"X":46.0,"Y":328.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":71295.0,"EndTime":71295.0,"X":100.017792,"Y":256.82428,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":71443.0,"Objects":[{"StartTime":71443.0,"EndTime":71443.0,"X":192.0,"Y":275.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":71629.0,"EndTime":71629.0,"X":206.980026,"Y":364.057648,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":71887.0,"Objects":[{"StartTime":71887.0,"EndTime":71887.0,"X":54.0,"Y":334.0}]},{"StartTime":72109.0,"Objects":[{"StartTime":72109.0,"EndTime":72109.0,"X":262.0,"Y":237.0}]},{"StartTime":72331.0,"Objects":[{"StartTime":72331.0,"EndTime":72331.0,"X":432.0,"Y":296.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":72553.0,"EndTime":72553.0,"X":339.460541,"Y":316.382751,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":72739.0,"EndTime":72739.0,"X":432.0,"Y":296.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":72998.0,"Objects":[{"StartTime":72998.0,"EndTime":72998.0,"X":432.0,"Y":296.0}]},{"StartTime":73220.0,"Objects":[{"StartTime":73220.0,"EndTime":73220.0,"X":369.0,"Y":137.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":73406.0,"EndTime":73406.0,"X":361.7752,"Y":231.724884,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":73665.0,"Objects":[{"StartTime":73665.0,"EndTime":73665.0,"X":411.0,"Y":17.0}]},{"StartTime":73887.0,"Objects":[{"StartTime":73887.0,"EndTime":73887.0,"X":451.0,"Y":169.0}]},{"StartTime":74035.0,"Objects":[{"StartTime":74035.0,"EndTime":74035.0,"X":288.260864,"Y":113.260864}]},{"StartTime":74109.0,"Objects":[{"StartTime":74109.0,"EndTime":74109.0,"X":292.0,"Y":117.0}]},{"StartTime":74331.0,"Objects":[{"StartTime":74331.0,"EndTime":74331.0,"X":415.0,"Y":26.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":74739.0,"EndTime":74739.0,"X":236.111053,"Y":44.37425,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":74998.0,"Objects":[{"StartTime":74998.0,"EndTime":74998.0,"X":236.0,"Y":44.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":75184.0,"EndTime":75184.0,"X":141.991653,"Y":57.6905365,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":75443.0,"Objects":[{"StartTime":75443.0,"EndTime":75443.0,"X":0.0,"Y":116.0}]},{"StartTime":75665.0,"Objects":[{"StartTime":75665.0,"EndTime":75665.0,"X":0.0,"Y":116.0}]},{"StartTime":75887.0,"Objects":[{"StartTime":75887.0,"EndTime":75887.0,"X":173.0,"Y":141.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":76073.0,"EndTime":76073.0,"X":79.0150757,"Y":127.14959,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":76331.0,"Objects":[{"StartTime":76331.0,"EndTime":76331.0,"X":82.0,"Y":0.0}]},{"StartTime":76554.0,"Objects":[{"StartTime":76554.0,"EndTime":76554.0,"X":82.0,"Y":0.0}]},{"StartTime":76776.0,"Objects":[{"StartTime":76776.0,"EndTime":76776.0,"X":79.0,"Y":127.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":76962.0,"EndTime":76962.0,"X":64.47652,"Y":267.4892,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77109.0,"Objects":[{"StartTime":77109.0,"EndTime":77109.0,"X":12.0,"Y":323.0}]},{"StartTime":77220.0,"Objects":[{"StartTime":77220.0,"EndTime":77220.0,"X":87.0,"Y":344.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77295.0,"EndTime":77295.0,"X":133.98877,"Y":347.2938,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77443.0,"Objects":[{"StartTime":77443.0,"EndTime":77443.0,"X":255.0,"Y":179.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77629.0,"EndTime":77629.0,"X":145.678146,"Y":268.647217,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77887.0,"Objects":[{"StartTime":77887.0,"EndTime":77887.0,"X":261.0,"Y":384.0}]},{"StartTime":78109.0,"Objects":[{"StartTime":78109.0,"EndTime":78109.0,"X":366.0,"Y":199.0}]},{"StartTime":78220.0,"Objects":[{"StartTime":78220.0,"EndTime":78220.0,"X":293.0,"Y":263.0}]},{"StartTime":78331.0,"Objects":[{"StartTime":78331.0,"EndTime":78331.0,"X":386.0,"Y":295.0}]},{"StartTime":78554.0,"Objects":[{"StartTime":78554.0,"EndTime":78554.0,"X":152.0,"Y":279.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78740.0,"EndTime":78740.0,"X":293.428223,"Y":263.192047,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78998.0,"Objects":[{"StartTime":78998.0,"EndTime":78998.0,"X":486.0,"Y":152.0}]},{"StartTime":79109.0,"Objects":[{"StartTime":79109.0,"EndTime":79109.0,"X":366.0,"Y":199.0}]},{"StartTime":79220.0,"Objects":[{"StartTime":79220.0,"EndTime":79220.0,"X":465.0,"Y":295.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":79295.0,"EndTime":79295.0,"X":512.003967,"Y":288.515656,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":79443.0,"Objects":[{"StartTime":79443.0,"EndTime":79443.0,"X":424.0,"Y":369.0}]},{"StartTime":79665.0,"Objects":[{"StartTime":79665.0,"EndTime":79665.0,"X":446.0,"Y":220.0}]},{"StartTime":79887.0,"Objects":[{"StartTime":79887.0,"EndTime":79887.0,"X":466.0,"Y":68.0}]},{"StartTime":79998.0,"Objects":[{"StartTime":79998.0,"EndTime":79998.0,"X":389.0,"Y":80.0}]},{"StartTime":80109.0,"Objects":[{"StartTime":80109.0,"EndTime":80109.0,"X":316.0,"Y":45.0}]},{"StartTime":80331.0,"Objects":[{"StartTime":80331.0,"EndTime":80331.0,"X":312.0,"Y":35.0}]},{"StartTime":80443.0,"Objects":[{"StartTime":80443.0,"EndTime":80443.0,"X":248.0,"Y":79.0}]},{"StartTime":80554.0,"Objects":[{"StartTime":80554.0,"EndTime":80554.0,"X":171.0,"Y":50.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":80629.0,"EndTime":80629.0,"X":165.3406,"Y":2.8383522,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":80776.0,"Objects":[{"StartTime":80776.0,"EndTime":80776.0,"X":23.0,"Y":80.0}]},{"StartTime":80887.0,"Objects":[{"StartTime":80887.0,"EndTime":80887.0,"X":104.0,"Y":98.0}]},{"StartTime":80998.0,"Objects":[{"StartTime":80998.0,"EndTime":80998.0,"X":176.0,"Y":58.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":81073.0,"EndTime":81073.0,"X":181.6594,"Y":10.8383522,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":81220.0,"Objects":[{"StartTime":81220.0,"EndTime":81220.0,"X":184.0,"Y":156.0}]},{"StartTime":81443.0,"Objects":[{"StartTime":81443.0,"EndTime":81443.0,"X":184.0,"Y":156.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":81629.0,"EndTime":81629.0,"X":197.0351,"Y":297.384857,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":81776.0,"Objects":[{"StartTime":81776.0,"EndTime":81776.0,"X":204.0,"Y":384.0}]},{"StartTime":81887.0,"Objects":[{"StartTime":81887.0,"EndTime":81887.0,"X":204.0,"Y":384.0}]},{"StartTime":82109.0,"Objects":[{"StartTime":82109.0,"EndTime":82109.0,"X":116.0,"Y":268.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":82295.0,"EndTime":82295.0,"X":25.2960758,"Y":261.874023,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82554.0,"Objects":[{"StartTime":82554.0,"EndTime":82554.0,"X":204.0,"Y":384.0}]},{"StartTime":82665.0,"Objects":[{"StartTime":82665.0,"EndTime":82665.0,"X":67.0,"Y":341.0}]},{"StartTime":82776.0,"Objects":[{"StartTime":82776.0,"EndTime":82776.0,"X":67.0,"Y":341.0}]},{"StartTime":82924.0,"Objects":[{"StartTime":82924.0,"EndTime":82924.0,"X":271.260864,"Y":333.260864}]},{"StartTime":82998.0,"Objects":[{"StartTime":82998.0,"EndTime":82998.0,"X":275.0,"Y":337.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":83184.0,"EndTime":83184.0,"X":365.5222,"Y":330.68634,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":83443.0,"Objects":[{"StartTime":83443.0,"EndTime":83443.0,"X":349.0,"Y":335.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":83777.0,"EndTime":83777.0,"X":206.640488,"Y":375.221741,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":83887.0,"Objects":[{"StartTime":83887.0,"EndTime":83887.0,"X":134.0,"Y":349.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84073.0,"EndTime":84073.0,"X":-0.785378,"Y":333.9109,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84257.0,"Objects":[{"StartTime":84257.0,"EndTime":84257.0,"X":418.260864,"Y":268.260864}]},{"StartTime":84331.0,"Objects":[{"StartTime":84331.0,"EndTime":84331.0,"X":422.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84443.0,"EndTime":84443.0,"X":482.78595,"Y":283.306061,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84554.0,"Objects":[{"StartTime":84554.0,"EndTime":84554.0,"X":496.0,"Y":101.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84666.0,"EndTime":84666.0,"X":405.197174,"Y":99.9096756,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84776.0,"Objects":[{"StartTime":84776.0,"EndTime":84776.0,"X":336.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84962.0,"EndTime":84962.0,"X":477.3753,"Y":176.171219,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":85220.0,"Objects":[{"StartTime":85220.0,"EndTime":85220.0,"X":478.0,"Y":177.0}]},{"StartTime":85369.0,"Objects":[{"StartTime":85369.0,"EndTime":85369.0,"X":498.260864,"Y":97.2608643}]},{"StartTime":85443.0,"Objects":[{"StartTime":85443.0,"EndTime":85443.0,"X":502.0,"Y":101.0}]},{"StartTime":85665.0,"Objects":[{"StartTime":85665.0,"EndTime":85665.0,"X":256.0,"Y":192.0}]},{"StartTime":85887.0,"Objects":[{"StartTime":85887.0,"EndTime":85887.0,"X":256.0,"Y":192.0}]},{"StartTime":86109.0,"Objects":[{"StartTime":86109.0,"EndTime":86109.0,"X":256.0,"Y":192.0}]},{"StartTime":86776.0,"Objects":[{"StartTime":86776.0,"EndTime":86776.0,"X":256.0,"Y":192.0}]},{"StartTime":86998.0,"Objects":[{"StartTime":86998.0,"EndTime":86998.0,"X":256.0,"Y":192.0}]},{"StartTime":87443.0,"Objects":[{"StartTime":87443.0,"EndTime":87443.0,"X":256.0,"Y":192.0}]},{"StartTime":87887.0,"Objects":[{"StartTime":87887.0,"EndTime":87887.0,"X":256.0,"Y":192.0}]},{"StartTime":88276.0,"Objects":[{"StartTime":88276.0,"EndTime":88276.0,"X":256.0,"Y":192.0}]},{"StartTime":88480.0,"Objects":[{"StartTime":88480.0,"EndTime":88480.0,"X":252.260864,"Y":188.260864}]},{"StartTime":88554.0,"Objects":[{"StartTime":88554.0,"EndTime":88554.0,"X":256.0,"Y":192.0}]},{"StartTime":88776.0,"Objects":[{"StartTime":88776.0,"EndTime":88776.0,"X":256.0,"Y":192.0}]},{"StartTime":88943.0,"Objects":[{"StartTime":88943.0,"EndTime":88943.0,"X":256.0,"Y":192.0}]},{"StartTime":89220.0,"Objects":[{"StartTime":89220.0,"EndTime":89220.0,"X":256.0,"Y":192.0}]},{"StartTime":89443.0,"Objects":[{"StartTime":89443.0,"EndTime":89443.0,"X":256.0,"Y":192.0}]},{"StartTime":89665.0,"Objects":[{"StartTime":89665.0,"EndTime":89665.0,"X":256.0,"Y":192.0}]},{"StartTime":90054.0,"Objects":[{"StartTime":90054.0,"EndTime":90054.0,"X":256.0,"Y":192.0}]},{"StartTime":90331.0,"Objects":[{"StartTime":90331.0,"EndTime":90331.0,"X":256.0,"Y":192.0}]},{"StartTime":90554.0,"Objects":[{"StartTime":90554.0,"EndTime":90554.0,"X":256.0,"Y":192.0}]},{"StartTime":90998.0,"Objects":[{"StartTime":90998.0,"EndTime":90998.0,"X":256.0,"Y":192.0}]},{"StartTime":91443.0,"Objects":[{"StartTime":91443.0,"EndTime":91443.0,"X":256.0,"Y":192.0}]},{"StartTime":91831.0,"Objects":[{"StartTime":91831.0,"EndTime":91831.0,"X":256.0,"Y":192.0}]},{"StartTime":92035.0,"Objects":[{"StartTime":92035.0,"EndTime":92035.0,"X":252.260864,"Y":188.260864}]},{"StartTime":92109.0,"Objects":[{"StartTime":92109.0,"EndTime":92109.0,"X":256.0,"Y":192.0}]},{"StartTime":92331.0,"Objects":[{"StartTime":92331.0,"EndTime":92331.0,"X":256.0,"Y":192.0}]},{"StartTime":92498.0,"Objects":[{"StartTime":92498.0,"EndTime":92498.0,"X":256.0,"Y":192.0}]},{"StartTime":92776.0,"Objects":[{"StartTime":92776.0,"EndTime":92776.0,"X":256.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92962.0,"EndTime":92962.0,"X":222.567719,"Y":250.718628,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93109.0,"Objects":[{"StartTime":93109.0,"EndTime":93109.0,"X":256.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93295.0,"EndTime":93295.0,"X":347.40506,"Y":186.090027,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93443.0,"Objects":[{"StartTime":93443.0,"EndTime":93443.0,"X":256.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93777.0,"EndTime":93777.0,"X":116.548386,"Y":75.43778,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93887.0,"Objects":[{"StartTime":93887.0,"EndTime":93887.0,"X":189.0,"Y":46.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":94073.0,"EndTime":94073.0,"X":281.007141,"Y":24.99693,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94554.0,"Objects":[{"StartTime":94554.0,"EndTime":94554.0,"X":36.0,"Y":22.0}]},{"StartTime":94776.0,"Objects":[{"StartTime":94776.0,"EndTime":94776.0,"X":103.0,"Y":73.0}]},{"StartTime":94998.0,"Objects":[{"StartTime":94998.0,"EndTime":94998.0,"X":185.0,"Y":45.0}]},{"StartTime":95387.0,"Objects":[{"StartTime":95387.0,"EndTime":95387.0,"X":512.0,"Y":0.0}]},{"StartTime":95665.0,"Objects":[{"StartTime":95665.0,"EndTime":95665.0,"X":512.0,"Y":0.0}]},{"StartTime":95887.0,"Objects":[{"StartTime":95887.0,"EndTime":95887.0,"X":512.0,"Y":0.0}]},{"StartTime":96331.0,"Objects":[{"StartTime":96331.0,"EndTime":96331.0,"X":512.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96517.0,"EndTime":96517.0,"X":459.134857,"Y":78.4148254,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96665.0,"Objects":[{"StartTime":96665.0,"EndTime":96665.0,"X":367.0,"Y":70.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96851.0,"EndTime":96851.0,"X":293.2465,"Y":122.00705,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96998.0,"Objects":[{"StartTime":96998.0,"EndTime":96998.0,"X":503.0,"Y":150.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97332.0,"EndTime":97332.0,"X":375.606934,"Y":85.94427,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":97443.0,"Objects":[{"StartTime":97443.0,"EndTime":97443.0,"X":370.0,"Y":71.0}]},{"StartTime":97665.0,"Objects":[{"StartTime":97665.0,"EndTime":97665.0,"X":285.0,"Y":7.0}]},{"StartTime":97887.0,"Objects":[{"StartTime":97887.0,"EndTime":97887.0,"X":189.0,"Y":47.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97999.0,"EndTime":97999.0,"X":126.681664,"Y":55.76924,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98109.0,"Objects":[{"StartTime":98109.0,"EndTime":98109.0,"X":32.0,"Y":20.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98295.0,"EndTime":98295.0,"X":48.56125,"Y":112.862427,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98480.0,"Objects":[{"StartTime":98480.0,"EndTime":98480.0,"X":123.260864,"Y":133.260864}]},{"StartTime":98554.0,"Objects":[{"StartTime":98554.0,"EndTime":98554.0,"X":127.0,"Y":137.0}]},{"StartTime":98776.0,"Objects":[{"StartTime":98776.0,"EndTime":98776.0,"X":189.0,"Y":41.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98906.0,"EndTime":98906.0,"X":205.639862,"Y":110.098328,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":99220.0,"Objects":[{"StartTime":99220.0,"EndTime":99220.0,"X":2.0,"Y":384.0}]},{"StartTime":99443.0,"Objects":[{"StartTime":99443.0,"EndTime":99443.0,"X":135.0,"Y":352.0}]},{"StartTime":99887.0,"Objects":[{"StartTime":99887.0,"EndTime":99887.0,"X":135.0,"Y":352.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":99999.0,"EndTime":99999.0,"X":54.624,"Y":180.20723,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100109.0,"Objects":[{"StartTime":100109.0,"EndTime":100109.0,"X":445.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100221.0,"EndTime":100221.0,"X":388.70285,"Y":164.508469,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100332.0,"Objects":[{"StartTime":100332.0,"EndTime":100332.0,"X":224.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100444.0,"EndTime":100444.0,"X":377.297821,"Y":54.7266,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100554.0,"Objects":[{"StartTime":100554.0,"EndTime":100554.0,"X":152.0,"Y":130.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100666.0,"EndTime":100666.0,"X":43.1472549,"Y":38.1323853,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100776.0,"Objects":[{"StartTime":100776.0,"EndTime":100776.0,"X":512.0,"Y":269.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100888.0,"EndTime":100888.0,"X":397.676056,"Y":322.976379,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100999.0,"Objects":[{"StartTime":100999.0,"EndTime":100999.0,"X":271.0,"Y":183.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101129.0,"EndTime":101129.0,"X":384.802155,"Y":136.151382,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101221.0,"Objects":[{"StartTime":101221.0,"EndTime":101221.0,"X":302.0,"Y":298.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101333.0,"EndTime":101333.0,"X":214.462448,"Y":262.777374,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101443.0,"Objects":[{"StartTime":101443.0,"EndTime":101443.0,"X":22.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101629.0,"EndTime":101629.0,"X":139.243927,"Y":189.986084,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101887.0,"Objects":[{"StartTime":101887.0,"EndTime":101887.0,"X":230.0,"Y":15.0}]},{"StartTime":101998.0,"Objects":[{"StartTime":101998.0,"EndTime":101998.0,"X":272.0,"Y":184.0}]},{"StartTime":102110.0,"Objects":[{"StartTime":102110.0,"EndTime":102110.0,"X":402.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102185.0,"EndTime":102185.0,"X":413.950653,"Y":3.84011459,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102332.0,"Objects":[{"StartTime":102332.0,"EndTime":102332.0,"X":320.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102518.0,"EndTime":102518.0,"X":271.278229,"Y":183.300629,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102776.0,"Objects":[{"StartTime":102776.0,"EndTime":102776.0,"X":512.0,"Y":179.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102906.0,"EndTime":102906.0,"X":373.0303,"Y":192.519409,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102998.0,"Objects":[{"StartTime":102998.0,"EndTime":102998.0,"X":373.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103295.0,"EndTime":103295.0,"X":477.322662,"Y":184.897552,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103443.0,"Objects":[{"StartTime":103443.0,"EndTime":103443.0,"X":197.0,"Y":228.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103555.0,"EndTime":103555.0,"X":25.3858719,"Y":308.758972,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103665.0,"Objects":[{"StartTime":103665.0,"EndTime":103665.0,"X":456.0,"Y":383.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103777.0,"EndTime":103777.0,"X":335.283752,"Y":257.830139,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103888.0,"Objects":[{"StartTime":103888.0,"EndTime":103888.0,"X":100.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104000.0,"EndTime":104000.0,"X":8.775268,"Y":150.12056,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104110.0,"Objects":[{"StartTime":104110.0,"EndTime":104110.0,"X":259.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104222.0,"EndTime":104222.0,"X":270.277527,"Y":26.5244961,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104332.0,"Objects":[{"StartTime":104332.0,"EndTime":104332.0,"X":83.0,"Y":198.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104444.0,"EndTime":104444.0,"X":122.788712,"Y":317.792664,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104555.0,"Objects":[{"StartTime":104555.0,"EndTime":104555.0,"X":473.0,"Y":90.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104667.0,"EndTime":104667.0,"X":369.6388,"Y":51.5944138,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104777.0,"Objects":[{"StartTime":104777.0,"EndTime":104777.0,"X":416.0,"Y":287.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104889.0,"EndTime":104889.0,"X":505.9493,"Y":258.8138,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104999.0,"Objects":[{"StartTime":104999.0,"EndTime":104999.0,"X":421.0,"Y":171.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105111.0,"EndTime":105111.0,"X":343.345825,"Y":156.099213,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105221.0,"Objects":[{"StartTime":105221.0,"EndTime":105221.0,"X":6.0,"Y":333.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105481.0,"EndTime":105481.0,"X":266.63913,"Y":226.153778,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105591.0,"Objects":[{"StartTime":105591.0,"EndTime":105591.0,"X":282.0,"Y":342.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105777.0,"EndTime":105777.0,"X":211.806335,"Y":290.17868,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105887.0,"Objects":[{"StartTime":105887.0,"EndTime":105887.0,"X":267.0,"Y":227.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106128.0,"EndTime":106128.0,"X":9.868117,"Y":135.161926,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106258.0,"Objects":[{"StartTime":106258.0,"EndTime":106258.0,"X":89.2608643,"Y":42.2608681}]},{"StartTime":106332.0,"Objects":[{"StartTime":106332.0,"EndTime":106332.0,"X":93.0,"Y":46.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106407.0,"EndTime":106407.0,"X":88.46499,"Y":92.80315,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106554.0,"Objects":[{"StartTime":106554.0,"EndTime":106554.0,"X":263.0,"Y":97.0}]},{"StartTime":106665.0,"Objects":[{"StartTime":106665.0,"EndTime":106665.0,"X":295.0,"Y":13.0}]},{"StartTime":106776.0,"Objects":[{"StartTime":106776.0,"EndTime":106776.0,"X":208.0,"Y":24.0}]},{"StartTime":106998.0,"Objects":[{"StartTime":106998.0,"EndTime":106998.0,"X":200.0,"Y":42.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107110.0,"EndTime":107110.0,"X":386.3626,"Y":7.87118,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107221.0,"Objects":[{"StartTime":107221.0,"EndTime":107221.0,"X":357.0,"Y":374.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107333.0,"EndTime":107333.0,"X":247.983688,"Y":239.126038,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107443.0,"Objects":[{"StartTime":107443.0,"EndTime":107443.0,"X":484.0,"Y":299.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107555.0,"EndTime":107555.0,"X":327.92514,"Y":275.123657,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107665.0,"Objects":[{"StartTime":107665.0,"EndTime":107665.0,"X":442.0,"Y":66.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107777.0,"EndTime":107777.0,"X":465.240326,"Y":206.247681,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107887.0,"Objects":[{"StartTime":107887.0,"EndTime":107887.0,"X":249.0,"Y":215.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107999.0,"EndTime":107999.0,"X":360.1639,"Y":154.788742,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108110.0,"Objects":[{"StartTime":108110.0,"EndTime":108110.0,"X":141.0,"Y":282.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108222.0,"EndTime":108222.0,"X":45.95927,"Y":337.653381,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108332.0,"Objects":[{"StartTime":108332.0,"EndTime":108332.0,"X":184.0,"Y":48.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108444.0,"EndTime":108444.0,"X":263.1376,"Y":100.1616,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108554.0,"Objects":[{"StartTime":108554.0,"EndTime":108554.0,"X":112.0,"Y":199.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108740.0,"EndTime":108740.0,"X":-0.18708849,"Y":166.1586,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108998.0,"Objects":[{"StartTime":108998.0,"EndTime":108998.0,"X":282.0,"Y":102.0}]},{"StartTime":109109.0,"Objects":[{"StartTime":109109.0,"EndTime":109109.0,"X":341.0,"Y":270.0}]},{"StartTime":109221.0,"Objects":[{"StartTime":109221.0,"EndTime":109221.0,"X":468.0,"Y":175.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109296.0,"EndTime":109296.0,"X":473.237274,"Y":117.198364,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109443.0,"Objects":[{"StartTime":109443.0,"EndTime":109443.0,"X":374.0,"Y":199.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109629.0,"EndTime":109629.0,"X":286.574,"Y":343.009827,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109887.0,"Objects":[{"StartTime":109887.0,"EndTime":109887.0,"X":133.0,"Y":261.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110017.0,"EndTime":110017.0,"X":-0.9225209,"Y":216.706558,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110109.0,"Objects":[{"StartTime":110109.0,"EndTime":110109.0,"X":0.0,"Y":217.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110350.0,"EndTime":110350.0,"X":84.9857559,"Y":191.816071,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110554.0,"Objects":[{"StartTime":110554.0,"EndTime":110554.0,"X":204.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110666.0,"EndTime":110666.0,"X":240.323792,"Y":185.752625,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110776.0,"Objects":[{"StartTime":110776.0,"EndTime":110776.0,"X":512.0,"Y":73.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110888.0,"EndTime":110888.0,"X":348.896,"Y":13.2173862,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110999.0,"Objects":[{"StartTime":110999.0,"EndTime":110999.0,"X":5.0,"Y":229.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111111.0,"EndTime":111111.0,"X":107.993919,"Y":349.083069,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111221.0,"Objects":[{"StartTime":111221.0,"EndTime":111221.0,"X":379.0,"Y":213.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111333.0,"EndTime":111333.0,"X":413.133057,"Y":75.231575,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111443.0,"Objects":[{"StartTime":111443.0,"EndTime":111443.0,"X":131.0,"Y":123.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111555.0,"EndTime":111555.0,"X":19.396656,"Y":64.64468,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111666.0,"Objects":[{"StartTime":111666.0,"EndTime":111666.0,"X":130.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111778.0,"EndTime":111778.0,"X":235.003479,"Y":320.128784,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111888.0,"Objects":[{"StartTime":111888.0,"EndTime":111888.0,"X":335.0,"Y":137.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112000.0,"EndTime":112000.0,"X":255.882919,"Y":188.859985,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112110.0,"Objects":[{"StartTime":112110.0,"EndTime":112110.0,"X":378.0,"Y":233.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112222.0,"EndTime":112222.0,"X":455.50174,"Y":217.178284,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112331.0,"Objects":[{"StartTime":112331.0,"EndTime":112331.0,"X":456.0,"Y":206.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112591.0,"EndTime":112591.0,"X":81.4273148,"Y":265.924347,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112702.0,"Objects":[{"StartTime":112702.0,"EndTime":112702.0,"X":12.0,"Y":151.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112888.0,"EndTime":112888.0,"X":97.3507156,"Y":181.102722,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112998.0,"Objects":[{"StartTime":112998.0,"EndTime":112998.0,"X":181.0,"Y":236.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":113184.0,"EndTime":113184.0,"X":4.88930559,"Y":383.485,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":113443.0,"Objects":[{"StartTime":113443.0,"EndTime":113443.0,"X":456.0,"Y":206.0}]},{"StartTime":113554.0,"Objects":[{"StartTime":113554.0,"EndTime":113554.0,"X":456.0,"Y":206.0}]},{"StartTime":113665.0,"Objects":[{"StartTime":113665.0,"EndTime":113665.0,"X":482.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":113740.0,"EndTime":113740.0,"X":499.6581,"Y":50.97281,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":113887.0,"Objects":[{"StartTime":113887.0,"EndTime":113887.0,"X":132.0,"Y":70.0}]},{"StartTime":113998.0,"Objects":[{"StartTime":113998.0,"EndTime":113998.0,"X":132.0,"Y":70.0}]},{"StartTime":114109.0,"Objects":[{"StartTime":114109.0,"EndTime":114109.0,"X":0.0,"Y":55.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114221.0,"EndTime":114221.0,"X":251.543,"Y":24.9351,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114331.0,"Objects":[{"StartTime":114331.0,"EndTime":114331.0,"X":482.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114443.0,"EndTime":114443.0,"X":262.662476,"Y":346.950684,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114554.0,"Objects":[{"StartTime":114554.0,"EndTime":114554.0,"X":63.0,"Y":2.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114666.0,"EndTime":114666.0,"X":251.470444,"Y":26.0600586,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114776.0,"Objects":[{"StartTime":114776.0,"EndTime":114776.0,"X":420.0,"Y":325.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114888.0,"EndTime":114888.0,"X":263.0821,"Y":346.123566,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114998.0,"Objects":[{"StartTime":114998.0,"EndTime":114998.0,"X":132.0,"Y":70.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115110.0,"EndTime":115110.0,"X":250.805573,"Y":26.071888,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115220.0,"Objects":[{"StartTime":115220.0,"EndTime":115220.0,"X":351.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115332.0,"EndTime":115332.0,"X":263.9421,"Y":345.9747,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115443.0,"Objects":[{"StartTime":115443.0,"EndTime":115443.0,"X":187.0,"Y":25.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115555.0,"EndTime":115555.0,"X":250.209991,"Y":21.0493755,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115665.0,"Objects":[{"StartTime":115665.0,"EndTime":115665.0,"X":32.0,"Y":192.0}]},{"StartTime":115887.0,"Objects":[{"StartTime":115887.0,"EndTime":115887.0,"X":251.0,"Y":6.0}]},{"StartTime":116109.0,"Objects":[{"StartTime":116109.0,"EndTime":116109.0,"X":480.0,"Y":192.0}]},{"StartTime":116331.0,"Objects":[{"StartTime":116331.0,"EndTime":116331.0,"X":261.0,"Y":378.0}]},{"StartTime":116554.0,"Objects":[{"StartTime":116554.0,"EndTime":116554.0,"X":274.0,"Y":103.0}]},{"StartTime":116665.0,"Objects":[{"StartTime":116665.0,"EndTime":116665.0,"X":299.0,"Y":223.0}]},{"StartTime":116776.0,"Objects":[{"StartTime":116776.0,"EndTime":116776.0,"X":176.0,"Y":174.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":116888.0,"EndTime":116888.0,"X":50.2636871,"Y":182.550323,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":116998.0,"Objects":[{"StartTime":116998.0,"EndTime":116998.0,"X":51.0,"Y":183.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117036.0,"EndTime":117036.0,"X":104.161346,"Y":152.739212,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":117220.0,"Objects":[{"StartTime":117220.0,"EndTime":117220.0,"X":248.0,"Y":277.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117480.0,"EndTime":117480.0,"X":181.608841,"Y":182.857773,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":117665.0,"Objects":[{"StartTime":117665.0,"EndTime":117665.0,"X":418.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117777.0,"EndTime":117777.0,"X":447.550781,"Y":328.603882,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":117887.0,"Objects":[{"StartTime":117887.0,"EndTime":117887.0,"X":228.0,"Y":360.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117999.0,"EndTime":117999.0,"X":447.40863,"Y":328.441223,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118109.0,"Objects":[{"StartTime":118109.0,"EndTime":118109.0,"X":471.0,"Y":140.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118221.0,"EndTime":118221.0,"X":447.093933,"Y":328.490051,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118331.0,"Objects":[{"StartTime":118331.0,"EndTime":118331.0,"X":290.0,"Y":307.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118443.0,"EndTime":118443.0,"X":446.999,"Y":327.512421,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118554.0,"Objects":[{"StartTime":118554.0,"EndTime":118554.0,"X":400.0,"Y":210.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118666.0,"EndTime":118666.0,"X":446.4021,"Y":327.861328,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118776.0,"Objects":[{"StartTime":118776.0,"EndTime":118776.0,"X":362.0,"Y":369.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118888.0,"EndTime":118888.0,"X":446.970581,"Y":326.5147,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118998.0,"Objects":[{"StartTime":118998.0,"EndTime":118998.0,"X":440.0,"Y":263.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119110.0,"EndTime":119110.0,"X":446.899323,"Y":325.956421,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":119220.0,"Objects":[{"StartTime":119220.0,"EndTime":119220.0,"X":402.0,"Y":310.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119332.0,"EndTime":119332.0,"X":446.77478,"Y":325.857727,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":119443.0,"Objects":[{"StartTime":119443.0,"EndTime":119443.0,"X":208.0,"Y":369.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119703.0,"EndTime":119703.0,"X":10.0663357,"Y":300.209625,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":119813.0,"Objects":[{"StartTime":119813.0,"EndTime":119813.0,"X":90.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119999.0,"EndTime":119999.0,"X":123.387047,"Y":295.620728,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":120109.0,"Objects":[{"StartTime":120109.0,"EndTime":120109.0,"X":328.0,"Y":170.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":120295.0,"EndTime":120295.0,"X":480.93573,"Y":118.882164,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":120480.0,"Objects":[{"StartTime":120480.0,"EndTime":120480.0,"X":322.260864,"Y":186.260864}]},{"StartTime":120554.0,"Objects":[{"StartTime":120554.0,"EndTime":120554.0,"X":326.0,"Y":190.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":120666.0,"EndTime":120666.0,"X":236.184631,"Y":160.0903,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":120776.0,"Objects":[{"StartTime":120776.0,"EndTime":120776.0,"X":0.0,"Y":156.0}]},{"StartTime":120887.0,"Objects":[{"StartTime":120887.0,"EndTime":120887.0,"X":104.0,"Y":100.0}]},{"StartTime":120998.0,"Objects":[{"StartTime":120998.0,"EndTime":120998.0,"X":97.0,"Y":220.0}]},{"StartTime":121220.0,"Objects":[{"StartTime":121220.0,"EndTime":121220.0,"X":135.0,"Y":351.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121332.0,"EndTime":121332.0,"X":103.97979,"Y":99.57303,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":121443.0,"Objects":[{"StartTime":121443.0,"EndTime":121443.0,"X":249.0,"Y":9.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121555.0,"EndTime":121555.0,"X":217.011963,"Y":228.346481,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":121665.0,"Objects":[{"StartTime":121665.0,"EndTime":121665.0,"X":0.0,"Y":249.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121777.0,"EndTime":121777.0,"X":21.9232922,"Y":60.269043,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":121887.0,"Objects":[{"StartTime":121887.0,"EndTime":121887.0,"X":318.0,"Y":198.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121999.0,"EndTime":121999.0,"X":342.0135,"Y":354.50174,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122109.0,"Objects":[{"StartTime":122109.0,"EndTime":122109.0,"X":48.0,"Y":366.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":122221.0,"EndTime":122221.0,"X":-0.5152321,"Y":248.992676,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122331.0,"Objects":[{"StartTime":122331.0,"EndTime":122331.0,"X":360.0,"Y":102.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":122443.0,"EndTime":122443.0,"X":406.299774,"Y":184.953781,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122554.0,"Objects":[{"StartTime":122554.0,"EndTime":122554.0,"X":148.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":122666.0,"EndTime":122666.0,"X":140.908722,"Y":321.0649,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122776.0,"Objects":[{"StartTime":122776.0,"EndTime":122776.0,"X":256.0,"Y":48.0}]},{"StartTime":122998.0,"Objects":[{"StartTime":122998.0,"EndTime":122998.0,"X":256.0,"Y":368.0}]},{"StartTime":123220.0,"Objects":[{"StartTime":123220.0,"EndTime":123220.0,"X":256.0,"Y":48.0}]},{"StartTime":123443.0,"Objects":[{"StartTime":123443.0,"EndTime":123443.0,"X":256.0,"Y":368.0}]},{"StartTime":123665.0,"Objects":[{"StartTime":123665.0,"EndTime":123665.0,"X":256.0,"Y":368.0}]},{"StartTime":123776.0,"Objects":[{"StartTime":123776.0,"EndTime":123776.0,"X":280.0,"Y":233.0}]},{"StartTime":123887.0,"Objects":[{"StartTime":123887.0,"EndTime":123887.0,"X":404.0,"Y":307.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":123999.0,"EndTime":123999.0,"X":474.8864,"Y":229.730469,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124109.0,"Objects":[{"StartTime":124109.0,"EndTime":124109.0,"X":497.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":124147.0,"EndTime":124147.0,"X":451.113678,"Y":182.153015,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124331.0,"Objects":[{"StartTime":124331.0,"EndTime":124331.0,"X":208.0,"Y":309.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":124591.0,"EndTime":124591.0,"X":84.4982452,"Y":283.459045,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124776.0,"Objects":[{"StartTime":124776.0,"EndTime":124776.0,"X":88.0,"Y":81.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":124888.0,"EndTime":124888.0,"X":205.119614,"Y":305.625366,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124998.0,"Objects":[{"StartTime":124998.0,"EndTime":124998.0,"X":243.0,"Y":156.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125110.0,"EndTime":125110.0,"X":29.6648064,"Y":19.4357738,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125220.0,"Objects":[{"StartTime":125220.0,"EndTime":125220.0,"X":0.0,"Y":250.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125332.0,"EndTime":125332.0,"X":239.246033,"Y":166.903748,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125443.0,"Objects":[{"StartTime":125443.0,"EndTime":125443.0,"X":363.0,"Y":16.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125555.0,"EndTime":125555.0,"X":263.409576,"Y":248.917145,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125665.0,"Objects":[{"StartTime":125665.0,"EndTime":125665.0,"X":458.0,"Y":340.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125777.0,"EndTime":125777.0,"X":205.791092,"Y":319.9836,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125887.0,"Objects":[{"StartTime":125887.0,"EndTime":125887.0,"X":186.0,"Y":7.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125999.0,"EndTime":125999.0,"X":263.27887,"Y":247.991531,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":126109.0,"Objects":[{"StartTime":126109.0,"EndTime":126109.0,"X":461.0,"Y":349.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":126221.0,"EndTime":126221.0,"X":363.435455,"Y":268.3229,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":126331.0,"Objects":[{"StartTime":126331.0,"EndTime":126331.0,"X":441.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":126443.0,"EndTime":126443.0,"X":502.8478,"Y":183.218109,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":126554.0,"Objects":[{"StartTime":126554.0,"EndTime":126554.0,"X":503.0,"Y":184.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":126814.0,"EndTime":126814.0,"X":261.078461,"Y":357.8552,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":126924.0,"Objects":[{"StartTime":126924.0,"EndTime":126924.0,"X":456.0,"Y":357.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":127110.0,"EndTime":127110.0,"X":365.160217,"Y":344.232941,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":127220.0,"Objects":[{"StartTime":127220.0,"EndTime":127220.0,"X":0.0,"Y":47.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":127517.0,"EndTime":127517.0,"X":202.168015,"Y":158.1352,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":127665.0,"Objects":[{"StartTime":127665.0,"EndTime":127665.0,"X":193.0,"Y":159.0}]},{"StartTime":127813.0,"Objects":[{"StartTime":127813.0,"EndTime":127813.0,"X":17.2608681,"Y":206.260864}]},{"StartTime":127887.0,"Objects":[{"StartTime":127887.0,"EndTime":127887.0,"X":21.0,"Y":210.0}]},{"StartTime":128035.0,"Objects":[{"StartTime":128035.0,"EndTime":128035.0,"X":145.260864,"Y":327.260864}]},{"StartTime":128109.0,"Objects":[{"StartTime":128109.0,"EndTime":128109.0,"X":149.0,"Y":331.0}]},{"StartTime":128257.0,"Objects":[{"StartTime":128257.0,"EndTime":128257.0,"X":202.0,"Y":158.0}]}]} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513.osu b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513.osu new file mode 100644 index 000000000000..01b85774e88b --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513.osu @@ -0,0 +1,825 @@ +osu file format v14 + +[General] +AudioLeadIn: 0 +PreviewTime: 10692 +Countdown: 0 +SampleSet: Soft +StackLeniency: 0.2 +Mode: 0 +LetterboxInBreaks: 1 +WidescreenStoryboard: 1 + +[Difficulty] +HPDrainRate:5 +CircleSize:3.8 +OverallDifficulty:8.5 +ApproachRate:9.3 +SliderMultiplier:1.9 +SliderTickRate:1 + +[Events] +//Background and Video events +//Break Periods +2,16309,17555 +//Storyboard Layer 0 (Background) +//Storyboard Layer 1 (Fail) +//Storyboard Layer 2 (Pass) +//Storyboard Layer 3 (Foreground) +//Storyboard Layer 4 (Overlay) +//Storyboard Sound Samples + +[TimingPoints] +332,444.444444444444,4,2,0,66,1,0 +14554,-100,4,2,50,30,0,0 +16109,-100,4,2,50,15,0,0 +18109,-80,4,2,50,50,0,0 +18702,-80,4,2,50,5,0,0 +18776,-80,4,2,50,50,0,0 +19813,-80,4,2,50,5,0,0 +19887,-66.6666666666667,4,2,50,50,0,0 +20257,-66.6666666666667,4,2,50,5,0,0 +20331,-66.6666666666667,4,2,50,50,0,0 +20479,-66.6666666666667,4,2,50,5,0,0 +20554,-66.6666666666667,4,2,50,50,0,0 +21220,-133.333333333333,4,2,50,50,0,0 +21590,-133.333333333333,4,2,50,5,0,0 +21665,-80,4,2,50,50,0,0 +22220,-80,4,2,50,5,0,0 +22331,-80,4,2,50,50,0,0 +22924,-80,4,2,50,5,0,0 +22998,-80,4,2,50,50,0,0 +24331,-100,4,2,50,50,0,0 +24776,-80,4,2,50,50,0,0 +25146,-80,4,2,50,5,0,0 +25220,-80,4,2,50,50,0,0 +25776,-80,4,2,50,5,0,0 +25887,-80,4,2,50,50,0,0 +26998,-66.6666666666667,4,2,50,50,0,0 +27294,-66.6666666666667,4,2,50,5,0,0 +27369,-66.6666666666667,4,2,50,50,0,0 +27591,-66.6666666666667,4,2,50,5,0,0 +27665,-66.6666666666667,4,2,50,50,0,0 +30035,-66.6666666666667,4,2,50,5,0,0 +30109,-66.6666666666667,4,2,50,50,0,0 +31443,-80,4,2,50,50,0,0 +31609,-80,4,2,50,5,0,0 +31665,-66.6666666666667,4,2,50,50,0,0 +32887,-66.6666666666667,4,2,50,5,0,0 +32998,-66.6666666666667,4,2,50,50,0,0 +33443,-100,4,2,50,50,0,0 +34109,-66.6666666666667,4,2,50,50,0,0 +34887,-66.6666666666667,4,2,50,5,0,0 +34998,-80,4,2,50,50,0,0 +35813,-80,4,2,50,5,0,0 +35887,-66.6666666666667,4,2,50,50,0,0 +36442,-66.6666666666667,4,2,50,5,0,0 +36554,-66.6666666666667,4,2,50,50,0,0 +36998,-80,4,2,50,50,0,0 +37146,-80,4,2,50,5,0,0 +37220,-80,4,2,50,50,0,0 +39443,-66.6666666666667,4,2,50,50,0,0 +40702,-66.6666666666667,4,2,50,5,0,0 +40776,-66.6666666666667,4,2,50,50,0,0 +41368,-66.6666666666667,4,2,50,5,0,0 +41443,-100,4,2,50,50,0,0 +41591,-100,4,2,50,5,0,0 +41665,-100,4,2,50,50,0,0 +41813,-100,4,2,50,5,0,0 +41887,-80,4,2,50,50,0,0 +42109,-133.333333333333,4,2,50,50,0,0 +42442,-133.333333333333,4,2,50,5,0,0 +42554,-50,4,2,50,50,0,0 +42887,-50,4,2,50,5,0,0 +42998,-133.333333333333,4,2,2,30,0,0 +44664,-133.333333333333,4,2,2,5,0,0 +44776,-133.333333333333,4,2,2,30,0,0 +47590,-133.333333333333,4,2,2,5,0,0 +47665,-133.333333333333,4,2,2,30,0,0 +50035,-133.333333333333,4,2,2,5,0,0 +50109,-133.333333333333,4,2,2,30,0,0 +51812,-133.333333333333,4,2,2,5,0,0 +51887,-133.333333333333,4,2,2,30,0,0 +54701,-133.333333333333,4,2,2,5,0,0 +54776,-133.333333333333,4,2,2,30,0,0 +56554,-133.333333333333,4,2,50,15,0,0 +57220,-33.3333333333333,4,2,50,65,0,1 +57368,-33.3333333333333,4,2,50,5,0,1 +57443,-36.3636363636364,4,2,50,65,0,0 +57591,-36.3636363636364,4,2,50,5,0,0 +57665,-40,4,2,50,65,0,0 +57813,-40,4,2,50,5,0,0 +57887,-44.4444444444445,4,2,50,65,0,0 +58035,-44.4444444444445,4,2,50,5,0,0 +58109,-50,4,2,50,65,0,0 +58257,-50,4,2,50,5,0,0 +58332,-57.1428571428571,4,2,50,65,0,0 +58480,-57.1428571428571,4,2,50,5,0,0 +58554,-66.6666666666667,4,2,50,65,0,0 +58702,-66.6666666666667,4,2,50,5,0,0 +58776,-80,4,2,50,65,0,0 +59554,-80,4,2,50,5,0,0 +59665,-50,4,2,50,65,0,0 +60275,-50,4,2,50,5,0,0 +60331,-133.333333333333,4,2,50,65,0,0 +60664,-133.333333333333,4,2,50,5,0,0 +60776,-33.3333333333333,4,2,50,65,0,1 +60924,-33.3333333333333,4,2,50,5,0,1 +60998,-36.3636363636364,4,2,50,65,0,0 +61147,-36.3636363636364,4,2,50,5,0,0 +61221,-40,4,2,50,65,0,0 +61369,-40,4,2,50,5,0,0 +61443,-44.4444444444445,4,2,50,65,0,0 +61591,-44.4444444444445,4,2,50,5,0,0 +61665,-50,4,2,50,65,0,0 +61813,-50,4,2,50,5,0,0 +61888,-57.1428571428571,4,2,50,65,0,0 +62036,-57.1428571428571,4,2,50,5,0,0 +62110,-66.6666666666667,4,2,50,65,0,0 +62258,-66.6666666666667,4,2,50,5,0,0 +62332,-80,4,2,50,65,0,0 +62480,-80,4,2,50,5,0,0 +62554,-33.3333333333333,4,2,50,65,0,0 +62850,-33.3333333333333,4,2,50,5,0,0 +62924,-100,4,2,50,65,0,0 +63072,-100,4,2,50,5,0,0 +63220,-33.3333333333333,4,2,50,65,0,0 +63516,-33.3333333333333,4,2,50,5,0,0 +63554,-100,4,2,50,65,0,0 +64331,-33.3333333333333,4,2,50,65,0,1 +64479,-33.3333333333333,4,2,50,5,0,1 +64554,-36.3636363636364,4,2,50,65,0,0 +64702,-36.3636363636364,4,2,50,5,0,0 +64776,-40,4,2,50,65,0,0 +64924,-40,4,2,50,5,0,0 +64998,-44.4444444444445,4,2,50,65,0,0 +65146,-44.4444444444445,4,2,50,5,0,0 +65220,-50,4,2,50,65,0,0 +65386,-50,4,2,50,5,0,0 +65443,-57.1428571428571,4,2,50,65,0,0 +65591,-57.1428571428571,4,2,50,5,0,0 +65665,-66.6666666666667,4,2,50,65,0,0 +65813,-66.6666666666667,4,2,50,5,0,0 +65887,-80,4,2,50,65,0,0 +66702,-80,4,2,50,5,0,0 +66776,-50,4,2,50,65,0,0 +67387,-50,4,2,50,5,0,0 +67443,-133.333333333333,4,2,50,65,0,0 +67776,-133.333333333333,4,2,50,5,0,0 +67887,-33.3333333333333,4,2,50,65,0,1 +68035,-33.3333333333333,4,2,50,5,0,1 +68109,-36.3636363636364,4,2,50,65,0,0 +68258,-36.3636363636364,4,2,50,5,0,0 +68332,-40,4,2,50,65,0,0 +68480,-40,4,2,50,5,0,0 +68554,-44.4444444444445,4,2,50,65,0,0 +68702,-44.4444444444445,4,2,50,5,0,0 +68776,-50,4,2,50,65,0,0 +68924,-50,4,2,50,5,0,0 +68999,-57.1428571428571,4,2,50,65,0,0 +69147,-57.1428571428571,4,2,50,5,0,0 +69220,-66.6666666666667,4,2,50,65,0,0 +69369,-66.6666666666667,4,2,50,5,0,0 +69443,-80,4,2,50,65,0,0 +69581,-80,4,2,50,5,0,0 +69665,-33.3333333333333,4,2,50,65,0,0 +69961,-33.3333333333333,4,2,50,5,0,0 +70035,-100,4,2,50,65,0,0 +70173,-100,4,2,50,5,0,0 +70331,-33.3333333333333,4,2,50,65,0,0 +70627,-33.3333333333333,4,2,50,5,0,0 +70776,-33.3333333333333,4,2,50,65,0,0 +71109,-33.3333333333333,4,2,50,5,0,0 +71220,-50,4,2,50,65,0,0 +71331,-50,4,2,50,5,0,0 +71443,-100,4,2,50,40,0,0 +76776,-66.6666666666667,4,2,50,40,0,0 +77220,-100,4,2,50,40,0,0 +77331,-100,4,2,50,5,0,0 +77443,-66.6666666666667,4,2,50,40,0,0 +78998,-100,4,2,50,40,0,0 +79331,-100,4,2,50,5,0,0 +79443,-100,4,2,50,40,0,0 +80665,-100,4,2,50,5,0,0 +80776,-100,4,2,50,40,0,0 +81109,-100,4,2,50,5,0,0 +81220,-100,4,2,50,40,0,0 +81443,-66.6666666666667,4,2,50,40,0,0 +82109,-100,4,2,50,40,0,0 +83443,-100,4,2,50,40,0,0 +83813,-100,4,2,50,5,0,0 +83887,-66.6666666666667,4,2,50,40,0,0 +84331,-100,4,2,50,40,0,0 +84479,-100,4,2,50,5,0,0 +84554,-66.6666666666667,4,2,50,40,0,0 +85665,-66.6666666666667,4,2,50,20,0,0 +92776,-133.333333333333,4,2,50,30,0,0 +93109,-100,4,2,50,30,0,0 +93331,-100,4,2,50,5,0,0 +93443,-80,4,2,50,30,0,0 +93813,-80,4,2,50,5,0,0 +93887,-100,4,2,50,30,0,0 +96887,-100,4,2,50,5,0,0 +96998,-100,4,2,50,30,0,0 +97368,-100,4,2,50,5,0,0 +97443,-100,4,2,50,30,0,0 +98035,-100,4,2,50,5,0,0 +98109,-100,4,2,50,30,0,0 +99220,-100,4,2,50,15,0,0 +99887,-33.3333333333333,4,2,50,65,0,1 +100035,-33.3333333333333,4,2,50,5,0,1 +100109,-36.3636363636364,4,2,50,65,0,0 +100258,-36.3636363636364,4,2,50,5,0,0 +100332,-40,4,2,50,65,0,0 +100480,-40,4,2,50,5,0,0 +100554,-44.4444444444445,4,2,50,65,0,0 +100702,-44.4444444444445,4,2,50,5,0,0 +100776,-50,4,2,50,65,0,0 +100924,-50,4,2,50,5,0,0 +100999,-57.1428571428571,4,2,50,65,0,0 +101165,-57.1428571428571,4,2,50,5,0,0 +101221,-66.6666666666667,4,2,50,65,0,0 +101369,-66.6666666666667,4,2,50,5,0,0 +101443,-80,4,2,50,65,0,0 +102221,-80,4,2,50,5,0,0 +102332,-50,4,2,50,65,0,0 +102942,-50,4,2,50,5,0,0 +102998,-133.333333333333,4,2,50,65,0,0 +103331,-133.333333333333,4,2,50,5,0,0 +103443,-33.3333333333333,4,2,50,65,0,1 +103591,-33.3333333333333,4,2,50,5,0,1 +103665,-36.3636363636364,4,2,50,65,0,0 +103814,-36.3636363636364,4,2,50,5,0,0 +103888,-40,4,2,50,65,0,0 +104036,-40,4,2,50,5,0,0 +104110,-44.4444444444445,4,2,50,65,0,0 +104258,-44.4444444444445,4,2,50,5,0,0 +104332,-50,4,2,50,65,0,0 +104480,-50,4,2,50,5,0,0 +104555,-57.1428571428571,4,2,50,65,0,0 +104703,-57.1428571428571,4,2,50,5,0,0 +104777,-66.6666666666667,4,2,50,65,0,0 +104925,-66.6666666666667,4,2,50,5,0,0 +104999,-80,4,2,50,65,0,0 +105147,-80,4,2,50,5,0,0 +105221,-33.3333333333333,4,2,50,65,0,0 +105517,-33.3333333333333,4,2,50,5,0,0 +105591,-100,4,2,50,65,0,0 +105813,-100,4,2,50,5,0,0 +105887,-33.3333333333333,4,2,50,65,0,0 +106164,-33.3333333333333,4,2,50,5,0,0 +106221,-100,4,2,50,65,0,0 +106998,-33.3333333333333,4,2,50,65,0,1 +107146,-33.3333333333333,4,2,50,5,0,1 +107220,-36.3636363636364,4,2,50,65,0,0 +107369,-36.3636363636364,4,2,50,5,0,0 +107443,-40,4,2,50,65,0,0 +107591,-40,4,2,50,5,0,0 +107665,-44.4444444444445,4,2,50,65,0,0 +107813,-44.4444444444445,4,2,50,5,0,0 +107887,-50,4,2,50,65,0,0 +108035,-50,4,2,50,5,0,0 +108110,-57.1428571428571,4,2,50,65,0,0 +108258,-57.1428571428571,4,2,50,5,0,0 +108332,-66.6666666666667,4,2,50,65,0,0 +108480,-66.6666666666667,4,2,50,5,0,0 +108554,-80,4,2,50,65,0,0 +109332,-80,4,2,50,5,0,0 +109443,-50,4,2,50,65,0,0 +110053,-50,4,2,50,5,0,0 +110109,-133.333333333333,4,2,50,65,0,0 +110386,-133.333333333333,4,2,50,5,0,0 +110554,-33.3333333333333,4,2,50,65,0,1 +110702,-33.3333333333333,4,2,50,5,0,1 +110776,-36.3636363636364,4,2,50,65,0,0 +110925,-36.3636363636364,4,2,50,5,0,0 +110999,-40,4,2,50,65,0,0 +111147,-40,4,2,50,5,0,0 +111221,-44.4444444444445,4,2,50,65,0,0 +111369,-44.4444444444445,4,2,50,5,0,0 +111443,-50,4,2,50,65,0,0 +111591,-50,4,2,50,5,0,0 +111666,-57.1428571428571,4,2,50,65,0,0 +111814,-57.1428571428571,4,2,50,5,0,0 +111888,-66.6666666666667,4,2,50,65,0,0 +112036,-66.6666666666667,4,2,50,5,0,0 +112110,-80,4,2,50,65,0,0 +112258,-80,4,2,50,5,0,0 +112331,-33.3333333333333,4,2,50,65,0,0 +112627,-33.3333333333333,4,2,50,5,0,0 +112702,-100,4,2,50,65,0,0 +112924,-100,4,2,50,5,0,0 +112998,-33.3333333333333,4,2,50,65,0,0 +113443,-66.6666666666667,4,2,50,65,0,0 +113776,-66.6666666666667,4,2,50,5,0,0 +113887,-66.6666666666667,4,2,50,65,0,0 +114109,-25,4,2,50,65,0,1 +114257,-25,4,2,50,5,0,1 +114331,-28.5714285714286,4,2,50,65,0,0 +114479,-28.5714285714286,4,2,50,5,0,0 +114554,-33.3333333333333,4,2,50,65,0,1 +114702,-33.3333333333333,4,2,50,5,0,1 +114776,-40,4,2,50,65,0,0 +114924,-40,4,2,50,5,0,0 +114998,-50,4,2,50,65,0,1 +115146,-50,4,2,50,5,0,1 +115220,-66.6666666666667,4,2,50,65,0,0 +115368,-66.6666666666667,4,2,50,5,0,0 +115443,-100,4,2,50,65,0,1 +115591,-100,4,2,50,5,0,1 +115665,-50,4,2,50,65,0,0 +116924,-50,4,2,50,5,0,0 +116998,-50,4,2,50,65,0,0 +117072,-50,4,2,50,5,0,0 +117220,-100,4,2,50,65,0,0 +117516,-100,4,2,50,5,0,0 +117665,-25,4,2,50,65,0,1 +117813,-25,4,2,50,5,0,1 +117887,-28.5714285714286,4,2,50,65,0,0 +118035,-28.5714285714286,4,2,50,5,0,0 +118109,-33.3333333333333,4,2,50,65,0,1 +118258,-33.3333333333333,4,2,50,5,0,1 +118331,-40,4,2,50,65,0,0 +118480,-40,4,2,50,5,0,0 +118554,-50,4,2,50,65,0,1 +118702,-50,4,2,50,5,0,1 +118776,-66.6666666666667,4,2,50,65,0,0 +118924,-66.6666666666667,4,2,50,5,0,0 +118998,-100,4,2,50,65,0,1 +119146,-100,4,2,50,5,0,1 +119220,-133.333333333333,4,2,50,65,0,0 +119368,-200,4,2,50,5,0,0 +119443,-33.3333333333333,4,2,50,65,0,0 +119739,-33.3333333333333,4,2,50,5,0,0 +119813,-100,4,2,50,65,0,0 +120035,-100,4,2,50,5,0,0 +120109,-33.3333333333333,4,2,50,65,0,0 +120480,-66.6666666666667,4,2,50,65,0,0 +120702,-66.6666666666667,4,2,50,5,0,0 +120776,-66.6666666666667,4,2,50,65,0,0 +121220,-25,4,2,50,65,0,1 +121368,-25,4,2,50,5,0,1 +121443,-28.5714285714286,4,2,50,65,0,0 +121590,-28.5714285714286,4,2,50,5,0,0 +121665,-33.3333333333333,4,2,50,65,0,1 +121813,-33.3333333333333,4,2,50,5,0,1 +121887,-40,4,2,50,65,0,0 +122035,-40,4,2,50,5,0,0 +122109,-50,4,2,50,65,0,1 +122257,-50,4,2,50,5,0,1 +122331,-66.6666666666667,4,2,50,65,0,0 +122479,-66.6666666666667,4,2,50,5,0,0 +122554,-100,4,2,50,65,0,1 +122702,-100,4,2,50,5,0,1 +122776,-50,4,2,50,65,0,0 +124035,-50,4,2,50,5,0,0 +124109,-50,4,2,50,65,0,0 +124183,-50,4,2,50,5,0,0 +124331,-100,4,2,50,65,0,0 +124627,-100,4,2,50,5,0,0 +124776,-25,4,2,50,65,0,1 +124924,-25,4,2,50,5,0,1 +124998,-25,4,2,50,65,0,1 +125146,-25,4,2,50,5,0,1 +125220,-25,4,2,50,65,0,1 +125368,-25,4,2,50,5,0,1 +125443,-25,4,2,50,65,0,1 +125591,-25,4,2,50,5,0,1 +125665,-25,4,2,50,65,0,1 +125813,-25,4,2,50,5,0,1 +125887,-25,4,2,50,65,0,1 +126035,-25,4,2,50,5,0,1 +126109,-50,4,2,50,65,0,1 +126257,-50,4,2,50,5,0,1 +126331,-100,4,2,50,65,0,0 +126479,-100,4,2,50,5,0,0 +126554,-33.3333333333333,4,2,50,65,0,0 +126850,-33.3333333333333,4,2,50,5,0,0 +126924,-100,4,2,50,65,0,0 +127146,-100,4,2,50,5,0,0 +127220,-50,4,2,50,65,0,0 +127553,-50,4,2,50,5,0,0 +127665,-50,4,2,50,65,0,0 + + +[Colours] +Combo1 : 141,216,109 +Combo2 : 191,181,119 + +[HitObjects] +140,242,14554,6,0,P|152:283|160:348,2,95,4|2|8,2:2|2:3|2:2,0:0:0:0: +98,147,15146,1,0,0:0:0:0: +90,162,15220,2,0,P|61:175|16:180,1,63.3333333333333,2|0,2:3|1:1,0:0:0:0: +30,180,15665,1,0,1:1:0:0: +252,94,15887,1,8,2:2:0:0: +453,164,16109,5,0,0:0:0:0: +462,154,18109,6,0,P|383:120|367:77,1,118.75,4|2,2:1|2:3,0:0:0:0: +335,24,18480,1,0,0:0:0:0: +335,24,18554,2,0,P|291:38|221:36,1,79.1666666666667,8|0,2:2|0:0,0:0:0:0: +168,119,18776,2,0,P|211:118|274:139,1,79.1666666666667,2|0,2:3|1:1,0:0:0:0: +246,126,19220,5,0,1:1:0:0: +115,44,19443,1,8,2:2:0:0: +104,194,19665,2,0,P|115:227|121:277,1,79.1666666666667,2|0,2:2|0:0,0:0:0:0: +48,124,19887,6,0,P|16:185|76:340,1,237.500009059906,2|0,2:2|0:0,0:0:0:0: +153,346,20331,2,0,P|201:335|251:329,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: +246,329,20554,2,0,P|250:279|201:237,1,95.0000036239625,2|0,2:2|1:1,0:0:0:0: +223,245,20776,5,2,2:2:0:0: +355,384,20924,1,2,2:3:0:0: +355,384,20998,1,0,1:1:0:0: +505,303,21220,2,0,P|447:290|390:271,1,118.750004529953,10|0,2:2|0:0,0:0:0:0: +375,269,21665,6,0,P|345:334|359:398,1,118.75,0|2,1:1|2:3,0:0:0:0: +309,215,21998,6,0,P|267:156|205:136,1,118.75 +389,184,22331,6,0,P|460:177|484:148,1,79.1666666666667,2|0,2:3|1:1,0:0:0:0: +463,174,22776,6,0,P|485:127|477:84,1,79.1666666666667,0|0,1:1|0:0,0:0:0:0: +330,0,22998,2,0,P|338:52|341:130,1,118.75,8|2,2:2|2:3,0:0:0:0: +341,118,23443,5,2,2:2:0:0: +417,37,23665,1,2,2:2:0:0: +384,274,23887,1,10,2:2:0:0: +189,125,24109,1,2,2:2:0:0: +164,50,24257,5,0,1:1:0:0: +164,50,24331,2,0,L|280:59,1,95,2|0,2:2|1:1,0:0:0:0: +259,59,24776,2,0,P|170:64|83:-9,1,197.916666666667,10|0,2:2|0:0,0:0:0:0: +39,64,25220,6,0,P|36:115|27:197,1,118.75,2|2,2:1|2:3,0:0:0:0: +145,273,25554,2,0,P|85:266|26:262,1,118.75 +234,202,25887,2,0,P|230:242|231:282,1,79.1666666666667,0|0,1:1|1:1,0:0:0:0: +231,282,26331,5,0,1:1:0:0: +12,377,26554,2,0,P|31:327|14:237,1,118.75,8|2,2:2|2:2,0:0:0:0: +234,202,26998,6,0,B|366:201|309:182|425:185,1,190.000007247925,2|0,2:2|0:0,0:0:0:0: +491,238,27369,1,0,0:0:0:0: +491,238,27443,2,0,P|444:271|378:262,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: +407,100,27665,2,0,P|453:105|490:134,1,95.0000036239625,2|0,2:2|1:1,0:0:0:0: +491,238,27887,5,2,2:2:0:0: +342,157,28109,1,0,1:1:0:0: +342,157,28183,1,2,2:2:0:0: +300,343,28443,5,2,0:0:0:0: +300,343,28776,6,0,P|394:320|508:388,2,213.750008153916,4|0|2,1:1|0:0|2:3,0:0:0:0: +285,110,29887,6,0,P|370:94|388:78,1,95.0000036239625,0|0,1:1|0:0,0:0:0:0: +474,9,30109,2,0,P|450:63|368:105,1,142.500005435944,8|2,2:2|2:3,0:0:0:0: +194,141,30554,5,2,2:2:0:0: +220,46,30776,1,2,2:2:0:0: +153,228,30998,5,10,2:2:0:0: +46,31,31220,1,2,2:2:0:0: +58,210,31369,5,2,2:3:0:0: +63,213,31443,2,0,P|104:213|171:199,1,89.0625,2|0,2:2|0:0,0:0:0:0: +245,224,31665,6,0,P|200:224|134:237,1,95.0000036239625,0|0,1:1|2:2,0:0:0:0: +87,292,31887,1,8,2:2:0:0: +87,292,31961,2,0,P|88:332|101:371,2,47.5000018119813,2|2|2,2:2|2:3|2:3,0:0:0:0: +40,20,32331,6,0,P|9:70|32:152,1,142.500005435944,0|2,1:1|2:3,0:0:0:0: +138,81,32665,2,0,P|110:29|27:8,1,142.500005435944 +38,140,32998,2,0,P|96:141|156:80,1,142.500005435944,0|0,1:1|0:0,0:0:0:0: +154,86,33443,6,0,P|212:80|247:70,1,95,0|8,1:1|2:2,0:0:0:0: +286,0,33776,1,0,0:0:0:0: +286,0,33887,1,2,2:2:0:0: +258,218,34109,6,0,P|271:292|271:368,2,142.500005435944,2|2|10,2:2|2:2|2:2,0:0:0:0: +380,251,34776,2,0,P|372:282|368:344,1,71.2500027179719,2|0,2:2|0:0,0:0:0:0: +471,384,34998,2,0,P|461:330|459:253,1,118.75,2|0,2:2|1:1,0:0:0:0: +260,217,35443,5,8,2:2:0:0: +161,298,35591,1,2,2:2:0:0: +161,298,35665,2,0,P|179:354|188:391,1,79.1666666666667,2|0,2:3|0:0,0:0:0:0: +46,246,35887,6,0,P|29:314|43:384,1,142.500005435944,0|2,1:1|2:3,0:0:0:0: +256,216,36220,2,0,P|189:192|120:205,1,142.500005435944 +371,232,36554,2,0,P|438:227|524:210,1,142.500005435944,2|0,2:3|0:0,0:0:0:0: +511,213,36998,6,0,P|497:171|496:130,1,79.1666666666667,0|0,1:1|0:0,0:0:0:0: +381,36,37220,2,0,P|376:78|428:153,1,118.75,8|2,2:2|2:3,0:0:0:0: +472,55,37665,5,2,2:2:0:0: +368,17,37887,1,2,2:2:0:0: +114,109,38109,5,10,2:2:0:0: +269,65,38331,1,2,2:2:0:0: +12,84,38554,5,2,2:1:0:0: +482,60,38998,1,10,2:1:0:0: +225,293,39443,6,0,P|129:279|22:359,2,213.750008153916,0|0|0,1:1|0:0|1:1,0:0:0:0: +511,364,40554,6,0,P|424:367|403:355,1,95.0000036239625,0|0,1:1|0:0,0:0:0:0: +322,284,40776,2,0,P|346:338|428:380,1,142.500005435944,8|2,2:2|2:3,0:0:0:0: +470,283,41146,5,0,0:0:0:0: +470,283,41220,2,0,P|455:233|449:167,1,95.0000036239625,2|0,2:2|0:0,0:0:0:0: +445,85,41443,2,0,P|412:94|382:97,1,63.3333333333333,2|0,2:2|0:0,0:0:0:0: +316,47,41665,2,0,P|296:28|273:0,1,63.3333333333333,10|0,2:2|0:0,0:0:0:0: +306,124,41887,6,0,P|302:155|290:203,1,79.1666666666667,2|2,2:2|2:3,0:0:0:0: +307,335,42109,2,0,P|322:283|360:244,1,106.875004076958,2|0,2:1|0:0,0:0:0:0: +231,286,42554,2,0,P|201:191|56:68,1,285,10|0,2:1|0:0,0:0:0:0: +0,28,42998,6,0,P|76:27|164:7,2,142.500005435944,10|8|8,2:2|2:3|2:3,0:0:0:0: +192,75,44109,1,2,2:2:0:0: +257,35,44331,2,0,P|301:22|380:23,1,106.875004076958,8|0,2:3|0:0,0:0:0:0: +361,20,44776,5,10,2:2:0:0: +453,10,44998,1,2,2:2:0:0: +512,73,45220,1,10,2:2:0:0: +0,12,45665,5,8,2:3:0:0: +0,12,45887,1,0,0:0:0:0: +0,12,46109,1,8,2:3:0:0: +0,12,46554,6,0,P|66:37|104:44,1,106.875004076958,10|2,2:2|2:2,0:0:0:0: +169,0,46998,1,8,2:3:0:0: +375,56,47220,2,0,P|425:82|492:71,1,118.750004529953,2|0,2:2|0:0,0:0:0:0: +501,55,47665,2,0,P|485:15|442:-6,1,71.2500027179719,2|10,2:2|2:2,0:0:0:0: +188,77,48109,5,0,0:0:0:0: +188,77,48331,2,0,L|201:158,2,71.2500027179719,10|2|10,2:2|2:2|2:2,0:0:0:0: +307,0,48998,2,0,L|296:83,1,71.2500027179719,0|8,0:0|2:3,0:0:0:0: +297,70,49665,1,8,2:3:0:0: +380,57,49887,2,0,L|407:5,1,47.5000018119813 +188,77,50109,6,0,P|141:70|67:52,2,106.875004076958,10|0|2,2:2|0:0|2:2,0:0:0:0: +188,77,51220,1,2,2:2:0:0: +33,125,51442,2,0,P|8:87|21:2,1,118.750004529953,8|0,2:3|0:0,0:0:0:0: +12,16,51887,5,10,2:2:0:0: +90,59,52109,1,2,2:2:0:0: +189,63,52331,1,10,2:2:0:0: +512,0,52776,5,8,2:3:0:0: +512,0,52998,1,0,0:0:0:0: +512,0,53220,1,8,2:3:0:0: +512,0,53665,6,0,P|446:25|408:32,1,106.875004076958,10|2,2:2|2:2,0:0:0:0: +410,31,54109,1,8,2:3:0:0: +359,110,54331,2,0,P|333:60|344:-7,1,118.750004529953,2|0,2:2|0:0,0:0:0:0: +492,96,54776,6,0,P|470:123|437:134,1,71.2500027179719,2|10,2:2|2:2,0:0:0:0: +256,75,55220,5,0,0:0:0:0: +256,75,55442,2,0,L|186:64,2,71.2500027179719,10|2|10,2:2|2:2|2:2,0:0:0:0: +359,110,56331,1,8,2:3:0:0: +256,384,56554,5,0,0:0:0:0: +135,352,56776,1,0,0:0:0:0: +135,352,57220,6,0,P|84:233|42:152,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: +214,2,57443,6,0,P|171:136|143:197,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: +63,39,57665,6,0,P|124:60|246:78,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: +256,370,57887,6,0,P|250:290|231:211,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: +494,219,58109,6,0,P|417:253|343:298,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: +322,67,58332,6,0,P|342:136|371:183,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: +242,377,58554,6,0,P|195:353|137:342,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: +22,207,58776,6,0,B|106:200|66:194|139:190,1,118.75,2|0,2:2|1:1,0:0:0:0: +491,202,59220,5,2,2:3:0:0: +370,162,59331,1,0,0:0:0:0: +442,76,59443,2,0,P|456:117|450:147,1,59.375,10|0,2:2|0:0,0:0:0:0: +362,170,59665,2,0,P|328:98|376:-9,1,190,2|0,2:2|1:1,0:0:0:0: +266,379,60109,6,0,B|286:309|235:316|253:224,1,142.5,2|0,2:2|0:0,0:0:0:0: +250,240,60331,2,0,L|263:356,1,106.875004076958,10|0,2:1|0:0,0:0:0:0: +243,145,60776,6,0,P|362:94|441:49,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: +108,108,60998,6,0,P|65:242|36:301,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: +422,317,61221,6,0,P|441:230|468:147,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: +188,69,61443,6,0,P|108:63|35:46,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: +2,355,61665,6,0,P|51:327|140:304,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: +155,168,61888,6,0,P|86:188|37:218,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: +328,287,62110,6,0,P|375:311|431:322,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: +259,156,62332,6,0,B|252:185|250:238,1,79.1666666666667,2|0,2:2|0:0,0:0:0:0: +439,37,62554,6,0,P|482:212|307:280,1,380.00001449585,4|0,1:1|0:0,0:0:0:0: +271,154,62924,2,0,P|277:121|312:93,1,63.3333333333333,2|0,2:3|0:0,0:0:0:0: +327,286,63220,6,0,P|378:148|208:19,1,380.00001449585,6|0,2:2|0:0,0:0:0:0: +162,83,63591,5,2,2:3:0:0: +162,83,63665,2,0,P|133:83|99:71,1,47.5,2|2,2:2|2:2,0:0:0:0: +63,227,63887,1,10,2:2:0:0: +40,145,63998,1,2,2:2:0:0: +20,64,64109,1,2,2:1:0:0: +30,67,64331,6,0,P|113:58|235:23,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: +184,369,64554,6,0,P|107:335|-9:304,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: +425,32,64776,6,0,P|409:124|401:231,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: +100,370,64998,6,0,P|87:270|66:189,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: +387,107,65220,6,0,P|442:142|527:177,1,142.5,2|0,1:2|0:0,0:0:0:0: +203,269,65443,6,0,P|229:203|246:129,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: +483,277,65665,6,0,P|486:330|502:392,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: +400,205,65887,6,0,B|480:198|440:171|528:172,1,118.75,2|0,2:2|1:1,0:0:0:0: +372,357,66331,5,2,2:3:0:0: +287,283,66442,1,0,0:0:0:0: +175,345,66554,2,0,P|132:357|93:360,1,79.1666666666667,10|0,2:2|0:0,0:0:0:0: +28,257,66776,2,0,P|100:223|207:271,1,190,2|0,2:2|1:1,0:0:0:0: +0,117,67221,6,0,P|76:106|183:76,1,142.5,2|0,2:2|0:0,0:0:0:0: +125,113,67443,2,0,P|65:108|18:101,1,106.875004076958,10|0,2:1|0:0,0:0:0:0: +194,0,67887,6,0,P|245:119|290:198,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: +10,350,68109,6,0,P|43:269|67:186,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: +412,34,68332,6,0,P|388:109|372:187,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: +194,0,68554,6,0,P|263:39|322:85,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: +197,271,68776,6,0,P|225:222|291:157,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: +448,305,68999,6,0,P|392:308|338:298,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: +409,117,69220,6,0,P|456:141|514:152,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: +225,349,69443,6,0,B|184:357|141:355,1,79.1666666666667,2|0,2:2|0:0,0:0:0:0: +198,200,69665,6,0,P|277:356|447:311,1,380.00001449585,4|0,1:1|0:0,0:0:0:0: +445,334,70035,2,0,P|424:355|391:370,1,63.3333333333333,2|0,2:3|0:0,0:0:0:0: +188,271,70331,6,0,P|238:100|416:93,1,380.00001449585,6|0,2:2|0:0,0:0:0:0: +341,222,70776,1,2,2:2:0:0: +341,222,70887,1,2,2:2:0:0: +134,157,70998,6,0,P|55:171|-17:118,1,142.500005435944,10|0,2:2|0:0,0:0:0:0: +46,328,71220,6,0,P|84:301|100:257,1,95,2|0,2:2|0:0,0:0:0:0: +192,275,71443,6,0,P|212:317|207:364,1,95,2|2,2:2|2:2,0:0:0:0: +54,334,71887,1,10,2:2:0:0: +262,237,72109,1,2,2:2:0:0: +432,296,72331,2,0,P|382:310|296:318,2,95,2|0|10,2:1|1:1|2:2,0:0:0:0: +432,296,72998,5,2,2:2:0:0: +369,137,73220,2,0,L|360:255,1,95,2|2,2:2|2:2,0:0:0:0: +411,17,73665,5,10,2:2:0:0: +451,169,73887,1,2,2:2:0:0: +292,117,74035,1,0,1:1:0:0: +292,117,74109,1,2,2:1:0:0: +415,26,74331,6,0,P|322:62|223:37,1,190,0|2,1:1|2:2,0:0:0:0: +236,44,74998,2,0,L|133:59,1,95,2|2,2:1|2:3,0:0:0:0: +0,116,75443,5,10,2:2:0:0: +0,116,75665,1,2,2:2:0:0: +173,141,75887,2,0,L|78:127,1,95,2|0,2:1|1:1,0:0:0:0: +82,0,76331,1,10,2:2:0:0: +82,0,76554,1,2,2:2:0:0: +79,127,76776,6,0,P|80:197|53:296,1,142.500005435944,2|2,2:2|2:2,0:0:0:0: +12,323,77109,1,2,2:2:0:0: +87,344,77220,2,0,P|111:343|149:353,1,47.5,10|0,2:2|0:0,0:0:0:0: +255,179,77443,2,0,P|205:230|145:269,1,142.500005435944,2|2,2:2|2:1,0:0:0:0: +261,384,77887,1,0,1:1:0:0: +366,199,78109,5,10,2:2:0:0: +293,263,78220,1,2,2:2:0:0: +386,295,78331,1,2,2:2:0:0: +152,279,78554,2,0,P|231:267|311:263,1,142.500005435944,2|2,2:1|2:3,0:0:0:0: +486,152,78998,5,10,2:2:0:0: +366,199,79109,1,2,2:2:0:0: +465,295,79220,2,0,P|487:291|532:288,1,47.5,2|0,2:2|0:0,0:0:0:0: +424,369,79443,5,2,2:1:0:0: +446,220,79665,5,0,1:1:0:0: +466,68,79887,5,10,2:2:0:0: +389,80,79998,1,2,2:2:0:0: +316,45,80109,1,2,2:2:0:0: +312,35,80331,5,2,2:2:0:0: +248,79,80443,1,2,2:2:0:0: +171,50,80554,2,0,L|162:-25,1,47.5,2|0,2:2|0:0,0:0:0:0: +23,80,80776,5,10,2:2:0:0: +104,98,80887,1,2,2:2:0:0: +176,58,80998,2,0,L|185:-17,1,47.5,2|0,2:2|0:0,0:0:0:0: +184,156,81220,1,2,2:1:0:0: +184,156,81443,6,0,B|183:248|198:192|197:314,1,142.500005435944,0|10,1:1|2:2,0:0:0:0: +204,384,81776,1,2,2:2:0:0: +204,384,81887,1,2,2:2:0:0: +116,268,82109,2,0,P|71:253|25:262,1,95,2|2,2:1|2:3,0:0:0:0: +204,384,82554,5,10,2:2:0:0: +67,341,82665,1,2,2:2:0:0: +67,341,82776,1,2,2:2:0:0: +275,337,82924,5,0,1:1:0:0: +275,337,82998,2,0,P|321:346|365:331,1,95,2|0,2:1|1:1,0:0:0:0: +349,335,83443,2,0,P|267:333|194:395,1,158.333333333333,10|0,2:1|0:0,0:0:0:0: +134,349,83887,6,0,P|77:361|-8:328,1,142.500005435944,2|2,2:2|2:2,0:0:0:0: +422,272,84257,1,0,0:0:0:0: +422,272,84331,2,0,P|479:284|506:275,1,63.3333333333333,10|0,2:1|0:0,0:0:0:0: +496,101,84554,2,0,P|439:89|386:114,1,95.0000036239625,2|0,1:2|1:1,0:0:0:0: +336,193,84776,6,0,B|430:186|387:182|480:176,1,142.500005435944,2|0,2:1|1:1,0:0:0:0: +478,177,85220,5,8,2:2:0:0: +502,101,85369,1,2,2:3:0:0: +502,101,85443,1,2,2:3:0:0: +256,192,85665,5,2,2:2:0:0: +256,192,85887,1,2,2:3:0:0: +256,192,86109,1,8,2:2:0:0: +256,192,86776,1,2,2:2:0:0: +256,192,86998,1,8,2:2:0:0: +256,192,87443,1,2,2:2:0:0: +256,192,87887,1,10,2:2:0:0: +256,192,88276,1,0,1:1:0:0: +256,192,88480,1,2,2:3:0:0: +256,192,88554,1,0,1:1:0:0: +256,192,88776,1,8,2:2:0:0: +256,192,88943,1,2,2:3:0:0: +256,192,89220,1,2,2:2:0:0: +256,192,89443,1,2,2:3:0:0: +256,192,89665,1,8,2:2:0:0: +256,192,90054,1,0,1:1:0:0: +256,192,90331,1,2,2:2:0:0: +256,192,90554,1,10,2:2:0:0: +256,192,90998,1,2,2:2:0:0: +256,192,91443,1,10,2:2:0:0: +256,192,91831,1,0,1:1:0:0: +256,192,92035,1,2,2:3:0:0: +256,192,92109,1,0,1:1:0:0: +256,192,92331,1,8,2:2:0:0: +256,192,92498,1,2,2:3:0:0: +256,192,92776,6,0,P|226:227|227:272,1,71.2500027179719,2|2,2:2|2:3,0:0:0:0: +256,192,93109,6,0,P|301:200|377:160,1,95 +256,192,93443,6,0,P|232:134|105:76,1,197.916666666667,2|0,2:2|0:0,0:0:0:0: +189,46,93887,2,0,P|232:41|281:25,1,95,2|8,2:2|2:2,0:0:0:0: +36,22,94554,5,2,2:2:0:0: +103,73,94776,1,2,2:2:0:0: +185,45,94998,1,10,2:2:0:0: +512,0,95387,5,0,1:0:0:0: +512,0,95665,5,0,1:1:0:0: +512,0,95887,5,8,2:2:0:0: +512,0,96331,2,0,P|481:39|451:98,1,95,2|2,2:2|2:3,0:0:0:0: +367,70,96665,2,0,P|325:84|289:134,1,95,2|0,2:2|0:0,0:0:0:0: +503,150,96998,2,0,P|462:97|354:96,1,158.333333333333,2|0,2:2|0:0,0:0:0:0: +370,71,97443,5,2,2:2:0:0: +285,7,97665,1,10,2:2:0:0: +189,47,97887,2,0,P|153:49|107:64,1,63.3333333333333 +32,20,98109,2,0,P|46:71|48:124,1,95,2|2,2:2|2:2,0:0:0:0: +127,137,98480,1,0,0:0:0:0: +127,137,98554,1,10,2:2:0:0: +189,41,98776,6,0,P|203:92|207:125,1,71.25,0|0,0:0|1:1,0:0:0:0: +2,384,99220,1,0,0:0:0:0: +135,352,99443,1,0,0:0:0:0: +135,352,99887,6,0,P|84:233|37:152,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: +445,0,100109,6,0,P|402:134|374:195,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: +224,18,100332,6,0,P|285:39|408:56,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: +152,130,100554,6,0,P|112:94|31:29,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: +512,269,100776,6,0,P|435:302|367:343,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: +271,183,100999,6,0,P|335:166|385:136,1,124.687501189113,2|0,2:2|0:0,0:0:0:0: +302,298,101221,6,0,P|255:274|195:260,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: +22,207,101443,6,0,B|106:200|66:194|139:190,1,118.75,2|0,2:2|1:1,0:0:0:0: +230,15,101887,5,2,2:3:0:0: +272,184,101998,1,0,0:0:0:0: +402,62,102110,2,0,L|417:-11,1,59.375,10|0,2:2|0:0,0:0:0:0: +320,21,102332,2,0,P|271:67|279:195,1,190,2|0,2:2|1:1,0:0:0:0: +512,179,102776,6,0,B|442:159|361:198,1,142.5,2|0,2:2|0:0,0:0:0:0: +373,192,102998,2,0,P|442:196|489:179,1,106.875004076958,10|0,2:1|0:0,0:0:0:0: +197,228,103443,6,0,P|102:278|7:315,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: +456,383,103665,6,0,P|356:283|317:234,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: +100,21,103888,6,0,P|46:91|1:164,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: +259,168,104110,6,0,P|260:87|274:12,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: +83,198,104332,6,0,P|106:280|133:337,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: +473,90,104555,6,0,P|395:65|347:37,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: +416,287,104777,6,0,P|468:276|514:254,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: +421,171,104999,6,0,B|377:166|343:156,1,79.1666666666667,2|0,2:2|0:0,0:0:0:0: +6,333,105221,6,0,P|90:183|289:267,1,380.00001449585,4|0,1:1|0:0,0:0:0:0: +282,342,105591,2,0,P|249:336|210:278,1,95,2|0,2:3|0:0,0:0:0:0: +267,227,105887,6,0,P|129:278|11:117,1,356.25001358986,6|0,2:2|0:0,0:0:0:0: +93,46,106258,5,2,2:3:0:0: +93,46,106332,2,0,P|93:75|81:109,1,47.5,2|2,2:2|2:2,0:0:0:0: +263,97,106554,1,10,2:2:0:0: +295,13,106665,1,2,2:2:0:0: +208,24,106776,1,2,2:1:0:0: +200,42,106998,6,0,P|283:33|415:-2,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: +357,374,107221,6,0,P|290:302|236:217,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: +484,299,107443,6,0,P|419:284|307:275,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: +442,66,107665,6,0,P|455:166|478:245,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: +249,215,107887,6,0,P|306:188|367:150,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: +141,282,108110,6,0,P|90:318|45:338,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: +184,48,108332,6,0,P|226:79|271:104,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: +112,199,108554,6,0,B|32:192|72:165|-16:166,1,118.75,2|0,2:2|1:1,0:0:0:0: +282,102,108998,5,2,2:3:0:0: +341,270,109109,1,0,0:0:0:0: +468,175,109221,2,0,P|465:148|483:102,1,59.375,10|0,2:2|0:0,0:0:0:0: +374,199,109443,2,0,P|282:302|305:379,1,190,2|0,2:2|1:1,0:0:0:0: +133,261,109887,6,0,P|64:229|-15:216,1,142.5,2|0,2:2|0:0,0:0:0:0: +0,217,110109,2,0,P|56:204|98:185,1,89.0625033974649,10|0,2:1|0:0,0:0:0:0: +204,0,110554,6,0,P|213:83|250:211,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: +512,73,110776,6,0,P|435:39|319:7,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: +5,229,110999,6,0,P|61:290|116:360,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: +379,213,111221,6,0,P|393:134|418:64,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: +131,123,111443,6,0,P|65:95|10:57,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: +130,355,111666,6,0,P|190:338|244:316,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: +335,137,111888,6,0,P|293:169|233:198,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: +378,233,112110,6,0,P|420:223|486:214,1,79.1666666666667,2|0,2:2|0:0,0:0:0:0: +456,206,112331,6,0,B|224:229|371:239|70:267,1,380.00001449585,4|0,1:1|0:0,0:0:0:0: +12,151,112702,2,0,P|51:178|98:181,1,95,2|0,2:3|0:0,0:0:0:0: +181,236,112998,2,0,P|47:255|5:384,1,285.000010871888,6|0,2:2|1:1,0:0:0:0: +456,206,113443,5,2,2:2:0:0: +456,206,113554,1,2,2:2:0:0: +482,120,113665,2,0,L|504:34,1,71.2500027179719,8|0,2:2|0:0,0:0:0:0: +132,70,113887,5,2,2:3:0:0: +132,70,113998,1,0,0:0:0:0: +0,55,114109,6,0,L|251:25,1,253.333333333333,6|0,1:2|0:0,0:0:0:0: +482,379,114331,6,0,L|263:347,1,221.666668780645,2|0,2:2|0:0,0:0:0:0: +63,2,114554,6,0,L|251:26,1,190.000007247925,10|0,2:2|0:0,0:0:0:0: +420,325,114776,6,0,L|264:346,1,158.333333333333,2|0,2:2|0:0,0:0:0:0: +132,70,114998,6,0,L|251:26,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: +351,384,115220,6,0,L|264:346,1,95.0000036239625,2|0,2:2|0:0,0:0:0:0: +187,25,115443,6,0,L|251:21,1,63.3333333333333,10|0,2:2|0:0,0:0:0:0: +32,192,115665,5,2,2:1:0:0: +251,6,115887,1,0,1:1:0:0: +480,192,116109,1,2,2:1:0:0: +261,378,116331,1,10,2:1:0:0: +274,103,116554,5,2,2:1:0:0: +299,223,116665,1,0,0:0:0:0: +176,174,116776,2,0,P|123:183|31:180,1,126.666666666667,6|0,2:2|0:0,0:0:0:0: +51,183,116998,2,0,P|84:157|138:159,1,63.3333333333333,2|0,2:3|0:0,0:0:0:0: +248,277,117220,2,0,P|236:221|168:181,1,126.666666666667,14|0,2:2|0:0,0:0:0:0: +418,77,117665,6,0,L|453:375,1,253.333333333333,6|0,1:2|0:0,0:0:0:0: +228,360,117887,6,0,L|520:318,1,221.666668780645,2|0,2:2|0:0,0:0:0:0: +471,140,118109,6,0,L|445:345,1,190.000007247925,10|0,2:2|0:0,0:0:0:0: +290,307,118331,6,0,L|489:333,1,158.333333333333,2|0,2:2|0:0,0:0:0:0: +400,210,118554,6,0,L|450:337,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: +362,369,118776,6,0,L|452:324,1,95.0000036239625,2|0,2:2|0:0,0:0:0:0: +440,263,118998,6,0,L|448:336,1,63.3333333333333,10|0,2:2|0:0,0:0:0:0: +402,310,119220,6,0,L|450:327,1,47.5000018119813,2|0,2:2|0:0,0:0:0:0: +208,369,119443,6,0,P|71:217|11:334,1,380.00001449585,4|0,1:1|0:0,0:0:0:0: +90,384,119813,2,0,P|116:326|127:267,1,95,2|0,2:3|0:0,0:0:0:0: +328,170,120109,2,0,P|373:54|480:149,1,285.000010871888,6|0,2:0|1:1,0:0:0:0: +326,190,120480,1,2,2:3:0:0: +326,190,120554,2,0,P|279:178|236:160,1,95.0000036239625,2|0,2:2|0:0,0:0:0:0: +0,156,120776,5,10,2:2:0:0: +104,100,120887,1,2,2:2:0:0: +97,220,120998,1,2,2:1:0:0: +135,351,121220,6,0,L|97:43,1,253.333333333333,6|0,1:2|0:0,0:0:0:0: +249,9,121443,6,0,L|207:297,1,221.666668780645,2|0,2:2|0:0,0:0:0:0: +0,249,121665,6,0,L|23:51,1,190.000007247925,10|0,2:2|0:0,0:0:0:0: +318,198,121887,6,0,L|347:387,1,158.333333333333,2|0,2:2|0:0,0:0:0:0: +48,366,122109,6,0,L|-3:243,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: +360,102,122331,6,0,L|408:188,1,95.0000036239625,2|0,2:2|0:0,0:0:0:0: +148,384,122554,6,0,L|140:313,1,63.3333333333333,10|0,2:2|0:0,0:0:0:0: +256,48,122776,5,2,2:1:0:0: +256,368,122998,1,0,1:1:0:0: +256,48,123220,5,2,2:1:0:0: +256,368,123443,1,10,2:1:0:0: +256,368,123665,5,2,2:1:0:0: +280,233,123776,1,0,0:0:0:0: +404,307,123887,2,0,P|451:298|470:218,1,126.666666666667,6|0,2:2|0:0,0:0:0:0: +497,219,124109,2,0,P|452:182|417:195,1,63.3333333333333,2|0,2:3|0:0,0:0:0:0: +208,309,124331,2,0,B|135:281|170:305|57:277,1,126.666666666667,14|0,2:2|0:0,0:0:0:0: +88,81,124776,6,0,P|135:173|249:386,1,253.333333333333,6|0,1:2|0:0,0:0:0:0: +243,156,124998,6,0,P|181:118|10:6,1,253.333333333333,2|0,2:2|0:0,0:0:0:0: +0,250,125220,6,0,P|120:211|239:167,1,253.333333333333,10|0,2:2|0:0,0:0:0:0: +363,16,125443,6,0,P|291:187|252:274,1,253.333333333333,2|0,2:2|0:0,0:0:0:0: +458,340,125665,6,0,P|351:337|178:315,1,253.333333333333,2|0,1:2|0:0,0:0:0:0: +186,7,125887,6,0,P|241:164|269:273,1,253.333333333333,2|0,2:2|0:0,0:0:0:0: +461,349,126109,6,0,P|413:307|363:268,1,126.666666666667,10|0,2:2|0:0,0:0:0:0: +441,193,126331,6,0,P|479:191|523:172,1,63.3333333333333,2|0,2:2|0:0,0:0:0:0: +503,184,126554,2,0,P|409:160|281:406,1,380.00001449585,4|0,1:1|0:0,0:0:0:0: +456,357,126924,2,0,P|412:340|366:344,1,95,2|0,2:3|0:0,0:0:0:0: +0,47,127220,2,0,P|107:29|201:172,1,285,6|0,2:2|0:0,0:0:0:0: +193,159,127665,5,2,2:2:0:0: +21,210,127813,1,0,0:0:0:0: +21,210,127887,1,8,2:2:0:0: +149,331,128035,5,2,2:3:0:0: +149,331,128109,1,2,2:3:0:0: +202,158,128257,1,2,2:3:0:0: diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/801165-expected-conversion.json b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/801165-expected-conversion.json new file mode 100644 index 000000000000..0309bb90fdc6 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/801165-expected-conversion.json @@ -0,0 +1 @@ +{"Mappings":[{"StartTime":6337.0,"Objects":[{"StartTime":6337.0,"EndTime":6337.0,"X":378.0,"Y":163.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":6559.0,"EndTime":6559.0,"X":467.160767,"Y":186.920609,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":6745.0,"EndTime":6745.0,"X":378.0,"Y":163.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7115.0,"Objects":[{"StartTime":7115.0,"EndTime":7115.0,"X":320.0,"Y":312.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":7190.0,"EndTime":7190.0,"X":332.12677,"Y":360.507141,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7560.0,"Objects":[{"StartTime":7560.0,"EndTime":7560.0,"X":164.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":7587.0,"EndTime":7587.0,"X":139.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7671.0,"Objects":[{"StartTime":7671.0,"EndTime":7671.0,"X":139.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":7698.0,"EndTime":7698.0,"X":114.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7782.0,"Objects":[{"StartTime":7782.0,"EndTime":7782.0,"X":114.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":7809.0,"EndTime":7809.0,"X":89.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7893.0,"Objects":[{"StartTime":7893.0,"EndTime":7893.0,"X":89.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":7920.0,"EndTime":7920.0,"X":64.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":8004.0,"Objects":[{"StartTime":8004.0,"EndTime":8004.0,"X":32.0,"Y":184.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":8079.0,"EndTime":8079.0,"X":42.8465233,"Y":135.190643,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":8226.0,"Objects":[{"StartTime":8226.0,"EndTime":8226.0,"X":144.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":8301.0,"EndTime":8301.0,"X":154.846527,"Y":79.19064,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":8449.0,"Objects":[{"StartTime":8449.0,"EndTime":8449.0,"X":266.0,"Y":68.0}]},{"StartTime":8560.0,"Objects":[{"StartTime":8560.0,"EndTime":8560.0,"X":306.0,"Y":40.0}]},{"StartTime":8671.0,"Objects":[{"StartTime":8671.0,"EndTime":8671.0,"X":356.0,"Y":39.0}]},{"StartTime":8782.0,"Objects":[{"StartTime":8782.0,"EndTime":8782.0,"X":397.0,"Y":66.0}]},{"StartTime":8893.0,"Objects":[{"StartTime":8893.0,"EndTime":8893.0,"X":415.0,"Y":111.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":8968.0,"EndTime":8968.0,"X":439.476746,"Y":154.599182,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":9115.0,"Objects":[{"StartTime":9115.0,"EndTime":9115.0,"X":429.0,"Y":263.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":9190.0,"EndTime":9190.0,"X":454.28598,"Y":306.1349,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":9337.0,"Objects":[{"StartTime":9337.0,"EndTime":9337.0,"X":328.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":9364.0,"EndTime":9364.0,"X":315.596527,"Y":250.293915,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":9449.0,"Objects":[{"StartTime":9449.0,"EndTime":9449.0,"X":315.0,"Y":250.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":9476.0,"EndTime":9476.0,"X":302.3705,"Y":228.424637,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":9560.0,"Objects":[{"StartTime":9560.0,"EndTime":9560.0,"X":303.0,"Y":228.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":9587.0,"EndTime":9587.0,"X":290.506927,"Y":206.345367,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":9671.0,"Objects":[{"StartTime":9671.0,"EndTime":9671.0,"X":290.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":9698.0,"EndTime":9698.0,"X":277.506927,"Y":185.345367,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":9782.0,"Objects":[{"StartTime":9782.0,"EndTime":9782.0,"X":248.0,"Y":152.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":9857.0,"EndTime":9857.0,"X":248.0,"Y":102.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":10004.0,"Objects":[{"StartTime":10004.0,"EndTime":10004.0,"X":154.0,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":10079.0,"EndTime":10079.0,"X":154.0,"Y":86.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":10226.0,"Objects":[{"StartTime":10226.0,"EndTime":10226.0,"X":64.0,"Y":168.0}]},{"StartTime":10337.0,"Objects":[{"StartTime":10337.0,"EndTime":10337.0,"X":19.0,"Y":187.0}]},{"StartTime":10449.0,"Objects":[{"StartTime":10449.0,"EndTime":10449.0,"X":0.0,"Y":232.0}]},{"StartTime":10560.0,"Objects":[{"StartTime":10560.0,"EndTime":10560.0,"X":14.0,"Y":278.0}]},{"StartTime":10671.0,"Objects":[{"StartTime":10671.0,"EndTime":10671.0,"X":56.0,"Y":303.0}]},{"StartTime":10782.0,"Objects":[{"StartTime":10782.0,"EndTime":10782.0,"X":101.0,"Y":282.0}]},{"StartTime":10893.0,"Objects":[{"StartTime":10893.0,"EndTime":10893.0,"X":151.0,"Y":282.0}]},{"StartTime":11004.0,"Objects":[{"StartTime":11004.0,"EndTime":11004.0,"X":196.0,"Y":302.0}]},{"StartTime":11115.0,"Objects":[{"StartTime":11115.0,"EndTime":11115.0,"X":240.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":11142.0,"EndTime":11142.0,"X":265.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":11226.0,"Objects":[{"StartTime":11226.0,"EndTime":11226.0,"X":265.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":11253.0,"EndTime":11253.0,"X":290.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":11337.0,"Objects":[{"StartTime":11337.0,"EndTime":11337.0,"X":290.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":11364.0,"EndTime":11364.0,"X":315.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":11449.0,"Objects":[{"StartTime":11449.0,"EndTime":11449.0,"X":315.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":11476.0,"EndTime":11476.0,"X":340.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":11560.0,"Objects":[{"StartTime":11560.0,"EndTime":11560.0,"X":384.0,"Y":340.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":11635.0,"EndTime":11635.0,"X":411.735016,"Y":298.3975,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":11782.0,"Objects":[{"StartTime":11782.0,"EndTime":11782.0,"X":376.0,"Y":196.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":11857.0,"EndTime":11857.0,"X":348.264984,"Y":237.602509,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":12004.0,"Objects":[{"StartTime":12004.0,"EndTime":12004.0,"X":416.0,"Y":308.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":12079.0,"EndTime":12079.0,"X":427.118,"Y":259.25177,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":12226.0,"Objects":[{"StartTime":12226.0,"EndTime":12226.0,"X":359.0,"Y":175.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":12301.0,"EndTime":12301.0,"X":346.87323,"Y":223.507126,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":12449.0,"Objects":[{"StartTime":12449.0,"EndTime":12449.0,"X":440.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":12524.0,"EndTime":12524.0,"X":434.009,"Y":210.360229,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":12671.0,"Objects":[{"StartTime":12671.0,"EndTime":12671.0,"X":340.0,"Y":154.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":12746.0,"EndTime":12746.0,"X":345.234253,"Y":203.725281,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":12893.0,"Objects":[{"StartTime":12893.0,"EndTime":12893.0,"X":432.0,"Y":124.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":12920.0,"EndTime":12920.0,"X":422.71524,"Y":100.788086,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":13004.0,"Objects":[{"StartTime":13004.0,"EndTime":13004.0,"X":422.0,"Y":100.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":13031.0,"EndTime":13031.0,"X":412.53418,"Y":76.86133,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":13115.0,"Objects":[{"StartTime":13115.0,"EndTime":13115.0,"X":412.0,"Y":76.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":13142.0,"EndTime":13142.0,"X":402.152,"Y":53.0213737,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":13226.0,"Objects":[{"StartTime":13226.0,"EndTime":13226.0,"X":403.0,"Y":53.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":13253.0,"EndTime":13253.0,"X":393.567566,"Y":29.8476925,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":13337.0,"Objects":[{"StartTime":13337.0,"EndTime":13337.0,"X":352.0,"Y":4.0}]},{"StartTime":13449.0,"Objects":[{"StartTime":13449.0,"EndTime":13449.0,"X":352.0,"Y":4.0}]},{"StartTime":13560.0,"Objects":[{"StartTime":13560.0,"EndTime":13560.0,"X":352.0,"Y":4.0}]},{"StartTime":13671.0,"Objects":[{"StartTime":13671.0,"EndTime":13671.0,"X":352.0,"Y":4.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":13746.0,"EndTime":13746.0,"X":337.441925,"Y":51.8336945,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":13893.0,"Objects":[{"StartTime":13893.0,"EndTime":13893.0,"X":257.0,"Y":89.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":13968.0,"EndTime":13968.0,"X":242.441925,"Y":41.1663055,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":17004.0,"Objects":[{"StartTime":17004.0,"EndTime":17004.0,"X":66.0,"Y":72.0}]},{"StartTime":17226.0,"Objects":[{"StartTime":17226.0,"EndTime":17226.0,"X":128.0,"Y":199.0}]},{"StartTime":17449.0,"Objects":[{"StartTime":17449.0,"EndTime":17449.0,"X":207.0,"Y":82.0}]},{"StartTime":17560.0,"Objects":[{"StartTime":17560.0,"EndTime":17560.0,"X":283.0,"Y":160.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":17635.0,"EndTime":17635.0,"X":332.767517,"Y":155.183792,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":17782.0,"Objects":[{"StartTime":17782.0,"EndTime":17782.0,"X":487.0,"Y":113.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":17893.0,"EndTime":17893.0,"X":437.356171,"Y":107.04274,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18004.0,"EndTime":18004.0,"X":487.0,"Y":113.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18079.0,"EndTime":18079.0,"X":437.356171,"Y":107.04274,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18226.0,"Objects":[{"StartTime":18226.0,"EndTime":18226.0,"X":403.0,"Y":76.0}]},{"StartTime":18337.0,"Objects":[{"StartTime":18337.0,"EndTime":18337.0,"X":365.0,"Y":107.0}]},{"StartTime":18449.0,"Objects":[{"StartTime":18449.0,"EndTime":18449.0,"X":356.0,"Y":156.0}]},{"StartTime":18560.0,"Objects":[{"StartTime":18560.0,"EndTime":18560.0,"X":379.0,"Y":199.0}]},{"StartTime":18671.0,"Objects":[{"StartTime":18671.0,"EndTime":18671.0,"X":423.0,"Y":222.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18746.0,"EndTime":18746.0,"X":472.643829,"Y":227.95726,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18893.0,"Objects":[{"StartTime":18893.0,"EndTime":18893.0,"X":332.0,"Y":345.0}]},{"StartTime":19004.0,"Objects":[{"StartTime":19004.0,"EndTime":19004.0,"X":332.0,"Y":345.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19079.0,"EndTime":19079.0,"X":324.509735,"Y":295.56424,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19226.0,"Objects":[{"StartTime":19226.0,"EndTime":19226.0,"X":211.0,"Y":233.0}]},{"StartTime":19337.0,"Objects":[{"StartTime":19337.0,"EndTime":19337.0,"X":211.0,"Y":233.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19412.0,"EndTime":19412.0,"X":203.509735,"Y":282.43576,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19560.0,"Objects":[{"StartTime":19560.0,"EndTime":19560.0,"X":91.0,"Y":298.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19635.0,"EndTime":19635.0,"X":41.3058128,"Y":292.478424,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19782.0,"Objects":[{"StartTime":19782.0,"EndTime":19782.0,"X":166.0,"Y":184.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19857.0,"EndTime":19857.0,"X":174.567062,"Y":233.26059,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20004.0,"Objects":[{"StartTime":20004.0,"EndTime":20004.0,"X":220.0,"Y":356.0}]},{"StartTime":20115.0,"Objects":[{"StartTime":20115.0,"EndTime":20115.0,"X":263.0,"Y":331.0}]},{"StartTime":20226.0,"Objects":[{"StartTime":20226.0,"EndTime":20226.0,"X":312.0,"Y":322.0}]},{"StartTime":20337.0,"Objects":[{"StartTime":20337.0,"EndTime":20337.0,"X":361.0,"Y":329.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20412.0,"EndTime":20412.0,"X":393.297119,"Y":367.1693,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20560.0,"Objects":[{"StartTime":20560.0,"EndTime":20560.0,"X":457.0,"Y":201.0}]},{"StartTime":20671.0,"Objects":[{"StartTime":20671.0,"EndTime":20671.0,"X":457.0,"Y":201.0}]},{"StartTime":20782.0,"Objects":[{"StartTime":20782.0,"EndTime":20782.0,"X":457.0,"Y":201.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20893.0,"EndTime":20893.0,"X":459.171875,"Y":151.0472,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20968.0,"EndTime":20968.0,"X":457.0,"Y":201.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21115.0,"Objects":[{"StartTime":21115.0,"EndTime":21115.0,"X":344.0,"Y":244.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21190.0,"EndTime":21190.0,"X":335.893219,"Y":184.550186,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21337.0,"Objects":[{"StartTime":21337.0,"EndTime":21337.0,"X":214.0,"Y":70.0}]},{"StartTime":21449.0,"Objects":[{"StartTime":21449.0,"EndTime":21449.0,"X":263.0,"Y":76.0}]},{"StartTime":21560.0,"Objects":[{"StartTime":21560.0,"EndTime":21560.0,"X":313.0,"Y":82.0}]},{"StartTime":21671.0,"Objects":[{"StartTime":21671.0,"EndTime":21671.0,"X":362.0,"Y":88.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21857.0,"EndTime":21857.0,"X":265.04364,"Y":112.483932,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22004.0,"Objects":[{"StartTime":22004.0,"EndTime":22004.0,"X":164.0,"Y":64.0}]},{"StartTime":22115.0,"Objects":[{"StartTime":22115.0,"EndTime":22115.0,"X":164.0,"Y":64.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22190.0,"EndTime":22190.0,"X":114.386108,"Y":57.7982635,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22337.0,"Objects":[{"StartTime":22337.0,"EndTime":22337.0,"X":21.0,"Y":221.0}]},{"StartTime":22449.0,"Objects":[{"StartTime":22449.0,"EndTime":22449.0,"X":69.0,"Y":229.0}]},{"StartTime":22560.0,"Objects":[{"StartTime":22560.0,"EndTime":22560.0,"X":114.0,"Y":208.0}]},{"StartTime":22671.0,"Objects":[{"StartTime":22671.0,"EndTime":22671.0,"X":139.0,"Y":166.0}]},{"StartTime":22782.0,"Objects":[{"StartTime":22782.0,"EndTime":22782.0,"X":145.0,"Y":226.0}]},{"StartTime":22893.0,"Objects":[{"StartTime":22893.0,"EndTime":22893.0,"X":150.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23079.0,"EndTime":23079.0,"X":258.789642,"Y":261.437683,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23226.0,"Objects":[{"StartTime":23226.0,"EndTime":23226.0,"X":384.0,"Y":243.0}]},{"StartTime":23337.0,"Objects":[{"StartTime":23337.0,"EndTime":23337.0,"X":384.0,"Y":243.0}]},{"StartTime":23449.0,"Objects":[{"StartTime":23449.0,"EndTime":23449.0,"X":384.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23560.0,"EndTime":23560.0,"X":388.9752,"Y":193.248138,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23635.0,"EndTime":23635.0,"X":384.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23782.0,"Objects":[{"StartTime":23782.0,"EndTime":23782.0,"X":334.0,"Y":331.0}]},{"StartTime":23893.0,"Objects":[{"StartTime":23893.0,"EndTime":23893.0,"X":285.0,"Y":319.0}]},{"StartTime":24004.0,"Objects":[{"StartTime":24004.0,"EndTime":24004.0,"X":236.0,"Y":325.0}]},{"StartTime":24115.0,"Objects":[{"StartTime":24115.0,"EndTime":24115.0,"X":191.0,"Y":346.0}]},{"StartTime":24226.0,"Objects":[{"StartTime":24226.0,"EndTime":24226.0,"X":155.0,"Y":381.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":24412.0,"EndTime":24412.0,"X":55.3892822,"Y":372.1849,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":24560.0,"Objects":[{"StartTime":24560.0,"EndTime":24560.0,"X":148.0,"Y":254.0}]},{"StartTime":24671.0,"Objects":[{"StartTime":24671.0,"EndTime":24671.0,"X":148.0,"Y":254.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":24857.0,"EndTime":24857.0,"X":247.529541,"Y":244.311279,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25115.0,"Objects":[{"StartTime":25115.0,"EndTime":25115.0,"X":90.0,"Y":134.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25190.0,"EndTime":25190.0,"X":96.39857,"Y":183.5889,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25337.0,"Objects":[{"StartTime":25337.0,"EndTime":25337.0,"X":30.0,"Y":218.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25523.0,"EndTime":25523.0,"X":55.3264046,"Y":72.97656,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25671.0,"Objects":[{"StartTime":25671.0,"EndTime":25671.0,"X":179.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25857.0,"EndTime":25857.0,"X":275.556946,"Y":103.126785,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26004.0,"Objects":[{"StartTime":26004.0,"EndTime":26004.0,"X":349.0,"Y":47.0}]},{"StartTime":26115.0,"Objects":[{"StartTime":26115.0,"EndTime":26115.0,"X":349.0,"Y":47.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26301.0,"EndTime":26301.0,"X":328.957245,"Y":140.003632,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26449.0,"Objects":[{"StartTime":26449.0,"EndTime":26449.0,"X":411.0,"Y":158.0}]},{"StartTime":26560.0,"Objects":[{"StartTime":26560.0,"EndTime":26560.0,"X":411.0,"Y":158.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26746.0,"EndTime":26746.0,"X":431.042755,"Y":64.99636,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26893.0,"Objects":[{"StartTime":26893.0,"EndTime":26893.0,"X":351.0,"Y":96.0}]},{"StartTime":27115.0,"Objects":[{"StartTime":27115.0,"EndTime":27115.0,"X":384.0,"Y":255.0}]},{"StartTime":27226.0,"Objects":[{"StartTime":27226.0,"EndTime":27226.0,"X":384.0,"Y":255.0}]},{"StartTime":27337.0,"Objects":[{"StartTime":27337.0,"EndTime":27337.0,"X":384.0,"Y":255.0}]},{"StartTime":27449.0,"Objects":[{"StartTime":27449.0,"EndTime":27449.0,"X":384.0,"Y":255.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27560.0,"EndTime":27560.0,"X":433.843262,"Y":251.044189,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27635.0,"EndTime":27635.0,"X":384.0,"Y":255.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27782.0,"Objects":[{"StartTime":27782.0,"EndTime":27782.0,"X":228.0,"Y":173.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27857.0,"EndTime":27857.0,"X":186.890381,"Y":201.4605,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":28004.0,"Objects":[{"StartTime":28004.0,"EndTime":28004.0,"X":279.0,"Y":342.0}]},{"StartTime":28115.0,"Objects":[{"StartTime":28115.0,"EndTime":28115.0,"X":279.0,"Y":342.0}]},{"StartTime":28226.0,"Objects":[{"StartTime":28226.0,"EndTime":28226.0,"X":279.0,"Y":342.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":28301.0,"EndTime":28301.0,"X":279.81955,"Y":292.0067,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":28449.0,"Objects":[{"StartTime":28449.0,"EndTime":28449.0,"X":357.0,"Y":136.0}]},{"StartTime":28560.0,"Objects":[{"StartTime":28560.0,"EndTime":28560.0,"X":307.0,"Y":139.0}]},{"StartTime":28671.0,"Objects":[{"StartTime":28671.0,"EndTime":28671.0,"X":257.0,"Y":142.0}]},{"StartTime":28782.0,"Objects":[{"StartTime":28782.0,"EndTime":28782.0,"X":207.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":28893.0,"EndTime":28893.0,"X":157.19812,"Y":149.4466,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":28968.0,"EndTime":28968.0,"X":207.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":29115.0,"Objects":[{"StartTime":29115.0,"EndTime":29115.0,"X":257.0,"Y":142.0}]},{"StartTime":29226.0,"Objects":[{"StartTime":29226.0,"EndTime":29226.0,"X":307.0,"Y":139.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29412.0,"EndTime":29412.0,"X":404.7521,"Y":160.083786,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":29560.0,"Objects":[{"StartTime":29560.0,"EndTime":29560.0,"X":445.0,"Y":188.0}]},{"StartTime":29671.0,"Objects":[{"StartTime":29671.0,"EndTime":29671.0,"X":468.0,"Y":231.0}]},{"StartTime":29782.0,"Objects":[{"StartTime":29782.0,"EndTime":29782.0,"X":464.0,"Y":280.0}]},{"StartTime":29893.0,"Objects":[{"StartTime":29893.0,"EndTime":29893.0,"X":435.0,"Y":320.0}]},{"StartTime":30004.0,"Objects":[{"StartTime":30004.0,"EndTime":30004.0,"X":389.0,"Y":339.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30079.0,"EndTime":30079.0,"X":339.970978,"Y":329.194183,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30226.0,"Objects":[{"StartTime":30226.0,"EndTime":30226.0,"X":177.0,"Y":222.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30253.0,"EndTime":30253.0,"X":158.74321,"Y":204.921066,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30337.0,"Objects":[{"StartTime":30337.0,"EndTime":30337.0,"X":145.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30364.0,"EndTime":30364.0,"X":121.750984,"Y":238.808533,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30449.0,"Objects":[{"StartTime":30449.0,"EndTime":30449.0,"X":130.0,"Y":287.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30476.0,"EndTime":30476.0,"X":105.070015,"Y":288.869751,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30560.0,"Objects":[{"StartTime":30560.0,"EndTime":30560.0,"X":134.0,"Y":328.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30746.0,"EndTime":30746.0,"X":228.590485,"Y":343.960876,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30893.0,"Objects":[{"StartTime":30893.0,"EndTime":30893.0,"X":294.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30968.0,"EndTime":30968.0,"X":290.61792,"Y":201.114517,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31115.0,"Objects":[{"StartTime":31115.0,"EndTime":31115.0,"X":226.0,"Y":74.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31190.0,"EndTime":31190.0,"X":222.617935,"Y":123.885483,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31337.0,"Objects":[{"StartTime":31337.0,"EndTime":31337.0,"X":359.0,"Y":150.0}]},{"StartTime":31782.0,"Objects":[{"StartTime":31782.0,"EndTime":31782.0,"X":359.0,"Y":150.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31857.0,"EndTime":31857.0,"X":439.999084,"Y":129.902328,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32004.0,"Objects":[{"StartTime":32004.0,"EndTime":32004.0,"X":340.0,"Y":240.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32190.0,"EndTime":32190.0,"X":295.539337,"Y":65.57739,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32449.0,"Objects":[{"StartTime":32449.0,"EndTime":32449.0,"X":176.0,"Y":132.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32635.0,"EndTime":32635.0,"X":21.1092339,"Y":143.401688,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32893.0,"Objects":[{"StartTime":32893.0,"EndTime":32893.0,"X":139.0,"Y":383.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33079.0,"EndTime":33079.0,"X":103.72628,"Y":232.345047,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33337.0,"Objects":[{"StartTime":33337.0,"EndTime":33337.0,"X":205.0,"Y":291.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33523.0,"EndTime":33523.0,"X":383.4717,"Y":314.406128,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33782.0,"Objects":[{"StartTime":33782.0,"EndTime":33782.0,"X":506.0,"Y":223.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33968.0,"EndTime":33968.0,"X":327.5283,"Y":199.593872,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34226.0,"Objects":[{"StartTime":34226.0,"EndTime":34226.0,"X":182.0,"Y":205.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34412.0,"EndTime":34412.0,"X":326.651245,"Y":199.355911,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34671.0,"Objects":[{"StartTime":34671.0,"EndTime":34671.0,"X":76.0,"Y":191.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34857.0,"EndTime":34857.0,"X":70.35591,"Y":46.3487358,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35115.0,"Objects":[{"StartTime":35115.0,"EndTime":35115.0,"X":182.0,"Y":205.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35190.0,"EndTime":35190.0,"X":158.54007,"Y":291.8886,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35337.0,"Objects":[{"StartTime":35337.0,"EndTime":35337.0,"X":257.0,"Y":361.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35412.0,"EndTime":35412.0,"X":280.45993,"Y":274.1114,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35560.0,"Objects":[{"StartTime":35560.0,"EndTime":35560.0,"X":334.0,"Y":174.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35746.0,"EndTime":35746.0,"X":399.559753,"Y":305.239624,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36004.0,"Objects":[{"StartTime":36004.0,"EndTime":36004.0,"X":447.0,"Y":191.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36190.0,"EndTime":36190.0,"X":505.1221,"Y":20.6420746,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36449.0,"Objects":[{"StartTime":36449.0,"EndTime":36449.0,"X":334.0,"Y":174.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36635.0,"EndTime":36635.0,"X":189.812637,"Y":134.164047,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36893.0,"Objects":[{"StartTime":36893.0,"EndTime":36893.0,"X":133.0,"Y":25.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37079.0,"EndTime":37079.0,"X":155.499313,"Y":203.5883,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":37337.0,"Objects":[{"StartTime":37337.0,"EndTime":37337.0,"X":22.0,"Y":281.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37523.0,"EndTime":37523.0,"X":173.001678,"Y":318.749268,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":37782.0,"Objects":[{"StartTime":37782.0,"EndTime":37782.0,"X":306.0,"Y":240.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37968.0,"EndTime":37968.0,"X":154.714111,"Y":203.211349,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38226.0,"Objects":[{"StartTime":38226.0,"EndTime":38226.0,"X":0.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38412.0,"EndTime":38412.0,"X":178.1909,"Y":66.54416,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38671.0,"Objects":[{"StartTime":38671.0,"EndTime":38671.0,"X":363.0,"Y":43.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38746.0,"EndTime":38746.0,"X":393.257751,"Y":124.443619,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38893.0,"Objects":[{"StartTime":38893.0,"EndTime":38893.0,"X":306.0,"Y":240.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38968.0,"EndTime":38968.0,"X":275.742249,"Y":158.556381,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":39115.0,"Objects":[{"StartTime":39115.0,"EndTime":39115.0,"X":421.0,"Y":293.0}]},{"StartTime":39226.0,"Objects":[{"StartTime":39226.0,"EndTime":39226.0,"X":368.0,"Y":278.0}]},{"StartTime":39337.0,"Objects":[{"StartTime":39337.0,"EndTime":39337.0,"X":313.0,"Y":273.0}]},{"StartTime":39449.0,"Objects":[{"StartTime":39449.0,"EndTime":39449.0,"X":259.0,"Y":284.0}]},{"StartTime":39560.0,"Objects":[{"StartTime":39560.0,"EndTime":39560.0,"X":214.0,"Y":316.0}]},{"StartTime":39671.0,"Objects":[{"StartTime":39671.0,"EndTime":39671.0,"X":166.0,"Y":343.0}]},{"StartTime":39782.0,"Objects":[{"StartTime":39782.0,"EndTime":39782.0,"X":112.0,"Y":332.0}]},{"StartTime":39893.0,"Objects":[{"StartTime":39893.0,"EndTime":39893.0,"X":76.0,"Y":289.0}]},{"StartTime":40004.0,"Objects":[{"StartTime":40004.0,"EndTime":40004.0,"X":68.0,"Y":234.0}]},{"StartTime":40115.0,"Objects":[{"StartTime":40115.0,"EndTime":40115.0,"X":94.0,"Y":185.0}]},{"StartTime":40226.0,"Objects":[{"StartTime":40226.0,"EndTime":40226.0,"X":136.0,"Y":149.0}]},{"StartTime":40337.0,"Objects":[{"StartTime":40337.0,"EndTime":40337.0,"X":190.0,"Y":147.0}]},{"StartTime":40449.0,"Objects":[{"StartTime":40449.0,"EndTime":40449.0,"X":241.0,"Y":167.0}]},{"StartTime":40560.0,"Objects":[{"StartTime":40560.0,"EndTime":40560.0,"X":261.0,"Y":217.0}]},{"StartTime":40671.0,"Objects":[{"StartTime":40671.0,"EndTime":40671.0,"X":240.0,"Y":267.0}]},{"StartTime":40782.0,"Objects":[{"StartTime":40782.0,"EndTime":40782.0,"X":188.0,"Y":285.0}]},{"StartTime":40893.0,"Objects":[{"StartTime":40893.0,"EndTime":40893.0,"X":135.0,"Y":268.0}]},{"StartTime":41004.0,"Objects":[{"StartTime":41004.0,"EndTime":41004.0,"X":114.0,"Y":216.0}]},{"StartTime":41115.0,"Objects":[{"StartTime":41115.0,"EndTime":41115.0,"X":137.0,"Y":166.0}]},{"StartTime":41226.0,"Objects":[{"StartTime":41226.0,"EndTime":41226.0,"X":190.0,"Y":147.0}]},{"StartTime":41337.0,"Objects":[{"StartTime":41337.0,"EndTime":41337.0,"X":241.0,"Y":167.0}]},{"StartTime":41449.0,"Objects":[{"StartTime":41449.0,"EndTime":41449.0,"X":295.0,"Y":170.0}]},{"StartTime":41560.0,"Objects":[{"StartTime":41560.0,"EndTime":41560.0,"X":348.0,"Y":157.0}]},{"StartTime":41671.0,"Objects":[{"StartTime":41671.0,"EndTime":41671.0,"X":390.0,"Y":121.0}]},{"StartTime":41782.0,"Objects":[{"StartTime":41782.0,"EndTime":41782.0,"X":394.0,"Y":66.0}]},{"StartTime":41893.0,"Objects":[{"StartTime":41893.0,"EndTime":41893.0,"X":364.0,"Y":18.0}]},{"StartTime":42004.0,"Objects":[{"StartTime":42004.0,"EndTime":42004.0,"X":316.0,"Y":0.0}]},{"StartTime":42115.0,"Objects":[{"StartTime":42115.0,"EndTime":42115.0,"X":262.0,"Y":11.0}]},{"StartTime":42226.0,"Objects":[{"StartTime":42226.0,"EndTime":42226.0,"X":214.0,"Y":26.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42301.0,"EndTime":42301.0,"X":125.114845,"Y":40.12194,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42449.0,"Objects":[{"StartTime":42449.0,"EndTime":42449.0,"X":2.0,"Y":149.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42524.0,"EndTime":42524.0,"X":90.8851547,"Y":163.121948,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42671.0,"Objects":[{"StartTime":42671.0,"EndTime":42671.0,"X":336.0,"Y":200.0}]},{"StartTime":42782.0,"Objects":[{"StartTime":42782.0,"EndTime":42782.0,"X":288.0,"Y":172.0}]},{"StartTime":42893.0,"Objects":[{"StartTime":42893.0,"EndTime":42893.0,"X":232.0,"Y":173.0}]},{"StartTime":43004.0,"Objects":[{"StartTime":43004.0,"EndTime":43004.0,"X":189.0,"Y":207.0}]},{"StartTime":43115.0,"Objects":[{"StartTime":43115.0,"EndTime":43115.0,"X":160.0,"Y":255.0}]},{"StartTime":43226.0,"Objects":[{"StartTime":43226.0,"EndTime":43226.0,"X":168.0,"Y":308.0}]},{"StartTime":43337.0,"Objects":[{"StartTime":43337.0,"EndTime":43337.0,"X":196.0,"Y":355.0}]},{"StartTime":43449.0,"Objects":[{"StartTime":43449.0,"EndTime":43449.0,"X":249.0,"Y":366.0}]},{"StartTime":43560.0,"Objects":[{"StartTime":43560.0,"EndTime":43560.0,"X":295.0,"Y":337.0}]},{"StartTime":43671.0,"Objects":[{"StartTime":43671.0,"EndTime":43671.0,"X":303.0,"Y":283.0}]},{"StartTime":43782.0,"Objects":[{"StartTime":43782.0,"EndTime":43782.0,"X":277.0,"Y":233.0}]},{"StartTime":43893.0,"Objects":[{"StartTime":43893.0,"EndTime":43893.0,"X":224.0,"Y":216.0}]},{"StartTime":44004.0,"Objects":[{"StartTime":44004.0,"EndTime":44004.0,"X":172.0,"Y":228.0}]},{"StartTime":44115.0,"Objects":[{"StartTime":44115.0,"EndTime":44115.0,"X":124.0,"Y":248.0}]},{"StartTime":44226.0,"Objects":[{"StartTime":44226.0,"EndTime":44226.0,"X":72.0,"Y":232.0}]},{"StartTime":44337.0,"Objects":[{"StartTime":44337.0,"EndTime":44337.0,"X":32.0,"Y":196.0}]},{"StartTime":44449.0,"Objects":[{"StartTime":44449.0,"EndTime":44449.0,"X":28.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44476.0,"EndTime":44476.0,"X":4.282917,"Y":136.0943,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44560.0,"Objects":[{"StartTime":44560.0,"EndTime":44560.0,"X":62.0,"Y":96.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44587.0,"EndTime":44587.0,"X":47.14022,"Y":75.8956,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44671.0,"Objects":[{"StartTime":44671.0,"EndTime":44671.0,"X":119.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44698.0,"EndTime":44698.0,"X":119.0,"Y":52.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44782.0,"Objects":[{"StartTime":44782.0,"EndTime":44782.0,"X":175.0,"Y":96.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44809.0,"EndTime":44809.0,"X":189.276611,"Y":75.47737,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44893.0,"Objects":[{"StartTime":44893.0,"EndTime":44893.0,"X":210.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44920.0,"EndTime":44920.0,"X":233.624649,"Y":135.822235,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":45004.0,"Objects":[{"StartTime":45004.0,"EndTime":45004.0,"X":228.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":45031.0,"EndTime":45031.0,"X":204.282913,"Y":207.9057,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":45115.0,"Objects":[{"StartTime":45115.0,"EndTime":45115.0,"X":262.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":45142.0,"EndTime":45142.0,"X":247.140228,"Y":268.1044,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":45226.0,"Objects":[{"StartTime":45226.0,"EndTime":45226.0,"X":319.0,"Y":267.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":45253.0,"EndTime":45253.0,"X":319.0,"Y":292.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":45337.0,"Objects":[{"StartTime":45337.0,"EndTime":45337.0,"X":375.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":45364.0,"EndTime":45364.0,"X":389.2766,"Y":268.522644,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":45449.0,"Objects":[{"StartTime":45449.0,"EndTime":45449.0,"X":410.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":45476.0,"EndTime":45476.0,"X":433.624664,"Y":208.177765,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":45560.0,"Objects":[{"StartTime":45560.0,"EndTime":45560.0,"X":410.0,"Y":141.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":45587.0,"EndTime":45587.0,"X":433.624664,"Y":132.822235,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":45671.0,"Objects":[{"StartTime":45671.0,"EndTime":45671.0,"X":375.0,"Y":93.0}]},{"StartTime":46004.0,"Objects":[{"StartTime":46004.0,"EndTime":46004.0,"X":375.0,"Y":93.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":46190.0,"EndTime":46190.0,"X":325.360229,"Y":87.0089951,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":46337.0,"Objects":[{"StartTime":46337.0,"EndTime":46337.0,"X":317.0,"Y":167.0}]},{"StartTime":46449.0,"Objects":[{"StartTime":46449.0,"EndTime":46449.0,"X":317.0,"Y":167.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":46635.0,"EndTime":46635.0,"X":167.871689,"Y":183.147659,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":46782.0,"Objects":[{"StartTime":46782.0,"EndTime":46782.0,"X":53.0,"Y":101.0}]},{"StartTime":46893.0,"Objects":[{"StartTime":46893.0,"EndTime":46893.0,"X":108.0,"Y":98.0}]},{"StartTime":47004.0,"Objects":[{"StartTime":47004.0,"EndTime":47004.0,"X":152.0,"Y":130.0}]},{"StartTime":47115.0,"Objects":[{"StartTime":47115.0,"EndTime":47115.0,"X":167.0,"Y":183.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":47190.0,"EndTime":47190.0,"X":161.719025,"Y":257.813843,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":47337.0,"Objects":[{"StartTime":47337.0,"EndTime":47337.0,"X":49.0,"Y":308.0}]},{"StartTime":47449.0,"Objects":[{"StartTime":47449.0,"EndTime":47449.0,"X":49.0,"Y":308.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":47524.0,"EndTime":47524.0,"X":45.39839,"Y":233.086517,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":47671.0,"Objects":[{"StartTime":47671.0,"EndTime":47671.0,"X":205.0,"Y":140.0}]},{"StartTime":47782.0,"Objects":[{"StartTime":47782.0,"EndTime":47782.0,"X":205.0,"Y":140.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":47857.0,"EndTime":47857.0,"X":208.601608,"Y":214.913483,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":48004.0,"Objects":[{"StartTime":48004.0,"EndTime":48004.0,"X":310.0,"Y":353.0}]},{"StartTime":48115.0,"Objects":[{"StartTime":48115.0,"EndTime":48115.0,"X":346.0,"Y":347.0}]},{"StartTime":48226.0,"Objects":[{"StartTime":48226.0,"EndTime":48226.0,"X":383.0,"Y":341.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48412.0,"EndTime":48412.0,"X":429.122864,"Y":223.2328,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":48560.0,"Objects":[{"StartTime":48560.0,"EndTime":48560.0,"X":317.0,"Y":167.0}]},{"StartTime":48671.0,"Objects":[{"StartTime":48671.0,"EndTime":48671.0,"X":307.0,"Y":112.0}]},{"StartTime":48782.0,"Objects":[{"StartTime":48782.0,"EndTime":48782.0,"X":333.0,"Y":64.0}]},{"StartTime":48893.0,"Objects":[{"StartTime":48893.0,"EndTime":48893.0,"X":384.0,"Y":43.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48968.0,"EndTime":48968.0,"X":458.365082,"Y":52.7382851,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49115.0,"Objects":[{"StartTime":49115.0,"EndTime":49115.0,"X":506.0,"Y":161.0}]},{"StartTime":49226.0,"Objects":[{"StartTime":49226.0,"EndTime":49226.0,"X":506.0,"Y":161.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49301.0,"EndTime":49301.0,"X":431.634918,"Y":151.261719,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49449.0,"Objects":[{"StartTime":49449.0,"EndTime":49449.0,"X":268.0,"Y":121.0}]},{"StartTime":49560.0,"Objects":[{"StartTime":49560.0,"EndTime":49560.0,"X":268.0,"Y":121.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49635.0,"EndTime":49635.0,"X":342.365082,"Y":111.261719,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49782.0,"Objects":[{"StartTime":49782.0,"EndTime":49782.0,"X":263.0,"Y":263.0}]},{"StartTime":49893.0,"Objects":[{"StartTime":49893.0,"EndTime":49893.0,"X":228.0,"Y":247.0}]},{"StartTime":50004.0,"Objects":[{"StartTime":50004.0,"EndTime":50004.0,"X":193.0,"Y":232.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50190.0,"EndTime":50190.0,"X":64.17105,"Y":285.840179,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50337.0,"Objects":[{"StartTime":50337.0,"EndTime":50337.0,"X":121.0,"Y":164.0}]},{"StartTime":50449.0,"Objects":[{"StartTime":50449.0,"EndTime":50449.0,"X":120.0,"Y":109.0}]},{"StartTime":50560.0,"Objects":[{"StartTime":50560.0,"EndTime":50560.0,"X":91.0,"Y":62.0}]},{"StartTime":50671.0,"Objects":[{"StartTime":50671.0,"EndTime":50671.0,"X":42.0,"Y":37.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50746.0,"EndTime":50746.0,"X":116.636856,"Y":29.628458,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50893.0,"Objects":[{"StartTime":50893.0,"EndTime":50893.0,"X":242.0,"Y":84.0}]},{"StartTime":51004.0,"Objects":[{"StartTime":51004.0,"EndTime":51004.0,"X":242.0,"Y":84.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51079.0,"EndTime":51079.0,"X":310.8907,"Y":113.649155,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":51226.0,"Objects":[{"StartTime":51226.0,"EndTime":51226.0,"X":341.0,"Y":245.0}]},{"StartTime":51337.0,"Objects":[{"StartTime":51337.0,"EndTime":51337.0,"X":341.0,"Y":245.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51412.0,"EndTime":51412.0,"X":351.364716,"Y":319.280365,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":51560.0,"Objects":[{"StartTime":51560.0,"EndTime":51560.0,"X":163.0,"Y":192.0}]},{"StartTime":51671.0,"Objects":[{"StartTime":51671.0,"EndTime":51671.0,"X":198.0,"Y":181.0}]},{"StartTime":51782.0,"Objects":[{"StartTime":51782.0,"EndTime":51782.0,"X":233.0,"Y":170.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51968.0,"EndTime":51968.0,"X":365.301575,"Y":207.308578,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":52115.0,"Objects":[{"StartTime":52115.0,"EndTime":52115.0,"X":458.0,"Y":297.0}]},{"StartTime":52226.0,"Objects":[{"StartTime":52226.0,"EndTime":52226.0,"X":460.0,"Y":240.0}]},{"StartTime":52337.0,"Objects":[{"StartTime":52337.0,"EndTime":52337.0,"X":463.0,"Y":184.0}]},{"StartTime":52449.0,"Objects":[{"StartTime":52449.0,"EndTime":52449.0,"X":466.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":52635.0,"EndTime":52635.0,"X":420.259766,"Y":144.350586,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":52782.0,"Objects":[{"StartTime":52782.0,"EndTime":52782.0,"X":272.0,"Y":189.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":52857.0,"EndTime":52857.0,"X":197.534241,"Y":180.0641,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":53004.0,"Objects":[{"StartTime":53004.0,"EndTime":53004.0,"X":338.0,"Y":25.0}]},{"StartTime":53115.0,"Objects":[{"StartTime":53115.0,"EndTime":53115.0,"X":338.0,"Y":25.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":53190.0,"EndTime":53190.0,"X":344.228424,"Y":99.74094,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":53337.0,"Objects":[{"StartTime":53337.0,"EndTime":53337.0,"X":179.0,"Y":225.0}]},{"StartTime":53449.0,"Objects":[{"StartTime":53449.0,"EndTime":53449.0,"X":175.0,"Y":187.0}]},{"StartTime":53560.0,"Objects":[{"StartTime":53560.0,"EndTime":53560.0,"X":172.0,"Y":149.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":53746.0,"EndTime":53746.0,"X":321.020142,"Y":166.117188,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":53893.0,"Objects":[{"StartTime":53893.0,"EndTime":53893.0,"X":296.0,"Y":293.0}]},{"StartTime":54004.0,"Objects":[{"StartTime":54004.0,"EndTime":54004.0,"X":259.0,"Y":334.0}]},{"StartTime":54115.0,"Objects":[{"StartTime":54115.0,"EndTime":54115.0,"X":209.0,"Y":357.0}]},{"StartTime":54226.0,"Objects":[{"StartTime":54226.0,"EndTime":54226.0,"X":154.0,"Y":358.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54301.0,"EndTime":54301.0,"X":79.53424,"Y":349.064117,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54449.0,"Objects":[{"StartTime":54449.0,"EndTime":54449.0,"X":179.0,"Y":225.0}]},{"StartTime":54560.0,"Objects":[{"StartTime":54560.0,"EndTime":54560.0,"X":179.0,"Y":225.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54635.0,"EndTime":54635.0,"X":253.565521,"Y":233.061142,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54782.0,"Objects":[{"StartTime":54782.0,"EndTime":54782.0,"X":91.0,"Y":140.0}]},{"StartTime":54893.0,"Objects":[{"StartTime":54893.0,"EndTime":54893.0,"X":91.0,"Y":140.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54968.0,"EndTime":54968.0,"X":16.4230576,"Y":147.95488,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":55115.0,"Objects":[{"StartTime":55115.0,"EndTime":55115.0,"X":191.0,"Y":43.0}]},{"StartTime":55226.0,"Objects":[{"StartTime":55226.0,"EndTime":55226.0,"X":195.0,"Y":80.0}]},{"StartTime":55337.0,"Objects":[{"StartTime":55337.0,"EndTime":55337.0,"X":199.0,"Y":117.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":55523.0,"EndTime":55523.0,"X":163.504578,"Y":187.945709,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":55671.0,"Objects":[{"StartTime":55671.0,"EndTime":55671.0,"X":289.0,"Y":165.0}]},{"StartTime":55782.0,"Objects":[{"StartTime":55782.0,"EndTime":55782.0,"X":344.0,"Y":159.0}]},{"StartTime":55893.0,"Objects":[{"StartTime":55893.0,"EndTime":55893.0,"X":399.0,"Y":154.0}]},{"StartTime":56004.0,"Objects":[{"StartTime":56004.0,"EndTime":56004.0,"X":454.0,"Y":149.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56079.0,"EndTime":56079.0,"X":460.084534,"Y":223.752777,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56226.0,"Objects":[{"StartTime":56226.0,"EndTime":56226.0,"X":359.0,"Y":281.0}]},{"StartTime":56337.0,"Objects":[{"StartTime":56337.0,"EndTime":56337.0,"X":359.0,"Y":281.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56412.0,"EndTime":56412.0,"X":364.280975,"Y":355.813843,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56560.0,"Objects":[{"StartTime":56560.0,"EndTime":56560.0,"X":262.0,"Y":132.0}]},{"StartTime":56671.0,"Objects":[{"StartTime":56671.0,"EndTime":56671.0,"X":262.0,"Y":132.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56746.0,"EndTime":56746.0,"X":267.280975,"Y":206.813843,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56893.0,"Objects":[{"StartTime":56893.0,"EndTime":56893.0,"X":148.0,"Y":358.0}]},{"StartTime":57004.0,"Objects":[{"StartTime":57004.0,"EndTime":57004.0,"X":110.0,"Y":355.0}]},{"StartTime":57115.0,"Objects":[{"StartTime":57115.0,"EndTime":57115.0,"X":79.0,"Y":333.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57301.0,"EndTime":57301.0,"X":200.969864,"Y":306.864716,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57449.0,"Objects":[{"StartTime":57449.0,"EndTime":57449.0,"X":329.0,"Y":327.0}]},{"StartTime":57560.0,"Objects":[{"StartTime":57560.0,"EndTime":57560.0,"X":359.0,"Y":281.0}]},{"StartTime":57671.0,"Objects":[{"StartTime":57671.0,"EndTime":57671.0,"X":364.0,"Y":226.0}]},{"StartTime":57782.0,"Objects":[{"StartTime":57782.0,"EndTime":57782.0,"X":343.0,"Y":175.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57857.0,"EndTime":57857.0,"X":268.32077,"Y":181.929,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58004.0,"Objects":[{"StartTime":58004.0,"EndTime":58004.0,"X":342.0,"Y":20.0}]},{"StartTime":58115.0,"Objects":[{"StartTime":58115.0,"EndTime":58115.0,"X":342.0,"Y":20.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58190.0,"EndTime":58190.0,"X":384.690735,"Y":81.66441,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58337.0,"Objects":[{"StartTime":58337.0,"EndTime":58337.0,"X":210.0,"Y":97.0}]},{"StartTime":58449.0,"Objects":[{"StartTime":58449.0,"EndTime":58449.0,"X":210.0,"Y":97.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58524.0,"EndTime":58524.0,"X":240.894089,"Y":28.6585312,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58671.0,"Objects":[{"StartTime":58671.0,"EndTime":58671.0,"X":343.0,"Y":175.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58726.0,"EndTime":58726.0,"X":305.7774,"Y":176.959091,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58782.0,"EndTime":58782.0,"X":342.7744,"Y":175.011871,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58801.0,"EndTime":58801.0,"X":305.551819,"Y":176.970963,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58893.0,"Objects":[{"StartTime":58893.0,"EndTime":58893.0,"X":209.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58948.0,"EndTime":58948.0,"X":244.437592,"Y":220.55574,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59004.0,"EndTime":59004.0,"X":209.214767,"Y":209.070038,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59023.0,"EndTime":59023.0,"X":244.652374,"Y":220.625778,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59115.0,"Objects":[{"StartTime":59115.0,"EndTime":59115.0,"X":316.0,"Y":267.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59170.0,"EndTime":59170.0,"X":290.0395,"Y":293.747162,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59226.0,"EndTime":59226.0,"X":315.842651,"Y":267.1621,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59245.0,"EndTime":59245.0,"X":289.882172,"Y":293.909271,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59337.0,"Objects":[{"StartTime":59337.0,"EndTime":59337.0,"X":211.0,"Y":329.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59392.0,"EndTime":59392.0,"X":199.992722,"Y":293.388245,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59448.0,"EndTime":59448.0,"X":210.933289,"Y":328.78418,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59467.0,"EndTime":59467.0,"X":199.92601,"Y":293.1724,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59560.0,"Objects":[{"StartTime":59560.0,"EndTime":59560.0,"X":103.0,"Y":287.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59587.0,"EndTime":59587.0,"X":67.42438,"Y":275.141449,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59671.0,"Objects":[{"StartTime":59671.0,"EndTime":59671.0,"X":108.0,"Y":240.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59698.0,"EndTime":59698.0,"X":72.42438,"Y":228.141464,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59782.0,"Objects":[{"StartTime":59782.0,"EndTime":59782.0,"X":113.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59809.0,"EndTime":59809.0,"X":77.42438,"Y":181.141464,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59893.0,"Objects":[{"StartTime":59893.0,"EndTime":59893.0,"X":120.0,"Y":146.0}]},{"StartTime":60226.0,"Objects":[{"StartTime":60226.0,"EndTime":60226.0,"X":120.0,"Y":146.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60412.0,"EndTime":60412.0,"X":130.32193,"Y":46.53414,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60893.0,"Objects":[{"StartTime":60893.0,"EndTime":60893.0,"X":374.0,"Y":174.0}]},{"StartTime":61115.0,"Objects":[{"StartTime":61115.0,"EndTime":61115.0,"X":326.0,"Y":323.0}]},{"StartTime":61337.0,"Objects":[{"StartTime":61337.0,"EndTime":61337.0,"X":462.0,"Y":267.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61412.0,"EndTime":61412.0,"X":512.0,"Y":267.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61560.0,"Objects":[{"StartTime":61560.0,"EndTime":61560.0,"X":344.0,"Y":182.0}]},{"StartTime":61671.0,"Objects":[{"StartTime":61671.0,"EndTime":61671.0,"X":344.0,"Y":182.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61746.0,"EndTime":61746.0,"X":302.261353,"Y":209.529739,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61893.0,"Objects":[{"StartTime":61893.0,"EndTime":61893.0,"X":174.0,"Y":241.0}]},{"StartTime":62004.0,"Objects":[{"StartTime":62004.0,"EndTime":62004.0,"X":174.0,"Y":241.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62079.0,"EndTime":62079.0,"X":215.738632,"Y":268.529724,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62226.0,"Objects":[{"StartTime":62226.0,"EndTime":62226.0,"X":66.0,"Y":161.0}]},{"StartTime":62449.0,"Objects":[{"StartTime":62449.0,"EndTime":62449.0,"X":104.0,"Y":326.0}]},{"StartTime":62671.0,"Objects":[{"StartTime":62671.0,"EndTime":62671.0,"X":269.0,"Y":288.0}]},{"StartTime":62893.0,"Objects":[{"StartTime":62893.0,"EndTime":62893.0,"X":231.0,"Y":122.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62968.0,"EndTime":62968.0,"X":220.153473,"Y":73.19064,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63115.0,"Objects":[{"StartTime":63115.0,"EndTime":63115.0,"X":296.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63190.0,"EndTime":63190.0,"X":306.846527,"Y":48.8093529,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63337.0,"Objects":[{"StartTime":63337.0,"EndTime":63337.0,"X":373.0,"Y":120.0}]},{"StartTime":63449.0,"Objects":[{"StartTime":63449.0,"EndTime":63449.0,"X":373.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63635.0,"EndTime":63635.0,"X":465.0729,"Y":136.1981,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63782.0,"Objects":[{"StartTime":63782.0,"EndTime":63782.0,"X":400.0,"Y":216.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63968.0,"EndTime":63968.0,"X":301.005066,"Y":230.142136,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64226.0,"Objects":[{"StartTime":64226.0,"EndTime":64226.0,"X":48.0,"Y":160.0}]},{"StartTime":64449.0,"Objects":[{"StartTime":64449.0,"EndTime":64449.0,"X":216.0,"Y":200.0}]},{"StartTime":64671.0,"Objects":[{"StartTime":64671.0,"EndTime":64671.0,"X":104.0,"Y":288.0}]},{"StartTime":64893.0,"Objects":[{"StartTime":64893.0,"EndTime":64893.0,"X":216.0,"Y":200.0}]},{"StartTime":65115.0,"Objects":[{"StartTime":65115.0,"EndTime":65115.0,"X":160.0,"Y":64.0}]},{"StartTime":65226.0,"Objects":[{"StartTime":65226.0,"EndTime":65226.0,"X":160.0,"Y":64.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65301.0,"EndTime":65301.0,"X":160.0,"Y":114.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65449.0,"Objects":[{"StartTime":65449.0,"EndTime":65449.0,"X":264.0,"Y":104.0}]},{"StartTime":65560.0,"Objects":[{"StartTime":65560.0,"EndTime":65560.0,"X":264.0,"Y":104.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65635.0,"EndTime":65635.0,"X":264.0,"Y":154.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65782.0,"Objects":[{"StartTime":65782.0,"EndTime":65782.0,"X":456.0,"Y":160.0}]},{"StartTime":66004.0,"Objects":[{"StartTime":66004.0,"EndTime":66004.0,"X":288.0,"Y":192.0}]},{"StartTime":66226.0,"Objects":[{"StartTime":66226.0,"EndTime":66226.0,"X":336.0,"Y":48.0}]},{"StartTime":66449.0,"Objects":[{"StartTime":66449.0,"EndTime":66449.0,"X":408.0,"Y":296.0}]},{"StartTime":66671.0,"Objects":[{"StartTime":66671.0,"EndTime":66671.0,"X":196.0,"Y":148.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66857.0,"EndTime":66857.0,"X":199.142975,"Y":244.112289,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":67004.0,"Objects":[{"StartTime":67004.0,"EndTime":67004.0,"X":288.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67079.0,"EndTime":67079.0,"X":335.8913,"Y":206.3674,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":67226.0,"Objects":[{"StartTime":67226.0,"EndTime":67226.0,"X":297.0,"Y":308.0}]},{"StartTime":67337.0,"Objects":[{"StartTime":67337.0,"EndTime":67337.0,"X":297.0,"Y":308.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67412.0,"EndTime":67412.0,"X":249.108688,"Y":322.3674,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":67560.0,"Objects":[{"StartTime":67560.0,"EndTime":67560.0,"X":107.0,"Y":256.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67746.0,"EndTime":67746.0,"X":198.869858,"Y":243.930862,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68004.0,"Objects":[{"StartTime":68004.0,"EndTime":68004.0,"X":460.0,"Y":300.0}]},{"StartTime":68226.0,"Objects":[{"StartTime":68226.0,"EndTime":68226.0,"X":407.0,"Y":107.0}]},{"StartTime":68449.0,"Objects":[{"StartTime":68449.0,"EndTime":68449.0,"X":364.0,"Y":364.0}]},{"StartTime":68671.0,"Objects":[{"StartTime":68671.0,"EndTime":68671.0,"X":345.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":68857.0,"EndTime":68857.0,"X":482.955933,"Y":34.298172,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":69115.0,"Objects":[{"StartTime":69115.0,"EndTime":69115.0,"X":167.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69301.0,"EndTime":69301.0,"X":29.044054,"Y":34.29817,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":69560.0,"Objects":[{"StartTime":69560.0,"EndTime":69560.0,"X":407.0,"Y":107.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69746.0,"EndTime":69746.0,"X":460.866516,"Y":235.137,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70004.0,"Objects":[{"StartTime":70004.0,"EndTime":70004.0,"X":158.0,"Y":202.0}]},{"StartTime":70226.0,"Objects":[{"StartTime":70226.0,"EndTime":70226.0,"X":354.0,"Y":202.0}]},{"StartTime":70449.0,"Objects":[{"StartTime":70449.0,"EndTime":70449.0,"X":105.0,"Y":107.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":70635.0,"EndTime":70635.0,"X":49.8107719,"Y":234.398621,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70893.0,"Objects":[{"StartTime":70893.0,"EndTime":70893.0,"X":364.0,"Y":281.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":71079.0,"EndTime":71079.0,"X":492.137024,"Y":334.866516,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":71337.0,"Objects":[{"StartTime":71337.0,"EndTime":71337.0,"X":424.0,"Y":64.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":71781.0,"EndTime":71781.0,"X":256.21228,"Y":97.33865,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":72225.0,"EndTime":72225.0,"X":154.641,"Y":186.241669,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":72670.0,"EndTime":72670.0,"X":297.514374,"Y":348.106232,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":72856.0,"EndTime":72856.0,"X":161.609192,"Y":331.680847,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":73337.0,"Objects":[{"StartTime":73337.0,"EndTime":73337.0,"X":161.0,"Y":331.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":73364.0,"EndTime":73364.0,"X":186.0,"Y":331.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":73449.0,"Objects":[{"StartTime":73449.0,"EndTime":73449.0,"X":186.0,"Y":331.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":73476.0,"EndTime":73476.0,"X":211.0,"Y":331.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":73560.0,"Objects":[{"StartTime":73560.0,"EndTime":73560.0,"X":211.0,"Y":331.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":73587.0,"EndTime":73587.0,"X":236.0,"Y":331.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":73671.0,"Objects":[{"StartTime":73671.0,"EndTime":73671.0,"X":236.0,"Y":331.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":73698.0,"EndTime":73698.0,"X":261.0,"Y":331.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":73782.0,"Objects":[{"StartTime":73782.0,"EndTime":73782.0,"X":297.0,"Y":339.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":73857.0,"EndTime":73857.0,"X":346.751862,"Y":343.9752,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":74004.0,"Objects":[{"StartTime":74004.0,"EndTime":74004.0,"X":321.0,"Y":181.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":74079.0,"EndTime":74079.0,"X":316.4732,"Y":230.794662,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":74226.0,"Objects":[{"StartTime":74226.0,"EndTime":74226.0,"X":184.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":74301.0,"EndTime":74301.0,"X":179.4732,"Y":66.20534,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":74449.0,"Objects":[{"StartTime":74449.0,"EndTime":74449.0,"X":283.0,"Y":82.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":74635.0,"EndTime":74635.0,"X":377.3881,"Y":94.27898,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":75115.0,"Objects":[{"StartTime":75115.0,"EndTime":75115.0,"X":150.0,"Y":188.0}]},{"StartTime":75337.0,"Objects":[{"StartTime":75337.0,"EndTime":75337.0,"X":127.0,"Y":46.0}]},{"StartTime":75560.0,"Objects":[{"StartTime":75560.0,"EndTime":75560.0,"X":157.0,"Y":218.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":75746.0,"EndTime":75746.0,"X":252.9821,"Y":201.569382,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":75893.0,"Objects":[{"StartTime":75893.0,"EndTime":75893.0,"X":322.0,"Y":283.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":76079.0,"EndTime":76079.0,"X":418.1396,"Y":269.035919,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":76226.0,"Objects":[{"StartTime":76226.0,"EndTime":76226.0,"X":439.0,"Y":170.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":76412.0,"EndTime":76412.0,"X":356.0464,"Y":190.903046,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":76671.0,"Objects":[{"StartTime":76671.0,"EndTime":76671.0,"X":219.0,"Y":92.0}]},{"StartTime":76893.0,"Objects":[{"StartTime":76893.0,"EndTime":76893.0,"X":371.0,"Y":22.0}]},{"StartTime":77115.0,"Objects":[{"StartTime":77115.0,"EndTime":77115.0,"X":356.0,"Y":191.0}]},{"StartTime":77337.0,"Objects":[{"StartTime":77337.0,"EndTime":77337.0,"X":194.0,"Y":73.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77523.0,"EndTime":77523.0,"X":94.5583954,"Y":81.89803,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77671.0,"Objects":[{"StartTime":77671.0,"EndTime":77671.0,"X":15.0,"Y":164.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77857.0,"EndTime":77857.0,"X":97.3508148,"Y":208.780609,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78004.0,"Objects":[{"StartTime":78004.0,"EndTime":78004.0,"X":26.0,"Y":302.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78079.0,"EndTime":78079.0,"X":20.9243164,"Y":252.258286,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78226.0,"Objects":[{"StartTime":78226.0,"EndTime":78226.0,"X":181.0,"Y":348.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78412.0,"EndTime":78412.0,"X":276.906036,"Y":335.082367,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78671.0,"Objects":[{"StartTime":78671.0,"EndTime":78671.0,"X":422.0,"Y":231.0}]},{"StartTime":78893.0,"Objects":[{"StartTime":78893.0,"EndTime":78893.0,"X":435.0,"Y":376.0}]},{"StartTime":79115.0,"Objects":[{"StartTime":79115.0,"EndTime":79115.0,"X":271.0,"Y":230.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":79301.0,"EndTime":79301.0,"X":280.305237,"Y":130.433868,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":79449.0,"Objects":[{"StartTime":79449.0,"EndTime":79449.0,"X":367.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":79635.0,"EndTime":79635.0,"X":392.598328,"Y":147.861,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":79782.0,"Objects":[{"StartTime":79782.0,"EndTime":79782.0,"X":280.0,"Y":130.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":79857.0,"EndTime":79857.0,"X":230.414871,"Y":136.4277,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":80004.0,"Objects":[{"StartTime":80004.0,"EndTime":80004.0,"X":104.0,"Y":280.0}]},{"StartTime":80226.0,"Objects":[{"StartTime":80226.0,"EndTime":80226.0,"X":243.0,"Y":207.0}]},{"StartTime":80449.0,"Objects":[{"StartTime":80449.0,"EndTime":80449.0,"X":104.0,"Y":134.0}]},{"StartTime":80671.0,"Objects":[{"StartTime":80671.0,"EndTime":80671.0,"X":243.0,"Y":61.0}]},{"StartTime":80893.0,"Objects":[{"StartTime":80893.0,"EndTime":80893.0,"X":384.0,"Y":189.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":80968.0,"EndTime":80968.0,"X":335.600159,"Y":201.548111,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":81115.0,"Objects":[{"StartTime":81115.0,"EndTime":81115.0,"X":259.0,"Y":262.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":81190.0,"EndTime":81190.0,"X":210.492874,"Y":249.873215,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":81337.0,"Objects":[{"StartTime":81337.0,"EndTime":81337.0,"X":83.0,"Y":157.0}]},{"StartTime":81449.0,"Objects":[{"StartTime":81449.0,"EndTime":81449.0,"X":60.0,"Y":186.0}]},{"StartTime":81560.0,"Objects":[{"StartTime":81560.0,"EndTime":81560.0,"X":48.0,"Y":221.0}]},{"StartTime":81671.0,"Objects":[{"StartTime":81671.0,"EndTime":81671.0,"X":48.0,"Y":259.0}]},{"StartTime":81782.0,"Objects":[{"StartTime":81782.0,"EndTime":81782.0,"X":61.0,"Y":294.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":81968.0,"EndTime":81968.0,"X":152.567673,"Y":316.582672,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82226.0,"Objects":[{"StartTime":82226.0,"EndTime":82226.0,"X":350.0,"Y":269.0}]},{"StartTime":82449.0,"Objects":[{"StartTime":82449.0,"EndTime":82449.0,"X":226.0,"Y":187.0}]},{"StartTime":82671.0,"Objects":[{"StartTime":82671.0,"EndTime":82671.0,"X":265.0,"Y":365.0}]},{"StartTime":82893.0,"Objects":[{"StartTime":82893.0,"EndTime":82893.0,"X":444.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":83079.0,"EndTime":83079.0,"X":420.485352,"Y":85.56759,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":83337.0,"Objects":[{"StartTime":83337.0,"EndTime":83337.0,"X":211.0,"Y":48.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":83523.0,"EndTime":83523.0,"X":135.939285,"Y":144.596344,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":83782.0,"Objects":[{"StartTime":83782.0,"EndTime":83782.0,"X":270.0,"Y":337.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":83968.0,"EndTime":83968.0,"X":285.4127,"Y":210.422119,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84226.0,"Objects":[{"StartTime":84226.0,"EndTime":84226.0,"X":427.0,"Y":124.0}]},{"StartTime":84337.0,"Objects":[{"StartTime":84337.0,"EndTime":84337.0,"X":427.0,"Y":124.0}]},{"StartTime":84449.0,"Objects":[{"StartTime":84449.0,"EndTime":84449.0,"X":427.0,"Y":124.0}]},{"StartTime":84671.0,"Objects":[{"StartTime":84671.0,"EndTime":84671.0,"X":136.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":85079.0,"EndTime":85079.0,"X":235.2148,"Y":264.073,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":85337.0,"Objects":[{"StartTime":85337.0,"EndTime":85337.0,"X":235.0,"Y":99.0}]},{"StartTime":85449.0,"Objects":[{"StartTime":85449.0,"EndTime":85449.0,"X":278.0,"Y":92.0}]},{"StartTime":85560.0,"Objects":[{"StartTime":85560.0,"EndTime":85560.0,"X":319.0,"Y":109.0}]},{"StartTime":85782.0,"Objects":[{"StartTime":85782.0,"EndTime":85782.0,"X":174.0,"Y":43.0}]},{"StartTime":85893.0,"Objects":[{"StartTime":85893.0,"EndTime":85893.0,"X":129.0,"Y":35.0}]},{"StartTime":86004.0,"Objects":[{"StartTime":86004.0,"EndTime":86004.0,"X":86.0,"Y":47.0}]},{"StartTime":86115.0,"Objects":[{"StartTime":86115.0,"EndTime":86115.0,"X":52.0,"Y":75.0}]},{"StartTime":86226.0,"Objects":[{"StartTime":86226.0,"EndTime":86226.0,"X":32.0,"Y":115.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86281.0,"EndTime":86281.0,"X":35.0821877,"Y":139.6575,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86337.0,"EndTime":86337.0,"X":32.01868,"Y":115.149437,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86356.0,"EndTime":86356.0,"X":35.10087,"Y":139.806946,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":86449.0,"Objects":[{"StartTime":86449.0,"EndTime":86449.0,"X":83.0,"Y":252.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86504.0,"EndTime":86504.0,"X":85.47261,"Y":227.273926,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86560.0,"EndTime":86560.0,"X":83.0149841,"Y":251.850143,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86579.0,"EndTime":86579.0,"X":85.4875946,"Y":227.124069,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":86671.0,"Objects":[{"StartTime":86671.0,"EndTime":86671.0,"X":174.0,"Y":189.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86782.0,"EndTime":86782.0,"X":223.892853,"Y":185.728333,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86857.0,"EndTime":86857.0,"X":174.0,"Y":189.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":87004.0,"Objects":[{"StartTime":87004.0,"EndTime":87004.0,"X":83.0,"Y":252.0}]},{"StartTime":87115.0,"Objects":[{"StartTime":87115.0,"EndTime":87115.0,"X":83.0,"Y":252.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87190.0,"EndTime":87190.0,"X":90.5399,"Y":301.428223,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":87337.0,"Objects":[{"StartTime":87337.0,"EndTime":87337.0,"X":185.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87412.0,"EndTime":87412.0,"X":203.254379,"Y":332.451355,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":87560.0,"Objects":[{"StartTime":87560.0,"EndTime":87560.0,"X":310.0,"Y":279.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87635.0,"EndTime":87635.0,"X":359.670441,"Y":284.7312,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":87782.0,"Objects":[{"StartTime":87782.0,"EndTime":87782.0,"X":490.0,"Y":357.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87837.0,"EndTime":87837.0,"X":492.549316,"Y":381.64325,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87857.0,"EndTime":87857.0,"X":490.0,"Y":357.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88004.0,"Objects":[{"StartTime":88004.0,"EndTime":88004.0,"X":448.701019,"Y":200.701}]},{"StartTime":88060.0,"Objects":[{"StartTime":88060.0,"EndTime":88060.0,"X":452.3505,"Y":204.35051}]},{"StartTime":88115.0,"Objects":[{"StartTime":88115.0,"EndTime":88115.0,"X":456.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88190.0,"EndTime":88190.0,"X":465.805817,"Y":158.970963,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88337.0,"Objects":[{"StartTime":88337.0,"EndTime":88337.0,"X":352.0,"Y":40.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88412.0,"EndTime":88412.0,"X":367.8114,"Y":87.43416,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88560.0,"Objects":[{"StartTime":88560.0,"EndTime":88560.0,"X":256.0,"Y":136.0}]},{"StartTime":88671.0,"Objects":[{"StartTime":88671.0,"EndTime":88671.0,"X":256.0,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88746.0,"EndTime":88746.0,"X":242.263947,"Y":87.9238,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88893.0,"Objects":[{"StartTime":88893.0,"EndTime":88893.0,"X":48.0,"Y":184.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89079.0,"EndTime":89079.0,"X":203.680511,"Y":208.498886,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":89226.0,"Objects":[{"StartTime":89226.0,"EndTime":89226.0,"X":328.0,"Y":336.0}]},{"StartTime":89337.0,"Objects":[{"StartTime":89337.0,"EndTime":89337.0,"X":424.0,"Y":328.0}]},{"StartTime":89449.0,"Objects":[{"StartTime":89449.0,"EndTime":89449.0,"X":472.0,"Y":248.0}]},{"StartTime":89560.0,"Objects":[{"StartTime":89560.0,"EndTime":89560.0,"X":488.0,"Y":160.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89746.0,"EndTime":89746.0,"X":394.248352,"Y":41.7970772,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":89893.0,"Objects":[{"StartTime":89893.0,"EndTime":89893.0,"X":256.0,"Y":104.0}]},{"StartTime":90004.0,"Objects":[{"StartTime":90004.0,"EndTime":90004.0,"X":168.0,"Y":128.0}]},{"StartTime":90115.0,"Objects":[{"StartTime":90115.0,"EndTime":90115.0,"X":80.0,"Y":120.0}]},{"StartTime":90226.0,"Objects":[{"StartTime":90226.0,"EndTime":90226.0,"X":0.0,"Y":88.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":90301.0,"EndTime":90301.0,"X":-5.43235159,"Y":172.040863,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":90449.0,"Objects":[{"StartTime":90449.0,"EndTime":90449.0,"X":96.0,"Y":336.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":90524.0,"EndTime":90524.0,"X":101.432358,"Y":251.959152,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":90671.0,"Objects":[{"StartTime":90671.0,"EndTime":90671.0,"X":173.0,"Y":43.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":90746.0,"EndTime":90746.0,"X":167.812271,"Y":126.927834,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":90893.0,"Objects":[{"StartTime":90893.0,"EndTime":90893.0,"X":256.0,"Y":296.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":90968.0,"EndTime":90968.0,"X":261.432373,"Y":211.959152,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":91115.0,"Objects":[{"StartTime":91115.0,"EndTime":91115.0,"X":336.0,"Y":72.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":91301.0,"EndTime":91301.0,"X":505.568,"Y":59.888,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":91449.0,"Objects":[{"StartTime":91449.0,"EndTime":91449.0,"X":432.0,"Y":120.0}]},{"StartTime":91560.0,"Objects":[{"StartTime":91560.0,"EndTime":91560.0,"X":392.0,"Y":200.0}]},{"StartTime":91671.0,"Objects":[{"StartTime":91671.0,"EndTime":91671.0,"X":432.0,"Y":288.0}]},{"StartTime":91782.0,"Objects":[{"StartTime":91782.0,"EndTime":91782.0,"X":496.0,"Y":360.0}]},{"StartTime":92004.0,"Objects":[{"StartTime":92004.0,"EndTime":92004.0,"X":256.0,"Y":296.0}]},{"StartTime":92226.0,"Objects":[{"StartTime":92226.0,"EndTime":92226.0,"X":16.0,"Y":360.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92412.0,"EndTime":92412.0,"X":57.4499359,"Y":205.3707,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":92560.0,"Objects":[{"StartTime":92560.0,"EndTime":92560.0,"X":120.0,"Y":40.0}]},{"StartTime":92671.0,"Objects":[{"StartTime":92671.0,"EndTime":92671.0,"X":168.0,"Y":120.0}]},{"StartTime":92782.0,"Objects":[{"StartTime":92782.0,"EndTime":92782.0,"X":248.0,"Y":168.0}]},{"StartTime":92893.0,"Objects":[{"StartTime":92893.0,"EndTime":92893.0,"X":328.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93079.0,"EndTime":93079.0,"X":470.241516,"Y":176.420227,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93226.0,"Objects":[{"StartTime":93226.0,"EndTime":93226.0,"X":472.0,"Y":360.0}]},{"StartTime":93337.0,"Objects":[{"StartTime":93337.0,"EndTime":93337.0,"X":472.0,"Y":360.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93523.0,"EndTime":93523.0,"X":372.6112,"Y":243.111877,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93671.0,"Objects":[{"StartTime":93671.0,"EndTime":93671.0,"X":328.0,"Y":120.0}]},{"StartTime":93782.0,"Objects":[{"StartTime":93782.0,"EndTime":93782.0,"X":328.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93857.0,"EndTime":93857.0,"X":315.9792,"Y":35.8542938,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94004.0,"Objects":[{"StartTime":94004.0,"EndTime":94004.0,"X":93.0,"Y":147.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":94190.0,"EndTime":94190.0,"X":247.311935,"Y":167.253586,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94337.0,"Objects":[{"StartTime":94337.0,"EndTime":94337.0,"X":448.0,"Y":288.0}]},{"StartTime":94449.0,"Objects":[{"StartTime":94449.0,"EndTime":94449.0,"X":360.0,"Y":264.0}]},{"StartTime":94560.0,"Objects":[{"StartTime":94560.0,"EndTime":94560.0,"X":272.0,"Y":288.0}]},{"StartTime":94671.0,"Objects":[{"StartTime":94671.0,"EndTime":94671.0,"X":216.0,"Y":360.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":94857.0,"EndTime":94857.0,"X":165.263092,"Y":227.525742,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":95004.0,"Objects":[{"StartTime":95004.0,"EndTime":95004.0,"X":216.0,"Y":104.0}]},{"StartTime":95115.0,"Objects":[{"StartTime":95115.0,"EndTime":95115.0,"X":216.0,"Y":104.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95190.0,"EndTime":95190.0,"X":231.205261,"Y":20.3710556,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":95337.0,"Objects":[{"StartTime":95337.0,"EndTime":95337.0,"X":368.0,"Y":48.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95412.0,"EndTime":95412.0,"X":448.936432,"Y":36.0525131,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":95560.0,"Objects":[{"StartTime":95560.0,"EndTime":95560.0,"X":432.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95635.0,"EndTime":95635.0,"X":420.052521,"Y":143.063568,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":95782.0,"Objects":[{"StartTime":95782.0,"EndTime":95782.0,"X":320.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95857.0,"EndTime":95857.0,"X":331.947479,"Y":360.936432,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96004.0,"Objects":[{"StartTime":96004.0,"EndTime":96004.0,"X":32.0,"Y":232.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96190.0,"EndTime":96190.0,"X":187.590439,"Y":208.254333,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96337.0,"Objects":[{"StartTime":96337.0,"EndTime":96337.0,"X":320.0,"Y":280.0}]},{"StartTime":96449.0,"Objects":[{"StartTime":96449.0,"EndTime":96449.0,"X":408.0,"Y":312.0}]},{"StartTime":96560.0,"Objects":[{"StartTime":96560.0,"EndTime":96560.0,"X":496.0,"Y":280.0}]},{"StartTime":96671.0,"Objects":[{"StartTime":96671.0,"EndTime":96671.0,"X":496.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96857.0,"EndTime":96857.0,"X":456.6245,"Y":114.62294,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":97004.0,"Objects":[{"StartTime":97004.0,"EndTime":97004.0,"X":384.0,"Y":56.0}]},{"StartTime":97115.0,"Objects":[{"StartTime":97115.0,"EndTime":97115.0,"X":296.0,"Y":24.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97190.0,"EndTime":97190.0,"X":213.0328,"Y":22.5670681,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":97337.0,"Objects":[{"StartTime":97337.0,"EndTime":97337.0,"X":104.0,"Y":160.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97412.0,"EndTime":97412.0,"X":186.9672,"Y":161.432938,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":97560.0,"Objects":[{"StartTime":97560.0,"EndTime":97560.0,"X":456.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97746.0,"EndTime":97746.0,"X":313.4922,"Y":206.126556,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":97893.0,"Objects":[{"StartTime":97893.0,"EndTime":97893.0,"X":264.0,"Y":288.0}]},{"StartTime":98004.0,"Objects":[{"StartTime":98004.0,"EndTime":98004.0,"X":176.0,"Y":264.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98079.0,"EndTime":98079.0,"X":91.38288,"Y":272.058777,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98226.0,"Objects":[{"StartTime":98226.0,"EndTime":98226.0,"X":16.0,"Y":88.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98412.0,"EndTime":98412.0,"X":153.034653,"Y":108.397804,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98560.0,"Objects":[{"StartTime":98560.0,"EndTime":98560.0,"X":328.0,"Y":56.0}]},{"StartTime":98671.0,"Objects":[{"StartTime":98671.0,"EndTime":98671.0,"X":416.0,"Y":32.0}]},{"StartTime":98782.0,"Objects":[{"StartTime":98782.0,"EndTime":98782.0,"X":480.0,"Y":104.0}]},{"StartTime":98893.0,"Objects":[{"StartTime":98893.0,"EndTime":98893.0,"X":456.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98968.0,"EndTime":98968.0,"X":463.695526,"Y":276.65094,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":99115.0,"Objects":[{"StartTime":99115.0,"EndTime":99115.0,"X":328.0,"Y":360.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":99190.0,"EndTime":99190.0,"X":320.304474,"Y":275.34906,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":99337.0,"Objects":[{"StartTime":99337.0,"EndTime":99337.0,"X":208.0,"Y":112.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":99412.0,"EndTime":99412.0,"X":215.695541,"Y":196.650925,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":99560.0,"Objects":[{"StartTime":99560.0,"EndTime":99560.0,"X":64.0,"Y":320.0}]},{"StartTime":99671.0,"Objects":[{"StartTime":99671.0,"EndTime":99671.0,"X":136.0,"Y":264.0}]},{"StartTime":99782.0,"Objects":[{"StartTime":99782.0,"EndTime":99782.0,"X":232.0,"Y":256.0}]},{"StartTime":99893.0,"Objects":[{"StartTime":99893.0,"EndTime":99893.0,"X":320.0,"Y":280.0}]},{"StartTime":100004.0,"Objects":[{"StartTime":100004.0,"EndTime":100004.0,"X":384.0,"Y":344.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100079.0,"EndTime":100079.0,"X":413.492859,"Y":264.728241,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100226.0,"Objects":[{"StartTime":100226.0,"EndTime":100226.0,"X":360.0,"Y":72.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100301.0,"EndTime":100301.0,"X":330.507141,"Y":151.271759,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100449.0,"Objects":[{"StartTime":100449.0,"EndTime":100449.0,"X":240.0,"Y":312.0}]},{"StartTime":100560.0,"Objects":[{"StartTime":100560.0,"EndTime":100560.0,"X":152.0,"Y":344.0}]},{"StartTime":100671.0,"Objects":[{"StartTime":100671.0,"EndTime":100671.0,"X":64.0,"Y":320.0}]},{"StartTime":100782.0,"Objects":[{"StartTime":100782.0,"EndTime":100782.0,"X":8.0,"Y":248.0}]},{"StartTime":100893.0,"Objects":[{"StartTime":100893.0,"EndTime":100893.0,"X":16.0,"Y":152.0}]},{"StartTime":101004.0,"Objects":[{"StartTime":101004.0,"EndTime":101004.0,"X":88.0,"Y":88.0}]},{"StartTime":101115.0,"Objects":[{"StartTime":101115.0,"EndTime":101115.0,"X":184.0,"Y":80.0}]},{"StartTime":101226.0,"Objects":[{"StartTime":101226.0,"EndTime":101226.0,"X":272.0,"Y":120.0}]},{"StartTime":101337.0,"Objects":[{"StartTime":101337.0,"EndTime":101337.0,"X":356.0,"Y":176.0}]},{"StartTime":101449.0,"Objects":[{"StartTime":101449.0,"EndTime":101449.0,"X":456.0,"Y":164.0}]},{"StartTime":101560.0,"Objects":[{"StartTime":101560.0,"EndTime":101560.0,"X":392.0,"Y":88.0}]},{"StartTime":101671.0,"Objects":[{"StartTime":101671.0,"EndTime":101671.0,"X":348.0,"Y":184.0}]},{"StartTime":101782.0,"Objects":[{"StartTime":101782.0,"EndTime":101782.0,"X":448.0,"Y":172.0}]},{"StartTime":101893.0,"Objects":[{"StartTime":101893.0,"EndTime":101893.0,"X":384.0,"Y":96.0}]},{"StartTime":102004.0,"Objects":[{"StartTime":102004.0,"EndTime":102004.0,"X":340.0,"Y":192.0}]},{"StartTime":102115.0,"Objects":[{"StartTime":102115.0,"EndTime":102115.0,"X":440.0,"Y":180.0}]},{"StartTime":102226.0,"Objects":[{"StartTime":102226.0,"EndTime":102226.0,"X":376.0,"Y":104.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102301.0,"EndTime":102301.0,"X":296.361084,"Y":106.489342,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102449.0,"Objects":[{"StartTime":102449.0,"EndTime":102449.0,"X":344.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102524.0,"EndTime":102524.0,"X":413.713257,"Y":230.646133,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102671.0,"Objects":[{"StartTime":102671.0,"EndTime":102671.0,"X":169.0,"Y":239.0}]},{"StartTime":102782.0,"Objects":[{"StartTime":102782.0,"EndTime":102782.0,"X":80.0,"Y":210.0}]},{"StartTime":102893.0,"Objects":[{"StartTime":102893.0,"EndTime":102893.0,"X":80.0,"Y":117.0}]},{"StartTime":103004.0,"Objects":[{"StartTime":103004.0,"EndTime":103004.0,"X":169.0,"Y":88.0}]},{"StartTime":103115.0,"Objects":[{"StartTime":103115.0,"EndTime":103115.0,"X":224.0,"Y":164.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103301.0,"EndTime":103301.0,"X":391.5921,"Y":148.586258,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103449.0,"Objects":[{"StartTime":103449.0,"EndTime":103449.0,"X":456.0,"Y":317.0}]},{"StartTime":103560.0,"Objects":[{"StartTime":103560.0,"EndTime":103560.0,"X":366.0,"Y":290.0}]},{"StartTime":103671.0,"Objects":[{"StartTime":103671.0,"EndTime":103671.0,"X":324.0,"Y":206.0}]},{"StartTime":103782.0,"Objects":[{"StartTime":103782.0,"EndTime":103782.0,"X":326.0,"Y":112.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103893.0,"EndTime":103893.0,"X":340.771759,"Y":28.293396,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103968.0,"EndTime":103968.0,"X":326.0,"Y":112.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104115.0,"Objects":[{"StartTime":104115.0,"EndTime":104115.0,"X":314.0,"Y":203.0}]},{"StartTime":104226.0,"Objects":[{"StartTime":104226.0,"EndTime":104226.0,"X":242.0,"Y":148.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104301.0,"EndTime":104301.0,"X":183.429764,"Y":86.40027,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104449.0,"Objects":[{"StartTime":104449.0,"EndTime":104449.0,"X":398.0,"Y":167.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104524.0,"EndTime":104524.0,"X":472.303375,"Y":125.720352,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104671.0,"Objects":[{"StartTime":104671.0,"EndTime":104671.0,"X":365.0,"Y":276.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104782.0,"EndTime":104782.0,"X":379.771759,"Y":359.7066,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104857.0,"EndTime":104857.0,"X":365.0,"Y":276.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105004.0,"Objects":[{"StartTime":105004.0,"EndTime":105004.0,"X":183.0,"Y":86.0}]},{"StartTime":105115.0,"Objects":[{"StartTime":105115.0,"EndTime":105115.0,"X":99.0,"Y":88.0}]},{"StartTime":105226.0,"Objects":[{"StartTime":105226.0,"EndTime":105226.0,"X":31.0,"Y":137.0}]},{"StartTime":105337.0,"Objects":[{"StartTime":105337.0,"EndTime":105337.0,"X":3.0,"Y":216.0}]},{"StartTime":105449.0,"Objects":[{"StartTime":105449.0,"EndTime":105449.0,"X":24.0,"Y":297.0}]},{"StartTime":105560.0,"Objects":[{"StartTime":105560.0,"EndTime":105560.0,"X":87.0,"Y":352.0}]},{"StartTime":105671.0,"Objects":[{"StartTime":105671.0,"EndTime":105671.0,"X":152.0,"Y":298.0}]},{"StartTime":105782.0,"Objects":[{"StartTime":105782.0,"EndTime":105782.0,"X":233.0,"Y":273.0}]},{"StartTime":105893.0,"Objects":[{"StartTime":105893.0,"EndTime":105893.0,"X":317.0,"Y":283.0}]},{"StartTime":106004.0,"Objects":[{"StartTime":106004.0,"EndTime":106004.0,"X":391.0,"Y":324.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106079.0,"EndTime":106079.0,"X":475.052948,"Y":311.346863,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106226.0,"Objects":[{"StartTime":106226.0,"EndTime":106226.0,"X":282.0,"Y":227.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106301.0,"EndTime":106301.0,"X":198.0845,"Y":213.46524,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106449.0,"Objects":[{"StartTime":106449.0,"EndTime":106449.0,"X":46.0,"Y":357.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106524.0,"EndTime":106524.0,"X":129.892242,"Y":343.32193,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106671.0,"Objects":[{"StartTime":106671.0,"EndTime":106671.0,"X":62.0,"Y":140.0}]},{"StartTime":106782.0,"Objects":[{"StartTime":106782.0,"EndTime":106782.0,"X":62.0,"Y":140.0}]},{"StartTime":106893.0,"Objects":[{"StartTime":106893.0,"EndTime":106893.0,"X":62.0,"Y":140.0}]},{"StartTime":107004.0,"Objects":[{"StartTime":107004.0,"EndTime":107004.0,"X":62.0,"Y":140.0}]},{"StartTime":107115.0,"Objects":[{"StartTime":107115.0,"EndTime":107115.0,"X":62.0,"Y":140.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107301.0,"EndTime":107301.0,"X":230.55661,"Y":117.894211,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107449.0,"Objects":[{"StartTime":107449.0,"EndTime":107449.0,"X":418.0,"Y":227.0}]},{"StartTime":107560.0,"Objects":[{"StartTime":107560.0,"EndTime":107560.0,"X":330.0,"Y":251.0}]},{"StartTime":107671.0,"Objects":[{"StartTime":107671.0,"EndTime":107671.0,"X":251.0,"Y":206.0}]},{"StartTime":107782.0,"Objects":[{"StartTime":107782.0,"EndTime":107782.0,"X":230.0,"Y":117.0}]},{"StartTime":107893.0,"Objects":[{"StartTime":107893.0,"EndTime":107893.0,"X":277.0,"Y":35.0}]},{"StartTime":108004.0,"Objects":[{"StartTime":108004.0,"EndTime":108004.0,"X":347.0,"Y":130.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108079.0,"EndTime":108079.0,"X":263.20224,"Y":144.245621,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108226.0,"Objects":[{"StartTime":108226.0,"EndTime":108226.0,"X":46.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108412.0,"EndTime":108412.0,"X":23.9974537,"Y":230.15947,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108560.0,"Objects":[{"StartTime":108560.0,"EndTime":108560.0,"X":215.0,"Y":312.0}]},{"StartTime":108671.0,"Objects":[{"StartTime":108671.0,"EndTime":108671.0,"X":215.0,"Y":312.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108746.0,"EndTime":108746.0,"X":158.405411,"Y":253.670273,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108893.0,"Objects":[{"StartTime":108893.0,"EndTime":108893.0,"X":62.0,"Y":140.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109079.0,"EndTime":109079.0,"X":224.426849,"Y":169.542343,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109226.0,"Objects":[{"StartTime":109226.0,"EndTime":109226.0,"X":371.0,"Y":114.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109337.0,"EndTime":109337.0,"X":375.612762,"Y":29.12526,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109412.0,"EndTime":109412.0,"X":371.0,"Y":114.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109560.0,"Objects":[{"StartTime":109560.0,"EndTime":109560.0,"X":312.0,"Y":190.0}]},{"StartTime":109671.0,"Objects":[{"StartTime":109671.0,"EndTime":109671.0,"X":389.0,"Y":239.0}]},{"StartTime":109782.0,"Objects":[{"StartTime":109782.0,"EndTime":109782.0,"X":308.0,"Y":283.0}]},{"StartTime":109893.0,"Objects":[{"StartTime":109893.0,"EndTime":109893.0,"X":386.0,"Y":333.0}]},{"StartTime":110004.0,"Objects":[{"StartTime":110004.0,"EndTime":110004.0,"X":305.0,"Y":377.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110079.0,"EndTime":110079.0,"X":231.754059,"Y":338.856445,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110226.0,"Objects":[{"StartTime":110226.0,"EndTime":110226.0,"X":77.0,"Y":199.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110412.0,"EndTime":110412.0,"X":223.643723,"Y":169.366547,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110560.0,"Objects":[{"StartTime":110560.0,"EndTime":110560.0,"X":417.0,"Y":221.0}]},{"StartTime":110671.0,"Objects":[{"StartTime":110671.0,"EndTime":110671.0,"X":444.0,"Y":135.0}]},{"StartTime":110782.0,"Objects":[{"StartTime":110782.0,"EndTime":110782.0,"X":389.0,"Y":64.0}]},{"StartTime":110893.0,"Objects":[{"StartTime":110893.0,"EndTime":110893.0,"X":299.0,"Y":68.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111079.0,"EndTime":111079.0,"X":158.284866,"Y":15.6295881,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111226.0,"Objects":[{"StartTime":111226.0,"EndTime":111226.0,"X":62.0,"Y":140.0}]},{"StartTime":111337.0,"Objects":[{"StartTime":111337.0,"EndTime":111337.0,"X":62.0,"Y":140.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111412.0,"EndTime":111412.0,"X":80.53252,"Y":222.955078,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111560.0,"Objects":[{"StartTime":111560.0,"EndTime":111560.0,"X":262.0,"Y":296.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111635.0,"EndTime":111635.0,"X":178.5487,"Y":279.848145,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111782.0,"Objects":[{"StartTime":111782.0,"EndTime":111782.0,"X":349.0,"Y":153.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111893.0,"EndTime":111893.0,"X":340.050018,"Y":68.4725,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111968.0,"EndTime":111968.0,"X":349.0,"Y":153.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112115.0,"Objects":[{"StartTime":112115.0,"EndTime":112115.0,"X":236.0,"Y":329.0}]},{"StartTime":112226.0,"Objects":[{"StartTime":112226.0,"EndTime":112226.0,"X":292.0,"Y":267.0}]},{"StartTime":112337.0,"Objects":[{"StartTime":112337.0,"EndTime":112337.0,"X":375.0,"Y":253.0}]},{"StartTime":112449.0,"Objects":[{"StartTime":112449.0,"EndTime":112449.0,"X":449.0,"Y":291.0}]},{"StartTime":112560.0,"Objects":[{"StartTime":112560.0,"EndTime":112560.0,"X":378.0,"Y":336.0}]},{"StartTime":112671.0,"Objects":[{"StartTime":112671.0,"EndTime":112671.0,"X":375.0,"Y":253.0}]},{"StartTime":112782.0,"Objects":[{"StartTime":112782.0,"EndTime":112782.0,"X":372.0,"Y":170.0}]},{"StartTime":112893.0,"Objects":[{"StartTime":112893.0,"EndTime":112893.0,"X":369.0,"Y":87.0}]},{"StartTime":113004.0,"Objects":[{"StartTime":113004.0,"EndTime":113004.0,"X":442.0,"Y":125.0}]},{"StartTime":113115.0,"Objects":[{"StartTime":113115.0,"EndTime":113115.0,"X":348.0,"Y":178.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":113190.0,"EndTime":113190.0,"X":263.3711,"Y":170.06604,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":113337.0,"Objects":[{"StartTime":113337.0,"EndTime":113337.0,"X":80.0,"Y":269.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":113412.0,"EndTime":113412.0,"X":162.128845,"Y":264.339417,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":113560.0,"Objects":[{"StartTime":113560.0,"EndTime":113560.0,"X":105.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":113635.0,"EndTime":113635.0,"X":85.68204,"Y":97.64976,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":113782.0,"Objects":[{"StartTime":113782.0,"EndTime":113782.0,"X":260.0,"Y":255.0}]},{"StartTime":113893.0,"Objects":[{"StartTime":113893.0,"EndTime":113893.0,"X":261.0,"Y":212.0}]},{"StartTime":114004.0,"Objects":[{"StartTime":114004.0,"EndTime":114004.0,"X":262.0,"Y":170.0}]},{"StartTime":114226.0,"Objects":[{"StartTime":114226.0,"EndTime":114226.0,"X":414.0,"Y":61.0}]},{"StartTime":114337.0,"Objects":[{"StartTime":114337.0,"EndTime":114337.0,"X":340.0,"Y":101.0}]},{"StartTime":114449.0,"Objects":[{"StartTime":114449.0,"EndTime":114449.0,"X":256.0,"Y":109.0}]},{"StartTime":114560.0,"Objects":[{"StartTime":114560.0,"EndTime":114560.0,"X":176.0,"Y":81.0}]},{"StartTime":114671.0,"Objects":[{"StartTime":114671.0,"EndTime":114671.0,"X":105.0,"Y":18.0}]},{"StartTime":114782.0,"Objects":[{"StartTime":114782.0,"EndTime":114782.0,"X":84.0,"Y":118.0}]},{"StartTime":114893.0,"Objects":[{"StartTime":114893.0,"EndTime":114893.0,"X":63.0,"Y":218.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114968.0,"EndTime":114968.0,"X":145.047943,"Y":235.7841,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115115.0,"Objects":[{"StartTime":115115.0,"EndTime":115115.0,"X":369.0,"Y":328.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115190.0,"EndTime":115190.0,"X":286.6682,"Y":330.003754,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115337.0,"Objects":[{"StartTime":115337.0,"EndTime":115337.0,"X":256.0,"Y":109.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115412.0,"EndTime":115412.0,"X":353.312866,"Y":115.327446,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115560.0,"Objects":[{"StartTime":115560.0,"EndTime":115560.0,"X":488.0,"Y":273.0}]},{"StartTime":115671.0,"Objects":[{"StartTime":115671.0,"EndTime":115671.0,"X":488.0,"Y":273.0}]},{"StartTime":115782.0,"Objects":[{"StartTime":115782.0,"EndTime":115782.0,"X":488.0,"Y":273.0}]},{"StartTime":116004.0,"Objects":[{"StartTime":116004.0,"EndTime":116004.0,"X":429.0,"Y":83.0}]},{"StartTime":116115.0,"Objects":[{"StartTime":116115.0,"EndTime":116115.0,"X":429.0,"Y":83.0}]},{"StartTime":116226.0,"Objects":[{"StartTime":116226.0,"EndTime":116226.0,"X":429.0,"Y":83.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":116281.0,"EndTime":116281.0,"X":430.78653,"Y":50.84238,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":116301.0,"EndTime":116301.0,"X":429.0,"Y":83.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":116449.0,"Objects":[{"StartTime":116449.0,"EndTime":116449.0,"X":381.0,"Y":198.0}]},{"StartTime":116560.0,"Objects":[{"StartTime":116560.0,"EndTime":116560.0,"X":381.0,"Y":198.0}]},{"StartTime":116782.0,"Objects":[{"StartTime":116782.0,"EndTime":116782.0,"X":187.0,"Y":140.0}]},{"StartTime":117004.0,"Objects":[{"StartTime":117004.0,"EndTime":117004.0,"X":102.0,"Y":323.0}]},{"StartTime":117337.0,"Objects":[{"StartTime":117337.0,"EndTime":117337.0,"X":58.0,"Y":34.0}]},{"StartTime":128004.0,"Objects":[{"StartTime":128004.0,"EndTime":128004.0,"X":380.0,"Y":124.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":128079.0,"EndTime":128079.0,"X":429.438324,"Y":121.441765,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":128226.0,"Objects":[{"StartTime":128226.0,"EndTime":128226.0,"X":396.0,"Y":256.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":128301.0,"EndTime":128301.0,"X":346.561676,"Y":258.558228,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":128449.0,"Objects":[{"StartTime":128449.0,"EndTime":128449.0,"X":104.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":128524.0,"EndTime":128524.0,"X":113.805809,"Y":249.029037,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":128671.0,"Objects":[{"StartTime":128671.0,"EndTime":128671.0,"X":172.0,"Y":104.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":128746.0,"EndTime":128746.0,"X":162.1942,"Y":54.9709663,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":128893.0,"Objects":[{"StartTime":128893.0,"EndTime":128893.0,"X":272.0,"Y":184.0}]},{"StartTime":129004.0,"Objects":[{"StartTime":129004.0,"EndTime":129004.0,"X":280.0,"Y":208.0}]},{"StartTime":129115.0,"Objects":[{"StartTime":129115.0,"EndTime":129115.0,"X":280.0,"Y":232.0}]},{"StartTime":129226.0,"Objects":[{"StartTime":129226.0,"EndTime":129226.0,"X":272.0,"Y":256.0}]},{"StartTime":129337.0,"Objects":[{"StartTime":129337.0,"EndTime":129337.0,"X":264.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":129412.0,"EndTime":129412.0,"X":309.807861,"Y":300.040955,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":129560.0,"Objects":[{"StartTime":129560.0,"EndTime":129560.0,"X":464.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":129635.0,"EndTime":129635.0,"X":418.192139,"Y":239.959061,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":129782.0,"Objects":[{"StartTime":129782.0,"EndTime":129782.0,"X":317.0,"Y":113.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":129809.0,"EndTime":129809.0,"X":332.10965,"Y":93.08272,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":129893.0,"Objects":[{"StartTime":129893.0,"EndTime":129893.0,"X":286.0,"Y":96.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":129920.0,"EndTime":129920.0,"X":294.3205,"Y":72.42524,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130004.0,"Objects":[{"StartTime":130004.0,"EndTime":130004.0,"X":252.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130031.0,"EndTime":130031.0,"X":251.305817,"Y":67.00964,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130115.0,"Objects":[{"StartTime":130115.0,"EndTime":130115.0,"X":218.0,"Y":99.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130142.0,"EndTime":130142.0,"X":209.071564,"Y":75.6487045,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130226.0,"Objects":[{"StartTime":130226.0,"EndTime":130226.0,"X":189.0,"Y":117.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130253.0,"EndTime":130253.0,"X":172.0148,"Y":98.65598,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130337.0,"Objects":[{"StartTime":130337.0,"EndTime":130337.0,"X":167.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130364.0,"EndTime":130364.0,"X":144.9221,"Y":133.271118,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130449.0,"Objects":[{"StartTime":130449.0,"EndTime":130449.0,"X":156.0,"Y":178.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130476.0,"EndTime":130476.0,"X":131.251266,"Y":174.464462,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130560.0,"Objects":[{"StartTime":130560.0,"EndTime":130560.0,"X":158.0,"Y":212.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130587.0,"EndTime":130587.0,"X":133.595322,"Y":217.423264,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130671.0,"Objects":[{"StartTime":130671.0,"EndTime":130671.0,"X":171.0,"Y":244.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130698.0,"EndTime":130698.0,"X":149.992584,"Y":257.553162,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130782.0,"Objects":[{"StartTime":130782.0,"EndTime":130782.0,"X":194.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130809.0,"EndTime":130809.0,"X":178.890335,"Y":289.917267,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130893.0,"Objects":[{"StartTime":130893.0,"EndTime":130893.0,"X":225.0,"Y":287.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130920.0,"EndTime":130920.0,"X":216.6795,"Y":310.574768,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":131004.0,"Objects":[{"StartTime":131004.0,"EndTime":131004.0,"X":259.0,"Y":291.0}]},{"StartTime":131337.0,"Objects":[{"StartTime":131337.0,"EndTime":131337.0,"X":259.0,"Y":291.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":131523.0,"EndTime":131523.0,"X":352.95874,"Y":282.156,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":132004.0,"Objects":[{"StartTime":132004.0,"EndTime":132004.0,"X":456.0,"Y":68.0}]},{"StartTime":132226.0,"Objects":[{"StartTime":132226.0,"EndTime":132226.0,"X":340.0,"Y":184.0}]},{"StartTime":132449.0,"Objects":[{"StartTime":132449.0,"EndTime":132449.0,"X":284.0,"Y":20.0}]},{"StartTime":132671.0,"Objects":[{"StartTime":132671.0,"EndTime":132671.0,"X":156.0,"Y":160.0}]},{"StartTime":132782.0,"Objects":[{"StartTime":132782.0,"EndTime":132782.0,"X":156.0,"Y":160.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":132968.0,"EndTime":132968.0,"X":254.257935,"Y":159.456436,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":133115.0,"Objects":[{"StartTime":133115.0,"EndTime":133115.0,"X":92.0,"Y":235.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":133190.0,"EndTime":133190.0,"X":43.1906471,"Y":245.846527,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":133337.0,"Objects":[{"StartTime":133337.0,"EndTime":133337.0,"X":281.0,"Y":303.0}]},{"StartTime":133560.0,"Objects":[{"StartTime":133560.0,"EndTime":133560.0,"X":471.0,"Y":213.0}]},{"StartTime":133782.0,"Objects":[{"StartTime":133782.0,"EndTime":133782.0,"X":281.0,"Y":303.0}]},{"StartTime":134004.0,"Objects":[{"StartTime":134004.0,"EndTime":134004.0,"X":363.0,"Y":84.0}]},{"StartTime":134226.0,"Objects":[{"StartTime":134226.0,"EndTime":134226.0,"X":241.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":134301.0,"EndTime":134301.0,"X":227.544769,"Y":113.844452,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":134449.0,"Objects":[{"StartTime":134449.0,"EndTime":134449.0,"X":164.0,"Y":204.0}]},{"StartTime":134560.0,"Objects":[{"StartTime":134560.0,"EndTime":134560.0,"X":164.0,"Y":204.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":134746.0,"EndTime":134746.0,"X":67.36322,"Y":209.315872,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":134893.0,"Objects":[{"StartTime":134893.0,"EndTime":134893.0,"X":281.0,"Y":303.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":135079.0,"EndTime":135079.0,"X":377.63678,"Y":297.684143,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":135337.0,"Objects":[{"StartTime":135337.0,"EndTime":135337.0,"X":500.0,"Y":184.0}]},{"StartTime":135560.0,"Objects":[{"StartTime":135560.0,"EndTime":135560.0,"X":465.0,"Y":11.0}]},{"StartTime":135782.0,"Objects":[{"StartTime":135782.0,"EndTime":135782.0,"X":294.0,"Y":44.0}]},{"StartTime":136004.0,"Objects":[{"StartTime":136004.0,"EndTime":136004.0,"X":327.0,"Y":217.0}]},{"StartTime":136226.0,"Objects":[{"StartTime":136226.0,"EndTime":136226.0,"X":408.0,"Y":112.0}]},{"StartTime":136337.0,"Objects":[{"StartTime":136337.0,"EndTime":136337.0,"X":408.0,"Y":112.0}]},{"StartTime":136560.0,"Objects":[{"StartTime":136560.0,"EndTime":136560.0,"X":364.0,"Y":316.0}]},{"StartTime":136671.0,"Objects":[{"StartTime":136671.0,"EndTime":136671.0,"X":364.0,"Y":316.0}]},{"StartTime":136893.0,"Objects":[{"StartTime":136893.0,"EndTime":136893.0,"X":168.0,"Y":292.0}]},{"StartTime":137115.0,"Objects":[{"StartTime":137115.0,"EndTime":137115.0,"X":48.0,"Y":212.0}]},{"StartTime":137337.0,"Objects":[{"StartTime":137337.0,"EndTime":137337.0,"X":188.0,"Y":16.0}]},{"StartTime":137560.0,"Objects":[{"StartTime":137560.0,"EndTime":137560.0,"X":176.0,"Y":156.0}]},{"StartTime":137782.0,"Objects":[{"StartTime":137782.0,"EndTime":137782.0,"X":344.0,"Y":292.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":137968.0,"EndTime":137968.0,"X":439.6384,"Y":272.7788,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":138115.0,"Objects":[{"StartTime":138115.0,"EndTime":138115.0,"X":388.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":138301.0,"EndTime":138301.0,"X":404.404022,"Y":80.73015,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":138449.0,"Objects":[{"StartTime":138449.0,"EndTime":138449.0,"X":168.0,"Y":192.0}]},{"StartTime":138560.0,"Objects":[{"StartTime":138560.0,"EndTime":138560.0,"X":168.0,"Y":192.0}]},{"StartTime":138671.0,"Objects":[{"StartTime":138671.0,"EndTime":138671.0,"X":168.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":138857.0,"EndTime":138857.0,"X":267.4309,"Y":202.65332,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":139115.0,"Objects":[{"StartTime":139115.0,"EndTime":139115.0,"X":464.0,"Y":168.0}]},{"StartTime":139337.0,"Objects":[{"StartTime":139337.0,"EndTime":139337.0,"X":344.0,"Y":292.0}]},{"StartTime":139560.0,"Objects":[{"StartTime":139560.0,"EndTime":139560.0,"X":332.0,"Y":24.0}]},{"StartTime":139782.0,"Objects":[{"StartTime":139782.0,"EndTime":139782.0,"X":288.0,"Y":368.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":139968.0,"EndTime":139968.0,"X":384.317841,"Y":377.256653,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":140226.0,"Objects":[{"StartTime":140226.0,"EndTime":140226.0,"X":224.0,"Y":16.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":140412.0,"EndTime":140412.0,"X":127.682182,"Y":6.743342,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":140671.0,"Objects":[{"StartTime":140671.0,"EndTime":140671.0,"X":80.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":140857.0,"EndTime":140857.0,"X":70.74335,"Y":320.3178,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":141115.0,"Objects":[{"StartTime":141115.0,"EndTime":141115.0,"X":400.0,"Y":152.0}]},{"StartTime":141337.0,"Objects":[{"StartTime":141337.0,"EndTime":141337.0,"X":300.0,"Y":268.0}]},{"StartTime":141560.0,"Objects":[{"StartTime":141560.0,"EndTime":141560.0,"X":460.0,"Y":80.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":141746.0,"EndTime":141746.0,"X":367.40332,"Y":63.3521423,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":142004.0,"Objects":[{"StartTime":142004.0,"EndTime":142004.0,"X":332.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":142190.0,"EndTime":142190.0,"X":346.5494,"Y":322.9359,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":142449.0,"Objects":[{"StartTime":142449.0,"EndTime":142449.0,"X":184.0,"Y":88.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":142524.0,"EndTime":142524.0,"X":178.04274,"Y":38.35616,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":142671.0,"Objects":[{"StartTime":142671.0,"EndTime":142671.0,"X":204.0,"Y":136.0}]},{"StartTime":142782.0,"Objects":[{"StartTime":142782.0,"EndTime":142782.0,"X":212.0,"Y":184.0}]},{"StartTime":142893.0,"Objects":[{"StartTime":142893.0,"EndTime":142893.0,"X":196.0,"Y":232.0}]},{"StartTime":143004.0,"Objects":[{"StartTime":143004.0,"EndTime":143004.0,"X":152.0,"Y":256.0}]},{"StartTime":143115.0,"Objects":[{"StartTime":143115.0,"EndTime":143115.0,"X":104.0,"Y":236.0}]},{"StartTime":143226.0,"Objects":[{"StartTime":143226.0,"EndTime":143226.0,"X":56.0,"Y":252.0}]},{"StartTime":143337.0,"Objects":[{"StartTime":143337.0,"EndTime":143337.0,"X":32.0,"Y":296.0}]},{"StartTime":143449.0,"Objects":[{"StartTime":143449.0,"EndTime":143449.0,"X":52.0,"Y":340.0}]},{"StartTime":143560.0,"Objects":[{"StartTime":143560.0,"EndTime":143560.0,"X":92.0,"Y":372.0}]},{"StartTime":143671.0,"Objects":[{"StartTime":143671.0,"EndTime":143671.0,"X":140.0,"Y":352.0}]},{"StartTime":143782.0,"Objects":[{"StartTime":143782.0,"EndTime":143782.0,"X":188.0,"Y":336.0}]},{"StartTime":143893.0,"Objects":[{"StartTime":143893.0,"EndTime":143893.0,"X":236.0,"Y":348.0}]},{"StartTime":144004.0,"Objects":[{"StartTime":144004.0,"EndTime":144004.0,"X":280.0,"Y":368.0}]},{"StartTime":144449.0,"Objects":[{"StartTime":144449.0,"EndTime":144449.0,"X":448.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":144476.0,"EndTime":144476.0,"X":424.591766,"Y":251.221909,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":144560.0,"Objects":[{"StartTime":144560.0,"EndTime":144560.0,"X":424.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":144587.0,"EndTime":144587.0,"X":400.357849,"Y":242.873,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":144671.0,"Objects":[{"StartTime":144671.0,"EndTime":144671.0,"X":400.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":144698.0,"EndTime":144698.0,"X":376.591766,"Y":234.221909,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":144782.0,"Objects":[{"StartTime":144782.0,"EndTime":144782.0,"X":377.0,"Y":234.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":144809.0,"EndTime":144809.0,"X":353.365662,"Y":225.850235,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":144893.0,"Objects":[{"StartTime":144893.0,"EndTime":144893.0,"X":316.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":144968.0,"EndTime":144968.0,"X":305.8368,"Y":151.497864,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":145115.0,"Objects":[{"StartTime":145115.0,"EndTime":145115.0,"X":404.0,"Y":40.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":145190.0,"EndTime":145190.0,"X":414.1632,"Y":88.50214,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":145337.0,"Objects":[{"StartTime":145337.0,"EndTime":145337.0,"X":252.0,"Y":264.0}]},{"StartTime":145449.0,"Objects":[{"StartTime":145449.0,"EndTime":145449.0,"X":252.0,"Y":264.0}]},{"StartTime":145560.0,"Objects":[{"StartTime":145560.0,"EndTime":145560.0,"X":252.0,"Y":264.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":145746.0,"EndTime":145746.0,"X":153.884521,"Y":264.3699,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":146226.0,"Objects":[{"StartTime":146226.0,"EndTime":146226.0,"X":34.0,"Y":77.0}]},{"StartTime":146449.0,"Objects":[{"StartTime":146449.0,"EndTime":146449.0,"X":54.0,"Y":230.0}]},{"StartTime":146671.0,"Objects":[{"StartTime":146671.0,"EndTime":146671.0,"X":28.0,"Y":27.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":146746.0,"EndTime":146746.0,"X":33.1014442,"Y":76.7390747,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":146893.0,"Objects":[{"StartTime":146893.0,"EndTime":146893.0,"X":54.0,"Y":230.0}]},{"StartTime":147004.0,"Objects":[{"StartTime":147004.0,"EndTime":147004.0,"X":54.0,"Y":230.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":147079.0,"EndTime":147079.0,"X":59.1014442,"Y":180.260925,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":147226.0,"Objects":[{"StartTime":147226.0,"EndTime":147226.0,"X":234.0,"Y":135.0}]},{"StartTime":147337.0,"Objects":[{"StartTime":147337.0,"EndTime":147337.0,"X":234.0,"Y":135.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":147523.0,"EndTime":147523.0,"X":333.241241,"Y":147.29538,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":147782.0,"Objects":[{"StartTime":147782.0,"EndTime":147782.0,"X":156.0,"Y":190.0}]},{"StartTime":148004.0,"Objects":[{"StartTime":148004.0,"EndTime":148004.0,"X":333.0,"Y":147.0}]},{"StartTime":148226.0,"Objects":[{"StartTime":148226.0,"EndTime":148226.0,"X":133.0,"Y":120.0}]},{"StartTime":148449.0,"Objects":[{"StartTime":148449.0,"EndTime":148449.0,"X":358.0,"Y":65.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148635.0,"EndTime":148635.0,"X":260.9272,"Y":89.01802,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":148782.0,"Objects":[{"StartTime":148782.0,"EndTime":148782.0,"X":333.0,"Y":147.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148968.0,"EndTime":148968.0,"X":432.241241,"Y":159.29538,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149115.0,"Objects":[{"StartTime":149115.0,"EndTime":149115.0,"X":321.0,"Y":275.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":149190.0,"EndTime":149190.0,"X":306.130829,"Y":227.2621,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149337.0,"Objects":[{"StartTime":149337.0,"EndTime":149337.0,"X":462.0,"Y":165.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":149523.0,"EndTime":149523.0,"X":431.9714,"Y":260.384918,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149782.0,"Objects":[{"StartTime":149782.0,"EndTime":149782.0,"X":393.0,"Y":83.0}]},{"StartTime":150004.0,"Objects":[{"StartTime":150004.0,"EndTime":150004.0,"X":431.0,"Y":260.0}]},{"StartTime":150226.0,"Objects":[{"StartTime":150226.0,"EndTime":150226.0,"X":221.0,"Y":288.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":150412.0,"EndTime":150412.0,"X":320.083,"Y":274.488678,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":150560.0,"Objects":[{"StartTime":150560.0,"EndTime":150560.0,"X":190.0,"Y":296.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":150635.0,"EndTime":150635.0,"X":175.130814,"Y":248.2621,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":150782.0,"Objects":[{"StartTime":150782.0,"EndTime":150782.0,"X":334.0,"Y":226.0}]},{"StartTime":150893.0,"Objects":[{"StartTime":150893.0,"EndTime":150893.0,"X":334.0,"Y":226.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":150968.0,"EndTime":150968.0,"X":319.130829,"Y":273.7379,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":151115.0,"Objects":[{"StartTime":151115.0,"EndTime":151115.0,"X":238.0,"Y":135.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":151190.0,"EndTime":151190.0,"X":252.869186,"Y":182.7379,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":151337.0,"Objects":[{"StartTime":151337.0,"EndTime":151337.0,"X":190.0,"Y":296.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":151412.0,"EndTime":151412.0,"X":204.869186,"Y":343.7379,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":151560.0,"Objects":[{"StartTime":151560.0,"EndTime":151560.0,"X":118.0,"Y":72.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":151635.0,"EndTime":151635.0,"X":132.869186,"Y":119.7379,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":151782.0,"Objects":[{"StartTime":151782.0,"EndTime":151782.0,"X":24.0,"Y":221.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":151857.0,"EndTime":151857.0,"X":38.8691826,"Y":268.7379,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":152004.0,"Objects":[{"StartTime":152004.0,"EndTime":152004.0,"X":242.0,"Y":367.0}]},{"StartTime":152115.0,"Objects":[{"StartTime":152115.0,"EndTime":152115.0,"X":276.0,"Y":362.0}]},{"StartTime":152226.0,"Objects":[{"StartTime":152226.0,"EndTime":152226.0,"X":311.0,"Y":357.0}]},{"StartTime":152337.0,"Objects":[{"StartTime":152337.0,"EndTime":152337.0,"X":346.0,"Y":353.0}]},{"StartTime":152449.0,"Objects":[{"StartTime":152449.0,"EndTime":152449.0,"X":386.0,"Y":338.0}]},{"StartTime":152560.0,"Objects":[{"StartTime":152560.0,"EndTime":152560.0,"X":337.0,"Y":327.0}]},{"StartTime":152671.0,"Objects":[{"StartTime":152671.0,"EndTime":152671.0,"X":288.0,"Y":317.0}]},{"StartTime":152782.0,"Objects":[{"StartTime":152782.0,"EndTime":152782.0,"X":239.0,"Y":306.0}]},{"StartTime":152893.0,"Objects":[{"StartTime":152893.0,"EndTime":152893.0,"X":190.0,"Y":296.0}]},{"StartTime":153337.0,"Objects":[{"StartTime":153337.0,"EndTime":153337.0,"X":190.0,"Y":296.0}]},{"StartTime":153560.0,"Objects":[{"StartTime":153560.0,"EndTime":153560.0,"X":241.0,"Y":77.0}]},{"StartTime":153782.0,"Objects":[{"StartTime":153782.0,"EndTime":153782.0,"X":200.0,"Y":262.0}]},{"StartTime":154004.0,"Objects":[{"StartTime":154004.0,"EndTime":154004.0,"X":447.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":154190.0,"EndTime":154190.0,"X":348.433533,"Y":183.128265,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":154449.0,"Objects":[{"StartTime":154449.0,"EndTime":154449.0,"X":97.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":154524.0,"EndTime":154524.0,"X":146.362061,"Y":111.038376,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":154671.0,"Objects":[{"StartTime":154671.0,"EndTime":154671.0,"X":348.0,"Y":183.0}]},{"StartTime":154893.0,"Objects":[{"StartTime":154893.0,"EndTime":154893.0,"X":151.0,"Y":210.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":155079.0,"EndTime":155079.0,"X":145.955917,"Y":110.1273,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":155337.0,"Objects":[{"StartTime":155337.0,"EndTime":155337.0,"X":353.0,"Y":83.0}]},{"StartTime":155449.0,"Objects":[{"StartTime":155449.0,"EndTime":155449.0,"X":350.0,"Y":132.0}]},{"StartTime":155560.0,"Objects":[{"StartTime":155560.0,"EndTime":155560.0,"X":347.0,"Y":182.0}]},{"StartTime":155782.0,"Objects":[{"StartTime":155782.0,"EndTime":155782.0,"X":31.0,"Y":78.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":156190.0,"EndTime":156190.0,"X":144.98584,"Y":110.023438,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":156449.0,"Objects":[{"StartTime":156449.0,"EndTime":156449.0,"X":113.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":156524.0,"EndTime":156524.0,"X":111.040718,"Y":230.038391,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":156671.0,"Objects":[{"StartTime":156671.0,"EndTime":156671.0,"X":145.0,"Y":110.0}]},{"StartTime":156893.0,"Objects":[{"StartTime":156893.0,"EndTime":156893.0,"X":108.0,"Y":312.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":156968.0,"EndTime":156968.0,"X":58.4584923,"Y":305.244354,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":157115.0,"Objects":[{"StartTime":157115.0,"EndTime":157115.0,"X":211.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":157190.0,"EndTime":157190.0,"X":260.5415,"Y":214.755661,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":157337.0,"Objects":[{"StartTime":157337.0,"EndTime":157337.0,"X":414.0,"Y":288.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":157392.0,"EndTime":157392.0,"X":389.2185,"Y":289.835663,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":157448.0,"EndTime":157448.0,"X":413.849823,"Y":288.011139,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":157467.0,"EndTime":157467.0,"X":389.0683,"Y":289.8468,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":157560.0,"Objects":[{"StartTime":157560.0,"EndTime":157560.0,"X":290.0,"Y":340.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":157615.0,"EndTime":157615.0,"X":314.7762,"Y":341.905884,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":157671.0,"EndTime":157671.0,"X":290.150146,"Y":340.011536,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":157690.0,"EndTime":157690.0,"X":314.926361,"Y":341.917419,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":157782.0,"Objects":[{"StartTime":157782.0,"EndTime":157782.0,"X":414.0,"Y":288.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":157857.0,"EndTime":157857.0,"X":419.1956,"Y":238.270676,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":158004.0,"Objects":[{"StartTime":158004.0,"EndTime":158004.0,"X":315.0,"Y":130.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":158079.0,"EndTime":158079.0,"X":328.026154,"Y":178.273376,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":158226.0,"Objects":[{"StartTime":158226.0,"EndTime":158226.0,"X":492.0,"Y":100.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":158301.0,"EndTime":158301.0,"X":442.4585,"Y":93.24434,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":158449.0,"Objects":[{"StartTime":158449.0,"EndTime":158449.0,"X":214.0,"Y":158.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":158524.0,"EndTime":158524.0,"X":204.3489,"Y":108.940277,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":158671.0,"Objects":[{"StartTime":158671.0,"EndTime":158671.0,"X":342.0,"Y":13.0}]},{"StartTime":158782.0,"Objects":[{"StartTime":158782.0,"EndTime":158782.0,"X":342.0,"Y":13.0}]},{"StartTime":158893.0,"Objects":[{"StartTime":158893.0,"EndTime":158893.0,"X":342.0,"Y":13.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":158948.0,"EndTime":158948.0,"X":339.757,"Y":37.673027,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":158968.0,"EndTime":158968.0,"X":342.0,"Y":13.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":159115.0,"Objects":[{"StartTime":159115.0,"EndTime":159115.0,"X":324.701019,"Y":148.701}]},{"StartTime":159171.0,"Objects":[{"StartTime":159171.0,"EndTime":159171.0,"X":328.3505,"Y":152.35051}]},{"StartTime":159226.0,"Objects":[{"StartTime":159226.0,"EndTime":159226.0,"X":332.0,"Y":156.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":159301.0,"EndTime":159301.0,"X":380.019165,"Y":166.010254,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":159449.0,"Objects":[{"StartTime":159449.0,"EndTime":159449.0,"X":456.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":159524.0,"EndTime":159524.0,"X":445.989746,"Y":308.019165,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":159671.0,"Objects":[{"StartTime":159671.0,"EndTime":159671.0,"X":340.0,"Y":368.0}]},{"StartTime":159782.0,"Objects":[{"StartTime":159782.0,"EndTime":159782.0,"X":340.0,"Y":368.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":159857.0,"EndTime":159857.0,"X":291.980835,"Y":357.989746,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":160004.0,"Objects":[{"StartTime":160004.0,"EndTime":160004.0,"X":44.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":160190.0,"EndTime":160190.0,"X":195.181229,"Y":229.801666,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":160337.0,"Objects":[{"StartTime":160337.0,"EndTime":160337.0,"X":324.0,"Y":28.0}]},{"StartTime":160449.0,"Objects":[{"StartTime":160449.0,"EndTime":160449.0,"X":264.0,"Y":100.0}]},{"StartTime":160560.0,"Objects":[{"StartTime":160560.0,"EndTime":160560.0,"X":312.0,"Y":180.0}]},{"StartTime":160671.0,"Objects":[{"StartTime":160671.0,"EndTime":160671.0,"X":404.0,"Y":164.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":160857.0,"EndTime":160857.0,"X":352.153137,"Y":316.6705,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":161004.0,"Objects":[{"StartTime":161004.0,"EndTime":161004.0,"X":184.0,"Y":328.0}]},{"StartTime":161115.0,"Objects":[{"StartTime":161115.0,"EndTime":161115.0,"X":96.0,"Y":352.0}]},{"StartTime":161226.0,"Objects":[{"StartTime":161226.0,"EndTime":161226.0,"X":32.0,"Y":280.0}]},{"StartTime":161337.0,"Objects":[{"StartTime":161337.0,"EndTime":161337.0,"X":56.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":161412.0,"EndTime":161412.0,"X":48.3044624,"Y":107.349075,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":161560.0,"Objects":[{"StartTime":161560.0,"EndTime":161560.0,"X":184.0,"Y":24.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":161746.0,"EndTime":161746.0,"X":321.449677,"Y":63.5203857,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":161893.0,"Objects":[{"StartTime":161893.0,"EndTime":161893.0,"X":476.0,"Y":176.0}]},{"StartTime":162004.0,"Objects":[{"StartTime":162004.0,"EndTime":162004.0,"X":384.0,"Y":196.0}]},{"StartTime":162115.0,"Objects":[{"StartTime":162115.0,"EndTime":162115.0,"X":356.0,"Y":280.0}]},{"StartTime":162226.0,"Objects":[{"StartTime":162226.0,"EndTime":162226.0,"X":416.0,"Y":352.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":162412.0,"EndTime":162412.0,"X":246.175339,"Y":359.7193,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":162560.0,"Objects":[{"StartTime":162560.0,"EndTime":162560.0,"X":64.0,"Y":312.0}]},{"StartTime":162671.0,"Objects":[{"StartTime":162671.0,"EndTime":162671.0,"X":128.0,"Y":244.0}]},{"StartTime":162782.0,"Objects":[{"StartTime":162782.0,"EndTime":162782.0,"X":152.0,"Y":156.0}]},{"StartTime":162893.0,"Objects":[{"StartTime":162893.0,"EndTime":162893.0,"X":96.0,"Y":80.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":162968.0,"EndTime":162968.0,"X":150.808136,"Y":18.1909065,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":163115.0,"Objects":[{"StartTime":163115.0,"EndTime":163115.0,"X":361.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":163190.0,"EndTime":163190.0,"X":415.8814,"Y":79.67221,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":163337.0,"Objects":[{"StartTime":163337.0,"EndTime":163337.0,"X":256.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":163412.0,"EndTime":163412.0,"X":256.0,"Y":139.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":163560.0,"Objects":[{"StartTime":163560.0,"EndTime":163560.0,"X":356.0,"Y":280.0}]},{"StartTime":163671.0,"Objects":[{"StartTime":163671.0,"EndTime":163671.0,"X":356.0,"Y":280.0}]},{"StartTime":163782.0,"Objects":[{"StartTime":163782.0,"EndTime":163782.0,"X":356.0,"Y":280.0}]},{"StartTime":163893.0,"Objects":[{"StartTime":163893.0,"EndTime":163893.0,"X":356.0,"Y":280.0}]},{"StartTime":164004.0,"Objects":[{"StartTime":164004.0,"EndTime":164004.0,"X":356.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":164190.0,"EndTime":164190.0,"X":216.722748,"Y":322.381317,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":164337.0,"Objects":[{"StartTime":164337.0,"EndTime":164337.0,"X":124.0,"Y":344.0}]},{"StartTime":164449.0,"Objects":[{"StartTime":164449.0,"EndTime":164449.0,"X":92.0,"Y":256.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":164635.0,"EndTime":164635.0,"X":116.255264,"Y":109.43438,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":164782.0,"Objects":[{"StartTime":164782.0,"EndTime":164782.0,"X":180.0,"Y":184.0}]},{"StartTime":164893.0,"Objects":[{"StartTime":164893.0,"EndTime":164893.0,"X":180.0,"Y":184.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":164968.0,"EndTime":164968.0,"X":264.749634,"Y":177.4808,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":165115.0,"Objects":[{"StartTime":165115.0,"EndTime":165115.0,"X":500.0,"Y":88.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":165301.0,"EndTime":165301.0,"X":345.542877,"Y":109.4133,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":165449.0,"Objects":[{"StartTime":165449.0,"EndTime":165449.0,"X":320.0,"Y":236.0}]},{"StartTime":165560.0,"Objects":[{"StartTime":165560.0,"EndTime":165560.0,"X":320.0,"Y":236.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":165635.0,"EndTime":165635.0,"X":330.12735,"Y":320.394531,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":165782.0,"Objects":[{"StartTime":165782.0,"EndTime":165782.0,"X":432.0,"Y":156.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":165968.0,"EndTime":165968.0,"X":355.944641,"Y":21.43514,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166115.0,"Objects":[{"StartTime":166115.0,"EndTime":166115.0,"X":216.0,"Y":64.0}]},{"StartTime":166226.0,"Objects":[{"StartTime":166226.0,"EndTime":166226.0,"X":216.0,"Y":64.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":166301.0,"EndTime":166301.0,"X":131.188263,"Y":69.65411,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166449.0,"Objects":[{"StartTime":166449.0,"EndTime":166449.0,"X":143.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":166524.0,"EndTime":166524.0,"X":121.902931,"Y":286.720856,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166671.0,"Objects":[{"StartTime":166671.0,"EndTime":166671.0,"X":312.0,"Y":291.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":166746.0,"EndTime":166746.0,"X":233.138763,"Y":269.922852,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166893.0,"Objects":[{"StartTime":166893.0,"EndTime":166893.0,"X":379.0,"Y":185.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":166968.0,"EndTime":166968.0,"X":458.244446,"Y":204.810349,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":167115.0,"Objects":[{"StartTime":167115.0,"EndTime":167115.0,"X":456.0,"Y":64.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":167301.0,"EndTime":167301.0,"X":298.885925,"Y":68.90503,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":167449.0,"Objects":[{"StartTime":167449.0,"EndTime":167449.0,"X":112.0,"Y":148.0}]},{"StartTime":167560.0,"Objects":[{"StartTime":167560.0,"EndTime":167560.0,"X":160.0,"Y":228.0}]},{"StartTime":167671.0,"Objects":[{"StartTime":167671.0,"EndTime":167671.0,"X":248.0,"Y":256.0}]},{"StartTime":167782.0,"Objects":[{"StartTime":167782.0,"EndTime":167782.0,"X":336.0,"Y":228.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":167968.0,"EndTime":167968.0,"X":477.379944,"Y":264.4144,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":168115.0,"Objects":[{"StartTime":168115.0,"EndTime":168115.0,"X":392.0,"Y":308.0}]},{"StartTime":168226.0,"Objects":[{"StartTime":168226.0,"EndTime":168226.0,"X":336.0,"Y":228.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":168301.0,"EndTime":168301.0,"X":332.7332,"Y":143.0628,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":168449.0,"Objects":[{"StartTime":168449.0,"EndTime":168449.0,"X":448.0,"Y":32.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":168524.0,"EndTime":168524.0,"X":451.2668,"Y":116.937195,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":168671.0,"Objects":[{"StartTime":168671.0,"EndTime":168671.0,"X":392.0,"Y":308.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":168857.0,"EndTime":168857.0,"X":238.278824,"Y":295.8506,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":169004.0,"Objects":[{"StartTime":169004.0,"EndTime":169004.0,"X":156.0,"Y":340.0}]},{"StartTime":169115.0,"Objects":[{"StartTime":169115.0,"EndTime":169115.0,"X":88.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":169190.0,"EndTime":169190.0,"X":117.84549,"Y":192.412018,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":169337.0,"Objects":[{"StartTime":169337.0,"EndTime":169337.0,"X":88.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":169523.0,"EndTime":169523.0,"X":241.888382,"Y":84.10678,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":169671.0,"Objects":[{"StartTime":169671.0,"EndTime":169671.0,"X":416.0,"Y":28.0}]},{"StartTime":169782.0,"Objects":[{"StartTime":169782.0,"EndTime":169782.0,"X":360.0,"Y":104.0}]},{"StartTime":169893.0,"Objects":[{"StartTime":169893.0,"EndTime":169893.0,"X":352.0,"Y":196.0}]},{"StartTime":170004.0,"Objects":[{"StartTime":170004.0,"EndTime":170004.0,"X":396.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":170079.0,"EndTime":170079.0,"X":421.4277,"Y":356.52002,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":170226.0,"Objects":[{"StartTime":170226.0,"EndTime":170226.0,"X":272.0,"Y":296.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":170301.0,"EndTime":170301.0,"X":246.572281,"Y":219.47998,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":170449.0,"Objects":[{"StartTime":170449.0,"EndTime":170449.0,"X":68.0,"Y":288.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":170524.0,"EndTime":170524.0,"X":150.606369,"Y":280.9753,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":170671.0,"Objects":[{"StartTime":170671.0,"EndTime":170671.0,"X":324.0,"Y":148.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":170857.0,"EndTime":170857.0,"X":216.197983,"Y":92.1464157,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":171004.0,"Objects":[{"StartTime":171004.0,"EndTime":171004.0,"X":0.0,"Y":244.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":171190.0,"EndTime":171190.0,"X":168.960251,"Y":262.773346,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":171337.0,"Objects":[{"StartTime":171337.0,"EndTime":171337.0,"X":460.0,"Y":240.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":171412.0,"EndTime":171412.0,"X":461.787476,"Y":324.6682,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":171560.0,"Objects":[{"StartTime":171560.0,"EndTime":171560.0,"X":336.0,"Y":284.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":171635.0,"EndTime":171635.0,"X":334.2125,"Y":199.331787,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":171782.0,"Objects":[{"StartTime":171782.0,"EndTime":171782.0,"X":388.0,"Y":40.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":171857.0,"EndTime":171857.0,"X":417.406158,"Y":117.402733,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":172004.0,"Objects":[{"StartTime":172004.0,"EndTime":172004.0,"X":204.0,"Y":80.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":172079.0,"EndTime":172079.0,"X":287.906921,"Y":88.144165,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":172226.0,"Objects":[{"StartTime":172226.0,"EndTime":172226.0,"X":208.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":172301.0,"EndTime":172301.0,"X":124.093079,"Y":183.855835,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":172449.0,"Objects":[{"StartTime":172449.0,"EndTime":172449.0,"X":256.0,"Y":48.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":172524.0,"EndTime":172524.0,"X":339.312347,"Y":63.6145,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":172671.0,"Objects":[{"StartTime":172671.0,"EndTime":172671.0,"X":400.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":172746.0,"EndTime":172746.0,"X":384.385468,"Y":275.312347,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":172893.0,"Objects":[{"StartTime":172893.0,"EndTime":172893.0,"X":256.0,"Y":336.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":172968.0,"EndTime":172968.0,"X":172.687653,"Y":320.3855,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":173115.0,"Objects":[{"StartTime":173115.0,"EndTime":173115.0,"X":112.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":173190.0,"EndTime":173190.0,"X":127.6145,"Y":108.687653,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":173337.0,"Objects":[{"StartTime":173337.0,"EndTime":173337.0,"X":400.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":173412.0,"EndTime":173412.0,"X":384.385468,"Y":275.312347,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":173560.0,"Objects":[{"StartTime":173560.0,"EndTime":173560.0,"X":256.0,"Y":48.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":173635.0,"EndTime":173635.0,"X":339.312347,"Y":63.6145,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":173782.0,"Objects":[{"StartTime":173782.0,"EndTime":173782.0,"X":172.0,"Y":320.0}]},{"StartTime":173893.0,"Objects":[{"StartTime":173893.0,"EndTime":173893.0,"X":117.0,"Y":245.0}]},{"StartTime":174004.0,"Objects":[{"StartTime":174004.0,"EndTime":174004.0,"X":116.0,"Y":153.0}]},{"StartTime":174115.0,"Objects":[{"StartTime":174115.0,"EndTime":174115.0,"X":169.0,"Y":78.0}]},{"StartTime":174226.0,"Objects":[{"StartTime":174226.0,"EndTime":174226.0,"X":256.0,"Y":48.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":174412.0,"EndTime":174412.0,"X":339.468872,"Y":164.666275,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":174560.0,"Objects":[{"StartTime":174560.0,"EndTime":174560.0,"X":168.0,"Y":268.0}]},{"StartTime":174671.0,"Objects":[{"StartTime":174671.0,"EndTime":174671.0,"X":238.0,"Y":207.0}]},{"StartTime":174782.0,"Objects":[{"StartTime":174782.0,"EndTime":174782.0,"X":329.0,"Y":194.0}]},{"StartTime":174893.0,"Objects":[{"StartTime":174893.0,"EndTime":174893.0,"X":413.0,"Y":232.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":175004.0,"EndTime":175004.0,"X":424.06662,"Y":316.27652,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":175079.0,"EndTime":175079.0,"X":413.0,"Y":232.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":175226.0,"Objects":[{"StartTime":175226.0,"EndTime":175226.0,"X":344.0,"Y":150.0}]},{"StartTime":175337.0,"Objects":[{"StartTime":175337.0,"EndTime":175337.0,"X":344.0,"Y":150.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":175412.0,"EndTime":175412.0,"X":260.536621,"Y":133.910675,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":175560.0,"Objects":[{"StartTime":175560.0,"EndTime":175560.0,"X":478.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":175635.0,"EndTime":175635.0,"X":468.068481,"Y":146.417816,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":175782.0,"Objects":[{"StartTime":175782.0,"EndTime":175782.0,"X":322.0,"Y":328.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":175968.0,"EndTime":175968.0,"X":170.064575,"Y":292.1422,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":176115.0,"Objects":[{"StartTime":176115.0,"EndTime":176115.0,"X":50.0,"Y":366.0}]},{"StartTime":176226.0,"Objects":[{"StartTime":176226.0,"EndTime":176226.0,"X":91.0,"Y":283.0}]},{"StartTime":176337.0,"Objects":[{"StartTime":176337.0,"EndTime":176337.0,"X":81.0,"Y":191.0}]},{"StartTime":176449.0,"Objects":[{"StartTime":176449.0,"EndTime":176449.0,"X":24.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":176635.0,"EndTime":176635.0,"X":175.935425,"Y":154.857788,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":176782.0,"Objects":[{"StartTime":176782.0,"EndTime":176782.0,"X":327.0,"Y":79.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":176968.0,"EndTime":176968.0,"X":306.514526,"Y":247.7612,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":177115.0,"Objects":[{"StartTime":177115.0,"EndTime":177115.0,"X":125.0,"Y":323.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":177190.0,"EndTime":177190.0,"X":203.49823,"Y":298.039764,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":177337.0,"Objects":[{"StartTime":177337.0,"EndTime":177337.0,"X":389.0,"Y":256.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":177412.0,"EndTime":177412.0,"X":306.045349,"Y":247.667252,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":177560.0,"Objects":[{"StartTime":177560.0,"EndTime":177560.0,"X":180.0,"Y":72.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":177635.0,"EndTime":177635.0,"X":249.856644,"Y":116.309669,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":177782.0,"Objects":[{"StartTime":177782.0,"EndTime":177782.0,"X":66.0,"Y":257.0}]},{"StartTime":177893.0,"Objects":[{"StartTime":177893.0,"EndTime":177893.0,"X":64.0,"Y":235.0}]},{"StartTime":178004.0,"Objects":[{"StartTime":178004.0,"EndTime":178004.0,"X":63.0,"Y":214.0}]},{"StartTime":178115.0,"Objects":[{"StartTime":178115.0,"EndTime":178115.0,"X":62.0,"Y":193.0}]},{"StartTime":178226.0,"Objects":[{"StartTime":178226.0,"EndTime":178226.0,"X":61.0,"Y":172.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":178412.0,"EndTime":178412.0,"X":146.4032,"Y":243.470139,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":178560.0,"Objects":[{"StartTime":178560.0,"EndTime":178560.0,"X":4.0,"Y":96.0}]},{"StartTime":178671.0,"Objects":[{"StartTime":178671.0,"EndTime":178671.0,"X":81.0,"Y":61.0}]},{"StartTime":178782.0,"Objects":[{"StartTime":178782.0,"EndTime":178782.0,"X":164.0,"Y":73.0}]},{"StartTime":178893.0,"Objects":[{"StartTime":178893.0,"EndTime":178893.0,"X":227.0,"Y":128.0}]},{"StartTime":179004.0,"Objects":[{"StartTime":179004.0,"EndTime":179004.0,"X":251.0,"Y":209.0}]},{"StartTime":179115.0,"Objects":[{"StartTime":179115.0,"EndTime":179115.0,"X":228.0,"Y":289.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":179190.0,"EndTime":179190.0,"X":215.417068,"Y":207.655624,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":179337.0,"Objects":[{"StartTime":179337.0,"EndTime":179337.0,"X":401.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":179523.0,"EndTime":179523.0,"X":254.5407,"Y":108.325722,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":179671.0,"Objects":[{"StartTime":179671.0,"EndTime":179671.0,"X":93.0,"Y":212.0}]},{"StartTime":179782.0,"Objects":[{"StartTime":179782.0,"EndTime":179782.0,"X":93.0,"Y":212.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":179857.0,"EndTime":179857.0,"X":172.022354,"Y":235.615982,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":180004.0,"Objects":[{"StartTime":180004.0,"EndTime":180004.0,"X":334.0,"Y":366.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":180190.0,"EndTime":180190.0,"X":344.786163,"Y":196.393326,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":180337.0,"Objects":[{"StartTime":180337.0,"EndTime":180337.0,"X":311.0,"Y":33.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":180448.0,"EndTime":180448.0,"X":230.004761,"Y":19.62839,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":180523.0,"EndTime":180523.0,"X":311.0,"Y":33.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":180671.0,"Objects":[{"StartTime":180671.0,"EndTime":180671.0,"X":289.0,"Y":212.0}]},{"StartTime":180782.0,"Objects":[{"StartTime":180782.0,"EndTime":180782.0,"X":196.0,"Y":198.0}]},{"StartTime":180893.0,"Objects":[{"StartTime":180893.0,"EndTime":180893.0,"X":255.0,"Y":124.0}]},{"StartTime":181004.0,"Objects":[{"StartTime":181004.0,"EndTime":181004.0,"X":301.0,"Y":221.0}]},{"StartTime":181115.0,"Objects":[{"StartTime":181115.0,"EndTime":181115.0,"X":181.0,"Y":203.0}]},{"StartTime":181226.0,"Objects":[{"StartTime":181226.0,"EndTime":181226.0,"X":257.0,"Y":108.0}]},{"StartTime":181337.0,"Objects":[{"StartTime":181337.0,"EndTime":181337.0,"X":372.0,"Y":147.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":181523.0,"EndTime":181523.0,"X":375.6031,"Y":297.656464,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":181671.0,"Objects":[{"StartTime":181671.0,"EndTime":181671.0,"X":163.0,"Y":238.0}]},{"StartTime":181782.0,"Objects":[{"StartTime":181782.0,"EndTime":181782.0,"X":74.0,"Y":225.0}]},{"StartTime":181893.0,"Objects":[{"StartTime":181893.0,"EndTime":181893.0,"X":18.0,"Y":294.0}]},{"StartTime":182004.0,"Objects":[{"StartTime":182004.0,"EndTime":182004.0,"X":50.0,"Y":378.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":182190.0,"EndTime":182190.0,"X":210.439133,"Y":359.855164,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":182337.0,"Objects":[{"StartTime":182337.0,"EndTime":182337.0,"X":355.0,"Y":315.0}]},{"StartTime":182449.0,"Objects":[{"StartTime":182449.0,"EndTime":182449.0,"X":355.0,"Y":315.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":182524.0,"EndTime":182524.0,"X":349.108246,"Y":231.35257,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":182671.0,"Objects":[{"StartTime":182671.0,"EndTime":182671.0,"X":423.0,"Y":86.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":182746.0,"EndTime":182746.0,"X":428.891754,"Y":169.64743,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":182893.0,"Objects":[{"StartTime":182893.0,"EndTime":182893.0,"X":214.0,"Y":113.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":183079.0,"EndTime":183079.0,"X":46.0509644,"Y":139.327148,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":183226.0,"Objects":[{"StartTime":183226.0,"EndTime":183226.0,"X":181.0,"Y":224.0}]},{"StartTime":183337.0,"Objects":[{"StartTime":183337.0,"EndTime":183337.0,"X":264.0,"Y":237.0}]},{"StartTime":183449.0,"Objects":[{"StartTime":183449.0,"EndTime":183449.0,"X":348.0,"Y":250.0}]},{"StartTime":183560.0,"Objects":[{"StartTime":183560.0,"EndTime":183560.0,"X":431.0,"Y":262.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":183671.0,"EndTime":183671.0,"X":448.007324,"Y":343.90332,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":183746.0,"EndTime":183746.0,"X":431.0,"Y":262.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":183893.0,"Objects":[{"StartTime":183893.0,"EndTime":183893.0,"X":282.0,"Y":68.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":184079.0,"EndTime":184079.0,"X":216.012039,"Y":194.120026,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":184226.0,"Objects":[{"StartTime":184226.0,"EndTime":184226.0,"X":391.0,"Y":175.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":184301.0,"EndTime":184301.0,"X":307.156525,"Y":161.0261,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":184449.0,"Objects":[{"StartTime":184449.0,"EndTime":184449.0,"X":132.0,"Y":298.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":184524.0,"EndTime":184524.0,"X":185.825211,"Y":232.213623,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":184671.0,"Objects":[{"StartTime":184671.0,"EndTime":184671.0,"X":154.0,"Y":12.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":184746.0,"EndTime":184746.0,"X":183.291321,"Y":91.7936,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":184893.0,"Objects":[{"StartTime":184893.0,"EndTime":184893.0,"X":395.0,"Y":82.0}]},{"StartTime":185004.0,"Objects":[{"StartTime":185004.0,"EndTime":185004.0,"X":473.0,"Y":129.0}]},{"StartTime":185115.0,"Objects":[{"StartTime":185115.0,"EndTime":185115.0,"X":391.0,"Y":175.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":185190.0,"EndTime":185190.0,"X":307.55957,"Y":170.7346,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":185337.0,"Objects":[{"StartTime":185337.0,"EndTime":185337.0,"X":105.0,"Y":112.0}]},{"StartTime":185449.0,"Objects":[{"StartTime":185449.0,"EndTime":185449.0,"X":26.0,"Y":158.0}]},{"StartTime":185560.0,"Objects":[{"StartTime":185560.0,"EndTime":185560.0,"X":108.0,"Y":204.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":185635.0,"EndTime":185635.0,"X":191.442719,"Y":198.202209,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":185782.0,"Objects":[{"StartTime":185782.0,"EndTime":185782.0,"X":314.0,"Y":35.0}]},{"StartTime":185893.0,"Objects":[{"StartTime":185893.0,"EndTime":185893.0,"X":230.0,"Y":71.0}]},{"StartTime":186004.0,"Objects":[{"StartTime":186004.0,"EndTime":186004.0,"X":188.0,"Y":153.0}]},{"StartTime":186115.0,"Objects":[{"StartTime":186115.0,"EndTime":186115.0,"X":206.0,"Y":243.0}]},{"StartTime":186226.0,"Objects":[{"StartTime":186226.0,"EndTime":186226.0,"X":277.0,"Y":300.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":186301.0,"EndTime":186301.0,"X":359.753845,"Y":313.858582,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":186449.0,"Objects":[{"StartTime":186449.0,"EndTime":186449.0,"X":469.0,"Y":143.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":186524.0,"EndTime":186524.0,"X":388.1845,"Y":159.058762,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":186671.0,"Objects":[{"StartTime":186671.0,"EndTime":186671.0,"X":180.0,"Y":96.0}]},{"StartTime":186782.0,"Objects":[{"StartTime":186782.0,"EndTime":186782.0,"X":180.0,"Y":96.0}]},{"StartTime":186893.0,"Objects":[{"StartTime":186893.0,"EndTime":186893.0,"X":180.0,"Y":96.0}]},{"StartTime":187115.0,"Objects":[{"StartTime":187115.0,"EndTime":187115.0,"X":333.0,"Y":236.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":187190.0,"EndTime":187190.0,"X":343.066284,"Y":151.598175,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":187337.0,"Objects":[{"StartTime":187337.0,"EndTime":187337.0,"X":404.0,"Y":53.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":187392.0,"EndTime":187392.0,"X":398.1796,"Y":11.2869987,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":187412.0,"EndTime":187412.0,"X":404.0,"Y":53.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":187560.0,"Objects":[{"StartTime":187560.0,"EndTime":187560.0,"X":426.0,"Y":195.0}]},{"StartTime":187671.0,"Objects":[{"StartTime":187671.0,"EndTime":187671.0,"X":426.0,"Y":195.0}]},{"StartTime":187893.0,"Objects":[{"StartTime":187893.0,"EndTime":187893.0,"X":240.0,"Y":159.0}]},{"StartTime":188115.0,"Objects":[{"StartTime":188115.0,"EndTime":188115.0,"X":350.0,"Y":339.0}]},{"StartTime":188449.0,"Objects":[{"StartTime":188449.0,"EndTime":188449.0,"X":70.0,"Y":296.0}]},{"StartTime":195560.0,"Objects":[{"StartTime":195560.0,"EndTime":195560.0,"X":432.0,"Y":192.0}]},{"StartTime":195671.0,"Objects":[{"StartTime":195671.0,"EndTime":195671.0,"X":432.0,"Y":168.0}]},{"StartTime":195782.0,"Objects":[{"StartTime":195782.0,"EndTime":195782.0,"X":424.0,"Y":144.0}]},{"StartTime":195893.0,"Objects":[{"StartTime":195893.0,"EndTime":195893.0,"X":416.0,"Y":120.0}]},{"StartTime":196004.0,"Objects":[{"StartTime":196004.0,"EndTime":196004.0,"X":400.0,"Y":96.0}]},{"StartTime":196115.0,"Objects":[{"StartTime":196115.0,"EndTime":196115.0,"X":384.0,"Y":80.0}]},{"StartTime":196226.0,"Objects":[{"StartTime":196226.0,"EndTime":196226.0,"X":368.0,"Y":64.0}]},{"StartTime":196337.0,"Objects":[{"StartTime":196337.0,"EndTime":196337.0,"X":344.0,"Y":48.0}]},{"StartTime":196449.0,"Objects":[{"StartTime":196449.0,"EndTime":196449.0,"X":320.0,"Y":40.0}]},{"StartTime":196560.0,"Objects":[{"StartTime":196560.0,"EndTime":196560.0,"X":296.0,"Y":40.0}]},{"StartTime":196671.0,"Objects":[{"StartTime":196671.0,"EndTime":196671.0,"X":272.0,"Y":40.0}]},{"StartTime":196782.0,"Objects":[{"StartTime":196782.0,"EndTime":196782.0,"X":248.0,"Y":48.0}]},{"StartTime":196893.0,"Objects":[{"StartTime":196893.0,"EndTime":196893.0,"X":224.0,"Y":64.0}]},{"StartTime":197004.0,"Objects":[{"StartTime":197004.0,"EndTime":197004.0,"X":208.0,"Y":80.0}]},{"StartTime":197115.0,"Objects":[{"StartTime":197115.0,"EndTime":197115.0,"X":192.0,"Y":104.0}]},{"StartTime":197226.0,"Objects":[{"StartTime":197226.0,"EndTime":197226.0,"X":184.0,"Y":128.0}]},{"StartTime":197337.0,"Objects":[{"StartTime":197337.0,"EndTime":197337.0,"X":176.0,"Y":152.0}]},{"StartTime":197449.0,"Objects":[{"StartTime":197449.0,"EndTime":197449.0,"X":160.0,"Y":168.0}]},{"StartTime":197560.0,"Objects":[{"StartTime":197560.0,"EndTime":197560.0,"X":136.0,"Y":184.0}]},{"StartTime":197671.0,"Objects":[{"StartTime":197671.0,"EndTime":197671.0,"X":112.0,"Y":192.0}]},{"StartTime":197782.0,"Objects":[{"StartTime":197782.0,"EndTime":197782.0,"X":96.0,"Y":208.0}]},{"StartTime":197893.0,"Objects":[{"StartTime":197893.0,"EndTime":197893.0,"X":80.0,"Y":232.0}]},{"StartTime":198004.0,"Objects":[{"StartTime":198004.0,"EndTime":198004.0,"X":80.0,"Y":256.0}]},{"StartTime":198115.0,"Objects":[{"StartTime":198115.0,"EndTime":198115.0,"X":88.0,"Y":280.0}]},{"StartTime":198226.0,"Objects":[{"StartTime":198226.0,"EndTime":198226.0,"X":112.0,"Y":296.0}]},{"StartTime":198337.0,"Objects":[{"StartTime":198337.0,"EndTime":198337.0,"X":136.0,"Y":304.0}]},{"StartTime":198449.0,"Objects":[{"StartTime":198449.0,"EndTime":198449.0,"X":160.0,"Y":304.0}]},{"StartTime":198560.0,"Objects":[{"StartTime":198560.0,"EndTime":198560.0,"X":184.0,"Y":296.0}]},{"StartTime":198671.0,"Objects":[{"StartTime":198671.0,"EndTime":198671.0,"X":200.0,"Y":280.0}]},{"StartTime":198782.0,"Objects":[{"StartTime":198782.0,"EndTime":198782.0,"X":224.0,"Y":264.0}]},{"StartTime":198893.0,"Objects":[{"StartTime":198893.0,"EndTime":198893.0,"X":248.0,"Y":256.0}]},{"StartTime":199004.0,"Objects":[{"StartTime":199004.0,"EndTime":199004.0,"X":272.0,"Y":264.0}]},{"StartTime":199115.0,"Objects":[{"StartTime":199115.0,"EndTime":199115.0,"X":296.0,"Y":280.0}]},{"StartTime":199226.0,"Objects":[{"StartTime":199226.0,"EndTime":199226.0,"X":320.0,"Y":288.0}]},{"StartTime":199337.0,"Objects":[{"StartTime":199337.0,"EndTime":199337.0,"X":344.0,"Y":288.0}]},{"StartTime":199449.0,"Objects":[{"StartTime":199449.0,"EndTime":199449.0,"X":368.0,"Y":280.0}]},{"StartTime":199560.0,"Objects":[{"StartTime":199560.0,"EndTime":199560.0,"X":392.0,"Y":264.0}]},{"StartTime":199671.0,"Objects":[{"StartTime":199671.0,"EndTime":199671.0,"X":408.0,"Y":248.0}]},{"StartTime":199782.0,"Objects":[{"StartTime":199782.0,"EndTime":199782.0,"X":424.0,"Y":224.0}]},{"StartTime":199893.0,"Objects":[{"StartTime":199893.0,"EndTime":199893.0,"X":432.0,"Y":200.0}]},{"StartTime":200004.0,"Objects":[{"StartTime":200004.0,"EndTime":200004.0,"X":432.0,"Y":176.0}]},{"StartTime":200115.0,"Objects":[{"StartTime":200115.0,"EndTime":200115.0,"X":424.0,"Y":152.0}]},{"StartTime":200226.0,"Objects":[{"StartTime":200226.0,"EndTime":200226.0,"X":416.0,"Y":128.0}]},{"StartTime":200337.0,"Objects":[{"StartTime":200337.0,"EndTime":200337.0,"X":400.0,"Y":104.0}]},{"StartTime":200449.0,"Objects":[{"StartTime":200449.0,"EndTime":200449.0,"X":384.0,"Y":88.0}]},{"StartTime":200560.0,"Objects":[{"StartTime":200560.0,"EndTime":200560.0,"X":360.0,"Y":72.0}]},{"StartTime":200671.0,"Objects":[{"StartTime":200671.0,"EndTime":200671.0,"X":336.0,"Y":64.0}]},{"StartTime":200782.0,"Objects":[{"StartTime":200782.0,"EndTime":200782.0,"X":312.0,"Y":64.0}]},{"StartTime":200893.0,"Objects":[{"StartTime":200893.0,"EndTime":200893.0,"X":288.0,"Y":72.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":200920.0,"EndTime":200920.0,"X":283.0971,"Y":47.48548,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201004.0,"Objects":[{"StartTime":201004.0,"EndTime":201004.0,"X":264.0,"Y":80.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201031.0,"EndTime":201031.0,"X":259.0971,"Y":55.48548,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201115.0,"Objects":[{"StartTime":201115.0,"EndTime":201115.0,"X":240.0,"Y":88.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201142.0,"EndTime":201142.0,"X":235.097092,"Y":63.48548,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201226.0,"Objects":[{"StartTime":201226.0,"EndTime":201226.0,"X":216.0,"Y":96.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201253.0,"EndTime":201253.0,"X":211.097092,"Y":71.48548,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201337.0,"Objects":[{"StartTime":201337.0,"EndTime":201337.0,"X":192.0,"Y":104.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201364.0,"EndTime":201364.0,"X":187.097092,"Y":79.48548,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201449.0,"Objects":[{"StartTime":201449.0,"EndTime":201449.0,"X":168.0,"Y":112.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201476.0,"EndTime":201476.0,"X":163.097092,"Y":87.48548,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201560.0,"Objects":[{"StartTime":201560.0,"EndTime":201560.0,"X":144.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201587.0,"EndTime":201587.0,"X":139.097092,"Y":95.48548,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201671.0,"Objects":[{"StartTime":201671.0,"EndTime":201671.0,"X":120.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201698.0,"EndTime":201698.0,"X":115.0971,"Y":103.485489,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201782.0,"Objects":[{"StartTime":201782.0,"EndTime":201782.0,"X":96.0,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201809.0,"EndTime":201809.0,"X":84.33103,"Y":113.890381,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201893.0,"Objects":[{"StartTime":201893.0,"EndTime":201893.0,"X":57.0,"Y":173.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201920.0,"EndTime":201920.0,"X":36.010746,"Y":159.418716,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202004.0,"Objects":[{"StartTime":202004.0,"EndTime":202004.0,"X":41.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202031.0,"EndTime":202031.0,"X":16.03119,"Y":222.751556,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202115.0,"Objects":[{"StartTime":202115.0,"EndTime":202115.0,"X":53.0,"Y":277.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202142.0,"EndTime":202142.0,"X":30.6393185,"Y":288.180328,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202226.0,"Objects":[{"StartTime":202226.0,"EndTime":202226.0,"X":90.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202253.0,"EndTime":202253.0,"X":76.13249,"Y":336.80127,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202337.0,"Objects":[{"StartTime":202337.0,"EndTime":202337.0,"X":141.0,"Y":332.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202364.0,"EndTime":202364.0,"X":139.719635,"Y":356.9672,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202449.0,"Objects":[{"StartTime":202449.0,"EndTime":202449.0,"X":194.0,"Y":320.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202476.0,"EndTime":202476.0,"X":205.4337,"Y":342.2322,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202560.0,"Objects":[{"StartTime":202560.0,"EndTime":202560.0,"X":233.0,"Y":283.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202587.0,"EndTime":202587.0,"X":254.091537,"Y":296.421875,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202671.0,"Objects":[{"StartTime":202671.0,"EndTime":202671.0,"X":249.0,"Y":231.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202857.0,"EndTime":202857.0,"X":398.498627,"Y":218.746017,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":203115.0,"Objects":[{"StartTime":203115.0,"EndTime":203115.0,"X":496.0,"Y":104.0}]},{"StartTime":203337.0,"Objects":[{"StartTime":203337.0,"EndTime":203337.0,"X":400.0,"Y":328.0}]},{"StartTime":203449.0,"Objects":[{"StartTime":203449.0,"EndTime":203449.0,"X":400.0,"Y":328.0}]},{"StartTime":203560.0,"Objects":[{"StartTime":203560.0,"EndTime":203560.0,"X":400.0,"Y":328.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":203746.0,"EndTime":203746.0,"X":336.4116,"Y":258.334137,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":203893.0,"Objects":[{"StartTime":203893.0,"EndTime":203893.0,"X":296.0,"Y":104.0}]},{"StartTime":204004.0,"Objects":[{"StartTime":204004.0,"EndTime":204004.0,"X":296.0,"Y":104.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":204079.0,"EndTime":204079.0,"X":345.497467,"Y":111.071068,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":204226.0,"Objects":[{"StartTime":204226.0,"EndTime":204226.0,"X":160.0,"Y":168.0}]},{"StartTime":204337.0,"Objects":[{"StartTime":204337.0,"EndTime":204337.0,"X":160.0,"Y":168.0}]},{"StartTime":204449.0,"Objects":[{"StartTime":204449.0,"EndTime":204449.0,"X":160.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":204635.0,"EndTime":204635.0,"X":66.598465,"Y":180.720764,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":204893.0,"Objects":[{"StartTime":204893.0,"EndTime":204893.0,"X":136.0,"Y":320.0}]},{"StartTime":205115.0,"Objects":[{"StartTime":205115.0,"EndTime":205115.0,"X":304.0,"Y":224.0}]},{"StartTime":205226.0,"Objects":[{"StartTime":205226.0,"EndTime":205226.0,"X":328.0,"Y":224.0}]},{"StartTime":205337.0,"Objects":[{"StartTime":205337.0,"EndTime":205337.0,"X":352.0,"Y":224.0}]},{"StartTime":205560.0,"Objects":[{"StartTime":205560.0,"EndTime":205560.0,"X":464.0,"Y":144.0}]},{"StartTime":205671.0,"Objects":[{"StartTime":205671.0,"EndTime":205671.0,"X":464.0,"Y":144.0}]},{"StartTime":205782.0,"Objects":[{"StartTime":205782.0,"EndTime":205782.0,"X":464.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":205857.0,"EndTime":205857.0,"X":480.1552,"Y":98.39854,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":206004.0,"Objects":[{"StartTime":206004.0,"EndTime":206004.0,"X":400.0,"Y":320.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":206079.0,"EndTime":206079.0,"X":383.8448,"Y":365.601471,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":206226.0,"Objects":[{"StartTime":206226.0,"EndTime":206226.0,"X":304.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":206412.0,"EndTime":206412.0,"X":211.075516,"Y":206.428955,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":206671.0,"Objects":[{"StartTime":206671.0,"EndTime":206671.0,"X":24.0,"Y":296.0}]},{"StartTime":206893.0,"Objects":[{"StartTime":206893.0,"EndTime":206893.0,"X":160.0,"Y":104.0}]},{"StartTime":207115.0,"Objects":[{"StartTime":207115.0,"EndTime":207115.0,"X":248.0,"Y":304.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":207301.0,"EndTime":207301.0,"X":340.9245,"Y":321.571045,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":207782.0,"Objects":[{"StartTime":207782.0,"EndTime":207782.0,"X":340.0,"Y":321.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":207968.0,"EndTime":207968.0,"X":321.571136,"Y":222.712769,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":208226.0,"Objects":[{"StartTime":208226.0,"EndTime":208226.0,"X":376.0,"Y":72.0}]},{"StartTime":208449.0,"Objects":[{"StartTime":208449.0,"EndTime":208449.0,"X":144.0,"Y":152.0}]},{"StartTime":208671.0,"Objects":[{"StartTime":208671.0,"EndTime":208671.0,"X":256.0,"Y":336.0}]},{"StartTime":208893.0,"Objects":[{"StartTime":208893.0,"EndTime":208893.0,"X":272.0,"Y":40.0}]},{"StartTime":209115.0,"Objects":[{"StartTime":209115.0,"EndTime":209115.0,"X":112.0,"Y":304.0}]},{"StartTime":209337.0,"Objects":[{"StartTime":209337.0,"EndTime":209337.0,"X":440.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":209412.0,"EndTime":209412.0,"X":489.739655,"Y":225.6747,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":209560.0,"Objects":[{"StartTime":209560.0,"EndTime":209560.0,"X":440.0,"Y":320.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":209635.0,"EndTime":209635.0,"X":390.260345,"Y":318.325317,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":209782.0,"Objects":[{"StartTime":209782.0,"EndTime":209782.0,"X":248.0,"Y":232.0}]},{"StartTime":209893.0,"Objects":[{"StartTime":209893.0,"EndTime":209893.0,"X":216.0,"Y":216.0}]},{"StartTime":210004.0,"Objects":[{"StartTime":210004.0,"EndTime":210004.0,"X":184.0,"Y":208.0}]},{"StartTime":210115.0,"Objects":[{"StartTime":210115.0,"EndTime":210115.0,"X":152.0,"Y":208.0}]},{"StartTime":210226.0,"Objects":[{"StartTime":210226.0,"EndTime":210226.0,"X":121.0,"Y":223.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":210301.0,"EndTime":210301.0,"X":114.463181,"Y":173.429138,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":210449.0,"Objects":[{"StartTime":210449.0,"EndTime":210449.0,"X":53.0,"Y":84.0}]},{"StartTime":210560.0,"Objects":[{"StartTime":210560.0,"EndTime":210560.0,"X":53.0,"Y":84.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":210746.0,"EndTime":210746.0,"X":149.715561,"Y":70.03106,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":210893.0,"Objects":[{"StartTime":210893.0,"EndTime":210893.0,"X":339.0,"Y":150.0}]},{"StartTime":211004.0,"Objects":[{"StartTime":211004.0,"EndTime":211004.0,"X":339.0,"Y":150.0}]},{"StartTime":211115.0,"Objects":[{"StartTime":211115.0,"EndTime":211115.0,"X":339.0,"Y":150.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":211301.0,"EndTime":211301.0,"X":239.215088,"Y":143.4448,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":211449.0,"Objects":[{"StartTime":211449.0,"EndTime":211449.0,"X":406.0,"Y":107.0}]},{"StartTime":211560.0,"Objects":[{"StartTime":211560.0,"EndTime":211560.0,"X":406.0,"Y":107.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":211857.0,"EndTime":211857.0,"X":400.23468,"Y":244.319275,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":212004.0,"Objects":[{"StartTime":212004.0,"EndTime":212004.0,"X":461.0,"Y":315.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":212079.0,"EndTime":212079.0,"X":510.76535,"Y":310.1617,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":212226.0,"Objects":[{"StartTime":212226.0,"EndTime":212226.0,"X":308.0,"Y":351.0}]},{"StartTime":212337.0,"Objects":[{"StartTime":212337.0,"EndTime":212337.0,"X":308.0,"Y":351.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":212523.0,"EndTime":212523.0,"X":212.197952,"Y":335.321045,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":212671.0,"Objects":[{"StartTime":212671.0,"EndTime":212671.0,"X":64.0,"Y":352.0}]},{"StartTime":212782.0,"Objects":[{"StartTime":212782.0,"EndTime":212782.0,"X":64.0,"Y":352.0}]},{"StartTime":212893.0,"Objects":[{"StartTime":212893.0,"EndTime":212893.0,"X":64.0,"Y":352.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":213079.0,"EndTime":213079.0,"X":91.47211,"Y":255.8476,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":213226.0,"Objects":[{"StartTime":213226.0,"EndTime":213226.0,"X":56.0,"Y":96.0}]},{"StartTime":213337.0,"Objects":[{"StartTime":213337.0,"EndTime":213337.0,"X":56.0,"Y":96.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":213634.0,"EndTime":213634.0,"X":185.197464,"Y":125.872383,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":213782.0,"Objects":[{"StartTime":213782.0,"EndTime":213782.0,"X":232.0,"Y":104.0}]},{"StartTime":213893.0,"Objects":[{"StartTime":213893.0,"EndTime":213893.0,"X":280.0,"Y":80.0}]},{"StartTime":214004.0,"Objects":[{"StartTime":214004.0,"EndTime":214004.0,"X":328.0,"Y":72.0}]},{"StartTime":214115.0,"Objects":[{"StartTime":214115.0,"EndTime":214115.0,"X":376.0,"Y":80.0}]},{"StartTime":214226.0,"Objects":[{"StartTime":214226.0,"EndTime":214226.0,"X":416.0,"Y":104.0}]},{"StartTime":214337.0,"Objects":[{"StartTime":214337.0,"EndTime":214337.0,"X":448.0,"Y":144.0}]},{"StartTime":214449.0,"Objects":[{"StartTime":214449.0,"EndTime":214449.0,"X":456.0,"Y":192.0}]},{"StartTime":214560.0,"Objects":[{"StartTime":214560.0,"EndTime":214560.0,"X":448.0,"Y":240.0}]},{"StartTime":214671.0,"Objects":[{"StartTime":214671.0,"EndTime":214671.0,"X":416.0,"Y":280.0}]},{"StartTime":214782.0,"Objects":[{"StartTime":214782.0,"EndTime":214782.0,"X":376.0,"Y":304.0}]},{"StartTime":214893.0,"Objects":[{"StartTime":214893.0,"EndTime":214893.0,"X":328.0,"Y":312.0}]},{"StartTime":215004.0,"Objects":[{"StartTime":215004.0,"EndTime":215004.0,"X":280.0,"Y":304.0}]},{"StartTime":215115.0,"Objects":[{"StartTime":215115.0,"EndTime":215115.0,"X":240.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":215142.0,"EndTime":215142.0,"X":215.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":215226.0,"Objects":[{"StartTime":215226.0,"EndTime":215226.0,"X":215.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":215253.0,"EndTime":215253.0,"X":190.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":215337.0,"Objects":[{"StartTime":215337.0,"EndTime":215337.0,"X":190.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":215364.0,"EndTime":215364.0,"X":165.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":215449.0,"Objects":[{"StartTime":215449.0,"EndTime":215449.0,"X":165.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":215476.0,"EndTime":215476.0,"X":140.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":215560.0,"Objects":[{"StartTime":215560.0,"EndTime":215560.0,"X":112.0,"Y":280.0}]},{"StartTime":215671.0,"Objects":[{"StartTime":215671.0,"EndTime":215671.0,"X":32.0,"Y":224.0}]},{"StartTime":215782.0,"Objects":[{"StartTime":215782.0,"EndTime":215782.0,"X":120.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":215837.0,"EndTime":215837.0,"X":120.0,"Y":151.22522,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":215857.0,"EndTime":215857.0,"X":120.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":216115.0,"Objects":[{"StartTime":216115.0,"EndTime":216115.0,"X":240.0,"Y":64.0}]},{"StartTime":216337.0,"Objects":[{"StartTime":216337.0,"EndTime":216337.0,"X":344.0,"Y":224.0}]},{"StartTime":216560.0,"Objects":[{"StartTime":216560.0,"EndTime":216560.0,"X":448.0,"Y":32.0}]},{"StartTime":216893.0,"Objects":[{"StartTime":216893.0,"EndTime":216893.0,"X":145.0,"Y":84.0}]},{"StartTime":217115.0,"Objects":[{"StartTime":217115.0,"EndTime":217115.0,"X":198.0,"Y":332.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":217301.0,"EndTime":217301.0,"X":215.926071,"Y":213.346481,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":217449.0,"Objects":[{"StartTime":217449.0,"EndTime":217449.0,"X":308.0,"Y":165.0}]},{"StartTime":217560.0,"Objects":[{"StartTime":217560.0,"EndTime":217560.0,"X":308.0,"Y":165.0}]},{"StartTime":217782.0,"Objects":[{"StartTime":217782.0,"EndTime":217782.0,"X":81.0,"Y":244.0}]},{"StartTime":217893.0,"Objects":[{"StartTime":217893.0,"EndTime":217893.0,"X":76.0,"Y":214.0}]},{"StartTime":218004.0,"Objects":[{"StartTime":218004.0,"EndTime":218004.0,"X":72.0,"Y":184.0}]},{"StartTime":218115.0,"Objects":[{"StartTime":218115.0,"EndTime":218115.0,"X":67.0,"Y":155.0}]},{"StartTime":218226.0,"Objects":[{"StartTime":218226.0,"EndTime":218226.0,"X":63.0,"Y":125.0}]},{"StartTime":218449.0,"Objects":[{"StartTime":218449.0,"EndTime":218449.0,"X":200.0,"Y":49.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":218746.0,"EndTime":218746.0,"X":368.463257,"Y":79.80888,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":218893.0,"Objects":[{"StartTime":218893.0,"EndTime":218893.0,"X":422.0,"Y":36.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219190.0,"EndTime":219190.0,"X":352.063354,"Y":185.676758,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":219337.0,"Objects":[{"StartTime":219337.0,"EndTime":219337.0,"X":512.0,"Y":151.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219412.0,"EndTime":219412.0,"X":452.663818,"Y":142.099579,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":219560.0,"Objects":[{"StartTime":219560.0,"EndTime":219560.0,"X":318.0,"Y":194.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219615.0,"EndTime":219615.0,"X":288.526764,"Y":198.287018,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219671.0,"EndTime":219671.0,"X":317.892822,"Y":194.0156,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219726.0,"EndTime":219726.0,"X":288.4196,"Y":198.3026,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219782.0,"EndTime":219782.0,"X":317.785645,"Y":194.031174,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219801.0,"EndTime":219801.0,"X":288.3124,"Y":198.318192,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":219893.0,"Objects":[{"StartTime":219893.0,"EndTime":219893.0,"X":424.0,"Y":218.0}]},{"StartTime":220004.0,"Objects":[{"StartTime":220004.0,"EndTime":220004.0,"X":426.0,"Y":247.0}]},{"StartTime":220115.0,"Objects":[{"StartTime":220115.0,"EndTime":220115.0,"X":429.0,"Y":276.0}]},{"StartTime":220226.0,"Objects":[{"StartTime":220226.0,"EndTime":220226.0,"X":432.0,"Y":305.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":220634.0,"EndTime":220634.0,"X":203.804153,"Y":317.883484,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":220893.0,"Objects":[{"StartTime":220893.0,"EndTime":220893.0,"X":97.0,"Y":166.0}]},{"StartTime":221115.0,"Objects":[{"StartTime":221115.0,"EndTime":221115.0,"X":269.0,"Y":215.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":221190.0,"EndTime":221190.0,"X":275.707672,"Y":155.376129,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":221337.0,"Objects":[{"StartTime":221337.0,"EndTime":221337.0,"X":159.0,"Y":41.0}]},{"StartTime":221449.0,"Objects":[{"StartTime":221449.0,"EndTime":221449.0,"X":163.0,"Y":78.0}]},{"StartTime":221560.0,"Objects":[{"StartTime":221560.0,"EndTime":221560.0,"X":167.0,"Y":115.0}]},{"StartTime":221671.0,"Objects":[{"StartTime":221671.0,"EndTime":221671.0,"X":171.0,"Y":152.0}]},{"StartTime":221782.0,"Objects":[{"StartTime":221782.0,"EndTime":221782.0,"X":176.0,"Y":189.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":221857.0,"EndTime":221857.0,"X":169.374115,"Y":248.633026,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":222004.0,"Objects":[{"StartTime":222004.0,"EndTime":222004.0,"X":24.0,"Y":352.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":222301.0,"EndTime":222301.0,"X":203.19368,"Y":334.9816,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":222449.0,"Objects":[{"StartTime":222449.0,"EndTime":222449.0,"X":346.0,"Y":297.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":222746.0,"EndTime":222746.0,"X":166.79744,"Y":280.075317,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":222893.0,"Objects":[{"StartTime":222893.0,"EndTime":222893.0,"X":68.0,"Y":237.0}]},{"StartTime":223004.0,"Objects":[{"StartTime":223004.0,"EndTime":223004.0,"X":103.0,"Y":233.0}]},{"StartTime":223115.0,"Objects":[{"StartTime":223115.0,"EndTime":223115.0,"X":139.0,"Y":230.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":223190.0,"EndTime":223190.0,"X":198.678772,"Y":236.2004,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":223337.0,"Objects":[{"StartTime":223337.0,"EndTime":223337.0,"X":377.0,"Y":324.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":223412.0,"EndTime":223412.0,"X":409.919373,"Y":273.837128,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":223560.0,"Objects":[{"StartTime":223560.0,"EndTime":223560.0,"X":278.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":223635.0,"EndTime":223635.0,"X":286.687958,"Y":204.367661,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":223782.0,"Objects":[{"StartTime":223782.0,"EndTime":223782.0,"X":452.0,"Y":83.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":223857.0,"EndTime":223857.0,"X":392.321228,"Y":89.20039,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":224004.0,"Objects":[{"StartTime":224004.0,"EndTime":224004.0,"X":186.0,"Y":134.0}]},{"StartTime":224115.0,"Objects":[{"StartTime":224115.0,"EndTime":224115.0,"X":146.0,"Y":131.0}]},{"StartTime":224226.0,"Objects":[{"StartTime":224226.0,"EndTime":224226.0,"X":109.0,"Y":116.0}]},{"StartTime":224337.0,"Objects":[{"StartTime":224337.0,"EndTime":224337.0,"X":77.0,"Y":92.0}]},{"StartTime":224449.0,"Objects":[{"StartTime":224449.0,"EndTime":224449.0,"X":15.0,"Y":29.0}]},{"StartTime":224560.0,"Objects":[{"StartTime":224560.0,"EndTime":224560.0,"X":11.0,"Y":78.0}]},{"StartTime":224671.0,"Objects":[{"StartTime":224671.0,"EndTime":224671.0,"X":8.0,"Y":128.0}]},{"StartTime":224782.0,"Objects":[{"StartTime":224782.0,"EndTime":224782.0,"X":4.0,"Y":178.0}]},{"StartTime":224893.0,"Objects":[{"StartTime":224893.0,"EndTime":224893.0,"X":89.0,"Y":198.0}]},{"StartTime":225004.0,"Objects":[{"StartTime":225004.0,"EndTime":225004.0,"X":96.0,"Y":237.0}]},{"StartTime":225115.0,"Objects":[{"StartTime":225115.0,"EndTime":225115.0,"X":103.0,"Y":276.0}]},{"StartTime":225226.0,"Objects":[{"StartTime":225226.0,"EndTime":225226.0,"X":111.0,"Y":315.0}]},{"StartTime":225337.0,"Objects":[{"StartTime":225337.0,"EndTime":225337.0,"X":206.0,"Y":281.0}]},{"StartTime":225449.0,"Objects":[{"StartTime":225449.0,"EndTime":225449.0,"X":245.0,"Y":287.0}]},{"StartTime":225560.0,"Objects":[{"StartTime":225560.0,"EndTime":225560.0,"X":285.0,"Y":293.0}]},{"StartTime":225671.0,"Objects":[{"StartTime":225671.0,"EndTime":225671.0,"X":324.0,"Y":299.0}]},{"StartTime":225782.0,"Objects":[{"StartTime":225782.0,"EndTime":225782.0,"X":408.0,"Y":249.0}]},{"StartTime":225893.0,"Objects":[{"StartTime":225893.0,"EndTime":225893.0,"X":373.0,"Y":213.0}]},{"StartTime":226004.0,"Objects":[{"StartTime":226004.0,"EndTime":226004.0,"X":326.0,"Y":200.0}]},{"StartTime":226115.0,"Objects":[{"StartTime":226115.0,"EndTime":226115.0,"X":278.0,"Y":213.0}]},{"StartTime":226226.0,"Objects":[{"StartTime":226226.0,"EndTime":226226.0,"X":206.0,"Y":281.0}]},{"StartTime":226337.0,"Objects":[{"StartTime":226337.0,"EndTime":226337.0,"X":182.0,"Y":237.0}]},{"StartTime":226449.0,"Objects":[{"StartTime":226449.0,"EndTime":226449.0,"X":182.0,"Y":188.0}]},{"StartTime":226560.0,"Objects":[{"StartTime":226560.0,"EndTime":226560.0,"X":207.0,"Y":144.0}]},{"StartTime":226671.0,"Objects":[{"StartTime":226671.0,"EndTime":226671.0,"X":306.0,"Y":164.0}]},{"StartTime":226782.0,"Objects":[{"StartTime":226782.0,"EndTime":226782.0,"X":354.0,"Y":156.0}]},{"StartTime":226893.0,"Objects":[{"StartTime":226893.0,"EndTime":226893.0,"X":392.0,"Y":124.0}]},{"StartTime":227004.0,"Objects":[{"StartTime":227004.0,"EndTime":227004.0,"X":407.0,"Y":77.0}]},{"StartTime":227115.0,"Objects":[{"StartTime":227115.0,"EndTime":227115.0,"X":301.0,"Y":55.0}]},{"StartTime":227226.0,"Objects":[{"StartTime":227226.0,"EndTime":227226.0,"X":303.0,"Y":109.0}]},{"StartTime":227337.0,"Objects":[{"StartTime":227337.0,"EndTime":227337.0,"X":306.0,"Y":164.0}]},{"StartTime":227449.0,"Objects":[{"StartTime":227449.0,"EndTime":227449.0,"X":308.0,"Y":219.0}]},{"StartTime":227560.0,"Objects":[{"StartTime":227560.0,"EndTime":227560.0,"X":360.0,"Y":304.0}]},{"StartTime":227671.0,"Objects":[{"StartTime":227671.0,"EndTime":227671.0,"X":301.0,"Y":297.0}]},{"StartTime":227782.0,"Objects":[{"StartTime":227782.0,"EndTime":227782.0,"X":246.0,"Y":321.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":227857.0,"EndTime":227857.0,"X":187.82814,"Y":324.502777,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":228004.0,"Objects":[{"StartTime":228004.0,"EndTime":228004.0,"X":49.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":228079.0,"EndTime":228079.0,"X":54.65045,"Y":266.733337,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":228226.0,"Objects":[{"StartTime":228226.0,"EndTime":228226.0,"X":208.0,"Y":185.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":228301.0,"EndTime":228301.0,"X":213.650452,"Y":125.266663,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":228449.0,"Objects":[{"StartTime":228449.0,"EndTime":228449.0,"X":44.0,"Y":29.0}]},{"StartTime":228560.0,"Objects":[{"StartTime":228560.0,"EndTime":228560.0,"X":40.0,"Y":58.0}]},{"StartTime":228671.0,"Objects":[{"StartTime":228671.0,"EndTime":228671.0,"X":36.0,"Y":88.0}]},{"StartTime":228782.0,"Objects":[{"StartTime":228782.0,"EndTime":228782.0,"X":32.0,"Y":117.0}]},{"StartTime":228893.0,"Objects":[{"StartTime":228893.0,"EndTime":228893.0,"X":123.0,"Y":105.0}]},{"StartTime":229004.0,"Objects":[{"StartTime":229004.0,"EndTime":229004.0,"X":212.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":229031.0,"EndTime":229031.0,"X":239.085815,"Y":79.10199,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":229115.0,"Objects":[{"StartTime":229115.0,"EndTime":229115.0,"X":260.0,"Y":125.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":229142.0,"EndTime":229142.0,"X":289.9626,"Y":123.501869,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":229226.0,"Objects":[{"StartTime":229226.0,"EndTime":229226.0,"X":282.0,"Y":180.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":229253.0,"EndTime":229253.0,"X":310.3038,"Y":189.94458,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":229337.0,"Objects":[{"StartTime":229337.0,"EndTime":229337.0,"X":269.0,"Y":237.0}]},{"StartTime":229449.0,"Objects":[{"StartTime":229449.0,"EndTime":229449.0,"X":219.0,"Y":237.0}]},{"StartTime":229560.0,"Objects":[{"StartTime":229560.0,"EndTime":229560.0,"X":174.0,"Y":257.0}]},{"StartTime":229671.0,"Objects":[{"StartTime":229671.0,"EndTime":229671.0,"X":142.0,"Y":295.0}]},{"StartTime":229782.0,"Objects":[{"StartTime":229782.0,"EndTime":229782.0,"X":245.0,"Y":353.0}]},{"StartTime":229893.0,"Objects":[{"StartTime":229893.0,"EndTime":229893.0,"X":293.0,"Y":340.0}]},{"StartTime":230004.0,"Objects":[{"StartTime":230004.0,"EndTime":230004.0,"X":342.0,"Y":349.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":230031.0,"EndTime":230031.0,"X":369.574341,"Y":337.182434,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":230115.0,"Objects":[{"StartTime":230115.0,"EndTime":230115.0,"X":383.0,"Y":376.0}]},{"StartTime":230226.0,"Objects":[{"StartTime":230226.0,"EndTime":230226.0,"X":467.0,"Y":284.0}]},{"StartTime":230337.0,"Objects":[{"StartTime":230337.0,"EndTime":230337.0,"X":464.0,"Y":234.0}]},{"StartTime":230449.0,"Objects":[{"StartTime":230449.0,"EndTime":230449.0,"X":461.0,"Y":184.0}]},{"StartTime":230560.0,"Objects":[{"StartTime":230560.0,"EndTime":230560.0,"X":458.0,"Y":134.0}]},{"StartTime":230671.0,"Objects":[{"StartTime":230671.0,"EndTime":230671.0,"X":310.0,"Y":42.0}]},{"StartTime":230782.0,"Objects":[{"StartTime":230782.0,"EndTime":230782.0,"X":300.0,"Y":90.0}]},{"StartTime":230893.0,"Objects":[{"StartTime":230893.0,"EndTime":230893.0,"X":322.0,"Y":133.0}]},{"StartTime":231004.0,"Objects":[{"StartTime":231004.0,"EndTime":231004.0,"X":367.0,"Y":154.0}]},{"StartTime":231115.0,"Objects":[{"StartTime":231115.0,"EndTime":231115.0,"X":458.0,"Y":134.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":231412.0,"EndTime":231412.0,"X":463.8211,"Y":223.811554,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":231782.0,"Objects":[{"StartTime":231782.0,"EndTime":231782.0,"X":369.0,"Y":307.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":232190.0,"EndTime":232190.0,"X":256.358734,"Y":326.1779,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":232449.0,"Objects":[{"StartTime":232449.0,"EndTime":232449.0,"X":137.0,"Y":289.0}]},{"StartTime":232671.0,"Objects":[{"StartTime":232671.0,"EndTime":232671.0,"X":137.0,"Y":289.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":233079.0,"EndTime":233079.0,"X":137.642288,"Y":172.083252,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":233337.0,"Objects":[{"StartTime":233337.0,"EndTime":233337.0,"X":159.0,"Y":135.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":233745.0,"EndTime":233745.0,"X":273.471161,"Y":155.800812,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":234004.0,"Objects":[{"StartTime":234004.0,"EndTime":234004.0,"X":375.0,"Y":81.0}]},{"StartTime":234226.0,"Objects":[{"StartTime":234226.0,"EndTime":234226.0,"X":389.0,"Y":206.0}]},{"StartTime":234449.0,"Objects":[{"StartTime":234449.0,"EndTime":234449.0,"X":273.0,"Y":155.0}]},{"StartTime":235115.0,"Objects":[{"StartTime":235115.0,"EndTime":235115.0,"X":143.0,"Y":320.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":235559.0,"EndTime":235559.0,"X":31.683857,"Y":336.082733,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":235967.0,"EndTime":235967.0,"X":143.0,"Y":320.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":236226.0,"Objects":[{"StartTime":236226.0,"EndTime":236226.0,"X":253.0,"Y":363.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":236634.0,"EndTime":236634.0,"X":258.2222,"Y":244.874435,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":236893.0,"Objects":[{"StartTime":236893.0,"EndTime":236893.0,"X":303.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":237301.0,"EndTime":237301.0,"X":183.374,"Y":198.533188,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":237560.0,"Objects":[{"StartTime":237560.0,"EndTime":237560.0,"X":76.0,"Y":264.0}]},{"StartTime":237782.0,"Objects":[{"StartTime":237782.0,"EndTime":237782.0,"X":48.0,"Y":170.0}]},{"StartTime":238004.0,"Objects":[{"StartTime":238004.0,"EndTime":238004.0,"X":99.0,"Y":88.0}]},{"StartTime":238226.0,"Objects":[{"StartTime":238226.0,"EndTime":238226.0,"X":195.0,"Y":72.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":238523.0,"EndTime":238523.0,"X":282.5216,"Y":88.84021,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":238893.0,"Objects":[{"StartTime":238893.0,"EndTime":238893.0,"X":430.0,"Y":40.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":239301.0,"EndTime":239301.0,"X":448.539764,"Y":158.521881,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":239560.0,"Objects":[{"StartTime":239560.0,"EndTime":239560.0,"X":443.0,"Y":280.0}]},{"StartTime":239782.0,"Objects":[{"StartTime":239782.0,"EndTime":239782.0,"X":340.0,"Y":214.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":240190.0,"EndTime":240190.0,"X":341.869324,"Y":99.87049,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":240449.0,"Objects":[{"StartTime":240449.0,"EndTime":240449.0,"X":430.0,"Y":40.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":240857.0,"EndTime":240857.0,"X":311.672272,"Y":37.1086044,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":241115.0,"Objects":[{"StartTime":241115.0,"EndTime":241115.0,"X":195.0,"Y":72.0}]},{"StartTime":241337.0,"Objects":[{"StartTime":241337.0,"EndTime":241337.0,"X":181.0,"Y":191.0}]},{"StartTime":241560.0,"Objects":[{"StartTime":241560.0,"EndTime":241560.0,"X":291.0,"Y":143.0}]},{"StartTime":241782.0,"Objects":[{"StartTime":241782.0,"EndTime":241782.0,"X":195.0,"Y":72.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":242079.0,"EndTime":242079.0,"X":110.66143,"Y":93.17287,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":242449.0,"Objects":[{"StartTime":242449.0,"EndTime":242449.0,"X":90.0,"Y":271.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":242893.0,"EndTime":242893.0,"X":197.600739,"Y":311.753632,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":243301.0,"EndTime":243301.0,"X":289.959,"Y":243.180267,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":243449.0,"Objects":[{"StartTime":243449.0,"EndTime":243449.0,"X":289.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":243746.0,"EndTime":243746.0,"X":372.825134,"Y":264.0362,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":244004.0,"Objects":[{"StartTime":244004.0,"EndTime":244004.0,"X":465.0,"Y":186.0}]},{"StartTime":244226.0,"Objects":[{"StartTime":244226.0,"EndTime":244226.0,"X":409.0,"Y":80.0}]},{"StartTime":244337.0,"Objects":[{"StartTime":244337.0,"EndTime":244337.0,"X":379.0,"Y":82.0}]},{"StartTime":244449.0,"Objects":[{"StartTime":244449.0,"EndTime":244449.0,"X":349.0,"Y":84.0}]},{"StartTime":244560.0,"Objects":[{"StartTime":244560.0,"EndTime":244560.0,"X":321.0,"Y":87.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":244635.0,"EndTime":244635.0,"X":291.095551,"Y":89.39236,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":244782.0,"Objects":[{"StartTime":244782.0,"EndTime":244782.0,"X":160.0,"Y":48.0}]},{"StartTime":244893.0,"Objects":[{"StartTime":244893.0,"EndTime":244893.0,"X":152.0,"Y":72.0}]},{"StartTime":245004.0,"Objects":[{"StartTime":245004.0,"EndTime":245004.0,"X":144.0,"Y":96.0}]},{"StartTime":245115.0,"Objects":[{"StartTime":245115.0,"EndTime":245115.0,"X":136.0,"Y":120.0}]},{"StartTime":245226.0,"Objects":[{"StartTime":245226.0,"EndTime":245226.0,"X":128.0,"Y":144.0}]},{"StartTime":245337.0,"Objects":[{"StartTime":245337.0,"EndTime":245337.0,"X":72.0,"Y":184.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":245523.0,"EndTime":245523.0,"X":171.634659,"Y":192.540115,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":245671.0,"Objects":[{"StartTime":245671.0,"EndTime":245671.0,"X":208.0,"Y":232.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":245857.0,"EndTime":245857.0,"X":298.983429,"Y":217.017059,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":246004.0,"Objects":[{"StartTime":246004.0,"EndTime":246004.0,"X":320.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":246190.0,"EndTime":246190.0,"X":312.025482,"Y":76.3184738,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":246449.0,"Objects":[{"StartTime":246449.0,"EndTime":246449.0,"X":200.0,"Y":136.0}]},{"StartTime":246671.0,"Objects":[{"StartTime":246671.0,"EndTime":246671.0,"X":304.0,"Y":256.0}]},{"StartTime":246893.0,"Objects":[{"StartTime":246893.0,"EndTime":246893.0,"X":400.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":247079.0,"EndTime":247079.0,"X":499.827454,"Y":114.1278,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":247337.0,"Objects":[{"StartTime":247337.0,"EndTime":247337.0,"X":336.0,"Y":176.0}]},{"StartTime":247449.0,"Objects":[{"StartTime":247449.0,"EndTime":247449.0,"X":336.0,"Y":176.0}]},{"StartTime":247560.0,"Objects":[{"StartTime":247560.0,"EndTime":247560.0,"X":336.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":247746.0,"EndTime":247746.0,"X":244.131042,"Y":160.010208,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":248004.0,"Objects":[{"StartTime":248004.0,"EndTime":248004.0,"X":244.0,"Y":160.0}]},{"StartTime":248226.0,"Objects":[{"StartTime":248226.0,"EndTime":248226.0,"X":80.0,"Y":216.0}]},{"StartTime":248449.0,"Objects":[{"StartTime":248449.0,"EndTime":248449.0,"X":280.0,"Y":256.0}]},{"StartTime":248671.0,"Objects":[{"StartTime":248671.0,"EndTime":248671.0,"X":192.0,"Y":80.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":248857.0,"EndTime":248857.0,"X":192.0,"Y":180.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":249115.0,"Objects":[{"StartTime":249115.0,"EndTime":249115.0,"X":280.0,"Y":256.0}]},{"StartTime":249337.0,"Objects":[{"StartTime":249337.0,"EndTime":249337.0,"X":392.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":249523.0,"EndTime":249523.0,"X":394.638275,"Y":302.004852,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":249782.0,"Objects":[{"StartTime":249782.0,"EndTime":249782.0,"X":280.0,"Y":256.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":249968.0,"EndTime":249968.0,"X":180.172562,"Y":261.8722,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":250226.0,"Objects":[{"StartTime":250226.0,"EndTime":250226.0,"X":72.0,"Y":184.0}]},{"StartTime":250449.0,"Objects":[{"StartTime":250449.0,"EndTime":250449.0,"X":120.0,"Y":80.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":250635.0,"EndTime":250635.0,"X":186.695938,"Y":145.538834,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":250893.0,"Objects":[{"StartTime":250893.0,"EndTime":250893.0,"X":136.0,"Y":280.0}]},{"StartTime":251115.0,"Objects":[{"StartTime":251115.0,"EndTime":251115.0,"X":136.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":251523.0,"EndTime":251523.0,"X":335.862976,"Y":272.597656,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":251782.0,"Objects":[{"StartTime":251782.0,"EndTime":251782.0,"X":416.0,"Y":152.0}]},{"StartTime":252004.0,"Objects":[{"StartTime":252004.0,"EndTime":252004.0,"X":488.0,"Y":80.0}]},{"StartTime":252226.0,"Objects":[{"StartTime":252226.0,"EndTime":252226.0,"X":416.0,"Y":8.0}]},{"StartTime":252449.0,"Objects":[{"StartTime":252449.0,"EndTime":252449.0,"X":344.0,"Y":80.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":252635.0,"EndTime":252635.0,"X":244.25412,"Y":87.1247,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":252782.0,"Objects":[{"StartTime":252782.0,"EndTime":252782.0,"X":192.0,"Y":48.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":252968.0,"EndTime":252968.0,"X":204.3272,"Y":146.078491,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":253115.0,"Objects":[{"StartTime":253115.0,"EndTime":253115.0,"X":152.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":253301.0,"EndTime":253301.0,"X":251.315063,"Y":187.684128,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":253560.0,"Objects":[{"StartTime":253560.0,"EndTime":253560.0,"X":448.0,"Y":176.0}]},{"StartTime":253782.0,"Objects":[{"StartTime":253782.0,"EndTime":253782.0,"X":344.0,"Y":304.0}]},{"StartTime":254004.0,"Objects":[{"StartTime":254004.0,"EndTime":254004.0,"X":272.0,"Y":152.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":254190.0,"EndTime":254190.0,"X":272.0,"Y":52.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":254449.0,"Objects":[{"StartTime":254449.0,"EndTime":254449.0,"X":328.0,"Y":208.0}]},{"StartTime":254671.0,"Objects":[{"StartTime":254671.0,"EndTime":254671.0,"X":328.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":254857.0,"EndTime":254857.0,"X":229.762344,"Y":207.021118,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":255115.0,"Objects":[{"StartTime":255115.0,"EndTime":255115.0,"X":72.0,"Y":288.0}]},{"StartTime":255337.0,"Objects":[{"StartTime":255337.0,"EndTime":255337.0,"X":136.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":255412.0,"EndTime":255412.0,"X":118.443825,"Y":121.18354,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":255560.0,"Objects":[{"StartTime":255560.0,"EndTime":255560.0,"X":216.0,"Y":32.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":255635.0,"EndTime":255635.0,"X":229.736053,"Y":80.0762,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":255782.0,"Objects":[{"StartTime":255782.0,"EndTime":255782.0,"X":328.0,"Y":160.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":255857.0,"EndTime":255857.0,"X":347.088,"Y":113.786926,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":256004.0,"Objects":[{"StartTime":256004.0,"EndTime":256004.0,"X":424.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":256031.0,"EndTime":256031.0,"X":447.717072,"Y":231.9057,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":256115.0,"Objects":[{"StartTime":256115.0,"EndTime":256115.0,"X":390.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":256142.0,"EndTime":256142.0,"X":404.859772,"Y":292.1044,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":256226.0,"Objects":[{"StartTime":256226.0,"EndTime":256226.0,"X":333.0,"Y":291.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":256253.0,"EndTime":256253.0,"X":333.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":256337.0,"Objects":[{"StartTime":256337.0,"EndTime":256337.0,"X":277.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":256364.0,"EndTime":256364.0,"X":262.7234,"Y":292.522644,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":256449.0,"Objects":[{"StartTime":256449.0,"EndTime":256449.0,"X":242.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":256476.0,"EndTime":256476.0,"X":218.375351,"Y":232.177765,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":256560.0,"Objects":[{"StartTime":256560.0,"EndTime":256560.0,"X":224.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":256587.0,"EndTime":256587.0,"X":247.717087,"Y":160.0943,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":256671.0,"Objects":[{"StartTime":256671.0,"EndTime":256671.0,"X":190.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":256698.0,"EndTime":256698.0,"X":204.859772,"Y":99.8956,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":256782.0,"Objects":[{"StartTime":256782.0,"EndTime":256782.0,"X":133.0,"Y":101.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":256809.0,"EndTime":256809.0,"X":133.0,"Y":76.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":256893.0,"Objects":[{"StartTime":256893.0,"EndTime":256893.0,"X":77.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":256920.0,"EndTime":256920.0,"X":62.72339,"Y":99.47737,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":257004.0,"Objects":[{"StartTime":257004.0,"EndTime":257004.0,"X":42.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":257031.0,"EndTime":257031.0,"X":18.375349,"Y":159.822235,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":257115.0,"Objects":[{"StartTime":257115.0,"EndTime":257115.0,"X":42.0,"Y":227.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":257142.0,"EndTime":257142.0,"X":18.282917,"Y":234.9057,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":257226.0,"Objects":[{"StartTime":257226.0,"EndTime":257226.0,"X":76.0,"Y":275.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":257253.0,"EndTime":257253.0,"X":61.14022,"Y":295.1044,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":257337.0,"Objects":[{"StartTime":257337.0,"EndTime":257337.0,"X":133.0,"Y":294.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":257364.0,"EndTime":257364.0,"X":133.0,"Y":319.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":257449.0,"Objects":[{"StartTime":257449.0,"EndTime":257449.0,"X":189.0,"Y":275.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":257476.0,"EndTime":257476.0,"X":203.276611,"Y":295.522644,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":257560.0,"Objects":[{"StartTime":257560.0,"EndTime":257560.0,"X":224.0,"Y":227.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":257587.0,"EndTime":257587.0,"X":247.624649,"Y":235.177765,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":257671.0,"Objects":[{"StartTime":257671.0,"EndTime":257671.0,"X":224.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":257698.0,"EndTime":257698.0,"X":247.624649,"Y":159.822235,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":257782.0,"Objects":[{"StartTime":257782.0,"EndTime":257782.0,"X":190.0,"Y":120.0}]},{"StartTime":257893.0,"Objects":[{"StartTime":257893.0,"EndTime":257893.0,"X":133.0,"Y":101.0}]},{"StartTime":258004.0,"Objects":[{"StartTime":258004.0,"EndTime":258004.0,"X":77.0,"Y":120.0}]},{"StartTime":258226.0,"Objects":[{"StartTime":258226.0,"EndTime":258226.0,"X":224.0,"Y":227.0}]},{"StartTime":258337.0,"Objects":[{"StartTime":258337.0,"EndTime":258337.0,"X":258.0,"Y":275.0}]},{"StartTime":258449.0,"Objects":[{"StartTime":258449.0,"EndTime":258449.0,"X":315.0,"Y":294.0}]},{"StartTime":258560.0,"Objects":[{"StartTime":258560.0,"EndTime":258560.0,"X":371.0,"Y":275.0}]},{"StartTime":258671.0,"Objects":[{"StartTime":258671.0,"EndTime":258671.0,"X":406.0,"Y":227.0}]},{"StartTime":258782.0,"Objects":[{"StartTime":258782.0,"EndTime":258782.0,"X":412.0,"Y":167.0}]},{"StartTime":258893.0,"Objects":[{"StartTime":258893.0,"EndTime":258893.0,"X":391.0,"Y":110.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":259004.0,"EndTime":259004.0,"X":341.4725,"Y":103.142349,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":259079.0,"EndTime":259079.0,"X":391.0,"Y":110.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":259226.0,"Objects":[{"StartTime":259226.0,"EndTime":259226.0,"X":315.0,"Y":194.0}]},{"StartTime":259337.0,"Objects":[{"StartTime":259337.0,"EndTime":259337.0,"X":315.0,"Y":194.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":259412.0,"EndTime":259412.0,"X":265.4725,"Y":200.857651,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":259560.0,"Objects":[{"StartTime":259560.0,"EndTime":259560.0,"X":88.0,"Y":95.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":259746.0,"EndTime":259746.0,"X":237.244583,"Y":76.19726,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":259893.0,"Objects":[{"StartTime":259893.0,"EndTime":259893.0,"X":362.0,"Y":269.0}]},{"StartTime":260004.0,"Objects":[{"StartTime":260004.0,"EndTime":260004.0,"X":272.0,"Y":288.0}]},{"StartTime":260115.0,"Objects":[{"StartTime":260115.0,"EndTime":260115.0,"X":194.0,"Y":241.0}]},{"StartTime":260226.0,"Objects":[{"StartTime":260226.0,"EndTime":260226.0,"X":171.0,"Y":153.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":260337.0,"EndTime":260337.0,"X":177.246231,"Y":68.22981,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":260412.0,"EndTime":260412.0,"X":171.0,"Y":153.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":260560.0,"Objects":[{"StartTime":260560.0,"EndTime":260560.0,"X":106.0,"Y":216.0}]},{"StartTime":260671.0,"Objects":[{"StartTime":260671.0,"EndTime":260671.0,"X":24.0,"Y":177.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":260746.0,"EndTime":260746.0,"X":29.0505848,"Y":261.849823,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":260893.0,"Objects":[{"StartTime":260893.0,"EndTime":260893.0,"X":165.0,"Y":349.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":260968.0,"EndTime":260968.0,"X":169.991379,"Y":264.146667,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":261115.0,"Objects":[{"StartTime":261115.0,"EndTime":261115.0,"X":394.0,"Y":84.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":261301.0,"EndTime":261301.0,"X":261.752472,"Y":137.17804,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":261449.0,"Objects":[{"StartTime":261449.0,"EndTime":261449.0,"X":394.0,"Y":84.0}]},{"StartTime":261560.0,"Objects":[{"StartTime":261560.0,"EndTime":261560.0,"X":425.0,"Y":169.0}]},{"StartTime":261671.0,"Objects":[{"StartTime":261671.0,"EndTime":261671.0,"X":388.0,"Y":252.0}]},{"StartTime":261782.0,"Objects":[{"StartTime":261782.0,"EndTime":261782.0,"X":303.0,"Y":285.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":261893.0,"EndTime":261893.0,"X":223.041077,"Y":263.3701,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":261968.0,"EndTime":261968.0,"X":303.0,"Y":285.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":262115.0,"Objects":[{"StartTime":262115.0,"EndTime":262115.0,"X":454.0,"Y":347.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":262301.0,"EndTime":262301.0,"X":462.396332,"Y":177.207474,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":262449.0,"Objects":[{"StartTime":262449.0,"EndTime":262449.0,"X":297.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":262524.0,"EndTime":262524.0,"X":309.2367,"Y":137.393311,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":262671.0,"Objects":[{"StartTime":262671.0,"EndTime":262671.0,"X":491.0,"Y":104.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":262746.0,"EndTime":262746.0,"X":410.68988,"Y":116.735062,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":262893.0,"Objects":[{"StartTime":262893.0,"EndTime":262893.0,"X":223.0,"Y":263.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":262968.0,"EndTime":262968.0,"X":216.6031,"Y":178.241058,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":263115.0,"Objects":[{"StartTime":263115.0,"EndTime":263115.0,"X":68.0,"Y":53.0}]},{"StartTime":263226.0,"Objects":[{"StartTime":263226.0,"EndTime":263226.0,"X":89.0,"Y":55.0}]},{"StartTime":263337.0,"Objects":[{"StartTime":263337.0,"EndTime":263337.0,"X":110.0,"Y":57.0}]},{"StartTime":263449.0,"Objects":[{"StartTime":263449.0,"EndTime":263449.0,"X":131.0,"Y":60.0}]},{"StartTime":263560.0,"Objects":[{"StartTime":263560.0,"EndTime":263560.0,"X":152.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":263746.0,"EndTime":263746.0,"X":283.057373,"Y":137.823868,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":263893.0,"Objects":[{"StartTime":263893.0,"EndTime":263893.0,"X":87.0,"Y":182.0}]},{"StartTime":264004.0,"Objects":[{"StartTime":264004.0,"EndTime":264004.0,"X":87.0,"Y":182.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":264190.0,"EndTime":264190.0,"X":45.0181046,"Y":329.32666,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":264337.0,"Objects":[{"StartTime":264337.0,"EndTime":264337.0,"X":269.0,"Y":306.0}]},{"StartTime":264449.0,"Objects":[{"StartTime":264449.0,"EndTime":264449.0,"X":269.0,"Y":306.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":264524.0,"EndTime":264524.0,"X":185.536621,"Y":289.910675,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":264671.0,"Objects":[{"StartTime":264671.0,"EndTime":264671.0,"X":283.0,"Y":137.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":264857.0,"EndTime":264857.0,"X":364.216919,"Y":176.3499,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":265004.0,"Objects":[{"StartTime":265004.0,"EndTime":265004.0,"X":165.0,"Y":193.0}]},{"StartTime":265115.0,"Objects":[{"StartTime":265115.0,"EndTime":265115.0,"X":165.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":265190.0,"EndTime":265190.0,"X":154.887192,"Y":110.947647,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":265337.0,"Objects":[{"StartTime":265337.0,"EndTime":265337.0,"X":299.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":265448.0,"EndTime":265448.0,"X":380.8016,"Y":271.549866,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":265523.0,"EndTime":265523.0,"X":299.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":265671.0,"Objects":[{"StartTime":265671.0,"EndTime":265671.0,"X":428.0,"Y":374.0}]},{"StartTime":265782.0,"Objects":[{"StartTime":265782.0,"EndTime":265782.0,"X":487.0,"Y":305.0}]},{"StartTime":265893.0,"Objects":[{"StartTime":265893.0,"EndTime":265893.0,"X":476.0,"Y":215.0}]},{"StartTime":266004.0,"Objects":[{"StartTime":266004.0,"EndTime":266004.0,"X":396.0,"Y":164.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":266079.0,"EndTime":266079.0,"X":311.5542,"Y":173.6905,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":266226.0,"Objects":[{"StartTime":266226.0,"EndTime":266226.0,"X":193.0,"Y":245.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":266301.0,"EndTime":266301.0,"X":108.582191,"Y":235.0685,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":266449.0,"Objects":[{"StartTime":266449.0,"EndTime":266449.0,"X":210.0,"Y":73.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":266524.0,"EndTime":266524.0,"X":291.8972,"Y":59.86789,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":266671.0,"Objects":[{"StartTime":266671.0,"EndTime":266671.0,"X":438.0,"Y":263.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":266857.0,"EndTime":266857.0,"X":334.252533,"Y":211.5238,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":267004.0,"Objects":[{"StartTime":267004.0,"EndTime":267004.0,"X":153.0,"Y":138.0}]},{"StartTime":267115.0,"Objects":[{"StartTime":267115.0,"EndTime":267115.0,"X":66.0,"Y":161.0}]},{"StartTime":267226.0,"Objects":[{"StartTime":267226.0,"EndTime":267226.0,"X":34.0,"Y":245.0}]},{"StartTime":267337.0,"Objects":[{"StartTime":267337.0,"EndTime":267337.0,"X":84.0,"Y":319.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":267523.0,"EndTime":267523.0,"X":253.51619,"Y":307.162628,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":267671.0,"Objects":[{"StartTime":267671.0,"EndTime":267671.0,"X":334.0,"Y":211.0}]},{"StartTime":267782.0,"Objects":[{"StartTime":267782.0,"EndTime":267782.0,"X":334.0,"Y":211.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":267857.0,"EndTime":267857.0,"X":333.140472,"Y":128.340088,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":268004.0,"Objects":[{"StartTime":268004.0,"EndTime":268004.0,"X":458.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":268079.0,"EndTime":268079.0,"X":458.859528,"Y":159.659912,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":268226.0,"Objects":[{"StartTime":268226.0,"EndTime":268226.0,"X":321.0,"Y":354.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":268412.0,"EndTime":268412.0,"X":169.8029,"Y":312.272034,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":268560.0,"Objects":[{"StartTime":268560.0,"EndTime":268560.0,"X":34.0,"Y":201.0}]},{"StartTime":268671.0,"Objects":[{"StartTime":268671.0,"EndTime":268671.0,"X":34.0,"Y":202.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":268746.0,"EndTime":268746.0,"X":118.7002,"Y":194.867355,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":268893.0,"Objects":[{"StartTime":268893.0,"EndTime":268893.0,"X":263.0,"Y":87.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":269079.0,"EndTime":269079.0,"X":129.963287,"Y":152.665192,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":269226.0,"Objects":[{"StartTime":269226.0,"EndTime":269226.0,"X":326.0,"Y":305.0}]},{"StartTime":269337.0,"Objects":[{"StartTime":269337.0,"EndTime":269337.0,"X":334.0,"Y":211.0}]},{"StartTime":269449.0,"Objects":[{"StartTime":269449.0,"EndTime":269449.0,"X":343.0,"Y":118.0}]},{"StartTime":269560.0,"Objects":[{"StartTime":269560.0,"EndTime":269560.0,"X":352.0,"Y":25.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":269635.0,"EndTime":269635.0,"X":362.0481,"Y":109.404,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":269782.0,"Objects":[{"StartTime":269782.0,"EndTime":269782.0,"X":223.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":269857.0,"EndTime":269857.0,"X":211.963272,"Y":260.280426,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":270004.0,"Objects":[{"StartTime":270004.0,"EndTime":270004.0,"X":446.0,"Y":266.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":270079.0,"EndTime":270079.0,"X":370.290771,"Y":233.114441,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":270226.0,"Objects":[{"StartTime":270226.0,"EndTime":270226.0,"X":113.0,"Y":288.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":270412.0,"EndTime":270412.0,"X":70.50296,"Y":137.697678,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":270560.0,"Objects":[{"StartTime":270560.0,"EndTime":270560.0,"X":165.0,"Y":55.0}]},{"StartTime":270671.0,"Objects":[{"StartTime":270671.0,"EndTime":270671.0,"X":232.0,"Y":116.0}]},{"StartTime":270782.0,"Objects":[{"StartTime":270782.0,"EndTime":270782.0,"X":323.0,"Y":130.0}]},{"StartTime":270893.0,"Objects":[{"StartTime":270893.0,"EndTime":270893.0,"X":407.0,"Y":90.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":270968.0,"EndTime":270968.0,"X":433.0655,"Y":169.055984,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":271115.0,"Objects":[{"StartTime":271115.0,"EndTime":271115.0,"X":317.0,"Y":319.0}]},{"StartTime":271226.0,"Objects":[{"StartTime":271226.0,"EndTime":271226.0,"X":317.0,"Y":225.0}]},{"StartTime":271337.0,"Objects":[{"StartTime":271337.0,"EndTime":271337.0,"X":406.0,"Y":196.0}]},{"StartTime":271449.0,"Objects":[{"StartTime":271449.0,"EndTime":271449.0,"X":460.0,"Y":272.0}]},{"StartTime":271560.0,"Objects":[{"StartTime":271560.0,"EndTime":271560.0,"X":406.0,"Y":348.0}]},{"StartTime":271671.0,"Objects":[{"StartTime":271671.0,"EndTime":271671.0,"X":317.0,"Y":319.0}]},{"StartTime":271782.0,"Objects":[{"StartTime":271782.0,"EndTime":271782.0,"X":224.0,"Y":303.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":271857.0,"EndTime":271857.0,"X":143.480118,"Y":319.5775,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":272004.0,"Objects":[{"StartTime":272004.0,"EndTime":272004.0,"X":43.0,"Y":164.0}]},{"StartTime":272115.0,"Objects":[{"StartTime":272115.0,"EndTime":272115.0,"X":127.0,"Y":124.0}]},{"StartTime":272226.0,"Objects":[{"StartTime":272226.0,"EndTime":272226.0,"X":117.0,"Y":217.0}]},{"StartTime":272337.0,"Objects":[{"StartTime":272337.0,"EndTime":272337.0,"X":43.0,"Y":164.0}]},{"StartTime":272449.0,"Objects":[{"StartTime":272449.0,"EndTime":272449.0,"X":77.0,"Y":48.0}]},{"StartTime":272560.0,"Objects":[{"StartTime":272560.0,"EndTime":272560.0,"X":157.0,"Y":138.0}]},{"StartTime":272671.0,"Objects":[{"StartTime":272671.0,"EndTime":272671.0,"X":43.0,"Y":164.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":272746.0,"EndTime":272746.0,"X":54.0161133,"Y":82.89177,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":272893.0,"Objects":[{"StartTime":272893.0,"EndTime":272893.0,"X":279.0,"Y":26.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":272968.0,"EndTime":272968.0,"X":363.774475,"Y":19.8120823,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":273115.0,"Objects":[{"StartTime":273115.0,"EndTime":273115.0,"X":504.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":273190.0,"EndTime":273190.0,"X":419.225525,"Y":126.18792,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":273337.0,"Objects":[{"StartTime":273337.0,"EndTime":273337.0,"X":176.0,"Y":120.0}]},{"StartTime":273449.0,"Objects":[{"StartTime":273449.0,"EndTime":273449.0,"X":216.0,"Y":208.0}]},{"StartTime":273560.0,"Objects":[{"StartTime":273560.0,"EndTime":273560.0,"X":184.0,"Y":296.0}]},{"StartTime":273671.0,"Objects":[{"StartTime":273671.0,"EndTime":273671.0,"X":112.0,"Y":352.0}]},{"StartTime":273782.0,"Objects":[{"StartTime":273782.0,"EndTime":273782.0,"X":16.0,"Y":344.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":273968.0,"EndTime":273968.0,"X":185.499268,"Y":330.9616,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":274115.0,"Objects":[{"StartTime":274115.0,"EndTime":274115.0,"X":464.0,"Y":288.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":274301.0,"EndTime":274301.0,"X":308.81308,"Y":276.728546,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":274449.0,"Objects":[{"StartTime":274449.0,"EndTime":274449.0,"X":105.0,"Y":186.0}]},{"StartTime":274560.0,"Objects":[{"StartTime":274560.0,"EndTime":274560.0,"X":143.0,"Y":95.0}]},{"StartTime":274671.0,"Objects":[{"StartTime":274671.0,"EndTime":274671.0,"X":233.0,"Y":58.0}]},{"StartTime":274782.0,"Objects":[{"StartTime":274782.0,"EndTime":274782.0,"X":324.0,"Y":95.0}]},{"StartTime":274893.0,"Objects":[{"StartTime":274893.0,"EndTime":274893.0,"X":361.0,"Y":186.0}]},{"StartTime":275004.0,"Objects":[{"StartTime":275004.0,"EndTime":275004.0,"X":324.0,"Y":276.0}]},{"StartTime":275115.0,"Objects":[{"StartTime":275115.0,"EndTime":275115.0,"X":233.0,"Y":314.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":275190.0,"EndTime":275190.0,"X":148.138428,"Y":318.849243,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":275337.0,"Objects":[{"StartTime":275337.0,"EndTime":275337.0,"X":0.0,"Y":216.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":275523.0,"EndTime":275523.0,"X":150.724564,"Y":185.118958,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":275671.0,"Objects":[{"StartTime":275671.0,"EndTime":275671.0,"X":324.0,"Y":276.0}]},{"StartTime":275782.0,"Objects":[{"StartTime":275782.0,"EndTime":275782.0,"X":392.0,"Y":336.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":275857.0,"EndTime":275857.0,"X":414.065216,"Y":257.376373,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":276004.0,"Objects":[{"StartTime":276004.0,"EndTime":276004.0,"X":320.0,"Y":155.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":276190.0,"EndTime":276190.0,"X":323.856537,"Y":275.96756,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":276337.0,"Objects":[{"StartTime":276337.0,"EndTime":276337.0,"X":424.0,"Y":368.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":276523.0,"EndTime":276523.0,"X":455.809052,"Y":201.002441,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":276671.0,"Objects":[{"StartTime":276671.0,"EndTime":276671.0,"X":360.0,"Y":24.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":276746.0,"EndTime":276746.0,"X":373.959381,"Y":100.147621,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":276893.0,"Objects":[{"StartTime":276893.0,"EndTime":276893.0,"X":232.0,"Y":112.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":276968.0,"EndTime":276968.0,"X":155.852371,"Y":125.959389,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":277115.0,"Objects":[{"StartTime":277115.0,"EndTime":277115.0,"X":200.0,"Y":296.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":277190.0,"EndTime":277190.0,"X":213.959381,"Y":219.852386,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":277337.0,"Objects":[{"StartTime":277337.0,"EndTime":277337.0,"X":360.0,"Y":144.0}]},{"StartTime":277449.0,"Objects":[{"StartTime":277449.0,"EndTime":277449.0,"X":360.0,"Y":144.0}]},{"StartTime":277560.0,"Objects":[{"StartTime":277560.0,"EndTime":277560.0,"X":360.0,"Y":144.0}]},{"StartTime":277671.0,"Objects":[{"StartTime":277671.0,"EndTime":277671.0,"X":360.0,"Y":144.0}]},{"StartTime":277782.0,"Objects":[{"StartTime":277782.0,"EndTime":277782.0,"X":360.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":277968.0,"EndTime":277968.0,"X":338.012329,"Y":312.572083,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":278115.0,"Objects":[{"StartTime":278115.0,"EndTime":278115.0,"X":256.0,"Y":352.0}]},{"StartTime":278226.0,"Objects":[{"StartTime":278226.0,"EndTime":278226.0,"X":168.0,"Y":328.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":278412.0,"EndTime":278412.0,"X":307.0137,"Y":274.775055,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":278560.0,"Objects":[{"StartTime":278560.0,"EndTime":278560.0,"X":184.0,"Y":352.0}]},{"StartTime":278671.0,"Objects":[{"StartTime":278671.0,"EndTime":278671.0,"X":184.0,"Y":352.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":278746.0,"EndTime":278746.0,"X":99.25037,"Y":358.5192,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":278893.0,"Objects":[{"StartTime":278893.0,"EndTime":278893.0,"X":307.0,"Y":274.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":279079.0,"EndTime":279079.0,"X":463.852173,"Y":278.797729,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":279226.0,"Objects":[{"StartTime":279226.0,"EndTime":279226.0,"X":504.0,"Y":136.0}]},{"StartTime":279337.0,"Objects":[{"StartTime":279337.0,"EndTime":279337.0,"X":504.0,"Y":137.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":279412.0,"EndTime":279412.0,"X":419.892517,"Y":124.714638,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":279560.0,"Objects":[{"StartTime":279560.0,"EndTime":279560.0,"X":232.0,"Y":64.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":279746.0,"EndTime":279746.0,"X":253.175323,"Y":199.085159,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":279893.0,"Objects":[{"StartTime":279893.0,"EndTime":279893.0,"X":488.0,"Y":264.0}]},{"StartTime":280004.0,"Objects":[{"StartTime":280004.0,"EndTime":280004.0,"X":400.0,"Y":232.0}]},{"StartTime":280115.0,"Objects":[{"StartTime":280115.0,"EndTime":280115.0,"X":312.0,"Y":256.0}]},{"StartTime":280226.0,"Objects":[{"StartTime":280226.0,"EndTime":280226.0,"X":248.0,"Y":320.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":280301.0,"EndTime":280301.0,"X":317.7344,"Y":353.346619,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":280449.0,"Objects":[{"StartTime":280449.0,"EndTime":280449.0,"X":120.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":280524.0,"EndTime":280524.0,"X":35.29361,"Y":272.941132,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":280671.0,"Objects":[{"StartTime":280671.0,"EndTime":280671.0,"X":216.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":280746.0,"EndTime":280746.0,"X":298.602722,"Y":192.804947,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":280893.0,"Objects":[{"StartTime":280893.0,"EndTime":280893.0,"X":160.0,"Y":104.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":281079.0,"EndTime":281079.0,"X":16.4957943,"Y":98.49811,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":281226.0,"Objects":[{"StartTime":281226.0,"EndTime":281226.0,"X":201.0,"Y":22.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":281412.0,"EndTime":281412.0,"X":215.117737,"Y":191.412781,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":281560.0,"Objects":[{"StartTime":281560.0,"EndTime":281560.0,"X":376.0,"Y":336.0}]},{"StartTime":281671.0,"Objects":[{"StartTime":281671.0,"EndTime":281671.0,"X":416.0,"Y":248.0}]},{"StartTime":281782.0,"Objects":[{"StartTime":281782.0,"EndTime":281782.0,"X":320.0,"Y":264.0}]},{"StartTime":281893.0,"Objects":[{"StartTime":281893.0,"EndTime":281893.0,"X":376.0,"Y":336.0}]},{"StartTime":282004.0,"Objects":[{"StartTime":282004.0,"EndTime":282004.0,"X":416.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":282079.0,"EndTime":282079.0,"X":420.598755,"Y":163.365021,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":282226.0,"Objects":[{"StartTime":282226.0,"EndTime":282226.0,"X":312.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":282301.0,"EndTime":282301.0,"X":306.3983,"Y":140.4634,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":282449.0,"Objects":[{"StartTime":282449.0,"EndTime":282449.0,"X":200.0,"Y":256.0}]},{"StartTime":282560.0,"Objects":[{"StartTime":282560.0,"EndTime":282560.0,"X":185.0,"Y":163.0}]},{"StartTime":282671.0,"Objects":[{"StartTime":282671.0,"EndTime":282671.0,"X":92.0,"Y":148.0}]},{"StartTime":282782.0,"Objects":[{"StartTime":282782.0,"EndTime":282782.0,"X":51.0,"Y":231.0}]},{"StartTime":282893.0,"Objects":[{"StartTime":282893.0,"EndTime":282893.0,"X":116.0,"Y":298.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":282968.0,"EndTime":282968.0,"X":200.88652,"Y":302.3907,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":283115.0,"Objects":[{"StartTime":283115.0,"EndTime":283115.0,"X":448.0,"Y":264.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":283301.0,"EndTime":283301.0,"X":290.477661,"Y":254.583908,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":283449.0,"Objects":[{"StartTime":283449.0,"EndTime":283449.0,"X":368.0,"Y":328.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":283635.0,"EndTime":283635.0,"X":385.492859,"Y":158.90239,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":283782.0,"Objects":[{"StartTime":283782.0,"EndTime":283782.0,"X":288.0,"Y":32.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":283857.0,"EndTime":283857.0,"X":298.542938,"Y":116.34362,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":284004.0,"Objects":[{"StartTime":284004.0,"EndTime":284004.0,"X":185.0,"Y":163.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":284079.0,"EndTime":284079.0,"X":136.88089,"Y":92.9318161,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":284226.0,"Objects":[{"StartTime":284226.0,"EndTime":284226.0,"X":51.0,"Y":231.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":284301.0,"EndTime":284301.0,"X":132.353348,"Y":255.629913,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":284449.0,"Objects":[{"StartTime":284449.0,"EndTime":284449.0,"X":360.0,"Y":336.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":284476.0,"EndTime":284476.0,"X":401.231049,"Y":346.30777,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":284560.0,"Objects":[{"StartTime":284560.0,"EndTime":284560.0,"X":384.0,"Y":304.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":284587.0,"EndTime":284587.0,"X":424.864777,"Y":315.675659,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":284671.0,"Objects":[{"StartTime":284671.0,"EndTime":284671.0,"X":408.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":284698.0,"EndTime":284698.0,"X":449.231049,"Y":282.30777,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":284782.0,"Objects":[{"StartTime":284782.0,"EndTime":284782.0,"X":432.0,"Y":240.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":284809.0,"EndTime":284809.0,"X":473.231049,"Y":250.30777,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":284893.0,"Objects":[{"StartTime":284893.0,"EndTime":284893.0,"X":376.0,"Y":160.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":284920.0,"EndTime":284920.0,"X":334.768951,"Y":170.30777,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":285004.0,"Objects":[{"StartTime":285004.0,"EndTime":285004.0,"X":352.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":285031.0,"EndTime":285031.0,"X":311.135223,"Y":139.675644,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":285115.0,"Objects":[{"StartTime":285115.0,"EndTime":285115.0,"X":328.0,"Y":96.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":285142.0,"EndTime":285142.0,"X":286.768951,"Y":106.307762,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":285226.0,"Objects":[{"StartTime":285226.0,"EndTime":285226.0,"X":304.0,"Y":64.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":285253.0,"EndTime":285253.0,"X":262.768951,"Y":74.30776,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":285337.0,"Objects":[{"StartTime":285337.0,"EndTime":285337.0,"X":160.0,"Y":64.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":285364.0,"EndTime":285364.0,"X":160.0,"Y":21.5,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":285449.0,"Objects":[{"StartTime":285449.0,"EndTime":285449.0,"X":112.0,"Y":88.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":285476.0,"EndTime":285476.0,"X":81.94796,"Y":57.94796,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":285560.0,"Objects":[{"StartTime":285560.0,"EndTime":285560.0,"X":84.0,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":285587.0,"EndTime":285587.0,"X":41.5,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":285671.0,"Objects":[{"StartTime":285671.0,"EndTime":285671.0,"X":84.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":285698.0,"EndTime":285698.0,"X":53.5699921,"Y":221.66925,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":285782.0,"Objects":[{"StartTime":285782.0,"EndTime":285782.0,"X":176.0,"Y":292.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":285809.0,"EndTime":285809.0,"X":176.0,"Y":334.5,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":285893.0,"Objects":[{"StartTime":285893.0,"EndTime":285893.0,"X":216.0,"Y":264.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":285920.0,"EndTime":285920.0,"X":246.052032,"Y":294.052032,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":286004.0,"Objects":[{"StartTime":286004.0,"EndTime":286004.0,"X":240.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":286031.0,"EndTime":286031.0,"X":282.5,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":286115.0,"Objects":[{"StartTime":286115.0,"EndTime":286115.0,"X":252.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":286142.0,"EndTime":286142.0,"X":281.66925,"Y":145.569992,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":286226.0,"Objects":[{"StartTime":286226.0,"EndTime":286226.0,"X":164.0,"Y":104.0}]},{"StartTime":286337.0,"Objects":[{"StartTime":286337.0,"EndTime":286337.0,"X":84.0,"Y":136.0}]},{"StartTime":286449.0,"Objects":[{"StartTime":286449.0,"EndTime":286449.0,"X":52.0,"Y":216.0}]},{"StartTime":286671.0,"Objects":[{"StartTime":286671.0,"EndTime":286671.0,"X":216.0,"Y":264.0}]},{"StartTime":286782.0,"Objects":[{"StartTime":286782.0,"EndTime":286782.0,"X":248.0,"Y":184.0}]},{"StartTime":286893.0,"Objects":[{"StartTime":286893.0,"EndTime":286893.0,"X":328.0,"Y":152.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":286948.0,"EndTime":286948.0,"X":328.0,"Y":109.882881,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":286968.0,"EndTime":286968.0,"X":328.0,"Y":152.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":287115.0,"Objects":[{"StartTime":287115.0,"EndTime":287115.0,"X":400.0,"Y":184.0}]},{"StartTime":287226.0,"Objects":[{"StartTime":287226.0,"EndTime":287226.0,"X":440.0,"Y":264.0}]},{"StartTime":287449.0,"Objects":[{"StartTime":287449.0,"EndTime":287449.0,"X":440.0,"Y":280.0}]},{"StartTime":287671.0,"Objects":[{"StartTime":287671.0,"EndTime":287671.0,"X":440.0,"Y":296.0}]},{"StartTime":288004.0,"Objects":[{"StartTime":288004.0,"EndTime":288004.0,"X":160.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":288190.0,"EndTime":288190.0,"X":308.9553,"Y":158.327332,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":288337.0,"Objects":[{"StartTime":288337.0,"EndTime":288337.0,"X":335.0,"Y":290.0}]},{"StartTime":288449.0,"Objects":[{"StartTime":288449.0,"EndTime":288449.0,"X":335.0,"Y":290.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":288524.0,"EndTime":288524.0,"X":260.534241,"Y":281.064117,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":288671.0,"Objects":[{"StartTime":288671.0,"EndTime":288671.0,"X":136.0,"Y":148.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":288746.0,"EndTime":288746.0,"X":117.603783,"Y":220.708862,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":288893.0,"Objects":[{"StartTime":288893.0,"EndTime":288893.0,"X":254.0,"Y":138.0}]},{"StartTime":289004.0,"Objects":[{"StartTime":289004.0,"EndTime":289004.0,"X":223.0,"Y":70.0}]},{"StartTime":289115.0,"Objects":[{"StartTime":289115.0,"EndTime":289115.0,"X":160.0,"Y":33.0}]},{"StartTime":289226.0,"Objects":[{"StartTime":289226.0,"EndTime":289226.0,"X":86.0,"Y":39.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":289301.0,"EndTime":289301.0,"X":33.20437,"Y":89.3222656,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":289449.0,"Objects":[{"StartTime":289449.0,"EndTime":289449.0,"X":117.0,"Y":220.0}]},{"StartTime":289560.0,"Objects":[{"StartTime":289560.0,"EndTime":289560.0,"X":117.0,"Y":220.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":289671.0,"EndTime":289671.0,"X":126.199661,"Y":294.433624,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":289746.0,"EndTime":289746.0,"X":117.0,"Y":220.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":289893.0,"Objects":[{"StartTime":289893.0,"EndTime":289893.0,"X":228.0,"Y":182.0}]},{"StartTime":290004.0,"Objects":[{"StartTime":290004.0,"EndTime":290004.0,"X":268.0,"Y":192.0}]},{"StartTime":290115.0,"Objects":[{"StartTime":290115.0,"EndTime":290115.0,"X":300.0,"Y":161.0}]},{"StartTime":290226.0,"Objects":[{"StartTime":290226.0,"EndTime":290226.0,"X":341.0,"Y":171.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":290301.0,"EndTime":290301.0,"X":413.869263,"Y":153.249786,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":290449.0,"Objects":[{"StartTime":290449.0,"EndTime":290449.0,"X":243.0,"Y":96.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":290524.0,"EndTime":290524.0,"X":315.869263,"Y":78.249794,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":290671.0,"Objects":[{"StartTime":290671.0,"EndTime":290671.0,"X":140.0,"Y":30.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":290746.0,"EndTime":290746.0,"X":67.23931,"Y":48.19017,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":290893.0,"Objects":[{"StartTime":290893.0,"EndTime":290893.0,"X":223.0,"Y":123.0}]},{"StartTime":291004.0,"Objects":[{"StartTime":291004.0,"EndTime":291004.0,"X":223.0,"Y":123.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":291079.0,"EndTime":291079.0,"X":150.239319,"Y":141.19017,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":291226.0,"Objects":[{"StartTime":291226.0,"EndTime":291226.0,"X":306.0,"Y":216.0}]},{"StartTime":291337.0,"Objects":[{"StartTime":291337.0,"EndTime":291337.0,"X":233.0,"Y":234.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":291412.0,"EndTime":291412.0,"X":160.239319,"Y":252.19017,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":291560.0,"Objects":[{"StartTime":291560.0,"EndTime":291560.0,"X":60.0,"Y":82.0}]},{"StartTime":291671.0,"Objects":[{"StartTime":291671.0,"EndTime":291671.0,"X":114.0,"Y":95.0}]},{"StartTime":291782.0,"Objects":[{"StartTime":291782.0,"EndTime":291782.0,"X":169.0,"Y":109.0}]},{"StartTime":291893.0,"Objects":[{"StartTime":291893.0,"EndTime":291893.0,"X":223.0,"Y":123.0}]},{"StartTime":292004.0,"Objects":[{"StartTime":292004.0,"EndTime":292004.0,"X":277.0,"Y":108.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":292079.0,"EndTime":292079.0,"X":348.8415,"Y":92.06539,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":292226.0,"Objects":[{"StartTime":292226.0,"EndTime":292226.0,"X":479.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":292301.0,"EndTime":292301.0,"X":500.194,"Y":279.897247,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":292449.0,"Objects":[{"StartTime":292449.0,"EndTime":292449.0,"X":285.0,"Y":299.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":292524.0,"EndTime":292524.0,"X":279.247772,"Y":373.779083,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":292671.0,"Objects":[{"StartTime":292671.0,"EndTime":292671.0,"X":407.0,"Y":190.0}]},{"StartTime":292782.0,"Objects":[{"StartTime":292782.0,"EndTime":292782.0,"X":407.0,"Y":190.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":292857.0,"EndTime":292857.0,"X":412.752228,"Y":264.779083,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":293004.0,"Objects":[{"StartTime":293004.0,"EndTime":293004.0,"X":253.0,"Y":128.0}]},{"StartTime":293115.0,"Objects":[{"StartTime":293115.0,"EndTime":293115.0,"X":248.0,"Y":203.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":293301.0,"EndTime":293301.0,"X":332.128082,"Y":159.941086,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":293449.0,"Objects":[{"StartTime":293449.0,"EndTime":293449.0,"X":482.0,"Y":90.0}]},{"StartTime":293560.0,"Objects":[{"StartTime":293560.0,"EndTime":293560.0,"X":487.0,"Y":164.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":293635.0,"EndTime":293635.0,"X":414.186737,"Y":146.021423,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":293782.0,"Objects":[{"StartTime":293782.0,"EndTime":293782.0,"X":248.0,"Y":203.0}]},{"StartTime":293893.0,"Objects":[{"StartTime":293893.0,"EndTime":293893.0,"X":196.0,"Y":180.0}]},{"StartTime":294004.0,"Objects":[{"StartTime":294004.0,"EndTime":294004.0,"X":140.0,"Y":180.0}]},{"StartTime":294115.0,"Objects":[{"StartTime":294115.0,"EndTime":294115.0,"X":89.0,"Y":202.0}]},{"StartTime":294226.0,"Objects":[{"StartTime":294226.0,"EndTime":294226.0,"X":51.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":294412.0,"EndTime":294412.0,"X":49.35009,"Y":164.435638,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":294560.0,"Objects":[{"StartTime":294560.0,"EndTime":294560.0,"X":92.0,"Y":319.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":294635.0,"EndTime":294635.0,"X":166.237274,"Y":309.999329,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":294782.0,"Objects":[{"StartTime":294782.0,"EndTime":294782.0,"X":317.0,"Y":351.0}]},{"StartTime":294893.0,"Objects":[{"StartTime":294893.0,"EndTime":294893.0,"X":399.0,"Y":338.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":294968.0,"EndTime":294968.0,"X":452.137421,"Y":286.427643,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":295115.0,"Objects":[{"StartTime":295115.0,"EndTime":295115.0,"X":281.0,"Y":104.0}]},{"StartTime":295226.0,"Objects":[{"StartTime":295226.0,"EndTime":295226.0,"X":247.0,"Y":147.0}]},{"StartTime":295337.0,"Objects":[{"StartTime":295337.0,"EndTime":295337.0,"X":248.0,"Y":203.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":295412.0,"EndTime":295412.0,"X":322.059174,"Y":206.941391,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":295560.0,"Objects":[{"StartTime":295560.0,"EndTime":295560.0,"X":281.0,"Y":104.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":295746.0,"EndTime":295746.0,"X":247.847549,"Y":202.258026,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":295893.0,"Objects":[{"StartTime":295893.0,"EndTime":295893.0,"X":301.0,"Y":78.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":295968.0,"EndTime":295968.0,"X":227.020447,"Y":65.6700745,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":296115.0,"Objects":[{"StartTime":296115.0,"EndTime":296115.0,"X":322.0,"Y":206.0}]},{"StartTime":296226.0,"Objects":[{"StartTime":296226.0,"EndTime":296226.0,"X":378.0,"Y":203.0}]},{"StartTime":296337.0,"Objects":[{"StartTime":296337.0,"EndTime":296337.0,"X":434.0,"Y":200.0}]},{"StartTime":296449.0,"Objects":[{"StartTime":296449.0,"EndTime":296449.0,"X":490.0,"Y":197.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":296524.0,"EndTime":296524.0,"X":481.9127,"Y":123.79538,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":296671.0,"Objects":[{"StartTime":296671.0,"EndTime":296671.0,"X":384.0,"Y":359.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":296746.0,"EndTime":296746.0,"X":446.2316,"Y":319.729828,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":296893.0,"Objects":[{"StartTime":296893.0,"EndTime":296893.0,"X":295.0,"Y":164.0}]},{"StartTime":297004.0,"Objects":[{"StartTime":297004.0,"EndTime":297004.0,"X":242.0,"Y":144.0}]},{"StartTime":297115.0,"Objects":[{"StartTime":297115.0,"EndTime":297115.0,"X":187.0,"Y":149.0}]},{"StartTime":297226.0,"Objects":[{"StartTime":297226.0,"EndTime":297226.0,"X":140.0,"Y":179.0}]},{"StartTime":297337.0,"Objects":[{"StartTime":297337.0,"EndTime":297337.0,"X":112.0,"Y":227.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":297412.0,"EndTime":297412.0,"X":104.972237,"Y":152.329987,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":297560.0,"Objects":[{"StartTime":297560.0,"EndTime":297560.0,"X":0.0,"Y":63.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":297635.0,"EndTime":297635.0,"X":72.19005,"Y":80.00728,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":297782.0,"Objects":[{"StartTime":297782.0,"EndTime":297782.0,"X":259.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":297893.0,"EndTime":297893.0,"X":186.83139,"Y":35.0842171,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":297968.0,"EndTime":297968.0,"X":259.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":298115.0,"Objects":[{"StartTime":298115.0,"EndTime":298115.0,"X":383.0,"Y":73.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":298226.0,"EndTime":298226.0,"X":418.150574,"Y":138.50589,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":298301.0,"EndTime":298301.0,"X":383.0,"Y":73.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":298449.0,"Objects":[{"StartTime":298449.0,"EndTime":298449.0,"X":242.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":298524.0,"EndTime":298524.0,"X":246.777512,"Y":218.847687,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":298671.0,"Objects":[{"StartTime":298671.0,"EndTime":298671.0,"X":409.0,"Y":298.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":298857.0,"EndTime":298857.0,"X":270.00058,"Y":329.671356,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":299115.0,"Objects":[{"StartTime":299115.0,"EndTime":299115.0,"X":47.0,"Y":287.0}]},{"StartTime":299226.0,"Objects":[{"StartTime":299226.0,"EndTime":299226.0,"X":11.0,"Y":243.0}]},{"StartTime":299337.0,"Objects":[{"StartTime":299337.0,"EndTime":299337.0,"X":0.0,"Y":189.0}]},{"StartTime":299449.0,"Objects":[{"StartTime":299449.0,"EndTime":299449.0,"X":13.0,"Y":135.0}]},{"StartTime":299560.0,"Objects":[{"StartTime":299560.0,"EndTime":299560.0,"X":49.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":299635.0,"EndTime":299635.0,"X":120.975449,"Y":88.04875,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":299782.0,"Objects":[{"StartTime":299782.0,"EndTime":299782.0,"X":244.0,"Y":186.0}]},{"StartTime":299893.0,"Objects":[{"StartTime":299893.0,"EndTime":299893.0,"X":244.0,"Y":186.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":299968.0,"EndTime":299968.0,"X":172.212662,"Y":189.046677,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":300115.0,"Objects":[{"StartTime":300115.0,"EndTime":300115.0,"X":363.0,"Y":223.0}]},{"StartTime":300226.0,"Objects":[{"StartTime":300226.0,"EndTime":300226.0,"X":363.0,"Y":223.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":300301.0,"EndTime":300301.0,"X":358.369659,"Y":148.143066,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":300449.0,"Objects":[{"StartTime":300449.0,"EndTime":300449.0,"X":449.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":300504.0,"EndTime":300504.0,"X":454.151123,"Y":19.08355,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":300560.0,"EndTime":300560.0,"X":449.031219,"Y":55.7762642,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":300579.0,"EndTime":300579.0,"X":454.182343,"Y":18.8598175,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":300671.0,"Objects":[{"StartTime":300671.0,"EndTime":300671.0,"X":403.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":300726.0,"EndTime":300726.0,"X":405.425751,"Y":199.195084,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":300782.0,"EndTime":300782.0,"X":403.0147,"Y":162.225418,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":300801.0,"EndTime":300801.0,"X":405.44046,"Y":199.4205,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":300893.0,"Objects":[{"StartTime":300893.0,"EndTime":300893.0,"X":340.0,"Y":71.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":300948.0,"EndTime":300948.0,"X":302.878967,"Y":67.62537,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":301004.0,"EndTime":301004.0,"X":339.775024,"Y":70.9795456,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":301023.0,"EndTime":301023.0,"X":302.654,"Y":67.60491,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":301115.0,"Objects":[{"StartTime":301115.0,"EndTime":301115.0,"X":254.0,"Y":153.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":301170.0,"EndTime":301170.0,"X":216.878983,"Y":156.374649,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":301226.0,"EndTime":301226.0,"X":253.775024,"Y":153.020447,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":301245.0,"EndTime":301245.0,"X":216.654,"Y":156.3951,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":301337.0,"Objects":[{"StartTime":301337.0,"EndTime":301337.0,"X":120.0,"Y":88.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":301364.0,"EndTime":301364.0,"X":90.89572,"Y":64.3527756,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":301449.0,"Objects":[{"StartTime":301449.0,"EndTime":301449.0,"X":66.0,"Y":100.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":301476.0,"EndTime":301476.0,"X":29.76619,"Y":90.33765,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":301560.0,"Objects":[{"StartTime":301560.0,"EndTime":301560.0,"X":30.0,"Y":141.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":301587.0,"EndTime":301587.0,"X":-7.21042252,"Y":145.6513,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":301671.0,"Objects":[{"StartTime":301671.0,"EndTime":301671.0,"X":23.0,"Y":196.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":301698.0,"EndTime":301698.0,"X":-10.5410194,"Y":212.770508,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":301782.0,"Objects":[{"StartTime":301782.0,"EndTime":301782.0,"X":50.0,"Y":245.0}]},{"StartTime":301893.0,"Objects":[{"StartTime":301893.0,"EndTime":301893.0,"X":100.0,"Y":226.0}]},{"StartTime":302004.0,"Objects":[{"StartTime":302004.0,"EndTime":302004.0,"X":146.0,"Y":250.0}]},{"StartTime":302115.0,"Objects":[{"StartTime":302115.0,"EndTime":302115.0,"X":159.0,"Y":300.0}]},{"StartTime":302226.0,"Objects":[{"StartTime":302226.0,"EndTime":302226.0,"X":136.0,"Y":344.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":302412.0,"EndTime":302412.0,"X":117.394791,"Y":195.158325,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":302560.0,"Objects":[{"StartTime":302560.0,"EndTime":302560.0,"X":192.0,"Y":80.0}]},{"StartTime":302671.0,"Objects":[{"StartTime":302671.0,"EndTime":302671.0,"X":192.0,"Y":80.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":302857.0,"EndTime":302857.0,"X":239.899292,"Y":201.07045,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":303004.0,"Objects":[{"StartTime":303004.0,"EndTime":303004.0,"X":146.0,"Y":250.0}]},{"StartTime":303115.0,"Objects":[{"StartTime":303115.0,"EndTime":303115.0,"X":72.0,"Y":304.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":303190.0,"EndTime":303190.0,"X":54.77756,"Y":232.478348,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":303337.0,"Objects":[{"StartTime":303337.0,"EndTime":303337.0,"X":106.0,"Y":129.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":303523.0,"EndTime":303523.0,"X":145.9509,"Y":250.0719,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":303671.0,"Objects":[{"StartTime":303671.0,"EndTime":303671.0,"X":72.0,"Y":152.0}]},{"StartTime":303782.0,"Objects":[{"StartTime":303782.0,"EndTime":303782.0,"X":72.0,"Y":152.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":303857.0,"EndTime":303857.0,"X":66.2477646,"Y":77.22091,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":304004.0,"Objects":[{"StartTime":304004.0,"EndTime":304004.0,"X":168.0,"Y":0.0}]},{"StartTime":304115.0,"Objects":[{"StartTime":304115.0,"EndTime":304115.0,"X":168.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":304190.0,"EndTime":304190.0,"X":173.752243,"Y":74.77909,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":304337.0,"Objects":[{"StartTime":304337.0,"EndTime":304337.0,"X":224.0,"Y":184.0}]},{"StartTime":304449.0,"Objects":[{"StartTime":304449.0,"EndTime":304449.0,"X":159.0,"Y":247.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":304635.0,"EndTime":304635.0,"X":291.3957,"Y":239.238037,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":304782.0,"Objects":[{"StartTime":304782.0,"EndTime":304782.0,"X":428.0,"Y":142.0}]},{"StartTime":304893.0,"Objects":[{"StartTime":304893.0,"EndTime":304893.0,"X":428.0,"Y":142.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":304968.0,"EndTime":304968.0,"X":353.110535,"Y":146.070084,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":305115.0,"Objects":[{"StartTime":305115.0,"EndTime":305115.0,"X":263.0,"Y":73.0}]},{"StartTime":305226.0,"Objects":[{"StartTime":305226.0,"EndTime":305226.0,"X":213.0,"Y":56.0}]},{"StartTime":305337.0,"Objects":[{"StartTime":305337.0,"EndTime":305337.0,"X":161.0,"Y":64.0}]},{"StartTime":305449.0,"Objects":[{"StartTime":305449.0,"EndTime":305449.0,"X":122.0,"Y":99.0}]},{"StartTime":305560.0,"Objects":[{"StartTime":305560.0,"EndTime":305560.0,"X":104.0,"Y":148.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":305635.0,"EndTime":305635.0,"X":121.072205,"Y":221.0311,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":305782.0,"Objects":[{"StartTime":305782.0,"EndTime":305782.0,"X":166.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":305968.0,"EndTime":305968.0,"X":21.8029289,"Y":327.180328,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":306115.0,"Objects":[{"StartTime":306115.0,"EndTime":306115.0,"X":309.0,"Y":200.0}]},{"StartTime":306226.0,"Objects":[{"StartTime":306226.0,"EndTime":306226.0,"X":309.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":306412.0,"EndTime":306412.0,"X":317.581451,"Y":338.349365,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":306560.0,"Objects":[{"StartTime":306560.0,"EndTime":306560.0,"X":243.0,"Y":278.0}]},{"StartTime":306671.0,"Objects":[{"StartTime":306671.0,"EndTime":306671.0,"X":309.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":306746.0,"EndTime":306746.0,"X":383.910919,"Y":196.34581,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":306893.0,"Objects":[{"StartTime":306893.0,"EndTime":306893.0,"X":500.0,"Y":99.0}]},{"StartTime":307004.0,"Objects":[{"StartTime":307004.0,"EndTime":307004.0,"X":447.0,"Y":92.0}]},{"StartTime":307115.0,"Objects":[{"StartTime":307115.0,"EndTime":307115.0,"X":397.0,"Y":75.0}]},{"StartTime":307226.0,"Objects":[{"StartTime":307226.0,"EndTime":307226.0,"X":344.0,"Y":69.0}]},{"StartTime":307337.0,"Objects":[{"StartTime":307337.0,"EndTime":307337.0,"X":296.0,"Y":47.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":307412.0,"EndTime":307412.0,"X":221.672577,"Y":36.9783249,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":307560.0,"Objects":[{"StartTime":307560.0,"EndTime":307560.0,"X":108.0,"Y":8.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":307746.0,"EndTime":307746.0,"X":109.323067,"Y":154.072922,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":307893.0,"Objects":[{"StartTime":307893.0,"EndTime":307893.0,"X":78.0,"Y":336.0}]},{"StartTime":308004.0,"Objects":[{"StartTime":308004.0,"EndTime":308004.0,"X":78.0,"Y":336.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":308190.0,"EndTime":308190.0,"X":24.1577778,"Y":213.150711,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":308337.0,"Objects":[{"StartTime":308337.0,"EndTime":308337.0,"X":194.0,"Y":174.0}]},{"StartTime":308449.0,"Objects":[{"StartTime":308449.0,"EndTime":308449.0,"X":194.0,"Y":174.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":308524.0,"EndTime":308524.0,"X":186.889313,"Y":248.66217,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":308671.0,"Objects":[{"StartTime":308671.0,"EndTime":308671.0,"X":288.0,"Y":113.0}]},{"StartTime":308782.0,"Objects":[{"StartTime":308782.0,"EndTime":308782.0,"X":323.0,"Y":74.0}]},{"StartTime":308893.0,"Objects":[{"StartTime":308893.0,"EndTime":308893.0,"X":373.0,"Y":59.0}]},{"StartTime":309004.0,"Objects":[{"StartTime":309004.0,"EndTime":309004.0,"X":424.0,"Y":70.0}]},{"StartTime":309115.0,"Objects":[{"StartTime":309115.0,"EndTime":309115.0,"X":476.0,"Y":67.0}]},{"StartTime":309226.0,"Objects":[{"StartTime":309226.0,"EndTime":309226.0,"X":462.0,"Y":117.0}]},{"StartTime":309337.0,"Objects":[{"StartTime":309337.0,"EndTime":309337.0,"X":448.0,"Y":167.0}]},{"StartTime":309449.0,"Objects":[{"StartTime":309449.0,"EndTime":309449.0,"X":434.0,"Y":217.0}]},{"StartTime":309560.0,"Objects":[{"StartTime":309560.0,"EndTime":309560.0,"X":460.0,"Y":262.0}]},{"StartTime":309671.0,"Objects":[{"StartTime":309671.0,"EndTime":309671.0,"X":408.0,"Y":253.0}]},{"StartTime":309782.0,"Objects":[{"StartTime":309782.0,"EndTime":309782.0,"X":359.0,"Y":274.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":309857.0,"EndTime":309857.0,"X":348.925232,"Y":344.30542,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":310004.0,"Objects":[{"StartTime":310004.0,"EndTime":310004.0,"X":305.0,"Y":191.0}]},{"StartTime":310115.0,"Objects":[{"StartTime":310115.0,"EndTime":310115.0,"X":305.0,"Y":191.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":310301.0,"EndTime":310301.0,"X":325.611847,"Y":42.4228973,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":310449.0,"Objects":[{"StartTime":310449.0,"EndTime":310449.0,"X":216.0,"Y":296.0}]},{"StartTime":310560.0,"Objects":[{"StartTime":310560.0,"EndTime":310560.0,"X":165.0,"Y":310.0}]},{"StartTime":310671.0,"Objects":[{"StartTime":310671.0,"EndTime":310671.0,"X":118.0,"Y":290.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":310857.0,"EndTime":310857.0,"X":80.842,"Y":168.38945,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":311004.0,"Objects":[{"StartTime":311004.0,"EndTime":311004.0,"X":230.0,"Y":113.0}]},{"StartTime":311115.0,"Objects":[{"StartTime":311115.0,"EndTime":311115.0,"X":230.0,"Y":113.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":311412.0,"EndTime":311412.0,"X":5.562317,"Y":128.897675,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":311560.0,"Objects":[{"StartTime":311560.0,"EndTime":311560.0,"X":95.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":311635.0,"EndTime":311635.0,"X":149.100632,"Y":108.046616,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":311782.0,"Objects":[{"StartTime":311782.0,"EndTime":311782.0,"X":169.0,"Y":270.0}]},{"StartTime":311893.0,"Objects":[{"StartTime":311893.0,"EndTime":311893.0,"X":169.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":312079.0,"EndTime":312079.0,"X":306.0838,"Y":246.75618,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":312226.0,"Objects":[{"StartTime":312226.0,"EndTime":312226.0,"X":405.0,"Y":327.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":312301.0,"EndTime":312301.0,"X":479.9522,"Y":329.67688,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":312449.0,"Objects":[{"StartTime":312449.0,"EndTime":312449.0,"X":200.0,"Y":285.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":312635.0,"EndTime":312635.0,"X":59.225914,"Y":275.1619,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":312782.0,"Objects":[{"StartTime":312782.0,"EndTime":312782.0,"X":13.0,"Y":105.0}]},{"StartTime":312893.0,"Objects":[{"StartTime":312893.0,"EndTime":312893.0,"X":95.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":313190.0,"EndTime":313190.0,"X":319.3316,"Y":79.33034,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":313337.0,"Objects":[{"StartTime":313337.0,"EndTime":313337.0,"X":488.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":313412.0,"EndTime":313412.0,"X":475.216217,"Y":200.466019,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":313560.0,"Objects":[{"StartTime":313560.0,"EndTime":313560.0,"X":360.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":313635.0,"EndTime":313635.0,"X":372.7838,"Y":239.533966,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":313782.0,"Objects":[{"StartTime":313782.0,"EndTime":313782.0,"X":464.0,"Y":312.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":313857.0,"EndTime":313857.0,"X":450.9661,"Y":238.141235,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":314004.0,"Objects":[{"StartTime":314004.0,"EndTime":314004.0,"X":320.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":314079.0,"EndTime":314079.0,"X":333.0339,"Y":217.858765,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":314226.0,"Objects":[{"StartTime":314226.0,"EndTime":314226.0,"X":288.0,"Y":352.0}]},{"StartTime":314337.0,"Objects":[{"StartTime":314337.0,"EndTime":314337.0,"X":248.0,"Y":320.0}]},{"StartTime":314449.0,"Objects":[{"StartTime":314449.0,"EndTime":314449.0,"X":208.0,"Y":304.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":314476.0,"EndTime":314476.0,"X":170.5,"Y":304.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":314560.0,"Objects":[{"StartTime":314560.0,"EndTime":314560.0,"X":168.0,"Y":304.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":314587.0,"EndTime":314587.0,"X":130.876892,"Y":309.3033,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":314671.0,"Objects":[{"StartTime":314671.0,"EndTime":314671.0,"X":112.0,"Y":320.0}]},{"StartTime":314782.0,"Objects":[{"StartTime":314782.0,"EndTime":314782.0,"X":64.0,"Y":312.0}]},{"StartTime":314893.0,"Objects":[{"StartTime":314893.0,"EndTime":314893.0,"X":32.0,"Y":272.0}]},{"StartTime":315004.0,"Objects":[{"StartTime":315004.0,"EndTime":315004.0,"X":40.0,"Y":216.0}]},{"StartTime":315115.0,"Objects":[{"StartTime":315115.0,"EndTime":315115.0,"X":72.0,"Y":176.0}]},{"StartTime":315226.0,"Objects":[{"StartTime":315226.0,"EndTime":315226.0,"X":120.0,"Y":160.0}]},{"StartTime":315337.0,"Objects":[{"StartTime":315337.0,"EndTime":315337.0,"X":168.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":315364.0,"EndTime":315364.0,"X":203.575623,"Y":132.141464,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":315449.0,"Objects":[{"StartTime":315449.0,"EndTime":315449.0,"X":203.0,"Y":132.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":315476.0,"EndTime":315476.0,"X":238.6336,"Y":120.316849,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":315560.0,"Objects":[{"StartTime":315560.0,"EndTime":315560.0,"X":264.0,"Y":136.0}]},{"StartTime":315671.0,"Objects":[{"StartTime":315671.0,"EndTime":315671.0,"X":296.0,"Y":96.0}]},{"StartTime":315782.0,"Objects":[{"StartTime":315782.0,"EndTime":315782.0,"X":288.0,"Y":48.0}]},{"StartTime":315893.0,"Objects":[{"StartTime":315893.0,"EndTime":315893.0,"X":256.0,"Y":8.0}]},{"StartTime":316115.0,"Objects":[{"StartTime":316115.0,"EndTime":316115.0,"X":256.0,"Y":352.0}]},{"StartTime":316337.0,"Objects":[{"StartTime":316337.0,"EndTime":316337.0,"X":256.0,"Y":8.0}]},{"StartTime":316449.0,"Objects":[{"StartTime":316449.0,"EndTime":316449.0,"X":219.0,"Y":91.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":316635.0,"EndTime":316635.0,"X":314.382172,"Y":76.83485,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":316893.0,"Objects":[{"StartTime":316893.0,"EndTime":316893.0,"X":434.0,"Y":29.0}]},{"StartTime":317004.0,"Objects":[{"StartTime":317004.0,"EndTime":317004.0,"X":437.0,"Y":66.0}]},{"StartTime":317115.0,"Objects":[{"StartTime":317115.0,"EndTime":317115.0,"X":440.0,"Y":103.0}]},{"StartTime":317337.0,"Objects":[{"StartTime":317337.0,"EndTime":317337.0,"X":371.0,"Y":215.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":317448.0,"EndTime":317448.0,"X":321.970978,"Y":205.1942,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":317559.0,"EndTime":317559.0,"X":371.0,"Y":215.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":317634.0,"EndTime":317634.0,"X":321.970978,"Y":205.1942,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":317782.0,"Objects":[{"StartTime":317782.0,"EndTime":317782.0,"X":298.0,"Y":247.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":317893.0,"EndTime":317893.0,"X":248.790833,"Y":255.857651,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":318004.0,"EndTime":318004.0,"X":298.0,"Y":247.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":318079.0,"EndTime":318079.0,"X":248.790833,"Y":255.857651,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":318226.0,"Objects":[{"StartTime":318226.0,"EndTime":318226.0,"X":216.0,"Y":221.0}]},{"StartTime":318337.0,"Objects":[{"StartTime":318337.0,"EndTime":318337.0,"X":178.0,"Y":217.0}]},{"StartTime":318449.0,"Objects":[{"StartTime":318449.0,"EndTime":318449.0,"X":143.0,"Y":229.0}]},{"StartTime":318671.0,"Objects":[{"StartTime":318671.0,"EndTime":318671.0,"X":23.0,"Y":142.0}]},{"StartTime":318893.0,"Objects":[{"StartTime":318893.0,"EndTime":318893.0,"X":161.0,"Y":78.0}]},{"StartTime":319115.0,"Objects":[{"StartTime":319115.0,"EndTime":319115.0,"X":56.0,"Y":224.0}]},{"StartTime":319226.0,"Objects":[{"StartTime":319226.0,"EndTime":319226.0,"X":36.0,"Y":255.0}]},{"StartTime":319337.0,"Objects":[{"StartTime":319337.0,"EndTime":319337.0,"X":31.0,"Y":292.0}]},{"StartTime":319449.0,"Objects":[{"StartTime":319449.0,"EndTime":319449.0,"X":40.0,"Y":328.0}]},{"StartTime":319560.0,"Objects":[{"StartTime":319560.0,"EndTime":319560.0,"X":62.0,"Y":358.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":319635.0,"EndTime":319635.0,"X":110.935852,"Y":347.739258,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":319782.0,"Objects":[{"StartTime":319782.0,"EndTime":319782.0,"X":249.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":319968.0,"EndTime":319968.0,"X":347.724121,"Y":287.923248,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":320226.0,"Objects":[{"StartTime":320226.0,"EndTime":320226.0,"X":219.0,"Y":363.0}]},{"StartTime":320449.0,"Objects":[{"StartTime":320449.0,"EndTime":320449.0,"X":260.0,"Y":226.0}]},{"StartTime":320671.0,"Objects":[{"StartTime":320671.0,"EndTime":320671.0,"X":380.0,"Y":331.0}]},{"StartTime":320893.0,"Objects":[{"StartTime":320893.0,"EndTime":320893.0,"X":462.0,"Y":168.0}]},{"StartTime":321004.0,"Objects":[{"StartTime":321004.0,"EndTime":321004.0,"X":420.0,"Y":173.0}]},{"StartTime":321115.0,"Objects":[{"StartTime":321115.0,"EndTime":321115.0,"X":379.0,"Y":178.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":321190.0,"EndTime":321190.0,"X":330.541565,"Y":190.319946,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":321337.0,"Objects":[{"StartTime":321337.0,"EndTime":321337.0,"X":200.0,"Y":259.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":321412.0,"EndTime":321412.0,"X":248.45842,"Y":271.319946,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":321560.0,"Objects":[{"StartTime":321560.0,"EndTime":321560.0,"X":380.0,"Y":331.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":321746.0,"EndTime":321746.0,"X":386.820923,"Y":234.890335,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":322004.0,"Objects":[{"StartTime":322004.0,"EndTime":322004.0,"X":338.0,"Y":49.0}]},{"StartTime":322226.0,"Objects":[{"StartTime":322226.0,"EndTime":322226.0,"X":330.0,"Y":190.0}]},{"StartTime":322449.0,"Objects":[{"StartTime":322449.0,"EndTime":322449.0,"X":443.0,"Y":275.0}]},{"StartTime":322671.0,"Objects":[{"StartTime":322671.0,"EndTime":322671.0,"X":426.0,"Y":118.0}]},{"StartTime":322782.0,"Objects":[{"StartTime":322782.0,"EndTime":322782.0,"X":394.0,"Y":97.0}]},{"StartTime":322893.0,"Objects":[{"StartTime":322893.0,"EndTime":322893.0,"X":360.0,"Y":83.0}]},{"StartTime":323004.0,"Objects":[{"StartTime":323004.0,"EndTime":323004.0,"X":323.0,"Y":76.0}]},{"StartTime":323115.0,"Objects":[{"StartTime":323115.0,"EndTime":323115.0,"X":285.0,"Y":78.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":323190.0,"EndTime":323190.0,"X":236.110245,"Y":84.99362,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":323337.0,"Objects":[{"StartTime":323337.0,"EndTime":323337.0,"X":165.0,"Y":223.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":323412.0,"EndTime":323412.0,"X":191.980072,"Y":181.488983,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":323560.0,"Objects":[{"StartTime":323560.0,"EndTime":323560.0,"X":65.0,"Y":126.0}]},{"StartTime":323671.0,"Objects":[{"StartTime":323671.0,"EndTime":323671.0,"X":43.0,"Y":156.0}]},{"StartTime":323782.0,"Objects":[{"StartTime":323782.0,"EndTime":323782.0,"X":30.0,"Y":191.0}]},{"StartTime":323893.0,"Objects":[{"StartTime":323893.0,"EndTime":323893.0,"X":27.0,"Y":229.0}]},{"StartTime":324004.0,"Objects":[{"StartTime":324004.0,"EndTime":324004.0,"X":34.0,"Y":265.0}]},{"StartTime":324115.0,"Objects":[{"StartTime":324115.0,"EndTime":324115.0,"X":69.0,"Y":278.0}]},{"StartTime":324226.0,"Objects":[{"StartTime":324226.0,"EndTime":324226.0,"X":106.0,"Y":283.0}]},{"StartTime":324337.0,"Objects":[{"StartTime":324337.0,"EndTime":324337.0,"X":144.0,"Y":280.0}]},{"StartTime":324449.0,"Objects":[{"StartTime":324449.0,"EndTime":324449.0,"X":179.0,"Y":269.0}]},{"StartTime":324560.0,"Objects":[{"StartTime":324560.0,"EndTime":324560.0,"X":205.0,"Y":294.0}]},{"StartTime":324671.0,"Objects":[{"StartTime":324671.0,"EndTime":324671.0,"X":205.0,"Y":331.0}]},{"StartTime":324782.0,"Objects":[{"StartTime":324782.0,"EndTime":324782.0,"X":179.0,"Y":356.0}]},{"StartTime":324893.0,"Objects":[{"StartTime":324893.0,"EndTime":324893.0,"X":143.0,"Y":356.0}]},{"StartTime":325004.0,"Objects":[{"StartTime":325004.0,"EndTime":325004.0,"X":120.0,"Y":319.0}]},{"StartTime":325115.0,"Objects":[{"StartTime":325115.0,"EndTime":325115.0,"X":111.0,"Y":276.0}]},{"StartTime":325226.0,"Objects":[{"StartTime":325226.0,"EndTime":325226.0,"X":118.0,"Y":233.0}]},{"StartTime":325337.0,"Objects":[{"StartTime":325337.0,"EndTime":325337.0,"X":139.0,"Y":195.0}]},{"StartTime":325449.0,"Objects":[{"StartTime":325449.0,"EndTime":325449.0,"X":168.0,"Y":203.0}]},{"StartTime":325560.0,"Objects":[{"StartTime":325560.0,"EndTime":325560.0,"X":199.0,"Y":204.0}]},{"StartTime":325671.0,"Objects":[{"StartTime":325671.0,"EndTime":325671.0,"X":230.0,"Y":196.0}]},{"StartTime":325782.0,"Objects":[{"StartTime":325782.0,"EndTime":325782.0,"X":256.0,"Y":180.0}]},{"StartTime":325893.0,"Objects":[{"StartTime":325893.0,"EndTime":325893.0,"X":282.0,"Y":164.0}]},{"StartTime":326004.0,"Objects":[{"StartTime":326004.0,"EndTime":326004.0,"X":313.0,"Y":156.0}]},{"StartTime":326115.0,"Objects":[{"StartTime":326115.0,"EndTime":326115.0,"X":344.0,"Y":157.0}]},{"StartTime":326226.0,"Objects":[{"StartTime":326226.0,"EndTime":326226.0,"X":374.0,"Y":166.0}]},{"StartTime":326337.0,"Objects":[{"StartTime":326337.0,"EndTime":326337.0,"X":334.0,"Y":137.0}]},{"StartTime":326449.0,"Objects":[{"StartTime":326449.0,"EndTime":326449.0,"X":318.0,"Y":90.0}]},{"StartTime":326560.0,"Objects":[{"StartTime":326560.0,"EndTime":326560.0,"X":331.0,"Y":43.0}]},{"StartTime":326671.0,"Objects":[{"StartTime":326671.0,"EndTime":326671.0,"X":370.0,"Y":12.0}]},{"StartTime":326782.0,"Objects":[{"StartTime":326782.0,"EndTime":326782.0,"X":419.0,"Y":9.0}]},{"StartTime":326893.0,"Objects":[{"StartTime":326893.0,"EndTime":326893.0,"X":461.0,"Y":35.0}]},{"StartTime":327004.0,"Objects":[{"StartTime":327004.0,"EndTime":327004.0,"X":480.0,"Y":80.0}]},{"StartTime":327115.0,"Objects":[{"StartTime":327115.0,"EndTime":327115.0,"X":470.0,"Y":128.0}]},{"StartTime":327226.0,"Objects":[{"StartTime":327226.0,"EndTime":327226.0,"X":448.0,"Y":166.0}]},{"StartTime":327337.0,"Objects":[{"StartTime":327337.0,"EndTime":327337.0,"X":444.0,"Y":209.0}]},{"StartTime":327449.0,"Objects":[{"StartTime":327449.0,"EndTime":327449.0,"X":458.0,"Y":250.0}]},{"StartTime":327560.0,"Objects":[{"StartTime":327560.0,"EndTime":327560.0,"X":487.0,"Y":282.0}]},{"StartTime":327671.0,"Objects":[{"StartTime":327671.0,"EndTime":327671.0,"X":475.0,"Y":241.0}]},{"StartTime":327782.0,"Objects":[{"StartTime":327782.0,"EndTime":327782.0,"X":442.0,"Y":213.0}]},{"StartTime":327893.0,"Objects":[{"StartTime":327893.0,"EndTime":327893.0,"X":400.0,"Y":208.0}]},{"StartTime":328004.0,"Objects":[{"StartTime":328004.0,"EndTime":328004.0,"X":361.0,"Y":227.0}]},{"StartTime":328115.0,"Objects":[{"StartTime":328115.0,"EndTime":328115.0,"X":336.0,"Y":258.0}]},{"StartTime":328226.0,"Objects":[{"StartTime":328226.0,"EndTime":328226.0,"X":275.0,"Y":214.0}]},{"StartTime":328337.0,"Objects":[{"StartTime":328337.0,"EndTime":328337.0,"X":261.0,"Y":246.0}]},{"StartTime":328449.0,"Objects":[{"StartTime":328449.0,"EndTime":328449.0,"X":192.0,"Y":227.0}]},{"StartTime":328560.0,"Objects":[{"StartTime":328560.0,"EndTime":328560.0,"X":186.0,"Y":256.0}]},{"StartTime":328671.0,"Objects":[{"StartTime":328671.0,"EndTime":328671.0,"X":114.0,"Y":258.0}]},{"StartTime":328782.0,"Objects":[{"StartTime":328782.0,"EndTime":328782.0,"X":113.0,"Y":282.0}]},{"StartTime":328893.0,"Objects":[{"StartTime":328893.0,"EndTime":328893.0,"X":45.0,"Y":304.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":328948.0,"EndTime":328948.0,"X":24.0972271,"Y":317.4375,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":329004.0,"EndTime":329004.0,"X":44.8733177,"Y":304.081451,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":329023.0,"EndTime":329023.0,"X":23.9705372,"Y":317.518951,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":329115.0,"Objects":[{"StartTime":329115.0,"EndTime":329115.0,"X":25.0,"Y":203.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":329170.0,"EndTime":329170.0,"X":0.34249115,"Y":206.082184,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":329226.0,"EndTime":329226.0,"X":24.8505611,"Y":203.018677,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":329245.0,"EndTime":329245.0,"X":0.1930542,"Y":206.100861,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":329337.0,"Objects":[{"StartTime":329337.0,"EndTime":329337.0,"X":69.0,"Y":115.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":329392.0,"EndTime":329392.0,"X":45.28175,"Y":107.588043,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":329448.0,"EndTime":329448.0,"X":68.8562546,"Y":114.955078,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":329467.0,"EndTime":329467.0,"X":45.138,"Y":107.543121,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":329560.0,"Objects":[{"StartTime":329560.0,"EndTime":329560.0,"X":154.0,"Y":70.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":329615.0,"EndTime":329615.0,"X":135.712555,"Y":53.17555,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":329671.0,"EndTime":329671.0,"X":153.88916,"Y":69.89803,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":329690.0,"EndTime":329690.0,"X":135.60173,"Y":53.0735855,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":329782.0,"Objects":[{"StartTime":329782.0,"EndTime":329782.0,"X":300.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":329809.0,"EndTime":329809.0,"X":323.513855,"Y":107.508888,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":329893.0,"Objects":[{"StartTime":329893.0,"EndTime":329893.0,"X":282.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":329920.0,"EndTime":329920.0,"X":297.2108,"Y":187.840164,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":330004.0,"Objects":[{"StartTime":330004.0,"EndTime":330004.0,"X":228.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":330031.0,"EndTime":330031.0,"X":213.531326,"Y":188.38768,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":330115.0,"Objects":[{"StartTime":330115.0,"EndTime":330115.0,"X":211.0,"Y":115.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":330142.0,"EndTime":330142.0,"X":187.036591,"Y":107.87574,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":330226.0,"Objects":[{"StartTime":330226.0,"EndTime":330226.0,"X":256.0,"Y":83.0}]},{"StartTime":330337.0,"Objects":[{"StartTime":330337.0,"EndTime":330337.0,"X":256.0,"Y":133.0}]},{"StartTime":330449.0,"Objects":[{"StartTime":330449.0,"EndTime":330449.0,"X":256.0,"Y":183.0}]},{"StartTime":330560.0,"Objects":[{"StartTime":330560.0,"EndTime":330560.0,"X":256.0,"Y":233.0}]}]} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/801165.osu b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/801165.osu new file mode 100644 index 000000000000..7357bb1dafb2 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/801165.osu @@ -0,0 +1,1768 @@ +osu file format v14 + +[General] +AudioLeadIn: 0 +PreviewTime: 231110 +Countdown: 0 +SampleSet: Normal +StackLeniency: 0.2 +Mode: 0 +LetterboxInBreaks: 0 +WidescreenStoryboard: 1 + +[Difficulty] +HPDrainRate:6 +CircleSize:4 +OverallDifficulty:8 +ApproachRate:9.3 +SliderMultiplier:2 +SliderTickRate:1 + +[Events] +//Background and Video events +//Break Periods +2,14204,16450 +2,117537,127450 +2,188649,195006 +//Storyboard Layer 0 (Background) +//Storyboard Layer 1 (Fail) +//Storyboard Layer 2 (Pass) +//Storyboard Layer 3 (Foreground) +//Storyboard Layer 4 (Overlay) +//Storyboard Sound Samples + +[TimingPoints] +5338,444.444444444444,4,2,0,50,1,0 +6338,-100,4,2,7,60,0,0 +7115,-100,4,2,7,50,0,0 +13671,-100,4,2,7,60,0,0 +17560,-100,4,2,8,60,0,0 +17782,-100,4,2,7,60,0,0 +18226,-100,4,2,8,60,0,0 +21114,-83.3333333333333,4,2,8,60,0,0 +21337,-100,4,2,8,60,0,0 +22893,-83.3333333333333,4,2,8,60,0,0 +23448,-100,4,2,8,60,0,0 +25337,-66.6666666666667,4,2,8,60,0,0 +25670,-100,4,2,8,60,0,0 +31559,-55.5555555555556,4,2,8,60,0,0 +44448,-100,4,2,8,50,0,0 +44893,-100,4,2,8,55,0,0 +45337,-100,4,2,7,60,0,0 +45670,-200,4,2,8,60,0,0 +46226,-66.6666666666667,4,2,8,65,0,0 +58670,-66.6666666666667,4,2,8,55,0,0 +59115,-66.6666666666667,4,2,8,60,0,0 +59559,-66.6666666666667,4,2,8,65,0,0 +60226,-100,4,2,8,60,0,0 +60893,-100,4,2,8,55,0,0 +68004,-66.6666666666667,4,2,8,65,0,0 +73337,-100,4,2,8,55,0,0 +73781,-100,4,2,8,55,0,0 +73893,-100,4,2,7,55,0,0 +74004,-100,4,2,8,55,0,0 +74115,-100,4,2,7,55,0,0 +74226,-100,4,2,8,55,0,0 +74337,-100,4,2,7,55,0,0 +74448,-100,4,2,8,55,0,0 +82893,-76.9230769230769,4,2,8,50,0,0 +85115,-76.9230769230769,4,2,0,50,0,0 +85337,-100,4,2,8,60,0,0 +85893,-100,4,2,7,60,0,0 +86226,-100,4,2,8,60,0,0 +88893,-58.8235294117647,4,1,8,70,0,1 +102226,-58.8235294117647,4,2,8,70,0,1 +103115,-58.8235294117647,4,1,8,70,0,1 +115337,-50,4,1,8,70,0,1 +115670,-50,4,2,7,70,0,1 +116004,-76.9230769230769,4,2,8,70,0,1 +116559,-76.9230769230769,4,2,7,60,0,1 +117337,-58.8235294117647,4,2,8,70,0,0 +128004,-100,4,2,8,65,0,0 +129781,-100,4,2,8,55,0,0 +130226,-100,4,2,8,60,0,0 +130670,-100,4,2,8,65,0,0 +131337,-100,4,2,8,60,0,0 +132004,-100,4,2,8,55,0,0 +145004,-100,4,2,7,55,0,0 +145115,-100,4,2,8,55,0,0 +145226,-100,4,2,7,55,0,0 +145337,-100,4,2,8,55,0,0 +145448,-100,4,2,7,55,0,0 +145559,-100,4,2,8,55,0,0 +156226,-100,4,2,0,50,0,0 +156448,-100,4,2,8,60,0,0 +157004,-100,4,2,7,60,0,0 +157337,-100,4,2,8,60,0,0 +160004,-58.8235294117647,4,1,8,70,0,1 +186781,-58.8235294117647,4,2,7,70,0,1 +187115,-58.8235294117647,4,1,8,70,0,1 +187670,-58.8235294117647,4,1,7,70,0,1 +188449,-58.8235294117647,4,2,8,70,0,0 +195559,-100,4,2,7,40,0,0 +195670,-100,4,2,8,40,0,0 +202670,-66.6666666666667,4,2,8,70,0,0 +203115,-100,4,2,8,60,0,0 +215559,-100,4,2,7,60,0,0 +216893,-83.3333333333333,4,2,8,60,0,0 +228115,-83.3333333333333,4,2,7,60,0,0 +228226,-83.3333333333333,4,2,8,60,0,0 +228337,-83.3333333333333,4,2,7,60,0,0 +228448,-83.3333333333333,4,2,8,60,0,0 +228781,-83.3333333333333,4,2,7,60,0,0 +228893,-83.3333333333333,4,2,8,60,0,0 +229893,-83.3333333333333,4,2,7,60,0,0 +230004,-83.3333333333333,4,2,8,60,0,0 +231115,-166.666666666667,4,2,8,60,0,0 +238226,-166.666666666667,4,2,7,60,0,0 +238893,-166.666666666667,4,2,8,60,0,0 +245004,-166.666666666667,4,2,7,60,0,0 +245115,-166.666666666667,4,2,8,60,0,0 +245337,-100,4,2,8,60,0,0 +257893,-100,4,2,7,60,0,0 +258226,-100,4,2,8,60,0,0 +258337,-100,4,2,7,60,0,0 +258448,-100,4,2,8,60,0,0 +258559,-100,4,2,7,60,0,0 +258670,-100,4,2,8,60,0,0 +259560,-58.8235294117647,4,1,8,70,0,1 +273448,-58.8235294117647,4,2,7,70,0,1 +273559,-58.8235294117647,4,1,8,70,0,1 +286337,-58.8235294117647,4,2,7,70,0,1 +286670,-58.8235294117647,4,2,8,70,0,1 +286781,-58.8235294117647,4,2,7,70,0,1 +286893,-58.8235294117647,4,2,8,70,0,1 +287226,-58.8235294117647,4,1,7,70,0,1 +288004,-66.6666666666667,4,2,8,65,0,0 +295559,-50,4,2,8,65,0,0 +295893,-66.6666666666667,4,2,8,65,0,0 +298448,-66.6666666666667,4,2,0,65,0,0 +298559,-66.6666666666667,4,2,8,65,0,0 +312670,-66.6666666666667,4,2,0,65,0,0 +312781,-66.6666666666667,4,2,8,65,0,0 +313448,-66.6666666666667,4,2,7,65,0,0 +313781,-66.6666666666667,4,2,8,65,0,0 +315337,-66.6666666666667,4,2,7,65,0,0 +315559,-66.6666666666667,4,2,8,65,0,0 +316448,-100,4,2,8,60,0,0 +330559,-100,4,2,7,60,0,0 + + +[Colours] +Combo1 : 139,159,214 +Combo2 : 128,128,255 +Combo3 : 227,227,227 + +[HitObjects] +378,163,6337,6,4,P|427:159|468:188,2,100,8|8|8,3:2|3:2|3:2,0:0:0:0: +320,312,7115,2,0,L|332:360,1,50,6|2,0:0|0:0,0:0:0:0: +164,208,7560,6,0,L|132:208,1,25,10|0,0:0|0:0,0:0:0:0: +139,208,7671,2,0,L|92:208,1,25,2|2,0:0|0:0,0:0:0:0: +114,208,7782,2,0,L|84:208,1,25,2|2,0:0|0:0,0:0:0:0: +89,208,7893,2,0,L|60:208,1,25,10|0,0:0|0:0,0:0:0:0: +32,184,8004,6,0,L|48:112,1,50,2|10,0:0|0:0,0:0:0:0: +144,128,8226,2,0,L|160:56,1,50,8|0,3:2|1:0,0:0:0:0: +266,68,8449,5,2,0:0:0:0: +306,40,8560,1,2,1:2:0:0: +356,39,8671,1,8,3:2:0:0: +397,66,8782,1,0,0:0:0:0: +415,111,8893,6,0,L|447:168,1,50,2|10,3:2|0:0,0:0:0:0: +429,263,9115,2,0,L|463:321,1,50,2|0,0:0|0:0,0:0:0:0: +328,272,9337,6,0,L|312:244,1,25,2|2,0:0|0:0,0:0:0:0: +315,250,9449,2,0,L|291:209,1,25,2|2,0:0|0:0,0:0:0:0: +303,228,9560,2,0,L|288:202,1,25,2|2,0:0|0:0,0:0:0:0: +290,207,9671,2,0,L|275:181,1,25,2|2,0:0|0:0,0:0:0:0: +248,152,9782,6,0,L|248:88,1,50,2|10,0:0|0:0,0:0:0:0: +154,136,10004,2,0,L|154:80,1,50,8|0,3:2|1:0,0:0:0:0: +64,168,10226,5,2,0:0:0:0: +19,187,10337,1,2,1:2:0:0: +0,232,10449,1,8,3:2:0:0: +14,278,10560,1,0,0:0:0:0: +56,303,10671,5,2,3:2:0:0: +101,282,10782,1,10,0:0:0:0: +151,282,10893,1,2,0:0:0:0: +196,302,11004,1,0,0:0:0:0: +240,316,11115,6,0,L|272:316,1,25,10|0,0:0|0:0,0:0:0:0: +265,316,11226,2,0,L|312:316,1,25,2|2,0:0|0:0,0:0:0:0: +290,316,11337,2,0,L|320:316,1,25,2|2,0:0|0:0,0:0:0:0: +315,316,11449,2,0,L|344:316,1,25,10|0,0:0|0:0,0:0:0:0: +384,340,11560,6,0,L|416:292,1,50,2|10,0:0|0:0,0:0:0:0: +376,196,11782,2,0,L|344:244,1,50,10|0,3:0|1:0,0:0:0:0: +416,308,12004,6,0,L|429:251,1,50,2|2,0:0|1:2,0:0:0:0: +359,175,12226,2,0,L|345:231,1,50,10|0,3:0|0:0,0:0:0:0: +440,260,12449,6,0,L|433:202,1,50,2|10,3:2|0:0,0:0:0:0: +340,154,12671,2,0,L|346:211,1,50,2|0,0:3|0:0,0:0:0:0: +432,124,12893,6,0,L|420:94,1,25,10|0,0:0|0:0,0:0:0:0: +422,100,13004,2,0,L|404:56,1,25,2|2,0:0|0:0,0:0:0:0: +412,76,13115,2,0,L|400:48,1,25,2|2,0:0|0:0,0:0:0:0: +403,53,13226,2,0,L|392:26,1,25,10|0,0:0|0:0,0:0:0:0: +352,4,13337,5,2,0:0:0:0: +352,4,13449,1,10,0:0:0:0: +352,4,13560,1,8,3:2:0:0: +352,4,13671,6,0,L|324:96,1,50,0|0,1:0|0:0,0:0:0:0: +257,89,13893,2,0,L|229:-3,1,50,0|0,1:0|0:0,0:0:0:0: +66,72,17004,5,8,3:2:0:0: +128,199,17226,1,8,3:2:0:0: +207,82,17449,1,8,3:2:0:0: +283,160,17560,6,0,L|345:154,1,50,8|0,0:0|2:0,0:0:0:0: +487,113,17782,6,0,L|437:107,3,50,4|0|0|0,0:2|0:0|0:0|0:0,0:0:0:0: +403,76,18226,1,8,0:0:0:0: +365,107,18337,1,0,0:0:0:0: +356,156,18449,1,0,0:0:0:0: +379,199,18560,1,0,0:0:0:0: +423,222,18671,6,0,L|473:228,1,50,8|0,0:0|0:0,0:0:0:0: +332,345,18893,1,0,0:0:0:0: +332,345,19004,2,0,L|322:279,1,50,0|8,0:0|0:0,0:0:0:0: +211,233,19226,1,0,0:0:0:0: +211,233,19337,2,0,L|201:299,1,50 +91,298,19560,6,0,L|28:291,1,50,8|0,0:0|0:0,0:0:0:0: +166,184,19782,2,0,L|178:253,1,50 +220,356,20004,1,8,0:0:0:0: +263,331,20115,1,0,0:0:0:0: +312,322,20226,1,0,0:0:0:0: +361,329,20337,2,0,L|394:368,1,50,0|8,0:0|0:0,0:0:0:0: +457,201,20560,5,0,0:0:0:0: +457,201,20671,1,0,0:0:0:0: +457,201,20782,2,0,L|460:132,2,50,2|8|0,0:0|0:0|0:0,0:0:0:0: +344,244,21115,2,0,L|335:178,1,59.9999981689454,2|2,0:0|0:0,0:0:0:0: +214,70,21337,5,8,3:2:0:0: +263,76,21449,1,0,3:0:0:0: +313,82,21560,1,0,3:0:0:0: +362,88,21671,2,0,L|263:113,1,100,0|0,3:0|3:0,0:0:0:0: +164,64,22004,1,0,3:0:0:0: +164,64,22115,2,0,L|92:55,1,50,0|8,3:0|0:0,0:0:0:0: +21,221,22337,5,0,3:0:0:0: +69,229,22449,1,0,3:0:0:0: +114,208,22560,1,0,3:0:0:0: +139,166,22671,1,10,3:2:0:0: +145,226,22782,1,2,3:2:0:0: +150,286,22893,2,0,P|210:292|268:248,1,119.999996337891,2|8,3:2|0:0,0:0:0:0: +384,243,23226,5,0,0:0:0:0: +384,243,23337,1,0,0:0:0:0: +384,243,23449,2,0,L|389:193,2,50,0|8|0,0:0|0:0|0:0,0:0:0:0: +334,331,23782,1,0,0:0:0:0: +285,319,23893,1,0,0:0:0:0: +236,325,24004,1,10,0:2:0:0: +191,346,24115,1,2,0:0:0:0: +155,381,24226,6,0,L|42:371,1,100,2|10,0:0|0:2,0:0:0:0: +148,254,24560,1,2,0:0:0:0: +148,254,24671,2,0,L|261:243,1,100,2|8,0:0|0:0,0:0:0:0: +90,134,25115,6,0,L|98:196,1,50 +30,218,25337,2,0,B|45:131|45:131|42:126|42:126|46:123|46:123|57:64,1,150.000005722046,2|2,1:0|0:0,0:0:0:0: +179,120,25671,6,0,P|234:119|291:93,1,100 +349,47,26004,1,0,0:0:0:0: +349,47,26115,2,0,P|325:96|342:165,1,100 +411,158,26449,1,0,0:0:0:0: +411,158,26560,2,0,P|435:109|418:40,1,100 +351,96,26893,1,0,0:0:0:0: +384,255,27115,5,8,0:0:0:0: +384,255,27226,1,0,0:0:0:0: +384,255,27337,1,0,0:0:0:0: +384,255,27449,2,0,L|447:250,2,50,0|8|0,0:0|0:0|0:0,0:0:0:0: +228,173,27782,6,0,L|176:209,1,50,2|2,0:0|0:0,0:0:0:0: +279,342,28004,1,8,0:0:0:0: +279,342,28115,1,0,0:0:0:0: +279,342,28226,2,0,L|280:281,1,50,2|2,0:0|0:0,0:0:0:0: +357,136,28449,5,8,3:2:0:0: +307,139,28560,1,0,3:0:0:0: +257,142,28671,1,0,3:0:0:0: +207,145,28782,2,0,L|151:150,2,50,0|8|0,3:0|0:0|3:0,0:0:0:0: +257,142,29115,5,0,3:0:0:0: +307,139,29226,2,0,L|409:161,1,100,0|0,3:0|3:0,0:0:0:0: +445,188,29560,1,0,3:0:0:0: +468,231,29671,1,0,3:0:0:0: +464,280,29782,1,10,3:2:0:0: +435,320,29893,1,2,3:2:0:0: +389,339,30004,2,0,L|329:327,1,50,10|0,3:2|0:0,0:0:0:0: +177,222,30226,6,0,L|146:193,1,25,8|0,0:0|3:0,3:0:0:0: +145,248,30337,2,0,L|102:231,1,25,8|0,0:0|3:0,0:0:0:0: +130,287,30449,2,0,L|90:290,1,25,8|0,0:0|3:0,0:0:0:0: +134,328,30560,2,0,B|174:349|174:349|239:343,1,100,8|0,1:2|3:0,0:0:0:0: +294,251,30893,6,0,L|290:192,1,50,0|0,1:0|3:0,0:0:0:0: +226,74,31115,2,0,L|222:133,1,50,4|0,0:1|3:0,0:0:0:0: +359,150,31337,1,4,0:1:0:0: +359,150,31782,6,0,P|408:124|464:148,1,89.9999972534181,0|0,1:0|1:0,0:0:0:0: +340,240,32004,6,0,L|288:36,1,179.999994506836,12|0,0:0|0:0,0:0:0:0: +176,132,32449,2,0,P|87:100|7:180,1,179.999994506836,8|0,0:0|0:0,0:0:0:0: +139,383,32893,2,0,P|83:316|104:232,1,179.999994506836,8|0,0:0|0:0,0:0:0:0: +205,291,33337,6,0,L|449:323,1,179.999994506836,8|0,0:0|0:0,0:0:0:0: +506,223,33782,2,0,L|262:191,1,179.999994506836,8|0,0:0|0:0,0:0:0:0: +182,205,34226,6,0,P|261:157|336:244,1,179.999994506836,8|0,0:0|0:0,0:0:0:0: +76,191,34671,2,0,P|28:112|115:37,1,179.999994506836,8|0,0:0|0:0,0:0:0:0: +182,205,35115,6,2,L|155:305,1,89.9999972534181,10|0,0:0|0:0,0:1:0:0: +257,361,35337,2,2,L|284:261,1,89.9999972534181,2|0,0:0|0:0,0:1:0:0: +334,174,35560,6,0,P|339:277|458:283,1,179.999994506836,8|0,0:0|0:0,0:0:0:0: +447,191,36004,2,0,L|505:21,1,179.999994506836,8|0,0:0|0:0,0:0:0:0: +334,174,36449,6,0,P|269:112|169:165,1,179.999994506836,8|0,0:0|0:0,0:0:0:0: +133,25,36893,2,0,L|165:279,1,179.999994506836,8|0,0:0|0:0,0:0:0:0: +22,281,37337,6,0,P|91:338|207:265,1,179.999994506836,8|0,0:0|0:0,0:0:0:0: +306,240,37782,2,0,P|239:184|155:203,1,179.999994506836,8|0,0:0|0:0,0:0:0:0: +0,92,38226,2,0,L|266:54,1,179.999994506836,8|8,0:0|0:0,0:0:0:0: +363,43,38671,6,2,P|386:76|392:133,1,89.9999972534181,10|0,0:0|0:0,0:1:0:0: +306,240,38893,2,2,P|283:207|277:150,1,89.9999972534181,10|0,0:0|0:0,0:1:0:0: +421,293,39115,5,8,3:2:0:0: +368,278,39226,1,0,3:0:0:0: +313,273,39337,1,2,3:3:0:0: +259,284,39449,1,0,0:0:0:0: +214,316,39560,1,8,3:2:0:0: +166,343,39671,1,0,3:0:0:0: +112,332,39782,1,2,3:3:0:0: +76,289,39893,1,0,0:0:0:0: +68,234,40004,1,10,3:2:0:0: +94,185,40115,1,0,3:0:0:0: +136,149,40226,1,0,3:0:0:0: +190,147,40337,1,2,3:0:0:0: +241,167,40449,1,8,0:0:0:0: +261,217,40560,1,0,3:0:0:0: +240,267,40671,1,2,3:0:0:0: +188,285,40782,1,0,0:0:0:0: +135,268,40893,5,8,3:2:0:0: +114,216,41004,1,0,3:0:0:0: +137,166,41115,1,2,3:0:0:0: +190,147,41226,1,0,0:0:0:0: +241,167,41337,1,8,3:2:0:0: +295,170,41449,1,0,3:0:0:0: +348,157,41560,1,2,3:0:0:0: +390,121,41671,1,0,0:0:0:0: +394,66,41782,1,10,3:2:0:0: +364,18,41893,1,0,3:0:0:0: +316,0,42004,1,0,3:0:0:0: +262,11,42115,1,2,3:0:0:0: +214,26,42226,6,2,L|107:43,1,89.9999972534181,8|2,0:0|3:0,0:1:0:0: +2,149,42449,2,2,L|109:166,1,89.9999972534181,4|0,3:2|0:0,0:1:0:0: +336,200,42671,5,12,3:2:0:0: +288,172,42782,1,0,3:0:0:0: +232,173,42893,1,0,3:0:0:0: +189,207,43004,1,0,0:0:0:0: +160,255,43115,1,10,3:0:0:0: +168,308,43226,1,0,3:0:0:0: +196,355,43337,1,2,3:0:0:0: +249,366,43449,1,0,0:0:0:0: +295,337,43560,1,8,3:2:0:0: +303,283,43671,1,0,3:0:0:0: +277,233,43782,1,0,3:0:0:0: +224,216,43893,1,2,3:0:0:0: +172,228,44004,1,8,0:0:0:0: +124,248,44115,1,0,0:0:0:0: +72,232,44226,1,2,3:0:0:0: +32,196,44337,1,0,3:0:0:0: +28,144,44449,6,0,L|1:135,1,25,8|0,0:0|0:0,0:0:0:0: +62,96,44560,2,0,L|45:73,1,25 +119,77,44671,2,0,L|119:49,1,25,8|0,0:0|0:0,0:0:0:0: +175,96,44782,2,0,L|191:73,1,25 +210,144,44893,2,0,L|236:135,1,25,8|0,0:0|0:0,0:0:0:0: +228,200,45004,2,0,L|201:209,1,25,8|0,0:0|0:0,0:0:0:0: +262,248,45115,2,0,L|245:271,1,25,8|0,0:0|0:0,0:0:0:0: +319,267,45226,2,0,L|319:295,1,25,8|0,0:0|0:0,0:0:0:0: +375,248,45337,2,8,L|391:271,1,25 +410,200,45449,2,8,L|436:209,1,25 +410,141,45560,2,8,L|436:132,1,25 +375,93,45671,5,12,0:3:0:0: +375,93,46004,2,0,L|317:86,1,50,0|12,1:0|0:2,0:0:0:0: +317,167,46337,5,0,0:0:0:0: +317,167,46449,2,0,L|160:184,1,150.000005722046,2|8,0:0|0:0,0:0:0:0: +53,101,46782,1,0,0:0:0:0: +108,98,46893,1,0,1:0:0:0: +152,130,47004,1,0,0:0:0:0: +167,183,47115,6,2,L|161:268,1,75.0000028610231,10|0,0:2|0:0,0:1:0:0: +49,308,47337,1,0,1:0:0:0: +49,308,47449,2,2,L|44:204,1,75.0000028610231,2|8,0:0|0:0,0:1:0:0: +205,140,47671,1,0,0:0:0:0: +205,140,47782,2,2,L|210:244,1,75.0000028610231,2|0,1:2|0:0,0:1:0:0: +310,353,48004,5,8,0:0:0:0: +346,347,48115,1,0,0:0:0:0: +383,341,48226,2,0,P|440:289|426:219,1,150.000005722046,2|8,1:2|0:0,0:0:0:0: +317,167,48560,1,0,0:0:0:0: +307,112,48671,1,0,1:0:0:0: +333,64,48782,1,0,0:0:0:0: +384,43,48893,6,2,L|468:54,1,75.0000028610231,10|0,0:2|0:0,0:1:0:0: +506,161,49115,1,0,1:0:0:0: +506,161,49226,2,2,L|422:150,1,75.0000028610231,2|8,0:0|0:0,0:1:0:0: +268,121,49449,1,0,0:0:0:0: +268,121,49560,2,2,L|352:110,1,75.0000028610231,2|0,1:2|0:0,0:1:0:0: +263,263,49782,5,8,0:0:0:0: +228,247,49893,1,0,0:0:0:0: +193,232,50004,2,0,P|128:234|53:312,1,150.000005722046,2|8,1:2|0:0,0:0:0:0: +121,164,50337,1,0,0:0:0:0: +120,109,50449,1,0,1:0:0:0: +91,62,50560,1,0,0:0:0:0: +42,37,50671,6,2,L|123:29,1,75.0000028610231,10|0,0:2|0:0,0:1:0:0: +242,84,50893,1,0,1:0:0:0: +242,84,51004,2,2,L|321:118,1,75.0000028610231,2|8,0:0|0:0,0:1:0:0: +341,245,51226,1,0,0:0:0:0: +341,245,51337,2,2,L|353:331,1,75.0000028610231,2|0,1:2|0:0,0:1:0:0: +163,192,51560,5,8,0:0:0:0: +198,181,51671,1,0,0:0:0:0: +233,170,51782,2,0,P|303:163|372:219,1,150.000005722046,2|8,1:2|0:0,0:0:0:0: +458,297,52115,1,0,0:0:0:0: +460,240,52226,1,0,1:0:0:0: +463,184,52337,1,0,0:0:0:0: +466,128,52449,6,0,B|452:65|452:65|416:155,1,150.000005722046,10|2,0:2|1:2,0:0:0:0: +272,189,52782,2,0,L|197:180,1,75.0000028610231,2|8,0:0|0:0,0:1:0:0: +338,25,53004,1,2,0:0:0:0: +338,25,53115,2,0,L|345:109,1,75.0000028610231,10|0,1:2|0:0,0:1:0:0: +179,225,53337,5,8,0:0:0:0: +175,187,53449,1,0,0:0:0:0: +172,149,53560,2,0,L|320:166,1,150.000005722046,2|8,1:2|0:0,0:0:0:0: +296,293,53893,1,0,0:0:0:0: +259,334,54004,1,0,1:0:0:0: +209,357,54115,1,0,0:0:0:0: +154,358,54226,6,2,L|79:349,1,75.0000028610231,10|0,0:2|0:0,0:1:0:0: +179,225,54449,1,0,1:0:0:0: +179,225,54560,2,2,L|253:233,1,75.0000028610231,2|8,0:0|0:0,0:1:0:0: +91,140,54782,1,0,0:0:0:0: +91,140,54893,2,2,L|16:148,1,75.0000028610231,2|0,1:2|0:0,0:1:0:0: +191,43,55115,5,8,0:0:0:0: +195,80,55226,1,0,0:0:0:0: +199,117,55337,2,0,B|179:225|179:225|156:170,1,150.000005722046,2|8,1:2|0:0,0:0:0:0: +289,165,55671,1,0,0:0:0:0: +344,159,55782,1,0,1:0:0:0: +399,154,55893,1,0,0:0:0:0: +454,149,56004,6,2,L|461:235,1,75.0000028610231,10|0,0:2|0:0,0:1:0:0: +359,281,56226,1,0,1:0:0:0: +359,281,56337,2,2,L|365:366,1,75.0000028610231,2|8,0:2|0:0,0:1:0:0: +262,132,56560,1,0,0:0:0:0: +262,132,56671,2,2,L|268:217,1,75.0000028610231,2|0,1:2|0:0,0:1:0:0: +148,358,56893,5,12,0:2:0:0: +110,355,57004,1,0,0:0:0:0: +79,333,57115,2,0,P|134:285|209:317,1,150.000005722046,2|8,1:2|0:0,0:0:0:0: +329,327,57449,1,0,0:0:0:0: +359,281,57560,1,0,1:0:0:0: +364,226,57671,1,0,0:0:0:0: +343,175,57782,6,2,L|246:184,1,75.0000028610231,10|0,0:2|0:0,0:1:0:0: +342,20,58004,1,0,1:0:0:0: +342,20,58115,2,2,L|387:85,1,75.0000028610231,2|8,0:0|0:0,0:1:0:0: +210,97,58337,1,0,0:0:0:0: +210,97,58449,2,2,L|243:24,1,75.0000028610231,10|0,1:2|0:0,0:1:0:0: +343,175,58671,6,0,L|305:177,3,37.5000014305115,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: +209,209,58893,2,0,L|255:224,3,37.5000014305115,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: +316,267,59115,2,0,L|283:301,3,37.5000014305115,8|0|8|0,0:0|0:0|0:0|0:0,0:0:0:0: +211,329,59337,2,0,L|194:274,3,37.5000014305115,8|0|8|0,0:0|0:0|0:0|0:0,0:0:0:0: +103,287,59560,6,0,L|67:275,1,37.5000014305115,0|0,1:0|3:0,0:0:0:0: +108,240,59671,2,0,L|72:228,1,37.5000014305115,0|0,1:0|3:0,0:0:0:0: +113,193,59782,2,0,L|77:181,1,37.5000014305115,0|0,1:0|3:0,0:0:0:0: +120,146,59893,1,12,0:3:0:0: +120,146,60226,6,0,L|131:40,1,100,0|12,1:0|0:2,0:0:0:0: +374,174,60893,5,8,0:0:0:0: +326,323,61115,1,0,3:0:0:0: +462,267,61337,2,0,L|518:267,1,50,8|0,0:0|0:0,0:0:0:0: +344,182,61560,5,0,0:0:0:0: +344,182,61671,2,0,L|297:213,1,50,0|8,3:0|0:0,0:0:0:0: +174,241,61893,1,0,0:0:0:0: +174,241,62004,2,0,L|221:272,1,50,0|0,3:0|0:0,0:0:0:0: +66,161,62226,5,8,0:0:0:0: +104,326,62449,1,0,3:0:0:0: +269,288,62671,1,8,0:0:0:0: +231,122,62893,2,0,L|215:50,1,50,0|0,3:0|0:0,0:0:0:0: +296,0,63115,2,0,L|312:72,1,50,8|0,0:0|0:0,0:0:0:0: +373,120,63337,5,0,0:0:0:0: +373,120,63449,2,0,P|413:112|477:152,1,100,0|0,3:0|3:0,0:0:0:0: +400,216,63782,2,0,L|288:232,1,100,0|8,0:0|0:0,0:0:0:0: +48,160,64226,5,0,3:0:0:0: +216,200,64449,1,8,0:0:0:0: +104,288,64671,1,0,3:0:0:0: +216,200,64893,1,8,0:0:0:0: +160,64,65115,5,0,0:0:0:0: +160,64,65226,2,0,L|160:136,1,50,0|8,3:0|0:0,0:0:0:0: +264,104,65449,1,0,0:0:0:0: +264,104,65560,2,0,L|264:168,1,50,0|0,3:0|0:0,0:0:0:0: +456,160,65782,5,8,0:0:0:0: +288,192,66004,1,0,3:0:0:0: +336,48,66226,1,8,0:0:0:0: +408,296,66449,1,0,3:0:0:0: +196,148,66671,6,0,P|188:215|221:271,1,100,8|8,0:0|0:0,0:0:0:0: +288,192,67004,6,0,L|368:216,1,50,0|8,3:0|0:0,0:0:0:0: +297,308,67226,1,0,3:0:0:0: +297,308,67337,2,0,L|217:332,1,50,12|0,0:0|0:0,0:0:0:0: +107,256,67560,6,0,P|150:234|199:244,1,100,14|0,0:0|0:0,0:0:0:0: +460,300,68004,5,8,0:0:0:0: +407,107,68226,1,0,3:0:0:0: +364,364,68449,1,8,0:0:0:0: +345,18,68671,6,0,P|417:2|505:66,1,150.000005722046,2|8,0:0|0:0,0:0:0:0: +167,18,69115,2,0,P|95:2|7:66,1,150.000005722046,2|8,0:0|0:0,0:0:0:0: +407,107,69560,6,0,P|456:161|445:269,1,150.000005722046,2|8,0:0|0:0,0:0:0:0: +158,202,70004,1,0,0:0:0:0: +354,202,70226,1,8,0:0:0:0: +105,107,70449,2,0,P|55:161|66:269,1,150.000005722046,2|8,0:0|0:0,0:0:0:0: +364,281,70893,6,0,P|418:330|526:319,1,150.000005722046,0|8,0:0|0:0,0:0:0:0: +424,64,71337,6,0,B|434:73|434:73|467:145|424:213|284:257|262:111|277:26|173:-19|99:9|48:91|87:209|211:192|211:192|334:175|373:294|323:376|248:404|162:332,1,1050.00004005432,2|8,3:2|0:0,0:0:0:0: +161,331,73337,6,0,L|201:331,1,25,8|0,0:0|3:0,0:0:0:0: +186,331,73449,2,2,L|233:331,1,25,0|0,3:0|3:0,0:0:0:0: +211,331,73560,2,2,L|257:331,1,25,8|0,0:0|3:0,0:0:0:0: +236,331,73671,2,2,L|273:331,1,25,0|0,3:0|3:0,0:0:0:0: +297,339,73782,6,0,L|377:347,1,50,8|8,0:0|0:0,0:0:0:0: +321,181,74004,2,0,L|313:269,1,50,8|8,0:0|3:2,0:0:0:0: +184,116,74226,2,0,L|176:28,1,50,0|8,0:0|3:2,0:0:0:0: +283,82,74449,6,0,P|332:75|377:94,1,100,8|12,0:0|0:0,0:0:0:0: +150,188,75115,5,8,0:0:0:0: +127,46,75337,1,0,0:0:0:0: +157,218,75560,2,0,P|211:199|262:204,1,100,8|0,0:0|0:0,0:0:0:0: +322,283,75893,2,0,B|370:288|370:288|436:262,1,100,0|0,3:0|3:0,0:0:0:0: +439,170,76226,2,0,P|392:159|356:191,1,100,0|8,3:0|0:0,0:0:0:0: +219,92,76671,5,0,3:0:0:0: +371,22,76893,1,8,0:0:0:0: +356,191,77115,1,0,3:0:0:0: +194,73,77337,2,0,P|144:75|94:82,1,100,8|0,0:0|0:0,0:0:0:0: +15,164,77671,2,0,P|63:173|98:210,1,100,0|0,3:0|3:0,0:0:0:0: +26,302,78004,2,0,L|21:253,1,50 +181,348,78226,6,0,B|221:330|221:330|276:335,1,100,8|0,0:0|3:0,0:0:0:0: +422,231,78671,1,8,0:0:0:0: +435,376,78893,1,0,3:0:0:0: +271,230,79115,2,0,L|281:123,1,100,8|0,0:0|0:0,0:0:0:0: +367,56,79449,2,0,P|393:101|389:159,1,100,0|0,3:0|3:0,0:0:0:0: +280,130,79782,2,0,L|226:137,1,50,0|0,3:0|0:0,0:0:0:0: +104,280,80004,5,8,0:0:0:0: +243,207,80226,1,0,3:0:0:0: +104,134,80449,1,8,0:0:0:0: +243,61,80671,1,0,3:0:0:0: +384,189,80893,6,0,L|330:203,1,50,8|0,0:0|0:0,0:0:0:0: +259,262,81115,2,0,L|211:250,1,50,8|0,0:0|0:0,0:0:0:0: +83,157,81337,1,8,1:2:0:0: +60,186,81449,1,0,3:0:0:0: +48,221,81560,1,8,1:2:0:0: +48,259,81671,1,0,3:0:0:0: +61,294,81782,6,0,P|116:293|162:329,1,100,10|0,1:2|0:0,0:0:0:0: +350,269,82226,1,8,0:0:0:0: +226,187,82449,1,0,3:0:0:0: +265,365,82671,1,8,0:0:0:0: +444,207,82893,2,0,P|449:142|420:85,1,129.999994049073,2|8,0:0|0:0,0:0:0:0: +211,48,83337,6,0,P|159:84|136:144,1,129.999994049073,2|8,0:0|0:0,0:0:0:0: +270,337,83782,2,0,B|297:279|256:269|288:205,1,129.999994049073,2|8,0:0|0:0,0:0:0:0: +427,124,84226,1,0,3:0:0:0: +427,124,84337,1,0,3:0:0:0: +427,124,84449,1,8,0:0:0:0: +136,144,84671,2,0,B|183:228|275:200|275:200|303:273|208:263,1,259.999988098145,2|4,0:0|0:1,0:0:0:0: +235,99,85337,5,12,0:2:0:0: +278,92,85449,1,0,0:0:0:0: +319,109,85560,1,2,0:0:0:0: +174,43,85782,1,10,0:2:0:0: +129,35,85893,1,0,1:0:0:0: +86,47,86004,1,0,3:0:0:0: +52,75,86115,1,0,1:0:0:0: +32,115,86226,6,0,L|37:155,3,25,10|0|0|0,0:2|3:0|3:0|3:0,0:0:0:0: +83,252,86449,2,0,L|87:212,3,25,0|0|2|0,1:0|3:0|3:2|3:0,0:0:0:0: +174,189,86671,6,0,L|235:185,2,50,8|0|8,0:0|3:0|0:0,0:0:0:0: +83,252,87004,1,0,0:0:0:0: +83,252,87115,6,0,L|92:311,1,50,12|2,1:2|3:2,0:0:0:0: +185,379,87337,2,0,L|205:328,1,50,10|0,1:2|3:0,0:0:0:0: +310,279,87560,2,0,L|362:285,1,50,8|8,1:2|1:2,0:0:0:0: +490,357,87782,2,0,L|493:386,2,25,8|0|8,1:2|3:0|1:2,0:0:0:0: +456,208,88004,5,0,1:0:0:0: +456,208,88060,1,0,3:0:0:0: +456,208,88115,2,0,L|472:128,1,50,8|0,1:2|0:0,0:0:0:0: +352,40,88337,2,0,L|368:88,1,50,8|2,1:2|0:0,0:0:0:0: +256,136,88560,1,8,1:2:0:0: +256,136,88671,2,0,L|240:80,1,50 +48,184,88893,6,0,P|120:168|216:224,1,170.000003242493,12|0,0:2|0:0,0:0:0:0: +328,336,89226,1,0,0:0:0:0: +424,328,89337,1,8,0:2:0:0: +472,248,89449,1,0,0:0:0:0: +488,160,89560,6,0,P|440:56|352:48,1,170.000003242493,0|8,0:0|0:2,0:0:0:0: +256,104,89893,1,0,0:0:0:0: +168,128,90004,1,0,0:0:0:0: +80,120,90115,1,0,0:0:0:0: +0,88,90226,6,0,P|-8:136|8:216,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +96,336,90449,2,0,P|104:288|88:208,1,85.0000016212464 +173,43,90671,6,0,P|165:85|168:128,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +256,296,90893,2,0,P|264:248|248:168,1,85.0000016212464 +336,72,91115,6,0,L|560:56,1,170.000003242493,10|0,0:2|0:0,0:0:0:0: +432,120,91449,1,2,0:2:0:0: +392,200,91560,1,8,0:2:0:0: +432,288,91671,1,0,0:0:0:0: +496,360,91782,5,2,0:2:0:0: +256,296,92004,1,10,0:2:0:0: +16,360,92226,2,0,P|64:272|48:184,1,170.000003242493,2|8,0:2|0:2,0:0:0:0: +120,40,92560,5,0,0:0:0:0: +168,120,92671,1,0,0:0:0:0: +248,168,92782,1,0,0:0:0:0: +328,120,92893,6,0,P|414:120|477:240,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +472,360,93226,1,0,0:0:0:0: +472,360,93337,2,0,P|396:319|396:183,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +328,120,93671,5,0,0:0:0:0: +328,120,93782,2,0,L|312:8,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +93,147,94004,6,0,P|174:128|248:168,1,170.000003242493,2|8,0:2|0:2,0:0:0:0: +448,288,94337,1,0,0:0:0:0: +360,264,94449,1,2,0:2:0:0: +272,288,94560,1,0,0:0:0:0: +216,360,94671,6,0,P|152:304|168:224,1,170.000003242493,10|0,0:2|0:0,0:0:0:0: +216,104,95004,5,2,0:2:0:0: +216,104,95115,2,0,L|232:16,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +368,48,95337,2,0,P|408:32|472:48,1,85.0000016212464 +432,224,95560,2,0,P|416:184|432:120,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +320,280,95782,2,0,P|336:320|320:384,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +32,232,96004,6,0,P|112:192|224:240,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +320,280,96337,1,0,0:0:0:0: +408,312,96449,1,8,0:2:0:0: +496,280,96560,1,0,0:0:0:0: +496,280,96671,6,0,L|456:112,1,170.000003242493,0|8,0:0|0:2,0:0:0:0: +384,56,97004,1,0,0:0:0:0: +296,24,97115,2,0,P|240:16|160:64,1,85.0000016212464 +104,160,97337,2,0,P|160:168|240:120,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +456,192,97560,6,0,P|384:160|304:248,1,170.000003242493,0|8,0:0|0:2,0:0:0:0: +264,288,97893,1,0,0:0:0:0: +176,264,98004,2,0,L|8:280,1,85.0000016212464 +16,88,98226,6,0,P|64:136|168:56,1,170.000003242493,10|0,0:2|0:0,0:0:0:0: +328,56,98560,1,2,0:2:0:0: +416,32,98671,1,8,0:2:0:0: +480,104,98782,1,0,0:0:0:0: +456,192,98893,6,0,L|464:280,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +328,360,99115,2,0,L|320:272,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +208,112,99337,2,0,L|216:200,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +64,320,99560,5,8,0:2:0:0: +136,264,99671,1,0,0:0:0:0: +232,256,99782,1,0,0:0:0:0: +320,280,99893,1,0,0:0:0:0: +384,344,100004,6,0,P|408:288|416:248,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +360,72,100226,2,0,P|336:128|328:168,1,85.0000016212464 +240,312,100449,5,8,0:2:0:0: +152,344,100560,1,0,0:0:0:0: +64,320,100671,1,0,0:0:0:0: +8,248,100782,1,0,0:0:0:0: +16,152,100893,1,8,0:2:0:0: +88,88,101004,1,0,0:0:0:0: +184,80,101115,1,0,0:0:0:0: +272,120,101226,1,0,0:0:0:0: +356,176,101337,5,10,0:2:0:0: +456,164,101449,1,0,0:0:0:0: +392,88,101560,1,2,0:2:0:0: +348,184,101671,5,0,0:0:0:0: +448,172,101782,1,10,0:2:0:0: +384,96,101893,1,0,0:0:0:0: +340,192,102004,5,10,0:2:0:0: +440,180,102115,1,0,0:0:0:0: +376,104,102226,2,0,P|329:93|290:112,1,85.0000016212464,10|8,1:2|1:2,0:0:0:0: +344,192,102449,2,0,P|380:226|423:229,1,85.0000016212464,0|8,0:0|0:0,0:0:0:0: +169,239,102671,5,2,1:2:0:0: +80,210,102782,1,0,1:0:0:0: +80,117,102893,1,8,1:2:0:0: +169,88,103004,1,8,1:2:0:0: +224,164,103115,6,0,P|315:166|404:144,1,170.000003242493,12|0,1:2|0:0,0:0:0:0: +456,317,103449,1,0,0:0:0:0: +366,290,103560,1,8,1:2:0:0: +324,206,103671,1,2,0:2:0:0: +326,112,103782,2,0,L|344:10,2,85.0000016212464,0|0|10,0:0|0:0|0:2,0:0:0:0: +314,203,104115,5,0,0:0:0:0: +242,148,104226,2,0,L|184:87,1,85.0000016212464 +398,167,104449,2,0,L|479:122,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +365,276,104671,2,0,L|383:378,2,85.0000016212464,0|0|8,0:0|0:0|0:2,0:0:0:0: +183,86,105004,5,0,0:0:0:0: +99,88,105115,1,0,0:0:0:0: +31,137,105226,1,0,0:0:0:0: +3,216,105337,1,10,0:2:0:0: +24,297,105449,1,0,0:0:0:0: +87,352,105560,1,0,0:0:0:0: +152,298,105671,1,2,0:2:0:0: +233,273,105782,1,8,0:2:0:0: +317,283,105893,1,0,0:0:0:0: +391,324,106004,6,0,L|484:310,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +282,227,106226,2,0,L|189:212,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +46,357,106449,2,0,L|138:342,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +62,140,106671,1,8,0:2:0:0: +62,140,106782,1,0,0:0:0:0: +62,140,106893,1,0,0:0:0:0: +62,140,107004,1,0,0:0:0:0: +62,140,107115,6,0,L|245:116,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +418,227,107449,1,0,0:0:0:0: +330,251,107560,1,8,1:2:0:0: +251,206,107671,1,0,0:0:0:0: +230,117,107782,1,0,0:0:0:0: +277,35,107893,1,0,0:0:0:0: +347,130,108004,2,0,L|247:147,1,85.0000016212464,8|0,1:2|0:0,0:0:0:0: +46,62,108226,6,0,P|30:145|24:230,1,170.000003242493,2|8,0:2|1:2,0:0:0:0: +215,312,108560,1,0,0:0:0:0: +215,312,108671,2,0,P|191:272|152:252,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +62,140,108893,2,0,P|146:173|234:167,1,170.000003242493,10|0,1:2|0:0,0:0:0:0: +371,114,109226,2,0,L|376:22,2,85.0000016212464,2|8|0,0:2|1:2|0:0,0:0:0:0: +312,190,109560,5,0,0:0:0:0: +389,239,109671,1,0,0:0:0:0: +308,283,109782,1,8,1:2:0:0: +386,333,109893,1,0,0:0:0:0: +305,377,110004,2,0,P|267:367|226:331,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +77,199,110226,6,0,P|152:149|227:172,1,170.000003242493,8|0,1:2|0:0,0:0:0:0: +417,221,110560,1,0,0:0:0:0: +444,135,110671,1,8,1:2:0:0: +389,64,110782,1,0,0:0:0:0: +299,68,110893,2,0,P|210:71|156:9,1,170.000003242493,0|8,0:0|1:2,0:0:0:0: +62,140,111226,1,0,0:0:0:0: +62,140,111337,2,0,L|83:234,1,85.0000016212464 +262,296,111560,2,0,L|169:278,1,85.0000016212464,8|0,1:2|0:0,0:0:0:0: +349,153,111782,6,0,L|340:68,2,85.0000016212464,0|0|8,0:0|0:0|1:2,0:0:0:0: +236,329,112115,1,0,0:0:0:0: +292,267,112226,1,0,0:0:0:0: +375,253,112337,1,0,0:0:0:0: +449,291,112449,1,10,1:2:0:0: +378,336,112560,5,2,0:2:0:0: +375,253,112671,1,0,0:0:0:0: +372,170,112782,1,2,0:2:0:0: +369,87,112893,1,8,1:2:0:0: +442,125,113004,1,0,0:0:0:0: +348,178,113115,6,0,L|252:169,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +80,269,113337,2,0,P|120:276|175:256,1,85.0000016212464,10|0,1:2|0:0,0:0:0:0: +105,18,113560,2,0,P|86:55|87:103,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +260,255,113782,5,12,1:2:0:0: +261,212,113893,1,0,0:0:0:0: +262,170,114004,1,2,0:2:0:0: +414,61,114226,5,8,1:2:0:0: +340,101,114337,1,0,0:0:0:0: +256,109,114449,1,2,0:2:0:0: +176,81,114560,1,0,0:0:0:0: +105,18,114671,1,8,1:2:0:0: +84,118,114782,1,0,0:0:0:0: +63,218,114893,6,2,P|105:233|154:235,1,85.0000016212464,2|0,0:2|0:0,0:2:0:0: +369,328,115115,2,2,P|325:320|276:336,1,85.0000016212464,10|0,1:2|0:0,0:2:0:0: +256,109,115337,2,2,B|301:123|301:123|376:112,1,100,2|0,0:2|0:0,0:1:0:0: +488,273,115560,5,8,1:2:0:0: +488,273,115671,1,8,0:0:0:0: +488,273,115782,1,8,0:0:0:0: +429,83,116004,1,8,1:2:0:0: +429,83,116115,1,0,3:0:0:0: +429,83,116226,6,0,L|431:47,2,32.4999985122681,8|0|0,3:2|3:0|3:0,3:0:0:0: +381,198,116449,1,8,1:2:0:0: +381,198,116560,5,0,1:1:0:0: +187,140,116782,1,0,1:1:0:0: +102,323,117004,1,0,1:1:0:0: +58,34,117337,5,12,0:0:0:0: +380,124,128004,6,0,P|400:120|440:124,1,50,12|0,0:0|0:0,0:0:0:0: +396,256,128226,2,0,P|376:260|336:256,1,50,2|0,1:2|0:0,0:0:0:0: +104,200,128449,6,0,L|116:260,1,50,8|0,0:0|0:0,0:0:0:0: +172,104,128671,2,0,L|160:44,1,50,0|0,1:0|0:0,0:0:0:0: +272,184,128893,5,10,0:2:0:0: +280,208,129004,1,0,0:0:0:0: +280,232,129115,1,0,1:0:0:0: +272,256,129226,1,2,0:2:0:0: +264,280,129337,6,0,L|328:308,1,50,8|0,0:0|0:0,0:0:0:0: +464,260,129560,2,0,L|400:232,1,50,10|0,1:2|0:0,0:0:0:0: +317,113,129782,6,0,L|339:84,1,25,8|0,0:0|0:0,0:0:0:0: +286,96,129893,2,0,L|298:62,1,25 +252,92,130004,2,0,L|251:56,1,25,8|0,0:0|0:0,0:0:0:0: +218,99,130115,2,0,L|205:65,1,25 +189,117,130226,2,0,L|164:90,1,25,8|0,0:0|0:0,0:0:0:0: +167,145,130337,2,0,L|135:128,1,25,8|0,0:0|0:0,0:0:0:0: +156,178,130449,2,0,L|121:173,1,25,8|0,0:0|0:0,0:0:0:0: +158,212,130560,2,0,L|122:220,1,25,8|0,0:0|0:0,0:0:0:0: +171,244,130671,2,0,L|140:264,1,25,0|0,1:0|3:0,0:0:0:0: +194,270,130782,2,0,L|172:299,1,25,0|0,1:0|3:0,0:0:0:0: +225,287,130893,2,0,L|213:321,1,25,0|0,1:0|3:0,0:0:0:0: +259,291,131004,5,12,0:3:0:0: +259,291,131337,6,0,P|312:272|376:300,1,100,0|12,1:0|0:0,0:0:0:0: +456,68,132004,5,8,0:0:0:0: +340,184,132226,1,0,3:0:0:0: +284,20,132449,1,8,0:0:0:0: +156,160,132671,5,0,0:0:0:0: +156,160,132782,2,0,P|216:152|256:160,1,100,0|0,3:0|0:0,0:0:0:0: +92,235,133115,2,0,L|20:251,1,50,0|0,3:0|0:0,0:0:0:0: +281,303,133337,5,8,0:0:0:0: +471,213,133560,1,0,3:0:0:0: +281,303,133782,1,8,0:0:0:0: +363,84,134004,1,0,3:0:0:0: +241,162,134226,6,0,L|222:94,1,50,8|0,0:0|0:0,0:0:0:0: +164,204,134449,1,0,0:0:0:0: +164,204,134560,2,0,P|112:196|51:220,1,100,0|0,3:0|3:0,0:0:0:0: +281,303,134893,2,0,P|333:311|394:287,1,100,0|8,0:0|0:0,0:0:0:0: +500,184,135337,5,0,3:0:0:0: +465,11,135560,1,8,0:0:0:0: +294,44,135782,1,0,3:0:0:0: +327,217,136004,1,8,0:0:0:0: +408,112,136226,5,0,0:0:0:0: +408,112,136337,1,0,3:0:0:0: +364,316,136560,1,0,0:0:0:0: +364,316,136671,1,0,3:0:0:0: +168,292,136893,5,8,0:0:0:0: +48,212,137115,1,0,3:0:0:0: +188,16,137337,1,8,0:0:0:0: +176,156,137560,1,0,3:0:0:0: +344,292,137782,6,0,P|408:288|464:252,1,100,8|0,0:0|0:0,0:0:0:0: +388,176,138115,2,0,P|408:124|400:68,1,100,0|0,3:0|3:0,0:0:0:0: +168,192,138449,1,0,0:0:0:0: +168,192,138560,1,0,0:0:0:0: +168,192,138671,2,0,L|280:204,1,100,10|0,0:0|3:0,0:0:0:0: +464,168,139115,5,8,0:0:0:0: +344,292,139337,1,0,3:0:0:0: +332,24,139560,1,8,0:0:0:0: +288,368,139782,6,0,P|344:384|404:368,1,100,2|8,0:0|0:0,0:0:0:0: +224,16,140226,2,0,P|168:0|108:16,1,100,2|8,0:0|0:0,0:0:0:0: +80,224,140671,2,0,P|64:280|80:340,1,100,2|8,0:0|0:0,0:0:0:0: +400,152,141115,5,0,0:0:0:0: +300,268,141337,1,8,0:0:0:0: +460,80,141560,2,0,P|404:56|336:88,1,100,2|8,0:0|0:0,0:0:0:0: +332,224,142004,2,0,L|352:360,1,100,0|8,0:0|0:0,0:0:0:0: +184,88,142449,6,0,L|178:38,1,50 +204,136,142671,1,8,0:0:0:0: +212,184,142782,1,0,3:0:0:0: +196,232,142893,1,0,3:0:0:0: +152,256,143004,1,0,0:0:0:0: +104,236,143115,1,8,0:0:0:0: +56,252,143226,1,0,3:0:0:0: +32,296,143337,1,0,3:0:0:0: +52,340,143449,1,0,3:0:0:0: +92,372,143560,1,8,0:0:0:0: +140,352,143671,1,0,3:0:0:0: +188,336,143782,1,8,0:0:0:0: +236,348,143893,1,0,3:0:0:0: +280,368,144004,5,8,0:0:0:0: +448,260,144449,6,0,L|416:248,1,25,8|0,0:0|3:0,0:0:0:0: +424,251,144560,2,0,L|392:240,1,25,0|0,3:0|3:0,0:0:0:0: +400,243,144671,2,0,L|360:228,1,25,8|0,0:0|3:0,0:0:0:0: +377,234,144782,2,0,L|348:224,1,25,0|0,3:0|3:0,0:0:0:0: +316,200,144893,6,0,P|308:176|308:132,1,50,8|8,0:0|0:0,0:0:0:0: +404,40,145115,2,0,P|412:64|412:108,1,50,8|8,0:0|3:2,0:0:0:0: +252,264,145337,5,8,0:0:0:0: +252,264,145449,1,8,3:2:0:0: +252,264,145560,2,0,P|196:256|136:272,1,100,8|12,0:0|0:0,0:0:0:0: +34,77,146226,5,8,0:0:0:0: +54,230,146449,1,0,3:0:0:0: +28,27,146671,2,0,L|36:105,1,50,8|0,0:0|0:0,0:0:0:0: +54,230,146893,1,0,0:0:0:0: +54,230,147004,2,0,L|62:152,1,50,0|8,3:0|0:0,0:0:0:0: +234,135,147226,1,0,0:0:0:0: +234,135,147337,2,0,L|347:149,1,100,0|8,3:0|0:0,0:0:0:0: +156,190,147782,5,0,3:0:0:0: +333,147,148004,1,8,0:0:0:0: +133,120,148226,1,0,3:0:0:0: +358,65,148449,2,0,L|261:89,1,100,8|0,0:0|0:0,0:0:0:0: +333,147,148782,2,0,L|446:161,1,100,0|0,3:0|3:0,0:0:0:0: +321,275,149115,2,0,L|302:214,1,50,0|0,1:0|0:0,0:0:0:0: +462,165,149337,6,0,L|428:273,1,100,8|0,0:0|3:0,0:0:0:0: +393,83,149782,1,8,0:0:0:0: +431,260,150004,1,0,3:0:0:0: +221,288,150226,2,0,L|331:273,1,100,8|0,0:0|0:0,0:0:0:0: +190,296,150560,2,0,L|171:235,1,50,0|8,3:0|0:0,0:0:0:0: +334,226,150782,1,0,0:0:0:0: +334,226,150893,2,0,L|315:287,1,50,0|0,3:0|0:0,0:0:0:0: +238,135,151115,6,0,L|257:196,1,50,8|0,0:0|0:0,0:0:0:0: +190,296,151337,2,0,L|209:357,1,50,0|0,3:0|0:0,0:0:0:0: +118,72,151560,2,0,L|137:133,1,50,8|0,0:0|0:0,0:0:0:0: +24,221,151782,2,0,L|43:282,1,50,0|0,3:0|0:0,0:0:0:0: +242,367,152004,5,8,0:0:0:0: +276,362,152115,1,0,3:0:0:0: +311,357,152226,1,8,0:0:0:0: +346,353,152337,1,0,3:0:0:0: +386,338,152449,5,8,1:2:0:0: +337,327,152560,1,0,3:0:0:0: +288,317,152671,1,8,1:2:0:0: +239,306,152782,1,0,3:0:0:0: +190,296,152893,1,10,1:2:0:0: +190,296,153337,5,8,0:0:0:0: +241,77,153560,1,0,3:0:0:0: +200,262,153782,1,8,0:0:0:0: +447,200,154004,2,0,L|336:181,1,100,2|8,0:0|0:0,0:0:0:0: +97,119,154449,2,0,L|159:109,1,50,2|0,0:0|0:0,0:0:0:0: +348,183,154671,5,10,0:2:0:0: +151,210,154893,2,0,L|146:111,1,100,2|8,0:0|0:0,0:0:0:0: +353,83,155337,1,0,3:0:0:0: +350,132,155449,1,0,3:0:0:0: +347,182,155560,1,8,0:0:0:0: +31,78,155782,2,0,B|174:62|174:62|145:110,1,200,2|4,0:0|0:1,0:0:0:0: +113,280,156449,6,0,L|111:229,1,50,12|0,0:2|0:0,0:0:0:0: +145,110,156671,1,2,0:0:0:0: +108,312,156893,2,0,L|42:303,1,50,10|0,0:2|1:0,0:0:0:0: +211,208,157115,2,0,L|277:217,1,50,0|0,3:0|1:0,0:0:0:0: +414,288,157337,6,0,L|387:290,3,25,10|0|0|0,0:2|3:0|3:0|3:0,0:0:0:0: +290,340,157560,2,0,L|316:342,3,25,0|0|2|0,1:0|3:0|3:2|3:0,0:0:0:0: +414,288,157782,6,0,L|421:221,1,50,8|0,0:0|3:0,0:0:0:0: +315,130,158004,2,0,L|332:193,1,50,8|0,0:0|3:0,0:0:0:0: +492,100,158226,2,0,L|426:91,1,50,12|2,1:2|3:2,0:0:0:0: +214,158,158449,2,0,L|202:97,1,50,10|0,1:2|3:0,0:0:0:0: +342,13,158671,1,8,1:2:0:0: +342,13,158782,1,8,1:2:0:0: +342,13,158893,2,0,L|339:46,2,25,8|0|8,1:2|3:0|1:2,0:0:0:0: +332,156,159115,5,0,1:0:0:0: +332,156,159171,1,0,3:0:0:0: +332,156,159226,2,0,P|352:156|380:166,1,50,8|0,1:2|0:0,0:0:0:0: +456,260,159449,2,0,P|456:280|446:308,1,50,8|2,1:2|0:0,0:0:0:0: +340,368,159671,1,8,1:2:0:0: +340,368,159782,2,0,P|320:368|292:358,1,50 +44,272,160004,6,0,P|152:268|212:196,1,170.000003242493,12|0,0:2|0:0,0:0:0:0: +324,28,160337,1,0,0:0:0:0: +264,100,160449,1,8,0:2:0:0: +312,180,160560,1,0,0:0:0:0: +404,164,160671,6,0,P|400:248|348:320,1,170.000003242493,0|8,0:0|0:2,0:0:0:0: +184,328,161004,1,0,0:0:0:0: +96,352,161115,1,0,0:0:0:0: +32,280,161226,1,0,0:0:0:0: +56,192,161337,6,0,L|48:104,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +184,24,161560,6,0,P|228:76|344:32,1,170.000003242493,0|8,0:0|0:2,0:0:0:0: +476,176,161893,1,0,0:0:0:0: +384,196,162004,1,0,0:0:0:0: +356,280,162115,1,0,0:0:0:0: +416,352,162226,6,0,L|240:360,1,170.000003242493,10|0,0:2|0:0,0:0:0:0: +64,312,162560,1,2,2:0:0:0: +128,244,162671,1,8,0:2:0:0: +152,156,162782,1,0,0:0:0:0: +96,80,162893,6,0,P|120:40|168:12,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +361,18,163115,2,0,P|395:43|416:80,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +256,224,163337,2,0,L|256:124,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +356,280,163560,5,8,0:2:0:0: +356,280,163671,1,0,0:0:0:0: +356,280,163782,1,0,0:0:0:0: +356,280,163893,1,0,0:0:0:0: +356,280,164004,2,0,P|268:268|212:348,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +124,344,164337,1,0,0:0:0:0: +92,256,164449,2,0,P|140:180|96:92,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +180,184,164782,5,0,0:0:0:0: +180,184,164893,2,0,L|284:176,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +500,88,165115,6,0,P|418:70|345:110,1,170.000003242493,2|8,0:2|0:2,0:0:0:0: +320,236,165449,1,0,0:0:0:0: +320,236,165560,2,0,L|332:336,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +432,156,165782,6,0,P|408:56|320:16,1,170.000003242493,10|0,0:2|0:0,0:0:0:0: +216,64,166115,5,2,0:2:0:0: +216,64,166226,2,0,L|126:70,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +143,208,166449,2,0,P|122:246|132:311,1,85.0000016212464 +312,291,166671,2,0,P|273:270|208:280,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +379,185,166893,2,0,P|417:205|482:195,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +456,64,167115,6,0,P|344:44|284:84,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +112,148,167449,1,0,0:0:0:0: +160,228,167560,1,8,0:2:0:0: +248,256,167671,1,0,0:0:0:0: +336,228,167782,6,0,P|432:216|480:272,1,170.000003242493,0|8,0:0|0:2,0:0:0:0: +392,308,168115,5,0,0:0:0:0: +336,228,168226,2,0,L|332:124,1,85.0000016212464 +448,32,168449,2,0,L|452:136,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +392,308,168671,6,0,P|324:272|216:320,1,170.000003242493,0|8,0:0|0:2,0:0:0:0: +156,340,169004,1,0,0:0:0:0: +88,272,169115,2,0,L|124:176,1,85.0000016212464 +88,56,169337,6,0,P|188:100|284:44,1,170.000003242493,10|0,0:2|0:0,0:0:0:0: +416,28,169671,1,2,0:2:0:0: +360,104,169782,1,8,0:2:0:0: +352,196,169893,1,0,0:0:0:0: +396,280,170004,6,0,P|400:328|432:364,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +272,296,170226,2,0,P|268:248|236:212,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +68,288,170449,2,0,P|116:276|168:288,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +324,148,170671,6,0,P|256:168|244:56,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +0,244,171004,2,0,L|180:264,1,170.000003242493 +460,240,171337,6,0,P|464:280|456:356,1,85.0000016212464 +336,284,171560,2,0,P|332:244|340:168,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +388,40,171782,2,0,P|412:80|416:132,1,85.0000016212464 +204,80,172004,2,0,P|252:80|308:96,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +208,192,172226,2,0,P|160:192|104:176,1,85.0000016212464 +256,48,172449,6,0,P|312:56|352:68,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +400,192,172671,2,0,P|392:248|380:288,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +256,336,172893,2,0,P|200:328|160:316,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +112,192,173115,2,0,P|120:136|132:96,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +400,192,173337,6,0,P|392:248|380:288,1,85.0000016212464,10|8,0:2|0:2,0:0:0:0: +256,48,173560,2,0,P|312:56|352:68,1,85.0000016212464,0|8,0:0|0:2,0:0:0:0: +172,320,173782,1,2,0:2:0:0: +117,245,173893,1,0,0:0:0:0: +116,153,174004,1,8,0:2:0:0: +169,78,174115,1,8,0:2:0:0: +256,48,174226,6,0,P|334:91|329:184,1,170.000003242493,12|0,0:2|0:0,0:0:0:0: +168,268,174560,1,0,0:0:0:0: +238,207,174671,1,8,0:2:0:0: +329,194,174782,1,0,0:0:0:0: +413,232,174893,2,0,L|426:331,2,85.0000016212464,0|0|8,0:0|0:0|0:2,0:0:0:0: +344,150,175226,1,0,0:0:0:0: +344,150,175337,2,0,L|261:134,1,85.0000016212464 +478,62,175560,2,0,L|466:164,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +322,328,175782,6,0,P|253:282|149:306,1,170.000003242493,0|8,0:0|0:2,0:0:0:0: +50,366,176115,1,0,0:0:0:0: +91,283,176226,1,0,0:0:0:0: +81,191,176337,1,0,0:0:0:0: +24,119,176449,2,0,P|93:165|197:141,1,170.000003242493,10|0,0:2|0:0,0:0:0:0: +327,79,176782,2,0,L|306:252,1,170.000003242493,2|0,0:2|0:0,0:0:0:0: +125,323,177115,6,0,P|161:302|203:298,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +389,256,177337,2,0,P|347:259|297:243,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +180,72,177560,2,0,P|221:88|261:137,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +66,257,177782,1,8,0:2:0:0: +64,235,177893,1,0,0:0:0:0: +63,214,178004,1,0,0:0:0:0: +62,193,178115,1,0,0:0:0:0: +61,172,178226,6,0,P|131:162|136:254,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +4,96,178560,1,0,0:0:0:0: +81,61,178671,1,8,0:2:0:0: +164,73,178782,1,0,0:0:0:0: +227,128,178893,1,0,0:0:0:0: +251,209,179004,1,0,0:0:0:0: +228,289,179115,2,0,P|213:252|218:200,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +401,62,179337,6,0,P|337:115|250:106,1,170.000003242493,2|8,0:2|0:2,0:0:0:0: +93,212,179671,1,0,0:0:0:0: +93,212,179782,2,0,P|143:218|184:248,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +334,366,180004,2,0,P|339:312|345:185,1,170.000003242493,10|0,0:2|0:0,0:0:0:0: +311,33,180337,2,0,P|265:16|223:22,2,85.0000016212464,2|8|0,2:0|0:2|0:0,0:0:0:0: +289,212,180671,5,0,0:0:0:0: +196,198,180782,1,0,0:0:0:0: +255,124,180893,1,8,0:2:0:0: +301,221,181004,5,0,0:0:0:0: +181,203,181115,1,8,0:2:0:0: +257,108,181226,1,0,0:0:0:0: +372,147,181337,6,0,P|407:214|372:301,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +163,238,181671,1,0,0:0:0:0: +74,225,181782,1,8,0:2:0:0: +18,294,181893,1,0,0:0:0:0: +50,378,182004,2,0,P|161:346|236:375,1,170.000003242493,0|8,0:0|0:2,0:0:0:0: +355,315,182337,1,0,0:0:0:0: +355,315,182449,2,0,P|346:273|355:211,1,85.0000016212464 +423,86,182671,2,0,P|432:128|423:190,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +214,113,182893,6,0,L|29:142,1,170.000003242493,0|8,0:0|0:2,0:0:0:0: +181,224,183226,1,0,0:0:0:0: +264,237,183337,1,0,0:0:0:0: +348,250,183449,1,0,0:0:0:0: +431,262,183560,2,0,P|446:302|448:344,2,85.0000016212464,10|2|0,0:2|0:2|0:0,0:0:0:0: +282,68,183893,2,0,P|211:119|219:199,1,170.000003242493,2|0,0:2|0:0,0:0:0:0: +391,175,184226,6,0,L|307:161,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +132,298,184449,2,0,L|186:232,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +154,12,184671,2,0,L|183:91,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +395,82,184893,5,12,0:2:0:0: +473,129,185004,1,0,0:0:0:0: +391,175,185115,2,0,P|341:179|286:160,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +105,112,185337,5,8,0:2:0:0: +26,158,185449,1,0,0:0:0:0: +108,204,185560,2,0,P|157:207|212:188,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +314,35,185782,5,8,0:2:0:0: +230,71,185893,1,0,0:0:0:0: +188,153,186004,1,2,0:2:0:0: +206,243,186115,1,0,0:0:0:0: +277,300,186226,2,0,P|319:313|381:310,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +469,143,186449,2,2,P|423:143|383:163,1,85.0000016212464,2|0,0:2|0:0,0:1:0:0: +180,96,186671,5,8,0:2:0:0: +180,96,186782,1,8,0:0:0:0: +180,96,186893,1,8,0:0:0:0: +333,236,187115,2,0,L|346:127,1,85.0000016212464,8|0,0:2|3:0,0:0:0:0: +404,53,187337,2,0,L|398:10,2,42.5000008106232,8|0|0,3:2|3:0|3:0,0:0:0:0: +426,195,187560,1,8,0:2:0:0: +426,195,187671,5,0,0:0:0:0: +240,159,187893,1,0,0:0:0:0: +350,339,188115,1,0,0:0:0:0: +70,296,188449,5,12,0:0:0:0: +432,192,195560,5,4,0:0:0:0: +432,168,195671,1,0,3:0:0:0: +424,144,195782,1,0,3:0:0:0: +416,120,195893,1,0,3:0:0:0: +400,96,196004,1,0,3:0:0:0: +384,80,196115,1,0,3:0:0:0: +368,64,196226,1,0,3:0:0:0: +344,48,196337,1,0,3:0:0:0: +320,40,196449,1,0,3:0:0:0: +296,40,196560,1,0,3:0:0:0: +272,40,196671,1,0,3:0:0:0: +248,48,196782,1,0,3:0:0:0: +224,64,196893,1,0,3:0:0:0: +208,80,197004,1,0,3:0:0:0: +192,104,197115,1,2,3:2:0:0: +184,128,197226,1,0,3:0:0:0: +176,152,197337,5,0,3:0:0:0: +160,168,197449,1,0,3:0:0:0: +136,184,197560,1,0,3:0:0:0: +112,192,197671,1,0,3:0:0:0: +96,208,197782,1,0,3:0:0:0: +80,232,197893,1,2,3:2:0:0: +80,256,198004,1,0,3:0:0:0: +88,280,198115,1,0,3:0:0:0: +112,296,198226,1,2,3:2:0:0: +136,304,198337,1,0,3:0:0:0: +160,304,198449,1,0,3:0:0:0: +184,296,198560,1,2,3:2:0:0: +200,280,198671,1,0,3:0:0:0: +224,264,198782,1,0,3:0:0:0: +248,256,198893,1,2,3:2:0:0: +272,264,199004,1,2,3:2:0:0: +296,280,199115,5,0,3:0:0:0: +320,288,199226,1,0,3:0:0:0: +344,288,199337,1,2,3:2:0:0: +368,280,199449,1,0,3:0:0:0: +392,264,199560,1,0,3:0:0:0: +408,248,199671,1,0,3:0:0:0: +424,224,199782,1,0,3:0:0:0: +432,200,199893,1,0,3:0:0:0: +432,176,200004,1,0,3:0:0:0: +424,152,200115,1,0,3:0:0:0: +416,128,200226,1,2,3:2:0:0: +400,104,200337,1,0,3:0:0:0: +384,88,200449,1,0,3:0:0:0: +360,72,200560,1,0,3:0:0:0: +336,64,200671,1,2,3:2:0:0: +312,64,200782,1,0,3:0:0:0: +288,72,200893,6,2,L|280:32,1,25,0|0,3:0|3:0,0:1:0:0: +264,80,201004,2,2,L|256:40,1,25,0|0,3:0|3:0,0:1:0:0: +240,88,201115,2,0,L|232:48,1,25,0|0,3:0|3:0,0:0:0:0: +216,96,201226,2,0,L|208:56,1,25,0|0,3:0|3:0,0:0:0:0: +192,104,201337,2,2,L|184:64,1,25,8|0,3:2|3:0,0:1:0:0: +168,112,201449,2,0,L|160:72,1,25,0|0,3:0|3:0,0:0:0:0: +144,120,201560,2,0,L|136:80,1,25,8|0,3:2|3:0,0:0:0:0: +120,128,201671,2,2,L|115:103,1,25,0|0,3:0|3:0,0:1:0:0: +96,136,201782,6,0,L|77:100,1,25,8|0,3:2|3:0,0:0:0:0: +57,173,201893,2,0,L|23:151,1,25,8|0,3:2|3:0,0:0:0:0: +41,224,202004,2,2,L|1:222,1,25,0|0,3:0|3:0,0:1:0:0: +53,277,202115,2,0,L|17:295,1,25,8|0,3:2|3:0,0:0:0:0: +90,316,202226,2,0,L|68:349,1,25,8|0,3:2|3:0,0:0:0:0: +141,332,202337,2,2,L|139:371,1,25,0|0,3:0|3:0,0:1:0:0: +194,320,202449,2,0,L|212:355,1,25,8|0,3:2|3:0,0:0:0:0: +233,283,202560,2,0,L|266:304,1,25,8|0,3:2|3:0,0:0:0:0: +249,231,202671,6,0,L|432:216,1,150.000005722046,12|0,0:0|0:0,0:0:0:0: +496,104,203115,5,8,0:0:0:0: +400,328,203337,1,0,0:0:0:0: +400,328,203449,1,0,0:0:0:0: +400,328,203560,2,0,P|352:296|336:256,1,100,10|0,0:0|0:0,0:0:0:0: +296,104,203893,5,0,0:0:0:0: +296,104,204004,2,0,L|352:112,1,50,8|0,0:0|0:0,0:0:0:0: +160,168,204226,1,0,0:0:0:0: +160,168,204337,1,0,0:0:0:0: +160,168,204449,2,0,P|112:160|56:192,1,100,10|2,0:0|0:0,0:0:0:0: +136,320,204893,5,8,0:0:0:0: +304,224,205115,1,0,0:0:0:0: +328,224,205226,1,0,0:0:0:0: +352,224,205337,1,10,0:0:0:0: +464,144,205560,5,0,0:0:0:0: +464,144,205671,1,0,0:0:0:0: +464,144,205782,2,2,P|480:112|480:96,1,50,8|0,0:0|0:0,0:1:0:0: +400,320,206004,2,2,P|384:352|384:368,1,50,0|0,3:0|0:0,0:1:0:0: +304,224,206226,6,0,P|248:200|184:224,1,100,10|2,0:0|0:0,0:0:0:0: +24,296,206671,1,8,0:0:0:0: +160,104,206893,1,0,0:0:0:0: +248,304,207115,2,0,P|304:328|368:304,1,100,10|0,0:0|0:0,0:0:0:0: +340,321,207782,6,0,L|316:193,1,100,2|8,0:0|0:0,0:0:0:0: +376,72,208226,1,2,0:0:0:0: +144,152,208449,1,8,0:0:0:0: +256,336,208671,1,0,0:0:0:0: +272,40,208893,5,10,0:0:0:0: +112,304,209115,1,8,0:0:0:0: +440,224,209337,6,2,P|480:224|512:232,1,50,8|0,0:0|3:0,0:1:0:0: +440,320,209560,2,2,P|400:320|368:312,1,50,8|0,0:0|3:0,0:1:0:0: +248,232,209782,5,8,3:2:0:0: +216,216,209893,1,0,3:0:0:0: +184,208,210004,1,2,3:0:0:0: +152,208,210115,1,0,0:0:0:0: +121,223,210226,6,2,L|109:132,1,50,8|0,3:2|3:0,0:1:0:0: +53,84,210449,1,2,3:0:0:0: +53,84,210560,2,0,P|108:67|180:81,1,100,0|0,0:0|3:0,0:0:0:0: +339,150,210893,1,0,3:0:0:0: +339,150,211004,1,2,3:0:0:0: +339,150,211115,2,0,L|202:141,1,100,8|2,0:0|3:0,0:0:0:0: +406,107,211449,5,0,3:0:0:0: +406,107,211560,2,0,P|380:155|400:244,1,150,8|0,0:2|0:0,0:0:0:0: +461,315,212004,6,0,L|533:308,1,50,8|0,3:2|3:0,0:0:0:0: +308,351,212226,1,2,3:0:0:0: +308,351,212337,2,0,P|255:332|177:351,1,100,0|0,0:0|3:0,0:0:0:0: +64,352,212671,1,0,3:0:0:0: +64,352,212782,1,2,3:0:0:0: +64,352,212893,2,0,L|96:240,1,100,8|4,0:0|3:2,0:0:0:0: +56,96,213226,5,0,0:0:0:0: +56,96,213337,2,0,P|113:140|185:126,1,150,12|0,0:0|0:0,0:0:0:0: +232,104,213782,1,8,0:0:0:0: +280,80,213893,1,0,0:0:0:0: +328,72,214004,1,0,0:0:0:0: +376,80,214115,1,0,0:0:0:0: +416,104,214226,1,10,0:0:0:0: +448,144,214337,1,0,0:0:0:0: +456,192,214449,1,2,0:0:0:0: +448,240,214560,1,0,0:0:0:0: +416,280,214671,1,8,0:0:0:0: +376,304,214782,1,0,0:0:0:0: +328,312,214893,1,10,0:0:0:0: +280,304,215004,1,0,0:0:0:0: +240,280,215115,6,0,L|192:280,1,25,8|0,3:2|3:0,0:0:0:0: +215,280,215226,2,0,L|176:280,1,25,0|0,3:0|3:0,0:0:0:0: +190,280,215337,2,0,L|160:280,1,25,2|0,3:2|3:0,0:0:0:0: +165,280,215449,2,0,L|120:280,1,25,0|0,3:0|3:0,0:0:0:0: +112,280,215560,5,8,0:0:0:0: +32,224,215671,1,8,0:0:0:0: +120,176,215782,2,0,L|120:128,2,25,8|8|8,0:0|0:0|0:0,0:0:0:0: +240,64,216115,5,0,1:0:0:0: +344,224,216337,1,0,1:0:0:0: +448,32,216560,1,0,1:0:0:0: +145,84,216893,5,12,0:0:0:0: +198,332,217115,2,0,L|219:193,1,119.999996337891,2|8,0:0|0:0,0:0:0:0: +308,165,217449,1,0,0:0:0:0: +308,165,217560,1,0,0:0:0:0: +81,244,217782,1,8,0:0:0:0: +76,214,217893,1,0,0:0:0:0: +72,184,218004,1,2,0:0:0:0: +67,155,218115,1,0,0:0:0:0: +63,125,218226,1,8,0:0:0:0: +200,49,218449,6,0,P|267:85|382:74,1,179.999994506836,2|0,0:0|0:0,0:0:0:0: +422,36,218893,2,0,P|355:108|357:200,1,179.999994506836,2|0,0:0|0:0,0:0:0:0: +512,151,219337,2,0,L|452:142,1,59.9999981689454,2|0,0:0|0:0,0:0:0:0: +318,194,219560,6,2,L|263:202,5,29.9999990844727,8|0|0|0|0|0,0:0|0:0|0:0|0:0|0:0|0:0,0:1:0:0: +424,218,219893,1,0,0:0:0:0: +426,247,220004,1,8,0:0:0:0: +429,276,220115,1,0,0:0:0:0: +432,305,220226,6,0,B|377:333|377:333|325:317|325:317|272:340|201:317,1,239.999992675781,2|0,0:0|0:0,0:0:0:0: +97,166,220893,1,8,0:0:0:0: +269,215,221115,2,0,L|278:135,1,59.9999981689454,2|0,0:0|0:0,0:0:0:0: +159,41,221337,1,8,3:2:0:0: +163,78,221449,1,0,3:0:0:0: +167,115,221560,1,0,3:0:0:0: +171,152,221671,1,2,3:2:0:0: +176,189,221782,2,0,L|167:270,1,59.9999981689454,8|0,0:0|0:0,0:0:0:0: +24,352,222004,6,0,L|203:335,1,179.999994506836,2|0,0:0|0:0,0:0:0:0: +346,297,222449,2,0,L|166:280,1,179.999994506836,2|0,0:0|3:0,0:0:0:0: +68,237,222893,1,2,3:2:0:0: +103,233,223004,1,0,3:0:0:0: +139,230,223115,6,2,L|216:238,1,59.9999981689454,8|0,0:0|0:0,0:1:0:0: +377,324,223337,2,2,L|419:260,1,59.9999981689454,8|0,0:0|0:0,0:1:0:0: +278,145,223560,2,0,L|290:227,1,59.9999981689454,8|0,0:0|0:0,0:0:0:0: +452,83,223782,2,0,L|375:91,1,59.9999981689454,8|0,0:0|0:0,0:0:0:0: +186,134,224004,5,8,3:2:0:0: +146,131,224115,1,0,3:0:0:0: +109,116,224226,1,2,3:0:0:0: +77,92,224337,1,0,0:0:0:0: +15,29,224449,5,8,3:2:0:0: +11,78,224560,1,0,3:0:0:0: +8,128,224671,1,2,3:0:0:0: +4,178,224782,1,0,0:0:0:0: +89,198,224893,5,8,3:2:0:0: +96,237,225004,1,0,3:0:0:0: +103,276,225115,1,0,3:0:0:0: +111,315,225226,1,2,3:0:0:0: +206,281,225337,5,8,0:0:0:0: +245,287,225449,1,0,3:0:0:0: +285,293,225560,1,2,3:0:0:0: +324,299,225671,1,0,0:0:0:0: +408,249,225782,5,8,3:2:0:0: +373,213,225893,1,0,3:0:0:0: +326,200,226004,1,0,3:0:0:0: +278,213,226115,1,0,3:0:0:0: +206,281,226226,5,8,3:2:0:0: +182,237,226337,1,0,3:0:0:0: +182,188,226449,1,0,3:0:0:0: +207,144,226560,1,0,0:0:0:0: +306,164,226671,5,8,3:2:0:0: +354,156,226782,1,0,3:0:0:0: +392,124,226893,1,0,3:0:0:0: +407,77,227004,1,2,3:0:0:0: +301,55,227115,5,8,0:0:0:0: +303,109,227226,1,2,3:0:0:0: +306,164,227337,1,0,3:0:0:0: +308,219,227449,1,0,0:0:0:0: +360,304,227560,5,8,3:2:0:0: +301,297,227671,1,0,3:2:0:0: +246,321,227782,2,0,P|216:329|176:319,1,59.9999981689454,2|0,3:2|0:0,0:0:0:0: +49,207,228004,2,0,L|56:281,1,59.9999981689454,8|0,3:2|1:0,0:0:0:0: +208,185,228226,2,0,L|215:111,1,59.9999981689454,2|0,3:2|1:0,0:0:0:0: +44,29,228449,5,10,3:2:0:0: +40,58,228560,1,0,3:0:0:0: +36,88,228671,1,0,3:0:0:0: +32,117,228782,1,8,0:0:0:0: +123,105,228893,1,8,3:2:0:0: +212,92,229004,6,0,L|254:72,1,29.9999990844727,0|0,3:0|3:0,3:0:0:0: +260,125,229115,2,0,L|300:123,1,29.9999990844727,10|0,3:2|3:0,3:0:0:0: +282,180,229226,2,0,L|319:193,1,29.9999990844727,0|0,3:0|3:0,3:0:0:0: +269,237,229337,5,8,3:2:0:0: +219,237,229449,1,0,3:0:0:0: +174,257,229560,1,2,3:2:0:0: +142,295,229671,1,0,0:0:0:0: +245,353,229782,5,8,3:2:0:0: +293,340,229893,1,8,3:2:0:0: +342,349,230004,2,0,L|377:334,1,29.9999990844727,2|0,3:2|3:0,0:0:0:0: +383,376,230115,1,0,3:0:0:0: +467,284,230226,5,0,1:0:0:0: +464,234,230337,1,8,1:2:0:0: +461,184,230449,1,0,0:0:0:0: +458,134,230560,1,8,1:2:0:0: +310,42,230671,5,0,3:0:0:0: +300,90,230782,1,8,1:2:0:0: +322,133,230893,1,0,3:0:0:0: +367,154,231004,1,0,0:0:0:0: +458,134,231115,6,0,L|465:242,1,89.9999972534181,12|0,0:0|0:0,0:0:0:0: +369,307,231782,2,0,P|310:301|248:334,1,119.999996337891 +137,289,232449,1,0,0:0:0:0: +137,289,232671,2,0,B|124:242|124:242|140:160,1,119.999996337891,2|0,0:0|0:0,0:0:0:0: +159,135,233337,2,0,P|221:159|296:148,1,119.999996337891,2|0,0:0|0:0,0:0:0:0: +375,81,234004,1,2,0:0:0:0: +389,206,234226,1,2,0:0:0:0: +273,155,234449,1,2,0:0:0:0: +143,320,235115,6,0,P|80:311|26:342,2,119.999996337891 +253,363,236226,2,0,B|274:307|240:278|261:239,1,119.999996337891,2|0,0:0|0:0,0:0:0:0: +303,208,236893,2,0,L|164:197,1,119.999996337891,2|0,0:0|0:0,0:0:0:0: +76,264,237560,1,0,0:0:0:0: +48,170,237782,1,2,0:0:0:0: +99,88,238004,1,10,0:0:0:0: +195,72,238226,6,0,P|245:87|301:87,1,89.9999972534181,4|0,0:0|0:0,0:0:0:0: +430,40,238893,2,0,P|441:102|450:172,1,119.999996337891 +443,280,239560,1,0,0:0:0:0: +340,214,239782,2,0,P|325:155|343:98,1,119.999996337891,2|0,0:0|0:0,0:0:0:0: +430,40,240449,2,0,P|384:47|286:27,1,119.999996337891,2|0,0:0|0:0,0:0:0:0: +195,72,241115,1,0,0:0:0:0: +181,191,241337,1,0,0:0:0:0: +291,143,241560,1,2,0:0:0:0: +195,72,241782,6,0,P|143:75|97:107,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: +90,271,242449,2,0,P|196:312|291:241,1,239.999992675781,2|2,0:0|0:0,0:0:0:0: +289,243,243449,2,0,P|328:264|373:264,1,89.9999972534181,2|0,0:0|3:0,0:0:0:0: +465,186,244004,1,0,3:0:0:0: +409,80,244226,5,0,3:0:0:0: +379,82,244337,1,0,3:0:0:0: +349,84,244449,1,10,0:0:0:0: +321,87,244560,2,0,L|271:91,1,29.9999990844727,8|0,1:2|0:0,0:0:0:0: +160,48,244782,5,8,1:2:0:0: +152,72,244893,1,10,0:0:0:0: +144,96,245004,1,8,0:0:0:0: +136,120,245115,1,8,0:0:0:0: +128,144,245226,1,8,0:0:0:0: +72,184,245337,6,0,L|212:196,1,100,12|0,0:0|0:0,0:0:0:0: +208,232,245671,2,0,P|256:241|299:217,1,100 +320,176,246004,2,0,L|312:76,1,100,0|8,0:0|0:0,0:0:0:0: +200,136,246449,5,0,0:0:0:0: +304,256,246671,1,8,0:0:0:0: +400,120,246893,2,0,L|536:112,1,100,2|8,0:0|0:0,0:0:0:0: +336,176,247337,5,0,0:0:0:0: +336,176,247449,1,0,0:0:0:0: +336,176,247560,2,0,P|288:152|216:184,1,100,10|0,0:0|0:0,0:0:0:0: +244,160,248004,1,8,0:0:0:0: +80,216,248226,5,2,0:0:0:0: +280,256,248449,1,10,0:0:0:0: +192,80,248671,2,0,L|192:200,1,100,2|8,0:0|0:0,0:0:0:0: +280,256,249115,1,0,0:0:0:0: +392,208,249337,6,0,P|408:256|368:328,1,100,8|0,0:0|0:0,0:0:0:0: +280,256,249782,2,0,L|144:264,1,100,8|0,0:0|0:0,0:0:0:0: +72,184,250226,1,8,0:0:0:0: +120,80,250449,2,0,P|161:99|185:179,1,100,2|8,0:0|0:0,0:0:0:0: +136,280,250893,5,0,0:0:0:0: +136,280,251115,2,0,L|352:272,1,200,10|8,0:0|0:0,0:0:0:0: +416,152,251782,5,0,0:0:0:0: +488,80,252004,1,10,0:0:0:0: +416,8,252226,1,2,0:0:0:0: +344,80,252449,6,0,L|232:88,1,100,10|0,0:0|0:0,0:0:0:0: +192,48,252782,2,0,P|200:72|200:168,1,100 +152,176,253115,2,0,L|288:192,1,100,0|8,0:0|0:0,0:0:0:0: +448,176,253560,5,0,0:0:0:0: +344,304,253782,1,8,0:0:0:0: +272,152,254004,2,0,L|272:16,1,100,2|8,0:0|0:0,0:0:0:0: +328,208,254449,5,0,0:0:0:0: +328,208,254671,2,0,P|264:200|208:216,1,100,10|0,0:0|0:0,0:0:0:0: +72,288,255115,1,8,0:0:0:0: +136,168,255337,6,0,L|112:104,1,50,2|0,0:0|0:0,0:0:0:0: +216,32,255560,2,0,L|232:88,1,50,10|0,0:0|0:0,0:0:0:0: +328,160,255782,2,0,L|347:114,1,50,2|0,0:0|0:0,0:0:0:0: +424,224,256004,6,0,L|451:233,1,25,10|0,2:2|2:0,2:0:0:0: +390,272,256115,2,0,L|407:295,1,25,0|0,2:0|2:0,2:0:0:0: +333,291,256226,2,0,L|333:319,1,25,2|0,2:2|2:0,2:0:0:0: +277,272,256337,2,0,L|261:295,1,25,0|0,2:0|2:0,2:0:0:0: +242,224,256449,2,0,L|216:233,1,25,10|0,2:2|2:0,2:0:0:0: +224,168,256560,2,0,L|251:159,1,25,0|0,2:0|2:0,2:0:0:0: +190,120,256671,2,0,L|207:97,1,25,2|0,2:2|2:0,2:0:0:0: +133,101,256782,2,0,L|133:73,1,25,0|0,2:0|2:0,2:0:0:0: +77,120,256893,2,8,L|61:97,1,25,8|0,2:2|2:0,2:0:0:0: +42,168,257004,2,8,L|16:159,1,25,8|0,2:2|2:0,2:0:0:0: +42,227,257115,2,0,L|15:236,1,25,4|0,2:2|2:0,2:0:0:0: +76,275,257226,2,0,L|59:298,1,25,0|0,2:0|2:0,2:0:0:0: +133,294,257337,2,0,L|133:322,1,25,8|0,2:2|2:0,2:0:0:0: +189,275,257449,2,8,L|205:298,1,25,0|0,2:0|2:0,2:0:0:0: +224,227,257560,2,8,L|250:236,1,25,12|0,2:2|2:0,2:0:0:0: +224,168,257671,2,8,L|250:159,1,25,0|0,2:0|2:0,2:0:0:0: +190,120,257782,5,8,0:0:0:0: +133,101,257893,1,8,0:0:0:0: +77,120,258004,1,8,0:0:0:0: +224,227,258226,1,8,0:0:0:0: +258,275,258337,1,8,0:0:0:0: +315,294,258449,1,8,0:0:0:0: +371,275,258560,1,8,0:0:0:0: +406,227,258671,1,8,0:0:0:0: +412,167,258782,1,8,0:0:0:0: +391,110,258893,6,0,L|326:101,2,50,0|12|8,0:0|0:3|0:0,0:0:0:0: +315,194,259226,1,0,1:0:0:0: +315,194,259337,2,0,L|250:203,1,50,8|8,0:0|0:0,0:0:0:0: +88,95,259560,6,0,P|158:52|237:76,1,170.000003242493,12|0,0:2|0:0,0:0:0:0: +362,269,259893,1,0,0:0:0:0: +272,288,260004,1,8,0:2:0:0: +194,241,260115,1,0,0:0:0:0: +171,153,260226,2,0,L|178:58,2,85.0000016212464,0|0|8,0:0|0:0|0:2,0:0:0:0: +106,216,260560,1,0,0:0:0:0: +24,177,260671,2,0,L|29:261,1,85.0000016212464 +165,349,260893,2,0,L|170:264,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +394,84,261115,6,0,P|343:147|251:128,1,170.000003242493,0|8,0:0|0:2,0:0:0:0: +394,84,261449,1,0,0:0:0:0: +425,169,261560,1,0,0:0:0:0: +388,252,261671,1,0,0:0:0:0: +303,285,261782,2,0,P|268:267|206:267,2,85.0000016212464,10|2|0,0:2|0:2|0:0,0:0:0:0: +454,347,262115,2,0,L|463:165,1,170.000003242493,2|0,0:2|0:0,0:0:0:0: +297,56,262449,6,0,P|294:98|309:137,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +491,104,262671,2,0,P|443:101|409:118,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +223,263,262893,2,0,L|215:157,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +68,53,263115,1,8,0:2:0:0: +89,55,263226,1,0,0:0:0:0: +110,57,263337,1,0,0:0:0:0: +131,60,263449,1,0,0:0:0:0: +152,62,263560,6,0,P|237:73|284:142,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +87,182,263893,1,0,0:0:0:0: +87,182,264004,2,0,P|39:237|58:348,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +269,306,264337,1,0,0:0:0:0: +269,306,264449,2,0,L|186:290,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +283,137,264671,6,0,B|406:160|406:160|360:178,1,170.000003242493,2|8,0:2|0:2,0:0:0:0: +165,193,265004,1,0,0:0:0:0: +165,193,265115,2,0,B|150:152|150:152|155:110,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +299,286,265337,2,0,P|339:271|391:274,2,85.0000016212464,10|2|0,0:2|0:2|0:0,0:0:0:0: +428,374,265671,1,2,0:2:0:0: +487,305,265782,1,8,0:2:0:0: +476,215,265893,1,0,0:0:0:0: +396,164,266004,6,0,L|274:178,1,85.0000016212464 +193,245,266226,2,0,L|108:235,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +210,73,266449,2,0,P|253:58|306:64,1,85.0000016212464 +438,263,266671,6,0,B|387:245|392:181|392:181|370:212|323:212,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +153,138,267004,1,0,0:0:0:0: +66,161,267115,1,8,0:2:0:0: +34,245,267226,1,0,0:0:0:0: +84,319,267337,2,0,P|168:311|263:307,1,170.000003242493,0|8,0:0|0:2,0:0:0:0: +334,211,267671,1,0,0:0:0:0: +334,211,267782,2,0,P|325:170|336:122,1,85.0000016212464 +458,77,268004,2,0,P|467:118|456:166,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +321,354,268226,6,0,P|253:306|164:315,1,170.000003242493,2|8,0:2|0:2,0:0:0:0: +34,201,268560,1,0,0:0:0:0: +34,202,268671,2,0,L|129:194,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +263,87,268893,2,0,P|177:90|129:157,1,170.000003242493,10|0,0:2|0:0,0:0:0:0: +326,305,269226,1,2,0:2:0:0: +334,211,269337,1,8,0:2:0:0: +343,118,269449,1,0,0:0:0:0: +352,25,269560,6,0,L|362:109,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +223,176,269782,2,0,L|212:260,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +446,266,270004,2,0,P|408:240|357:234,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +113,288,270226,6,0,P|65:224|76:127,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +165,55,270560,1,0,0:0:0:0: +232,116,270671,1,8,0:2:0:0: +323,130,270782,1,0,0:0:0:0: +407,90,270893,2,0,P|426:124|432:182,1,85.0000016212464 +317,319,271115,5,8,0:2:0:0: +317,225,271226,1,0,0:0:0:0: +406,196,271337,1,0,0:0:0:0: +460,272,271449,1,0,0:0:0:0: +406,348,271560,1,8,0:2:0:0: +317,319,271671,1,0,0:0:0:0: +224,303,271782,2,0,P|178:303|138:324,1,85.0000016212464 +43,164,272004,5,10,0:2:0:0: +127,124,272115,1,0,0:0:0:0: +117,217,272226,1,2,0:2:0:0: +43,164,272337,5,0,0:0:0:0: +77,48,272449,1,10,0:2:0:0: +157,138,272560,1,0,0:0:0:0: +43,164,272671,2,2,P|39:120|56:80,1,85.0000016212464,2|0,0:2|0:0,0:1:0:0: +279,26,272893,6,0,L|416:16,1,85.0000016212464,10|8,0:2|0:2,0:0:0:0: +504,120,273115,2,0,L|367:130,1,85.0000016212464,0|8,0:0|0:2,0:0:0:0: +176,120,273337,5,10,0:2:0:0: +216,208,273449,1,8,0:2:0:0: +184,296,273560,1,8,0:2:0:0: +112,352,273671,1,8,0:2:0:0: +16,344,273782,6,0,L|224:328,1,170.000003242493,12|0,0:2|0:0,0:0:0:0: +464,288,274115,2,0,P|392:312|288:248,1,170.000003242493 +105,186,274449,5,0,0:0:0:0: +143,95,274560,1,0,0:0:0:0: +233,58,274671,1,8,0:2:0:0: +324,95,274782,1,0,3:0:0:0: +361,186,274893,1,0,0:0:0:0: +324,276,275004,1,0,0:0:0:0: +233,314,275115,6,0,L|128:320,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +0,216,275337,2,0,P|96:168|192:232,1,170.000003242493,0|8,0:0|0:2,0:0:0:0: +324,276,275671,1,0,0:0:0:0: +392,336,275782,2,0,P|413:299|414:257,1,85.0000016212464 +320,155,276004,6,0,P|272:217|324:276,1,170.000003242493,10|0,0:2|0:0,0:0:0:0: +424,368,276337,2,0,L|456:200,1,170.000003242493,2|0,0:2|0:0,0:0:0:0: +360,24,276671,6,0,P|352:64|408:112,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +232,112,276893,2,0,P|192:104|144:160,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +200,296,277115,2,0,P|192:256|248:208,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +360,144,277337,5,8,0:2:0:0: +360,144,277449,1,0,0:0:0:0: +360,144,277560,1,0,0:0:0:0: +360,144,277671,1,0,0:0:0:0: +360,144,277782,2,0,L|336:328,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +256,352,278115,1,0,0:0:0:0: +168,328,278226,2,0,P|241:264|351:328,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +184,352,278560,5,0,0:0:0:0: +184,352,278671,2,0,L|80:360,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +307,274,278893,2,0,P|400:304|480:264,1,170.000003242493,2|8,0:2|0:2,0:0:0:0: +504,136,279226,5,0,0:0:0:0: +504,137,279337,2,0,L|415:124,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +232,64,279560,2,0,P|200:136|256:200,1,170.000003242493,10|0,0:2|0:0,0:0:0:0: +488,264,279893,5,2,0:2:0:0: +400,232,280004,1,8,0:2:0:0: +312,256,280115,1,0,0:0:0:0: +248,320,280226,6,0,P|280:352|336:344,1,85.0000016212464 +120,280,280449,2,0,L|24:272,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +216,192,280671,2,0,P|264:184|312:200,1,85.0000016212464 +160,104,280893,6,0,P|64:136|8:80,1,170.000003242493,8|0,0:2|0:0,0:0:0:0: +201,22,281226,2,0,L|217:214,1,170.000003242493 +376,336,281560,5,0,0:0:0:0: +416,248,281671,1,0,0:0:0:0: +320,264,281782,1,8,0:2:0:0: +376,336,281893,1,0,0:0:0:0: +416,248,282004,6,0,P|421:207|416:128,1,85.0000016212464 +312,56,282226,2,0,P|306:96|312:176,1,85.0000016212464,8|0,0:2|0:0,0:0:0:0: +200,256,282449,5,0,0:0:0:0: +185,163,282560,1,0,0:0:0:0: +92,148,282671,1,8,0:2:0:0: +51,231,282782,1,0,0:0:0:0: +116,298,282893,6,0,L|232:304,1,85.0000016212464 +448,264,283115,2,0,P|368:232|248:304,1,170.000003242493,10|0,0:2|0:0,0:0:0:0: +368,328,283449,2,0,L|392:96,1,170.000003242493,2|0,0:2|0:0,0:0:0:0: +288,32,283782,6,0,L|304:160,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +185,163,284004,2,0,L|128:80,1,85.0000016212464,10|0,0:2|0:0,0:0:0:0: +51,231,284226,2,0,L|160:264,1,85.0000016212464,2|0,0:2|0:0,0:0:0:0: +360,336,284449,6,0,L|424:352,1,42.5000008106232,10|0,3:2|3:0,0:0:0:0: +384,304,284560,2,0,L|440:320,1,42.5000008106232,0|4,3:0|3:2,0:0:0:0: +408,272,284671,2,0,L|472:288,1,42.5000008106232,2|0,3:2|3:0,0:0:0:0: +432,240,284782,2,0,L|496:256,1,42.5000008106232,0|0,3:0|3:0,0:0:0:0: +376,160,284893,6,0,L|312:176,1,42.5000008106232,10|0,3:2|3:0,0:0:0:0: +352,128,285004,2,0,L|296:144,1,42.5000008106232,0|0,3:0|3:0,0:0:0:0: +328,96,285115,2,0,L|264:112,1,42.5000008106232,2|0,3:2|3:0,0:0:0:0: +304,64,285226,2,0,L|240:80,1,42.5000008106232,0|0,3:0|3:0,0:0:0:0: +160,64,285337,6,0,L|160:8,1,42.5000008106232,8|0,3:2|3:0,0:0:0:0: +112,88,285449,2,0,L|72:48,1,42.5000008106232,0|0,3:0|3:0,0:0:0:0: +84,136,285560,2,2,L|28:136,1,42.5000008106232,4|0,3:2|2:0,0:1:0:0: +84,192,285671,2,0,L|44:231,1,42.5000008106232,0|0,2:0|2:0,2:0:0:0: +176,292,285782,6,0,L|176:348,1,42.5000008106232,8|0,2:2|2:0,2:0:0:0: +216,264,285893,2,0,L|255:303,1,42.5000008106232,0|0,2:0|2:0,2:0:0:0: +240,224,286004,2,2,L|296:224,1,42.5000008106232,2|0,2:2|2:0,2:1:0:0: +252,176,286115,2,0,L|291:136,1,42.5000008106232,0|0,2:0|2:0,2:0:0:0: +164,104,286226,5,8,0:2:0:0: +84,136,286337,1,8,2:0:0:0: +52,216,286449,1,8,2:0:0:0: +216,264,286671,1,8,0:0:0:0: +248,184,286782,1,8,0:0:0:0: +328,152,286893,2,0,L|328:104,2,42.5000008106232,8|0|0,3:2|3:0|3:0,0:0:0:0: +400,184,287115,1,8,0:0:0:0: +440,264,287226,5,0,0:0:0:0: +440,280,287449,1,4,0:3:0:0: +440,296,287671,1,0,0:0:0:0: +160,176,288004,6,0,L|337:155,1,150.000005722046,4|2,0:0|0:0,0:0:0:0: +335,290,288337,1,0,0:0:0:0: +335,290,288449,2,0,L|260:281,1,75.0000028610231,8|0,3:2|3:0,0:0:0:0: +136,148,288671,2,0,L|115:231,1,75.0000028610231,2|0,3:0|0:0,0:0:0:0: +254,138,288893,5,10,0:0:0:0: +223,70,289004,1,0,0:0:0:0: +160,33,289115,1,0,3:0:0:0: +86,39,289226,2,0,P|53:60|30:98,1,75.0000028610231,0|8,3:0|0:0,0:0:0:0: +117,220,289449,1,0,0:0:0:0: +117,220,289560,2,0,L|128:309,2,75.0000028610231,2|0|8,3:0|3:0|3:2,0:0:0:0: +228,182,289893,5,0,3:0:0:0: +268,192,290004,1,2,3:0:0:0: +300,161,290115,1,0,0:0:0:0: +341,171,290226,2,0,L|419:152,1,75.0000028610231,10|0,3:2|3:0,0:0:0:0: +243,96,290449,2,0,L|321:77,1,75.0000028610231,2|0,3:2|0:0,0:0:0:0: +140,30,290671,6,0,L|56:51,1,75.0000028610231,10|0,3:2|3:0,0:0:0:0: +223,123,290893,1,0,3:0:0:0: +223,123,291004,2,0,L|139:144,1,75.0000028610231,2|8,0:2|3:2,0:0:0:0: +306,216,291226,1,0,3:0:0:0: +233,234,291337,2,0,L|149:255,1,75.0000028610231,2|2,3:2|3:2,0:0:0:0: +60,82,291560,5,8,0:2:0:0: +114,95,291671,1,0,3:0:0:0: +169,109,291782,1,2,3:0:0:0: +223,123,291893,1,0,0:0:0:0: +277,108,292004,2,0,P|311:94|348:92,1,75.0000028610231,8|0,0:2|0:0,0:0:0:0: +479,209,292226,2,0,P|495:244|499:299,1,75.0000028610231,2|0,3:0|3:0,0:0:0:0: +285,299,292449,6,0,L|279:377,1,75.0000028610231,10|0,3:2|3:0,0:0:0:0: +407,190,292671,1,0,3:0:0:0: +407,190,292782,2,0,L|413:268,1,75.0000028610231,2|8,0:2|3:2,0:0:0:0: +253,128,293004,1,0,3:0:0:0: +248,203,293115,2,0,B|246:234|246:234|273:164|352:157,1,150.000005722046,2|8,3:2|0:2,0:0:0:0: +482,90,293449,5,0,0:0:0:0: +487,164,293560,2,0,L|406:144,1,75.0000028610231,2|0,0:3|0:0,0:0:0:0: +248,203,293782,1,8,3:2:0:0: +196,180,293893,1,0,3:0:0:0: +140,180,294004,1,0,3:0:0:0: +89,202,294115,1,0,3:0:0:0: +51,243,294226,6,0,B|12:200|46:133|46:133|43:157|54:173,1,150.000005722046,10|2,0:2|1:2,0:0:0:0: +92,319,294560,2,0,P|129:312|166:310,1,75.0000028610231,4|8,0:3|0:0,0:0:0:0: +317,351,294782,1,2,0:0:0:0: +399,338,294893,2,0,P|434:311|453:285,1,75.0000028610231,2|0,1:2|0:0,0:0:0:0: +281,104,295115,5,8,0:0:0:0: +247,147,295226,1,0,3:0:0:0: +248,203,295337,2,0,P|290:210|334:204,1,75.0000028610231,2|0,3:0|0:0,0:0:0:0: +281,104,295560,6,0,P|199:131|256:202,1,200,2|2,1:0|0:0,0:0:0:0: +301,78,295893,6,0,L|199:61,1,75.0000028610231,0|8,0:0|0:0,0:0:0:0: +322,206,296115,1,0,3:0:0:0: +378,203,296226,1,2,3:0:0:0: +434,200,296337,1,0,3:0:0:0: +490,197,296449,2,0,P|492:159|482:124,1,75.0000028610231,8|0,0:0|0:0,0:0:0:0: +384,359,296671,2,0,P|418:345|446:320,1,75.0000028610231,2|0,3:0|3:0,0:0:0:0: +295,164,296893,5,8,3:2:0:0: +242,144,297004,1,0,3:2:0:0: +187,149,297115,1,0,3:2:0:0: +140,179,297226,1,0,0:0:0:0: +112,227,297337,2,0,L|104:142,1,75.0000028610231,8|0,0:0|0:0,0:0:0:0: +0,63,297560,2,0,P|34:76|71:80,1,75.0000028610231,2|0,3:0|3:0,0:0:0:0: +259,18,297782,6,0,P|221:22|187:35,2,75.0000028610231,10|0|0,0:0|3:0|0:0,0:0:0:0: +383,73,298115,2,0,P|404:103|418:138,2,75.0000028610231,2|8|0,0:0|3:2|0:0,0:0:0:0: +242,144,298449,2,0,L|248:238,1,75.0000028610231,4|2,0:1|0:0,0:0:0:0: +409,298,298671,6,0,P|336:294|258:343,1,150.000005722046,12|0,0:0|3:0,0:0:0:0: +47,287,299115,1,10,0:0:0:0: +11,243,299226,1,0,3:0:0:0: +0,189,299337,1,2,3:0:0:0: +13,135,299449,1,0,0:0:0:0: +49,92,299560,6,0,B|80:80|80:80|136:91,1,75.0000028610231,10|0,0:0|3:0,0:0:0:0: +244,186,299782,1,0,3:0:0:0: +244,186,299893,2,0,B|213:198|213:198|172:189,1,75.0000028610231,2|8,0:0|0:0,0:0:0:0: +363,223,300115,1,0,0:0:0:0: +363,223,300226,2,0,L|357:126,1,75.0000028610231,10|0,1:2|0:0,0:0:0:0: +449,56,300449,6,0,L|455:13,3,37.5000014305115,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: +403,162,300671,2,0,L|406:208,3,37.5000014305115,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: +340,71,300893,2,0,L|296:67,3,37.5000014305115,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: +254,153,301115,2,0,L|210:157,3,37.5000014305115,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: +120,88,301337,6,0,L|88:62,1,37.5000014305115,10|0,0:0|0:0,0:0:0:0: +66,100,301449,2,0,L|21:88,1,37.5000014305115,8|0,0:0|0:0,0:0:0:0: +30,141,301560,2,0,L|-10:146,1,37.5000014305115,10|0,0:0|0:0,0:0:0:0: +23,196,301671,2,0,L|-21:218,1,37.5000014305115,10|0,0:0|0:0,0:0:0:0: +50,245,301782,1,8,0:0:0:0: +100,226,301893,1,10,0:0:0:0: +146,250,302004,1,10,0:0:0:0: +159,300,302115,1,8,0:0:0:0: +136,344,302226,6,0,L|112:152,1,150.000005722046,12|0,0:0|0:0,0:0:0:0: +192,80,302560,1,0,0:0:0:0: +192,80,302671,2,0,P|248:136|208:232,1,150.000005722046,8|2,3:2|3:0,0:0:0:0: +146,250,303004,5,0,0:0:0:0: +72,304,303115,2,0,P|56:264|56:224,1,75.0000028610231,10|0,0:0|0:0,0:0:0:0: +106,129,303337,6,0,P|158:179|146:250,1,150.000005722046,0|8,3:0|0:0,0:0:0:0: +72,152,303671,1,0,0:0:0:0: +72,152,303782,2,0,L|64:48,1,75.0000028610231,2|0,3:0|3:0,0:0:0:0: +168,0,304004,1,8,3:2:0:0: +168,0,304115,2,0,L|176:104,1,75.0000028610231,0|2,3:0|3:0,0:0:0:0: +224,184,304337,5,0,0:0:0:0: +159,247,304449,2,0,P|228:273|310:179,1,150.000005722046,10|2,3:2|3:2,0:0:0:0: +428,142,304782,1,0,0:0:0:0: +428,142,304893,2,0,L|336:147,1,75.0000028610231,10|0,3:2|3:0,0:0:0:0: +263,73,305115,5,0,3:0:0:0: +213,56,305226,1,4,0:3:0:0: +161,64,305337,1,8,3:2:0:0: +122,99,305449,1,0,3:0:0:0: +104,148,305560,2,0,L|122:225,1,75.0000028610231,2|2,3:2|3:2,0:0:0:0: +166,316,305782,6,0,B|96:318|90:334|90:334|65:342|12:324,1,150.000005722046,8|2,0:0|3:0,0:0:0:0: +309,200,306115,1,0,0:0:0:0: +309,200,306226,2,0,P|336:253|307:351,1,150.000005722046,8|2,0:0|3:0,0:0:0:0: +243,278,306560,5,0,3:0:0:0: +309,200,306671,2,0,L|391:196,1,75.0000028610231,10|0,3:2|3:0,0:0:0:0: +500,99,306893,5,0,3:0:0:0: +447,92,307004,1,2,0:2:0:0: +397,75,307115,1,8,3:2:0:0: +344,69,307226,1,0,3:0:0:0: +296,47,307337,2,0,L|207:35,1,75.0000028610231,2|0,3:2|0:0,0:0:0:0: +108,8,307560,6,0,B|110:50|110:50|124:100|124:100|105:170,1,150.000005722046,8|2,0:0|3:0,0:0:0:0: +78,336,307893,1,0,0:0:0:0: +78,336,308004,2,0,P|31:298|55:174,1,150.000005722046,8|0,3:2|3:0,0:0:0:0: +194,174,308337,1,0,3:0:0:0: +194,174,308449,2,0,L|186:258,1,75.0000028610231,10|0,0:2|0:0,0:0:0:0: +288,113,308671,5,2,1:2:0:0: +323,74,308782,1,2,0:0:0:0: +373,59,308893,1,8,0:0:0:0: +424,70,309004,1,2,0:0:0:0: +476,67,309115,5,2,1:2:0:0: +462,117,309226,1,0,0:0:0:0: +448,167,309337,1,8,0:0:0:0: +434,217,309449,1,0,3:0:0:0: +460,262,309560,5,2,3:0:0:0: +408,253,309671,1,0,0:0:0:0: +359,274,309782,2,0,P|343:319|405:383,1,75.0000028610231,2|0,1:0|0:0,0:0:0:0: +305,191,310004,1,2,0:0:0:0: +305,191,310115,2,0,L|329:18,1,150.000005722046,0|0,0:0|3:0,0:0:0:0: +216,296,310449,5,2,3:0:0:0: +165,310,310560,1,0,3:0:0:0: +118,290,310671,2,0,P|80:264|128:141,1,150.000005722046,8|2,0:0|3:0,0:0:0:0: +230,113,311004,5,0,0:0:0:0: +230,113,311115,2,0,L|-10:130,1,225.000008583069,8|0,3:2|0:0,0:0:0:0: +95,62,311560,6,0,P|132:80|151:116,1,75.0000028610231,8|0,0:0|0:0,0:0:0:0: +169,270,311782,1,2,3:0:0:0: +169,270,311893,2,0,P|248:233|338:273,1,150.000005722046,0|0,3:0|3:0,0:0:0:0: +405,327,312226,6,0,L|489:330,1,75.0000028610231,0|4,3:0|0:3,0:0:0:0: +200,285,312449,2,0,P|129:302|52:269,1,150.000005722046,8|4,0:0|0:1,0:0:0:0: +13,105,312782,5,0,0:0:0:0: +95,62,312893,2,0,L|328:80,1,225.000008583069,12|2,0:0|0:0,0:0:0:0: +488,272,313337,6,0,P|480:208|432:168,1,75.0000028610231,8|0,0:0|1:0,0:0:0:0: +360,168,313560,2,0,P|368:232|416:272,1,75.0000028610231,0|0,3:2|1:0,0:0:0:0: +464,312,313782,6,0,L|440:176,1,75.0000028610231,8|0,3:2|3:0,0:0:0:0: +320,144,314004,2,0,L|344:280,1,75.0000028610231,2|0,3:0|3:0,0:0:0:0: +288,352,314226,5,8,0:0:0:0: +248,320,314337,1,0,0:0:0:0: +208,304,314449,2,0,L|144:304,1,37.5000014305115,0|0,3:0|3:0,0:0:0:0: +168,304,314560,2,0,L|112:312,1,37.5000014305115,0|0,3:0|3:0,0:0:0:0: +112,320,314671,5,8,3:2:0:0: +64,312,314782,1,0,3:0:0:0: +32,272,314893,1,8,3:2:0:0: +40,216,315004,1,0,0:0:0:0: +72,176,315115,5,8,0:0:0:0: +120,160,315226,1,0,0:0:0:0: +168,144,315337,2,0,L|216:128,1,37.5000014305115,8|8,0:0|0:0,0:0:0:0: +203,132,315449,2,0,L|264:112,1,37.5000014305115,8|8,0:0|0:0,0:0:0:0: +264,136,315560,5,8,0:0:0:0: +296,96,315671,1,8,0:0:0:0: +288,48,315782,1,8,0:0:0:0: +256,8,315893,5,8,0:0:0:0: +256,352,316115,1,4,0:1:0:0: +256,8,316337,1,8,0:0:0:0: +219,91,316449,6,0,P|270:95|322:71,1,100,12|0,0:0|0:0,0:0:0:0: +434,29,316893,1,8,0:0:0:0: +437,66,317004,1,0,0:0:0:0: +440,103,317115,1,0,0:0:0:0: +371,215,317337,2,0,L|321:205,3,50,10|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: +298,247,317782,2,0,L|248:256,3,50,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: +216,221,318226,5,8,0:0:0:0: +178,217,318337,1,0,0:0:0:0: +143,229,318449,1,2,0:0:0:0: +23,142,318671,1,8,0:0:0:0: +161,78,318893,1,2,0:0:0:0: +56,224,319115,1,10,0:0:0:0: +36,255,319226,1,0,0:0:0:0: +31,292,319337,1,0,0:0:0:0: +40,328,319449,1,4,0:3:0:0: +62,358,319560,2,0,L|124:345,1,50,8|0,0:0|0:0,0:0:0:0: +249,272,319782,6,0,L|373:292,1,100,0|8,0:0|0:0,0:0:0:0: +219,363,320226,1,2,0:0:0:0: +260,226,320449,1,8,0:0:0:0: +380,331,320671,1,2,0:0:0:0: +462,168,320893,1,10,0:0:0:0: +420,173,321004,1,0,0:0:0:0: +379,178,321115,2,0,L|320:193,1,50,2|0,0:0|0:0,0:0:0:0: +200,259,321337,2,0,L|259:274,1,50,10|0,0:0|0:0,0:0:0:0: +380,331,321560,6,0,P|395:283|381:223,1,100,2|8,0:0|0:0,0:0:0:0: +338,49,322004,1,0,0:0:0:0: +330,190,322226,1,8,0:0:0:0: +443,275,322449,1,0,0:0:0:0: +426,118,322671,1,8,0:0:0:0: +394,97,322782,1,0,0:0:0:0: +360,83,322893,1,0,0:0:0:0: +323,76,323004,1,4,0:3:0:0: +285,78,323115,2,0,P|261:78|223:92,1,50,8|0,0:0|0:0,0:0:0:0: +165,223,323337,2,0,P|181:204|196:166,1,50 +65,126,323560,5,8,3:2:0:0: +43,156,323671,1,0,3:0:0:0: +30,191,323782,1,2,3:0:0:0: +27,229,323893,1,0,0:0:0:0: +34,265,324004,1,8,3:2:0:0: +69,278,324115,1,0,3:0:0:0: +106,283,324226,1,2,3:0:0:0: +144,280,324337,1,0,0:0:0:0: +179,269,324449,5,8,0:0:0:0: +205,294,324560,1,0,0:0:0:0: +205,331,324671,1,0,3:0:0:0: +179,356,324782,1,2,3:0:0:0: +143,356,324893,1,10,0:0:0:0: +120,319,325004,1,0,3:0:0:0: +111,276,325115,1,2,3:0:0:0: +118,233,325226,1,0,0:0:0:0: +139,195,325337,5,8,3:2:0:0: +168,203,325449,1,0,3:0:0:0: +199,204,325560,1,2,3:0:0:0: +230,196,325671,1,0,0:0:0:0: +256,180,325782,1,8,3:2:0:0: +282,164,325893,1,0,3:0:0:0: +313,156,326004,1,2,3:0:0:0: +344,157,326115,1,0,0:0:0:0: +374,166,326226,5,10,3:2:0:0: +334,137,326337,1,0,3:2:0:0: +318,90,326449,1,0,3:2:0:0: +331,43,326560,1,6,3:3:0:0: +370,12,326671,1,8,0:0:0:0: +419,9,326782,1,2,3:0:0:0: +461,35,326893,1,0,3:0:0:0: +480,80,327004,1,0,3:0:0:0: +470,128,327115,5,12,0:0:0:0: +448,166,327226,1,0,3:0:0:0: +444,209,327337,1,0,3:0:0:0: +458,250,327449,1,0,0:0:0:0: +487,282,327560,1,10,3:0:0:0: +475,241,327671,1,0,3:0:0:0: +442,213,327782,1,2,3:0:0:0: +400,208,327893,1,0,0:0:0:0: +361,227,328004,5,8,3:2:0:0: +336,258,328115,1,0,3:0:0:0: +275,214,328226,1,0,3:0:0:0: +261,246,328337,1,2,3:0:0:0: +192,227,328449,1,8,0:0:0:0: +186,256,328560,1,0,3:0:0:0: +114,258,328671,1,2,3:0:0:0: +113,282,328782,1,0,0:0:0:0: +45,304,328893,6,0,L|17:322,3,25,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: +25,203,329115,2,0,L|-7:207,3,25,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: +69,115,329337,2,0,L|37:105,3,25,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: +154,70,329560,2,0,L|129:47,3,25,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: +300,116,329782,6,0,L|336:103,1,25,8|0,3:2|3:0,0:0:0:0: +282,168,329893,2,0,L|305:198,1,25,8|0,3:2|0:0,0:0:0:0: +228,168,330004,2,0,L|206:199,1,25,8|0,3:2|3:2,0:0:0:0: +211,115,330115,2,0,L|174:104,1,25,12|0,3:0|3:0,0:0:0:0: +256,83,330226,5,8,0:0:0:0: +256,133,330337,1,8,0:0:0:0: +256,183,330449,1,8,0:0:0:0: +256,233,330560,1,4,0:0:0:0: From 0f538867843ee1642797252befba64415ef9a196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 19 Dec 2025 10:10:33 +0100 Subject: [PATCH 298/836] Fix stack threshold being calculated in a different way than stable --- .../Beatmaps/OsuBeatmapProcessor.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs index e49d72ef33c8..bbe28817a0bb 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs @@ -91,7 +91,7 @@ private static void applyStacking(IBeatmap beatmap, List hitObject continue; double endTime = stackBaseObject.GetEndTime(); - double stackThreshold = objectN.TimePreempt * beatmap.StackLeniency; + float stackThreshold = calculateStackThreshold(beatmap, objectN); if (objectN.StartTime - endTime > stackThreshold) // We are no longer within stacking range of the next object. @@ -136,7 +136,7 @@ private static void applyStacking(IBeatmap beatmap, List hitObject OsuHitObject objectI = hitObjects[i]; if (objectI.StackHeight != 0 || objectI is Spinner) continue; - double stackThreshold = objectI.TimePreempt * beatmap.StackLeniency; + float stackThreshold = calculateStackThreshold(beatmap, objectI); /* If this object is a hitcircle, then we enter this "special" case. * It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider. @@ -232,7 +232,7 @@ private static void applyStackingOld(IBeatmap beatmap, List hitObj for (int j = i + 1; j < hitObjects.Count; j++) { - double stackThreshold = hitObjects[i].TimePreempt * beatmap.StackLeniency; + float stackThreshold = calculateStackThreshold(beatmap, hitObjects[i]); if (hitObjects[j].StartTime - stackThreshold > startTime) break; @@ -264,5 +264,17 @@ private static void applyStackingOld(IBeatmap beatmap, List hitObj } } } + + /// + /// Truncation of to , as well as keeping the result as , are both done + /// + /// for the purposes of stable compatibility + /// . + /// Note that for top-level objects is supposed to be integral anyway; + /// see using when calculating it. + /// Slider ticks and end circles are the exception to that, but they do not matter for stacking. + /// + private static float calculateStackThreshold(IBeatmap beatmap, OsuHitObject hitObject) + => (int)hitObject.TimePreempt * beatmap.StackLeniency; } } From 32454caaa96fa3b8047c01a83faf8da8ffc76608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 19 Dec 2025 12:05:36 +0100 Subject: [PATCH 299/836] Add failing test --- .../UserInterface/TestSceneFormSliderBar.cs | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs index d25ef3a88971..f4d6569dcab9 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs @@ -107,5 +107,63 @@ public void TestNubDoubleClickRevertToDefault() AddAssert("slider is default", () => slider.Current.IsDefault); } + + [Test] + public void TestDisabled() + { + FormSliderBar slider = null!; + + AddStep("create content", () => + { + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.5f, + Direction = FillDirection.Vertical, + Spacing = new Vector2(10), + Children = new Drawable[] + { + slider = new FormSliderBar + { + Caption = "Slider", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Precision = 0.1f, + Default = 5f, + } + }, + } + }; + }); + AddStep("set slider to 1", () => slider.Current.Value = 1); + AddStep("disable slider", () => slider.Current.Disabled = true); + + AddStep("move mouse to nub", () => InputManager.MoveMouseTo(slider.ChildrenOfType().Single())); + + AddStep("double click nub", () => + { + InputManager.Click(MouseButton.Left); + InputManager.Click(MouseButton.Left); + }); + + AddAssert("slider is still at 1", () => slider.Current.Value, () => Is.EqualTo(1)); + + AddStep("click on textbox part", () => + { + InputManager.MoveMouseTo(slider.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + AddAssert("no text selected", () => slider.ChildrenOfType().Single().SelectedText, () => Is.Empty); + AddStep("attempt to input text", () => + { + InputManager.Key(Key.Number4); + InputManager.Key(Key.Enter); + }); + AddAssert("slider is still at 1", () => slider.Current.Value, () => Is.EqualTo(1)); + } } } From ecc51d47016b60e93fcf7736821f2a7230f7778b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 19 Dec 2025 12:17:44 +0100 Subject: [PATCH 300/836] Fix disabled form slider bars being half-baked In order of severity: - You could actually click on the textbox portion of a disabled textbox, focus it, select text, input stuff, and commit, which would die on the spot. - The slider part had no visual indication that it's not interactable anymore. --- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 8ebaf48ed6af..f4702f000cdf 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -207,6 +207,8 @@ protected override void LoadComplete() } currentNumberInstantaneous.Disabled = disabled; + textBox.ReadOnly = disabled; + updateState(); }; current.CopyTo(currentNumberInstantaneous); @@ -283,7 +285,8 @@ protected override void OnHoverLost(HoverLostEvent e) protected override bool OnClick(ClickEvent e) { - focusManager.ChangeFocus(textBox); + if (!Current.Disabled) + focusManager.ChangeFocus(textBox); return true; } @@ -380,7 +383,7 @@ private void load() protected override void LoadComplete() { base.LoadComplete(); - updateState(); + Current.BindDisabledChanged(_ => updateState(), true); } protected override void UpdateAfterChildren() @@ -434,8 +437,17 @@ protected override void OnFocusLost(FocusLostEvent e) private void updateState() { rightBox.Colour = colourProvider.Background6; - leftBox.Colour = HasFocus || IsHovered || IsDragged ? colourProvider.Highlight1.Opacity(0.5f) : colourProvider.Dark2; - nub.Colour = HasFocus || IsHovered || IsDragged ? colourProvider.Highlight1 : colourProvider.Light4; + + if (Current.Disabled) + { + leftBox.Colour = colourProvider.Dark3; + nub.Colour = colourProvider.Dark1; + } + else + { + leftBox.Colour = HasFocus || IsHovered || IsDragged ? colourProvider.Highlight1.Opacity(0.5f) : colourProvider.Dark2; + nub.Colour = HasFocus || IsHovered || IsDragged ? colourProvider.Highlight1 : colourProvider.Light4; + } } protected override void UpdateValue(float value) From 25ba3f2dc6ef7a36b3917c636e4fecc61d9966ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 19 Dec 2025 13:11:07 +0100 Subject: [PATCH 301/836] Fix yet another incorrect threshold check in stacking code --- osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs | 2 +- osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs index aaff1a2554c5..2b7ae143d845 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs @@ -27,7 +27,7 @@ public class OsuBeatmapConversionTest : BeatmapConversionTest [TestCase("multi-segment-slider")] [TestCase("nan-slider")] [TestCase("1124896")] - // [TestCase("1341554")] TODO: investigate later + [TestCase("1341554")] [TestCase("2593923")] // [TestCase("2730824")] TODO: investigate later // [TestCase("4235513")] TODO: investigate later diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs index bbe28817a0bb..0566b7f3341d 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs @@ -151,7 +151,10 @@ private static void applyStacking(IBeatmap beatmap, List hitObject double endTime = objectN.GetEndTime(); - if (objectI.StartTime - endTime > stackThreshold) + // truncation to integer is required to match stable + // compare https://github.com/peppy/osu-stable-reference/blob/08e3dafd525934cf48880b08e91c24ce4ad8b761/osu!/GameplayElements/HitObjectManager.cs#L1725 + // - both quantities being subtracted there are integers + if ((int)objectI.StartTime - (int)endTime > stackThreshold) // We are no longer within stacking range of the previous object. break; From bba4329ab581edd749de5054db453162d978803f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 19 Dec 2025 13:11:31 +0100 Subject: [PATCH 302/836] Remove now-redundant tests They all pass along with the last stacking threshold fix, so I see no reason to keep them in. --- .../OsuBeatmapConversionTest.cs | 2 - .../Beatmaps/2730824-expected-conversion.json | 1 - .../Resources/Testing/Beatmaps/2730824.osu | 1140 ----------------- .../Beatmaps/4235513-expected-conversion.json | 1 - .../Resources/Testing/Beatmaps/4235513.osu | 825 ------------ 5 files changed, 1969 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824-expected-conversion.json delete mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824.osu delete mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513-expected-conversion.json delete mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513.osu diff --git a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs index 2b7ae143d845..b91dcaf7576f 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs @@ -29,8 +29,6 @@ public class OsuBeatmapConversionTest : BeatmapConversionTest [TestCase("1124896")] [TestCase("1341554")] [TestCase("2593923")] - // [TestCase("2730824")] TODO: investigate later - // [TestCase("4235513")] TODO: investigate later [TestCase("801165")] public void Test(string name) => base.Test(name); diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824-expected-conversion.json b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824-expected-conversion.json deleted file mode 100644 index 4c196a182c18..000000000000 --- a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824-expected-conversion.json +++ /dev/null @@ -1 +0,0 @@ -{"Mappings":[{"StartTime":3135.0,"Objects":[{"StartTime":3135.0,"EndTime":3135.0,"X":31.0,"Y":114.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":3321.0,"EndTime":3321.0,"X":121.109383,"Y":118.3692,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":3468.0,"Objects":[{"StartTime":3468.0,"EndTime":3468.0,"X":183.0,"Y":39.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":3654.0,"EndTime":3654.0,"X":273.109375,"Y":34.6308022,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":3801.0,"Objects":[{"StartTime":3801.0,"EndTime":3801.0,"X":358.0,"Y":104.0}]},{"StartTime":4023.0,"Objects":[{"StartTime":4023.0,"EndTime":4023.0,"X":274.0,"Y":180.0}]},{"StartTime":4246.0,"Objects":[{"StartTime":4246.0,"EndTime":4246.0,"X":367.0,"Y":238.0}]},{"StartTime":4468.0,"Objects":[{"StartTime":4468.0,"EndTime":4468.0,"X":273.0,"Y":34.0}]},{"StartTime":4690.0,"Objects":[{"StartTime":4690.0,"EndTime":4690.0,"X":209.0,"Y":249.0}]},{"StartTime":4912.0,"Objects":[{"StartTime":4912.0,"EndTime":4912.0,"X":413.0,"Y":99.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":5245.0,"EndTime":5245.0,"X":281.78244,"Y":149.250275,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":5542.0,"EndTime":5542.0,"X":413.0,"Y":99.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":5801.0,"Objects":[{"StartTime":5801.0,"EndTime":5801.0,"X":504.0,"Y":157.0}]},{"StartTime":6023.0,"Objects":[{"StartTime":6023.0,"EndTime":6023.0,"X":429.0,"Y":235.0}]},{"StartTime":6246.0,"Objects":[{"StartTime":6246.0,"EndTime":6246.0,"X":498.0,"Y":324.0}]},{"StartTime":6468.0,"Objects":[{"StartTime":6468.0,"EndTime":6468.0,"X":331.0,"Y":232.0}]},{"StartTime":6579.0,"Objects":[{"StartTime":6579.0,"EndTime":6579.0,"X":321.0,"Y":232.0}]},{"StartTime":6690.0,"Objects":[{"StartTime":6690.0,"EndTime":6690.0,"X":311.0,"Y":233.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":6876.0,"EndTime":6876.0,"X":304.188019,"Y":322.47525,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7023.0,"Objects":[{"StartTime":7023.0,"EndTime":7023.0,"X":160.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":7209.0,"EndTime":7209.0,"X":166.811981,"Y":294.52475,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":7357.0,"Objects":[{"StartTime":7357.0,"EndTime":7357.0,"X":78.0,"Y":237.0}]},{"StartTime":7579.0,"Objects":[{"StartTime":7579.0,"EndTime":7579.0,"X":14.0,"Y":325.0}]},{"StartTime":7801.0,"Objects":[{"StartTime":7801.0,"EndTime":7801.0,"X":190.0,"Y":197.0}]},{"StartTime":8023.0,"Objects":[{"StartTime":8023.0,"EndTime":8023.0,"X":0.0,"Y":74.0}]},{"StartTime":8134.0,"Objects":[{"StartTime":8134.0,"EndTime":8134.0,"X":25.0,"Y":114.0}]},{"StartTime":8245.0,"Objects":[{"StartTime":8245.0,"EndTime":8245.0,"X":70.0,"Y":131.0}]},{"StartTime":8356.0,"Objects":[{"StartTime":8356.0,"EndTime":8356.0,"X":116.0,"Y":117.0}]},{"StartTime":8468.0,"Objects":[{"StartTime":8468.0,"EndTime":8468.0,"X":143.0,"Y":78.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":8801.0,"EndTime":8801.0,"X":256.694672,"Y":40.1920738,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":9098.0,"EndTime":9098.0,"X":143.0,"Y":78.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":9357.0,"Objects":[{"StartTime":9357.0,"EndTime":9357.0,"X":69.0,"Y":241.0}]},{"StartTime":9579.0,"Objects":[{"StartTime":9579.0,"EndTime":9579.0,"X":48.0,"Y":132.0}]},{"StartTime":9801.0,"Objects":[{"StartTime":9801.0,"EndTime":9801.0,"X":191.0,"Y":187.0}]},{"StartTime":10023.0,"Objects":[{"StartTime":10023.0,"EndTime":10023.0,"X":173.0,"Y":308.0}]},{"StartTime":10246.0,"Objects":[{"StartTime":10246.0,"EndTime":10246.0,"X":0.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":10432.0,"EndTime":10432.0,"X":90.3386841,"Y":374.001251,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":10579.0,"Objects":[{"StartTime":10579.0,"EndTime":10579.0,"X":179.0,"Y":287.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":10765.0,"EndTime":10765.0,"X":269.338684,"Y":296.998749,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":10912.0,"Objects":[{"StartTime":10912.0,"EndTime":10912.0,"X":363.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":10987.0,"EndTime":10987.0,"X":355.587219,"Y":224.183121,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":11134.0,"Objects":[{"StartTime":11134.0,"EndTime":11134.0,"X":415.0,"Y":327.0}]},{"StartTime":11579.0,"Objects":[{"StartTime":11579.0,"EndTime":11579.0,"X":267.0,"Y":121.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":11654.0,"EndTime":11654.0,"X":259.587219,"Y":169.183121,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":11801.0,"Objects":[{"StartTime":11801.0,"EndTime":11801.0,"X":503.983917,"Y":122.983917}]},{"StartTime":11912.0,"Objects":[{"StartTime":11912.0,"EndTime":11912.0,"X":507.991943,"Y":126.991959}]},{"StartTime":12023.0,"Objects":[{"StartTime":12023.0,"EndTime":12023.0,"X":512.0,"Y":131.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":12356.0,"EndTime":12356.0,"X":369.271851,"Y":134.8306,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":12653.0,"EndTime":12653.0,"X":512.0,"Y":131.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":12912.0,"Objects":[{"StartTime":12912.0,"EndTime":12912.0,"X":275.0,"Y":68.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":13098.0,"EndTime":13098.0,"X":345.202454,"Y":16.3424149,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":13357.0,"Objects":[{"StartTime":13357.0,"EndTime":13357.0,"X":276.0,"Y":180.0}]},{"StartTime":13579.0,"Objects":[{"StartTime":13579.0,"EndTime":13579.0,"X":121.0,"Y":111.0}]},{"StartTime":13690.0,"Objects":[{"StartTime":13690.0,"EndTime":13690.0,"X":72.0,"Y":116.0}]},{"StartTime":13801.0,"Objects":[{"StartTime":13801.0,"EndTime":13801.0,"X":24.0,"Y":122.0}]},{"StartTime":14023.0,"Objects":[{"StartTime":14023.0,"EndTime":14023.0,"X":188.0,"Y":13.0}]},{"StartTime":14246.0,"Objects":[{"StartTime":14246.0,"EndTime":14246.0,"X":86.0,"Y":226.0}]},{"StartTime":14468.0,"Objects":[{"StartTime":14468.0,"EndTime":14468.0,"X":235.0,"Y":139.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":14876.0,"EndTime":14876.0,"X":243.728867,"Y":327.927429,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":15134.0,"Objects":[{"StartTime":15134.0,"EndTime":15134.0,"X":23.0,"Y":350.0}]},{"StartTime":15245.0,"Objects":[{"StartTime":15245.0,"EndTime":15245.0,"X":21.0,"Y":302.0}]},{"StartTime":15356.0,"Objects":[{"StartTime":15356.0,"EndTime":15356.0,"X":52.0,"Y":265.0}]},{"StartTime":15467.0,"Objects":[{"StartTime":15467.0,"EndTime":15467.0,"X":99.0,"Y":257.0}]},{"StartTime":15579.0,"Objects":[{"StartTime":15579.0,"EndTime":15579.0,"X":140.0,"Y":281.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":15765.0,"EndTime":15765.0,"X":236.782974,"Y":269.1972,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":15912.0,"Objects":[{"StartTime":15912.0,"EndTime":15912.0,"X":184.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":16098.0,"EndTime":16098.0,"X":280.782959,"Y":150.1972,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":16246.0,"Objects":[{"StartTime":16246.0,"EndTime":16246.0,"X":412.0,"Y":135.0}]},{"StartTime":16468.0,"Objects":[{"StartTime":16468.0,"EndTime":16468.0,"X":394.0,"Y":22.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":16765.0,"EndTime":16765.0,"X":382.8766,"Y":156.34137,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":16912.0,"Objects":[{"StartTime":16912.0,"EndTime":16912.0,"X":487.0,"Y":220.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":16987.0,"EndTime":16987.0,"X":477.05722,"Y":267.725281,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":17134.0,"Objects":[{"StartTime":17134.0,"EndTime":17134.0,"X":380.0,"Y":382.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":17209.0,"EndTime":17209.0,"X":370.05722,"Y":334.274719,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":17357.0,"Objects":[{"StartTime":17357.0,"EndTime":17357.0,"X":264.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":17543.0,"EndTime":17543.0,"X":137.27359,"Y":327.860168,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":17690.0,"Objects":[{"StartTime":17690.0,"EndTime":17690.0,"X":26.0,"Y":244.0}]},{"StartTime":17801.0,"Objects":[{"StartTime":17801.0,"EndTime":17801.0,"X":56.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":17987.0,"EndTime":17987.0,"X":130.303314,"Y":232.876617,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18134.0,"Objects":[{"StartTime":18134.0,"EndTime":18134.0,"X":43.99196,"Y":356.991943}]},{"StartTime":18246.0,"Objects":[{"StartTime":18246.0,"EndTime":18246.0,"X":48.0,"Y":361.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18321.0,"EndTime":18321.0,"X":29.613245,"Y":288.288757,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18468.0,"Objects":[{"StartTime":18468.0,"EndTime":18468.0,"X":130.0,"Y":232.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18543.0,"EndTime":18543.0,"X":146.027267,"Y":158.7325,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18690.0,"Objects":[{"StartTime":18690.0,"EndTime":18690.0,"X":231.0,"Y":7.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18876.0,"EndTime":18876.0,"X":308.9407,"Y":100.850838,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19023.0,"Objects":[{"StartTime":19023.0,"EndTime":19023.0,"X":257.991943,"Y":218.991959}]},{"StartTime":19134.0,"Objects":[{"StartTime":19134.0,"EndTime":19134.0,"X":262.0,"Y":223.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19320.0,"EndTime":19320.0,"X":406.117065,"Y":241.147919,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19468.0,"Objects":[{"StartTime":19468.0,"EndTime":19468.0,"X":487.991943,"Y":161.991959}]},{"StartTime":19579.0,"Objects":[{"StartTime":19579.0,"EndTime":19579.0,"X":492.0,"Y":166.0}]},{"StartTime":19801.0,"Objects":[{"StartTime":19801.0,"EndTime":19801.0,"X":411.0,"Y":310.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19876.0,"EndTime":19876.0,"X":405.865967,"Y":240.440765,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20023.0,"Objects":[{"StartTime":20023.0,"EndTime":20023.0,"X":372.0,"Y":6.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20209.0,"EndTime":20209.0,"X":395.446167,"Y":136.246689,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20357.0,"Objects":[{"StartTime":20357.0,"EndTime":20357.0,"X":257.991943,"Y":142.991959}]},{"StartTime":20468.0,"Objects":[{"StartTime":20468.0,"EndTime":20468.0,"X":262.0,"Y":147.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20543.0,"EndTime":20543.0,"X":305.505249,"Y":85.90751,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20690.0,"Objects":[{"StartTime":20690.0,"EndTime":20690.0,"X":160.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20765.0,"EndTime":20765.0,"X":193.541016,"Y":67.08204,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20912.0,"Objects":[{"StartTime":20912.0,"EndTime":20912.0,"X":306.0,"Y":220.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21098.0,"EndTime":21098.0,"X":183.694366,"Y":194.6086,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21246.0,"Objects":[{"StartTime":21246.0,"EndTime":21246.0,"X":27.9919586,"Y":175.991959}]},{"StartTime":21357.0,"Objects":[{"StartTime":21357.0,"EndTime":21357.0,"X":32.0,"Y":180.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21543.0,"EndTime":21543.0,"X":85.78159,"Y":113.576027,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21690.0,"Objects":[{"StartTime":21690.0,"EndTime":21690.0,"X":113.0,"Y":363.0}]},{"StartTime":21801.0,"Objects":[{"StartTime":21801.0,"EndTime":21801.0,"X":43.0,"Y":305.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21876.0,"EndTime":21876.0,"X":103.223976,"Y":267.573425,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22023.0,"Objects":[{"StartTime":22023.0,"EndTime":22023.0,"X":209.0,"Y":310.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22098.0,"EndTime":22098.0,"X":198.14006,"Y":384.2096,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22246.0,"Objects":[{"StartTime":22246.0,"EndTime":22246.0,"X":102.0,"Y":166.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22321.0,"EndTime":22321.0,"X":170.558487,"Y":184.751465,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22468.0,"Objects":[{"StartTime":22468.0,"EndTime":22468.0,"X":249.0,"Y":121.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22543.0,"EndTime":22543.0,"X":280.5543,"Y":184.69635,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22690.0,"Objects":[{"StartTime":22690.0,"EndTime":22690.0,"X":209.0,"Y":310.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22876.0,"EndTime":22876.0,"X":350.500458,"Y":343.22287,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23023.0,"Objects":[{"StartTime":23023.0,"EndTime":23023.0,"X":437.991943,"Y":255.991959}]},{"StartTime":23134.0,"Objects":[{"StartTime":23134.0,"EndTime":23134.0,"X":442.0,"Y":260.0}]},{"StartTime":23357.0,"Objects":[{"StartTime":23357.0,"EndTime":23357.0,"X":250.0,"Y":201.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23432.0,"EndTime":23432.0,"X":325.0,"Y":201.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23579.0,"Objects":[{"StartTime":23579.0,"EndTime":23579.0,"X":442.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23654.0,"EndTime":23654.0,"X":446.8069,"Y":191.50061,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23801.0,"Objects":[{"StartTime":23801.0,"EndTime":23801.0,"X":343.0,"Y":301.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23876.0,"EndTime":23876.0,"X":335.715149,"Y":371.783661,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":24023.0,"Objects":[{"StartTime":24023.0,"EndTime":24023.0,"X":442.0,"Y":260.0}]},{"StartTime":24134.0,"Objects":[{"StartTime":24134.0,"EndTime":24134.0,"X":397.0,"Y":202.0}]},{"StartTime":24245.0,"Objects":[{"StartTime":24245.0,"EndTime":24245.0,"X":325.0,"Y":202.0}]},{"StartTime":24357.0,"Objects":[{"StartTime":24357.0,"EndTime":24357.0,"X":246.0,"Y":274.0}]},{"StartTime":24468.0,"Objects":[{"StartTime":24468.0,"EndTime":24468.0,"X":153.0,"Y":226.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":24654.0,"EndTime":24654.0,"X":147.008972,"Y":368.243042,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":24801.0,"Objects":[{"StartTime":24801.0,"EndTime":24801.0,"X":18.9919586,"Y":65.99196}]},{"StartTime":24912.0,"Objects":[{"StartTime":24912.0,"EndTime":24912.0,"X":23.0,"Y":70.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25098.0,"EndTime":25098.0,"X":28.99103,"Y":212.243042,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25246.0,"Objects":[{"StartTime":25246.0,"EndTime":25246.0,"X":211.991959,"Y":139.991959}]},{"StartTime":25357.0,"Objects":[{"StartTime":25357.0,"EndTime":25357.0,"X":216.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25432.0,"EndTime":25432.0,"X":141.9953,"Y":131.822,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25579.0,"Objects":[{"StartTime":25579.0,"EndTime":25579.0,"X":105.0,"Y":32.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25654.0,"EndTime":25654.0,"X":179.0047,"Y":44.17799,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25801.0,"Objects":[{"StartTime":25801.0,"EndTime":25801.0,"X":328.0,"Y":246.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25876.0,"EndTime":25876.0,"X":253.9953,"Y":233.822,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26023.0,"Objects":[{"StartTime":26023.0,"EndTime":26023.0,"X":270.0,"Y":66.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26098.0,"EndTime":26098.0,"X":303.2081,"Y":129.55838,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26246.0,"Objects":[{"StartTime":26246.0,"EndTime":26246.0,"X":162.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26432.0,"EndTime":26432.0,"X":207.819519,"Y":145.865692,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26579.0,"Objects":[{"StartTime":26579.0,"EndTime":26579.0,"X":206.991959,"Y":368.991943}]},{"StartTime":26690.0,"Objects":[{"StartTime":26690.0,"EndTime":26690.0,"X":211.0,"Y":373.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26876.0,"EndTime":26876.0,"X":91.82551,"Y":333.5027,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27023.0,"Objects":[{"StartTime":27023.0,"EndTime":27023.0,"X":295.991943,"Y":195.991959}]},{"StartTime":27134.0,"Objects":[{"StartTime":27134.0,"EndTime":27134.0,"X":300.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27209.0,"EndTime":27209.0,"X":267.82074,"Y":267.745819,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27357.0,"Objects":[{"StartTime":27357.0,"EndTime":27357.0,"X":402.0,"Y":363.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27432.0,"EndTime":27432.0,"X":373.273865,"Y":293.71936,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27579.0,"Objects":[{"StartTime":27579.0,"EndTime":27579.0,"X":178.0,"Y":44.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27765.0,"EndTime":27765.0,"X":183.8688,"Y":176.813446,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27912.0,"Objects":[{"StartTime":27912.0,"EndTime":27912.0,"X":324.991943,"Y":84.99196}]},{"StartTime":28023.0,"Objects":[{"StartTime":28023.0,"EndTime":28023.0,"X":329.0,"Y":89.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":28098.0,"EndTime":28098.0,"X":255.973389,"Y":106.091339,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":28246.0,"Objects":[{"StartTime":28246.0,"EndTime":28246.0,"X":103.0,"Y":268.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":28432.0,"EndTime":28432.0,"X":183.533081,"Y":176.552429,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":28690.0,"Objects":[{"StartTime":28690.0,"EndTime":28690.0,"X":360.0,"Y":217.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":28765.0,"EndTime":28765.0,"X":286.9734,"Y":234.091339,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":28912.0,"Objects":[{"StartTime":28912.0,"EndTime":28912.0,"X":178.0,"Y":44.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29098.0,"EndTime":29098.0,"X":183.8688,"Y":176.813446,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":29357.0,"Objects":[{"StartTime":29357.0,"EndTime":29357.0,"X":247.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29432.0,"EndTime":29432.0,"X":229.52034,"Y":316.708374,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":29579.0,"Objects":[{"StartTime":29579.0,"EndTime":29579.0,"X":26.0,"Y":254.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29654.0,"EndTime":29654.0,"X":93.5281143,"Y":271.24292,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":29801.0,"Objects":[{"StartTime":29801.0,"EndTime":29801.0,"X":233.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29876.0,"EndTime":29876.0,"X":182.988586,"Y":176.208755,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30023.0,"Objects":[{"StartTime":30023.0,"EndTime":30023.0,"X":173.0,"Y":257.0}]},{"StartTime":30246.0,"Objects":[{"StartTime":30246.0,"EndTime":30246.0,"X":173.0,"Y":257.0}]},{"StartTime":30690.0,"Objects":[{"StartTime":30690.0,"EndTime":30690.0,"X":173.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30765.0,"EndTime":30765.0,"X":230.78125,"Y":218.994263,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30912.0,"Objects":[{"StartTime":30912.0,"EndTime":30912.0,"X":173.0,"Y":42.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30987.0,"EndTime":30987.0,"X":176.039978,"Y":111.164528,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31134.0,"Objects":[{"StartTime":31134.0,"EndTime":31134.0,"X":353.0,"Y":122.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31209.0,"EndTime":31209.0,"X":290.774017,"Y":91.4817657,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31357.0,"Objects":[{"StartTime":31357.0,"EndTime":31357.0,"X":173.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31432.0,"EndTime":31432.0,"X":230.78125,"Y":218.994263,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31579.0,"Objects":[{"StartTime":31579.0,"EndTime":31579.0,"X":331.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31765.0,"EndTime":31765.0,"X":339.830933,"Y":355.1529,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31912.0,"Objects":[{"StartTime":31912.0,"EndTime":31912.0,"X":433.0,"Y":278.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32098.0,"EndTime":32098.0,"X":424.9847,"Y":165.785889,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32246.0,"Objects":[{"StartTime":32246.0,"EndTime":32246.0,"X":510.0,"Y":105.0}]},{"StartTime":32468.0,"Objects":[{"StartTime":32468.0,"EndTime":32468.0,"X":510.0,"Y":105.0}]},{"StartTime":32690.0,"Objects":[{"StartTime":32690.0,"EndTime":32690.0,"X":235.0,"Y":27.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32765.0,"EndTime":32765.0,"X":226.30426,"Y":90.74597,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32912.0,"Objects":[{"StartTime":32912.0,"EndTime":32912.0,"X":350.0,"Y":138.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32987.0,"EndTime":32987.0,"X":319.980743,"Y":86.37892,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33134.0,"Objects":[{"StartTime":33134.0,"EndTime":33134.0,"X":183.0,"Y":198.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33209.0,"EndTime":33209.0,"X":257.0822,"Y":186.302811,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33357.0,"Objects":[{"StartTime":33357.0,"EndTime":33357.0,"X":384.0,"Y":39.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33543.0,"EndTime":33543.0,"X":349.632935,"Y":137.788986,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33690.0,"Objects":[{"StartTime":33690.0,"EndTime":33690.0,"X":501.0,"Y":181.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33876.0,"EndTime":33876.0,"X":454.8317,"Y":124.837044,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34023.0,"Objects":[{"StartTime":34023.0,"EndTime":34023.0,"X":388.0,"Y":225.0}]},{"StartTime":34246.0,"Objects":[{"StartTime":34246.0,"EndTime":34246.0,"X":388.0,"Y":225.0}]},{"StartTime":34468.0,"Objects":[{"StartTime":34468.0,"EndTime":34468.0,"X":512.0,"Y":329.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34543.0,"EndTime":34543.0,"X":471.919983,"Y":272.1336,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34690.0,"Objects":[{"StartTime":34690.0,"EndTime":34690.0,"X":382.0,"Y":326.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34876.0,"EndTime":34876.0,"X":240.883636,"Y":335.966736,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35023.0,"Objects":[{"StartTime":35023.0,"EndTime":35023.0,"X":135.991959,"Y":292.991943}]},{"StartTime":35134.0,"Objects":[{"StartTime":35134.0,"EndTime":35134.0,"X":140.0,"Y":297.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35209.0,"EndTime":35209.0,"X":187.189865,"Y":238.706635,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35357.0,"Objects":[{"StartTime":35357.0,"EndTime":35357.0,"X":322.0,"Y":42.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35543.0,"EndTime":35543.0,"X":274.3119,"Y":151.136856,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35801.0,"Objects":[{"StartTime":35801.0,"EndTime":35801.0,"X":121.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35876.0,"EndTime":35876.0,"X":168.189865,"Y":135.293365,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36024.0,"Objects":[{"StartTime":36024.0,"EndTime":36024.0,"X":299.0,"Y":267.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36210.0,"EndTime":36210.0,"X":274.15448,"Y":150.210541,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36468.0,"Objects":[{"StartTime":36468.0,"EndTime":36468.0,"X":197.0,"Y":292.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36543.0,"EndTime":36543.0,"X":220.717087,"Y":363.151245,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36690.0,"Objects":[{"StartTime":36690.0,"EndTime":36690.0,"X":105.0,"Y":216.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36765.0,"EndTime":36765.0,"X":90.92856,"Y":289.668152,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36912.0,"Objects":[{"StartTime":36912.0,"EndTime":36912.0,"X":325.0,"Y":312.0}]},{"StartTime":37134.0,"Objects":[{"StartTime":37134.0,"EndTime":37134.0,"X":207.0,"Y":192.0}]},{"StartTime":37357.0,"Objects":[{"StartTime":37357.0,"EndTime":37357.0,"X":478.0,"Y":185.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37543.0,"EndTime":37543.0,"X":338.679565,"Y":200.801971,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":37801.0,"Objects":[{"StartTime":37801.0,"EndTime":37801.0,"X":409.0,"Y":38.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37876.0,"EndTime":37876.0,"X":397.115051,"Y":112.052338,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38023.0,"Objects":[{"StartTime":38023.0,"EndTime":38023.0,"X":218.0,"Y":266.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38098.0,"EndTime":38098.0,"X":206.115051,"Y":191.947662,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38246.0,"Objects":[{"StartTime":38246.0,"EndTime":38246.0,"X":299.0,"Y":30.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38432.0,"EndTime":38432.0,"X":188.825577,"Y":79.8648148,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":38579.0,"Objects":[{"StartTime":38579.0,"EndTime":38579.0,"X":74.99196,"Y":28.9919586}]},{"StartTime":38690.0,"Objects":[{"StartTime":38690.0,"EndTime":38690.0,"X":79.0,"Y":33.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":38876.0,"EndTime":38876.0,"X":72.29509,"Y":141.819641,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":39023.0,"Objects":[{"StartTime":39023.0,"EndTime":39023.0,"X":182.0,"Y":295.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":39209.0,"EndTime":39209.0,"X":175.535126,"Y":186.1405,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":39357.0,"Objects":[{"StartTime":39357.0,"EndTime":39357.0,"X":69.0,"Y":244.0}]},{"StartTime":39579.0,"Objects":[{"StartTime":39579.0,"EndTime":39579.0,"X":69.0,"Y":244.0}]},{"StartTime":39801.0,"Objects":[{"StartTime":39801.0,"EndTime":39801.0,"X":257.0,"Y":133.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":39876.0,"EndTime":39876.0,"X":204.156845,"Y":89.1012344,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":40023.0,"Objects":[{"StartTime":40023.0,"EndTime":40023.0,"X":179.0,"Y":216.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":40209.0,"EndTime":40209.0,"X":318.21756,"Y":227.418915,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":40468.0,"Objects":[{"StartTime":40468.0,"EndTime":40468.0,"X":492.0,"Y":74.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":40912.0,"EndTime":40912.0,"X":383.634857,"Y":63.100235,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41209.0,"EndTime":41209.0,"X":407.914,"Y":149.609482,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41357.0,"Objects":[{"StartTime":41357.0,"EndTime":41357.0,"X":492.0,"Y":74.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41801.0,"EndTime":41801.0,"X":380.8066,"Y":100.582275,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42098.0,"EndTime":42098.0,"X":294.218781,"Y":115.022942,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42246.0,"Objects":[{"StartTime":42246.0,"EndTime":42246.0,"X":202.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42432.0,"EndTime":42432.0,"X":194.000076,"Y":168.117783,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42690.0,"Objects":[{"StartTime":42690.0,"EndTime":42690.0,"X":294.0,"Y":115.0}]},{"StartTime":42912.0,"Objects":[{"StartTime":42912.0,"EndTime":42912.0,"X":98.0,"Y":226.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43098.0,"EndTime":43098.0,"X":193.181259,"Y":167.556946,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":43357.0,"Objects":[{"StartTime":43357.0,"EndTime":43357.0,"X":212.0,"Y":338.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43432.0,"EndTime":43432.0,"X":191.175934,"Y":273.79245,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":43579.0,"Objects":[{"StartTime":43579.0,"EndTime":43579.0,"X":289.0,"Y":235.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43654.0,"EndTime":43654.0,"X":310.0445,"Y":170.864365,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":43801.0,"Objects":[{"StartTime":43801.0,"EndTime":43801.0,"X":417.0,"Y":146.0}]},{"StartTime":44023.0,"Objects":[{"StartTime":44023.0,"EndTime":44023.0,"X":417.0,"Y":146.0}]},{"StartTime":44246.0,"Objects":[{"StartTime":44246.0,"EndTime":44246.0,"X":212.0,"Y":338.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44321.0,"EndTime":44321.0,"X":184.7824,"Y":277.928528,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44468.0,"Objects":[{"StartTime":44468.0,"EndTime":44468.0,"X":289.0,"Y":235.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44543.0,"EndTime":44543.0,"X":290.496,"Y":172.141,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44690.0,"Objects":[{"StartTime":44690.0,"EndTime":44690.0,"X":417.0,"Y":146.0}]},{"StartTime":44912.0,"Objects":[{"StartTime":44912.0,"EndTime":44912.0,"X":417.0,"Y":146.0}]},{"StartTime":45134.0,"Objects":[{"StartTime":45134.0,"EndTime":45134.0,"X":192.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":45209.0,"EndTime":45209.0,"X":211.809387,"Y":102.229622,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":45357.0,"Objects":[{"StartTime":45357.0,"EndTime":45357.0,"X":427.0,"Y":40.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":45543.0,"EndTime":45543.0,"X":303.3012,"Y":45.94596,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":45690.0,"Objects":[{"StartTime":45690.0,"EndTime":45690.0,"X":215.991959,"Y":4.99195766}]},{"StartTime":45801.0,"Objects":[{"StartTime":45801.0,"EndTime":45801.0,"X":220.0,"Y":9.0}]},{"StartTime":46023.0,"Objects":[{"StartTime":46023.0,"EndTime":46023.0,"X":301.0,"Y":160.0}]},{"StartTime":46246.0,"Objects":[{"StartTime":46246.0,"EndTime":46246.0,"X":129.0,"Y":125.0}]},{"StartTime":46468.0,"Objects":[{"StartTime":46468.0,"EndTime":46468.0,"X":310.983917,"Y":37.9839172}]},{"StartTime":46579.0,"Objects":[{"StartTime":46579.0,"EndTime":46579.0,"X":314.991943,"Y":41.99196}]},{"StartTime":46690.0,"Objects":[{"StartTime":46690.0,"EndTime":46690.0,"X":319.0,"Y":46.0}]},{"StartTime":46912.0,"Objects":[{"StartTime":46912.0,"EndTime":46912.0,"X":184.0,"Y":235.0}]},{"StartTime":47134.0,"Objects":[{"StartTime":47134.0,"EndTime":47134.0,"X":424.0,"Y":203.0}]},{"StartTime":47357.0,"Objects":[{"StartTime":47357.0,"EndTime":47357.0,"X":222.0,"Y":101.0}]},{"StartTime":47579.0,"Objects":[{"StartTime":47579.0,"EndTime":47579.0,"X":317.0,"Y":195.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":47765.0,"EndTime":47765.0,"X":311.3081,"Y":318.992,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":47912.0,"Objects":[{"StartTime":47912.0,"EndTime":47912.0,"X":405.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48098.0,"EndTime":48098.0,"X":398.957825,"Y":254.92,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":48246.0,"Objects":[{"StartTime":48246.0,"EndTime":48246.0,"X":311.0,"Y":318.0}]},{"StartTime":48468.0,"Objects":[{"StartTime":48468.0,"EndTime":48468.0,"X":477.0,"Y":199.0}]},{"StartTime":48690.0,"Objects":[{"StartTime":48690.0,"EndTime":48690.0,"X":195.0,"Y":231.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48765.0,"EndTime":48765.0,"X":262.158875,"Y":224.2225,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":48912.0,"Objects":[{"StartTime":48912.0,"EndTime":48912.0,"X":246.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48987.0,"EndTime":48987.0,"X":313.158875,"Y":121.222496,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49134.0,"Objects":[{"StartTime":49134.0,"EndTime":49134.0,"X":468.0,"Y":54.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49320.0,"EndTime":49320.0,"X":368.604065,"Y":25.4110832,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49579.0,"Objects":[{"StartTime":49579.0,"EndTime":49579.0,"X":195.0,"Y":231.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49654.0,"EndTime":49654.0,"X":262.158875,"Y":224.2225,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49801.0,"Objects":[{"StartTime":49801.0,"EndTime":49801.0,"X":246.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49876.0,"EndTime":49876.0,"X":313.158875,"Y":121.222496,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50023.0,"Objects":[{"StartTime":50023.0,"EndTime":50023.0,"X":468.0,"Y":54.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50209.0,"EndTime":50209.0,"X":422.311432,"Y":155.298447,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50468.0,"Objects":[{"StartTime":50468.0,"EndTime":50468.0,"X":195.0,"Y":231.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50543.0,"EndTime":50543.0,"X":262.158875,"Y":224.2225,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50690.0,"Objects":[{"StartTime":50690.0,"EndTime":50690.0,"X":246.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50765.0,"EndTime":50765.0,"X":313.158875,"Y":121.222496,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50912.0,"Objects":[{"StartTime":50912.0,"EndTime":50912.0,"X":483.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51098.0,"EndTime":51098.0,"X":421.906952,"Y":154.214828,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":51357.0,"Objects":[{"StartTime":51357.0,"EndTime":51357.0,"X":375.0,"Y":361.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51432.0,"EndTime":51432.0,"X":379.676239,"Y":293.66217,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":51579.0,"Objects":[{"StartTime":51579.0,"EndTime":51579.0,"X":314.0,"Y":122.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51654.0,"EndTime":51654.0,"X":309.323761,"Y":189.33783,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":51801.0,"Objects":[{"StartTime":51801.0,"EndTime":51801.0,"X":379.0,"Y":293.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51987.0,"EndTime":51987.0,"X":248.055283,"Y":303.25946,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":52246.0,"Objects":[{"StartTime":52246.0,"EndTime":52246.0,"X":22.0,"Y":215.0}]},{"StartTime":52357.0,"Objects":[{"StartTime":52357.0,"EndTime":52357.0,"X":55.0,"Y":212.0}]},{"StartTime":52468.0,"Objects":[{"StartTime":52468.0,"EndTime":52468.0,"X":89.0,"Y":209.0}]},{"StartTime":52690.0,"Objects":[{"StartTime":52690.0,"EndTime":52690.0,"X":229.0,"Y":127.0}]},{"StartTime":52912.0,"Objects":[{"StartTime":52912.0,"EndTime":52912.0,"X":152.0,"Y":6.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":53098.0,"EndTime":53098.0,"X":130.962738,"Y":121.142517,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":53357.0,"Objects":[{"StartTime":53357.0,"EndTime":53357.0,"X":240.0,"Y":226.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":53432.0,"EndTime":53432.0,"X":253.058411,"Y":159.775177,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":53579.0,"Objects":[{"StartTime":53579.0,"EndTime":53579.0,"X":31.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":53765.0,"EndTime":53765.0,"X":103.393211,"Y":213.200455,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54023.0,"Objects":[{"StartTime":54023.0,"EndTime":54023.0,"X":260.0,"Y":41.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54098.0,"EndTime":54098.0,"X":206.719482,"Y":69.47305,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54246.0,"Objects":[{"StartTime":54246.0,"EndTime":54246.0,"X":306.0,"Y":188.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54321.0,"EndTime":54321.0,"X":252.739288,"Y":158.844131,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54468.0,"Objects":[{"StartTime":54468.0,"EndTime":54468.0,"X":71.98392,"Y":285.983917}]},{"StartTime":54579.0,"Objects":[{"StartTime":54579.0,"EndTime":54579.0,"X":75.99196,"Y":289.991943}]},{"StartTime":54690.0,"Objects":[{"StartTime":54690.0,"EndTime":54690.0,"X":80.0,"Y":294.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54876.0,"EndTime":54876.0,"X":192.993744,"Y":272.5478,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":55023.0,"Objects":[{"StartTime":55023.0,"EndTime":55023.0,"X":306.0,"Y":294.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":55209.0,"EndTime":55209.0,"X":192.104675,"Y":272.193573,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":55357.0,"Objects":[{"StartTime":55357.0,"EndTime":55357.0,"X":202.0,"Y":155.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":55432.0,"EndTime":55432.0,"X":257.5735,"Y":189.935318,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":55579.0,"Objects":[{"StartTime":55579.0,"EndTime":55579.0,"X":148.0,"Y":372.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":55765.0,"EndTime":55765.0,"X":192.697815,"Y":272.199921,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":55912.0,"Objects":[{"StartTime":55912.0,"EndTime":55912.0,"X":281.991943,"Y":124.991959}]},{"StartTime":56023.0,"Objects":[{"StartTime":56023.0,"EndTime":56023.0,"X":286.0,"Y":129.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56098.0,"EndTime":56098.0,"X":256.8464,"Y":189.879547,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56246.0,"Objects":[{"StartTime":56246.0,"EndTime":56246.0,"X":383.0,"Y":267.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56321.0,"EndTime":56321.0,"X":353.210938,"Y":206.428879,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56468.0,"Objects":[{"StartTime":56468.0,"EndTime":56468.0,"X":164.0,"Y":44.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56654.0,"EndTime":56654.0,"X":147.254028,"Y":186.346436,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56801.0,"Objects":[{"StartTime":56801.0,"EndTime":56801.0,"X":367.0,"Y":78.0}]},{"StartTime":56912.0,"Objects":[{"StartTime":56912.0,"EndTime":56912.0,"X":283.0,"Y":29.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":56987.0,"EndTime":56987.0,"X":273.013336,"Y":109.284035,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57134.0,"Objects":[{"StartTime":57134.0,"EndTime":57134.0,"X":237.0,"Y":264.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57320.0,"EndTime":57320.0,"X":90.27847,"Y":356.257324,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57579.0,"Objects":[{"StartTime":57579.0,"EndTime":57579.0,"X":342.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57654.0,"EndTime":57654.0,"X":345.1496,"Y":303.2366,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57801.0,"Objects":[{"StartTime":57801.0,"EndTime":57801.0,"X":509.0,"Y":173.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57987.0,"EndTime":57987.0,"X":347.468536,"Y":192.426285,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58134.0,"Objects":[{"StartTime":58134.0,"EndTime":58134.0,"X":243.991959,"Y":146.991959}]},{"StartTime":58246.0,"Objects":[{"StartTime":58246.0,"EndTime":58246.0,"X":248.0,"Y":151.0}]},{"StartTime":58468.0,"Objects":[{"StartTime":58468.0,"EndTime":58468.0,"X":386.0,"Y":20.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58543.0,"EndTime":58543.0,"X":338.760651,"Y":91.60191,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58690.0,"Objects":[{"StartTime":58690.0,"EndTime":58690.0,"X":157.0,"Y":70.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58765.0,"EndTime":58765.0,"X":241.659058,"Y":52.80721,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58912.0,"Objects":[{"StartTime":58912.0,"EndTime":58912.0,"X":348.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59098.0,"EndTime":59098.0,"X":193.521332,"Y":272.03418,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59357.0,"Objects":[{"StartTime":59357.0,"EndTime":59357.0,"X":15.0,"Y":170.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59432.0,"EndTime":59432.0,"X":88.98373,"Y":211.08371,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59579.0,"Objects":[{"StartTime":59579.0,"EndTime":59579.0,"X":21.0,"Y":297.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59765.0,"EndTime":59765.0,"X":192.964737,"Y":271.068176,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59912.0,"Objects":[{"StartTime":59912.0,"EndTime":59912.0,"X":264.991943,"Y":85.99196}]},{"StartTime":60023.0,"Objects":[{"StartTime":60023.0,"EndTime":60023.0,"X":269.0,"Y":90.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60098.0,"EndTime":60098.0,"X":224.308014,"Y":165.543427,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60246.0,"Objects":[{"StartTime":60246.0,"EndTime":60246.0,"X":124.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60321.0,"EndTime":60321.0,"X":160.52005,"Y":76.5283051,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60468.0,"Objects":[{"StartTime":60468.0,"EndTime":60468.0,"X":110.0,"Y":347.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60543.0,"EndTime":60543.0,"X":89.8069153,"Y":263.089447,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60690.0,"Objects":[{"StartTime":60690.0,"EndTime":60690.0,"X":192.0,"Y":271.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60765.0,"EndTime":60765.0,"X":246.522369,"Y":205.4,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60912.0,"Objects":[{"StartTime":60912.0,"EndTime":60912.0,"X":358.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61098.0,"EndTime":61098.0,"X":373.250122,"Y":217.322479,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61246.0,"Objects":[{"StartTime":61246.0,"EndTime":61246.0,"X":430.0,"Y":30.0}]},{"StartTime":61357.0,"Objects":[{"StartTime":61357.0,"EndTime":61357.0,"X":505.0,"Y":82.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61432.0,"EndTime":61432.0,"X":431.744324,"Y":122.383575,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61579.0,"Objects":[{"StartTime":61579.0,"EndTime":61579.0,"X":291.0,"Y":5.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61654.0,"EndTime":61654.0,"X":323.602966,"Y":81.7476959,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61801.0,"Objects":[{"StartTime":61801.0,"EndTime":61801.0,"X":241.0,"Y":182.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61876.0,"EndTime":61876.0,"X":152.224548,"Y":196.795914,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62023.0,"Objects":[{"StartTime":62023.0,"EndTime":62023.0,"X":4.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62209.0,"EndTime":62209.0,"X":173.169617,"Y":74.65553,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62468.0,"Objects":[{"StartTime":62468.0,"EndTime":62468.0,"X":118.0,"Y":348.0}]},{"StartTime":62579.0,"Objects":[{"StartTime":62579.0,"EndTime":62579.0,"X":68.0,"Y":264.0}]},{"StartTime":62690.0,"Objects":[{"StartTime":62690.0,"EndTime":62690.0,"X":134.0,"Y":181.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62765.0,"EndTime":62765.0,"X":160.78125,"Y":258.295074,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62912.0,"Objects":[{"StartTime":62912.0,"EndTime":62912.0,"X":264.0,"Y":364.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62987.0,"EndTime":62987.0,"X":272.42923,"Y":281.0493,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63134.0,"Objects":[{"StartTime":63134.0,"EndTime":63134.0,"X":79.0,"Y":96.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63320.0,"EndTime":63320.0,"X":225.852829,"Y":152.494583,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63468.0,"Objects":[{"StartTime":63468.0,"EndTime":63468.0,"X":295.991943,"Y":67.99196}]},{"StartTime":63579.0,"Objects":[{"StartTime":63579.0,"EndTime":63579.0,"X":300.0,"Y":72.0}]},{"StartTime":63801.0,"Objects":[{"StartTime":63801.0,"EndTime":63801.0,"X":188.0,"Y":7.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63876.0,"EndTime":63876.0,"X":179.597717,"Y":72.3198853,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64023.0,"Objects":[{"StartTime":64023.0,"EndTime":64023.0,"X":376.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64209.0,"EndTime":64209.0,"X":299.1473,"Y":71.53191,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64357.0,"Objects":[{"StartTime":64357.0,"EndTime":64357.0,"X":272.991943,"Y":171.991959}]},{"StartTime":64468.0,"Objects":[{"StartTime":64468.0,"EndTime":64468.0,"X":277.0,"Y":176.0}]},{"StartTime":64690.0,"Objects":[{"StartTime":64690.0,"EndTime":64690.0,"X":474.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64765.0,"EndTime":64765.0,"X":414.378662,"Y":73.66836,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64912.0,"Objects":[{"StartTime":64912.0,"EndTime":64912.0,"X":494.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65098.0,"EndTime":65098.0,"X":375.9208,"Y":207.62468,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65246.0,"Objects":[{"StartTime":65246.0,"EndTime":65246.0,"X":311.991943,"Y":367.991943}]},{"StartTime":65357.0,"Objects":[{"StartTime":65357.0,"EndTime":65357.0,"X":316.0,"Y":372.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65432.0,"EndTime":65432.0,"X":310.725769,"Y":296.927643,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65579.0,"Objects":[{"StartTime":65579.0,"EndTime":65579.0,"X":188.0,"Y":163.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65654.0,"EndTime":65654.0,"X":191.017456,"Y":246.244186,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65801.0,"Objects":[{"StartTime":65801.0,"EndTime":65801.0,"X":449.0,"Y":141.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65987.0,"EndTime":65987.0,"X":294.266144,"Y":193.555252,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66134.0,"Objects":[{"StartTime":66134.0,"EndTime":66134.0,"X":246.991959,"Y":22.9919586}]},{"StartTime":66246.0,"Objects":[{"StartTime":66246.0,"EndTime":66246.0,"X":251.0,"Y":27.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66321.0,"EndTime":66321.0,"X":280.9946,"Y":103.377113,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66468.0,"Objects":[{"StartTime":66468.0,"EndTime":66468.0,"X":131.0,"Y":223.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66543.0,"EndTime":66543.0,"X":186.999573,"Y":162.000076,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66690.0,"Objects":[{"StartTime":66690.0,"EndTime":66690.0,"X":292.0,"Y":356.0}]},{"StartTime":66801.0,"Objects":[{"StartTime":66801.0,"EndTime":66801.0,"X":233.0,"Y":273.0}]},{"StartTime":66912.0,"Objects":[{"StartTime":66912.0,"EndTime":66912.0,"X":283.0,"Y":188.0}]},{"StartTime":67023.0,"Objects":[{"StartTime":67023.0,"EndTime":67023.0,"X":387.0,"Y":198.0}]},{"StartTime":67134.0,"Objects":[{"StartTime":67134.0,"EndTime":67134.0,"X":327.0,"Y":275.0}]},{"StartTime":77357.0,"Objects":[{"StartTime":77357.0,"EndTime":77357.0,"X":22.0,"Y":236.0}]},{"StartTime":77468.0,"Objects":[{"StartTime":77468.0,"EndTime":77468.0,"X":28.0,"Y":134.0}]},{"StartTime":77579.0,"Objects":[{"StartTime":77579.0,"EndTime":77579.0,"X":127.0,"Y":121.0}]},{"StartTime":77690.0,"Objects":[{"StartTime":77690.0,"EndTime":77690.0,"X":193.0,"Y":191.0}]},{"StartTime":77801.0,"Objects":[{"StartTime":77801.0,"EndTime":77801.0,"X":272.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77987.0,"EndTime":77987.0,"X":235.886368,"Y":42.98614,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78134.0,"Objects":[{"StartTime":78134.0,"EndTime":78134.0,"X":153.991959,"Y":261.991943}]},{"StartTime":78246.0,"Objects":[{"StartTime":78246.0,"EndTime":78246.0,"X":158.0,"Y":266.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78432.0,"EndTime":78432.0,"X":193.2372,"Y":191.506226,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78579.0,"Objects":[{"StartTime":78579.0,"EndTime":78579.0,"X":263.991943,"Y":281.991943}]},{"StartTime":78690.0,"Objects":[{"StartTime":78690.0,"EndTime":78690.0,"X":268.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78765.0,"EndTime":78765.0,"X":269.681641,"Y":341.7793,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78912.0,"Objects":[{"StartTime":78912.0,"EndTime":78912.0,"X":472.0,"Y":268.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78987.0,"EndTime":78987.0,"X":470.318359,"Y":323.7793,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":79134.0,"Objects":[{"StartTime":79134.0,"EndTime":79134.0,"X":382.0,"Y":379.0}]},{"StartTime":79245.0,"Objects":[{"StartTime":79245.0,"EndTime":79245.0,"X":361.0,"Y":323.0}]},{"StartTime":79356.0,"Objects":[{"StartTime":79356.0,"EndTime":79356.0,"X":369.0,"Y":264.0}]},{"StartTime":79579.0,"Objects":[{"StartTime":79579.0,"EndTime":79579.0,"X":341.0,"Y":102.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":79765.0,"EndTime":79765.0,"X":191.770432,"Y":106.0115,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":79912.0,"Objects":[{"StartTime":79912.0,"EndTime":79912.0,"X":13.9919577,"Y":77.99196}]},{"StartTime":80023.0,"Objects":[{"StartTime":80023.0,"EndTime":80023.0,"X":18.0,"Y":82.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":80209.0,"EndTime":80209.0,"X":112.42717,"Y":24.9309063,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":80357.0,"Objects":[{"StartTime":80357.0,"EndTime":80357.0,"X":44.0,"Y":222.0}]},{"StartTime":80468.0,"Objects":[{"StartTime":80468.0,"EndTime":80468.0,"X":31.0,"Y":206.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":80543.0,"EndTime":80543.0,"X":87.72538,"Y":166.579071,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":80690.0,"Objects":[{"StartTime":80690.0,"EndTime":80690.0,"X":191.0,"Y":106.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":80765.0,"EndTime":80765.0,"X":236.460342,"Y":159.530334,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":80912.0,"Objects":[{"StartTime":80912.0,"EndTime":80912.0,"X":125.0,"Y":355.0}]},{"StartTime":81023.0,"Objects":[{"StartTime":81023.0,"EndTime":81023.0,"X":100.0,"Y":316.0}]},{"StartTime":81134.0,"Objects":[{"StartTime":81134.0,"EndTime":81134.0,"X":122.0,"Y":267.0}]},{"StartTime":81357.0,"Objects":[{"StartTime":81357.0,"EndTime":81357.0,"X":253.0,"Y":316.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":81543.0,"EndTime":81543.0,"X":395.074554,"Y":351.882355,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":81690.0,"Objects":[{"StartTime":81690.0,"EndTime":81690.0,"X":512.0,"Y":190.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":81876.0,"EndTime":81876.0,"X":369.925446,"Y":225.88237,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82023.0,"Objects":[{"StartTime":82023.0,"EndTime":82023.0,"X":328.0,"Y":71.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":82098.0,"EndTime":82098.0,"X":383.893555,"Y":101.619812,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82246.0,"Objects":[{"StartTime":82246.0,"EndTime":82246.0,"X":257.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":82432.0,"EndTime":82432.0,"X":237.943909,"Y":158.504913,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82579.0,"Objects":[{"StartTime":82579.0,"EndTime":82579.0,"X":163.0,"Y":99.0}]},{"StartTime":82690.0,"Objects":[{"StartTime":82690.0,"EndTime":82690.0,"X":111.0,"Y":178.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":82765.0,"EndTime":82765.0,"X":59.71753,"Y":227.345261,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82912.0,"Objects":[{"StartTime":82912.0,"EndTime":82912.0,"X":81.0,"Y":47.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":82987.0,"EndTime":82987.0,"X":135.614578,"Y":4.255745,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":83134.0,"Objects":[{"StartTime":83134.0,"EndTime":83134.0,"X":0.0,"Y":177.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":83320.0,"EndTime":83320.0,"X":43.84988,"Y":309.314972,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":83468.0,"Objects":[{"StartTime":83468.0,"EndTime":83468.0,"X":47.00804,"Y":313.008057}]},{"StartTime":83579.0,"Objects":[{"StartTime":83579.0,"EndTime":83579.0,"X":51.0160828,"Y":317.016083}]},{"StartTime":83801.0,"Objects":[{"StartTime":83801.0,"EndTime":83801.0,"X":139.0,"Y":384.0}]},{"StartTime":84023.0,"Objects":[{"StartTime":84023.0,"EndTime":84023.0,"X":188.0,"Y":280.0}]},{"StartTime":84246.0,"Objects":[{"StartTime":84246.0,"EndTime":84246.0,"X":103.0,"Y":89.0}]},{"StartTime":84468.0,"Objects":[{"StartTime":84468.0,"EndTime":84468.0,"X":224.0,"Y":144.0}]},{"StartTime":84579.0,"Objects":[{"StartTime":84579.0,"EndTime":84579.0,"X":290.0,"Y":148.0}]},{"StartTime":84690.0,"Objects":[{"StartTime":84690.0,"EndTime":84690.0,"X":337.0,"Y":103.0}]},{"StartTime":84801.0,"Objects":[{"StartTime":84801.0,"EndTime":84801.0,"X":339.0,"Y":38.0}]},{"StartTime":84912.0,"Objects":[{"StartTime":84912.0,"EndTime":84912.0,"X":295.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":85098.0,"EndTime":85098.0,"X":290.461456,"Y":146.231247,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":85246.0,"Objects":[{"StartTime":85246.0,"EndTime":85246.0,"X":220.991959,"Y":231.991959}]},{"StartTime":85357.0,"Objects":[{"StartTime":85357.0,"EndTime":85357.0,"X":225.0,"Y":236.0}]},{"StartTime":85579.0,"Objects":[{"StartTime":85579.0,"EndTime":85579.0,"X":398.0,"Y":86.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":85654.0,"EndTime":85654.0,"X":390.427429,"Y":126.911087,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":85801.0,"Objects":[{"StartTime":85801.0,"EndTime":85801.0,"X":115.0,"Y":294.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":85987.0,"EndTime":85987.0,"X":224.971466,"Y":235.134537,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":86246.0,"Objects":[{"StartTime":86246.0,"EndTime":86246.0,"X":115.0,"Y":294.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86321.0,"EndTime":86321.0,"X":115.371964,"Y":222.39064,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":86468.0,"Objects":[{"StartTime":86468.0,"EndTime":86468.0,"X":22.0,"Y":157.0}]},{"StartTime":86579.0,"Objects":[{"StartTime":86579.0,"EndTime":86579.0,"X":55.0,"Y":100.0}]},{"StartTime":86690.0,"Objects":[{"StartTime":86690.0,"EndTime":86690.0,"X":119.0,"Y":90.0}]},{"StartTime":86912.0,"Objects":[{"StartTime":86912.0,"EndTime":86912.0,"X":308.0,"Y":247.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":86987.0,"EndTime":86987.0,"X":233.004623,"Y":247.833282,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":87134.0,"Objects":[{"StartTime":87134.0,"EndTime":87134.0,"X":228.0,"Y":131.0}]},{"StartTime":87357.0,"Objects":[{"StartTime":87357.0,"EndTime":87357.0,"X":177.0,"Y":357.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87432.0,"EndTime":87432.0,"X":117.9708,"Y":310.7339,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":87579.0,"Objects":[{"StartTime":87579.0,"EndTime":87579.0,"X":233.0,"Y":249.0}]},{"StartTime":87801.0,"Objects":[{"StartTime":87801.0,"EndTime":87801.0,"X":15.0,"Y":324.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":87876.0,"EndTime":87876.0,"X":38.60399,"Y":258.514923,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88023.0,"Objects":[{"StartTime":88023.0,"EndTime":88023.0,"X":224.0,"Y":165.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88098.0,"EndTime":88098.0,"X":149.013092,"Y":166.401627,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88246.0,"Objects":[{"StartTime":88246.0,"EndTime":88246.0,"X":258.0,"Y":70.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88321.0,"EndTime":88321.0,"X":183.013092,"Y":71.40163,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88468.0,"Objects":[{"StartTime":88468.0,"EndTime":88468.0,"X":5.0,"Y":16.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88654.0,"EndTime":88654.0,"X":43.598732,"Y":145.0479,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":88912.0,"Objects":[{"StartTime":88912.0,"EndTime":88912.0,"X":273.0,"Y":256.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":88987.0,"EndTime":88987.0,"X":198.00383,"Y":255.242462,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":89134.0,"Objects":[{"StartTime":89134.0,"EndTime":89134.0,"X":3.0,"Y":269.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89320.0,"EndTime":89320.0,"X":42.83066,"Y":145.045731,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":89579.0,"Objects":[{"StartTime":89579.0,"EndTime":89579.0,"X":124.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89654.0,"EndTime":89654.0,"X":114.932907,"Y":317.385345,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":89801.0,"Objects":[{"StartTime":89801.0,"EndTime":89801.0,"X":208.0,"Y":188.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":89876.0,"EndTime":89876.0,"X":197.526962,"Y":254.4049,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":90023.0,"Objects":[{"StartTime":90023.0,"EndTime":90023.0,"X":3.0,"Y":269.0}]},{"StartTime":90134.0,"Objects":[{"StartTime":90134.0,"EndTime":90134.0,"X":49.0,"Y":218.0}]},{"StartTime":90246.0,"Objects":[{"StartTime":90246.0,"EndTime":90246.0,"X":115.0,"Y":225.0}]},{"StartTime":90468.0,"Objects":[{"StartTime":90468.0,"EndTime":90468.0,"X":0.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":90543.0,"EndTime":90543.0,"X":55.339325,"Y":99.68659,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":90690.0,"Objects":[{"StartTime":90690.0,"EndTime":90690.0,"X":218.0,"Y":6.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":90876.0,"EndTime":90876.0,"X":195.563538,"Y":127.699821,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":91134.0,"Objects":[{"StartTime":91134.0,"EndTime":91134.0,"X":419.0,"Y":145.0}]},{"StartTime":91246.0,"Objects":[{"StartTime":91246.0,"EndTime":91246.0,"X":479.0,"Y":56.0}]},{"StartTime":91357.0,"Objects":[{"StartTime":91357.0,"EndTime":91357.0,"X":379.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":91432.0,"EndTime":91432.0,"X":367.074463,"Y":67.35657,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":91579.0,"Objects":[{"StartTime":91579.0,"EndTime":91579.0,"X":512.0,"Y":276.0}]},{"StartTime":91690.0,"Objects":[{"StartTime":91690.0,"EndTime":91690.0,"X":468.0,"Y":233.0}]},{"StartTime":91801.0,"Objects":[{"StartTime":91801.0,"EndTime":91801.0,"X":406.0,"Y":261.0}]},{"StartTime":91912.0,"Objects":[{"StartTime":91912.0,"EndTime":91912.0,"X":318.0,"Y":330.0}]},{"StartTime":92023.0,"Objects":[{"StartTime":92023.0,"EndTime":92023.0,"X":224.0,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92209.0,"EndTime":92209.0,"X":226.0476,"Y":150.599991,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":92357.0,"Objects":[{"StartTime":92357.0,"EndTime":92357.0,"X":313.991943,"Y":212.991959}]},{"StartTime":92468.0,"Objects":[{"StartTime":92468.0,"EndTime":92468.0,"X":318.0,"Y":217.0}]},{"StartTime":92690.0,"Objects":[{"StartTime":92690.0,"EndTime":92690.0,"X":149.0,"Y":15.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92765.0,"EndTime":92765.0,"X":131.775192,"Y":83.55616,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":92912.0,"Objects":[{"StartTime":92912.0,"EndTime":92912.0,"X":342.0,"Y":63.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92987.0,"EndTime":92987.0,"X":267.0478,"Y":60.3231354,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93134.0,"Objects":[{"StartTime":93134.0,"EndTime":93134.0,"X":170.0,"Y":201.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93209.0,"EndTime":93209.0,"X":244.952209,"Y":203.676865,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93357.0,"Objects":[{"StartTime":93357.0,"EndTime":93357.0,"X":472.0,"Y":64.0}]},{"StartTime":93468.0,"Objects":[{"StartTime":93468.0,"EndTime":93468.0,"X":506.0,"Y":125.0}]},{"StartTime":93579.0,"Objects":[{"StartTime":93579.0,"EndTime":93579.0,"X":462.0,"Y":179.0}]},{"StartTime":93690.0,"Objects":[{"StartTime":93690.0,"EndTime":93690.0,"X":366.0,"Y":146.0}]},{"StartTime":93801.0,"Objects":[{"StartTime":93801.0,"EndTime":93801.0,"X":285.0,"Y":212.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93987.0,"EndTime":93987.0,"X":272.6529,"Y":342.357147,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94134.0,"Objects":[{"StartTime":94134.0,"EndTime":94134.0,"X":364.991943,"Y":282.991943}]},{"StartTime":94246.0,"Objects":[{"StartTime":94246.0,"EndTime":94246.0,"X":369.0,"Y":287.0}]},{"StartTime":94468.0,"Objects":[{"StartTime":94468.0,"EndTime":94468.0,"X":219.0,"Y":185.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":94543.0,"EndTime":94543.0,"X":284.25824,"Y":211.452911,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94690.0,"Objects":[{"StartTime":94690.0,"EndTime":94690.0,"X":336.0,"Y":23.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":94765.0,"EndTime":94765.0,"X":347.338745,"Y":97.13793,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94912.0,"Objects":[{"StartTime":94912.0,"EndTime":94912.0,"X":433.0,"Y":84.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":94987.0,"EndTime":94987.0,"X":444.338745,"Y":158.137939,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":95134.0,"Objects":[{"StartTime":95134.0,"EndTime":95134.0,"X":284.0,"Y":211.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95209.0,"EndTime":95209.0,"X":272.661255,"Y":285.137939,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":95356.0,"Objects":[{"StartTime":95356.0,"EndTime":95356.0,"X":187.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95431.0,"EndTime":95431.0,"X":175.661255,"Y":346.137939,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":95579.0,"Objects":[{"StartTime":95579.0,"EndTime":95579.0,"X":356.0,"Y":383.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":95765.0,"EndTime":95765.0,"X":488.053619,"Y":358.016022,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96023.0,"Objects":[{"StartTime":96023.0,"EndTime":96023.0,"X":272.0,"Y":285.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96209.0,"EndTime":96209.0,"X":139.5626,"Y":259.780029,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96357.0,"Objects":[{"StartTime":96357.0,"EndTime":96357.0,"X":196.991959,"Y":120.991959}]},{"StartTime":96468.0,"Objects":[{"StartTime":96468.0,"EndTime":96468.0,"X":201.0,"Y":125.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96543.0,"EndTime":96543.0,"X":216.962341,"Y":198.281677,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96690.0,"Objects":[{"StartTime":96690.0,"EndTime":96690.0,"X":271.0,"Y":284.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96765.0,"EndTime":96765.0,"X":256.1003,"Y":357.5051,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96912.0,"Objects":[{"StartTime":96912.0,"EndTime":96912.0,"X":84.0,"Y":186.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97098.0,"EndTime":97098.0,"X":216.1286,"Y":197.325577,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":97246.0,"Objects":[{"StartTime":97246.0,"EndTime":97246.0,"X":142.991959,"Y":263.991943}]},{"StartTime":97357.0,"Objects":[{"StartTime":97357.0,"EndTime":97357.0,"X":147.0,"Y":268.0}]},{"StartTime":97579.0,"Objects":[{"StartTime":97579.0,"EndTime":97579.0,"X":357.0,"Y":138.0}]},{"StartTime":97801.0,"Objects":[{"StartTime":97801.0,"EndTime":97801.0,"X":176.0,"Y":7.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97987.0,"EndTime":97987.0,"X":155.1887,"Y":93.60436,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98134.0,"Objects":[{"StartTime":98134.0,"EndTime":98134.0,"X":202.991959,"Y":265.991943}]},{"StartTime":98246.0,"Objects":[{"StartTime":98246.0,"EndTime":98246.0,"X":207.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98321.0,"EndTime":98321.0,"X":224.953857,"Y":204.034622,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98468.0,"Objects":[{"StartTime":98468.0,"EndTime":98468.0,"X":247.0,"Y":69.0}]},{"StartTime":98579.0,"Objects":[{"StartTime":98579.0,"EndTime":98579.0,"X":294.0,"Y":108.0}]},{"StartTime":98690.0,"Objects":[{"StartTime":98690.0,"EndTime":98690.0,"X":353.0,"Y":100.0}]},{"StartTime":98801.0,"Objects":[{"StartTime":98801.0,"EndTime":98801.0,"X":397.0,"Y":60.0}]},{"StartTime":98912.0,"Objects":[{"StartTime":98912.0,"EndTime":98912.0,"X":496.0,"Y":86.0}]},{"StartTime":99023.0,"Objects":[{"StartTime":99023.0,"EndTime":99023.0,"X":491.0,"Y":189.0}]},{"StartTime":99134.0,"Objects":[{"StartTime":99134.0,"EndTime":99134.0,"X":389.0,"Y":228.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":99320.0,"EndTime":99320.0,"X":379.916351,"Y":364.565735,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":99468.0,"Objects":[{"StartTime":99468.0,"EndTime":99468.0,"X":266.991943,"Y":53.99196}]},{"StartTime":99579.0,"Objects":[{"StartTime":99579.0,"EndTime":99579.0,"X":271.0,"Y":58.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":99765.0,"EndTime":99765.0,"X":280.083649,"Y":194.56575,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":99912.0,"Objects":[{"StartTime":99912.0,"EndTime":99912.0,"X":185.991959,"Y":347.991943}]},{"StartTime":100023.0,"Objects":[{"StartTime":100023.0,"EndTime":100023.0,"X":190.0,"Y":352.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100098.0,"EndTime":100098.0,"X":237.068085,"Y":307.034576,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100246.0,"Objects":[{"StartTime":100246.0,"EndTime":100246.0,"X":347.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100321.0,"EndTime":100321.0,"X":278.9459,"Y":193.096,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100468.0,"Objects":[{"StartTime":100468.0,"EndTime":100468.0,"X":84.0,"Y":306.0}]},{"StartTime":100579.0,"Objects":[{"StartTime":100579.0,"EndTime":100579.0,"X":105.0,"Y":243.0}]},{"StartTime":100690.0,"Objects":[{"StartTime":100690.0,"EndTime":100690.0,"X":170.0,"Y":218.0}]},{"StartTime":100912.0,"Objects":[{"StartTime":100912.0,"EndTime":100912.0,"X":231.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101098.0,"EndTime":101098.0,"X":278.354858,"Y":193.081116,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101246.0,"Objects":[{"StartTime":101246.0,"EndTime":101246.0,"X":344.0,"Y":370.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101432.0,"EndTime":101432.0,"X":391.354858,"Y":232.918884,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101579.0,"Objects":[{"StartTime":101579.0,"EndTime":101579.0,"X":448.0,"Y":146.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101654.0,"EndTime":101654.0,"X":378.303619,"Y":128.719528,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101801.0,"Objects":[{"StartTime":101801.0,"EndTime":101801.0,"X":205.0,"Y":282.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101876.0,"EndTime":101876.0,"X":270.360626,"Y":249.990387,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102023.0,"Objects":[{"StartTime":102023.0,"EndTime":102023.0,"X":197.0,"Y":178.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102098.0,"EndTime":102098.0,"X":237.161285,"Y":117.944107,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102246.0,"Objects":[{"StartTime":102246.0,"EndTime":102246.0,"X":70.0,"Y":284.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102321.0,"EndTime":102321.0,"X":4.63935757,"Y":251.990387,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102468.0,"Objects":[{"StartTime":102468.0,"EndTime":102468.0,"X":78.0,"Y":180.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102543.0,"EndTime":102543.0,"X":37.8387,"Y":119.944115,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102690.0,"Objects":[{"StartTime":102690.0,"EndTime":102690.0,"X":178.0,"Y":15.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102876.0,"EndTime":102876.0,"X":104.018806,"Y":12.1474352,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103023.0,"Objects":[{"StartTime":103023.0,"EndTime":103023.0,"X":281.0,"Y":207.0}]},{"StartTime":103134.0,"Objects":[{"StartTime":103134.0,"EndTime":103134.0,"X":260.0,"Y":203.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103209.0,"EndTime":103209.0,"X":251.868073,"Y":136.364059,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103357.0,"Objects":[{"StartTime":103357.0,"EndTime":103357.0,"X":354.0,"Y":14.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103432.0,"EndTime":103432.0,"X":344.82843,"Y":80.1442642,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103579.0,"Objects":[{"StartTime":103579.0,"EndTime":103579.0,"X":178.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103765.0,"EndTime":103765.0,"X":157.606537,"Y":114.033684,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103912.0,"Objects":[{"StartTime":103912.0,"EndTime":103912.0,"X":379.0,"Y":203.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104098.0,"EndTime":104098.0,"X":259.0721,"Y":202.865311,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104246.0,"Objects":[{"StartTime":104246.0,"EndTime":104246.0,"X":168.0,"Y":324.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104321.0,"EndTime":104321.0,"X":177.0319,"Y":252.65538,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104468.0,"Objects":[{"StartTime":104468.0,"EndTime":104468.0,"X":304.0,"Y":76.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104654.0,"EndTime":104654.0,"X":258.715973,"Y":202.396683,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104801.0,"Objects":[{"StartTime":104801.0,"EndTime":104801.0,"X":464.0,"Y":172.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104987.0,"EndTime":104987.0,"X":360.003235,"Y":162.668,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105134.0,"Objects":[{"StartTime":105134.0,"EndTime":105134.0,"X":253.0,"Y":328.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105209.0,"EndTime":105209.0,"X":310.076935,"Y":287.604034,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105357.0,"Objects":[{"StartTime":105357.0,"EndTime":105357.0,"X":360.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105432.0,"EndTime":105432.0,"X":285.5137,"Y":170.763092,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105579.0,"Objects":[{"StartTime":105579.0,"EndTime":105579.0,"X":166.0,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105654.0,"EndTime":105654.0,"X":240.4863,"Y":76.23691,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105801.0,"Objects":[{"StartTime":105801.0,"EndTime":105801.0,"X":166.0,"Y":271.0}]},{"StartTime":105912.0,"Objects":[{"StartTime":105912.0,"EndTime":105912.0,"X":164.0,"Y":228.0}]},{"StartTime":106023.0,"Objects":[{"StartTime":106023.0,"EndTime":106023.0,"X":60.0,"Y":177.0}]},{"StartTime":106134.0,"Objects":[{"StartTime":106134.0,"EndTime":106134.0,"X":59.0,"Y":134.0}]},{"StartTime":106246.0,"Objects":[{"StartTime":106246.0,"EndTime":106246.0,"X":226.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106432.0,"EndTime":106432.0,"X":165.177826,"Y":84.50453,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106690.0,"Objects":[{"StartTime":106690.0,"EndTime":106690.0,"X":323.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106765.0,"EndTime":106765.0,"X":330.090057,"Y":124.520119,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106912.0,"Objects":[{"StartTime":106912.0,"EndTime":106912.0,"X":166.0,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107098.0,"EndTime":107098.0,"X":202.6605,"Y":243.165527,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107246.0,"Objects":[{"StartTime":107246.0,"EndTime":107246.0,"X":42.0,"Y":125.0}]},{"StartTime":107357.0,"Objects":[{"StartTime":107357.0,"EndTime":107357.0,"X":20.0,"Y":228.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107432.0,"EndTime":107432.0,"X":106.100655,"Y":201.795456,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107579.0,"Objects":[{"StartTime":107579.0,"EndTime":107579.0,"X":225.0,"Y":148.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107654.0,"EndTime":107654.0,"X":165.022446,"Y":84.57403,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107801.0,"Objects":[{"StartTime":107801.0,"EndTime":107801.0,"X":176.0,"Y":305.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107876.0,"EndTime":107876.0,"X":235.406113,"Y":241.261124,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108023.0,"Objects":[{"StartTime":108023.0,"EndTime":108023.0,"X":106.0,"Y":201.0}]},{"StartTime":108246.0,"Objects":[{"StartTime":108246.0,"EndTime":108246.0,"X":323.0,"Y":179.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108321.0,"EndTime":108321.0,"X":325.87088,"Y":89.0458,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108468.0,"Objects":[{"StartTime":108468.0,"EndTime":108468.0,"X":426.0,"Y":19.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108543.0,"EndTime":108543.0,"X":423.12912,"Y":108.9542,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108690.0,"Objects":[{"StartTime":108690.0,"EndTime":108690.0,"X":371.0,"Y":297.0}]},{"StartTime":108801.0,"Objects":[{"StartTime":108801.0,"EndTime":108801.0,"X":427.0,"Y":211.0}]},{"StartTime":108912.0,"Objects":[{"StartTime":108912.0,"EndTime":108912.0,"X":508.0,"Y":272.0}]},{"StartTime":109134.0,"Objects":[{"StartTime":109134.0,"EndTime":109134.0,"X":302.0,"Y":358.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109209.0,"EndTime":109209.0,"X":278.45575,"Y":279.0938,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109357.0,"Objects":[{"StartTime":109357.0,"EndTime":109357.0,"X":169.0,"Y":263.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109432.0,"EndTime":109432.0,"X":209.881577,"Y":190.538345,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109579.0,"Objects":[{"StartTime":109579.0,"EndTime":109579.0,"X":418.0,"Y":133.0}]},{"StartTime":109690.0,"Objects":[{"StartTime":109690.0,"EndTime":109690.0,"X":326.0,"Y":187.0}]},{"StartTime":109801.0,"Objects":[{"StartTime":109801.0,"EndTime":109801.0,"X":264.0,"Y":99.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109987.0,"EndTime":109987.0,"X":125.060516,"Y":76.14555,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110134.0,"Objects":[{"StartTime":110134.0,"EndTime":110134.0,"X":-4.00804234,"Y":238.991959}]},{"StartTime":110246.0,"Objects":[{"StartTime":110246.0,"EndTime":110246.0,"X":0.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110321.0,"EndTime":110321.0,"X":60.9713249,"Y":186.021042,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110468.0,"Objects":[{"StartTime":110468.0,"EndTime":110468.0,"X":203.0,"Y":40.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110654.0,"EndTime":110654.0,"X":168.509491,"Y":196.267059,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110801.0,"Objects":[{"StartTime":110801.0,"EndTime":110801.0,"X":141.991959,"Y":369.991943}]},{"StartTime":110912.0,"Objects":[{"StartTime":110912.0,"EndTime":110912.0,"X":146.0,"Y":374.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110987.0,"EndTime":110987.0,"X":105.254768,"Y":302.029266,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111134.0,"Objects":[{"StartTime":111134.0,"EndTime":111134.0,"X":271.0,"Y":133.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111320.0,"EndTime":111320.0,"X":230.608124,"Y":291.669281,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111468.0,"Objects":[{"StartTime":111468.0,"EndTime":111468.0,"X":398.0,"Y":293.0}]},{"StartTime":111579.0,"Objects":[{"StartTime":111579.0,"EndTime":111579.0,"X":402.0,"Y":194.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111654.0,"EndTime":111654.0,"X":319.0025,"Y":228.8054,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111801.0,"Objects":[{"StartTime":111801.0,"EndTime":111801.0,"X":153.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111876.0,"EndTime":111876.0,"X":164.993683,"Y":196.600021,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112023.0,"Objects":[{"StartTime":112023.0,"EndTime":112023.0,"X":436.0,"Y":63.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112209.0,"EndTime":112209.0,"X":270.123169,"Y":132.891922,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112357.0,"Objects":[{"StartTime":112357.0,"EndTime":112357.0,"X":296.991943,"Y":13.9919577}]},{"StartTime":112468.0,"Objects":[{"StartTime":112468.0,"EndTime":112468.0,"X":301.0,"Y":18.0}]},{"StartTime":112690.0,"Objects":[{"StartTime":112690.0,"EndTime":112690.0,"X":153.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112765.0,"EndTime":112765.0,"X":142.674759,"Y":35.2563171,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112912.0,"Objects":[{"StartTime":112912.0,"EndTime":112912.0,"X":335.0,"Y":186.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112987.0,"EndTime":112987.0,"X":270.000671,"Y":132.817719,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":113134.0,"Objects":[{"StartTime":113134.0,"EndTime":113134.0,"X":197.0,"Y":215.0}]},{"StartTime":113357.0,"Objects":[{"StartTime":113357.0,"EndTime":113357.0,"X":197.0,"Y":215.0}]},{"StartTime":113579.0,"Objects":[{"StartTime":113579.0,"EndTime":113579.0,"X":246.0,"Y":30.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":113654.0,"EndTime":113654.0,"X":322.939545,"Y":22.0649261,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":113801.0,"Objects":[{"StartTime":113801.0,"EndTime":113801.0,"X":487.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":113876.0,"EndTime":113876.0,"X":410.060455,"Y":120.064926,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114023.0,"Objects":[{"StartTime":114023.0,"EndTime":114023.0,"X":307.0,"Y":215.0}]},{"StartTime":114246.0,"Objects":[{"StartTime":114246.0,"EndTime":114246.0,"X":307.0,"Y":215.0}]},{"StartTime":114468.0,"Objects":[{"StartTime":114468.0,"EndTime":114468.0,"X":306.0,"Y":214.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114543.0,"EndTime":114543.0,"X":299.8086,"Y":294.7465,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114690.0,"Objects":[{"StartTime":114690.0,"EndTime":114690.0,"X":420.0,"Y":354.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114765.0,"EndTime":114765.0,"X":411.106842,"Y":271.121,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114912.0,"Objects":[{"StartTime":114912.0,"EndTime":114912.0,"X":232.0,"Y":153.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115098.0,"EndTime":115098.0,"X":200.770355,"Y":314.7974,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115357.0,"Objects":[{"StartTime":115357.0,"EndTime":115357.0,"X":232.0,"Y":153.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115432.0,"EndTime":115432.0,"X":262.242279,"Y":76.66023,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115579.0,"Objects":[{"StartTime":115579.0,"EndTime":115579.0,"X":134.0,"Y":49.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115654.0,"EndTime":115654.0,"X":113.259193,"Y":127.8234,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115801.0,"Objects":[{"StartTime":115801.0,"EndTime":115801.0,"X":379.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115987.0,"EndTime":115987.0,"X":231.178818,"Y":152.268,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":116246.0,"Objects":[{"StartTime":116246.0,"EndTime":116246.0,"X":291.0,"Y":331.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":116321.0,"EndTime":116321.0,"X":277.160767,"Y":273.2597,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":116468.0,"Objects":[{"StartTime":116468.0,"EndTime":116468.0,"X":98.0,"Y":122.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":116543.0,"EndTime":116543.0,"X":110.779022,"Y":204.751175,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":116690.0,"Objects":[{"StartTime":116690.0,"EndTime":116690.0,"X":303.0,"Y":183.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":116765.0,"EndTime":116765.0,"X":219.3649,"Y":196.415344,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":116912.0,"Objects":[{"StartTime":116912.0,"EndTime":116912.0,"X":120.0,"Y":366.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117209.0,"EndTime":117209.0,"X":24.3464966,"Y":257.467133,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":117357.0,"Objects":[{"StartTime":117357.0,"EndTime":117357.0,"X":24.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117432.0,"EndTime":117432.0,"X":99.04936,"Y":214.926025,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":117579.0,"Objects":[{"StartTime":117579.0,"EndTime":117579.0,"X":171.0,"Y":32.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117876.0,"EndTime":117876.0,"X":227.881714,"Y":272.095856,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118023.0,"Objects":[{"StartTime":118023.0,"EndTime":118023.0,"X":228.0,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118098.0,"EndTime":118098.0,"X":236.877625,"Y":190.670639,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118246.0,"Objects":[{"StartTime":118246.0,"EndTime":118246.0,"X":341.0,"Y":196.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118321.0,"EndTime":118321.0,"X":348.764679,"Y":278.39035,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118468.0,"Objects":[{"StartTime":118468.0,"EndTime":118468.0,"X":211.0,"Y":45.0}]},{"StartTime":118579.0,"Objects":[{"StartTime":118579.0,"EndTime":118579.0,"X":283.0,"Y":109.0}]},{"StartTime":118690.0,"Objects":[{"StartTime":118690.0,"EndTime":118690.0,"X":349.0,"Y":39.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118765.0,"EndTime":118765.0,"X":428.230774,"Y":20.6932182,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118912.0,"Objects":[{"StartTime":118912.0,"EndTime":118912.0,"X":512.0,"Y":138.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118987.0,"EndTime":118987.0,"X":432.769226,"Y":156.306778,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":119134.0,"Objects":[{"StartTime":119134.0,"EndTime":119134.0,"X":305.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119320.0,"EndTime":119320.0,"X":317.103851,"Y":213.768875,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":119468.0,"Objects":[{"StartTime":119468.0,"EndTime":119468.0,"X":145.0,"Y":89.0}]},{"StartTime":119579.0,"Objects":[{"StartTime":119579.0,"EndTime":119579.0,"X":236.0,"Y":33.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119654.0,"EndTime":119654.0,"X":247.9182,"Y":116.346733,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":119801.0,"Objects":[{"StartTime":119801.0,"EndTime":119801.0,"X":98.0,"Y":245.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119876.0,"EndTime":119876.0,"X":180.54184,"Y":225.650055,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":120023.0,"Objects":[{"StartTime":120023.0,"EndTime":120023.0,"X":357.0,"Y":302.0}]},{"StartTime":120134.0,"Objects":[{"StartTime":120134.0,"EndTime":120134.0,"X":317.0,"Y":213.0}]},{"StartTime":120246.0,"Objects":[{"StartTime":120246.0,"EndTime":120246.0,"X":379.0,"Y":134.0}]},{"StartTime":120357.0,"Objects":[{"StartTime":120357.0,"EndTime":120357.0,"X":475.0,"Y":159.0}]},{"StartTime":120468.0,"Objects":[{"StartTime":120468.0,"EndTime":120468.0,"X":412.0,"Y":227.0}]},{"StartTime":120690.0,"Objects":[{"StartTime":120690.0,"EndTime":120690.0,"X":507.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":120765.0,"EndTime":120765.0,"X":452.0761,"Y":60.7611046,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":120912.0,"Objects":[{"StartTime":120912.0,"EndTime":120912.0,"X":205.0,"Y":127.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":120987.0,"EndTime":120987.0,"X":203.958939,"Y":41.8644447,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":121134.0,"Objects":[{"StartTime":121134.0,"EndTime":121134.0,"X":317.0,"Y":15.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121320.0,"EndTime":121320.0,"X":319.1678,"Y":185.7771,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":121468.0,"Objects":[{"StartTime":121468.0,"EndTime":121468.0,"X":206.991959,"Y":248.991959}]},{"StartTime":121579.0,"Objects":[{"StartTime":121579.0,"EndTime":121579.0,"X":211.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121654.0,"EndTime":121654.0,"X":121.147781,"Y":247.844543,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":121801.0,"Objects":[{"StartTime":121801.0,"EndTime":121801.0,"X":117.0,"Y":78.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121876.0,"EndTime":121876.0,"X":206.852219,"Y":72.84454,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122023.0,"Objects":[{"StartTime":122023.0,"EndTime":122023.0,"X":319.0,"Y":185.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":122209.0,"EndTime":122209.0,"X":291.38446,"Y":345.232025,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122357.0,"Objects":[{"StartTime":122357.0,"EndTime":122357.0,"X":511.0,"Y":320.0}]},{"StartTime":122468.0,"Objects":[{"StartTime":122468.0,"EndTime":122468.0,"X":436.0,"Y":249.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":122543.0,"EndTime":122543.0,"X":382.6199,"Y":296.860382,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122690.0,"Objects":[{"StartTime":122690.0,"EndTime":122690.0,"X":312.0,"Y":102.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":122765.0,"EndTime":122765.0,"X":318.238678,"Y":185.758011,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122912.0,"Objects":[{"StartTime":122912.0,"EndTime":122912.0,"X":411.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":123098.0,"EndTime":123098.0,"X":261.447,"Y":321.2776,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":123246.0,"Objects":[{"StartTime":123246.0,"EndTime":123246.0,"X":115.991959,"Y":227.991959}]},{"StartTime":123357.0,"Objects":[{"StartTime":123357.0,"EndTime":123357.0,"X":120.0,"Y":232.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":123432.0,"EndTime":123432.0,"X":129.313568,"Y":276.144958,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":123579.0,"Objects":[{"StartTime":123579.0,"EndTime":123579.0,"X":185.0,"Y":60.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":123654.0,"EndTime":123654.0,"X":175.686432,"Y":104.144951,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":123801.0,"Objects":[{"StartTime":123801.0,"EndTime":123801.0,"X":0.0,"Y":305.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":123876.0,"EndTime":123876.0,"X":-0.89471674,"Y":221.483368,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124023.0,"Objects":[{"StartTime":124023.0,"EndTime":124023.0,"X":175.0,"Y":104.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":124209.0,"EndTime":124209.0,"X":16.7900982,"Y":103.414063,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124357.0,"Objects":[{"StartTime":124357.0,"EndTime":124357.0,"X":201.991959,"Y":278.991943}]},{"StartTime":124468.0,"Objects":[{"StartTime":124468.0,"EndTime":124468.0,"X":206.0,"Y":283.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":124543.0,"EndTime":124543.0,"X":172.017578,"Y":199.66217,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124690.0,"Objects":[{"StartTime":124690.0,"EndTime":124690.0,"X":288.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":124765.0,"EndTime":124765.0,"X":305.650452,"Y":104.747742,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124912.0,"Objects":[{"StartTime":124912.0,"EndTime":124912.0,"X":358.0,"Y":14.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125098.0,"EndTime":125098.0,"X":464.55777,"Y":99.8785,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125246.0,"Objects":[{"StartTime":125246.0,"EndTime":125246.0,"X":363.0,"Y":246.0}]},{"StartTime":125357.0,"Objects":[{"StartTime":125357.0,"EndTime":125357.0,"X":288.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125432.0,"EndTime":125432.0,"X":360.534882,"Y":151.889328,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125579.0,"Objects":[{"StartTime":125579.0,"EndTime":125579.0,"X":477.0,"Y":281.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125654.0,"EndTime":125654.0,"X":458.6441,"Y":369.108246,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125801.0,"Objects":[{"StartTime":125801.0,"EndTime":125801.0,"X":224.0,"Y":50.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125987.0,"EndTime":125987.0,"X":287.6426,"Y":192.975677,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":126134.0,"Objects":[{"StartTime":126134.0,"EndTime":126134.0,"X":216.0,"Y":266.0}]},{"StartTime":126246.0,"Objects":[{"StartTime":126246.0,"EndTime":126246.0,"X":261.0,"Y":353.0}]},{"StartTime":126468.0,"Objects":[{"StartTime":126468.0,"EndTime":126468.0,"X":158.0,"Y":188.0}]},{"StartTime":126579.0,"Objects":[{"StartTime":126579.0,"EndTime":126579.0,"X":105.0,"Y":268.0}]},{"StartTime":126690.0,"Objects":[{"StartTime":126690.0,"EndTime":126690.0,"X":147.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":126765.0,"EndTime":126765.0,"X":236.8718,"Y":359.8023,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":126912.0,"Objects":[{"StartTime":126912.0,"EndTime":126912.0,"X":305.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":126987.0,"EndTime":126987.0,"X":215.1282,"Y":265.1977,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":127134.0,"Objects":[{"StartTime":127134.0,"EndTime":127134.0,"X":71.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":127320.0,"EndTime":127320.0,"X":39.2628021,"Y":188.96315,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":127468.0,"Objects":[{"StartTime":127468.0,"EndTime":127468.0,"X":145.0,"Y":172.0}]},{"StartTime":127579.0,"Objects":[{"StartTime":127579.0,"EndTime":127579.0,"X":105.0,"Y":268.0}]},{"StartTime":127801.0,"Objects":[{"StartTime":127801.0,"EndTime":127801.0,"X":167.0,"Y":76.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":127876.0,"EndTime":127876.0,"X":228.04187,"Y":133.115982,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":128023.0,"Objects":[{"StartTime":128023.0,"EndTime":128023.0,"X":210.0,"Y":346.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":128098.0,"EndTime":128098.0,"X":214.49173,"Y":264.965332,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":128246.0,"Objects":[{"StartTime":128246.0,"EndTime":128246.0,"X":493.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":128432.0,"EndTime":128432.0,"X":316.4311,"Y":212.7431,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":128690.0,"Objects":[{"StartTime":128690.0,"EndTime":128690.0,"X":404.0,"Y":107.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":128765.0,"EndTime":128765.0,"X":470.7821,"Y":102.797379,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":128912.0,"Objects":[{"StartTime":128912.0,"EndTime":128912.0,"X":332.0,"Y":362.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":129098.0,"EndTime":129098.0,"X":315.634277,"Y":212.514771,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":129246.0,"Objects":[{"StartTime":129246.0,"EndTime":129246.0,"X":118.0,"Y":206.0}]},{"StartTime":129357.0,"Objects":[{"StartTime":129357.0,"EndTime":129357.0,"X":185.0,"Y":135.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":129432.0,"EndTime":129432.0,"X":210.139664,"Y":221.417572,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":129579.0,"Objects":[{"StartTime":129579.0,"EndTime":129579.0,"X":381.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":129654.0,"EndTime":129654.0,"X":298.13324,"Y":97.3488159,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":129801.0,"Objects":[{"StartTime":129801.0,"EndTime":129801.0,"X":130.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":129876.0,"EndTime":129876.0,"X":86.73138,"Y":121.130447,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130023.0,"Objects":[{"StartTime":130023.0,"EndTime":130023.0,"X":363.0,"Y":274.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130098.0,"EndTime":130098.0,"X":317.3323,"Y":210.8698,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":130246.0,"Objects":[{"StartTime":130246.0,"EndTime":130246.0,"X":121.0,"Y":364.0}]},{"StartTime":130468.0,"Objects":[{"StartTime":130468.0,"EndTime":130468.0,"X":199.0,"Y":178.0}]},{"StartTime":130690.0,"Objects":[{"StartTime":130690.0,"EndTime":130690.0,"X":71.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":130987.0,"EndTime":130987.0,"X":237.43425,"Y":296.5649,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":131134.0,"Objects":[{"StartTime":131134.0,"EndTime":131134.0,"X":350.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":131209.0,"EndTime":131209.0,"X":351.217255,"Y":306.720581,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":131357.0,"Objects":[{"StartTime":131357.0,"EndTime":131357.0,"X":512.0,"Y":189.0}]},{"StartTime":131468.0,"Objects":[{"StartTime":131468.0,"EndTime":131468.0,"X":418.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":131543.0,"EndTime":131543.0,"X":418.495758,"Y":222.902069,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":131690.0,"Objects":[{"StartTime":131690.0,"EndTime":131690.0,"X":258.0,"Y":98.0}]},{"StartTime":131801.0,"Objects":[{"StartTime":131801.0,"EndTime":131801.0,"X":322.0,"Y":184.0}]},{"StartTime":131912.0,"Objects":[{"StartTime":131912.0,"EndTime":131912.0,"X":259.0,"Y":270.0}]},{"StartTime":132023.0,"Objects":[{"StartTime":132023.0,"EndTime":132023.0,"X":197.0,"Y":184.0}]},{"StartTime":132468.0,"Objects":[{"StartTime":132468.0,"EndTime":132468.0,"X":400.0,"Y":134.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":132543.0,"EndTime":132543.0,"X":405.635132,"Y":210.747955,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":132690.0,"Objects":[{"StartTime":132690.0,"EndTime":132690.0,"X":110.0,"Y":214.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":132765.0,"EndTime":132765.0,"X":104.364876,"Y":137.252045,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":132912.0,"Objects":[{"StartTime":132912.0,"EndTime":132912.0,"X":259.0,"Y":270.0}]},{"StartTime":133134.0,"Objects":[{"StartTime":133134.0,"EndTime":133134.0,"X":191.991959,"Y":48.99196}]},{"StartTime":133246.0,"Objects":[{"StartTime":133246.0,"EndTime":133246.0,"X":196.0,"Y":53.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":133321.0,"EndTime":133321.0,"X":197.738525,"Y":129.95166,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":133468.0,"Objects":[{"StartTime":133468.0,"EndTime":133468.0,"X":313.991943,"Y":46.99196}]},{"StartTime":133580.0,"Objects":[{"StartTime":133580.0,"EndTime":133580.0,"X":318.0,"Y":51.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":133655.0,"EndTime":133655.0,"X":316.261475,"Y":127.95166,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":133801.0,"Objects":[{"StartTime":133801.0,"EndTime":133801.0,"X":259.0,"Y":270.0}]},{"StartTime":134246.0,"Objects":[{"StartTime":134246.0,"EndTime":134246.0,"X":259.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":134321.0,"EndTime":134321.0,"X":255.945129,"Y":347.246368,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":134468.0,"Objects":[{"StartTime":134468.0,"EndTime":134468.0,"X":45.0,"Y":203.0}]},{"StartTime":134579.0,"Objects":[{"StartTime":134579.0,"EndTime":134579.0,"X":78.0,"Y":202.0}]},{"StartTime":134690.0,"Objects":[{"StartTime":134690.0,"EndTime":134690.0,"X":166.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":134765.0,"EndTime":134765.0,"X":169.054871,"Y":173.753632,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":134912.0,"Objects":[{"StartTime":134912.0,"EndTime":134912.0,"X":85.0,"Y":27.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":134987.0,"EndTime":134987.0,"X":88.07755,"Y":104.19873,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":135134.0,"Objects":[{"StartTime":135134.0,"EndTime":135134.0,"X":0.0,"Y":226.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":135209.0,"EndTime":135209.0,"X":77.76112,"Y":202.808533,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":135357.0,"Objects":[{"StartTime":135357.0,"EndTime":135357.0,"X":266.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":135432.0,"EndTime":135432.0,"X":188.238876,"Y":68.80853,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":135579.0,"Objects":[{"StartTime":135579.0,"EndTime":135579.0,"X":130.0,"Y":373.0}]},{"StartTime":135690.0,"Objects":[{"StartTime":135690.0,"EndTime":135690.0,"X":108.0,"Y":310.0}]},{"StartTime":135801.0,"Objects":[{"StartTime":135801.0,"EndTime":135801.0,"X":159.0,"Y":262.0}]},{"StartTime":135912.0,"Objects":[{"StartTime":135912.0,"EndTime":135912.0,"X":250.0,"Y":304.0}]},{"StartTime":136023.0,"Objects":[{"StartTime":136023.0,"EndTime":136023.0,"X":341.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":136098.0,"EndTime":136098.0,"X":339.675476,"Y":173.298676,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":136246.0,"Objects":[{"StartTime":136246.0,"EndTime":136246.0,"X":442.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":136321.0,"EndTime":136321.0,"X":391.297943,"Y":58.8912926,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":136468.0,"Objects":[{"StartTime":136468.0,"EndTime":136468.0,"X":250.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":136543.0,"EndTime":136543.0,"X":255.012466,"Y":103.347588,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":136690.0,"Objects":[{"StartTime":136690.0,"EndTime":136690.0,"X":107.0,"Y":212.0}]},{"StartTime":136801.0,"Objects":[{"StartTime":136801.0,"EndTime":136801.0,"X":23.0,"Y":181.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":136987.0,"EndTime":136987.0,"X":154.333725,"Y":133.844666,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":137134.0,"Objects":[{"StartTime":137134.0,"EndTime":137134.0,"X":229.0,"Y":189.0}]},{"StartTime":137246.0,"Objects":[{"StartTime":137246.0,"EndTime":137246.0,"X":224.0,"Y":287.0}]},{"StartTime":137357.0,"Objects":[{"StartTime":137357.0,"EndTime":137357.0,"X":220.0,"Y":384.0}]},{"StartTime":137579.0,"Objects":[{"StartTime":137579.0,"EndTime":137579.0,"X":220.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":137654.0,"EndTime":137654.0,"X":286.980377,"Y":346.6252,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":137801.0,"Objects":[{"StartTime":137801.0,"EndTime":137801.0,"X":505.0,"Y":241.0}]},{"StartTime":137912.0,"Objects":[{"StartTime":137912.0,"EndTime":137912.0,"X":442.0,"Y":269.0}]},{"StartTime":138023.0,"Objects":[{"StartTime":138023.0,"EndTime":138023.0,"X":382.0,"Y":242.0}]},{"StartTime":138134.0,"Objects":[{"StartTime":138134.0,"EndTime":138134.0,"X":307.0,"Y":183.0}]},{"StartTime":138246.0,"Objects":[{"StartTime":138246.0,"EndTime":138246.0,"X":222.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":138432.0,"EndTime":138432.0,"X":71.38295,"Y":275.653046,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":138579.0,"Objects":[{"StartTime":138579.0,"EndTime":138579.0,"X":71.0,"Y":171.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":138765.0,"EndTime":138765.0,"X":221.926514,"Y":223.005737,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":138912.0,"Objects":[{"StartTime":138912.0,"EndTime":138912.0,"X":343.0,"Y":94.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":138987.0,"EndTime":138987.0,"X":260.5,"Y":94.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":139134.0,"Objects":[{"StartTime":139134.0,"EndTime":139134.0,"X":134.0,"Y":26.0}]},{"StartTime":139357.0,"Objects":[{"StartTime":139357.0,"EndTime":139357.0,"X":134.0,"Y":26.0}]},{"StartTime":139468.0,"Objects":[{"StartTime":139468.0,"EndTime":139468.0,"X":104.0,"Y":77.0}]},{"StartTime":139579.0,"Objects":[{"StartTime":139579.0,"EndTime":139579.0,"X":129.0,"Y":129.0}]},{"StartTime":139690.0,"Objects":[{"StartTime":139690.0,"EndTime":139690.0,"X":188.0,"Y":207.0}]},{"StartTime":139801.0,"Objects":[{"StartTime":139801.0,"EndTime":139801.0,"X":114.0,"Y":291.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":139876.0,"EndTime":139876.0,"X":99.4008255,"Y":215.296585,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":140023.0,"Objects":[{"StartTime":140023.0,"EndTime":140023.0,"X":216.0,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":140098.0,"EndTime":140098.0,"X":298.5,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":140246.0,"Objects":[{"StartTime":140246.0,"EndTime":140246.0,"X":432.0,"Y":90.0}]},{"StartTime":140357.0,"Objects":[{"StartTime":140357.0,"EndTime":140357.0,"X":347.0,"Y":152.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":140543.0,"EndTime":140543.0,"X":357.324921,"Y":10.7098618,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":140690.0,"Objects":[{"StartTime":140690.0,"EndTime":140690.0,"X":512.0,"Y":253.0}]},{"StartTime":140801.0,"Objects":[{"StartTime":140801.0,"EndTime":140801.0,"X":441.0,"Y":179.0}]},{"StartTime":140912.0,"Objects":[{"StartTime":140912.0,"EndTime":140912.0,"X":376.0,"Y":255.0}]},{"StartTime":141357.0,"Objects":[{"StartTime":141357.0,"EndTime":141357.0,"X":376.0,"Y":255.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":141432.0,"EndTime":141432.0,"X":382.0538,"Y":332.489,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":141579.0,"Objects":[{"StartTime":141579.0,"EndTime":141579.0,"X":245.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":141654.0,"EndTime":141654.0,"X":250.6925,"Y":141.435944,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":141801.0,"Objects":[{"StartTime":141801.0,"EndTime":141801.0,"X":179.0,"Y":302.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":141876.0,"EndTime":141876.0,"X":141.112991,"Y":232.186615,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":142023.0,"Objects":[{"StartTime":142023.0,"EndTime":142023.0,"X":368.0,"Y":164.0}]},{"StartTime":142134.0,"Objects":[{"StartTime":142134.0,"EndTime":142134.0,"X":342.0,"Y":166.0}]},{"StartTime":142246.0,"Objects":[{"StartTime":142246.0,"EndTime":142246.0,"X":177.0,"Y":98.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":142321.0,"EndTime":142321.0,"X":259.205322,"Y":91.03345,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":142468.0,"Objects":[{"StartTime":142468.0,"EndTime":142468.0,"X":341.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":142543.0,"EndTime":142543.0,"X":361.5398,"Y":72.01209,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":142690.0,"Objects":[{"StartTime":142690.0,"EndTime":142690.0,"X":245.0,"Y":219.0}]},{"StartTime":142912.0,"Objects":[{"StartTime":142912.0,"EndTime":142912.0,"X":456.991943,"Y":107.991959}]},{"StartTime":143023.0,"Objects":[{"StartTime":143023.0,"EndTime":143023.0,"X":461.0,"Y":112.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":143098.0,"EndTime":143098.0,"X":455.83255,"Y":188.940552,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":143246.0,"Objects":[{"StartTime":143246.0,"EndTime":143246.0,"X":368.0,"Y":371.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":143321.0,"EndTime":143321.0,"X":361.7833,"Y":293.69873,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":143468.0,"Objects":[{"StartTime":143468.0,"EndTime":143468.0,"X":192.0,"Y":166.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":143654.0,"EndTime":143654.0,"X":331.016968,"Y":191.846024,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":143801.0,"Objects":[{"StartTime":143801.0,"EndTime":143801.0,"X":315.0,"Y":32.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":143876.0,"EndTime":143876.0,"X":274.3848,"Y":93.43054,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":144023.0,"Objects":[{"StartTime":144023.0,"EndTime":144023.0,"X":268.0,"Y":351.0}]},{"StartTime":144134.0,"Objects":[{"StartTime":144134.0,"EndTime":144134.0,"X":282.0,"Y":287.0}]},{"StartTime":144246.0,"Objects":[{"StartTime":144246.0,"EndTime":144246.0,"X":230.0,"Y":251.0}]},{"StartTime":144357.0,"Objects":[{"StartTime":144357.0,"EndTime":144357.0,"X":138.0,"Y":305.0}]},{"StartTime":144468.0,"Objects":[{"StartTime":144468.0,"EndTime":144468.0,"X":59.0,"Y":249.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":144543.0,"EndTime":144543.0,"X":56.647377,"Y":173.0617,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":144690.0,"Objects":[{"StartTime":144690.0,"EndTime":144690.0,"X":144.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":144765.0,"EndTime":144765.0,"X":146.352631,"Y":203.9383,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":144912.0,"Objects":[{"StartTime":144912.0,"EndTime":144912.0,"X":18.0,"Y":81.0}]},{"StartTime":145023.0,"Objects":[{"StartTime":145023.0,"EndTime":145023.0,"X":69.0,"Y":1.0}]},{"StartTime":145134.0,"Objects":[{"StartTime":145134.0,"EndTime":145134.0,"X":172.0,"Y":11.0}]},{"StartTime":145246.0,"Objects":[{"StartTime":145246.0,"EndTime":145246.0,"X":231.0,"Y":98.0}]},{"StartTime":145357.0,"Objects":[{"StartTime":145357.0,"EndTime":145357.0,"X":303.0,"Y":28.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":145432.0,"EndTime":145432.0,"X":374.9048,"Y":-0.0191259384,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":145579.0,"Objects":[{"StartTime":145579.0,"EndTime":145579.0,"X":384.0,"Y":220.0}]},{"StartTime":145690.0,"Objects":[{"StartTime":145690.0,"EndTime":145690.0,"X":285.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":145765.0,"EndTime":145765.0,"X":336.018738,"Y":135.212479,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":145912.0,"Objects":[{"StartTime":145912.0,"EndTime":145912.0,"X":507.0,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":145987.0,"EndTime":145987.0,"X":442.2237,"Y":76.94097,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":146134.0,"Objects":[{"StartTime":146134.0,"EndTime":146134.0,"X":504.991943,"Y":238.991959}]},{"StartTime":146246.0,"Objects":[{"StartTime":146246.0,"EndTime":146246.0,"X":509.0,"Y":243.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":146321.0,"EndTime":146321.0,"X":447.662445,"Y":200.745743,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":146468.0,"Objects":[{"StartTime":146468.0,"EndTime":146468.0,"X":270.0,"Y":374.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":146543.0,"EndTime":146543.0,"X":286.513733,"Y":293.169647,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":146690.0,"Objects":[{"StartTime":146690.0,"EndTime":146690.0,"X":168.0,"Y":143.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":146765.0,"EndTime":146765.0,"X":184.513733,"Y":223.830353,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":146912.0,"Objects":[{"StartTime":146912.0,"EndTime":146912.0,"X":401.0,"Y":283.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":146987.0,"EndTime":146987.0,"X":365.557617,"Y":213.172012,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":147134.0,"Objects":[{"StartTime":147134.0,"EndTime":147134.0,"X":50.0,"Y":214.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":147320.0,"EndTime":147320.0,"X":183.730637,"Y":223.72197,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":147468.0,"Objects":[{"StartTime":147468.0,"EndTime":147468.0,"X":306.0,"Y":64.0}]},{"StartTime":147579.0,"Objects":[{"StartTime":147579.0,"EndTime":147579.0,"X":204.0,"Y":48.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":147690.0,"EndTime":147690.0,"X":220.76535,"Y":128.778534,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":147765.0,"EndTime":147765.0,"X":204.0,"Y":48.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":147912.0,"Objects":[{"StartTime":147912.0,"EndTime":147912.0,"X":360.0,"Y":154.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148098.0,"EndTime":148098.0,"X":345.995636,"Y":303.007568,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":148246.0,"Objects":[{"StartTime":148246.0,"EndTime":148246.0,"X":208.0,"Y":368.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148321.0,"EndTime":148321.0,"X":230.968475,"Y":316.226654,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":148468.0,"Objects":[{"StartTime":148468.0,"EndTime":148468.0,"X":106.0,"Y":264.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148543.0,"EndTime":148543.0,"X":169.758072,"Y":216.935791,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":148690.0,"Objects":[{"StartTime":148690.0,"EndTime":148690.0,"X":399.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148765.0,"EndTime":148765.0,"X":323.475,"Y":223.086472,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":148912.0,"Objects":[{"StartTime":148912.0,"EndTime":148912.0,"X":126.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":148987.0,"EndTime":148987.0,"X":203.621765,"Y":125.594574,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149134.0,"Objects":[{"StartTime":149134.0,"EndTime":149134.0,"X":249.0,"Y":36.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":149209.0,"EndTime":149209.0,"X":300.844055,"Y":95.0325,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149357.0,"Objects":[{"StartTime":149357.0,"EndTime":149357.0,"X":388.0,"Y":280.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":149432.0,"EndTime":149432.0,"X":460.192932,"Y":248.763474,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149579.0,"Objects":[{"StartTime":149579.0,"EndTime":149579.0,"X":390.0,"Y":178.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":149654.0,"EndTime":149654.0,"X":411.7897,"Y":103.093239,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":149801.0,"Objects":[{"StartTime":149801.0,"EndTime":149801.0,"X":272.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":149876.0,"EndTime":149876.0,"X":278.945923,"Y":361.0271,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":150023.0,"Objects":[{"StartTime":150023.0,"EndTime":150023.0,"X":161.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":150098.0,"EndTime":150098.0,"X":166.382416,"Y":195.049881,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":150246.0,"Objects":[{"StartTime":150246.0,"EndTime":150246.0,"X":390.0,"Y":178.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":150321.0,"EndTime":150321.0,"X":307.832764,"Y":185.402451,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":150468.0,"Objects":[{"StartTime":150468.0,"EndTime":150468.0,"X":55.0,"Y":95.0}]},{"StartTime":150579.0,"Objects":[{"StartTime":150579.0,"EndTime":150579.0,"X":20.0,"Y":98.0}]},{"StartTime":150690.0,"Objects":[{"StartTime":150690.0,"EndTime":150690.0,"X":119.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":150876.0,"EndTime":150876.0,"X":229.438019,"Y":88.46765,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":151023.0,"Objects":[{"StartTime":151023.0,"EndTime":151023.0,"X":68.0,"Y":214.0}]},{"StartTime":151134.0,"Objects":[{"StartTime":151134.0,"EndTime":151134.0,"X":170.0,"Y":229.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":151209.0,"EndTime":151209.0,"X":147.563553,"Y":149.609467,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":151357.0,"Objects":[{"StartTime":151357.0,"EndTime":151357.0,"X":263.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":151432.0,"EndTime":151432.0,"X":239.9385,"Y":365.211243,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":151579.0,"Objects":[{"StartTime":151579.0,"EndTime":151579.0,"X":94.0,"Y":322.0}]},{"StartTime":151801.0,"Objects":[{"StartTime":151801.0,"EndTime":151801.0,"X":394.0,"Y":216.0}]},{"StartTime":152023.0,"Objects":[{"StartTime":152023.0,"EndTime":152023.0,"X":370.0,"Y":57.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":152320.0,"EndTime":152320.0,"X":253.870209,"Y":172.60585,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":152468.0,"Objects":[{"StartTime":152468.0,"EndTime":152468.0,"X":317.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":152654.0,"EndTime":152654.0,"X":158.693573,"Y":141.477356,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":152912.0,"Objects":[{"StartTime":152912.0,"EndTime":152912.0,"X":8.0,"Y":52.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":152987.0,"EndTime":152987.0,"X":41.25625,"Y":44.6429024,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":153134.0,"Objects":[{"StartTime":153134.0,"EndTime":153134.0,"X":317.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":153320.0,"EndTime":153320.0,"X":158.693573,"Y":141.477356,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":153579.0,"Objects":[{"StartTime":153579.0,"EndTime":153579.0,"X":71.0,"Y":190.0}]},{"StartTime":153690.0,"Objects":[{"StartTime":153690.0,"EndTime":153690.0,"X":38.0,"Y":191.0}]},{"StartTime":153801.0,"Objects":[{"StartTime":153801.0,"EndTime":153801.0,"X":158.0,"Y":141.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":153876.0,"EndTime":153876.0,"X":168.284653,"Y":218.124176,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":154023.0,"Objects":[{"StartTime":154023.0,"EndTime":154023.0,"X":93.0,"Y":372.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":154098.0,"EndTime":154098.0,"X":82.7153549,"Y":294.875824,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":154246.0,"Objects":[{"StartTime":154246.0,"EndTime":154246.0,"X":255.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":154432.0,"EndTime":154432.0,"X":284.45993,"Y":213.542831,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":154690.0,"Objects":[{"StartTime":154690.0,"EndTime":154690.0,"X":202.0,"Y":347.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":154765.0,"EndTime":154765.0,"X":212.29007,"Y":315.725861,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":154912.0,"Objects":[{"StartTime":154912.0,"EndTime":154912.0,"X":255.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":155098.0,"EndTime":155098.0,"X":284.45993,"Y":213.542831,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":155357.0,"Objects":[{"StartTime":155357.0,"EndTime":155357.0,"X":488.0,"Y":313.0}]},{"StartTime":155468.0,"Objects":[{"StartTime":155468.0,"EndTime":155468.0,"X":454.0,"Y":314.0}]},{"StartTime":155579.0,"Objects":[{"StartTime":155579.0,"EndTime":155579.0,"X":367.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":155654.0,"EndTime":155654.0,"X":364.4232,"Y":278.617371,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":155801.0,"Objects":[{"StartTime":155801.0,"EndTime":155801.0,"X":503.0,"Y":146.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":155876.0,"EndTime":155876.0,"X":445.314484,"Y":195.759918,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":156023.0,"Objects":[{"StartTime":156023.0,"EndTime":156023.0,"X":220.0,"Y":123.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":156209.0,"EndTime":156209.0,"X":289.916,"Y":201.523849,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":156357.0,"Objects":[{"StartTime":156357.0,"EndTime":156357.0,"X":111.0,"Y":158.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":156543.0,"EndTime":156543.0,"X":142.369736,"Y":56.6978226,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":156690.0,"Objects":[{"StartTime":156690.0,"EndTime":156690.0,"X":186.0,"Y":229.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":156765.0,"EndTime":156765.0,"X":135.32048,"Y":252.494751,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":156912.0,"Objects":[{"StartTime":156912.0,"EndTime":156912.0,"X":220.0,"Y":123.0}]},{"StartTime":157060.0,"Objects":[{"StartTime":157060.0,"EndTime":157060.0,"X":186.0,"Y":229.0}]},{"StartTime":157209.0,"Objects":[{"StartTime":157209.0,"EndTime":157209.0,"X":111.0,"Y":158.0}]},{"StartTime":157357.0,"Objects":[{"StartTime":157357.0,"EndTime":157357.0,"X":288.0,"Y":199.0}]},{"StartTime":157505.0,"Objects":[{"StartTime":157505.0,"EndTime":157505.0,"X":94.0,"Y":258.0}]},{"StartTime":157653.0,"Objects":[{"StartTime":157653.0,"EndTime":157653.0,"X":144.0,"Y":56.0}]},{"StartTime":157801.0,"Objects":[{"StartTime":157801.0,"EndTime":157801.0,"X":150.0,"Y":383.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":157987.0,"EndTime":157987.0,"X":236.781082,"Y":319.1922,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":158246.0,"Objects":[{"StartTime":158246.0,"EndTime":158246.0,"X":359.0,"Y":145.0}]},{"StartTime":158468.0,"Objects":[{"StartTime":158468.0,"EndTime":158468.0,"X":270.0,"Y":182.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":158654.0,"EndTime":158654.0,"X":369.479736,"Y":249.689819,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":158912.0,"Objects":[{"StartTime":158912.0,"EndTime":158912.0,"X":359.0,"Y":145.0}]},{"StartTime":159134.0,"Objects":[{"StartTime":159134.0,"EndTime":159134.0,"X":236.0,"Y":319.0}]},{"StartTime":159357.0,"Objects":[{"StartTime":159357.0,"EndTime":159357.0,"X":460.0,"Y":160.0}]},{"StartTime":159579.0,"Objects":[{"StartTime":159579.0,"EndTime":159579.0,"X":233.0,"Y":22.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":159912.0,"EndTime":159912.0,"X":268.943939,"Y":181.561172,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":160209.0,"EndTime":160209.0,"X":233.0,"Y":22.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":160468.0,"Objects":[{"StartTime":160468.0,"EndTime":160468.0,"X":454.0,"Y":29.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":160654.0,"EndTime":160654.0,"X":345.565582,"Y":31.0499535,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":160912.0,"Objects":[{"StartTime":160912.0,"EndTime":160912.0,"X":173.0,"Y":216.0}]},{"StartTime":161134.0,"Objects":[{"StartTime":161134.0,"EndTime":161134.0,"X":424.983917,"Y":195.983917}]},{"StartTime":161246.0,"Objects":[{"StartTime":161246.0,"EndTime":161246.0,"X":428.991943,"Y":199.991959}]},{"StartTime":161357.0,"Objects":[{"StartTime":161357.0,"EndTime":161357.0,"X":433.0,"Y":204.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":161765.0,"EndTime":161765.0,"X":269.099426,"Y":180.445,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":162023.0,"Objects":[{"StartTime":162023.0,"EndTime":162023.0,"X":268.0,"Y":79.0}]},{"StartTime":162246.0,"Objects":[{"StartTime":162246.0,"EndTime":162246.0,"X":344.0,"Y":362.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":162432.0,"EndTime":162432.0,"X":293.673523,"Y":285.970734,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":162690.0,"Objects":[{"StartTime":162690.0,"EndTime":162690.0,"X":159.0,"Y":224.0}]},{"StartTime":162912.0,"Objects":[{"StartTime":162912.0,"EndTime":162912.0,"X":316.0,"Y":154.0}]},{"StartTime":163134.0,"Objects":[{"StartTime":163134.0,"EndTime":163134.0,"X":213.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":163467.0,"EndTime":163467.0,"X":205.7877,"Y":92.723114,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":163764.0,"EndTime":163764.0,"X":213.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":164023.0,"Objects":[{"StartTime":164023.0,"EndTime":164023.0,"X":337.0,"Y":271.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":164209.0,"EndTime":164209.0,"X":298.85553,"Y":168.804764,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":164468.0,"Objects":[{"StartTime":164468.0,"EndTime":164468.0,"X":99.0,"Y":334.0}]},{"StartTime":164579.0,"Objects":[{"StartTime":164579.0,"EndTime":164579.0,"X":133.0,"Y":332.0}]},{"StartTime":164690.0,"Objects":[{"StartTime":164690.0,"EndTime":164690.0,"X":166.0,"Y":329.0}]},{"StartTime":164801.0,"Objects":[{"StartTime":164801.0,"EndTime":164801.0,"X":200.0,"Y":326.0}]},{"StartTime":164912.0,"Objects":[{"StartTime":164912.0,"EndTime":164912.0,"X":234.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":165098.0,"EndTime":165098.0,"X":130.22879,"Y":254.891266,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":165357.0,"Objects":[{"StartTime":165357.0,"EndTime":165357.0,"X":67.0,"Y":174.0}]},{"StartTime":165579.0,"Objects":[{"StartTime":165579.0,"EndTime":165579.0,"X":234.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":165765.0,"EndTime":165765.0,"X":227.521072,"Y":127.2661,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166023.0,"Objects":[{"StartTime":166023.0,"EndTime":166023.0,"X":391.0,"Y":159.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":166098.0,"EndTime":166098.0,"X":323.841736,"Y":165.783661,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166246.0,"Objects":[{"StartTime":166246.0,"EndTime":166246.0,"X":253.0,"Y":28.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":166321.0,"EndTime":166321.0,"X":305.653931,"Y":61.37197,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166468.0,"Objects":[{"StartTime":166468.0,"EndTime":166468.0,"X":209.0,"Y":188.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":166543.0,"EndTime":166543.0,"X":226.751892,"Y":127.185547,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":166690.0,"Objects":[{"StartTime":166690.0,"EndTime":166690.0,"X":444.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":167023.0,"EndTime":167023.0,"X":283.719574,"Y":276.808929,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":167320.0,"EndTime":167320.0,"X":444.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":167579.0,"Objects":[{"StartTime":167579.0,"EndTime":167579.0,"X":216.0,"Y":360.0}]},{"StartTime":167801.0,"Objects":[{"StartTime":167801.0,"EndTime":167801.0,"X":177.0,"Y":264.0}]},{"StartTime":168023.0,"Objects":[{"StartTime":168023.0,"EndTime":168023.0,"X":312.0,"Y":162.0}]},{"StartTime":168134.0,"Objects":[{"StartTime":168134.0,"EndTime":168134.0,"X":266.0,"Y":190.0}]},{"StartTime":168245.0,"Objects":[{"StartTime":168245.0,"EndTime":168245.0,"X":218.0,"Y":166.0}]},{"StartTime":168356.0,"Objects":[{"StartTime":168356.0,"EndTime":168356.0,"X":213.0,"Y":112.0}]},{"StartTime":168468.0,"Objects":[{"StartTime":168468.0,"EndTime":168468.0,"X":287.0,"Y":65.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":168876.0,"EndTime":168876.0,"X":167.100861,"Y":18.7974186,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":169134.0,"Objects":[{"StartTime":169134.0,"EndTime":169134.0,"X":0.0,"Y":205.0}]},{"StartTime":169357.0,"Objects":[{"StartTime":169357.0,"EndTime":169357.0,"X":54.0,"Y":125.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":169543.0,"EndTime":169543.0,"X":88.6647,"Y":218.9704,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":169801.0,"Objects":[{"StartTime":169801.0,"EndTime":169801.0,"X":254.0,"Y":281.0}]},{"StartTime":170023.0,"Objects":[{"StartTime":170023.0,"EndTime":170023.0,"X":192.0,"Y":190.0}]},{"StartTime":170246.0,"Objects":[{"StartTime":170246.0,"EndTime":170246.0,"X":0.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":170579.0,"EndTime":170579.0,"X":149.732025,"Y":293.5072,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":170876.0,"EndTime":170876.0,"X":0.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":171134.0,"Objects":[{"StartTime":171134.0,"EndTime":171134.0,"X":0.0,"Y":355.0}]},{"StartTime":171357.0,"Objects":[{"StartTime":171357.0,"EndTime":171357.0,"X":219.0,"Y":363.0}]},{"StartTime":171579.0,"Objects":[{"StartTime":171579.0,"EndTime":171579.0,"X":120.0,"Y":195.0}]},{"StartTime":171690.0,"Objects":[{"StartTime":171690.0,"EndTime":171690.0,"X":153.0,"Y":196.0}]},{"StartTime":171801.0,"Objects":[{"StartTime":171801.0,"EndTime":171801.0,"X":187.0,"Y":198.0}]},{"StartTime":171912.0,"Objects":[{"StartTime":171912.0,"EndTime":171912.0,"X":221.0,"Y":200.0}]},{"StartTime":172023.0,"Objects":[{"StartTime":172023.0,"EndTime":172023.0,"X":297.0,"Y":155.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":172209.0,"EndTime":172209.0,"X":286.743378,"Y":280.805,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":172357.0,"Objects":[{"StartTime":172357.0,"EndTime":172357.0,"X":450.991943,"Y":233.991959}]},{"StartTime":172468.0,"Objects":[{"StartTime":172468.0,"EndTime":172468.0,"X":455.0,"Y":238.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":172543.0,"EndTime":172543.0,"X":388.201447,"Y":228.29422,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":172690.0,"Objects":[{"StartTime":172690.0,"EndTime":172690.0,"X":307.0,"Y":52.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":172876.0,"EndTime":172876.0,"X":399.912659,"Y":120.163414,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":173134.0,"Objects":[{"StartTime":173134.0,"EndTime":173134.0,"X":182.0,"Y":98.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":173209.0,"EndTime":173209.0,"X":170.090744,"Y":31.5588989,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":173357.0,"Objects":[{"StartTime":173357.0,"EndTime":173357.0,"X":281.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":173432.0,"EndTime":173432.0,"X":268.925232,"Y":228.411224,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":173579.0,"Objects":[{"StartTime":173579.0,"EndTime":173579.0,"X":36.9839172,"Y":287.983917}]},{"StartTime":173690.0,"Objects":[{"StartTime":173690.0,"EndTime":173690.0,"X":40.99196,"Y":291.991943}]},{"StartTime":173801.0,"Objects":[{"StartTime":173801.0,"EndTime":173801.0,"X":45.0,"Y":296.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":173987.0,"EndTime":173987.0,"X":129.058121,"Y":220.794525,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":174134.0,"Objects":[{"StartTime":174134.0,"EndTime":174134.0,"X":217.991959,"Y":361.991943}]},{"StartTime":174246.0,"Objects":[{"StartTime":174246.0,"EndTime":174246.0,"X":222.0,"Y":366.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":174321.0,"EndTime":174321.0,"X":198.07811,"Y":307.061584,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":174468.0,"Objects":[{"StartTime":174468.0,"EndTime":174468.0,"X":287.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":174543.0,"EndTime":174543.0,"X":326.644043,"Y":204.022247,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":174690.0,"Objects":[{"StartTime":174690.0,"EndTime":174690.0,"X":506.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":174876.0,"EndTime":174876.0,"X":386.5124,"Y":106.955444,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":175023.0,"Objects":[{"StartTime":175023.0,"EndTime":175023.0,"X":224.991959,"Y":67.99196}]},{"StartTime":175134.0,"Objects":[{"StartTime":175134.0,"EndTime":175134.0,"X":229.0,"Y":72.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":175209.0,"EndTime":175209.0,"X":243.306,"Y":137.966568,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":175357.0,"Objects":[{"StartTime":175357.0,"EndTime":175357.0,"X":312.0,"Y":269.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":175432.0,"EndTime":175432.0,"X":326.306,"Y":203.033432,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":175579.0,"Objects":[{"StartTime":175579.0,"EndTime":175579.0,"X":146.0,"Y":16.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":175765.0,"EndTime":175765.0,"X":139.074585,"Y":137.318375,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":175912.0,"Objects":[{"StartTime":175912.0,"EndTime":175912.0,"X":243.991959,"Y":224.991959}]},{"StartTime":176023.0,"Objects":[{"StartTime":176023.0,"EndTime":176023.0,"X":248.0,"Y":229.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":176098.0,"EndTime":176098.0,"X":180.809891,"Y":222.539413,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":176246.0,"Objects":[{"StartTime":176246.0,"EndTime":176246.0,"X":36.0,"Y":384.0}]},{"StartTime":176357.0,"Objects":[{"StartTime":176357.0,"EndTime":176357.0,"X":20.0,"Y":335.0}]},{"StartTime":176468.0,"Objects":[{"StartTime":176468.0,"EndTime":176468.0,"X":64.0,"Y":300.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":176654.0,"EndTime":176654.0,"X":190.327454,"Y":337.0614,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":176801.0,"Objects":[{"StartTime":176801.0,"EndTime":176801.0,"X":293.991943,"Y":379.991943}]},{"StartTime":176912.0,"Objects":[{"StartTime":176912.0,"EndTime":176912.0,"X":298.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":176987.0,"EndTime":176987.0,"X":300.6823,"Y":322.70462,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":177134.0,"Objects":[{"StartTime":177134.0,"EndTime":177134.0,"X":423.0,"Y":236.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":177209.0,"EndTime":177209.0,"X":419.9614,"Y":297.0566,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":177357.0,"Objects":[{"StartTime":177357.0,"EndTime":177357.0,"X":217.0,"Y":241.0}]},{"StartTime":177579.0,"Objects":[{"StartTime":177579.0,"EndTime":177579.0,"X":300.0,"Y":31.0}]},{"StartTime":177690.0,"Objects":[{"StartTime":177690.0,"EndTime":177690.0,"X":343.0,"Y":86.0}]},{"StartTime":177801.0,"Objects":[{"StartTime":177801.0,"EndTime":177801.0,"X":314.0,"Y":148.0}]},{"StartTime":178023.0,"Objects":[{"StartTime":178023.0,"EndTime":178023.0,"X":74.98392,"Y":70.98392}]},{"StartTime":178134.0,"Objects":[{"StartTime":178134.0,"EndTime":178134.0,"X":78.99196,"Y":74.99196}]},{"StartTime":178246.0,"Objects":[{"StartTime":178246.0,"EndTime":178246.0,"X":83.0,"Y":79.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":178432.0,"EndTime":178432.0,"X":205.811111,"Y":97.7642059,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":178579.0,"Objects":[{"StartTime":178579.0,"EndTime":178579.0,"X":332.991943,"Y":15.9919577}]},{"StartTime":178690.0,"Objects":[{"StartTime":178690.0,"EndTime":178690.0,"X":337.0,"Y":20.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":178765.0,"EndTime":178765.0,"X":318.676453,"Y":84.9653549,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":178912.0,"Objects":[{"StartTime":178912.0,"EndTime":178912.0,"X":214.0,"Y":239.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":178987.0,"EndTime":178987.0,"X":258.598236,"Y":196.108292,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":179134.0,"Objects":[{"StartTime":179134.0,"EndTime":179134.0,"X":435.0,"Y":127.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":179320.0,"EndTime":179320.0,"X":410.495239,"Y":246.099274,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":179468.0,"Objects":[{"StartTime":179468.0,"EndTime":179468.0,"X":470.991943,"Y":351.991943}]},{"StartTime":179579.0,"Objects":[{"StartTime":179579.0,"EndTime":179579.0,"X":475.0,"Y":356.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":179654.0,"EndTime":179654.0,"X":506.7647,"Y":296.441162,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":179801.0,"Objects":[{"StartTime":179801.0,"EndTime":179801.0,"X":278.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":179876.0,"EndTime":179876.0,"X":299.962067,"Y":231.827255,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":180023.0,"Objects":[{"StartTime":180023.0,"EndTime":180023.0,"X":351.0,"Y":348.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":180209.0,"EndTime":180209.0,"X":220.201462,"Y":363.836945,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":180357.0,"Objects":[{"StartTime":180357.0,"EndTime":180357.0,"X":99.99196,"Y":348.991943}]},{"StartTime":180468.0,"Objects":[{"StartTime":180468.0,"EndTime":180468.0,"X":104.0,"Y":353.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":180543.0,"EndTime":180543.0,"X":141.955933,"Y":297.182465,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":180690.0,"Objects":[{"StartTime":180690.0,"EndTime":180690.0,"X":0.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":180765.0,"EndTime":180765.0,"X":47.40831,"Y":267.04895,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":180912.0,"Objects":[{"StartTime":180912.0,"EndTime":180912.0,"X":245.0,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":180987.0,"EndTime":180987.0,"X":223.346817,"Y":212.329941,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":181134.0,"Objects":[{"StartTime":181134.0,"EndTime":181134.0,"X":352.0,"Y":194.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":181209.0,"EndTime":181209.0,"X":323.133057,"Y":136.271255,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":181357.0,"Objects":[{"StartTime":181357.0,"EndTime":181357.0,"X":37.0,"Y":82.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":181432.0,"EndTime":181432.0,"X":72.12841,"Y":135.108,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":181579.0,"Objects":[{"StartTime":181579.0,"EndTime":181579.0,"X":188.0,"Y":19.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":181654.0,"EndTime":181654.0,"X":167.375656,"Y":81.45676,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":181801.0,"Objects":[{"StartTime":181801.0,"EndTime":181801.0,"X":342.0,"Y":220.0}]},{"StartTime":182023.0,"Objects":[{"StartTime":182023.0,"EndTime":182023.0,"X":268.0,"Y":81.0}]},{"StartTime":182246.0,"Objects":[{"StartTime":182246.0,"EndTime":182246.0,"X":158.0,"Y":195.0}]},{"StartTime":182690.0,"Objects":[{"StartTime":182690.0,"EndTime":182690.0,"X":309.0,"Y":231.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":182765.0,"EndTime":182765.0,"X":287.637878,"Y":291.5341,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":182912.0,"Objects":[{"StartTime":182912.0,"EndTime":182912.0,"X":388.0,"Y":302.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":182987.0,"EndTime":182987.0,"X":396.8215,"Y":376.820435,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":183134.0,"Objects":[{"StartTime":183134.0,"EndTime":183134.0,"X":490.0,"Y":52.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":183209.0,"EndTime":183209.0,"X":511.362122,"Y":112.534065,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":183357.0,"Objects":[{"StartTime":183357.0,"EndTime":183357.0,"X":414.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":183432.0,"EndTime":183432.0,"X":403.953461,"Y":195.117416,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":183579.0,"Objects":[{"StartTime":183579.0,"EndTime":183579.0,"X":269.0,"Y":0.0}]},{"StartTime":183690.0,"Objects":[{"StartTime":183690.0,"EndTime":183690.0,"X":320.0,"Y":15.0}]},{"StartTime":183801.0,"Objects":[{"StartTime":183801.0,"EndTime":183801.0,"X":340.0,"Y":64.0}]},{"StartTime":183912.0,"Objects":[{"StartTime":183912.0,"EndTime":183912.0,"X":311.0,"Y":124.0}]},{"StartTime":184023.0,"Objects":[{"StartTime":184023.0,"EndTime":184023.0,"X":225.0,"Y":160.0}]},{"StartTime":184134.0,"Objects":[{"StartTime":184134.0,"EndTime":184134.0,"X":160.0,"Y":95.0}]},{"StartTime":184246.0,"Objects":[{"StartTime":184246.0,"EndTime":184246.0,"X":79.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":184543.0,"EndTime":184543.0,"X":133.33046,"Y":376.409332,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":184690.0,"Objects":[{"StartTime":184690.0,"EndTime":184690.0,"X":137.008041,"Y":380.008057}]},{"StartTime":184912.0,"Objects":[{"StartTime":184912.0,"EndTime":184912.0,"X":169.0,"Y":151.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":185098.0,"EndTime":185098.0,"X":25.66817,"Y":349.460663,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":185357.0,"Objects":[{"StartTime":185357.0,"EndTime":185357.0,"X":26.0,"Y":350.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":185801.0,"EndTime":185801.0,"X":67.54302,"Y":333.1509,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":186098.0,"EndTime":186098.0,"X":100.962524,"Y":328.956482,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":186246.0,"Objects":[{"StartTime":186246.0,"EndTime":186246.0,"X":205.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":186432.0,"EndTime":186432.0,"X":283.367523,"Y":261.024628,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":186579.0,"Objects":[{"StartTime":186579.0,"EndTime":186579.0,"X":410.0,"Y":99.0}]},{"StartTime":186690.0,"Objects":[{"StartTime":186690.0,"EndTime":186690.0,"X":471.0,"Y":176.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":186765.0,"EndTime":186765.0,"X":380.588684,"Y":194.399445,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":186912.0,"Objects":[{"StartTime":186912.0,"EndTime":186912.0,"X":242.0,"Y":64.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":186987.0,"EndTime":186987.0,"X":288.7081,"Y":142.4731,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":187134.0,"Objects":[{"StartTime":187134.0,"EndTime":187134.0,"X":283.0,"Y":261.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":187320.0,"EndTime":187320.0,"X":104.302727,"Y":321.47583,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":187468.0,"Objects":[{"StartTime":187468.0,"EndTime":187468.0,"X":107.991959,"Y":212.991959}]},{"StartTime":187579.0,"Objects":[{"StartTime":187579.0,"EndTime":187579.0,"X":112.0,"Y":217.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":187654.0,"EndTime":187654.0,"X":88.1223145,"Y":144.955582,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":187801.0,"Objects":[{"StartTime":187801.0,"EndTime":187801.0,"X":0.0,"Y":293.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":187876.0,"EndTime":187876.0,"X":34.3335266,"Y":384.254883,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":188023.0,"Objects":[{"StartTime":188023.0,"EndTime":188023.0,"X":220.0,"Y":151.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":188209.0,"EndTime":188209.0,"X":89.1849747,"Y":38.11739,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":188357.0,"Objects":[{"StartTime":188357.0,"EndTime":188357.0,"X":193.991959,"Y":281.991943}]},{"StartTime":188468.0,"Objects":[{"StartTime":188468.0,"EndTime":188468.0,"X":198.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":188543.0,"EndTime":188543.0,"X":115.5115,"Y":246.779144,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":188690.0,"Objects":[{"StartTime":188690.0,"EndTime":188690.0,"X":328.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":188765.0,"EndTime":188765.0,"X":323.656677,"Y":293.825745,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":188912.0,"Objects":[{"StartTime":188912.0,"EndTime":188912.0,"X":506.0,"Y":165.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":189098.0,"EndTime":189098.0,"X":325.711121,"Y":174.086273,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":189246.0,"Objects":[{"StartTime":189246.0,"EndTime":189246.0,"X":136.0,"Y":81.0}]},{"StartTime":189357.0,"Objects":[{"StartTime":189357.0,"EndTime":189357.0,"X":219.0,"Y":40.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":189432.0,"EndTime":189432.0,"X":264.425018,"Y":22.49165,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":189579.0,"Objects":[{"StartTime":189579.0,"EndTime":189579.0,"X":333.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":189654.0,"EndTime":189654.0,"X":287.444427,"Y":234.581711,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":189801.0,"Objects":[{"StartTime":189801.0,"EndTime":189801.0,"X":78.0,"Y":253.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":189987.0,"EndTime":189987.0,"X":215.659058,"Y":383.269257,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":190134.0,"Objects":[{"StartTime":190134.0,"EndTime":190134.0,"X":240.991959,"Y":156.991959}]},{"StartTime":190246.0,"Objects":[{"StartTime":190246.0,"EndTime":190246.0,"X":245.0,"Y":161.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":190321.0,"EndTime":190321.0,"X":177.97789,"Y":216.226547,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":190468.0,"Objects":[{"StartTime":190468.0,"EndTime":190468.0,"X":11.0,"Y":128.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":190543.0,"EndTime":190543.0,"X":97.85994,"Y":143.0787,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":190690.0,"Objects":[{"StartTime":190690.0,"EndTime":190690.0,"X":55.0,"Y":345.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":190876.0,"EndTime":190876.0,"X":245.305511,"Y":318.198578,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":191023.0,"Objects":[{"StartTime":191023.0,"EndTime":191023.0,"X":400.991943,"Y":189.991959}]},{"StartTime":191134.0,"Objects":[{"StartTime":191134.0,"EndTime":191134.0,"X":405.0,"Y":194.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":191209.0,"EndTime":191209.0,"X":361.7055,"Y":274.186035,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":191357.0,"Objects":[{"StartTime":191357.0,"EndTime":191357.0,"X":498.0,"Y":363.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":191432.0,"EndTime":191432.0,"X":480.31192,"Y":278.6314,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":191579.0,"Objects":[{"StartTime":191579.0,"EndTime":191579.0,"X":468.0,"Y":72.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":191765.0,"EndTime":191765.0,"X":306.435425,"Y":130.6289,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":191912.0,"Objects":[{"StartTime":191912.0,"EndTime":191912.0,"X":101.0,"Y":81.0}]},{"StartTime":192023.0,"Objects":[{"StartTime":192023.0,"EndTime":192023.0,"X":182.0,"Y":24.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":192098.0,"EndTime":192098.0,"X":199.58197,"Y":119.901642,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":192246.0,"Objects":[{"StartTime":192246.0,"EndTime":192246.0,"X":302.0,"Y":384.0}]},{"StartTime":192357.0,"Objects":[{"StartTime":192357.0,"EndTime":192357.0,"X":355.0,"Y":305.0}]},{"StartTime":192468.0,"Objects":[{"StartTime":192468.0,"EndTime":192468.0,"X":281.0,"Y":239.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":192543.0,"EndTime":192543.0,"X":194.7636,"Y":248.249023,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":192690.0,"Objects":[{"StartTime":192690.0,"EndTime":192690.0,"X":18.0,"Y":347.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":192765.0,"EndTime":192765.0,"X":71.3199844,"Y":326.631134,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":192912.0,"Objects":[{"StartTime":192912.0,"EndTime":192912.0,"X":89.0,"Y":106.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":192987.0,"EndTime":192987.0,"X":71.78304,"Y":160.039886,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":193134.0,"Objects":[{"StartTime":193134.0,"EndTime":193134.0,"X":252.0,"Y":287.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":193209.0,"EndTime":193209.0,"X":212.6236,"Y":244.7909,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":193357.0,"Objects":[{"StartTime":193357.0,"EndTime":193357.0,"X":111.0,"Y":244.0}]},{"StartTime":193579.0,"Objects":[{"StartTime":193579.0,"EndTime":193579.0,"X":215.0,"Y":37.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":193654.0,"EndTime":193654.0,"X":200.609528,"Y":126.211754,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":193801.0,"Objects":[{"StartTime":193801.0,"EndTime":193801.0,"X":371.0,"Y":126.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":193876.0,"EndTime":193876.0,"X":356.564331,"Y":36.5752678,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":194023.0,"Objects":[{"StartTime":194023.0,"EndTime":194023.0,"X":282.0,"Y":276.0}]},{"StartTime":194246.0,"Objects":[{"StartTime":194246.0,"EndTime":194246.0,"X":282.0,"Y":276.0}]},{"StartTime":194468.0,"Objects":[{"StartTime":194468.0,"EndTime":194468.0,"X":239.0,"Y":195.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":194543.0,"EndTime":194543.0,"X":328.394379,"Y":191.421982,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":194690.0,"Objects":[{"StartTime":194690.0,"EndTime":194690.0,"X":508.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":194765.0,"EndTime":194765.0,"X":418.383057,"Y":244.1962,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":194912.0,"Objects":[{"StartTime":194912.0,"EndTime":194912.0,"X":334.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":195098.0,"EndTime":195098.0,"X":463.9035,"Y":157.835983,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":195357.0,"Objects":[{"StartTime":195357.0,"EndTime":195357.0,"X":316.0,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":195432.0,"EndTime":195432.0,"X":327.604462,"Y":190.84021,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":195579.0,"Objects":[{"StartTime":195579.0,"EndTime":195579.0,"X":253.0,"Y":92.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":195654.0,"EndTime":195654.0,"X":333.9576,"Y":55.0459251,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":195801.0,"Objects":[{"StartTime":195801.0,"EndTime":195801.0,"X":418.0,"Y":244.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":195987.0,"EndTime":195987.0,"X":232.039337,"Y":278.23053,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":196246.0,"Objects":[{"StartTime":196246.0,"EndTime":196246.0,"X":96.0,"Y":93.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":196321.0,"EndTime":196321.0,"X":158.051941,"Y":152.6015,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":196468.0,"Objects":[{"StartTime":196468.0,"EndTime":196468.0,"X":36.0,"Y":291.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":196543.0,"EndTime":196543.0,"X":43.7772751,"Y":205.244049,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":196690.0,"Objects":[{"StartTime":196690.0,"EndTime":196690.0,"X":316.0,"Y":108.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":196765.0,"EndTime":196765.0,"X":258.890442,"Y":187.023712,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":196912.0,"Objects":[{"StartTime":196912.0,"EndTime":196912.0,"X":158.0,"Y":342.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":197209.0,"EndTime":197209.0,"X":381.5317,"Y":332.94693,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":197357.0,"Objects":[{"StartTime":197357.0,"EndTime":197357.0,"X":381.0,"Y":332.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":197432.0,"EndTime":197432.0,"X":388.862427,"Y":243.495224,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":197579.0,"Objects":[{"StartTime":197579.0,"EndTime":197579.0,"X":512.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":197876.0,"EndTime":197876.0,"X":285.27533,"Y":102.821617,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":198023.0,"Objects":[{"StartTime":198023.0,"EndTime":198023.0,"X":285.0,"Y":102.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":198098.0,"EndTime":198098.0,"X":308.620453,"Y":188.817657,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":198246.0,"Objects":[{"StartTime":198246.0,"EndTime":198246.0,"X":139.0,"Y":368.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":198321.0,"EndTime":198321.0,"X":161.313477,"Y":281.518036,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":198468.0,"Objects":[{"StartTime":198468.0,"EndTime":198468.0,"X":202.0,"Y":186.0}]},{"StartTime":198579.0,"Objects":[{"StartTime":198579.0,"EndTime":198579.0,"X":116.0,"Y":180.0}]},{"StartTime":198690.0,"Objects":[{"StartTime":198690.0,"EndTime":198690.0,"X":60.0,"Y":113.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":198765.0,"EndTime":198765.0,"X":143.467941,"Y":93.9362,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":198912.0,"Objects":[{"StartTime":198912.0,"EndTime":198912.0,"X":259.0,"Y":291.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":198987.0,"EndTime":198987.0,"X":162.120941,"Y":280.0137,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":199134.0,"Objects":[{"StartTime":199134.0,"EndTime":199134.0,"X":187.0,"Y":7.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":199320.0,"EndTime":199320.0,"X":229.512268,"Y":159.866241,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":199468.0,"Objects":[{"StartTime":199468.0,"EndTime":199468.0,"X":72.0,"Y":342.0}]},{"StartTime":199579.0,"Objects":[{"StartTime":199579.0,"EndTime":199579.0,"X":0.0,"Y":282.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":199654.0,"EndTime":199654.0,"X":78.95528,"Y":246.232529,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":199801.0,"Objects":[{"StartTime":199801.0,"EndTime":199801.0,"X":173.0,"Y":337.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":199876.0,"EndTime":199876.0,"X":257.654663,"Y":349.431061,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":200023.0,"Objects":[{"StartTime":200023.0,"EndTime":200023.0,"X":494.0,"Y":181.0}]},{"StartTime":200134.0,"Objects":[{"StartTime":200134.0,"EndTime":200134.0,"X":402.0,"Y":122.0}]},{"StartTime":200246.0,"Objects":[{"StartTime":200246.0,"EndTime":200246.0,"X":323.0,"Y":194.0}]},{"StartTime":200357.0,"Objects":[{"StartTime":200357.0,"EndTime":200357.0,"X":371.0,"Y":288.0}]},{"StartTime":200468.0,"Objects":[{"StartTime":200468.0,"EndTime":200468.0,"X":414.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":200654.0,"EndTime":200654.0,"X":236.752914,"Y":258.171417,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":200801.0,"Objects":[{"StartTime":200801.0,"EndTime":200801.0,"X":127.991959,"Y":157.991959}]},{"StartTime":200912.0,"Objects":[{"StartTime":200912.0,"EndTime":200912.0,"X":132.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":200987.0,"EndTime":200987.0,"X":184.15062,"Y":152.335556,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201134.0,"Objects":[{"StartTime":201134.0,"EndTime":201134.0,"X":236.0,"Y":258.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201209.0,"EndTime":201209.0,"X":220.839447,"Y":354.314117,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201357.0,"Objects":[{"StartTime":201357.0,"EndTime":201357.0,"X":58.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201543.0,"EndTime":201543.0,"X":35.1479073,"Y":86.65965,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":201690.0,"Objects":[{"StartTime":201690.0,"EndTime":201690.0,"X":190.0,"Y":71.0}]},{"StartTime":201801.0,"Objects":[{"StartTime":201801.0,"EndTime":201801.0,"X":229.0,"Y":171.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":201876.0,"EndTime":201876.0,"X":131.975967,"Y":161.377777,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202023.0,"Objects":[{"StartTime":202023.0,"EndTime":202023.0,"X":63.0,"Y":335.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202098.0,"EndTime":202098.0,"X":134.2772,"Y":290.463074,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202246.0,"Objects":[{"StartTime":202246.0,"EndTime":202246.0,"X":408.0,"Y":277.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202432.0,"EndTime":202432.0,"X":244.544388,"Y":290.6308,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202579.0,"Objects":[{"StartTime":202579.0,"EndTime":202579.0,"X":208.991959,"Y":80.99196}]},{"StartTime":202690.0,"Objects":[{"StartTime":202690.0,"EndTime":202690.0,"X":213.0,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":202765.0,"EndTime":202765.0,"X":228.79689,"Y":170.052963,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":202912.0,"Objects":[{"StartTime":202912.0,"EndTime":202912.0,"X":49.0,"Y":312.0}]},{"StartTime":203023.0,"Objects":[{"StartTime":203023.0,"EndTime":203023.0,"X":24.0,"Y":224.0}]},{"StartTime":203134.0,"Objects":[{"StartTime":203134.0,"EndTime":203134.0,"X":122.0,"Y":233.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":203320.0,"EndTime":203320.0,"X":191.638641,"Y":368.68396,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":203468.0,"Objects":[{"StartTime":203468.0,"EndTime":203468.0,"X":141.991959,"Y":66.99196}]},{"StartTime":203579.0,"Objects":[{"StartTime":203579.0,"EndTime":203579.0,"X":146.0,"Y":71.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":203654.0,"EndTime":203654.0,"X":199.075058,"Y":144.244308,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":203801.0,"Objects":[{"StartTime":203801.0,"EndTime":203801.0,"X":307.0,"Y":98.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":203876.0,"EndTime":203876.0,"X":306.357178,"Y":192.275589,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":204023.0,"Objects":[{"StartTime":204023.0,"EndTime":204023.0,"X":148.0,"Y":315.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":204209.0,"EndTime":204209.0,"X":338.9172,"Y":312.6326,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":204357.0,"Objects":[{"StartTime":204357.0,"EndTime":204357.0,"X":476.991943,"Y":265.991943}]},{"StartTime":204468.0,"Objects":[{"StartTime":204468.0,"EndTime":204468.0,"X":481.0,"Y":270.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":204543.0,"EndTime":204543.0,"X":484.560455,"Y":339.2592,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":204690.0,"Objects":[{"StartTime":204690.0,"EndTime":204690.0,"X":374.0,"Y":187.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":204765.0,"EndTime":204765.0,"X":439.03717,"Y":114.361069,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":204912.0,"Objects":[{"StartTime":204912.0,"EndTime":204912.0,"X":246.0,"Y":22.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":205098.0,"EndTime":205098.0,"X":242.783752,"Y":185.724686,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":205246.0,"Objects":[{"StartTime":205246.0,"EndTime":205246.0,"X":284.0,"Y":353.0}]},{"StartTime":205357.0,"Objects":[{"StartTime":205357.0,"EndTime":205357.0,"X":377.0,"Y":329.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":205432.0,"EndTime":205432.0,"X":310.678467,"Y":265.608063,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":205579.0,"Objects":[{"StartTime":205579.0,"EndTime":205579.0,"X":140.0,"Y":351.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":205654.0,"EndTime":205654.0,"X":198.56424,"Y":287.309631,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":205801.0,"Objects":[{"StartTime":205801.0,"EndTime":205801.0,"X":71.0,"Y":229.0}]},{"StartTime":206023.0,"Objects":[{"StartTime":206023.0,"EndTime":206023.0,"X":284.0,"Y":353.0}]},{"StartTime":206134.0,"Objects":[{"StartTime":206134.0,"EndTime":206134.0,"X":310.0,"Y":265.0}]},{"StartTime":206246.0,"Objects":[{"StartTime":206246.0,"EndTime":206246.0,"X":270.0,"Y":189.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":206321.0,"EndTime":206321.0,"X":172.514236,"Y":190.666428,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":206468.0,"Objects":[{"StartTime":206468.0,"EndTime":206468.0,"X":0.0,"Y":130.0}]},{"StartTime":206579.0,"Objects":[{"StartTime":206579.0,"EndTime":206579.0,"X":21.0,"Y":49.0}]},{"StartTime":206690.0,"Objects":[{"StartTime":206690.0,"EndTime":206690.0,"X":108.0,"Y":42.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":206876.0,"EndTime":206876.0,"X":171.950943,"Y":190.486923,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":207023.0,"Objects":[{"StartTime":207023.0,"EndTime":207023.0,"X":15.9919577,"Y":318.991943}]},{"StartTime":207134.0,"Objects":[{"StartTime":207134.0,"EndTime":207134.0,"X":20.0,"Y":323.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":207209.0,"EndTime":207209.0,"X":102.738419,"Y":285.6162,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":207357.0,"Objects":[{"StartTime":207357.0,"EndTime":207357.0,"X":251.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":207432.0,"EndTime":207432.0,"X":234.77272,"Y":297.868958,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":207579.0,"Objects":[{"StartTime":207579.0,"EndTime":207579.0,"X":480.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":207765.0,"EndTime":207765.0,"X":303.419739,"Y":213.402771,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":207912.0,"Objects":[{"StartTime":207912.0,"EndTime":207912.0,"X":125.991959,"Y":118.991959}]},{"StartTime":208023.0,"Objects":[{"StartTime":208023.0,"EndTime":208023.0,"X":130.0,"Y":123.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":208098.0,"EndTime":208098.0,"X":171.601212,"Y":189.693237,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":208246.0,"Objects":[{"StartTime":208246.0,"EndTime":208246.0,"X":368.0,"Y":138.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":208321.0,"EndTime":208321.0,"X":280.454285,"Y":113.3478,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":208468.0,"Objects":[{"StartTime":208468.0,"EndTime":208468.0,"X":133.0,"Y":360.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":208654.0,"EndTime":208654.0,"X":287.511,"Y":308.130524,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":208801.0,"Objects":[{"StartTime":208801.0,"EndTime":208801.0,"X":437.991943,"Y":301.991943}]},{"StartTime":208912.0,"Objects":[{"StartTime":208912.0,"EndTime":208912.0,"X":442.0,"Y":306.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":208987.0,"EndTime":208987.0,"X":387.819427,"Y":378.516083,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":209134.0,"Objects":[{"StartTime":209134.0,"EndTime":209134.0,"X":512.0,"Y":182.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":209209.0,"EndTime":209209.0,"X":419.7707,"Y":188.271652,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":209357.0,"Objects":[{"StartTime":209357.0,"EndTime":209357.0,"X":275.0,"Y":16.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":209543.0,"EndTime":209543.0,"X":298.5103,"Y":195.631866,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":209690.0,"Objects":[{"StartTime":209690.0,"EndTime":209690.0,"X":136.991959,"Y":190.991959}]},{"StartTime":209801.0,"Objects":[{"StartTime":209801.0,"EndTime":209801.0,"X":141.0,"Y":195.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":209876.0,"EndTime":209876.0,"X":191.738983,"Y":133.100525,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":210023.0,"Objects":[{"StartTime":210023.0,"EndTime":210023.0,"X":55.0,"Y":267.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":210098.0,"EndTime":210098.0,"X":29.103653,"Y":182.072876,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":210246.0,"Objects":[{"StartTime":210246.0,"EndTime":210246.0,"X":223.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":210321.0,"EndTime":210321.0,"X":213.5535,"Y":357.041321,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":210468.0,"Objects":[{"StartTime":210468.0,"EndTime":210468.0,"X":327.0,"Y":210.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":210543.0,"EndTime":210543.0,"X":317.5535,"Y":307.041321,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":210690.0,"Objects":[{"StartTime":210690.0,"EndTime":210690.0,"X":104.0,"Y":111.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":210765.0,"EndTime":210765.0,"X":140.630753,"Y":194.91655,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":210912.0,"Objects":[{"StartTime":210912.0,"EndTime":210912.0,"X":253.0,"Y":11.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":210987.0,"EndTime":210987.0,"X":235.838547,"Y":96.9594955,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":211134.0,"Objects":[{"StartTime":211134.0,"EndTime":211134.0,"X":29.0,"Y":278.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":211320.0,"EndTime":211320.0,"X":222.616745,"Y":259.101837,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":211468.0,"Objects":[{"StartTime":211468.0,"EndTime":211468.0,"X":394.991943,"Y":183.991959}]},{"StartTime":211579.0,"Objects":[{"StartTime":211579.0,"EndTime":211579.0,"X":399.0,"Y":188.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":211654.0,"EndTime":211654.0,"X":303.68924,"Y":168.970551,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":211801.0,"Objects":[{"StartTime":211801.0,"EndTime":211801.0,"X":316.0,"Y":367.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":211876.0,"EndTime":211876.0,"X":329.0899,"Y":271.836945,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":212023.0,"Objects":[{"StartTime":212023.0,"EndTime":212023.0,"X":191.0,"Y":159.0}]},{"StartTime":212246.0,"Objects":[{"StartTime":212246.0,"EndTime":212246.0,"X":379.991943,"Y":78.99196}]},{"StartTime":212357.0,"Objects":[{"StartTime":212357.0,"EndTime":212357.0,"X":384.0,"Y":83.0}]},{"StartTime":212579.0,"Objects":[{"StartTime":212579.0,"EndTime":212579.0,"X":251.991959,"Y":-4.00804234}]},{"StartTime":212690.0,"Objects":[{"StartTime":212690.0,"EndTime":212690.0,"X":256.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":212765.0,"EndTime":212765.0,"X":274.741,"Y":95.5859146,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":212912.0,"Objects":[{"StartTime":212912.0,"EndTime":212912.0,"X":370.0,"Y":188.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":213098.0,"EndTime":213098.0,"X":336.668121,"Y":378.5493,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":213246.0,"Objects":[{"StartTime":213246.0,"EndTime":213246.0,"X":106.991959,"Y":164.991959}]},{"StartTime":213357.0,"Objects":[{"StartTime":213357.0,"EndTime":213357.0,"X":111.0,"Y":169.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":213432.0,"EndTime":213432.0,"X":139.0973,"Y":261.838654,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":213579.0,"Objects":[{"StartTime":213579.0,"EndTime":213579.0,"X":254.0,"Y":288.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":213654.0,"EndTime":213654.0,"X":224.939835,"Y":380.4556,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":213801.0,"Objects":[{"StartTime":213801.0,"EndTime":213801.0,"X":36.0,"Y":223.0}]},{"StartTime":213912.0,"Objects":[{"StartTime":213912.0,"EndTime":213912.0,"X":2.0,"Y":171.0}]},{"StartTime":214023.0,"Objects":[{"StartTime":214023.0,"EndTime":214023.0,"X":19.0,"Y":113.0}]},{"StartTime":214134.0,"Objects":[{"StartTime":214134.0,"EndTime":214134.0,"X":92.0,"Y":47.0}]},{"StartTime":214246.0,"Objects":[{"StartTime":214246.0,"EndTime":214246.0,"X":189.0,"Y":76.0}]},{"StartTime":214357.0,"Objects":[{"StartTime":214357.0,"EndTime":214357.0,"X":205.0,"Y":179.0}]},{"StartTime":214468.0,"Objects":[{"StartTime":214468.0,"EndTime":214468.0,"X":305.0,"Y":229.0}]},{"StartTime":214579.0,"Objects":[{"StartTime":214579.0,"EndTime":214579.0,"X":395.0,"Y":167.0}]},{"StartTime":214690.0,"Objects":[{"StartTime":214690.0,"EndTime":214690.0,"X":306.0,"Y":121.0}]},{"StartTime":215134.0,"Objects":[{"StartTime":215134.0,"EndTime":215134.0,"X":306.0,"Y":149.0}]},{"StartTime":215579.0,"Objects":[{"StartTime":215579.0,"EndTime":215579.0,"X":302.0,"Y":179.0}]},{"StartTime":216023.0,"Objects":[{"StartTime":216023.0,"EndTime":216023.0,"X":299.0,"Y":214.0}]},{"StartTime":216468.0,"Objects":[{"StartTime":216468.0,"EndTime":216468.0,"X":295.0,"Y":261.0}]},{"StartTime":216690.0,"Objects":[{"StartTime":216690.0,"EndTime":216690.0,"X":206.0,"Y":318.0}]},{"StartTime":216912.0,"Objects":[{"StartTime":216912.0,"EndTime":216912.0,"X":128.0,"Y":248.0}]},{"StartTime":217134.0,"Objects":[{"StartTime":217134.0,"EndTime":217134.0,"X":177.0,"Y":139.0}]},{"StartTime":217357.0,"Objects":[{"StartTime":217357.0,"EndTime":217357.0,"X":289.0,"Y":164.0}]},{"StartTime":217579.0,"Objects":[{"StartTime":217579.0,"EndTime":217579.0,"X":358.0,"Y":74.0}]},{"StartTime":217801.0,"Objects":[{"StartTime":217801.0,"EndTime":217801.0,"X":243.0,"Y":22.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":218098.0,"EndTime":218098.0,"X":259.170074,"Y":239.193665,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":218246.0,"Objects":[{"StartTime":218246.0,"EndTime":218246.0,"X":99.0,"Y":350.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":218321.0,"EndTime":218321.0,"X":189.276535,"Y":334.704254,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":218468.0,"Objects":[{"StartTime":218468.0,"EndTime":218468.0,"X":316.0,"Y":338.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":218654.0,"EndTime":218654.0,"X":190.048248,"Y":335.3634,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":218912.0,"Objects":[{"StartTime":218912.0,"EndTime":218912.0,"X":188.0,"Y":186.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":218987.0,"EndTime":218987.0,"X":258.7948,"Y":238.577835,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":219134.0,"Objects":[{"StartTime":219134.0,"EndTime":219134.0,"X":77.0,"Y":265.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219320.0,"EndTime":219320.0,"X":69.94787,"Y":134.962021,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":219468.0,"Objects":[{"StartTime":219468.0,"EndTime":219468.0,"X":199.991959,"Y":39.99196}]},{"StartTime":219579.0,"Objects":[{"StartTime":219579.0,"EndTime":219579.0,"X":204.0,"Y":44.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219654.0,"EndTime":219654.0,"X":140.776764,"Y":17.8049469,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":219801.0,"Objects":[{"StartTime":219801.0,"EndTime":219801.0,"X":272.0,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":219876.0,"EndTime":219876.0,"X":184.1349,"Y":160.285843,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":220023.0,"Objects":[{"StartTime":220023.0,"EndTime":220023.0,"X":345.0,"Y":38.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":220098.0,"EndTime":220098.0,"X":425.9743,"Y":-2.0466094,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":220246.0,"Objects":[{"StartTime":220246.0,"EndTime":220246.0,"X":293.0,"Y":246.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":220321.0,"EndTime":220321.0,"X":284.1332,"Y":153.632828,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":220468.0,"Objects":[{"StartTime":220468.0,"EndTime":220468.0,"X":454.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":220654.0,"EndTime":220654.0,"X":442.845032,"Y":293.1156,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":220801.0,"Objects":[{"StartTime":220801.0,"EndTime":220801.0,"X":267.0,"Y":384.0}]},{"StartTime":220912.0,"Objects":[{"StartTime":220912.0,"EndTime":220912.0,"X":330.0,"Y":303.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":220987.0,"EndTime":220987.0,"X":256.6342,"Y":277.682,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":221134.0,"Objects":[{"StartTime":221134.0,"EndTime":221134.0,"X":122.0,"Y":252.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":221209.0,"EndTime":221209.0,"X":77.28965,"Y":302.866638,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":221357.0,"Objects":[{"StartTime":221357.0,"EndTime":221357.0,"X":358.0,"Y":189.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":221432.0,"EndTime":221432.0,"X":291.6313,"Y":167.885254,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":221579.0,"Objects":[{"StartTime":221579.0,"EndTime":221579.0,"X":122.0,"Y":252.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":221654.0,"EndTime":221654.0,"X":144.643356,"Y":362.1977,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":221801.0,"Objects":[{"StartTime":221801.0,"EndTime":221801.0,"X":180.0,"Y":89.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":221987.0,"EndTime":221987.0,"X":-0.212159589,"Y":155.517212,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":222134.0,"Objects":[{"StartTime":222134.0,"EndTime":222134.0,"X":2.0,"Y":52.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":222320.0,"EndTime":222320.0,"X":179.106552,"Y":118.010155,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":222468.0,"Objects":[{"StartTime":222468.0,"EndTime":222468.0,"X":310.0,"Y":3.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":222543.0,"EndTime":222543.0,"X":314.75592,"Y":71.55705,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":222690.0,"Objects":[{"StartTime":222690.0,"EndTime":222690.0,"X":86.0,"Y":282.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":222876.0,"EndTime":222876.0,"X":247.322327,"Y":250.250336,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":223023.0,"Objects":[{"StartTime":223023.0,"EndTime":223023.0,"X":385.991943,"Y":130.991959}]},{"StartTime":223134.0,"Objects":[{"StartTime":223134.0,"EndTime":223134.0,"X":390.0,"Y":135.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":223209.0,"EndTime":223209.0,"X":404.3002,"Y":216.25119,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":223357.0,"Objects":[{"StartTime":223357.0,"EndTime":223357.0,"X":503.0,"Y":302.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":223432.0,"EndTime":223432.0,"X":487.977631,"Y":383.120758,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":223579.0,"Objects":[{"StartTime":223579.0,"EndTime":223579.0,"X":272.0,"Y":306.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":223765.0,"EndTime":223765.0,"X":403.882141,"Y":215.343521,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":223912.0,"Objects":[{"StartTime":223912.0,"EndTime":223912.0,"X":368.0,"Y":309.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":224098.0,"EndTime":224098.0,"X":235.15654,"Y":204.242447,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":224246.0,"Objects":[{"StartTime":224246.0,"EndTime":224246.0,"X":131.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":224321.0,"EndTime":224321.0,"X":144.1626,"Y":297.576355,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":224468.0,"Objects":[{"StartTime":224468.0,"EndTime":224468.0,"X":95.0,"Y":94.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":224543.0,"EndTime":224543.0,"X":110.714821,"Y":179.094528,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":224690.0,"Objects":[{"StartTime":224690.0,"EndTime":224690.0,"X":18.0,"Y":376.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":224765.0,"EndTime":224765.0,"X":32.05672,"Y":287.904755,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":224912.0,"Objects":[{"StartTime":224912.0,"EndTime":224912.0,"X":221.0,"Y":91.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":224987.0,"EndTime":224987.0,"X":170.667969,"Y":-0.700416565,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":225134.0,"Objects":[{"StartTime":225134.0,"EndTime":225134.0,"X":0.0,"Y":195.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":225209.0,"EndTime":225209.0,"X":110.847977,"Y":179.233826,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":225357.0,"Objects":[{"StartTime":225357.0,"EndTime":225357.0,"X":225.0,"Y":279.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":225432.0,"EndTime":225432.0,"X":250.488,"Y":373.109558,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":225579.0,"Objects":[{"StartTime":225579.0,"EndTime":225579.0,"X":303.0,"Y":187.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":225765.0,"EndTime":225765.0,"X":302.1273,"Y":313.028442,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":226023.0,"Objects":[{"StartTime":226023.0,"EndTime":226023.0,"X":7.0,"Y":167.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":226098.0,"EndTime":226098.0,"X":85.87472,"Y":124.424934,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":226246.0,"Objects":[{"StartTime":226246.0,"EndTime":226246.0,"X":256.0,"Y":71.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":226432.0,"EndTime":226432.0,"X":145.4533,"Y":3.64019942,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":226579.0,"Objects":[{"StartTime":226579.0,"EndTime":226579.0,"X":176.991959,"Y":204.991959}]},{"StartTime":226690.0,"Objects":[{"StartTime":226690.0,"EndTime":226690.0,"X":181.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":226765.0,"EndTime":226765.0,"X":136.537048,"Y":259.55426,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":226912.0,"Objects":[{"StartTime":226912.0,"EndTime":226912.0,"X":259.0,"Y":383.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":226987.0,"EndTime":226987.0,"X":251.052277,"Y":292.364258,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":227134.0,"Objects":[{"StartTime":227134.0,"EndTime":227134.0,"X":479.0,"Y":317.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":227209.0,"EndTime":227209.0,"X":382.294434,"Y":329.4209,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":227357.0,"Objects":[{"StartTime":227357.0,"EndTime":227357.0,"X":181.0,"Y":209.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":227432.0,"EndTime":227432.0,"X":254.120087,"Y":153.375763,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":227579.0,"Objects":[{"StartTime":227579.0,"EndTime":227579.0,"X":510.0,"Y":38.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":227765.0,"EndTime":227765.0,"X":354.12912,"Y":1.18961823,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":227912.0,"Objects":[{"StartTime":227912.0,"EndTime":227912.0,"X":254.0,"Y":153.0}]},{"StartTime":228023.0,"Objects":[{"StartTime":228023.0,"EndTime":228023.0,"X":327.0,"Y":97.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":228098.0,"EndTime":228098.0,"X":345.770142,"Y":185.498367,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":228246.0,"Objects":[{"StartTime":228246.0,"EndTime":228246.0,"X":160.0,"Y":133.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":228321.0,"EndTime":228321.0,"X":223.510559,"Y":56.254303,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":228468.0,"Objects":[{"StartTime":228468.0,"EndTime":228468.0,"X":59.0,"Y":248.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":228543.0,"EndTime":228543.0,"X":23.5169945,"Y":163.594849,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":228690.0,"Objects":[{"StartTime":228690.0,"EndTime":228690.0,"X":210.0,"Y":274.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":228765.0,"EndTime":228765.0,"X":169.413956,"Y":371.345062,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":228912.0,"Objects":[{"StartTime":228912.0,"EndTime":228912.0,"X":124.0,"Y":143.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":229098.0,"EndTime":229098.0,"X":287.543579,"Y":107.639671,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":229246.0,"Objects":[{"StartTime":229246.0,"EndTime":229246.0,"X":436.0,"Y":260.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":229432.0,"EndTime":229432.0,"X":272.456421,"Y":295.360321,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":229579.0,"Objects":[{"StartTime":229579.0,"EndTime":229579.0,"X":392.0,"Y":42.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":229654.0,"EndTime":229654.0,"X":425.099121,"Y":124.701683,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":229801.0,"Objects":[{"StartTime":229801.0,"EndTime":229801.0,"X":164.0,"Y":360.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":229987.0,"EndTime":229987.0,"X":271.6051,"Y":295.145325,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":230134.0,"Objects":[{"StartTime":230134.0,"EndTime":230134.0,"X":234.0,"Y":80.0}]},{"StartTime":230246.0,"Objects":[{"StartTime":230246.0,"EndTime":230246.0,"X":331.0,"Y":158.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":230321.0,"EndTime":230321.0,"X":239.261871,"Y":182.147629,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":230468.0,"Objects":[{"StartTime":230468.0,"EndTime":230468.0,"X":114.0,"Y":95.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":230543.0,"EndTime":230543.0,"X":22.4259262,"Y":70.0677643,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":230690.0,"Objects":[{"StartTime":230690.0,"EndTime":230690.0,"X":68.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":230876.0,"EndTime":230876.0,"X":77.38308,"Y":207.233841,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":231023.0,"Objects":[{"StartTime":231023.0,"EndTime":231023.0,"X":194.0,"Y":44.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":231209.0,"EndTime":231209.0,"X":197.103,"Y":193.028,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":231357.0,"Objects":[{"StartTime":231357.0,"EndTime":231357.0,"X":246.0,"Y":376.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":231432.0,"EndTime":231432.0,"X":183.012833,"Y":319.709869,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":231579.0,"Objects":[{"StartTime":231579.0,"EndTime":231579.0,"X":351.0,"Y":144.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":231654.0,"EndTime":231654.0,"X":302.545776,"Y":223.952576,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":231801.0,"Objects":[{"StartTime":231801.0,"EndTime":231801.0,"X":439.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":231876.0,"EndTime":231876.0,"X":405.727173,"Y":301.005463,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":232023.0,"Objects":[{"StartTime":232023.0,"EndTime":232023.0,"X":464.0,"Y":28.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":232098.0,"EndTime":232098.0,"X":511.817963,"Y":101.332527,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":232246.0,"Objects":[{"StartTime":232246.0,"EndTime":232246.0,"X":404.0,"Y":300.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":232321.0,"EndTime":232321.0,"X":419.2058,"Y":214.033356,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":232468.0,"Objects":[{"StartTime":232468.0,"EndTime":232468.0,"X":219.0,"Y":236.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":232543.0,"EndTime":232543.0,"X":282.5849,"Y":174.9625,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":232690.0,"Objects":[{"StartTime":232690.0,"EndTime":232690.0,"X":342.0,"Y":39.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":232876.0,"EndTime":232876.0,"X":324.964325,"Y":159.368423,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":233134.0,"Objects":[{"StartTime":233134.0,"EndTime":233134.0,"X":126.0,"Y":136.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":233209.0,"EndTime":233209.0,"X":198.389069,"Y":83.24417,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":233357.0,"Objects":[{"StartTime":233357.0,"EndTime":233357.0,"X":443.0,"Y":238.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":233543.0,"EndTime":233543.0,"X":303.395447,"Y":265.311,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":233690.0,"Objects":[{"StartTime":233690.0,"EndTime":233690.0,"X":173.991959,"Y":277.991943}]},{"StartTime":233801.0,"Objects":[{"StartTime":233801.0,"EndTime":233801.0,"X":178.0,"Y":282.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":233876.0,"EndTime":233876.0,"X":162.8839,"Y":345.9473,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":234023.0,"Objects":[{"StartTime":234023.0,"EndTime":234023.0,"X":85.0,"Y":181.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":234098.0,"EndTime":234098.0,"X":33.3551064,"Y":255.5539,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":234246.0,"Objects":[{"StartTime":234246.0,"EndTime":234246.0,"X":347.0,"Y":157.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":234321.0,"EndTime":234321.0,"X":265.2607,"Y":189.827148,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":234468.0,"Objects":[{"StartTime":234468.0,"EndTime":234468.0,"X":158.0,"Y":87.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":234543.0,"EndTime":234543.0,"X":69.60225,"Y":68.49895,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":234690.0,"Objects":[{"StartTime":234690.0,"EndTime":234690.0,"X":242.0,"Y":11.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":234876.0,"EndTime":234876.0,"X":264.992859,"Y":188.8681,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":235023.0,"Objects":[{"StartTime":235023.0,"EndTime":235023.0,"X":149.991959,"Y":366.991943}]},{"StartTime":235134.0,"Objects":[{"StartTime":235134.0,"EndTime":235134.0,"X":154.0,"Y":371.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":235209.0,"EndTime":235209.0,"X":117.766327,"Y":311.878845,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":235357.0,"Objects":[{"StartTime":235357.0,"EndTime":235357.0,"X":352.0,"Y":150.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":235432.0,"EndTime":235432.0,"X":316.041229,"Y":233.2105,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":235579.0,"Objects":[{"StartTime":235579.0,"EndTime":235579.0,"X":214.0,"Y":285.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":235654.0,"EndTime":235654.0,"X":203.611847,"Y":217.484741,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":235801.0,"Objects":[{"StartTime":235801.0,"EndTime":235801.0,"X":437.0,"Y":116.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":235876.0,"EndTime":235876.0,"X":351.636444,"Y":149.2189,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":236023.0,"Objects":[{"StartTime":236023.0,"EndTime":236023.0,"X":458.0,"Y":323.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":236209.0,"EndTime":236209.0,"X":423.702148,"Y":240.080933,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":236357.0,"Objects":[{"StartTime":236357.0,"EndTime":236357.0,"X":329.0,"Y":261.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":236543.0,"EndTime":236543.0,"X":203.401733,"Y":267.2608,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":236690.0,"Objects":[{"StartTime":236690.0,"EndTime":236690.0,"X":35.0,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":236765.0,"EndTime":236765.0,"X":35.1037254,"Y":356.016968,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":236912.0,"Objects":[{"StartTime":236912.0,"EndTime":236912.0,"X":130.0,"Y":357.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":237098.0,"EndTime":237098.0,"X":87.5048752,"Y":200.5525,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":237246.0,"Objects":[{"StartTime":237246.0,"EndTime":237246.0,"X":16.9919586,"Y":51.99196}]},{"StartTime":237357.0,"Objects":[{"StartTime":237357.0,"EndTime":237357.0,"X":21.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":237432.0,"EndTime":237432.0,"X":101.406532,"Y":89.1720352,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":237579.0,"Objects":[{"StartTime":237579.0,"EndTime":237579.0,"X":230.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":237654.0,"EndTime":237654.0,"X":208.203568,"Y":95.03244,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":237801.0,"Objects":[{"StartTime":237801.0,"EndTime":237801.0,"X":44.0,"Y":226.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":237987.0,"EndTime":237987.0,"X":70.47167,"Y":311.8084,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":238134.0,"Objects":[{"StartTime":238134.0,"EndTime":238134.0,"X":207.0,"Y":190.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":238320.0,"EndTime":238320.0,"X":331.306183,"Y":171.1106,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":238468.0,"Objects":[{"StartTime":238468.0,"EndTime":238468.0,"X":501.0,"Y":143.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":238543.0,"EndTime":238543.0,"X":509.553375,"Y":231.402039,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":238690.0,"Objects":[{"StartTime":238690.0,"EndTime":238690.0,"X":411.0,"Y":240.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":238765.0,"EndTime":238765.0,"X":408.77948,"Y":148.338074,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":238912.0,"Objects":[{"StartTime":238912.0,"EndTime":238912.0,"X":496.0,"Y":14.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":238987.0,"EndTime":238987.0,"X":414.912842,"Y":53.2139854,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":239134.0,"Objects":[{"StartTime":239134.0,"EndTime":239134.0,"X":204.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":239209.0,"EndTime":239209.0,"X":283.579468,"Y":30.7221928,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":239357.0,"Objects":[{"StartTime":239357.0,"EndTime":239357.0,"X":299.0,"Y":259.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":239432.0,"EndTime":239432.0,"X":219.272232,"Y":212.447662,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":239579.0,"Objects":[{"StartTime":239579.0,"EndTime":239579.0,"X":0.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":239654.0,"EndTime":239654.0,"X":87.22065,"Y":41.1654,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":239801.0,"Objects":[{"StartTime":239801.0,"EndTime":239801.0,"X":89.0,"Y":177.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":239987.0,"EndTime":239987.0,"X":86.67163,"Y":40.7199364,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":240246.0,"Objects":[{"StartTime":240246.0,"EndTime":240246.0,"X":310.0,"Y":181.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":240321.0,"EndTime":240321.0,"X":222.779343,"Y":145.1654,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":240468.0,"Objects":[{"StartTime":240468.0,"EndTime":240468.0,"X":36.0,"Y":338.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":240654.0,"EndTime":240654.0,"X":160.513031,"Y":285.858368,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":240801.0,"Objects":[{"StartTime":240801.0,"EndTime":240801.0,"X":268.991943,"Y":319.991943}]},{"StartTime":240912.0,"Objects":[{"StartTime":240912.0,"EndTime":240912.0,"X":273.0,"Y":324.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":240987.0,"EndTime":240987.0,"X":240.250153,"Y":383.3273,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":241134.0,"Objects":[{"StartTime":241134.0,"EndTime":241134.0,"X":454.0,"Y":329.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":241209.0,"EndTime":241209.0,"X":421.2658,"Y":242.324371,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":241357.0,"Objects":[{"StartTime":241357.0,"EndTime":241357.0,"X":270.0,"Y":208.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":241432.0,"EndTime":241432.0,"X":314.621155,"Y":127.794777,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":241579.0,"Objects":[{"StartTime":241579.0,"EndTime":241579.0,"X":512.0,"Y":65.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":241654.0,"EndTime":241654.0,"X":442.488647,"Y":119.759155,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":241801.0,"Objects":[{"StartTime":241801.0,"EndTime":241801.0,"X":197.0,"Y":29.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":241987.0,"EndTime":241987.0,"X":314.3943,"Y":126.814934,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":242134.0,"Objects":[{"StartTime":242134.0,"EndTime":242134.0,"X":122.0,"Y":235.0}]},{"StartTime":242246.0,"Objects":[{"StartTime":242246.0,"EndTime":242246.0,"X":223.0,"Y":265.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":242321.0,"EndTime":242321.0,"X":215.238159,"Y":199.806656,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":242468.0,"Objects":[{"StartTime":242468.0,"EndTime":242468.0,"X":97.0,"Y":19.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":242543.0,"EndTime":242543.0,"X":99.42523,"Y":106.645737,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":242690.0,"Objects":[{"StartTime":242690.0,"EndTime":242690.0,"X":314.0,"Y":127.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":242765.0,"EndTime":242765.0,"X":250.80098,"Y":68.37848,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":242912.0,"Objects":[{"StartTime":242912.0,"EndTime":242912.0,"X":14.0,"Y":268.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":242987.0,"EndTime":242987.0,"X":121.45948,"Y":234.7027,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":243134.0,"Objects":[{"StartTime":243134.0,"EndTime":243134.0,"X":354.0,"Y":245.0}]},{"StartTime":243468.0,"Objects":[{"StartTime":243468.0,"EndTime":243468.0,"X":158.0,"Y":49.0}]},{"StartTime":243801.0,"Objects":[{"StartTime":243801.0,"EndTime":243801.0,"X":121.0,"Y":331.0}]},{"StartTime":244246.0,"Objects":[{"StartTime":244246.0,"EndTime":244246.0,"X":291.0,"Y":99.0}]},{"StartTime":244469.0,"Objects":[{"StartTime":244469.0,"EndTime":244469.0,"X":270.0,"Y":314.0}]},{"StartTime":244691.0,"Objects":[{"StartTime":244691.0,"EndTime":244691.0,"X":91.0,"Y":198.0}]},{"StartTime":244912.0,"Objects":[{"StartTime":244912.0,"EndTime":244912.0,"X":244.0,"Y":208.0}]},{"StartTime":245246.0,"Objects":[{"StartTime":245246.0,"EndTime":245246.0,"X":192.0,"Y":228.0}]},{"StartTime":245579.0,"Objects":[{"StartTime":245579.0,"EndTime":245579.0,"X":199.0,"Y":179.0}]}]} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824.osu b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824.osu deleted file mode 100644 index 7b53a82b51b3..000000000000 --- a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/2730824.osu +++ /dev/null @@ -1,1140 +0,0 @@ -osu file format v14 - -[General] -AudioLeadIn: 0 -PreviewTime: 27912 -Countdown: 0 -SampleSet: Soft -StackLeniency: 0.4 -Mode: 0 -LetterboxInBreaks: 0 -WidescreenStoryboard: 1 - -[Difficulty] -HPDrainRate:5.5 -CircleSize:3.2 -OverallDifficulty:8.7 -ApproachRate:9.3 -SliderMultiplier:3 -SliderTickRate:1 - -[Events] -//Background and Video events -//Break Periods -2,67334,76803 -//Storyboard Layer 0 (Background) -//Storyboard Layer 1 (Fail) -//Storyboard Layer 2 (Pass) -//Storyboard Layer 3 (Foreground) -//Storyboard Layer 4 (Overlay) -//Storyboard Sound Samples - -[TimingPoints] -3135,444.444444444444,4,2,1,60,1,0 -3135,-153.846153846153,4,2,1,60,0,0 -17357,-100,4,2,1,65,0,0 -28023,-100,4,2,1,70,0,0 -31579,-133.333333333333,4,2,1,70,0,0 -32690,-100,4,2,1,70,0,0 -33357,-133.333333333333,4,2,1,70,0,0 -34468,-100,4,2,1,70,0,0 -38690,-133.333333333333,4,2,1,70,0,0 -39801,-100,4,2,1,70,0,0 -40468,-222.222222222221,4,2,1,70,0,0 -41246,-222.222222222221,4,2,1,5,0,0 -41357,-250,4,2,1,80,0,0 -42134,-222.222222222221,4,2,1,5,0,0 -42246,-111.111111111111,4,2,1,75,0,0 -56468,-83.3333333333333,4,2,1,80,0,1 -67134,-100,4,2,1,85,0,0 -77801,-100,4,2,1,70,0,0 -92023,-100,4,2,1,75,0,0 -106246,-83.3333333333333,4,2,1,90,0,1 -129801,-90.9090909090909,4,2,1,90,0,1 -130246,-125,4,2,1,90,0,1 -131134,-90.9090909090909,4,2,1,80,0,0 -145357,-90.9090909090909,4,2,1,85,0,0 -152357,-222.222222222221,4,2,1,5,0,0 -152468,-90.9090909090909,4,2,1,85,0,0 -156023,-76.9230769230769,4,2,1,85,0,0 -157801,-111.111111111111,4,2,1,70,0,0 -159579,-133.333333333333,4,2,1,70,0,0 -160468,-111.111111111111,4,2,1,70,0,0 -161357,-133.333333333333,4,2,1,70,0,0 -162246,-111.111111111111,4,2,1,70,0,0 -166690,-133.333333333333,4,2,1,70,0,0 -172023,-111.111111111111,4,2,1,75,0,0 -182690,-111.111111111111,4,2,1,70,0,0 -182912,-90.9090909090908,4,2,1,70,0,0 -183134,-111.111111111111,4,2,1,80,0,0 -183357,-90.9090909090908,4,2,1,80,0,0 -183579,-90.9090909090908,4,2,1,90,0,0 -184912,-58.8235294117647,4,2,1,90,0,0 -185134,-111.111111111111,4,2,1,5,0,0 -185357,-666.666666666658,4,2,1,90,0,0 -186246,-76.9230769230769,4,2,1,95,0,1 -214690,-100,4,2,1,80,0,0 -218246,-76.9230769230769,4,2,1,85,0,1 -218468,-105.263157894737,4,2,1,85,0,1 -218912,-76.9230769230769,4,2,1,85,0,1 -219134,-105.263157894737,4,2,1,85,0,1 -219801,-76.9230769230769,4,2,1,85,0,1 -221134,-105.263157894737,4,2,1,85,0,1 -221367,-76.9230769230769,4,2,1,85,0,1 -221579,-66.6666666666667,4,2,1,85,0,1 -221801,-76.9230769230769,4,2,1,85,0,1 -223023,-90.9090909090909,4,2,1,85,0,1 -223579,-76.9230769230769,4,2,1,85,0,1 -224912,-66.6666666666667,4,2,1,85,0,1 -225357,-76.9230769230769,4,2,1,85,0,1 -225579,-105.263157894737,4,2,1,85,0,1 -226023,-76.9230769230769,4,2,1,85,0,1 -226246,-105.263157894737,4,2,1,85,0,1 -226912,-76.9230769230769,4,2,1,85,0,1 -228244,-66.6666666666667,4,2,1,85,0,1 -228468,-76.9230769230769,4,2,1,85,0,1 -228690,-66.6666666666667,4,2,1,85,0,1 -228912,-76.9230769230769,4,2,1,85,0,1 -230690,-66.6666666666667,4,2,1,85,0,1 -231357,-76.9230769230769,4,2,1,85,0,1 -232690,-105.263157894737,4,2,1,85,0,1 -233134,-76.9230769230769,4,2,1,85,0,1 -233357,-105.263157894737,4,2,1,85,0,1 -234023,-76.9230769230769,4,2,1,85,0,1 -235023,-105.263157894737,4,2,1,85,0,1 -235357,-76.9230769230769,4,2,1,85,0,1 -235579,-105.263157894737,4,2,1,85,0,1 -235801,-76.9230769230769,4,2,1,85,0,1 -236357,-55.5555555555556,4,2,1,85,0,1 -236690,-76.9230769230769,4,2,1,85,0,1 -238134,-55.5555555555556,4,2,1,85,0,1 -238468,-76.9230769230769,4,2,1,85,0,1 -239134,-55.5555555555556,4,2,1,85,0,1 -239579,-76.9230769230769,4,2,1,85,0,1 -239801,-105.263157894737,4,2,1,85,0,1 -240246,-76.9230769230769,4,2,1,85,0,1 -240468,-105.263157894737,4,2,1,85,0,1 -241134,-76.9230769230769,4,2,1,85,0,1 -242246,-105.263157894737,4,2,1,85,0,1 -242468,-76.9230769230769,4,2,1,85,0,1 -242690,-80.0000000000001,4,2,1,85,0,1 -242912,-66.6666666666667,4,2,1,85,0,1 -243134,-66.6666666666667,4,2,1,85,0,0 - - -[Colours] -Combo1 : 234,69,21 -Combo2 : 46,46,199 -Combo3 : 74,85,217 -Combo4 : 82,49,168 - -[HitObjects] -31,114,3135,6,0,B|55:132|55:132|152:112,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -183,39,3468,2,0,B|207:21|207:21|304:41,1,97.4999955368044,0|0,3:2|0:0,0:0:0:0: -358,104,3801,1,2,3:2:0:0: -274,180,4023,1,2,1:2:0:0: -367,238,4246,1,2,0:0:0:0: -273,34,4468,1,2,0:0:0:0: -209,249,4690,1,2,0:0:0:0: -413,99,4912,6,0,B|318:97|380:159|248:148,2,146.249993305207,2|0|2,3:2|3:2|3:2,0:0:0:0: -504,157,5801,1,2,1:2:0:0: -429,235,6023,1,2,0:0:0:0: -498,324,6246,1,2,3:2:0:0: -331,232,6468,5,2,3:2:0:0: -321,232,6579,1,0,3:2:0:0: -311,233,6690,2,0,P|295:305|321:339,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -160,384,7023,2,0,P|176:312|150:278,1,97.4999955368044,0|0,3:2|0:0,0:0:0:0: -78,237,7357,1,2,3:2:0:0: -14,325,7579,1,2,1:2:0:0: -190,197,7801,1,2,0:0:0:0: -0,74,8023,1,2,3:2:0:0: -25,114,8134,1,0,3:2:0:0: -70,131,8245,1,2,3:2:0:0: -116,117,8356,1,0,3:2:0:0: -143,78,8468,6,0,P|193:24|264:48,2,146.249993305207,2|0|0,3:2|3:2|3:2,0:0:0:0: -69,241,9357,1,2,1:2:0:0: -48,132,9579,1,2,0:0:0:0: -191,187,9801,1,2,0:0:0:0: -173,308,10023,1,2,0:0:0:0: -0,384,10246,6,0,B|39:362|39:362|116:380,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -179,287,10579,2,0,B|218:309|218:309|295:291,1,97.4999955368044,0|0,3:2|0:0,0:0:0:0: -363,176,10912,2,0,L|353:241,1,48.7499977684022,2|0,3:2|0:0,0:0:0:0: -415,327,11134,1,2,1:2:0:0: -267,121,11579,2,0,L|257:186,1,48.7499977684022,2|0,0:0|0:0,0:0:0:0: -512,131,11801,1,2,0:0:0:0: -512,131,11912,1,0,0:0:0:0: -512,131,12023,6,0,B|459:125|459:125|414:141|414:141|356:133,2,146.249993305207,0|0|2,3:2|3:2|3:2,0:0:0:0: -275,68,12912,2,0,P|314:19|360:21,1,97.4999955368044,0|2,1:2|0:0,0:0:0:0: -276,180,13357,1,2,3:2:0:0: -121,111,13579,1,2,3:2:0:0: -72,116,13690,1,0,3:2:0:0: -24,122,13801,5,2,3:2:0:0: -188,13,14023,1,2,0:0:0:0: -86,226,14246,1,2,0:0:0:0: -235,139,14468,2,0,B|197:247|276:206|239:348,1,194.999991073609,2|2,3:2|0:0,0:0:0:0: -23,350,15134,1,2,3:2:0:0: -21,302,15245,1,0,3:2:0:0: -52,265,15356,1,2,3:2:0:0: -99,257,15467,1,0,3:2:0:0: -140,281,15579,6,0,B|263:266,1,97.4999955368044,0|2,3:2|0:0,0:0:0:0: -184,162,15912,2,0,B|307:147,1,97.4999955368044,0|0,3:2|0:0,0:0:0:0: -412,135,16246,1,0,3:2:0:0: -394,22,16468,2,0,B|362:72|362:72|387:173,1,146.249993305207,0|0,1:2|0:0,0:0:0:0: -487,220,16912,2,0,L|472:292,1,48.7499977684022,2|0,3:2|0:0,0:0:0:0: -380,382,17134,2,0,L|370:334,1,48.7499977684022,2|0,3:2|3:2,0:0:0:0: -264,260,17357,6,0,B|171:266|230:323|116:330,1,150,2|0,3:2|0:0,0:0:0:0: -26,244,17690,1,0,0:0:0:0: -56,145,17801,2,0,P|115:154|117:249,1,150,0|2,3:2|0:0,0:0:0:0: -48,361,18134,1,0,0:0:0:0: -48,361,18246,6,0,L|26:274,1,75,2|0,3:2|0:0,0:0:0:0: -130,232,18468,2,0,L|151:136,1,75,2|0,0:0|0:0,0:0:0:0: -231,7,18690,2,0,P|311:53|295:122,1,150,2|2,3:2|0:0,0:0:0:0: -262,223,19023,1,0,0:0:0:0: -262,223,19134,6,0,B|367:199|316:270|444:232,1,150,2|0,3:2|0:0,0:0:0:0: -492,166,19468,1,0,0:0:0:0: -492,166,19579,1,0,3:2:0:0: -411,310,19801,2,0,P|406:240|427:221,1,75,2|0,0:0|0:0,0:0:0:0: -372,6,20023,6,0,P|414:69|384:148,1,150,2|2,3:2|0:0,0:0:0:0: -262,147,20357,1,0,0:0:0:0: -262,147,20468,2,0,L|309:81,1,75,2|0,3:2|0:0,0:0:0:0: -160,0,20690,2,0,L|193:66,1,75,2|0,0:0|0:0,0:0:0:0: -306,220,20912,6,0,P|248:172|165:233,1,150,2|0,3:2|0:0,0:0:0:0: -32,180,21246,1,0,0:0:0:0: -32,180,21357,2,0,P|77:106|93:160,1,150,0|2,3:2|0:0,0:0:0:0: -113,363,21690,1,0,0:0:0:0: -43,305,21801,6,0,P|120:270|139:279,1,75,2|0,3:2|0:0,0:0:0:0: -209,310,22023,2,0,L|197:392,1,75,2|0,0:0|0:0,0:0:0:0: -102,166,22246,2,0,P|175:190|188:227,1,75,2|0,3:2|0:0,0:0:0:0: -249,121,22468,2,0,P|281:178|271:213,1,75,2|0,0:0|0:0,0:0:0:0: -209,310,22690,6,0,B|300:297|261:364|383:338,1,150,2|0,3:2|0:0,0:0:0:0: -442,260,23023,1,0,0:0:0:0: -442,260,23134,1,0,3:2:0:0: -250,201,23357,6,0,L|337:201,1,75,2|0,0:0|0:0,0:0:0:0: -442,260,23579,2,0,P|450:196|430:177,1,75,2|0,3:2|0:0,0:0:0:0: -343,301,23801,2,0,P|330:355|353:394,1,75,2|0,0:0|0:0,0:0:0:0: -442,260,24023,5,2,3:2:0:0: -397,202,24134,1,0,0:0:0:0: -325,202,24245,1,2,0:0:0:0: -246,274,24357,1,0,0:0:0:0: -153,226,24468,6,0,B|128:277|128:277|148:373,1,150,2|0,3:2|0:0,0:0:0:0: -23,70,24801,1,0,0:0:0:0: -23,70,24912,2,0,B|48:121|48:121|28:217,1,150,0|2,3:2|0:0,0:0:0:0: -216,144,25246,1,0,0:0:0:0: -216,144,25357,6,0,L|137:131,1,75,2|0,3:2|0:0,0:0:0:0: -105,32,25579,2,0,L|184:45,1,75,2|0,0:0|0:0,0:0:0:0: -328,246,25801,2,0,L|249:233,1,75,2|0,3:2|0:0,0:0:0:0: -270,66,26023,2,0,P|303:120|300:149,1,75,2|0,0:0|0:0,0:0:0:0: -162,270,26246,6,0,B|154:193|154:193|171:162|220:140,1,150,2|0,3:2|0:0,0:0:0:0: -211,373,26579,1,0,0:0:0:0: -211,373,26690,2,0,P|165:321|67:374,1,150,0|2,3:2|0:0,0:0:0:0: -300,200,27023,1,0,0:0:0:0: -300,200,27134,6,0,L|262:280,1,75,2|0,3:2|0:0,0:0:0:0: -402,363,27357,2,0,L|368:281,1,75,2|0,0:0|0:0,0:0:0:0: -178,44,27579,2,0,P|164:154|217:194,1,150,2|0,3:2|0:0,0:0:0:0: -329,89,27912,1,0,0:0:0:0: -329,89,28023,6,0,L|235:111,1,75,6|0,3:2|0:0,0:0:0:0: -103,268,28246,2,0,P|126:188|208:188,1,150,2|0,0:0|1:2,0:0:0:0: -360,217,28690,6,0,L|266:239,1,75,2|0,0:0|0:0,0:0:0:0: -178,44,28912,2,0,P|164:154|217:194,1,150,2|0,1:2|0:0,0:0:0:0: -247,384,29357,6,0,P|216:309|186:306,1,75,2|0,1:2|0:0,0:0:0:0: -26,254,29579,2,0,P|106:264|124:240,1,75,2|0,0:0|0:0,0:0:0:0: -233,128,29801,2,0,P|183:192|195:219,1,75,2|0,1:2|0:0,0:0:0:0: -173,257,30023,1,2,0:0:0:0: -173,257,30246,1,2,1:2:0:0: -173,257,30690,6,0,P|218:219|241:221,1,75,2|0,1:2|0:0,0:0:0:0: -173,42,30912,2,0,P|183:99|170:118,1,75,2|0,0:0|0:0,0:0:0:0: -353,122,31134,2,0,P|297:102|287:81,1,75,2|0,1:2|0:0,0:0:0:0: -173,257,31357,2,0,P|218:219|241:221,1,75,2|0,0:0|0:0,0:0:0:0: -331,243,31579,6,0,L|341:370,1,112.500004291535,2|0,1:2|0:0,0:0:0:0: -433,278,31912,2,0,L|425:166,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: -510,105,32246,1,2,0:0:0:0: -510,105,32468,1,0,1:2:0:0: -235,27,32690,6,0,P|215:53|245:101,1,75,2|0,0:0|0:0,0:0:0:0: -350,138,32912,2,0,P|331:87|303:93,1,75,2|0,1:2|0:0,0:0:0:0: -183,198,33134,2,0,L|259:186,1,75,2|0,0:0|0:0,0:0:0:0: -384,39,33357,6,0,P|346:99|372:173,1,112.500004291535,2|0,1:2|0:0,0:0:0:0: -501,181,33690,2,0,P|500:125|447:174,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: -388,225,34023,1,2,0:0:0:0: -388,225,34246,1,0,1:2:0:0: -512,329,34468,6,0,P|468:271|434:274,1,75,2|0,0:0|0:0,0:0:0:0: -382,326,34690,2,0,B|311:356|311:356|234:334,1,150,2|0,1:2|0:0,0:0:0:0: -140,297,35023,1,0,0:0:0:0: -140,297,35134,6,0,L|191:234,1,75,2|0,1:2|0:0,0:0:0:0: -322,42,35357,2,0,P|261:129|296:167,1,150,2|0,0:0|1:2,0:0:0:0: -121,77,35801,6,0,L|172:140,1,75,2|0,0:0|0:0,0:0:0:0: -299,267,36024,2,0,P|297:160|246:150,1,150,2|0,1:2|0:0,0:0:0:0: -197,292,36468,6,0,L|225:376,1,75,2|0,1:2|0:0,0:0:0:0: -105,216,36690,2,0,L|88:305,1,75,2|0,0:0|0:0,0:0:0:0: -325,312,36912,1,2,1:2:0:0: -207,192,37134,1,2,0:0:0:0: -478,185,37357,2,0,B|405:220|405:220|329:198,1,150,2|0,1:2|0:0,0:0:0:0: -409,38,37801,6,0,L|396:119,1,75,2|0,1:2|0:0,0:0:0:0: -218,266,38023,2,0,L|205:185,1,75,2|0,0:0|0:0,0:0:0:0: -299,30,38246,2,0,P|273:81|174:63,1,150,2|2,1:2|0:0,0:0:0:0: -79,33,38579,1,0,0:0:0:0: -79,33,38690,6,0,B|73:74|73:74|83:99|83:99|71:147,1,112.500004291535,2|0,1:2|0:0,0:0:0:0: -182,295,39023,2,0,B|176:253|176:253|186:228|186:228|174:180,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: -69,244,39357,1,2,0:0:0:0: -69,244,39579,1,0,1:2:0:0: -257,133,39801,6,0,P|195:90|176:98,1,75,2|0,0:0|0:0,0:0:0:0: -179,216,40023,2,0,B|247:249|247:249|346:219,1,150,2|0,1:2|0:0,0:0:0:0: -492,74,40468,6,0,P|422:36|419:154,1,236.249992790222,2|0,0:0|0:0,0:0:0:0: -492,74,41357,6,2,B|361:53|421:129|294:115,1,210,0|0,0:0|0:0,0:0:0:0: -202,56,42246,6,0,B|161:106|161:106|195:170,1,134.999995880127,6|2,3:2|0:0,0:0:0:0: -294,115,42690,1,2,0:0:0:0: -98,226,42912,2,0,P|137:165|213:184,1,134.999995880127,2|8,3:2|0:0,0:0:0:0: -212,338,43357,6,0,L|188:264,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -289,235,43579,2,0,L|310:171,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -417,146,43801,1,2,0:0:0:0: -417,146,44023,1,0,3:2:0:0: -212,338,44246,6,0,P|189:301|187:253,1,67.4999979400635,2|0,0:0|3:2,0:0:0:0: -289,235,44468,2,0,P|280:195|301:162,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -417,146,44690,1,2,3:2:0:0: -417,146,44912,1,8,0:0:0:0: -192,162,45134,6,0,P|254:94|272:102,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -427,40,45357,2,0,B|360:70|360:70|294:42,1,134.999995880127,2|2,0:0|0:0,0:0:0:0: -220,9,45690,1,0,0:0:0:0: -220,9,45801,5,0,3:2:0:0: -301,160,46023,1,2,0:0:0:0: -129,125,46246,1,2,0:0:0:0: -319,46,46468,5,2,3:2:0:0: -319,46,46579,1,0,0:0:0:0: -319,46,46690,1,8,0:0:0:0: -184,235,46912,1,2,0:0:0:0: -424,203,47134,1,2,0:0:0:0: -222,101,47357,1,2,0:0:0:0: -317,195,47579,6,0,B|288:250|288:250|313:324,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: -405,379,47912,2,0,B|428:310|428:310|399:255,1,134.999995880127,0|0,3:2|0:0,0:0:0:0: -311,318,48246,1,2,3:2:0:0: -477,199,48468,1,8,0:0:0:0: -195,231,48690,6,0,L|304:220,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -246,128,48912,2,0,L|355:117,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -468,54,49134,2,0,P|405:3|364:33,1,134.999995880127,2|0,0:0|3:2,0:0:0:0: -195,231,49579,6,0,L|304:220,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -246,128,49801,2,0,L|355:117,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -468,54,50023,2,0,P|431:70|428:162,1,134.999995880127,2|8,3:2|0:0,0:0:0:0: -195,231,50468,6,0,L|304:220,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -246,128,50690,2,0,L|355:117,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -483,257,50912,2,0,P|475:191|421:154,1,134.999995880127,2|0,0:0|3:2,0:0:0:0: -375,361,51357,6,0,L|380:289,1,67.4999979400635,2|0,0:0|3:2,0:0:0:0: -314,122,51579,2,0,L|309:194,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -379,293,51801,2,0,B|329:289|329:289|293:306|293:306|211:301,1,134.999995880127,2|8,3:2|0:0,0:0:0:0: -22,215,52246,5,2,0:0:0:0: -55,212,52357,1,0,0:0:0:0: -89,209,52468,1,2,0:0:0:0: -229,127,52690,1,2,0:0:0:0: -152,6,52912,6,0,P|112:71|139:129,1,134.999995880127,2|0,3:2|0:0,0:0:0:0: -240,226,53357,6,0,L|254:155,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -31,120,53579,2,0,P|80:209|140:205,1,134.999995880127,2|8,3:2|0:0,0:0:0:0: -260,41,54023,6,0,P|210:100|222:114,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -306,188,54246,2,0,P|285:162|252:159,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -80,294,54468,1,2,0:0:0:0: -80,294,54579,1,0,0:0:0:0: -80,294,54690,6,0,P|135:253|205:288,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: -306,294,55023,2,0,P|243:312|192:272,1,134.999995880127,0|0,3:2|0:0,0:0:0:0: -202,155,55357,2,0,P|257:189|271:223,1,67.4999979400635,0|0,3:2|0:0,0:0:0:0: -148,372,55579,6,0,P|196:272|236:287,1,134.999995880127,8|2,0:0|0:0,0:0:0:0: -286,129,55912,1,0,0:0:0:0: -286,129,56023,2,0,L|252:200,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -383,267,56246,2,0,L|353:206,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -164,44,56468,6,0,P|117:153|167:195,1,179.999994506836,4|2,3:2|0:0,0:0:0:0: -367,78,56801,1,0,0:0:0:0: -283,29,56912,2,0,B|258:71|258:71|278:122,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: -237,264,57134,2,0,B|134:289|203:339|80:358,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: -342,384,57579,6,0,P|338:311|359:294,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -509,173,57801,2,0,B|427:220|427:220|396:193|324:191,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: -248,151,58134,1,0,0:0:0:0: -248,151,58246,1,0,3:2:0:0: -386,20,58468,6,0,P|377:54|336:93,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -157,70,58690,2,0,P|255:58|282:78,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: -348,193,58912,2,0,B|239:203|292:268|180:273,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: -15,170,59357,6,0,P|83:201|96:234,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -21,297,59579,2,0,P|131:262|196:272,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: -269,90,59912,1,0,0:0:0:0: -269,90,60023,6,0,P|221:168|197:181,1,89.9999972534181,0|0,3:2|0:0,0:0:0:0: -124,0,60246,2,0,P|154:98|137:121,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -110,347,60468,6,0,P|90:262|102:236,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: -192,271,60690,2,0,P|242:207|279:202,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -358,379,60912,6,0,P|338:269|386:208,1,179.999994506836,0|2,3:2|0:0,0:0:0:0: -430,30,61246,1,0,0:0:0:0: -505,82,61357,2,0,P|448:123|408:114,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: -291,5,61579,2,0,P|322:87|300:117,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -241,182,61801,2,0,L|151:197,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: -4,119,62023,2,0,B|69:108|69:108|93:85|93:85|186:73,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: -118,348,62468,5,2,0:0:0:0: -68,264,62579,1,0,0:0:0:0: -134,181,62690,2,0,P|165:245|150:275,1,89.9999972534181,0|0,3:2|0:0,0:0:0:0: -264,364,62912,2,0,P|265:290|290:268,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -79,96,63134,2,0,P|195:164|261:119,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: -300,72,63468,1,0,0:0:0:0: -300,72,63579,1,0,3:2:0:0: -188,7,63801,6,0,P|162:57|184:74,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -376,208,64023,2,0,P|375:130|296:71,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: -277,176,64357,1,0,0:0:0:0: -277,176,64468,1,0,3:2:0:0: -474,21,64690,6,0,P|419:95|436:116,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -494,270,64912,2,0,P|423:186|369:216,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: -316,372,65246,1,0,0:0:0:0: -316,372,65357,6,0,B|338:333|338:333|307:292,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: -188,163,65579,2,0,P|211:262|235:269,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -449,141,65801,2,0,P|352:204|277:184,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: -251,27,66134,1,0,0:0:0:0: -251,27,66246,6,0,P|285:84|242:140,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: -131,223,66468,2,0,P|148:182|187:162,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -292,356,66690,1,8,0:1:0:0: -233,273,66801,1,0,3:0:0:0: -283,188,66912,1,8,0:1:0:0: -387,198,67023,1,8,0:1:0:0: -327,275,67134,5,6,3:2:0:0: -22,236,77357,5,8,0:1:0:0: -28,134,77468,1,8,0:1:0:0: -127,121,77579,1,8,0:1:0:0: -193,191,77690,1,8,0:1:0:0: -272,116,77801,6,0,P|290:44|223:90,1,150,6|0,3:2|0:0,0:0:0:0: -158,266,78134,1,0,0:0:0:0: -158,266,78246,2,0,P|130:206|194:192,1,150,8|2,0:0|0:0,0:0:0:0: -268,286,78579,1,0,0:0:0:0: -268,286,78690,6,0,B|244:318|244:318|271:343,1,75,2|0,3:2|0:0,0:0:0:0: -472,268,78912,2,0,B|496:300|496:300|469:325,1,75,2|0,0:0|0:0,0:0:0:0: -382,379,79134,1,10,0:0:0:0: -361,323,79245,1,0,0:0:0:0: -369,264,79356,1,2,0:0:0:0: -341,102,79579,6,0,B|274:102|274:102|258:107|258:107|191:106,1,150,2|0,3:2|0:0,0:0:0:0: -18,82,79912,1,0,0:0:0:0: -18,82,80023,2,0,P|51:13|129:56,1,150,8|2,0:0|0:0,0:0:0:0: -44,222,80357,1,0,0:0:0:0: -31,206,80468,6,0,P|74:167|114:176,1,75,2|0,3:2|0:0,0:0:0:0: -191,106,80690,2,0,P|236:155|231:190,1,75,2|0,0:0|0:0,0:0:0:0: -125,355,80912,1,10,0:0:0:0: -100,316,81023,1,0,0:0:0:0: -122,267,81134,1,2,0:0:0:0: -253,316,81357,6,0,B|353:309|301:365|437:349,1,150,2|0,3:2|0:0,0:0:0:0: -512,190,81690,2,0,B|412:183|464:239|328:223,1,150 -328,71,82023,2,0,P|384:108|378:126,1,75,2|0,0:0|0:0,0:0:0:0: -257,286,82246,6,0,P|263:179|225:153,1,150,2|2,3:2|0:0,0:0:0:0: -163,99,82579,1,0,0:0:0:0: -111,178,82690,2,0,P|88:214|19:223,1,75,10|0,0:0|0:0,0:0:0:0: -81,47,82912,2,0,P|144:5|166:14,1,75,2|0,0:0|0:0,0:0:0:0: -0,177,83134,6,0,P|49:289|19:350,1,150,2|0,3:2|0:0,0:0:0:0: -43,309,83468,1,0,0:0:0:0: -43,309,83579,1,8,0:0:0:0: -139,384,83801,1,0,0:0:0:0: -188,280,84023,5,2,3:2:0:0: -103,89,84246,1,2,0:0:0:0: -224,144,84468,1,10,0:0:0:0: -290,148,84579,1,0,0:0:0:0: -337,103,84690,1,2,0:0:0:0: -339,38,84801,1,0,0:0:0:0: -295,0,84912,6,0,B|287:55|287:55|300:89|300:89|288:161,1,150,2|0,3:2|0:0,0:0:0:0: -225,236,85246,1,0,0:0:0:0: -225,236,85357,1,8,0:0:0:0: -398,86,85579,6,0,B|424:116|424:116|384:129,1,75,2|0,0:0|0:0,0:0:0:0: -115,294,85801,2,0,P|181:225|250:260,1,150,2|0,3:2|0:0,0:0:0:0: -115,294,86246,6,0,P|111:231|142:196,1,75,10|0,0:0|0:0,0:0:0:0: -22,157,86468,1,2,0:0:0:0: -55,100,86579,1,0,0:0:0:0: -119,90,86690,1,0,3:2:0:0: -308,247,86912,6,0,L|218:248,1,75,2|0,0:0|0:0,0:0:0:0: -228,131,87134,1,8,0:0:0:0: -177,357,87357,6,0,L|103:299,1,75,2|0,0:0|0:0,0:0:0:0: -233,249,87579,1,0,3:2:0:0: -15,324,87801,6,0,P|43:256|71:250,1,75,2|0,0:0|0:0,0:0:0:0: -224,165,88023,2,0,L|117:167,1,75,10|0,0:0|0:0,0:0:0:0: -258,70,88246,2,0,L|151:72,1,75,2|0,0:0|0:0,0:0:0:0: -5,16,88468,6,0,P|55:108|28:166,1,150,2|2,3:2|0:0,0:0:0:0: -273,256,88912,6,0,L|174:255,1,75,10|0,0:0|0:0,0:0:0:0: -3,269,89134,2,0,P|14:163|74:140,1,150,2|0,0:0|3:2,0:0:0:0: -124,384,89579,6,0,P|116:316|134:303,1,75,2|0,0:0|0:0,0:0:0:0: -208,188,89801,2,0,P|217:223|198:254,1,75,10|0,0:0|0:0,0:0:0:0: -3,269,90023,1,2,0:0:0:0: -49,218,90134,1,0,0:0:0:0: -115,225,90246,5,0,3:2:0:0: -0,145,90468,2,0,P|79:100|95:105,1,75,2|0,0:0|0:0,0:0:0:0: -218,6,90690,2,0,P|181:111|249:144,1,150,10|0,0:0|0:0,0:0:0:0: -419,145,91134,5,0,3:2:0:0: -479,56,91246,1,0,0:0:0:0: -379,0,91357,2,0,P|363:21|368:69,1,75,8|0,1:2|0:0,0:0:0:0: -512,276,91579,5,10,1:2:0:0: -468,233,91690,1,2,0:0:0:0: -406,261,91801,1,2,0:0:0:0: -318,330,91912,1,2,0:0:0:0: -224,273,92023,6,0,P|193:187|241:145,1,150,6|0,3:2|0:0,0:0:0:0: -318,217,92357,1,0,0:0:0:0: -318,217,92468,1,8,0:0:0:0: -149,15,92690,2,0,P|150:110|166:120,1,75,2|0,0:0|0:0,0:0:0:0: -342,63,92912,6,0,L|230:59,1,75,2|0,3:2|0:0,0:0:0:0: -170,201,93134,2,0,L|282:205,1,75,2|0,0:0|0:0,0:0:0:0: -472,64,93357,1,10,0:0:0:0: -506,125,93468,1,0,0:0:0:0: -462,179,93579,1,2,0:0:0:0: -366,146,93690,1,0,0:0:0:0: -285,212,93801,6,0,P|250:261|286:353,1,150,2|0,3:2|0:0,0:0:0:0: -369,287,94134,1,0,0:0:0:0: -369,287,94246,1,8,0:0:0:0: -219,185,94468,2,0,P|304:203|319:189,1,75,2|0,0:0|0:0,0:0:0:0: -336,23,94690,6,0,L|349:108,1,75,2|0,3:2|0:0,0:0:0:0: -433,84,94912,2,0,L|446:169,1,75,2|0,0:0|0:0,0:0:0:0: -284,211,95134,6,0,L|271:296,1,75,10|0,0:0|0:0,0:0:0:0: -187,272,95356,2,0,L|174:357,1,75,2|0,0:0|0:0,0:0:0:0: -356,383,95579,6,0,P|440:341|498:366,1,150,2|0,3:2|0:0,0:0:0:0: -272,285,96023,2,0,P|200:300|139:259,1,150,8|2,0:0|0:0,0:0:0:0: -201,125,96357,1,0,0:0:0:0: -201,125,96468,6,0,L|223:226,1,75,2|0,3:2|0:0,0:0:0:0: -271,284,96690,2,0,L|256:358,1,75,2|0,0:0|0:0,0:0:0:0: -84,186,96912,2,0,P|155:162|224:210,1,150,10|2,0:0|0:0,0:0:0:0: -147,268,97246,1,0,0:0:0:0: -147,268,97357,5,2,3:2:0:0: -357,138,97579,1,0,0:0:0:0: -176,7,97801,2,0,P|117:41|182:89,1,150,8|2,0:0|0:0,0:0:0:0: -207,270,98134,1,0,0:0:0:0: -207,270,98246,2,0,P|203:234|225:204,1,75,2|0,3:2|0:0,0:0:0:0: -247,69,98468,5,2,0:0:0:0: -294,108,98579,1,0,0:0:0:0: -353,100,98690,1,10,0:0:0:0: -397,60,98801,1,0,0:0:0:0: -496,86,98912,1,2,0:0:0:0: -491,189,99023,1,0,0:0:0:0: -389,228,99134,6,0,B|354:292|354:292|384:376,1,150,2|0,3:2|0:0,0:0:0:0: -271,58,99468,1,0,0:0:0:0: -271,58,99579,2,0,B|306:122|306:122|276:206,1,150,8|2,0:0|0:0,0:0:0:0: -190,352,99912,1,0,0:0:0:0: -190,352,100023,6,0,P|242:308|264:323,1,75,2|0,3:2|0:0,0:0:0:0: -347,176,100246,2,0,P|274:191|256:177,1,75,2|0,0:0|0:0,0:0:0:0: -84,306,100468,1,10,0:0:0:0: -105,243,100579,1,0,0:0:0:0: -170,218,100690,1,2,0:0:0:0: -231,56,100912,6,0,B|226:145|275:94|279:205,1,150,2|0,3:2|0:0,0:0:0:0: -344,370,101246,2,0,B|339:281|388:332|392:221,1,150 -448,146,101579,2,0,P|371:131|346:147,1,75,2|0,0:0|0:0,0:0:0:0: -205,282,101801,6,0,P|272:248|286:222,1,75,2|0,3:2|0:0,0:0:0:0: -197,178,102023,2,0,P|237:97|230:74,1,75,2|0,0:0|0:0,0:0:0:0: -70,284,102246,6,0,P|3:250|-11:224,1,75,10|0,0:0|0:0,0:0:0:0: -78,180,102468,2,0,P|38:99|45:76,1,75,2|0,0:0|0:0,0:0:0:0: -178,15,102690,6,0,P|149:65|148:-12,1,150,2|0,3:2|0:0,0:0:0:0: -281,207,103023,1,0,0:0:0:0: -260,203,103134,2,0,P|249:140|267:124,1,75,8|0,0:0|0:0,0:0:0:0: -354,14,103357,2,0,P|364:49|345:80,1,75 -178,253,103579,6,0,P|147:143|164:103,1,150,2|0,3:2|0:0,0:0:0:0: -379,203,103912,2,0,P|299:238|253:180,1,150,2|0,0:0|0:0,0:0:0:0: -168,324,104246,2,0,P|198:233|219:224,1,75,2|0,0:0|0:0,0:0:0:0: -304,76,104468,6,0,P|249:165|267:216,1,150,2|0,3:2|0:0,0:0:0:0: -464,172,104801,2,0,P|380:201|364:139,1,150,2|0,0:0|0:0,0:0:0:0: -253,328,105134,2,0,P|301:288|335:294,1,75,2|0,0:0|0:0,0:0:0:0: -360,162,105357,6,0,L|275:172,1,75,2|0,3:1|0:0,0:0:0:0: -166,85,105579,2,0,L|251:75,1,75 -166,271,105801,5,10,0:0:0:0: -164,228,105912,1,2,0:0:0:0: -60,177,106023,5,2,0:0:0:0: -59,134,106134,1,2,0:0:0:0: -226,0,106246,6,0,P|147:7|166:85,1,179.999994506836,6|2,3:2|0:0,0:0:0:0: -323,209,106690,2,0,P|335:135|308:100,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -166,85,106912,2,0,P|212:141|196:253,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: -42,125,107246,1,0,0:0:0:0: -20,228,107357,6,0,B|112:200,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -225,148,107579,2,0,P|167:90|160:63,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -176,305,107801,2,0,P|199:266|236:241,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -106,201,108023,1,0,3:2:0:0: -323,179,108246,6,0,L|326:85,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -426,19,108468,2,0,L|423:113,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -371,297,108690,1,2,0:0:0:0: -427,211,108801,1,0,0:0:0:0: -508,272,108912,1,0,3:2:0:0: -302,358,109134,6,0,P|289:263|310:248,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: -169,263,109357,2,0,P|234:186|250:188,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: -418,133,109579,1,2,0:0:0:0: -326,187,109690,1,0,0:0:0:0: -264,99,109801,6,0,P|195:40|115:102,1,179.999994506836,0|2,3:2|0:0,0:0:0:0: -0,243,110134,1,0,0:0:0:0: -0,243,110246,6,0,P|59:195|58:154,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -203,40,110468,2,0,P|153:164|178:208,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: -146,374,110801,1,0,0:0:0:0: -146,374,110912,6,0,P|116:307|85:298,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -271,133,111134,2,0,P|216:237|233:296,1,179.999994506836,10|2,0:0|0:0,0:0:0:0: -398,293,111468,1,0,0:0:0:0: -402,194,111579,6,0,L|309:233,1,89.9999972534181,0|0,3:2|0:0,0:0:0:0: -153,116,111801,2,0,P|175:203|198:209,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -436,63,112023,2,0,L|258:138,1,179.999994506836,10|2,0:0|0:0,0:0:0:0: -301,18,112357,1,2,0:0:0:0: -301,18,112468,1,2,3:2:0:0: -153,116,112690,6,0,P|131:69|147:30,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: -335,186,112912,2,0,P|291:137|238:139,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: -197,215,113134,1,2,0:0:0:0: -197,215,113357,1,0,3:2:0:0: -246,30,113579,6,0,B|286:49|286:49|334:14,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -487,128,113801,2,0,B|447:147|447:147|399:112,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -307,215,114023,1,2,0:0:0:0: -307,215,114246,1,0,3:2:0:0: -306,214,114468,6,0,P|286:254|300:295,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: -420,354,114690,2,0,P|430:310|411:271,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: -232,153,114912,2,0,P|184:262|212:331,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: -232,153,115357,6,0,P|257:66|229:42,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -134,49,115579,2,0,P|106:104|129:146,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -379,208,115801,2,0,P|284:139|210:168,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: -291,331,116246,6,0,P|263:280|254:311,1,89.9999972534181,8|0,1:2|0:0,0:0:0:0: -98,122,116468,2,0,P|107:201|135:220,1,89.9999972534181,8|0,1:2|0:0,0:0:0:0: -303,183,116690,2,0,P|227:190|210:207,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -120,366,116912,6,0,P|145:255|12:288,1,269.999991760254,2|0,3:2|0:0,0:0:0:0: -24,257,117357,6,0,P|67:246|99:215,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -171,32,117579,2,0,B|136:90|150:180|246:133|269:227|205:313,1,269.999991760254,2|0,0:0|0:0,0:0:0:0: -228,273,118023,6,0,P|231:197|256:178,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -341,196,118246,2,0,P|360:235|349:278,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -211,45,118468,5,2,0:0:0:0: -283,109,118579,1,0,0:0:0:0: -349,39,118690,2,0,P|429:21|452:48,1,89.9999972534181,0|0,3:2|0:0,0:0:0:0: -512,138,118912,2,0,P|432:156|409:129,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -305,379,119134,6,0,P|285:270|329:203,1,179.999994506836,10|2,0:0|0:0,0:0:0:0: -145,89,119468,1,2,0:0:0:0: -236,33,119579,2,0,P|251:110|236:133,1,89.9999972534181,0|0,3:2|0:0,0:0:0:0: -98,245,119801,2,0,P|146:221|203:239,1,89.9999972534181,10|2,1:2|0:0,0:0:0:0: -357,302,120023,1,10,1:2:0:0: -317,213,120134,1,2,0:0:0:0: -379,134,120246,1,2,0:0:0:0: -475,159,120357,1,2,0:0:0:0: -412,227,120468,5,4,3:2:0:0: -507,0,120690,2,0,P|435:60|399:38,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -205,127,120912,2,0,P|202:45|236:13,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -317,15,121134,2,0,P|339:136|311:198,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: -211,253,121468,1,0,0:0:0:0: -211,253,121579,6,0,L|89:246,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -117,78,121801,2,0,L|239:71,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -319,185,122023,2,0,P|271:285|294:349,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: -511,320,122357,1,0,0:0:0:0: -436,249,122468,6,0,P|389:261|393:314,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -312,102,122690,2,0,P|304:160|337:201,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -411,384,122912,2,0,P|288:314|219:351,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: -120,232,123246,1,0,0:0:0:0: -120,232,123357,6,0,B|86:259|86:259|134:278,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: -185,60,123579,2,0,B|219:87|219:87|171:106,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: -0,305,123801,2,0,P|-9:235|25:201,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -175,104,124023,6,0,B|127:105|92:141|92:141|60:100|-7:103,1,179.999994506836,0|2,3:2|0:0,0:0:0:0: -206,283,124357,1,0,0:0:0:0: -206,283,124468,2,0,L|164:180,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -288,193,124690,2,0,L|309:88,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -358,14,124912,6,0,P|459:38|428:140,1,179.999994506836,0|2,3:2|0:0,0:0:0:0: -363,246,125246,1,0,0:0:0:0: -288,193,125357,2,0,P|366:153|402:176,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -477,281,125579,2,0,L|452:401,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -224,50,125801,2,0,P|291:186|234:240,1,179.999994506836,2|2,3:2|0:0,0:0:0:0: -216,266,126134,1,0,0:0:0:0: -261,353,126246,1,8,0:0:0:0: -158,188,126468,5,2,0:0:0:0: -105,268,126579,1,2,0:0:0:0: -147,355,126690,2,0,L|278:362,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: -305,270,126912,2,0,L|174:263,1,89.9999972534181,10|0,1:2|0:0,0:0:0:0: -71,77,127134,2,0,P|39:189|74:189,1,179.999994506836,10|2,1:2|0:0,0:0:0:0: -145,172,127468,1,0,0:0:0:0: -105,268,127579,1,0,3:2:0:0: -167,76,127801,6,0,P|229:145|221:176,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -210,346,128023,2,0,P|218:262|235:253,1,89.9999972534181,10|0,0:0|0:0,0:0:0:0: -493,209,128246,2,0,B|443:201|443:201|379:219|379:219|279:209,1,179.999994506836,2|0,0:0|3:2,0:0:0:0: -404,107,128690,6,0,P|464:91|472:123,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -332,362,128912,2,0,B|373:282|373:282|302:196,1,179.999994506836,10|2,0:0|0:0,0:0:0:0: -118,206,129246,1,0,0:0:0:0: -185,135,129357,6,0,L|217:245,1,89.9999972534181,2|0,3:2|0:0,0:0:0:0: -381,119,129579,2,0,P|299:97|280:105,1,89.9999972534181,2|0,0:0|0:0,0:0:0:0: -130,56,129801,6,0,P|90:145|95:157,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: -363,274,130023,2,0,P|303:207|264:212,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -121,364,130246,5,2,3:2:0:0: -199,178,130468,1,0,0:0:0:0: -71,243,130690,2,0,B|159:307|137:227|247:303,1,180,10|0,0:0|0:0,0:0:0:0: -350,384,131134,6,0,P|347:313|381:284,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -512,189,131357,1,0,0:0:0:0: -418,145,131468,2,0,P|430:183|419:222,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -258,98,131690,1,0,0:0:0:0: -322,184,131801,1,2,3:2:0:0: -259,270,131912,1,0,0:0:0:0: -197,184,132023,5,10,1:2:0:0: -400,134,132468,6,0,P|409:205|391:227,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -110,214,132690,2,0,P|101:143|119:121,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -259,270,132912,5,2,0:0:0:0: -196,53,133134,1,0,3:2:0:0: -196,53,133246,2,0,B|182:90|182:90|208:156,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -318,51,133468,1,0,3:2:0:0: -318,51,133580,2,0,B|332:88|332:88|306:154,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -259,270,133801,1,10,1:2:0:0: -259,270,134246,6,0,B|243:311|243:311|263:367,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -45,203,134468,1,2,3:2:0:0: -78,202,134579,1,0,3:2:0:0: -166,251,134690,6,0,B|182:210|182:210|162:154,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -85,27,134912,2,0,B|72:63|72:63|88:104,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -0,226,135134,6,0,B|32:220|32:220|45:210|45:210|86:201,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -266,92,135357,2,0,B|234:86|234:86|221:76|221:76|180:67,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -130,373,135579,1,10,1:2:0:0: -108,310,135690,1,0,0:0:0:0: -159,262,135801,1,2,3:2:0:0: -250,304,135912,1,0,0:0:0:0: -341,248,136023,6,0,P|321:161|293:158,1,82.5000025177003,2|0,0:0|3:2,0:0:0:0: -442,119,136246,2,0,P|401:63|358:55,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -250,21,136468,6,0,L|257:136,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -107,212,136690,1,0,0:0:0:0: -23,181,136801,2,0,P|69:125|175:156,1,165.000005035401,2|0,3:2|0:0,0:0:0:0: -229,189,137134,1,2,3:2:0:0: -224,287,137246,1,0,0:0:0:0: -220,384,137357,1,10,1:2:0:0: -220,384,137579,6,0,P|282:346|321:363,1,82.5000025177003,0|0,3:2|0:0,0:0:0:0: -505,241,137801,1,2,3:2:0:0: -442,269,137912,1,0,3:2:0:0: -382,242,138023,1,0,3:2:0:0: -307,183,138134,1,0,3:2:0:0: -222,224,138246,6,0,B|121:224|174:283|58:275,1,165.000005035401,2|0,3:2|0:0,0:0:0:0: -71,171,138579,2,0,B|164:167|132:223|221:223,1,165.000005035401,2|0,3:2|0:0,0:0:0:0: -343,94,138912,2,0,L|250:94,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -134,26,139134,1,10,1:2:0:0: -134,26,139357,5,2,0:0:0:0: -104,77,139468,1,2,0:0:0:0: -129,129,139579,1,2,0:0:0:0: -188,207,139690,1,2,0:0:0:0: -114,291,139801,2,0,P|94:232|106:204,1,82.5000025177003,2|2,0:0|0:0,0:0:0:0: -216,85,140023,6,0,L|315:85,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -432,90,140246,1,0,3:2:0:0: -347,152,140357,2,0,B|310:78|310:78|374:-13,1,165.000005035401,2|0,0:0|3:2,0:0:0:0: -512,253,140690,1,2,0:0:0:0: -441,179,140801,1,0,0:0:0:0: -376,255,140912,1,10,1:2:0:0: -376,255,141357,6,0,P|391:303|372:346,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -245,219,141579,2,0,P|236:179|251:141,1,82.5000025177003,2|0,3:2|3:2,0:0:0:0: -179,302,141801,2,0,P|141:229|145:204,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -368,164,142023,5,2,3:2:0:0: -342,166,142134,1,0,0:0:0:0: -177,98,142246,2,0,L|295:88,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -341,0,142468,2,0,P|365:64|341:94,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -245,219,142690,1,10,1:2:0:0: -461,112,142912,5,2,3:2:0:0: -461,112,143023,2,0,P|451:180|470:205,1,82.5000025177003,2|2,0:0|0:0,0:0:0:0: -368,371,143246,2,0,P|377:331|362:294,1,82.5000025177003,0|0,3:2|0:0,0:0:0:0: -192,166,143468,2,0,B|244:218|244:218|299:189|360:191,1,165.000005035401,2|0,3:2|0:0,0:0:0:0: -315,32,143801,2,0,P|282:53|279:106,1,82.5000025177003,0|0,3:2|0:0,0:0:0:0: -268,351,144023,5,2,0:0:0:0: -282,287,144134,1,0,0:0:0:0: -230,251,144246,1,2,3:2:0:0: -138,305,144357,1,0,0:0:0:0: -59,249,144468,2,0,P|44:207|61:168,1,82.5000025177003,10|2,1:2|0:0,0:0:0:0: -144,128,144690,2,0,P|159:170|142:209,1,82.5000025177003,2|2,3:2|0:0,0:0:0:0: -18,81,144912,5,2,3:2:0:0: -69,1,145023,1,2,3:2:0:0: -172,11,145134,1,2,3:2:0:0: -231,98,145246,1,2,3:2:0:0: -303,28,145357,6,0,P|335:2|375:0,1,82.5000025177003,6|0,3:2|0:0,0:0:0:0: -384,220,145579,1,2,0:0:0:0: -285,192,145690,2,0,P|301:154|337:135,1,82.5000025177003,0|10,0:0|0:0,0:0:0:0: -507,85,145912,2,0,P|459:98|453:40,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -509,243,146134,1,2,0:0:0:0: -509,243,146246,2,0,P|453:200|415:220,1,82.5000025177003,0|0,3:2|0:0,0:0:0:0: -270,374,146468,6,0,L|289:281,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -168,143,146690,2,0,L|187:236,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: -401,283,146912,2,0,P|370:216|337:203,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -50,214,147134,6,0,P|130:259|186:220,1,165.000005035401,2|2,3:2|0:3,0:0:0:0: -306,64,147468,1,0,0:0:0:0: -204,48,147579,2,0,L|226:154,2,82.5000025177003,10|2|0,0:0|0:0|0:0,0:0:0:0: -360,154,147912,2,0,B|321:223|321:223|351:257|345:323,1,165.000005035401,2|0,0:0|0:0,0:0:0:0: -208,368,148246,6,0,P|205:321|242:322,1,82.5000025177003,10|0,1:2|0:0,0:0:0:0: -106,264,148468,2,0,P|180:216|220:225,1,82.5000025177003,10|0,1:2|0:0,0:0:0:0: -399,200,148690,2,0,P|310:219|283:201,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -126,128,148912,6,0,P|223:144|235:175,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -249,36,149134,2,0,P|299:87|299:131,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -388,280,149357,6,0,P|429:274|460:249,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: -390,178,149579,2,0,P|412:144|412:104,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -272,286,149801,6,0,B|292:320|292:320|271:386,1,82.5000025177003,2|0,3:2|0:0,0:0:0:0: -161,270,150023,2,0,B|147:228|147:228|167:194,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -390,178,150246,6,0,L|279:188,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: -55,95,150468,1,2,0:0:0:0: -20,98,150579,1,0,0:0:0:0: -119,18,150690,2,0,P|210:28|208:130,1,165.000005035401,0|2,3:2|0:0,0:0:0:0: -68,214,151023,1,0,0:0:0:0: -170,229,151134,6,0,L|144:137,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: -263,286,151357,2,0,L|240:365,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -94,322,151579,1,2,3:2:0:0: -394,216,151801,1,8,1:2:0:0: -370,57,152023,6,0,P|256:62|299:199,1,247.500007553101,10|0,1:2|0:0,0:0:0:0: -317,120,152468,6,0,B|213:98|254:179|118:129,1,165.000005035401,2|0,3:2|0:0,0:0:0:0: -8,52,152912,6,0,B|15:12|15:12|52:58,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: -317,120,153134,2,0,B|213:98|254:179|118:129,1,165.000005035401,2|0,0:0|3:2,0:0:0:0: -71,190,153579,5,2,0:0:0:0: -38,191,153690,1,0,0:0:0:0: -158,141,153801,2,0,P|171:212|142:247,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: -93,372,154023,2,0,P|80:301|109:266,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -255,62,154246,6,0,P|296:144|264:245,1,165.000005035401,2|2,3:2|0:3,0:0:0:0: -202,347,154690,6,0,B|170:324|170:324|216:315,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: -255,62,154912,2,0,P|296:144|264:245,1,165.000005035401,2|0,0:0|3:2,0:0:0:0: -488,313,155357,5,2,0:0:0:0: -454,314,155468,1,0,0:0:0:0: -367,355,155579,2,0,P|355:297|373:269,1,82.5000025177003,10|0,0:0|0:0,0:0:0:0: -503,146,155801,2,0,P|465:192|425:193,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -220,123,156023,6,0,B|288:121|341:175|341:175|303:177|278:218,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: -111,158,156357,2,0,B|75:99|95:26|95:26|116:58|164:59,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: -186,229,156690,2,0,B|173:263|137:278|137:278|143:259|127:239,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -220,123,156912,5,2,0:0:0:0: -186,229,157060,1,2,0:0:0:0: -111,158,157209,1,2,0:0:0:0: -288,199,157357,5,2,0:0:0:0: -94,258,157505,1,2,0:0:0:0: -144,56,157653,1,2,0:0:0:0: -150,383,157801,6,0,P|192:314|249:328,1,134.999995880127,6|2,3:2|0:0,0:0:0:0: -359,145,158246,1,2,0:0:0:0: -270,182,158468,2,0,P|330:249|412:225,1,134.999995880127,2|8,3:2|0:0,0:0:0:0: -359,145,158912,1,2,0:0:0:0: -236,319,159134,1,2,0:0:0:0: -460,160,159357,1,2,0:0:0:0: -233,22,159579,6,0,B|218:118|280:81|268:192,2,168.750006437302,0|0|2,3:2|3:2|3:2,0:0:0:0: -454,29,160468,2,0,P|363:52|339:6,1,134.999995880127,8|2,0:0|0:0,0:0:0:0: -173,216,160912,1,2,0:0:0:0: -433,204,161134,1,2,3:2:0:0: -433,204,161246,1,0,3:2:0:0: -433,204,161357,6,0,B|380:169|363:120|363:120|318:175|246:185,1,225.000008583069,2|0,3:2|0:0,0:0:0:0: -268,79,162023,1,2,3:2:0:0: -344,362,162246,2,0,P|330:283|279:298,1,134.999995880127,10|2,0:0|0:0,0:0:0:0: -159,224,162690,1,2,0:0:0:0: -316,154,162912,1,2,0:0:0:0: -213,21,163134,6,0,P|174:99|217:83,2,202.499993820191,0|0|2,3:2|3:2|3:2,0:0:0:0: -337,271,164023,2,0,P|332:183|278:170,1,134.999995880127,10|2,0:0|0:0,0:0:0:0: -99,334,164468,1,8,3:0:0:0: -133,332,164579,1,8,3:0:0:0: -166,329,164690,1,2,3:2:0:0: -200,326,164801,1,0,3:2:0:0: -234,251,164912,6,0,P|161:221|133:296,1,134.999995880127,2|0,3:2|0:0,0:0:0:0: -67,174,165357,1,2,0:0:0:0: -234,251,165579,2,0,P|224:132|257:102,1,134.999995880127,2|8,3:2|0:0,0:0:0:0: -391,159,166023,6,0,L|292:169,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -253,28,166246,2,0,P|307:88|298:107,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -209,188,166468,2,0,P|215:140|241:119,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -444,248,166690,6,0,B|365:259|365:259|363:268|363:268|273:278,2,168.750006437302,0|0|2,3:2|3:2|3:2,0:0:0:0: -216,360,167579,1,10,0:0:0:0: -177,264,167801,1,2,0:0:0:0: -312,162,168023,1,2,0:0:0:0: -266,190,168134,1,0,0:0:0:0: -218,166,168245,1,2,3:2:0:0: -213,112,168356,1,0,3:2:0:0: -287,65,168468,6,0,P|209:115|167:19,1,225.000008583069,2|0,3:2|0:0,0:0:0:0: -0,205,169134,1,2,3:2:0:0: -54,125,169357,2,0,P|96:193|81:231,1,112.500004291535,10|2,0:0|0:0,0:0:0:0: -254,281,169801,1,2,0:0:0:0: -192,190,170023,1,2,0:0:0:0: -0,355,170246,6,0,B|101:354|39:279|186:296,2,168.750006437302,0|0|0,3:2|3:2|3:2,0:0:0:0: -0,355,171134,1,8,0:0:0:0: -219,363,171357,1,2,0:0:0:0: -120,195,171579,5,8,3:0:0:0: -153,196,171690,1,8,3:0:0:0: -187,198,171801,1,2,3:2:0:0: -221,200,171912,1,0,3:2:0:0: -297,155,172023,6,0,B|270:200|270:200|293:311,1,134.999995880127,4|2,3:2|0:0,0:0:0:0: -455,238,172357,1,0,0:0:0:0: -455,238,172468,2,0,L|338:221,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: -307,52,172690,6,0,P|384:74|380:168,1,134.999995880127,2|0,0:0|3:2,0:0:0:0: -182,98,173134,2,0,L|163:-8,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -281,162,173357,2,0,L|269:228,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: -45,296,173579,1,2,0:0:0:0: -45,296,173690,1,0,0:0:0:0: -45,296,173801,6,0,P|130:221|171:258,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: -222,366,174134,1,0,0:0:0:0: -222,366,174246,2,0,P|197:314|208:285,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: -287,253,174468,2,0,P|314:209|353:204,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -506,116,174690,6,0,B|447:141|447:141|420:105|345:102,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: -229,72,175023,1,0,0:0:0:0: -229,72,175134,2,0,L|247:155,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: -312,269,175357,2,0,L|330:186,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -146,16,175579,6,0,P|127:120|174:161,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: -248,229,175912,1,0,0:0:0:0: -248,229,176023,2,0,L|144:219,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: -36,384,176246,1,2,0:0:0:0: -20,335,176357,1,0,0:0:0:0: -64,300,176468,6,0,B|118:308|118:308|142:328|142:328|238:346,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: -298,384,176801,1,0,0:0:0:0: -298,384,176912,2,0,B|286:345|286:345|313:304,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: -423,236,177134,2,0,B|435:275|435:275|420:297,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -217,241,177357,5,2,3:2:0:0: -300,31,177579,1,2,0:0:0:0: -343,86,177690,1,0,0:0:0:0: -314,148,177801,1,0,3:2:0:0: -83,79,178023,1,2,0:0:0:0: -83,79,178134,1,0,0:0:0:0: -83,79,178246,6,0,B|144:115|144:115|248:86,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: -337,20,178579,1,0,0:0:0:0: -337,20,178690,2,0,L|315:98,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: -214,239,178912,2,0,P|262:196|282:201,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -435,127,179134,6,0,B|392:193|392:193|423:282,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: -475,356,179468,1,0,0:0:0:0: -475,356,179579,2,0,L|515:281,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: -278,168,179801,2,0,L|310:261,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -351,348,180023,6,0,B|256:331|314:385|179:357,1,134.999995880127,0|2,3:2|0:0,0:0:0:0: -104,353,180357,1,0,0:0:0:0: -104,353,180468,2,0,L|155:278,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: -0,219,180690,2,0,L|74:294,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -245,273,180912,6,0,P|204:201|163:200,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: -352,194,181134,2,0,P|297:126|268:128,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -37,82,181357,2,0,P|74:136|85:139,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: -188,19,181579,2,0,P|169:93|177:115,1,67.4999979400635,2|0,0:0|0:0,0:0:0:0: -342,220,181801,5,2,3:2:0:0: -268,81,182023,1,2,0:0:0:0: -158,195,182246,1,2,0:0:0:0: -309,231,182690,6,0,P|290:300|302:320,1,67.4999979400635,6|0,3:1|0:0,0:0:0:0: -388,302,182912,2,0,P|378:341|397:377,1,82.5000025177003,10|0,3:2|0:0,0:0:0:0: -490,52,183134,6,0,P|509:121|497:141,1,67.4999979400635,2|0,3:2|0:0,0:0:0:0: -414,120,183357,2,0,P|423:159|405:194,1,82.5000025177003,10|0,3:2|0:0,0:0:0:0: -269,0,183579,5,2,3:2:0:0: -320,15,183690,1,0,3:2:0:0: -340,64,183801,1,2,3:2:0:0: -311,124,183912,1,0,3:2:0:0: -225,160,184023,1,2,3:2:0:0: -160,95,184134,1,0,3:2:0:0: -79,145,184246,6,0,B|51:288|151:224|132:390,1,247.500007553101,6|0,3:1|0:0,0:0:0:0: -133,376,184690,1,2,3:2:0:0: -169,151,184912,6,0,B|138:293|71:195|24:355,1,255.000004863739,2|0,3:2|0:0,0:0:0:0: -26,350,185357,6,2,P|85:330|100:329,1,78.7499975967408,2|0,0:0|0:0,0:0:0:0: -205,384,186246,6,0,P|209:280|316:280,1,194.999991073609,6|2,3:2|0:0,0:0:0:0: -410,99,186579,1,0,0:0:0:0: -471,176,186690,2,0,P|405:200|366:187,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -242,64,186912,2,0,P|287:118|279:174,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -283,261,187134,6,0,B|168:256|219:328|88:321,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -112,217,187468,1,0,0:0:0:0: -112,217,187579,2,0,P|115:157|45:187,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -0,293,187801,2,0,L|38:394,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -220,151,188023,6,0,P|151:47|55:48,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -198,286,188357,1,0,0:0:0:0: -198,286,188468,2,0,P|120:246|81:262,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -328,384,188690,2,0,P|316:307|345:274,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -506,165,188912,6,0,B|412:205|412:205|376:177|313:173,1,194.999991073609,0|10,3:2|1:2,0:0:0:0: -136,81,189246,1,0,0:0:0:0: -219,40,189357,2,0,B|253:72|253:72|265:20,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -333,253,189579,2,0,B|321:203|321:203|287:235,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -78,253,189801,6,0,B|130:342|170:284|216:384,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -245,161,190134,1,0,0:0:0:0: -245,161,190246,2,0,P|196:216|158:210,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -11,128,190468,2,0,P|92:136|110:176,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -55,345,190690,6,0,B|164:350|137:295|272:323,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -405,194,191023,1,0,0:0:0:0: -405,194,191134,2,0,P|361:268|371:302,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -498,363,191357,2,0,P|475:287|487:271,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -468,72,191579,6,0,P|411:134|277:107,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -101,81,191912,1,0,0:0:0:0: -182,24,192023,2,0,L|204:144,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -302,384,192246,1,2,0:0:0:0: -355,305,192357,1,2,0:0:0:0: -281,239,192468,2,0,P|228:226|184:273,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -18,347,192690,6,0,B|15:372|15:372|87:314,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -89,106,192912,2,0,B|71:88|71:88|72:180,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -252,287,193134,2,0,B|276:280|276:280|195:235,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -111,244,193357,1,0,3:2:0:0: -215,37,193579,6,0,P|207:136|219:148,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -371,126,193801,2,0,P|379:78|356:36,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -282,276,194023,1,2,0:0:0:0: -282,276,194246,1,0,3:2:0:0: -239,195,194468,6,0,B|280:174|280:174|355:201,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -508,248,194690,2,0,B|459:265|459:265|418:244,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -334,56,194912,2,0,P|399:57|460:179,1,194.999991073609,2|0,0:0|3:2,0:0:0:0: -316,273,195357,6,0,P|334:188|363:187,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -253,92,195579,2,0,P|318:52|346:60,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -418,244,195801,2,0,B|299:221|358:308|183:270,1,194.999991073609,2|0,0:0|3:2,0:0:0:0: -96,93,196246,6,0,P|153:126|137:194,1,97.4999955368044,8|0,1:2|0:0,0:0:0:0: -36,291,196468,2,0,B|18:239|18:239|60:184,1,97.4999955368044,8|0,1:2|0:0,0:0:0:0: -316,108,196690,2,0,L|230:227,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -158,342,196912,6,0,B|175:373|214:367|214:367|215:374|215:374|214:367|214:367|246:362|265:336|265:336|286:310|318:301|318:301|318:295|318:295|318:301|318:301|386:305|389:362,1,292.499986610413,2|0,3:2|0:0,0:0:0:0: -381,332,197357,6,0,P|381:252|411:230,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -512,116,197579,2,0,B|495:147|456:141|456:141|455:148|455:148|456:141|456:141|424:136|405:110|405:110|384:84|352:75|352:75|352:69|352:69|352:75|352:75|284:79|272:131,1,292.499986610413,2|0,0:0|0:0,0:0:0:0: -285,102,198023,6,0,P|312:180|272:225,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -139,368,198246,2,0,P|134:320|162:281,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -202,186,198468,5,2,0:0:0:0: -116,180,198579,1,0,0:0:0:0: -60,113,198690,2,0,P|141:92|164:124,1,97.4999955368044,0|0,3:2|0:0,0:0:0:0: -259,291,198912,2,0,L|162:280,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -187,7,199134,6,0,P|257:107|215:171,1,194.999991073609,10|2,0:0|0:0,0:0:0:0: -72,342,199468,1,2,0:0:0:0: -0,282,199579,2,0,P|81:247|110:277,1,97.4999955368044,0|0,3:2|0:0,0:0:0:0: -173,337,199801,2,0,P|229:363|267:339,1,97.4999955368044,10|2,1:2|0:0,0:0:0:0: -494,181,200023,1,10,1:2:0:0: -402,122,200134,1,2,0:0:0:0: -323,194,200246,1,2,0:0:0:0: -371,288,200357,1,2,0:0:0:0: -414,207,200468,6,0,B|280:178|340:289|201:251,1,194.999991073609,4|2,3:2|0:0,0:0:0:0: -132,162,200801,1,0,0:0:0:0: -132,162,200912,2,0,B|146:118|146:118|196:163,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -236,258,201134,2,0,L|219:366,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -58,251,201357,6,0,P|9:125|49:76,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -190,71,201690,1,0,0:0:0:0: -229,171,201801,2,0,L|108:159,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -63,335,202023,2,0,P|142:294|162:315,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -408,277,202246,6,0,B|354:286|319:240|319:240|294:290|202:297,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -213,85,202579,1,0,0:0:0:0: -213,85,202690,2,0,P|236:158|201:190,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -49,312,202912,1,2,0:0:0:0: -24,224,203023,1,0,0:0:0:0: -122,233,203134,6,0,P|208:291|149:395,1,194.999991073609,0|10,3:2|1:2,0:0:0:0: -146,71,203468,1,0,0:0:0:0: -146,71,203579,2,0,P|196:120|196:163,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -307,98,203801,2,0,P|297:208|287:220,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -148,315,204023,6,0,B|228:306|228:306|270:322|270:322|373:308,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -481,270,204357,1,0,0:0:0:0: -481,270,204468,2,0,B|517:310|517:310|466:356,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -374,187,204690,2,0,L|451:101,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -246,22,204912,6,0,P|208:145|273:199,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -284,353,205246,1,0,0:0:0:0: -377,329,205357,2,0,P|327:270|268:270,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -140,351,205579,2,0,P|187:328|197:278,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -71,229,205801,5,2,3:2:0:0: -284,353,206023,1,2,0:0:0:0: -310,265,206134,1,0,0:0:0:0: -270,189,206246,2,0,L|153:191,1,97.4999955368044,8|0,0:0|0:0,0:0:0:0: -0,130,206468,1,2,0:0:0:0: -21,49,206579,1,2,0:0:0:0: -108,42,206690,6,0,P|190:129|154:209,1,194.999991073609,2|10,3:2|1:2,0:0:0:0: -20,323,207023,1,0,0:0:0:0: -20,323,207134,2,0,P|93:284|124:294,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -251,384,207357,2,0,P|232:302|257:278,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -480,209,207579,6,0,B|370:251|370:251|335:217|279:208,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -130,123,207912,1,0,0:0:0:0: -130,123,208023,2,0,P|204:170|211:144,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -368,138,208246,2,0,P|284:112|264:122,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -133,360,208468,6,0,P|222:286|302:323,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -442,306,208801,1,0,0:0:0:0: -442,306,208912,2,0,P|389:391|391:399,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -512,182,209134,2,0,P|421:189|393:166,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -275,16,209357,6,0,B|325:101|322:148|322:148|286:221,1,194.999991073609,2|2,3:2|0:0,0:0:0:0: -141,195,209690,1,0,0:0:0:0: -141,195,209801,2,0,P|196:134|218:148,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -55,267,210023,2,0,P|30:180|46:160,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -223,260,210246,6,0,L|212:373,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -327,210,210468,2,0,L|316:323,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -104,111,210690,6,0,P|142:186|125:229,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -253,11,210912,2,0,P|263:54|207:107,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -29,278,211134,6,0,P|146:261|263:261,1,194.999991073609,2|2,3:2|0:0,0:0:0:0: -399,188,211468,1,0,0:0:0:0: -399,188,211579,2,0,P|317:170|261:169,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -316,367,211801,2,0,P|331:289|327:261,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -191,159,212023,5,2,3:2:0:0: -384,83,212246,1,0,0:0:0:0: -384,83,212357,1,2,0:0:0:0: -256,0,212579,1,0,0:0:0:0: -256,0,212690,2,0,P|273:82|276:107,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -370,188,212912,6,0,P|340:300|337:385,1,194.999991073609,2|2,3:2|0:0,0:0:0:0: -111,169,213246,1,0,0:0:0:0: -111,169,213357,2,0,P|139:261|141:294,1,97.4999955368044,10|0,0:0|0:0,0:0:0:0: -254,288,213579,2,0,P|235:333|225:380,1,97.4999955368044,2|2,0:0|0:0,0:0:0:0: -36,223,213801,5,2,3:2:0:0: -2,171,213912,1,0,0:0:0:0: -19,113,214023,1,10,1:2:0:0: -92,47,214134,1,2,0:0:0:0: -189,76,214246,1,10,1:2:0:0: -205,179,214357,1,2,0:0:0:0: -305,229,214468,1,2,0:0:0:0: -395,167,214579,1,2,0:0:0:0: -306,121,214690,5,0,3:2:0:0: -306,149,215134,5,10,3:2:0:0: -302,179,215579,5,0,3:2:0:0: -299,214,216023,5,10,3:2:0:0: -295,261,216468,5,2,3:2:0:0: -206,318,216690,1,2,0:3:0:0: -128,248,216912,1,10,0:0:0:0: -177,139,217134,1,2,0:3:0:0: -289,164,217357,1,2,3:2:0:0: -358,74,217579,1,2,0:0:0:0: -243,22,217801,6,0,B|202:147|303:106|250:272,1,225,2|0,0:0|0:0,0:0:0:0: -99,350,218246,6,0,P|168:328|194:337,1,97.4999955368044,6|0,3:2|0:0,0:0:0:0: -316,338,218468,2,0,P|240:364|173:303,1,142.49999619484,2|8,0:0|0:2,0:0:0:0: -188,186,218912,6,0,P|239:202|256:270,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -77,265,219134,2,0,P|60:150|116:103,1,142.49999619484,2|0,3:2|0:0,0:0:0:0: -204,44,219468,1,0,0:0:0:0: -204,44,219579,6,0,P|137:13|129:-2,1,71.2499980974198,10|0,0:2|0:0,0:0:0:0: -272,136,219801,2,0,P|197:164|159:145,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -345,38,220023,2,0,P|456:12|474:33,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -293,246,220246,2,0,P|276:181|290:143,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -454,119,220468,6,0,P|416:246|453:303,1,194.999991073609,10|0,0:2|0:0,0:0:0:0: -267,384,220801,1,0,0:0:0:0: -330,303,220912,6,0,P|268:269|245:302,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -122,252,221134,2,0,P|79:333|84:345,1,71.2499980974198,10|0,1:2|0:0,0:0:0:0: -358,189,221357,6,0,P|289:168|250:180,1,71.2499980974198,10|0,1:2|0:0,0:0:0:0: -122,252,221579,2,0,L|152:398,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: -180,89,221801,6,0,B|55:104|133:146|-49:161,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: -2,52,222134,2,0,B|117:58|67:119|182:118,1,194.999991073609,2|0,0:0|0:0,0:0:0:0: -310,3,222468,2,0,B|347:42|347:42|311:75,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -86,282,222690,2,0,B|155:215|155:215|265:257,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -390,135,223023,1,0,0:0:0:0: -390,135,223134,2,0,L|412:260,1,82.5000025177003,10|0,1:2|0:0,0:0:0:0: -503,302,223357,2,0,L|488:383,1,82.5000025177003,2|0,0:0|0:0,0:0:0:0: -272,306,223579,6,0,P|347:207|430:235,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: -368,309,223912,2,0,P|296:207|218:210,1,194.999991073609,2|0,0:0|0:0,0:0:0:0: -131,384,224246,2,0,P|129:313|161:289,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -95,94,224468,2,0,P|116:171|94:194,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -18,376,224690,6,0,P|67:273|120:290,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -221,91,224912,2,0,P|210:34|162:-4,1,112.500004291535,10|0,1:2|0:0,0:0:0:0: -0,195,225134,2,0,P|77:180|169:186,1,112.500004291535 -225,279,225357,6,0,L|251:375,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -303,187,225579,2,0,P|331:252|280:327,1,142.49999619484,2|8,0:0|1:2,0:0:0:0: -7,167,226023,6,0,P|67:123|100:129,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -256,71,226246,2,0,P|176:51|142:-21,1,142.49999619484,2|0,3:2|0:0,0:0:0:0: -181,209,226579,1,0,0:0:0:0: -181,209,226690,6,0,P|138:285|147:304,1,71.2499980974198,10|0,1:2|0:0,0:0:0:0: -259,383,226912,2,0,P|246:302|267:274,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -479,317,227134,2,0,L|370:331,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -181,209,227357,2,0,P|247:154|298:163,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -510,38,227579,6,0,B|435:75|435:75|415:32|348:-2,1,194.999991073609,10|0,1:2|0:0,0:0:0:0: -254,153,227912,1,0,0:0:0:0: -327,97,228023,6,0,P|353:160|325:211,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -160,133,228246,2,0,P|215:57|261:66,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: -59,248,228468,6,0,P|24:161|35:136,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -210,274,228690,2,0,P|168:364|174:386,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: -124,143,228912,6,0,B|182:129|219:166|219:166|250:107|325:100,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: -436,260,229246,2,0,B|378:274|341:237|341:237|310:296|235:303,1,194.999991073609,2|0,0:0|0:0,0:0:0:0: -392,42,229579,2,0,P|429:107|421:134,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -164,360,229801,2,0,P|253:276|274:299,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -234,80,230134,1,0,0:0:0:0: -331,158,230246,6,0,B|287:165|287:165|280:174|280:174|220:186,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -114,95,230468,2,0,B|73:86|73:86|66:77|66:77|22:70,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -68,355,230690,6,0,B|21:369|21:369|49:289|49:289|43:276|43:276|82:198,1,225.000008583069,2|0,3:2|0:0,0:0:0:0: -194,44,231023,2,0,B|148:28|148:28|172:108|172:108|166:121|166:121|204:209,1,225.000008583069,2|0,0:0|0:0,0:0:0:0: -246,376,231357,2,0,P|233:337|148:343,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -351,144,231579,2,0,P|305:206|303:239,1,97.4999955368044,0|0,3:2|0:2,0:0:0:0: -439,384,231801,6,0,P|427:318|383:294,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -464,28,232023,2,0,P|503:54|512:100,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -404,300,232246,2,0,P|393:255|418:215,1,97.4999955368044,2|0,1:2|0:0,0:0:0:0: -219,236,232468,6,0,P|245:187|282:175,1,97.4999955368044,6|0,3:2|0:0,0:0:0:0: -342,39,232690,2,0,P|358:126|314:164,1,142.49999619484,2|8,0:0|0:2,0:0:0:0: -126,136,233134,6,0,P|190:83|210:85,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -443,238,233357,2,0,P|363:250|255:282,1,142.49999619484,2|0,3:2|0:0,0:0:0:0: -178,282,233690,1,0,0:0:0:0: -178,282,233801,6,0,P|185:369|208:375,1,71.2499980974198,10|0,0:2|0:0,0:0:0:0: -85,181,234023,2,0,P|34:263|43:289,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -347,157,234246,2,0,P|280:194|254:184,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -158,87,234468,2,0,P|75:66|44:90,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -242,11,234690,6,0,P|287:122|252:206,1,194.999991073609,10|0,0:2|0:0,0:0:0:0: -154,371,235023,1,0,0:0:0:0: -154,371,235134,6,0,P|117:291|126:259,1,71.2499980974198,2|0,3:2|0:0,0:0:0:0: -352,150,235357,2,0,P|320:185|316:233,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -214,285,235579,6,0,P|210:204|245:175,1,71.2499980974198,10|0,1:2|0:0,0:0:0:0: -437,116,235801,2,0,P|348:155|338:190,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -458,323,236023,6,0,P|505:256|425:239,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: -329,261,236357,2,0,B|306:302|302:337|302:337|268:296|268:296|236:340|236:340|236:304|194:256,1,269.999991760254,2|0,0:0|0:0,0:0:0:0: -35,273,236690,2,0,P|16:298|64:365,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -130,357,236912,2,0,P|154:313|61:197,1,194.999991073609,0|2,3:2|0:0,0:0:0:0: -21,56,237246,1,0,0:0:0:0: -21,56,237357,6,0,P|104:88|125:70,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -230,0,237579,2,0,B|205:109,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -44,226,237801,6,0,B|108:259|144:265|144:265|109:281|36:338,1,194.999991073609,2|0,3:2|0:0,0:0:0:0: -207,190,238134,2,0,B|237:225|248:259|248:259|273:212|273:212|313:249|313:249|306:214|338:159,1,269.999991760254,2|0,0:0|0:0,0:0:0:0: -501,143,238468,2,0,P|519:214|503:239,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -411,240,238690,2,0,P|407:151|450:116,1,97.4999955368044,0|2,3:2|0:2,0:0:0:0: -496,14,238912,6,0,P|426:55|385:38,1,97.4999955368044,10|0,1:2|0:0,0:0:0:0: -204,77,239134,2,0,P|222:19|292:49,1,134.999995880127,10|0,1:2|0:0,0:0:0:0: -299,259,239357,2,0,P|281:201|214:221,1,134.999995880127 -0,77,239579,6,0,P|76:52|94:33,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -89,177,239801,2,0,P|76:66|102:18,1,142.49999619484,2|8,0:0|1:2,0:0:0:0: -310,181,240246,6,0,P|234:156|216:137,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -36,338,240468,2,0,P|140:284|186:293,1,142.49999619484,2|0,3:2|0:0,0:0:0:0: -273,324,240801,1,0,0:0:0:0: -273,324,240912,6,0,P|246:408|251:417,1,71.2499980974198,10|0,1:2|0:0,0:0:0:0: -454,329,241134,2,0,P|420:267|444:198,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -270,208,241357,2,0,P|326:123|350:119,1,97.4999955368044,2|0,3:2|0:0,0:0:0:0: -512,65,241579,2,0,P|452:120|409:107,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -197,29,241801,6,0,P|317:88|299:155,1,194.999991073609,10|0,1:2|0:0,0:0:0:0: -122,235,242134,1,0,0:0:0:0: -223,265,242246,6,0,B|233:232|233:232|201:174,1,71.2499980974198,2|0,3:2|0:0,0:0:0:0: -97,19,242468,2,0,B|77:66|77:66|109:124,1,97.4999955368044,2|0,0:0|0:0,0:0:0:0: -314,127,242690,6,0,P|258:69|213:78,1,93.75,10|0,1:2|0:0,0:0:0:0: -14,268,242912,2,0,L|156:224,1,112.500004291535,2|0,0:0|0:0,0:0:0:0: -354,245,243134,5,2,0:0:0:0: -158,49,243468,1,2,0:0:0:0: -121,331,243801,1,2,0:0:0:0: -291,99,244246,5,2,0:0:0:0: -270,314,244469,1,2,0:0:0:0: -91,198,244691,1,2,0:0:0:0: -244,208,244912,5,2,0:0:0:0: -192,228,245246,1,2,0:0:0:0: -199,179,245579,1,2,0:0:0:0: diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513-expected-conversion.json b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513-expected-conversion.json deleted file mode 100644 index a7a2ba4e24c7..000000000000 --- a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513-expected-conversion.json +++ /dev/null @@ -1 +0,0 @@ -{"Mappings":[{"StartTime":14554.0,"Objects":[{"StartTime":14554.0,"EndTime":14554.0,"X":140.0,"Y":242.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":14776.0,"EndTime":14776.0,"X":159.385574,"Y":334.6728,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":14962.0,"EndTime":14962.0,"X":140.0,"Y":242.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":15146.0,"Objects":[{"StartTime":15146.0,"EndTime":15146.0,"X":98.0,"Y":147.0}]},{"StartTime":15220.0,"Objects":[{"StartTime":15220.0,"EndTime":15220.0,"X":90.0,"Y":162.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":15332.0,"EndTime":15332.0,"X":30.0399876,"Y":180.1521,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":15665.0,"Objects":[{"StartTime":15665.0,"EndTime":15665.0,"X":30.0,"Y":180.0}]},{"StartTime":15887.0,"Objects":[{"StartTime":15887.0,"EndTime":15887.0,"X":252.0,"Y":94.0}]},{"StartTime":16109.0,"Objects":[{"StartTime":16109.0,"EndTime":16109.0,"X":453.0,"Y":164.0}]},{"StartTime":18109.0,"Objects":[{"StartTime":18109.0,"EndTime":18109.0,"X":462.0,"Y":154.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18295.0,"EndTime":18295.0,"X":370.388947,"Y":94.52616,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18480.0,"Objects":[{"StartTime":18480.0,"EndTime":18480.0,"X":331.260864,"Y":20.2608681}]},{"StartTime":18554.0,"Objects":[{"StartTime":18554.0,"EndTime":18554.0,"X":335.0,"Y":24.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18666.0,"EndTime":18666.0,"X":258.2912,"Y":40.5695877,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":18776.0,"Objects":[{"StartTime":18776.0,"EndTime":18776.0,"X":168.0,"Y":119.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":18888.0,"EndTime":18888.0,"X":246.032837,"Y":126.069855,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19220.0,"Objects":[{"StartTime":19220.0,"EndTime":19220.0,"X":246.0,"Y":126.0}]},{"StartTime":19443.0,"Objects":[{"StartTime":19443.0,"EndTime":19443.0,"X":115.0,"Y":44.0}]},{"StartTime":19665.0,"Objects":[{"StartTime":19665.0,"EndTime":19665.0,"X":104.0,"Y":194.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":19777.0,"EndTime":19777.0,"X":120.877777,"Y":270.869843,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":19887.0,"Objects":[{"StartTime":19887.0,"EndTime":19887.0,"X":48.0,"Y":124.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20221.0,"EndTime":20221.0,"X":68.6317749,"Y":334.704071,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20331.0,"Objects":[{"StartTime":20331.0,"EndTime":20331.0,"X":153.0,"Y":346.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20443.0,"EndTime":20443.0,"X":246.364746,"Y":329.347076,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20554.0,"Objects":[{"StartTime":20554.0,"EndTime":20554.0,"X":246.0,"Y":329.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":20666.0,"EndTime":20666.0,"X":223.447632,"Y":245.661713,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":20776.0,"Objects":[{"StartTime":20776.0,"EndTime":20776.0,"X":226.739136,"Y":248.739136}]},{"StartTime":20924.0,"Objects":[{"StartTime":20924.0,"EndTime":20924.0,"X":351.260864,"Y":380.260864}]},{"StartTime":20998.0,"Objects":[{"StartTime":20998.0,"EndTime":20998.0,"X":355.0,"Y":384.0}]},{"StartTime":21220.0,"Objects":[{"StartTime":21220.0,"EndTime":21220.0,"X":505.0,"Y":303.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21554.0,"EndTime":21554.0,"X":390.768066,"Y":271.293854,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21665.0,"Objects":[{"StartTime":21665.0,"EndTime":21665.0,"X":375.0,"Y":269.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":21851.0,"EndTime":21851.0,"X":350.468628,"Y":379.1108,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":21998.0,"Objects":[{"StartTime":21998.0,"EndTime":21998.0,"X":309.0,"Y":215.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22184.0,"EndTime":22184.0,"X":226.02095,"Y":138.321442,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22331.0,"Objects":[{"StartTime":22331.0,"EndTime":22331.0,"X":389.0,"Y":184.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22443.0,"EndTime":22443.0,"X":463.616272,"Y":174.1903,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22776.0,"Objects":[{"StartTime":22776.0,"EndTime":22776.0,"X":463.0,"Y":174.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":22888.0,"EndTime":22888.0,"X":483.131836,"Y":100.896431,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":22998.0,"Objects":[{"StartTime":22998.0,"EndTime":22998.0,"X":330.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":23184.0,"EndTime":23184.0,"X":341.2172,"Y":118.004745,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":23443.0,"Objects":[{"StartTime":23443.0,"EndTime":23443.0,"X":341.0,"Y":118.0}]},{"StartTime":23665.0,"Objects":[{"StartTime":23665.0,"EndTime":23665.0,"X":417.0,"Y":37.0}]},{"StartTime":23887.0,"Objects":[{"StartTime":23887.0,"EndTime":23887.0,"X":384.0,"Y":274.0}]},{"StartTime":24109.0,"Objects":[{"StartTime":24109.0,"EndTime":24109.0,"X":189.0,"Y":125.0}]},{"StartTime":24257.0,"Objects":[{"StartTime":24257.0,"EndTime":24257.0,"X":160.260864,"Y":46.2608681}]},{"StartTime":24331.0,"Objects":[{"StartTime":24331.0,"EndTime":24331.0,"X":164.0,"Y":50.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":24517.0,"EndTime":24517.0,"X":258.715332,"Y":57.3486023,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":24776.0,"Objects":[{"StartTime":24776.0,"EndTime":24776.0,"X":259.0,"Y":59.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25110.0,"EndTime":25110.0,"X":87.62962,"Y":-0.2703557,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25220.0,"Objects":[{"StartTime":25220.0,"EndTime":25220.0,"X":39.0,"Y":64.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25406.0,"EndTime":25406.0,"X":28.9925976,"Y":182.287445,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25554.0,"Objects":[{"StartTime":25554.0,"EndTime":25554.0,"X":145.0,"Y":273.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25740.0,"EndTime":25740.0,"X":26.8029518,"Y":262.037933,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":25887.0,"Objects":[{"StartTime":25887.0,"EndTime":25887.0,"X":234.0,"Y":202.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":25999.0,"EndTime":25999.0,"X":230.918243,"Y":280.907837,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26331.0,"Objects":[{"StartTime":26331.0,"EndTime":26331.0,"X":231.0,"Y":282.0}]},{"StartTime":26554.0,"Objects":[{"StartTime":26554.0,"EndTime":26554.0,"X":12.0,"Y":377.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":26740.0,"EndTime":26740.0,"X":25.7964287,"Y":262.9408,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":26998.0,"Objects":[{"StartTime":26998.0,"EndTime":26998.0,"X":234.0,"Y":202.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27258.0,"EndTime":27258.0,"X":422.545441,"Y":184.940186,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27369.0,"Objects":[{"StartTime":27369.0,"EndTime":27369.0,"X":487.260864,"Y":234.260864}]},{"StartTime":27443.0,"Objects":[{"StartTime":27443.0,"EndTime":27443.0,"X":491.0,"Y":238.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27555.0,"EndTime":27555.0,"X":407.885376,"Y":272.836151,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27665.0,"Objects":[{"StartTime":27665.0,"EndTime":27665.0,"X":407.0,"Y":100.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":27777.0,"EndTime":27777.0,"X":490.3403,"Y":134.4242,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":27887.0,"Objects":[{"StartTime":27887.0,"EndTime":27887.0,"X":491.0,"Y":238.0}]},{"StartTime":28109.0,"Objects":[{"StartTime":28109.0,"EndTime":28109.0,"X":338.260864,"Y":153.260864}]},{"StartTime":28183.0,"Objects":[{"StartTime":28183.0,"EndTime":28183.0,"X":342.0,"Y":157.0}]},{"StartTime":28443.0,"Objects":[{"StartTime":28443.0,"EndTime":28443.0,"X":300.0,"Y":343.0}]},{"StartTime":28776.0,"Objects":[{"StartTime":28776.0,"EndTime":28776.0,"X":300.0,"Y":343.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29109.0,"EndTime":29109.0,"X":494.547028,"Y":370.47995,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29406.0,"EndTime":29406.0,"X":300.0,"Y":343.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":29887.0,"Objects":[{"StartTime":29887.0,"EndTime":29887.0,"X":285.0,"Y":110.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":29999.0,"EndTime":29999.0,"X":374.669769,"Y":90.45255,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30109.0,"Objects":[{"StartTime":30109.0,"EndTime":30109.0,"X":474.0,"Y":9.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":30295.0,"EndTime":30295.0,"X":380.0077,"Y":103.602509,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":30554.0,"Objects":[{"StartTime":30554.0,"EndTime":30554.0,"X":194.0,"Y":141.0}]},{"StartTime":30776.0,"Objects":[{"StartTime":30776.0,"EndTime":30776.0,"X":220.0,"Y":46.0}]},{"StartTime":30998.0,"Objects":[{"StartTime":30998.0,"EndTime":30998.0,"X":153.0,"Y":228.0}]},{"StartTime":31220.0,"Objects":[{"StartTime":31220.0,"EndTime":31220.0,"X":46.0,"Y":31.0}]},{"StartTime":31369.0,"Objects":[{"StartTime":31369.0,"EndTime":31369.0,"X":58.0,"Y":210.0}]},{"StartTime":31443.0,"Objects":[{"StartTime":31443.0,"EndTime":31443.0,"X":63.0,"Y":213.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31573.0,"EndTime":31573.0,"X":151.282684,"Y":204.9826,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31665.0,"Objects":[{"StartTime":31665.0,"EndTime":31665.0,"X":245.0,"Y":224.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":31777.0,"EndTime":31777.0,"X":150.780273,"Y":232.175674,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":31887.0,"Objects":[{"StartTime":31887.0,"EndTime":31887.0,"X":83.2608643,"Y":288.260864}]},{"StartTime":31961.0,"Objects":[{"StartTime":31961.0,"EndTime":31961.0,"X":87.0,"Y":292.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32035.0,"EndTime":32035.0,"X":89.47952,"Y":339.199554,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32073.0,"EndTime":32073.0,"X":87.0,"Y":292.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32331.0,"Objects":[{"StartTime":32331.0,"EndTime":32331.0,"X":40.0,"Y":20.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32517.0,"EndTime":32517.0,"X":27.954195,"Y":147.40477,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32665.0,"Objects":[{"StartTime":32665.0,"EndTime":32665.0,"X":138.0,"Y":81.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":32851.0,"EndTime":32851.0,"X":33.6966553,"Y":6.6338315,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":32998.0,"Objects":[{"StartTime":32998.0,"EndTime":32998.0,"X":38.0,"Y":140.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33184.0,"EndTime":33184.0,"X":154.183746,"Y":85.22502,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33443.0,"Objects":[{"StartTime":33443.0,"EndTime":33443.0,"X":154.0,"Y":86.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":33629.0,"EndTime":33629.0,"X":247.144852,"Y":69.95044,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":33776.0,"Objects":[{"StartTime":33776.0,"EndTime":33776.0,"X":286.0,"Y":0.0}]},{"StartTime":33887.0,"Objects":[{"StartTime":33887.0,"EndTime":33887.0,"X":286.0,"Y":0.0}]},{"StartTime":34109.0,"Objects":[{"StartTime":34109.0,"EndTime":34109.0,"X":258.0,"Y":218.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34331.0,"EndTime":34331.0,"X":271.6775,"Y":359.204651,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34517.0,"EndTime":34517.0,"X":258.0,"Y":218.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34776.0,"Objects":[{"StartTime":34776.0,"EndTime":34776.0,"X":380.0,"Y":251.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":34851.0,"EndTime":34851.0,"X":367.713348,"Y":320.938263,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":34998.0,"Objects":[{"StartTime":34998.0,"EndTime":34998.0,"X":471.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35184.0,"EndTime":35184.0,"X":458.353516,"Y":266.323029,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35443.0,"Objects":[{"StartTime":35443.0,"EndTime":35443.0,"X":260.0,"Y":217.0}]},{"StartTime":35591.0,"Objects":[{"StartTime":35591.0,"EndTime":35591.0,"X":157.260864,"Y":294.260864}]},{"StartTime":35665.0,"Objects":[{"StartTime":35665.0,"EndTime":35665.0,"X":161.0,"Y":298.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":35777.0,"EndTime":35777.0,"X":184.057953,"Y":373.6862,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":35887.0,"Objects":[{"StartTime":35887.0,"EndTime":35887.0,"X":46.0,"Y":246.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36073.0,"EndTime":36073.0,"X":42.9525223,"Y":383.886,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36220.0,"Objects":[{"StartTime":36220.0,"EndTime":36220.0,"X":256.0,"Y":216.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36406.0,"EndTime":36406.0,"X":120.48381,"Y":204.784927,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36554.0,"Objects":[{"StartTime":36554.0,"EndTime":36554.0,"X":371.0,"Y":232.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":36740.0,"EndTime":36740.0,"X":511.9474,"Y":213.112839,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":36998.0,"Objects":[{"StartTime":36998.0,"EndTime":36998.0,"X":511.0,"Y":213.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37110.0,"EndTime":37110.0,"X":495.4303,"Y":136.39592,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":37220.0,"Objects":[{"StartTime":37220.0,"EndTime":37220.0,"X":381.0,"Y":36.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":37406.0,"EndTime":37406.0,"X":411.975159,"Y":142.76506,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":37665.0,"Objects":[{"StartTime":37665.0,"EndTime":37665.0,"X":472.0,"Y":55.0}]},{"StartTime":37887.0,"Objects":[{"StartTime":37887.0,"EndTime":37887.0,"X":368.0,"Y":17.0}]},{"StartTime":38109.0,"Objects":[{"StartTime":38109.0,"EndTime":38109.0,"X":114.0,"Y":109.0}]},{"StartTime":38331.0,"Objects":[{"StartTime":38331.0,"EndTime":38331.0,"X":269.0,"Y":65.0}]},{"StartTime":38554.0,"Objects":[{"StartTime":38554.0,"EndTime":38554.0,"X":12.0,"Y":84.0}]},{"StartTime":38998.0,"Objects":[{"StartTime":38998.0,"EndTime":38998.0,"X":482.0,"Y":60.0}]},{"StartTime":39443.0,"Objects":[{"StartTime":39443.0,"EndTime":39443.0,"X":225.0,"Y":293.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":39776.0,"EndTime":39776.0,"X":34.1912575,"Y":339.044769,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":40073.0,"EndTime":40073.0,"X":225.0,"Y":293.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":40554.0,"Objects":[{"StartTime":40554.0,"EndTime":40554.0,"X":511.0,"Y":364.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":40666.0,"EndTime":40666.0,"X":419.3407,"Y":364.803,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":40776.0,"Objects":[{"StartTime":40776.0,"EndTime":40776.0,"X":322.0,"Y":284.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":40962.0,"EndTime":40962.0,"X":415.9923,"Y":378.6025,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41146.0,"Objects":[{"StartTime":41146.0,"EndTime":41146.0,"X":466.260864,"Y":279.260864}]},{"StartTime":41220.0,"Objects":[{"StartTime":41220.0,"EndTime":41220.0,"X":470.0,"Y":283.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41332.0,"EndTime":41332.0,"X":449.4545,"Y":190.666824,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41443.0,"Objects":[{"StartTime":41443.0,"EndTime":41443.0,"X":445.0,"Y":85.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41555.0,"EndTime":41555.0,"X":383.091278,"Y":96.9536362,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41665.0,"Objects":[{"StartTime":41665.0,"EndTime":41665.0,"X":316.0,"Y":47.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41777.0,"EndTime":41777.0,"X":273.3131,"Y":0.42472744,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":41887.0,"Objects":[{"StartTime":41887.0,"EndTime":41887.0,"X":306.0,"Y":124.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":41999.0,"EndTime":41999.0,"X":290.485779,"Y":201.456039,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42109.0,"Objects":[{"StartTime":42109.0,"EndTime":42109.0,"X":307.0,"Y":335.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42406.0,"EndTime":42406.0,"X":357.6962,"Y":245.541336,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42554.0,"Objects":[{"StartTime":42554.0,"EndTime":42554.0,"X":231.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":42851.0,"EndTime":42851.0,"X":65.17772,"Y":71.38798,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":42998.0,"Objects":[{"StartTime":42998.0,"EndTime":42998.0,"X":0.0,"Y":28.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43442.0,"EndTime":43442.0,"X":141.066589,"Y":14.2687416,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":43850.0,"EndTime":43850.0,"X":0.0,"Y":28.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44109.0,"Objects":[{"StartTime":44109.0,"EndTime":44109.0,"X":192.0,"Y":75.0}]},{"StartTime":44331.0,"Objects":[{"StartTime":44331.0,"EndTime":44331.0,"X":257.0,"Y":35.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":44628.0,"EndTime":44628.0,"X":361.660645,"Y":20.101881,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":44776.0,"Objects":[{"StartTime":44776.0,"EndTime":44776.0,"X":361.0,"Y":20.0}]},{"StartTime":44998.0,"Objects":[{"StartTime":44998.0,"EndTime":44998.0,"X":453.0,"Y":10.0}]},{"StartTime":45220.0,"Objects":[{"StartTime":45220.0,"EndTime":45220.0,"X":512.0,"Y":73.0}]},{"StartTime":45665.0,"Objects":[{"StartTime":45665.0,"EndTime":45665.0,"X":0.0,"Y":12.0}]},{"StartTime":45887.0,"Objects":[{"StartTime":45887.0,"EndTime":45887.0,"X":0.0,"Y":12.0}]},{"StartTime":46109.0,"Objects":[{"StartTime":46109.0,"EndTime":46109.0,"X":0.0,"Y":12.0}]},{"StartTime":46554.0,"Objects":[{"StartTime":46554.0,"EndTime":46554.0,"X":0.0,"Y":12.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":46851.0,"EndTime":46851.0,"X":101.499535,"Y":43.66694,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":46998.0,"Objects":[{"StartTime":46998.0,"EndTime":46998.0,"X":169.0,"Y":0.0}]},{"StartTime":47220.0,"Objects":[{"StartTime":47220.0,"EndTime":47220.0,"X":375.0,"Y":56.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":47554.0,"EndTime":47554.0,"X":485.153961,"Y":74.49411,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":47665.0,"Objects":[{"StartTime":47665.0,"EndTime":47665.0,"X":501.0,"Y":55.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":47851.0,"EndTime":47851.0,"X":462.965179,"Y":-0.772694349,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":48109.0,"Objects":[{"StartTime":48109.0,"EndTime":48109.0,"X":188.0,"Y":77.0}]},{"StartTime":48331.0,"Objects":[{"StartTime":48331.0,"EndTime":48331.0,"X":188.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48553.0,"EndTime":48553.0,"X":199.2907,"Y":147.349716,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":48739.0,"EndTime":48739.0,"X":188.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":48998.0,"Objects":[{"StartTime":48998.0,"EndTime":48998.0,"X":307.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49184.0,"EndTime":49184.0,"X":297.639069,"Y":70.63239,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":49665.0,"Objects":[{"StartTime":49665.0,"EndTime":49665.0,"X":297.0,"Y":70.0}]},{"StartTime":49887.0,"Objects":[{"StartTime":49887.0,"EndTime":49887.0,"X":380.0,"Y":57.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":49999.0,"EndTime":49999.0,"X":401.888733,"Y":14.8439369,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":50109.0,"Objects":[{"StartTime":50109.0,"EndTime":50109.0,"X":188.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50442.0,"EndTime":50442.0,"X":83.18368,"Y":56.6891975,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":50739.0,"EndTime":50739.0,"X":188.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":51220.0,"Objects":[{"StartTime":51220.0,"EndTime":51220.0,"X":188.0,"Y":77.0}]},{"StartTime":51442.0,"Objects":[{"StartTime":51442.0,"EndTime":51442.0,"X":33.0,"Y":125.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":51776.0,"EndTime":51776.0,"X":12.38936,"Y":16.1852417,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":51887.0,"Objects":[{"StartTime":51887.0,"EndTime":51887.0,"X":15.7391319,"Y":19.7391319}]},{"StartTime":52109.0,"Objects":[{"StartTime":52109.0,"EndTime":52109.0,"X":90.0,"Y":59.0}]},{"StartTime":52331.0,"Objects":[{"StartTime":52331.0,"EndTime":52331.0,"X":189.0,"Y":63.0}]},{"StartTime":52776.0,"Objects":[{"StartTime":52776.0,"EndTime":52776.0,"X":512.0,"Y":0.0}]},{"StartTime":52998.0,"Objects":[{"StartTime":52998.0,"EndTime":52998.0,"X":512.0,"Y":0.0}]},{"StartTime":53220.0,"Objects":[{"StartTime":53220.0,"EndTime":53220.0,"X":512.0,"Y":0.0}]},{"StartTime":53665.0,"Objects":[{"StartTime":53665.0,"EndTime":53665.0,"X":512.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":53962.0,"EndTime":53962.0,"X":410.500458,"Y":31.6669388,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54109.0,"Objects":[{"StartTime":54109.0,"EndTime":54109.0,"X":410.0,"Y":31.0}]},{"StartTime":54331.0,"Objects":[{"StartTime":54331.0,"EndTime":54331.0,"X":359.0,"Y":110.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54665.0,"EndTime":54665.0,"X":340.5059,"Y":-0.153986454,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":54776.0,"Objects":[{"StartTime":54776.0,"EndTime":54776.0,"X":492.0,"Y":96.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":54962.0,"EndTime":54962.0,"X":436.244843,"Y":134.083344,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":55220.0,"Objects":[{"StartTime":55220.0,"EndTime":55220.0,"X":256.0,"Y":75.0}]},{"StartTime":55442.0,"Objects":[{"StartTime":55442.0,"EndTime":55442.0,"X":256.0,"Y":75.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":55664.0,"EndTime":55664.0,"X":185.613754,"Y":63.9393044,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":55850.0,"EndTime":55850.0,"X":256.0,"Y":75.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":56331.0,"Objects":[{"StartTime":56331.0,"EndTime":56331.0,"X":359.0,"Y":110.0}]},{"StartTime":56554.0,"Objects":[{"StartTime":56554.0,"EndTime":56554.0,"X":256.0,"Y":384.0}]},{"StartTime":56776.0,"Objects":[{"StartTime":56776.0,"EndTime":56776.0,"X":135.0,"Y":352.0}]},{"StartTime":57220.0,"Objects":[{"StartTime":57220.0,"EndTime":57220.0,"X":135.0,"Y":352.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57332.0,"EndTime":57332.0,"X":56.703907,"Y":179.021271,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57443.0,"Objects":[{"StartTime":57443.0,"EndTime":57443.0,"X":214.0,"Y":2.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57555.0,"EndTime":57555.0,"X":157.702835,"Y":166.508469,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57665.0,"Objects":[{"StartTime":57665.0,"EndTime":57665.0,"X":63.0,"Y":39.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57777.0,"EndTime":57777.0,"X":216.202484,"Y":76.36667,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":57887.0,"Objects":[{"StartTime":57887.0,"EndTime":57887.0,"X":256.0,"Y":370.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":57999.0,"EndTime":57999.0,"X":236.6084,"Y":229.30957,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58109.0,"Objects":[{"StartTime":58109.0,"EndTime":58109.0,"X":494.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58221.0,"EndTime":58221.0,"X":380.0297,"Y":273.818848,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58332.0,"Objects":[{"StartTime":58332.0,"EndTime":58332.0,"X":322.0,"Y":67.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58444.0,"EndTime":58444.0,"X":361.137817,"Y":169.606186,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58554.0,"Objects":[{"StartTime":58554.0,"EndTime":58554.0,"X":242.0,"Y":377.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58666.0,"EndTime":58666.0,"X":154.118546,"Y":343.403931,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":58776.0,"Objects":[{"StartTime":58776.0,"EndTime":58776.0,"X":22.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":58962.0,"EndTime":58962.0,"X":139.243927,"Y":189.986084,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59220.0,"Objects":[{"StartTime":59220.0,"EndTime":59220.0,"X":491.0,"Y":202.0}]},{"StartTime":59331.0,"Objects":[{"StartTime":59331.0,"EndTime":59331.0,"X":370.0,"Y":162.0}]},{"StartTime":59443.0,"Objects":[{"StartTime":59443.0,"EndTime":59443.0,"X":442.0,"Y":76.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59518.0,"EndTime":59518.0,"X":454.5813,"Y":132.28093,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":59665.0,"Objects":[{"StartTime":59665.0,"EndTime":59665.0,"X":362.0,"Y":170.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":59851.0,"EndTime":59851.0,"X":365.3222,"Y":-0.135499477,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60109.0,"Objects":[{"StartTime":60109.0,"EndTime":60109.0,"X":266.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60239.0,"EndTime":60239.0,"X":250.3682,"Y":240.412949,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60331.0,"Objects":[{"StartTime":60331.0,"EndTime":60331.0,"X":250.0,"Y":240.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60628.0,"EndTime":60628.0,"X":261.902863,"Y":346.2101,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60776.0,"Objects":[{"StartTime":60776.0,"EndTime":60776.0,"X":243.0,"Y":145.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":60888.0,"EndTime":60888.0,"X":414.964264,"Y":64.90915,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":60998.0,"Objects":[{"StartTime":60998.0,"EndTime":60998.0,"X":108.0,"Y":108.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61110.0,"EndTime":61110.0,"X":51.0426025,"Y":272.124146,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61221.0,"Objects":[{"StartTime":61221.0,"EndTime":61221.0,"X":422.0,"Y":317.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61333.0,"EndTime":61333.0,"X":461.749878,"Y":163.95488,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61443.0,"Objects":[{"StartTime":61443.0,"EndTime":61443.0,"X":188.0,"Y":69.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61555.0,"EndTime":61555.0,"X":47.2970963,"Y":49.65848,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61665.0,"Objects":[{"StartTime":61665.0,"EndTime":61665.0,"X":2.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":61777.0,"EndTime":61777.0,"X":117.986351,"Y":306.8477,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":61888.0,"Objects":[{"StartTime":61888.0,"EndTime":61888.0,"X":155.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62000.0,"EndTime":62000.0,"X":52.2578239,"Y":206.931015,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62110.0,"Objects":[{"StartTime":62110.0,"EndTime":62110.0,"X":328.0,"Y":287.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62222.0,"EndTime":62222.0,"X":415.8731,"Y":320.639221,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62332.0,"Objects":[{"StartTime":62332.0,"EndTime":62332.0,"X":259.0,"Y":156.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62444.0,"EndTime":62444.0,"X":250.142136,"Y":234.555649,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62554.0,"Objects":[{"StartTime":62554.0,"EndTime":62554.0,"X":439.0,"Y":37.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":62814.0,"EndTime":62814.0,"X":327.925018,"Y":286.186462,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":62924.0,"Objects":[{"StartTime":62924.0,"EndTime":62924.0,"X":271.0,"Y":154.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63036.0,"EndTime":63036.0,"X":296.7042,"Y":99.75176,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63220.0,"Objects":[{"StartTime":63220.0,"EndTime":63220.0,"X":327.0,"Y":286.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63480.0,"EndTime":63480.0,"X":217.666336,"Y":18.1386681,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63591.0,"Objects":[{"StartTime":63591.0,"EndTime":63591.0,"X":158.260864,"Y":79.2608643}]},{"StartTime":63665.0,"Objects":[{"StartTime":63665.0,"EndTime":63665.0,"X":162.0,"Y":83.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":63740.0,"EndTime":63740.0,"X":115.196854,"Y":78.46499,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":63887.0,"Objects":[{"StartTime":63887.0,"EndTime":63887.0,"X":63.0,"Y":227.0}]},{"StartTime":63998.0,"Objects":[{"StartTime":63998.0,"EndTime":63998.0,"X":40.0,"Y":145.0}]},{"StartTime":64109.0,"Objects":[{"StartTime":64109.0,"EndTime":64109.0,"X":20.0,"Y":64.0}]},{"StartTime":64331.0,"Objects":[{"StartTime":64331.0,"EndTime":64331.0,"X":30.0,"Y":67.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64443.0,"EndTime":64443.0,"X":215.669785,"Y":30.3937016,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64554.0,"Objects":[{"StartTime":64554.0,"EndTime":64554.0,"X":184.0,"Y":369.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64666.0,"EndTime":64666.0,"X":20.7301826,"Y":309.824158,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64776.0,"Objects":[{"StartTime":64776.0,"EndTime":64776.0,"X":425.0,"Y":32.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":64888.0,"EndTime":64888.0,"X":402.833282,"Y":188.61615,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":64998.0,"Objects":[{"StartTime":64998.0,"EndTime":64998.0,"X":100.0,"Y":370.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65110.0,"EndTime":65110.0,"X":77.70479,"Y":229.476547,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65220.0,"Objects":[{"StartTime":65220.0,"EndTime":65220.0,"X":387.0,"Y":107.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65350.0,"EndTime":65350.0,"X":512.8505,"Y":172.545654,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65443.0,"Objects":[{"StartTime":65443.0,"EndTime":65443.0,"X":203.0,"Y":269.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65555.0,"EndTime":65555.0,"X":239.321548,"Y":164.535965,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65665.0,"Objects":[{"StartTime":65665.0,"EndTime":65665.0,"X":483.0,"Y":277.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":65777.0,"EndTime":65777.0,"X":494.957733,"Y":370.8416,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":65887.0,"Objects":[{"StartTime":65887.0,"EndTime":65887.0,"X":400.0,"Y":205.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66073.0,"EndTime":66073.0,"X":512.1871,"Y":172.1586,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66331.0,"Objects":[{"StartTime":66331.0,"EndTime":66331.0,"X":372.0,"Y":357.0}]},{"StartTime":66442.0,"Objects":[{"StartTime":66442.0,"EndTime":66442.0,"X":287.0,"Y":283.0}]},{"StartTime":66554.0,"Objects":[{"StartTime":66554.0,"EndTime":66554.0,"X":175.0,"Y":345.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66666.0,"EndTime":66666.0,"X":97.7213,"Y":359.975983,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":66776.0,"Objects":[{"StartTime":66776.0,"EndTime":66776.0,"X":28.0,"Y":257.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":66962.0,"EndTime":66962.0,"X":198.1355,"Y":260.3222,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":67221.0,"Objects":[{"StartTime":67221.0,"EndTime":67221.0,"X":0.0,"Y":117.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67351.0,"EndTime":67351.0,"X":139.735031,"Y":90.25935,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":67443.0,"Objects":[{"StartTime":67443.0,"EndTime":67443.0,"X":125.0,"Y":113.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67740.0,"EndTime":67740.0,"X":18.8577633,"Y":101.148491,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":67887.0,"Objects":[{"StartTime":67887.0,"EndTime":67887.0,"X":194.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":67999.0,"EndTime":67999.0,"X":274.090851,"Y":171.964279,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68109.0,"Objects":[{"StartTime":68109.0,"EndTime":68109.0,"X":10.0,"Y":350.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":68221.0,"EndTime":68221.0,"X":67.05159,"Y":185.783691,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68332.0,"Objects":[{"StartTime":68332.0,"EndTime":68332.0,"X":412.0,"Y":34.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":68444.0,"EndTime":68444.0,"X":372.017242,"Y":186.88884,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68554.0,"Objects":[{"StartTime":68554.0,"EndTime":68554.0,"X":194.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":68666.0,"EndTime":68666.0,"X":313.206573,"Y":77.26558,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68776.0,"Objects":[{"StartTime":68776.0,"EndTime":68776.0,"X":197.0,"Y":271.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":68888.0,"EndTime":68888.0,"X":272.742371,"Y":170.890579,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":68999.0,"Objects":[{"StartTime":68999.0,"EndTime":68999.0,"X":448.0,"Y":305.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69111.0,"EndTime":69111.0,"X":338.401917,"Y":298.116425,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":69220.0,"Objects":[{"StartTime":69220.0,"EndTime":69220.0,"X":409.0,"Y":117.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69332.0,"EndTime":69332.0,"X":496.88147,"Y":150.596054,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":69443.0,"Objects":[{"StartTime":69443.0,"EndTime":69443.0,"X":225.0,"Y":349.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69555.0,"EndTime":69555.0,"X":146.244675,"Y":355.206116,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":69665.0,"Objects":[{"StartTime":69665.0,"EndTime":69665.0,"X":198.0,"Y":200.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":69925.0,"EndTime":69925.0,"X":447.4509,"Y":310.416962,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70035.0,"Objects":[{"StartTime":70035.0,"EndTime":70035.0,"X":445.0,"Y":334.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":70147.0,"EndTime":70147.0,"X":393.847443,"Y":369.199432,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70331.0,"Objects":[{"StartTime":70331.0,"EndTime":70331.0,"X":188.0,"Y":271.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":70591.0,"EndTime":70591.0,"X":415.634369,"Y":92.77198,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":70776.0,"Objects":[{"StartTime":70776.0,"EndTime":70776.0,"X":341.0,"Y":222.0}]},{"StartTime":70887.0,"Objects":[{"StartTime":70887.0,"EndTime":70887.0,"X":341.0,"Y":222.0}]},{"StartTime":70998.0,"Objects":[{"StartTime":70998.0,"EndTime":70998.0,"X":134.0,"Y":157.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":71073.0,"EndTime":71073.0,"X":2.40367842,"Y":143.132309,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":71220.0,"Objects":[{"StartTime":71220.0,"EndTime":71220.0,"X":46.0,"Y":328.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":71295.0,"EndTime":71295.0,"X":100.017792,"Y":256.82428,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":71443.0,"Objects":[{"StartTime":71443.0,"EndTime":71443.0,"X":192.0,"Y":275.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":71629.0,"EndTime":71629.0,"X":206.980026,"Y":364.057648,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":71887.0,"Objects":[{"StartTime":71887.0,"EndTime":71887.0,"X":54.0,"Y":334.0}]},{"StartTime":72109.0,"Objects":[{"StartTime":72109.0,"EndTime":72109.0,"X":262.0,"Y":237.0}]},{"StartTime":72331.0,"Objects":[{"StartTime":72331.0,"EndTime":72331.0,"X":432.0,"Y":296.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":72553.0,"EndTime":72553.0,"X":339.460541,"Y":316.382751,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":72739.0,"EndTime":72739.0,"X":432.0,"Y":296.0,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":72998.0,"Objects":[{"StartTime":72998.0,"EndTime":72998.0,"X":432.0,"Y":296.0}]},{"StartTime":73220.0,"Objects":[{"StartTime":73220.0,"EndTime":73220.0,"X":369.0,"Y":137.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":73406.0,"EndTime":73406.0,"X":361.7752,"Y":231.724884,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":73665.0,"Objects":[{"StartTime":73665.0,"EndTime":73665.0,"X":411.0,"Y":17.0}]},{"StartTime":73887.0,"Objects":[{"StartTime":73887.0,"EndTime":73887.0,"X":451.0,"Y":169.0}]},{"StartTime":74035.0,"Objects":[{"StartTime":74035.0,"EndTime":74035.0,"X":288.260864,"Y":113.260864}]},{"StartTime":74109.0,"Objects":[{"StartTime":74109.0,"EndTime":74109.0,"X":292.0,"Y":117.0}]},{"StartTime":74331.0,"Objects":[{"StartTime":74331.0,"EndTime":74331.0,"X":415.0,"Y":26.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":74739.0,"EndTime":74739.0,"X":236.111053,"Y":44.37425,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":74998.0,"Objects":[{"StartTime":74998.0,"EndTime":74998.0,"X":236.0,"Y":44.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":75184.0,"EndTime":75184.0,"X":141.991653,"Y":57.6905365,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":75443.0,"Objects":[{"StartTime":75443.0,"EndTime":75443.0,"X":0.0,"Y":116.0}]},{"StartTime":75665.0,"Objects":[{"StartTime":75665.0,"EndTime":75665.0,"X":0.0,"Y":116.0}]},{"StartTime":75887.0,"Objects":[{"StartTime":75887.0,"EndTime":75887.0,"X":173.0,"Y":141.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":76073.0,"EndTime":76073.0,"X":79.0150757,"Y":127.14959,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":76331.0,"Objects":[{"StartTime":76331.0,"EndTime":76331.0,"X":82.0,"Y":0.0}]},{"StartTime":76554.0,"Objects":[{"StartTime":76554.0,"EndTime":76554.0,"X":82.0,"Y":0.0}]},{"StartTime":76776.0,"Objects":[{"StartTime":76776.0,"EndTime":76776.0,"X":79.0,"Y":127.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":76962.0,"EndTime":76962.0,"X":64.47652,"Y":267.4892,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77109.0,"Objects":[{"StartTime":77109.0,"EndTime":77109.0,"X":12.0,"Y":323.0}]},{"StartTime":77220.0,"Objects":[{"StartTime":77220.0,"EndTime":77220.0,"X":87.0,"Y":344.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77295.0,"EndTime":77295.0,"X":133.98877,"Y":347.2938,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77443.0,"Objects":[{"StartTime":77443.0,"EndTime":77443.0,"X":255.0,"Y":179.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":77629.0,"EndTime":77629.0,"X":145.678146,"Y":268.647217,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":77887.0,"Objects":[{"StartTime":77887.0,"EndTime":77887.0,"X":261.0,"Y":384.0}]},{"StartTime":78109.0,"Objects":[{"StartTime":78109.0,"EndTime":78109.0,"X":366.0,"Y":199.0}]},{"StartTime":78220.0,"Objects":[{"StartTime":78220.0,"EndTime":78220.0,"X":293.0,"Y":263.0}]},{"StartTime":78331.0,"Objects":[{"StartTime":78331.0,"EndTime":78331.0,"X":386.0,"Y":295.0}]},{"StartTime":78554.0,"Objects":[{"StartTime":78554.0,"EndTime":78554.0,"X":152.0,"Y":279.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":78740.0,"EndTime":78740.0,"X":293.428223,"Y":263.192047,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":78998.0,"Objects":[{"StartTime":78998.0,"EndTime":78998.0,"X":486.0,"Y":152.0}]},{"StartTime":79109.0,"Objects":[{"StartTime":79109.0,"EndTime":79109.0,"X":366.0,"Y":199.0}]},{"StartTime":79220.0,"Objects":[{"StartTime":79220.0,"EndTime":79220.0,"X":465.0,"Y":295.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":79295.0,"EndTime":79295.0,"X":512.003967,"Y":288.515656,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":79443.0,"Objects":[{"StartTime":79443.0,"EndTime":79443.0,"X":424.0,"Y":369.0}]},{"StartTime":79665.0,"Objects":[{"StartTime":79665.0,"EndTime":79665.0,"X":446.0,"Y":220.0}]},{"StartTime":79887.0,"Objects":[{"StartTime":79887.0,"EndTime":79887.0,"X":466.0,"Y":68.0}]},{"StartTime":79998.0,"Objects":[{"StartTime":79998.0,"EndTime":79998.0,"X":389.0,"Y":80.0}]},{"StartTime":80109.0,"Objects":[{"StartTime":80109.0,"EndTime":80109.0,"X":316.0,"Y":45.0}]},{"StartTime":80331.0,"Objects":[{"StartTime":80331.0,"EndTime":80331.0,"X":312.0,"Y":35.0}]},{"StartTime":80443.0,"Objects":[{"StartTime":80443.0,"EndTime":80443.0,"X":248.0,"Y":79.0}]},{"StartTime":80554.0,"Objects":[{"StartTime":80554.0,"EndTime":80554.0,"X":171.0,"Y":50.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":80629.0,"EndTime":80629.0,"X":165.3406,"Y":2.8383522,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":80776.0,"Objects":[{"StartTime":80776.0,"EndTime":80776.0,"X":23.0,"Y":80.0}]},{"StartTime":80887.0,"Objects":[{"StartTime":80887.0,"EndTime":80887.0,"X":104.0,"Y":98.0}]},{"StartTime":80998.0,"Objects":[{"StartTime":80998.0,"EndTime":80998.0,"X":176.0,"Y":58.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":81073.0,"EndTime":81073.0,"X":181.6594,"Y":10.8383522,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":81220.0,"Objects":[{"StartTime":81220.0,"EndTime":81220.0,"X":184.0,"Y":156.0}]},{"StartTime":81443.0,"Objects":[{"StartTime":81443.0,"EndTime":81443.0,"X":184.0,"Y":156.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":81629.0,"EndTime":81629.0,"X":197.0351,"Y":297.384857,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":81776.0,"Objects":[{"StartTime":81776.0,"EndTime":81776.0,"X":204.0,"Y":384.0}]},{"StartTime":81887.0,"Objects":[{"StartTime":81887.0,"EndTime":81887.0,"X":204.0,"Y":384.0}]},{"StartTime":82109.0,"Objects":[{"StartTime":82109.0,"EndTime":82109.0,"X":116.0,"Y":268.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":82295.0,"EndTime":82295.0,"X":25.2960758,"Y":261.874023,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":82554.0,"Objects":[{"StartTime":82554.0,"EndTime":82554.0,"X":204.0,"Y":384.0}]},{"StartTime":82665.0,"Objects":[{"StartTime":82665.0,"EndTime":82665.0,"X":67.0,"Y":341.0}]},{"StartTime":82776.0,"Objects":[{"StartTime":82776.0,"EndTime":82776.0,"X":67.0,"Y":341.0}]},{"StartTime":82924.0,"Objects":[{"StartTime":82924.0,"EndTime":82924.0,"X":271.260864,"Y":333.260864}]},{"StartTime":82998.0,"Objects":[{"StartTime":82998.0,"EndTime":82998.0,"X":275.0,"Y":337.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":83184.0,"EndTime":83184.0,"X":365.5222,"Y":330.68634,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":83443.0,"Objects":[{"StartTime":83443.0,"EndTime":83443.0,"X":349.0,"Y":335.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":83777.0,"EndTime":83777.0,"X":206.640488,"Y":375.221741,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":83887.0,"Objects":[{"StartTime":83887.0,"EndTime":83887.0,"X":134.0,"Y":349.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84073.0,"EndTime":84073.0,"X":-0.785378,"Y":333.9109,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84257.0,"Objects":[{"StartTime":84257.0,"EndTime":84257.0,"X":418.260864,"Y":268.260864}]},{"StartTime":84331.0,"Objects":[{"StartTime":84331.0,"EndTime":84331.0,"X":422.0,"Y":272.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84443.0,"EndTime":84443.0,"X":482.78595,"Y":283.306061,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84554.0,"Objects":[{"StartTime":84554.0,"EndTime":84554.0,"X":496.0,"Y":101.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84666.0,"EndTime":84666.0,"X":405.197174,"Y":99.9096756,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":84776.0,"Objects":[{"StartTime":84776.0,"EndTime":84776.0,"X":336.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":84962.0,"EndTime":84962.0,"X":477.3753,"Y":176.171219,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":85220.0,"Objects":[{"StartTime":85220.0,"EndTime":85220.0,"X":478.0,"Y":177.0}]},{"StartTime":85369.0,"Objects":[{"StartTime":85369.0,"EndTime":85369.0,"X":498.260864,"Y":97.2608643}]},{"StartTime":85443.0,"Objects":[{"StartTime":85443.0,"EndTime":85443.0,"X":502.0,"Y":101.0}]},{"StartTime":85665.0,"Objects":[{"StartTime":85665.0,"EndTime":85665.0,"X":256.0,"Y":192.0}]},{"StartTime":85887.0,"Objects":[{"StartTime":85887.0,"EndTime":85887.0,"X":256.0,"Y":192.0}]},{"StartTime":86109.0,"Objects":[{"StartTime":86109.0,"EndTime":86109.0,"X":256.0,"Y":192.0}]},{"StartTime":86776.0,"Objects":[{"StartTime":86776.0,"EndTime":86776.0,"X":256.0,"Y":192.0}]},{"StartTime":86998.0,"Objects":[{"StartTime":86998.0,"EndTime":86998.0,"X":256.0,"Y":192.0}]},{"StartTime":87443.0,"Objects":[{"StartTime":87443.0,"EndTime":87443.0,"X":256.0,"Y":192.0}]},{"StartTime":87887.0,"Objects":[{"StartTime":87887.0,"EndTime":87887.0,"X":256.0,"Y":192.0}]},{"StartTime":88276.0,"Objects":[{"StartTime":88276.0,"EndTime":88276.0,"X":256.0,"Y":192.0}]},{"StartTime":88480.0,"Objects":[{"StartTime":88480.0,"EndTime":88480.0,"X":252.260864,"Y":188.260864}]},{"StartTime":88554.0,"Objects":[{"StartTime":88554.0,"EndTime":88554.0,"X":256.0,"Y":192.0}]},{"StartTime":88776.0,"Objects":[{"StartTime":88776.0,"EndTime":88776.0,"X":256.0,"Y":192.0}]},{"StartTime":88943.0,"Objects":[{"StartTime":88943.0,"EndTime":88943.0,"X":256.0,"Y":192.0}]},{"StartTime":89220.0,"Objects":[{"StartTime":89220.0,"EndTime":89220.0,"X":256.0,"Y":192.0}]},{"StartTime":89443.0,"Objects":[{"StartTime":89443.0,"EndTime":89443.0,"X":256.0,"Y":192.0}]},{"StartTime":89665.0,"Objects":[{"StartTime":89665.0,"EndTime":89665.0,"X":256.0,"Y":192.0}]},{"StartTime":90054.0,"Objects":[{"StartTime":90054.0,"EndTime":90054.0,"X":256.0,"Y":192.0}]},{"StartTime":90331.0,"Objects":[{"StartTime":90331.0,"EndTime":90331.0,"X":256.0,"Y":192.0}]},{"StartTime":90554.0,"Objects":[{"StartTime":90554.0,"EndTime":90554.0,"X":256.0,"Y":192.0}]},{"StartTime":90998.0,"Objects":[{"StartTime":90998.0,"EndTime":90998.0,"X":256.0,"Y":192.0}]},{"StartTime":91443.0,"Objects":[{"StartTime":91443.0,"EndTime":91443.0,"X":256.0,"Y":192.0}]},{"StartTime":91831.0,"Objects":[{"StartTime":91831.0,"EndTime":91831.0,"X":256.0,"Y":192.0}]},{"StartTime":92035.0,"Objects":[{"StartTime":92035.0,"EndTime":92035.0,"X":252.260864,"Y":188.260864}]},{"StartTime":92109.0,"Objects":[{"StartTime":92109.0,"EndTime":92109.0,"X":256.0,"Y":192.0}]},{"StartTime":92331.0,"Objects":[{"StartTime":92331.0,"EndTime":92331.0,"X":256.0,"Y":192.0}]},{"StartTime":92498.0,"Objects":[{"StartTime":92498.0,"EndTime":92498.0,"X":256.0,"Y":192.0}]},{"StartTime":92776.0,"Objects":[{"StartTime":92776.0,"EndTime":92776.0,"X":256.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":92962.0,"EndTime":92962.0,"X":222.567719,"Y":250.718628,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93109.0,"Objects":[{"StartTime":93109.0,"EndTime":93109.0,"X":256.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93295.0,"EndTime":93295.0,"X":347.40506,"Y":186.090027,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93443.0,"Objects":[{"StartTime":93443.0,"EndTime":93443.0,"X":256.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":93777.0,"EndTime":93777.0,"X":116.548386,"Y":75.43778,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":93887.0,"Objects":[{"StartTime":93887.0,"EndTime":93887.0,"X":189.0,"Y":46.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":94073.0,"EndTime":94073.0,"X":281.007141,"Y":24.99693,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":94554.0,"Objects":[{"StartTime":94554.0,"EndTime":94554.0,"X":36.0,"Y":22.0}]},{"StartTime":94776.0,"Objects":[{"StartTime":94776.0,"EndTime":94776.0,"X":103.0,"Y":73.0}]},{"StartTime":94998.0,"Objects":[{"StartTime":94998.0,"EndTime":94998.0,"X":185.0,"Y":45.0}]},{"StartTime":95387.0,"Objects":[{"StartTime":95387.0,"EndTime":95387.0,"X":512.0,"Y":0.0}]},{"StartTime":95665.0,"Objects":[{"StartTime":95665.0,"EndTime":95665.0,"X":512.0,"Y":0.0}]},{"StartTime":95887.0,"Objects":[{"StartTime":95887.0,"EndTime":95887.0,"X":512.0,"Y":0.0}]},{"StartTime":96331.0,"Objects":[{"StartTime":96331.0,"EndTime":96331.0,"X":512.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96517.0,"EndTime":96517.0,"X":459.134857,"Y":78.4148254,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96665.0,"Objects":[{"StartTime":96665.0,"EndTime":96665.0,"X":367.0,"Y":70.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":96851.0,"EndTime":96851.0,"X":293.2465,"Y":122.00705,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":96998.0,"Objects":[{"StartTime":96998.0,"EndTime":96998.0,"X":503.0,"Y":150.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97332.0,"EndTime":97332.0,"X":375.606934,"Y":85.94427,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":97443.0,"Objects":[{"StartTime":97443.0,"EndTime":97443.0,"X":370.0,"Y":71.0}]},{"StartTime":97665.0,"Objects":[{"StartTime":97665.0,"EndTime":97665.0,"X":285.0,"Y":7.0}]},{"StartTime":97887.0,"Objects":[{"StartTime":97887.0,"EndTime":97887.0,"X":189.0,"Y":47.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":97999.0,"EndTime":97999.0,"X":126.681664,"Y":55.76924,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98109.0,"Objects":[{"StartTime":98109.0,"EndTime":98109.0,"X":32.0,"Y":20.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98295.0,"EndTime":98295.0,"X":48.56125,"Y":112.862427,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":98480.0,"Objects":[{"StartTime":98480.0,"EndTime":98480.0,"X":123.260864,"Y":133.260864}]},{"StartTime":98554.0,"Objects":[{"StartTime":98554.0,"EndTime":98554.0,"X":127.0,"Y":137.0}]},{"StartTime":98776.0,"Objects":[{"StartTime":98776.0,"EndTime":98776.0,"X":189.0,"Y":41.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":98906.0,"EndTime":98906.0,"X":205.639862,"Y":110.098328,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":99220.0,"Objects":[{"StartTime":99220.0,"EndTime":99220.0,"X":2.0,"Y":384.0}]},{"StartTime":99443.0,"Objects":[{"StartTime":99443.0,"EndTime":99443.0,"X":135.0,"Y":352.0}]},{"StartTime":99887.0,"Objects":[{"StartTime":99887.0,"EndTime":99887.0,"X":135.0,"Y":352.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":99999.0,"EndTime":99999.0,"X":54.624,"Y":180.20723,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100109.0,"Objects":[{"StartTime":100109.0,"EndTime":100109.0,"X":445.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100221.0,"EndTime":100221.0,"X":388.70285,"Y":164.508469,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100332.0,"Objects":[{"StartTime":100332.0,"EndTime":100332.0,"X":224.0,"Y":18.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100444.0,"EndTime":100444.0,"X":377.297821,"Y":54.7266,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100554.0,"Objects":[{"StartTime":100554.0,"EndTime":100554.0,"X":152.0,"Y":130.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100666.0,"EndTime":100666.0,"X":43.1472549,"Y":38.1323853,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100776.0,"Objects":[{"StartTime":100776.0,"EndTime":100776.0,"X":512.0,"Y":269.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":100888.0,"EndTime":100888.0,"X":397.676056,"Y":322.976379,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":100999.0,"Objects":[{"StartTime":100999.0,"EndTime":100999.0,"X":271.0,"Y":183.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101129.0,"EndTime":101129.0,"X":384.802155,"Y":136.151382,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101221.0,"Objects":[{"StartTime":101221.0,"EndTime":101221.0,"X":302.0,"Y":298.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101333.0,"EndTime":101333.0,"X":214.462448,"Y":262.777374,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101443.0,"Objects":[{"StartTime":101443.0,"EndTime":101443.0,"X":22.0,"Y":207.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":101629.0,"EndTime":101629.0,"X":139.243927,"Y":189.986084,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":101887.0,"Objects":[{"StartTime":101887.0,"EndTime":101887.0,"X":230.0,"Y":15.0}]},{"StartTime":101998.0,"Objects":[{"StartTime":101998.0,"EndTime":101998.0,"X":272.0,"Y":184.0}]},{"StartTime":102110.0,"Objects":[{"StartTime":102110.0,"EndTime":102110.0,"X":402.0,"Y":62.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102185.0,"EndTime":102185.0,"X":413.950653,"Y":3.84011459,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102332.0,"Objects":[{"StartTime":102332.0,"EndTime":102332.0,"X":320.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102518.0,"EndTime":102518.0,"X":271.278229,"Y":183.300629,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102776.0,"Objects":[{"StartTime":102776.0,"EndTime":102776.0,"X":512.0,"Y":179.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":102906.0,"EndTime":102906.0,"X":373.0303,"Y":192.519409,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":102998.0,"Objects":[{"StartTime":102998.0,"EndTime":102998.0,"X":373.0,"Y":192.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103295.0,"EndTime":103295.0,"X":477.322662,"Y":184.897552,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103443.0,"Objects":[{"StartTime":103443.0,"EndTime":103443.0,"X":197.0,"Y":228.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103555.0,"EndTime":103555.0,"X":25.3858719,"Y":308.758972,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103665.0,"Objects":[{"StartTime":103665.0,"EndTime":103665.0,"X":456.0,"Y":383.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":103777.0,"EndTime":103777.0,"X":335.283752,"Y":257.830139,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":103888.0,"Objects":[{"StartTime":103888.0,"EndTime":103888.0,"X":100.0,"Y":21.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104000.0,"EndTime":104000.0,"X":8.775268,"Y":150.12056,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104110.0,"Objects":[{"StartTime":104110.0,"EndTime":104110.0,"X":259.0,"Y":168.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104222.0,"EndTime":104222.0,"X":270.277527,"Y":26.5244961,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104332.0,"Objects":[{"StartTime":104332.0,"EndTime":104332.0,"X":83.0,"Y":198.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104444.0,"EndTime":104444.0,"X":122.788712,"Y":317.792664,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104555.0,"Objects":[{"StartTime":104555.0,"EndTime":104555.0,"X":473.0,"Y":90.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104667.0,"EndTime":104667.0,"X":369.6388,"Y":51.5944138,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104777.0,"Objects":[{"StartTime":104777.0,"EndTime":104777.0,"X":416.0,"Y":287.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":104889.0,"EndTime":104889.0,"X":505.9493,"Y":258.8138,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":104999.0,"Objects":[{"StartTime":104999.0,"EndTime":104999.0,"X":421.0,"Y":171.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105111.0,"EndTime":105111.0,"X":343.345825,"Y":156.099213,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105221.0,"Objects":[{"StartTime":105221.0,"EndTime":105221.0,"X":6.0,"Y":333.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105481.0,"EndTime":105481.0,"X":266.63913,"Y":226.153778,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105591.0,"Objects":[{"StartTime":105591.0,"EndTime":105591.0,"X":282.0,"Y":342.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":105777.0,"EndTime":105777.0,"X":211.806335,"Y":290.17868,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":105887.0,"Objects":[{"StartTime":105887.0,"EndTime":105887.0,"X":267.0,"Y":227.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106128.0,"EndTime":106128.0,"X":9.868117,"Y":135.161926,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106258.0,"Objects":[{"StartTime":106258.0,"EndTime":106258.0,"X":89.2608643,"Y":42.2608681}]},{"StartTime":106332.0,"Objects":[{"StartTime":106332.0,"EndTime":106332.0,"X":93.0,"Y":46.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":106407.0,"EndTime":106407.0,"X":88.46499,"Y":92.80315,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":106554.0,"Objects":[{"StartTime":106554.0,"EndTime":106554.0,"X":263.0,"Y":97.0}]},{"StartTime":106665.0,"Objects":[{"StartTime":106665.0,"EndTime":106665.0,"X":295.0,"Y":13.0}]},{"StartTime":106776.0,"Objects":[{"StartTime":106776.0,"EndTime":106776.0,"X":208.0,"Y":24.0}]},{"StartTime":106998.0,"Objects":[{"StartTime":106998.0,"EndTime":106998.0,"X":200.0,"Y":42.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107110.0,"EndTime":107110.0,"X":386.3626,"Y":7.87118,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107221.0,"Objects":[{"StartTime":107221.0,"EndTime":107221.0,"X":357.0,"Y":374.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107333.0,"EndTime":107333.0,"X":247.983688,"Y":239.126038,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107443.0,"Objects":[{"StartTime":107443.0,"EndTime":107443.0,"X":484.0,"Y":299.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107555.0,"EndTime":107555.0,"X":327.92514,"Y":275.123657,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107665.0,"Objects":[{"StartTime":107665.0,"EndTime":107665.0,"X":442.0,"Y":66.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107777.0,"EndTime":107777.0,"X":465.240326,"Y":206.247681,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":107887.0,"Objects":[{"StartTime":107887.0,"EndTime":107887.0,"X":249.0,"Y":215.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":107999.0,"EndTime":107999.0,"X":360.1639,"Y":154.788742,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108110.0,"Objects":[{"StartTime":108110.0,"EndTime":108110.0,"X":141.0,"Y":282.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108222.0,"EndTime":108222.0,"X":45.95927,"Y":337.653381,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108332.0,"Objects":[{"StartTime":108332.0,"EndTime":108332.0,"X":184.0,"Y":48.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108444.0,"EndTime":108444.0,"X":263.1376,"Y":100.1616,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108554.0,"Objects":[{"StartTime":108554.0,"EndTime":108554.0,"X":112.0,"Y":199.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":108740.0,"EndTime":108740.0,"X":-0.18708849,"Y":166.1586,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":108998.0,"Objects":[{"StartTime":108998.0,"EndTime":108998.0,"X":282.0,"Y":102.0}]},{"StartTime":109109.0,"Objects":[{"StartTime":109109.0,"EndTime":109109.0,"X":341.0,"Y":270.0}]},{"StartTime":109221.0,"Objects":[{"StartTime":109221.0,"EndTime":109221.0,"X":468.0,"Y":175.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109296.0,"EndTime":109296.0,"X":473.237274,"Y":117.198364,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109443.0,"Objects":[{"StartTime":109443.0,"EndTime":109443.0,"X":374.0,"Y":199.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":109629.0,"EndTime":109629.0,"X":286.574,"Y":343.009827,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":109887.0,"Objects":[{"StartTime":109887.0,"EndTime":109887.0,"X":133.0,"Y":261.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110017.0,"EndTime":110017.0,"X":-0.9225209,"Y":216.706558,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110109.0,"Objects":[{"StartTime":110109.0,"EndTime":110109.0,"X":0.0,"Y":217.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110350.0,"EndTime":110350.0,"X":84.9857559,"Y":191.816071,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110554.0,"Objects":[{"StartTime":110554.0,"EndTime":110554.0,"X":204.0,"Y":0.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110666.0,"EndTime":110666.0,"X":240.323792,"Y":185.752625,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110776.0,"Objects":[{"StartTime":110776.0,"EndTime":110776.0,"X":512.0,"Y":73.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":110888.0,"EndTime":110888.0,"X":348.896,"Y":13.2173862,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":110999.0,"Objects":[{"StartTime":110999.0,"EndTime":110999.0,"X":5.0,"Y":229.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111111.0,"EndTime":111111.0,"X":107.993919,"Y":349.083069,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111221.0,"Objects":[{"StartTime":111221.0,"EndTime":111221.0,"X":379.0,"Y":213.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111333.0,"EndTime":111333.0,"X":413.133057,"Y":75.231575,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111443.0,"Objects":[{"StartTime":111443.0,"EndTime":111443.0,"X":131.0,"Y":123.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111555.0,"EndTime":111555.0,"X":19.396656,"Y":64.64468,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111666.0,"Objects":[{"StartTime":111666.0,"EndTime":111666.0,"X":130.0,"Y":355.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":111778.0,"EndTime":111778.0,"X":235.003479,"Y":320.128784,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":111888.0,"Objects":[{"StartTime":111888.0,"EndTime":111888.0,"X":335.0,"Y":137.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112000.0,"EndTime":112000.0,"X":255.882919,"Y":188.859985,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112110.0,"Objects":[{"StartTime":112110.0,"EndTime":112110.0,"X":378.0,"Y":233.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112222.0,"EndTime":112222.0,"X":455.50174,"Y":217.178284,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112331.0,"Objects":[{"StartTime":112331.0,"EndTime":112331.0,"X":456.0,"Y":206.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112591.0,"EndTime":112591.0,"X":81.4273148,"Y":265.924347,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112702.0,"Objects":[{"StartTime":112702.0,"EndTime":112702.0,"X":12.0,"Y":151.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":112888.0,"EndTime":112888.0,"X":97.3507156,"Y":181.102722,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":112998.0,"Objects":[{"StartTime":112998.0,"EndTime":112998.0,"X":181.0,"Y":236.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":113184.0,"EndTime":113184.0,"X":4.88930559,"Y":383.485,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":113443.0,"Objects":[{"StartTime":113443.0,"EndTime":113443.0,"X":456.0,"Y":206.0}]},{"StartTime":113554.0,"Objects":[{"StartTime":113554.0,"EndTime":113554.0,"X":456.0,"Y":206.0}]},{"StartTime":113665.0,"Objects":[{"StartTime":113665.0,"EndTime":113665.0,"X":482.0,"Y":120.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":113740.0,"EndTime":113740.0,"X":499.6581,"Y":50.97281,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":113887.0,"Objects":[{"StartTime":113887.0,"EndTime":113887.0,"X":132.0,"Y":70.0}]},{"StartTime":113998.0,"Objects":[{"StartTime":113998.0,"EndTime":113998.0,"X":132.0,"Y":70.0}]},{"StartTime":114109.0,"Objects":[{"StartTime":114109.0,"EndTime":114109.0,"X":0.0,"Y":55.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114221.0,"EndTime":114221.0,"X":251.543,"Y":24.9351,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114331.0,"Objects":[{"StartTime":114331.0,"EndTime":114331.0,"X":482.0,"Y":379.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114443.0,"EndTime":114443.0,"X":262.662476,"Y":346.950684,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114554.0,"Objects":[{"StartTime":114554.0,"EndTime":114554.0,"X":63.0,"Y":2.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114666.0,"EndTime":114666.0,"X":251.470444,"Y":26.0600586,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114776.0,"Objects":[{"StartTime":114776.0,"EndTime":114776.0,"X":420.0,"Y":325.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":114888.0,"EndTime":114888.0,"X":263.0821,"Y":346.123566,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":114998.0,"Objects":[{"StartTime":114998.0,"EndTime":114998.0,"X":132.0,"Y":70.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115110.0,"EndTime":115110.0,"X":250.805573,"Y":26.071888,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115220.0,"Objects":[{"StartTime":115220.0,"EndTime":115220.0,"X":351.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115332.0,"EndTime":115332.0,"X":263.9421,"Y":345.9747,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115443.0,"Objects":[{"StartTime":115443.0,"EndTime":115443.0,"X":187.0,"Y":25.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":115555.0,"EndTime":115555.0,"X":250.209991,"Y":21.0493755,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":115665.0,"Objects":[{"StartTime":115665.0,"EndTime":115665.0,"X":32.0,"Y":192.0}]},{"StartTime":115887.0,"Objects":[{"StartTime":115887.0,"EndTime":115887.0,"X":251.0,"Y":6.0}]},{"StartTime":116109.0,"Objects":[{"StartTime":116109.0,"EndTime":116109.0,"X":480.0,"Y":192.0}]},{"StartTime":116331.0,"Objects":[{"StartTime":116331.0,"EndTime":116331.0,"X":261.0,"Y":378.0}]},{"StartTime":116554.0,"Objects":[{"StartTime":116554.0,"EndTime":116554.0,"X":274.0,"Y":103.0}]},{"StartTime":116665.0,"Objects":[{"StartTime":116665.0,"EndTime":116665.0,"X":299.0,"Y":223.0}]},{"StartTime":116776.0,"Objects":[{"StartTime":116776.0,"EndTime":116776.0,"X":176.0,"Y":174.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":116888.0,"EndTime":116888.0,"X":50.2636871,"Y":182.550323,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":116998.0,"Objects":[{"StartTime":116998.0,"EndTime":116998.0,"X":51.0,"Y":183.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117036.0,"EndTime":117036.0,"X":104.161346,"Y":152.739212,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":117220.0,"Objects":[{"StartTime":117220.0,"EndTime":117220.0,"X":248.0,"Y":277.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117480.0,"EndTime":117480.0,"X":181.608841,"Y":182.857773,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":117665.0,"Objects":[{"StartTime":117665.0,"EndTime":117665.0,"X":418.0,"Y":77.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117777.0,"EndTime":117777.0,"X":447.550781,"Y":328.603882,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":117887.0,"Objects":[{"StartTime":117887.0,"EndTime":117887.0,"X":228.0,"Y":360.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":117999.0,"EndTime":117999.0,"X":447.40863,"Y":328.441223,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118109.0,"Objects":[{"StartTime":118109.0,"EndTime":118109.0,"X":471.0,"Y":140.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118221.0,"EndTime":118221.0,"X":447.093933,"Y":328.490051,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118331.0,"Objects":[{"StartTime":118331.0,"EndTime":118331.0,"X":290.0,"Y":307.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118443.0,"EndTime":118443.0,"X":446.999,"Y":327.512421,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118554.0,"Objects":[{"StartTime":118554.0,"EndTime":118554.0,"X":400.0,"Y":210.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118666.0,"EndTime":118666.0,"X":446.4021,"Y":327.861328,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118776.0,"Objects":[{"StartTime":118776.0,"EndTime":118776.0,"X":362.0,"Y":369.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":118888.0,"EndTime":118888.0,"X":446.970581,"Y":326.5147,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":118998.0,"Objects":[{"StartTime":118998.0,"EndTime":118998.0,"X":440.0,"Y":263.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119110.0,"EndTime":119110.0,"X":446.899323,"Y":325.956421,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":119220.0,"Objects":[{"StartTime":119220.0,"EndTime":119220.0,"X":402.0,"Y":310.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119332.0,"EndTime":119332.0,"X":446.77478,"Y":325.857727,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":119443.0,"Objects":[{"StartTime":119443.0,"EndTime":119443.0,"X":208.0,"Y":369.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119703.0,"EndTime":119703.0,"X":10.0663357,"Y":300.209625,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":119813.0,"Objects":[{"StartTime":119813.0,"EndTime":119813.0,"X":90.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":119999.0,"EndTime":119999.0,"X":123.387047,"Y":295.620728,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":120109.0,"Objects":[{"StartTime":120109.0,"EndTime":120109.0,"X":328.0,"Y":170.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":120295.0,"EndTime":120295.0,"X":480.93573,"Y":118.882164,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":120480.0,"Objects":[{"StartTime":120480.0,"EndTime":120480.0,"X":322.260864,"Y":186.260864}]},{"StartTime":120554.0,"Objects":[{"StartTime":120554.0,"EndTime":120554.0,"X":326.0,"Y":190.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":120666.0,"EndTime":120666.0,"X":236.184631,"Y":160.0903,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":120776.0,"Objects":[{"StartTime":120776.0,"EndTime":120776.0,"X":0.0,"Y":156.0}]},{"StartTime":120887.0,"Objects":[{"StartTime":120887.0,"EndTime":120887.0,"X":104.0,"Y":100.0}]},{"StartTime":120998.0,"Objects":[{"StartTime":120998.0,"EndTime":120998.0,"X":97.0,"Y":220.0}]},{"StartTime":121220.0,"Objects":[{"StartTime":121220.0,"EndTime":121220.0,"X":135.0,"Y":351.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121332.0,"EndTime":121332.0,"X":103.97979,"Y":99.57303,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":121443.0,"Objects":[{"StartTime":121443.0,"EndTime":121443.0,"X":249.0,"Y":9.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121555.0,"EndTime":121555.0,"X":217.011963,"Y":228.346481,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":121665.0,"Objects":[{"StartTime":121665.0,"EndTime":121665.0,"X":0.0,"Y":249.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121777.0,"EndTime":121777.0,"X":21.9232922,"Y":60.269043,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":121887.0,"Objects":[{"StartTime":121887.0,"EndTime":121887.0,"X":318.0,"Y":198.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":121999.0,"EndTime":121999.0,"X":342.0135,"Y":354.50174,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122109.0,"Objects":[{"StartTime":122109.0,"EndTime":122109.0,"X":48.0,"Y":366.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":122221.0,"EndTime":122221.0,"X":-0.5152321,"Y":248.992676,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122331.0,"Objects":[{"StartTime":122331.0,"EndTime":122331.0,"X":360.0,"Y":102.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":122443.0,"EndTime":122443.0,"X":406.299774,"Y":184.953781,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122554.0,"Objects":[{"StartTime":122554.0,"EndTime":122554.0,"X":148.0,"Y":384.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":122666.0,"EndTime":122666.0,"X":140.908722,"Y":321.0649,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":122776.0,"Objects":[{"StartTime":122776.0,"EndTime":122776.0,"X":256.0,"Y":48.0}]},{"StartTime":122998.0,"Objects":[{"StartTime":122998.0,"EndTime":122998.0,"X":256.0,"Y":368.0}]},{"StartTime":123220.0,"Objects":[{"StartTime":123220.0,"EndTime":123220.0,"X":256.0,"Y":48.0}]},{"StartTime":123443.0,"Objects":[{"StartTime":123443.0,"EndTime":123443.0,"X":256.0,"Y":368.0}]},{"StartTime":123665.0,"Objects":[{"StartTime":123665.0,"EndTime":123665.0,"X":256.0,"Y":368.0}]},{"StartTime":123776.0,"Objects":[{"StartTime":123776.0,"EndTime":123776.0,"X":280.0,"Y":233.0}]},{"StartTime":123887.0,"Objects":[{"StartTime":123887.0,"EndTime":123887.0,"X":404.0,"Y":307.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":123999.0,"EndTime":123999.0,"X":474.8864,"Y":229.730469,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124109.0,"Objects":[{"StartTime":124109.0,"EndTime":124109.0,"X":497.0,"Y":219.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":124147.0,"EndTime":124147.0,"X":451.113678,"Y":182.153015,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124331.0,"Objects":[{"StartTime":124331.0,"EndTime":124331.0,"X":208.0,"Y":309.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":124591.0,"EndTime":124591.0,"X":84.4982452,"Y":283.459045,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124776.0,"Objects":[{"StartTime":124776.0,"EndTime":124776.0,"X":88.0,"Y":81.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":124888.0,"EndTime":124888.0,"X":205.119614,"Y":305.625366,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":124998.0,"Objects":[{"StartTime":124998.0,"EndTime":124998.0,"X":243.0,"Y":156.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125110.0,"EndTime":125110.0,"X":29.6648064,"Y":19.4357738,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125220.0,"Objects":[{"StartTime":125220.0,"EndTime":125220.0,"X":0.0,"Y":250.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125332.0,"EndTime":125332.0,"X":239.246033,"Y":166.903748,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125443.0,"Objects":[{"StartTime":125443.0,"EndTime":125443.0,"X":363.0,"Y":16.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125555.0,"EndTime":125555.0,"X":263.409576,"Y":248.917145,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125665.0,"Objects":[{"StartTime":125665.0,"EndTime":125665.0,"X":458.0,"Y":340.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125777.0,"EndTime":125777.0,"X":205.791092,"Y":319.9836,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":125887.0,"Objects":[{"StartTime":125887.0,"EndTime":125887.0,"X":186.0,"Y":7.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":125999.0,"EndTime":125999.0,"X":263.27887,"Y":247.991531,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":126109.0,"Objects":[{"StartTime":126109.0,"EndTime":126109.0,"X":461.0,"Y":349.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":126221.0,"EndTime":126221.0,"X":363.435455,"Y":268.3229,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":126331.0,"Objects":[{"StartTime":126331.0,"EndTime":126331.0,"X":441.0,"Y":193.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":126443.0,"EndTime":126443.0,"X":502.8478,"Y":183.218109,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":126554.0,"Objects":[{"StartTime":126554.0,"EndTime":126554.0,"X":503.0,"Y":184.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":126814.0,"EndTime":126814.0,"X":261.078461,"Y":357.8552,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":126924.0,"Objects":[{"StartTime":126924.0,"EndTime":126924.0,"X":456.0,"Y":357.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":127110.0,"EndTime":127110.0,"X":365.160217,"Y":344.232941,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":127220.0,"Objects":[{"StartTime":127220.0,"EndTime":127220.0,"X":0.0,"Y":47.0,"StackOffset":{"X":0.0,"Y":0.0}},{"StartTime":127517.0,"EndTime":127517.0,"X":202.168015,"Y":158.1352,"StackOffset":{"X":0.0,"Y":0.0}}]},{"StartTime":127665.0,"Objects":[{"StartTime":127665.0,"EndTime":127665.0,"X":193.0,"Y":159.0}]},{"StartTime":127813.0,"Objects":[{"StartTime":127813.0,"EndTime":127813.0,"X":17.2608681,"Y":206.260864}]},{"StartTime":127887.0,"Objects":[{"StartTime":127887.0,"EndTime":127887.0,"X":21.0,"Y":210.0}]},{"StartTime":128035.0,"Objects":[{"StartTime":128035.0,"EndTime":128035.0,"X":145.260864,"Y":327.260864}]},{"StartTime":128109.0,"Objects":[{"StartTime":128109.0,"EndTime":128109.0,"X":149.0,"Y":331.0}]},{"StartTime":128257.0,"Objects":[{"StartTime":128257.0,"EndTime":128257.0,"X":202.0,"Y":158.0}]}]} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513.osu b/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513.osu deleted file mode 100644 index 01b85774e88b..000000000000 --- a/osu.Game.Rulesets.Osu.Tests/Resources/Testing/Beatmaps/4235513.osu +++ /dev/null @@ -1,825 +0,0 @@ -osu file format v14 - -[General] -AudioLeadIn: 0 -PreviewTime: 10692 -Countdown: 0 -SampleSet: Soft -StackLeniency: 0.2 -Mode: 0 -LetterboxInBreaks: 1 -WidescreenStoryboard: 1 - -[Difficulty] -HPDrainRate:5 -CircleSize:3.8 -OverallDifficulty:8.5 -ApproachRate:9.3 -SliderMultiplier:1.9 -SliderTickRate:1 - -[Events] -//Background and Video events -//Break Periods -2,16309,17555 -//Storyboard Layer 0 (Background) -//Storyboard Layer 1 (Fail) -//Storyboard Layer 2 (Pass) -//Storyboard Layer 3 (Foreground) -//Storyboard Layer 4 (Overlay) -//Storyboard Sound Samples - -[TimingPoints] -332,444.444444444444,4,2,0,66,1,0 -14554,-100,4,2,50,30,0,0 -16109,-100,4,2,50,15,0,0 -18109,-80,4,2,50,50,0,0 -18702,-80,4,2,50,5,0,0 -18776,-80,4,2,50,50,0,0 -19813,-80,4,2,50,5,0,0 -19887,-66.6666666666667,4,2,50,50,0,0 -20257,-66.6666666666667,4,2,50,5,0,0 -20331,-66.6666666666667,4,2,50,50,0,0 -20479,-66.6666666666667,4,2,50,5,0,0 -20554,-66.6666666666667,4,2,50,50,0,0 -21220,-133.333333333333,4,2,50,50,0,0 -21590,-133.333333333333,4,2,50,5,0,0 -21665,-80,4,2,50,50,0,0 -22220,-80,4,2,50,5,0,0 -22331,-80,4,2,50,50,0,0 -22924,-80,4,2,50,5,0,0 -22998,-80,4,2,50,50,0,0 -24331,-100,4,2,50,50,0,0 -24776,-80,4,2,50,50,0,0 -25146,-80,4,2,50,5,0,0 -25220,-80,4,2,50,50,0,0 -25776,-80,4,2,50,5,0,0 -25887,-80,4,2,50,50,0,0 -26998,-66.6666666666667,4,2,50,50,0,0 -27294,-66.6666666666667,4,2,50,5,0,0 -27369,-66.6666666666667,4,2,50,50,0,0 -27591,-66.6666666666667,4,2,50,5,0,0 -27665,-66.6666666666667,4,2,50,50,0,0 -30035,-66.6666666666667,4,2,50,5,0,0 -30109,-66.6666666666667,4,2,50,50,0,0 -31443,-80,4,2,50,50,0,0 -31609,-80,4,2,50,5,0,0 -31665,-66.6666666666667,4,2,50,50,0,0 -32887,-66.6666666666667,4,2,50,5,0,0 -32998,-66.6666666666667,4,2,50,50,0,0 -33443,-100,4,2,50,50,0,0 -34109,-66.6666666666667,4,2,50,50,0,0 -34887,-66.6666666666667,4,2,50,5,0,0 -34998,-80,4,2,50,50,0,0 -35813,-80,4,2,50,5,0,0 -35887,-66.6666666666667,4,2,50,50,0,0 -36442,-66.6666666666667,4,2,50,5,0,0 -36554,-66.6666666666667,4,2,50,50,0,0 -36998,-80,4,2,50,50,0,0 -37146,-80,4,2,50,5,0,0 -37220,-80,4,2,50,50,0,0 -39443,-66.6666666666667,4,2,50,50,0,0 -40702,-66.6666666666667,4,2,50,5,0,0 -40776,-66.6666666666667,4,2,50,50,0,0 -41368,-66.6666666666667,4,2,50,5,0,0 -41443,-100,4,2,50,50,0,0 -41591,-100,4,2,50,5,0,0 -41665,-100,4,2,50,50,0,0 -41813,-100,4,2,50,5,0,0 -41887,-80,4,2,50,50,0,0 -42109,-133.333333333333,4,2,50,50,0,0 -42442,-133.333333333333,4,2,50,5,0,0 -42554,-50,4,2,50,50,0,0 -42887,-50,4,2,50,5,0,0 -42998,-133.333333333333,4,2,2,30,0,0 -44664,-133.333333333333,4,2,2,5,0,0 -44776,-133.333333333333,4,2,2,30,0,0 -47590,-133.333333333333,4,2,2,5,0,0 -47665,-133.333333333333,4,2,2,30,0,0 -50035,-133.333333333333,4,2,2,5,0,0 -50109,-133.333333333333,4,2,2,30,0,0 -51812,-133.333333333333,4,2,2,5,0,0 -51887,-133.333333333333,4,2,2,30,0,0 -54701,-133.333333333333,4,2,2,5,0,0 -54776,-133.333333333333,4,2,2,30,0,0 -56554,-133.333333333333,4,2,50,15,0,0 -57220,-33.3333333333333,4,2,50,65,0,1 -57368,-33.3333333333333,4,2,50,5,0,1 -57443,-36.3636363636364,4,2,50,65,0,0 -57591,-36.3636363636364,4,2,50,5,0,0 -57665,-40,4,2,50,65,0,0 -57813,-40,4,2,50,5,0,0 -57887,-44.4444444444445,4,2,50,65,0,0 -58035,-44.4444444444445,4,2,50,5,0,0 -58109,-50,4,2,50,65,0,0 -58257,-50,4,2,50,5,0,0 -58332,-57.1428571428571,4,2,50,65,0,0 -58480,-57.1428571428571,4,2,50,5,0,0 -58554,-66.6666666666667,4,2,50,65,0,0 -58702,-66.6666666666667,4,2,50,5,0,0 -58776,-80,4,2,50,65,0,0 -59554,-80,4,2,50,5,0,0 -59665,-50,4,2,50,65,0,0 -60275,-50,4,2,50,5,0,0 -60331,-133.333333333333,4,2,50,65,0,0 -60664,-133.333333333333,4,2,50,5,0,0 -60776,-33.3333333333333,4,2,50,65,0,1 -60924,-33.3333333333333,4,2,50,5,0,1 -60998,-36.3636363636364,4,2,50,65,0,0 -61147,-36.3636363636364,4,2,50,5,0,0 -61221,-40,4,2,50,65,0,0 -61369,-40,4,2,50,5,0,0 -61443,-44.4444444444445,4,2,50,65,0,0 -61591,-44.4444444444445,4,2,50,5,0,0 -61665,-50,4,2,50,65,0,0 -61813,-50,4,2,50,5,0,0 -61888,-57.1428571428571,4,2,50,65,0,0 -62036,-57.1428571428571,4,2,50,5,0,0 -62110,-66.6666666666667,4,2,50,65,0,0 -62258,-66.6666666666667,4,2,50,5,0,0 -62332,-80,4,2,50,65,0,0 -62480,-80,4,2,50,5,0,0 -62554,-33.3333333333333,4,2,50,65,0,0 -62850,-33.3333333333333,4,2,50,5,0,0 -62924,-100,4,2,50,65,0,0 -63072,-100,4,2,50,5,0,0 -63220,-33.3333333333333,4,2,50,65,0,0 -63516,-33.3333333333333,4,2,50,5,0,0 -63554,-100,4,2,50,65,0,0 -64331,-33.3333333333333,4,2,50,65,0,1 -64479,-33.3333333333333,4,2,50,5,0,1 -64554,-36.3636363636364,4,2,50,65,0,0 -64702,-36.3636363636364,4,2,50,5,0,0 -64776,-40,4,2,50,65,0,0 -64924,-40,4,2,50,5,0,0 -64998,-44.4444444444445,4,2,50,65,0,0 -65146,-44.4444444444445,4,2,50,5,0,0 -65220,-50,4,2,50,65,0,0 -65386,-50,4,2,50,5,0,0 -65443,-57.1428571428571,4,2,50,65,0,0 -65591,-57.1428571428571,4,2,50,5,0,0 -65665,-66.6666666666667,4,2,50,65,0,0 -65813,-66.6666666666667,4,2,50,5,0,0 -65887,-80,4,2,50,65,0,0 -66702,-80,4,2,50,5,0,0 -66776,-50,4,2,50,65,0,0 -67387,-50,4,2,50,5,0,0 -67443,-133.333333333333,4,2,50,65,0,0 -67776,-133.333333333333,4,2,50,5,0,0 -67887,-33.3333333333333,4,2,50,65,0,1 -68035,-33.3333333333333,4,2,50,5,0,1 -68109,-36.3636363636364,4,2,50,65,0,0 -68258,-36.3636363636364,4,2,50,5,0,0 -68332,-40,4,2,50,65,0,0 -68480,-40,4,2,50,5,0,0 -68554,-44.4444444444445,4,2,50,65,0,0 -68702,-44.4444444444445,4,2,50,5,0,0 -68776,-50,4,2,50,65,0,0 -68924,-50,4,2,50,5,0,0 -68999,-57.1428571428571,4,2,50,65,0,0 -69147,-57.1428571428571,4,2,50,5,0,0 -69220,-66.6666666666667,4,2,50,65,0,0 -69369,-66.6666666666667,4,2,50,5,0,0 -69443,-80,4,2,50,65,0,0 -69581,-80,4,2,50,5,0,0 -69665,-33.3333333333333,4,2,50,65,0,0 -69961,-33.3333333333333,4,2,50,5,0,0 -70035,-100,4,2,50,65,0,0 -70173,-100,4,2,50,5,0,0 -70331,-33.3333333333333,4,2,50,65,0,0 -70627,-33.3333333333333,4,2,50,5,0,0 -70776,-33.3333333333333,4,2,50,65,0,0 -71109,-33.3333333333333,4,2,50,5,0,0 -71220,-50,4,2,50,65,0,0 -71331,-50,4,2,50,5,0,0 -71443,-100,4,2,50,40,0,0 -76776,-66.6666666666667,4,2,50,40,0,0 -77220,-100,4,2,50,40,0,0 -77331,-100,4,2,50,5,0,0 -77443,-66.6666666666667,4,2,50,40,0,0 -78998,-100,4,2,50,40,0,0 -79331,-100,4,2,50,5,0,0 -79443,-100,4,2,50,40,0,0 -80665,-100,4,2,50,5,0,0 -80776,-100,4,2,50,40,0,0 -81109,-100,4,2,50,5,0,0 -81220,-100,4,2,50,40,0,0 -81443,-66.6666666666667,4,2,50,40,0,0 -82109,-100,4,2,50,40,0,0 -83443,-100,4,2,50,40,0,0 -83813,-100,4,2,50,5,0,0 -83887,-66.6666666666667,4,2,50,40,0,0 -84331,-100,4,2,50,40,0,0 -84479,-100,4,2,50,5,0,0 -84554,-66.6666666666667,4,2,50,40,0,0 -85665,-66.6666666666667,4,2,50,20,0,0 -92776,-133.333333333333,4,2,50,30,0,0 -93109,-100,4,2,50,30,0,0 -93331,-100,4,2,50,5,0,0 -93443,-80,4,2,50,30,0,0 -93813,-80,4,2,50,5,0,0 -93887,-100,4,2,50,30,0,0 -96887,-100,4,2,50,5,0,0 -96998,-100,4,2,50,30,0,0 -97368,-100,4,2,50,5,0,0 -97443,-100,4,2,50,30,0,0 -98035,-100,4,2,50,5,0,0 -98109,-100,4,2,50,30,0,0 -99220,-100,4,2,50,15,0,0 -99887,-33.3333333333333,4,2,50,65,0,1 -100035,-33.3333333333333,4,2,50,5,0,1 -100109,-36.3636363636364,4,2,50,65,0,0 -100258,-36.3636363636364,4,2,50,5,0,0 -100332,-40,4,2,50,65,0,0 -100480,-40,4,2,50,5,0,0 -100554,-44.4444444444445,4,2,50,65,0,0 -100702,-44.4444444444445,4,2,50,5,0,0 -100776,-50,4,2,50,65,0,0 -100924,-50,4,2,50,5,0,0 -100999,-57.1428571428571,4,2,50,65,0,0 -101165,-57.1428571428571,4,2,50,5,0,0 -101221,-66.6666666666667,4,2,50,65,0,0 -101369,-66.6666666666667,4,2,50,5,0,0 -101443,-80,4,2,50,65,0,0 -102221,-80,4,2,50,5,0,0 -102332,-50,4,2,50,65,0,0 -102942,-50,4,2,50,5,0,0 -102998,-133.333333333333,4,2,50,65,0,0 -103331,-133.333333333333,4,2,50,5,0,0 -103443,-33.3333333333333,4,2,50,65,0,1 -103591,-33.3333333333333,4,2,50,5,0,1 -103665,-36.3636363636364,4,2,50,65,0,0 -103814,-36.3636363636364,4,2,50,5,0,0 -103888,-40,4,2,50,65,0,0 -104036,-40,4,2,50,5,0,0 -104110,-44.4444444444445,4,2,50,65,0,0 -104258,-44.4444444444445,4,2,50,5,0,0 -104332,-50,4,2,50,65,0,0 -104480,-50,4,2,50,5,0,0 -104555,-57.1428571428571,4,2,50,65,0,0 -104703,-57.1428571428571,4,2,50,5,0,0 -104777,-66.6666666666667,4,2,50,65,0,0 -104925,-66.6666666666667,4,2,50,5,0,0 -104999,-80,4,2,50,65,0,0 -105147,-80,4,2,50,5,0,0 -105221,-33.3333333333333,4,2,50,65,0,0 -105517,-33.3333333333333,4,2,50,5,0,0 -105591,-100,4,2,50,65,0,0 -105813,-100,4,2,50,5,0,0 -105887,-33.3333333333333,4,2,50,65,0,0 -106164,-33.3333333333333,4,2,50,5,0,0 -106221,-100,4,2,50,65,0,0 -106998,-33.3333333333333,4,2,50,65,0,1 -107146,-33.3333333333333,4,2,50,5,0,1 -107220,-36.3636363636364,4,2,50,65,0,0 -107369,-36.3636363636364,4,2,50,5,0,0 -107443,-40,4,2,50,65,0,0 -107591,-40,4,2,50,5,0,0 -107665,-44.4444444444445,4,2,50,65,0,0 -107813,-44.4444444444445,4,2,50,5,0,0 -107887,-50,4,2,50,65,0,0 -108035,-50,4,2,50,5,0,0 -108110,-57.1428571428571,4,2,50,65,0,0 -108258,-57.1428571428571,4,2,50,5,0,0 -108332,-66.6666666666667,4,2,50,65,0,0 -108480,-66.6666666666667,4,2,50,5,0,0 -108554,-80,4,2,50,65,0,0 -109332,-80,4,2,50,5,0,0 -109443,-50,4,2,50,65,0,0 -110053,-50,4,2,50,5,0,0 -110109,-133.333333333333,4,2,50,65,0,0 -110386,-133.333333333333,4,2,50,5,0,0 -110554,-33.3333333333333,4,2,50,65,0,1 -110702,-33.3333333333333,4,2,50,5,0,1 -110776,-36.3636363636364,4,2,50,65,0,0 -110925,-36.3636363636364,4,2,50,5,0,0 -110999,-40,4,2,50,65,0,0 -111147,-40,4,2,50,5,0,0 -111221,-44.4444444444445,4,2,50,65,0,0 -111369,-44.4444444444445,4,2,50,5,0,0 -111443,-50,4,2,50,65,0,0 -111591,-50,4,2,50,5,0,0 -111666,-57.1428571428571,4,2,50,65,0,0 -111814,-57.1428571428571,4,2,50,5,0,0 -111888,-66.6666666666667,4,2,50,65,0,0 -112036,-66.6666666666667,4,2,50,5,0,0 -112110,-80,4,2,50,65,0,0 -112258,-80,4,2,50,5,0,0 -112331,-33.3333333333333,4,2,50,65,0,0 -112627,-33.3333333333333,4,2,50,5,0,0 -112702,-100,4,2,50,65,0,0 -112924,-100,4,2,50,5,0,0 -112998,-33.3333333333333,4,2,50,65,0,0 -113443,-66.6666666666667,4,2,50,65,0,0 -113776,-66.6666666666667,4,2,50,5,0,0 -113887,-66.6666666666667,4,2,50,65,0,0 -114109,-25,4,2,50,65,0,1 -114257,-25,4,2,50,5,0,1 -114331,-28.5714285714286,4,2,50,65,0,0 -114479,-28.5714285714286,4,2,50,5,0,0 -114554,-33.3333333333333,4,2,50,65,0,1 -114702,-33.3333333333333,4,2,50,5,0,1 -114776,-40,4,2,50,65,0,0 -114924,-40,4,2,50,5,0,0 -114998,-50,4,2,50,65,0,1 -115146,-50,4,2,50,5,0,1 -115220,-66.6666666666667,4,2,50,65,0,0 -115368,-66.6666666666667,4,2,50,5,0,0 -115443,-100,4,2,50,65,0,1 -115591,-100,4,2,50,5,0,1 -115665,-50,4,2,50,65,0,0 -116924,-50,4,2,50,5,0,0 -116998,-50,4,2,50,65,0,0 -117072,-50,4,2,50,5,0,0 -117220,-100,4,2,50,65,0,0 -117516,-100,4,2,50,5,0,0 -117665,-25,4,2,50,65,0,1 -117813,-25,4,2,50,5,0,1 -117887,-28.5714285714286,4,2,50,65,0,0 -118035,-28.5714285714286,4,2,50,5,0,0 -118109,-33.3333333333333,4,2,50,65,0,1 -118258,-33.3333333333333,4,2,50,5,0,1 -118331,-40,4,2,50,65,0,0 -118480,-40,4,2,50,5,0,0 -118554,-50,4,2,50,65,0,1 -118702,-50,4,2,50,5,0,1 -118776,-66.6666666666667,4,2,50,65,0,0 -118924,-66.6666666666667,4,2,50,5,0,0 -118998,-100,4,2,50,65,0,1 -119146,-100,4,2,50,5,0,1 -119220,-133.333333333333,4,2,50,65,0,0 -119368,-200,4,2,50,5,0,0 -119443,-33.3333333333333,4,2,50,65,0,0 -119739,-33.3333333333333,4,2,50,5,0,0 -119813,-100,4,2,50,65,0,0 -120035,-100,4,2,50,5,0,0 -120109,-33.3333333333333,4,2,50,65,0,0 -120480,-66.6666666666667,4,2,50,65,0,0 -120702,-66.6666666666667,4,2,50,5,0,0 -120776,-66.6666666666667,4,2,50,65,0,0 -121220,-25,4,2,50,65,0,1 -121368,-25,4,2,50,5,0,1 -121443,-28.5714285714286,4,2,50,65,0,0 -121590,-28.5714285714286,4,2,50,5,0,0 -121665,-33.3333333333333,4,2,50,65,0,1 -121813,-33.3333333333333,4,2,50,5,0,1 -121887,-40,4,2,50,65,0,0 -122035,-40,4,2,50,5,0,0 -122109,-50,4,2,50,65,0,1 -122257,-50,4,2,50,5,0,1 -122331,-66.6666666666667,4,2,50,65,0,0 -122479,-66.6666666666667,4,2,50,5,0,0 -122554,-100,4,2,50,65,0,1 -122702,-100,4,2,50,5,0,1 -122776,-50,4,2,50,65,0,0 -124035,-50,4,2,50,5,0,0 -124109,-50,4,2,50,65,0,0 -124183,-50,4,2,50,5,0,0 -124331,-100,4,2,50,65,0,0 -124627,-100,4,2,50,5,0,0 -124776,-25,4,2,50,65,0,1 -124924,-25,4,2,50,5,0,1 -124998,-25,4,2,50,65,0,1 -125146,-25,4,2,50,5,0,1 -125220,-25,4,2,50,65,0,1 -125368,-25,4,2,50,5,0,1 -125443,-25,4,2,50,65,0,1 -125591,-25,4,2,50,5,0,1 -125665,-25,4,2,50,65,0,1 -125813,-25,4,2,50,5,0,1 -125887,-25,4,2,50,65,0,1 -126035,-25,4,2,50,5,0,1 -126109,-50,4,2,50,65,0,1 -126257,-50,4,2,50,5,0,1 -126331,-100,4,2,50,65,0,0 -126479,-100,4,2,50,5,0,0 -126554,-33.3333333333333,4,2,50,65,0,0 -126850,-33.3333333333333,4,2,50,5,0,0 -126924,-100,4,2,50,65,0,0 -127146,-100,4,2,50,5,0,0 -127220,-50,4,2,50,65,0,0 -127553,-50,4,2,50,5,0,0 -127665,-50,4,2,50,65,0,0 - - -[Colours] -Combo1 : 141,216,109 -Combo2 : 191,181,119 - -[HitObjects] -140,242,14554,6,0,P|152:283|160:348,2,95,4|2|8,2:2|2:3|2:2,0:0:0:0: -98,147,15146,1,0,0:0:0:0: -90,162,15220,2,0,P|61:175|16:180,1,63.3333333333333,2|0,2:3|1:1,0:0:0:0: -30,180,15665,1,0,1:1:0:0: -252,94,15887,1,8,2:2:0:0: -453,164,16109,5,0,0:0:0:0: -462,154,18109,6,0,P|383:120|367:77,1,118.75,4|2,2:1|2:3,0:0:0:0: -335,24,18480,1,0,0:0:0:0: -335,24,18554,2,0,P|291:38|221:36,1,79.1666666666667,8|0,2:2|0:0,0:0:0:0: -168,119,18776,2,0,P|211:118|274:139,1,79.1666666666667,2|0,2:3|1:1,0:0:0:0: -246,126,19220,5,0,1:1:0:0: -115,44,19443,1,8,2:2:0:0: -104,194,19665,2,0,P|115:227|121:277,1,79.1666666666667,2|0,2:2|0:0,0:0:0:0: -48,124,19887,6,0,P|16:185|76:340,1,237.500009059906,2|0,2:2|0:0,0:0:0:0: -153,346,20331,2,0,P|201:335|251:329,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: -246,329,20554,2,0,P|250:279|201:237,1,95.0000036239625,2|0,2:2|1:1,0:0:0:0: -223,245,20776,5,2,2:2:0:0: -355,384,20924,1,2,2:3:0:0: -355,384,20998,1,0,1:1:0:0: -505,303,21220,2,0,P|447:290|390:271,1,118.750004529953,10|0,2:2|0:0,0:0:0:0: -375,269,21665,6,0,P|345:334|359:398,1,118.75,0|2,1:1|2:3,0:0:0:0: -309,215,21998,6,0,P|267:156|205:136,1,118.75 -389,184,22331,6,0,P|460:177|484:148,1,79.1666666666667,2|0,2:3|1:1,0:0:0:0: -463,174,22776,6,0,P|485:127|477:84,1,79.1666666666667,0|0,1:1|0:0,0:0:0:0: -330,0,22998,2,0,P|338:52|341:130,1,118.75,8|2,2:2|2:3,0:0:0:0: -341,118,23443,5,2,2:2:0:0: -417,37,23665,1,2,2:2:0:0: -384,274,23887,1,10,2:2:0:0: -189,125,24109,1,2,2:2:0:0: -164,50,24257,5,0,1:1:0:0: -164,50,24331,2,0,L|280:59,1,95,2|0,2:2|1:1,0:0:0:0: -259,59,24776,2,0,P|170:64|83:-9,1,197.916666666667,10|0,2:2|0:0,0:0:0:0: -39,64,25220,6,0,P|36:115|27:197,1,118.75,2|2,2:1|2:3,0:0:0:0: -145,273,25554,2,0,P|85:266|26:262,1,118.75 -234,202,25887,2,0,P|230:242|231:282,1,79.1666666666667,0|0,1:1|1:1,0:0:0:0: -231,282,26331,5,0,1:1:0:0: -12,377,26554,2,0,P|31:327|14:237,1,118.75,8|2,2:2|2:2,0:0:0:0: -234,202,26998,6,0,B|366:201|309:182|425:185,1,190.000007247925,2|0,2:2|0:0,0:0:0:0: -491,238,27369,1,0,0:0:0:0: -491,238,27443,2,0,P|444:271|378:262,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: -407,100,27665,2,0,P|453:105|490:134,1,95.0000036239625,2|0,2:2|1:1,0:0:0:0: -491,238,27887,5,2,2:2:0:0: -342,157,28109,1,0,1:1:0:0: -342,157,28183,1,2,2:2:0:0: -300,343,28443,5,2,0:0:0:0: -300,343,28776,6,0,P|394:320|508:388,2,213.750008153916,4|0|2,1:1|0:0|2:3,0:0:0:0: -285,110,29887,6,0,P|370:94|388:78,1,95.0000036239625,0|0,1:1|0:0,0:0:0:0: -474,9,30109,2,0,P|450:63|368:105,1,142.500005435944,8|2,2:2|2:3,0:0:0:0: -194,141,30554,5,2,2:2:0:0: -220,46,30776,1,2,2:2:0:0: -153,228,30998,5,10,2:2:0:0: -46,31,31220,1,2,2:2:0:0: -58,210,31369,5,2,2:3:0:0: -63,213,31443,2,0,P|104:213|171:199,1,89.0625,2|0,2:2|0:0,0:0:0:0: -245,224,31665,6,0,P|200:224|134:237,1,95.0000036239625,0|0,1:1|2:2,0:0:0:0: -87,292,31887,1,8,2:2:0:0: -87,292,31961,2,0,P|88:332|101:371,2,47.5000018119813,2|2|2,2:2|2:3|2:3,0:0:0:0: -40,20,32331,6,0,P|9:70|32:152,1,142.500005435944,0|2,1:1|2:3,0:0:0:0: -138,81,32665,2,0,P|110:29|27:8,1,142.500005435944 -38,140,32998,2,0,P|96:141|156:80,1,142.500005435944,0|0,1:1|0:0,0:0:0:0: -154,86,33443,6,0,P|212:80|247:70,1,95,0|8,1:1|2:2,0:0:0:0: -286,0,33776,1,0,0:0:0:0: -286,0,33887,1,2,2:2:0:0: -258,218,34109,6,0,P|271:292|271:368,2,142.500005435944,2|2|10,2:2|2:2|2:2,0:0:0:0: -380,251,34776,2,0,P|372:282|368:344,1,71.2500027179719,2|0,2:2|0:0,0:0:0:0: -471,384,34998,2,0,P|461:330|459:253,1,118.75,2|0,2:2|1:1,0:0:0:0: -260,217,35443,5,8,2:2:0:0: -161,298,35591,1,2,2:2:0:0: -161,298,35665,2,0,P|179:354|188:391,1,79.1666666666667,2|0,2:3|0:0,0:0:0:0: -46,246,35887,6,0,P|29:314|43:384,1,142.500005435944,0|2,1:1|2:3,0:0:0:0: -256,216,36220,2,0,P|189:192|120:205,1,142.500005435944 -371,232,36554,2,0,P|438:227|524:210,1,142.500005435944,2|0,2:3|0:0,0:0:0:0: -511,213,36998,6,0,P|497:171|496:130,1,79.1666666666667,0|0,1:1|0:0,0:0:0:0: -381,36,37220,2,0,P|376:78|428:153,1,118.75,8|2,2:2|2:3,0:0:0:0: -472,55,37665,5,2,2:2:0:0: -368,17,37887,1,2,2:2:0:0: -114,109,38109,5,10,2:2:0:0: -269,65,38331,1,2,2:2:0:0: -12,84,38554,5,2,2:1:0:0: -482,60,38998,1,10,2:1:0:0: -225,293,39443,6,0,P|129:279|22:359,2,213.750008153916,0|0|0,1:1|0:0|1:1,0:0:0:0: -511,364,40554,6,0,P|424:367|403:355,1,95.0000036239625,0|0,1:1|0:0,0:0:0:0: -322,284,40776,2,0,P|346:338|428:380,1,142.500005435944,8|2,2:2|2:3,0:0:0:0: -470,283,41146,5,0,0:0:0:0: -470,283,41220,2,0,P|455:233|449:167,1,95.0000036239625,2|0,2:2|0:0,0:0:0:0: -445,85,41443,2,0,P|412:94|382:97,1,63.3333333333333,2|0,2:2|0:0,0:0:0:0: -316,47,41665,2,0,P|296:28|273:0,1,63.3333333333333,10|0,2:2|0:0,0:0:0:0: -306,124,41887,6,0,P|302:155|290:203,1,79.1666666666667,2|2,2:2|2:3,0:0:0:0: -307,335,42109,2,0,P|322:283|360:244,1,106.875004076958,2|0,2:1|0:0,0:0:0:0: -231,286,42554,2,0,P|201:191|56:68,1,285,10|0,2:1|0:0,0:0:0:0: -0,28,42998,6,0,P|76:27|164:7,2,142.500005435944,10|8|8,2:2|2:3|2:3,0:0:0:0: -192,75,44109,1,2,2:2:0:0: -257,35,44331,2,0,P|301:22|380:23,1,106.875004076958,8|0,2:3|0:0,0:0:0:0: -361,20,44776,5,10,2:2:0:0: -453,10,44998,1,2,2:2:0:0: -512,73,45220,1,10,2:2:0:0: -0,12,45665,5,8,2:3:0:0: -0,12,45887,1,0,0:0:0:0: -0,12,46109,1,8,2:3:0:0: -0,12,46554,6,0,P|66:37|104:44,1,106.875004076958,10|2,2:2|2:2,0:0:0:0: -169,0,46998,1,8,2:3:0:0: -375,56,47220,2,0,P|425:82|492:71,1,118.750004529953,2|0,2:2|0:0,0:0:0:0: -501,55,47665,2,0,P|485:15|442:-6,1,71.2500027179719,2|10,2:2|2:2,0:0:0:0: -188,77,48109,5,0,0:0:0:0: -188,77,48331,2,0,L|201:158,2,71.2500027179719,10|2|10,2:2|2:2|2:2,0:0:0:0: -307,0,48998,2,0,L|296:83,1,71.2500027179719,0|8,0:0|2:3,0:0:0:0: -297,70,49665,1,8,2:3:0:0: -380,57,49887,2,0,L|407:5,1,47.5000018119813 -188,77,50109,6,0,P|141:70|67:52,2,106.875004076958,10|0|2,2:2|0:0|2:2,0:0:0:0: -188,77,51220,1,2,2:2:0:0: -33,125,51442,2,0,P|8:87|21:2,1,118.750004529953,8|0,2:3|0:0,0:0:0:0: -12,16,51887,5,10,2:2:0:0: -90,59,52109,1,2,2:2:0:0: -189,63,52331,1,10,2:2:0:0: -512,0,52776,5,8,2:3:0:0: -512,0,52998,1,0,0:0:0:0: -512,0,53220,1,8,2:3:0:0: -512,0,53665,6,0,P|446:25|408:32,1,106.875004076958,10|2,2:2|2:2,0:0:0:0: -410,31,54109,1,8,2:3:0:0: -359,110,54331,2,0,P|333:60|344:-7,1,118.750004529953,2|0,2:2|0:0,0:0:0:0: -492,96,54776,6,0,P|470:123|437:134,1,71.2500027179719,2|10,2:2|2:2,0:0:0:0: -256,75,55220,5,0,0:0:0:0: -256,75,55442,2,0,L|186:64,2,71.2500027179719,10|2|10,2:2|2:2|2:2,0:0:0:0: -359,110,56331,1,8,2:3:0:0: -256,384,56554,5,0,0:0:0:0: -135,352,56776,1,0,0:0:0:0: -135,352,57220,6,0,P|84:233|42:152,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: -214,2,57443,6,0,P|171:136|143:197,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: -63,39,57665,6,0,P|124:60|246:78,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: -256,370,57887,6,0,P|250:290|231:211,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: -494,219,58109,6,0,P|417:253|343:298,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: -322,67,58332,6,0,P|342:136|371:183,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: -242,377,58554,6,0,P|195:353|137:342,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: -22,207,58776,6,0,B|106:200|66:194|139:190,1,118.75,2|0,2:2|1:1,0:0:0:0: -491,202,59220,5,2,2:3:0:0: -370,162,59331,1,0,0:0:0:0: -442,76,59443,2,0,P|456:117|450:147,1,59.375,10|0,2:2|0:0,0:0:0:0: -362,170,59665,2,0,P|328:98|376:-9,1,190,2|0,2:2|1:1,0:0:0:0: -266,379,60109,6,0,B|286:309|235:316|253:224,1,142.5,2|0,2:2|0:0,0:0:0:0: -250,240,60331,2,0,L|263:356,1,106.875004076958,10|0,2:1|0:0,0:0:0:0: -243,145,60776,6,0,P|362:94|441:49,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: -108,108,60998,6,0,P|65:242|36:301,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: -422,317,61221,6,0,P|441:230|468:147,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: -188,69,61443,6,0,P|108:63|35:46,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: -2,355,61665,6,0,P|51:327|140:304,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: -155,168,61888,6,0,P|86:188|37:218,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: -328,287,62110,6,0,P|375:311|431:322,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: -259,156,62332,6,0,B|252:185|250:238,1,79.1666666666667,2|0,2:2|0:0,0:0:0:0: -439,37,62554,6,0,P|482:212|307:280,1,380.00001449585,4|0,1:1|0:0,0:0:0:0: -271,154,62924,2,0,P|277:121|312:93,1,63.3333333333333,2|0,2:3|0:0,0:0:0:0: -327,286,63220,6,0,P|378:148|208:19,1,380.00001449585,6|0,2:2|0:0,0:0:0:0: -162,83,63591,5,2,2:3:0:0: -162,83,63665,2,0,P|133:83|99:71,1,47.5,2|2,2:2|2:2,0:0:0:0: -63,227,63887,1,10,2:2:0:0: -40,145,63998,1,2,2:2:0:0: -20,64,64109,1,2,2:1:0:0: -30,67,64331,6,0,P|113:58|235:23,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: -184,369,64554,6,0,P|107:335|-9:304,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: -425,32,64776,6,0,P|409:124|401:231,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: -100,370,64998,6,0,P|87:270|66:189,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: -387,107,65220,6,0,P|442:142|527:177,1,142.5,2|0,1:2|0:0,0:0:0:0: -203,269,65443,6,0,P|229:203|246:129,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: -483,277,65665,6,0,P|486:330|502:392,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: -400,205,65887,6,0,B|480:198|440:171|528:172,1,118.75,2|0,2:2|1:1,0:0:0:0: -372,357,66331,5,2,2:3:0:0: -287,283,66442,1,0,0:0:0:0: -175,345,66554,2,0,P|132:357|93:360,1,79.1666666666667,10|0,2:2|0:0,0:0:0:0: -28,257,66776,2,0,P|100:223|207:271,1,190,2|0,2:2|1:1,0:0:0:0: -0,117,67221,6,0,P|76:106|183:76,1,142.5,2|0,2:2|0:0,0:0:0:0: -125,113,67443,2,0,P|65:108|18:101,1,106.875004076958,10|0,2:1|0:0,0:0:0:0: -194,0,67887,6,0,P|245:119|290:198,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: -10,350,68109,6,0,P|43:269|67:186,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: -412,34,68332,6,0,P|388:109|372:187,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: -194,0,68554,6,0,P|263:39|322:85,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: -197,271,68776,6,0,P|225:222|291:157,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: -448,305,68999,6,0,P|392:308|338:298,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: -409,117,69220,6,0,P|456:141|514:152,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: -225,349,69443,6,0,B|184:357|141:355,1,79.1666666666667,2|0,2:2|0:0,0:0:0:0: -198,200,69665,6,0,P|277:356|447:311,1,380.00001449585,4|0,1:1|0:0,0:0:0:0: -445,334,70035,2,0,P|424:355|391:370,1,63.3333333333333,2|0,2:3|0:0,0:0:0:0: -188,271,70331,6,0,P|238:100|416:93,1,380.00001449585,6|0,2:2|0:0,0:0:0:0: -341,222,70776,1,2,2:2:0:0: -341,222,70887,1,2,2:2:0:0: -134,157,70998,6,0,P|55:171|-17:118,1,142.500005435944,10|0,2:2|0:0,0:0:0:0: -46,328,71220,6,0,P|84:301|100:257,1,95,2|0,2:2|0:0,0:0:0:0: -192,275,71443,6,0,P|212:317|207:364,1,95,2|2,2:2|2:2,0:0:0:0: -54,334,71887,1,10,2:2:0:0: -262,237,72109,1,2,2:2:0:0: -432,296,72331,2,0,P|382:310|296:318,2,95,2|0|10,2:1|1:1|2:2,0:0:0:0: -432,296,72998,5,2,2:2:0:0: -369,137,73220,2,0,L|360:255,1,95,2|2,2:2|2:2,0:0:0:0: -411,17,73665,5,10,2:2:0:0: -451,169,73887,1,2,2:2:0:0: -292,117,74035,1,0,1:1:0:0: -292,117,74109,1,2,2:1:0:0: -415,26,74331,6,0,P|322:62|223:37,1,190,0|2,1:1|2:2,0:0:0:0: -236,44,74998,2,0,L|133:59,1,95,2|2,2:1|2:3,0:0:0:0: -0,116,75443,5,10,2:2:0:0: -0,116,75665,1,2,2:2:0:0: -173,141,75887,2,0,L|78:127,1,95,2|0,2:1|1:1,0:0:0:0: -82,0,76331,1,10,2:2:0:0: -82,0,76554,1,2,2:2:0:0: -79,127,76776,6,0,P|80:197|53:296,1,142.500005435944,2|2,2:2|2:2,0:0:0:0: -12,323,77109,1,2,2:2:0:0: -87,344,77220,2,0,P|111:343|149:353,1,47.5,10|0,2:2|0:0,0:0:0:0: -255,179,77443,2,0,P|205:230|145:269,1,142.500005435944,2|2,2:2|2:1,0:0:0:0: -261,384,77887,1,0,1:1:0:0: -366,199,78109,5,10,2:2:0:0: -293,263,78220,1,2,2:2:0:0: -386,295,78331,1,2,2:2:0:0: -152,279,78554,2,0,P|231:267|311:263,1,142.500005435944,2|2,2:1|2:3,0:0:0:0: -486,152,78998,5,10,2:2:0:0: -366,199,79109,1,2,2:2:0:0: -465,295,79220,2,0,P|487:291|532:288,1,47.5,2|0,2:2|0:0,0:0:0:0: -424,369,79443,5,2,2:1:0:0: -446,220,79665,5,0,1:1:0:0: -466,68,79887,5,10,2:2:0:0: -389,80,79998,1,2,2:2:0:0: -316,45,80109,1,2,2:2:0:0: -312,35,80331,5,2,2:2:0:0: -248,79,80443,1,2,2:2:0:0: -171,50,80554,2,0,L|162:-25,1,47.5,2|0,2:2|0:0,0:0:0:0: -23,80,80776,5,10,2:2:0:0: -104,98,80887,1,2,2:2:0:0: -176,58,80998,2,0,L|185:-17,1,47.5,2|0,2:2|0:0,0:0:0:0: -184,156,81220,1,2,2:1:0:0: -184,156,81443,6,0,B|183:248|198:192|197:314,1,142.500005435944,0|10,1:1|2:2,0:0:0:0: -204,384,81776,1,2,2:2:0:0: -204,384,81887,1,2,2:2:0:0: -116,268,82109,2,0,P|71:253|25:262,1,95,2|2,2:1|2:3,0:0:0:0: -204,384,82554,5,10,2:2:0:0: -67,341,82665,1,2,2:2:0:0: -67,341,82776,1,2,2:2:0:0: -275,337,82924,5,0,1:1:0:0: -275,337,82998,2,0,P|321:346|365:331,1,95,2|0,2:1|1:1,0:0:0:0: -349,335,83443,2,0,P|267:333|194:395,1,158.333333333333,10|0,2:1|0:0,0:0:0:0: -134,349,83887,6,0,P|77:361|-8:328,1,142.500005435944,2|2,2:2|2:2,0:0:0:0: -422,272,84257,1,0,0:0:0:0: -422,272,84331,2,0,P|479:284|506:275,1,63.3333333333333,10|0,2:1|0:0,0:0:0:0: -496,101,84554,2,0,P|439:89|386:114,1,95.0000036239625,2|0,1:2|1:1,0:0:0:0: -336,193,84776,6,0,B|430:186|387:182|480:176,1,142.500005435944,2|0,2:1|1:1,0:0:0:0: -478,177,85220,5,8,2:2:0:0: -502,101,85369,1,2,2:3:0:0: -502,101,85443,1,2,2:3:0:0: -256,192,85665,5,2,2:2:0:0: -256,192,85887,1,2,2:3:0:0: -256,192,86109,1,8,2:2:0:0: -256,192,86776,1,2,2:2:0:0: -256,192,86998,1,8,2:2:0:0: -256,192,87443,1,2,2:2:0:0: -256,192,87887,1,10,2:2:0:0: -256,192,88276,1,0,1:1:0:0: -256,192,88480,1,2,2:3:0:0: -256,192,88554,1,0,1:1:0:0: -256,192,88776,1,8,2:2:0:0: -256,192,88943,1,2,2:3:0:0: -256,192,89220,1,2,2:2:0:0: -256,192,89443,1,2,2:3:0:0: -256,192,89665,1,8,2:2:0:0: -256,192,90054,1,0,1:1:0:0: -256,192,90331,1,2,2:2:0:0: -256,192,90554,1,10,2:2:0:0: -256,192,90998,1,2,2:2:0:0: -256,192,91443,1,10,2:2:0:0: -256,192,91831,1,0,1:1:0:0: -256,192,92035,1,2,2:3:0:0: -256,192,92109,1,0,1:1:0:0: -256,192,92331,1,8,2:2:0:0: -256,192,92498,1,2,2:3:0:0: -256,192,92776,6,0,P|226:227|227:272,1,71.2500027179719,2|2,2:2|2:3,0:0:0:0: -256,192,93109,6,0,P|301:200|377:160,1,95 -256,192,93443,6,0,P|232:134|105:76,1,197.916666666667,2|0,2:2|0:0,0:0:0:0: -189,46,93887,2,0,P|232:41|281:25,1,95,2|8,2:2|2:2,0:0:0:0: -36,22,94554,5,2,2:2:0:0: -103,73,94776,1,2,2:2:0:0: -185,45,94998,1,10,2:2:0:0: -512,0,95387,5,0,1:0:0:0: -512,0,95665,5,0,1:1:0:0: -512,0,95887,5,8,2:2:0:0: -512,0,96331,2,0,P|481:39|451:98,1,95,2|2,2:2|2:3,0:0:0:0: -367,70,96665,2,0,P|325:84|289:134,1,95,2|0,2:2|0:0,0:0:0:0: -503,150,96998,2,0,P|462:97|354:96,1,158.333333333333,2|0,2:2|0:0,0:0:0:0: -370,71,97443,5,2,2:2:0:0: -285,7,97665,1,10,2:2:0:0: -189,47,97887,2,0,P|153:49|107:64,1,63.3333333333333 -32,20,98109,2,0,P|46:71|48:124,1,95,2|2,2:2|2:2,0:0:0:0: -127,137,98480,1,0,0:0:0:0: -127,137,98554,1,10,2:2:0:0: -189,41,98776,6,0,P|203:92|207:125,1,71.25,0|0,0:0|1:1,0:0:0:0: -2,384,99220,1,0,0:0:0:0: -135,352,99443,1,0,0:0:0:0: -135,352,99887,6,0,P|84:233|37:152,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: -445,0,100109,6,0,P|402:134|374:195,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: -224,18,100332,6,0,P|285:39|408:56,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: -152,130,100554,6,0,P|112:94|31:29,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: -512,269,100776,6,0,P|435:302|367:343,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: -271,183,100999,6,0,P|335:166|385:136,1,124.687501189113,2|0,2:2|0:0,0:0:0:0: -302,298,101221,6,0,P|255:274|195:260,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: -22,207,101443,6,0,B|106:200|66:194|139:190,1,118.75,2|0,2:2|1:1,0:0:0:0: -230,15,101887,5,2,2:3:0:0: -272,184,101998,1,0,0:0:0:0: -402,62,102110,2,0,L|417:-11,1,59.375,10|0,2:2|0:0,0:0:0:0: -320,21,102332,2,0,P|271:67|279:195,1,190,2|0,2:2|1:1,0:0:0:0: -512,179,102776,6,0,B|442:159|361:198,1,142.5,2|0,2:2|0:0,0:0:0:0: -373,192,102998,2,0,P|442:196|489:179,1,106.875004076958,10|0,2:1|0:0,0:0:0:0: -197,228,103443,6,0,P|102:278|7:315,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: -456,383,103665,6,0,P|356:283|317:234,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: -100,21,103888,6,0,P|46:91|1:164,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: -259,168,104110,6,0,P|260:87|274:12,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: -83,198,104332,6,0,P|106:280|133:337,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: -473,90,104555,6,0,P|395:65|347:37,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: -416,287,104777,6,0,P|468:276|514:254,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: -421,171,104999,6,0,B|377:166|343:156,1,79.1666666666667,2|0,2:2|0:0,0:0:0:0: -6,333,105221,6,0,P|90:183|289:267,1,380.00001449585,4|0,1:1|0:0,0:0:0:0: -282,342,105591,2,0,P|249:336|210:278,1,95,2|0,2:3|0:0,0:0:0:0: -267,227,105887,6,0,P|129:278|11:117,1,356.25001358986,6|0,2:2|0:0,0:0:0:0: -93,46,106258,5,2,2:3:0:0: -93,46,106332,2,0,P|93:75|81:109,1,47.5,2|2,2:2|2:2,0:0:0:0: -263,97,106554,1,10,2:2:0:0: -295,13,106665,1,2,2:2:0:0: -208,24,106776,1,2,2:1:0:0: -200,42,106998,6,0,P|283:33|415:-2,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: -357,374,107221,6,0,P|290:302|236:217,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: -484,299,107443,6,0,P|419:284|307:275,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: -442,66,107665,6,0,P|455:166|478:245,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: -249,215,107887,6,0,P|306:188|367:150,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: -141,282,108110,6,0,P|90:318|45:338,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: -184,48,108332,6,0,P|226:79|271:104,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: -112,199,108554,6,0,B|32:192|72:165|-16:166,1,118.75,2|0,2:2|1:1,0:0:0:0: -282,102,108998,5,2,2:3:0:0: -341,270,109109,1,0,0:0:0:0: -468,175,109221,2,0,P|465:148|483:102,1,59.375,10|0,2:2|0:0,0:0:0:0: -374,199,109443,2,0,P|282:302|305:379,1,190,2|0,2:2|1:1,0:0:0:0: -133,261,109887,6,0,P|64:229|-15:216,1,142.5,2|0,2:2|0:0,0:0:0:0: -0,217,110109,2,0,P|56:204|98:185,1,89.0625033974649,10|0,2:1|0:0,0:0:0:0: -204,0,110554,6,0,P|213:83|250:211,1,190.000007247925,6|0,1:2|0:0,0:0:0:0: -512,73,110776,6,0,P|435:39|319:7,1,174.166668327649,2|0,2:2|0:0,0:0:0:0: -5,229,110999,6,0,P|61:290|116:360,1,158.333333333333,10|0,2:2|0:0,0:0:0:0: -379,213,111221,6,0,P|393:134|418:64,1,142.500005435944,2|0,2:2|0:0,0:0:0:0: -131,123,111443,6,0,P|65:95|10:57,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: -130,355,111666,6,0,P|190:338|244:316,1,110.833334390322,2|0,2:2|0:0,0:0:0:0: -335,137,111888,6,0,P|293:169|233:198,1,95.0000036239625,10|0,2:2|0:0,0:0:0:0: -378,233,112110,6,0,P|420:223|486:214,1,79.1666666666667,2|0,2:2|0:0,0:0:0:0: -456,206,112331,6,0,B|224:229|371:239|70:267,1,380.00001449585,4|0,1:1|0:0,0:0:0:0: -12,151,112702,2,0,P|51:178|98:181,1,95,2|0,2:3|0:0,0:0:0:0: -181,236,112998,2,0,P|47:255|5:384,1,285.000010871888,6|0,2:2|1:1,0:0:0:0: -456,206,113443,5,2,2:2:0:0: -456,206,113554,1,2,2:2:0:0: -482,120,113665,2,0,L|504:34,1,71.2500027179719,8|0,2:2|0:0,0:0:0:0: -132,70,113887,5,2,2:3:0:0: -132,70,113998,1,0,0:0:0:0: -0,55,114109,6,0,L|251:25,1,253.333333333333,6|0,1:2|0:0,0:0:0:0: -482,379,114331,6,0,L|263:347,1,221.666668780645,2|0,2:2|0:0,0:0:0:0: -63,2,114554,6,0,L|251:26,1,190.000007247925,10|0,2:2|0:0,0:0:0:0: -420,325,114776,6,0,L|264:346,1,158.333333333333,2|0,2:2|0:0,0:0:0:0: -132,70,114998,6,0,L|251:26,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: -351,384,115220,6,0,L|264:346,1,95.0000036239625,2|0,2:2|0:0,0:0:0:0: -187,25,115443,6,0,L|251:21,1,63.3333333333333,10|0,2:2|0:0,0:0:0:0: -32,192,115665,5,2,2:1:0:0: -251,6,115887,1,0,1:1:0:0: -480,192,116109,1,2,2:1:0:0: -261,378,116331,1,10,2:1:0:0: -274,103,116554,5,2,2:1:0:0: -299,223,116665,1,0,0:0:0:0: -176,174,116776,2,0,P|123:183|31:180,1,126.666666666667,6|0,2:2|0:0,0:0:0:0: -51,183,116998,2,0,P|84:157|138:159,1,63.3333333333333,2|0,2:3|0:0,0:0:0:0: -248,277,117220,2,0,P|236:221|168:181,1,126.666666666667,14|0,2:2|0:0,0:0:0:0: -418,77,117665,6,0,L|453:375,1,253.333333333333,6|0,1:2|0:0,0:0:0:0: -228,360,117887,6,0,L|520:318,1,221.666668780645,2|0,2:2|0:0,0:0:0:0: -471,140,118109,6,0,L|445:345,1,190.000007247925,10|0,2:2|0:0,0:0:0:0: -290,307,118331,6,0,L|489:333,1,158.333333333333,2|0,2:2|0:0,0:0:0:0: -400,210,118554,6,0,L|450:337,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: -362,369,118776,6,0,L|452:324,1,95.0000036239625,2|0,2:2|0:0,0:0:0:0: -440,263,118998,6,0,L|448:336,1,63.3333333333333,10|0,2:2|0:0,0:0:0:0: -402,310,119220,6,0,L|450:327,1,47.5000018119813,2|0,2:2|0:0,0:0:0:0: -208,369,119443,6,0,P|71:217|11:334,1,380.00001449585,4|0,1:1|0:0,0:0:0:0: -90,384,119813,2,0,P|116:326|127:267,1,95,2|0,2:3|0:0,0:0:0:0: -328,170,120109,2,0,P|373:54|480:149,1,285.000010871888,6|0,2:0|1:1,0:0:0:0: -326,190,120480,1,2,2:3:0:0: -326,190,120554,2,0,P|279:178|236:160,1,95.0000036239625,2|0,2:2|0:0,0:0:0:0: -0,156,120776,5,10,2:2:0:0: -104,100,120887,1,2,2:2:0:0: -97,220,120998,1,2,2:1:0:0: -135,351,121220,6,0,L|97:43,1,253.333333333333,6|0,1:2|0:0,0:0:0:0: -249,9,121443,6,0,L|207:297,1,221.666668780645,2|0,2:2|0:0,0:0:0:0: -0,249,121665,6,0,L|23:51,1,190.000007247925,10|0,2:2|0:0,0:0:0:0: -318,198,121887,6,0,L|347:387,1,158.333333333333,2|0,2:2|0:0,0:0:0:0: -48,366,122109,6,0,L|-3:243,1,126.666666666667,2|0,1:2|0:0,0:0:0:0: -360,102,122331,6,0,L|408:188,1,95.0000036239625,2|0,2:2|0:0,0:0:0:0: -148,384,122554,6,0,L|140:313,1,63.3333333333333,10|0,2:2|0:0,0:0:0:0: -256,48,122776,5,2,2:1:0:0: -256,368,122998,1,0,1:1:0:0: -256,48,123220,5,2,2:1:0:0: -256,368,123443,1,10,2:1:0:0: -256,368,123665,5,2,2:1:0:0: -280,233,123776,1,0,0:0:0:0: -404,307,123887,2,0,P|451:298|470:218,1,126.666666666667,6|0,2:2|0:0,0:0:0:0: -497,219,124109,2,0,P|452:182|417:195,1,63.3333333333333,2|0,2:3|0:0,0:0:0:0: -208,309,124331,2,0,B|135:281|170:305|57:277,1,126.666666666667,14|0,2:2|0:0,0:0:0:0: -88,81,124776,6,0,P|135:173|249:386,1,253.333333333333,6|0,1:2|0:0,0:0:0:0: -243,156,124998,6,0,P|181:118|10:6,1,253.333333333333,2|0,2:2|0:0,0:0:0:0: -0,250,125220,6,0,P|120:211|239:167,1,253.333333333333,10|0,2:2|0:0,0:0:0:0: -363,16,125443,6,0,P|291:187|252:274,1,253.333333333333,2|0,2:2|0:0,0:0:0:0: -458,340,125665,6,0,P|351:337|178:315,1,253.333333333333,2|0,1:2|0:0,0:0:0:0: -186,7,125887,6,0,P|241:164|269:273,1,253.333333333333,2|0,2:2|0:0,0:0:0:0: -461,349,126109,6,0,P|413:307|363:268,1,126.666666666667,10|0,2:2|0:0,0:0:0:0: -441,193,126331,6,0,P|479:191|523:172,1,63.3333333333333,2|0,2:2|0:0,0:0:0:0: -503,184,126554,2,0,P|409:160|281:406,1,380.00001449585,4|0,1:1|0:0,0:0:0:0: -456,357,126924,2,0,P|412:340|366:344,1,95,2|0,2:3|0:0,0:0:0:0: -0,47,127220,2,0,P|107:29|201:172,1,285,6|0,2:2|0:0,0:0:0:0: -193,159,127665,5,2,2:2:0:0: -21,210,127813,1,0,0:0:0:0: -21,210,127887,1,8,2:2:0:0: -149,331,128035,5,2,2:3:0:0: -149,331,128109,1,2,2:3:0:0: -202,158,128257,1,2,2:3:0:0: From 99daec3835045477546effe3b622c2e57bb254c7 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Fri, 19 Dec 2025 17:59:22 +0500 Subject: [PATCH 303/836] Simplify osu! star rating calculations (#36063) * Simplify star rating calculations * Refactor --- .../Difficulty/OsuDifficultyCalculator.cs | 7 +------ .../Difficulty/OsuPerformanceCalculator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs | 2 +- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 509619df4c6c..32e3829f7444 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -22,8 +22,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuDifficultyCalculator : DifficultyCalculator { - private const double star_rating_multiplier = 0.0265; - public override int Version => 20250306; public OsuDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) @@ -150,10 +148,7 @@ private double calculateMechanicalDifficultyRating(double aimDifficultyValue, do private double calculateStarRating(double basePerformance) { - if (basePerformance <= 0.00001) - return 0; - - return Math.Cbrt(OsuPerformanceCalculator.PERFORMANCE_BASE_MULTIPLIER) * star_rating_multiplier * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4); + return Math.Cbrt(basePerformance * OsuPerformanceCalculator.PERFORMANCE_BASE_MULTIPLIER); } protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 66d6cc32cd94..9dde9dfdea7c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuPerformanceCalculator : PerformanceCalculator { - public const double PERFORMANCE_BASE_MULTIPLIER = 1.14; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. + public const double PERFORMANCE_BASE_MULTIPLIER = 1.12; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. public const double PERFORMANCE_NORM_EXPONENT = 1.1; private bool usingClassicSliderAccuracy; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs index 6823512cef12..916b6e7b2d51 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs @@ -57,6 +57,6 @@ public override double DifficultyValue() return difficulty; } - public static double DifficultyToPerformance(double difficulty) => Math.Pow(5.0 * Math.Max(1.0, difficulty / 0.0675) - 4.0, 3.0) / 100000.0; + public static double DifficultyToPerformance(double difficulty) => 4.0 * Math.Pow(difficulty, 3.0); } } From 4cce6aa1230188aa8293b2df3f44bb7b552d47a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 19 Dec 2025 13:55:57 +0100 Subject: [PATCH 304/836] Address review concerns --- osu.Game/Screens/SelectV2/FilterControl.cs | 1 + .../PanelBeatmapStandalone.SpreadDisplay.cs | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/SelectV2/FilterControl.cs b/osu.Game/Screens/SelectV2/FilterControl.cs index 2df2dcdc131c..88a527b66c26 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.cs +++ b/osu.Game/Screens/SelectV2/FilterControl.cs @@ -189,6 +189,7 @@ private void load(IAPIProvider api) new ScopedBeatmapSetDisplay { ScopedBeatmapSet = ScopedBeatmapSet, + Depth = float.MinValue, // hack to ensure that the scoped display handles `GlobalAction.Back` input before the filter control } }, } diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs index faa5ee5f05d8..32a48996a707 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs @@ -47,7 +47,8 @@ public partial class SpreadDisplay : OsuAnimatedButton public SpreadDisplay() { - AutoSizeAxes = Axes.Both; + AutoSizeAxes = Axes.X; + RelativeSizeAxes = Axes.Y; Content.CornerRadius = 5; } @@ -57,6 +58,8 @@ private void load(ISongSelect? songSelect, OsuConfigManager configManager) Add(new FillFlowContainer { AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, Direction = FillDirection.Horizontal, Spacing = new Vector2(5), Padding = new MarginPadding { Horizontal = 5 }, @@ -132,15 +135,15 @@ protected override void LoadComplete() private void updateBeatmap() { - preceding.Clear(); - succeeding.Clear(); - if (Beatmap.Value == null || scopedBeatmapSet.Value != null) { this.FadeOut(transition_duration, Easing.OutQuint); return; } + preceding.Clear(); + succeeding.Clear(); + var otherStarDifficulties = Beatmap.Value.BeatmapSet!.Beatmaps .Except([Beatmap.Value]) .Where(b => b.AllowGameplayWithRuleset(ruleset.Value, showConvertedBeatmaps.Value)) @@ -218,7 +221,8 @@ protected override bool OnMouseDown(MouseDownEvent e) if (!Enabled.Value) return false; - return base.OnMouseDown(e); + base.OnMouseDown(e); + return true; } protected override bool OnClick(ClickEvent e) From e094eefafb9066024e10f285efb794c21d416567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 19 Dec 2025 14:26:31 +0100 Subject: [PATCH 305/836] Fix cursor scale affecting trail spacing Closes https://github.com/ppy/osu/issues/36061. Regressed in https://github.com/ppy/osu/pull/35802. It's either this or revert of aforementioned pull. I dunno. --- osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index fc5ad2d955f3..c52bc92f8395 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -198,7 +198,7 @@ protected void AddTrail(Vector2 position) float distance = diff.Length; Vector2 direction = diff / distance; - float interval = Texture.DisplayWidth / 2.5f * IntervalMultiplier; + float interval = Texture.DisplayWidth * CursorScale.X / 2.5f * IntervalMultiplier; float stopAt = distance - (AvoidDrawingNearCursor ? interval : 0); for (float d = interval; d < stopAt; d += interval) From daaea093f0cc735fa9ca1905fe7ca88f6085c891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 22 Dec 2025 10:04:18 +0100 Subject: [PATCH 306/836] Add another failing test --- .../UserInterface/TestSceneFormSliderBar.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs index f4d6569dcab9..a962cd4a6f4b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs @@ -165,5 +165,47 @@ public void TestDisabled() }); AddAssert("slider is still at 1", () => slider.Current.Value, () => Is.EqualTo(1)); } + + [Test] + public void TestDisabledImmediately() + { + FormSliderBar slider = null!; + + AddStep("create content", () => + { + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.5f, + Direction = FillDirection.Vertical, + Spacing = new Vector2(10), + Children = new Drawable[] + { + slider = new FormSliderBar + { + Caption = "Slider", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Precision = 0.1f, + Default = 5f, + Disabled = true, + }, + TransferValueOnCommit = true, + }, + } + }; + }); + + AddStep("click on textbox part", () => + { + InputManager.MoveMouseTo(slider.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + AddAssert("no text selected", () => slider.ChildrenOfType().Single().SelectedText, () => Is.Empty); + } } } From df524d68fd82722f5ea3a18a42f62db807ce5326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 22 Dec 2025 10:04:29 +0100 Subject: [PATCH 307/836] Move disable to better place --- osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index f4702f000cdf..aaa66742b3d3 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -207,7 +207,6 @@ protected override void LoadComplete() } currentNumberInstantaneous.Disabled = disabled; - textBox.ReadOnly = disabled; updateState(); }; @@ -295,6 +294,7 @@ private void updateState() bool childHasFocus = slider.Focused.Value || textBox.Focused.Value; textBox.Alpha = 1; + textBox.ReadOnly = Current.Disabled; background.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background4 : colourProvider.Background5; captionText.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Foreground1 : colourProvider.Content2; From 3712093158df40b82f33bf4b75b12754baed6d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 22 Dec 2025 11:22:37 +0100 Subject: [PATCH 308/836] Add explicit menu item for exporting guest difficulties from editor A few facts of life: - Guest difficulties are at this point a staple of mapping. - People are very much used to flinging `.osu`s around (because there's no better alternative). - Currently there are two ways to get an `.osu` out of lazer. You can: - Export the beatmap as "compatibility" to an `.osz`, then transmogrify the `.osz` to a `.zip`, then extract the `.zip`, then pluck out the `.osu`. This is the "correct" way to make sure stable works, but is also stupidly arcane. - Use "edit externally" to mount the beatmap files to disk, then copy-paste out the `.osu`. This is the *wrong* way to make sure stable works, because the mounting process exposes the raw "for editing" format with features stable doesn't support, but it the actual easy one. - Reports about guest difficulties exported from lazer "working wrong on stable" are prevalent. Probably mostly because of the preceding point. What this PR does is introduce a *third* method to export an `.osu`, which is designed to be both the easiest one yet *and* correct. I am hoping this will curb the complaints until support for direct submission of guest difficulties is added - which I still hope to see, but it will be a significant effort *client-side* (the server side has been ready for years now). And yes, you will notice that much of the code added in `LegacyBeatmapExporter` related to manipulation of the path is copy-pasted from `LegacyExporter`. I don't care enough to invent protected / abstract / whatever else OOP faff for something that may not survive review and is mostly a weird semi-temporary wart. --- osu.Game/Beatmaps/BeatmapManager.cs | 6 ++- osu.Game/Database/LegacyBeatmapExporter.cs | 54 ++++++++++++++++++++++ osu.Game/Database/LegacyExporter.cs | 14 +++--- osu.Game/Localisation/EditorStrings.cs | 5 ++ osu.Game/Screens/Edit/Editor.cs | 19 +++----- 5 files changed, 76 insertions(+), 22 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 08a611e3206d..62c03b4fcdc4 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -476,9 +476,11 @@ public void UndeleteAll() public Task> BeginExternalEditing(BeatmapSetInfo model) => beatmapImporter.BeginExternalEditing(model); - public Task Export(BeatmapSetInfo beatmap) => beatmapExporter.ExportAsync(beatmap.ToLive(Realm)); + public Task Export(BeatmapSetInfo beatmapSet) => beatmapExporter.ExportAsync(beatmapSet.ToLive(Realm)); - public Task ExportLegacy(BeatmapSetInfo beatmap) => legacyBeatmapExporter.ExportAsync(beatmap.ToLive(Realm)); + public Task ExportLegacy(BeatmapSetInfo beatmapSet) => legacyBeatmapExporter.ExportAsync(beatmapSet.ToLive(Realm)); + + public Task ExportLegacy(BeatmapInfo beatmap) => legacyBeatmapExporter.ExportAsync(beatmap.ToLive(Realm)); private void updateHashAndMarkDirty(BeatmapSetInfo setInfo) { diff --git a/osu.Game/Database/LegacyBeatmapExporter.cs b/osu.Game/Database/LegacyBeatmapExporter.cs index 8d90c9adb499..7587c2332fa0 100644 --- a/osu.Game/Database/LegacyBeatmapExporter.cs +++ b/osu.Game/Database/LegacyBeatmapExporter.cs @@ -2,17 +2,22 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using System.Threading.Tasks; using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Timing; +using osu.Game.Extensions; using osu.Game.IO; +using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Skinning; +using osu.Game.Utils; using osuTK; namespace osu.Game.Database @@ -175,5 +180,54 @@ protected virtual void MutateBeatmap(BeatmapSetInfo beatmapSet, IBeatmap playabl } protected override string FileExtension => @".osz"; + + public Task ExportAsync(Live beatmap) => Task.Run(() => + { + string itemFilename = Path.GetFileNameWithoutExtension(beatmap.PerformRead(s => s.File!.Filename.GetValidFilename())); + const string osu_extension = @".osu"; + + if (itemFilename.Length > MAX_FILENAME_LENGTH - osu_extension.Length) + itemFilename = itemFilename.Remove(MAX_FILENAME_LENGTH - osu_extension.Length); + + IEnumerable existingExports = ExportStorage + .GetFiles(string.Empty, $"{itemFilename}*{osu_extension}") + .Concat(ExportStorage.GetDirectories(string.Empty)); + + string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{osu_extension}"); + + ProgressNotification notification = new ProgressNotification + { + State = ProgressNotificationState.Active, + Text = $"Exporting {itemFilename}...", + }; + + PostNotification?.Invoke(notification); + + try + { + beatmap.PerformRead(b => + { + using var exportStream = ExportStorage.CreateFileSafely(filename); + using var inputFile = GetFileContents(b.BeatmapSet!, b.File!); + + if (inputFile == null) + throw new InvalidOperationException($"Beatmap file {b.File!.Filename} could not be opened!"); + + inputFile.CopyTo(exportStream); + }); + } + catch + { + notification.State = ProgressNotificationState.Cancelled; + + // cleanup if export is failed or canceled. + ExportStorage.Delete(filename); + throw; + } + + notification.CompletionText = $"Exported {itemFilename}! Click to view."; + notification.CompletionClickAction = () => ExportStorage.PresentFileExternally(filename); + notification.State = ProgressNotificationState.Completed; + }); } } diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 80393c27f725..cc0fd8f8a2ae 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -41,13 +41,13 @@ public abstract class LegacyExporter protected abstract string FileExtension { get; } protected readonly Storage UserFileStorage; - private readonly Storage exportStorage; + protected readonly Storage ExportStorage; public Action? PostNotification { get; set; } protected LegacyExporter(Storage storage) { - exportStorage = (storage as OsuStorage)?.GetExportStorage() ?? storage.GetStorageForDirectory(@"exports"); + ExportStorage = (storage as OsuStorage)?.GetExportStorage() ?? storage.GetStorageForDirectory(@"exports"); UserFileStorage = storage.GetStorageForDirectory(@"files"); } @@ -74,9 +74,9 @@ public async Task ExportAsync(Live model, CancellationToken cancellation if (itemFilename.Length > MAX_FILENAME_LENGTH - FileExtension.Length) itemFilename = itemFilename.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); - IEnumerable existingExports = exportStorage + IEnumerable existingExports = ExportStorage .GetFiles(string.Empty, $"{itemFilename}*{FileExtension}") - .Concat(exportStorage.GetDirectories(string.Empty)); + .Concat(ExportStorage.GetDirectories(string.Empty)); string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}"); @@ -92,7 +92,7 @@ public async Task ExportAsync(Live model, CancellationToken cancellation try { - using (var stream = exportStorage.CreateFileSafely(filename)) + using (var stream = ExportStorage.CreateFileSafely(filename)) { await ExportToStreamAsync(model, stream, notification, linkedSource.Token).ConfigureAwait(false); } @@ -102,12 +102,12 @@ public async Task ExportAsync(Live model, CancellationToken cancellation notification.State = ProgressNotificationState.Cancelled; // cleanup if export is failed or canceled. - exportStorage.Delete(filename); + ExportStorage.Delete(filename); throw; } notification.CompletionText = $"Exported {itemFilename}! Click to view."; - notification.CompletionClickAction = () => exportStorage.PresentFileExternally(filename); + notification.CompletionClickAction = () => ExportStorage.PresentFileExternally(filename); notification.State = ProgressNotificationState.Completed; } diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs index c8b163c67859..a9e151d3e5a6 100644 --- a/osu.Game/Localisation/EditorStrings.cs +++ b/osu.Game/Localisation/EditorStrings.cs @@ -54,6 +54,11 @@ public static class EditorStrings /// public static LocalisableString ExportForCompatibility => new TranslatableString(getKey(@"export_for_compatibility"), @"For compatibility (.osz)"); + /// + /// "Guest difficulty (.osu)" + /// + public static LocalisableString ExportGuestDifficulty => new TranslatableString(getKey(@"export_guest_difficulty"), @"Guest difficulty (.osu)"); + /// /// "Create new difficulty" /// diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index d40d36530aeb..03a0942e190e 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -1329,8 +1329,9 @@ private EditorMenuItem createExportMenu() { var exportItems = new List { - new EditorMenuItem(EditorStrings.ExportForEditing, MenuItemType.Standard, () => exportBeatmap(false)), - new EditorMenuItem(EditorStrings.ExportForCompatibility, MenuItemType.Standard, () => exportBeatmap(true)), + new EditorMenuItem(EditorStrings.ExportForEditing, MenuItemType.Standard, () => runExport(manager => manager.Export(Beatmap.Value.BeatmapSetInfo))), + new EditorMenuItem(EditorStrings.ExportForCompatibility, MenuItemType.Standard, () => runExport(manager => manager.ExportLegacy(Beatmap.Value.BeatmapSetInfo))), + new EditorMenuItem(EditorStrings.ExportGuestDifficulty, MenuItemType.Standard, () => runExport(manager => manager.ExportLegacy(Beatmap.Value.BeatmapInfo))), }; return new EditorMenuItem(CommonStrings.Export) { Items = exportItems }; @@ -1396,7 +1397,7 @@ private void submitBeatmap() void startSubmission() => this.Push(new BeatmapSubmissionScreen()); } - private void exportBeatmap(bool legacy) + private void runExport(Func exportAction) { if (HasUnsavedChanges) { @@ -1405,20 +1406,12 @@ private void exportBeatmap(bool legacy) if (!Save()) return Task.CompletedTask; - return runExport(); + return exportAction.Invoke(beatmapManager); }))); } else { - attemptAsyncMutationOperation(runExport); - } - - Task runExport() - { - if (legacy) - return beatmapManager.ExportLegacy(Beatmap.Value.BeatmapSetInfo); - else - return beatmapManager.Export(Beatmap.Value.BeatmapSetInfo); + attemptAsyncMutationOperation(() => exportAction(beatmapManager)); } } From 17143ca0a8eaa36687edb55d4b6e780f505f6954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 22 Dec 2025 12:22:04 +0100 Subject: [PATCH 309/836] Move online ID validation check into its proper location The end of `Populate()` is too early to do any validation of online IDs, as population happens in `PostImport()` via `ProcessBeatmap`. Additionally, this modifies the check to also include the set's ID. This is one part of curtailing issues like https://osu.ppy.sh/community/forums/topics/2162457?n=8 - the featured artist template beatmap in question has a single difficulty with a bogus positive beatmap set ID and a beatmap ID of 0, and my opinion is that this sort of situation should for all intents and purposes cause the beatmap set's ID to be reset. --- osu.Game/Beatmaps/BeatmapImporter.cs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs index f80c4de4ea6e..9ef686bde911 100644 --- a/osu.Game/Beatmaps/BeatmapImporter.cs +++ b/osu.Game/Beatmaps/BeatmapImporter.cs @@ -182,19 +182,6 @@ protected override void Populate(BeatmapSetInfo beatmapSet, ArchiveReader? archi } validateOnlineIds(beatmapSet, realm); - - bool hadOnlineIDs = beatmapSet.Beatmaps.Any(b => b.OnlineID > 0); - - // TODO: this may no longer be valid as we aren't doing an online population at this point. - // ensure at least one beatmap was able to retrieve or keep an online ID, else drop the set ID. - if (hadOnlineIDs && !beatmapSet.Beatmaps.Any(b => b.OnlineID > 0)) - { - if (beatmapSet.OnlineID > 0) - { - beatmapSet.OnlineID = -1; - LogForModel(beatmapSet, "Disassociating beatmap set ID due to loss of all beatmap IDs"); - } - } } protected override void PreImport(BeatmapSetInfo beatmapSet, Realm realm) @@ -235,6 +222,15 @@ protected override void PostImport(BeatmapSetInfo model, Realm realm, ImportPara } ProcessBeatmap?.Invoke(model, parameters.Batch ? MetadataLookupScope.LocalCacheFirst : MetadataLookupScope.OnlineFirst); + + bool hadOnlineIDs = model.OnlineID > 0 || model.Beatmaps.Any(b => b.OnlineID > 0); + + // ensure at least one beatmap was able to retrieve or keep an online ID, else drop the set ID. + if (hadOnlineIDs && !model.Beatmaps.Any(b => b.OnlineID > 0)) + { + model.OnlineID = -1; + LogForModel(model, "Disassociating beatmap set ID due to loss of all beatmap IDs"); + } } private void validateOnlineIds(BeatmapSetInfo beatmapSet, Realm realm) From 44df9047aec190dad0409185d631b5b7a45c2e31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 22 Dec 2025 12:26:07 +0100 Subject: [PATCH 310/836] Only perform replace-on-import based on online beatmap set ID after it's validated Even without the ID resetting logic before `Populate()` getting broken and annotated with a TODO, this was kinda stupid. Why was purging logic allowed to run *using a not-yet-completely-validated online ID of the set*? This is the other part of hopefully fixing scenarios like https://osu.ppy.sh/community/forums/topics/2162457?n=8 (hopefully with no babies poured out in the mean time, but only time will tell). --- osu.Game/Beatmaps/BeatmapImporter.cs | 50 +++++++++++++--------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs index 9ef686bde911..d8508ce6de8c 100644 --- a/osu.Game/Beatmaps/BeatmapImporter.cs +++ b/osu.Game/Beatmaps/BeatmapImporter.cs @@ -184,32 +184,6 @@ protected override void Populate(BeatmapSetInfo beatmapSet, ArchiveReader? archi validateOnlineIds(beatmapSet, realm); } - protected override void PreImport(BeatmapSetInfo beatmapSet, Realm realm) - { - // We are about to import a new beatmap. Before doing so, ensure that no other set shares the online IDs used by the new one. - // Note that this means if the previous beatmap is restored by the user, it will no longer be linked to its online IDs. - // If this is ever an issue, we can consider marking as pending delete but not resetting the IDs (but care will be required for - // beatmaps, which don't have their own `DeletePending` state). - - if (beatmapSet.OnlineID > 0) - { - // Required local for iOS. Will cause runtime crash if inlined. - int onlineId = beatmapSet.OnlineID; - - // OnlineID should really be unique, but to avoid catastrophic failure let's iterate just to be sure. - foreach (var existingSetWithSameOnlineID in realm.All().Where(b => b.OnlineID == onlineId)) - { - existingSetWithSameOnlineID.DeletePending = true; - existingSetWithSameOnlineID.OnlineID = -1; - - foreach (var b in existingSetWithSameOnlineID.Beatmaps) - b.ResetOnlineInfo(); - - LogForModel(beatmapSet, $"Found existing beatmap set with same OnlineID ({beatmapSet.OnlineID}). It will be disassociated and marked for deletion."); - } - } - } - protected override void PostImport(BeatmapSetInfo model, Realm realm, ImportParameters parameters) { base.PostImport(model, realm, parameters); @@ -231,6 +205,30 @@ protected override void PostImport(BeatmapSetInfo model, Realm realm, ImportPara model.OnlineID = -1; LogForModel(model, "Disassociating beatmap set ID due to loss of all beatmap IDs"); } + + // Before concluding the import, ensure that no other set shares the online IDs used by the new one. + // Note that this means if the previous beatmap is restored by the user, it will no longer be linked to its online IDs. + // If this is ever an issue, we can consider marking as pending delete but not resetting the IDs (but care will be required for + // beatmaps, which don't have their own `DeletePending` state). + + if (model.OnlineID > 0) + { + // Required local for iOS. Will cause runtime crash if inlined. + int onlineId = model.OnlineID; + Guid guid = model.ID; + + // OnlineID should really be unique, but to avoid catastrophic failure let's iterate just to be sure. + foreach (var existingSetWithSameOnlineID in realm.All().Where(b => b.OnlineID == onlineId && b.ID != guid)) + { + existingSetWithSameOnlineID.DeletePending = true; + existingSetWithSameOnlineID.OnlineID = -1; + + foreach (var b in existingSetWithSameOnlineID.Beatmaps) + b.ResetOnlineInfo(); + + LogForModel(model, $"Found existing beatmap set with same OnlineID ({model.OnlineID}). It will be disassociated and marked for deletion."); + } + } } private void validateOnlineIds(BeatmapSetInfo beatmapSet, Realm realm) From 1ab922af1255a46f670fecd8115c286d1e8c37f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 22 Dec 2025 12:48:53 +0100 Subject: [PATCH 311/836] Fix test --- osu.Game.Tests/Database/BeatmapImporterTests.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index f3ca66538015..bdba1c368fd8 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -778,7 +778,19 @@ public void TestImportThenReimportWithNewDifficulty() { RunTestWithRealmAsync(async (realm, storage) => { - var importer = new BeatmapImporter(storage, realm); + var importer = new BeatmapImporter(storage, realm) + { + ProcessBeatmap = (set, _) => + { + set.OnlineID = 1234; + // note: this is only intended to be a quick-and-easy approximation of proper operation + // the more proper way to do this would be to assign IDs based on content hash or something, but it largely doesn't matter here + // so long as the beatmaps in the set get assigned an ID by the process flow + for (int i = 0; i < set.Beatmaps.Count; ++i) + set.Beatmaps[i].OnlineID = 5678 + i; + } + }; + using var store = new RealmRulesetStore(realm, storage); string? pathOriginal = TestResources.GetTestBeatmapForImport(); From 9d07ad2761c8bcb181540a3f0c1642f83a192d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 22 Dec 2025 13:19:59 +0100 Subject: [PATCH 312/836] Implement form control for adding/removing custom samples in editor The test scene doesn't exercise the custom sample playback, but I hope I can be forgiven for this as setting up a custom editor beatmap just for this to work is rather cumbersome. --- .../Visual/Editing/TestSceneFormSampleSet.cs | 42 +++ .../UserInterfaceV2/FormFileSelector.cs | 2 +- .../Screens/Edit/Components/FormSampleSet.cs | 346 ++++++++++++++++++ osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 8 + 4 files changed, 397 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/Editing/TestSceneFormSampleSet.cs create mode 100644 osu.Game/Screens/Edit/Components/FormSampleSet.cs diff --git a/osu.Game.Tests/Visual/Editing/TestSceneFormSampleSet.cs b/osu.Game.Tests/Visual/Editing/TestSceneFormSampleSet.cs new file mode 100644 index 000000000000..cc6b4b05d231 --- /dev/null +++ b/osu.Game.Tests/Visual/Editing/TestSceneFormSampleSet.cs @@ -0,0 +1,42 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Cursor; +using osu.Game.Graphics.Cursor; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Components; +using osu.Game.Tests.Visual.UserInterface; + +namespace osu.Game.Tests.Visual.Editing +{ + public partial class TestSceneFormSampleSet : ThemeComparisonTestScene + { + public TestSceneFormSampleSet() + : base(false) + { + } + + protected override Drawable CreateContent() => new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + Child = new OsuContextMenuContainer + { + RelativeSizeAxes = Axes.Both, + Child = new FormSampleSet + { + Current = + { + Value = new EditorBeatmapSkin.SampleSet(3, "Custom set #3") + { + Filenames = ["normal-hitwhistle3.wav"] + } + }, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.4f, + } + } + }; + } +} diff --git a/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs b/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs index 5fdf453fc4c2..fe4e764836d3 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs @@ -252,7 +252,7 @@ public Popover GetPopover() return popover; } - protected partial class FileChooserPopover : OsuPopover + public partial class FileChooserPopover : OsuPopover { protected override string PopInSampleName => "UI/overlay-big-pop-in"; protected override string PopOutSampleName => "UI/overlay-big-pop-out"; diff --git a/osu.Game/Screens/Edit/Components/FormSampleSet.cs b/osu.Game/Screens/Edit/Components/FormSampleSet.cs new file mode 100644 index 000000000000..d3a640abb8d5 --- /dev/null +++ b/osu.Game/Screens/Edit/Components/FormSampleSet.cs @@ -0,0 +1,346 @@ +// 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.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Extensions; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Audio; +using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Overlays; +using osu.Game.Resources.Localisation.Web; +using osu.Game.Utils; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.Edit.Components +{ + public partial class FormSampleSet : CompositeDrawable, IHasCurrentValue + { + public Bindable Current + { + get => current.Current; + set => current.Current = value; + } + + public Func? SampleAddRequested { get; init; } + public Action? SampleRemoveRequested { get; init; } + + private readonly BindableWithCurrent current = new BindableWithCurrent(); + private readonly Dictionary<(string sound, string bank), SampleButton> buttons = new Dictionary<(string, string), SampleButton>(); + + private Box background = null!; + private FormFieldCaption caption = null!; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + Masking = true; + CornerRadius = 5; + + InternalChildren = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background5, + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding(9), + Spacing = new Vector2(7), + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + caption = new FormFieldCaption(), + new GridContainer + { + AutoSizeAxes = Axes.Both, + RowDimensions = Enumerable.Repeat(new Dimension(GridSizeMode.AutoSize), 4).ToArray(), + ColumnDimensions = Enumerable.Repeat(new Dimension(GridSizeMode.AutoSize), 5).ToArray(), + Content = createTableContent().ToArray(), + } + }, + }, + }; + } + + private IEnumerable createTableContent() + { + string[] columns = [HitSampleInfo.HIT_NORMAL, ..HitSampleInfo.ALL_ADDITIONS]; + string[] rows = HitSampleInfo.ALL_BANKS; + + yield return columns.Select(makeTableHeading).Prepend(Empty()).ToArray(); + + foreach (string row in rows) + { + List drawables = [makeTableHeading(row)]; + + foreach (string col in columns) + drawables.Add(buttons[(col, row)] = makeButton()); + + yield return drawables.ToArray(); + } + } + + private OsuSpriteText makeTableHeading(string text) => new OsuSpriteText + { + Text = text, + Font = OsuFont.Style.Caption1, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + + private SampleButton makeButton() => new SampleButton + { + Width = 60, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding(5), + SampleAddRequested = SampleAddRequested, + SampleRemoveRequested = SampleRemoveRequested, + }; + + protected override void LoadComplete() + { + base.LoadComplete(); + + updateState(); + Current.BindValueChanged(setChanged, true); + } + + private void setChanged(ValueChangedEvent valueChangedEvent) + { + var set = valueChangedEvent.NewValue; + + caption.Caption = set?.Name ?? default(LocalisableString); + Alpha = set != null && set.SampleSetIndex > 0 ? 1 : 0; + + if (set != null) + { + foreach (var (sound, button) in buttons) + { + button.ExpectedFilename.Value = $@"{sound.bank}-{sound.sound}{(set.SampleSetIndex > 1 ? set.SampleSetIndex : null)}"; + button.ActualFilename.Value = set.FindSound(sound.sound, sound.bank); + } + } + } + + protected override bool OnHover(HoverEvent e) + { + updateState(); + return true; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateState(); + base.OnHoverLost(e); + } + + private void updateState() + { + background.Colour = colourProvider.Background5; + caption.Colour = colourProvider.Content2; + + BorderThickness = IsHovered ? 2 : 0; + + if (IsHovered) + BorderColour = colourProvider.Light4; + } + + public partial class SampleButton : OsuButton, IHasPopover, IHasContextMenu + { + /// + /// The expected filename for the sample that this button represents. + /// Does not contain extension. + /// + public Bindable ExpectedFilename { get; } = new Bindable(); + + /// + /// The actual chosen filename for the sample that this button represent. + /// Can be if the sample is omitted / missing. + /// Does contain extension. + /// + public Bindable ActualFilename { get; } = new Bindable(); + + /// + /// Invoked when a new sample is selected via this button. + /// + public Func? SampleAddRequested { get; init; } + + /// + /// Invoked when a sample removal is selected via this button. + /// + public Action? SampleRemoveRequested { get; init; } + + private Bindable selectedFile { get; } = new Bindable(); + + private TrianglesV2? triangles { get; set; } + + protected override float HoverLayerFinalAlpha => 0; + + private Color4? triangleGradientSecondColour; + private SpriteIcon icon = null!; + + [Resolved] + private OverlayColourProvider overlayColourProvider { get; set; } = null!; + + [Resolved] + private EditorBeatmap? editorBeatmap { get; set; } + + private HoverSounds? hoverSounds; + private ISample? sample; + + public SampleButton() + : base(null) + { + } + + [BackgroundDependencyLoader] + private void load() + { + Add(icon = new SpriteIcon + { + Icon = FontAwesome.Solid.Plus, + Size = new Vector2(16), + Shadow = true, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + + Action = () => + { + if (ActualFilename.Value == null) + { + selectedFile.Value = null; + this.ShowPopover(); + } + else + sample?.Play(); + }; + + if (editorBeatmap?.BeatmapSkin != null) + editorBeatmap.BeatmapSkin.BeatmapSkinChanged += recycleSamples; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Content.CornerRadius = 4; + + Add(triangles = new TrianglesV2 + { + Thickness = 0.02f, + SpawnRatio = 0.6f, + RelativeSizeAxes = Axes.Both, + Depth = float.MaxValue, + }); + + ActualFilename.BindValueChanged(_ => updateState(), true); + selectedFile.BindValueChanged(_ => addSample()); + } + + private void updateState() + { + BackgroundColour = ActualFilename.Value == null ? overlayColourProvider.Background3 : overlayColourProvider.Colour3; + triangleGradientSecondColour = BackgroundColour.Lighten(0.2f); + icon.Icon = ActualFilename.Value == null ? FontAwesome.Solid.Plus : FontAwesome.Solid.Play; + + recycleSamples(); + + if (triangles == null) + return; + + triangles.Colour = ColourInfo.GradientVertical(triangleGradientSecondColour.Value, BackgroundColour); + } + + private void recycleSamples() + { + if (hoverSounds?.Parent == this) + { + RemoveInternal(hoverSounds, true); + hoverSounds = null; + } + + AddInternal(hoverSounds = (ActualFilename.Value == null ? new HoverClickSounds(HoverSampleSet.Button) : new HoverSounds(HoverSampleSet.Button))); + + sample = ActualFilename.Value == null ? null : editorBeatmap?.BeatmapSkin?.Skin.Samples?.Get(ActualFilename.Value); + } + + protected override bool OnHover(HoverEvent e) + { + Debug.Assert(triangleGradientSecondColour != null); + + Background.FadeColour(triangleGradientSecondColour.Value, 300, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + Background.FadeColour(BackgroundColour, 300, Easing.OutQuint); + base.OnHoverLost(e); + } + + private void addSample() + { + if (selectedFile.Value == null) + return; + + this.HidePopover(); + ActualFilename.Value = SampleAddRequested?.Invoke(selectedFile.Value) ?? selectedFile.Value.ToString(); + } + + private void deleteSample() + { + if (ActualFilename.Value == null) + return; + + SampleRemoveRequested?.Invoke(ActualFilename.Value); + ActualFilename.Value = null; + } + + public Popover? GetPopover() => ActualFilename.Value == null ? new FormFileSelector.FileChooserPopover(SupportedExtensions.AUDIO_EXTENSIONS, selectedFile, null) : null; + + public MenuItem[]? ContextMenuItems => + ActualFilename.Value != null + ? [new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, deleteSample)] + : null; + + protected override void Dispose(bool isDisposing) + { + if (editorBeatmap?.BeatmapSkin != null) + editorBeatmap.BeatmapSkin.BeatmapSkinChanged -= recycleSamples; + base.Dispose(isDisposing); + } + } + } +} diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index ab1f5e4ad1fc..3c50adc47170 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -71,6 +71,14 @@ public SampleSet(int sampleSetIndex) } public override string ToString() => Name; + + public HashSet Filenames = []; + + public string? FindSound(string soundName, string bankName) + => Filenames.SingleOrDefault(f => f.StartsWith($@"{bankName}-{soundName}{(SampleSetIndex > 1 ? SampleSetIndex : null)}", StringComparison.Ordinal)); + + public virtual bool Equals(SampleSet? other) => SampleSetIndex == other?.SampleSetIndex; + public override int GetHashCode() => SampleSetIndex; } public IEnumerable GetAvailableSampleSets() From 0787345a84e62bf131ec5ef6efef7996e6f8d1da Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Dec 2025 22:06:39 +0900 Subject: [PATCH 313/836] Adjust colour of inactive slider bar --- osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 5e843fd75188..5487f27254db 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -440,7 +440,7 @@ protected override void OnFocusLost(FocusLostEvent e) private void updateState() { rightBox.Colour = colourProvider.Background6; - leftBox.Colour = HasFocus || IsHovered || IsDragged ? colourProvider.Highlight1.Opacity(0.5f) : colourProvider.Dark2; + leftBox.Colour = HasFocus || IsHovered || IsDragged ? colourProvider.Highlight1.Opacity(0.5f) : colourProvider.Highlight1.Opacity(0.3f); nub.Colour = HasFocus || IsHovered || IsDragged ? colourProvider.Highlight1 : colourProvider.Light4; } From 90e820b76ad2624ac5c3a8e0b962aab6499d36a8 Mon Sep 17 00:00:00 2001 From: Nathan Corbett <75299710+Finadoggie@users.noreply.github.com> Date: Mon, 22 Dec 2025 14:58:31 -0800 Subject: [PATCH 314/836] Uses real distance in speed instead of mishandling variables (#35387) Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com> --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs index a58c1d36853e..e6197b177bdc 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs @@ -51,8 +51,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, IReadOnly if (DifficultyCalculationUtils.MillisecondsToBPM(strainTime) > min_speed_bonus) speedBonus = 0.75 * Math.Pow((DifficultyCalculationUtils.BPMToMilliseconds(min_speed_bonus) - strainTime) / speed_balancing_factor, 2); - double travelDistance = osuPrevObj?.TravelDistance ?? 0; - double distance = travelDistance + osuCurrObj.MinimumJumpDistance; + double travelDistance = osuPrevObj?.LazyTravelDistance ?? 0; + double distance = travelDistance + osuCurrObj.LazyJumpDistance; // Cap distance at single_spacing_threshold distance = Math.Min(distance, single_spacing_threshold); From a25f1cde25a0d15bdb7f62058ecf8c8f96846750 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Tue, 23 Dec 2025 02:36:54 +0300 Subject: [PATCH 315/836] Localise various strings in settings --- osu.Game/Configuration/IntroSequence.cs | 5 +++++ osu.Game/Localisation/CommonStrings.cs | 5 +++++ osu.Game/Localisation/SettingsStrings.cs | 5 +++++ osu.Game/Overlays/Settings/Sections/SkinSection.cs | 2 +- osu.Game/Overlays/Settings/SettingsFooter.cs | 3 ++- 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/osu.Game/Configuration/IntroSequence.cs b/osu.Game/Configuration/IntroSequence.cs index 5672c44bbe24..70b8b0f8425d 100644 --- a/osu.Game/Configuration/IntroSequence.cs +++ b/osu.Game/Configuration/IntroSequence.cs @@ -1,6 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Localisation; +using osu.Game.Localisation; + namespace osu.Game.Configuration { public enum IntroSequence @@ -8,6 +11,8 @@ public enum IntroSequence Circles, Welcome, Triangles, + + [LocalisableDescription(typeof(CommonStrings), nameof(CommonStrings.Random))] Random } } diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index d72257f43804..1e1f83acf346 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -204,6 +204,11 @@ public static class CommonStrings /// public static LocalisableString DeleteWithConfirmation => new TranslatableString(getKey(@"delete_with_confrmation"), @"Delete..."); + /// + /// "Random" + /// + public static LocalisableString Random => new TranslatableString(getKey(@"random"), @"Random"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/SettingsStrings.cs b/osu.Game/Localisation/SettingsStrings.cs index aa2e2740ebe8..7208be8c9195 100644 --- a/osu.Game/Localisation/SettingsStrings.cs +++ b/osu.Game/Localisation/SettingsStrings.cs @@ -19,6 +19,11 @@ public static class SettingsStrings /// public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"change the way osu! behaves"); + /// + /// "Copy version" + /// + public static LocalisableString CopyVersion => new TranslatableString(getKey(@"copy_version"), @"Copy version"); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 2c24a5b277d2..93cab9e8de03 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -294,7 +294,7 @@ public RenameSkinPopover() Height = 40, RelativeSizeAxes = Axes.X, MatchingFilter = true, - Text = "Save", + Text = WebCommonStrings.ButtonsSave, } } }; diff --git a/osu.Game/Overlays/Settings/SettingsFooter.cs b/osu.Game/Overlays/Settings/SettingsFooter.cs index f50fca418d39..2e23577743a6 100644 --- a/osu.Game/Overlays/Settings/SettingsFooter.cs +++ b/osu.Game/Overlays/Settings/SettingsFooter.cs @@ -12,6 +12,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -116,7 +117,7 @@ private void load(ChangelogOverlay? changelog) public MenuItem[] ContextMenuItems => new MenuItem[] { - new OsuMenuItem("Copy version", MenuItemType.Standard, () => game?.CopyToClipboard(version)) + new OsuMenuItem(SettingsStrings.CopyVersion, MenuItemType.Standard, () => game?.CopyToClipboard(version)) }; } } From 906df15cbe81898ecc6aca9115b4f1fa69332214 Mon Sep 17 00:00:00 2001 From: Givy120 <89256026+Givikap120@users.noreply.github.com> Date: Tue, 23 Dec 2025 01:50:35 +0200 Subject: [PATCH 316/836] change FL calc depending on HD settings (#33019) Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com> --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 10 +++++++--- osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs | 6 +----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 55192df7af93..e828eba1cc61 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -2,8 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; +using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators @@ -28,7 +32,7 @@ public static class FlashlightEvaluator /// and whether the hidden mod is enabled. /// /// - public static double EvaluateDifficultyOf(DifficultyHitObject current, bool hidden) + public static double EvaluateDifficultyOf(DifficultyHitObject current, IReadOnlyList mods) { if (current.BaseObject is Spinner) return 0; @@ -66,7 +70,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool hidd double stackNerf = Math.Min(1.0, (currentObj.LazyJumpDistance / scalingFactor) / 25.0); // Bonus based on how visible the object is. - double opacityBonus = 1.0 + max_opacity_bonus * (1.0 - osuCurrent.OpacityAt(currentHitObject.StartTime, hidden)); + double opacityBonus = 1.0 + max_opacity_bonus * (1.0 - osuCurrent.OpacityAt(currentHitObject.StartTime, mods.OfType().Any(m => !m.OnlyFadeApproachCircles.Value))); result += stackNerf * opacityBonus * scalingFactor * jumpDistance / cumulativeStrainTime; @@ -84,7 +88,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool hidd result = Math.Pow(smallDistNerf * result, 2.0); // Additional bonus for Hidden due to there being no approach circles. - if (hidden) + if (mods.OfType().Any()) result *= 1.0 + hidden_bonus; // Nerf patterns with repeated angles. diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index 6c839eac3fef..70d61250bbf1 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -7,7 +7,6 @@ using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; -using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Rulesets.Osu.Difficulty.Skills { @@ -16,12 +15,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Flashlight : StrainSkill { - private readonly bool hasHiddenMod; - public Flashlight(Mod[] mods) : base(mods) { - hasHiddenMod = mods.Any(m => m is OsuModHidden); } private double skillMultiplier => 0.05512; @@ -36,7 +32,7 @@ public Flashlight(Mod[] mods) protected override double StrainValueAt(DifficultyHitObject current) { currentStrain *= strainDecay(current.DeltaTime); - currentStrain += FlashlightEvaluator.EvaluateDifficultyOf(current, hasHiddenMod) * skillMultiplier; + currentStrain += FlashlightEvaluator.EvaluateDifficultyOf(current, Mods) * skillMultiplier; return currentStrain; } From 6356d50f13942787c8c29d1bcec052d4f80cc4ac Mon Sep 17 00:00:00 2001 From: Nathan Corbett <75299710+Finadoggie@users.noreply.github.com> Date: Mon, 22 Dec 2025 16:16:01 -0800 Subject: [PATCH 317/836] Use number calculated at runtime from DecayWeight (#33733) Replaces a constant that assumes DecayWeight == 0.9 Co-authored-by: James Wilson Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com> --- osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs index b6272bf56b85..63e639cb8774 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs @@ -73,7 +73,7 @@ public virtual double CountTopWeightedStrains() if (ObjectStrains.Count == 0) return 0.0; - double consistentTopStrain = DifficultyValue() / 10; // What would the top strain be if all strain values were identical + double consistentTopStrain = DifficultyValue() * (1 - DecayWeight); // What would the top strain be if all strain values were identical if (consistentTopStrain == 0) return ObjectStrains.Count; From 277e00c74ed0525a75cc128e454d13a9a398d9e7 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Tue, 23 Dec 2025 03:21:08 +0300 Subject: [PATCH 318/836] Localise various strings on `Play` screen (again) --- .../BeatmapOffsetControlStrings.cs | 5 +++ .../Localisation/RankingStatisticsStrings.cs | 39 +++++++++++++++++++ .../PlayerSettings/BeatmapOffsetControl.cs | 2 +- .../Ranking/Statistics/AverageHitError.cs | 8 +++- .../Ranking/Statistics/SimpleStatisticItem.cs | 13 ++++--- .../Ranking/Statistics/UnstableRate.cs | 6 ++- 6 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Localisation/RankingStatisticsStrings.cs diff --git a/osu.Game/Localisation/BeatmapOffsetControlStrings.cs b/osu.Game/Localisation/BeatmapOffsetControlStrings.cs index b905b7ae1c01..37412b6a7afa 100644 --- a/osu.Game/Localisation/BeatmapOffsetControlStrings.cs +++ b/osu.Game/Localisation/BeatmapOffsetControlStrings.cs @@ -39,6 +39,11 @@ public static class BeatmapOffsetControlStrings /// public static LocalisableString HitObjectsAppearEarlier => new TranslatableString(getKey(@"hit_objects_appear_earlier"), @"(hit objects appear earlier)"); + /// + /// "Beatmap offset was adjusted to {0} ms." + /// + public static LocalisableString BeatmapOffsetWasAdjustedTo(string offset) => new TranslatableString(getKey(@"beatmap_offset_was_adjusted_to"), @"Beatmap offset was adjusted to {0} ms.", offset); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/RankingStatisticsStrings.cs b/osu.Game/Localisation/RankingStatisticsStrings.cs new file mode 100644 index 000000000000..e6bd8bdc49b8 --- /dev/null +++ b/osu.Game/Localisation/RankingStatisticsStrings.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class RankingStatisticsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.RankingStatisticsStrings"; + + /// + /// "Average Hit Error" + /// + public static LocalisableString AverageHitErrorTitle => new TranslatableString(getKey(@"average_hit_error_title"), @"Average Hit Error"); + + /// + /// "Unstable Rate" + /// + public static LocalisableString UnstableRateTitle => new TranslatableString(getKey(@"unstable_rate_title"), @"Unstable Rate"); + + /// + /// "early" + /// + public static LocalisableString Early => new TranslatableString(getKey(@"early"), @"early"); + + /// + /// "late" + /// + public static LocalisableString Late => new TranslatableString(getKey(@"late"), @"late"); + + /// + /// "(not available)" + /// + public static LocalisableString NotAvailable => new TranslatableString(getKey(@"not_available"), @"(not available)"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs b/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs index e2337a4e0eae..634f1f85d248 100644 --- a/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs +++ b/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs @@ -330,7 +330,7 @@ private void scoreChanged(ValueChangedEvent score) if (offsetChanged) { - offsetText.AddText($"Beatmap offset was adjusted to {Current.Value.ToStandardFormattedString(1)} ms.", t => t.Font = OsuFont.Style.Caption1); + offsetText.AddText(BeatmapOffsetControlStrings.BeatmapOffsetWasAdjustedTo(Current.Value.ToStandardFormattedString(1)), t => t.Font = OsuFont.Style.Caption1); offsetText.NewParagraph(); } } diff --git a/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs b/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs index fb7107cc88b3..2670a68f039f 100644 --- a/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs +++ b/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; +using osu.Framework.Localisation; using osu.Game.Rulesets.Scoring; +using osu.Game.Localisation; namespace osu.Game.Screens.Ranking.Statistics { @@ -17,11 +19,13 @@ public partial class AverageHitError : SimpleStatisticItem /// /// Sequence of s to calculate the unstable rate based on. public AverageHitError(IEnumerable hitEvents) - : base("Average Hit Error") + : base(RankingStatisticsStrings.AverageHitErrorTitle) { Value = hitEvents.CalculateAverageHitError(); } - protected override string DisplayValue(double? value) => value == null ? "(not available)" : $"{Math.Abs(value.Value):N2} ms {(value.Value < 0 ? "early" : "late")}"; + protected override LocalisableString DisplayValue(double? value) => value == null + ? RankingStatisticsStrings.NotAvailable + : $"{Math.Abs(value.Value):N2} ms {(value.Value < 0 ? RankingStatisticsStrings.Early : RankingStatisticsStrings.Late)}"; } } diff --git a/osu.Game/Screens/Ranking/Statistics/SimpleStatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/SimpleStatisticItem.cs index 280227baea78..7acb1573c36f 100644 --- a/osu.Game/Screens/Ranking/Statistics/SimpleStatisticItem.cs +++ b/osu.Game/Screens/Ranking/Statistics/SimpleStatisticItem.cs @@ -3,6 +3,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -17,7 +18,7 @@ public abstract partial class SimpleStatisticItem : Container /// /// The text to display as the statistic's value. /// - protected string Value + protected LocalisableString Value { set => valueText.Text = value; } @@ -41,9 +42,9 @@ public float FontSize /// Creates a new simple statistic item. /// /// The name of the statistic. - protected SimpleStatisticItem(string name) + protected SimpleStatisticItem(LocalisableString name) { - Name = name; + Name = name.ToString(); RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -52,7 +53,7 @@ protected SimpleStatisticItem(string name) { nameText = new OsuSpriteText { - Text = Name, + Text = name, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Font = OsuFont.GetFont(size: StatisticItem.FONT_SIZE) @@ -91,9 +92,9 @@ public partial class SimpleStatisticItem : SimpleStatisticItem /// Used to convert to a text representation. /// Defaults to using . /// - protected virtual string DisplayValue(TValue value) => value!.ToString() ?? string.Empty; + protected virtual LocalisableString DisplayValue(TValue value) => value!.ToString() ?? string.Empty; - public SimpleStatisticItem(string name) + public SimpleStatisticItem(LocalisableString name) : base(name) { } diff --git a/osu.Game/Screens/Ranking/Statistics/UnstableRate.cs b/osu.Game/Screens/Ranking/Statistics/UnstableRate.cs index c89e48e78df2..0aaf7fd06350 100644 --- a/osu.Game/Screens/Ranking/Statistics/UnstableRate.cs +++ b/osu.Game/Screens/Ranking/Statistics/UnstableRate.cs @@ -2,6 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Ranking.Statistics @@ -16,11 +18,11 @@ public partial class UnstableRate : SimpleStatisticItem /// /// Sequence of s to calculate the unstable rate based on. public UnstableRate(IReadOnlyList hitEvents) - : base("Unstable Rate") + : base(RankingStatisticsStrings.UnstableRateTitle) { Value = hitEvents.CalculateUnstableRate()?.Result; } - protected override string DisplayValue(double? value) => value?.ToString(@"N2") ?? "(not available)"; + protected override LocalisableString DisplayValue(double? value) => value?.ToString(@"N2") ?? RankingStatisticsStrings.NotAvailable; } } From d150e273818b1e8e78743f0c4f48970478d06212 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Tue, 23 Dec 2025 00:41:24 +0000 Subject: [PATCH 319/836] Reduce calls to `DifficultyValue` where possible (#36112) --- .../Difficulty/OsuDifficultyCalculator.cs | 18 +++++++++--------- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 3 ++- .../Difficulty/Skills/Speed.cs | 3 ++- .../Difficulty/TaikoDifficultyCalculator.cs | 6 ++++-- .../Rulesets/Difficulty/Skills/StrainSkill.cs | 4 ++-- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 32e3829f7444..edaef0aa75cd 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -55,17 +55,21 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat var speed = skills.OfType().Single(); var flashlight = skills.OfType().SingleOrDefault(); + double aimDifficultyValue = aim.DifficultyValue(); + double aimNoSlidersDifficultyValue = aimWithoutSliders.DifficultyValue(); + double speedDifficultyValue = speed.DifficultyValue(); + double speedNotes = speed.RelevantNoteCount(); - double aimDifficultStrainCount = aim.CountTopWeightedStrains(); - double speedDifficultStrainCount = speed.CountTopWeightedStrains(); + double aimDifficultStrainCount = aim.CountTopWeightedStrains(aimDifficultyValue); + double speedDifficultStrainCount = speed.CountTopWeightedStrains(speedDifficultyValue); - double aimNoSlidersTopWeightedSliderCount = aimWithoutSliders.CountTopWeightedSliders(); - double aimNoSlidersDifficultStrainCount = aimWithoutSliders.CountTopWeightedStrains(); + double aimNoSlidersTopWeightedSliderCount = aimWithoutSliders.CountTopWeightedSliders(aimNoSlidersDifficultyValue); + double aimNoSlidersDifficultStrainCount = aimWithoutSliders.CountTopWeightedStrains(aimNoSlidersDifficultyValue); double aimTopWeightedSliderFactor = aimNoSlidersTopWeightedSliderCount / Math.Max(1, aimNoSlidersDifficultStrainCount - aimNoSlidersTopWeightedSliderCount); - double speedTopWeightedSliderCount = speed.CountTopWeightedSliders(); + double speedTopWeightedSliderCount = speed.CountTopWeightedSliders(speedDifficultyValue); double speedTopWeightedSliderFactor = speedTopWeightedSliderCount / Math.Max(1, speedDifficultStrainCount - speedTopWeightedSliderCount); double difficultSliders = aim.GetDifficultSliders(); @@ -79,10 +83,6 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat int totalHits = beatmap.HitObjects.Count; - double aimDifficultyValue = aim.DifficultyValue(); - double aimNoSlidersDifficultyValue = aimWithoutSliders.DifficultyValue(); - double speedDifficultyValue = speed.DifficultyValue(); - double mechanicalDifficultyRating = calculateMechanicalDifficultyRating(aimDifficultyValue, speedDifficultyValue); double sliderFactor = aimDifficultyValue > 0 ? OsuRatingCalculator.CalculateDifficultyRating(aimNoSlidersDifficultyValue) / OsuRatingCalculator.CalculateDifficultyRating(aimDifficultyValue) : 1; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 5816d27a5e81..dbdfef4199ed 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -60,6 +60,7 @@ public double GetDifficultSliders() return sliderStrains.Sum(strain => 1.0 / (1.0 + Math.Exp(-(strain / maxSliderStrain * 12.0 - 6.0)))); } - public double CountTopWeightedSliders() => OsuStrainUtils.CountTopWeightedSliders(sliderStrains, DifficultyValue()); + public double CountTopWeightedSliders(double difficultyValue) + => OsuStrainUtils.CountTopWeightedSliders(sliderStrains, difficultyValue); } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 8fe3df43470e..105d3956ac6b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -64,6 +64,7 @@ public double RelevantNoteCount() return ObjectStrains.Sum(strain => 1.0 / (1.0 + Math.Exp(-(strain / maxStrain * 12.0 - 6.0)))); } - public double CountTopWeightedSliders() => OsuStrainUtils.CountTopWeightedSliders(sliderStrains, DifficultyValue()); + public double CountTopWeightedSliders(double difficultyValue) + => OsuStrainUtils.CountTopWeightedSliders(sliderStrains, difficultyValue); } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index cdb5a36f659e..4905dd327594 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -108,14 +108,16 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat var stamina = skills.OfType().Single(s => !s.SingleColourStamina); var singleColourStamina = skills.OfType().Single(s => s.SingleColourStamina); + double staminaDifficultyValue = stamina.DifficultyValue(); + double rhythmSkill = rhythm.DifficultyValue() * rhythm_skill_multiplier; double readingSkill = reading.DifficultyValue() * reading_skill_multiplier; double colourSkill = colour.DifficultyValue() * colour_skill_multiplier; - double staminaSkill = stamina.DifficultyValue() * stamina_skill_multiplier; + double staminaSkill = staminaDifficultyValue * stamina_skill_multiplier; double monoStaminaSkill = singleColourStamina.DifficultyValue() * stamina_skill_multiplier; double monoStaminaFactor = staminaSkill == 0 ? 1 : Math.Pow(monoStaminaSkill / staminaSkill, 5); - double staminaDifficultStrains = stamina.CountTopWeightedStrains(); + double staminaDifficultStrains = stamina.CountTopWeightedStrains(staminaDifficultyValue); // As we don't have pattern integration in osu!taiko, we apply the other two skills relative to rhythm. patternMultiplier = Math.Pow(staminaSkill * colourSkill, 0.10); diff --git a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs index 63e639cb8774..1fccf32242b2 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs @@ -68,12 +68,12 @@ public sealed override void Process(DifficultyHitObject current) /// Calculates the number of strains weighted against the top strain. /// The result is scaled by clock rate as it affects the total number of strains. /// - public virtual double CountTopWeightedStrains() + public virtual double CountTopWeightedStrains(double difficultyValue) { if (ObjectStrains.Count == 0) return 0.0; - double consistentTopStrain = DifficultyValue() * (1 - DecayWeight); // What would the top strain be if all strain values were identical + double consistentTopStrain = difficultyValue * (1 - DecayWeight); // What would the top strain be if all strain values were identical if (consistentTopStrain == 0) return ObjectStrains.Count; From 95233fc6384a924afefd058201946114eb40973a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 23 Dec 2025 08:23:23 +0100 Subject: [PATCH 320/836] Fix replay files potentially getting misclassified as zip archives Resolves https://github.com/ppy/osu/discussions/36107. The replay linked in the aforementioned discussion happens to contain the magic sequence for ZIP headers in the binary stream (50 4b 05 06) which led to it getting classified as a ZIP with no entries and completely bogus everything in the header at https://github.com/ppy/osu/blob/c8b18acd4dd1d98170a069240b6666cea3d5da07/osu.Game/Database/ImportTask.cs#L51-L56 and then finally dying of 2025-12-23 07:26:45 [error]: [?????] Model creation of replay-osu_2040232_4828629841.osr failed. 2025-12-23 07:26:45 [error]: System.InvalidOperationException: Sequence contains no matching element 2025-12-23 07:26:45 [error]: at System.Linq.ThrowHelper.ThrowNoMatchException() 2025-12-23 07:26:45 [error]: at System.Linq.Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate) 2025-12-23 07:26:45 [error]: at osu.Game.Scoring.ScoreImporter.CreateModel(ArchiveReader archive, ImportParameters parameters) 2025-12-23 07:26:45 [error]: at osu.Game.Database.RealmArchiveModelImporter`1.importFromArchive(ArchiveReader archive, ImportParameters parameters, CancellationToken cancellationToken) at https://github.com/ppy/osu/blob/554961036e23615b35eb6b66b341b10924664c4d/osu.Game/Scoring/ScoreImporter.cs#L46 --- osu.Game/Utils/ZipUtils.cs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/osu.Game/Utils/ZipUtils.cs b/osu.Game/Utils/ZipUtils.cs index eb2d2d3b8022..bebeff29d8cc 100644 --- a/osu.Game/Utils/ZipUtils.cs +++ b/osu.Game/Utils/ZipUtils.cs @@ -23,9 +23,15 @@ public static bool IsZipArchive(MemoryStream stream) { } } - } - return true; + // aside from opening every zip entry not failing, we also require there to *be* at least one entry. + // if there are no entries, the best case is that it's an actual empty zip + // and as such probably useless to whatever wants to use it later. + // the worst case is that it's actually *not* a zip and instead a stream of binary + // which *accidentally* happened to contain the magic sequence of bytes for the zip header (50 4b 05 06), + // and if that's the case, then we are *misclassifying* it as a zip by returning `true` unconditionally. + return arc.Entries.Count > 0; + } } catch (Exception) { @@ -52,9 +58,15 @@ public static bool IsZipArchive(string path) { } } - } - return true; + // aside from opening every zip entry not failing, we also require there to *be* at least one entry. + // if there are no entries, the best case is that it's an actual empty zip + // and as such probably useless to whatever wants to use it later. + // the worst case is that it's actually *not* a zip and instead a stream of binary + // which *accidentally* happened to contain the magic sequence of bytes for the zip header (50 4b 05 06), + // and if that's the case, then we are *misclassifying* it as a zip by returning `true` unconditionally. + return arc.Entries.Count > 0; + } } catch (Exception) { From 0bebabba9425e57a59b588d645eacae700475c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 23 Dec 2025 08:35:20 +0100 Subject: [PATCH 321/836] Replace spread operator usage with manual linq `dotnet format` expects me to put a space between the spread `..` and the expression after which is UTTERLY STUPID AND UGLY AND WRONG AND CANNOT BE `.editorconfig`'d BECAUSE [INSERT EXCESSIVELY LONG BLEEP]. God I hate when good features are kneecapped by this sort of stupidity. --- osu.Game/Screens/Edit/Components/FormSampleSet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Components/FormSampleSet.cs b/osu.Game/Screens/Edit/Components/FormSampleSet.cs index d3a640abb8d5..268795591107 100644 --- a/osu.Game/Screens/Edit/Components/FormSampleSet.cs +++ b/osu.Game/Screens/Edit/Components/FormSampleSet.cs @@ -94,7 +94,7 @@ private void load() private IEnumerable createTableContent() { - string[] columns = [HitSampleInfo.HIT_NORMAL, ..HitSampleInfo.ALL_ADDITIONS]; + string[] columns = HitSampleInfo.ALL_ADDITIONS.Prepend(HitSampleInfo.HIT_NORMAL).ToArray(); string[] rows = HitSampleInfo.ALL_BANKS; yield return columns.Select(makeTableHeading).Prepend(Empty()).ToArray(); From f58e4e48623064cf29e8013ba0cf3bf8f863fda2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 23 Dec 2025 08:43:07 +0100 Subject: [PATCH 322/836] Use sane initial value for cursor scale to avoid infinite loops --- osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index c52bc92f8395..8ddb599c2e42 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -49,7 +49,7 @@ public partial class CursorTrail : Drawable, IRequireHighFrequencyMousePosition /// protected bool AllowPartRotation { get; set; } - private Vector2 cursorScale; + private Vector2 cursorScale = Vector2.One; public Vector2 CursorScale { From c6a8d9a15074ec129041237eb817b05c7c0ed7e4 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Fri, 19 Dec 2025 01:27:01 -0500 Subject: [PATCH 323/836] Add extra form controls in test scene --- .../UserInterface/TestSceneFormControls.cs | 275 ++++++++++++------ 1 file changed, 184 insertions(+), 91 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFormControls.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFormControls.cs index 2003f5de8358..a1872b30defd 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFormControls.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFormControls.cs @@ -1,15 +1,18 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; +using osu.Game.Overlays; using osu.Game.Screens.Edit.Setup; using osuTK; @@ -25,109 +28,199 @@ public TestSceneFormControls() protected override Drawable CreateContent() => new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, - Child = new PopoverContainer + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Child = new OsuScrollContainer + new BackgroundBox { RelativeSizeAxes = Axes.Both, - Child = new FillFlowContainer + }, + new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + Child = new OsuScrollContainer { - AutoSizeAxes = Axes.Y, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Width = 400, - Direction = FillDirection.Vertical, - Spacing = new Vector2(5), - Padding = new MarginPadding(10), - Children = new Drawable[] + RelativeSizeAxes = Axes.Both, + Child = new FillFlowContainer { - new FormTextBox - { - Caption = "Artist", - HintText = "Poot artist here!", - PlaceholderText = "Here is an artist", - TabbableContentContainer = this, - }, - new FormTextBox - { - Caption = "Artist", - HintText = "Poot artist here!", - PlaceholderText = "Here is an artist", - Current = { Disabled = true }, - TabbableContentContainer = this, - }, - new FormNumberBox(allowDecimals: true) - { - Caption = "Number", - HintText = "Insert your favourite number", - PlaceholderText = "Mine is 42!", - TabbableContentContainer = this, - }, - new FormCheckBox + AutoSizeAxes = Axes.Y, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 400, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + Padding = new MarginPadding(10), + Children = new Drawable[] { - Caption = EditorSetupStrings.LetterboxDuringBreaks, - HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, - }, - new FormCheckBox - { - Caption = EditorSetupStrings.LetterboxDuringBreaks, - HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, - Current = { Disabled = true }, - }, - new FormSliderBar - { - Caption = "Slider", - Current = new BindableFloat + new FormTextBox { - MinValue = 0, - MaxValue = 10, - Value = 5, - Precision = 0.1f, + Caption = "Artist", + HintText = "Poot artist here!", + PlaceholderText = "Here is an artist", + TabbableContentContainer = this, + }, + new FormTextBox + { + Caption = "Artist", + HintText = "Poot artist here!", + PlaceholderText = "Here is an artist", + Current = { Disabled = true }, + TabbableContentContainer = this, + }, + new FormNumberBox(allowDecimals: true) + { + Caption = "Number", + HintText = "Insert your favourite number", + PlaceholderText = "Mine is 42!", + TabbableContentContainer = this, + }, + new FormCheckBox + { + Caption = EditorSetupStrings.LetterboxDuringBreaks, + HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, + }, + new FormCheckBox + { + Caption = EditorSetupStrings.LetterboxDuringBreaks, + HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, + Current = { Disabled = true }, + }, + new FormCheckBox + { + Caption = EditorSetupStrings.LetterboxDuringBreaks, + HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, + Current = { Value = true, Disabled = true }, + }, + new FormSliderBar + { + Caption = "Slider", + HintText = "Slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Value = 5, + Precision = 0.1f, + }, + TabbableContentContainer = this, + }, + new FormSliderBar + { + Caption = "Slider", + HintText = "Slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Value = 5, + Precision = 0.1f, + Disabled = true, + }, + TransferValueOnCommit = true, + TabbableContentContainer = this, + }, + new FormSliderBar + { + Caption = "Slider (percentage)", + HintText = "Percentage slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 1, + Value = 0.2f, + Precision = 0.0001f, + }, + DisplayAsPercentage = true, + TabbableContentContainer = this, + }, + new FormSliderBar + { + Caption = "Slider (custom)", + HintText = "Custom slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 1, + Value = 0.2f, + Precision = 0.0001f, + }, + LabelFormat = v => $"{v * 100:0.00} funometer", + TooltipFormat = v => $"This setting has the value set to {v * 100:0.00} funometer.", + TabbableContentContainer = this, + }, + new FormSliderBar + { + Caption = "Slider (custom)", + HintText = "Custom slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 1, + Value = 0.2f, + Precision = 0.0001f, + Disabled = true, + }, + TransferValueOnCommit = true, + LabelFormat = v => $"{v * 100:0.00} funometer", + TooltipFormat = v => $"This setting has the value set to {v * 100:0.00} funometer.", + TabbableContentContainer = this, + }, + new FormEnumDropdown + { + Caption = EditorSetupStrings.EnableCountdown, + HintText = EditorSetupStrings.CountdownDescription, + }, + new FormEnumDropdown + { + Caption = EditorSetupStrings.EnableCountdown, + HintText = EditorSetupStrings.CountdownDescription, + Current = { Disabled = true }, + }, + new FormFileSelector + { + Caption = "File selector", + PlaceholderText = "Select a file", + }, + new FormBeatmapFileSelector(true) + { + Caption = "File selector with intermediate choice dialog", + PlaceholderText = "Select a file", + }, + new FormColourPalette + { + Caption = "Combo colours", + Colours = + { + Colour4.Red, + Colour4.Green, + Colour4.Blue, + Colour4.Yellow, + } + }, + new FormButton + { + Caption = "No text in button", + Action = () => { }, + }, + new FormButton + { + Caption = "Text in button which is pretty long and is very likely to wrap", + ButtonText = "Foo the bar", + Action = () => { }, }, - TabbableContentContainer = this, - }, - new FormEnumDropdown - { - Caption = EditorSetupStrings.EnableCountdown, - HintText = EditorSetupStrings.CountdownDescription, - }, - new FormFileSelector - { - Caption = "File selector", - PlaceholderText = "Select a file", - }, - new FormBeatmapFileSelector(true) - { - Caption = "File selector with intermediate choice dialog", - PlaceholderText = "Select a file", - }, - new FormColourPalette - { - Caption = "Combo colours", - Colours = - { - Colour4.Red, - Colour4.Green, - Colour4.Blue, - Colour4.Yellow, - } - }, - new FormButton - { - Caption = "No text in button", - Action = () => { }, - }, - new FormButton - { - Caption = "Text in button which is pretty long and is very likely to wrap", - ButtonText = "Foo the bar", - Action = () => { }, }, }, }, - }, + } } }; + + private partial class BackgroundBox : Box + { + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Colour = colourProvider.Background4; + } + } } } From a2872ee87071624911fc7540e279552179dbc272 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Fri, 19 Dec 2025 01:21:39 -0500 Subject: [PATCH 324/836] Update "disabled" visual feedback of form controls --- .../Graphics/UserInterfaceV2/FormCheckBox.cs | 18 +++++------- .../Graphics/UserInterfaceV2/FormDropdown.cs | 29 +++++++++---------- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 11 ++++--- .../Graphics/UserInterfaceV2/FormTextBox.cs | 26 +++++++---------- 4 files changed, 39 insertions(+), 45 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs index 586f6546ab19..df5b3c433b50 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs @@ -147,20 +147,18 @@ protected override bool OnClick(ClickEvent e) private void updateState() { - background.Colour = Current.Disabled ? colourProvider.Background4 : colourProvider.Background5; - caption.Colour = Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content2; - checkbox.Colour = Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content1; - text.Colour = Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content1; + caption.Colour = Current.Disabled ? colourProvider.Background1 : colourProvider.Content2; + text.Colour = Current.Disabled ? colourProvider.Background1 : colourProvider.Content1; text.Text = Current.Value ? CommonStrings.Enabled : CommonStrings.Disabled; - if (!Current.Disabled) - { - BorderThickness = IsHovered ? 2 : 0; + // use FadeColour to override any existing colour transform (i.e. FlashColour on click). + background.FadeColour(IsHovered + ? ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4) + : colourProvider.Background5); - if (IsHovered) - BorderColour = colourProvider.Light4; - } + BorderThickness = IsHovered ? 2 : 0; + BorderColour = Current.Disabled ? colourProvider.Dark1 : colourProvider.Light4; } public IEnumerable FilterTerms => Caption.Yield(); diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index a12d166f5620..4b9c94d10194 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -210,29 +210,26 @@ private void updateState() { label.Alpha = string.IsNullOrEmpty(SearchBar.SearchTerm.Value) ? 1 : 0; - caption.Colour = Dropdown.Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content2; - label.Colour = Dropdown.Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content1; - chevron.Colour = Dropdown.Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content1; + caption.Colour = Dropdown.Current.Disabled ? colourProvider.Background1 : colourProvider.Content2; + label.Colour = Dropdown.Current.Disabled ? colourProvider.Background1 : colourProvider.Content1; + chevron.Colour = Dropdown.Current.Disabled ? colourProvider.Background1 : colourProvider.Content1; DisabledColour = Colour4.White; bool dropdownOpen = Dropdown.Menu.State == MenuState.Open; - if (!Dropdown.Current.Disabled) - { - BorderThickness = IsHovered || dropdownOpen ? 2 : 0; + BorderThickness = IsHovered || dropdownOpen ? 2 : 0; + + if (Dropdown.Current.Disabled) + BorderColour = colourProvider.Dark1; + else BorderColour = dropdownOpen ? colourProvider.Highlight1 : colourProvider.Light4; - if (dropdownOpen) - Background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); - else if (IsHovered) - Background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); - else - Background.Colour = colourProvider.Background5; - } + if (dropdownOpen) + Background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); + else if (IsHovered) + Background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); else - { - Background.Colour = colourProvider.Background4; - } + Background.Colour = colourProvider.Background5; } private void updateChevron() diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 06f9db78464e..dfed778bbfe3 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -302,12 +302,15 @@ private void updateState() textBox.Alpha = 1; textBox.ReadOnly = Current.Disabled; - background.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background4 : colourProvider.Background5; - captionText.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Foreground1 : colourProvider.Content2; - textBox.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Foreground1 : colourProvider.Content1; + captionText.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background1 : colourProvider.Content2; + textBox.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background1 : colourProvider.Content1; BorderThickness = childHasFocus || IsHovered || slider.IsDragging.Value ? 2 : 0; - BorderColour = childHasFocus ? colourProvider.Highlight1 : colourProvider.Light4; + + if (Current.Disabled) + BorderColour = colourProvider.Dark1; + else + BorderColour = childHasFocus ? colourProvider.Highlight1 : colourProvider.Light4; if (childHasFocus) background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); diff --git a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs index 4981557e3712..6429eb6e960c 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs @@ -189,26 +189,22 @@ private void updateState() textBox.ReadOnly = disabled; textBox.Alpha = 1; - caption.Colour = disabled ? colourProvider.Foreground1 : colourProvider.Content2; + caption.Colour = disabled ? colourProvider.Background1 : colourProvider.Content2; textBox.Colour = disabled ? colourProvider.Foreground1 : colourProvider.Content1; - if (!disabled) - { - BorderThickness = IsHovered || textBox.Focused.Value ? 2 : 0; + BorderThickness = IsHovered || textBox.Focused.Value ? 2 : 0; + + if (disabled) + BorderColour = colourProvider.Dark1; + else BorderColour = textBox.Focused.Value ? colourProvider.Highlight1 : colourProvider.Light4; - if (textBox.Focused.Value) - background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); - else if (IsHovered) - background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); - else - background.Colour = colourProvider.Background5; - } + if (textBox.Focused.Value) + background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); + else if (IsHovered) + background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); else - { - BorderThickness = 0; - background.Colour = colourProvider.Background4; - } + background.Colour = colourProvider.Background5; } internal partial class InnerTextBox : OsuTextBox From 339aad42a7a261faf6be7e53375dcdee7baecb6d Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Fri, 19 Dec 2025 01:28:29 -0500 Subject: [PATCH 325/836] Use switch button for form checkbox controls --- .../UserInterface/TestSceneSwitchButton.cs | 11 ++++ .../Graphics/UserInterfaceV2/FormCheckBox.cs | 9 ++- .../Graphics/UserInterfaceV2/SwitchButton.cs | 66 +++++++++++-------- 3 files changed, 57 insertions(+), 29 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs index f3ab5dbff87e..93b96dd5ec76 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterfaceV2; using osuTK.Input; @@ -42,5 +43,15 @@ public void TestChangeThroughBindable() AddStep("toggle bindable", () => bindable.Toggle()); AddStep("toggle bindable", () => bindable.Toggle()); } + + [Test] + public void TestDisabledState() + { + AddToggleStep("toggle disabled", v => + { + if (switchButton.IsNotNull()) + switchButton.Current.Disabled = v; + }); + } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs index df5b3c433b50..01a197c99c1e 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs @@ -16,7 +16,6 @@ using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays; @@ -45,7 +44,6 @@ public Bindable Current private Box background = null!; private FormFieldCaption caption = null!; private OsuSpriteText text = null!; - private Nub checkbox = null!; private Sample? sampleChecked; private Sample? sampleUnchecked; @@ -89,7 +87,7 @@ private void load(AudioManager audio) Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, }, - checkbox = new Nub + new FormSwitchButton { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, @@ -170,5 +168,10 @@ private void updateState() public void SetDefault() => Current.SetDefault(); public bool IsDisabled => Current.Disabled; + + private partial class FormSwitchButton : SwitchButton + { + public override bool PropagatePositionalInputSubTree => false; + } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs index cf569a73ca0e..fe72775bb582 100644 --- a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs @@ -4,7 +4,6 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -26,10 +25,10 @@ public partial class SwitchButton : Checkbox private readonly Box fill; private readonly Container switchContainer; private readonly Drawable switchCircle; - private readonly CircularBorderContainer circularContainer; + private readonly CircularContainer circularContainer; - private Color4 enabledColour; - private Color4 disabledColour; + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; private Sample? sampleChecked; private Sample? sampleUnchecked; @@ -38,7 +37,7 @@ public SwitchButton() { Size = new Vector2(45, 20); - InternalChild = circularContainer = new CircularBorderContainer + InternalChild = circularContainer = new CircularContainer { RelativeSizeAxes = Axes.Both, BorderColour = Color4.White, @@ -73,14 +72,8 @@ public SwitchButton() } [BackgroundDependencyLoader(true)] - private void load(OverlayColourProvider? colourProvider, OsuColour colours, AudioManager audio) + private void load(AudioManager audio) { - enabledColour = colourProvider?.Highlight1 ?? colours.BlueDark; - disabledColour = colourProvider?.Background3 ?? colours.Gray3; - - switchContainer.Colour = enabledColour; - fill.Colour = disabledColour; - sampleChecked = audio.Samples.Get(@"UI/check-on"); sampleUnchecked = audio.Samples.Get(@"UI/check-off"); } @@ -89,27 +82,29 @@ protected override void LoadComplete() { base.LoadComplete(); - Current.BindValueChanged(updateState, true); + Current.BindDisabledChanged(_ => updateColours()); + Current.BindValueChanged(_ => updateState(), true); + FinishTransforms(true); } - private void updateState(ValueChangedEvent state) + private void updateState() { - switchCircle.MoveToX(state.NewValue ? switchContainer.DrawWidth - switchCircle.DrawWidth : 0, 200, Easing.OutQuint); - fill.FadeTo(state.NewValue ? 1 : 0, 250, Easing.OutQuint); + switchCircle.MoveToX(Current.Value ? switchContainer.DrawWidth - switchCircle.DrawWidth : 0, 200, Easing.OutQuint); + fill.FadeTo(Current.Value ? 1 : 0, 250, Easing.OutQuint); - updateBorder(); + updateColours(); } protected override bool OnHover(HoverEvent e) { - updateBorder(); + updateColours(); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - updateBorder(); + updateColours(); base.OnHoverLost(e); } @@ -123,15 +118,34 @@ protected override void OnUserChange(bool value) sampleUnchecked?.Play(); } - private void updateBorder() + private void updateColours() { - circularContainer.TransformBorderTo((Current.Value ? enabledColour : disabledColour).Lighten(IsHovered ? 0.3f : 0)); - } + ColourInfo targetSwitchColour; + ColourInfo targetBorderColour; - private partial class CircularBorderContainer : CircularContainer - { - public void TransformBorderTo(ColourInfo colour) - => this.TransformTo(nameof(BorderColour), colour, 250, Easing.OutQuint); + if (Current.Disabled) + { + if (Current.Value) + targetBorderColour = colourProvider.Dark1.Opacity(0.5f); + else + targetBorderColour = colourProvider.Background2.Opacity(0.5f); + + targetSwitchColour = colourProvider.Dark1.Opacity(0.5f); + fill.Colour = colourProvider.Background5; + } + else + { + if (Current.Value) + targetBorderColour = IsHovered ? colourProvider.Highlight1.Lighten(0.3f) : colourProvider.Highlight1; + else + targetBorderColour = IsHovered ? colourProvider.Background1 : colourProvider.Background2; + + targetSwitchColour = colourProvider.Highlight1; + fill.Colour = colourProvider.Background4; + } + + switchContainer.FadeColour(targetSwitchColour, 250, Easing.OutQuint); + circularContainer.TransformTo(nameof(BorderColour), targetBorderColour, 250, Easing.OutQuint); } } } From c2c1fa4d4c10e662a310f502245b66556369a47f Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Fri, 19 Dec 2025 01:28:43 -0500 Subject: [PATCH 326/836] Add right margin to form dropdown chevron --- osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index 4b9c94d10194..1f6928b22d5a 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -171,6 +171,7 @@ private void load() Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Size = new Vector2(16), + Margin = new MarginPadding { Right = 5 }, }, }; From 4ee7e6f787435188a7a1d58832d5fb6e1a6ebf74 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Fri, 19 Dec 2025 01:42:32 -0500 Subject: [PATCH 327/836] Add label and tooltip formatting to form sliders --- .../Graphics/UserInterface/OsuSliderBar.cs | 6 +- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 62 ++++++++++++++++++- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index ca95d45042a9..3aeb95ac01fc 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -46,7 +46,7 @@ private void load(AudioManager audio) protected override void LoadComplete() { base.LoadComplete(); - CurrentNumber.BindValueChanged(current => TooltipText = GetDisplayableValue(current.NewValue), true); + CurrentNumber.BindValueChanged(current => TooltipText = GetTooltipText(current.NewValue), true); } protected override void OnUserChange(T value) @@ -55,7 +55,7 @@ protected override void OnUserChange(T value) playSample(value); - TooltipText = GetDisplayableValue(value); + TooltipText = GetTooltipText(value); } private void playSample(T value) @@ -83,6 +83,6 @@ private void playSample(T value) channel.Play(); } - public LocalisableString GetDisplayableValue(T value) => value.ToStandardFormattedString(max_decimal_digits, DisplayAsPercentage); + protected virtual LocalisableString GetTooltipText(T value) => value.ToStandardFormattedString(max_decimal_digits, DisplayAsPercentage); } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index dfed778bbfe3..6e3c0594707e 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -17,6 +17,8 @@ using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Game.Extensions; +using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays; @@ -97,9 +99,31 @@ public float KeyboardStep } } + /// + /// Whether to format the tooltip as a percentage or the actual value. + /// + public bool DisplayAsPercentage { get; init; } + + /// + /// Whether sound effects should play when adjusting this slider. + /// + public bool PlaySamplesOnAdjust { get; init; } + + /// + /// The string formatting function to use for the value label. + /// + public Func LabelFormat { get; init; } + + /// + /// The string formatting function to use for the slider's tooltip text. + /// If not provided, is used. + /// + public Func TooltipFormat { get; init; } + private Box background = null!; private Box flashLayer = null!; private FormTextBox.InnerTextBox textBox = null!; + private OsuSpriteText valueLabel = null!; private InnerSlider slider = null!; private FormFieldCaption captionText = null!; private IFocusManager focusManager = null!; @@ -109,6 +133,12 @@ public float KeyboardStep private readonly Bindable currentLanguage = new Bindable(); + public FormSliderBar() + { + LabelFormat ??= defaultLabelFormat; + TooltipFormat ??= v => LabelFormat(v); + } + [BackgroundDependencyLoader] private void load(OsuColour colours, OsuGame? game) { @@ -153,6 +183,10 @@ private void load(OsuColour colours, OsuGame? game) Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.X, Width = 0.5f, + // the textbox is hidden when the control is unfocused, + // but clicking on the label should reach the textbox, + // therefore make it always present. + AlwaysPresent = true, CommitOnFocusLost = true, SelectAllOnFocus = true, OnInputError = () => @@ -162,6 +196,14 @@ private void load(OsuColour colours, OsuGame? game) }, TabbableContentContainer = tabbableContentContainer, }, + valueLabel = new TruncatingSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Width = 0.5f, + Padding = new MarginPadding { Right = 5 }, + }, slider = new InnerSlider { Anchor = Anchor.CentreRight, @@ -170,6 +212,9 @@ private void load(OsuColour colours, OsuGame? game) Width = 0.5f, Current = currentNumberInstantaneous, OnCommit = () => current.Value = currentNumberInstantaneous.Value, + TooltipFormat = TooltipFormat, + DisplayAsPercentage = DisplayAsPercentage, + PlaySamplesOnAdjust = PlaySamplesOnAdjust, } }, }, @@ -218,6 +263,7 @@ protected override void LoadComplete() current.CopyTo(currentNumberInstantaneous); currentLanguage.BindValueChanged(_ => Schedule(updateValueDisplay)); + currentNumberInstantaneous.BindDisabledChanged(_ => updateState()); currentNumberInstantaneous.BindValueChanged(e => { if (!TransferValueOnCommit) @@ -299,11 +345,13 @@ private void updateState() { bool childHasFocus = slider.Focused.Value || textBox.Focused.Value; - textBox.Alpha = 1; - textBox.ReadOnly = Current.Disabled; + textBox.ReadOnly = currentNumberInstantaneous.Disabled; + textBox.Alpha = textBox.Focused.Value ? 1 : 0; + valueLabel.Alpha = textBox.Focused.Value ? 0 : 1; captionText.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background1 : colourProvider.Content2; textBox.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background1 : colourProvider.Content1; + valueLabel.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background1 : colourProvider.Content1; BorderThickness = childHasFocus || IsHovered || slider.IsDragging.Value ? 2 : 0; @@ -324,16 +372,22 @@ private void updateValueDisplay() { if (updatingFromTextBox) return; - textBox.Text = slider.GetDisplayableValue(currentNumberInstantaneous.Value).ToString(); + textBox.Text = currentNumberInstantaneous.Value.ToStandardFormattedString(5); + valueLabel.Text = LabelFormat(currentNumberInstantaneous.Value); } + private LocalisableString defaultLabelFormat(T value) => currentNumberInstantaneous.Value.ToStandardFormattedString(5, DisplayAsPercentage); + private partial class InnerSlider : OsuSliderBar { public BindableBool Focused { get; } = new BindableBool(); public BindableBool IsDragging { get; set; } = new BindableBool(); + public Action? OnCommit { get; set; } + public required Func TooltipFormat { get; init; } + private Box leftBox = null!; private Box rightBox = null!; private InnerSliderNub nub = null!; @@ -473,6 +527,8 @@ protected override bool Commit() return result; } + + protected override LocalisableString GetTooltipText(T value) => TooltipFormat(value); } private partial class InnerSliderNub : Circle From cb32d2da3e9fc780138d7d604a1ff8c62be8d8a0 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Mon, 22 Dec 2025 20:19:36 -0500 Subject: [PATCH 328/836] Make sound playback consistent across all disabled controls --- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 4 +++- osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs | 5 +++++ osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs | 5 ++++- osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs | 4 +++- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 3aeb95ac01fc..f584e1e5d90c 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -33,6 +33,7 @@ public abstract partial class OsuSliderBar : SliderBar, IHasTooltip private const int max_decimal_digits = 5; private Sample sample = null!; + private Sample sampleDisabled = null!; private double lastSampleTime; private T lastSampleValue; @@ -41,6 +42,7 @@ public abstract partial class OsuSliderBar : SliderBar, IHasTooltip private void load(AudioManager audio) { sample = audio.Samples.Get(@"UI/notch-tick"); + sampleDisabled = audio.Samples.Get(@"UI/default-select-disabled"); } protected override void LoadComplete() @@ -72,7 +74,7 @@ private void playSample(T value) lastSampleValue = value; lastSampleTime = Clock.CurrentTime; - var channel = sample.GetChannel(); + var channel = Current.Disabled ? sampleDisabled.GetChannel() : sample.GetChannel(); channel.Frequency.Value = 0.99f + RNG.NextDouble(0.02f) + NormalizedValue * 0.2f; diff --git a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs index 01a197c99c1e..43e42faa2442 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs @@ -47,6 +47,7 @@ public Bindable Current private Sample? sampleChecked; private Sample? sampleUnchecked; + private Sample? sampleDisabled; [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -99,6 +100,7 @@ private void load(AudioManager audio) sampleChecked = audio.Samples.Get(@"UI/check-on"); sampleUnchecked = audio.Samples.Get(@"UI/check-off"); + sampleDisabled = audio.Samples.Get(@"UI/default-select-disabled"); } protected override void LoadComplete() @@ -140,6 +142,9 @@ protected override bool OnClick(ClickEvent e) { if (!Current.Disabled) Current.Value = !Current.Value; + else + sampleDisabled?.Play(); + return true; } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index 1f6928b22d5a..1c595e138623 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -175,7 +175,10 @@ private void load() }, }; - AddInternal(new HoverClickSounds()); + AddInternal(new HoverClickSounds + { + Enabled = { BindTarget = Enabled }, + }); } protected override void LoadComplete() diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 6e3c0594707e..884ae91aa82c 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -391,6 +391,7 @@ private partial class InnerSlider : OsuSliderBar private Box leftBox = null!; private Box rightBox = null!; private InnerSliderNub nub = null!; + private HoverClickSounds sounds = null!; public const float NUB_WIDTH = 10; [Resolved] @@ -439,7 +440,7 @@ private void load() } } }, - new HoverClickSounds() + sounds = new HoverClickSounds() }; } @@ -499,6 +500,7 @@ protected override void OnFocusLost(FocusLostEvent e) private void updateState() { + sounds.Enabled.Value = !Current.Disabled; rightBox.Colour = colourProvider.Background6; if (Current.Disabled) From a3a5b2ca92a9335a7233b89abc2801576bf7f069 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Tue, 23 Dec 2025 05:58:57 -0500 Subject: [PATCH 329/836] Fix tests not having colour providers --- .../Visual/UserInterface/TestSceneLabelledSwitchButton.cs | 5 +++++ osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs index bec517af2c11..24ef51806a21 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs @@ -2,14 +2,19 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Overlays; namespace osu.Game.Tests.Visual.UserInterface { public partial class TestSceneLabelledSwitchButton : OsuTestScene { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); + [TestCase(false)] [TestCase(true)] public void TestSwitchButton(bool hasDescription) => createSwitchButton(hasDescription); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs index 93b96dd5ec76..9b2a7ae2ef26 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs @@ -4,16 +4,21 @@ #nullable disable using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Overlays; using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { public partial class TestSceneSwitchButton : OsuManualInputManagerTestScene { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); + private SwitchButton switchButton; [SetUp] From a1d4d4415130b6fc54647f8943b3ce28e73a69fa Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Tue, 23 Dec 2025 05:59:51 -0500 Subject: [PATCH 330/836] Revert unintended change --- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index f584e1e5d90c..3aeb95ac01fc 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -33,7 +33,6 @@ public abstract partial class OsuSliderBar : SliderBar, IHasTooltip private const int max_decimal_digits = 5; private Sample sample = null!; - private Sample sampleDisabled = null!; private double lastSampleTime; private T lastSampleValue; @@ -42,7 +41,6 @@ public abstract partial class OsuSliderBar : SliderBar, IHasTooltip private void load(AudioManager audio) { sample = audio.Samples.Get(@"UI/notch-tick"); - sampleDisabled = audio.Samples.Get(@"UI/default-select-disabled"); } protected override void LoadComplete() @@ -74,7 +72,7 @@ private void playSample(T value) lastSampleValue = value; lastSampleTime = Clock.CurrentTime; - var channel = Current.Disabled ? sampleDisabled.GetChannel() : sample.GetChannel(); + var channel = sample.GetChannel(); channel.Frequency.Value = 0.99f + RNG.NextDouble(0.02f) + NormalizedValue * 0.2f; From 520baf6c5080562ea745bcdfeec7686331397c0a Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Tue, 23 Dec 2025 06:03:04 -0500 Subject: [PATCH 331/836] Add explanatory note --- osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs index 43e42faa2442..78feee871d19 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs @@ -176,6 +176,8 @@ private void updateState() private partial class FormSwitchButton : SwitchButton { + // it doesn't make sense for this to show hover state or respond to input. + // FormCheckBox already handles all of that. public override bool PropagatePositionalInputSubTree => false; } } From e4d7bc3896f0200f466c3e59d64b9956629eaeb7 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Tue, 23 Dec 2025 06:10:42 -0500 Subject: [PATCH 332/836] Seal tooltip text overrides --- osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 884ae91aa82c..e8af73ed8bd5 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -386,6 +386,8 @@ private partial class InnerSlider : OsuSliderBar public Action? OnCommit { get; set; } + public sealed override LocalisableString TooltipText => base.TooltipText; + public required Func TooltipFormat { get; init; } private Box leftBox = null!; @@ -530,7 +532,7 @@ protected override bool Commit() return result; } - protected override LocalisableString GetTooltipText(T value) => TooltipFormat(value); + protected sealed override LocalisableString GetTooltipText(T value) => TooltipFormat(value); } private partial class InnerSliderNub : Circle From fa32be37d69f080a9cfa36a40936fa10cee4d72e Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Tue, 23 Dec 2025 06:14:48 -0500 Subject: [PATCH 333/836] Expose constant for max decimal digits display --- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 4 ++-- osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 3aeb95ac01fc..f9a7f475d615 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -30,7 +30,7 @@ public abstract partial class OsuSliderBar : SliderBar, IHasTooltip /// /// Maximum number of decimal digits to be displayed in the tooltip. /// - private const int max_decimal_digits = 5; + public const int MAX_DECIMAL_DIGITS = 5; private Sample sample = null!; @@ -83,6 +83,6 @@ private void playSample(T value) channel.Play(); } - protected virtual LocalisableString GetTooltipText(T value) => value.ToStandardFormattedString(max_decimal_digits, DisplayAsPercentage); + protected virtual LocalisableString GetTooltipText(T value) => value.ToStandardFormattedString(MAX_DECIMAL_DIGITS, DisplayAsPercentage); } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index e8af73ed8bd5..310be77f31de 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -372,11 +372,11 @@ private void updateValueDisplay() { if (updatingFromTextBox) return; - textBox.Text = currentNumberInstantaneous.Value.ToStandardFormattedString(5); + textBox.Text = currentNumberInstantaneous.Value.ToStandardFormattedString(OsuSliderBar.MAX_DECIMAL_DIGITS); valueLabel.Text = LabelFormat(currentNumberInstantaneous.Value); } - private LocalisableString defaultLabelFormat(T value) => currentNumberInstantaneous.Value.ToStandardFormattedString(5, DisplayAsPercentage); + private LocalisableString defaultLabelFormat(T value) => currentNumberInstantaneous.Value.ToStandardFormattedString(OsuSliderBar.MAX_DECIMAL_DIGITS, DisplayAsPercentage); private partial class InnerSlider : OsuSliderBar { From 0bfff2bf88808ae7fbbdfd7e4fc4d70a3771d9d5 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Tue, 23 Dec 2025 14:27:34 +0300 Subject: [PATCH 334/836] Make edits based on reviews --- osu.Game/Localisation/RankingStatisticsStrings.cs | 8 ++++---- .../Screens/Ranking/Statistics/AverageHitError.cs | 12 +++++++++--- .../Ranking/Statistics/SimpleStatisticItem.cs | 10 +++++++++- osu.Game/Screens/Ranking/Statistics/UnstableRate.cs | 3 ++- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/osu.Game/Localisation/RankingStatisticsStrings.cs b/osu.Game/Localisation/RankingStatisticsStrings.cs index e6bd8bdc49b8..5d26390c7963 100644 --- a/osu.Game/Localisation/RankingStatisticsStrings.cs +++ b/osu.Game/Localisation/RankingStatisticsStrings.cs @@ -20,14 +20,14 @@ public static class RankingStatisticsStrings public static LocalisableString UnstableRateTitle => new TranslatableString(getKey(@"unstable_rate_title"), @"Unstable Rate"); /// - /// "early" + /// "{0} ms early" /// - public static LocalisableString Early => new TranslatableString(getKey(@"early"), @"early"); + public static LocalisableString Early(string offset) => new TranslatableString(getKey(@"early"), @"{0} ms early", offset); /// - /// "late" + /// "{0} ms late" /// - public static LocalisableString Late => new TranslatableString(getKey(@"late"), @"late"); + public static LocalisableString Late(string offset) => new TranslatableString(getKey(@"late"), @"{0} ms late", offset); /// /// "(not available)" diff --git a/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs b/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs index 2670a68f039f..1d20479e18f9 100644 --- a/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs +++ b/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs @@ -24,8 +24,14 @@ public AverageHitError(IEnumerable hitEvents) Value = hitEvents.CalculateAverageHitError(); } - protected override LocalisableString DisplayValue(double? value) => value == null - ? RankingStatisticsStrings.NotAvailable - : $"{Math.Abs(value.Value):N2} ms {(value.Value < 0 ? RankingStatisticsStrings.Early : RankingStatisticsStrings.Late)}"; + protected override LocalisableString DisplayValue(double? value) + { + return value == null ? RankingStatisticsStrings.NotAvailable : getEarlyLateText(value.Value); + + LocalisableString getEarlyLateText(double offset) => + offset < 0 + ? RankingStatisticsStrings.Early(Math.Abs(offset).ToString(@"N2")) + : RankingStatisticsStrings.Late(Math.Abs(offset).ToString(@"N2")); + } } } diff --git a/osu.Game/Screens/Ranking/Statistics/SimpleStatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/SimpleStatisticItem.cs index 7acb1573c36f..f56b09cfc070 100644 --- a/osu.Game/Screens/Ranking/Statistics/SimpleStatisticItem.cs +++ b/osu.Game/Screens/Ranking/Statistics/SimpleStatisticItem.cs @@ -1,6 +1,8 @@ // 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 osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; @@ -92,7 +94,13 @@ public partial class SimpleStatisticItem : SimpleStatisticItem /// Used to convert to a text representation. /// Defaults to using . /// - protected virtual LocalisableString DisplayValue(TValue value) => value!.ToString() ?? string.Empty; + protected virtual LocalisableString DisplayValue(TValue value) + { + if (value is IFormattable formattable) + return formattable.ToLocalisableString(); + + return value!.ToString() ?? string.Empty; + } public SimpleStatisticItem(LocalisableString name) : base(name) diff --git a/osu.Game/Screens/Ranking/Statistics/UnstableRate.cs b/osu.Game/Screens/Ranking/Statistics/UnstableRate.cs index 0aaf7fd06350..3cdc29e26807 100644 --- a/osu.Game/Screens/Ranking/Statistics/UnstableRate.cs +++ b/osu.Game/Screens/Ranking/Statistics/UnstableRate.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; using osu.Game.Localisation; using osu.Game.Rulesets.Scoring; @@ -23,6 +24,6 @@ public UnstableRate(IReadOnlyList hitEvents) Value = hitEvents.CalculateUnstableRate()?.Result; } - protected override LocalisableString DisplayValue(double? value) => value?.ToString(@"N2") ?? RankingStatisticsStrings.NotAvailable; + protected override LocalisableString DisplayValue(double? value) => value?.ToLocalisableString(@"N2") ?? RankingStatisticsStrings.NotAvailable; } } From 95cf05029884bb1ccff19171f005eeef774bdf1e Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Tue, 23 Dec 2025 06:31:26 -0500 Subject: [PATCH 335/836] Make setter protected to fix build error --- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index f9a7f475d615..72e3b19a6a27 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -25,7 +25,7 @@ public abstract partial class OsuSliderBar : SliderBar, IHasTooltip /// public bool DisplayAsPercentage { get; set; } - public virtual LocalisableString TooltipText { get; private set; } + public virtual LocalisableString TooltipText { get; protected set; } /// /// Maximum number of decimal digits to be displayed in the tooltip. From dc531985770e5e00f5938d591005c90d5c056f88 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Tue, 23 Dec 2025 14:36:12 +0300 Subject: [PATCH 336/836] Make edits based on reviews --- osu.Game/Configuration/IntroSequence.cs | 2 +- osu.Game/Localisation/CommonStrings.cs | 5 ----- osu.Game/Localisation/IntroSequenceStrings.cs | 19 +++++++++++++++++++ 3 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Localisation/IntroSequenceStrings.cs diff --git a/osu.Game/Configuration/IntroSequence.cs b/osu.Game/Configuration/IntroSequence.cs index 70b8b0f8425d..31b58b0174b3 100644 --- a/osu.Game/Configuration/IntroSequence.cs +++ b/osu.Game/Configuration/IntroSequence.cs @@ -12,7 +12,7 @@ public enum IntroSequence Welcome, Triangles, - [LocalisableDescription(typeof(CommonStrings), nameof(CommonStrings.Random))] + [LocalisableDescription(typeof(IntroSequenceStrings), nameof(IntroSequenceStrings.Random))] Random } } diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 1e1f83acf346..d72257f43804 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -204,11 +204,6 @@ public static class CommonStrings /// public static LocalisableString DeleteWithConfirmation => new TranslatableString(getKey(@"delete_with_confrmation"), @"Delete..."); - /// - /// "Random" - /// - public static LocalisableString Random => new TranslatableString(getKey(@"random"), @"Random"); - private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/IntroSequenceStrings.cs b/osu.Game/Localisation/IntroSequenceStrings.cs new file mode 100644 index 000000000000..9a3da64a295e --- /dev/null +++ b/osu.Game/Localisation/IntroSequenceStrings.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class IntroSequenceStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.IntroSequence"; + + /// + /// "Random" + /// + public static LocalisableString Random => new TranslatableString(getKey(@"random"), @"Random"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} From 43e217120d349c03e5e50ef79d82a1f6221b90bd Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Tue, 23 Dec 2025 14:51:31 +0300 Subject: [PATCH 337/836] Fix offset not changing using current culture --- osu.Game/Localisation/RankingStatisticsStrings.cs | 8 ++++---- osu.Game/Screens/Ranking/Statistics/AverageHitError.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Localisation/RankingStatisticsStrings.cs b/osu.Game/Localisation/RankingStatisticsStrings.cs index 5d26390c7963..b69d96d1a1bb 100644 --- a/osu.Game/Localisation/RankingStatisticsStrings.cs +++ b/osu.Game/Localisation/RankingStatisticsStrings.cs @@ -20,14 +20,14 @@ public static class RankingStatisticsStrings public static LocalisableString UnstableRateTitle => new TranslatableString(getKey(@"unstable_rate_title"), @"Unstable Rate"); /// - /// "{0} ms early" + /// "{0:N2} ms early" /// - public static LocalisableString Early(string offset) => new TranslatableString(getKey(@"early"), @"{0} ms early", offset); + public static LocalisableString Early(double offset) => new TranslatableString(getKey(@"early"), @"{0:N2} ms early", offset); /// - /// "{0} ms late" + /// "{0:N2} ms late" /// - public static LocalisableString Late(string offset) => new TranslatableString(getKey(@"late"), @"{0} ms late", offset); + public static LocalisableString Late(double offset) => new TranslatableString(getKey(@"late"), @"{0:N2} ms late", offset); /// /// "(not available)" diff --git a/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs b/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs index 1d20479e18f9..08a67b8fdcde 100644 --- a/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs +++ b/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs @@ -30,8 +30,8 @@ protected override LocalisableString DisplayValue(double? value) LocalisableString getEarlyLateText(double offset) => offset < 0 - ? RankingStatisticsStrings.Early(Math.Abs(offset).ToString(@"N2")) - : RankingStatisticsStrings.Late(Math.Abs(offset).ToString(@"N2")); + ? RankingStatisticsStrings.Early(Math.Abs(offset)) + : RankingStatisticsStrings.Late(Math.Abs(offset)); } } } From 033a73e969c12058349c06fd3f6ab37b2eba8b55 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Tue, 23 Dec 2025 20:18:59 -0500 Subject: [PATCH 338/836] Update switch button visuals --- .../Graphics/UserInterfaceV2/FormCheckBox.cs | 9 +--- .../Graphics/UserInterfaceV2/SwitchButton.cs | 50 +++++++++---------- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs index 78feee871d19..f54cc7cc7c20 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs @@ -88,7 +88,7 @@ private void load(AudioManager audio) Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, }, - new FormSwitchButton + new SwitchButton { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, @@ -173,12 +173,5 @@ private void updateState() public void SetDefault() => Current.SetDefault(); public bool IsDisabled => Current.Disabled; - - private partial class FormSwitchButton : SwitchButton - { - // it doesn't make sense for this to show hover state or respond to input. - // FormCheckBox already handles all of that. - public override bool PropagatePositionalInputSubTree => false; - } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs index fe72775bb582..1c1dae0f315a 100644 --- a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs @@ -23,9 +23,9 @@ public partial class SwitchButton : Checkbox private const float padding = 1.25f; private readonly Box fill; - private readonly Container switchContainer; - private readonly Drawable switchCircle; - private readonly CircularContainer circularContainer; + private readonly Container nubContainer; + private readonly Drawable nub; + private readonly CircularContainer content; [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -37,7 +37,7 @@ public SwitchButton() { Size = new Vector2(45, 20); - InternalChild = circularContainer = new CircularContainer + InternalChild = content = new CircularContainer { RelativeSizeAxes = Axes.Both, BorderColour = Color4.White, @@ -55,15 +55,14 @@ public SwitchButton() { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(border_thickness + padding), - Child = switchContainer = new Container + Child = nubContainer = new Container { RelativeSizeAxes = Axes.Both, - Child = switchCircle = new CircularContainer + Child = nub = new Circle { RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, Masking = true, - Child = new Box { RelativeSizeAxes = Axes.Both } } } } @@ -90,7 +89,7 @@ protected override void LoadComplete() private void updateState() { - switchCircle.MoveToX(Current.Value ? switchContainer.DrawWidth - switchCircle.DrawWidth : 0, 200, Easing.OutQuint); + nub.MoveToX(Current.Value ? nubContainer.DrawWidth - nub.DrawWidth : 0, 200, Easing.OutQuint); fill.FadeTo(Current.Value ? 1 : 0, 250, Easing.OutQuint); updateColours(); @@ -120,32 +119,33 @@ protected override void OnUserChange(bool value) private void updateColours() { - ColourInfo targetSwitchColour; - ColourInfo targetBorderColour; + ColourInfo borderColour; + ColourInfo switchColour; if (Current.Disabled) { - if (Current.Value) - targetBorderColour = colourProvider.Dark1.Opacity(0.5f); - else - targetBorderColour = colourProvider.Background2.Opacity(0.5f); - - targetSwitchColour = colourProvider.Dark1.Opacity(0.5f); - fill.Colour = colourProvider.Background5; + borderColour = colourProvider.Dark2; + switchColour = colourProvider.Dark1; + fill.Colour = colourProvider.Dark5; } else { - if (Current.Value) - targetBorderColour = IsHovered ? colourProvider.Highlight1.Lighten(0.3f) : colourProvider.Highlight1; - else - targetBorderColour = IsHovered ? colourProvider.Background1 : colourProvider.Background2; + bool hover = IsHovered && !Current.Disabled; + + borderColour = hover ? colourProvider.Highlight1.Opacity(0.5f) : colourProvider.Highlight1.Opacity(0.3f); + switchColour = hover ? colourProvider.Highlight1 : colourProvider.Light4; + + if (!Current.Value) + { + borderColour = borderColour.MultiplyAlpha(0.8f); + switchColour = switchColour.MultiplyAlpha(0.8f); + } - targetSwitchColour = colourProvider.Highlight1; - fill.Colour = colourProvider.Background4; + fill.Colour = colourProvider.Background6; } - switchContainer.FadeColour(targetSwitchColour, 250, Easing.OutQuint); - circularContainer.TransformTo(nameof(BorderColour), targetBorderColour, 250, Easing.OutQuint); + nubContainer.FadeColour(switchColour, 250, Easing.OutQuint); + content.TransformTo(nameof(BorderColour), borderColour, 250, Easing.OutQuint); } } } From 03f44705b3b42309ea1011d1f88992d78072cec7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Dec 2025 14:57:17 +0900 Subject: [PATCH 339/836] Adjust naming --- osu.Game/Screens/Edit/Components/FormSampleSet.cs | 9 +++++---- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/FormSampleSet.cs b/osu.Game/Screens/Edit/Components/FormSampleSet.cs index 268795591107..50c0532c022e 100644 --- a/osu.Game/Screens/Edit/Components/FormSampleSet.cs +++ b/osu.Game/Screens/Edit/Components/FormSampleSet.cs @@ -46,7 +46,7 @@ public Bindable Current public Action? SampleRemoveRequested { get; init; } private readonly BindableWithCurrent current = new BindableWithCurrent(); - private readonly Dictionary<(string sound, string bank), SampleButton> buttons = new Dictionary<(string, string), SampleButton>(); + private readonly Dictionary<(string name, string bank), SampleButton> buttons = new Dictionary<(string, string), SampleButton>(); private Box background = null!; private FormFieldCaption caption = null!; @@ -145,10 +145,10 @@ private void setChanged(ValueChangedEvent valueCha if (set != null) { - foreach (var (sound, button) in buttons) + foreach (var (sample, button) in buttons) { - button.ExpectedFilename.Value = $@"{sound.bank}-{sound.sound}{(set.SampleSetIndex > 1 ? set.SampleSetIndex : null)}"; - button.ActualFilename.Value = set.FindSound(sound.sound, sound.bank); + button.ExpectedFilename.Value = $@"{sample.bank}-{sample.name}{(set.SampleSetIndex > 1 ? set.SampleSetIndex : null)}"; + button.ActualFilename.Value = set.FindSampleIfExists(sample.name, sample.bank); } } } @@ -217,6 +217,7 @@ public partial class SampleButton : OsuButton, IHasPopover, IHasContextMenu private EditorBeatmap? editorBeatmap { get; set; } private HoverSounds? hoverSounds; + private ISample? sample; public SampleButton() diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 3c50adc47170..531f77d238aa 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -74,8 +74,8 @@ public SampleSet(int sampleSetIndex) public HashSet Filenames = []; - public string? FindSound(string soundName, string bankName) - => Filenames.SingleOrDefault(f => f.StartsWith($@"{bankName}-{soundName}{(SampleSetIndex > 1 ? SampleSetIndex : null)}", StringComparison.Ordinal)); + public string? FindSampleIfExists(string sampleName, string bankName) + => Filenames.SingleOrDefault(f => f.StartsWith($@"{bankName}-{sampleName}{(SampleSetIndex > 1 ? SampleSetIndex : null)}", StringComparison.Ordinal)); public virtual bool Equals(SampleSet? other) => SampleSetIndex == other?.SampleSetIndex; public override int GetHashCode() => SampleSetIndex; From 0af07b97c5b864c743257ec42f3943e2171a337b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 24 Dec 2025 14:51:42 +0900 Subject: [PATCH 340/836] Fix potentially incorrect online play beatmap availability --- .../OnlinePlay/OnlinePlayBeatmapAvailabilityTracker.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayBeatmapAvailabilityTracker.cs index ae0b4a9943af..d4d161a3d079 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayBeatmapAvailabilityTracker.cs @@ -153,8 +153,13 @@ void updateAvailability() } } - IQueryable queryBeatmap() => - realm.Realm.All().Filter("OnlineID == $0 && MD5Hash == $1 && BeatmapSet.DeletePending == false", beatmap.OnlineID, beatmap.MD5Hash); + IQueryable queryBeatmap() + { + // See: BeatmapManager.QueryBeatmap() + return realm.Realm.All() + .Filter($@"{nameof(BeatmapInfo.BeatmapSet)}.{nameof(BeatmapSetInfo.DeletePending)} == false") + .Filter($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", beatmap.OnlineID); + } } protected override void Dispose(bool isDisposing) From 2d85fe8133802e97d4353aed90bec6b5e177847d Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 24 Dec 2025 02:22:51 -0500 Subject: [PATCH 341/836] Fix tournament screens not having colour provider cached --- osu.Game.Tournament/Screens/Setup/SetupScreen.cs | 3 +-- osu.Game.Tournament/Screens/TournamentScreen.cs | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs index bd368d88a05f..6bed3c87dfb7 100644 --- a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; @@ -56,7 +55,7 @@ private void load(FrameworkConfigManager frameworkConfig) new Box { RelativeSizeAxes = Axes.Both, - Colour = OsuColour.Gray(0.2f), + Colour = ColourProvider.Background5, }, new OsuScrollContainer { diff --git a/osu.Game.Tournament/Screens/TournamentScreen.cs b/osu.Game.Tournament/Screens/TournamentScreen.cs index 1e119e03365e..137153b91df8 100644 --- a/osu.Game.Tournament/Screens/TournamentScreen.cs +++ b/osu.Game.Tournament/Screens/TournamentScreen.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Overlays; using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Screens @@ -15,6 +16,9 @@ public abstract partial class TournamentScreen : CompositeDrawable [Resolved] protected LadderInfo LadderInfo { get; private set; } = null!; + [Cached] + protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + protected TournamentScreen() { RelativeSizeAxes = Axes.Both; From ecaf3e05d492ee0a6f6198445ed2cbe1e47895ab Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 24 Dec 2025 16:39:26 +0900 Subject: [PATCH 342/836] Fix tests --- .../TestSceneMultiplayerBeatmapAvailabilityTracker.cs | 8 +++++++- .../TestScenePlaylistsBeatmapAvailabilityTracker.cs | 9 +++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Online/TestSceneMultiplayerBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneMultiplayerBeatmapAvailabilityTracker.cs index 41ffd9c9a90f..ed1a7bd48306 100644 --- a/osu.Game.Tests/Online/TestSceneMultiplayerBeatmapAvailabilityTracker.cs +++ b/osu.Game.Tests/Online/TestSceneMultiplayerBeatmapAvailabilityTracker.cs @@ -44,7 +44,13 @@ private void load(GameHost host) availableBeatmap = importedSet.Beatmaps[0]; unavailableBeatmap = importedSet.Beatmaps[1]; - Realm.Write(r => r.Remove(r.Find(unavailableBeatmap.ID)!)); + Realm.Write(r => + { + BeatmapInfo available = r.Find(availableBeatmap.ID)!; + available.OnlineMD5Hash = available.MD5Hash; + + r.Remove(r.Find(unavailableBeatmap.ID)!); + }); } public override void SetUpSteps() diff --git a/osu.Game.Tests/Online/TestScenePlaylistsBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestScenePlaylistsBeatmapAvailabilityTracker.cs index 220c23b5bcc9..1887d0f38115 100644 --- a/osu.Game.Tests/Online/TestScenePlaylistsBeatmapAvailabilityTracker.cs +++ b/osu.Game.Tests/Online/TestScenePlaylistsBeatmapAvailabilityTracker.cs @@ -27,6 +27,7 @@ using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual; +using Realms; namespace osu.Game.Tests.Online { @@ -229,6 +230,14 @@ public TestBeatmapImporter(TestBeatmapManager testBeatmapManager, Storage storag return testBeatmapManager.CurrentImport = base.ImportModel(item, archive, parameters, cancellationToken); } + + protected override void PostImport(BeatmapSetInfo model, Realm realm, ImportParameters parameters) + { + foreach (var beatmap in model.Beatmaps) + beatmap.OnlineMD5Hash = beatmap.MD5Hash; + + base.PostImport(model, realm, parameters); + } } } From 81f03957d8ae928dba906e1b1f368dc40f1cde20 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 24 Dec 2025 19:30:02 +0900 Subject: [PATCH 343/836] Reduce code duplication Co-authored-by: Dean Herbert --- osu.Game/Beatmaps/BeatmapManager.cs | 8 ++++++++ osu.Game/Database/RealmExtensions.cs | 10 ++++++++++ .../OnlinePlay/DailyChallenge/DailyChallenge.cs | 2 +- .../OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs | 2 +- .../Multiplayer/MultiplayerMatchSubScreen.cs | 4 ++-- .../OnlinePlayBeatmapAvailabilityTracker.cs | 11 +++-------- .../OnlinePlay/Playlists/PlaylistItemResultsScreen.cs | 3 +-- .../OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs | 2 +- 8 files changed, 27 insertions(+), 15 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 62c03b4fcdc4..d50862a36970 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -328,6 +328,14 @@ public List GetAllUsableBeatmapSets() .Filter(query, arguments) .FirstOrDefault()?.Detach()); + /// + /// Perform a lookup query on available s for a specific online ID. + /// + /// A matching local beatmap info if existing and in a valid state. + public BeatmapInfo? QueryOnlineBeatmapId(int id) => Realm.Run(r => + r.All() + .ForOnlineId(id).SingleOrDefault()?.Detach()); + /// /// A default representation of a WorkingBeatmap to use when no beatmap is available. /// diff --git a/osu.Game/Database/RealmExtensions.cs b/osu.Game/Database/RealmExtensions.cs index 1bb6b0aba4a2..65ae42a3da22 100644 --- a/osu.Game/Database/RealmExtensions.cs +++ b/osu.Game/Database/RealmExtensions.cs @@ -2,7 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using osu.Framework.Logging; +using osu.Game.Beatmaps; using Realms; namespace osu.Game.Database @@ -102,5 +104,13 @@ public static T Write(this Realm realm, Func function) /// Quite often we only care about changes at a collection level. This can be used to guard and early-return when no such changes are in a callback. /// public static bool HasCollectionChanges(this ChangeSet changes) => changes.InsertedIndices.Length > 0 || changes.DeletedIndices.Length > 0 || changes.Moves.Length > 0; + + public static IQueryable NotDeleted(this IQueryable beatmaps) => + beatmaps.Filter($@"{nameof(BeatmapInfo.BeatmapSet)}.{nameof(BeatmapSetInfo.DeletePending)} == false"); + + public static IQueryable ForOnlineId(this IQueryable beatmaps, int id) => + beatmaps + .NotDeleted() + .Filter($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", id); } } diff --git a/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallenge.cs b/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallenge.cs index c3648a7edfa1..6db293ec7167 100644 --- a/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallenge.cs +++ b/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallenge.cs @@ -489,7 +489,7 @@ public static void TrySetDailyChallengeBeatmap(OsuScreen screen, BeatmapManager if (!screen.IsCurrentScreen()) return; - var beatmap = beatmaps.QueryBeatmap($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", item.Beatmap.OnlineID); + var beatmap = beatmaps.QueryOnlineBeatmapId(item.Beatmap.OnlineID); screen.Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); // this will gracefully fall back to dummy beatmap if missing locally. screen.Ruleset.Value = rulesets.GetRuleset(item.RulesetID); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs index a689ac85eece..d692783e487e 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs @@ -246,7 +246,7 @@ private void updateGameplayState() // Update global gameplay state to correspond to the new selection. // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info - var localBeatmap = beatmapManager.QueryBeatmap($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", item.BeatmapID); + var localBeatmap = beatmapManager.QueryOnlineBeatmapId(item.BeatmapID); if (localBeatmap != null) { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 16c6a46a9c98..05fd5b8c6961 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -510,7 +510,7 @@ private void onActivePlaylistItemChanged() { MultiplayerPlaylistItem item = client.Room.CurrentPlaylistItem; - var newBeatmap = beatmapManager.QueryBeatmap($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", item.BeatmapID); + var newBeatmap = beatmapManager.QueryOnlineBeatmapId(item.BeatmapID); if (!Beatmap.Value.BeatmapSetInfo.Equals(newBeatmap?.BeatmapSet)) this.MakeCurrent(); @@ -652,7 +652,7 @@ private void updateGameplayState() // Update global gameplay state to correspond to the new selection. // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info - var localBeatmap = beatmapManager.QueryBeatmap($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", gameplayBeatmapId); + var localBeatmap = beatmapManager.QueryOnlineBeatmapId(gameplayBeatmapId); Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); Ruleset.Value = ruleset; Mods.Value = client.LocalUser.Mods.Concat(item.RequiredMods).Select(m => m.ToMod(rulesetInstance)).ToArray(); diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayBeatmapAvailabilityTracker.cs index d4d161a3d079..1bb67cc3afc5 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayBeatmapAvailabilityTracker.cs @@ -17,7 +17,6 @@ using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; -using Realms; namespace osu.Game.Screens.OnlinePlay { @@ -153,13 +152,9 @@ void updateAvailability() } } - IQueryable queryBeatmap() - { - // See: BeatmapManager.QueryBeatmap() - return realm.Realm.All() - .Filter($@"{nameof(BeatmapInfo.BeatmapSet)}.{nameof(BeatmapSetInfo.DeletePending)} == false") - .Filter($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", beatmap.OnlineID); - } + IQueryable queryBeatmap() => + realm.Realm.All() + .ForOnlineId(beatmap.OnlineID); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistItemResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistItemResultsScreen.cs index e99429960680..df5a9db8e75b 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistItemResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistItemResultsScreen.cs @@ -62,8 +62,7 @@ protected PlaylistItemResultsScreen(ScoreInfo? score, long roomId, PlaylistItem [BackgroundDependencyLoader] private void load() { - var localBeatmap = beatmapManager.QueryBeatmap($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", - PlaylistItem.Beatmap.OnlineID); + var localBeatmap = beatmapManager.QueryOnlineBeatmapId(PlaylistItem.Beatmap.OnlineID); itemBeatmap = beatmapManager.GetWorkingBeatmap(localBeatmap); AddInternal(new Container diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index fdda6f6c8551..58e260c85769 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -609,7 +609,7 @@ private void updateGameplayState() // Update global gameplay state to correspond to the new selection. // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info - var localBeatmap = beatmapManager.QueryBeatmap($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", gameplayBeatmap.OnlineID); + var localBeatmap = beatmapManager.QueryOnlineBeatmapId(gameplayBeatmap.OnlineID); Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); Ruleset.Value = gameplayRuleset; Mods.Value = UserMods.Value.Concat(item.RequiredMods.Select(m => m.ToMod(rulesetInstance))).ToArray(); From 206578bf10708672f3607df41a150d37c605b355 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Dec 2025 21:39:17 +0900 Subject: [PATCH 344/836] Always flash button when adding a new item to playlist --- .../Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index b1adcadbc0c8..586898f41493 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -149,7 +149,10 @@ private void updateValidMods() freeModSelect.IsValidMod = isValidAllowedMod; } - protected override void OnStart() => AddNewItem(); + protected override void OnStart() + { + addToPlaylistFooterButton.TriggerClick(); + } public override void OnEntering(ScreenTransitionEvent e) { From 56ef5eae1409622518fbc19872d5e3477abe90a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Dec 2025 22:36:16 +0900 Subject: [PATCH 345/836] Revert "Merge pull request #36102 from bdach/move-check-to-better-place" This reverts commit 2cb2167765a2c5514841657a63845d2c4d078649, reversing changes made to 0bcb3c5839ac300c689e4edf6582a94dbf8cb748. --- .../Database/BeatmapImporterTests.cs | 14 +---- osu.Game/Beatmaps/BeatmapImporter.cs | 54 ++++++++++--------- 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index bdba1c368fd8..f3ca66538015 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -778,19 +778,7 @@ public void TestImportThenReimportWithNewDifficulty() { RunTestWithRealmAsync(async (realm, storage) => { - var importer = new BeatmapImporter(storage, realm) - { - ProcessBeatmap = (set, _) => - { - set.OnlineID = 1234; - // note: this is only intended to be a quick-and-easy approximation of proper operation - // the more proper way to do this would be to assign IDs based on content hash or something, but it largely doesn't matter here - // so long as the beatmaps in the set get assigned an ID by the process flow - for (int i = 0; i < set.Beatmaps.Count; ++i) - set.Beatmaps[i].OnlineID = 5678 + i; - } - }; - + var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); string? pathOriginal = TestResources.GetTestBeatmapForImport(); diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs index d8508ce6de8c..f80c4de4ea6e 100644 --- a/osu.Game/Beatmaps/BeatmapImporter.cs +++ b/osu.Game/Beatmaps/BeatmapImporter.cs @@ -182,43 +182,35 @@ protected override void Populate(BeatmapSetInfo beatmapSet, ArchiveReader? archi } validateOnlineIds(beatmapSet, realm); - } - - protected override void PostImport(BeatmapSetInfo model, Realm realm, ImportParameters parameters) - { - base.PostImport(model, realm, parameters); - - // Scores are stored separately from beatmaps, and persist even when a beatmap is modified or deleted. - // Let's reattach any matching scores that exist in the database, based on hash. - foreach (BeatmapInfo beatmap in model.Beatmaps) - { - beatmap.UpdateLocalScores(realm); - } - ProcessBeatmap?.Invoke(model, parameters.Batch ? MetadataLookupScope.LocalCacheFirst : MetadataLookupScope.OnlineFirst); - - bool hadOnlineIDs = model.OnlineID > 0 || model.Beatmaps.Any(b => b.OnlineID > 0); + bool hadOnlineIDs = beatmapSet.Beatmaps.Any(b => b.OnlineID > 0); + // TODO: this may no longer be valid as we aren't doing an online population at this point. // ensure at least one beatmap was able to retrieve or keep an online ID, else drop the set ID. - if (hadOnlineIDs && !model.Beatmaps.Any(b => b.OnlineID > 0)) + if (hadOnlineIDs && !beatmapSet.Beatmaps.Any(b => b.OnlineID > 0)) { - model.OnlineID = -1; - LogForModel(model, "Disassociating beatmap set ID due to loss of all beatmap IDs"); + if (beatmapSet.OnlineID > 0) + { + beatmapSet.OnlineID = -1; + LogForModel(beatmapSet, "Disassociating beatmap set ID due to loss of all beatmap IDs"); + } } + } - // Before concluding the import, ensure that no other set shares the online IDs used by the new one. + protected override void PreImport(BeatmapSetInfo beatmapSet, Realm realm) + { + // We are about to import a new beatmap. Before doing so, ensure that no other set shares the online IDs used by the new one. // Note that this means if the previous beatmap is restored by the user, it will no longer be linked to its online IDs. // If this is ever an issue, we can consider marking as pending delete but not resetting the IDs (but care will be required for // beatmaps, which don't have their own `DeletePending` state). - if (model.OnlineID > 0) + if (beatmapSet.OnlineID > 0) { // Required local for iOS. Will cause runtime crash if inlined. - int onlineId = model.OnlineID; - Guid guid = model.ID; + int onlineId = beatmapSet.OnlineID; // OnlineID should really be unique, but to avoid catastrophic failure let's iterate just to be sure. - foreach (var existingSetWithSameOnlineID in realm.All().Where(b => b.OnlineID == onlineId && b.ID != guid)) + foreach (var existingSetWithSameOnlineID in realm.All().Where(b => b.OnlineID == onlineId)) { existingSetWithSameOnlineID.DeletePending = true; existingSetWithSameOnlineID.OnlineID = -1; @@ -226,11 +218,25 @@ protected override void PostImport(BeatmapSetInfo model, Realm realm, ImportPara foreach (var b in existingSetWithSameOnlineID.Beatmaps) b.ResetOnlineInfo(); - LogForModel(model, $"Found existing beatmap set with same OnlineID ({model.OnlineID}). It will be disassociated and marked for deletion."); + LogForModel(beatmapSet, $"Found existing beatmap set with same OnlineID ({beatmapSet.OnlineID}). It will be disassociated and marked for deletion."); } } } + protected override void PostImport(BeatmapSetInfo model, Realm realm, ImportParameters parameters) + { + base.PostImport(model, realm, parameters); + + // Scores are stored separately from beatmaps, and persist even when a beatmap is modified or deleted. + // Let's reattach any matching scores that exist in the database, based on hash. + foreach (BeatmapInfo beatmap in model.Beatmaps) + { + beatmap.UpdateLocalScores(realm); + } + + ProcessBeatmap?.Invoke(model, parameters.Batch ? MetadataLookupScope.LocalCacheFirst : MetadataLookupScope.OnlineFirst); + } + private void validateOnlineIds(BeatmapSetInfo beatmapSet, Realm realm) { var beatmapIds = beatmapSet.Beatmaps.Where(b => b.OnlineID > 0).Select(b => b.OnlineID).ToList(); From 99b00ab72f7ef35890c2f6726120d171bfcfc616 Mon Sep 17 00:00:00 2001 From: Nathan van der Kamp Date: Fri, 26 Dec 2025 00:52:07 +0100 Subject: [PATCH 346/836] Add keywords to FPS related settings --- .../Overlays/Settings/Sections/Graphics/RendererSettings.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs index a8b127d5229a..69697bd9a301 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs @@ -44,7 +44,7 @@ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, IDi { LabelText = GraphicsSettingsStrings.FrameLimiter, Current = config.GetBindable(FrameworkSetting.FrameSync), - Keywords = new[] { @"fps" }, + Keywords = new[] { @"fps", @"framerate" }, }, new SettingsEnumDropdown { @@ -54,7 +54,8 @@ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, IDi new SettingsCheckbox { LabelText = GraphicsSettingsStrings.ShowFPS, - Current = osuConfig.GetBindable(OsuSetting.ShowFpsDisplay) + Current = osuConfig.GetBindable(OsuSetting.ShowFpsDisplay), + Keywords = new[] { @"framerate", @"counter" }, }, }; From a07d7ad4cbfb73a8a823790aae18ce90a6e2428f Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Sun, 28 Dec 2025 18:56:55 +0500 Subject: [PATCH 347/836] Extend `Skill` to include `ObjectDifficulties` (#36152) * Extend `Skill` to include `ObjectDifficulties` * Remove generic * Change `ObjectDifficulties` to be modifiable by children skills * Fix tests --- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 6 +++--- .../Difficulty/TaikoDifficultyCalculator.cs | 10 +++++----- .../TestSceneTimedDifficultyCalculation.cs | 3 ++- osu.Game/Rulesets/Difficulty/Skills/Skill.cs | 15 ++++++++++++++- .../Rulesets/Difficulty/Skills/StrainSkill.cs | 14 +++++--------- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 105d3956ac6b..33dc23b7d8cf 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -54,14 +54,14 @@ protected override double StrainValueAt(DifficultyHitObject current) public double RelevantNoteCount() { - if (ObjectStrains.Count == 0) + if (ObjectDifficulties.Count == 0) return 0; - double maxStrain = ObjectStrains.Max(); + double maxStrain = ObjectDifficulties.Max(); if (maxStrain == 0) return 0; - return ObjectStrains.Sum(strain => 1.0 / (1.0 + Math.Exp(-(strain / maxStrain * 12.0 - 6.0)))); + return ObjectDifficulties.Sum(strain => 1.0 / (1.0 + Math.Exp(-(strain / maxStrain * 12.0 - 6.0)))); } public double CountTopWeightedSliders(double difficultyValue) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 4905dd327594..42a5dad31520 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -186,10 +186,10 @@ private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour co } List hitObjectStrainPeaks = combinePeaks( - rhythm.GetObjectStrains().ToList(), - reading.GetObjectStrains().ToList(), - colour.GetObjectStrains().ToList(), - stamina.GetObjectStrains().ToList() + rhythm.GetObjectDifficulties(), + reading.GetObjectDifficulties(), + colour.GetObjectDifficulties(), + stamina.GetObjectDifficulties() ); if (hitObjectStrainPeaks.Count == 0) @@ -211,7 +211,7 @@ private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour co /// /// Combines lists of peak strains from multiple skills into a list of single peak strains for each section. /// - private List combinePeaks(List rhythmPeaks, List readingPeaks, List colourPeaks, List staminaPeaks) + private List combinePeaks(IReadOnlyList rhythmPeaks, IReadOnlyList readingPeaks, IReadOnlyList colourPeaks, IReadOnlyList staminaPeaks) { var combinedPeaks = new List(); diff --git a/osu.Game.Tests/NonVisual/TestSceneTimedDifficultyCalculation.cs b/osu.Game.Tests/NonVisual/TestSceneTimedDifficultyCalculation.cs index f860cd097a72..daf0bec44c0c 100644 --- a/osu.Game.Tests/NonVisual/TestSceneTimedDifficultyCalculation.cs +++ b/osu.Game.Tests/NonVisual/TestSceneTimedDifficultyCalculation.cs @@ -200,8 +200,9 @@ public PassThroughSkill(Mod[] mods) { } - public override void Process(DifficultyHitObject current) + protected override double ProcessInternal(DifficultyHitObject current) { + return 0; } public override double DifficultyValue() => 1; diff --git a/osu.Game/Rulesets/Difficulty/Skills/Skill.cs b/osu.Game/Rulesets/Difficulty/Skills/Skill.cs index 8b8892113b8a..cf45104c942c 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/Skill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/Skill.cs @@ -20,6 +20,11 @@ public abstract class Skill /// protected IReadOnlyList Mods => mods; + /// + /// List of calculated per-object difficulties, populated by Process + /// + protected readonly List ObjectDifficulties = new List(); + private readonly Mod[] mods; protected Skill(Mod[] mods) @@ -31,11 +36,19 @@ protected Skill(Mod[] mods) /// Process a . /// /// The to process. - public abstract void Process(DifficultyHitObject current); + public void Process(DifficultyHitObject current) + { + double difficultyValue = ProcessInternal(current); + ObjectDifficulties.Add(difficultyValue); + } + + protected abstract double ProcessInternal(DifficultyHitObject current); /// /// Returns the calculated difficulty value representing all s that have been processed up to this point. /// public abstract double DifficultyValue(); + + public IReadOnlyList GetObjectDifficulties() => ObjectDifficulties; } } diff --git a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs index 1fccf32242b2..f066be0ec750 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs @@ -29,7 +29,6 @@ public abstract class StrainSkill : Skill private double currentSectionEnd; private readonly List strainPeaks = new List(); - protected readonly List ObjectStrains = new List(); // Store individual strains protected StrainSkill(Mod[] mods) : base(mods) @@ -44,7 +43,7 @@ protected StrainSkill(Mod[] mods) /// /// Process a and update current strain values accordingly. /// - public sealed override void Process(DifficultyHitObject current) + protected sealed override double ProcessInternal(DifficultyHitObject current) { // The first object doesn't generate a strain, so we begin with an incremented section end if (current.Index == 0) @@ -60,8 +59,7 @@ public sealed override void Process(DifficultyHitObject current) double strain = StrainValueAt(current); currentSectionPeak = Math.Max(strain, currentSectionPeak); - // Store the strain value for the object - ObjectStrains.Add(strain); + return strain; } /// @@ -70,16 +68,16 @@ public sealed override void Process(DifficultyHitObject current) /// public virtual double CountTopWeightedStrains(double difficultyValue) { - if (ObjectStrains.Count == 0) + if (ObjectDifficulties.Count == 0) return 0.0; double consistentTopStrain = difficultyValue * (1 - DecayWeight); // What would the top strain be if all strain values were identical if (consistentTopStrain == 0) - return ObjectStrains.Count; + return ObjectDifficulties.Count; // Use a weighted sum of all strains. Constants are arbitrary and give nice values - return ObjectStrains.Sum(s => 1.1 / (1 + Math.Exp(-10 * (s / consistentTopStrain - 0.88)))); + return ObjectDifficulties.Sum(s => 1.1 / (1 + Math.Exp(-10 * (s / consistentTopStrain - 0.88)))); } /// @@ -116,8 +114,6 @@ private void startNewSectionFrom(double time, DifficultyHitObject current) /// public IEnumerable GetCurrentStrainPeaks() => strainPeaks.Append(currentSectionPeak); - public IEnumerable GetObjectStrains() => ObjectStrains; - /// /// Returns the calculated difficulty value representing all s that have been processed up to this point. /// From c6441723b316f1f03b091f8aa4103204a2321e11 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Sun, 28 Dec 2025 17:42:26 +0000 Subject: [PATCH 348/836] Add `HarmonicSkill` (#36153) * Add `OsuHarmonicSkill` * Make `ProcessInternal` a sealed override * Move to main game project --- .../Difficulty/Skills/HarmonicSkill.cs | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 osu.Game/Rulesets/Difficulty/Skills/HarmonicSkill.cs diff --git a/osu.Game/Rulesets/Difficulty/Skills/HarmonicSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/HarmonicSkill.cs new file mode 100644 index 000000000000..b89b53d8cbac --- /dev/null +++ b/osu.Game/Rulesets/Difficulty/Skills/HarmonicSkill.cs @@ -0,0 +1,102 @@ +// 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.Linq; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Utils; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Difficulty.Skills +{ + public abstract class HarmonicSkill : Skill + { + /// + /// The sum of note weights, calculated during summation. + /// Required for any calculations which need to normalise difficulty value. + /// + protected double NoteWeightSum; + + /// + /// Scaling factor applied as HarmonicScale / (1 + index) during weight calculations. + /// A higher value will increase the influence of the hardest object difficulties during summation. + /// + protected virtual double HarmonicScale => 1.0; + + /// + /// Exponent that controls the rate of which decay increases as the index increases. + /// Values closer to 1 decay faster whilst lower values give more weight to lower object difficulties. + /// + protected virtual double DecayExponent => 0.9; + + protected HarmonicSkill(Mod[] mods) + : base(mods) + { + } + + /// + /// Returns the difficulty value of the current . This value is calculated with or without respect to previous objects. + /// + protected abstract double ObjectDifficultyOf(DifficultyHitObject current); + + protected sealed override double ProcessInternal(DifficultyHitObject current) + => ObjectDifficultyOf(current); + + /// + /// Transforms the object difficulties specifically for final difficulty summation. + /// This can be used to decrease weight of certain notes based on a skill-specific criteria. + /// + protected virtual void ApplyDifficultyTransformation(double[] difficulties) + { + } + + public override double DifficultyValue() + { + if (ObjectDifficulties.Count == 0) + return 0; + + // Notes with 0 difficulty are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871). + // These notes will not contribute to the difficulty. + double[] difficulties = ObjectDifficulties.Where(p => p > 0).ToArray(); + + ApplyDifficultyTransformation(difficulties); + + double difficulty = 0; + int index = 0; + + foreach (double note in difficulties.OrderDescending()) + { + // Use a harmonic sum that considers each note of the map according to a predefined weight. + double weight = (1 + (HarmonicScale / (1 + index))) / (Math.Pow(index, DecayExponent) + 1 + (HarmonicScale / (1 + index))); + + NoteWeightSum += weight; + + difficulty += note * weight; + index += 1; + } + + return difficulty; + } + + /// + /// Calculates the number of object difficulties weighted against the top object difficulty. + /// + public virtual double CountTopWeightedObjectDifficulties(double difficultyValue) + { + if (ObjectDifficulties.Count == 0) + return 0.0; + + if (NoteWeightSum == 0) + return 0.0; + + double consistentTopNote = difficultyValue / NoteWeightSum; // What would the top difficulty be if all object difficulties were identical + + if (consistentTopNote == 0) + return 0; + + return ObjectDifficulties.Sum(d => DifficultyCalculationUtils.Logistic(d / consistentTopNote, 0.88, 10, 1.1)); + } + + public static double DifficultyToPerformance(double difficulty) => 4.0 * Math.Pow(difficulty, 3.0); + } +} From b3ba5b9d8644b5141b2ffb0488d0ce46c46bd381 Mon Sep 17 00:00:00 2001 From: Natelytle Date: Sun, 28 Dec 2025 18:30:20 -0500 Subject: [PATCH 349/836] Implement fc time on top of pp-dev --- .../Difficulty/Aggregation/OsuFcTimeSkill.cs | 223 +++++++++++++++ .../{Skills => Aggregation}/OsuStrainSkill.cs | 2 +- .../Difficulty/OsuDifficultyAttributes.cs | 7 +- .../Difficulty/OsuDifficultyCalculator.cs | 4 +- .../Difficulty/OsuPerformanceCalculator.cs | 25 +- .../Difficulty/Skills/Aim.cs | 16 +- .../Difficulty/Skills/Speed.cs | 1 + osu.Game.Rulesets.Osu/Difficulty/Utils/Bin.cs | 75 ++++++ .../Difficulty/Utils/PoissonBinomial.cs | 160 +++++++++++ .../Difficulty/Utils/Polynomial.cs | 90 +++++++ .../Difficulty/Utils/RootFinding.cs | 119 ++++++++ .../Utils/DifficultyCalculationUtils.cs | 43 +++ ...icultyCalculationUtils_PolynomialSolver.cs | 253 ++++++++++++++++++ 13 files changed, 998 insertions(+), 20 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuFcTimeSkill.cs rename osu.Game.Rulesets.Osu/Difficulty/{Skills => Aggregation}/OsuStrainSkill.cs (97%) create mode 100644 osu.Game.Rulesets.Osu/Difficulty/Utils/Bin.cs create mode 100644 osu.Game.Rulesets.Osu/Difficulty/Utils/PoissonBinomial.cs create mode 100644 osu.Game.Rulesets.Osu/Difficulty/Utils/Polynomial.cs create mode 100644 osu.Game.Rulesets.Osu/Difficulty/Utils/RootFinding.cs create mode 100644 osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils_PolynomialSolver.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuFcTimeSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuFcTimeSkill.cs new file mode 100644 index 000000000000..d43bef7fd484 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuFcTimeSkill.cs @@ -0,0 +1,223 @@ +// 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.Collections.Generic; +using System.Linq; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Skills; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Difficulty.Utils; + +namespace osu.Game.Rulesets.Osu.Difficulty.Aggregation +{ + public abstract class OsuFcTimeSkill : Skill + { + protected OsuFcTimeSkill(Mod[] mods) + : base(mods) + { + } + + private const double ms_to_minutes = 1.0 / 60000.0; + + // FC time specific constants + private const double time_threshold_minutes = 24; + private const double max_delta_time = 5000; + + // Bin specific constants + private const double bin_threshold_note_count = 64; + private const int difficulty_bin_count = 8; + private const int time_bin_count = 16; + + private const double epsilon = 1e-4; + + private readonly List difficulties = new List(); + private readonly List times = new List(); + + /// + /// Returns the strain value at . This value is calculated with or without respect to previous objects. + /// + protected abstract double StrainValueAt(DifficultyHitObject current); + + public override void Process(DifficultyHitObject current) + { + difficulties.Add(StrainValueAt(current)); + + times.Add(times.LastOrDefault() + Math.Min(current.DeltaTime, max_delta_time)); + } + + protected abstract double HitProbability(double skill, double difficulty); + + public override double DifficultyValue() + { + if (difficulties.Count == 0 || difficulties.Max() <= epsilon) + return 0; + + // We only initialize bins if we have enough notes to use them. + List? binList = null; + + if (difficulties.Count > bin_threshold_note_count) + { + binList = Bin.CreateBins(difficulties, times, difficulty_bin_count, time_bin_count); + } + + // Lower bound and upper bound are generally unimportant + return RootFinding.FindRootExpand(skill => timeSpentRetryingAtSkill(skill, binList) - time_threshold_minutes, 0, 10); + } + + private double timeSpentRetryingAtSkill(double skill, List? binList = null) + { + if (skill <= 0) return double.PositiveInfinity; + + double timeSpentRetrying = 0; + double hitProbabilityProduct = 1; + + // We use bins, falling back to exact difficulty calculation if not available. + if (binList is not null) + { + for (int timeIndex = time_bin_count - 1; timeIndex >= 0; timeIndex--) + { + double deltaTime = times.LastOrDefault() / time_bin_count; + + for (int difficultyIndex = 0; difficultyIndex < difficulty_bin_count; difficultyIndex++) + { + Bin bin = binList[difficulty_bin_count * timeIndex + difficultyIndex]; + + hitProbabilityProduct *= Math.Pow(HitProbability(skill, bin.Difficulty), bin.NoteCount); + } + + timeSpentRetrying += deltaTime / hitProbabilityProduct - deltaTime; + } + } + else + { + for (int n = difficulties.Count - 1; n >= 0; n--) + { + double deltaTime = n > 0 ? times[n] - times[n - 1] : times[n]; + + hitProbabilityProduct *= HitProbability(skill, difficulties[n]); + timeSpentRetrying += deltaTime / hitProbabilityProduct - deltaTime; + } + } + + return timeSpentRetrying * ms_to_minutes; + } + + /// + /// The coefficients of a quartic fitted to the miss counts at each skill level. + /// + /// The coefficients for ax^4+bx^3+cx^2. The 4th coefficient for dx^1 can be deduced from the first 3 in the performance calculator. + public Polynomial GetMissPenaltyCurve() + { + Dictionary missCounts = new Dictionary(); + + Polynomial missPenaltyCurve = new Polynomial(); + + // If there are no notes, we just return the polynomial with all coefficients 0. + if (difficulties.Count == 0 || difficulties.Max() == 0) + return missPenaltyCurve; + + double fcSkill = DifficultyValue(); + + var bins = Bin.CreateBins(difficulties, times, difficulty_bin_count, time_bin_count); + + foreach (double skillProportion in Polynomial.SKILL_PROPORTIONS) + { + if (skillProportion == 0) + { + missCounts[skillProportion] = 0; + continue; + } + + double penalizedSkill = fcSkill * skillProportion; + + // We take the log to squash miss counts, which have large absolute value differences, but low relative differences, into a straighter line for the polynomial. + missCounts[skillProportion] = Math.Log(getMissCountAtSkill(penalizedSkill, bins) + 1); + } + + missPenaltyCurve.Fit(missCounts); + + return missPenaltyCurve; + } + + /// + /// Find the lowest misscount that a player with the provided would likely achieve within 12 minutes of retrying. + /// + private double getMissCountAtSkill(double skill, List bins) + { + double maxDiff = difficulties.Max(); + double endTime = times.Max(); + + if (maxDiff == 0) + return 0; + if (skill <= 0) + return difficulties.Count; + + IterativePoissonBinomial poiBin = new IterativePoissonBinomial(); + + return Math.Max(0, RootFinding.FindRootExpand(x => retryTimeRequiredToObtainMissCount(x) - time_threshold_minutes, -50, 1000, accuracy: 0.01)); + + double retryTimeRequiredToObtainMissCount(double missCount) + { + poiBin.Reset(); + + double timeSpentRetrying = 0; + + if (difficulties.Count > time_bin_count * difficulty_bin_count) + { + double binTimeSteps = endTime / time_bin_count; + + for (int timeIndex = 0; timeIndex < time_bin_count; timeIndex++) + { + for (int difficultyIndex = 0; difficultyIndex < difficulty_bin_count; difficultyIndex++) + { + Bin bin = bins[timeIndex * difficulty_bin_count + difficultyIndex]; + + double missProb = 1 - HitProbability(skill, bin.Difficulty); + poiBin.AddBinnedProbabilities(missProb, bin.NoteCount); + } + + timeSpentRetrying += binTimeSteps * poiBin.Cdf(missCount); + } + } + else + { + for (int i = 0; i < difficulties.Count; i++) + { + double deltaTime = i > 0 ? times[i] - times[i - 1] : times[i]; + + double missProb = 1 - HitProbability(skill, difficulties[i]); + poiBin.AddProbability(missProb); + + timeSpentRetrying += deltaTime * poiBin.Cdf(missCount); + } + } + + if (poiBin.Cdf(missCount) < 1e-10) + return double.PositiveInfinity; + + return (timeSpentRetrying / poiBin.Cdf(missCount) - endTime) * ms_to_minutes; + } + } + + /// + /// Calculates the number of strains weighted against the top strain. + /// The result is scaled by clock rate as it affects the total number of strains. + /// + public virtual double CountTopWeightedStrains(double difficultyValue) + { + if (difficulties.Count == 0) + return 0.0; + + // What would the top strain be if all strain values were identical. + // We don't have decay weight in FC time, so we just use the old live one of 0.95. + double consistentTopStrain = difficultyValue * (1 - 0.95); + + if (consistentTopStrain == 0) + return difficulties.Count; + + // Use a weighted sum of all strains. Constants are arbitrary and give nice values + return difficulties.Sum(s => 1.1 / (1 + Math.Exp(-10 * (s / consistentTopStrain - 0.88)))); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuStrainSkill.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs rename to osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuStrainSkill.cs index 916b6e7b2d51..7dd015735d7f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuStrainSkill.cs @@ -8,7 +8,7 @@ using System.Linq; using osu.Framework.Utils; -namespace osu.Game.Rulesets.Osu.Difficulty.Skills +namespace osu.Game.Rulesets.Osu.Difficulty.Aggregation { public abstract class OsuStrainSkill : StrainSkill { diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index be5e0385ee1f..0eae3f37cae9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -8,6 +8,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Difficulty.Utils; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Difficulty @@ -69,8 +70,8 @@ public class OsuDifficultyAttributes : DifficultyAttributes [JsonProperty("speed_top_weighted_slider_factor")] public double SpeedTopWeightedSliderFactor { get; set; } - [JsonProperty("aim_difficult_strain_count")] - public double AimDifficultStrainCount { get; set; } + [JsonProperty("aim_penalty_curve")] + public Polynomial AimMissPenaltyCurve { get; set; } [JsonProperty("speed_difficult_strain_count")] public double SpeedDifficultStrainCount { get; set; } @@ -113,7 +114,6 @@ public class OsuDifficultyAttributes : DifficultyAttributes yield return (ATTRIB_ID_SLIDER_FACTOR, SliderFactor); - yield return (ATTRIB_ID_AIM_DIFFICULT_STRAIN_COUNT, AimDifficultStrainCount); yield return (ATTRIB_ID_SPEED_DIFFICULT_STRAIN_COUNT, SpeedDifficultStrainCount); yield return (ATTRIB_ID_SPEED_NOTE_COUNT, SpeedNoteCount); yield return (ATTRIB_ID_AIM_DIFFICULT_SLIDER_COUNT, AimDifficultSliderCount); @@ -133,7 +133,6 @@ public override void FromDatabaseAttributes(IReadOnlyDictionary val StarRating = values[ATTRIB_ID_DIFFICULTY]; FlashlightDifficulty = values.GetValueOrDefault(ATTRIB_ID_FLASHLIGHT); SliderFactor = values[ATTRIB_ID_SLIDER_FACTOR]; - AimDifficultStrainCount = values[ATTRIB_ID_AIM_DIFFICULT_STRAIN_COUNT]; SpeedDifficultStrainCount = values[ATTRIB_ID_SPEED_DIFFICULT_STRAIN_COUNT]; SpeedNoteCount = values[ATTRIB_ID_SPEED_NOTE_COUNT]; AimDifficultSliderCount = values[ATTRIB_ID_AIM_DIFFICULT_SLIDER_COUNT]; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index edaef0aa75cd..548855dbb5ed 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -10,6 +10,7 @@ using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Difficulty.Aggregation; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Skills; using osu.Game.Rulesets.Osu.Difficulty.Utils; @@ -62,6 +63,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat double speedNotes = speed.RelevantNoteCount(); double aimDifficultStrainCount = aim.CountTopWeightedStrains(aimDifficultyValue); + Polynomial aimMissPenaltyCurve = aim.GetMissPenaltyCurve(); double speedDifficultStrainCount = speed.CountTopWeightedStrains(speedDifficultyValue); double aimNoSlidersTopWeightedSliderCount = aimWithoutSliders.CountTopWeightedSliders(aimNoSlidersDifficultyValue); @@ -120,7 +122,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat SpeedNoteCount = speedNotes, FlashlightDifficulty = flashlightRating, SliderFactor = sliderFactor, - AimDifficultStrainCount = aimDifficultStrainCount, + AimMissPenaltyCurve = aimMissPenaltyCurve, SpeedDifficultStrainCount = speedDifficultStrainCount, AimTopWeightedSliderFactor = aimTopWeightedSliderFactor, SpeedTopWeightedSliderFactor = speedTopWeightedSliderFactor, diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 9dde9dfdea7c..6cb48d118d14 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -9,7 +9,9 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Osu.Difficulty.Aggregation; using osu.Game.Rulesets.Osu.Difficulty.Skills; +using osu.Game.Rulesets.Osu.Difficulty.Utils; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; @@ -194,17 +196,13 @@ private double computeAimValue(ScoreInfo score, OsuDifficultyAttributes attribut double aimValue = OsuStrainSkill.DifficultyToPerformance(aimDifficulty); - double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + - (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); - aimValue *= lengthBonus; - if (effectiveMissCount > 0) { aimEstimatedSliderBreaks = calculateEstimatedSliderBreaks(attributes.AimTopWeightedSliderFactor, attributes); double relevantMissCount = Math.Min(effectiveMissCount + aimEstimatedSliderBreaks, totalImperfectHits + countSliderTickMiss); - aimValue *= calculateMissPenalty(relevantMissCount, attributes.AimDifficultStrainCount); + aimValue *= calculateCurveFittedMissPenalty(relevantMissCount, attributes.AimMissPenaltyCurve); } // TC bonuses are excluded when blinds is present as the increased visual difficulty is unimportant when notes cannot be seen. @@ -237,7 +235,7 @@ private double computeSpeedValue(ScoreInfo score, OsuDifficultyAttributes attrib double relevantMissCount = Math.Min(effectiveMissCount + speedEstimatedSliderBreaks, totalImperfectHits + countSliderTickMiss); - speedValue *= calculateMissPenalty(relevantMissCount, attributes.SpeedDifficultStrainCount); + speedValue *= calculateStrainCountMissPenalty(relevantMissCount, attributes.SpeedDifficultStrainCount); } // TC bonuses are excluded when blinds is present as the increased visual difficulty is unimportant when notes cannot be seen. @@ -487,10 +485,17 @@ private double calculateSpeedHighDeviationNerf(OsuDifficultyAttributes attribute return adjustedSpeedValue / speedValue; } - // Miss penalty assumes that a player will miss on the hardest parts of a map, - // so we use the amount of relatively difficult sections to adjust miss penalty - // to make it more punishing on maps with lower amount of hard sections. - private double calculateMissPenalty(double missCount, double difficultStrainCount) => 0.96 / ((missCount / (4 * Math.Pow(Math.Log(difficultStrainCount), 0.94))) + 1); + // Due to the unavailability of miss location in PP, the following formulas assume that a player will miss on the hardest parts of a map. + + // With the curve fitted miss penalty, we use a pre-computed curve of skill levels for each miss count, raised to the power of 1.5 as + // the multiple of the exponents on star rating and PP. This power should be changed if either SR or PP begin to use a different exponent. + // As a result, this exponent is not subject to balance. + private double calculateCurveFittedMissPenalty(double missCount, Polynomial curve) => Math.Pow(1 - curve.GetPenaltyAt(Math.Log(missCount + 1)), 1.5); + + // With the strain count miss penalty, we use the amount of relatively difficult sections to adjust the miss penalty, + // to make it more punishing on maps with lower amount of hard sections. This formula is subject to balance. + private double calculateStrainCountMissPenalty(double missCount, double difficultStrainCount) => 0.96 / (missCount / (4 * Math.Pow(Math.Log(difficultStrainCount), 0.94)) + 1); + private double getComboScalingFactor(OsuDifficultyAttributes attributes) => attributes.MaxCombo <= 0 ? 1.0 : Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(attributes.MaxCombo, 0.8), 1.0); private int totalHits => countGreat + countOk + countMeh + countMiss; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index dbdfef4199ed..616b2e638bac 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -6,7 +6,9 @@ using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Difficulty.Aggregation; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; +using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Osu.Difficulty.Utils; using osu.Game.Rulesets.Osu.Objects; @@ -15,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// /// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances. /// - public class Aim : OsuStrainSkill + public class Aim : OsuFcTimeSkill { public readonly bool IncludeSliders; @@ -27,14 +29,20 @@ public Aim(Mod[] mods, bool includeSliders) private double currentStrain; - private double skillMultiplier => 26; + private double skillMultiplier => 130; private double strainDecayBase => 0.15; private readonly List sliderStrains = new List(); - private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); + protected override double HitProbability(double skill, double difficulty) + { + if (difficulty <= 0) return 1; + if (skill <= 0) return 0; - protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => currentStrain * strainDecay(time - current.Previous(0).StartTime); + return DifficultyCalculationUtils.Erf(skill / (Math.Sqrt(2) * difficulty)); + } + + private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); protected override double StrainValueAt(DifficultyHitObject current) { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 105d3956ac6b..63bfe75ad267 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -9,6 +9,7 @@ using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; using System.Linq; +using osu.Game.Rulesets.Osu.Difficulty.Aggregation; using osu.Game.Rulesets.Osu.Difficulty.Utils; namespace osu.Game.Rulesets.Osu.Difficulty.Skills diff --git a/osu.Game.Rulesets.Osu/Difficulty/Utils/Bin.cs b/osu.Game.Rulesets.Osu/Difficulty/Utils/Bin.cs new file mode 100644 index 000000000000..b3465feb1941 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Utils/Bin.cs @@ -0,0 +1,75 @@ +// 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.Collections.Generic; +using System.Linq; + +namespace osu.Game.Rulesets.Osu.Difficulty.Utils +{ + public struct Bin + { + public double Difficulty; + public double Time; + public double NoteCount; + + /// + /// Creates a 2D grid of bins using bilinear interpolation. + /// Notes are distributed across neighboring bins weighted by their fractional position. + /// + public static List CreateBins(List difficulties, List times, int difficultyDimensionLength, int timeDimensionLength) + { + double maxDifficulty = difficulties.Max(); + double endTime = times.Max(); + + var binsArray = new Bin[timeDimensionLength * difficultyDimensionLength]; + + for (int timeIndex = 0; timeIndex < timeDimensionLength; timeIndex++) + { + double time = endTime * timeIndex / (timeDimensionLength - 1); + + for (int diffIndex = 0; diffIndex < difficultyDimensionLength; diffIndex++) + { + int binIndex = difficultyDimensionLength * timeIndex + diffIndex; + + binsArray[binIndex].Time = time; + + // We don't create a 0 difficulty bin because 0 difficulty notes don't contribute to star rating. + binsArray[binIndex].Difficulty = maxDifficulty * (diffIndex + 1) / difficultyDimensionLength; + } + } + + for (int noteIndex = 0; noteIndex < difficulties.Count; noteIndex++) + { + double timeBinIndex = timeDimensionLength * (times[noteIndex] / endTime); + double difficultyBinIndex = difficultyDimensionLength * (difficulties[noteIndex] / maxDifficulty) - 1; + + int timeLower = Math.Min((int)timeBinIndex, timeDimensionLength - 1); + int timeUpper = Math.Min(timeLower + 1, timeDimensionLength - 1); + double timeWeight = timeBinIndex - timeLower; + + int difficultyLower = fastFloor(difficultyBinIndex); + int difficultyUpper = Math.Min(difficultyLower + 1, difficultyDimensionLength - 1); + double difficultyWeight = difficultyBinIndex - difficultyLower; + + // The lower bound of difficulty can be -1, corresponding to buckets with 0 difficulty. + // We don't store those since they don't contribute to star rating. + if (difficultyLower >= 0) + { + binsArray[difficultyDimensionLength * timeLower + difficultyLower].NoteCount += (1 - timeWeight) * (1 - difficultyWeight); + binsArray[difficultyDimensionLength * timeUpper + difficultyLower].NoteCount += timeWeight * (1 - difficultyWeight); + } + + binsArray[difficultyDimensionLength * timeLower + difficultyUpper].NoteCount += (1 - timeWeight) * difficultyWeight; + binsArray[difficultyDimensionLength * timeUpper + difficultyUpper].NoteCount += timeWeight * difficultyWeight; + } + + var binsList = binsArray.ToList(); + + return binsList; + } + + // Faster implementation of the floor function to speed up binning times. + private static int fastFloor(double x) => x >= 0 || x == -1 ? (int)x : (int)(x - 1); + } +} diff --git a/osu.Game.Rulesets.Osu/Difficulty/Utils/PoissonBinomial.cs b/osu.Game.Rulesets.Osu/Difficulty/Utils/PoissonBinomial.cs new file mode 100644 index 000000000000..2bd4c58d638f --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Utils/PoissonBinomial.cs @@ -0,0 +1,160 @@ +// 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.Collections.Generic; +using osu.Game.Rulesets.Difficulty.Utils; + +namespace osu.Game.Rulesets.Osu.Difficulty.Utils +{ + /// + /// Approximation of the Poisson binomial distribution: + /// https://en.wikipedia.org/wiki/Poisson_binomial_distribution + /// + /// + /// + /// For the approximation method, see "Refined Normal Approximation (RNA)" from: + /// Hong, Y. (2013). On computing the distribution function for the Poisson binomial distribution. Computational Statistics and Data Analysis, Vol. 59, pp. 41-51. + /// (https://www.researchgate.net/publication/257017356_On_computing_the_distribution_function_for_the_Poisson_binomial_distribution) + /// + /// + /// This has been verified against a reference implementation provided by the authors in the R package "poibin", + /// which can be viewed here: + /// https://rdrr.io/cran/poibin/man/poibin-package.html + /// + /// + public class PoissonBinomial + { + /// + /// The expected value of the distribution. + /// + private readonly double mu; + + /// + /// The standard deviation of the distribution. + /// + private readonly double sigma; + + /// + /// The gamma factor from equation (11) in the cited paper, pre-divided by 6 to save on re-computation. + /// + private readonly double v; + + /// + /// Creates a Poisson binomial distribution based on N trials with the provided difficulties, skill, and method for getting the miss probabilities. + /// + /// The list of difficulties in the map. + /// The skill level to get the miss probabilities with. + /// Converts difficulties and skill to miss probabilities. + public PoissonBinomial(IList difficulties, double skill, Func hitProbability) + { + double variance = 0; + double gamma = 0; + + foreach (double d in difficulties) + { + double p = 1 - hitProbability(skill, d); + + mu += p; + variance += p * (1 - p); + gamma += p * (1 - p) * (1 - 2 * p); + } + + sigma = Math.Sqrt(variance); + + v = gamma / (6 * Math.Pow(sigma, 3)); + } + + /// + /// Creates a Poisson binomial distribution based on N trials with the provided bins of difficulties, skill, and method for getting the miss probabilities. + /// + /// The bins of difficulties in the map. + /// The skill level to get the miss probabilities with. + /// /// Converts difficulties and skill to miss probabilities. + public PoissonBinomial(List bins, double skill, Func hitProbability) + { + double variance = 0; + double gamma = 0; + + foreach (Bin bin in bins) + { + double p = 1 - hitProbability(skill, bin.Difficulty); + + mu += p * bin.NoteCount; + variance += p * (1 - p) * bin.NoteCount; + gamma += p * (1 - p) * (1 - 2 * p) * bin.NoteCount; + } + + sigma = Math.Sqrt(variance); + + v = gamma / (6 * Math.Pow(sigma, 3)); + } + + /// + /// Computes the value of the cumulative distribution function for this Poisson binomial distribution. + /// + /// + /// The argument of the CDF to sample the distribution for. + /// In the discrete case (when it is a whole number), this corresponds to the number + /// of successful Bernoulli trials to query the CDF for. + /// + /// + /// The value of the CDF at . + /// In the discrete case this corresponds to the probability that at most + /// Bernoulli trials ended in a success. + /// + // ReSharper disable once InconsistentNaming + public double CDF(double count) + { + if (sigma == 0) + return 1; + + double k = (count + 0.5 - mu) / sigma; + + // see equation (14) of the cited paper + double result = DifficultyCalculationUtils.NormalCdf(0, 1, k) + v * (1 - k * k) * DifficultyCalculationUtils.NormalPdf(0, 1, k); + + return Math.Clamp(result, 0, 1); + } + } + + public class IterativePoissonBinomial + { + private double mu, var, gamma; + + public void Reset() + { + mu = 0; + var = 0; + gamma = 0; + } + + public void AddProbability(double p) + { + mu += p; + var += p * (1 - p); + gamma += p * (1 - p) * (1 - 2 * p); + } + + public void AddBinnedProbabilities(double p, double count) + { + mu += p * count; + var += p * (1 - p) * count; + gamma += p * (1 - p) * (1 - 2 * p) * count; + } + + public double Cdf(double count) + { + if (var == 0) + return mu <= count ? 1 : 0; + + double sigma = Math.Sqrt(var); + double v = gamma / (6 * Math.Pow(sigma, 3)); + double k = (count + 0.5 - mu) / sigma; + + double result = DifficultyCalculationUtils.NormalCdf(0, 1, k) + v * (1 - k * k) * DifficultyCalculationUtils.NormalPdf(0, 1, k); + + return Math.Clamp(result, 0, 1); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Difficulty/Utils/Polynomial.cs b/osu.Game.Rulesets.Osu/Difficulty/Utils/Polynomial.cs new file mode 100644 index 000000000000..b43a38873918 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Utils/Polynomial.cs @@ -0,0 +1,90 @@ +// 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.Collections.Generic; +using System.Linq; +using osu.Game.Rulesets.Difficulty.Utils; + +namespace osu.Game.Rulesets.Osu.Difficulty.Utils +{ + /// + /// Represents a polynomial fitted to a given set of points. + /// + public struct Polynomial + { + /// + /// The proportions of skill that this polynomial will fit a curve to the miss counts of. + /// If you want to change these, you need to recompute the as it is precomputed to fit these specific values. + /// + public static readonly double[] SKILL_PROPORTIONS = [1, 0.95, 0.9, 0.8, 0.6, 0.3, 0]; + + // Stores the coefficients [a, b, c, d] of our polynomial ax^4 + bx^3 + cx^2 + dx + private double[]? coefficients; + + // Pre-calculated matrix used for curve fitting. + // It's derived using least-squares regression to find the best-fit polynomial through our data points. + private static readonly double[][] matrix = + { + new[] { 0.0, -25.8899, -32.6909, -11.9147, 48.8588, -26.8943, 0.0 }, + new[] { 0.0, 51.7787, 66.595, 28.8517, -90.3185, 40.9864, 0.0 }, + new[] { 0.0, -31.5028, -41.7398, -22.7118, 46.438, -15.5156, 0.0 } + }; + + /// + /// Creates a polynomial curve that maps miss counts to miss penalties. + /// Used to smoothly interpolate between miss counts, with 0 misses fixed to 0% penalty, and all misses fixed to 100% penalty. + /// + /// + /// A dictionary of miss counts, with keys representing skill proportions and values representing the miss count a player would achieve at that skill proportion. + /// See comment on if you want to use custom skill proportions. + /// + public void Fit(Dictionary missCounts) + { + double endPoint = missCounts.Values.Max(); + + double[] sortedSkillProportions = missCounts.Keys.OrderByDescending(k => k).ToArray(); + + coefficients = new double[4]; + + coefficients[3] = endPoint; + + // Now we dot product the adjusted miss counts with the matrix. + for (int row = 0; row < matrix.Length; row++) + { + for (int column = 0; column < matrix[row].Length; column++) + { + double skillProportion = sortedSkillProportions[column]; + double missCountAtSkill = missCounts[skillProportion]; + + coefficients[row] += matrix[row][column] * (missCountAtSkill - endPoint * (1 - skillProportion)); + } + + coefficients[3] -= coefficients[row]; + } + } + + /// + /// Calculates what percentage penalty the player should receive. + /// + /// The number of misses the player got + /// A value between 0 and 1 representing the penalty percentage (0 = no penalty, 1 = full penalty) + public double GetPenaltyAt(double missCount) + { + if (coefficients is null) + return 1; + + List listCoefficients = coefficients.ToList(); + listCoefficients.Add(-missCount); + + List xVals = DifficultyCalculationUtils.SolvePolynomialRoots(listCoefficients); + + const double max_error = 1e-7; + + // We find the largest value of x (corresponding to the penalty) found as a root of the function, with a fallback of a 100% penalty if no roots were found. + double largestValue = xVals.Where(x => x >= 0 - max_error && x <= 1 + max_error).OrderDescending().FirstOrDefault() ?? 1; + + return Math.Clamp(largestValue, 0, 1); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Difficulty/Utils/RootFinding.cs b/osu.Game.Rulesets.Osu/Difficulty/Utils/RootFinding.cs new file mode 100644 index 000000000000..bb01e8162c76 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Utils/RootFinding.cs @@ -0,0 +1,119 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; + +namespace osu.Game.Rulesets.Osu.Difficulty.Utils +{ + public static class RootFinding + { + /// + /// Finds the root of a using the Chandrupatla method, expanding the bounds if the root is not located within. + /// Expansion only occurs for the upward bound, as this function is optimized for functions of range [0, x), + /// which is useful for finding skill level (skill can never be below 0). + /// + /// The function of which to find the root. + /// The lower bound of the function inputs. + /// The upper bound of the function inputs. + /// The maximum number of iterations before the function throws an error. + /// The desired precision in which the root is returned. + /// The multiplier on the upper bound when no root is found within the provided bounds. + /// The maximum number of times the bounds of the function should increase. + public static double FindRootExpand(Func function, double guessLowerBound, double guessUpperBound, int maxIterations = 25, double accuracy = 1e-6D, double expansionFactor = 2, double maxExpansions = 32) + { + double a = guessLowerBound; + double b = guessUpperBound; + double fa = function(a); + double fb = function(b); + + int expansions = 0; + + while (fa * fb > 0) + { + a = b; + b *= expansionFactor; + fa = function(a); + fb = function(b); + + expansions++; + + if (expansions > maxExpansions) + { + throw new MaximumIterationsException("No root was found within the provided function."); + } + } + + double t = 0.5; + + for (int i = 0; i < maxIterations; i++) + { + double xt = a + t * (b - a); + double ft = function(xt); + + double c; + double fc; + + if (Math.Sign(ft) == Math.Sign(fa)) + { + c = a; + fc = fa; + } + else + { + c = b; + b = a; + fc = fb; + fb = fa; + } + + a = xt; + fa = ft; + + double xm, fm; + + if (Math.Abs(fa) < Math.Abs(fb)) + { + xm = a; + fm = fa; + } + else + { + xm = b; + fm = fb; + } + + if (fm == 0) + return xm; + + double tol = 2 * accuracy * Math.Abs(xm) + 2 * accuracy; + double tlim = tol / Math.Abs(b - c); + + if (tlim > 0.5) + { + return xm; + } + + double chi = (a - b) / (c - b); + double phi = (fa - fb) / (fc - fb); + bool iqi = phi * phi < chi && (1 - phi) * (1 - phi) < chi; + + if (iqi) + t = fa / (fb - fa) * fc / (fb - fc) + (c - a) / (b - a) * fa / (fc - fa) * fb / (fc - fb); + else + t = 0.5; + + t = Math.Min(1 - tlim, Math.Max(tlim, t)); + } + + return 0; + } + + private class MaximumIterationsException : Exception + { + public MaximumIterationsException(string message) + : base(message) + { + } + } + } +} diff --git a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs index c813627d5162..cf1fe6957236 100644 --- a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs +++ b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs @@ -190,5 +190,48 @@ public static double ErfInv(double x) /// /// Value to calculate the function for public static double ErfcInv(double x) => ErfInv(1 - x); + + /// + /// Computes the cumulative distribution (CDF) of the distribution at x, i.e. P(X ≤ x). + /// + /// The location at which to compute the cumulative distribution function. + /// The mean (μ) of the normal distribution. + /// The standard deviation (σ) of the normal distribution. Range: σ ≥ 0. + /// the cumulative distribution at location . + public static double NormalCdf(double mean, double stddev, double x) + { + const double sqrt2 = 1.4142135623730950488016887242096980785696718753769d; + + if (stddev < 0.0) + { + throw new ArgumentException("Invalid parametrization for the distribution."); + } + + if (mean == x && stddev == 0) + return 0; + + return 0.5 * Erfc((mean - x) / (stddev * sqrt2)); + } + + /// + /// Computes the probability density of the distribution (PDF) at x, i.e. ∂P(X ≤ x)/∂x. + /// + /// The mean (μ) of the normal distribution. + /// The standard deviation (σ) of the normal distribution. Range: σ ≥ 0. + /// The location at which to compute the density. + /// the density at . + /// MATLAB: normpdf + public static double NormalPdf(double mean, double stddev, double x) + { + const double sqrt2_pi = 2.5066282746310005024157652848110452530069867406099d; + + if (stddev < 0.0) + { + throw new ArgumentException("Invalid parametrization for the distribution."); + } + + double d = (x - mean) / stddev; + return Math.Exp(-0.5 * d * d) / (sqrt2_pi * stddev); + } } } diff --git a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils_PolynomialSolver.cs b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils_PolynomialSolver.cs new file mode 100644 index 000000000000..1ed4a39d605d --- /dev/null +++ b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils_PolynomialSolver.cs @@ -0,0 +1,253 @@ +// 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.Collections.Generic; +using System.Linq; +using osu.Framework.Utils; + +namespace osu.Game.Rulesets.Difficulty.Utils +{ + public partial class DifficultyCalculationUtils + { + private const double pi_mult_2 = 6.28318530717958647692528676655900576d; + + /// + /// Solve for the exact real roots of any polynomial up to degree 4. + /// + /// The coefficients of the polynomial, in ascending order ([1, 3, 5] -> x^2 + 3x + 5). + /// The real roots of the polynomial, and null if the root does not exist. + public static List SolvePolynomialRoots(List coefficients) + { + List xVals = new List(); + + switch (coefficients.Count) + { + case 5: + xVals = solveP4(coefficients[0], coefficients[1], coefficients[2], coefficients[3], coefficients[4], out int _).ToList(); + break; + + case 4: + xVals = solveP3(coefficients[0], coefficients[1], coefficients[2], coefficients[3], out int _).ToList(); + break; + + case 3: + xVals = solveP2(coefficients[0], coefficients[1], coefficients[2], out int _).ToList(); + break; + + case 2: + xVals = solveP2(0, coefficients[1], coefficients[2], out int _).ToList(); + break; + } + + return xVals; + } + + // https://github.com/sasamil/Quartic/blob/master/quartic.cpp + private static double?[] solveP4(double a, double b, double c, double d, double e, out int nRoots) + { + double?[] xVals = new double?[4]; + + nRoots = 0; + + if (a == 0) + { + double?[] xValsCubic = solveP3(b, c, d, e, out nRoots); + + xVals[0] = xValsCubic[0]; + xVals[1] = xValsCubic[1]; + xVals[2] = xValsCubic[2]; + xVals[3] = null; + + return xVals; + } + + b /= a; + c /= a; + d /= a; + e /= a; + + double a3 = -c; + double b3 = b * d - 4 * e; + double c3 = -b * b * e - d * d + 4 * c * e; + + double?[] x3 = solveP3(1, a3, b3, c3, out int iZeroes); + + double q1, q2, p1, p2, sqD; + + double y = x3[0]!.Value; + + // Get the y value with the highest absolute value. + if (iZeroes != 1) + { + if (Math.Abs(x3[1]!.Value) > Math.Abs(y)) + y = x3[1]!.Value; + if (Math.Abs(x3[2]!.Value) > Math.Abs(y)) + y = x3[2]!.Value; + } + + double upperD = y * y - 4 * e; + + if (Precision.AlmostEquals(upperD, 0)) + { + q1 = q2 = y * 0.5; + + upperD = b * b - 4 * (c - y); + + if (Precision.AlmostEquals(upperD, 0)) + p1 = p2 = b * 0.5; + + else + { + sqD = Math.Sqrt(upperD); + p1 = (b + sqD) * 0.5; + p2 = (b - sqD) * 0.5; + } + } + else + { + sqD = Math.Sqrt(upperD); + q1 = (y + sqD) * 0.5; + q2 = (y - sqD) * 0.5; + + p1 = (b * q1 - d) / (q1 - q2); + p2 = (d - b * q2) / (q1 - q2); + } + + // solving quadratic eq. - x^2 + p1*x + q1 = 0 + upperD = p1 * p1 - 4 * q1; + + if (upperD >= 0) + { + nRoots += 2; + + sqD = Math.Sqrt(upperD); + xVals[0] = (-p1 + sqD) * 0.5; + xVals[1] = (-p1 - sqD) * 0.5; + } + + // solving quadratic eq. - x^2 + p2*x + q2 = 0 + upperD = p2 * p2 - 4 * q2; + + if (upperD >= 0) + { + nRoots += 2; + + sqD = Math.Sqrt(upperD); + xVals[2] = (-p2 + sqD) * 0.5; + xVals[3] = (-p2 - sqD) * 0.5; + } + + // Put the null roots at the end of the array. + var nonNulls = xVals.Where(x => x != null); + var nulls = xVals.Where(x => x == null); + xVals = nonNulls.Concat(nulls).ToArray(); + + return xVals; + } + + private static double?[] solveP3(double a, double b, double c, double d, out int nRoots) + { + double?[] xVals = new double?[3]; + + nRoots = 0; + + if (a == 0) + { + double?[] xValsQuadratic = solveP2(b, c, d, out nRoots); + + xVals[0] = xValsQuadratic[0]; + xVals[1] = xValsQuadratic[1]; + xVals[2] = null; + + return xVals; + } + + b /= a; + c /= a; + d /= a; + + double a2 = b * b; + double q = (a2 - 3 * c) / 9; + double q3 = q * q * q; + double r = (b * (2 * a2 - 9 * c) + 27 * d) / 54; + double r2 = r * r; + + if (r2 < q3) + { + nRoots = 3; + + double t = r / Math.Sqrt(q3); + t = Math.Clamp(t, -1, 1); + t = Math.Acos(t); + b /= 3; + q = -2 * Math.Sqrt(q); + + xVals[0] = q * Math.Cos(t / 3) - b; + xVals[1] = q * Math.Cos((t + pi_mult_2) / 3) - b; + xVals[2] = q * Math.Cos((t - pi_mult_2) / 3) - b; + + return xVals; + } + + double upperA = -Math.Cbrt(Math.Abs(r) + Math.Sqrt(r2 - q3)); + + if (r < 0) + upperA = -upperA; + + double upperB = upperA == 0 ? 0 : q / upperA; + b /= 3; + + xVals[0] = upperA + upperB - b; + + if (Precision.AlmostEquals(0.5 * Math.Sqrt(3) * (upperA - upperB), 0)) + { + nRoots = 2; + xVals[1] = -0.5 * (upperA + upperB) - b; + + return xVals; + } + + nRoots = 1; + + return xVals; + } + + private static double?[] solveP2(double a, double b, double c, out int nRoots) + { + double?[] xVals = new double?[2]; + + nRoots = 0; + + if (a == 0) + { + if (b == 0) + return xVals; + + nRoots = 1; + xVals[0] = -c / b; + } + + double discriminant = b * b - 4 * a * c; + + switch (discriminant) + { + case < 0: + break; + + case 0: + nRoots = 1; + xVals[0] = -b / (2 * a); + break; + + default: + nRoots = 2; + xVals[0] = (-b + Math.Sqrt(discriminant)) / (2 * a); + xVals[1] = (-b - Math.Sqrt(discriminant)) / (2 * a); + break; + } + + return xVals; + } + } +} From a500fb96ee66b4527792be5d70a11c8c35d55f51 Mon Sep 17 00:00:00 2001 From: Natelytle Date: Sun, 28 Dec 2025 19:34:17 -0500 Subject: [PATCH 350/836] Fix merge issue --- .../Difficulty/Aggregation/OsuFcTimeSkill.cs | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuFcTimeSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuFcTimeSkill.cs index d43bef7fd484..61469942a9e1 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuFcTimeSkill.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuFcTimeSkill.cs @@ -31,7 +31,6 @@ protected OsuFcTimeSkill(Mod[] mods) private const double epsilon = 1e-4; - private readonly List difficulties = new List(); private readonly List times = new List(); /// @@ -39,26 +38,26 @@ protected OsuFcTimeSkill(Mod[] mods) /// protected abstract double StrainValueAt(DifficultyHitObject current); - public override void Process(DifficultyHitObject current) + protected override double ProcessInternal(DifficultyHitObject current) { - difficulties.Add(StrainValueAt(current)); - times.Add(times.LastOrDefault() + Math.Min(current.DeltaTime, max_delta_time)); + + return StrainValueAt(current); } protected abstract double HitProbability(double skill, double difficulty); public override double DifficultyValue() { - if (difficulties.Count == 0 || difficulties.Max() <= epsilon) + if (ObjectDifficulties.Count == 0 || ObjectDifficulties.Max() <= epsilon) return 0; // We only initialize bins if we have enough notes to use them. List? binList = null; - if (difficulties.Count > bin_threshold_note_count) + if (ObjectDifficulties.Count > bin_threshold_note_count) { - binList = Bin.CreateBins(difficulties, times, difficulty_bin_count, time_bin_count); + binList = Bin.CreateBins(ObjectDifficulties, times, difficulty_bin_count, time_bin_count); } // Lower bound and upper bound are generally unimportant @@ -91,11 +90,11 @@ private double timeSpentRetryingAtSkill(double skill, List? binList = null) } else { - for (int n = difficulties.Count - 1; n >= 0; n--) + for (int n = ObjectDifficulties.Count - 1; n >= 0; n--) { double deltaTime = n > 0 ? times[n] - times[n - 1] : times[n]; - hitProbabilityProduct *= HitProbability(skill, difficulties[n]); + hitProbabilityProduct *= HitProbability(skill, ObjectDifficulties[n]); timeSpentRetrying += deltaTime / hitProbabilityProduct - deltaTime; } } @@ -114,12 +113,12 @@ public Polynomial GetMissPenaltyCurve() Polynomial missPenaltyCurve = new Polynomial(); // If there are no notes, we just return the polynomial with all coefficients 0. - if (difficulties.Count == 0 || difficulties.Max() == 0) + if (ObjectDifficulties.Count == 0 || ObjectDifficulties.Max() == 0) return missPenaltyCurve; double fcSkill = DifficultyValue(); - var bins = Bin.CreateBins(difficulties, times, difficulty_bin_count, time_bin_count); + var bins = Bin.CreateBins(ObjectDifficulties, times, difficulty_bin_count, time_bin_count); foreach (double skillProportion in Polynomial.SKILL_PROPORTIONS) { @@ -145,13 +144,13 @@ public Polynomial GetMissPenaltyCurve() /// private double getMissCountAtSkill(double skill, List bins) { - double maxDiff = difficulties.Max(); + double maxDiff = ObjectDifficulties.Max(); double endTime = times.Max(); if (maxDiff == 0) return 0; if (skill <= 0) - return difficulties.Count; + return ObjectDifficulties.Count; IterativePoissonBinomial poiBin = new IterativePoissonBinomial(); @@ -163,7 +162,7 @@ double retryTimeRequiredToObtainMissCount(double missCount) double timeSpentRetrying = 0; - if (difficulties.Count > time_bin_count * difficulty_bin_count) + if (ObjectDifficulties.Count > time_bin_count * difficulty_bin_count) { double binTimeSteps = endTime / time_bin_count; @@ -182,11 +181,11 @@ double retryTimeRequiredToObtainMissCount(double missCount) } else { - for (int i = 0; i < difficulties.Count; i++) + for (int i = 0; i < ObjectDifficulties.Count; i++) { double deltaTime = i > 0 ? times[i] - times[i - 1] : times[i]; - double missProb = 1 - HitProbability(skill, difficulties[i]); + double missProb = 1 - HitProbability(skill, ObjectDifficulties[i]); poiBin.AddProbability(missProb); timeSpentRetrying += deltaTime * poiBin.Cdf(missCount); @@ -206,7 +205,7 @@ double retryTimeRequiredToObtainMissCount(double missCount) /// public virtual double CountTopWeightedStrains(double difficultyValue) { - if (difficulties.Count == 0) + if (ObjectDifficulties.Count == 0) return 0.0; // What would the top strain be if all strain values were identical. @@ -214,10 +213,10 @@ public virtual double CountTopWeightedStrains(double difficultyValue) double consistentTopStrain = difficultyValue * (1 - 0.95); if (consistentTopStrain == 0) - return difficulties.Count; + return ObjectDifficulties.Count; // Use a weighted sum of all strains. Constants are arbitrary and give nice values - return difficulties.Sum(s => 1.1 / (1 + Math.Exp(-10 * (s / consistentTopStrain - 0.88)))); + return ObjectDifficulties.Sum(s => 1.1 / (1 + Math.Exp(-10 * (s / consistentTopStrain - 0.88)))); } } } From 60d9c358b8ec6a4be778078956c907a4d47c0360 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 29 Dec 2025 15:43:43 +0900 Subject: [PATCH 351/836] Move top user tags enumeration to helper --- .../API/Requests/Responses/APIBeatmap.cs | 19 +++++++++++++++++++ osu.Game/Overlays/BeatmapSet/Info.cs | 17 +---------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index cbd8833fe874..6fd8416270c0 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -2,6 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; +using System.Linq; using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Extensions; @@ -115,6 +117,23 @@ private double hitLengthInSeconds [JsonProperty(@"owners")] public BeatmapOwner[] BeatmapOwners { get; set; } = Array.Empty(); + public APITag[] GetTopUserTags() + { + if (TopTags == null || TopTags.Length == 0 || BeatmapSet?.RelatedTags == null) + return []; + + var tagsById = BeatmapSet.RelatedTags.ToDictionary(t => t.Id); + + return TopTags + .Select(t => (topTag: t, relatedTag: tagsById.GetValueOrDefault(t.TagId))) + .Where(t => t.relatedTag != null) + // see https://github.com/ppy/osu-web/blob/bb3bd2e7c6f84f26066df5ea20a81c77ec9bb60a/resources/js/beatmapsets-show/controller.ts#L103-L106 for sort criteria + .OrderByDescending(t => t.topTag.VoteCount) + .ThenBy(t => t.relatedTag!.Name) + .Select(t => t.relatedTag!) + .ToArray(); + } + #region Implementation of IBeatmapInfo public IBeatmapMetadataInfo Metadata => (BeatmapSet as IBeatmapSetInfo)?.Metadata ?? new BeatmapMetadata(); diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 96e6622507dd..f7e3fa93c54e 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -130,21 +129,7 @@ public Info() private void updateUserTags() { - if (Beatmap.Value?.TopTags == null || Beatmap.Value.TopTags.Length == 0 || BeatmapSet.Value?.RelatedTags == null) - { - userTags.Metadata = null; - return; - } - - var tagsById = BeatmapSet.Value.RelatedTags.ToDictionary(t => t.Id); - userTags.Metadata = Beatmap.Value.TopTags - .Select(t => (topTag: t, relatedTag: tagsById.GetValueOrDefault(t.TagId))) - .Where(t => t.relatedTag != null) - // see https://github.com/ppy/osu-web/blob/bb3bd2e7c6f84f26066df5ea20a81c77ec9bb60a/resources/js/beatmapsets-show/controller.ts#L103-L106 for sort criteria - .OrderByDescending(t => t.topTag.VoteCount) - .ThenBy(t => t.relatedTag!.Name) - .Select(t => t.relatedTag!.Name) - .ToArray(); + userTags.Metadata = Beatmap.Value.GetTopUserTags().Select(t => t.Name).ToArray(); } [BackgroundDependencyLoader] From 69250b3260321268f9dc6320e74ef34f22247409 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Dec 2025 16:02:31 +0900 Subject: [PATCH 352/836] Reduce audio seek debounce time downwards I found this way too high in the editor, not giving enough feedback when seeking. To recap, this was put in place to avoid glitchy sounding audio. Such glitchiness only occurs with *very* fast seeks. This is still well within sane range. --- osu.Game/Overlays/NowPlayingOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index eb4e2db5d1e1..617cbc305925 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -29,7 +29,7 @@ namespace osu.Game.Overlays { public partial class NowPlayingOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent { - public const double TRACK_DRAG_SEEK_DEBOUNCE = 200; + public const double TRACK_DRAG_SEEK_DEBOUNCE = 40; public IconUsage Icon => OsuIcon.Music; public LocalisableString Title => NowPlayingStrings.HeaderTitle; From 4a60d7fe71fb348dd647602df3227940f0471c63 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Dec 2025 16:04:08 +0900 Subject: [PATCH 353/836] Fix now playing overlay responding to key events when seek bar is not visually focused --- osu.Game/Overlays/NowPlayingOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index eb4e2db5d1e1..0d7f7b94bd0e 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -518,6 +518,8 @@ protected override void OnDragEnd(DragEndEvent e) private partial class HoverableProgressBar : ProgressBar { + public override bool HandleNonPositionalInput => IsHovered; + public HoverableProgressBar() : base(true) { From 0f018988b5661f7bf0706b2e3626ea961444a285 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Dec 2025 16:04:20 +0900 Subject: [PATCH 354/836] Fix double seek when using keyboard with now playing overlay seek bar --- osu.Game/Overlays/NowPlayingOverlay.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index 0d7f7b94bd0e..b2676395fe60 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -224,21 +224,27 @@ private void load() }; } - private double? lastSeekTime; + private double? lastSeekGameTime; + private double? lastSeekAudioTargetTime; private void onSeek(double progress) { - if (!musicController.IsPlaying || lastSeekTime == null || Time.Current - lastSeekTime > TRACK_DRAG_SEEK_DEBOUNCE) + if (!musicController.IsPlaying || lastSeekGameTime == null || Time.Current - lastSeekGameTime > TRACK_DRAG_SEEK_DEBOUNCE) { musicController.SeekTo(progress); - lastSeekTime = Time.Current; + lastSeekGameTime = Time.Current; + lastSeekAudioTargetTime = progress; } } private void onCommit(double progress) { - musicController.SeekTo(progress); - lastSeekTime = null; + // Avoid a second seek to the same location, which could occur when using keyboard navigation from `OnSeek` and subsequent `OnCommit` calls. + if (progress != lastSeekAudioTargetTime) + musicController.SeekTo(progress); + + lastSeekGameTime = null; + lastSeekAudioTargetTime = null; } private void togglePlaylist() From f3fa1122c2a60704832ffba46b2016347802e0b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Dec 2025 16:07:14 +0900 Subject: [PATCH 355/836] End christmas --- osu.Game/Seasonal/SeasonalUIConfig.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Seasonal/SeasonalUIConfig.cs b/osu.Game/Seasonal/SeasonalUIConfig.cs index 060913a8bf0b..b894a42108c1 100644 --- a/osu.Game/Seasonal/SeasonalUIConfig.cs +++ b/osu.Game/Seasonal/SeasonalUIConfig.cs @@ -11,7 +11,7 @@ namespace osu.Game.Seasonal /// public static class SeasonalUIConfig { - public static readonly bool ENABLED = true; + public static readonly bool ENABLED = false; public static readonly Color4 PRIMARY_COLOUR_1 = Color4Extensions.FromHex(@"D32F2F"); From 69fee16eeef9beb61072b49b25908f3a82ca3cb2 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 29 Dec 2025 15:44:03 +0900 Subject: [PATCH 356/836] Add top tag and difficulty attributes --- .../TestSceneBeatmapSelectPanel.cs | 34 ++++- ...tchmakingSelectPanel.CardContentBeatmap.cs | 139 +++++++++++++++++- 2 files changed, 167 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs index 4d2cf0bffe24..4b2e470f36ce 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Game.Beatmaps; using osu.Game.Graphics.Cursor; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; @@ -45,10 +46,41 @@ public void TestBeatmapPanel() AddStep("add panel", () => { + var beatmap = CreateAPIBeatmap(); + + beatmap.TopTags = + [ + new APIBeatmapTag { TagId = 4, VoteCount = 1 }, + new APIBeatmapTag { TagId = 2, VoteCount = 1 }, + new APIBeatmapTag { TagId = 23, VoteCount = 5 }, + ]; + + beatmap.BeatmapSet!.RelatedTags = + [ + new APITag + { + Id = 2, + Name = "song representation/simple", + Description = "Accessible and straightforward map design." + }, + new APITag + { + Id = 4, + Name = "style/clean", + Description = "Visually uncluttered and organised patterns, often involving few overlaps and equal visual spacing between objects." + }, + new APITag + { + Id = 23, + Name = "aim/aim control", + Description = "Patterns with velocity or direction changes which strongly go against a player's natural movement pattern." + } + ]; + Child = new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, - Child = panel = new MatchmakingSelectPanelBeatmap(new MatchmakingPlaylistItem(new MultiplayerPlaylistItem(), CreateAPIBeatmap(), [])) + Child = panel = new MatchmakingSelectPanelBeatmap(new MatchmakingPlaylistItem(new MultiplayerPlaylistItem(), beatmap, [])) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs index b27ab2850bbc..ee7b2740a644 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -10,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Localisation; @@ -26,6 +28,7 @@ using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; using osu.Game.Resources.Localisation.Web; +using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play.HUD; using osuTK; @@ -44,6 +47,9 @@ public partial class CardContentBeatmap : CardContent, IHasContextMenu [Resolved] private BeatmapSetOverlay? beatmapSetOverlay { get; set; } + [Resolved] + private RulesetStore rulesets { get; set; } = null!; + private readonly IBindable downloadState = new Bindable(); private readonly IBindableNumber downloadProgress = new BindableDouble(); private readonly Bindable favouriteState = new Bindable(); @@ -56,6 +62,7 @@ public partial class CardContentBeatmap : CardContent, IHasContextMenu private FillFlowContainer idleBottomContent = null!; private BeatmapCardDownloadProgressBar downloadProgressBar = null!; private AvatarOverlay selectionOverlay = null!; + private OsuTextFlowContainer beatmapAttributesText = null!; public CardContentBeatmap(APIBeatmap beatmap, Mod[] mods) { @@ -181,6 +188,28 @@ private void load(OsuColour colours) }), } }, + new FillFlowContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(2), + Children = new Drawable[] + { + new TopTagPill(beatmap) + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }, + beatmapAttributesText = new OsuTextFlowContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + } + } + }, new Container { Name = @"Bottom content", @@ -255,13 +284,18 @@ private void load(OsuColour colours) }, } }, - new ModFlowDisplay + new Container { AutoSizeAxes = Axes.Both, - Scale = new Vector2(0.5f), - Margin = new MarginPadding { Left = 5 }, - Current = { Value = mods } - }, + Alpha = mods.Length > 0 ? 1 : 0, + Child = new ModFlowDisplay + { + AutoSizeAxes = Axes.Both, + Scale = new Vector2(0.5f), + Margin = new MarginPadding { Left = 5 }, + Current = { Value = mods }, + } + } }, } }, @@ -322,6 +356,62 @@ private void load(OsuColour colours) Margin = new MarginPadding { Left = 4 } }; } + + bool firstAttribute = true; + + foreach (var attribute in getBeatmapAttributes()) + { + if (!firstAttribute) + { + beatmapAttributesText.AddText(@" / ", s => + { + font(s, false); + s.Spacing = new Vector2(-2, 0); + }); + } + + beatmapAttributesText.AddText(attribute.heading, s => font(s, false)); + beatmapAttributesText.AddText(@" ", s => font(s, false)); + beatmapAttributesText.AddText(attribute.content, s => font(s, true)); + + firstAttribute = false; + + static void font(SpriteText s, bool bold) + => s.Font = OsuFont.Style.Caption2.With(weight: bold ? FontWeight.Bold : FontWeight.Regular); + } + } + + private (string heading, string content)[] getBeatmapAttributes() + { + BeatmapDifficulty adjustedDifficulty = new BeatmapDifficulty(beatmap.Difficulty); + foreach (var mod in mods.OfType()) + mod.ApplyToDifficulty(adjustedDifficulty); + + switch (beatmap.Ruleset.OnlineID) + { + default: + return new (string heading, string content)[] + { + ("CS", $"{adjustedDifficulty.CircleSize:0.#}"), + ("AR", $"{adjustedDifficulty.ApproachRate:0.#}"), + ("OD", $"{adjustedDifficulty.OverallDifficulty:0.#}"), + }; + + case 1: + case 3: + return new (string heading, string content)[] + { + ("OD", $"{adjustedDifficulty.OverallDifficulty:0.#}"), + ("HP", $"{adjustedDifficulty.DrainRate:0.#}") + }; + + case 2: + return new (string heading, string content)[] + { + ("CS", $"{adjustedDifficulty.CircleSize:0.#}"), + ("AR", $"{adjustedDifficulty.ApproachRate:0.#}"), + }; + } } protected override void LoadComplete() @@ -376,6 +466,45 @@ public MenuItem[] ContextMenuItems return items.ToArray(); } } + + private partial class TopTagPill : CompositeDrawable, IHasTooltip + { + private readonly APIBeatmap beatmap; + + public TopTagPill(APIBeatmap beatmap) + { + this.beatmap = beatmap; + + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + InternalChild = new CircularContainer + { + AutoSizeAxes = Axes.Both, + Masking = true, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background1 + }, + new OsuSpriteText + { + Padding = new MarginPadding { Vertical = 2, Horizontal = 8 }, + Text = beatmap.GetTopUserTags().FirstOrDefault()?.Name ?? string.Empty, + Colour = colourProvider.Content2, + Font = OsuFont.Style.Caption2 + } + } + }; + } + + public LocalisableString TooltipText => string.Join('\n', beatmap.GetTopUserTags().Select(t => t.Name)); + } } } } From 10ebb5286f8303edf0fcdd661d8b802873a97936 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 29 Dec 2025 17:17:38 +0900 Subject: [PATCH 357/836] Adjust metrics --- .../TestSceneBeatmapSelectPanel.cs | 11 + ...tchmakingSelectPanel.CardContentBeatmap.cs | 373 ++++++++---------- ...atchmakingSelectPanel.CardContentRandom.cs | 67 ++-- .../BeatmapSelect/MatchmakingSelectPanel.cs | 15 +- .../MatchmakingSelectPanelRandom.cs | 10 +- .../Matchmaking/Match/MatchmakingAvatar.cs | 2 +- 6 files changed, 234 insertions(+), 244 deletions(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs index 4b2e470f36ce..905c4d63e58c 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectPanel.cs @@ -55,6 +55,11 @@ public void TestBeatmapPanel() new APIBeatmapTag { TagId = 23, VoteCount = 5 }, ]; + beatmap.BeatmapSet!.HasExplicitContent = true; + beatmap.BeatmapSet!.HasVideo = true; + beatmap.BeatmapSet!.HasStoryboard = true; + beatmap.BeatmapSet.FeaturedInSpotlight = true; + beatmap.BeatmapSet.TrackId = 1; beatmap.BeatmapSet!.RelatedTags = [ new APITag @@ -128,6 +133,12 @@ public void TestRandomPanel() }; }); + AddStep("add peppy", () => panel!.AddUser(new APIUser + { + Id = 2, + Username = "peppy", + })); + AddToggleStep("allow selection", value => panel!.AllowSelection = value); AddStep("reveal beatmap", () => panel!.PresentAsChosenBeatmap(new MatchmakingPlaylistItem(new MultiplayerPlaylistItem(), CreateAPIBeatmap(), []))); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs index ee7b2740a644..f8c8b9a5aa68 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs @@ -28,7 +28,6 @@ using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; using osu.Game.Resources.Localisation.Web; -using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play.HUD; using osuTK; @@ -47,9 +46,6 @@ public partial class CardContentBeatmap : CardContent, IHasContextMenu [Resolved] private BeatmapSetOverlay? beatmapSetOverlay { get; set; } - [Resolved] - private RulesetStore rulesets { get; set; } = null!; - private readonly IBindable downloadState = new Bindable(); private readonly IBindableNumber downloadProgress = new BindableDouble(); private readonly Bindable favouriteState = new Bindable(); @@ -77,157 +73,66 @@ public CardContentBeatmap(APIBeatmap beatmap, Mod[] mods) private void load(OsuColour colours) { FillFlowContainer leftIconArea; - FillFlowContainer titleBadgeArea; - GridContainer artistContainer; + Container explicitBadgeArea; InternalChildren = new Drawable[] { - new BeatmapDownloadTracker(beatmap.BeatmapSet!) - { - State = { BindTarget = downloadState }, - Progress = { BindTarget = downloadProgress }, - }, - thumbnail = new BeatmapCardThumbnail(beatmapSet, beatmapSet, keepLoaded: true) - { - Name = @"Left (icon) area", - Size = new Vector2(MatchmakingSelectPanel.HEIGHT), - Padding = new MarginPadding { Right = BeatmapCard.CORNER_RADIUS }, - Child = leftIconArea = new FillFlowContainer - { - Margin = new MarginPadding(4), - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(1) - } - }, - buttonContainer = new CollapsibleButtonContainer(beatmapSet, allowNavigationToBeatmap: false, keepBackgroundLoaded: true) + new Container { - X = MatchmakingSelectPanel.HEIGHT - BeatmapCard.CORNER_RADIUS, - Width = BeatmapCard.WIDTH - MatchmakingSelectPanel.HEIGHT + BeatmapCard.CORNER_RADIUS, - FavouriteState = { BindTarget = favouriteState }, - ButtonsCollapsedWidth = 0, - ButtonsExpandedWidth = 24, + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = BeatmapCard.CORNER_RADIUS, Children = new Drawable[] { - new FillFlowContainer + new BeatmapDownloadTracker(beatmap.BeatmapSet!) { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.AutoSize), - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new Drawable[] - { - new TruncatingSpriteText - { - Text = new RomanisableString(beatmapSet.TitleUnicode, beatmapSet.Title), - Font = OsuFont.Default.With(size: 18f, weight: FontWeight.SemiBold), - RelativeSizeAxes = Axes.X, - }, - titleBadgeArea = new FillFlowContainer - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - } - } - } - }, - artistContainer = new GridContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.AutoSize) - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new[] - { - new TruncatingSpriteText - { - Text = BeatmapsetsStrings.ShowDetailsByArtist(new RomanisableString(beatmapSet.ArtistUnicode, beatmapSet.Artist)), - Font = OsuFont.Default.With(size: 14f, weight: FontWeight.SemiBold), - RelativeSizeAxes = Axes.X, - }, - Empty() - }, - } - }, - new LinkFlowContainer(s => - { - s.Shadow = false; - s.Font = OsuFont.GetFont(size: 11f, weight: FontWeight.SemiBold); - }).With(d => - { - d.AutoSizeAxes = Axes.Both; - d.Margin = new MarginPadding { Top = 1 }; - d.AddText("mapped by ", t => t.Colour = colourProvider.Content2); - d.AddUserLink(beatmapSet.Author); - }), - } + State = { BindTarget = downloadState }, + Progress = { BindTarget = downloadProgress }, }, - new FillFlowContainer + thumbnail = new BeatmapCardThumbnail(beatmapSet, beatmapSet, keepLoaded: true) { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(2), + Name = @"Left (icon) area", + Size = new Vector2(MatchmakingSelectPanel.HEIGHT), + Padding = new MarginPadding { Right = BeatmapCard.CORNER_RADIUS }, Children = new Drawable[] { - new TopTagPill(beatmap) + leftIconArea = new FillFlowContainer { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Margin = new MarginPadding(4), + Direction = FillDirection.Horizontal, + Spacing = new Vector2(1) }, - beatmapAttributesText = new OsuTextFlowContainer + explicitBadgeArea = new Container { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, AutoSizeAxes = Axes.Both, + Margin = new MarginPadding(4), } } }, - new Container + buttonContainer = new CollapsibleButtonContainer(beatmapSet, allowNavigationToBeatmap: false, keepBackgroundLoaded: true) { - Name = @"Bottom content", - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, + X = MatchmakingSelectPanel.HEIGHT - BeatmapCard.CORNER_RADIUS, + Width = BeatmapCard.WIDTH - MatchmakingSelectPanel.HEIGHT + BeatmapCard.CORNER_RADIUS, + FavouriteState = { BindTarget = favouriteState }, + ButtonsCollapsedWidth = 0, + ButtonsExpandedWidth = 24, Children = new Drawable[] { - idleBottomContent = new FillFlowContainer + new FillFlowContainer { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.Both, Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 2), - AlwaysPresent = true, Children = new Drawable[] { + new TruncatingSpriteText + { + Text = new RomanisableString(beatmapSet.TitleUnicode, beatmapSet.Title), + Font = OsuFont.Default.With(size: 18f, weight: FontWeight.SemiBold), + RelativeSizeAxes = Axes.X, + }, new GridContainer { RelativeSizeAxes = Axes.X, @@ -245,80 +150,160 @@ private void load(OsuColour colours) { new Drawable[] { - new Container + new TruncatingSpriteText { - Masking = true, - CornerRadius = BeatmapCard.CORNER_RADIUS, + Text = BeatmapsetsStrings.ShowDetailsByArtist(new RomanisableString(beatmapSet.ArtistUnicode, beatmapSet.Artist)), + Font = OsuFont.Default.With(size: 14f, weight: FontWeight.SemiBold), RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] + }, + new TopTagPill(beatmap) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + } + }, + } + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new LinkFlowContainer(s => + { + s.Shadow = false; + s.Font = OsuFont.Style.Caption2.With(weight: FontWeight.SemiBold); + }).With(d => + { + d.AutoSizeAxes = Axes.Both; + d.Margin = new MarginPadding { Top = 1 }; + d.AddText("mapped by ", t => t.Colour = colourProvider.Content2); + d.AddUserLink(beatmapSet.Author); + }), + beatmapAttributesText = new OsuTextFlowContainer + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + AutoSizeAxes = Axes.Both, + } + } + } + } + }, + new Container + { + Name = @"Bottom content", + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Children = new Drawable[] + { + idleBottomContent = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 2), + AlwaysPresent = true, + Children = new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize) + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] { - new Box - { - Colour = colours.ForStarDifficulty(beatmap.StarRating).Darken(0.8f), - RelativeSizeAxes = Axes.Both, - }, - new FillFlowContainer + new Container { - Padding = new MarginPadding(4), + Masking = true, + CornerRadius = BeatmapCard.CORNER_RADIUS, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(6, 0), Children = new Drawable[] { - new StarRatingDisplay(new StarDifficulty(beatmap.StarRating, 0), StarRatingDisplaySize.Small, animated: true) + new Box { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Scale = new Vector2(0.9f), + Colour = colours.ForStarDifficulty(beatmap.StarRating).Darken(0.8f), + RelativeSizeAxes = Axes.Both, }, - new TruncatingSpriteText + new FillFlowContainer { - Text = beatmap.DifficultyName, - Font = OsuFont.Style.Caption1.With(weight: FontWeight.Bold), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + Padding = new MarginPadding(4), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(6, 0), + Children = new Drawable[] + { + new StarRatingDisplay(new StarDifficulty(beatmap.StarRating, 0), StarRatingDisplaySize.Small, animated: true) + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Scale = new Vector2(0.9f), + }, + new TruncatingSpriteText + { + Text = beatmap.DifficultyName, + Font = OsuFont.Style.Caption1.With(weight: FontWeight.Bold), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + } }, } }, - } - }, - new Container - { - AutoSizeAxes = Axes.Both, - Alpha = mods.Length > 0 ? 1 : 0, - Child = new ModFlowDisplay - { - AutoSizeAxes = Axes.Both, - Scale = new Vector2(0.5f), - Margin = new MarginPadding { Left = 5 }, - Current = { Value = mods }, - } + new Container + { + AutoSizeAxes = Axes.Both, + Alpha = mods.Length > 0 ? 1 : 0, + Child = new ModFlowDisplay + { + AutoSizeAxes = Axes.Both, + Scale = new Vector2(0.5f), + Margin = new MarginPadding { Left = 5 }, + Current = { Value = mods }, + } + } + }, } }, } }, + downloadProgressBar = new BeatmapCardDownloadProgressBar + { + RelativeSizeAxes = Axes.X, + Height = 5, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + State = { BindTarget = downloadState }, + Progress = { BindTarget = downloadProgress } + } } }, - downloadProgressBar = new BeatmapCardDownloadProgressBar + selectionOverlay = new AvatarOverlay { - RelativeSizeAxes = Axes.X, - Height = 5, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - State = { BindTarget = downloadState }, - Progress = { BindTarget = downloadProgress } + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Margin = new MarginPadding { Top = -20 } } } }, - selectionOverlay = new AvatarOverlay - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - } } - } + }, + selectionOverlay.CreateProxy() }; if (beatmapSet.HasVideo) @@ -327,36 +312,14 @@ private void load(OsuColour colours) if (beatmapSet.HasStoryboard) leftIconArea.Add(new StoryboardIconPill { IconSize = new Vector2(16) }); - if (beatmapSet.FeaturedInSpotlight) - { - titleBadgeArea.Add(new SpotlightBeatmapBadge - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Margin = new MarginPadding { Left = 4 } - }); - } - if (beatmapSet.HasExplicitContent) { - titleBadgeArea.Add(new ExplicitContentBeatmapBadge + explicitBadgeArea.Add(new ExplicitContentBeatmapBadge { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, Margin = new MarginPadding { Left = 4 } }); } - if (beatmapSet.TrackId != null) - { - artistContainer.Content[0][1] = new FeaturedArtistBeatmapBadge - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Margin = new MarginPadding { Left = 4 } - }; - } - bool firstAttribute = true; foreach (var attribute in getBeatmapAttributes()) @@ -494,10 +457,12 @@ private void load(OverlayColourProvider colourProvider) }, new OsuSpriteText { - Padding = new MarginPadding { Vertical = 2, Horizontal = 8 }, + Padding = new MarginPadding { Vertical = 3, Horizontal = 8 }, Text = beatmap.GetTopUserTags().FirstOrDefault()?.Name ?? string.Empty, + AlwaysPresent = true, Colour = colourProvider.Content2, - Font = OsuFont.Style.Caption2 + Font = OsuFont.Style.Caption2, + UseFullGlyphHeight = false, } } }; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs index 0fc5a9fa4695..3e4130fa8b04 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentRandom.cs @@ -3,9 +3,11 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; +using osu.Game.Beatmaps.Drawables.Cards; using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; @@ -29,37 +31,44 @@ public partial class CardContentRandom : CardContent [BackgroundDependencyLoader] private void load() { - InternalChildren = new Drawable[] + InternalChild = new Container { - new Box + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = BeatmapCard.CORNER_RADIUS, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Dark5, - }, - new TrianglesV2 - { - RelativeSizeAxes = Axes.Both, - Alpha = 0.1f, - }, - Label = new OsuSpriteText - { - Y = 20, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "Random" - }, - Dice = new SpriteIcon - { - Y = -10, - Size = new Vector2(28), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Icon = randomDiceIcon(), - }, - selectionOverlay = new AvatarOverlay - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Dark5, + }, + new TrianglesV2 + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.1f, + }, + Label = new OsuSpriteText + { + Y = 20, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "Random" + }, + Dice = new SpriteIcon + { + Y = -10, + Size = new Vector2(28), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Icon = randomDiceIcon(), + }, + selectionOverlay = new AvatarOverlay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Margin = new MarginPadding { Right = 5 } + } } }; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs index 23d5f8cfb005..4bee234786f4 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.cs @@ -61,21 +61,18 @@ private void load(OverlayColourProvider colourProvider) { new Container { + RelativeSizeAxes = Axes.Both, Masking = true, CornerRadius = BeatmapCard.CORNER_RADIUS, CornerExponent = 10, - RelativeSizeAxes = Axes.Both, - Children = new[] + Child = lighting = new Box { - Content, - lighting = new Box - { - Blending = BlendingParameters.Additive, - RelativeSizeAxes = Axes.Both, - Alpha = 0, - }, + Blending = BlendingParameters.Additive, + RelativeSizeAxes = Axes.Both, + Alpha = 0, } }, + Content, border = new Container { Alpha = 0, diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs index 6389766b4684..d7ec134066ce 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanelRandom.cs @@ -6,9 +6,11 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Transforms; using osu.Framework.Input.Events; +using osu.Game.Beatmaps.Drawables.Cards; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osuTK; @@ -69,7 +71,13 @@ public override void PresentAsChosenBeatmap(MatchmakingPlaylistItem playlistItem AddRange(new Drawable[] { new CardContentBeatmap(playlistItem.Beatmap, playlistItem.Mods), - flashLayer, + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = BeatmapCard.CORNER_RADIUS, + Child = flashLayer + } }); foreach (var user in users) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingAvatar.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingAvatar.cs index e0f46d89f095..194d0d578bfb 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingAvatar.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingAvatar.cs @@ -51,7 +51,7 @@ private void load(OsuColour colour) AddInternal(new Container { - Padding = new MarginPadding(2), + Padding = new MarginPadding(isOwnUser ? 2 : 0), RelativeSizeAxes = Axes.Both, Child = new CircularContainer { From a6e1713514b6d04e3bca99a76c3fc482d07c3cc7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 29 Dec 2025 17:24:29 +0900 Subject: [PATCH 358/836] Fix panel depth --- .../Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs index a3ee24d479c8..27cb78e57943 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs @@ -94,6 +94,7 @@ public void AddItems(IEnumerable items) Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Action = i => ItemSelected?.Invoke(i), + Depth = -(float)item.PlaylistItem.StarRating }; panelGridContainer.Add(panel); From e34d2669875e53c27cf8a94ff7b6feec6fbd6cba Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 29 Dec 2025 17:37:57 +0900 Subject: [PATCH 359/836] Fix code style --- .../BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs index f8c8b9a5aa68..8a5d81c018c5 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs @@ -75,7 +75,7 @@ private void load(OsuColour colours) FillFlowContainer leftIconArea; Container explicitBadgeArea; - InternalChildren = new Drawable[] + InternalChildren = new[] { new Container { From 8347f83f9cd2859173c67889092485323da917a3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Dec 2025 17:33:02 +0900 Subject: [PATCH 360/836] Change editor to not seek smoothly when performing distant seeks This reverts to the way stable does things. Smooth seeking is nice and all, but slows things down and doesn't give the instant reponse that mappers are used to. This should fix some performance issues regarding seeking as it no longer tries to render large portions of the map during the seek operation. Note that I've also forced the summary timeline to always non-smooth seek. It was bugging out in weird ways when doing smooth seeks and I don't want to attempt to fix it. --- .../Timelines/Summary/Parts/MarkerPart.cs | 2 +- osu.Game/Screens/Edit/EditorClock.cs | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs index 1783bfb1e5e4..d3d5de389e32 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -70,7 +70,7 @@ private void seekToPosition(Vector2 screenPosition, bool instant) if (editorClock.IsRunning && !instant && lastSeekTime != null && Time.Current - lastSeekTime < NowPlayingOverlay.TRACK_DRAG_SEEK_DEBOUNCE) return; - editorClock.SeekSmoothlyTo(seekDestination); + editorClock.Seek(seekDestination); lastSeekTime = instant ? null : Time.Current; } diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index 4f700f2316f3..d82ecbeff609 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -209,7 +209,7 @@ public bool Seek(double position) } /// - /// Seek smoothly to the provided destination. + /// Seek smoothly to the provided destination, if within a certain proximity to the current viewport. /// Use to perform an immediate seek. /// /// @@ -217,12 +217,17 @@ public void SeekSmoothlyTo(double seekDestination) { seekingOrStopped.Value = true; - if (IsRunning) - Seek(seekDestination); - else + // The whole point of seeking smoothly is to maintain continuity for the user. + // Above a certain proximity, there's little reason to do this as the jump is already huge. + const double smooth_seek_max_proximity = 5000; + + if (IsRunning || Math.Abs(seekDestination - currentTime) > smooth_seek_max_proximity) { - transformSeekTo(seekDestination, transform_time, Easing.OutQuint); + Seek(seekDestination); + return; } + + transformSeekTo(seekDestination, transform_time, Easing.OutQuint); } public void BindAdjustments() => track.Value?.BindAdjustments(AudioAdjustments); From 2e324fe856bd6a9c7f12c0e2aa00a580a104980c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 29 Dec 2025 17:45:31 +0900 Subject: [PATCH 361/836] Show vote count in tag tooltip --- osu.Game/Online/API/Requests/Responses/APIBeatmap.cs | 4 ++-- osu.Game/Overlays/BeatmapSet/Info.cs | 2 +- .../MatchmakingSelectPanel.CardContentBeatmap.cs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index 6fd8416270c0..3a0afcd0abe2 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -117,7 +117,7 @@ private double hitLengthInSeconds [JsonProperty(@"owners")] public BeatmapOwner[] BeatmapOwners { get; set; } = Array.Empty(); - public APITag[] GetTopUserTags() + public (APITag Tag, int VoteCount)[] GetTopUserTags() { if (TopTags == null || TopTags.Length == 0 || BeatmapSet?.RelatedTags == null) return []; @@ -130,7 +130,7 @@ public APITag[] GetTopUserTags() // see https://github.com/ppy/osu-web/blob/bb3bd2e7c6f84f26066df5ea20a81c77ec9bb60a/resources/js/beatmapsets-show/controller.ts#L103-L106 for sort criteria .OrderByDescending(t => t.topTag.VoteCount) .ThenBy(t => t.relatedTag!.Name) - .Select(t => t.relatedTag!) + .Select(t => (t.relatedTag!, t.topTag.VoteCount)) .ToArray(); } diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index f7e3fa93c54e..9a2199523410 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -129,7 +129,7 @@ public Info() private void updateUserTags() { - userTags.Metadata = Beatmap.Value.GetTopUserTags().Select(t => t.Name).ToArray(); + userTags.Metadata = Beatmap.Value.GetTopUserTags().Select(t => t.Tag.Name).ToArray(); } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs index 8a5d81c018c5..e2d5fa7890bf 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs @@ -458,7 +458,7 @@ private void load(OverlayColourProvider colourProvider) new OsuSpriteText { Padding = new MarginPadding { Vertical = 3, Horizontal = 8 }, - Text = beatmap.GetTopUserTags().FirstOrDefault()?.Name ?? string.Empty, + Text = beatmap.GetTopUserTags().FirstOrDefault().Tag?.Name ?? string.Empty, AlwaysPresent = true, Colour = colourProvider.Content2, Font = OsuFont.Style.Caption2, @@ -468,7 +468,7 @@ private void load(OverlayColourProvider colourProvider) }; } - public LocalisableString TooltipText => string.Join('\n', beatmap.GetTopUserTags().Select(t => t.Name)); + public LocalisableString TooltipText => string.Join('\n', beatmap.GetTopUserTags().Select(t => $"{t.Tag.Name} ({t.VoteCount})")); } } } From dd261623cde58dd7b1c402ec4a65c9ec60745478 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Mon, 29 Dec 2025 15:11:25 +0500 Subject: [PATCH 362/836] Change the doubletapness scaling to be more punishing on the low end of the hitwindow (#36148) --- .../Difficulty/Evaluators/RhythmEvaluator.cs | 7 +------ .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 5 ++++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs index 9349083951e1..3bb35ccf1553 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs @@ -26,8 +26,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) if (current.BaseObject is Spinner) return 0; - var currentOsuObject = (OsuDifficultyHitObject)current; - double rhythmComplexitySum = 0; double deltaDifferenceEpsilon = ((OsuDifficultyHitObject)current).HitWindowGreat * 0.3; @@ -176,10 +174,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) prevObj = currObj; } - double rhythmDifficulty = Math.Sqrt(4 + rhythmComplexitySum * rhythm_overall_multiplier) / 2.0; // produces multiplier that can be applied to strain. range [1, infinity) (not really though) - rhythmDifficulty *= 1 - currentOsuObject.GetDoubletapness((OsuDifficultyHitObject)current.Next(0)); - - return rhythmDifficulty; + return Math.Sqrt(4 + rhythmComplexitySum * rhythm_overall_multiplier) / 2.0; // produces multiplier that can be applied to strain. range [1, infinity) (not really though); } private class Island : IEquatable diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 5e9fc10ef877..2641475810d9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -175,9 +175,12 @@ public double GetDoubletapness(OsuDifficultyHitObject? osuNextObj) { double currDeltaTime = Math.Max(1, DeltaTime); double nextDeltaTime = Math.Max(1, osuNextObj.DeltaTime); + double deltaDifference = Math.Abs(nextDeltaTime - currDeltaTime); + double speedRatio = currDeltaTime / Math.Max(currDeltaTime, deltaDifference); - double windowRatio = Math.Pow(Math.Min(1, currDeltaTime / HitWindowGreat), 2); + double windowRatio = Math.Pow(Math.Min(1, currDeltaTime / HitWindowGreat), 5); + return 1.0 - Math.Pow(speedRatio, 1 - windowRatio); } From 8ff2329e22af78c1d81acb8be0d44c8443363b9b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 29 Dec 2025 19:13:39 +0900 Subject: [PATCH 363/836] Fix tests --- osu.Game/Overlays/BeatmapSet/Info.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 9a2199523410..e25c1370c548 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -129,7 +129,7 @@ public Info() private void updateUserTags() { - userTags.Metadata = Beatmap.Value.GetTopUserTags().Select(t => t.Tag.Name).ToArray(); + userTags.Metadata = Beatmap.Value?.GetTopUserTags().Select(t => t.Tag.Name).ToArray(); } [BackgroundDependencyLoader] From 056d8323711c0508ae931a55acd09af7662b3892 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Mon, 29 Dec 2025 14:12:02 +0300 Subject: [PATCH 364/836] Move "Random" string to `UserInterfaceStrings` --- osu.Game/Configuration/IntroSequence.cs | 2 +- osu.Game/Localisation/IntroSequenceStrings.cs | 19 ------------------- osu.Game/Localisation/UserInterfaceStrings.cs | 5 +++++ 3 files changed, 6 insertions(+), 20 deletions(-) delete mode 100644 osu.Game/Localisation/IntroSequenceStrings.cs diff --git a/osu.Game/Configuration/IntroSequence.cs b/osu.Game/Configuration/IntroSequence.cs index 31b58b0174b3..04323cd14749 100644 --- a/osu.Game/Configuration/IntroSequence.cs +++ b/osu.Game/Configuration/IntroSequence.cs @@ -12,7 +12,7 @@ public enum IntroSequence Welcome, Triangles, - [LocalisableDescription(typeof(IntroSequenceStrings), nameof(IntroSequenceStrings.Random))] + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.IntroRandom))] Random } } diff --git a/osu.Game/Localisation/IntroSequenceStrings.cs b/osu.Game/Localisation/IntroSequenceStrings.cs deleted file mode 100644 index 9a3da64a295e..000000000000 --- a/osu.Game/Localisation/IntroSequenceStrings.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Localisation; - -namespace osu.Game.Localisation -{ - public static class IntroSequenceStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.IntroSequence"; - - /// - /// "Random" - /// - public static LocalisableString Random => new TranslatableString(getKey(@"random"), @"Random"); - - private static string getKey(string key) => $@"{prefix}:{key}"; - } -} diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index 7fbccf1919e6..facea0f66cd7 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -59,6 +59,11 @@ public static class UserInterfaceStrings /// public static LocalisableString IntroSequence => new TranslatableString(getKey(@"intro_sequence"), @"Intro sequence"); + /// + /// "Random" + /// + public static LocalisableString IntroRandom => new TranslatableString(getKey(@"intro_random"), @"Random"); + /// /// "Background source" /// From d421678d3459e4a7b67b11305ae1dfb651f6fcfa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Dec 2025 20:18:18 +0900 Subject: [PATCH 365/836] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 09c83cf37bb0..3a0d771fbf7a 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index aa5f4de8c947..5a2f7f5f1879 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From 3c084c60aa065d5377a2814c4513050659be4436 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Dec 2025 01:27:08 +0900 Subject: [PATCH 366/836] Fix iOS compilation --- osu.iOS/AppDelegate.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.iOS/AppDelegate.cs b/osu.iOS/AppDelegate.cs index 5d309f2fc171..65c1951e801a 100644 --- a/osu.iOS/AppDelegate.cs +++ b/osu.iOS/AppDelegate.cs @@ -9,7 +9,7 @@ namespace osu.iOS { [Register("AppDelegate")] - public class AppDelegate : GameApplicationDelegate + public class AppDelegate : GameApplicationDelegate, IUIApplicationDelegate { private UIInterfaceOrientationMask? defaultOrientationsMask; private UIInterfaceOrientationMask? orientations; @@ -41,7 +41,7 @@ public UIInterfaceOrientationMask? Orientations protected override Framework.Game CreateGame() => new OsuGameIOS(this); - public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow) + public UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow) { if (orientations != null) return orientations.Value; From 6e41332ea311f1880545e87eeee23b19733acb4b Mon Sep 17 00:00:00 2001 From: ILW8 Date: Tue, 30 Dec 2025 00:55:22 +0000 Subject: [PATCH 367/836] Change last year placing from integer to string --- osu.Game.Tournament.Tests/TournamentTestScene.cs | 2 +- osu.Game.Tournament/Models/TournamentTeam.cs | 6 +----- osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs | 9 +-------- osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs | 2 +- 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tournament.Tests/TournamentTestScene.cs b/osu.Game.Tournament.Tests/TournamentTestScene.cs index 4106556ee12b..e459bb60c6ab 100644 --- a/osu.Game.Tournament.Tests/TournamentTestScene.cs +++ b/osu.Game.Tournament.Tests/TournamentTestScene.cs @@ -66,7 +66,7 @@ public virtual void SetUpSteps() Acronym = { Value = "JPN" }, FlagName = { Value = "JP" }, FullName = { Value = "Japan" }, - LastYearPlacing = { Value = 10 }, + LastYearPlacing = { Value = "#10" }, Seed = { Value = "#12" }, SeedingResults = { diff --git a/osu.Game.Tournament/Models/TournamentTeam.cs b/osu.Game.Tournament/Models/TournamentTeam.cs index 95858240a8ec..b6d9486b6813 100644 --- a/osu.Game.Tournament/Models/TournamentTeam.cs +++ b/osu.Game.Tournament/Models/TournamentTeam.cs @@ -49,11 +49,7 @@ public double AverageRank public Bindable Seed = new Bindable(string.Empty); - public Bindable LastYearPlacing = new BindableInt - { - MinValue = 0, - MaxValue = 256 - }; + public Bindable LastYearPlacing = new Bindable("N/A"); [JsonProperty] public BindableList Players { get; } = new BindableList(); diff --git a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs index 162379f4aa85..05ffaf710d56 100644 --- a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs @@ -10,9 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Localisation; using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osu.Game.Overlays.Settings; using osu.Game.Tournament.Models; @@ -132,7 +130,7 @@ public TeamRow(TournamentTeam team, TournamentScreen parent) Width = 0.2f, Current = Model.Seed }, - new SettingsSlider + new SettingsTextBox { LabelText = "Last Year Placement", Width = 0.33f, @@ -200,11 +198,6 @@ protected override void LoadComplete() }, true); } - private partial class LastYearPlacementSlider : RoundedSliderBar - { - public override LocalisableString TooltipText => Current.Value == 0 ? "N/A" : base.TooltipText; - } - public partial class PlayerEditor : CompositeDrawable { private readonly TournamentTeam team; diff --git a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs index 899d462e4eba..ddfff54ded1a 100644 --- a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs +++ b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs @@ -274,7 +274,7 @@ public LeftInfo(TournamentTeam? team) new TeamDisplay(team) { Margin = new MarginPadding { Bottom = 30 } }, new RowDisplay("Average Rank:", $"#{team.AverageRank:#,0}"), new RowDisplay("Seed:", team.Seed.Value), - new RowDisplay("Last year's placing:", team.LastYearPlacing.Value > 0 ? $"#{team.LastYearPlacing:#,0}" : "N/A"), + new RowDisplay("Last year's placing:", team.LastYearPlacing.Value), new Container { Margin = new MarginPadding { Bottom = 30 } }, } }, From 71be574c2b48efba36e80bcfeeeb71f315e01df0 Mon Sep 17 00:00:00 2001 From: ILW8 Date: Tue, 30 Dec 2025 00:55:55 +0000 Subject: [PATCH 368/836] Update seeding screen tests to include last year placing --- .../Screens/TestSceneSeedingScreen.cs | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneSeedingScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneSeedingScreen.cs index a3890bbff031..f0a81a71b4d2 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneSeedingScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneSeedingScreen.cs @@ -23,6 +23,8 @@ public partial class TestSceneSeedingScreen : TournamentScreenTestScene { FullName = { Value = @"Japan" }, Acronym = { Value = "JPN" }, + Seed = { Value = "#28" }, + LastYearPlacing = { Value = "#17-24" }, SeedingResults = { new SeedingResult @@ -36,20 +38,38 @@ public partial class TestSceneSeedingScreen : TournamentScreenTestScene Seed = { Value = 8 } } } + }, + new TournamentTeam + { + Acronym = { Value = "USA" }, + FlagName = { Value = "US" }, + FullName = { Value = "United States" }, } } }; - [Test] - public void TestBasic() + [BackgroundDependencyLoader] + private void load() { - AddStep("create seeding screen", () => Add(new SeedingScreen + Add(new SeedingScreen { FillMode = FillMode.Fit, FillAspectRatio = 16 / 9f - })); + }); + } + + [Test] + public void TestBasic() + { + AddStep("set team to Japan", () => + this.ChildrenOfType().Single().Current.Value = ladder.Teams.Single(t => t.FullName.Value == "Japan")); + } - AddStep("set team to Japan", () => this.ChildrenOfType().Single().Current.Value = ladder.Teams.Single()); + [Test] + public void TestNoSeed() + { + AddStep("set team to USA", () => + this.ChildrenOfType().Single().Current.Value = ladder.Teams.Single(t => t.FullName.Value == "United States")); } } } From 1cff386b3a377a0966735da5bdfe316947a4b28f Mon Sep 17 00:00:00 2001 From: ILW8 Date: Tue, 30 Dec 2025 01:55:42 +0000 Subject: [PATCH 369/836] Adjust seed and last year placing textbox positioning in team editor --- .../Screens/Editors/TeamEditorScreen.cs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs index 05ffaf710d56..56333eb2a347 100644 --- a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs @@ -109,43 +109,43 @@ public TeamRow(TournamentTeam team, TournamentScreen parent) new SettingsTextBox { LabelText = "Name", - Width = 0.2f, + Width = 0.33f, Current = Model.FullName }, acronymTextBox = new SettingsTextBox { LabelText = "Acronym", - Width = 0.2f, + Width = 0.25f, Current = Model.Acronym }, new SettingsTextBox { LabelText = "Flag", - Width = 0.2f, + Width = 0.25f, Current = Model.FlagName }, + new SettingsButton + { + Width = 0.33f, + Margin = new MarginPadding { Top = 20 }, + Text = "Edit seeding results", + Action = () => + { + sceneManager?.SetScreen(new SeedingEditorScreen(team, parent)); + } + }, new SettingsTextBox { LabelText = "Seed", - Width = 0.2f, + Width = 0.25f, Current = Model.Seed }, new SettingsTextBox { LabelText = "Last Year Placement", - Width = 0.33f, + Width = 0.25f, Current = Model.LastYearPlacing }, - new SettingsButton - { - Width = 0.2f, - Margin = new MarginPadding(10), - Text = "Edit seeding results", - Action = () => - { - sceneManager?.SetScreen(new SeedingEditorScreen(team, parent)); - } - }, playerEditor, new SettingsButton { From 191ec072a87eb335301857f34f00e4ed856f6534 Mon Sep 17 00:00:00 2001 From: ILW8 Date: Tue, 30 Dec 2025 02:31:11 +0000 Subject: [PATCH 370/836] Add conversion from `0` last year placing value to new default "N/A" --- osu.Game.Tournament/Models/TournamentTeam.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/osu.Game.Tournament/Models/TournamentTeam.cs b/osu.Game.Tournament/Models/TournamentTeam.cs index b6d9486b6813..ab353d771abc 100644 --- a/osu.Game.Tournament/Models/TournamentTeam.cs +++ b/osu.Game.Tournament/Models/TournamentTeam.cs @@ -49,8 +49,26 @@ public double AverageRank public Bindable Seed = new Bindable(string.Empty); + [JsonIgnore] public Bindable LastYearPlacing = new Bindable("N/A"); + /// + /// Previously, a value of 0 was meant to indicate "no placement last year". + /// This will convert the number 0 from an old bracket.json file back to the "N/A" string (new default). + /// + [JsonProperty("LastYearPlacing")] + private object lastYearPlacing + { + get => LastYearPlacing.Value; + set + { + if (value is long oldValue && oldValue == 0) + LastYearPlacing.Value = LastYearPlacing.Default; + else + LastYearPlacing.Value = value.ToString() ?? LastYearPlacing.Default; + } + } + [JsonProperty] public BindableList Players { get; } = new BindableList(); From e2a245b04948d8aabd43ca8a122c1f669e542b7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 30 Dec 2025 09:57:31 +0100 Subject: [PATCH 371/836] Add minimal spread display control for beatmap set panels --- .../UserInterface/OsuAnimatedButton.cs | 3 +- .../SelectV2/PanelBeatmapSet.SpreadDisplay.cs | 204 ++++++++++++++++++ osu.Game/Screens/SelectV2/PanelBeatmapSet.cs | 11 +- 3 files changed, 212 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs diff --git a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs index 67a4cf689044..9eda0654951a 100644 --- a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs @@ -93,7 +93,8 @@ protected override void LoadComplete() base.LoadComplete(); Colour = dimColour; - Enabled.BindValueChanged(_ => this.FadeColour(dimColour, 200, Easing.OutQuint)); + Enabled.BindValueChanged(_ => this.FadeColour(dimColour, 200, Easing.OutQuint), true); + FinishTransforms(true); } private Color4 dimColour => Enabled.Value ? Color4.White : colours.Gray9; diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs new file mode 100644 index 000000000000..177d7c716274 --- /dev/null +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs @@ -0,0 +1,204 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets; +using osuTK; + +namespace osu.Game.Screens.SelectV2 +{ + public partial class PanelBeatmapSet + { + public partial class SpreadDisplay : OsuAnimatedButton + { + public Bindable BeatmapSet { get; } = new Bindable(); + public BindableBool Expanded { get; } = new BindableBool(); + + private readonly Bindable scopedBeatmapSet = new Bindable(); + private readonly Bindable showConvertedBeatmaps = new Bindable(); + + private const double transition_duration = 200; + + [Resolved] + private Bindable ruleset { get; set; } = null!; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + private FillFlowContainer flow = null!; + private OsuSpriteText countText = null!; // TODO + private SpriteIcon icon = null!; + + public SpreadDisplay() + { + AutoSizeAxes = Axes.X; + Height = 14; + Content.CornerRadius = 5; + } + + [BackgroundDependencyLoader] + private void load(ISongSelect? songSelect, OsuConfigManager configManager) + { + Add(new FillFlowContainer + { + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5), + Padding = new MarginPadding { Horizontal = 5 }, + Children = new Drawable[] + { + flow = new FillFlowContainer + { + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(2), + }, + countText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.Style.Caption2, + }, + icon = new SpriteIcon + { + Size = new Vector2(12), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Icon = FontAwesome.Solid.Eye, + Alpha = 0, + } + } + }); + + if (songSelect != null) + scopedBeatmapSet.BindTo(songSelect.ScopedBeatmapSet); + + configManager.BindWith(OsuSetting.ShowConvertedBeatmaps, showConvertedBeatmaps); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + BeatmapSet.BindValueChanged(_ => updateBeatmapSet()); + showConvertedBeatmaps.BindValueChanged(_ => updateBeatmapSet(), true); + Expanded.BindValueChanged(_ => updateEnabled()); + scopedBeatmapSet.BindValueChanged(_ => updateEnabled(), true); + Enabled.BindValueChanged(_ => updateAppearance(), true); + FinishTransforms(true); + } + + private void updateBeatmapSet() + { + if (BeatmapSet.Value == null) + { + this.FadeOut(transition_duration, Easing.OutQuint); + return; + } + + flow.Clear(); + + var starDifficulties = BeatmapSet.Value.Beatmaps + .Where(b => b.AllowGameplayWithRuleset(ruleset.Value, showConvertedBeatmaps.Value)) + .OrderBy(b => b.Ruleset.OnlineID) + .ThenBy(b => b.StarRating) + .Select(b => b.StarRating) + .ToList(); + this.FadeTo(starDifficulties.Count > 0 ? 1 : 0, transition_duration, Easing.OutQuint); + + if (starDifficulties.Count == 0) + return; + + // TODO: figure overflow later + + foreach (double starDifficulty in starDifficulties) + { + var circle = new Circle + { + Size = new Vector2(5, 10), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Colour = colours.ForStarDifficulty(starDifficulty) + }; + flow.Add(circle); + flow.SetLayoutPosition(circle, (float)starDifficulty); + } + + Action = () => scopedBeatmapSet.Value = BeatmapSet.Value; + updateEnabled(); + } + + private void updateEnabled() + { + Enabled.Value = Expanded.Value && scopedBeatmapSet.Value == null; + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (!Enabled.Value) + return false; + + base.OnMouseDown(e); + return true; + } + + protected override bool OnClick(ClickEvent e) + { + if (!Enabled.Value) + return false; + + // this is a crude workaround with an issue with `OsuAnimatedButton` that isn't easily fixable. + // the issue is that when wanting to turn off the hover layer upon click, `HoverColour` can be set to a transparent colour, + // *but* this has to happen *before* `base.OnClick()`. + // this is because `base.OnClick()` uses `FlashColour()` to flash the button on click, + // but that `FlashColour()` call implicitly copies `hoverColour` *at the point of call* into the transform that ends the flash. + updateAppearance(false); + return base.OnClick(e); + } + + protected override bool OnHover(HoverEvent e) + { + updateAppearance(); + + if (!Enabled.Value) + return false; + + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateAppearance(); + + if (!Enabled.Value) + return; + + base.OnHoverLost(e); + } + + private void updateAppearance(bool? isInteractable = null) + { + isInteractable ??= Enabled.Value && IsHovered; + + HoverColour = isInteractable.Value ? Colour4.White.Opacity(0.1f) : Colour4.Transparent; + icon.FadeTo(isInteractable.Value ? 1 : 0, transition_duration, Easing.OutQuint); + } + } + } +} diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs index befdba1b2b13..95262e16e1c4 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs @@ -47,7 +47,7 @@ public partial class PanelBeatmapSet : Panel private Drawable chevronIcon = null!; private PanelUpdateBeatmapButton updateButton = null!; private BeatmapSetOnlineStatusPill statusPill = null!; - private DifficultySpectrumDisplay difficultiesDisplay = null!; + private SpreadDisplay spreadDisplay = null!; [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -151,10 +151,11 @@ private void load() Origin = Anchor.CentreLeft, Margin = new MarginPadding { Right = 5f, Top = -2f }, }, - difficultiesDisplay = new DifficultySpectrumDisplay + spreadDisplay = new SpreadDisplay { - Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Expanded = { BindTarget = Expanded } }, }, } @@ -200,7 +201,7 @@ protected override void PrepareForUse() artistText.Text = new RomanisableString(beatmapSet.Metadata.ArtistUnicode, beatmapSet.Metadata.Artist); updateButton.BeatmapSet = beatmapSet; statusPill.Status = beatmapSet.Status; - difficultiesDisplay.BeatmapSet = beatmapSet; + spreadDisplay.BeatmapSet.Value = beatmapSet; } protected override void FreeAfterUse() @@ -211,7 +212,7 @@ protected override void FreeAfterUse() scheduledBackgroundRetrieval = null; setBackground.Beatmap = null; updateButton.BeatmapSet = null; - difficultiesDisplay.BeatmapSet = null; + spreadDisplay.BeatmapSet.Value = null; } [Resolved] From e07b828f30731ca4416c531cb936844d759534f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 30 Dec 2025 10:22:33 +0100 Subject: [PATCH 372/836] Add support for showing which beatmaps in a set are currently filtered out --- osu.Game/Screens/SelectV2/BeatmapCarousel.cs | 18 +++++++++-- .../SelectV2/PanelBeatmapSet.SpreadDisplay.cs | 31 +++++++++++-------- osu.Game/Screens/SelectV2/PanelBeatmapSet.cs | 5 ++- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index aacebe4e8867..4519e594c6f1 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -532,6 +532,9 @@ protected override void HandleFilterCompleted() // If a group was selected that is not the one containing the selection, attempt to reselect it. if (groupForReselection != null && grouping.GroupItems.TryGetValue(groupForReselection, out _)) setExpandedGroup(groupForReselection); + + foreach (var item in Scroll.Panels.OfType().Where(p => p.Item != null)) + updateVisibleBeatmaps((GroupedBeatmapSet)item.Item!.Model, item); } private void selectRecommendedDifficultyForBeatmapSet(GroupedBeatmapSet set) @@ -959,13 +962,24 @@ protected override Drawable GetDrawableForDisplay(CarouselItem item) return beatmapPanelPool.Get(); - case GroupedBeatmapSet: - return setPanelPool.Get(); + case GroupedBeatmapSet groupedBeatmapSet: + var setPanel = setPanelPool.Get(); + updateVisibleBeatmaps(groupedBeatmapSet, setPanel); + return setPanel; } throw new InvalidOperationException(); } + private void updateVisibleBeatmaps(GroupedBeatmapSet groupedBeatmapSet, PanelBeatmapSet setPanel) + { + HashSet visibleBeatmaps = []; + if (grouping.SetItems.TryGetValue(groupedBeatmapSet, out var visibleItems)) + visibleBeatmaps = visibleItems.Where(i => i.Model is GroupedBeatmap).Select(i => ((GroupedBeatmap)i.Model).Beatmap).ToHashSet(); + + setPanel.VisibleBeatmaps.Value = visibleBeatmaps; + } + #endregion #region Random selection handling diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs index 177d7c716274..3023471ee59c 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.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.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -24,6 +25,8 @@ public partial class PanelBeatmapSet public partial class SpreadDisplay : OsuAnimatedButton { public Bindable BeatmapSet { get; } = new Bindable(); + public Bindable?> VisibleBeatmaps { get; } = new Bindable?>(); + public BindableBool Expanded { get; } = new BindableBool(); private readonly Bindable scopedBeatmapSet = new Bindable(); @@ -67,7 +70,7 @@ private void load(ISongSelect? songSelect, OsuConfigManager configManager) AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, Direction = FillDirection.Horizontal, - Spacing = new Vector2(2), + Spacing = new Vector2(1), }, countText = new OsuSpriteText { @@ -97,6 +100,7 @@ protected override void LoadComplete() base.LoadComplete(); BeatmapSet.BindValueChanged(_ => updateBeatmapSet()); + VisibleBeatmaps.BindValueChanged(_ => updateBeatmapSet()); showConvertedBeatmaps.BindValueChanged(_ => updateBeatmapSet(), true); Expanded.BindValueChanged(_ => updateEnabled()); scopedBeatmapSet.BindValueChanged(_ => updateEnabled(), true); @@ -114,30 +118,31 @@ private void updateBeatmapSet() flow.Clear(); - var starDifficulties = BeatmapSet.Value.Beatmaps - .Where(b => b.AllowGameplayWithRuleset(ruleset.Value, showConvertedBeatmaps.Value)) - .OrderBy(b => b.Ruleset.OnlineID) - .ThenBy(b => b.StarRating) - .Select(b => b.StarRating) - .ToList(); - this.FadeTo(starDifficulties.Count > 0 ? 1 : 0, transition_duration, Easing.OutQuint); + var beatmaps = BeatmapSet.Value.Beatmaps + .Where(b => b.AllowGameplayWithRuleset(ruleset.Value, showConvertedBeatmaps.Value)) + .OrderBy(b => b.Ruleset.OnlineID) + .ThenBy(b => b.StarRating) + .ToList(); + this.FadeTo(beatmaps.Count > 0 ? 1 : 0, transition_duration, Easing.OutQuint); - if (starDifficulties.Count == 0) + if (beatmaps.Count == 0) return; // TODO: figure overflow later - foreach (double starDifficulty in starDifficulties) + foreach (var beatmap in beatmaps) { + bool visible = VisibleBeatmaps.Value?.Contains(beatmap) != false; + var circle = new Circle { - Size = new Vector2(5, 10), + Size = visible ? new Vector2(7, 12) : new Vector2(5, 10), + Alpha = visible ? 1 : 0.5f, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Colour = colours.ForStarDifficulty(starDifficulty) + Colour = colours.ForStarDifficulty(beatmap.StarRating) }; flow.Add(circle); - flow.SetLayoutPosition(circle, (float)starDifficulty); } Action = () => scopedBeatmapSet.Value = BeatmapSet.Value; diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs index 95262e16e1c4..fb31d7a790dc 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs @@ -38,6 +38,8 @@ public partial class PanelBeatmapSet : Panel { public const float HEIGHT = CarouselItem.DEFAULT_HEIGHT * 1.6f; + public Bindable?> VisibleBeatmaps { get; } = new Bindable?>(); + private Box chevronBackground = null!; private PanelSetBackground setBackground = null!; private ScheduledDelegate? scheduledBackgroundRetrieval; @@ -155,7 +157,8 @@ private void load() { Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, - Expanded = { BindTarget = Expanded } + Expanded = { BindTarget = Expanded }, + VisibleBeatmaps = { BindTarget = VisibleBeatmaps }, }, }, } From e2ed5208fec1a489e0242a8ab49c200be8bd4393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 30 Dec 2025 11:42:41 +0100 Subject: [PATCH 373/836] Bring back ruleset grouping & overflow handling to spread display --- .../SelectV2/PanelBeatmapSet.SpreadDisplay.cs | 93 +++++++++++++++---- 1 file changed, 73 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs index 3023471ee59c..e7ecc9ceb796 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs @@ -5,11 +5,13 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics; @@ -40,8 +42,10 @@ public partial class SpreadDisplay : OsuAnimatedButton [Resolved] private OsuColour colours { get; set; } = null!; + [Resolved] + private RulesetStore rulesets { get; set; } = null!; + private FillFlowContainer flow = null!; - private OsuSpriteText countText = null!; // TODO private SpriteIcon icon = null!; public SpreadDisplay() @@ -72,12 +76,6 @@ private void load(ISongSelect? songSelect, OsuConfigManager configManager) Direction = FillDirection.Horizontal, Spacing = new Vector2(1), }, - countText = new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.Style.Caption2, - }, icon = new SpriteIcon { Size = new Vector2(12), @@ -118,31 +116,86 @@ private void updateBeatmapSet() flow.Clear(); + const int max_difficulties_before_collapsing = 12; + var beatmaps = BeatmapSet.Value.Beatmaps .Where(b => b.AllowGameplayWithRuleset(ruleset.Value, showConvertedBeatmaps.Value)) - .OrderBy(b => b.Ruleset.OnlineID) - .ThenBy(b => b.StarRating) .ToList(); this.FadeTo(beatmaps.Count > 0 ? 1 : 0, transition_duration, Easing.OutQuint); if (beatmaps.Count == 0) return; - // TODO: figure overflow later + bool showVisible = VisibleBeatmaps.Value == null || VisibleBeatmaps.Value?.Count <= max_difficulties_before_collapsing; + bool showHidden = beatmaps.Count <= max_difficulties_before_collapsing; - foreach (var beatmap in beatmaps) + var beatmapsByRuleset = beatmaps.GroupBy(beatmap => beatmap.Ruleset.OnlineID).OrderBy(group => group.Key); + + foreach (var rulesetGrouping in beatmapsByRuleset) { - bool visible = VisibleBeatmaps.Value?.Contains(beatmap) != false; + int rulesetId = rulesetGrouping.Key; + var rulesetIcon = rulesets.GetRuleset(rulesetId)?.CreateInstance().CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle }; + flow.Add(rulesetIcon.With(i => + { + i.Size = new Vector2(14); + i.Anchor = i.Origin = Anchor.CentreLeft; + i.Margin = new MarginPadding { Left = flow.Count > 0 ? 9 : 0 }; + })); - var circle = new Circle + int overflowVisible = 0; + int overflowHidden = 0; + bool? lastBeatmapVisible = null; + + foreach (var beatmap in rulesetGrouping.OrderBy(beatmap => beatmap.StarRating)) { - Size = visible ? new Vector2(7, 12) : new Vector2(5, 10), - Alpha = visible ? 1 : 0.5f, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Colour = colours.ForStarDifficulty(beatmap.StarRating) - }; - flow.Add(circle); + bool visible = VisibleBeatmaps.Value?.Contains(beatmap) != false; + + if ((visible && showVisible) || (!visible && showHidden)) + { + var circle = new Circle + { + Size = visible ? new Vector2(7, 12) : new Vector2(5, 10), + Alpha = visible ? 1 : 0.5f, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Colour = colours.ForStarDifficulty(beatmap.StarRating), + Margin = new MarginPadding { Left = lastBeatmapVisible != null && lastBeatmapVisible != visible ? 1 : 0 } + }; + flow.Add(circle); + + lastBeatmapVisible = visible; + } + else + { + if (visible) + overflowVisible++; + else + overflowHidden++; + } + } + + if (overflowVisible > 0) + { + flow.Add(new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.Style.Caption2, + Text = overflowVisible.ToLocalisableString(), + }); + } + + if (overflowHidden > 0) + { + flow.Add(new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.Style.Caption2, + Text = LocalisableString.Interpolate($@"+{overflowHidden}"), + Alpha = 0.7f, + }); + } } Action = () => scopedBeatmapSet.Value = BeatmapSet.Value; From ebb898f67cb18214ad59050a18b00f22630a2963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 30 Dec 2025 12:30:47 +0100 Subject: [PATCH 374/836] Add test case --- .../TestSceneSongSelectFiltering.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs index e5d537d84e87..a83ec3377821 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs @@ -379,6 +379,25 @@ public void TestScopeToBeatmapWhenDifficultiesSplitApart() checkMatchedBeatmaps(6); } + [Test] + public void TestScopeToBeatmapWhenDifficultiesGroupedBySet() + { + ImportBeatmapForRuleset(0); + ImportBeatmapForRuleset(0); + + LoadSongSelect(); + SortBy(SortMode.Artist); + checkMatchedBeatmaps(6); + + AddStep("click spread indicator", () => this.ChildrenOfType().Single(d => d.Enabled.Value).TriggerClick()); + WaitForFiltering(); + checkMatchedBeatmaps(3); + + AddStep("press Escape", () => InputManager.Key(Key.Escape)); + WaitForFiltering(); + checkMatchedBeatmaps(6); + } + private NoResultsPlaceholder? getPlaceholder() => SongSelect.ChildrenOfType().FirstOrDefault(); private void checkMatchedBeatmaps(int expected) => AddUntilStep($"{expected} matching shown", () => Carousel.MatchedBeatmapsCount, () => Is.EqualTo(expected)); From 24a0de1020c6cb3bb5fdda1926303f4f036d7472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 30 Dec 2025 13:40:27 +0100 Subject: [PATCH 375/836] Allow clicking anywhere on the scoped beatmap set indicator to dismiss it --- .../FilterControl.ScopedBeatmapSetDisplay.cs | 47 +++++++++++++------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs b/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs index d09c0ff3e312..650ef4a1a99b 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs +++ b/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.SelectV2 { public partial class FilterControl { - public partial class ScopedBeatmapSetDisplay : CompositeDrawable, IKeyBindingHandler + public partial class ScopedBeatmapSetDisplay : OsuClickableContainer, IKeyBindingHandler { public Bindable ScopedBeatmapSet { @@ -29,20 +29,27 @@ public Bindable ScopedBeatmapSet } private readonly BindableWithCurrent scopedBeatmapSet = new BindableWithCurrent(); + private Box flashLayer = null!; private Container content = null!; private OsuTextFlowContainer text = null!; - private ShearedButton goBackButton = null!; - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private const float transition_duration = 300; + + public ScopedBeatmapSetDisplay() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - AutoSizeEasing = Easing.OutQuint; - AutoSizeDuration = 200; CornerRadius = 8f; Masking = true; - InternalChildren = new Drawable[] + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Content.AutoSizeEasing = Easing.OutQuint; + Content.AutoSizeDuration = transition_duration; + + AddRange(new Drawable[] { new Box { @@ -71,18 +78,26 @@ private void load(OverlayColourProvider colourProvider) Colour = colourProvider.Background6, Padding = new MarginPadding { Right = 80, Vertical = 5 } }, - goBackButton = new ShearedButton(80) + new ShearedButton(80) { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Text = CommonStrings.Back, RelativeSizeAxes = Axes.Y, Height = 1, - Action = () => scopedBeatmapSet.Value = null, + Action = () => Action?.Invoke(), } } - } - }; + }, + flashLayer = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Colour4.White, + Blending = BlendingParameters.Additive, + Alpha = 0, + }, + }); + Action = () => scopedBeatmapSet.Value = null; } protected override void LoadComplete() @@ -94,22 +109,26 @@ protected override void LoadComplete() private void updateState() { - content.BypassAutoSizeAxes = scopedBeatmapSet.Value != null ? Axes.None : Axes.Y; - if (scopedBeatmapSet.Value != null) { + content.BypassAutoSizeAxes = Axes.None; text.Clear(); text.AddText(SongSelectStrings.TemporarilyShowingAllBeatmapsIn); text.AddText(@" "); text.AddText(scopedBeatmapSet.Value.Metadata.GetDisplayTitleRomanisable(), t => t.Font = OsuFont.Style.Body.With(weight: FontWeight.Bold)); } + else + { + flashLayer.FadeOutFromOne(transition_duration, Easing.OutQuint); + content.BypassAutoSizeAxes = Axes.Y; + } } public bool OnPressed(KeyBindingPressEvent e) { if (scopedBeatmapSet.Value != null && e.Action == GlobalAction.Back && !e.Repeat) { - goBackButton.TriggerClick(); + TriggerClick(); return true; } From 853836a48bb8dd232e94d3398977a74d0f5d9b7d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Dec 2025 23:16:08 +0900 Subject: [PATCH 376/836] Fix editor seeks not being debounced enough Could lead to huge slowdowns when running multi-threaded and performing a long drag. --- .../Timelines/Summary/Parts/MarkerPart.cs | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs index d3d5de389e32..1fedd6f589af 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -63,16 +63,24 @@ protected override bool OnMouseDown(MouseDownEvent e) /// Whether the seek should be instant (drag end, mouse button press) or debounced (drag in progress). private void seekToPosition(Vector2 screenPosition, bool instant) { - float markerPos = Math.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth); - double seekDestination = markerPos / DrawWidth * editorClock.TrackLength; - marker.X = (float)seekDestination; + // Debounce seeks to ensure we only run one per update frame at most. + // + // Without this, we could end up seeking 1000+ times per second, leading to + // unexpected performance overheads as the editor tries to prepare for displaying + // each of the destinations. + Scheduler.AddOnce(data => + { + float markerPos = Math.Clamp(ToLocalSpace(data.screenPosition).X, 0, DrawWidth); + double seekDestination = markerPos / DrawWidth * editorClock.TrackLength; + marker.X = (float)seekDestination; - if (editorClock.IsRunning && !instant && lastSeekTime != null && Time.Current - lastSeekTime < NowPlayingOverlay.TRACK_DRAG_SEEK_DEBOUNCE) - return; + if (editorClock.IsRunning && !data.instant && lastSeekTime != null && Time.Current - lastSeekTime < NowPlayingOverlay.TRACK_DRAG_SEEK_DEBOUNCE) + return; - editorClock.Seek(seekDestination); + editorClock.Seek(seekDestination); - lastSeekTime = instant ? null : Time.Current; + lastSeekTime = data.instant ? null : Time.Current; + }, (screenPosition, instant)); } protected override void Update() From a23024d80e6790edbf9821ebf6a35cf2b1957e75 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Tue, 30 Dec 2025 18:54:28 +0300 Subject: [PATCH 377/836] Display an old-style notification if multiple users should be displayed --- osu.Game/Online/FriendPresenceNotifier.cs | 94 ++++++++++++------- .../Notifications/UserAvatarNotification.cs | 9 +- 2 files changed, 64 insertions(+), 39 deletions(-) diff --git a/osu.Game/Online/FriendPresenceNotifier.cs b/osu.Game/Online/FriendPresenceNotifier.cs index 5ba5b48e59ae..f8e9189ec92f 100644 --- a/osu.Game/Online/FriendPresenceNotifier.cs +++ b/osu.Game/Online/FriendPresenceNotifier.cs @@ -158,7 +158,13 @@ private void alertOnlineUsers() return; } - notifications.Post(new FriendOnlineNotification(onlineAlertQueue.ToArray())); + var users = onlineAlertQueue.ToArray(); + + notifications.Post(users.Length switch + { + 1 => new SingleFriendOnlineNotification(users.Single()), + _ => new MultipleFriendsOnlineNotification(users), + }); onlineAlertQueue.Clear(); lastOnlineAlertTime = null; @@ -178,60 +184,84 @@ private void alertOfflineUsers() return; } - notifications.Post(new FriendOfflineNotification(offlineAlertQueue.ToArray())); + var users = offlineAlertQueue.ToArray(); + + notifications.Post(users.Length switch + { + 1 => new SingleFriendOfflineNotification(users.Single()), + _ => new MultipleFriendsOfflineNotification(users), + }); offlineAlertQueue.Clear(); lastOfflineAlertTime = null; } - public partial class FriendOnlineNotification : UserAvatarNotification + public partial class SingleFriendOnlineNotification : UserAvatarNotification { - private readonly ICollection users; - - public FriendOnlineNotification(ICollection users) - : base(users.Count == 1 ? users.Single() : null) + public SingleFriendOnlineNotification(APIUser user) + : base(user) { - this.users = users; - Transient = true; IsImportant = false; - Text = $"Online: {string.Join(@", ", users.Select(u => u.Username))}"; + Text = $"Online: {User.Username}"; } [BackgroundDependencyLoader] - private void load(OsuColour colours, ChannelManager channelManager, ChatOverlay chatOverlay) + private void load(ChannelManager channelManager, ChatOverlay chatOverlay) { - if (users.Count > 1) + Activated = () => { - Icon = FontAwesome.Solid.User; - IconColour = colours.GrayD; - } - else - { - Activated = () => - { - channelManager.OpenPrivateChannel(users.Single()); - chatOverlay.Show(); + channelManager.OpenPrivateChannel(User); + chatOverlay.Show(); - return true; - }; - } + return true; + }; } public override string PopInSampleName => "UI/notification-friend-online"; } - public partial class FriendOfflineNotification : UserAvatarNotification + public partial class MultipleFriendsOnlineNotification : SimpleNotification { - private readonly ICollection users; + public MultipleFriendsOnlineNotification(ICollection users) + { + Text = $"Online: {string.Join(@", ", users.Select(u => u.Username))}"; + } - public FriendOfflineNotification(ICollection users) - : base(users.Count == 1 ? users.Single() : null) + [BackgroundDependencyLoader] + private void load(OsuColour colours) { - this.users = users; + Icon = FontAwesome.Solid.User; + IconColour = colours.Green; + } + public override string PopInSampleName => "UI/notification-friend-online"; + } + + public partial class SingleFriendOfflineNotification : UserAvatarNotification + { + public SingleFriendOfflineNotification(APIUser user) + : base(user) + { Transient = true; IsImportant = false; + Text = $"Offline: {User.Username}"; + } + + [BackgroundDependencyLoader] + private void load() + { + Icon = FontAwesome.Solid.UserSlash; + Avatar.Colour = Color4.White.Opacity(0.25f); + } + + public override string PopInSampleName => "UI/notification-friend-offline"; + } + + public partial class MultipleFriendsOfflineNotification : SimpleNotification + { + public MultipleFriendsOfflineNotification(ICollection users) + { Text = $"Offline: {string.Join(@", ", users.Select(u => u.Username))}"; } @@ -239,11 +269,7 @@ public FriendOfflineNotification(ICollection users) private void load(OsuColour colours) { Icon = FontAwesome.Solid.UserSlash; - - if (users.Count == 1) - Avatar.Colour = Color4.White.Opacity(0.25f); - else - IconColour = colours.Gray3; + IconColour = colours.Red; } public override string PopInSampleName => "UI/notification-friend-offline"; diff --git a/osu.Game/Overlays/Notifications/UserAvatarNotification.cs b/osu.Game/Overlays/Notifications/UserAvatarNotification.cs index fcc1d59dde6b..8ea79623c7f7 100644 --- a/osu.Game/Overlays/Notifications/UserAvatarNotification.cs +++ b/osu.Game/Overlays/Notifications/UserAvatarNotification.cs @@ -12,14 +12,13 @@ namespace osu.Game.Overlays.Notifications { public abstract partial class UserAvatarNotification : SimpleNotification { - private readonly APIUser? user; + protected readonly APIUser User; protected DrawableAvatar Avatar { get; private set; } = null!; - protected UserAvatarNotification(APIUser? user, LocalisableString text = default) + protected UserAvatarNotification(APIUser user, LocalisableString text = default) { - this.user = user; - + User = user; Icon = default; Text = text; } @@ -31,7 +30,7 @@ private void load() IconContent.CornerRadius = CORNER_RADIUS; IconContent.ChangeChildDepth(IconDrawable, float.MinValue); - LoadComponentAsync(Avatar = new DrawableAvatar(user) + LoadComponentAsync(Avatar = new DrawableAvatar(User) { FillMode = FillMode.Fill, }, IconContent.Add); From dad138223b9937138c210e8a6e23675a1c2343df Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Tue, 30 Dec 2025 19:36:43 +0300 Subject: [PATCH 378/836] Small refactoring --- osu.Game/Online/FriendPresenceNotifier.cs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/osu.Game/Online/FriendPresenceNotifier.cs b/osu.Game/Online/FriendPresenceNotifier.cs index f8e9189ec92f..53c8ff7b5a81 100644 --- a/osu.Game/Online/FriendPresenceNotifier.cs +++ b/osu.Game/Online/FriendPresenceNotifier.cs @@ -158,13 +158,10 @@ private void alertOnlineUsers() return; } - var users = onlineAlertQueue.ToArray(); - - notifications.Post(users.Length switch - { - 1 => new SingleFriendOnlineNotification(users.Single()), - _ => new MultipleFriendsOnlineNotification(users), - }); + if (onlineAlertQueue.Count == 1) + notifications.Post(new SingleFriendOnlineNotification(onlineAlertQueue.Single())); + else + notifications.Post(new MultipleFriendsOnlineNotification(onlineAlertQueue.ToArray())); onlineAlertQueue.Clear(); lastOnlineAlertTime = null; @@ -184,13 +181,10 @@ private void alertOfflineUsers() return; } - var users = offlineAlertQueue.ToArray(); - - notifications.Post(users.Length switch - { - 1 => new SingleFriendOfflineNotification(users.Single()), - _ => new MultipleFriendsOfflineNotification(users), - }); + if (offlineAlertQueue.Count == 1) + notifications.Post(new SingleFriendOfflineNotification(offlineAlertQueue.Single())); + else + notifications.Post(new MultipleFriendsOfflineNotification(offlineAlertQueue.ToArray())); offlineAlertQueue.Clear(); lastOfflineAlertTime = null; From 1cf14952de28ec111d2356cf0e4e8cda9e1cb697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 31 Dec 2025 09:25:42 +0100 Subject: [PATCH 379/836] Privatise setter of weirdly exposed field --- osu.Game/Screens/Edit/ExternalEditScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/ExternalEditScreen.cs b/osu.Game/Screens/Edit/ExternalEditScreen.cs index e906d748553f..19d8a7f46c5d 100644 --- a/osu.Game/Screens/Edit/ExternalEditScreen.cs +++ b/osu.Game/Screens/Edit/ExternalEditScreen.cs @@ -48,7 +48,7 @@ internal partial class ExternalEditScreen : OsuScreen private Task? fileMountOperation; - public ExternalEditOperation? EditOperation; + public ExternalEditOperation? EditOperation { get; private set; } private FillFlowContainer flow = null!; From 9f40d630dc593bce5db3613b1a625bcc0c8fa0f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 31 Dec 2025 09:26:00 +0100 Subject: [PATCH 380/836] Do not allow multiple concurrent finishes of external beatmap edit --- osu.Game/Screens/Edit/ExternalEditScreen.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/ExternalEditScreen.cs b/osu.Game/Screens/Edit/ExternalEditScreen.cs index 19d8a7f46c5d..baaff20c2b34 100644 --- a/osu.Game/Screens/Edit/ExternalEditScreen.cs +++ b/osu.Game/Screens/Edit/ExternalEditScreen.cs @@ -50,6 +50,8 @@ internal partial class ExternalEditScreen : OsuScreen public ExternalEditOperation? EditOperation { get; private set; } + private Task? finishOperation; + private FillFlowContainer flow = null!; [BackgroundDependencyLoader] @@ -98,11 +100,15 @@ public override bool OnExiting(ScreenExitEvent e) if (fileMountOperation?.IsCompleted == false) return true; + // Similarly do not allow interrupting an ongoing finish. + if (finishOperation?.IsCompleted == false) + return true; + // If the operation completed successfully, ensure that we finish the operation before exiting. // The finish() call will subsequently call Exit() when done. - if (EditOperation != null) + if (EditOperation != null && finishOperation == null) { - finish().FireAndForget(); + (finishOperation = finish()).FireAndForget(); return true; } @@ -161,7 +167,7 @@ private async Task begin() Width = 350, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Action = () => finish().FireAndForget(), + Action = () => (finishOperation = finish()).FireAndForget(), Enabled = { Value = false } } }; From 7e823af70b0dfafc597ae6a1c9496998a407a273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 31 Dec 2025 09:26:08 +0100 Subject: [PATCH 381/836] Hide back button when finishing external edit --- osu.Game/Screens/Edit/ExternalEditScreen.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Edit/ExternalEditScreen.cs b/osu.Game/Screens/Edit/ExternalEditScreen.cs index baaff20c2b34..ef72c7e1b8af 100644 --- a/osu.Game/Screens/Edit/ExternalEditScreen.cs +++ b/osu.Game/Screens/Edit/ExternalEditScreen.cs @@ -191,6 +191,7 @@ private void openDirectory() private async Task finish() { + BackButtonVisibility.Value = false; string originalDifficulty = editor.Beatmap.Value.Beatmap.BeatmapInfo.DifficultyName; showSpinner("Cleaning up..."); From a6545bea684b40addb800cc3aec6d7c77934816b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 31 Dec 2025 10:05:59 +0100 Subject: [PATCH 382/836] Remove dim effect from disabled spread displays on song select panels --- osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs | 6 +++--- osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs | 2 ++ .../SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs index 9eda0654951a..f77d00e6e76a 100644 --- a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs @@ -92,12 +92,12 @@ protected override void LoadComplete() { base.LoadComplete(); - Colour = dimColour; - Enabled.BindValueChanged(_ => this.FadeColour(dimColour, 200, Easing.OutQuint), true); + Colour = Enabled.Value ? Colour4.White : DimColour; + Enabled.BindValueChanged(_ => this.FadeColour(DimColour, 200, Easing.OutQuint), true); FinishTransforms(true); } - private Color4 dimColour => Enabled.Value ? Color4.White : colours.Gray9; + protected virtual Colour4 DimColour => colours.Gray9; protected override bool OnHover(HoverEvent e) { diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs index e7ecc9ceb796..4cbe4521bb00 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs @@ -31,6 +31,8 @@ public partial class SpreadDisplay : OsuAnimatedButton public BindableBool Expanded { get; } = new BindableBool(); + protected override Colour4 DimColour => Colour4.White; + private readonly Bindable scopedBeatmapSet = new Bindable(); private readonly Bindable showConvertedBeatmaps = new Bindable(); diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs index 32a48996a707..b3fa2fa01e79 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs @@ -27,6 +27,8 @@ public partial class SpreadDisplay : OsuAnimatedButton public Bindable Beatmap { get; } = new Bindable(); public Bindable StarDifficulty { get; } = new Bindable(); + protected override Colour4 DimColour => Colour4.White; + private readonly Bindable scopedBeatmapSet = new Bindable(); private readonly Bindable showConvertedBeatmaps = new Bindable(); From 334a54e6f72edcea66f45e2ee8993d85a19eebba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 22 Dec 2025 13:21:59 +0100 Subject: [PATCH 383/836] Add way to add/remove custom beatmap samples to setup screen Among others, this features a scary-looking change wherein `WorkingBeatmap` now exposes a `RealmAccess` via `IStorageResourceProvider`. This is necessary to make `RealmBackedResourceStore` actually start firing callbacks when the edited beatmap's skin is modified by adding new samples to it. --- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- osu.Game/Beatmaps/WorkingBeatmapCache.cs | 6 +- .../Screens/Edit/Components/FormSampleSet.cs | 19 ++- osu.Game/Screens/Edit/EditorBeatmap.cs | 10 +- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 51 +++++-- .../Edit/Setup/FormSampleSetChooser.cs | 144 ++++++++++++++++++ .../Screens/Edit/Setup/ResourcesSection.cs | 24 +++ osu.Game/Skinning/LegacyBeatmapSkin.cs | 2 + osu.Game/Skinning/RealmBackedResourceStore.cs | 8 +- osu.Game/Skinning/Skin.cs | 3 + 10 files changed, 248 insertions(+), 21 deletions(-) create mode 100644 osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index d50862a36970..c67c5521d356 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -95,7 +95,7 @@ public BeatmapManager(Storage storage, RealmAccess realm, IAPIProvider? api, Aud protected virtual WorkingBeatmapCache CreateWorkingBeatmapCache(AudioManager audioManager, IResourceStore resources, IResourceStore storage, WorkingBeatmap? defaultBeatmap, GameHost? host) { - return new WorkingBeatmapCache(BeatmapTrackStore, audioManager, resources, storage, defaultBeatmap, host); + return new WorkingBeatmapCache(BeatmapTrackStore, audioManager, resources, storage, defaultBeatmap, host, Realm); } protected virtual BeatmapImporter CreateBeatmapImporter(Storage storage, RealmAccess realm) => new BeatmapImporter(storage, realm); diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs index 9957935977b9..0bb61798dc94 100644 --- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs +++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs @@ -47,12 +47,13 @@ public class WorkingBeatmapCache : IBeatmapResourceProvider, IWorkingBeatmapCach private readonly LargeTextureStore beatmapPanelTextureStore; private readonly ITrackStore trackStore; private readonly IResourceStore files; + private readonly RealmAccess realm; [CanBeNull] private readonly GameHost host; public WorkingBeatmapCache(ITrackStore trackStore, AudioManager audioManager, IResourceStore resources, IResourceStore files, WorkingBeatmap defaultBeatmap = null, - GameHost host = null) + GameHost host = null, RealmAccess realm = null) { DefaultBeatmap = defaultBeatmap; @@ -63,6 +64,7 @@ public WorkingBeatmapCache(ITrackStore trackStore, AudioManager audioManager, IR largeTextureStore = new LargeTextureStore(host?.Renderer ?? new DummyRenderer(), host?.CreateTextureLoaderStore(files)); beatmapPanelTextureStore = new LargeTextureStore(host?.Renderer ?? new DummyRenderer(), new BeatmapPanelBackgroundTextureLoaderStore(host?.CreateTextureLoaderStore(files))); this.trackStore = trackStore; + this.realm = realm; } public void Invalidate(BeatmapSetInfo info) @@ -118,7 +120,7 @@ public virtual WorkingBeatmap GetWorkingBeatmap([CanBeNull] BeatmapInfo beatmapI ITrackStore IBeatmapResourceProvider.Tracks => trackStore; IRenderer IStorageResourceProvider.Renderer => host?.Renderer ?? new DummyRenderer(); AudioManager IStorageResourceProvider.AudioManager => audioManager; - RealmAccess IStorageResourceProvider.RealmAccess => null!; + RealmAccess IStorageResourceProvider.RealmAccess => realm; IResourceStore IStorageResourceProvider.Files => files; IResourceStore IStorageResourceProvider.Resources => resources; IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host?.CreateTextureLoaderStore(underlyingStore); diff --git a/osu.Game/Screens/Edit/Components/FormSampleSet.cs b/osu.Game/Screens/Edit/Components/FormSampleSet.cs index 50c0532c022e..f2d31dea060f 100644 --- a/osu.Game/Screens/Edit/Components/FormSampleSet.cs +++ b/osu.Game/Screens/Edit/Components/FormSampleSet.cs @@ -42,7 +42,7 @@ public Bindable Current set => current.Current = value; } - public Func? SampleAddRequested { get; init; } + public Func? SampleAddRequested { get; init; } public Action? SampleRemoveRequested { get; init; } private readonly BindableWithCurrent current = new BindableWithCurrent(); @@ -194,7 +194,7 @@ public partial class SampleButton : OsuButton, IHasPopover, IHasContextMenu /// /// Invoked when a new sample is selected via this button. /// - public Func? SampleAddRequested { get; init; } + public Func? SampleAddRequested { get; init; } /// /// Invoked when a sample removal is selected via this button. @@ -294,7 +294,18 @@ private void recycleSamples() AddInternal(hoverSounds = (ActualFilename.Value == null ? new HoverClickSounds(HoverSampleSet.Button) : new HoverSounds(HoverSampleSet.Button))); - sample = ActualFilename.Value == null ? null : editorBeatmap?.BeatmapSkin?.Skin.Samples?.Get(ActualFilename.Value); + if (ActualFilename.Value != null) + { + // to cover all bases, invalidate the extensionless filename (which gameplay is most likely to use) + // as well as the filename with extension (which we are using here). + editorBeatmap?.BeatmapSkin?.Skin.Samples?.Invalidate(ExpectedFilename.Value); + editorBeatmap?.BeatmapSkin?.Skin.Samples?.Invalidate(ActualFilename.Value); + sample = editorBeatmap?.BeatmapSkin?.Skin.Samples?.Get(ActualFilename.Value); + } + else + { + sample = null; + } } protected override bool OnHover(HoverEvent e) @@ -317,7 +328,7 @@ private void addSample() return; this.HidePopover(); - ActualFilename.Value = SampleAddRequested?.Invoke(selectedFile.Value) ?? selectedFile.Value.ToString(); + ActualFilename.Value = SampleAddRequested?.Invoke(selectedFile.Value, ExpectedFilename.Value) ?? selectedFile.Value.ToString(); } private void deleteSample() diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 91ae4593dd61..248779a9f8f2 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -101,9 +101,9 @@ public EditorBeatmap(IBeatmap playableBeatmap, ISkin beatmapSkin = null, Beatmap this.beatmapInfo = beatmapInfo ?? playableBeatmap.BeatmapInfo; - if (beatmapSkin is Skin skin) + if (beatmapSkin is LegacyBeatmapSkin skin) { - BeatmapSkin = new EditorBeatmapSkin(skin); + BeatmapSkin = new EditorBeatmapSkin(playableBeatmap.BeatmapInfo!.BeatmapSet!, skin); BeatmapSkin.BeatmapSkinChanged += SaveState; } @@ -532,5 +532,11 @@ private int findInsertionIndex(IReadOnlyList list, double startTime) public double GetBeatLengthAtTime(double referenceTime) => ControlPointInfo.TimingPointAt(referenceTime).BeatLength / BeatDivisor; public int BeatDivisor => beatDivisor?.Value ?? 1; + + protected override void Dispose(bool isDisposing) + { + BeatmapSkin?.Dispose(); + base.Dispose(isDisposing); + } } } diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 531f77d238aa..0fbfb7b2d0a9 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Game.Audio; +using osu.Game.Beatmaps; using osu.Game.Skinning; using osuTK.Graphics; @@ -18,14 +19,14 @@ namespace osu.Game.Screens.Edit /// /// A beatmap skin which is being edited. /// - public class EditorBeatmapSkin : ISkin + public class EditorBeatmapSkin : ISkin, IDisposable { public event Action? BeatmapSkinChanged; /// /// The underlying beatmap skin. /// - protected internal readonly Skin Skin; + protected internal readonly LegacyBeatmapSkin Skin; /// /// The combo colours of this skin. @@ -33,7 +34,7 @@ public class EditorBeatmapSkin : ISkin /// public BindableList ComboColours { get; } - public EditorBeatmapSkin(Skin skin) + public EditorBeatmapSkin(BeatmapSetInfo beatmapSet, LegacyBeatmapSkin skin) { Skin = skin; @@ -50,9 +51,14 @@ public EditorBeatmapSkin(Skin skin) } ComboColours.BindCollectionChanged((_, _) => updateColours()); + + if (skin.BeatmapSetResources != null) + skin.BeatmapSetResources.CacheInvalidated += InvokeSkinChanged; } - private void invokeSkinChanged() => BeatmapSkinChanged?.Invoke(); + public void InvokeSkinChanged() => BeatmapSkinChanged?.Invoke(); + + #region Combo colours private void updateColours() { @@ -60,9 +66,13 @@ private void updateColours() Skin.Configuration.CustomComboColours.Clear(); for (int i = 0; i < ComboColours.Count; ++i) Skin.Configuration.CustomComboColours.Add(ComboColours[(ComboColours.Count + i - 1) % ComboColours.Count]); - invokeSkinChanged(); + InvokeSkinChanged(); } + #endregion + + #region Sample sets + public record SampleSet(int SampleSetIndex, string Name) { public SampleSet(int sampleSetIndex) @@ -88,7 +98,7 @@ public IEnumerable GetAvailableSampleSets() string[] possiblePrefixes = possibleSounds.SelectMany(sound => possibleBanks.Select(bank => $@"{bank}-{sound}")).ToArray(); - HashSet indices = new HashSet(); + Dictionary sampleSets = new Dictionary(); if (Skin.Samples != null) { @@ -96,19 +106,38 @@ public IEnumerable GetAvailableSampleSets() { foreach (string possiblePrefix in possiblePrefixes) { - if (!sample.StartsWith(possiblePrefix, StringComparison.InvariantCultureIgnoreCase)) + if (!sample.StartsWith(possiblePrefix, StringComparison.Ordinal)) continue; string indexString = Path.GetFileNameWithoutExtension(sample)[possiblePrefix.Length..]; + int? index = null; + if (string.IsNullOrEmpty(indexString)) - indices.Add(1); - if (int.TryParse(indexString, out int index)) - indices.Add(index); + index = 1; + if (int.TryParse(indexString, out int parsed)) + index = parsed; + + if (!index.HasValue) + continue; + + SampleSet? sampleSet; + if (!sampleSets.TryGetValue(index.Value, out sampleSet)) + sampleSet = sampleSets[index.Value] = new SampleSet(index.Value); + + sampleSet.Filenames.Add(sample); } } } - return indices.OrderBy(i => i).Select(i => new SampleSet(i)); + return sampleSets.OrderBy(i => i.Key).Select(i => i.Value); + } + + #endregion + + public void Dispose() + { + if (Skin.BeatmapSetResources != null) + Skin.BeatmapSetResources.CacheInvalidated -= InvokeSkinChanged; } #region Delegated ISkin implementation diff --git a/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs b/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs new file mode 100644 index 000000000000..750586dfe31b --- /dev/null +++ b/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs @@ -0,0 +1,144 @@ +// 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.Globalization; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Graphics.UserInterfaceV2; + +namespace osu.Game.Screens.Edit.Setup +{ + public partial class FormSampleSetChooser : FormDropdown, IHasPopover + { + private EditorBeatmapSkin? beatmapSkin; + + public FormSampleSetChooser() + { + Caption = "Custom sample sets"; + } + + [BackgroundDependencyLoader] + private void load(EditorBeatmap editorBeatmap) + { + beatmapSkin = editorBeatmap.BeatmapSkin; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + populateItems(); + if (beatmapSkin != null) + beatmapSkin.BeatmapSkinChanged += populateItems; + + Current.Value = Items.FirstOrDefault(i => i?.SampleSetIndex > 0); + Current.BindValueChanged(val => + { + if (val.NewValue?.SampleSetIndex == -1) + this.ShowPopover(); + }); + } + + private void populateItems() + { + var items = beatmapSkin?.GetAvailableSampleSets().ToList() ?? []; + items.Add(new EditorBeatmapSkin.SampleSet(-1, "Add new...")); + Items = items; + } + + protected override LocalisableString GenerateItemText(EditorBeatmapSkin.SampleSet? item) + { + if (item == null) + return string.Empty; + + return base.GenerateItemText(item); + } + + public Popover GetPopover() => new NewSampleSetPopover( + Items.Any(i => i?.SampleSetIndex > 0) ? Items.Max(i => i!.SampleSetIndex) : 0, + idx => + { + if (idx == null) + { + Current.Value = Items.FirstOrDefault(i => i?.SampleSetIndex > 0); + return; + } + + if (Items.SingleOrDefault(i => i?.SampleSetIndex == idx) is EditorBeatmapSkin.SampleSet existing) + { + Current.Value = existing; + return; + } + + var sampleSet = new EditorBeatmapSkin.SampleSet(idx.Value, $@"Custom #{idx}"); + var newItems = Items.ToList(); + newItems.Insert(newItems.Count - 1, sampleSet); + Items = newItems; + Current.Value = sampleSet; + }); + + protected override void Dispose(bool isDisposing) + { + if (beatmapSkin != null) + beatmapSkin.BeatmapSkinChanged -= populateItems; + + base.Dispose(isDisposing); + } + + private partial class NewSampleSetPopover : OsuPopover + { + private readonly int currentLargestIndex; + private readonly Action onCommit; + + private int? committedIndex; + + private LabelledNumberBox numberBox = null!; + + public NewSampleSetPopover(int currentLargestIndex, Action onCommit) + { + this.currentLargestIndex = currentLargestIndex; + this.onCommit = onCommit; + } + + [BackgroundDependencyLoader] + private void load() + { + Child = numberBox = new LabelledNumberBox + { + RelativeSizeAxes = Axes.None, + Width = 250, + Label = "Sample set index", + Current = { Value = (currentLargestIndex + 1).ToString(CultureInfo.InvariantCulture) } + }; + numberBox.OnCommit += (_, _) => + { + committedIndex = int.Parse(numberBox.Current.Value); + Hide(); + }; + } + + protected override void OnFocus(FocusEvent e) + { + base.OnFocus(e); + // avoids infinite refocus loop + if (committedIndex == null) + GetContainingFocusManager()?.ChangeFocus(numberBox); + } + + public override void Hide() + { + if (State.Value == Visibility.Visible) + onCommit.Invoke(committedIndex > 0 ? committedIndex : null); + base.Hide(); + } + } + } +} diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index f52d865d5f62..8a55db8420cf 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -14,6 +14,7 @@ using osu.Game.Models; using osu.Game.Overlays; using osu.Game.Screens.Backgrounds; +using osu.Game.Screens.Edit.Components; using osu.Game.Utils; namespace osu.Game.Screens.Edit.Setup @@ -23,6 +24,8 @@ public partial class ResourcesSection : SetupSection private FormBeatmapFileSelector audioTrackChooser = null!; private FormBeatmapFileSelector backgroundChooser = null!; + private readonly Bindable currentSampleSet = new Bindable(); + public override LocalisableString Title => EditorSetupStrings.ResourcesHeader; [Resolved] @@ -65,6 +68,27 @@ private void load() Caption = EditorSetupStrings.AudioTrack, PlaceholderText = EditorSetupStrings.ClickToSelectTrack, }, + new FormSampleSetChooser + { + Current = { BindTarget = currentSampleSet }, + }, + new FormSampleSet + { + Current = { BindTarget = currentSampleSet }, + SampleAddRequested = (file, targetName) => + { + string actualFilename = string.Concat(targetName, file.Extension); + using var stream = file.OpenRead(); + beatmaps.AddFile(working.Value.BeatmapSetInfo, stream, actualFilename); + return actualFilename; + }, + SampleRemoveRequested = filename => + { + var file = working.Value.BeatmapSetInfo.GetFile(filename); + if (file != null) + beatmaps.DeleteFile(working.Value.BeatmapSetInfo, file); + } + }, }; backgroundChooser.PreviewContainer.Add(headerBackground); diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index e198d43be740..365652e6ad25 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -26,6 +26,8 @@ public class LegacyBeatmapSkin : LegacySkin // 2. https://github.com/peppy/osu-stable-reference/blob/dc0994645801010d4b628fff5ff79cd3c286ca83/osu!/Graphics/Textures/TextureManager.cs#L158-L196 (user skin textures lookup) protected override bool AllowHighResolutionSprites => false; + public RealmBackedResourceStore? BeatmapSetResources => FallbackStore as RealmBackedResourceStore; + /// /// Construct a new legacy beatmap skin instance. /// diff --git a/osu.Game/Skinning/RealmBackedResourceStore.cs b/osu.Game/Skinning/RealmBackedResourceStore.cs index 093248534918..36561e0d696f 100644 --- a/osu.Game/Skinning/RealmBackedResourceStore.cs +++ b/osu.Game/Skinning/RealmBackedResourceStore.cs @@ -16,6 +16,8 @@ namespace osu.Game.Skinning public class RealmBackedResourceStore : ResourceStore where T : RealmObject, IHasRealmFiles, IHasGuidPrimaryKey { + public event Action? CacheInvalidated; + private Lazy> fileToStoragePathMapping; private readonly Live liveSource; @@ -56,7 +58,11 @@ protected override IEnumerable GetFilenames(string name) private string? getPathForFile(string filename) => fileToStoragePathMapping.Value.GetValueOrDefault(filename.ToLowerInvariant()); - private void invalidateCache() => fileToStoragePathMapping = new Lazy>(initialiseFileCache); + private void invalidateCache() + { + fileToStoragePathMapping = new Lazy>(initialiseFileCache); + CacheInvalidated?.Invoke(); + } private Dictionary initialiseFileCache() => liveSource.PerformRead(source => { diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 3a0d0b16e563..8c287a010ee9 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -63,6 +63,8 @@ public abstract class Skin : IDisposable, ISkin public string Name { get; } + protected IResourceStore? FallbackStore { get; } + /// /// Construct a new skin. /// @@ -102,6 +104,7 @@ protected Skin(SkinInfo skin, IStorageResourceProvider? resources, IResourceStor SkinInfo = skin.ToLiveUnmanaged(); } + FallbackStore = fallbackStore; if (fallbackStore != null) store.AddStore(fallbackStore); From 28a6d6211c17ba10440fe4b164dfb4e9b3a9ef8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 31 Dec 2025 12:01:50 +0100 Subject: [PATCH 384/836] Manually fire editor save operations on skin change This is invariably a test fix but also a valid change to make in isolation. In short, the problem is thus: Now that the beatmap skin is hooked up to realm to receive notifications about changed files (which is required for correctly handling custom samples), tests started failing, because of the following sequence of events - Saving a brand new `.osu` to a beatmap set causes `RealmBackedResourceStore` to fire subscription callbacks because a new file was added to the set - This fires `RealmBackedResourceStore.CacheInvalidated` - Which fires `EditorBeatmapSkin.BeatmapSkinChanged` - Which would previously fire `EditorBeatmap.SaveState()` and as such mark the beatmap dirty / modified. In this scenario this is gratuitous. There's no need to be raising save states here, a new `.osu` was added to the set that is in a consistent saved state and nothing actually changed in the beatmap. However it does not appear sane to attempt to circumvent this with conditional guards or something, because in cases where files are added/removed from the set, *there isn't really any reason to take save states anyway*. The change handler only deals with the `.osu`, any modifications to any of the other files cannot be undone anyway. Therefore, only keep the state save to the one change to beatmap skin that *can* actually be sanely undone which is changing combo colours. --- osu.Game/Screens/Edit/EditorBeatmap.cs | 5 +---- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 9 ++++++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 248779a9f8f2..48b793d1b5d8 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -102,10 +102,7 @@ public EditorBeatmap(IBeatmap playableBeatmap, ISkin beatmapSkin = null, Beatmap this.beatmapInfo = beatmapInfo ?? playableBeatmap.BeatmapInfo; if (beatmapSkin is LegacyBeatmapSkin skin) - { - BeatmapSkin = new EditorBeatmapSkin(playableBeatmap.BeatmapInfo!.BeatmapSet!, skin); - BeatmapSkin.BeatmapSkinChanged += SaveState; - } + BeatmapSkin = new EditorBeatmapSkin(this, skin); beatmapProcessor = new EditorBeatmapProcessor(this, playableBeatmap.BeatmapInfo.Ruleset.CreateInstance()); diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 0fbfb7b2d0a9..50090b703508 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Game.Audio; -using osu.Game.Beatmaps; using osu.Game.Skinning; using osuTK.Graphics; @@ -34,10 +33,13 @@ public class EditorBeatmapSkin : ISkin, IDisposable /// public BindableList ComboColours { get; } - public EditorBeatmapSkin(BeatmapSetInfo beatmapSet, LegacyBeatmapSkin skin) + private readonly EditorBeatmap editorBeatmap; + + public EditorBeatmapSkin(EditorBeatmap editorBeatmap, LegacyBeatmapSkin skin) { - Skin = skin; + this.editorBeatmap = editorBeatmap; + Skin = skin; ComboColours = new BindableList(); if (Skin.Configuration.ComboColours is IReadOnlyList comboColours) @@ -67,6 +69,7 @@ private void updateColours() for (int i = 0; i < ComboColours.Count; ++i) Skin.Configuration.CustomComboColours.Add(ComboColours[(ComboColours.Count + i - 1) % ComboColours.Count]); InvokeSkinChanged(); + editorBeatmap.SaveState(); } #endregion From bd29c46bd74f030a51263e514ef6cc57f64eb17e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 31 Dec 2025 12:53:59 +0100 Subject: [PATCH 385/836] Fix tests --- osu.Game/Screens/Edit/ExternalEditScreen.cs | 22 ++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/ExternalEditScreen.cs b/osu.Game/Screens/Edit/ExternalEditScreen.cs index ef72c7e1b8af..21eff365583f 100644 --- a/osu.Game/Screens/Edit/ExternalEditScreen.cs +++ b/osu.Game/Screens/Edit/ExternalEditScreen.cs @@ -50,7 +50,8 @@ internal partial class ExternalEditScreen : OsuScreen public ExternalEditOperation? EditOperation { get; private set; } - private Task? finishOperation; + private bool operationFinishStarted; + private bool operationFinished; private FillFlowContainer flow = null!; @@ -101,14 +102,14 @@ public override bool OnExiting(ScreenExitEvent e) return true; // Similarly do not allow interrupting an ongoing finish. - if (finishOperation?.IsCompleted == false) + if (operationFinishStarted && !operationFinished) return true; // If the operation completed successfully, ensure that we finish the operation before exiting. // The finish() call will subsequently call Exit() when done. - if (EditOperation != null && finishOperation == null) + if (EditOperation != null && !operationFinishStarted) { - (finishOperation = finish()).FireAndForget(); + finish().FireAndForget(); return true; } @@ -167,7 +168,7 @@ private async Task begin() Width = 350, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Action = () => (finishOperation = finish()).FireAndForget(), + Action = () => finish().FireAndForget(), Enabled = { Value = false } } }; @@ -191,6 +192,11 @@ private void openDirectory() private async Task finish() { + if (operationFinishStarted) + return; + + operationFinishStarted = true; + BackButtonVisibility.Value = false; string originalDifficulty = editor.Beatmap.Value.Beatmap.BeatmapInfo.DifficultyName; @@ -213,7 +219,11 @@ private async Task finish() EditOperation = null; if (beatmap == null) + { + // has to be set before `Exit()` call to ensure the exit isn't blocked in `OnExiting()` + operationFinished = true; this.Exit(); + } else { // the `ImportAsUpdate()` flow will yield beatmap(sets) with online status of `None` if online lookup fails. @@ -230,6 +240,8 @@ private async Task finish() beatmap.Value.Beatmaps.FirstOrDefault(b => b.DifficultyName == originalDifficulty) ?? beatmap.Value.Beatmaps.First(); + // has to be set before `SwitchToDifficulty()` call to ensure the exit isn't blocked in `OnExiting()` + operationFinished = true; editor.SwitchToDifficulty(closestMatchingBeatmap); } } From affe295f50580de5fd3a7d9894f85e503cb48df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 31 Dec 2025 13:02:03 +0100 Subject: [PATCH 386/836] Fix missing disposal --- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 1 + osu.Game/Skinning/Skin.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 50090b703508..8992211ace3c 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -141,6 +141,7 @@ public void Dispose() { if (Skin.BeatmapSetResources != null) Skin.BeatmapSetResources.CacheInvalidated -= InvokeSkinChanged; + Skin.Dispose(); } #region Delegated ISkin implementation diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 8c287a010ee9..3affd5afa675 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -342,6 +342,7 @@ protected virtual void Dispose(bool isDisposing) Textures?.Dispose(); Samples?.Dispose(); + FallbackStore?.Dispose(); store.Dispose(); } From 04bd381ee3a1d2eff58ab79cb1a6d6cce32bbbee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 31 Dec 2025 12:33:31 +0000 Subject: [PATCH 387/836] Fix number conversion setter hack used by LastYearPlacing --- osu.Game.Tournament/Models/TournamentTeam.cs | 55 +++++++++++++------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/osu.Game.Tournament/Models/TournamentTeam.cs b/osu.Game.Tournament/Models/TournamentTeam.cs index ab353d771abc..4368c2fda87e 100644 --- a/osu.Game.Tournament/Models/TournamentTeam.cs +++ b/osu.Game.Tournament/Models/TournamentTeam.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using System.Linq; using Newtonsoft.Json; using osu.Framework.Bindables; @@ -49,25 +50,9 @@ public double AverageRank public Bindable Seed = new Bindable(string.Empty); - [JsonIgnore] - public Bindable LastYearPlacing = new Bindable("N/A"); - - /// - /// Previously, a value of 0 was meant to indicate "no placement last year". - /// This will convert the number 0 from an old bracket.json file back to the "N/A" string (new default). - /// - [JsonProperty("LastYearPlacing")] - private object lastYearPlacing - { - get => LastYearPlacing.Value; - set - { - if (value is long oldValue && oldValue == 0) - LastYearPlacing.Value = LastYearPlacing.Default; - else - LastYearPlacing.Value = value.ToString() ?? LastYearPlacing.Default; - } - } + [JsonProperty] + [JsonConverter(typeof(LastYearPlacingConverter))] + public Bindable LastYearPlacing = new Bindable(@"N/A"); [JsonProperty] public BindableList Players { get; } = new BindableList(); @@ -90,5 +75,37 @@ public TournamentTeam() } public override string ToString() => FullName.Value ?? Acronym.Value; + + public class LastYearPlacingConverter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(Bindable); + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + => serializer.Serialize(writer, ((Bindable)value!).Value); + + public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + var lastYearPlacing = existingValue as Bindable; + Debug.Assert(lastYearPlacing != null); + + switch (reader.TokenType) + { + case JsonToken.String: + lastYearPlacing.Value = (string?)reader.Value ?? lastYearPlacing.Default; + break; + + case JsonToken.Integer: + long value = (long)reader.Value!; + lastYearPlacing.Value = value > 0 ? $@"#{value}" : lastYearPlacing.Default; + break; + + default: + reader.Read(); + break; + } + + return lastYearPlacing; + } + } } } From 0a2fc12061885c57b21046447600c3c3adceae37 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Dec 2025 23:58:33 +0900 Subject: [PATCH 388/836] Fix/remove tests broken by screen behaviour change --- .../Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs | 8 -------- .../Visual/Navigation/TestSceneScreenNavigation.cs | 3 ++- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs index 1d78896ce7c0..6d2d507bf1a6 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs @@ -89,14 +89,6 @@ public void TestItemAddedWhenCreateNewItemClicked() AddAssert("playlist has 1 item", () => room.Playlist.Count == 1); } - [Test] - public void TestItemNotAddedIfExistingOnStart() - { - AddStep("create new item", () => songSelect.AddNewItem()); - AddStep("finalise selection", () => InputManager.Key(Key.Enter)); - AddAssert("playlist has 1 item", () => room.Playlist.Count == 1); - } - [Test] public void TestAddSameItemMultipleTimes() { diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index a55fe4c89e33..b1c9ab1dfb2c 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -99,12 +99,13 @@ public void TestConfirmationRequiredToDiscardPlaylist(bool withPlaylistItemAdded AddUntilStep("wait for selection", () => !Game.Beatmap.IsDefault); AddStep("add item", () => InputManager.Key(Key.Enter)); + AddStep("exit screen", () => InputManager.Key(Key.Escape)); AddUntilStep("wait for return to playlist screen", () => playlistScreen.CurrentSubScreen is PlaylistsRoomSubScreen); AddStep("go back to song select", () => { - InputManager.MoveMouseTo(playlistScreen.ChildrenOfType().Single(b => b.Text == "Edit playlist")); + InputManager.MoveMouseTo(playlistScreen.ChildrenOfType().Single(b => b.Text == "+ Add more beatmaps")); InputManager.Click(MouseButton.Left); }); From 19cfe9abe6afca6adffcb16f9322e6264e41f2a0 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 31 Dec 2025 11:28:19 -0500 Subject: [PATCH 389/836] Fix button spacing in account creation overlay --- osu.Game/Overlays/AccountCreation/ScreenWarning.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs index c24bd32bb425..d9c8a20470c3 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs @@ -71,7 +71,7 @@ private void load(OsuColour colours, TextureStore textures) Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Padding = new MarginPadding(20), - Spacing = new Vector2(0, 5), + Spacing = new Vector2(0, 7), Children = new Drawable[] { new Container From e539660b14ff8d4fc26a2de11a2f65d3c1ee6cd0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Jan 2026 19:41:14 +0900 Subject: [PATCH 390/836] Attempt to fix flaky test --- .../Visual/Editing/TestSceneLocallyModifyingOnlineBeatmaps.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneLocallyModifyingOnlineBeatmaps.cs b/osu.Game.Tests/Visual/Editing/TestSceneLocallyModifyingOnlineBeatmaps.cs index 636b3f54d80e..7ded3467c6e7 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneLocallyModifyingOnlineBeatmaps.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneLocallyModifyingOnlineBeatmaps.cs @@ -34,7 +34,7 @@ public void TestLocallyModifyingOnlineBeatmap() SaveEditor(); ReloadEditorToSameBeatmap(); - AddAssert("beatmap marked as locally modified", () => EditorBeatmap.BeatmapInfo.Status, () => Is.EqualTo(BeatmapOnlineStatus.LocallyModified)); + AddUntilStep("beatmap marked as locally modified", () => EditorBeatmap.BeatmapInfo.Status, () => Is.EqualTo(BeatmapOnlineStatus.LocallyModified)); AddAssert("beatmap hash changed", () => EditorBeatmap.BeatmapInfo.MD5Hash, () => Is.Not.EqualTo(initialHash)); } } From 833617e27924799a234ee69233125caba3a45c56 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 1 Jan 2026 08:42:41 -0500 Subject: [PATCH 391/836] Fix casing in random selection algorithm dropdown --- osu.Game/Localisation/UserInterfaceStrings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index facea0f66cd7..9883ffe17326 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -165,9 +165,9 @@ public static class UserInterfaceStrings public static LocalisableString NeverRepeat => new TranslatableString(getKey(@"never_repeat_random"), @"Never repeat"); /// - /// "True Random" + /// "True random" /// - public static LocalisableString TrueRandom => new TranslatableString(getKey(@"true_random"), @"True Random"); + public static LocalisableString TrueRandom => new TranslatableString(getKey(@"true_random"), @"True random"); /// /// "Selected Mods" From 2fc621b4f3e20d331a7a5720d2f2c522f9668770 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Thu, 1 Jan 2026 20:47:35 +0300 Subject: [PATCH 392/836] Fix incorrect `OsuAnimatedButton`'s `DimColour` for child classes without override --- osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs index f77d00e6e76a..31ac777eaaa0 100644 --- a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs @@ -92,12 +92,12 @@ protected override void LoadComplete() { base.LoadComplete(); - Colour = Enabled.Value ? Colour4.White : DimColour; + Colour = DimColour; Enabled.BindValueChanged(_ => this.FadeColour(DimColour, 200, Easing.OutQuint), true); FinishTransforms(true); } - protected virtual Colour4 DimColour => colours.Gray9; + protected virtual Colour4 DimColour => Enabled.Value ? Color4.White : colours.Gray9; protected override bool OnHover(HoverEvent e) { From 212973bd632a03a836deeb16ad4e8881315901f4 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Thu, 1 Jan 2026 21:26:48 +0300 Subject: [PATCH 393/836] Localise friend presence notifications --- osu.Game/Localisation/NotificationsStrings.cs | 10 ++++++++++ osu.Game/Online/FriendPresenceNotifier.cs | 9 +++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 66250d162943..ae9267990d75 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -135,6 +135,16 @@ public static class NotificationsStrings /// public static LocalisableString Mention => new TranslatableString(getKey(@"mention"), @"Mention"); + /// + /// "Online: {0}" + /// + public static LocalisableString FriendOnline(string info) => new TranslatableString(getKey(@"friend_online"), @"Online: {0}", info); + + /// + /// "Offline: {0}" + /// + public static LocalisableString FriendOffline(string info) => new TranslatableString(getKey(@"friend_offline"), @"Offline: {0}", info); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Online/FriendPresenceNotifier.cs b/osu.Game/Online/FriendPresenceNotifier.cs index 53c8ff7b5a81..8329f3b46bcb 100644 --- a/osu.Game/Online/FriendPresenceNotifier.cs +++ b/osu.Game/Online/FriendPresenceNotifier.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics; +using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; @@ -197,7 +198,7 @@ public SingleFriendOnlineNotification(APIUser user) { Transient = true; IsImportant = false; - Text = $"Online: {User.Username}"; + Text = NotificationsStrings.FriendOnline(User.Username); } [BackgroundDependencyLoader] @@ -219,7 +220,7 @@ public partial class MultipleFriendsOnlineNotification : SimpleNotification { public MultipleFriendsOnlineNotification(ICollection users) { - Text = $"Online: {string.Join(@", ", users.Select(u => u.Username))}"; + Text = NotificationsStrings.FriendOnline(string.Join(@", ", users.Select(u => u.Username))); } [BackgroundDependencyLoader] @@ -239,7 +240,7 @@ public SingleFriendOfflineNotification(APIUser user) { Transient = true; IsImportant = false; - Text = $"Offline: {User.Username}"; + Text = NotificationsStrings.FriendOffline(User.Username); } [BackgroundDependencyLoader] @@ -256,7 +257,7 @@ public partial class MultipleFriendsOfflineNotification : SimpleNotification { public MultipleFriendsOfflineNotification(ICollection users) { - Text = $"Offline: {string.Join(@", ", users.Select(u => u.Username))}"; + Text = NotificationsStrings.FriendOffline(string.Join(@", ", users.Select(u => u.Username))); } [BackgroundDependencyLoader] From 1fcae16be90dbeb6f48b5889930c1d3b95940554 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Jan 2026 16:39:37 +0900 Subject: [PATCH 394/836] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 3a0d771fbf7a..6d667fb81419 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index 5a2f7f5f1879..ec09350de6f4 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From bcaf35dae71f07b3f7c3928bce85e98567049613 Mon Sep 17 00:00:00 2001 From: Givy120 <89256026+Givikap120@users.noreply.github.com> Date: Sat, 3 Jan 2026 21:51:45 +0200 Subject: [PATCH 395/836] Improve fullcombo threshold formula (#35724) * Implement new portion formula * Change the formula * Use base value of 5 sliders * Make the threshold harsher --------- Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com> --- .../Difficulty/OsuLegacyScoreMissCalculator.cs | 8 ++++++-- .../Difficulty/OsuPerformanceCalculator.cs | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs index 0d406ea72a60..8bde33d292c1 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs @@ -115,9 +115,13 @@ private double calculateMaximumComboBasedMissCount() double missCount = 0; + // If sliders in the map are hard - it's likely for player to drop sliderends + // If map has easy sliders - it's more likely for player to sliderbreak + double likelyMissedSliderendPortion = 0.04 + 0.06 * Math.Pow(Math.Min(attributes.AimTopWeightedSliderFactor, 1), 2); + // Consider that full combo is maximum combo minus dropped slider tails since they don't contribute to combo but also don't break it - // In classic scores we can't know the amount of dropped sliders so we estimate to 10% of all sliders on the map - double fullComboThreshold = attributes.MaxCombo - 0.1 * attributes.SliderCount; + // In classic scores we can't know the amount of dropped sliders so we estimate it + double fullComboThreshold = attributes.MaxCombo - Math.Min(4 + likelyMissedSliderendPortion * attributes.SliderCount, attributes.SliderCount); if (score.MaxCombo < fullComboThreshold) missCount = Math.Pow(fullComboThreshold / Math.Max(1.0, score.MaxCombo), 2.5); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 9dde9dfdea7c..dc4ac6c37320 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -337,9 +337,13 @@ private double calculateComboBasedEstimatedMissCount(OsuDifficultyAttributes att if (usingClassicSliderAccuracy) { + // If sliders in the map are hard - it's likely for player to drop sliderends + // If map has easy sliders - it's more likely for player to sliderbreak + double likelyMissedSliderendPortion = 0.04 + 0.06 * Math.Pow(Math.Min(attributes.AimTopWeightedSliderFactor, 1), 2); + // Consider that full combo is maximum combo minus dropped slider tails since they don't contribute to combo but also don't break it - // In classic scores we can't know the amount of dropped sliders so we estimate to 10% of all sliders on the map - double fullComboThreshold = attributes.MaxCombo - 0.1 * attributes.SliderCount; + // In classic scores we can't know the amount of dropped sliders so we estimate it + double fullComboThreshold = attributes.MaxCombo - Math.Min(4 + likelyMissedSliderendPortion * attributes.SliderCount, attributes.SliderCount); if (scoreMaxCombo < fullComboThreshold) missCount = fullComboThreshold / Math.Max(1.0, scoreMaxCombo); From 00560cbfbab084b1de0c40f0ca40edcdc82266dc Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Sun, 4 Jan 2026 20:54:50 +0300 Subject: [PATCH 396/836] Localise notifications in `LegacyCollectionImporter` --- osu.Game/Database/LegacyCollectionImporter.cs | 9 +++++---- osu.Game/Localisation/NotificationsStrings.cs | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/osu.Game/Database/LegacyCollectionImporter.cs b/osu.Game/Database/LegacyCollectionImporter.cs index 6d3e3fb76ae7..b8a515b96f65 100644 --- a/osu.Game/Database/LegacyCollectionImporter.cs +++ b/osu.Game/Database/LegacyCollectionImporter.cs @@ -10,6 +10,7 @@ using osu.Framework.Platform; using osu.Game.Collections; using osu.Game.IO.Legacy; +using osu.Game.Localisation; using osu.Game.Overlays.Notifications; namespace osu.Game.Database @@ -63,7 +64,7 @@ public async Task Import(Stream stream) var notification = new ProgressNotification { State = ProgressNotificationState.Active, - Text = "Collections import is initialising..." + Text = NotificationsStrings.CollectionsImportInitialising, }; PostNotification?.Invoke(notification); @@ -71,7 +72,7 @@ public async Task Import(Stream stream) var importedCollections = readCollections(stream, notification); await importCollections(importedCollections).ConfigureAwait(false); - notification.CompletionText = $"Imported {importedCollections.Count} collections"; + notification.CompletionText = NotificationsStrings.CollectionsImportProgress(importedCollections.Count); notification.State = ProgressNotificationState.Completed; } @@ -115,7 +116,7 @@ private List readCollections(Stream stream, ProgressNotificat { if (notification != null) { - notification.Text = "Reading collections..."; + notification.Text = NotificationsStrings.ReadingCollections; notification.Progress = 0; } @@ -150,7 +151,7 @@ private List readCollections(Stream stream, ProgressNotificat if (notification != null) { - notification.Text = $"Imported {i + 1} of {collectionCount} collections"; + notification.Text = NotificationsStrings.CollectionsImportProgressTotal(i + 1, collectionCount); notification.Progress = (float)(i + 1) / collectionCount; } diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index ae9267990d75..0a97806b7255 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -145,6 +145,26 @@ public static class NotificationsStrings /// public static LocalisableString FriendOffline(string info) => new TranslatableString(getKey(@"friend_offline"), @"Offline: {0}", info); + /// + /// "Collections import is initialising..." + /// + public static LocalisableString CollectionsImportInitialising => new TranslatableString(getKey(@"collections_import_initialising"), @"Collections import is initialising..."); + + /// + /// "Reading collections..." + /// + public static LocalisableString ReadingCollections => new TranslatableString(getKey(@"reading_collections"), @"Reading collections..."); + + /// + /// "Imported {0} collections" + /// + public static LocalisableString CollectionsImportProgress(int count) => new TranslatableString(getKey(@"collections_import_progress"), @"Imported {0} collections", count); + + /// + /// "Imported {0} of {1} collections" + /// + public static LocalisableString CollectionsImportProgressTotal(int count, int totalCount) => new TranslatableString(getKey(@"collections_import_progress_total"), @"Imported {0} of {1} collections", count, totalCount); + private static string getKey(string key) => $@"{prefix}:{key}"; } } From 351a717795b27ed4802aba041fc3af4fb99b399e Mon Sep 17 00:00:00 2001 From: Marvin Date: Mon, 5 Jan 2026 01:52:13 +0100 Subject: [PATCH 397/836] Alternate buttons in OsuAutoPlay generator even when time difference is exactly zero. Previously, there if two consecutive hitobjects were 50ms apart both mechanisms to make sure that the input buttons are alternated would fail. This produced a replay frame which lifts the current button, followed by a frame which presses the same button again, at the same time as it was lifted. The key-up frame would always get skipped without frame-stability, leading to hitsounds and hit animations not getting played in the editor. --- osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs index d43e6092c22c..9bf93dfd1b0a 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs @@ -266,7 +266,7 @@ private void moveToHitObject(OsuHitObject h, Vector2 targetPos, Easing easing) } // Start alternating once the time separation is too small (faster than ~225BPM). - if (timeDifference > 0 && timeDifference < 266) + if (timeDifference >= 0 && timeDifference < 266) buttonIndex++; else buttonIndex = 0; From 3bd20509548ab78624c4594b1929fd55e8ce0f16 Mon Sep 17 00:00:00 2001 From: Marvin Date: Mon, 5 Jan 2026 03:15:45 +0100 Subject: [PATCH 398/836] Fix interpolation not being applied when previous frame-up frame is at the same time as current frame --- osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs index 9bf93dfd1b0a..6520b9a50c6c 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs @@ -245,7 +245,7 @@ private void moveToHitObject(OsuHitObject h, Vector2 targetPos, Easing easing) double timeDifference = ApplyModsToTimeDelta(lastFrame.Time, h.StartTime); OsuReplayFrame? lastLastFrame = Frames.Count >= 2 ? (OsuReplayFrame)Frames[^2] : null; - if (timeDifference > 0) + if (timeDifference >= 0) { // If the last frame is a key-up frame and there has been no wait period, adjust the last frame's position such that it begins eased movement instantaneously. if (lastLastFrame != null && lastFrame is OsuKeyUpReplayFrame && !hasWaited) From af08416880cc84ae0410878db94615db821c188f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Jan 2026 13:16:25 +0900 Subject: [PATCH 399/836] Add test coverage --- .../TestSceneAutoGeneration.cs | 63 +++++++++++++++++++ .../Replays/OsuAutoGenerator.cs | 4 +- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneAutoGeneration.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneAutoGeneration.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneAutoGeneration.cs new file mode 100644 index 000000000000..e2c66af19f85 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneAutoGeneration.cs @@ -0,0 +1,63 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Testing; +using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Replays; +using osu.Game.Rulesets.Replays; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Osu.Tests +{ + [TestFixture] + [HeadlessTest] + public partial class TestSceneAutoGeneration : OsuTestScene + { + [TestCase(-1, true)] + [TestCase(0, false)] + [TestCase(1, false)] + public void TestAlternating(double offset, bool shouldAlternate) + { + const double first_object_time = 1000; + double secondObjectTime = first_object_time + AutoGenerator.KEY_UP_DELAY + OsuAutoGenerator.MIN_FRAME_SEPARATION_FOR_ALTERNATING + offset; + + var beatmap = new OsuBeatmap(); + beatmap.HitObjects.Add(new HitCircle { StartTime = first_object_time }); + beatmap.HitObjects.Add(new HitCircle { StartTime = secondObjectTime }); + + var generated = new OsuAutoGenerator(beatmap, []).Generate(); + var frames = generated.Frames.OfType().ToList(); + + Assert.That(frames.Exists(f => f.Time == first_object_time && f.Actions.SingleOrDefault() == OsuAction.LeftButton)); + Assert.That(frames.Exists(f => f.Time == first_object_time + AutoGenerator.KEY_UP_DELAY && !f.Actions.Any())); + + Assert.That(frames.Exists(f => f.Time == secondObjectTime && f.Actions.SingleOrDefault() == (shouldAlternate ? OsuAction.RightButton : OsuAction.LeftButton))); + Assert.That(frames.Exists(f => f.Time == secondObjectTime + AutoGenerator.KEY_UP_DELAY && !f.Actions.Any())); + } + + [TestCase(300)] + [TestCase(600)] + [TestCase(1200)] + public void TestAlternatingSpecificBPM(double bpm) + { + const double first_object_time = 1000; + double secondObjectTime = first_object_time + 60000 / bpm; + + var beatmap = new OsuBeatmap(); + beatmap.HitObjects.Add(new HitCircle { StartTime = first_object_time }); + beatmap.HitObjects.Add(new HitCircle { StartTime = secondObjectTime }); + + var generated = new OsuAutoGenerator(beatmap, []).Generate(); + var frames = generated.Frames.OfType().ToList(); + + Assert.That(frames.Exists(f => f.Time == first_object_time && f.Actions.SingleOrDefault() == OsuAction.LeftButton)); + Assert.That(frames.Exists(f => f.Time == first_object_time + AutoGenerator.KEY_UP_DELAY && !f.Actions.Any())); + + Assert.That(frames.Exists(f => f.Time == secondObjectTime && f.Actions.SingleOrDefault() == OsuAction.RightButton)); + Assert.That(frames.Exists(f => f.Time == secondObjectTime + AutoGenerator.KEY_UP_DELAY && !f.Actions.Any())); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs index 6520b9a50c6c..f08e8133230c 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs @@ -21,6 +21,8 @@ namespace osu.Game.Rulesets.Osu.Replays { public class OsuAutoGenerator : OsuAutoGeneratorBase { + public const double MIN_FRAME_SEPARATION_FOR_ALTERNATING = 266; + public new OsuBeatmap Beatmap => (OsuBeatmap)base.Beatmap; #region Parameters @@ -266,7 +268,7 @@ private void moveToHitObject(OsuHitObject h, Vector2 targetPos, Easing easing) } // Start alternating once the time separation is too small (faster than ~225BPM). - if (timeDifference >= 0 && timeDifference < 266) + if (timeDifference >= 0 && timeDifference < MIN_FRAME_SEPARATION_FOR_ALTERNATING) buttonIndex++; else buttonIndex = 0; From ebf9c19ad35573740eedc870e4ec6bf78ff0b304 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Jan 2026 14:10:23 +0900 Subject: [PATCH 400/836] Revert no longer necessary change Additionally to fix the options button, I could either cache the interface in PlaylistsSongSelectV2 or make the interface cache itself. I went with the latter option. --- .../Visual/SongSelectV2/TestSceneScreenFooter.cs | 2 +- osu.Game/Screens/SelectV2/FooterButtonOptions.cs | 8 ++------ osu.Game/Screens/SelectV2/ISongSelect.cs | 2 ++ osu.Game/Screens/SelectV2/SongSelect.cs | 3 +-- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneScreenFooter.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneScreenFooter.cs index bb0fb16dcf5d..e247b92f528a 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneScreenFooter.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneScreenFooter.cs @@ -53,7 +53,7 @@ public void SetUp() => Schedule(() => { new FooterButtonMods(modOverlay) { Current = SelectedMods }, new FooterButtonRandom(), - new FooterButtonOptions(null), + new FooterButtonOptions(), }); }); diff --git a/osu.Game/Screens/SelectV2/FooterButtonOptions.cs b/osu.Game/Screens/SelectV2/FooterButtonOptions.cs index 8de0908af153..4da40559e98a 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonOptions.cs +++ b/osu.Game/Screens/SelectV2/FooterButtonOptions.cs @@ -24,12 +24,8 @@ public partial class FooterButtonOptions : ScreenFooterButton, IHasPopover [Resolved] private IBindable workingBeatmap { get; set; } = null!; - private readonly ISongSelect? songSelect; - - public FooterButtonOptions(ISongSelect? songSelect) - { - this.songSelect = songSelect; - } + [Resolved] + private ISongSelect? songSelect { get; set; } [Resolved] private RealmAccess realm { get; set; } = null!; diff --git a/osu.Game/Screens/SelectV2/ISongSelect.cs b/osu.Game/Screens/SelectV2/ISongSelect.cs index 3fede4401f79..6280e4048ae4 100644 --- a/osu.Game/Screens/SelectV2/ISongSelect.cs +++ b/osu.Game/Screens/SelectV2/ISongSelect.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; @@ -12,6 +13,7 @@ namespace osu.Game.Screens.SelectV2 /// /// Actions exposed by song select which are used by subcomponents to perform top-level operations. /// + [Cached] public interface ISongSelect { /// diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index 6cfe7206f8f1..49d9bab9c229 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -63,7 +63,6 @@ namespace osu.Game.Screens.SelectV2 /// This screen is intended to house all components introduced in the new song select design to add transitions and examine the overall look. /// This will be gradually built upon and ultimately replace once everything is in place. /// - [Cached(typeof(ISongSelect))] public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler, ISongSelect, IHandlePresentBeatmap { /// @@ -352,7 +351,7 @@ private void requestRecommendedSelection(IEnumerable groupedBeat errorSample?.Play(); } }, - new FooterButtonOptions(this) + new FooterButtonOptions { Hotkey = GlobalAction.ToggleBeatmapOptions, } From 593cc37ea693d5bece683a76fa81e1f15a7835bf Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Jan 2026 14:35:34 +0900 Subject: [PATCH 401/836] Adjust styling of freestyle button --- .../OnlinePlay/FooterButtonFreestyleV2.cs | 67 +------------------ 1 file changed, 2 insertions(+), 65 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs index 03d590ac6ec3..517807363265 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs @@ -4,24 +4,15 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Overlays; using osu.Game.Screens.Footer; -using osuTK; -using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay { public partial class FooterButtonFreestyleV2 : ScreenFooterButton { - private const float bar_height = 30f; - public readonly Bindable Freestyle = new Bindable(); public new Action Action @@ -32,12 +23,6 @@ public partial class FooterButtonFreestyleV2 : ScreenFooterButton [Resolved] private OsuColour colours { get; set; } = null!; - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; - - private Drawable statusBackground = null!; - private OsuSpriteText statusText = null!; - public FooterButtonFreestyleV2() { // Overwrite any external behaviour as we delegate the main toggle action to a sub-button. @@ -50,63 +35,15 @@ private void load() Text = "Freestyle"; Icon = FontAwesome.Solid.ExchangeAlt; AccentColour = colours.Lime1; - - AddRange(new[] - { - new Container - { - Y = -5f, - Depth = float.MaxValue, - Origin = Anchor.BottomLeft, - Shear = OsuGame.SHEAR, - CornerRadius = CORNER_RADIUS, - Size = new Vector2(BUTTON_WIDTH, bar_height), - Masking = true, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Radius = 4, - // Figma says 50% opacity, but it does not match up visually if taken at face value, and looks bad. - Colour = Colour4.Black.Opacity(0.25f), - Offset = new Vector2(0, 2), - }, - Children = new[] - { - statusBackground = new Box - { - Colour = colourProvider.Background3, - RelativeSizeAxes = Axes.Both, - }, - statusText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.Torus.With(size: 14f, weight: FontWeight.Bold), - Shear = -OsuGame.SHEAR, - }, - } - }, - }); } protected override void LoadComplete() { base.LoadComplete(); - Freestyle.BindValueChanged(v => + Freestyle.BindValueChanged(active => { - if (v.NewValue) - { - statusBackground.Colour = colours.Yellow; - statusText.Text = "ON"; - statusText.Colour = Color4.Black; - } - else - { - statusBackground.Colour = colourProvider.Background3; - statusText.Text = "OFF"; - statusText.Colour = Color4.White; - } + OverlayState.Value = active.NewValue ? Visibility.Visible : Visibility.Hidden; }, true); } } From ff820f730e821c67b02f18b00b079ecbd564aaca Mon Sep 17 00:00:00 2001 From: Jul Date: Mon, 5 Jan 2026 06:54:25 +0100 Subject: [PATCH 402/836] Fix play button starting wrong beatmap before selection loads (#36104) * Fix play button starting wrong beatmap before selection loads When clicking the osu! cookie (play button) before a newly selected beatmap finishes loading, the previous beatmap would be played instead of the currently selected one. This was caused by the cookie reading from the global beatmap state which is debounced by 150ms, while the Enter key correctly used the carousel's current selection. The fix makes the cookie use the same beatmap source as Enter - the carousel's current selection - which is always up-to-date regardless of debounce timing. Closes #36074 * Use ensureGlobalBeatmapValid() for logo and Enter key actions * Add test for beatmap selection timing bug Tests the fix for issue #36074 where clicking the play button immediately after selecting a different difficulty would start the wrong beatmap due to the 150ms selection debounce. --- .../SongSelectV2/TestSceneSongSelect.cs | 45 +++++++++++++++++++ osu.Game/Screens/SelectV2/SongSelect.cs | 2 + 2 files changed, 47 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs index a480e51adf14..f47eafc93737 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs @@ -659,6 +659,51 @@ public void TestFooterOptionsState() AddAssert("options disabled", () => !this.ChildrenOfType().Single().Enabled.Value); } + /// + /// tests that clicking the osu! logo immediately after selecting a different difficulty + /// (before the selection debounce completes) starts the correct beatmap. + /// this tests the fix for https://github.com/ppy/osu/issues/36074 + /// + [Test] + public void TestPlayCorrectBeatmapWhenSelectionNotFullyLoaded() + { + // import a beatmap set with multiple difficulties + ImportBeatmapForRuleset(0); + + LoadSongSelect(); + + // wait for initial beatmap to be selected + AddUntilStep("wait for first beatmap selected", () => !Beatmap.IsDefault); + + BeatmapInfo? firstBeatmap = null; + AddStep("store first difficulty", () => firstBeatmap = Beatmap.Value.BeatmapInfo); + + // start loading the first difficulty + AddStep("click logo to start loading", () => this.ChildrenOfType().Single().TriggerClick()); + AddUntilStep("wait for player loader", () => Stack.CurrentScreen is PlayerLoader); + + // return to song select + AddStep("press escape to return", () => InputManager.Key(Key.Escape)); + AddUntilStep("wait for return to song select", () => SongSelect.IsCurrentScreen()); + + // press down and schedule logo click to happen shortly after (but before 150ms debounce) + // this reproduces the race condition where Beatmap.Value hasn't updated yet + AddStep("select next difficulty and click logo immediately", () => + { + InputManager.Key(Key.Down); + Schedule(() => this.ChildrenOfType().Single().TriggerClick()); + }); + + AddUntilStep("wait for player loader", () => Stack.CurrentScreen is PlayerLoader); + + // verify we're loading the second difficulty, not the first + // without the fix, this would fail because Beatmap.Value still has the old value + AddAssert("player is loading second difficulty", () => + Beatmap.Value.BeatmapInfo.ID != firstBeatmap!.ID); + + AddUntilStep("wait for return to song select", () => SongSelect.IsCurrentScreen()); + } + #endregion } } diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index 944c93bd5f60..4bee63b57c4e 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -756,6 +756,7 @@ protected override void LogoArriving(OsuLogo logo, bool resuming) logo.Action = () => { + ensureGlobalBeatmapValid(); SelectAndRun(Beatmap.Value.BeatmapInfo, OnStart); return false; }; @@ -999,6 +1000,7 @@ public virtual bool OnPressed(KeyBindingPressEvent e) // one of which is filtering out all visible beatmaps and attempting to start gameplay. // in that case, users still expect a `Select` press to advance to gameplay anyway, using the ambient selected beatmap if there is one, // which matches the behaviour resulting from clicking the osu! cookie in that scenario. + ensureGlobalBeatmapValid(); SelectAndRun(Beatmap.Value.BeatmapInfo, OnStart); return true; From 88f80799c3e33ee55eeb56686bd48c6c23b37f63 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Jan 2026 15:21:49 +0900 Subject: [PATCH 403/836] Add test --- .../Matchmaking/TestScenePlayerPanel.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanel.cs index 897d59657c80..8d98eba317a2 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanel.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanel.cs @@ -122,5 +122,51 @@ public void TestDownloadProgress() AddStep("set download progress 90%", () => MultiplayerClient.ChangeUserBeatmapAvailability(2, BeatmapAvailability.Downloading(0.9f))); AddStep("set locally available", () => MultiplayerClient.ChangeUserBeatmapAvailability(2, BeatmapAvailability.LocallyAvailable())); } + + [Test] + public void TestLongUsername() + { + AddStep("set long username", () => + { + MultiplayerClient.ChangeMatchRoomState(new MatchmakingRoomState + { + Users = + { + UserDictionary = + { + { + 2, new MatchmakingUser + { + UserId = 2, + Placement = 1 + } + } + } + } + }).WaitSafely(); + + Child = panel = new PlayerPanel(new MultiplayerRoomUser(2) + { + User = new APIUser + { + Username = @"ThisIsALongUsername", + Id = 2, + Colour = "99EB47", + CountryCode = CountryCode.AU, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/2/baba245ef60834b769694178f8f6d4f6166c5188c740de084656ad2b80f1eea7.jpeg", + Statistics = new UserStatistics { GlobalRank = null, CountryRank = null } + } + }) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }; + }); + + foreach (var layout in Enum.GetValues()) + { + AddStep($"set layout to {layout}", () => panel.DisplayMode = layout); + } + } } } From b7b3e028abba3d5c59db7636c8955e4fdae4a23e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Jan 2026 15:22:03 +0900 Subject: [PATCH 404/836] Adjust quick play player panels for long usernames --- .../Match/BeatmapSelect/SubScreenBeatmapSelect.cs | 2 +- osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs index 9574fec554ce..c7b0c66f46da 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs @@ -44,7 +44,7 @@ public SubScreenBeatmapSelect() new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = 200 }, + Padding = new MarginPadding { Horizontal = 250 }, Children = new Drawable[] { beatmapSelectGrid = new BeatmapSelectGrid diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs index 9f3509951692..58d29220dc57 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs @@ -47,7 +47,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match /// public partial class PlayerPanel : OsuClickableContainer, IHasContextMenu { - private static readonly Vector2 size_horizontal = new Vector2(250, 100); + private static readonly Vector2 size_horizontal = new Vector2(300, 100); private static readonly Vector2 size_vertical = new Vector2(150, 200); private static readonly Vector2 avatar_size = new Vector2(80); @@ -236,13 +236,14 @@ private void load(AudioManager audio) Text = "-", Font = OsuFont.Style.Title.With(size: 55), }, - username = new OsuSpriteText + username = new TruncatingSpriteText { Alpha = 0, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, Text = User.Username, Font = OsuFont.Style.Heading1, + MaxWidth = 120 }, scoreText = new OsuSpriteText { From 25dab7258c904e41676e97151041d830511a802e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Jan 2026 15:24:15 +0900 Subject: [PATCH 405/836] Add test coverage of editor placement scenarios --- .../Editing/TestScenePlacementBlueprint.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestScenePlacementBlueprint.cs b/osu.Game.Tests/Visual/Editing/TestScenePlacementBlueprint.cs index 822c04535574..675de2f57a86 100644 --- a/osu.Game.Tests/Visual/Editing/TestScenePlacementBlueprint.cs +++ b/osu.Game.Tests/Visual/Editing/TestScenePlacementBlueprint.cs @@ -37,6 +37,42 @@ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) private GlobalActionContainer globalActionContainer => this.ChildrenOfType().Single(); + [Test] + public void TestPlaceThenUndo() + { + AddStep("select circle placement tool", () => InputManager.Key(Key.Number2)); + AddStep("move mouse to center of playfield", () => InputManager.MoveMouseTo(this.ChildrenOfType().Single())); + AddStep("place circle", () => InputManager.Click(MouseButton.Left)); + + AddAssert("one circle added", () => EditorBeatmap.HitObjects, () => Has.One.Items); + + AddStep("undo", () => Editor.Undo()); + + AddAssert("circle removed", () => EditorBeatmap.HitObjects, () => Is.Empty); + } + + [Test] + public void TestTimingLost() + { + AddStep("select circle placement tool", () => InputManager.Key(Key.Number2)); + AddStep("move mouse to center of playfield", () => InputManager.MoveMouseTo(this.ChildrenOfType().Single())); + + AddAssert("placement ready", () => this.ChildrenOfType().Single().CurrentPlacement, () => Is.Not.Null); + + AddStep("nuke timing", () => EditorBeatmap.ControlPointInfo.Clear()); + + AddAssert("placement not available", () => this.ChildrenOfType().Single().CurrentPlacement, () => Is.Null); + + AddStep("select circle placement tool", () => InputManager.Key(Key.Number2)); + + AddAssert("placement not available", () => this.ChildrenOfType().Single().CurrentPlacement, () => Is.Null); + + AddStep("add back timing", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint())); + AddStep("select circle placement tool", () => InputManager.Key(Key.Number2)); + + AddAssert("placement ready", () => this.ChildrenOfType().Single().CurrentPlacement, () => Is.Not.Null); + } + [Test] public void TestDeleteUsingMiddleMouse() { From 9916e5bb1c96f7086c684c705c77f712558fa392 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Jan 2026 15:26:12 +0900 Subject: [PATCH 406/836] Fix editor crashing on undoing after hit object placement Happens when initial timing is undone. Regressed in https://github.com/ppy/osu/commit/12170df80add87e8f292545f67566f8d25465efc. Closes https://github.com/ppy/osu/issues/36228. --- osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs b/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs index 4688c7c8ca7c..7b378edda6b4 100644 --- a/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs @@ -48,7 +48,7 @@ public abstract partial class HitObjectPlacementBlueprint : PlacementBlueprint private HitObject? getPreviousHitObject() => beatmap.HitObjects.TakeWhile(h => h.StartTime <= startTimeBindable.Value).LastOrDefault(); - protected override bool IsValidForPlacement => HitObject.StartTime >= beatmap.ControlPointInfo.TimingPoints[0].Time; + protected override bool IsValidForPlacement => HitObject.StartTime >= beatmap.ControlPointInfo.TimingPoints.FirstOrDefault()?.Time; [Resolved] private IPlacementHandler placementHandler { get; set; } = null!; From a4fe0c924d5fdc8607cb8e64096b8c21927249d5 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Mon, 5 Jan 2026 10:12:20 +0300 Subject: [PATCH 407/836] Localise `DownloadNotification` (#36224) Co-authored-by: Dean Herbert --- osu.Game/Database/ModelDownloader.cs | 3 ++- osu.Game/Localisation/NotificationsStrings.cs | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/ModelDownloader.cs b/osu.Game/Database/ModelDownloader.cs index 8e89db4d069f..235c30b58965 100644 --- a/osu.Game/Database/ModelDownloader.cs +++ b/osu.Game/Database/ModelDownloader.cs @@ -9,6 +9,7 @@ using Humanizer; using osu.Framework.Logging; using osu.Game.Extensions; +using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Overlays.Notifications; @@ -55,7 +56,7 @@ protected bool Download(T model, bool minimiseDownloadSize, TModel? originalMode DownloadNotification notification = new DownloadNotification { - Text = $"Downloading {request.Model.GetDisplayString()}", + Text = NotificationsStrings.Downloading(request.Model.GetDisplayString()), }; request.DownloadProgressed += progress => diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 0a97806b7255..d641a85ebe60 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -145,6 +145,11 @@ public static class NotificationsStrings /// public static LocalisableString FriendOffline(string info) => new TranslatableString(getKey(@"friend_offline"), @"Offline: {0}", info); + /// + /// "Downloading {0}" + /// + public static LocalisableString Downloading(string info) => new TranslatableString(getKey(@"downloading"), @"Downloading {0}", info); + /// /// "Collections import is initialising..." /// From ff3397b6b75299cc8bc8e3983714634865091fa0 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Mon, 5 Jan 2026 10:15:01 +0300 Subject: [PATCH 408/836] Localise notifications in `OnlineStatusNotifier` (#36223) Co-authored-by: Dean Herbert --- osu.Game/Localisation/NotificationsStrings.cs | 20 +++++++++++++++++++ osu.Game/Online/OnlineStatusNotifier.cs | 9 +++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index d641a85ebe60..75f1a39a69df 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -145,6 +145,26 @@ public static class NotificationsStrings /// public static LocalisableString FriendOffline(string info) => new TranslatableString(getKey(@"friend_offline"), @"Offline: {0}", info); + /// + /// "Connection to API was lost. Can't continue with online play." + /// + public static LocalisableString APIDisconnect => new TranslatableString(getKey(@"api_disconnect"), @"Connection to API was lost. Can't continue with online play."); + + /// + /// "Connection to the multiplayer server was lost. Exiting multiplayer." + /// + public static LocalisableString MultiplayerDisconnect => new TranslatableString(getKey(@"multiplayer_disconnect"), @"Connection to the multiplayer server was lost. Exiting multiplayer."); + + /// + /// "You have been logged out on this device due to a login to your account on another device." + /// + public static LocalisableString AnotherDeviceDisconnect => new TranslatableString(getKey(@"another_device_disconnect"), @"You have been logged out on this device due to a login to your account on another device."); + + /// + /// "You have been logged out due to a change to your account. Please log in again." + /// + public static LocalisableString AccountChangeDisconnect => new TranslatableString(getKey(@"account_change_disconnect"), @"You have been logged out due to a change to your account. Please log in again."); + /// /// "Downloading {0}" /// diff --git a/osu.Game/Online/OnlineStatusNotifier.cs b/osu.Game/Online/OnlineStatusNotifier.cs index 10d766c729e4..da58dc3d46b9 100644 --- a/osu.Game/Online/OnlineStatusNotifier.cs +++ b/osu.Game/Online/OnlineStatusNotifier.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Screens; +using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.Metadata; using osu.Game.Online.Multiplayer; @@ -88,7 +89,7 @@ protected override void LoadComplete() notificationOverlay?.Post(new SimpleErrorNotification { Icon = FontAwesome.Solid.ExclamationCircle, - Text = "Connection to API was lost. Can't continue with online play." + Text = NotificationsStrings.APIDisconnect, }); } }); @@ -109,7 +110,7 @@ protected override void LoadComplete() notificationOverlay?.Post(new SimpleErrorNotification { Icon = FontAwesome.Solid.ExclamationCircle, - Text = "Connection to the multiplayer server was lost. Exiting multiplayer." + Text = NotificationsStrings.MultiplayerDisconnect, }); } })); @@ -128,7 +129,7 @@ private void notifyAboutForcedDisconnection() notificationOverlay?.Post(new SimpleErrorNotification { Icon = FontAwesome.Solid.ExclamationCircle, - Text = "You have been logged out on this device due to a login to your account on another device." + Text = NotificationsStrings.AnotherDeviceDisconnect, }); } @@ -142,7 +143,7 @@ private void notifyAboutForcedDisconnection(SocketMessage obj) notificationOverlay?.Post(new SimpleErrorNotification { Icon = FontAwesome.Solid.ExclamationCircle, - Text = "You have been logged out due to a change to your account. Please log in again." + Text = NotificationsStrings.AccountChangeDisconnect, }); } From ea289460b07c48b87e8b1acb655fc8be69bec711 Mon Sep 17 00:00:00 2001 From: pishifat <31551350+pishifat@users.noreply.github.com> Date: Sun, 4 Jan 2026 23:16:04 -0800 Subject: [PATCH 409/836] remove map from list (#36218) --- osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs b/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs index b61b2358b09b..36c40e690843 100644 --- a/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs +++ b/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs @@ -467,7 +467,6 @@ public BundledBeatmapDownloadRequest(IBeatmapSetInfo beatmapSetInfo, bool minimi @"2055329 miraie & blackwinterwells - facade.osz", @"2069877 Sephid - Thunderstrike 1988.osz", @"2119716 Aethoro - Snowy.osz", - @"2120379 Synthion - VIVIDVELOCITY.osz", @"2124805 Frums (unknown ""lambda"") - 19ZZ.osz", @"2127811 Wiklund - Joy of Living (Cut Ver.).osz", }; From 2b90cbf59f32c9cf98933a895890c3af1e9b05ca Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Jan 2026 16:44:34 +0900 Subject: [PATCH 410/836] Attempt to fix display issues at high UI scales --- .../Multiplayer/MultiplayerPlayerLoader.cs | 24 ------ osu.Game/Screens/Play/PlayerLoader.cs | 74 +++++++++++++++---- 2 files changed, 60 insertions(+), 38 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayerLoader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayerLoader.cs index 4e8a2e08ce74..b13069a43658 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayerLoader.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayerLoader.cs @@ -4,13 +4,10 @@ using System; using System.Threading.Tasks; using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Play; -using osu.Game.Screens.Play.HUD; namespace osu.Game.Screens.OnlinePlay.Multiplayer { @@ -33,27 +30,6 @@ public MultiplayerPlayerLoader(Func createPlayer) { } - [BackgroundDependencyLoader] - private void load() - { - PlayerSettings.Add(new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Child = new HoldForMenuButton(true) - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Margin = new MarginPadding(10), - Action = () => - { - if (this.IsCurrentScreen()) - this.Exit(); - } - } - }); - } - protected override bool ReadyForGameplay => ( // The user is ready to enter gameplay. diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 3209ee21fea0..34577c1e56be 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -31,7 +31,9 @@ using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Volume; using osu.Game.Performance; +using osu.Game.Screens.Footer; using osu.Game.Screens.Menu; +using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Screens.Select.Leaderboards; using osu.Game.Skinning; @@ -72,7 +74,7 @@ public partial class PlayerLoader : ScreenWithBeatmapBackground /// /// A fill flow containing the player settings groups, exposed for the ability to hide it from inheritors of the player loader. /// - protected FillFlowContainer PlayerSettings { get; private set; } = null!; + protected FillFlowContainer PlayerSettings { get; private set; } = null!; protected VisualSettings VisualSettings { get; private set; } = null!; @@ -135,6 +137,8 @@ protected bool BackgroundBrightnessReduction // or if a child of a focused overlay is focused, like settings' search textbox. && inputManager.FocusedDrawable?.FindClosestParent() == null; + private bool holdForMenuExitButton => !AllowUserExit; + private readonly Func createPlayer; /// @@ -225,27 +229,69 @@ private void load(SessionStatics sessionStatics, OsuConfigManager config) Padding = new MarginPadding(padding), Spacing = new Vector2(20), }, - settingsScroll = new OsuScrollContainer + new GridContainer { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, RelativeSizeAxes = Axes.Y, Width = SettingsToolboxGroup.CONTAINER_WIDTH + padding * 2, - Padding = new MarginPadding { Vertical = padding }, - Masking = false, - Child = PlayerSettings = new FillFlowContainer + Padding = new MarginPadding + { + Top = padding, + Bottom = ScreenFooter.HEIGHT + padding + }, + RowDimensions = + [ + new Dimension(), + new Dimension(GridSizeMode.AutoSize) + ], + Content = new[] { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 20), - Padding = new MarginPadding { Horizontal = padding }, - Children = new PlayerSettingsGroup[] + new Drawable[] { - VisualSettings = new VisualSettings(), - AudioSettings = new AudioSettings(), - new InputSettings() + settingsScroll = new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both, + Masking = holdForMenuExitButton, + Child = PlayerSettings = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Padding = new MarginPadding { Horizontal = padding }, + Children = new PlayerSettingsGroup[] + { + VisualSettings = new VisualSettings(), + AudioSettings = new AudioSettings(), + new InputSettings() + } + }, + } + }, + new Drawable[] + { + new Container + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Alpha = holdForMenuExitButton ? 1 : 0, + AutoSizeAxes = Axes.Both, + Child = new HoldForMenuButton(true) + { + Margin = new MarginPadding + { + Top = 20, + Horizontal = padding, + }, + Action = () => + { + if (this.IsCurrentScreen()) + this.Exit(); + } + } + } } - }, + } }, idleTracker = new IdleTracker(1500), sampleRestart = new SkinnableSound(new SampleInfo(@"Gameplay/restart", @"pause-retry-click")) From 78a5654e1f55869acd7dbd08dedade01b4d63a79 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Jan 2026 17:15:18 +0900 Subject: [PATCH 411/836] Adjust beatmap query to fix potential crash --- osu.Game/Beatmaps/BeatmapManager.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index d50862a36970..7860dba075f8 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -334,7 +334,11 @@ public List GetAllUsableBeatmapSets() /// A matching local beatmap info if existing and in a valid state. public BeatmapInfo? QueryOnlineBeatmapId(int id) => Realm.Run(r => r.All() - .ForOnlineId(id).SingleOrDefault()?.Detach()); + .ForOnlineId(id) + // See https://github.com/ppy/osu/issues/36234 for why this isn't a SingleOrDefault(). + .FirstOrDefault() + ?.Detach() + ); /// /// A default representation of a WorkingBeatmap to use when no beatmap is available. From 8b49572c44f654f7cd59036c204b3975fc2e91c7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Jan 2026 17:44:41 +0900 Subject: [PATCH 412/836] Fix title overlap Uses the same method of displaying the mod selection as the old song select (as an overlay of the entire game). --- .../Playlists/PlaylistsSongSelectV2.cs | 40 ++++++++++++------- osu.Game/Screens/SelectV2/SongSelect.cs | 18 ++++++++- 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index 586898f41493..20c08ce2d1a9 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.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.Collections.Generic; using System.Linq; using Humanizer; @@ -31,12 +32,17 @@ public partial class PlaylistsSongSelectV2 : SongSelect, IOnlinePlaySubScreen protected readonly Bindable Freestyle = new Bindable(true); private readonly Bindable> freeMods = new Bindable>([]); + [Resolved] + private IOverlayManager? overlayManager { get; set; } + private readonly AddToPlaylistFooterButton addToPlaylistFooterButton; private readonly Room room; private ModSelectOverlay modSelect = null!; private FreeModSelectOverlay freeModSelect = null!; + private IDisposable? modSelectOverlayRegistration; + public PlaylistsSongSelectV2(Room room) { this.room = room; @@ -61,30 +67,30 @@ public PlaylistsSongSelectV2(Room room) [BackgroundDependencyLoader] private void load() { - AddRangeInternal(new Drawable[] + AddInternal(new PlaylistTray(room) { - freeModSelect = new FreeModSelectOverlay - { - SelectedMods = { BindTarget = freeMods }, - IsValidMod = isValidAllowedMod, - }, - new PlaylistTray(room) + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Margin = new MarginPadding { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Margin = new MarginPadding - { - Bottom = ScreenFooterButton.HEIGHT, - Right = OsuGame.SCREEN_EDGE_MARGIN - } + Bottom = ScreenFooterButton.HEIGHT, + Right = OsuGame.SCREEN_EDGE_MARGIN } }); + + LoadComponent(freeModSelect = new FreeModSelectOverlay + { + SelectedMods = { BindTarget = freeMods }, + IsValidMod = isValidAllowedMod, + }); } protected override void LoadComplete() { base.LoadComplete(); + modSelectOverlayRegistration = overlayManager?.RegisterBlockingOverlay(freeModSelect); + Mods.BindValueChanged(onGlobalModsChanged); Ruleset.BindValueChanged(onRulesetChanged); Freestyle.BindValueChanged(onFreestyleChanged); @@ -250,5 +256,11 @@ private bool isValidAllowedMod(Mod mod) => ModUtils.IsValidModForMatch(mod, fals && Mods.Value.All(m => m.Acronym != mod.Acronym) // Mod must be compatible with all the required mods. && ModUtils.CheckCompatibleSet(Mods.Value.Append(mod).ToArray()); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + modSelectOverlayRegistration?.Dispose(); + } } } diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index 49d9bab9c229..c467ee6d504c 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -146,6 +146,9 @@ public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBind [Resolved] private IDialogOverlay? dialogOverlay { get; set; } + [Resolved] + private IOverlayManager? overlayManager { get; set; } + private InputManager inputManager = null!; private readonly RealmPopulatingOnlineLookupSource onlineLookupSource = new RealmPopulatingOnlineLookupSource(); @@ -153,6 +156,8 @@ public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBind private Bindable configBackgroundBlur = null!; private Bindable showConvertedBeatmaps = null!; + private IDisposable? modSelectOverlayRegistration; + [BackgroundDependencyLoader] private void load(AudioManager audio, OsuConfigManager config) { @@ -288,10 +293,11 @@ private void load(AudioManager audio, OsuConfigManager config) Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, }, - modSpeedHotkeyHandler = new ModSpeedHotkeyHandler(), - modSelectOverlay = CreateModSelectOverlay(), + modSpeedHotkeyHandler = new ModSpeedHotkeyHandler() }); + LoadComponent(modSelectOverlay = CreateModSelectOverlay()); + configBackgroundBlur = config.GetBindable(OsuSetting.SongSelectBackgroundBlur); configBackgroundBlur.BindValueChanged(e => { @@ -361,6 +367,8 @@ protected override void LoadComplete() { base.LoadComplete(); + modSelectOverlayRegistration = overlayManager?.RegisterBlockingOverlay(modSelectOverlay); + inputManager = GetContainingInputManager()!; filterControl.CriteriaChanged += criteriaChanged; @@ -1210,5 +1218,11 @@ public void RestoreAllHidden(BeatmapSetInfo beatmapSet) public Bindable ScopedBeatmapSet => filterControl.ScopedBeatmapSet; #endregion + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + modSelectOverlayRegistration?.Dispose(); + } } } From 61c4a3dba0722005afa71e74c8142b63e2775365 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Jan 2026 17:55:36 +0900 Subject: [PATCH 413/836] Fix footer button overlap The scheduled events don't fire because the content is hidden. --- osu.Game/Screens/Footer/ScreenFooter.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Footer/ScreenFooter.cs b/osu.Game/Screens/Footer/ScreenFooter.cs index 5dbc7a55ab84..8a08f786c7fa 100644 --- a/osu.Game/Screens/Footer/ScreenFooter.cs +++ b/osu.Game/Screens/Footer/ScreenFooter.cs @@ -291,7 +291,9 @@ private void clearActiveOverlayContainer() return; Debug.Assert(activeOverlayContent != null); + activeOverlayContent.Hide(); + activeOverlayContent.Expire(); double timeUntilRun = activeOverlayContent.LatestTransformEndTime - Time.Current; @@ -299,6 +301,7 @@ private void clearActiveOverlayContainer() { var button = temporarilyHiddenButtons[i]; hiddenButtonsContainer.Remove(button, false); + // temporarily bypass autosize on the X axis to prevent the buttons taking space // immediately upon being moved back to the flow. // this prevents the overlay content jumping to the right during its fade-out. @@ -312,12 +315,13 @@ private void clearActiveOverlayContainer() updateColourScheme(OverlayColourScheme.Aquamarine.GetHue()); - activeOverlayContent.Delay(timeUntilRun).Schedule(() => + Scheduler.AddDelayed(() => { // overlay content is done displaying, re-enable autosize on all active buttons foreach (var button in buttonsFlow) button.BypassAutoSizeAxes = Axes.None; - }).Expire(); + }, timeUntilRun); + activeOverlayContent = null; ActiveOverlay = null; } From fad53d91340bffb43920ddf599c96f3fdb01ba1e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Jan 2026 18:03:46 +0900 Subject: [PATCH 414/836] Hide mods wedge when empty --- .../OnlinePlay/FooterButtonFreeModsV2.cs | 107 +++++++++--------- 1 file changed, 55 insertions(+), 52 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs index d9cb0acb4fc0..84c9334b45d2 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs @@ -41,6 +41,7 @@ public partial class FooterButtonFreeModsV2 : ScreenFooterButton [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; + private Drawable modsWedge = null!; private ModDisplay modDisplay = null!; private Container modContainer = null!; private ModCountText overflowModCountDisplay = null!; @@ -57,62 +58,60 @@ private void load() Icon = FontAwesome.Solid.ExchangeAlt; AccentColour = colours.Lime1; - AddRange(new[] + Add(modsWedge = new Container { - new Container + Y = -5f, + Depth = float.MaxValue, + Origin = Anchor.BottomLeft, + Shear = OsuGame.SHEAR, + CornerRadius = CORNER_RADIUS, + Size = new Vector2(BUTTON_WIDTH, bar_height), + Masking = true, + EdgeEffect = new EdgeEffectParameters { - Y = -5f, - Depth = float.MaxValue, - Origin = Anchor.BottomLeft, - Shear = OsuGame.SHEAR, - CornerRadius = CORNER_RADIUS, - Size = new Vector2(BUTTON_WIDTH, bar_height), - Masking = true, - EdgeEffect = new EdgeEffectParameters + Type = EdgeEffectType.Shadow, + Radius = 4, + // Figma says 50% opacity, but it does not match up visually if taken at face value, and looks bad. + Colour = Colour4.Black.Opacity(0.25f), + Offset = new Vector2(0, 2), + }, + Alpha = 0, + Children = new Drawable[] + { + new Box { - Type = EdgeEffectType.Shadow, - Radius = 4, - // Figma says 50% opacity, but it does not match up visually if taken at face value, and looks bad. - Colour = Colour4.Black.Opacity(0.25f), - Offset = new Vector2(0, 2), + Colour = colourProvider.Background4, + RelativeSizeAxes = Axes.Both, }, - Children = new Drawable[] + modContainer = new Container { - new Box - { - Colour = colourProvider.Background4, - RelativeSizeAxes = Axes.Both, - }, - modContainer = new Container + CornerRadius = CORNER_RADIUS, + RelativeSizeAxes = Axes.Both, + Masking = true, + Children = new Drawable[] { - CornerRadius = CORNER_RADIUS, - RelativeSizeAxes = Axes.Both, - Masking = true, - Children = new Drawable[] + new Box { - new Box - { - Colour = colourProvider.Background3, - RelativeSizeAxes = Axes.Both, - }, - modDisplay = new ModDisplay(showExtendedInformation: true) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Shear = -OsuGame.SHEAR, - Scale = new Vector2(0.5f), - Current = { BindTarget = FreeMods }, - ExpansionMode = ExpansionMode.AlwaysContracted, - }, - overflowModCountDisplay = new ModCountText - { - Mods = { BindTarget = FreeMods }, - Freestyle = { BindTarget = Freestyle } - }, - } - }, - } - }, + Colour = colourProvider.Background3, + RelativeSizeAxes = Axes.Both, + }, + modDisplay = new ModDisplay(showExtendedInformation: true) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Shear = -OsuGame.SHEAR, + Scale = new Vector2(0.5f), + Current = { BindTarget = FreeMods }, + ExpansionMode = ExpansionMode.AlwaysContracted, + }, + overflowModCountDisplay = new ModCountText + { + Mods = { BindTarget = FreeMods }, + Freestyle = { BindTarget = Freestyle } + }, + } + }, + } }); } @@ -121,15 +120,19 @@ protected override void LoadComplete() base.LoadComplete(); Freestyle.BindValueChanged(f => Enabled.Value = !f.NewValue, true); + FreeMods.BindValueChanged(m => + { + if (m.NewValue.Count == 0) + modsWedge.FadeOut(200); + else + modsWedge.FadeIn(200); + }, true); } protected override void Update() { base.Update(); - if (FreeMods.Value.Count == 0) - return; - if (modDisplay.DrawWidth * modDisplay.Scale.X > modContainer.DrawWidth) overflowModCountDisplay.Show(); else From 59b3afe5aa4cb0d1d41d70a8bf0e941fe1215c74 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Jan 2026 18:24:48 +0900 Subject: [PATCH 415/836] Hide add button when mod selects are shown The important one is the required mod selection, whose overlay contents overlap with the add button. The free mod selection would otherwise be fine, if not for consistency. --- .../OnlinePlay/Playlists/PlaylistsSongSelectV2.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index 20c08ce2d1a9..58d472fb993f 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Game.Localisation; using osu.Game.Online.API; @@ -91,6 +92,9 @@ protected override void LoadComplete() modSelectOverlayRegistration = overlayManager?.RegisterBlockingOverlay(freeModSelect); + modSelect.State.BindValueChanged(onModSelectStateChanged, true); + freeModSelect.State.BindValueChanged(onModSelectStateChanged, true); + Mods.BindValueChanged(onGlobalModsChanged); Ruleset.BindValueChanged(onRulesetChanged); Freestyle.BindValueChanged(onFreestyleChanged); @@ -105,6 +109,14 @@ public void AddNewItem() room.Playlist = room.Playlist.Append(createItem()).ToArray(); } + private void onModSelectStateChanged(ValueChangedEvent state) + { + if (state.NewValue == Visibility.Visible) + addToPlaylistFooterButton.Disappear(); + else + addToPlaylistFooterButton.Appear(); + } + private void onGlobalModsChanged(ValueChangedEvent> mods) { updateValidMods(); From 4f2dfccb0f3f92781e77a9efaacd33c7e48025bd Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Mon, 5 Jan 2026 16:13:36 -0500 Subject: [PATCH 416/836] Add test cases requiring text wrapping --- .../UserInterface/TestSceneFormControls.cs | 379 ++++++++++-------- 1 file changed, 222 insertions(+), 157 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFormControls.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFormControls.cs index a1872b30defd..22b3753320ca 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFormControls.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFormControls.cs @@ -42,171 +42,236 @@ public TestSceneFormControls() RelativeSizeAxes = Axes.Both, Child = new FillFlowContainer { - AutoSizeAxes = Axes.Y, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Width = 400, - Direction = FillDirection.Vertical, - Spacing = new Vector2(5), - Padding = new MarginPadding(10), - Children = new Drawable[] + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Direction = FillDirection.Horizontal, + Children = new[] { - new FormTextBox + new FillFlowContainer { - Caption = "Artist", - HintText = "Poot artist here!", - PlaceholderText = "Here is an artist", - TabbableContentContainer = this, - }, - new FormTextBox - { - Caption = "Artist", - HintText = "Poot artist here!", - PlaceholderText = "Here is an artist", - Current = { Disabled = true }, - TabbableContentContainer = this, - }, - new FormNumberBox(allowDecimals: true) - { - Caption = "Number", - HintText = "Insert your favourite number", - PlaceholderText = "Mine is 42!", - TabbableContentContainer = this, - }, - new FormCheckBox - { - Caption = EditorSetupStrings.LetterboxDuringBreaks, - HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, - }, - new FormCheckBox - { - Caption = EditorSetupStrings.LetterboxDuringBreaks, - HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, - Current = { Disabled = true }, - }, - new FormCheckBox - { - Caption = EditorSetupStrings.LetterboxDuringBreaks, - HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, - Current = { Value = true, Disabled = true }, - }, - new FormSliderBar - { - Caption = "Slider", - HintText = "Slider hint", - Current = new BindableFloat - { - MinValue = 0, - MaxValue = 10, - Value = 5, - Precision = 0.1f, - }, - TabbableContentContainer = this, - }, - new FormSliderBar - { - Caption = "Slider", - HintText = "Slider hint", - Current = new BindableFloat - { - MinValue = 0, - MaxValue = 10, - Value = 5, - Precision = 0.1f, - Disabled = true, - }, - TransferValueOnCommit = true, - TabbableContentContainer = this, - }, - new FormSliderBar - { - Caption = "Slider (percentage)", - HintText = "Percentage slider hint", - Current = new BindableFloat + AutoSizeAxes = Axes.Y, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Width = 400, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + Padding = new MarginPadding(10), + Children = new Drawable[] { - MinValue = 0, - MaxValue = 1, - Value = 0.2f, - Precision = 0.0001f, + new FormTextBox + { + Caption = "Artist", + HintText = "Poot artist here!", + PlaceholderText = "Here is an artist", + TabbableContentContainer = this, + }, + new FormTextBox + { + Caption = "Artist", + HintText = "Poot artist here!", + PlaceholderText = "Here is an artist", + Current = { Disabled = true }, + TabbableContentContainer = this, + }, + new FormNumberBox(allowDecimals: true) + { + Caption = "Number", + HintText = "Insert your favourite number", + PlaceholderText = "Mine is 42!", + TabbableContentContainer = this, + }, + new FormCheckBox + { + Caption = EditorSetupStrings.LetterboxDuringBreaks, + HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, + }, + new FormCheckBox + { + Caption = EditorSetupStrings.LetterboxDuringBreaks, + HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, + Current = { Disabled = true }, + }, + new FormCheckBox + { + Caption = EditorSetupStrings.LetterboxDuringBreaks, + HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, + Current = { Value = true, Disabled = true }, + }, + new FormSliderBar + { + Caption = "Slider", + HintText = "Slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Value = 5, + Precision = 0.1f, + }, + TabbableContentContainer = this, + }, + new FormSliderBar + { + Caption = "Slider", + HintText = "Slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Value = 5, + Precision = 0.1f, + Disabled = true, + }, + TransferValueOnCommit = true, + TabbableContentContainer = this, + }, + new FormSliderBar + { + Caption = "Slider (percentage)", + HintText = "Percentage slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 1, + Value = 0.2f, + Precision = 0.0001f, + }, + DisplayAsPercentage = true, + TabbableContentContainer = this, + }, + new FormSliderBar + { + Caption = "Slider (custom)", + HintText = "Custom slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 1, + Value = 0.2f, + Precision = 0.0001f, + }, + LabelFormat = v => $"{v * 100:0.00} funometer", + TooltipFormat = v => $"This setting has the value set to {v * 100:0.00} funometer.", + TabbableContentContainer = this, + }, + new FormSliderBar + { + Caption = "Slider (custom)", + HintText = "Custom slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 1, + Value = 0.2f, + Precision = 0.0001f, + Disabled = true, + }, + TransferValueOnCommit = true, + LabelFormat = v => $"{v * 100:0.00} funometer", + TooltipFormat = v => $"This setting has the value set to {v * 100:0.00} funometer.", + TabbableContentContainer = this, + }, + new FormEnumDropdown + { + Caption = EditorSetupStrings.EnableCountdown, + HintText = EditorSetupStrings.CountdownDescription, + }, + new FormEnumDropdown + { + Caption = EditorSetupStrings.EnableCountdown, + HintText = EditorSetupStrings.CountdownDescription, + Current = { Disabled = true }, + }, + new FormFileSelector + { + Caption = "File selector", + PlaceholderText = "Select a file", + }, + new FormBeatmapFileSelector(true) + { + Caption = "File selector with intermediate choice dialog", + PlaceholderText = "Select a file", + }, + new FormColourPalette + { + Caption = "Combo colours", + Colours = + { + Colour4.Red, + Colour4.Green, + Colour4.Blue, + Colour4.Yellow, + } + }, + new FormButton + { + Caption = "No text in button", + Action = () => { }, + }, }, - DisplayAsPercentage = true, - TabbableContentContainer = this, }, - new FormSliderBar + new FillFlowContainer { - Caption = "Slider (custom)", - HintText = "Custom slider hint", - Current = new BindableFloat + AutoSizeAxes = Axes.Y, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Width = 400, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + Padding = new MarginPadding(10), + Children = new Drawable[] { - MinValue = 0, - MaxValue = 1, - Value = 0.2f, - Precision = 0.0001f, + new FormNumberBox(allowDecimals: true) + { + Caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", + HintText = "Insert your favourite number", + PlaceholderText = "Mine is 42!", + TabbableContentContainer = this, + }, + new FormCheckBox + { + Caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", + HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, + }, + new FormSliderBar + { + Caption = "Lorem ipsum dolor sit amet, conse adipiscing elit, sed do eiusmod", + HintText = "Slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Value = 5, + Precision = 0.1f, + }, + TabbableContentContainer = this, + }, + new FormEnumDropdown + { + Caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", + HintText = EditorSetupStrings.CountdownDescription, + }, + new FormFileSelector + { + Caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", + HintText = EditorSetupStrings.CountdownDescription, + PlaceholderText = "Select a file", + }, + new FormColourPalette + { + Caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", + HintText = EditorSetupStrings.CountdownDescription, + Colours = + { + Colour4.Red, + Colour4.Green, + Colour4.Blue, + Colour4.Yellow, + } + }, }, - LabelFormat = v => $"{v * 100:0.00} funometer", - TooltipFormat = v => $"This setting has the value set to {v * 100:0.00} funometer.", - TabbableContentContainer = this, - }, - new FormSliderBar - { - Caption = "Slider (custom)", - HintText = "Custom slider hint", - Current = new BindableFloat - { - MinValue = 0, - MaxValue = 1, - Value = 0.2f, - Precision = 0.0001f, - Disabled = true, - }, - TransferValueOnCommit = true, - LabelFormat = v => $"{v * 100:0.00} funometer", - TooltipFormat = v => $"This setting has the value set to {v * 100:0.00} funometer.", - TabbableContentContainer = this, - }, - new FormEnumDropdown - { - Caption = EditorSetupStrings.EnableCountdown, - HintText = EditorSetupStrings.CountdownDescription, - }, - new FormEnumDropdown - { - Caption = EditorSetupStrings.EnableCountdown, - HintText = EditorSetupStrings.CountdownDescription, - Current = { Disabled = true }, - }, - new FormFileSelector - { - Caption = "File selector", - PlaceholderText = "Select a file", - }, - new FormBeatmapFileSelector(true) - { - Caption = "File selector with intermediate choice dialog", - PlaceholderText = "Select a file", - }, - new FormColourPalette - { - Caption = "Combo colours", - Colours = - { - Colour4.Red, - Colour4.Green, - Colour4.Blue, - Colour4.Yellow, - } - }, - new FormButton - { - Caption = "No text in button", - Action = () => { }, - }, - new FormButton - { - Caption = "Text in button which is pretty long and is very likely to wrap", - ButtonText = "Foo the bar", - Action = () => { }, - }, + } }, }, }, From 465ec88371102dc388ef6fca2a902e19a9999029 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Mon, 5 Jan 2026 16:13:21 -0500 Subject: [PATCH 417/836] Expose switch button width --- osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs index 1c1dae0f315a..5bb6aca7f4bf 100644 --- a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs @@ -19,6 +19,8 @@ namespace osu.Game.Graphics.UserInterfaceV2 { public partial class SwitchButton : Checkbox { + public const float WIDTH = 45; + private const float border_thickness = 4.5f; private const float padding = 1.25f; @@ -35,7 +37,7 @@ public partial class SwitchButton : Checkbox public SwitchButton() { - Size = new Vector2(45, 20); + Size = new Vector2(WIDTH, 20); InternalChild = content = new CircularContainer { From 08364a7b97c50779c022879661d4cf81939397c3 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Mon, 5 Jan 2026 16:13:51 -0500 Subject: [PATCH 418/836] Support text wrapping in form controls --- .../Graphics/UserInterfaceV2/FormCheckBox.cs | 34 ++++---- .../Graphics/UserInterfaceV2/FormDropdown.cs | 33 ++++---- .../UserInterfaceV2/FormFieldCaption.cs | 76 +++++++++++------- .../UserInterfaceV2/FormFileSelector.cs | 57 ++++++++------ .../Graphics/UserInterfaceV2/FormSliderBar.cs | 78 ++++++++++++------- .../Graphics/UserInterfaceV2/FormTextBox.cs | 11 +-- 6 files changed, 173 insertions(+), 116 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs index f54cc7cc7c20..dfe4f6c43912 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs @@ -18,6 +18,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Localisation; using osu.Game.Overlays; +using osuTK; namespace osu.Game.Graphics.UserInterfaceV2 { @@ -56,7 +57,7 @@ public Bindable Current private void load(AudioManager audio) { RelativeSizeAxes = Axes.X; - Height = 50; + AutoSizeAxes = Axes.Y; Masking = true; CornerRadius = 5; @@ -71,22 +72,30 @@ private void load(AudioManager audio) }, new Container { - RelativeSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, Padding = new MarginPadding(9), Children = new Drawable[] { - caption = new FormFieldCaption - { - Caption = Caption, - TooltipText = HintText, - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - }, - text = new OsuSpriteText + new FillFlowContainer { RelativeSizeAxes = Axes.X, - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Padding = new MarginPadding { Right = SwitchButton.WIDTH + 5 }, + Spacing = new Vector2(0f, 4f), + Children = new Drawable[] + { + caption = new FormFieldCaption + { + Caption = Caption, + TooltipText = HintText, + }, + text = new OsuSpriteText + { + RelativeSizeAxes = Axes.X, + }, + }, }, new SwitchButton { @@ -97,7 +106,6 @@ private void load(AudioManager audio) }, }, }; - sampleChecked = audio.Samples.Get(@"UI/check-on"); sampleUnchecked = audio.Samples.Get(@"UI/check-off"); sampleDisabled = audio.Samples.Get(@"UI/default-select-disabled"); diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index 1c595e138623..d7e734468177 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -7,6 +7,7 @@ using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; @@ -140,30 +141,30 @@ protected override LocalisableString Label [BackgroundDependencyLoader] private void load() { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.None; - Height = 50; - Masking = true; CornerRadius = 5; - Foreground.AutoSizeAxes = Axes.None; - Foreground.RelativeSizeAxes = Axes.Both; Foreground.Padding = new MarginPadding(9); Foreground.Children = new Drawable[] { - caption = new FormFieldCaption - { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Caption = Caption, - TooltipText = HintText, - }, - label = new OsuSpriteText + new FillFlowContainer { RelativeSizeAxes = Axes.X, - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 4), + Children = new Drawable[] + { + caption = new FormFieldCaption + { + Caption = Caption, + TooltipText = HintText, + }, + label = new OsuSpriteText + { + RelativeSizeAxes = Axes.X, + }, + } }, chevron = new SpriteIcon { diff --git a/osu.Game/Graphics/UserInterfaceV2/FormFieldCaption.cs b/osu.Game/Graphics/UserInterfaceV2/FormFieldCaption.cs index 75c27618e9e4..3bc54359b850 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormFieldCaption.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormFieldCaption.cs @@ -2,19 +2,20 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.Containers; using osuTK; namespace osu.Game.Graphics.UserInterfaceV2 { public partial class FormFieldCaption : CompositeDrawable, IHasTooltip { + private OsuTextFlowContainer textFlow = null!; + private LocalisableString caption; public LocalisableString Caption @@ -24,45 +25,60 @@ public LocalisableString Caption { caption = value; - if (captionText.IsNotNull()) - captionText.Text = value; + if (IsLoaded) + updateDisplay(); } } - private OsuSpriteText captionText = null!; + private LocalisableString tooltipText; - public LocalisableString TooltipText { get; set; } + public LocalisableString TooltipText + { + get => tooltipText; + set + { + tooltipText = value; + + if (IsLoaded) + updateDisplay(); + } + } [BackgroundDependencyLoader] private void load() { - AutoSizeAxes = Axes.Both; + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; - InternalChild = new FillFlowContainer + InternalChild = textFlow = new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(size: 12, weight: FontWeight.SemiBold)) { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5), - Children = new Drawable[] - { - captionText = new OsuSpriteText - { - Text = caption, - Font = OsuFont.Default.With(size: 12, weight: FontWeight.SemiBold), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - new SpriteIcon - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Alpha = TooltipText == default ? 0 : 1, - Size = new Vector2(10), - Icon = FontAwesome.Solid.QuestionCircle, - Margin = new MarginPadding { Top = 1, }, - } - }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, }; } + + protected override void LoadComplete() + { + base.LoadComplete(); + updateDisplay(); + } + + private void updateDisplay() + { + textFlow.Text = caption; + + if (TooltipText != default) + { + textFlow.AddArbitraryDrawable(new SpriteIcon + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Size = new Vector2(10), + Icon = FontAwesome.Solid.QuestionCircle, + Margin = new MarginPadding { Left = 5 }, + Y = 1f, + }); + } + } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs b/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs index fe4e764836d3..8f402e4da9e3 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs @@ -117,34 +117,46 @@ private void load() new Container { RelativeSizeAxes = Axes.X, - Height = 50, + AutoSizeAxes = Axes.Y, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Padding = new MarginPadding(9), Children = new Drawable[] { - caption = new FormFieldCaption - { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Caption = Caption, - TooltipText = HintText, - }, - placeholderText = new OsuSpriteText - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - Width = 1, - Text = PlaceholderText, - Colour = colourProvider.Foreground1, - }, - filenameText = new OsuSpriteText + new FillFlowContainer { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.X, - Width = 1, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0f, 4f), + Children = new Drawable[] + { + caption = new FormFieldCaption + { + Caption = Caption, + TooltipText = HintText, + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new[] + { + placeholderText = new OsuSpriteText + { + RelativeSizeAxes = Axes.X, + Width = 1, + Text = PlaceholderText, + Colour = colourProvider.Foreground1, + }, + filenameText = new OsuSpriteText + { + RelativeSizeAxes = Axes.X, + Width = 1, + }, + } + } + }, }, new SpriteIcon { @@ -242,7 +254,8 @@ Task ICanAcceptFiles.Import(params string[] paths) Task ICanAcceptFiles.Import(ImportTask[] tasks, ImportParameters parameters) => throw new NotImplementedException(); - protected virtual FileChooserPopover CreatePopover(string[] handledExtensions, Bindable current, string? chooserPath) => new FileChooserPopover(handledExtensions, current, chooserPath); + protected virtual FileChooserPopover CreatePopover(string[] handledExtensions, Bindable current, string? chooserPath) => + new FileChooserPopover(handledExtensions, current, chooserPath); public Popover GetPopover() { diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 310be77f31de..625967dc6620 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -22,6 +22,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays; +using Vector2 = osuTK.Vector2; namespace osu.Game.Graphics.UserInterfaceV2 { @@ -143,7 +144,7 @@ public FormSliderBar() private void load(OsuColour colours, OsuGame? game) { RelativeSizeAxes = Axes.X; - Height = 50; + AutoSizeAxes = Axes.Y; Masking = true; CornerRadius = 5; @@ -162,47 +163,64 @@ private void load(OsuColour colours, OsuGame? game) }, new Container { - RelativeSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, Padding = new MarginPadding { - Vertical = 9, + Vertical = 5, Left = 9, Right = 5, }, Children = new Drawable[] { - captionText = new FormFieldCaption - { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - TooltipText = HintText, - }, - textBox = new FormNumberBox.InnerNumberBox(allowDecimals: true) + new FillFlowContainer { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0f, 4f), Width = 0.5f, - // the textbox is hidden when the control is unfocused, - // but clicking on the label should reach the textbox, - // therefore make it always present. - AlwaysPresent = true, - CommitOnFocusLost = true, - SelectAllOnFocus = true, - OnInputError = () => + Padding = new MarginPadding { - flashLayer.Colour = ColourInfo.GradientVertical(colours.Red3.Opacity(0), colours.Red3); - flashLayer.FadeOutFromOne(200, Easing.OutQuint); + Right = 10, + Vertical = 4, + }, + Children = new Drawable[] + { + captionText = new FormFieldCaption + { + TooltipText = HintText, + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + textBox = new FormNumberBox.InnerNumberBox(allowDecimals: true) + { + RelativeSizeAxes = Axes.X, + // the textbox is hidden when the control is unfocused, + // but clicking on the label should reach the textbox, + // therefore make it always present. + AlwaysPresent = true, + CommitOnFocusLost = true, + SelectAllOnFocus = true, + OnInputError = () => + { + flashLayer.Colour = ColourInfo.GradientVertical(colours.Red3.Opacity(0), colours.Red3); + flashLayer.FadeOutFromOne(200, Easing.OutQuint); + }, + TabbableContentContainer = tabbableContentContainer, + }, + valueLabel = new TruncatingSpriteText + { + RelativeSizeAxes = Axes.X, + Padding = new MarginPadding { Right = 5 }, + }, + }, + }, }, - TabbableContentContainer = tabbableContentContainer, - }, - valueLabel = new TruncatingSpriteText - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - Width = 0.5f, - Padding = new MarginPadding { Right = 5 }, }, slider = new InnerSlider { diff --git a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs index 6429eb6e960c..b85ee3d2c8fe 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs @@ -19,6 +19,7 @@ using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; +using osuTK; namespace osu.Game.Graphics.UserInterfaceV2 { @@ -89,7 +90,7 @@ public CompositeDrawable? TabbableContentContainer private void load(OsuColour colours) { RelativeSizeAxes = Axes.X; - Height = 50; + AutoSizeAxes = Axes.Y; Masking = true; CornerRadius = 5; @@ -107,10 +108,12 @@ private void load(OsuColour colours) RelativeSizeAxes = Axes.Both, Colour = Colour4.Transparent, }, - new Container + new FillFlowContainer { - RelativeSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, Padding = new MarginPadding(9), + Spacing = new Vector2(0, 4), Children = new Drawable[] { caption = new FormFieldCaption @@ -122,8 +125,6 @@ private void load(OsuColour colours) }, textBox = CreateTextBox().With(t => { - t.Anchor = Anchor.BottomRight; - t.Origin = Anchor.BottomRight; t.RelativeSizeAxes = Axes.X; t.Width = 1; t.PlaceholderText = PlaceholderText; From 61d0b5a03c4bccb179ae08a0eac43660ff6524ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Jan 2026 15:01:28 +0900 Subject: [PATCH 419/836] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index f7360ab1d85f..b282963aac98 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From 86220622fbd477a31ce8fc2d5135642e2dc6c876 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 6 Jan 2026 17:20:28 +0900 Subject: [PATCH 420/836] Remove HoldForMenuButton player dependency --- osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +- .../Visual/Gameplay/TestSceneHUDOverlayRulesetLayouts.cs | 2 +- .../Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs | 2 +- .../Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +- osu.Game/Screens/Play/HUD/HoldForMenuButton.cs | 6 +++--- osu.Game/Screens/Play/HUDOverlay.cs | 6 ++++-- osu.Game/Screens/Play/Player.cs | 2 +- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index d51c9b3f8836..1e6e0007b555 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -270,7 +270,7 @@ private void createNew(Action? action = null) { AddStep("create overlay", () => { - hudOverlay = new HUDOverlay(null, Array.Empty()); + hudOverlay = new HUDOverlay(null, Array.Empty(), new PlayerConfiguration()); // Add any key just to display the key counter visually. hudOverlay.InputCountController.Add(new KeyCounterKeyboardTrigger(Key.Space)); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlayRulesetLayouts.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlayRulesetLayouts.cs index 47791dd46207..e67c2d9f090c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlayRulesetLayouts.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlayRulesetLayouts.cs @@ -119,7 +119,7 @@ public void TestLayout( Children = new Drawable[] { drawableRuleset, - new HUDOverlay(drawableRuleset, []) + new HUDOverlay(drawableRuleset, [], new PlayerConfiguration()) { RelativeSizeAxes = Axes.Both, } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs index 00369ade184f..76daffbbadba 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs @@ -60,7 +60,7 @@ public void SetUpSteps() var drawableRuleset = ruleset.CreateDrawableRulesetWith(beatmap, mods); - var hudOverlay = new HUDOverlay(drawableRuleset, mods) + var hudOverlay = new HUDOverlay(drawableRuleset, mods, new PlayerConfiguration()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs index 754ec841d852..6e4f3af70a25 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs @@ -96,7 +96,7 @@ private void createNew(Action action = null) { SetContents(_ => { - hudOverlay = new HUDOverlay(new DrawableOsuRuleset(new OsuRuleset(), new OsuBeatmap()), Array.Empty()); + hudOverlay = new HUDOverlay(new DrawableOsuRuleset(new OsuRuleset(), new OsuBeatmap()), Array.Empty(), new PlayerConfiguration()); action?.Invoke(hudOverlay); diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index c271adc057d2..01314c5de6d1 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -57,8 +57,8 @@ public HoldForMenuButton(bool isDangerousAction = false) AlwaysPresent = true; } - [BackgroundDependencyLoader(true)] - private void load(Player player, OsuConfigManager config) + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) { Children = new Drawable[] { @@ -68,7 +68,7 @@ private void load(Player player, OsuConfigManager config) Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft }, - button = new HoldButton(isDangerousAction || player?.Configuration.AllowRestart == false) + button = new HoldButton(isDangerousAction) { HoverGained = () => text.FadeIn(500, Easing.OutQuint), HoverLost = () => text.FadeOut(500, Easing.OutQuint), diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 806e59372901..d7283b227fb4 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -73,6 +73,7 @@ protected override bool ShouldBeConsideredForInput(Drawable child) private readonly DrawableRuleset drawableRuleset; private readonly IReadOnlyList mods; + private readonly PlayerConfiguration configuration; /// /// Whether the elements that can optionally be hidden should be visible. @@ -113,12 +114,13 @@ protected override bool ShouldBeConsideredForInput(Drawable child) /// internal readonly Drawable PlayfieldSkinLayer; - public HUDOverlay([CanBeNull] DrawableRuleset drawableRuleset, IReadOnlyList mods) + public HUDOverlay([CanBeNull] DrawableRuleset drawableRuleset, IReadOnlyList mods, PlayerConfiguration configuration) { Container rightSettings; this.drawableRuleset = drawableRuleset; this.mods = mods; + this.configuration = configuration; RelativeSizeAxes = Axes.Both; @@ -391,7 +393,7 @@ protected virtual void BindDrawableRuleset(DrawableRuleset drawableRuleset) ShowHealth = { BindTarget = ShowHealthBar } }; - protected HoldForMenuButton CreateHoldForMenuButton() => new HoldForMenuButton + protected HoldForMenuButton CreateHoldForMenuButton() => new HoldForMenuButton(!configuration.AllowRestart) { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 21e0d3c8b95f..ba543db996fb 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -474,7 +474,7 @@ private Drawable createOverlayComponents() Children = new[] { DimmableStoryboard.OverlayLayerContainer.CreateProxy(), - HUDOverlay = new HUDOverlay(DrawableRuleset, GameplayState.Mods) + HUDOverlay = new HUDOverlay(DrawableRuleset, GameplayState.Mods, Configuration) { HoldToQuit = { From 679c6d022954eef1310b0774299070a990a3188e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 6 Jan 2026 17:25:08 +0900 Subject: [PATCH 421/836] Remove `Masking` definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Screens/Play/PlayerLoader.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 34577c1e56be..bfec95018faf 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -237,8 +237,7 @@ private void load(SessionStatics sessionStatics, OsuConfigManager config) Width = SettingsToolboxGroup.CONTAINER_WIDTH + padding * 2, Padding = new MarginPadding { - Top = padding, - Bottom = ScreenFooter.HEIGHT + padding + Bottom = ScreenFooter.HEIGHT }, RowDimensions = [ @@ -252,13 +251,16 @@ private void load(SessionStatics sessionStatics, OsuConfigManager config) settingsScroll = new OsuScrollContainer { RelativeSizeAxes = Axes.Both, - Masking = holdForMenuExitButton, Child = PlayerSettings = new FillFlowContainer { AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, Spacing = new Vector2(0, 20), - Padding = new MarginPadding { Horizontal = padding }, + Padding = new MarginPadding + { + Horizontal = padding, + Vertical = padding, + }, Children = new PlayerSettingsGroup[] { VisualSettings = new VisualSettings(), @@ -282,6 +284,7 @@ private void load(SessionStatics sessionStatics, OsuConfigManager config) { Top = 20, Horizontal = padding, + Bottom = padding, }, Action = () => { From 53a5157a2f9278ec0f0b1d730edc86315b772260 Mon Sep 17 00:00:00 2001 From: Jonas Schips <104238285+jonaasdev@users.noreply.github.com> Date: Tue, 6 Jan 2026 13:10:34 +0100 Subject: [PATCH 422/836] feat: added whitespace between "fps"/"ms" and it's value to prevent clipping --- osu.Game/Graphics/UserInterface/FPSCounter.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/FPSCounter.cs b/osu.Game/Graphics/UserInterface/FPSCounter.cs index 000b85b9004c..190d88a6e464 100644 --- a/osu.Game/Graphics/UserInterface/FPSCounter.cs +++ b/osu.Game/Graphics/UserInterface/FPSCounter.cs @@ -232,14 +232,14 @@ private void requestDisplay() private void updateFpsDisplay() { counterDrawFPS.Colour = getColour(displayedFpsCount / aimDrawFPS); - counterDrawFPS.Text = $"{displayedFpsCount:#,0}fps"; + counterDrawFPS.Text = $"{displayedFpsCount:#,0} fps"; } private void updateFrameTimeDisplay() { counterUpdateFrameTime.Text = displayedFrameTime < 5 - ? $"{displayedFrameTime:N1}ms" - : $"{displayedFrameTime:N0}ms"; + ? $"{displayedFrameTime:N1} ms" + : $"{displayedFrameTime:N0} ms"; counterUpdateFrameTime.Colour = getColour((1000 / displayedFrameTime) / aimUpdateFPS); } From 86a3c19547634d5d8314b371856a47e4a67a5c3a Mon Sep 17 00:00:00 2001 From: Jonas Schips <104238285+jonaasdev@users.noreply.github.com> Date: Tue, 6 Jan 2026 13:37:10 +0100 Subject: [PATCH 423/836] feat: added whitespaces between "fps"/"ms" and it's value in FPSCounterTooltip.cs --- osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs b/osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs index e64a4c6c0751..2faf03d2f414 100644 --- a/osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs +++ b/osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs @@ -82,7 +82,7 @@ protected override void Update() ? $"/{(clock.MaximumUpdateHz > 0 && clock.MaximumUpdateHz < 10000 ? clock.MaximumUpdateHz.ToString("0") : "∞"),4}" : string.Empty; - textFlow.AddParagraph($"{clock.FramesPerSecond:0}{maximum}fps ({clock.ElapsedFrameTime:0.00}ms)"); + textFlow.AddParagraph($"{clock.FramesPerSecond:0}{maximum} fps ({clock.ElapsedFrameTime:0.00} ms)"); } } } From 8cbcb0e74f8aea2cc0e4830ab489f882233ba234 Mon Sep 17 00:00:00 2001 From: UltraDrakon Date: Tue, 6 Jan 2026 14:51:07 +0100 Subject: [PATCH 424/836] Hide cursor during background reveal in song select - Implement IProvideCursor in SongSelect to hide cursor when background is revealed - Cursor reappears on mouse movement and hides again after 1 second of inactivity - Fix MenuCursorContainer to preserve drag rotation state during hide/show cycles --- .../Graphics/Cursor/MenuCursorContainer.cs | 10 +++++--- osu.Game/Screens/SelectV2/SongSelect.cs | 25 ++++++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index 696ea62b42d8..2ea30d86bd5c 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -220,16 +220,18 @@ protected override void PopIn() { activeCursor.FadeTo(1, 250, Easing.OutQuint); activeCursor.ScaleTo(1, 400, Easing.OutQuint); - activeCursor.RotateTo(0, 400, Easing.OutQuint); - dragRotationState = DragRotationState.NotDragging; + + if (dragRotationState == DragRotationState.NotDragging) + activeCursor.RotateTo(0, 400, Easing.OutQuint); } protected override void PopOut() { activeCursor.FadeTo(0, 250, Easing.OutQuint); activeCursor.ScaleTo(0.6f, 250, Easing.In); - activeCursor.RotateTo(0, 400, Easing.OutQuint); - dragRotationState = DragRotationState.NotDragging; + + if (dragRotationState == DragRotationState.NotDragging) + activeCursor.RotateTo(0, 400, Easing.OutQuint); } private void playTapSample(double baseFrequency = 1f) diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index 4bee63b57c4e..e0e6e8842a27 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -64,7 +64,7 @@ namespace osu.Game.Screens.SelectV2 /// This will be gradually built upon and ultimately replace once everything is in place. /// [Cached(typeof(ISongSelect))] - public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler, ISongSelect, IHandlePresentBeatmap + public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler, ISongSelect, IHandlePresentBeatmap, IProvideCursor { /// /// A debounce that governs how long after a panel is selected before the rest of song select (and the game at large) @@ -911,6 +911,23 @@ private void updateNoResultsPlaceholder() #region Input private ScheduledDelegate? revealingBackground; + private bool isRevealingBackground; + private double? lastCursorMoveTimeDuringReveal; + + private bool cursorRecentlyMoved => lastCursorMoveTimeDuringReveal.HasValue && + Clock.CurrentTime - lastCursorMoveTimeDuringReveal.Value < 1000; + + public CursorContainer? Cursor => null; + public bool ProvidingUserCursor => isRevealingBackground && !cursorRecentlyMoved; + + protected override bool OnHover(HoverEvent e) => true; + + protected override bool OnMouseMove(MouseMoveEvent e) + { + if (isRevealingBackground) + lastCursorMoveTimeDuringReveal = Clock.CurrentTime; + return base.OnMouseMove(e); + } private GridContainer mainGridContainer = null!; @@ -948,6 +965,9 @@ protected override bool OnMouseDown(MouseDownEvent e) updateBackgroundDim(); Footer?.Hide(); + + isRevealingBackground = true; + lastCursorMoveTimeDuringReveal = null; }, 200); } @@ -981,6 +1001,9 @@ private void restoreBackground() revealingBackground.Cancel(); revealingBackground = null; + isRevealingBackground = false; + lastCursorMoveTimeDuringReveal = null; + updateBackgroundDim(); } From d05acc3d4f0a890074823a7134617402eabe1e4b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Jan 2026 22:54:27 +0900 Subject: [PATCH 425/836] Fix tray showing first item too far to left --- .../Playlists/PlaylistsSongSelectV2.PlaylistTray.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs index 1b44106e36b2..f634daf48195 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs @@ -29,6 +29,8 @@ public partial class PlaylistTray : CompositeDrawable private FillFlowContainer flow = null!; private OsuSpriteText text = null!; + private const float item_width = 250; + public PlaylistTray(Room room) { this.room = room; @@ -107,6 +109,7 @@ private void load(OverlayColourProvider colourProvider) { RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, + Padding = new MarginPadding { Left = item_width }, Spacing = new Vector2(5), Direction = FillDirection.Horizontal } @@ -150,7 +153,7 @@ private void updateRoomPlaylist() var newItem = new DrawableRoomPlaylistItem(room.Playlist[^1], loadImmediately: true) { RelativeSizeAxes = Axes.None, - Width = 250, + Width = item_width, AllowReordering = false, }; @@ -159,7 +162,8 @@ private void updateRoomPlaylist() flow.Add(newItem); - scroll.ScrollToStart(animated: false); + if (scroll.IsLoaded) + scroll.ScrollToStart(animated: false); ScheduleAfterChildren(() => scroll.ScrollToEnd()); Scheduler.AddDelayed(() => text.Text = $"{room.Playlist.Count} item(s)", 100); From 85747f88660b8381688edadeb2f268f9d9cb1c61 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Jan 2026 23:24:31 +0900 Subject: [PATCH 426/836] Fix replay settings appearing momentarily when replay is not loaded Closes #36237. --- osu.Game/Screens/Play/HUDOverlay.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 806e59372901..c2e5a4327d5d 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -173,7 +173,10 @@ public HUDOverlay([CanBeNull] DrawableRuleset drawableRuleset, IReadOnlyList Date: Tue, 6 Jan 2026 23:24:49 +0900 Subject: [PATCH 427/836] Fix settings toggle for replay settings overlay not being obeyed in multiplayer spectator Noticed in passing. --- .../Spectate/MultiSpectatorScreen.cs | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index fb9343c51903..f0b0709ab2aa 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -6,9 +6,11 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Logging; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; @@ -63,6 +65,9 @@ public partial class MultiSpectatorScreen : SpectatorScreen private readonly Room room; + private PlayerSettingsOverlay playerSettingsOverlay = null!; + private Bindable configSettingsOverlay = null!; + /// /// Creates a new . /// @@ -78,8 +83,10 @@ public MultiSpectatorScreen(Room room, MultiplayerRoomUser[] users) } [BackgroundDependencyLoader] - private void load() + private void load(OsuConfigManager config) { + configSettingsOverlay = config.GetBindable(OsuSetting.ReplaySettingsOverlay); + FillFlowContainer leaderboardFlow; Container scoreDisplayContainer; @@ -131,7 +138,10 @@ private void load() { ReadyToStart = performInitialSeek, }, - new PlayerSettingsOverlay() + playerSettingsOverlay = new PlayerSettingsOverlay + { + Alpha = 0, + } }; for (int i = 0; i < Users.Count; i++) @@ -172,6 +182,16 @@ protected override void LoadComplete() // Start with adjustments from the first player to keep a sane state. bindAudioAdjustments(instances.First()); + + configSettingsOverlay.BindValueChanged(_ => updateVisibility(), true); + } + + private void updateVisibility() + { + if (configSettingsOverlay.Value) + playerSettingsOverlay.Show(); + else + playerSettingsOverlay.Hide(); } protected override void Update() From 3ae98fd6649c72e561dcdde498ecd519c75f35d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 7 Jan 2026 10:21:04 +0100 Subject: [PATCH 428/836] Fix broken transition of player loader right side content (#36261) before: https://github.com/user-attachments/assets/dd9bfef0-d653-4aa6-b48d-fe01774d3f89 after: https://github.com/user-attachments/assets/bb3541f9-65f2-4c34-9943-ba2b63b7dbf8 regressed in 2b90cbf59f32c9cf98933a895890c3af1e9b05ca --- osu.Game/Screens/Play/PlayerLoader.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index bfec95018faf..df535169b3b1 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -85,7 +85,7 @@ public partial class PlayerLoader : ScreenWithBeatmapBackground protected Task? DisposalTask { get; private set; } private FillFlowContainer disclaimers = null!; - private OsuScrollContainer settingsScroll = null!; + private GridContainer sideContent = null!; private Bindable showStoryboards = null!; @@ -229,7 +229,7 @@ private void load(SessionStatics sessionStatics, OsuConfigManager config) Padding = new MarginPadding(padding), Spacing = new Vector2(20), }, - new GridContainer + sideContent = new GridContainer { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, @@ -248,7 +248,7 @@ private void load(SessionStatics sessionStatics, OsuConfigManager config) { new Drawable[] { - settingsScroll = new OsuScrollContainer + new OsuScrollContainer { RelativeSizeAxes = Axes.Both, Child = PlayerSettings = new FillFlowContainer @@ -354,7 +354,7 @@ public override void OnEntering(ScreenTransitionEvent e) // Start side content off-screen. disclaimers.MoveToX(-disclaimers.DrawWidth); - settingsScroll.MoveToX(settingsScroll.DrawWidth); + sideContent.MoveToX(sideContent.DrawWidth); content.ScaleTo(0.7f); @@ -600,8 +600,8 @@ private void contentIn(double delayBeforeSideDisplays = 0) using (BeginDelayedSequence(delayBeforeSideDisplays)) { - settingsScroll.FadeInFromZero(500, Easing.Out) - .MoveToX(0, 500, Easing.OutQuint); + sideContent.FadeInFromZero(500, Easing.Out) + .MoveToX(0, 500, Easing.OutQuint); disclaimers.FadeInFromZero(500, Easing.Out) .MoveToX(0, 500, Easing.OutQuint); @@ -641,8 +641,8 @@ protected virtual void ContentOut() disclaimers.FadeOut(CONTENT_OUT_DURATION, Easing.Out) .MoveToX(-disclaimers.DrawWidth, CONTENT_OUT_DURATION * 2, Easing.OutQuint); - settingsScroll.FadeOut(CONTENT_OUT_DURATION, Easing.OutQuint) - .MoveToX(settingsScroll.DrawWidth, CONTENT_OUT_DURATION * 2, Easing.OutQuint); + sideContent.FadeOut(CONTENT_OUT_DURATION, Easing.OutQuint) + .MoveToX(sideContent.DrawWidth, CONTENT_OUT_DURATION * 2, Easing.OutQuint); lowPassFilter?.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF, CONTENT_OUT_DURATION); highPassFilter?.CutoffTo(0, CONTENT_OUT_DURATION); From 7f99650a047074d33c6b223e31d5f78a381db6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 7 Jan 2026 11:08:51 +0100 Subject: [PATCH 429/836] Add test covering desired behaviour of dismissing beatmap set scope --- .../TestSceneSongSelectFiltering.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs index a83ec3377821..3eb97cf2dd04 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs @@ -398,6 +398,30 @@ public void TestScopeToBeatmapWhenDifficultiesGroupedBySet() checkMatchedBeatmaps(6); } + [Test] + public void TestDismissingScopeDoesNotClearSearchTextBox() + { + ImportBeatmapForRuleset(0); + ImportBeatmapForRuleset(0); + + LoadSongSelect(); + SortBy(SortMode.Artist); + checkMatchedBeatmaps(6); + + AddStep("set text filter", () => filterTextBox.Current.Value = Beatmaps.GetAllUsableBeatmapSets().First().Metadata.Title); + WaitForFiltering(); + checkMatchedBeatmaps(3); + + AddStep("click spread indicator", () => this.ChildrenOfType().Single(d => d.Enabled.Value).TriggerClick()); + WaitForFiltering(); + checkMatchedBeatmaps(3); + + AddStep("press Escape", () => InputManager.Key(Key.Escape)); + WaitForFiltering(); + checkMatchedBeatmaps(3); + AddAssert("text filter not emptied", () => filterTextBox.Current.Value, () => Is.Not.Empty); + } + private NoResultsPlaceholder? getPlaceholder() => SongSelect.ChildrenOfType().FirstOrDefault(); private void checkMatchedBeatmaps(int expected) => AddUntilStep($"{expected} matching shown", () => Carousel.MatchedBeatmapsCount, () => Is.EqualTo(expected)); From 9b26b83d55a4bba4204e60a8786da779c818feeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 7 Jan 2026 11:13:33 +0100 Subject: [PATCH 430/836] Fix beatmap scope dismiss bar showing on top of filter control dropdowns closes https://github.com/ppy/osu/issues/36259 --- osu.Game/Screens/SelectV2/FilterControl.cs | 32 ++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/SelectV2/FilterControl.cs b/osu.Game/Screens/SelectV2/FilterControl.cs index 88a527b66c26..268e9371678f 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.cs +++ b/osu.Game/Screens/SelectV2/FilterControl.cs @@ -19,6 +19,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Input.Bindings; using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; @@ -114,6 +115,7 @@ private void load(IAPIProvider api) { RelativeSizeAxes = Axes.X, HoldFocus = true, + ScopedBeatmapSet = ScopedBeatmapSet, }, }, new GridContainer @@ -189,7 +191,6 @@ private void load(IAPIProvider api) new ScopedBeatmapSetDisplay { ScopedBeatmapSet = ScopedBeatmapSet, - Depth = float.MinValue, // hack to ensure that the scoped display handles `GlobalAction.Back` input before the filter control } }, } @@ -330,12 +331,39 @@ protected override void PopOut() internal partial class SongSelectSearchTextBox : ShearedFilterTextBox { - protected override InnerSearchTextBox CreateInnerTextBox() => new InnerTextBox(); + public Bindable ScopedBeatmapSet + { + get => scopedBeatmapSet.Current; + set => scopedBeatmapSet.Current = value; + } + + private readonly BindableWithCurrent scopedBeatmapSet = new BindableWithCurrent(); + + protected override InnerSearchTextBox CreateInnerTextBox() => new InnerTextBox + { + ScopedBeatmapSet = ScopedBeatmapSet, + }; private partial class InnerTextBox : InnerFilterTextBox { + public Bindable ScopedBeatmapSet + { + get => scopedBeatmapSet.Current; + set => scopedBeatmapSet.Current = value; + } + + private readonly BindableWithCurrent scopedBeatmapSet = new BindableWithCurrent(); + public override bool HandleLeftRightArrows => false; + public override bool OnPressed(KeyBindingPressEvent e) + { + if (e.Action == GlobalAction.Back && scopedBeatmapSet.Value != null) + return false; + + return base.OnPressed(e); + } + public override bool OnPressed(KeyBindingPressEvent e) { // Conflicts with default group navigation keys (shift-left shift-right). From 48de70e719e8fab05ea7abc81794128808aef66f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 7 Jan 2026 13:03:20 +0100 Subject: [PATCH 431/836] Log version hash to sentry This is the counterpart to https://github.com/ppy/osu-server-spectator/pull/413. The goal is to log the value which is seemingly failing to work correctly client-side as well. The reason for doing that is two-fold: - To eliminate possibility of freakazoid issues wherein some computers miscalculate the version hash somehow - To eliminate possibility of the version hash somehow getting lost in transit (e.g. present client-side but no longer present server-side). --- osu.Game/Utils/SentryLogger.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Utils/SentryLogger.cs b/osu.Game/Utils/SentryLogger.cs index aa1fd429a74c..9b3b78cd0e29 100644 --- a/osu.Game/Utils/SentryLogger.cs +++ b/osu.Game/Utils/SentryLogger.cs @@ -176,6 +176,7 @@ private void processLogEntry(LogEntry entry) scope.SetTag(@"beatmap", $"{beatmap.OnlineID}"); scope.SetTag(@"ruleset", ruleset.ShortName); scope.SetTag(@"os", $"{RuntimeInfo.OS} ({Environment.OSVersion})"); + scope.SetTag(@"version hash", game.VersionHash); scope.SetTag(@"processor count", Environment.ProcessorCount.ToString()); }); } From 3157e82f51d1711817597a9adfc8322ca736ecf7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Jan 2026 01:45:02 +0900 Subject: [PATCH 432/836] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 6d667fb81419..146becc7c993 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index ec09350de6f4..3e2f63780e9f 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From 2963ebae963596b36356c0928170ae245c78c223 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Jan 2026 02:04:18 +0900 Subject: [PATCH 433/836] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 3bd38bb2a44a..4e0138afd1a7 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From 3f577aae602fbd27b8c462ea7b6c419c8632c59b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Jan 2026 15:18:29 +0900 Subject: [PATCH 434/836] Fix now playing overlay buttons not showing toggle colour correctly Closes https://github.com/ppy/osu/issues/36280. --- osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs index 31ac777eaaa0..8faa5322169b 100644 --- a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs @@ -93,7 +93,7 @@ protected override void LoadComplete() base.LoadComplete(); Colour = DimColour; - Enabled.BindValueChanged(_ => this.FadeColour(DimColour, 200, Easing.OutQuint), true); + Enabled.BindValueChanged(_ => content.FadeColour(DimColour, 200, Easing.OutQuint), true); FinishTransforms(true); } From 23c68cbfea109c7fc38f7239ee4458e81aea4495 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Jan 2026 19:28:33 +0900 Subject: [PATCH 435/836] Add support for global rank parsing in /users/ batch lookups See https://github.com/ppy/osu-web/pull/12651 for web-side implementation. To be used to fix https://github.com/ppy/osu/pull/33649/changes#diff-32784a778b34c671e1f72c00e1f4161a5e774e849aae5631ee71b31fc32e5d42R218 (have tested this works there). Use simple set-get rather than transforming to `APIUser.Statistics` --- osu.Game/Online/API/Requests/LookupUsersRequest.cs | 9 +++++++-- osu.Game/Online/API/Requests/Responses/APIUser.cs | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/LookupUsersRequest.cs b/osu.Game/Online/API/Requests/LookupUsersRequest.cs index 6e98ce064e9a..99c1c551e4f1 100644 --- a/osu.Game/Online/API/Requests/LookupUsersRequest.cs +++ b/osu.Game/Online/API/Requests/LookupUsersRequest.cs @@ -10,21 +10,26 @@ namespace osu.Game.Online.API.Requests /// Looks up users with the given . /// In comparison to , the response here does not contain , /// but in exchange is subject to less stringent rate limiting, making it suitable for mass user listings. + /// + /// Providing a ruleset ID will give `global_rank`s in the response. /// public class LookupUsersRequest : APIRequest { public readonly int[] UserIds; + public readonly int? RulesetId; + private const int max_ids_per_request = 50; - public LookupUsersRequest(int[] userIds) + public LookupUsersRequest(int[] userIds, int? rulesetId = null) { if (userIds.Length > max_ids_per_request) throw new ArgumentException($"{nameof(LookupUsersRequest)} calls only support up to {max_ids_per_request} IDs at once"); UserIds = userIds; + RulesetId = rulesetId; } - protected override string Target => @"users/lookup/?ids[]=" + string.Join(@"&ids[]=", UserIds); + protected override string Target => @"users/lookup/?ids[]=" + string.Join(@"&ids[]=", UserIds) + (RulesetId != null ? "&ruleset_id=" + RulesetId : ""); } } diff --git a/osu.Game/Online/API/Requests/Responses/APIUser.cs b/osu.Game/Online/API/Requests/Responses/APIUser.cs index 6f122c58afd5..fa90e5cd509c 100644 --- a/osu.Game/Online/API/Requests/Responses/APIUser.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUser.cs @@ -247,6 +247,20 @@ public UserStatistics Statistics } } + // Only provided via /users/ batch lookups. Usually implicitly comes inside `UserStatistics`. + [JsonProperty(@"global_rank")] + [CanBeNull] + public GlobalRank Rank { get; set; } + + public class GlobalRank + { + [JsonProperty(@"rank")] + public int? Rank; + + [JsonProperty(@"ruleset_id")] + public int RulesetId; + } + [JsonProperty(@"rank_history")] private APIRankHistory rankHistory { From a2d2c3287bc90836ecd383e678abd9170382a482 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Jan 2026 16:27:33 +0900 Subject: [PATCH 436/836] Remove unnecessary and incorrect colour application --- osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs index 8faa5322169b..87aa4547d4bf 100644 --- a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs @@ -92,7 +92,6 @@ protected override void LoadComplete() { base.LoadComplete(); - Colour = DimColour; Enabled.BindValueChanged(_ => content.FadeColour(DimColour, 200, Easing.OutQuint), true); FinishTransforms(true); } From 5e4e28ef00073a76f27e05faaadaae75575bced2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Jan 2026 16:15:36 +0900 Subject: [PATCH 437/836] Fix online lookup cache not recovering from faulted tasks --- osu.Game/Database/OnlineLookupCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/OnlineLookupCache.cs b/osu.Game/Database/OnlineLookupCache.cs index 3b54804fecb2..cedb406048ff 100644 --- a/osu.Game/Database/OnlineLookupCache.cs +++ b/osu.Game/Database/OnlineLookupCache.cs @@ -81,7 +81,7 @@ public abstract partial class OnlineLookupCache : Mem pendingTasks.Enqueue((id, tcs)); // Create a request task if there's not already one. - if (pendingRequestTask == null) + if (pendingRequestTask == null || pendingRequestTask.IsFaulted) createNewTask(); return tcs.Task; From 576be6793bc7aac3fcc9d42ff1b71fdf84276a9c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Jan 2026 16:52:04 +0900 Subject: [PATCH 438/836] Add proper logging of failed scenario in `OnlineLookupCache` --- osu.Game/Database/OnlineLookupCache.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/OnlineLookupCache.cs b/osu.Game/Database/OnlineLookupCache.cs index cedb406048ff..a8bd5cbff252 100644 --- a/osu.Game/Database/OnlineLookupCache.cs +++ b/osu.Game/Database/OnlineLookupCache.cs @@ -8,6 +8,8 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Extensions; +using osu.Framework.Extensions.ExceptionExtensions; +using osu.Framework.Logging; using osu.Game.Online.API; namespace osu.Game.Database @@ -163,6 +165,14 @@ private void finishPendingTask() } } - private void createNewTask() => pendingRequestTask = Task.Run(performLookup); + private void createNewTask() + { + var nextTask = Task.Run(performLookup); + nextTask.ContinueWith(t => + { + Logger.Error(t.Exception.AsSingular(), $"{nameof(OnlineLookupCache)} lookup request failed!"); + }, TaskContinuationOptions.OnlyOnFaulted); + pendingRequestTask = nextTask; + } } } From 1c1a3fbe8d8f347abd5a7764085c44808c56c291 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Jan 2026 18:00:12 +0900 Subject: [PATCH 439/836] Simplify logic --- osu.Game/Screens/SelectV2/SongSelect.cs | 48 +++++++++---------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index e0e6e8842a27..e25597b64240 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -119,6 +119,8 @@ public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBind private Container mainContent = null!; private SkinnableContainer skinnableContent = null!; + private GridContainer mainGridContainer = null!; + private NoResultsPlaceholder noResultsPlaceholder = null!; public override bool? ApplyModTrackAdjustments => true; @@ -812,7 +814,7 @@ private void updateBackgroundDim() => ApplyToBackground(backgroundModeBeatmap => // Probably needs more thought because this needs to be in every `ApplyToBackground` currently to restore sane defaults. backgroundModeBeatmap.FadeColour(Color4.White, 250); - bool backgroundRevealActive = revealingBackground?.State == ScheduledDelegate.RunState.Running || revealingBackground?.State == ScheduledDelegate.RunState.Complete; + bool backgroundRevealActive = revealBackgroundDelegate?.State == ScheduledDelegate.RunState.Running || revealBackgroundDelegate?.State == ScheduledDelegate.RunState.Complete; backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value && !backgroundRevealActive ? 20 : 0f; }); @@ -908,29 +910,15 @@ private void updateNoResultsPlaceholder() #endregion - #region Input - - private ScheduledDelegate? revealingBackground; - private bool isRevealingBackground; - private double? lastCursorMoveTimeDuringReveal; + #region Background reveal - private bool cursorRecentlyMoved => lastCursorMoveTimeDuringReveal.HasValue && - Clock.CurrentTime - lastCursorMoveTimeDuringReveal.Value < 1000; + private ScheduledDelegate? revealBackgroundDelegate; public CursorContainer? Cursor => null; - public bool ProvidingUserCursor => isRevealingBackground && !cursorRecentlyMoved; + bool IProvideCursor.ProvidingUserCursor => revealBackgroundDelegate?.Completed == true; protected override bool OnHover(HoverEvent e) => true; - protected override bool OnMouseMove(MouseMoveEvent e) - { - if (isRevealingBackground) - lastCursorMoveTimeDuringReveal = Clock.CurrentTime; - return base.OnMouseMove(e); - } - - private GridContainer mainGridContainer = null!; - protected override bool OnMouseDown(MouseDownEvent e) { var containingInputManager = GetContainingInputManager(); @@ -944,13 +932,13 @@ protected override bool OnMouseDown(MouseDownEvent e) // For simplicity, disable this functionality on mobile. bool isTouchInput = e.CurrentState.Mouse.LastSource is ISourcedFromTouch; - if (!carousel.AbsoluteScrolling && !isTouchInput && mouseDownPriority && revealingBackground == null) + if (!carousel.AbsoluteScrolling && !isTouchInput && mouseDownPriority && revealBackgroundDelegate == null) { - revealingBackground = Scheduler.AddDelayed(() => + revealBackgroundDelegate = Scheduler.AddDelayed(() => { if (containingInputManager.DraggedDrawable != null) { - revealingBackground = null; + revealBackgroundDelegate = null; return; } @@ -965,9 +953,6 @@ protected override bool OnMouseDown(MouseDownEvent e) updateBackgroundDim(); Footer?.Hide(); - - isRevealingBackground = true; - lastCursorMoveTimeDuringReveal = null; }, 200); } @@ -982,10 +967,10 @@ protected override void OnMouseUp(MouseUpEvent e) private void restoreBackground() { - if (revealingBackground == null) + if (revealBackgroundDelegate == null) return; - if (revealingBackground.State == ScheduledDelegate.RunState.Complete) + if (revealBackgroundDelegate.State == ScheduledDelegate.RunState.Complete) { mainContent.ResizeWidthTo(1f, 500, Easing.OutQuint); mainContent.ScaleTo(1, 500, Easing.OutQuint); @@ -998,15 +983,16 @@ private void restoreBackground() Footer?.Show(); } - revealingBackground.Cancel(); - revealingBackground = null; - - isRevealingBackground = false; - lastCursorMoveTimeDuringReveal = null; + revealBackgroundDelegate.Cancel(); + revealBackgroundDelegate = null; updateBackgroundDim(); } + #endregion + + #region Input + public virtual bool OnPressed(KeyBindingPressEvent e) { if (!this.IsCurrentScreen()) return false; From dda1c7f75b3f9dd630473ef46d4c866d9be190af Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Jan 2026 18:13:48 +0900 Subject: [PATCH 440/836] Fix failing test case due to mod overlay being moved to game level --- .../Navigation/TestSceneScreenNavigation.cs | 18 +++++++----------- .../TestSceneSkinEditorNavigation.cs | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index b1c9ab1dfb2c..e46d8f74a553 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -142,13 +142,12 @@ public void TestConfirmationRequiredToDiscardPlaylist(bool withPlaylistItemAdded [Test] public void TestExitSongSelectWithEscape() { - SoloSongSelect songSelect = null; ModSelectOverlay modSelect = null; - PushAndConfirm(() => songSelect = new SoloSongSelect()); + PushAndConfirm(() => new SoloSongSelect()); AddStep("Show mods overlay", () => { - modSelect = songSelect!.ChildrenOfType().Single(); + modSelect = Game!.ChildrenOfType().Single(); modSelect.Show(); }); AddAssert("Overlay was shown", () => modSelect.State.Value == Visibility.Visible); @@ -310,11 +309,9 @@ public void TestSongSelectScrollHandling() [Test] public void TestOpenModSelectOverlayUsingAction() { - SoloSongSelect songSelect = null; - - PushAndConfirm(() => songSelect = new SoloSongSelect()); + PushAndConfirm(() => new SoloSongSelect()); AddStep("Show mods overlay", () => InputManager.Key(Key.F1)); - AddAssert("Overlay was shown", () => songSelect!.ChildrenOfType().Single().State.Value == Visibility.Visible); + AddAssert("Overlay was shown", () => Game!.ChildrenOfType().Single().State.Value == Visibility.Visible); } [Test] @@ -731,7 +728,7 @@ public void TestExitSongSelectWithClick() PushAndConfirm(() => songSelect = new SoloSongSelect()); AddStep("Show mods overlay", () => { - modSelect = songSelect!.ChildrenOfType().Single(); + modSelect = Game!.ChildrenOfType().Single(); modSelect.Show(); }); AddAssert("Overlay was shown", () => modSelect.State.Value == Visibility.Visible); @@ -806,13 +803,12 @@ public void TestModSelectInput() { AddUntilStep("Wait for toolbar to load", () => Game.Toolbar.IsLoaded); - SoloSongSelect songSelect = null; ModSelectOverlay modSelect = null; - PushAndConfirm(() => songSelect = new SoloSongSelect()); + PushAndConfirm(() => new SoloSongSelect()); AddStep("Show mods overlay", () => { - modSelect = songSelect!.ChildrenOfType().Single(); + modSelect = Game!.ChildrenOfType().Single(); modSelect.Show(); }); AddAssert("Overlay was shown", () => modSelect.State.Value == Visibility.Visible); diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index 0e1fa634395e..9ddeb7870ba2 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Navigation public partial class TestSceneSkinEditorNavigation : OsuGameTestScene { private SoloSongSelect songSelect; - private ModSelectOverlay modSelect => songSelect.ChildrenOfType().First(); + private ModSelectOverlay modSelect => Game.ChildrenOfType().First(); private SkinEditor skinEditor => Game.ChildrenOfType().FirstOrDefault(); From 3e7f0f4c619adfc5133dc443df14a1b7574223db Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Sat, 10 Jan 2026 20:30:48 +0500 Subject: [PATCH 441/836] Add star rating text gradient (#36292) Implements https://github.com/ppy/osu-web/pull/12363 There's one less colour in the spectrum than in the [web code](https://github.com/ppy/osu-web/pull/12363/changes#diff-a9bdefd7233ca98f7f89cd76213aba5d869ae0424c8e79d1e322abd3e43462fbR31) because the spectrum was actually defined incorrectly and has [one less domain entry than it should](https://github.com/ppy/osu-web/pull/12363/changes#diff-a9bdefd7233ca98f7f89cd76213aba5d869ae0424c8e79d1e322abd3e43462fbR29). I've chose to not add it because of consistency with the web and because it looked pretty ugly (it was pretty much unreadable) image image --- .../Colours/TestSceneStarDifficultyColours.cs | 41 ++++++++----------- .../Beatmaps/Drawables/StarRatingDisplay.cs | 15 +++---- osu.Game/Graphics/OsuColour.cs | 28 +++++++++++++ osu.Game/Screens/SelectV2/PanelBeatmap.cs | 13 +++--- .../SelectV2/PanelBeatmapStandalone.cs | 5 +-- 5 files changed, 60 insertions(+), 42 deletions(-) diff --git a/osu.Game.Tests/Visual/Colours/TestSceneStarDifficultyColours.cs b/osu.Game.Tests/Visual/Colours/TestSceneStarDifficultyColours.cs index 7f07563dfd4f..8ad7bf47b4e6 100644 --- a/osu.Game.Tests/Visual/Colours/TestSceneStarDifficultyColours.cs +++ b/osu.Game.Tests/Visual/Colours/TestSceneStarDifficultyColours.cs @@ -7,7 +7,9 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK; @@ -31,7 +33,7 @@ public void TestColours() AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, Spacing = new Vector2(5f), - ChildrenEnumerable = Enumerable.Range(0, 10).Select(i => new FillFlowContainer + ChildrenEnumerable = Enumerable.Range(0, 15).Select(i => new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -40,7 +42,9 @@ public void TestColours() Spacing = new Vector2(10f), ChildrenEnumerable = Enumerable.Range(0, 10).Select(j => { - var colour = colours.ForStarDifficulty(1f * i + 0.1f * j); + float difficulty = 1f * i + 0.1f * j; + var colour = colours.ForStarDifficulty(difficulty); + var textColour = colours.ForStarDifficultyText(difficulty); return new FillFlowContainer { @@ -48,36 +52,27 @@ public void TestColours() Origin = Anchor.Centre, AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, - Spacing = new Vector2(0f, 10f), + Spacing = new Vector2(0f, 5f), Children = new Drawable[] { - new CircularContainer + new OsuSpriteText { - Masking = true, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Size = new Vector2(75f, 25f), - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colour, - }, - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = OsuColour.ForegroundTextColourFor(colour), - Text = colour.ToHex(), - }, - } + Font = FontUsage.Default.With(size: 10), + Text = $"BG: {colour.ToHex()}", }, new OsuSpriteText { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = $"*{(1f * i + 0.1f * j):0.00}", + Font = FontUsage.Default.With(size: 10), + Text = $"Text: {textColour.ToHex()}", + }, + new StarRatingDisplay(new StarDifficulty(difficulty, 0)) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, } } }; diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs index c9f2f8a4b1df..991654638ff6 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs @@ -4,7 +4,6 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -12,7 +11,6 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Overlays; using osu.Game.Utils; using osuTK; using osuTK.Graphics; @@ -43,6 +41,12 @@ public Bindable Current /// public Color4 DisplayedDifficultyColour => background.Colour; + /// + /// The difficulty text colour currently displayed. + /// Can be used to have other components match the spectrum animation. + /// + public Color4 DisplayedDifficultyTextColour => starsText.Colour; + private readonly Bindable displayedStars = new BindableDouble(); /// @@ -54,9 +58,6 @@ public Bindable Current [Resolved] private OsuColour colours { get; set; } = null!; - [Resolved] - private OverlayColourProvider? colourProvider { get; set; } - /// /// Creates a new using an already computed . /// @@ -160,8 +161,8 @@ protected override void LoadComplete() background.Colour = colours.ForStarDifficulty(s.NewValue); - starIcon.Colour = s.NewValue >= OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF ? colours.Orange1 : colourProvider?.Background5 ?? Color4Extensions.FromHex("303d47"); - starsText.Colour = s.NewValue >= OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF ? colours.Orange1 : colourProvider?.Background5 ?? Color4.Black.Opacity(0.75f); + starIcon.Colour = colours.ForStarDifficultyText(s.NewValue); + starsText.Colour = colours.ForStarDifficultyText(s.NewValue); }, true); } } diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index 0eca359060c1..5dd6dc0c539c 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -25,6 +25,11 @@ public class OsuColour /// public const float STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF = 6.5f; + /// + /// Star rating at which display text switches from static colours to a gradient. + /// + public const float STAR_DIFFICULTY_TEXT_GRADIENT_CUTOFF = 9.0f; + public static readonly (float, Color4)[] STAR_DIFFICULTY_SPECTRUM = { (0.1f, Color4Extensions.FromHex("aaaaaa")), @@ -42,11 +47,34 @@ public static readonly (float, Color4)[] STAR_DIFFICULTY_SPECTRUM = (10.0f, Color4.Black), }; + public static readonly (float, Color4)[] STAR_DIFFICULTY_TEXT_SPECTRUM = + { + (9.0f, Color4Extensions.FromHex("f6f05c")), + (9.9f, Color4Extensions.FromHex("ff8068")), + (10.6f, Color4Extensions.FromHex("ff4e6f")), + (11.5f, Color4Extensions.FromHex("c645b8")), + (12.4f, Color4Extensions.FromHex("6563de")), + }; + /// /// Retrieves the colour for a given point in the star range. /// public Color4 ForStarDifficulty(double starDifficulty) => ColourUtils.SampleFromLinearGradient(STAR_DIFFICULTY_SPECTRUM, (float)Math.Round(starDifficulty, 2, MidpointRounding.AwayFromZero)); + /// + /// Retrieves the colour for the text inside the star rating display. + /// + public Color4 ForStarDifficultyText(double starDifficulty) + { + if (starDifficulty < STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF) + return Color4.Black.Opacity(0.75f); + + if (starDifficulty < STAR_DIFFICULTY_TEXT_GRADIENT_CUTOFF) + return Orange1; + + return ColourUtils.SampleFromLinearGradient(STAR_DIFFICULTY_TEXT_SPECTRUM, (float)Math.Round(starDifficulty, 2, MidpointRounding.AwayFromZero)); + } + /// /// Retrieves the colour for a . /// diff --git a/osu.Game/Screens/SelectV2/PanelBeatmap.cs b/osu.Game/Screens/SelectV2/PanelBeatmap.cs index 59603e145d7c..6dc2286f44b0 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmap.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmap.cs @@ -53,12 +53,6 @@ public partial class PanelBeatmap : Panel [Resolved] private IRulesetStore rulesets { get; set; } = null!; - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; - - [Resolved] - private OsuColour colours { get; set; } = null!; - [Resolved] private BeatmapDifficultyCache difficultyCache { get; set; } = null!; @@ -278,10 +272,13 @@ protected override void Update() backgroundBorder.Colour = diffColour; backgroundDifficultyTint.Colour = ColourInfo.GradientHorizontal(diffColour.Opacity(0.25f), diffColour.Opacity(0f)); - difficultyIcon.Colour = starRatingDisplay.DisplayedStars.Value > OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF ? colours.Orange1 : colourProvider.Background5; - triangles.Colour = ColourInfo.GradientVertical(diffColour.Opacity(0.25f), diffColour.Opacity(0f)); } + + if (difficultyIcon.Colour != starRatingDisplay.DisplayedDifficultyTextColour) + { + difficultyIcon.Colour = starRatingDisplay.DisplayedDifficultyTextColour; + } } private void updateKeyCount() diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs index fdea4575511d..5071fe4aaa1c 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs @@ -45,9 +45,6 @@ public partial class PanelBeatmapStandalone : Panel [Resolved] private BeatmapManager beatmaps { get; set; } = null!; - [Resolved] - private OsuColour colours { get; set; } = null!; - [Resolved] private BeatmapDifficultyCache difficultyCache { get; set; } = null!; @@ -293,7 +290,7 @@ protected override void Update() spreadDisplay.Current.Colour = diffColour; backgroundBorder.Colour = diffColour; - difficultyIcon.Colour = starRatingDisplay.DisplayedStars.Value > OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF ? colours.Orange1 : colourProvider.Background5; + difficultyIcon.Colour = starRatingDisplay.DisplayedDifficultyTextColour; } private void updateKeyCount() From ee5cf25628161db4901391774e637732f966f765 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Sun, 11 Jan 2026 15:58:59 +0300 Subject: [PATCH 442/836] Localise notifications in `MobileUpdateNotifier` and `NoActionUpdateManager` --- osu.Game/Localisation/NotificationsStrings.cs | 15 +++++++++++++++ osu.Game/Updater/MobileUpdateNotifier.cs | 5 +++-- osu.Game/Updater/NoActionUpdateManager.cs | 5 +++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 75f1a39a69df..b6c38ebdcac4 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -190,6 +190,21 @@ public static class NotificationsStrings /// public static LocalisableString CollectionsImportProgressTotal(int count, int totalCount) => new TranslatableString(getKey(@"collections_import_progress_total"), @"Imported {0} of {1} collections", count, totalCount); + /// + /// "A newer release of osu! has been found ({0} → {1})." + /// + public static LocalisableString UpdateAvailable(string version, string latestTagName) => new TranslatableString(getKey(@"update_available"), @"A newer release of osu! has been found ({0} → {1}).", version, latestTagName); + + /// + /// "Click here to download the new version, which can be installed over the top of your existing installation" + /// + public static LocalisableString UpdateMobile => new TranslatableString(getKey(@"update_mobile"), @"Click here to download the new version, which can be installed over the top of your existing installation"); + + /// + /// "Check with your package manager / provider to bring osu! up-to-date!" + /// + public static LocalisableString UpdateNoAction => new TranslatableString(getKey(@"update_no_action"), @"Check with your package manager / provider to bring osu! up-to-date!"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Updater/MobileUpdateNotifier.cs b/osu.Game/Updater/MobileUpdateNotifier.cs index 3a290c9a63fe..804d61c8de0b 100644 --- a/osu.Game/Updater/MobileUpdateNotifier.cs +++ b/osu.Game/Updater/MobileUpdateNotifier.cs @@ -9,8 +9,10 @@ using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Game.Configuration; +using osu.Game.Localisation; using osu.Game.Online.API; namespace osu.Game.Updater @@ -57,8 +59,7 @@ protected override async Task PerformUpdateCheck(CancellationToken cancell { Notifications.Post(new UpdateAvailableNotification(cancellationToken) { - Text = $"A newer release of osu! has been found ({version} → {latestTagName}).\n\n" - + "Click here to download the new version, which can be installed over the top of your existing installation", + Text = LocalisableString.Interpolate($"{NotificationsStrings.UpdateAvailable(version, latestTagName)}\n\n{NotificationsStrings.UpdateMobile}"), Icon = FontAwesome.Solid.Download, Activated = () => { diff --git a/osu.Game/Updater/NoActionUpdateManager.cs b/osu.Game/Updater/NoActionUpdateManager.cs index 0710797b60d5..9aef5ba2b181 100644 --- a/osu.Game/Updater/NoActionUpdateManager.cs +++ b/osu.Game/Updater/NoActionUpdateManager.cs @@ -6,7 +6,9 @@ using System.Threading; using System.Threading.Tasks; using osu.Framework.Allocation; +using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Localisation; using osu.Game.Online.API; namespace osu.Game.Updater @@ -51,8 +53,7 @@ protected override async Task PerformUpdateCheck(CancellationToken cancell { Notifications.Post(new UpdateAvailableNotification(cancellationToken) { - Text = $"A newer release of osu! has been found ({version} → {latestTagName}).\n\n" - + "Check with your package manager / provider to bring osu! up-to-date!", + Text = LocalisableString.Interpolate($"{NotificationsStrings.UpdateAvailable(version, latestTagName)}\n\n{NotificationsStrings.UpdateNoAction}"), }); return true; From f3205922299507e8a950ce010254ead4d58515b8 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Sun, 11 Jan 2026 16:17:09 +0300 Subject: [PATCH 443/836] Localise notification in `PerformFromMenuRunner` --- osu.Game/Localisation/NotificationsStrings.cs | 5 +++++ osu.Game/PerformFromMenuRunner.cs | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 75f1a39a69df..35d4310b4627 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -190,6 +190,11 @@ public static class NotificationsStrings /// public static LocalisableString CollectionsImportProgressTotal(int count, int totalCount) => new TranslatableString(getKey(@"collections_import_progress_total"), @"Imported {0} of {1} collections", count, totalCount); + /// + /// "An action was interrupted due to a dialog being displayed." + /// + public static LocalisableString ActionInterruptedByDialog => new TranslatableString(getKey(@"action_interrupted_by_dialog"), @"An action was interrupted due to a dialog being displayed."); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/PerformFromMenuRunner.cs b/osu.Game/PerformFromMenuRunner.cs index 21beadf36639..006430c4274d 100644 --- a/osu.Game/PerformFromMenuRunner.cs +++ b/osu.Game/PerformFromMenuRunner.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Framework.Threading; +using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Overlays.Dialog; using osu.Game.Overlays.Notifications; @@ -165,7 +166,11 @@ private bool checkForDialog(IScreen current) // the last dialog encountered has been dismissed but the screen has not changed, abort. Cancel(); - notifications.Post(new SimpleNotification { Text = @"An action was interrupted due to a dialog being displayed." }); + notifications.Post(new SimpleNotification + { + Text = NotificationsStrings.ActionInterruptedByDialog + }); + return true; } From 8a21c6814cf13a879ace7ee4bf1970d9ca64bae1 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Sun, 11 Jan 2026 16:53:44 +0300 Subject: [PATCH 444/836] Localise notification in `OsuGame` --- osu.Game/Localisation/NotificationsStrings.cs | 5 +++++ osu.Game/OsuGame.cs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 75f1a39a69df..c4df6e4fcc26 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -190,6 +190,11 @@ public static class NotificationsStrings /// public static LocalisableString CollectionsImportProgressTotal(int count, int totalCount) => new TranslatableString(getKey(@"collections_import_progress_total"), @"Imported {0} of {1} collections", count, totalCount); + /// + /// "This error has been automatically reported to the devs." + /// + public static LocalisableString ErrorAutomaticallyReported => new TranslatableString(getKey(@"error_automatically_reported"), @"This error has been automatically reported to the devs."); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4ea9fae1838b..0649846b973e 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1383,7 +1383,7 @@ private void forwardGeneralLogToNotifications(LogEntry entry) Schedule(() => Notifications.Post(new SimpleErrorNotification { Icon = entry.Level == LogLevel.Important ? FontAwesome.Solid.ExclamationCircle : FontAwesome.Solid.Bomb, - Text = entry.Message.Truncate(256) + (entry.Exception != null && IsDeployedBuild ? "\n\nThis error has been automatically reported to the devs." : string.Empty), + Text = LocalisableString.Interpolate($"{entry.Message.Truncate(256)}{(entry.Exception != null && IsDeployedBuild ? LocalisableString.Interpolate($"\n\n{NotificationsStrings.ErrorAutomaticallyReported}") : string.Empty)}"), })); } else if (generalLogRecentCount == short_term_display_limit) From ae284fcf057cee8652069d3b80b6a46951e4b58d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 12 Jan 2026 09:34:53 +0100 Subject: [PATCH 445/836] Fix broken date formatting in some languages on several overlays Fixes https://osu.ppy.sh/community/forums/topics/2169438?n=1. --- .../Statistics/BeatmapCardDateStatistic.cs | 4 +- osu.Game/Overlays/News/NewsCard.cs | 3 +- .../Header/Components/GlobalRankDisplay.cs | 3 +- osu.Game/Utils/FormatUtils.cs | 82 +++++++++++++++++++ 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs index 2948e89e6074..861ec9f0274a 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs @@ -2,10 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; +using osu.Game.Utils; namespace osu.Game.Beatmaps.Drawables.Cards.Statistics { @@ -18,7 +18,7 @@ private BeatmapCardDateStatistic(DateTimeOffset dateTime) this.dateTime = dateTime; Icon = FontAwesome.Regular.CheckCircle; - Text = dateTime.ToLocalisableString(@"d MMM yyyy"); + Text = dateTime.ToLocalisedMediumDate(); } public override object TooltipContent => dateTime; diff --git a/osu.Game/Overlays/News/NewsCard.cs b/osu.Game/Overlays/News/NewsCard.cs index 8a579a5ccc8a..863e0db64863 100644 --- a/osu.Game/Overlays/News/NewsCard.cs +++ b/osu.Game/Overlays/News/NewsCard.cs @@ -16,6 +16,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Utils; namespace osu.Game.Overlays.News { @@ -143,7 +144,7 @@ private void load(OverlayColourProvider colourProvider) }, new OsuSpriteText { - Text = date.ToLocalisableString(@"d MMM yyyy").ToUpper(), + Text = date.ToLocalisedMediumDate().ToUpper(), Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), Margin = new MarginPadding { diff --git a/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs b/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs index f48d467d8771..2e5374fdb7cc 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs @@ -13,6 +13,7 @@ using osu.Game.Resources.Localisation.Web; using osu.Game.Scoring; using osu.Game.Users; +using osu.Game.Utils; namespace osu.Game.Overlays.Profile.Header.Components { @@ -123,7 +124,7 @@ private LocalisableString getGlobalRankTooltipText() { var rankHighestText = UsersStrings.ShowRankHighest( rankHighest.Rank.ToLocalisableString("\\##,##0"), - rankHighest.UpdatedAt.ToLocalisableString(@"d MMM yyyy")); + rankHighest.UpdatedAt.ToLocalisedMediumDate()); if (result == null) result = rankHighestText; diff --git a/osu.Game/Utils/FormatUtils.cs b/osu.Game/Utils/FormatUtils.cs index 29e402144a75..823c6b376dd7 100644 --- a/osu.Game/Utils/FormatUtils.cs +++ b/osu.Game/Utils/FormatUtils.cs @@ -2,9 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using Humanizer; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; +using osu.Game.Extensions; +using osu.Game.Localisation; namespace osu.Game.Utils { @@ -73,5 +76,84 @@ public static int FindPrecision(decimal d) /// The base BPM to round. /// Rate adjustment, if applicable. public static int RoundBPM(double baseBpm, double rate = 1) => (int)Math.Round(baseBpm * rate); + + public static LocalisableString ToLocalisedMediumDate(this DateTimeOffset dateTime) + => new LocalisableString(new MediumFormattedDate(dateTime)); + + /// + /// This class is supposed to provide date formatting roughly equivalent to + /// + /// moment().format('ll'); + /// + /// which is used in several places on the website, and as such needs to be mirrored to the relevant game overlays reimplementing those places. + /// + private class MediumFormattedDate : ILocalisableStringData + { + public readonly DateTimeOffset Date; + + public MediumFormattedDate(DateTimeOffset date) + { + Date = date; + } + + public bool Equals(ILocalisableStringData? other) + => other is MediumFormattedDate date && Date.Equals(date.Date); + + // reference: individual language files in https://github.com/moment/moment/tree/18aba135ab927ffe7f868ee09276979bed6993a6/locale + private static readonly Dictionary format_mapping = new Dictionary + { + [Language.en] = @"d MMM yyyy", + [Language.be] = @"d MMM yyyy 'г.'", + [Language.bg] = @"d MMM yyyy", + [Language.ca] = @"d MMM yyyy", + [Language.cs] = @"d. MMM yyyy", + [Language.da] = @"d. MMM yyyy", + [Language.de] = @"d. MMM yyyy", + [Language.el] = @"d MMM yyyy", + [Language.es] = @"d 'de' MMM 'de' yyyy", + [Language.fi] = @"d. MMM yyyy", + [Language.fr] = @"d MMM yyyy", + [Language.hr_hr] = @"d. MMM yyyy", + [Language.hu] = @"yyyy. MMM d.", + [Language.id] = @"d MMM yyyy", + [Language.it] = @"d MMM yyyy", + [Language.ja] = @"yyyy年M月d日", + [Language.ko] = @"yyyy년 MMMM d일", + [Language.lt] = @"yyyy 'm.' MMM d 'd.'", + [Language.lv_lv] = @"yyyy. 'gada' d. MMM", + [Language.ms_my] = @"d MMM yyyy", + [Language.nl] = @"d MMM yyyy", + [Language.no] = @"d. MMM yyyy", // look under `nb` (Norsk Bokmål) and `nn` (Nynorsk) in momentjs source + [Language.pl] = @"d MMM yyyy", + [Language.pt] = @"d 'de' MMM 'de' yyyy", + [Language.pt_br] = @"d 'de' MMM 'de' yyyy", + [Language.ro] = @"d MMM yyyy", + [Language.ru] = @"d MMM yyyy 'г.'", + [Language.sk] = @"d. MMM yyyy", + [Language.sl] = @"d. MMM yyyy", + [Language.sr] = @"d. MMM yyyy.", + [Language.sv] = @"d MMM yyyy", + [Language.th] = @"d MMM yyyy", + [Language.tr] = @"d MMM yyyy", + [Language.uk] = @"d MMM yyyy 'р.'", + [Language.vi] = @"d MMM yyyy", + [Language.zh] = @"yyyy年M月d日", + [Language.zh_hant] = @"yyyy年M月d日", + }; + + public string GetLocalised(LocalisationParameters parameters) + { + string? cultureCode = parameters.Store?.EffectiveCulture.Name.ToLowerInvariant(); + + if (!string.IsNullOrEmpty(cultureCode) + && LanguageExtensions.TryParseCultureCode(cultureCode, out var language) + && format_mapping.TryGetValue(language, out string? format)) + { + return Date.ToString(format); + } + + return Date.ToString(@"d MMM yyyy"); + } + } } } From 57f16646a343f5911feabc7cce13ba879b87c404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 12 Jan 2026 11:11:11 +0100 Subject: [PATCH 446/836] Add failing tests --- .../Mods/TestSceneOsuModFreezeFrame.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs index 57d2b9418809..31498295da80 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs @@ -2,7 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.UI; namespace osu.Game.Rulesets.Osu.Tests.Mods { @@ -18,5 +21,39 @@ public void TestFreezeFrame() Autoplay = false, }); } + + [Test] + public void TestSkipToFirstCircleNotSuppressed() + { + CreateModTest(new ModTestData + { + Mod = new OsuModFreezeFrame(), + CreateBeatmap = () => new OsuBeatmap + { + HitObjects = + { + new HitCircle { StartTime = 5000, Position = OsuPlayfield.BASE_SIZE / 2 } + } + }, + PassCondition = () => Player.GameplayClockContainer.GameplayStartTime > 0 + }); + } + + [Test] + public void TestSkipToFirstSpinnerNotSuppressed() + { + CreateModTest(new ModTestData + { + Mod = new OsuModFreezeFrame(), + CreateBeatmap = () => new OsuBeatmap + { + HitObjects = + { + new Spinner { StartTime = 5000, Position = OsuPlayfield.BASE_SIZE / 2 } + } + }, + PassCondition = () => Player.GameplayClockContainer.GameplayStartTime > 0 + }); + } } } From 38c89a914b7d57ea29edfb167b985eccbc4c018f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 12 Jan 2026 11:11:38 +0100 Subject: [PATCH 447/836] Fix Freeze Frame mod suppressing skip if the first object is a spinner Fixes https://osu.ppy.sh/community/forums/topics/2169899?n=1. `TimePreempt` doesn't affect the appearance of a spinner, but it *will* affect the value of `GameplayStartTime`: https://github.com/ppy/osu/blob/4bf90a5571bb508444178f3d98a2b2a10c549534/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs#L82-L91 While at parsing it is enforced that every object following a spinner has `NewCombo` set, it is *not* enforced that every spinner has `NewCombo` set. See also: https://github.com/ppy/osu/issues/24156. But that's sort of orthogonal to the entire issue as well because why touch the preempt of an object that's not visually affected by preempt to begin with. --- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index e75ed24a7dc3..368d76d1ba40 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -57,7 +57,8 @@ public void ApplyToBeatmap(IBeatmap beatmap) void applyFadeInAdjustment(OsuHitObject osuObject) { - osuObject.TimePreempt += osuObject.StartTime - lastNewComboTime; + if (osuObject is not Spinner) + osuObject.TimePreempt += osuObject.StartTime - lastNewComboTime; foreach (var nested in osuObject.NestedHitObjects.OfType()) { From a81a77c60f070ba7a25fd50d660d2282f9ae91bc Mon Sep 17 00:00:00 2001 From: Linus Genz Date: Mon, 12 Jan 2026 15:40:13 +0100 Subject: [PATCH 448/836] Fix underline size at song select details panel not matching after changing language (#36303) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #36274 **Change:** Registered a `BindValueChanged` callback on each TabItem’s `Text.Current` to ensure the underline indicator (strip) updates whenever the displayed tab text changes and calling `updateDisplay` accordingly to update the underline. **Result:** https://github.com/user-attachments/assets/6fb95a46-c768-46ec-a68a-a5e394e08a78 --------- Signed-off-by: Linus Genz Co-authored-by: Dean Herbert --- .../BeatmapDetailsArea.WedgeSelector.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.WedgeSelector.cs b/osu.Game/Screens/SelectV2/BeatmapDetailsArea.WedgeSelector.cs index b5cdeee792bd..95f60fb423c8 100644 --- a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.WedgeSelector.cs +++ b/osu.Game/Screens/SelectV2/BeatmapDetailsArea.WedgeSelector.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; @@ -13,6 +14,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays; using osuTK; @@ -25,6 +27,8 @@ public partial class WedgeSelector : TabControl { private Circle strip = null!; + private Bindable currentLanguage = null!; + protected override Dropdown? CreateDropdown() => null; protected override TabItem CreateTabItem(T value) => new TabItem(value); @@ -37,7 +41,7 @@ public WedgeSelector(float spacing) } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load(OverlayColourProvider colourProvider, OsuGameBase game) { AddInternal(strip = new Circle { @@ -49,6 +53,8 @@ private void load(OverlayColourProvider colourProvider) foreach (var type in Enum.GetValues()) AddItem(type); + + currentLanguage = game.CurrentLanguage.GetBoundCopy(); } protected override void LoadComplete() @@ -57,11 +63,14 @@ protected override void LoadComplete() Current.BindValueChanged(_ => updateDisplay()); - ScheduleAfterChildren(() => + currentLanguage.BindValueChanged(_ => { - updateDisplay(); - FinishTransforms(true); - }); + ScheduleAfterChildren(() => + { + updateDisplay(); + FinishTransforms(true); + }); + }, true); } private void updateDisplay() From a8989eb117ec3b2bc2db11716ae9e9a502cfdf93 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Mon, 12 Jan 2026 18:03:20 +0300 Subject: [PATCH 449/836] Expand settings in `ReplayPlayer` by default (#36308) ~i recently saw an suggestion to do this, but don't remember where~ - addresses https://github.com/ppy/osu/discussions/36189 i think it's logical, since the settings have been displayed in a separate overlay for more than six months, and not on top of the gameplay itself, and for example, it can be difficult to expand section on phones | master | pr | |-|-| | osu_2026-01-12_09-40-23 | osu_2026-01-12_09-39-40 | --- osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs | 8 +------- osu.Game/Screens/Play/ReplayPlayer.cs | 6 +----- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index 635d140a4af1..4fe207a6f901 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -21,8 +21,6 @@ namespace osu.Game.Screens.Play.HUD { public partial class PlayerSettingsOverlay : ExpandingContainer { - public VisualSettings VisualSettings { get; private set; } - private const float padding = 10; public const float EXPANDED_WIDTH = player_settings_width + padding * 2; @@ -66,11 +64,7 @@ public PlayerSettingsOverlay() Direction = FillDirection.Vertical, Spacing = new Vector2(0, 20), Margin = new MarginPadding(padding), - Children = new PlayerSettingsGroup[] - { - VisualSettings = new VisualSettings { Expanded = { Value = false } }, - new AudioSettings { Expanded = { Value = false } } - } + Children = new PlayerSettingsGroup[] { new VisualSettings(), new AudioSettings() } }); // For future consideration, this icon should probably not exist. diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 7fec8d63325d..b9a6de54b4ae 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -77,11 +77,7 @@ public ReplayPlayer(Func, Score> createScore, Playe /// Add a settings group to the HUD overlay. Intended to be used by rulesets to add replay-specific settings. /// /// The settings group to be shown. - public void AddSettings(PlayerSettingsGroup settings) => Schedule(() => - { - settings.Expanded.Value = false; - HUDOverlay.PlayerSettingsOverlay.Add(settings); - }); + public void AddSettings(PlayerSettingsGroup settings) => Schedule(() => HUDOverlay.PlayerSettingsOverlay.Add(settings)); [BackgroundDependencyLoader] private void load(OsuConfigManager config) From 5de23e41cf1dc26708e6f008c894fadbfe95193f Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 12 Jan 2026 14:20:10 -0800 Subject: [PATCH 450/836] Fix skin section buttons disappearing when searching for plural "skins" --- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 93cab9e8de03..4d7c0117e2c4 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -42,6 +42,8 @@ public partial class SkinSection : SettingsSection Icon = OsuIcon.SkinB }; + public override IEnumerable FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { "skins" }); + private static readonly Live random_skin_info = new SkinInfo { ID = SkinInfo.RANDOM_SKIN, @@ -69,7 +71,6 @@ private void load([CanBeNull] SkinEditorOverlay skinEditor) AllowNonContiguousMatching = true, LabelText = SkinSettingsStrings.CurrentSkin, Current = skins.CurrentSkinInfo, - Keywords = new[] { @"skins" }, }, new FillFlowContainer { From 18fd4758d736b2a14aead9a11ad9a1256df186c7 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Mon, 12 Jan 2026 23:28:10 -0500 Subject: [PATCH 451/836] Update form button UI/UX and support text wrapping --- .../Graphics/UserInterfaceV2/FormButton.cs | 176 ++++++++++++++---- 1 file changed, 137 insertions(+), 39 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormButton.cs b/osu.Game/Graphics/UserInterfaceV2/FormButton.cs index 85198191b872..d10134911f23 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormButton.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -12,6 +13,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Framework.Utils; using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -28,62 +30,137 @@ public partial class FormButton : CompositeDrawable /// public LocalisableString Caption { get; init; } + /// + /// Sets text inside the button. + /// public LocalisableString ButtonText { get; init; } - public Action? Action { get; init; } + /// + /// Sets a custom button icon. Not shown when is set. + /// + public IconUsage ButtonIcon { get; init; } = FontAwesome.Solid.ChevronRight; + + private Color4? backgroundColour; + + /// + /// Sets a custom background colour for the button. + /// + public Color4? BackgroundColour + { + get => backgroundColour; + set + { + backgroundColour = value; + + if (IsLoaded && value != null) + button.BackgroundColour = value.Value; + } + } + + /// + /// The action to invoke when the button is clicked. + /// + public Action? Action { get; set; } + + /// + /// Whether the button is enabled. + /// + public readonly BindableBool Enabled = new BindableBool(true); [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; + private Container content = null!; + private Box background = null!; + private OsuTextFlowContainer text = null!; + private Button button = null!; + [BackgroundDependencyLoader] private void load() { RelativeSizeAxes = Axes.X; - Height = 50; - - Masking = true; - CornerRadius = 5; - CornerExponent = 2.5f; + AutoSizeAxes = Axes.Y; - InternalChildren = new Drawable[] + InternalChild = content = new Container { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5, - }, - new Container + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Masking = true, + CornerRadius = 5, + CornerExponent = 2.5f, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding + background = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background5, + }, + new TrianglesV2 + { + SpawnRatio = 0.5f, + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(colourProvider.Background4, colourProvider.Background5), + }, + new HoverClickSounds(HoverSampleSet.Button) { - Left = 9, - Right = 5, - Vertical = 5, + Enabled = { BindTarget = Enabled }, }, - Children = new Drawable[] + new Container { - new OsuTextFlowContainer + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Width = 0.45f, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Text = Caption, + Left = 9, + Right = 5, + Vertical = 5, }, - new Button + Children = new Drawable[] { - Action = Action, - Text = ButtonText, - RelativeSizeAxes = ButtonText == default ? Axes.None : Axes.X, - Width = ButtonText == default ? 90 : 0.45f, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - } + text = new OsuTextFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = Caption, + }, + button = new Button + { + Action = () => Action?.Invoke(), + Text = ButtonText, + Icon = ButtonIcon, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Enabled = { BindTarget = Enabled }, + } + }, }, - }, + } }; + + if (ButtonText == default) + { + text.Padding = new MarginPadding { Right = 100 }; + button.Width = 90; + } + else + { + text.Width = 0.55f; + text.Padding = new MarginPadding { Right = 10 }; + button.RelativeSizeAxes = Axes.X; + button.Width = 0.45f; + } + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + if (BackgroundColour != null) + button.BackgroundColour = BackgroundColour.Value; + + Enabled.BindValueChanged(_ => updateState(), true); } protected override bool OnHover(HoverEvent e) @@ -98,12 +175,31 @@ protected override void OnHoverLost(HoverLostEvent e) updateState(); } + protected override bool OnClick(ClickEvent e) + { + if (Enabled.Value) + { + background.FlashColour(ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark2), 800, Easing.OutQuint); + button.TriggerClick(); + } + + return true; + } + private void updateState() { - BorderThickness = IsHovered ? 2 : 0; + text.Colour = !Enabled.Value ? colourProvider.Background1 : colourProvider.Content1; - if (IsHovered) - BorderColour = colourProvider.Light4; + background.FadeColour(IsHovered + ? ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4) + : colourProvider.Background5, 200, Easing.OutQuint); + + content.BorderThickness = IsHovered ? 2 : 0; + + if (!Enabled.Value) + content.BorderColour = BackgroundColour != null ? Interpolation.ValueAt(0.75, BackgroundColour.Value, colourProvider.Dark1, 0, 1) : colourProvider.Dark1; + else + content.BorderColour = BackgroundColour ?? colourProvider.Light4; } public partial class Button : OsuButton @@ -125,6 +221,8 @@ public override Color4 BackgroundColour } } + public IconUsage Icon { get; init; } + [BackgroundDependencyLoader] private void load(OverlayColourProvider overlayColourProvider) { @@ -135,7 +233,7 @@ private void load(OverlayColourProvider overlayColourProvider) { Add(new SpriteIcon { - Icon = FontAwesome.Solid.ChevronRight, + Icon = Icon, Size = new Vector2(16), Shadow = true, Anchor = Anchor.Centre, From df1304af9e1042823352f9e6b9ce325601a311e2 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Mon, 12 Jan 2026 23:28:14 -0500 Subject: [PATCH 452/836] Add visual test --- .../UserInterface/TestSceneFormButton.cs | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneFormButton.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFormButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFormButton.cs new file mode 100644 index 000000000000..a22607e78160 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFormButton.cs @@ -0,0 +1,139 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Cursor; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public partial class TestSceneFormButton : ThemeComparisonTestScene + { + public TestSceneFormButton() + : base(false) + { + } + + protected override Drawable CreateContent() => new OsuContextMenuContainer + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new BackgroundBox + { + RelativeSizeAxes = Axes.Both, + }, + new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + Child = new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Width = 400, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + Padding = new MarginPadding(10), + Children = new Drawable[] + { + new FormButton + { + Caption = "Button with default style", + Action = () => { }, + }, + new FormButton + { + Caption = "Button with default style", + Enabled = { Value = false }, + }, + new FormButton + { + Caption = "Button with custom style", + BackgroundColour = new OsuColour().DangerousButtonColour, + ButtonIcon = FontAwesome.Solid.Hamburger, + Action = () => { }, + }, + new FormButton + { + Caption = "Button with custom style", + BackgroundColour = new OsuColour().DangerousButtonColour, + ButtonIcon = FontAwesome.Solid.Hamburger, + Enabled = { Value = false }, + }, + new FormButton + { + Caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", + BackgroundColour = new OsuColour().Blue3, + ButtonIcon = FontAwesome.Solid.Book, + Action = () => { }, + }, + new FormButton + { + Caption = "Button with text inside", + ButtonText = "Text in button", + Action = () => { }, + }, + new FormButton + { + Caption = "Button with text inside", + ButtonText = "Text in button", + Enabled = { Value = false }, + }, + new FormButton + { + Caption = "Button with text inside", + ButtonText = "Text in button", + BackgroundColour = new OsuColour().DangerousButtonColour, + Action = () => { }, + }, + new FormButton + { + Caption = "Button with text inside", + ButtonText = "Text in button", + BackgroundColour = new OsuColour().DangerousButtonColour, + Enabled = { Value = false }, + }, + new FormButton + { + Caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor", + ButtonText = "Text in button", + BackgroundColour = new OsuColour().Blue3, + Action = () => { }, + }, + new FormButton + { + Caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor", + ButtonText = "Text in button", + BackgroundColour = new OsuColour().Blue3, + Enabled = { Value = false }, + }, + }, + }, + }, + } + } + }; + + private partial class BackgroundBox : Box + { + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Colour = colourProvider.Background4; + } + } + } +} From 37257a7a028608faf891a885e7cf2f16217a50bc Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Tue, 13 Jan 2026 07:47:25 +0300 Subject: [PATCH 453/836] Make edits based on reviews --- osu.Game/Localisation/NotificationsStrings.cs | 8 ++++---- osu.Game/Updater/MobileUpdateNotifier.cs | 2 +- osu.Game/Updater/NoActionUpdateManager.cs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index b8dde9dde997..55a89d9ceefe 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -198,17 +198,17 @@ public static class NotificationsStrings /// /// "A newer release of osu! has been found ({0} → {1})." /// - public static LocalisableString UpdateAvailable(string version, string latestTagName) => new TranslatableString(getKey(@"update_available"), @"A newer release of osu! has been found ({0} → {1}).", version, latestTagName); + public static LocalisableString UpdateAvailable(string oldVersion, string newVersion) => new TranslatableString(getKey(@"update_available"), @"A newer release of osu! has been found ({0} → {1}).", oldVersion, newVersion); /// - /// "Click here to download the new version, which can be installed over the top of your existing installation" + /// "Click here to download the new version, which can be installed over the top of your existing installation." /// - public static LocalisableString UpdateMobile => new TranslatableString(getKey(@"update_mobile"), @"Click here to download the new version, which can be installed over the top of your existing installation"); + public static LocalisableString UpdateAvailableManualInstall => new TranslatableString(getKey(@"update_available_manual_install"), @"Click here to download the new version, which can be installed over the top of your existing installation."); /// /// "Check with your package manager / provider to bring osu! up-to-date!" /// - public static LocalisableString UpdateNoAction => new TranslatableString(getKey(@"update_no_action"), @"Check with your package manager / provider to bring osu! up-to-date!"); + public static LocalisableString UpdateAvailablePackageManaged => new TranslatableString(getKey(@"update_available_package_managed"), @"Check with your package manager / provider to bring osu! up-to-date!"); /// /// "An action was interrupted due to a dialog being displayed." diff --git a/osu.Game/Updater/MobileUpdateNotifier.cs b/osu.Game/Updater/MobileUpdateNotifier.cs index 804d61c8de0b..43e4df53241c 100644 --- a/osu.Game/Updater/MobileUpdateNotifier.cs +++ b/osu.Game/Updater/MobileUpdateNotifier.cs @@ -59,7 +59,7 @@ protected override async Task PerformUpdateCheck(CancellationToken cancell { Notifications.Post(new UpdateAvailableNotification(cancellationToken) { - Text = LocalisableString.Interpolate($"{NotificationsStrings.UpdateAvailable(version, latestTagName)}\n\n{NotificationsStrings.UpdateMobile}"), + Text = LocalisableString.Interpolate($"{NotificationsStrings.UpdateAvailable(version, latestTagName)}\n\n{NotificationsStrings.UpdateAvailableManualInstall}"), Icon = FontAwesome.Solid.Download, Activated = () => { diff --git a/osu.Game/Updater/NoActionUpdateManager.cs b/osu.Game/Updater/NoActionUpdateManager.cs index 9aef5ba2b181..bc9d00b80446 100644 --- a/osu.Game/Updater/NoActionUpdateManager.cs +++ b/osu.Game/Updater/NoActionUpdateManager.cs @@ -53,7 +53,7 @@ protected override async Task PerformUpdateCheck(CancellationToken cancell { Notifications.Post(new UpdateAvailableNotification(cancellationToken) { - Text = LocalisableString.Interpolate($"{NotificationsStrings.UpdateAvailable(version, latestTagName)}\n\n{NotificationsStrings.UpdateNoAction}"), + Text = LocalisableString.Interpolate($"{NotificationsStrings.UpdateAvailable(version, latestTagName)}\n\n{NotificationsStrings.UpdateAvailablePackageManaged}"), }); return true; From d3ed93280a66b51789c040a5699e4fa7042c67c0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Jan 2026 16:10:40 +0900 Subject: [PATCH 454/836] Make error message string construction actually understandable --- osu.Game/Localisation/NotificationsStrings.cs | 4 ++-- osu.Game/OsuGame.cs | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 55a89d9ceefe..0d22d98eb1c3 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -191,9 +191,9 @@ public static class NotificationsStrings public static LocalisableString CollectionsImportProgressTotal(int count, int totalCount) => new TranslatableString(getKey(@"collections_import_progress_total"), @"Imported {0} of {1} collections", count, totalCount); /// - /// "This error has been automatically reported to the devs." + /// "This error has been automatically reported to the dev team." /// - public static LocalisableString ErrorAutomaticallyReported => new TranslatableString(getKey(@"error_automatically_reported"), @"This error has been automatically reported to the devs."); + public static LocalisableString ErrorAutomaticallyReported => new TranslatableString(getKey(@"error_automatically_reported"), @"This error has been automatically reported to the dev team."); /// /// "A newer release of osu! has been found ({0} → {1})." diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 0649846b973e..f707f0d19828 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1380,10 +1380,17 @@ private void forwardGeneralLogToNotifications(LogEntry entry) if (generalLogRecentCount < short_term_display_limit) { + LocalisableString message; + + if (entry.Exception != null && IsDeployedBuild) + message = LocalisableString.Interpolate($"{entry.Message.Truncate(256)}\n\n{NotificationsStrings.ErrorAutomaticallyReported}"); + else + message = entry.Message.Truncate(256); + Schedule(() => Notifications.Post(new SimpleErrorNotification { Icon = entry.Level == LogLevel.Important ? FontAwesome.Solid.ExclamationCircle : FontAwesome.Solid.Bomb, - Text = LocalisableString.Interpolate($"{entry.Message.Truncate(256)}{(entry.Exception != null && IsDeployedBuild ? LocalisableString.Interpolate($"\n\n{NotificationsStrings.ErrorAutomaticallyReported}") : string.Empty)}"), + Text = message })); } else if (generalLogRecentCount == short_term_display_limit) From 0ba4e9e2a42ce041c0a58da42ba4cdb4656ac7ec Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Tue, 13 Jan 2026 02:13:00 -0500 Subject: [PATCH 455/836] Fix mod footer button with unranked badge not resizing on localisation changes (#33810) - Closes https://github.com/ppy/osu/issues/33789 --- osu.Game/Screens/SelectV2/FooterButtonMods.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Screens/SelectV2/FooterButtonMods.cs b/osu.Game/Screens/SelectV2/FooterButtonMods.cs index 4720c1173179..13192df85d08 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonMods.cs +++ b/osu.Game/Screens/SelectV2/FooterButtonMods.cs @@ -65,6 +65,11 @@ public Bindable> Current [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; + [Resolved] + private OsuGameBase game { get; set; } = null!; + + private IBindable currentLanguage = null!; + public FooterButtonMods(ModSelectOverlay overlay) : base(overlay) { @@ -156,6 +161,9 @@ protected override void LoadComplete() { base.LoadComplete(); + currentLanguage = game.CurrentLanguage.GetBoundCopy(); + currentLanguage.BindValueChanged(_ => ScheduleAfterChildren(updateDisplay)); + Current.BindValueChanged(m => { modSettingChangeTracker?.Dispose(); From f892d5fbaab4c723b8dbf46c720753b3c3b5edf3 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Tue, 13 Jan 2026 02:20:03 -0500 Subject: [PATCH 456/836] Improve form dropdown UX (#36325) Addresses concerns in https://github.com/ppy/osu/pull/36193#issuecomment-3728177951 (excluding the last part, that is too involved and I can't imagine any workaround for it due to how strict the `Dropdown` structure is). Also adds truncation/padding to header label and search bar. Preview: https://github.com/user-attachments/assets/8885cb90-44dc-42ee-af21-cb33f7723e63 --- .../UserInterface/TestSceneFormDropdown.cs | 104 ++++++++++++++++++ .../Graphics/UserInterfaceV2/FormDropdown.cs | 19 +++- 2 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneFormDropdown.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFormDropdown.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFormDropdown.cs new file mode 100644 index 000000000000..69d6057b9a68 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFormDropdown.cs @@ -0,0 +1,104 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Cursor; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Localisation; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public partial class TestSceneFormDropdown : ThemeComparisonTestScene + { + public TestSceneFormDropdown() + : base(false) + { + } + + protected override Drawable CreateContent() => new OsuContextMenuContainer + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new BackgroundBox + { + RelativeSizeAxes = Axes.Both, + }, + new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + Child = new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Width = 400, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + Padding = new MarginPadding(10), + Children = new Drawable[] + { + new FormEnumDropdown + { + Caption = EditorSetupStrings.EnableCountdown, + HintText = EditorSetupStrings.CountdownDescription, + }, + new FormEnumDropdown + { + Caption = EditorSetupStrings.EnableCountdown, + HintText = EditorSetupStrings.CountdownDescription, + Current = { Disabled = true }, + }, + new FormDropdown + { + Caption = "Custom dropdown", + HintText = "Custom dropdown hint", + Items = new[] + { + "A verrry looooongggg thiiiinngggggg toooooo fittttt iiinnnn thhiisssss droooppdddoowwwnn", + "B verrry looooongggg thiiiinngggggg toooooo fittttt iiinnnn thhiisssss droooppdddoowwwnn", + "C verrry looooongggg thiiiinngggggg toooooo fittttt iiinnnn thhiisssss droooppdddoowwwnn", + "D verrry looooongggg thiiiinngggggg toooooo fittttt iiinnnn thhiisssss droooppdddoowwwnn", + }, + }, + new FormDropdown + { + Caption = "Custom dropdown", + HintText = "Custom dropdown hint", + AlwaysShowSearchBar = true, + Items = new[] + { + "A verrry looooongggg thiiiinngggggg toooooo fittttt iiinnnn thhiisssss droooppdddoowwwnn", + "B verrry looooongggg thiiiinngggggg toooooo fittttt iiinnnn thhiisssss droooppdddoowwwnn", + "C verrry looooongggg thiiiinngggggg toooooo fittttt iiinnnn thhiisssss droooppdddoowwwnn", + "D verrry looooongggg thiiiinngggggg toooooo fittttt iiinnnn thhiisssss droooppdddoowwwnn", + }, + }, + }, + }, + }, + } + } + }; + + private partial class BackgroundBox : Box + { + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Colour = colourProvider.Background4; + } + } + } +} diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index d7e734468177..91ea036ec6fa 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -15,6 +15,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; +using osu.Game.Resources.Localisation.Web; using osuTK; namespace osu.Game.Graphics.UserInterfaceV2 @@ -160,9 +161,11 @@ private void load() Caption = Caption, TooltipText = HintText, }, - label = new OsuSpriteText + label = new TruncatingSpriteText { RelativeSizeAxes = Axes.X, + Padding = new MarginPadding { Right = 25 }, + AlwaysPresent = true, }, } }, @@ -213,8 +216,6 @@ protected override void OnHoverLost(HoverLostEvent e) private void updateState() { - label.Alpha = string.IsNullOrEmpty(SearchBar.SearchTerm.Value) ? 1 : 0; - caption.Colour = Dropdown.Current.Disabled ? colourProvider.Background1 : colourProvider.Content2; label.Colour = Dropdown.Current.Disabled ? colourProvider.Background1 : colourProvider.Content1; chevron.Colour = Dropdown.Current.Disabled ? colourProvider.Background1 : colourProvider.Content1; @@ -222,6 +223,11 @@ private void updateState() bool dropdownOpen = Dropdown.Menu.State == MenuState.Open; + if (dropdownOpen) + label.Alpha = AlwaysShowSearchBar || !string.IsNullOrEmpty(SearchBar.SearchTerm.Value) ? 0 : 1; + else + label.Alpha = 1; + BorderThickness = IsHovered || dropdownOpen ? 2 : 0; if (Dropdown.Current.Disabled) @@ -251,7 +257,10 @@ private partial class FormDropdownSearchBar : DropdownSearchBar protected override void PopIn() => this.FadeIn(); protected override void PopOut() => this.FadeOut(); - protected override TextBox CreateTextBox() => TextBox = new FormTextBox.InnerTextBox(); + protected override TextBox CreateTextBox() => TextBox = new FormTextBox.InnerTextBox + { + PlaceholderText = HomeStrings.SearchPlaceholder, + }; [BackgroundDependencyLoader] private void load() @@ -259,7 +268,7 @@ private void load() TextBox.Anchor = Anchor.BottomLeft; TextBox.Origin = Anchor.BottomLeft; TextBox.RelativeSizeAxes = Axes.X; - TextBox.Margin = new MarginPadding(9); + Padding = new MarginPadding { Left = 9, Bottom = 9, Right = 34 }; } } From eeb4680795bfca35b28d2d640eba53eb5b5a3c9c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Jan 2026 16:57:50 +0900 Subject: [PATCH 457/836] Remove unused button --- .../TestSceneFooterButtonPlaylistV2.cs | 35 -------- .../OnlinePlay/FooterButtonPlaylistV2.cs | 87 ------------------- 2 files changed, 122 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonPlaylistV2.cs delete mode 100644 osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs diff --git a/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonPlaylistV2.cs b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonPlaylistV2.cs deleted file mode 100644 index 730696c36377..000000000000 --- a/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonPlaylistV2.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Cursor; -using osu.Game.Online.Rooms; -using osu.Game.Overlays; -using osu.Game.Screens.OnlinePlay; -using osu.Game.Tests.Visual.OnlinePlay; - -namespace osu.Game.Tests.Visual.Playlists -{ - public partial class TestSceneFooterButtonPlaylistV2 : OnlinePlayTestScene - { - [Cached] - private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); - - public TestSceneFooterButtonPlaylistV2() - { - Room room = new Room(); - - Add(new PopoverContainer - { - RelativeSizeAxes = Axes.Both, - Child = new FooterButtonPlaylistV2(room) - { - Anchor = Anchor.Centre, - Origin = Anchor.CentreLeft, - X = -100, - } - }); - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs deleted file mode 100644 index f5f5024d4f93..000000000000 --- a/osu.Game/Screens/OnlinePlay/FooterButtonPlaylistV2.cs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.ComponentModel; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics; -using osu.Game.Graphics.UserInterfaceV2; -using osu.Game.Online.Rooms; -using osu.Game.Overlays; -using osu.Game.Screens.Footer; -using osu.Game.Screens.OnlinePlay.Playlists; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay -{ - public partial class FooterButtonPlaylistV2 : ScreenFooterButton, IHasPopover - { - private readonly Room room; - - public FooterButtonPlaylistV2(Room room) - { - this.room = room; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colour) - { - Text = "Playlist"; - Icon = FontAwesome.Solid.List; - AccentColour = colour.Purple1; - - Action = this.ShowPopover; - } - - public Popover GetPopover() => new PlaylistPopover(room); - - private partial class PlaylistPopover : OsuPopover - { - private readonly Room room; - private PlaylistsRoomSettingsPlaylist playlist = null!; - - [Cached] - private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); - - public PlaylistPopover(Room room) - { - this.room = room; - } - - [BackgroundDependencyLoader] - private void load() - { - Content.Padding = new MarginPadding(10); - - Child = playlist = new PlaylistsRoomSettingsPlaylist - { - Size = new Vector2(300) - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - playlist.Items.BindCollectionChanged((_, __) => room.Playlist = playlist.Items.ToArray()); - - room.PropertyChanged += onRoomPropertyChanged; - updateRoomPlaylist(); - } - - private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == nameof(Room.Playlist)) - updateRoomPlaylist(); - } - - private void updateRoomPlaylist() - => playlist.Items.ReplaceRange(0, playlist.Items.Count, room.Playlist); - } - } -} From d5aa5b61ad2eac7eb9c06b7b67d4309a8ea07d7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 13 Jan 2026 10:55:51 +0100 Subject: [PATCH 458/836] Replace manual specification of `Authorization` header with SignalR-provided provider property The property used here is listed in SignalR documentation: https://learn.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-10.0#bearer-token-authentication While in practice this probably has zero bearing on anything, theoretically the way proposed in this commit is more correct. As the documentation states, with some transports the token may need to be renewed if it expires, which providing it via a header as done previously would not achieve, while going through `API.AccessToken` every time will perform a token refresh if one is needed. --- osu.Game/Online/HubClientConnector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index e6391e8810ac..7ccf763e62a0 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -65,7 +65,7 @@ protected override Task BuildConnectionAsync(Cancellat options.Proxy.Credentials = CredentialCache.DefaultCredentials; } - options.Headers.Add(@"Authorization", @$"Bearer {API.AccessToken}"); + options.AccessTokenProvider = () => Task.FromResult(API.AccessToken); // non-standard header name kept for backwards compatibility, can be removed after server side has migrated to `VERSION_HASH_HEADER` options.Headers.Add(@"OsuVersionHash", versionHash); options.Headers.Add(VERSION_HASH_HEADER, versionHash); From 5abc0f93fe67b424a97ae5869535535ae8af330a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 13 Jan 2026 11:00:45 +0100 Subject: [PATCH 459/836] Remove no longer needed header alias for version hash Clean-up from an old change (see https://github.com/ppy/osu/pull/28892#discussion_r1681136250). --- osu.Game/Online/HubClientConnector.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index 7ccf763e62a0..9dba778e4106 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -66,8 +66,6 @@ protected override Task BuildConnectionAsync(Cancellat } options.AccessTokenProvider = () => Task.FromResult(API.AccessToken); - // non-standard header name kept for backwards compatibility, can be removed after server side has migrated to `VERSION_HASH_HEADER` - options.Headers.Add(@"OsuVersionHash", versionHash); options.Headers.Add(VERSION_HASH_HEADER, versionHash); options.Headers.Add(CLIENT_SESSION_ID_HEADER, API.SessionIdentifier.ToString()); }); From 9c8d6e63a7473dec0bf80f35fa9e76a89e57ac34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 13 Jan 2026 11:16:10 +0100 Subject: [PATCH 460/836] Simplify proxy configuration More clean-up. --- osu.Game/Online/HubClientConnector.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index 9dba778e4106..c12043c7271a 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Net; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR.Client; @@ -57,13 +57,7 @@ protected override Task BuildConnectionAsync(Cancellat { // Configuring proxies is not supported on iOS, see https://github.com/xamarin/xamarin-macios/issues/14632. if (RuntimeInfo.OS != RuntimeInfo.Platform.iOS) - { - // Use HttpClient.DefaultProxy once on net6 everywhere. - // The credential setter can also be removed at this point. - options.Proxy = WebRequest.DefaultWebProxy; - if (options.Proxy != null) - options.Proxy.Credentials = CredentialCache.DefaultCredentials; - } + options.Proxy = HttpClient.DefaultProxy; options.AccessTokenProvider = () => Task.FromResult(API.AccessToken); options.Headers.Add(VERSION_HASH_HEADER, versionHash); From 3f4d1b798e0ca5919d2078ea78d6c6ce74165132 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 14 Jan 2026 01:33:42 -0500 Subject: [PATCH 461/836] Update button background colour in update function --- .../Graphics/UserInterfaceV2/FormButton.cs | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormButton.cs b/osu.Game/Graphics/UserInterfaceV2/FormButton.cs index d10134911f23..7b95a7e976a1 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormButton.cs @@ -40,7 +40,7 @@ public partial class FormButton : CompositeDrawable /// public IconUsage ButtonIcon { get; init; } = FontAwesome.Solid.ChevronRight; - private Color4? backgroundColour; + private readonly Color4? backgroundColour; /// /// Sets a custom background colour for the button. @@ -48,12 +48,12 @@ public partial class FormButton : CompositeDrawable public Color4? BackgroundColour { get => backgroundColour; - set + init { backgroundColour = value; - if (IsLoaded && value != null) - button.BackgroundColour = value.Value; + if (IsLoaded) + updateState(); } } @@ -156,10 +156,6 @@ private void load() protected override void LoadComplete() { base.LoadComplete(); - - if (BackgroundColour != null) - button.BackgroundColour = BackgroundColour.Value; - Enabled.BindValueChanged(_ => updateState(), true); } @@ -188,7 +184,7 @@ protected override bool OnClick(ClickEvent e) private void updateState() { - text.Colour = !Enabled.Value ? colourProvider.Background1 : colourProvider.Content1; + text.Colour = Enabled.Value ? colourProvider.Content1 : colourProvider.Background1; background.FadeColour(IsHovered ? ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4) @@ -196,10 +192,13 @@ private void updateState() content.BorderThickness = IsHovered ? 2 : 0; - if (!Enabled.Value) - content.BorderColour = BackgroundColour != null ? Interpolation.ValueAt(0.75, BackgroundColour.Value, colourProvider.Dark1, 0, 1) : colourProvider.Dark1; + if (BackgroundColour != null) + { + button.BackgroundColour = BackgroundColour.Value; + content.BorderColour = Enabled.Value ? BackgroundColour.Value : Interpolation.ValueAt(0.75, BackgroundColour.Value, colourProvider.Dark1, 0, 1); + } else - content.BorderColour = BackgroundColour ?? colourProvider.Light4; + content.BorderColour = Enabled.Value ? colourProvider.Light4 : colourProvider.Dark1; } public partial class Button : OsuButton From 8a581f5a90510ac1688d632fb1f91bd7765e118a Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 31 Dec 2025 13:40:06 -0500 Subject: [PATCH 462/836] Fix sliders not playing samples on adjust Should've been true by default, minor mistake from a previous PR. --- osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 625967dc6620..086bf7674f88 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -108,7 +108,7 @@ public float KeyboardStep /// /// Whether sound effects should play when adjusting this slider. /// - public bool PlaySamplesOnAdjust { get; init; } + public bool PlaySamplesOnAdjust { get; init; } = true; /// /// The string formatting function to use for the value label. From 27abce74ce772cddbdca0d6207b8d0c5aae1aea2 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 31 Dec 2025 12:15:01 -0500 Subject: [PATCH 463/836] Allow dynamically configuring dropdown hint text Used for "confine mouse mode" dropdown tooltip text. --- osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index 91ea036ec6fa..68d8103d918d 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -30,7 +30,11 @@ public partial class FormDropdown : OsuDropdown, IFormControl /// /// Hint text containing an extended description of this slider bar, displayed in a tooltip when hovering the caption. /// - public LocalisableString HintText { get; init; } + public LocalisableString HintText + { + get => header.HintText; + set => header.HintText = value; + } /// /// The maximum height of the dropdown's menu. @@ -46,7 +50,6 @@ private void load() RelativeSizeAxes = Axes.X; header.Caption = Caption; - header.HintText = HintText; } protected override void LoadComplete() From 7ea1bbf91ecb4ca227c60b1f88725b53c3ace717 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 31 Dec 2025 09:58:16 -0500 Subject: [PATCH 464/836] Introduce and use constants and classes for new settings overlay --- .../UserInterface/TestSceneButtonsInput.cs | 2 +- .../Settings/DangerousSettingsButtonV2.cs | 20 +++++++++ .../Overlays/Settings/SettingsButtonV2.cs | 43 +++++++++++++++++++ osu.Game/Overlays/Settings/SettingsFooter.cs | 2 +- osu.Game/Overlays/Settings/SettingsHeader.cs | 3 +- osu.Game/Overlays/Settings/SettingsItemV2.cs | 2 +- osu.Game/Overlays/Settings/SettingsSection.cs | 8 ++-- .../Overlays/Settings/SettingsSubsection.cs | 4 +- osu.Game/Overlays/SettingsPanel.cs | 7 +-- 9 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 osu.Game/Overlays/Settings/DangerousSettingsButtonV2.cs create mode 100644 osu.Game/Overlays/Settings/SettingsButtonV2.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs index 985f613b63b2..0f6716fd9c61 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs @@ -91,7 +91,7 @@ public void TestSettingsButtonInput() { AddStep("Move cursor to button", () => InputManager.MoveMouseTo(settingsButton)); AddAssert("Button is hovered", () => settingsButton.IsHovered); - AddStep("Move cursor to padded area", () => InputManager.MoveMouseTo(settingsButton.ScreenSpaceDrawQuad.TopLeft + new Vector2(SettingsPanel.CONTENT_MARGINS / 2f, 10))); + AddStep("Move cursor to padded area", () => InputManager.MoveMouseTo(settingsButton.ScreenSpaceDrawQuad.TopLeft + new Vector2(SettingsPanel.ContentPaddingV2.Left / 2f, 10))); AddAssert("Cursor within a button", () => settingsButton.ScreenSpaceDrawQuad.Contains(InputManager.CurrentState.Mouse.Position)); AddAssert("Button is not hovered", () => !settingsButton.IsHovered); } diff --git a/osu.Game/Overlays/Settings/DangerousSettingsButtonV2.cs b/osu.Game/Overlays/Settings/DangerousSettingsButtonV2.cs new file mode 100644 index 000000000000..9c2c73944414 --- /dev/null +++ b/osu.Game/Overlays/Settings/DangerousSettingsButtonV2.cs @@ -0,0 +1,20 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Game.Graphics; + +namespace osu.Game.Overlays.Settings +{ + /// + /// A with pink colours to mark dangerous/destructive actions. + /// + public partial class DangerousSettingsButtonV2 : SettingsButtonV2 + { + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.DangerousButtonColour; + } + } +} diff --git a/osu.Game/Overlays/Settings/SettingsButtonV2.cs b/osu.Game/Overlays/Settings/SettingsButtonV2.cs new file mode 100644 index 000000000000..28f569e03516 --- /dev/null +++ b/osu.Game/Overlays/Settings/SettingsButtonV2.cs @@ -0,0 +1,43 @@ +// 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.Collections.Generic; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Game.Graphics.UserInterfaceV2; + +namespace osu.Game.Overlays.Settings +{ + public partial class SettingsButtonV2 : RoundedButton, IConditionalFilterable + { + public SettingsButtonV2() + { + RelativeSizeAxes = Axes.X; + Margin = new MarginPadding { Vertical = -1.5f }; + Padding = SettingsPanel.ContentPaddingV2; + } + + public IEnumerable Keywords { get; set; } = Array.Empty(); + + public BindableBool CanBeShown { get; } = new BindableBool(true); + IBindable IConditionalFilterable.CanBeShown => CanBeShown; + + public override IEnumerable FilterTerms + { + get + { + if (TooltipText != default) + yield return TooltipText; + + foreach (string s in Keywords) + yield return s; + + foreach (LocalisableString s in base.FilterTerms) + yield return s; + } + } + } +} diff --git a/osu.Game/Overlays/Settings/SettingsFooter.cs b/osu.Game/Overlays/Settings/SettingsFooter.cs index 2e23577743a6..6ed59857157e 100644 --- a/osu.Game/Overlays/Settings/SettingsFooter.cs +++ b/osu.Game/Overlays/Settings/SettingsFooter.cs @@ -27,7 +27,7 @@ private void load(OsuGameBase game, RulesetStore rulesets) RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Direction = FillDirection.Vertical; - Padding = new MarginPadding { Top = 20, Bottom = 30, Horizontal = SettingsPanel.CONTENT_MARGINS }; + Padding = new MarginPadding { Top = 20, Bottom = 30, Left = SettingsPanel.ContentPaddingV2.Left, Right = SettingsPanel.ContentPaddingV2.Right }; FillFlowContainer modes; diff --git a/osu.Game/Overlays/Settings/SettingsHeader.cs b/osu.Game/Overlays/Settings/SettingsHeader.cs index 8d155fd01e14..3ed12f7d9f1a 100644 --- a/osu.Game/Overlays/Settings/SettingsHeader.cs +++ b/osu.Game/Overlays/Settings/SettingsHeader.cs @@ -35,7 +35,8 @@ private void load(OverlayColourProvider colourProvider) RelativeSizeAxes = Axes.X, Padding = new MarginPadding { - Horizontal = SettingsPanel.CONTENT_MARGINS, + Left = SettingsPanel.ContentPaddingV2.Left, + Right = SettingsPanel.ContentPaddingV2.Right, Top = Toolbar.Toolbar.TOOLTIP_HEIGHT, Bottom = 30 } diff --git a/osu.Game/Overlays/Settings/SettingsItemV2.cs b/osu.Game/Overlays/Settings/SettingsItemV2.cs index 084aa1ad1fd8..ad4e922ac243 100644 --- a/osu.Game/Overlays/Settings/SettingsItemV2.cs +++ b/osu.Game/Overlays/Settings/SettingsItemV2.cs @@ -41,7 +41,7 @@ public SettingsItemV2(IFormControl control) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS_RIGHT }, + Padding = SettingsPanel.ContentPaddingV2, Direction = FillDirection.Vertical, Children = new Drawable[] { diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index 9602e4373f97..f359e59e8016 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -35,6 +35,7 @@ public abstract partial class SettingsSection : Container, IFilterable public virtual IEnumerable FilterTerms => new[] { Header }; public const int ITEM_SPACING = 14; + public const int ITEM_SPACING_V2 = 7; private const int header_size = 24; private const int border_size = 4; @@ -73,7 +74,7 @@ protected SettingsSection() { Top = 36 }, - Spacing = new Vector2(0, ITEM_SPACING), + Spacing = new Vector2(0, ITEM_SPACING_V2), Direction = FillDirection.Vertical, AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, @@ -114,10 +115,7 @@ private void load(OverlayColourProvider colourProvider) { Font = OsuFont.TorusAlternate.With(size: header_size), Text = Header, - Margin = new MarginPadding - { - Horizontal = SettingsPanel.CONTENT_MARGINS - } + Margin = SettingsPanel.ContentPaddingV2, }, FlowContent } diff --git a/osu.Game/Overlays/Settings/SettingsSubsection.cs b/osu.Game/Overlays/Settings/SettingsSubsection.cs index 87772eb18c86..34809f3bbbff 100644 --- a/osu.Game/Overlays/Settings/SettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/SettingsSubsection.cs @@ -37,9 +37,9 @@ protected SettingsSubsection() FlowContent = new FillFlowContainer { - Margin = new MarginPadding { Top = SettingsSection.ITEM_SPACING }, + Margin = new MarginPadding { Top = SettingsSection.ITEM_SPACING_V2 }, Direction = FillDirection.Vertical, - Spacing = new Vector2(0, SettingsSection.ITEM_SPACING), + Spacing = new Vector2(0, SettingsSection.ITEM_SPACING_V2), RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, }; diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index 8fd12e1e13b2..446e24223bb3 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -31,8 +31,8 @@ public abstract partial class SettingsPanel : OsuFocusedOverlayContainer { public const float CONTENT_MARGINS = 20; - // extra margin to give room to the revert-to-default button in settings controls. - public const float CONTENT_MARGINS_RIGHT = 30; + // extra right padding to give room to the revert-to-default button in settings controls. + public static MarginPadding ContentPaddingV2 { get; } = new MarginPadding { Left = 20, Right = 30 }; public const float TRANSITION_LENGTH = 600; @@ -134,7 +134,8 @@ private void load() Padding = new MarginPadding { Vertical = 20, - Horizontal = CONTENT_MARGINS + Left = ContentPaddingV2.Left, + Right = ContentPaddingV2.Right, }, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, From e548cd40dc5944e11a2628c3a2c32bdb98a7d07a Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 31 Dec 2025 10:02:34 -0500 Subject: [PATCH 465/836] Update game settings to use new form controls --- .../ManiaSettingsSubsection.cs | 42 ++-- .../UI/OsuSettingsSubsection.cs | 35 +-- .../TaikoSettingsSubsection.cs | 7 +- .../TestSceneAudioOffsetAdjustControl.cs | 4 + .../Graphics/UserInterfaceV2/FormSliderBar.cs | 2 +- .../Sections/Audio/AudioDevicesSettings.cs | 41 +-- .../Audio/AudioOffsetAdjustControl.cs | 237 +++++++++--------- .../Settings/Sections/Audio/OffsetSettings.cs | 9 +- .../Settings/Sections/Audio/VolumeSettings.cs | 46 ++-- .../DebugSettings/BatchImportSettings.cs | 16 +- .../Sections/DebugSettings/GeneralSettings.cs | 13 +- .../Sections/DebugSettings/MemorySettings.cs | 21 +- .../Sections/Gameplay/AudioSettings.cs | 19 +- .../Sections/Gameplay/BackgroundSettings.cs | 25 +- .../Sections/Gameplay/BeatmapSettings.cs | 39 +-- .../Sections/Gameplay/GeneralSettings.cs | 25 +- .../Settings/Sections/Gameplay/HUDSettings.cs | 49 ++-- .../Sections/Gameplay/InputSettings.cs | 30 ++- .../Sections/Gameplay/ModsSettings.cs | 7 +- .../Sections/General/InstallationSettings.cs | 4 +- .../Sections/General/LanguageSettings.cs | 19 +- .../Sections/General/QuickActionSettings.cs | 8 +- .../Sections/General/UpdateSettings.cs | 19 +- .../Sections/Graphics/RendererSettings.cs | 59 ++--- .../Sections/Graphics/ScreenshotSettings.cs | 13 +- .../Sections/Graphics/VideoSettings.cs | 9 +- .../Sections/Input/BindingSettings.cs | 2 +- .../Sections/Input/KeyBindingsSubsection.cs | 2 +- .../Sections/Maintenance/BeatmapSettings.cs | 20 +- .../Maintenance/CollectionsSettings.cs | 2 +- .../Sections/Maintenance/GeneralSettings.cs | 4 +- .../Sections/Maintenance/ModPresetSettings.cs | 8 +- .../Sections/Maintenance/ScoreSettings.cs | 4 +- .../Sections/Maintenance/SkinSettings.cs | 4 +- .../Online/AlertsAndPrivacySettings.cs | 27 +- .../Sections/Online/IntegrationSettings.cs | 7 +- .../Settings/Sections/Online/WebSettings.cs | 31 ++- .../Overlays/Settings/Sections/SkinSection.cs | 34 ++- .../Sections/UserInterface/GeneralSettings.cs | 36 +-- .../UserInterface/MainMenuSettings.cs | 52 ++-- .../UserInterface/SongSelectSettings.cs | 42 ++-- 41 files changed, 575 insertions(+), 498 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs index 791f46d40739..b1884aab6fa1 100644 --- a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs +++ b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs @@ -7,7 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Mania.Configuration; @@ -31,47 +31,45 @@ private void load() Children = new Drawable[] { - new SettingsEnumDropdown + new SettingsItemV2(new FormEnumDropdown { - LabelText = RulesetSettingsStrings.ScrollingDirection, + Caption = RulesetSettingsStrings.ScrollingDirection, Current = config.GetBindable(ManiaRulesetSetting.ScrollDirection) - }, - new SettingsSlider + }), + new SettingsItemV2(new FormSliderBar { - LabelText = RulesetSettingsStrings.ScrollSpeed, + Caption = RulesetSettingsStrings.ScrollSpeed, Current = config.GetBindable(ManiaRulesetSetting.ScrollSpeed), - KeyboardStep = 1 - }, - new SettingsCheckbox + KeyboardStep = 1, + LabelFormat = v => RulesetSettingsStrings.ScrollSpeedTooltip((int)DrawableManiaRuleset.ComputeScrollTime(v), v), + }), + new SettingsItemV2(new FormCheckBox { - Keywords = new[] { "color" }, - LabelText = RulesetSettingsStrings.TimingBasedColouring, + Caption = RulesetSettingsStrings.TimingBasedColouring, Current = config.GetBindable(ManiaRulesetSetting.TimingBasedNoteColouring), + }) + { + Keywords = new[] { "color" }, }, }; - Add(new SettingsCheckbox + Add(new SettingsItemV2(new FormCheckBox { - LabelText = RulesetSettingsStrings.TouchOverlay, + Caption = RulesetSettingsStrings.TouchOverlay, Current = config.GetBindable(ManiaRulesetSetting.TouchOverlay) - }); + })); if (RuntimeInfo.IsMobile) { - Add(new SettingsEnumDropdown + Add(new SettingsItemV2(new FormEnumDropdown { - LabelText = RulesetSettingsStrings.MobileLayout, + Caption = RulesetSettingsStrings.MobileLayout, Current = config.GetBindable(ManiaRulesetSetting.MobileLayout), #pragma warning disable CS0618 // Type or member is obsolete Items = Enum.GetValues().Where(l => l != ManiaMobileLayout.LandscapeWithOverlay), #pragma warning restore CS0618 // Type or member is obsolete - }); + })); } } - - private partial class ManiaScrollSlider : RoundedSliderBar - { - public override LocalisableString TooltipText => RulesetSettingsStrings.ScrollSpeedTooltip((int)DrawableManiaRuleset.ComputeScrollTime(Current.Value), Current.Value); - } } } diff --git a/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs b/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs index 0e410dbf57d6..56a30f89ac88 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Osu.Configuration; @@ -13,6 +14,8 @@ namespace osu.Game.Rulesets.Osu.UI { public partial class OsuSettingsSubsection : RulesetSettingsSubsection { + private FormCheckBox snakingOutSliders = null!; + protected override LocalisableString Header => "osu!"; public OsuSettingsSubsection(Ruleset ruleset) @@ -27,32 +30,34 @@ private void load() Children = new Drawable[] { - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = RulesetSettingsStrings.SnakingInSliders, + Caption = RulesetSettingsStrings.SnakingInSliders, Current = config.GetBindable(OsuRulesetSetting.SnakingInSliders) - }, - new SettingsCheckbox + }), + new SettingsItemV2(snakingOutSliders = new FormCheckBox { - ClassicDefault = false, - LabelText = RulesetSettingsStrings.SnakingOutSliders, + Caption = RulesetSettingsStrings.SnakingOutSliders, Current = config.GetBindable(OsuRulesetSetting.SnakingOutSliders) + }) + { + ApplyClassicDefault = () => snakingOutSliders.Current.Value = false, }, - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = RulesetSettingsStrings.CursorTrail, + Caption = RulesetSettingsStrings.CursorTrail, Current = config.GetBindable(OsuRulesetSetting.ShowCursorTrail) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = RulesetSettingsStrings.CursorRipples, + Caption = RulesetSettingsStrings.CursorRipples, Current = config.GetBindable(OsuRulesetSetting.ShowCursorRipples) - }, - new SettingsEnumDropdown + }), + new SettingsItemV2(new FormEnumDropdown { - LabelText = RulesetSettingsStrings.PlayfieldBorderStyle, + Caption = RulesetSettingsStrings.PlayfieldBorderStyle, Current = config.GetBindable(OsuRulesetSetting.PlayfieldBorderStyle), - }, + }), }; } } diff --git a/osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs b/osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs index 84dea474c545..58fb6a024661 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Taiko.Configuration; @@ -26,11 +27,11 @@ private void load() Children = new Drawable[] { - new SettingsEnumDropdown + new SettingsItemV2(new FormEnumDropdown { - LabelText = RulesetSettingsStrings.TouchControlScheme, + Caption = RulesetSettingsStrings.TouchControlScheme, Current = config.GetBindable(TaikoRulesetSetting.TouchControlScheme) - } + }) }; } } diff --git a/osu.Game.Tests/Visual/Settings/TestSceneAudioOffsetAdjustControl.cs b/osu.Game.Tests/Visual/Settings/TestSceneAudioOffsetAdjustControl.cs index 2fc5378ba144..ceca59dccf21 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneAudioOffsetAdjustControl.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneAudioOffsetAdjustControl.cs @@ -11,6 +11,7 @@ using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Configuration; +using osu.Game.Overlays; using osu.Game.Overlays.Settings.Sections.Audio; using osu.Game.Scoring; using osu.Game.Tests.Visual.Ranking; @@ -25,6 +26,9 @@ public partial class TestSceneAudioOffsetAdjustControl : OsuTestScene [Cached] private SessionAverageHitErrorTracker tracker = new SessionAverageHitErrorTracker(); + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + private Container content = null!; protected override Container Content => content; diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 086bf7674f88..116e283737f0 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -396,7 +396,7 @@ private void updateValueDisplay() private LocalisableString defaultLabelFormat(T value) => currentNumberInstantaneous.Value.ToStandardFormattedString(OsuSliderBar.MAX_DECIMAL_DIGITS, DisplayAsPercentage); - private partial class InnerSlider : OsuSliderBar + public partial class InnerSlider : OsuSliderBar { public BindableBool Focused { get; } = new BindableBool(); diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs index 811f6b606ac9..5742272e9676 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs @@ -7,9 +7,10 @@ using System.Collections.Generic; using System.Linq; using osu.Framework; +using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Localisation; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Audio @@ -21,30 +22,37 @@ public partial class AudioDevicesSettings : SettingsSubsection [Resolved] private AudioManager audio { get; set; } = null!; - private SettingsDropdown dropdown = null!; + private AudioDeviceDropdown dropdown = null!; - private SettingsCheckbox? wasapiExperimental; + private FormCheckBox? wasapiExperimental; + + private readonly Bindable wasapiExperimentalNote = new Bindable(); [BackgroundDependencyLoader] private void load() { Children = new Drawable[] { - dropdown = new AudioDeviceSettingsDropdown + new SettingsItemV2(dropdown = new AudioDeviceDropdown + { + Caption = AudioSettingsStrings.OutputDevice, + }) { - LabelText = AudioSettingsStrings.OutputDevice, Keywords = new[] { "speaker", "headphone", "output" } }, }; if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows) { - Add(wasapiExperimental = new SettingsCheckbox + Add(new SettingsItemV2(wasapiExperimental = new FormCheckBox { - LabelText = AudioSettingsStrings.WasapiLabel, - TooltipText = AudioSettingsStrings.WasapiTooltip, + Caption = AudioSettingsStrings.WasapiLabel, + HintText = AudioSettingsStrings.WasapiTooltip, Current = audio.UseExperimentalWasapi, - Keywords = new[] { "wasapi", "latency", "exclusive" } + }) + { + Keywords = new[] { "wasapi", "latency", "exclusive" }, + Note = { BindTarget = wasapiExperimentalNote }, }); wasapiExperimental.Current.ValueChanged += _ => onDeviceChanged(string.Empty); @@ -64,9 +72,9 @@ private void onDeviceChanged(string _) if (wasapiExperimental != null) { if (wasapiExperimental.Current.Value) - wasapiExperimental.SetNoticeText(AudioSettingsStrings.WasapiNotice, true); + wasapiExperimentalNote.Value = new SettingsNote.Data(AudioSettingsStrings.WasapiNotice, SettingsNote.Type.Warning); else - wasapiExperimental.ClearNoticeText(); + wasapiExperimentalNote.Value = null; } } @@ -103,15 +111,10 @@ protected override void Dispose(bool isDisposing) } } - private partial class AudioDeviceSettingsDropdown : SettingsDropdown + private partial class AudioDeviceDropdown : FormDropdown { - protected override OsuDropdown CreateDropdown() => new AudioDeviceDropdownControl(); - - private partial class AudioDeviceDropdownControl : DropdownControl - { - protected override LocalisableString GenerateItemText(string item) - => string.IsNullOrEmpty(item) ? CommonStrings.Default : base.GenerateItemText(item); - } + protected override LocalisableString GenerateItemText(string item) + => string.IsNullOrEmpty(item) ? CommonStrings.Default : base.GenerateItemText(item); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs index 6e5e0105184e..fca7aaffd983 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs @@ -11,13 +11,10 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Extensions; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Screens.Play.PlayerSettings; @@ -25,157 +22,157 @@ namespace osu.Game.Overlays.Settings.Sections.Audio { - public partial class AudioOffsetAdjustControl : SettingsItem + public partial class AudioOffsetAdjustControl : CompositeDrawable { - public IBindable SuggestedOffset => ((AudioOffsetPreview)Control).SuggestedOffset; - - [BackgroundDependencyLoader] - private void load() + public Bindable Current { - LabelText = AudioSettingsStrings.AudioOffset; + get => current.Current; + set => current.Current = value; } - protected override Drawable CreateControl() => new AudioOffsetPreview(); - - private partial class AudioOffsetPreview : CompositeDrawable, IHasCurrentValue - { - public Bindable Current - { - get => current.Current; - set => current.Current = value; - } + private readonly BindableNumberWithCurrent current = new BindableNumberWithCurrent(); - private readonly BindableNumberWithCurrent current = new BindableNumberWithCurrent(); + private readonly IBindableList averageHitErrorHistory = new BindableList(); - private readonly IBindableList averageHitErrorHistory = new BindableList(); + public readonly Bindable SuggestedOffset = new Bindable(); - public readonly Bindable SuggestedOffset = new Bindable(); + private Container notchContainer = null!; + private TextFlowContainer hintText = null!; + private RoundedButton applySuggestion = null!; - private Container notchContainer = null!; - private TextFlowContainer hintText = null!; - private RoundedButton applySuggestion = null!; + [BackgroundDependencyLoader] + private void load(SessionAverageHitErrorTracker hitErrorTracker) + { + averageHitErrorHistory.BindTo(hitErrorTracker.AverageHitErrorHistory); - [BackgroundDependencyLoader] - private void load(SessionAverageHitErrorTracker hitErrorTracker) + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + InternalChild = new FillFlowContainer { - averageHitErrorHistory.BindTo(hitErrorTracker.AverageHitErrorHistory); - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - InternalChild = new FillFlowContainer + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(7), + Direction = FillDirection.Vertical, + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(10), - Direction = FillDirection.Vertical, - Children = new Drawable[] + new SettingsItemV2(new FormSliderBar { - new OffsetSliderBar - { - RelativeSizeAxes = Axes.X, - Current = { BindTarget = Current }, - KeyboardStep = 1, - }, - notchContainer = new Container + Caption = AudioSettingsStrings.AudioOffset, + RelativeSizeAxes = Axes.X, + Current = { BindTarget = Current }, + KeyboardStep = 1, + LabelFormat = v => $"{v:N0} ms", + TooltipFormat = BeatmapOffsetControl.GetOffsetExplanatoryText, + }), + new Container + { + RelativeSizeAxes = Axes.X, + Height = 10, + Padding = new MarginPadding { - RelativeSizeAxes = Axes.X, - Height = 10, - Padding = new MarginPadding { Horizontal = Nub.DEFAULT_EXPANDED_SIZE / 2 }, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, + Left = SettingsPanel.ContentPaddingV2.Left + 9, + Right = SettingsPanel.ContentPaddingV2.Right + 5 }, - hintText = new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(size: 16)) + Child = notchContainer = new Container { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.Both, + Width = 0.5f, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Padding = new MarginPadding + { + Horizontal = FormSliderBar.InnerSlider.NUB_WIDTH / 2 + }, }, - applySuggestion = new RoundedButton + }, + hintText = new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(size: 16)) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = SettingsPanel.ContentPaddingV2, + }, + applySuggestion = new RoundedButton + { + RelativeSizeAxes = Axes.X, + Text = AudioSettingsStrings.ApplySuggestedOffset, + Padding = SettingsPanel.ContentPaddingV2, + Action = () => { - RelativeSizeAxes = Axes.X, - Text = AudioSettingsStrings.ApplySuggestedOffset, - Action = () => - { - if (SuggestedOffset.Value.HasValue) - current.Value = SuggestedOffset.Value.Value; - hitErrorTracker.ClearHistory(); - } + if (SuggestedOffset.Value.HasValue) + current.Value = SuggestedOffset.Value.Value; + hitErrorTracker.ClearHistory(); } } - }; - } + } + }; + } - protected override void LoadComplete() - { - base.LoadComplete(); + protected override void LoadComplete() + { + base.LoadComplete(); - averageHitErrorHistory.BindCollectionChanged(updateDisplay, true); - current.BindValueChanged(_ => updateHintText()); - SuggestedOffset.BindValueChanged(_ => updateHintText(), true); - } + averageHitErrorHistory.BindCollectionChanged(updateDisplay, true); + current.BindValueChanged(_ => updateHintText()); + SuggestedOffset.BindValueChanged(_ => updateHintText(), true); + } - private void updateDisplay(object? _, NotifyCollectionChangedEventArgs e) + private void updateDisplay(object? _, NotifyCollectionChangedEventArgs e) + { + switch (e.Action) { - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - foreach (SessionAverageHitErrorTracker.DataPoint dataPoint in e.NewItems!) + case NotifyCollectionChangedAction.Add: + foreach (SessionAverageHitErrorTracker.DataPoint dataPoint in e.NewItems!) + { + notchContainer.ForEach(n => n.Alpha *= 0.95f); + notchContainer.Add(new Box { - notchContainer.ForEach(n => n.Alpha *= 0.95f); - notchContainer.Add(new Box - { - RelativeSizeAxes = Axes.Y, - Width = 2, - RelativePositionAxes = Axes.X, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - X = getXPositionForOffset(dataPoint.SuggestedGlobalAudioOffset) - }); - } - - break; + RelativeSizeAxes = Axes.Y, + Width = 2, + RelativePositionAxes = Axes.X, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + X = getXPositionForOffset(dataPoint.SuggestedGlobalAudioOffset) + }); + } - case NotifyCollectionChangedAction.Remove: - foreach (SessionAverageHitErrorTracker.DataPoint dataPoint in e.OldItems!) - { - var notch = notchContainer.FirstOrDefault(n => n.X == getXPositionForOffset(dataPoint.SuggestedGlobalAudioOffset)); - Debug.Assert(notch != null); - notchContainer.Remove(notch, true); - } + break; - break; + case NotifyCollectionChangedAction.Remove: + foreach (SessionAverageHitErrorTracker.DataPoint dataPoint in e.OldItems!) + { + var notch = notchContainer.FirstOrDefault(n => n.X == getXPositionForOffset(dataPoint.SuggestedGlobalAudioOffset)); + Debug.Assert(notch != null); + notchContainer.Remove(notch, true); + } - case NotifyCollectionChangedAction.Reset: - notchContainer.Clear(); - break; - } + break; - SuggestedOffset.Value = averageHitErrorHistory.Any() ? Math.Round(averageHitErrorHistory.Average(dataPoint => dataPoint.SuggestedGlobalAudioOffset)) : null; + case NotifyCollectionChangedAction.Reset: + notchContainer.Clear(); + break; } - private float getXPositionForOffset(double offset) => (float)(Math.Clamp(offset, current.MinValue, current.MaxValue) / (2 * current.MaxValue)); + SuggestedOffset.Value = averageHitErrorHistory.Any() ? Math.Round(averageHitErrorHistory.Average(dataPoint => dataPoint.SuggestedGlobalAudioOffset)) : null; + } - private void updateHintText() + private float getXPositionForOffset(double offset) => (float)(Math.Clamp(offset, current.MinValue, current.MaxValue) / (2 * current.MaxValue)); + + private void updateHintText() + { + if (SuggestedOffset.Value == null) { - if (SuggestedOffset.Value == null) - { - applySuggestion.Enabled.Value = false; - hintText.Text = AudioSettingsStrings.SuggestedOffsetNote; - } - else if (Math.Abs(SuggestedOffset.Value.Value - current.Value) < 1) - { - applySuggestion.Enabled.Value = false; - hintText.Text = AudioSettingsStrings.SuggestedOffsetCorrect(averageHitErrorHistory.Count); - } - else - { - applySuggestion.Enabled.Value = true; - hintText.Text = AudioSettingsStrings.SuggestedOffsetValueReceived(averageHitErrorHistory.Count, SuggestedOffset.Value.Value.ToStandardFormattedString(0)); - } + applySuggestion.Enabled.Value = false; + hintText.Text = AudioSettingsStrings.SuggestedOffsetNote; } - - private partial class OffsetSliderBar : RoundedSliderBar + else if (Math.Abs(SuggestedOffset.Value.Value - current.Value) < 1) + { + applySuggestion.Enabled.Value = false; + hintText.Text = AudioSettingsStrings.SuggestedOffsetCorrect(averageHitErrorHistory.Count); + } + else { - public override LocalisableString TooltipText => BeatmapOffsetControl.GetOffsetExplanatoryText(Current.Value); + applySuggestion.Enabled.Value = true; + hintText.Text = AudioSettingsStrings.SuggestedOffsetValueReceived(averageHitErrorHistory.Count, SuggestedOffset.Value.Value.ToStandardFormattedString(0)); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs index b839c98f9f12..498b04b7a837 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Audio @@ -26,12 +27,12 @@ private void load(OsuConfigManager config) { Current = config.GetBindable(OsuSetting.AudioOffset), }, - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = AudioSettingsStrings.AdjustBeatmapOffsetAutomatically, - TooltipText = AudioSettingsStrings.AdjustBeatmapOffsetAutomaticallyTooltip, + Caption = AudioSettingsStrings.AdjustBeatmapOffsetAutomatically, + HintText = AudioSettingsStrings.AdjustBeatmapOffsetAutomaticallyTooltip, Current = config.GetBindable(OsuSetting.AutomaticallyAdjustBeatmapOffset), - } + }) }; } } diff --git a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs index 2bb5fa983f54..c0d38e50c151 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Audio @@ -20,46 +20,38 @@ private void load(AudioManager audio, OsuConfigManager config) { Children = new Drawable[] { - new VolumeAdjustSlider + new SettingsItemV2(new FormSliderBar { - LabelText = AudioSettingsStrings.MasterVolume, + Caption = AudioSettingsStrings.MasterVolume, Current = audio.Volume, KeyboardStep = 0.01f, - DisplayAsPercentage = true - }, - new SettingsSlider + DisplayAsPercentage = true, + PlaySamplesOnAdjust = false, + }), + new SettingsItemV2(new FormSliderBar { - LabelText = AudioSettingsStrings.MasterVolumeInactive, + Caption = AudioSettingsStrings.MasterVolumeInactive, Current = config.GetBindable(OsuSetting.VolumeInactive), KeyboardStep = 0.01f, DisplayAsPercentage = true - }, - new VolumeAdjustSlider + }), + new SettingsItemV2(new FormSliderBar { - LabelText = AudioSettingsStrings.EffectVolume, + Caption = AudioSettingsStrings.EffectVolume, Current = audio.VolumeSample, KeyboardStep = 0.01f, - DisplayAsPercentage = true - }, - - new VolumeAdjustSlider + DisplayAsPercentage = true, + PlaySamplesOnAdjust = false, + }), + new SettingsItemV2(new FormSliderBar { - LabelText = AudioSettingsStrings.MusicVolume, + Caption = AudioSettingsStrings.MusicVolume, Current = audio.VolumeTrack, KeyboardStep = 0.01f, - DisplayAsPercentage = true - }, + DisplayAsPercentage = true, + PlaySamplesOnAdjust = false, + }), }; } - - private partial class VolumeAdjustSlider : SettingsSlider - { - protected override Drawable CreateControl() - { - var sliderBar = (RoundedSliderBar)base.CreateControl(); - sliderBar.PlaySamplesOnAdjust = false; - return sliderBar; - } - } } } diff --git a/osu.Game/Overlays/Settings/Sections/DebugSettings/BatchImportSettings.cs b/osu.Game/Overlays/Settings/Sections/DebugSettings/BatchImportSettings.cs index 1c1735631313..86455c458591 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSettings/BatchImportSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSettings/BatchImportSettings.cs @@ -11,10 +11,10 @@ public partial class BatchImportSettings : SettingsSubsection { protected override LocalisableString Header => @"Batch Import"; - private SettingsButton importBeatmapsButton = null!; - private SettingsButton importCollectionsButton = null!; - private SettingsButton importScoresButton = null!; - private SettingsButton importSkinsButton = null!; + private SettingsButtonV2 importBeatmapsButton = null!; + private SettingsButtonV2 importCollectionsButton = null!; + private SettingsButtonV2 importScoresButton = null!; + private SettingsButtonV2 importSkinsButton = null!; [BackgroundDependencyLoader] private void load(LegacyImportManager? legacyImportManager) @@ -24,7 +24,7 @@ private void load(LegacyImportManager? legacyImportManager) AddRange(new[] { - importBeatmapsButton = new SettingsButton + importBeatmapsButton = new SettingsButtonV2 { Text = @"Import beatmaps from stable", Action = () => @@ -33,7 +33,7 @@ private void load(LegacyImportManager? legacyImportManager) legacyImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(_ => Schedule(() => importBeatmapsButton.Enabled.Value = true)); } }, - importSkinsButton = new SettingsButton + importSkinsButton = new SettingsButtonV2 { Text = @"Import skins from stable", Action = () => @@ -42,7 +42,7 @@ private void load(LegacyImportManager? legacyImportManager) legacyImportManager.ImportFromStableAsync(StableContent.Skins).ContinueWith(_ => Schedule(() => importSkinsButton.Enabled.Value = true)); } }, - importCollectionsButton = new SettingsButton + importCollectionsButton = new SettingsButtonV2 { Text = @"Import collections from stable", Action = () => @@ -51,7 +51,7 @@ private void load(LegacyImportManager? legacyImportManager) legacyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(_ => Schedule(() => importCollectionsButton.Enabled.Value = true)); } }, - importScoresButton = new SettingsButton + importScoresButton = new SettingsButtonV2 { Text = @"Import scores from stable", Action = () => diff --git a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs index 914fc9d141c6..04b63ccb844e 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Localisation; +using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Overlays.Settings.Sections.DebugSettings { @@ -14,17 +15,17 @@ public partial class GeneralSettings : SettingsSubsection [BackgroundDependencyLoader] private void load(FrameworkDebugConfigManager config, FrameworkConfigManager frameworkConfig) { - Add(new SettingsCheckbox + Add(new SettingsItemV2(new FormCheckBox { - LabelText = @"Show log overlay", + Caption = @"Show log overlay", Current = frameworkConfig.GetBindable(FrameworkSetting.ShowLogOverlay) - }); + })); - Add(new SettingsCheckbox + Add(new SettingsItemV2(new FormCheckBox { - LabelText = @"Bypass front-to-back render pass", + Caption = @"Bypass front-to-back render pass", Current = config.GetBindable(DebugSetting.BypassFrontToBackPass) - }); + })); } } } diff --git a/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs b/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs index 7b9b88a213fd..63b09872b763 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs @@ -13,6 +13,7 @@ using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Database; +using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Overlays.Settings.Sections.DebugSettings { @@ -23,10 +24,10 @@ public partial class MemorySettings : SettingsSubsection [BackgroundDependencyLoader] private void load(GameHost host, RealmAccess realm) { - SettingsButton blockAction; - SettingsButton unblockAction; + SettingsButtonV2 blockAction; + SettingsButtonV2 unblockAction; - Add(new SettingsButton + Add(new SettingsButtonV2 { Text = @"Clear all caches", Action = () => @@ -38,11 +39,11 @@ private void load(GameHost host, RealmAccess realm) } }); - SettingsEnumDropdown latencyModeDropdown; - Add(latencyModeDropdown = new SettingsEnumDropdown + FormEnumDropdown latencyModeDropdown; + Add(new SettingsItemV2(latencyModeDropdown = new FormEnumDropdown { - LabelText = "GC mode", - }); + Caption = "GC mode", + })); latencyModeDropdown.Current.BindValueChanged(mode => { @@ -65,7 +66,7 @@ private void load(GameHost host, RealmAccess realm) { AddRange(new Drawable[] { - new SettingsButton + new SettingsButtonV2 { Text = @"Compact realm", Action = () => @@ -76,11 +77,11 @@ private void load(GameHost host, RealmAccess realm) } } }, - blockAction = new SettingsButton + blockAction = new SettingsButtonV2 { Text = @"Block realm", }, - unblockAction = new SettingsButton + unblockAction = new SettingsButtonV2 { Text = @"Unblock realm", } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/AudioSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/AudioSettings.cs index 467c98802074..403b4f237801 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/AudioSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/AudioSettings.cs @@ -5,12 +5,15 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Gameplay { public partial class AudioSettings : SettingsSubsection { + private FormCheckBox alwaysPlayFirstComboBreak = null!; + protected override LocalisableString Header => GameplaySettingsStrings.AudioHeader; [BackgroundDependencyLoader] @@ -18,19 +21,23 @@ private void load(OsuConfigManager config, OsuConfigManager osuConfig) { Children = new Drawable[] { - new SettingsSlider + new SettingsItemV2(new FormSliderBar { - LabelText = AudioSettingsStrings.PositionalLevel, - Keywords = new[] { @"positional", @"balance" }, + Caption = AudioSettingsStrings.PositionalLevel, Current = osuConfig.GetBindable(OsuSetting.PositionalHitsoundsLevel), KeyboardStep = 0.01f, DisplayAsPercentage = true + }) + { + Keywords = new[] { @"positional", @"balance" }, }, - new SettingsCheckbox + new SettingsItemV2(alwaysPlayFirstComboBreak = new FormCheckBox { - ClassicDefault = false, - LabelText = GameplaySettingsStrings.AlwaysPlayFirstComboBreak, + Caption = GameplaySettingsStrings.AlwaysPlayFirstComboBreak, Current = config.GetBindable(OsuSetting.AlwaysPlayFirstComboBreak) + }) + { + ApplyClassicDefault = () => alwaysPlayFirstComboBreak.Current.Value = false, } }; } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/BackgroundSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/BackgroundSettings.cs index 830ccec27926..23478fe95457 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/BackgroundSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/BackgroundSettings.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Gameplay @@ -18,31 +19,33 @@ private void load(OsuConfigManager config) { Children = new Drawable[] { - new SettingsSlider + new SettingsItemV2(new FormSliderBar { - LabelText = GameplaySettingsStrings.BackgroundDim, + Caption = GameplaySettingsStrings.BackgroundDim, Current = config.GetBindable(OsuSetting.DimLevel), KeyboardStep = 0.01f, DisplayAsPercentage = true - }, - new SettingsSlider + }), + new SettingsItemV2(new FormSliderBar { - LabelText = GameplaySettingsStrings.BackgroundBlur, + Caption = GameplaySettingsStrings.BackgroundBlur, Current = config.GetBindable(OsuSetting.BlurLevel), KeyboardStep = 0.01f, DisplayAsPercentage = true - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = GameplaySettingsStrings.LightenDuringBreaks, + Caption = GameplaySettingsStrings.LightenDuringBreaks, Current = config.GetBindable(OsuSetting.LightenDuringBreaks), + }) + { Keywords = new[] { "dim", "level" } }, - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = GameplaySettingsStrings.FadePlayfieldWhenHealthLow, + Caption = GameplaySettingsStrings.FadePlayfieldWhenHealthLow, Current = config.GetBindable(OsuSetting.FadePlayfieldWhenHealthLow), - }, + }), }; } } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs index 69566d85f489..32e79809e5e6 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Gameplay @@ -23,35 +24,41 @@ private void load(OsuConfigManager config) Children = new Drawable[] { - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = SkinSettingsStrings.BeatmapSkins, + Caption = SkinSettingsStrings.BeatmapSkins, Current = config.GetBindable(OsuSetting.BeatmapSkins) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - Keywords = new[] { "combo", "override", "color" }, - LabelText = SkinSettingsStrings.BeatmapColours, + Caption = SkinSettingsStrings.BeatmapColours, Current = config.GetBindable(OsuSetting.BeatmapColours) + }) + { + Keywords = new[] { "combo", "override", "color" }, }, - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - Keywords = new[] { "samples", "override" }, - LabelText = SkinSettingsStrings.BeatmapHitsounds, + Caption = SkinSettingsStrings.BeatmapHitsounds, Current = config.GetBindable(OsuSetting.BeatmapHitsounds) + }) + { + Keywords = new[] { "samples", "override" }, }, - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = GraphicsSettingsStrings.StoryboardVideo, + Caption = GraphicsSettingsStrings.StoryboardVideo, Current = config.GetBindable(OsuSetting.ShowStoryboard) - }, - new SettingsSlider + }), + new SettingsItemV2(new FormSliderBar { - Keywords = new[] { "color" }, - LabelText = GraphicsSettingsStrings.ComboColourNormalisation, + Caption = GraphicsSettingsStrings.ComboColourNormalisation, Current = comboColourNormalisation, DisplayAsPercentage = true, - } + }) + { + Keywords = new[] { "color" }, + }, }; } } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs index 779d5cdf005f..34879ffa996d 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Rulesets.Scoring; @@ -12,6 +13,8 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { public partial class GeneralSettings : SettingsSubsection { + private FormEnumDropdown scoringModeDropdown = null!; + protected override LocalisableString Header => CommonStrings.General; [BackgroundDependencyLoader] @@ -19,23 +22,25 @@ private void load(OsuConfigManager config) { Children = new Drawable[] { - new SettingsEnumDropdown + new SettingsItemV2(scoringModeDropdown = new FormEnumDropdown { - ClassicDefault = ScoringMode.Classic, - LabelText = GameplaySettingsStrings.ScoreDisplayMode, + Caption = GameplaySettingsStrings.ScoreDisplayMode, Current = config.GetBindable(OsuSetting.ScoreDisplayMode), - Keywords = new[] { "scoring" } + }) + { + Keywords = new[] { "scoring" }, + ApplyClassicDefault = () => scoringModeDropdown.Current.Value = ScoringMode.Classic, }, - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = GraphicsSettingsStrings.HitLighting, + Caption = GraphicsSettingsStrings.HitLighting, Current = config.GetBindable(OsuSetting.HitLighting) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = GameplaySettingsStrings.StarFountains, + Caption = GameplaySettingsStrings.StarFountains, Current = config.GetBindable(OsuSetting.StarFountains) - }, + }), }; } } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs index b4caaf798378..7c9fad624c4d 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs @@ -5,12 +5,15 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Gameplay { public partial class HUDSettings : SettingsSubsection { + private FormCheckBox showHealthDisplayWhenCantFail = null!; + protected override LocalisableString Header => GameplaySettingsStrings.HUDHeader; [BackgroundDependencyLoader] @@ -18,44 +21,50 @@ private void load(OsuConfigManager config) { Children = new Drawable[] { - new SettingsEnumDropdown + new SettingsItemV2(new FormEnumDropdown { - LabelText = GameplaySettingsStrings.HUDVisibilityMode, + Caption = GameplaySettingsStrings.HUDVisibilityMode, Current = config.GetBindable(OsuSetting.HUDVisibilityMode) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = GameplaySettingsStrings.ShowReplaySettingsOverlay, + Caption = GameplaySettingsStrings.ShowReplaySettingsOverlay, Current = config.GetBindable(OsuSetting.ReplaySettingsOverlay), + }) + { Keywords = new[] { "hide" }, }, - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = GameplaySettingsStrings.AlwaysShowKeyOverlay, + Caption = GameplaySettingsStrings.AlwaysShowKeyOverlay, Current = config.GetBindable(OsuSetting.KeyOverlay), + }) + { Keywords = new[] { "counter" }, }, - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = GameplaySettingsStrings.AlwaysShowGameplayLeaderboard, + Caption = GameplaySettingsStrings.AlwaysShowGameplayLeaderboard, Current = config.GetBindable(OsuSetting.GameplayLeaderboard), - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = GameplaySettingsStrings.AlwaysRequireHoldForMenu, + Caption = GameplaySettingsStrings.AlwaysRequireHoldForMenu, Current = config.GetBindable(OsuSetting.AlwaysRequireHoldingForPause), - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = GameplaySettingsStrings.AlwaysShowHoldForMenuButton, + Caption = GameplaySettingsStrings.AlwaysShowHoldForMenuButton, Current = config.GetBindable(OsuSetting.AlwaysShowHoldForMenuButton), - }, - new SettingsCheckbox + }), + new SettingsItemV2(showHealthDisplayWhenCantFail = new FormCheckBox { - ClassicDefault = false, - LabelText = GameplaySettingsStrings.ShowHealthDisplayWhenCantFail, + Caption = GameplaySettingsStrings.ShowHealthDisplayWhenCantFail, Current = config.GetBindable(OsuSetting.ShowHealthDisplayWhenCantFail), - Keywords = new[] { "hp", "bar" } + }) + { + Keywords = new[] { "hp", "bar" }, + ApplyClassicDefault = () => showHealthDisplayWhenCantFail.Current.Value = false, }, }; } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/InputSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/InputSettings.cs index c245a1a9ea5e..bed050fac50a 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/InputSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/InputSettings.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Gameplay @@ -19,32 +20,35 @@ private void load(OsuConfigManager config) { Children = new Drawable[] { - new SettingsSlider> + new SettingsItemV2(new FormSliderBar { - LabelText = SkinSettingsStrings.GameplayCursorSize, + Caption = SkinSettingsStrings.GameplayCursorSize, Current = config.GetBindable(OsuSetting.GameplayCursorSize), - KeyboardStep = 0.01f - }, - new SettingsCheckbox + KeyboardStep = 0.01f, + LabelFormat = v => $"{v:0.##}x" + }), + new SettingsItemV2(new FormCheckBox { - LabelText = SkinSettingsStrings.AutoCursorSize, + Caption = SkinSettingsStrings.AutoCursorSize, Current = config.GetBindable(OsuSetting.AutoCursorSize) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = SkinSettingsStrings.GameplayCursorDuringTouch, - Keywords = new[] { @"touchscreen" }, + Caption = SkinSettingsStrings.GameplayCursorDuringTouch, Current = config.GetBindable(OsuSetting.GameplayCursorDuringTouch) + }) + { + Keywords = new[] { @"touchscreen" }, }, }; if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows) { - Add(new SettingsCheckbox + Add(new SettingsItemV2(new FormCheckBox { - LabelText = GameplaySettingsStrings.DisableWinKey, + Caption = GameplaySettingsStrings.DisableWinKey, Current = config.GetBindable(OsuSetting.GameplayDisableWinKey) - }); + })); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs index 79a971510fd7..136108e0abc7 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Gameplay @@ -21,10 +22,12 @@ private void load(OsuConfigManager config) { Children = new[] { - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = GameplaySettingsStrings.IncreaseFirstObjectVisibility, + Caption = GameplaySettingsStrings.IncreaseFirstObjectVisibility, Current = config.GetBindable(OsuSetting.IncreaseFirstObjectVisibility), + }) + { Keywords = new[] { @"approach", @"circle", @"hidden" }, }, }; diff --git a/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs b/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs index 68f3ba9b1722..99d04398dfda 100644 --- a/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/InstallationSettings.cs @@ -20,14 +20,14 @@ public partial class InstallationSettings : SettingsSubsection [BackgroundDependencyLoader] private void load(Storage storage) { - Add(new SettingsButton + Add(new SettingsButtonV2 { Text = GeneralSettingsStrings.OpenOsuFolder, Keywords = new[] { @"logs", @"files", @"access", "directory" }, Action = () => storage.PresentExternally(), }); - Add(new DangerousSettingsButton + Add(new DangerousSettingsButtonV2 { Text = GeneralSettingsStrings.ChangeFolderLocation, Action = () => game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen())) diff --git a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs index 2af6e36b7fe0..515302239b2a 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.General @@ -19,22 +20,22 @@ private void load(OsuGameBase game, OsuConfigManager config, FrameworkConfigMana { Children = new Drawable[] { - new SettingsEnumDropdown + new SettingsItemV2(new FormEnumDropdown { - LabelText = GeneralSettingsStrings.LanguageDropdown, + Caption = GeneralSettingsStrings.LanguageDropdown, Current = game.CurrentLanguage, AlwaysShowSearchBar = true, - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = GeneralSettingsStrings.PreferOriginalMetadataLanguage, + Caption = GeneralSettingsStrings.PreferOriginalMetadataLanguage, Current = frameworkConfig.GetBindable(FrameworkSetting.ShowUnicode) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = GeneralSettingsStrings.Prefer24HourTimeDisplay, + Caption = GeneralSettingsStrings.Prefer24HourTimeDisplay, Current = config.GetBindable(OsuSetting.Prefer24HourTime) - }, + }), }; } } diff --git a/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs index b6b78a6d00f4..4b504a7e9eda 100644 --- a/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs @@ -35,21 +35,21 @@ private void load(OsuColour colours, Storage storage) { AddRange(new Drawable[] { - new SettingsButton + new SettingsButtonV2 { Text = GeneralSettingsStrings.RunSetupWizard, Keywords = new[] { @"first run", @"initial", @"getting started", @"import", @"tutorial", @"recommended beatmaps" }, TooltipText = FirstRunSetupOverlayStrings.FirstRunSetupDescription, Action = () => firstRunSetupOverlay?.Show(), }, - new SettingsButton + new SettingsButtonV2 { Text = GeneralSettingsStrings.LearnMoreAboutLazer, TooltipText = GeneralSettingsStrings.LearnMoreAboutLazerTooltip, BackgroundColour = colours.YellowDark, Action = () => game?.ShowWiki(@"Help_centre/Upgrading_to_lazer") }, - new SettingsButton + new SettingsButtonV2 { Text = GeneralSettingsStrings.ReportIssue, TooltipText = GeneralSettingsStrings.ReportIssueTooltip, @@ -62,7 +62,7 @@ private void load(OsuColour colours, Storage storage) if (supportsExport) { - Add(new SettingsButton + Add(new SettingsButtonV2 { Text = GeneralSettingsStrings.ExportLogs, BackgroundColour = colours.YellowDarker.Darken(0.5f), diff --git a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs index 87b1acc23a83..c8efb50accf2 100644 --- a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Online.Multiplayer; using osu.Game.Overlays.Dialog; @@ -20,8 +21,10 @@ public partial class UpdateSettings : SettingsSubsection { protected override LocalisableString Header => GeneralSettingsStrings.UpdateHeader; - private SettingsButton checkForUpdatesButton = null!; - private SettingsEnumDropdown releaseStreamDropdown = null!; + private SettingsButtonV2 checkForUpdatesButton = null!; + private FormEnumDropdown releaseStreamDropdown = null!; + + private readonly Bindable releaseStreamDropdownNote = new Bindable(); private readonly Bindable configReleaseStream = new Bindable(); @@ -47,26 +50,28 @@ private void load(OsuConfigManager config) // For simplicity, hide the concept of release streams from mobile users. if (isDesktop) { - Add(releaseStreamDropdown = new SettingsEnumDropdown + Add(new SettingsItemV2(releaseStreamDropdown = new FormEnumDropdown { - LabelText = GeneralSettingsStrings.ReleaseStream, + Caption = GeneralSettingsStrings.ReleaseStream, Current = { Value = configReleaseStream.Value }, + }) + { Keywords = new[] { @"version" }, + ShowRevertToDefaultButton = updateManager!.FixedReleaseStream == null }); if (updateManager!.FixedReleaseStream != null) { configReleaseStream.Value = updateManager.FixedReleaseStream.Value; - releaseStreamDropdown.ShowsDefaultIndicator = false; releaseStreamDropdown.Items = [updateManager.FixedReleaseStream.Value]; - releaseStreamDropdown.SetNoticeText(GeneralSettingsStrings.ChangeReleaseStreamPackageManagerWarning); + releaseStreamDropdownNote.Value = new SettingsNote.Data(GeneralSettingsStrings.ChangeReleaseStreamPackageManagerWarning, SettingsNote.Type.Warning); } releaseStreamDropdown.Current.BindValueChanged(releaseStreamChanged); } - Add(checkForUpdatesButton = new SettingsButton + Add(checkForUpdatesButton = new SettingsButtonV2 { Text = GeneralSettingsStrings.CheckUpdate, Action = () => checkForUpdates().FireAndForget() diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs index 69697bd9a301..f1cec99f38a0 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs @@ -9,7 +9,7 @@ using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Game.Configuration; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Overlays.Dialog; @@ -29,32 +29,38 @@ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, IDi Children = new Drawable[] { - new RendererSettingsDropdown + new SettingsItemV2(new RendererDropdown { - LabelText = GraphicsSettingsStrings.Renderer, + Caption = GraphicsSettingsStrings.Renderer, Current = renderer, Items = host.GetPreferredRenderersForCurrentPlatform().Order() #pragma warning disable CS0612 // Type or member is obsolete .Where(t => t != RendererType.Vulkan && t != RendererType.OpenGLLegacy), #pragma warning restore CS0612 // Type or member is obsolete + }) + { Keywords = new[] { @"compatibility", @"directx" }, }, // TODO: this needs to be a custom dropdown at some point - new SettingsEnumDropdown + new SettingsItemV2(new FormEnumDropdown { - LabelText = GraphicsSettingsStrings.FrameLimiter, + Caption = GraphicsSettingsStrings.FrameLimiter, Current = config.GetBindable(FrameworkSetting.FrameSync), + }) + { Keywords = new[] { @"fps", @"framerate" }, }, - new SettingsEnumDropdown + new SettingsItemV2(new FormEnumDropdown { - LabelText = GraphicsSettingsStrings.ThreadingMode, + Caption = GraphicsSettingsStrings.ThreadingMode, Current = config.GetBindable(FrameworkSetting.ExecutionMode) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = GraphicsSettingsStrings.ShowFPS, + Caption = GraphicsSettingsStrings.ShowFPS, Current = osuConfig.GetBindable(OsuSetting.ShowFpsDisplay), + }) + { Keywords = new[] { @"framerate", @"counter" }, }, }; @@ -82,30 +88,25 @@ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, IDi }); } - private partial class RendererSettingsDropdown : SettingsEnumDropdown + private partial class RendererDropdown : FormEnumDropdown { - protected override OsuDropdown CreateDropdown() => new RendererDropdown(); + private RendererType hostResolvedRenderer; + private bool automaticRendererInUse; - protected partial class RendererDropdown : DropdownControl + [BackgroundDependencyLoader] + private void load(FrameworkConfigManager config, GameHost host) { - private RendererType hostResolvedRenderer; - private bool automaticRendererInUse; - - [BackgroundDependencyLoader] - private void load(FrameworkConfigManager config, GameHost host) - { - var renderer = config.GetBindable(FrameworkSetting.Renderer); - automaticRendererInUse = renderer.Value == RendererType.Automatic; - hostResolvedRenderer = host.ResolvedRenderer; - } + var renderer = config.GetBindable(FrameworkSetting.Renderer); + automaticRendererInUse = renderer.Value == RendererType.Automatic; + hostResolvedRenderer = host.ResolvedRenderer; + } - protected override LocalisableString GenerateItemText(RendererType item) - { - if (item == RendererType.Automatic && automaticRendererInUse) - return LocalisableString.Interpolate($"{base.GenerateItemText(item)} ({hostResolvedRenderer.GetDescription()})"); + protected override LocalisableString GenerateItemText(RendererType item) + { + if (item == RendererType.Automatic && automaticRendererInUse) + return LocalisableString.Interpolate($"{base.GenerateItemText(item)} ({hostResolvedRenderer.GetDescription()})"); - return base.GenerateItemText(item); - } + return base.GenerateItemText(item); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/ScreenshotSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/ScreenshotSettings.cs index c7180ec51bb9..f5dd19dc9904 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/ScreenshotSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/ScreenshotSettings.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Graphics @@ -18,16 +19,16 @@ private void load(OsuConfigManager config) { Children = new Drawable[] { - new SettingsEnumDropdown + new SettingsItemV2(new FormEnumDropdown { - LabelText = GraphicsSettingsStrings.ScreenshotFormat, + Caption = GraphicsSettingsStrings.ScreenshotFormat, Current = config.GetBindable(OsuSetting.ScreenshotFormat) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = GraphicsSettingsStrings.ShowCursorInScreenshots, + Caption = GraphicsSettingsStrings.ShowCursorInScreenshots, Current = config.GetBindable(OsuSetting.ScreenshotCaptureMenuCursor) - } + }) }; } } diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/VideoSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/VideoSettings.cs index 2e0bbe3c162b..0481b450377b 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/VideoSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/VideoSettings.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Video; using osu.Framework.Localisation; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Graphics @@ -18,7 +19,7 @@ public partial class VideoSettings : SettingsSubsection protected override LocalisableString Header => GraphicsSettingsStrings.VideoHeader; private Bindable hardwareVideoDecoder; - private SettingsCheckbox hwAccelCheckbox; + private FormCheckBox hwAccelCheckbox; [BackgroundDependencyLoader] private void load(FrameworkConfigManager config) @@ -27,10 +28,10 @@ private void load(FrameworkConfigManager config) Children = new Drawable[] { - hwAccelCheckbox = new SettingsCheckbox + new SettingsItemV2(hwAccelCheckbox = new FormCheckBox { - LabelText = GraphicsSettingsStrings.UseHardwareAcceleration, - }, + Caption = GraphicsSettingsStrings.UseHardwareAcceleration, + }), }; hwAccelCheckbox.Current.Default = hardwareVideoDecoder.Default != HardwareVideoDecoder.None; diff --git a/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs index 704fa6e907d3..c892e8fa2157 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs @@ -19,7 +19,7 @@ public BindingSettings(KeyBindingPanel keyConfig) { Children = new Drawable[] { - new SettingsButton + new SettingsButtonV2 { Text = BindingSettingsStrings.Configure, TooltipText = BindingSettingsStrings.ChangeBindingsButton, diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs index cde9f1054959..873ecc3f470b 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs @@ -111,7 +111,7 @@ private void onBindingUpdated(KeyBindingRow sender, KeyBindingRow.KeyBindingUpda } } - public partial class ResetButton : DangerousSettingsButton + public partial class ResetButton : DangerousSettingsButtonV2 { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs index 597e03fab21e..a4d20fb459cf 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs @@ -14,16 +14,16 @@ public partial class BeatmapSettings : SettingsSubsection { protected override LocalisableString Header => CommonStrings.Beatmaps; - private SettingsButton deleteBeatmapsButton = null!; - private SettingsButton deleteBeatmapVideosButton = null!; - private SettingsButton resetOffsetsButton = null!; - private SettingsButton restoreButton = null!; - private SettingsButton undeleteButton = null!; + private SettingsButtonV2 deleteBeatmapsButton = null!; + private SettingsButtonV2 deleteBeatmapVideosButton = null!; + private SettingsButtonV2 resetOffsetsButton = null!; + private SettingsButtonV2 restoreButton = null!; + private SettingsButtonV2 undeleteButton = null!; [BackgroundDependencyLoader] private void load(BeatmapManager beatmaps, IDialogOverlay? dialogOverlay) { - Add(deleteBeatmapsButton = new DangerousSettingsButton + Add(deleteBeatmapsButton = new DangerousSettingsButtonV2 { Text = MaintenanceSettingsStrings.DeleteAllBeatmaps, Action = () => @@ -36,7 +36,7 @@ private void load(BeatmapManager beatmaps, IDialogOverlay? dialogOverlay) } }); - Add(deleteBeatmapVideosButton = new DangerousSettingsButton + Add(deleteBeatmapVideosButton = new DangerousSettingsButtonV2 { Text = MaintenanceSettingsStrings.DeleteAllBeatmapVideos, Action = () => @@ -49,7 +49,7 @@ private void load(BeatmapManager beatmaps, IDialogOverlay? dialogOverlay) } }); - Add(resetOffsetsButton = new DangerousSettingsButton + Add(resetOffsetsButton = new DangerousSettingsButtonV2 { Text = MaintenanceSettingsStrings.ResetAllOffsets, Action = () => @@ -64,7 +64,7 @@ private void load(BeatmapManager beatmaps, IDialogOverlay? dialogOverlay) AddRange(new Drawable[] { - restoreButton = new SettingsButton + restoreButton = new SettingsButtonV2 { Text = MaintenanceSettingsStrings.RestoreAllHiddenDifficulties, Action = () => @@ -73,7 +73,7 @@ private void load(BeatmapManager beatmaps, IDialogOverlay? dialogOverlay) Task.Run(beatmaps.RestoreAll).ContinueWith(_ => Schedule(() => restoreButton.Enabled.Value = true)); } }, - undeleteButton = new SettingsButton + undeleteButton = new SettingsButtonV2 { Text = MaintenanceSettingsStrings.RestoreAllRecentlyDeletedBeatmaps, Action = () => diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs index b1c44aa93c04..922969035dc7 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs @@ -24,7 +24,7 @@ public partial class CollectionsSettings : SettingsSubsection [BackgroundDependencyLoader] private void load(IDialogOverlay? dialogOverlay) { - Add(new DangerousSettingsButton + Add(new DangerousSettingsButtonV2 { Text = MaintenanceSettingsStrings.DeleteAllCollections, Action = () => diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 47314dcafef4..2c79daffb6ab 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -29,7 +29,7 @@ private void load(OsuGameBase game, GameHost host, IPerformFromScreenRunner? per AddRange(new Drawable[] { - new SettingsButton + new SettingsButtonV2 { Text = DebugSettingsStrings.ImportFiles, Action = () => @@ -40,7 +40,7 @@ private void load(OsuGameBase game, GameHost host, IPerformFromScreenRunner? per performer?.PerformFromScreen(menu => menu.Push(new FileImportScreen())); }, }, - new SettingsButton + new SettingsButtonV2 { Text = DebugSettingsStrings.RunLatencyCertifier, Action = () => performer?.PerformFromScreen(menu => menu.Push(new LatencyCertifierScreen())) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs index 9c55308abe83..17101c65260e 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs @@ -25,15 +25,15 @@ public partial class ModPresetSettings : SettingsSubsection [Resolved] private INotificationOverlay? notificationOverlay { get; set; } - private SettingsButton undeleteButton = null!; - private SettingsButton deleteAllButton = null!; + private SettingsButtonV2 undeleteButton = null!; + private SettingsButtonV2 deleteAllButton = null!; [BackgroundDependencyLoader] private void load(IDialogOverlay? dialogOverlay) { AddRange(new Drawable[] { - deleteAllButton = new DangerousSettingsButton + deleteAllButton = new DangerousSettingsButtonV2 { Text = MaintenanceSettingsStrings.DeleteAllModPresets, Action = () => @@ -45,7 +45,7 @@ private void load(IDialogOverlay? dialogOverlay) }, DeleteConfirmationContentStrings.ModPresets)); } }, - undeleteButton = new SettingsButton + undeleteButton = new SettingsButtonV2 { Text = MaintenanceSettingsStrings.RestoreAllRecentlyDeletedModPresets, Action = () => Task.Run(undeleteModPresets).ContinueWith(t => Schedule(onModPresetsUndeleted, t)) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs index 235f239c7c95..b4a1d449ed16 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs @@ -13,12 +13,12 @@ public partial class ScoreSettings : SettingsSubsection { protected override LocalisableString Header => CommonStrings.Scores; - private SettingsButton deleteScoresButton = null!; + private SettingsButtonV2 deleteScoresButton = null!; [BackgroundDependencyLoader] private void load(ScoreManager scores, IDialogOverlay? dialogOverlay) { - Add(deleteScoresButton = new DangerousSettingsButton + Add(deleteScoresButton = new DangerousSettingsButtonV2 { Text = MaintenanceSettingsStrings.DeleteAllScores, Action = () => diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs index e962118a368a..85b4898e0508 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs @@ -13,12 +13,12 @@ public partial class SkinSettings : SettingsSubsection { protected override LocalisableString Header => CommonStrings.Skins; - private SettingsButton deleteSkinsButton = null!; + private SettingsButtonV2 deleteSkinsButton = null!; [BackgroundDependencyLoader] private void load(SkinManager skins, IDialogOverlay? dialogOverlay) { - Add(deleteSkinsButton = new DangerousSettingsButton + Add(deleteSkinsButton = new DangerousSettingsButtonV2 { Text = MaintenanceSettingsStrings.DeleteAllSkins, Action = () => diff --git a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs index 608c6ef1b291..227d3feeaf23 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Online @@ -18,27 +19,27 @@ private void load(OsuConfigManager config) { Children = new Drawable[] { - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = OnlineSettingsStrings.NotifyOnMentioned, + Caption = OnlineSettingsStrings.NotifyOnMentioned, Current = config.GetBindable(OsuSetting.NotifyOnUsernameMentioned) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = OnlineSettingsStrings.NotifyOnPrivateMessage, + Caption = OnlineSettingsStrings.NotifyOnPrivateMessage, Current = config.GetBindable(OsuSetting.NotifyOnPrivateMessage) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = OnlineSettingsStrings.NotifyOnFriendPresenceChange, - TooltipText = OnlineSettingsStrings.NotifyOnFriendPresenceChangeTooltip, + Caption = OnlineSettingsStrings.NotifyOnFriendPresenceChange, + HintText = OnlineSettingsStrings.NotifyOnFriendPresenceChangeTooltip, Current = config.GetBindable(OsuSetting.NotifyOnFriendPresenceChange), - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = OnlineSettingsStrings.HideCountryFlags, + Caption = OnlineSettingsStrings.HideCountryFlags, Current = config.GetBindable(OsuSetting.HideCountryFlags) - }, + }), }; } } diff --git a/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs b/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs index 3d0fac32cfca..3445c67b95cc 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Online @@ -18,11 +19,11 @@ private void load(OsuConfigManager config) { Children = new Drawable[] { - new SettingsEnumDropdown + new SettingsItemV2(new FormEnumDropdown { - LabelText = OnlineSettingsStrings.DiscordRichPresence, + Caption = OnlineSettingsStrings.DiscordRichPresence, Current = config.GetBindable(OsuSetting.DiscordRichPresence) - } + }), }; } } diff --git a/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs b/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs index ce5c85bed097..bcb1d91547ed 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Online @@ -18,28 +19,34 @@ private void load(OsuConfigManager config) { Children = new Drawable[] { - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = OnlineSettingsStrings.ExternalLinkWarning, + Caption = OnlineSettingsStrings.ExternalLinkWarning, Current = config.GetBindable(OsuSetting.ExternalLinkWarning) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = OnlineSettingsStrings.PreferNoVideo, - Keywords = new[] { "no-video" }, + Caption = OnlineSettingsStrings.PreferNoVideo, Current = config.GetBindable(OsuSetting.PreferNoVideo) + }) + { + Keywords = new[] { "no-video" }, }, - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = OnlineSettingsStrings.AutomaticallyDownloadMissingBeatmaps, - Keywords = new[] { "spectator", "replay" }, + Caption = OnlineSettingsStrings.AutomaticallyDownloadMissingBeatmaps, Current = config.GetBindable(OsuSetting.AutomaticallyDownloadMissingBeatmaps), + }) + { + Keywords = new[] { "spectator", "replay" }, }, - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = OnlineSettingsStrings.ShowExplicitContent, - Keywords = new[] { "nsfw", "18+", "offensive" }, + Caption = OnlineSettingsStrings.ShowExplicitContent, Current = config.GetBindable(OsuSetting.ShowOnlineExplicitContent), + }) + { + Keywords = new[] { "nsfw", "18+", "offensive" }, } }; } diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 4d7c0117e2c4..022d7d38c9e6 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Settings.Sections { public partial class SkinSection : SettingsSection { - private SkinSettingsDropdown skinDropdown; + private SkinDropdown skinDropdown; public override LocalisableString Header => SkinSettingsStrings.SkinSectionHeader; @@ -65,29 +65,28 @@ private void load([CanBeNull] SkinEditorOverlay skinEditor) { Children = new Drawable[] { - skinDropdown = new SkinSettingsDropdown + new SettingsItemV2(skinDropdown = new SkinDropdown { AlwaysShowSearchBar = true, AllowNonContiguousMatching = true, - LabelText = SkinSettingsStrings.CurrentSkin, + Caption = SkinSettingsStrings.CurrentSkin, Current = skins.CurrentSkinInfo, - }, + }), new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Horizontal, - Spacing = new Vector2(5, 0), - Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS }, + Padding = SettingsPanel.ContentPaddingV2, Children = new Drawable[] { // This is all super-temporary until we move skin settings to their own panel / overlay. - new RenameSkinButton { Padding = new MarginPadding(), RelativeSizeAxes = Axes.None, Width = 120 }, - new ExportSkinButton { Padding = new MarginPadding(), RelativeSizeAxes = Axes.None, Width = 120 }, - new DeleteSkinButton { Padding = new MarginPadding(), RelativeSizeAxes = Axes.None, Width = 110 }, + new RenameSkinButton { Padding = new MarginPadding { Right = 2.5f }, RelativeSizeAxes = Axes.X, Width = 1 / 3f }, + new ExportSkinButton { Padding = new MarginPadding { Horizontal = 2.5f }, RelativeSizeAxes = Axes.X, Width = 1 / 3f }, + new DeleteSkinButton { Padding = new MarginPadding { Left = 2.5f }, RelativeSizeAxes = Axes.X, Width = 1 / 3f }, } }, - new SettingsButton + new SettingsButtonV2 { Text = SkinSettingsStrings.SkinLayoutEditor, Action = () => skinEditor?.ToggleVisibility(), @@ -148,17 +147,12 @@ protected override void Dispose(bool isDisposing) realmSubscription?.Dispose(); } - private partial class SkinSettingsDropdown : SettingsDropdown> + private partial class SkinDropdown : FormDropdown> { - protected override OsuDropdown> CreateDropdown() => new SkinDropdownControl(); - - private partial class SkinDropdownControl : DropdownControl - { - protected override LocalisableString GenerateItemText(Live item) => item.ToString(); - } + protected override LocalisableString GenerateItemText(Live item) => item.ToString(); } - public partial class RenameSkinButton : SettingsButton, IHasPopover + public partial class RenameSkinButton : SettingsButtonV2, IHasPopover { [Resolved] private SkinManager skins { get; set; } @@ -189,7 +183,7 @@ public Popover GetPopover() } } - public partial class ExportSkinButton : SettingsButton + public partial class ExportSkinButton : SettingsButtonV2 { [Resolved] private SkinManager skins { get; set; } @@ -227,7 +221,7 @@ private void export() } } - public partial class DeleteSkinButton : DangerousSettingsButton + public partial class DeleteSkinButton : DangerousSettingsButtonV2 { [Resolved] private SkinManager skins { get; set; } diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs index 3f39980b43bd..1e8852d4b7ed 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs @@ -5,13 +5,15 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.UserInterface { public partial class GeneralSettings : SettingsSubsection { + private FormSliderBar holdToConfirmSlider = null!; + protected override LocalisableString Header => CommonStrings.General; [BackgroundDependencyLoader] @@ -19,29 +21,33 @@ private void load(OsuConfigManager config) { Children = new Drawable[] { - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = UserInterfaceStrings.CursorRotation, + Caption = UserInterfaceStrings.CursorRotation, Current = config.GetBindable(OsuSetting.CursorRotation) - }, - new SettingsSlider> + }), + new SettingsItemV2(new FormSliderBar { - LabelText = UserInterfaceStrings.MenuCursorSize, + Caption = UserInterfaceStrings.MenuCursorSize, Current = config.GetBindable(OsuSetting.MenuCursorSize), - KeyboardStep = 0.01f - }, - new SettingsCheckbox + KeyboardStep = 0.01f, + LabelFormat = v => $"{v:0.##}x" + }), + new SettingsItemV2(new FormCheckBox { - LabelText = UserInterfaceStrings.Parallax, + Caption = UserInterfaceStrings.Parallax, Current = config.GetBindable(OsuSetting.MenuParallax) - }, - new SettingsSlider + }), + new SettingsItemV2(holdToConfirmSlider = new FormSliderBar { - ClassicDefault = 0, - LabelText = UserInterfaceStrings.HoldToConfirmActivationTime, + Caption = UserInterfaceStrings.HoldToConfirmActivationTime, Current = config.GetBindable(OsuSetting.UIHoldActivationDelay), + KeyboardStep = 50, + LabelFormat = v => $"{v:N0} ms", + }) + { Keywords = new[] { @"delay" }, - KeyboardStep = 50 + ApplyClassicDefault = () => holdToConfirmSlider.Current.Value = 0, }, }; } diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs index c50d56b458f0..f9f57d07f8f9 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs @@ -1,13 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; @@ -18,9 +17,9 @@ public partial class MainMenuSettings : SettingsSubsection { protected override LocalisableString Header => UserInterfaceStrings.MainMenuHeader; - private IBindable user; + private IBindable user = null!; - private SettingsEnumDropdown backgroundSourceDropdown; + private readonly Bindable backgroundSourceNote = new Bindable(); [BackgroundDependencyLoader] private void load(OsuConfigManager config, IAPIProvider api) @@ -29,38 +28,45 @@ private void load(OsuConfigManager config, IAPIProvider api) Children = new Drawable[] { - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = UserInterfaceStrings.ShowMenuTips, + Caption = UserInterfaceStrings.ShowMenuTips, Current = config.GetBindable(OsuSetting.MenuTips) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - Keywords = new[] { "intro", "welcome" }, - LabelText = UserInterfaceStrings.InterfaceVoices, + Caption = UserInterfaceStrings.InterfaceVoices, Current = config.GetBindable(OsuSetting.MenuVoice) - }, - new SettingsCheckbox + }) { Keywords = new[] { "intro", "welcome" }, - LabelText = UserInterfaceStrings.OsuMusicTheme, + }, + new SettingsItemV2(new FormCheckBox + { + Caption = UserInterfaceStrings.OsuMusicTheme, Current = config.GetBindable(OsuSetting.MenuMusic) + }) + { + Keywords = new[] { "intro", "welcome" }, }, - new SettingsEnumDropdown + new SettingsItemV2(new FormEnumDropdown { - LabelText = UserInterfaceStrings.IntroSequence, + Caption = UserInterfaceStrings.IntroSequence, Current = config.GetBindable(OsuSetting.IntroSequence), - }, - backgroundSourceDropdown = new SettingsEnumDropdown + }), + new SettingsItemV2(new FormEnumDropdown { - LabelText = UserInterfaceStrings.BackgroundSource, + Caption = UserInterfaceStrings.BackgroundSource, Current = config.GetBindable(OsuSetting.MenuBackgroundSource), + }) + { + Note = { BindTarget = backgroundSourceNote }, }, - new SettingsEnumDropdown + new SettingsItemV2(new FormEnumDropdown { - LabelText = UserInterfaceStrings.SeasonalBackgrounds, + Caption = UserInterfaceStrings.SeasonalBackgrounds, Current = config.GetBindable(OsuSetting.SeasonalBackgroundMode), - } + }) }; } @@ -71,9 +77,9 @@ protected override void LoadComplete() user.BindValueChanged(u => { if (u.NewValue?.IsSupporter != true) - backgroundSourceDropdown.SetNoticeText(UserInterfaceStrings.NotSupporterNote, true); + backgroundSourceNote.Value = new SettingsNote.Data(UserInterfaceStrings.NotSupporterNote, SettingsNote.Type.Warning); else - backgroundSourceDropdown.ClearNoticeText(); + backgroundSourceNote.Value = null; }, true); } } diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index d15008f858d1..72ebe33491e5 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Overlays.Mods.Input; @@ -12,6 +13,9 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface { public partial class SongSelectSettings : SettingsSubsection { + private FormEnumDropdown modSelectHotkeyStyle = null!; + private FormCheckBox modSelectTextSearchStartsActive = null!; + protected override LocalisableString Header => UserInterfaceStrings.SongSelectHeader; [BackgroundDependencyLoader] @@ -19,35 +23,43 @@ private void load(OsuConfigManager config) { Children = new Drawable[] { - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = UserInterfaceStrings.ShowConvertedBeatmaps, + Caption = UserInterfaceStrings.ShowConvertedBeatmaps, Current = config.GetBindable(OsuSetting.ShowConvertedBeatmaps), + }) + { Keywords = new[] { "converts", "converted" } }, - new SettingsEnumDropdown + new SettingsItemV2(new FormEnumDropdown { - LabelText = UserInterfaceStrings.RandomSelectionAlgorithm, + Caption = UserInterfaceStrings.RandomSelectionAlgorithm, Current = config.GetBindable(OsuSetting.RandomSelectAlgorithm), - }, - new SettingsEnumDropdown + }), + new SettingsItemV2(modSelectHotkeyStyle = new FormEnumDropdown { - LabelText = UserInterfaceStrings.ModSelectHotkeyStyle, + Caption = UserInterfaceStrings.ModSelectHotkeyStyle, Current = config.GetBindable(OsuSetting.ModSelectHotkeyStyle), - ClassicDefault = ModSelectHotkeyStyle.Classic + }) + { + ApplyClassicDefault = () => modSelectHotkeyStyle.Current.Value = ModSelectHotkeyStyle.Classic, }, - new SettingsCheckbox + new SettingsItemV2(modSelectTextSearchStartsActive = new FormCheckBox { - LabelText = UserInterfaceStrings.ModSelectTextSearchStartsActive, + Caption = UserInterfaceStrings.ModSelectTextSearchStartsActive, Current = config.GetBindable(OsuSetting.ModSelectTextSearchStartsActive), - ClassicDefault = false + }) + { + ApplyClassicDefault = () => modSelectTextSearchStartsActive.Current.Value = false, }, - new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = GameplaySettingsStrings.BackgroundBlur, + Caption = GameplaySettingsStrings.BackgroundBlur, Current = config.GetBindable(OsuSetting.SongSelectBackgroundBlur), - ClassicDefault = false, - } + }) + { + ApplyClassicDefault = () => backgroundBlurCheckbox.Current.Value = false, + }, }; } } From 874e3adcb74bffb77d7b7a23aec829f6fda34dfa Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 31 Dec 2025 14:36:35 -0500 Subject: [PATCH 466/836] Update layout settings section to use new controls --- .../Sections/Graphics/LayoutSettings.cs | 209 ++++++++++-------- osu.Game/Overlays/Settings/SettingsItemV2.cs | 23 +- 2 files changed, 127 insertions(+), 105 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index cdc4f328c376..81a3029c2dfe 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -18,7 +18,7 @@ using osu.Framework.Platform.Windows; using osu.Game.Configuration; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osuTK; using osuTK.Graphics; @@ -29,8 +29,7 @@ public partial class LayoutSettings : SettingsSubsection { protected override LocalisableString Header => GraphicsSettingsStrings.LayoutHeader; - private FillFlowContainer> scalingSettings = null!; - private SettingsSlider dimSlider = null!; + private FillFlowContainer scalingSettings = null!; private readonly Bindable currentDisplay = new Bindable(); @@ -51,12 +50,19 @@ public partial class LayoutSettings : SettingsSubsection private IWindow? window; - private SettingsDropdown resolutionFullscreenDropdown = null!; - private SettingsDropdown resolutionWindowedDropdown = null!; - private SettingsDropdown displayDropdown = null!; - private SettingsDropdown windowModeDropdown = null!; - private SettingsCheckbox minimiseOnFocusLossCheckbox = null!; - private SettingsCheckbox safeAreaConsiderationsCheckbox = null!; + private readonly BindableBool resolutionFullscreenCanBeShown = new BindableBool(true); + private readonly BindableBool resolutionWindowedCanBeShown = new BindableBool(true); + private readonly BindableBool displayDropdownCanBeShown = new BindableBool(true); + private readonly BindableBool minimiseOnFocusLossCanBeShown = new BindableBool(true); + private readonly BindableBool safeAreaConsiderationsCanBeShown = new BindableBool(true); + + private FormDropdown resolutionWindowedDropdown = null!; + private FormDropdown displayDropdown = null!; + private FormDropdown windowModeDropdown = null!; + + private FormSliderBar dimSlider = null!; + + private readonly Bindable windowModeDropdownNote = new Bindable(); private Bindable windowedPositionX = null!; private Bindable windowedPositionY = null!; @@ -98,105 +104,137 @@ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, Gam Children = new Drawable[] { - windowModeDropdown = new SettingsDropdown + new SettingsItemV2(windowModeDropdown = new FormDropdown { - LabelText = GraphicsSettingsStrings.ScreenMode, + Caption = GraphicsSettingsStrings.ScreenMode, Items = window?.SupportedWindowModes, - CanBeShown = { Value = window?.SupportedWindowModes.Count() > 1 }, Current = config.GetBindable(FrameworkSetting.WindowMode), + }) + { + CanBeShown = { Value = window?.SupportedWindowModes.Count() > 1 }, + Note = { BindTarget = windowModeDropdownNote }, }, - displayDropdown = new DisplaySettingsDropdown + new SettingsItemV2(displayDropdown = new DisplayDropdown { - LabelText = GraphicsSettingsStrings.Display, + Caption = GraphicsSettingsStrings.Display, Items = window?.Displays, Current = currentDisplay, + }) + { + CanBeShown = { BindTarget = displayDropdownCanBeShown } }, - resolutionFullscreenDropdown = new ResolutionSettingsDropdown + new SettingsItemV2(new ResolutionDropdown { - LabelText = GraphicsSettingsStrings.Resolution, - ShowsDefaultIndicator = false, + Caption = GraphicsSettingsStrings.Resolution, ItemSource = resolutionsFullscreen, Current = sizeFullscreen + }) + { + CanBeShown = { BindTarget = resolutionFullscreenCanBeShown }, + ShowRevertToDefaultButton = false, }, - resolutionWindowedDropdown = new ResolutionSettingsDropdown + new SettingsItemV2(resolutionWindowedDropdown = new ResolutionDropdown { - LabelText = GraphicsSettingsStrings.Resolution, - ShowsDefaultIndicator = false, + Caption = GraphicsSettingsStrings.Resolution, ItemSource = resolutionsWindowed, Current = windowedResolution + }) + { + CanBeShown = { BindTarget = resolutionWindowedCanBeShown }, + ShowRevertToDefaultButton = false, }, - minimiseOnFocusLossCheckbox = new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = GraphicsSettingsStrings.MinimiseOnFocusLoss, + Caption = GraphicsSettingsStrings.MinimiseOnFocusLoss, Current = config.GetBindable(FrameworkSetting.MinimiseOnFocusLossInFullscreen), + }) + { + CanBeShown = { BindTarget = minimiseOnFocusLossCanBeShown }, Keywords = new[] { "alt-tab", "minimize", "focus", "hide" }, }, - safeAreaConsiderationsCheckbox = new SettingsCheckbox + new SettingsItemV2(new FormCheckBox { - LabelText = GraphicsSettingsStrings.ShrinkGameToSafeArea, + Caption = GraphicsSettingsStrings.ShrinkGameToSafeArea, Current = osuConfig.GetBindable(OsuSetting.SafeAreaConsiderations), + }) + { + CanBeShown = { BindTarget = safeAreaConsiderationsCanBeShown }, }, - new SettingsSlider + new SettingsItemV2(new FormSliderBar { - LabelText = GraphicsSettingsStrings.UIScaling, + Caption = GraphicsSettingsStrings.UIScaling, TransferValueOnCommit = true, Current = osuConfig.GetBindable(OsuSetting.UIScale), KeyboardStep = 0.01f, + LabelFormat = v => $@"{v:0.##}x", + }) + { Keywords = new[] { "scale", "letterbox" }, }, - new SettingsEnumDropdown + new SettingsItemV2(new FormEnumDropdown { - LabelText = GraphicsSettingsStrings.ScreenScaling, + Caption = GraphicsSettingsStrings.ScreenScaling, Current = osuConfig.GetBindable(OsuSetting.Scaling), + }) + { Keywords = new[] { "scale", "letterbox" }, }, - scalingSettings = new FillFlowContainer> + scalingSettings = new FillFlowContainer { Direction = FillDirection.Vertical, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Masking = true, + Spacing = new Vector2(0, SettingsSection.ITEM_SPACING_V2), Children = new[] { - new SettingsSlider + new SettingsItemV2(new FormSliderBar { - LabelText = GraphicsSettingsStrings.HorizontalPosition, - Keywords = new[] { "screen", "scaling" }, + Caption = GraphicsSettingsStrings.HorizontalPosition, Current = scalingPositionX, KeyboardStep = 0.01f, - DisplayAsPercentage = true - }, - new SettingsSlider + DisplayAsPercentage = true, + }.With(bindPreviewEvent)) { - LabelText = GraphicsSettingsStrings.VerticalPosition, Keywords = new[] { "screen", "scaling" }, + }, + new SettingsItemV2(new FormSliderBar + { + Caption = GraphicsSettingsStrings.VerticalPosition, Current = scalingPositionY, KeyboardStep = 0.01f, - DisplayAsPercentage = true - }, - new SettingsSlider + DisplayAsPercentage = true, + }.With(bindPreviewEvent)) { - LabelText = GraphicsSettingsStrings.HorizontalScale, Keywords = new[] { "screen", "scaling" }, + }, + new SettingsItemV2(new FormSliderBar + { + Caption = GraphicsSettingsStrings.HorizontalScale, Current = scalingSizeX, KeyboardStep = 0.01f, - DisplayAsPercentage = true - }, - new SettingsSlider + DisplayAsPercentage = true, + }.With(bindPreviewEvent)) { - LabelText = GraphicsSettingsStrings.VerticalScale, Keywords = new[] { "screen", "scaling" }, + }, + new SettingsItemV2(new FormSliderBar + { + Caption = GraphicsSettingsStrings.VerticalScale, Current = scalingSizeY, KeyboardStep = 0.01f, - DisplayAsPercentage = true + DisplayAsPercentage = true, + }.With(bindPreviewEvent)) + { + Keywords = new[] { "screen", "scaling" }, }, - dimSlider = new SettingsSlider + new SettingsItemV2(dimSlider = new FormSliderBar { - LabelText = GameplaySettingsStrings.BackgroundDim, + Caption = GameplaySettingsStrings.BackgroundDim, Current = scalingBackgroundDim, KeyboardStep = 0.01f, DisplayAsPercentage = true, - }, + }.With(bindPreviewEvent)), } }, }; @@ -208,8 +246,6 @@ protected override void LoadComplete() { base.LoadComplete(); - scalingSettings.ForEach(s => bindPreviewEvent(s.Current)); - windowModeDropdown.Current.BindValueChanged(_ => { updateDisplaySettingsVisibility(); @@ -298,16 +334,16 @@ void updateScalingModeVisibility() scalingSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint); scalingSettings.AutoSizeAxes = scalingMode.Value != ScalingMode.Off ? Axes.Y : Axes.None; - scalingSettings.ForEach(s => + scalingSettings.ForEach(item => { - if (s == dimSlider) - { - s.CanBeShown.Value = scalingMode.Value == ScalingMode.Everything || scalingMode.Value == ScalingMode.ExcludeOverlays; - } + FormSliderBar slider = (FormSliderBar)item.Control; + + if (slider == dimSlider) + item.CanBeShown.Value = scalingMode.Value == ScalingMode.Everything || scalingMode.Value == ScalingMode.ExcludeOverlays; else { - s.TransferValueOnCommit = scalingMode.Value == ScalingMode.Everything; - s.CanBeShown.Value = scalingMode.Value != ScalingMode.Off; + slider.TransferValueOnCommit = scalingMode.Value == ScalingMode.Everything; + item.CanBeShown.Value = scalingMode.Value != ScalingMode.Off; } }); } @@ -325,12 +361,12 @@ private void onDisplaysChanged(IEnumerable displays) private void updateDisplaySettingsVisibility() { - resolutionFullscreenDropdown.CanBeShown.Value = windowModeDropdown.Current.Value == WindowMode.Fullscreen && resolutionsFullscreen.Count > 1; - resolutionWindowedDropdown.CanBeShown.Value = windowModeDropdown.Current.Value == WindowMode.Windowed && resolutionsWindowed.Count > 1; + resolutionFullscreenCanBeShown.Value = windowModeDropdown.Current.Value == WindowMode.Fullscreen && resolutionsFullscreen.Count > 1; + resolutionWindowedCanBeShown.Value = windowModeDropdown.Current.Value == WindowMode.Windowed && resolutionsWindowed.Count > 1; - displayDropdown.CanBeShown.Value = displayDropdown.Items.Count() > 1; - minimiseOnFocusLossCheckbox.CanBeShown.Value = RuntimeInfo.IsDesktop && windowModeDropdown.Current.Value == WindowMode.Fullscreen; - safeAreaConsiderationsCheckbox.CanBeShown.Value = host.Window?.SafeAreaPadding.Value.Total != Vector2.Zero; + displayDropdownCanBeShown.Value = displayDropdown.Items.Count() > 1; + minimiseOnFocusLossCanBeShown.Value = RuntimeInfo.IsDesktop && windowModeDropdown.Current.Value == WindowMode.Fullscreen; + safeAreaConsiderationsCanBeShown.Value = host.Window?.SafeAreaPadding.Value.Total != Vector2.Zero; } private void updateScreenModeWarning() @@ -339,16 +375,16 @@ private void updateScreenModeWarning() if (RuntimeInfo.OS == RuntimeInfo.Platform.macOS && !FrameworkEnvironment.UseSDL3) { if (windowModeDropdown.Current.Value == WindowMode.Fullscreen) - windowModeDropdown.SetNoticeText(LayoutSettingsStrings.FullscreenMacOSNote, true); + windowModeDropdownNote.Value = new SettingsNote.Data(LayoutSettingsStrings.FullscreenMacOSNote, SettingsNote.Type.Critical); else - windowModeDropdown.ClearNoticeText(); + windowModeDropdownNote.Value = null; return; } if (windowModeDropdown.Current.Value != WindowMode.Fullscreen) { - windowModeDropdown.SetNoticeText(GraphicsSettingsStrings.NotFullscreenNote, true); + windowModeDropdownNote.Value = new SettingsNote.Data(GraphicsSettingsStrings.NotFullscreenNote, SettingsNote.Type.Warning); return; } @@ -357,28 +393,28 @@ private void updateScreenModeWarning() switch (fullscreenCapability.Value) { case FullscreenCapability.Unknown: - windowModeDropdown.SetNoticeText(LayoutSettingsStrings.CheckingForFullscreenCapabilities, true); + windowModeDropdownNote.Value = new SettingsNote.Data(LayoutSettingsStrings.CheckingForFullscreenCapabilities, SettingsNote.Type.Informational); break; case FullscreenCapability.Capable: - windowModeDropdown.SetNoticeText(LayoutSettingsStrings.OsuIsRunningExclusiveFullscreen); + windowModeDropdownNote.Value = new SettingsNote.Data(LayoutSettingsStrings.OsuIsRunningExclusiveFullscreen, SettingsNote.Type.Informational); break; case FullscreenCapability.Incapable: - windowModeDropdown.SetNoticeText(LayoutSettingsStrings.UnableToRunExclusiveFullscreen, true); + windowModeDropdownNote.Value = new SettingsNote.Data(LayoutSettingsStrings.UnableToRunExclusiveFullscreen, SettingsNote.Type.Warning); break; } } else { // We can only detect exclusive fullscreen status on windows currently. - windowModeDropdown.ClearNoticeText(); + windowModeDropdownNote.Value = null; } } - private void bindPreviewEvent(Bindable bindable) + private void bindPreviewEvent(FormSliderBar slider) { - bindable.ValueChanged += _ => + slider.Current.ValueChanged += _ => { switch (scalingMode.Value) { @@ -421,37 +457,22 @@ public ScalingPreview() } } - private partial class UIScaleSlider : RoundedSliderBar + private partial class DisplayDropdown : FormDropdown { - public override LocalisableString TooltipText => base.TooltipText + "x"; - } - - private partial class DisplaySettingsDropdown : SettingsDropdown - { - protected override OsuDropdown CreateDropdown() => new DisplaySettingsDropdownControl(); - - private partial class DisplaySettingsDropdownControl : DropdownControl + protected override LocalisableString GenerateItemText(Display item) { - protected override LocalisableString GenerateItemText(Display item) - { - return $"{item.Index}: {item.Name} ({item.Bounds.Width}x{item.Bounds.Height})"; - } + return $"{item.Index}: {item.Name} ({item.Bounds.Width}x{item.Bounds.Height})"; } } - private partial class ResolutionSettingsDropdown : SettingsDropdown + private partial class ResolutionDropdown : FormDropdown { - protected override OsuDropdown CreateDropdown() => new ResolutionDropdownControl(); - - private partial class ResolutionDropdownControl : DropdownControl + protected override LocalisableString GenerateItemText(Size item) { - protected override LocalisableString GenerateItemText(Size item) - { - if (item == new Size(9999, 9999)) - return CommonStrings.Default; + if (item == new Size(9999, 9999)) + return CommonStrings.Default; - return $"{item.Width}x{item.Height}"; - } + return $"{item.Width}x{item.Height}"; } } diff --git a/osu.Game/Overlays/Settings/SettingsItemV2.cs b/osu.Game/Overlays/Settings/SettingsItemV2.cs index ad4e922ac243..48de6723ea0b 100644 --- a/osu.Game/Overlays/Settings/SettingsItemV2.cs +++ b/osu.Game/Overlays/Settings/SettingsItemV2.cs @@ -14,7 +14,8 @@ namespace osu.Game.Overlays.Settings { public sealed partial class SettingsItemV2 : CompositeDrawable, ISettingsItem, IConditionalFilterable { - private readonly IFormControl control; + public readonly IFormControl Control; + private readonly SettingsRevertToDefaultButton revertButton; private readonly BindableBool controlDefault = new BindableBool(true); @@ -32,7 +33,7 @@ public sealed partial class SettingsItemV2 : CompositeDrawable, ISettingsItem, I public SettingsItemV2(IFormControl control) { - this.control = control; + Control = control; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -78,8 +79,8 @@ protected override void LoadComplete() { base.LoadComplete(); - controlDefault.Value = control.IsDefault; - controlEnabled.Value = !control.IsDisabled; + controlDefault.Value = Control.IsDefault; + controlEnabled.Value = !Control.IsDisabled; controlDefault.BindValueChanged(_ => updateDefaultState()); controlEnabled.BindValueChanged(_ => updateDefaultState(), true); @@ -99,8 +100,8 @@ private void updateDefaultState() protected override void Update() { base.Update(); - controlDefault.Value = control.IsDefault; - controlEnabled.Value = !control.IsDisabled; + controlDefault.Value = Control.IsDefault; + controlEnabled.Value = !Control.IsDisabled; } #region ISettingsItem @@ -117,14 +118,14 @@ protected override void Update() public void ApplyDefault() { - if (!control.IsDisabled) - control.SetDefault(); + if (!Control.IsDisabled) + Control.SetDefault(); } public event Action SettingChanged { - add => control.ValueChanged += value; - remove => control.ValueChanged -= value; + add => Control.ValueChanged += value; + remove => Control.ValueChanged -= value; } #endregion @@ -140,7 +141,7 @@ public IEnumerable FilterTerms get { var filterTerms = new List(Keywords.Select(k => (LocalisableString)k)); - filterTerms.AddRange(control.FilterTerms); + filterTerms.AddRange(Control.FilterTerms); if (HasClassicDefault) filterTerms.Add(CLASSIC_DEFAULT_SEARCH_TERM); From 5d9ea9d6995034f086abfaa85d2fed4a2be900f1 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 31 Dec 2025 10:45:11 -0500 Subject: [PATCH 467/836] Rewrite input settings and use new form controls --- .../Settings/TestSceneTabletSettings.cs | 7 +- .../Graphics/UserInterfaceV2/SwitchButton.cs | 4 + osu.Game/OsuGameBase.cs | 2 +- .../Sections/Input/JoystickSettings.cs | 26 +-- .../Settings/Sections/Input/MouseSettings.cs | 90 +++++---- .../Sections/Input/TabletAreaSelection.cs | 2 +- .../Settings/Sections/Input/TabletSettings.cs | 171 +++++++++-------- .../Settings/Sections/Input/TouchSettings.cs | 24 +-- .../Settings/Sections/InputSection.cs | 26 --- .../Settings/Sections/InputSubsection.cs | 179 ++++++++++++++++++ .../Overlays/Settings/SettingsSubsection.cs | 19 +- 11 files changed, 355 insertions(+), 195 deletions(-) create mode 100644 osu.Game/Overlays/Settings/Sections/InputSubsection.cs diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index e9f70180e1a2..194e4301c232 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Input.Handlers; using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Testing; using osu.Framework.Utils; @@ -69,7 +70,7 @@ public void TestWideAspectRatioValidity() { AddStep("Test with wide tablet", () => tabletHandler.SetTabletSize(new Vector2(160, 100))); - AddStep("Reset to full area", () => settings.ChildrenOfType().First().TriggerClick()); + AddStep("Reset to full area", () => settings.ChildrenOfType().First().TriggerClick()); ensureValid(); AddStep("rotate 10", () => tabletHandler.Rotation.Value = 10); @@ -129,7 +130,7 @@ public void TestOffsetValidity() private void ensureInvalid() => AddAssert("area invalid", () => !settings.AreaSelection.IsWithinBounds); - public class TestTabletHandler : ITabletHandler + public class TestTabletHandler : InputHandler, ITabletHandler { public Bindable AreaOffset { get; } = new Bindable(); public Bindable AreaSize { get; } = new Bindable(); @@ -149,7 +150,7 @@ public class TestTabletHandler : ITabletHandler private readonly Bindable tablet = new Bindable(); - public BindableBool Enabled { get; } = new BindableBool(true); + public override bool IsActive => true; public void SetTabletSize(Vector2 size) { diff --git a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs index 5bb6aca7f4bf..f2d2f9c618c0 100644 --- a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs @@ -112,7 +112,11 @@ protected override void OnHoverLost(HoverLostEvent e) protected override void OnUserChange(bool value) { base.OnUserChange(value); + PlaySample(value); + } + public void PlaySample(bool value) + { if (value) sampleChecked?.Play(); else diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 222427cb60da..a2f3871cf37e 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -625,7 +625,7 @@ public virtual SettingsSubsection CreateSettingsSubsectionFor(InputHandler handl return new TouchSettings(th); case MidiHandler: - return new InputSection.HandlerSection(handler); + return new InputSubsection(handler); // return null for handlers that shouldn't have settings. default: diff --git a/osu.Game/Overlays/Settings/Sections/Input/JoystickSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/JoystickSettings.cs index 8455c096336a..d5d7540f791e 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/JoystickSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/JoystickSettings.cs @@ -8,25 +8,23 @@ using osu.Framework.Graphics; using osu.Framework.Input.Handlers.Joystick; using osu.Framework.Localisation; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Input { - public partial class JoystickSettings : SettingsSubsection + public partial class JoystickSettings : InputSubsection { protected override LocalisableString Header => JoystickSettingsStrings.JoystickGamepad; private readonly JoystickHandler joystickHandler; - private readonly Bindable enabled = new BindableBool(true); - - private SettingsSlider deadzoneSlider; - private Bindable handlerDeadzone; private Bindable localDeadzone; public JoystickSettings(JoystickHandler joystickHandler) + : base(joystickHandler) { this.joystickHandler = joystickHandler; } @@ -38,30 +36,22 @@ private void load() handlerDeadzone = joystickHandler.DeadzoneThreshold.GetBoundCopy(); localDeadzone = handlerDeadzone.GetUnboundCopy(); - Children = new Drawable[] + AddRange(new Drawable[] { - new SettingsCheckbox + new SettingsItemV2(new FormSliderBar { - LabelText = CommonStrings.Enabled, - Current = enabled - }, - deadzoneSlider = new SettingsSlider - { - LabelText = JoystickSettingsStrings.DeadzoneThreshold, + Caption = JoystickSettingsStrings.DeadzoneThreshold, KeyboardStep = 0.01f, DisplayAsPercentage = true, Current = localDeadzone, - }, - }; + }) + }); } protected override void LoadComplete() { base.LoadComplete(); - enabled.BindTo(joystickHandler.Enabled); - enabled.BindValueChanged(e => deadzoneSlider.Current.Disabled = !e.NewValue, true); - handlerDeadzone.BindValueChanged(val => { bool disabled = localDeadzone.Disabled; diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs index 3fb4016498f0..1d4538baef52 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -11,30 +9,33 @@ using osu.Framework.Input.Handlers.Mouse; using osu.Framework.Localisation; using osu.Game.Configuration; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Input; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Input { - public partial class MouseSettings : SettingsSubsection + public partial class MouseSettings : InputSubsection { private readonly MouseHandler mouseHandler; protected override LocalisableString Header => MouseSettingsStrings.Mouse; - private Bindable handlerSensitivity; + private Bindable handlerSensitivity = null!; + private Bindable localSensitivity = null!; + private Bindable windowMode = null!; + private Bindable minimiseOnFocusLoss = null!; + private FormEnumDropdown confineMouseModeSetting = null!; + private Bindable relativeMode = null!; - private Bindable localSensitivity; + private FormCheckBox highPrecisionMouse = null!; - private Bindable windowMode; - private Bindable minimiseOnFocusLoss; - private SettingsEnumDropdown confineMouseModeSetting; - private Bindable relativeMode; + private readonly Bindable highPrecisionMouseNote = new Bindable(); - private SettingsCheckbox highPrecisionMouse; + protected override bool IsToggleable => false; public MouseSettings(MouseHandler mouseHandler) + : base(mouseHandler) { this.mouseHandler = mouseHandler; } @@ -50,38 +51,47 @@ private void load(OsuConfigManager osuConfig, FrameworkConfigManager config) windowMode = config.GetBindable(FrameworkSetting.WindowMode); minimiseOnFocusLoss = config.GetBindable(FrameworkSetting.MinimiseOnFocusLossInFullscreen); - Children = new Drawable[] + AddRange(new Drawable[] { - highPrecisionMouse = new SettingsCheckbox + new SettingsItemV2(highPrecisionMouse = new FormCheckBox { - LabelText = MouseSettingsStrings.HighPrecisionMouse, - TooltipText = MouseSettingsStrings.HighPrecisionMouseTooltip, + Caption = MouseSettingsStrings.HighPrecisionMouse, + HintText = MouseSettingsStrings.HighPrecisionMouseTooltip, Current = relativeMode, + }) + { Keywords = new[] { @"raw", @"input", @"relative", @"cursor", "sensitivity", "speed", "velocity" }, + Note = { BindTarget = highPrecisionMouseNote }, }, - new SensitivitySetting + new SettingsItemV2(new FormSliderBar + { + Caption = MouseSettingsStrings.CursorSensitivity, + Current = localSensitivity, + KeyboardStep = 0.01f, + TransferValueOnCommit = true, + LabelFormat = v => $@"{v:0.##}x", + TooltipFormat = v => localSensitivity.Disabled ? MouseSettingsStrings.EnableHighPrecisionForSensitivityAdjust : $@"{v:0.##}x", + }) { Keywords = new[] { "speed", "velocity" }, - LabelText = MouseSettingsStrings.CursorSensitivity, - Current = localSensitivity }, - confineMouseModeSetting = new SettingsEnumDropdown + new SettingsItemV2(confineMouseModeSetting = new FormEnumDropdown { - LabelText = MouseSettingsStrings.ConfineMouseMode, + Caption = MouseSettingsStrings.ConfineMouseMode, Current = osuConfig.GetBindable(OsuSetting.ConfineMouseMode) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = MouseSettingsStrings.DisableMouseWheelVolumeAdjust, - TooltipText = MouseSettingsStrings.DisableMouseWheelVolumeAdjustTooltip, + Caption = MouseSettingsStrings.DisableMouseWheelVolumeAdjust, + HintText = MouseSettingsStrings.DisableMouseWheelVolumeAdjustTooltip, Current = osuConfig.GetBindable(OsuSetting.MouseDisableWheel) - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = MouseSettingsStrings.DisableClicksDuringGameplay, + Caption = MouseSettingsStrings.DisableClicksDuringGameplay, Current = osuConfig.GetBindable(OsuSetting.MouseDisableButtons) - }, - }; + }), + }); } protected override void LoadComplete() @@ -112,9 +122,9 @@ protected override void LoadComplete() case RuntimeInfo.Platform.macOS: case RuntimeInfo.Platform.iOS: if (highPrecision.NewValue) - highPrecisionMouse.SetNoticeText(MouseSettingsStrings.HighPrecisionPlatformWarning, true); + highPrecisionMouseNote.Value = new SettingsNote.Data(MouseSettingsStrings.HighPrecisionPlatformWarning, SettingsNote.Type.Warning); else - highPrecisionMouse.ClearNoticeText(); + highPrecisionMouseNote.Value = null; break; } @@ -131,27 +141,13 @@ private void updateConfineMouseModeSettingVisibility() if (confineModeOverriden) { confineMouseModeSetting.Current.Disabled = true; - confineMouseModeSetting.TooltipText = MouseSettingsStrings.NotApplicableFullscreen; + confineMouseModeSetting.HintText = MouseSettingsStrings.NotApplicableFullscreen; } else { confineMouseModeSetting.Current.Disabled = false; - confineMouseModeSetting.TooltipText = string.Empty; - } - } - - public partial class SensitivitySetting : SettingsSlider - { - public SensitivitySetting() - { - KeyboardStep = 0.01f; - TransferValueOnCommit = true; + confineMouseModeSetting.HintText = default; } } - - public partial class SensitivitySlider : RoundedSliderBar - { - public override LocalisableString TooltipText => Current.Disabled ? MouseSettingsStrings.EnableHighPrecisionForSensitivityAdjust : $"{base.TooltipText}x"; - } } } diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs index b3fdd534666d..bdc7c9bb35eb 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs @@ -45,7 +45,7 @@ public TabletAreaSelection(ITabletHandler handler) { this.handler = handler; - Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS }; + Padding = SettingsPanel.ContentPaddingV2; } [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 2a3710c67be8..00ddbf17def2 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -9,6 +9,8 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Handlers; using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Localisation; using osu.Framework.Platform; @@ -17,13 +19,14 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterfaceV2; using osuTK; using osu.Game.Localisation; using osu.Game.Online.Chat; namespace osu.Game.Overlays.Settings.Sections.Input { - public partial class TabletSettings : SettingsSubsection + public partial class TabletSettings : InputSubsection { public override IEnumerable FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { "area" }); @@ -74,70 +77,92 @@ public partial class TabletSettings : SettingsSubsection private FillFlowContainer mainSettings; - private FillFlowContainer noTabletMessage; + private Container noTabletMessage; protected override LocalisableString Header => TabletSettingsStrings.Tablet; public TabletSettings(ITabletHandler tabletHandler) + : base((InputHandler)tabletHandler) { this.tabletHandler = tabletHandler; } [BackgroundDependencyLoader] - private void load(OsuColour colours, LocalisationManager localisation, OsuConfigManager osuConfig) + private void load(OsuColour colours, LocalisationManager localisation, OsuConfigManager osuConfig, OverlayColourProvider colourProvider) { scalingMode = osuConfig.GetBindable(OsuSetting.Scaling); scalingSizeX = osuConfig.GetBindable(OsuSetting.ScalingSizeX); scalingSizeY = osuConfig.GetBindable(OsuSetting.ScalingSizeY); - Children = new Drawable[] + AddRange(new Drawable[] { - new SettingsCheckbox - { - LabelText = CommonStrings.Enabled, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Current = enabled, - }, - noTabletMessage = new FillFlowContainer + noTabletMessage = new Container { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS }, - Spacing = new Vector2(5f), - Children = new Drawable[] + Padding = SettingsPanel.ContentPaddingV2, + Child = new Container { - new OsuSpriteText + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Masking = true, + CornerRadius = 5, + CornerExponent = 2.5f, + Children = new Drawable[] { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = TabletSettingsStrings.NoTabletDetected, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Dark2, + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5f), + Padding = new MarginPadding { Horizontal = 8, Vertical = 10 }, + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = TabletSettingsStrings.NoTabletDetected, + Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold), + Colour = colourProvider.Content2, + }, + new LinkFlowContainer(cp => + { + cp.Colour = colours.Orange1; + cp.Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold); + }) + { + TextAnchor = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }.With(t => + { + t.NewLine(); + + const string url = @"https://opentabletdriver.net/Wiki/FAQ/General"; + var formattedSource = MessageFormatter.FormatText(localisation.GetLocalisedString(TabletSettingsStrings.NoTabletDetectedDescription(url))); + + t.AddLinks(formattedSource.Text, formattedSource.Links); + }), + } + }, }, - new LinkFlowContainer(cp => cp.Colour = colours.Yellow) - { - TextAnchor = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }.With(t => - { - t.NewLine(); - - const string url = @"https://opentabletdriver.net/Wiki/FAQ/General"; - var formattedSource = MessageFormatter.FormatText(localisation.GetLocalisedString(TabletSettingsStrings.NoTabletDetectedDescription(url))); - - t.AddLinks(formattedSource.Text, formattedSource.Links); - }), - } + }, }, mainSettings = new FillFlowContainer { Alpha = 0, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Spacing = new Vector2(0, SettingsSection.ITEM_SPACING), + Spacing = new Vector2(0, SettingsSection.ITEM_SPACING_V2), Direction = FillDirection.Vertical, Children = new Drawable[] { @@ -146,7 +171,7 @@ private void load(OsuColour colours, LocalisationManager localisation, OsuConfig RelativeSizeAxes = Axes.X, Height = 300, }, - new DangerousSettingsButton + new DangerousSettingsButtonV2 { Text = TabletSettingsStrings.ResetToFullArea, Action = () => @@ -156,9 +181,8 @@ private void load(OsuColour colours, LocalisationManager localisation, OsuConfig areaOffset.SetDefault(); areaSize.SetDefault(); }, - CanBeShown = { BindTarget = enabled } }, - new SettingsButton + new SettingsButtonV2 { Text = TabletSettingsStrings.ConformToCurrentGameAspectRatio, Action = () => @@ -174,73 +198,62 @@ private void load(OsuColour colours, LocalisationManager localisation, OsuConfig forceAspectRatio(gameplayWidth / gameplayHeight); }, - CanBeShown = { BindTarget = enabled } }, - new SettingsSlider + new SettingsItemV2(new FormSliderBar { TransferValueOnCommit = true, - LabelText = TabletSettingsStrings.XOffset, + Caption = TabletSettingsStrings.XOffset, Current = offsetX, - CanBeShown = { BindTarget = enabled } - }, - new SettingsSlider + }), + new SettingsItemV2(new FormSliderBar { TransferValueOnCommit = true, - LabelText = TabletSettingsStrings.YOffset, + Caption = TabletSettingsStrings.YOffset, Current = offsetY, - CanBeShown = { BindTarget = enabled } - }, - new SettingsSlider + }), + new SettingsItemV2(new FormSliderBar { TransferValueOnCommit = true, - LabelText = TabletSettingsStrings.Rotation, + Caption = TabletSettingsStrings.Rotation, Current = rotation, - CanBeShown = { BindTarget = enabled } - }, + }), new RotationPresetButtons(tabletHandler) { - Padding = new MarginPadding - { - Horizontal = SettingsPanel.CONTENT_MARGINS - } + Padding = SettingsPanel.ContentPaddingV2, }, - new SettingsSlider + new SettingsItemV2(new FormSliderBar { TransferValueOnCommit = true, - LabelText = TabletSettingsStrings.AspectRatio, + Caption = TabletSettingsStrings.AspectRatio, Current = aspectRatio, - CanBeShown = { BindTarget = enabled } - }, - new SettingsCheckbox + }), + new SettingsItemV2(new FormCheckBox { - LabelText = TabletSettingsStrings.LockAspectRatio, + Caption = TabletSettingsStrings.LockAspectRatio, Current = aspectLock, - CanBeShown = { BindTarget = enabled } - }, - new SettingsSlider + }), + new SettingsItemV2(new FormSliderBar { TransferValueOnCommit = true, - LabelText = CommonStrings.Width, + Caption = CommonStrings.Width, Current = sizeX, - CanBeShown = { BindTarget = enabled } - }, - new SettingsSlider + }), + new SettingsItemV2(new FormSliderBar { TransferValueOnCommit = true, - LabelText = CommonStrings.Height, + Caption = CommonStrings.Height, Current = sizeY, - CanBeShown = { BindTarget = enabled } - }, - new SettingsPercentageSlider + }), + new SettingsItemV2(new FormSliderBar { TransferValueOnCommit = true, - LabelText = TabletSettingsStrings.TipPressureForClick, + Caption = TabletSettingsStrings.TipPressureForClick, Current = pressureThreshold, - CanBeShown = { BindTarget = enabled } - }, + DisplayAsPercentage = true, + }), } }, - }; + }); } protected override void LoadComplete() diff --git a/osu.Game/Overlays/Settings/Sections/Input/TouchSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TouchSettings.cs index 0056de667471..5499d4964845 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TouchSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TouchSettings.cs @@ -8,6 +8,7 @@ using osu.Framework.Input.Handlers; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Input @@ -15,34 +16,25 @@ namespace osu.Game.Overlays.Settings.Sections.Input /// /// Touch input settings subsection common to all touch handlers (even on different platforms). /// - public partial class TouchSettings : SettingsSubsection + public partial class TouchSettings : InputSubsection { - private readonly InputHandler handler; - protected override LocalisableString Header => TouchSettingsStrings.Touch; + protected override bool IsToggleable => !RuntimeInfo.IsMobile; + public TouchSettings(InputHandler handler) + : base(handler) { - this.handler = handler; } [BackgroundDependencyLoader] private void load(OsuConfigManager osuConfig) { - if (!RuntimeInfo.IsMobile) // don't allow disabling the only input method (touch) on mobile. - { - Add(new SettingsCheckbox - { - LabelText = CommonStrings.Enabled, - Current = handler.Enabled - }); - } - - Add(new SettingsCheckbox + Add(new SettingsItemV2(new FormCheckBox { - LabelText = TouchSettingsStrings.DisableTapsDuringGameplay, + Caption = TouchSettingsStrings.DisableTapsDuringGameplay, Current = osuConfig.GetBindable(OsuSetting.TouchDisableGameplayTaps) - }); + })); } public override IEnumerable FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { @"touchscreen" }); diff --git a/osu.Game/Overlays/Settings/Sections/InputSection.cs b/osu.Game/Overlays/Settings/Sections/InputSection.cs index 0204aa5e644e..0b22022362ea 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSection.cs @@ -4,7 +4,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; -using osu.Framework.Input.Handlers; using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Game.Graphics; @@ -45,30 +44,5 @@ private void load(GameHost host, OsuGameBase game) Add(handlerSection); } } - - public partial class HandlerSection : SettingsSubsection - { - private readonly InputHandler handler; - - public HandlerSection(InputHandler handler) - { - this.handler = handler; - } - - [BackgroundDependencyLoader] - private void load() - { - Children = new Drawable[] - { - new SettingsCheckbox - { - LabelText = CommonStrings.Enabled, - Current = handler.Enabled - }, - }; - } - - protected override LocalisableString Header => handler.Description; - } } } diff --git a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs new file mode 100644 index 000000000000..985c4fb4f097 --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs @@ -0,0 +1,179 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Events; +using osu.Framework.Input.Handlers; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; +using osuTK; + +namespace osu.Game.Overlays.Settings.Sections +{ + public partial class InputSubsection : SettingsSubsection + { + private readonly InputHandler handler; + + protected override LocalisableString Header => handler.Description; + + /// + /// Whether the input handler can be toggled on/off by the user. + /// + protected virtual bool IsToggleable => true; + + private readonly BindableBool handlerEnabled = new BindableBool(); + + public InputSubsection(InputHandler handler) + { + this.handler = handler; + + FlowContent.AlwaysPresent = true; + } + + [BackgroundDependencyLoader] + private void load() + { + HeaderContainer.Child = new ToggleableHeader(Header, IsToggleable) + { + Current = { BindTarget = handlerEnabled }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + handlerEnabled.BindTo(handler.Enabled); + handlerEnabled.BindValueChanged(v => updateEnabledState(), true); + } + + private void updateEnabledState() + { + // set negative bottom margin to not have too much vertical gap between disabled input subsections. + bool negativeBottomMargin = !handlerEnabled.Value || FlowContent.Count == 0; + HeaderContainer.TransformTo(nameof(Margin), new MarginPadding { Bottom = negativeBottomMargin ? -15 : 0 }, 300, Easing.OutQuint); + + FlowContent.ClearTransforms(); + + if (!handlerEnabled.Value) + { + FlowContent.AutoSizeAxes = Axes.None; + FlowContent.ResizeHeightTo(0, 300, Easing.OutQuint); + + FlowContent.FadeOut(200, Easing.OutQuint); + } + else + { + // enable auto size transform momentarily for smooth pop in animation, and disable it right after the transform is added. + // we don't want this specification to apply when a dropdown in the input settings is being open, it causes too slow animation. + // (try removing the schedule below then watch a settings dropdown menu opening animation). + FlowContent.AutoSizeDuration = 300; + FlowContent.AutoSizeEasing = Easing.OutQuint; + FlowContent.AutoSizeAxes = Axes.Y; + ScheduleAfterChildren(() => FlowContent.AutoSizeDuration = 0); + + FlowContent.FadeIn(300, Easing.OutQuint); + } + } + + private partial class ToggleableHeader : CompositeDrawable + { + private readonly LocalisableString header; + private readonly bool toggleable; + + public readonly BindableBool Current = new BindableBool(true); + + public ToggleableHeader(LocalisableString header, bool toggleable) + { + this.header = header; + this.toggleable = toggleable; + } + + private SwitchButton switchButton = null!; + private OsuSpriteText headerText = null!; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + switchButton = new SwitchButton + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + Scale = new Vector2(0.6f), + Position = new Vector2(12, 8), + Rotation = 90, + }, + headerText = new OsuSpriteText + { + Text = header, + Font = OsuFont.GetFont(size: 20), + Margin = new MarginPadding { Vertical = 12 }, + X = 20, + }, + new HoverSounds(), + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + switchButton.Current.ValueChanged += v => Current.Value = v.NewValue; + + Current.BindValueChanged(v => + { + switchButton.Current.Disabled = false; + switchButton.Current.Value = v.NewValue; + switchButton.Current.Disabled = !toggleable; + + updateDisplay(); + }, true); + } + + protected override bool OnHover(HoverEvent e) + { + updateDisplay(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateDisplay(); + base.OnHoverLost(e); + } + + protected override bool OnClick(ClickEvent e) + { + if (toggleable) + { + Current.Toggle(); + switchButton.PlaySample(Current.Value); + } + + updateDisplay(); + return true; + } + + private void updateDisplay() + { + if (toggleable && IsHovered) + headerText.FadeColour(colourProvider.Light1, 300, Easing.OutQuint); + else + headerText.FadeColour(Current.Value ? colourProvider.Content1 : colourProvider.Foreground1, 300, Easing.OutQuint); + } + } + } +} diff --git a/osu.Game/Overlays/Settings/SettingsSubsection.cs b/osu.Game/Overlays/Settings/SettingsSubsection.cs index 34809f3bbbff..d614311bab5a 100644 --- a/osu.Game/Overlays/Settings/SettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/SettingsSubsection.cs @@ -18,6 +18,8 @@ public abstract partial class SettingsSubsection : FillFlowContainer, IFilterabl protected readonly FillFlowContainer FlowContent; + protected Container HeaderContainer { get; private set; } = null!; + protected abstract LocalisableString Header { get; } public virtual IEnumerable FilterTerms => new[] { Header }; @@ -53,11 +55,20 @@ private void load() { AddRangeInternal(new Drawable[] { - new OsuSpriteText + HeaderContainer = new Container { - Text = Header, - Margin = new MarginPadding { Vertical = (header_height - header_font_size) * 0.5f, Horizontal = SettingsPanel.CONTENT_MARGINS }, - Font = OsuFont.GetFont(size: header_font_size), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = SettingsPanel.ContentPaddingV2, + Children = new[] + { + new OsuSpriteText + { + Text = Header, + Font = OsuFont.GetFont(size: header_font_size), + Margin = new MarginPadding { Vertical = (header_height - header_font_size) * 0.5f }, + }, + }, }, FlowContent }); From ed760e638985a286f6ed885ec121c2041482e10f Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 31 Dec 2025 10:56:38 -0500 Subject: [PATCH 468/836] Update keybind settings to use new revert button --- .../Settings/TestSceneKeyBindingPanel.cs | 15 ++++---- .../Visual/Settings/TestSceneKeyBindingRow.cs | 5 ++- .../Settings/Sections/Input/KeyBindingRow.cs | 38 ++++++++++++------- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 287b678b07de..ac413fe306c5 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -13,6 +13,7 @@ using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Overlays; +using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings.Sections.Input; using osu.Game.Rulesets.Taiko; using osuTK.Input; @@ -202,16 +203,16 @@ public void TestSingleBindingResetButton() InputManager.ReleaseKey(Key.P); }); - AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha > 0); + AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType().First().Alpha > 0); AddStep("click reset button for bindings", () => { - var resetButton = settingsKeyBindingRow.ChildrenOfType>().First(); + var resetButton = settingsKeyBindingRow.ChildrenOfType().First(); resetButton.TriggerClick(); }); - AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); + AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType().First().Alpha == 0); AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.Value.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0))); @@ -232,7 +233,7 @@ public void TestResetAllBindingsButton() InputManager.ReleaseKey(Key.P); }); - AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha > 0); + AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType().First().Alpha > 0); AddStep("click reset button for bindings", () => { @@ -241,7 +242,7 @@ public void TestResetAllBindingsButton() resetButton.TriggerClick(); }); - AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); + AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType().First().Alpha == 0); AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.Value.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0))); @@ -394,7 +395,7 @@ public void TestBindingConflictCausedByResetToDefaultOfSingleRow() AddStep("reset Left (centre) to default", () => { var row = panel.ChildrenOfType().First(r => r.ChildrenOfType().Any(s => s.Text.ToString() == "Left (centre)")); - row.ChildrenOfType>().Single().TriggerClick(); + row.ChildrenOfType().Single().TriggerClick(); }); KeyBindingConflictPopover popover = null; @@ -450,7 +451,7 @@ public void TestResettingRowCannotConflictWithItself() AddStep("revert row to default", () => { var row = panel.ChildrenOfType().First(r => r.ChildrenOfType().Any(s => s.Text.ToString() == "Left (centre)")); - InputManager.MoveMouseTo(row.ChildrenOfType>().Single()); + InputManager.MoveMouseTo(row.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); AddWaitStep("wait a bit", 3); diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingRow.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingRow.cs index ff996a9ca118..09a46ba88c51 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingRow.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingRow.cs @@ -10,6 +10,7 @@ using osu.Framework.Testing; using osu.Game.Input.Bindings; using osu.Game.Overlays; +using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings.Sections.Input; namespace osu.Game.Tests.Visual.Settings @@ -45,7 +46,7 @@ public void TestChangesAfterConstruction() row.KeyBindings.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.Escape))); row.KeyBindings.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.ExtraMouseButton1))); }); - AddUntilStep("revert to default button not shown", () => row.ChildrenOfType>().Single().Alpha, () => Is.Zero); + AddUntilStep("revert to default button not shown", () => row.ChildrenOfType().Single().Alpha, () => Is.Zero); AddStep("change key bindings", () => { @@ -54,7 +55,7 @@ public void TestChangesAfterConstruction() row.KeyBindings.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.Z))); row.KeyBindings.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.I))); }); - AddUntilStep("revert to default button not shown", () => row.ChildrenOfType>().Single().Alpha, () => Is.Not.Zero); + AddUntilStep("revert to default button not shown", () => row.ChildrenOfType().Single().Alpha, () => Is.Not.Zero); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index c9ef6ef891ca..54ab537d9c7d 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -94,6 +94,7 @@ public bool MatchingFilter private Container content = null!; private OsuSpriteText text = null!; + private SettingsRevertToDefaultButton revertButton = null!; private FillFlowContainer cancelAndClearButtons = null!; private FillFlowContainer buttons = null!; @@ -127,27 +128,24 @@ private void load(OverlayColourProvider colourProvider, AudioManager audioManage { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; + Padding = new MarginPadding { Right = SettingsPanel.ContentPaddingV2.Right }; InternalChildren = new Drawable[] { - new Container + revertButton = new SettingsRevertToDefaultButton { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Height = 1, RelativeSizeAxes = Axes.Y, - Width = SettingsPanel.CONTENT_MARGINS, - Child = new RevertToDefaultButton - { - Current = isDefault, - Action = RestoreDefaults, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } + IconSize = 12, + Action = RestoreDefaults, }, new Container { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, + Padding = new MarginPadding { Left = SettingsPanel.ContentPaddingV2.Left }, Children = new Drawable[] { content = new Container @@ -179,7 +177,8 @@ private void load(OverlayColourProvider colourProvider, AudioManager audioManage { AutoSizeAxes = Axes.Both, Anchor = Anchor.TopRight, - Origin = Anchor.TopRight + Origin = Anchor.TopRight, + Spacing = new Vector2(-6, 0), }, cancelAndClearButtons = new FillFlowContainer { @@ -223,6 +222,19 @@ private void load(OverlayColourProvider colourProvider, AudioManager audioManage keypressSamples[i] = audioManager.Samples.Get($@"Keyboard/key-press-{1 + i}"); } + protected override void LoadComplete() + { + base.LoadComplete(); + + isDefault.BindValueChanged(d => + { + if (d.NewValue) + revertButton.Hide(); + else + revertButton.Show(); + }, true); + } + public void RestoreDefaults() { int i = 0; @@ -483,7 +495,7 @@ private void finalise(bool advanceToNextBinding = true) protected override void OnFocus(FocusEvent e) { - content.AutoSizeDuration = 500; + content.AutoSizeDuration = 250; content.AutoSizeEasing = Easing.OutQuint; cancelAndClearButtons.FadeIn(300, Easing.OutQuint); From 30a60d83e2e0755a2f7028caf6f81e1f49475efa Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 31 Dec 2025 13:25:06 -0500 Subject: [PATCH 469/836] Allow configuring settings note text anchor --- osu.Game/Overlays/Settings/SettingsNote.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Overlays/Settings/SettingsNote.cs b/osu.Game/Overlays/Settings/SettingsNote.cs index 3552e32d4e18..dec2694b4ffa 100644 --- a/osu.Game/Overlays/Settings/SettingsNote.cs +++ b/osu.Game/Overlays/Settings/SettingsNote.cs @@ -26,6 +26,14 @@ public sealed partial class SettingsNote : CompositeDrawable [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; + public new MarginPadding Padding + { + get => base.Padding; + set => base.Padding = value; + } + + public Anchor TextAnchor { get; init; } = Anchor.TopLeft; + [BackgroundDependencyLoader] private void load() { @@ -53,6 +61,7 @@ private void load() }, text = new OsuTextFlowContainer(s => s.Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold)) { + TextAnchor = TextAnchor, Padding = new MarginPadding(8), RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, From 96c414be86082bf47061853bc07ff22abff9832e Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 31 Dec 2025 13:40:39 -0500 Subject: [PATCH 470/836] Adjust audio offset controls to match design language --- .../Audio/AudioOffsetAdjustControl.cs | 35 +++++++++++-------- .../Settings/Sections/Audio/OffsetSettings.cs | 1 + 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs index fca7aaffd983..7d3596c25945 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs @@ -13,12 +13,9 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Configuration; using osu.Game.Extensions; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Screens.Play.PlayerSettings; -using osuTK; namespace osu.Game.Overlays.Settings.Sections.Audio { @@ -36,10 +33,13 @@ public Bindable Current public readonly Bindable SuggestedOffset = new Bindable(); - private Container notchContainer = null!; - private TextFlowContainer hintText = null!; + private Container notchContainer = null!; + private SettingsNote hintNote = null!; private RoundedButton applySuggestion = null!; + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + [BackgroundDependencyLoader] private void load(SessionAverageHitErrorTracker hitErrorTracker) { @@ -51,7 +51,6 @@ private void load(SessionAverageHitErrorTracker hitErrorTracker) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Spacing = new Vector2(7), Direction = FillDirection.Vertical, Children = new Drawable[] { @@ -67,16 +66,18 @@ private void load(SessionAverageHitErrorTracker hitErrorTracker) new Container { RelativeSizeAxes = Axes.X, - Height = 10, + AutoSizeAxes = Axes.Y, Padding = new MarginPadding { Left = SettingsPanel.ContentPaddingV2.Left + 9, Right = SettingsPanel.ContentPaddingV2.Right + 5 }, - Child = notchContainer = new Container + Child = notchContainer = new Container { - RelativeSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.X, Width = 0.5f, + Height = 10, + Margin = new MarginPadding { Top = 2 }, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Padding = new MarginPadding @@ -85,11 +86,11 @@ private void load(SessionAverageHitErrorTracker hitErrorTracker) }, }, }, - hintText = new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(size: 16)) + hintNote = new SettingsNote { RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, Padding = SettingsPanel.ContentPaddingV2, + TextAnchor = Anchor.TopCentre, }, applySuggestion = new RoundedButton { @@ -124,13 +125,14 @@ private void updateDisplay(object? _, NotifyCollectionChangedEventArgs e) foreach (SessionAverageHitErrorTracker.DataPoint dataPoint in e.NewItems!) { notchContainer.ForEach(n => n.Alpha *= 0.95f); - notchContainer.Add(new Box + notchContainer.Add(new Circle { RelativeSizeAxes = Axes.Y, Width = 2, RelativePositionAxes = Axes.X, Anchor = Anchor.Centre, Origin = Anchor.Centre, + Colour = colourProvider.Light1, X = getXPositionForOffset(dataPoint.SuggestedGlobalAudioOffset) }); } @@ -162,17 +164,20 @@ private void updateHintText() if (SuggestedOffset.Value == null) { applySuggestion.Enabled.Value = false; - hintText.Text = AudioSettingsStrings.SuggestedOffsetNote; + notchContainer.Hide(); + hintNote.Current.Value = new SettingsNote.Data(AudioSettingsStrings.SuggestedOffsetNote, SettingsNote.Type.Informational); } else if (Math.Abs(SuggestedOffset.Value.Value - current.Value) < 1) { applySuggestion.Enabled.Value = false; - hintText.Text = AudioSettingsStrings.SuggestedOffsetCorrect(averageHitErrorHistory.Count); + notchContainer.Show(); + hintNote.Current.Value = new SettingsNote.Data(AudioSettingsStrings.SuggestedOffsetCorrect(averageHitErrorHistory.Count), SettingsNote.Type.Informational); } else { applySuggestion.Enabled.Value = true; - hintText.Text = AudioSettingsStrings.SuggestedOffsetValueReceived(averageHitErrorHistory.Count, SuggestedOffset.Value.Value.ToStandardFormattedString(0)); + notchContainer.Show(); + hintNote.Current.Value = new SettingsNote.Data(AudioSettingsStrings.SuggestedOffsetValueReceived(averageHitErrorHistory.Count, SuggestedOffset.Value.Value.ToStandardFormattedString(0)), SettingsNote.Type.Informational); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs index 498b04b7a837..1cfba9632f09 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs @@ -26,6 +26,7 @@ private void load(OsuConfigManager config) new AudioOffsetAdjustControl { Current = config.GetBindable(OsuSetting.AudioOffset), + Margin = new MarginPadding { Bottom = 5 }, }, new SettingsItemV2(new FormCheckBox { From c5a30d3244c22ff3a781fa69dcc5452e19450a3f Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 31 Dec 2025 14:45:51 -0500 Subject: [PATCH 471/836] Remove unnecessary classic default specification Background blur is disabled by default. --- .../Settings/Sections/UserInterface/SongSelectSettings.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index 72ebe33491e5..4052842de95e 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -56,10 +56,7 @@ private void load(OsuConfigManager config) { Caption = GameplaySettingsStrings.BackgroundBlur, Current = config.GetBindable(OsuSetting.SongSelectBackgroundBlur), - }) - { - ApplyClassicDefault = () => backgroundBlurCheckbox.Current.Value = false, - }, + }), }; } } From b9a37453f93a656bda9c1cb01cf99540acecaaa4 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Wed, 31 Dec 2025 15:47:39 -0500 Subject: [PATCH 472/836] Shorten "increase first object visibility" label text --- osu.Game/Localisation/GameplaySettingsStrings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/GameplaySettingsStrings.cs b/osu.Game/Localisation/GameplaySettingsStrings.cs index 2715f0b8cfdb..6c4ccfb5728b 100644 --- a/osu.Game/Localisation/GameplaySettingsStrings.cs +++ b/osu.Game/Localisation/GameplaySettingsStrings.cs @@ -120,9 +120,9 @@ public static class GameplaySettingsStrings public static LocalisableString ModsHeader => new TranslatableString(getKey(@"mods_header"), @"Mods"); /// - /// "Increase visibility of first object when visual impairment mods are enabled" + /// "Increase first object visibility on visual impairment mods" /// - public static LocalisableString IncreaseFirstObjectVisibility => new TranslatableString(getKey(@"increase_first_object_visibility"), @"Increase visibility of first object when visual impairment mods are enabled"); + public static LocalisableString IncreaseFirstObjectVisibility => new TranslatableString(getKey(@"increase_first_object_visibility"), @"Increase first object visibility on visual impairment mods"); /// /// "Hide during gameplay" From 876dcd060ce810b380395e4c019feda3e675f6be Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 1 Jan 2026 06:34:02 -0500 Subject: [PATCH 473/836] Reduce supporter note to informational --- .../Settings/Sections/UserInterface/MainMenuSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs index f9f57d07f8f9..e38dcbc0060e 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs @@ -77,7 +77,7 @@ protected override void LoadComplete() user.BindValueChanged(u => { if (u.NewValue?.IsSupporter != true) - backgroundSourceNote.Value = new SettingsNote.Data(UserInterfaceStrings.NotSupporterNote, SettingsNote.Type.Warning); + backgroundSourceNote.Value = new SettingsNote.Data(UserInterfaceStrings.NotSupporterNote, SettingsNote.Type.Informational); else backgroundSourceNote.Value = null; }, true); From 029d544720ef7cf02f4e37f5d938c8f129dac192 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Jan 2026 17:42:54 +0900 Subject: [PATCH 474/836] Adjust switch buttons to make the state more obvious --- osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs index f2d2f9c618c0..ce4b1e93c743 100644 --- a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs @@ -51,7 +51,6 @@ public SwitchButton() { RelativeSizeAxes = Axes.Both, AlwaysPresent = true, - Alpha = 0 }, new Container { @@ -92,7 +91,6 @@ protected override void LoadComplete() private void updateState() { nub.MoveToX(Current.Value ? nubContainer.DrawWidth - nub.DrawWidth : 0, 200, Easing.OutQuint); - fill.FadeTo(Current.Value ? 1 : 0, 250, Easing.OutQuint); updateColours(); } @@ -139,7 +137,7 @@ private void updateColours() bool hover = IsHovered && !Current.Disabled; borderColour = hover ? colourProvider.Highlight1.Opacity(0.5f) : colourProvider.Highlight1.Opacity(0.3f); - switchColour = hover ? colourProvider.Highlight1 : colourProvider.Light4; + switchColour = hover || Current.Value ? colourProvider.Highlight1 : colourProvider.Light4; if (!Current.Value) { @@ -147,7 +145,7 @@ private void updateColours() switchColour = switchColour.MultiplyAlpha(0.8f); } - fill.Colour = colourProvider.Background6; + fill.Colour = Current.Value ? colourProvider.Colour4.Darken(0.2f) : colourProvider.Background6; } nubContainer.FadeColour(switchColour, 250, Easing.OutQuint); From ed091dc9cd696f2f681d2fb9303595d9f63d1898 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Jan 2026 17:48:44 +0900 Subject: [PATCH 475/836] Adjust toggleable subsection colour to always be bright when enabled --- .../Overlays/Settings/Sections/InputSubsection.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs index 985c4fb4f097..50fb68870758 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs @@ -13,6 +13,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osuTK; +using osuTK.Graphics; namespace osu.Game.Overlays.Settings.Sections { @@ -169,10 +170,13 @@ protected override bool OnClick(ClickEvent e) private void updateDisplay() { - if (toggleable && IsHovered) - headerText.FadeColour(colourProvider.Light1, 300, Easing.OutQuint); - else - headerText.FadeColour(Current.Value ? colourProvider.Content1 : colourProvider.Foreground1, 300, Easing.OutQuint); + // default, toggled on (or not toggleable) + Color4 col = colourProvider.Content1; + + if (toggleable && !Current.Value) + col = IsHovered ? colourProvider.Light1 : colourProvider.Foreground1; + + headerText.FadeColour(col, 300, Easing.OutQuint); } } } From 3f92b451d945298e24bb024d16d9d5ed33a1757c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Jan 2026 19:37:51 +0900 Subject: [PATCH 476/836] Use `foreach` isntead of `ForEach` --- .../Overlays/Settings/Sections/Graphics/LayoutSettings.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 81a3029c2dfe..cc1105c57921 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -9,7 +9,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Configuration; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -334,7 +333,8 @@ void updateScalingModeVisibility() scalingSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint); scalingSettings.AutoSizeAxes = scalingMode.Value != ScalingMode.Off ? Axes.Y : Axes.None; - scalingSettings.ForEach(item => + + foreach (SettingsItemV2 item in scalingSettings) { FormSliderBar slider = (FormSliderBar)item.Control; @@ -345,7 +345,7 @@ void updateScalingModeVisibility() slider.TransferValueOnCommit = scalingMode.Value == ScalingMode.Everything; item.CanBeShown.Value = scalingMode.Value != ScalingMode.Off; } - }); + } } } From 79f1d77fedbd47f1ec8cd8ababff92088b95721e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Jan 2026 20:02:11 +0900 Subject: [PATCH 477/836] Fix copy paste failure in `MultiplayerMatchSettingsOverlay` --- .../Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 018d36069e0a..80179bd1dd29 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -370,7 +370,7 @@ private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e) break; case nameof(Room.Type): - updateRoomName(); + updateRoomType(); break; case nameof(Room.QueueMode): From 3302e2e180778bb52c51ef81d109f097d4845152 Mon Sep 17 00:00:00 2001 From: De4n <55669793+tadatomix@users.noreply.github.com> Date: Thu, 15 Jan 2026 10:00:27 +0300 Subject: [PATCH 478/836] Use new star rating text gradient for the difficulty name, "mapped by" text and difficulty bars (#36345) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: #36312 I think that's exactly what needed to be done to fix this issue. |master|this PR| |:---:|:---:| |изображение|изображение| |изображение|изображение| |изображение|изображение |изображение|изображение --------- Co-authored-by: Dean Herbert --- .../Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs index 55ed488d87e8..65e55ff27742 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs +++ b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs @@ -48,9 +48,6 @@ public partial class DifficultyDisplay : CompositeDrawable [Resolved] private BeatmapDifficultyCache difficultyCache { get; set; } = null!; - [Resolved] - private OsuColour colours { get; set; } = null!; - private StarRatingDisplay starRatingDisplay = null!; private FillFlowContainer nameLine = null!; private OsuSpriteText difficultyText = null!; @@ -304,7 +301,7 @@ protected override void Update() difficultyText.MaxWidth = Math.Max(nameLine.DrawWidth - mappedByText.DrawWidth - mapperText.DrawWidth - 20, 0); // Use difficulty colour until it gets too dark to be visible against dark backgrounds. - Color4 col = starRatingDisplay.DisplayedStars.Value >= OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF ? colours.Orange1 : starRatingDisplay.DisplayedDifficultyColour; + Color4 col = starRatingDisplay.DisplayedStars.Value >= OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF ? starRatingDisplay.DisplayedDifficultyTextColour : starRatingDisplay.DisplayedDifficultyColour; difficultyText.Colour = col; mappedByText.Colour = col; From 2bf0dcf398f2f62a00158a37801ca74ff18c2492 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 16:31:15 +0900 Subject: [PATCH 479/836] Adjust friend notification logic to fix a few flaws (#36348) Just a couple of things I noticed in passing: - When changing the configuration setting, things were not reset. Likewise, if the setting was off the queues would still be added to but never flushed. - When the setting is toggled, a stale next notification time was still present due to the `??=` and lack of resetting. This should no longer be the case. --- osu.Game/Online/FriendPresenceNotifier.cs | 65 ++++++++++++----------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/osu.Game/Online/FriendPresenceNotifier.cs b/osu.Game/Online/FriendPresenceNotifier.cs index 8329f3b46bcb..0297aea556da 100644 --- a/osu.Game/Online/FriendPresenceNotifier.cs +++ b/osu.Game/Online/FriendPresenceNotifier.cs @@ -45,14 +45,24 @@ public partial class FriendPresenceNotifier : Component private readonly HashSet onlineAlertQueue = new HashSet(); private readonly HashSet offlineAlertQueue = new HashSet(); - private double? lastOnlineAlertTime; - private double? lastOfflineAlertTime; + private double? nextOnlineAlertTime; + private double? nextOfflineAlertTime; + + private const double debounce_time_before_notification = 1000; protected override void LoadComplete() { base.LoadComplete(); config.BindWith(OsuSetting.NotifyOnFriendPresenceChange, notifyOnFriendPresenceChange); + notifyOnFriendPresenceChange.BindValueChanged(_ => + { + onlineAlertQueue.Clear(); + offlineAlertQueue.Clear(); + + nextOfflineAlertTime = null; + nextOnlineAlertTime = null; + }); friends.BindTo(api.LocalUserState.Friends); friends.BindCollectionChanged(onFriendsChanged, true); @@ -65,8 +75,11 @@ protected override void Update() { base.Update(); - alertOnlineUsers(); - alertOfflineUsers(); + if (notifyOnFriendPresenceChange.Value) + { + alertOnlineUsers(); + alertOfflineUsers(); + } } private void onFriendsChanged(object? sender, NotifyCollectionChangedEventArgs e) @@ -132,7 +145,7 @@ private void markUserOnline(APIUser user) if (!offlineAlertQueue.Remove(user)) { onlineAlertQueue.Add(user); - lastOnlineAlertTime ??= Time.Current; + nextOnlineAlertTime ??= Time.Current + debounce_time_before_notification; } } @@ -141,57 +154,45 @@ private void markUserOffline(APIUser user) if (!onlineAlertQueue.Remove(user)) { offlineAlertQueue.Add(user); - lastOfflineAlertTime ??= Time.Current; + nextOfflineAlertTime ??= Time.Current + debounce_time_before_notification; } } private void alertOnlineUsers() { - if (onlineAlertQueue.Count == 0) + if (nextOnlineAlertTime == null || Time.Current < nextOnlineAlertTime) return; - if (lastOnlineAlertTime == null || Time.Current - lastOnlineAlertTime < 1000) - return; - - if (!notifyOnFriendPresenceChange.Value) - { - lastOnlineAlertTime = null; - return; - } + // If a user quickly switches online-offline, we might reach here without actually having a notification + // to fire. Importantly, we should still reset the next alert time in such a scenario. if (onlineAlertQueue.Count == 1) notifications.Post(new SingleFriendOnlineNotification(onlineAlertQueue.Single())); - else + else if (onlineAlertQueue.Count > 1) notifications.Post(new MultipleFriendsOnlineNotification(onlineAlertQueue.ToArray())); onlineAlertQueue.Clear(); - lastOnlineAlertTime = null; + nextOnlineAlertTime = null; } private void alertOfflineUsers() { - if (offlineAlertQueue.Count == 0) - return; - - if (lastOfflineAlertTime == null || Time.Current - lastOfflineAlertTime < 1000) + if (nextOfflineAlertTime == null || Time.Current < nextOfflineAlertTime) return; - if (!notifyOnFriendPresenceChange.Value) - { - lastOfflineAlertTime = null; - return; - } + // If a user quickly switches offline-online, we might reach here without actually having a notification + // to fire. Importantly, we should still reset the next alert time in such a scenario. if (offlineAlertQueue.Count == 1) notifications.Post(new SingleFriendOfflineNotification(offlineAlertQueue.Single())); - else + else if (offlineAlertQueue.Count > 1) notifications.Post(new MultipleFriendsOfflineNotification(offlineAlertQueue.ToArray())); offlineAlertQueue.Clear(); - lastOfflineAlertTime = null; + nextOfflineAlertTime = null; } - public partial class SingleFriendOnlineNotification : UserAvatarNotification + private partial class SingleFriendOnlineNotification : UserAvatarNotification { public SingleFriendOnlineNotification(APIUser user) : base(user) @@ -216,7 +217,7 @@ private void load(ChannelManager channelManager, ChatOverlay chatOverlay) public override string PopInSampleName => "UI/notification-friend-online"; } - public partial class MultipleFriendsOnlineNotification : SimpleNotification + private partial class MultipleFriendsOnlineNotification : SimpleNotification { public MultipleFriendsOnlineNotification(ICollection users) { @@ -233,7 +234,7 @@ private void load(OsuColour colours) public override string PopInSampleName => "UI/notification-friend-online"; } - public partial class SingleFriendOfflineNotification : UserAvatarNotification + private partial class SingleFriendOfflineNotification : UserAvatarNotification { public SingleFriendOfflineNotification(APIUser user) : base(user) @@ -253,7 +254,7 @@ private void load() public override string PopInSampleName => "UI/notification-friend-offline"; } - public partial class MultipleFriendsOfflineNotification : SimpleNotification + private partial class MultipleFriendsOfflineNotification : SimpleNotification { public MultipleFriendsOfflineNotification(ICollection users) { From 0551c75c6bb435a7d8f64deff52d38fd6b2b57d9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 16:21:50 +0900 Subject: [PATCH 480/836] Adjust API disconnection text to be usable in more scenarios --- osu.Game/Localisation/NotificationsStrings.cs | 4 ++-- osu.Game/Online/OnlineStatusNotifier.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 0d22d98eb1c3..91d2615e4703 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -146,9 +146,9 @@ public static class NotificationsStrings public static LocalisableString FriendOffline(string info) => new TranslatableString(getKey(@"friend_offline"), @"Offline: {0}", info); /// - /// "Connection to API was lost. Can't continue with online play." + /// "Connection to online services was interrupted. osu! will be operating with limited functionality." /// - public static LocalisableString APIDisconnect => new TranslatableString(getKey(@"api_disconnect"), @"Connection to API was lost. Can't continue with online play."); + public static LocalisableString APIConnectionInterrupted => new TranslatableString(getKey(@"api_connection_interrupted"), @"Connection to online services was interrupted. osu! will be operating with limited functionality."); /// /// "Connection to the multiplayer server was lost. Exiting multiplayer." diff --git a/osu.Game/Online/OnlineStatusNotifier.cs b/osu.Game/Online/OnlineStatusNotifier.cs index da58dc3d46b9..0c4f6df96af5 100644 --- a/osu.Game/Online/OnlineStatusNotifier.cs +++ b/osu.Game/Online/OnlineStatusNotifier.cs @@ -89,7 +89,7 @@ protected override void LoadComplete() notificationOverlay?.Post(new SimpleErrorNotification { Icon = FontAwesome.Solid.ExclamationCircle, - Text = NotificationsStrings.APIDisconnect, + Text = NotificationsStrings.APIConnectionInterrupted, }); } }); From 15cb3b7a278ad12a9dff6550f5948cb73b162e02 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 16:32:06 +0900 Subject: [PATCH 481/836] Use same message for multiplayer disconnects to simplify things further --- osu.Game/Localisation/NotificationsStrings.cs | 5 ----- osu.Game/Online/OnlineStatusNotifier.cs | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 91d2615e4703..1d6b69a0075a 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -150,11 +150,6 @@ public static class NotificationsStrings /// public static LocalisableString APIConnectionInterrupted => new TranslatableString(getKey(@"api_connection_interrupted"), @"Connection to online services was interrupted. osu! will be operating with limited functionality."); - /// - /// "Connection to the multiplayer server was lost. Exiting multiplayer." - /// - public static LocalisableString MultiplayerDisconnect => new TranslatableString(getKey(@"multiplayer_disconnect"), @"Connection to the multiplayer server was lost. Exiting multiplayer."); - /// /// "You have been logged out on this device due to a login to your account on another device." /// diff --git a/osu.Game/Online/OnlineStatusNotifier.cs b/osu.Game/Online/OnlineStatusNotifier.cs index 0c4f6df96af5..70020f4b8416 100644 --- a/osu.Game/Online/OnlineStatusNotifier.cs +++ b/osu.Game/Online/OnlineStatusNotifier.cs @@ -110,7 +110,7 @@ protected override void LoadComplete() notificationOverlay?.Post(new SimpleErrorNotification { Icon = FontAwesome.Solid.ExclamationCircle, - Text = NotificationsStrings.MultiplayerDisconnect, + Text = NotificationsStrings.APIConnectionInterrupted, }); } })); From c646b4e5ec55bae66abf1bd8fd44a430082d0fa1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 17:11:29 +0900 Subject: [PATCH 482/836] Alert when spectator server disconnects during gameplay This can cause issues liek loss of replays, so it's worth notifying the user and keeping things visible. --- osu.Game/Online/OnlineStatusNotifier.cs | 55 ++++++++++++++----------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/osu.Game/Online/OnlineStatusNotifier.cs b/osu.Game/Online/OnlineStatusNotifier.cs index 70020f4b8416..66282e48fd02 100644 --- a/osu.Game/Online/OnlineStatusNotifier.cs +++ b/osu.Game/Online/OnlineStatusNotifier.cs @@ -17,6 +17,7 @@ using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osu.Game.Screens.OnlinePlay; +using osu.Game.Screens.Play; namespace osu.Game.Online { @@ -75,22 +76,16 @@ protected override void LoadComplete() apiState.BindValueChanged(state => { - if (state.NewValue == APIState.Online) + switch (state.NewValue) { - userNotified = false; - return; - } - - if (userNotified) return; - - if (state.NewValue == APIState.Offline && getCurrentScreen() is OnlinePlayScreen) - { - userNotified = true; - notificationOverlay?.Post(new SimpleErrorNotification - { - Icon = FontAwesome.Solid.ExclamationCircle, - Text = NotificationsStrings.APIConnectionInterrupted, - }); + case APIState.Online: + userNotified = false; + return; + + case APIState.Offline: + if (getCurrentScreen() is OnlinePlayScreen) + notifyApiDisconnection(); + break; } }); @@ -102,22 +97,32 @@ protected override void LoadComplete() return; } - if (userNotified) return; - if (multiplayerClient.Room != null) + notifyApiDisconnection(); + })); + + spectatorState.BindValueChanged(connected => Schedule(() => + { + if (connected.NewValue) { - userNotified = true; - notificationOverlay?.Post(new SimpleErrorNotification - { - Icon = FontAwesome.Solid.ExclamationCircle, - Text = NotificationsStrings.APIConnectionInterrupted, - }); + userNotified = false; + return; } + + if (getCurrentScreen() is Player) + notifyApiDisconnection(); })); + } + + private void notifyApiDisconnection() + { + if (userNotified) return; - spectatorState.BindValueChanged(_ => + userNotified = true; + notificationOverlay?.Post(new SimpleErrorNotification { - // TODO: handle spectator server failure somehow? + Icon = FontAwesome.Solid.ExclamationCircle, + Text = NotificationsStrings.APIConnectionInterrupted, }); } From b4ba327c1c0595de0bb4f2ea586dc052949290b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 17:52:30 +0900 Subject: [PATCH 483/836] Fix toasts showing "no key bound" for operations which can't have keys bound Supersedes and closes https://github.com/ppy/osu/pull/35781. Closes https://github.com/ppy/osu/issues/36294. --- .../UserInterface/TestSceneOnScreenDisplay.cs | 5 ++-- .../Overlays/Music/MusicKeyBindingHandler.cs | 5 ++-- .../Overlays/OSD/CopiedToClipboardToast.cs | 2 +- osu.Game/Overlays/OSD/SpeedChangeToast.cs | 11 +++++++-- osu.Game/Overlays/OSD/Toast.cs | 24 ++++++++++++------- osu.Game/Overlays/OSD/TrackedSettingToast.cs | 6 +++-- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 3 ++- .../Edit/ComposerDistanceSnapProvider.cs | 4 ++-- osu.Game/Screens/Edit/Editor.cs | 3 ++- .../Screens/Select/ModSpeedHotkeyHandler.cs | 8 ++----- 10 files changed, 42 insertions(+), 29 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOnScreenDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOnScreenDisplay.cs index 4bd3a883f1ab..34795f3b1f84 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOnScreenDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOnScreenDisplay.cs @@ -96,7 +96,7 @@ private enum EnumSetting private partial class EmptyToast : Toast { public EmptyToast() - : base("", "", "") + : base("", "") { } } @@ -104,8 +104,9 @@ public EmptyToast() private partial class LengthyToast : Toast { public LengthyToast() - : base("Toast with a very very very long text", "A very very very very very very long text also", "A very very very very very long shortcut") + : base("Toast with a very very very long text", "A very very very very very very long text also") { + ExtraText = "A very very very very very long shortcut"; } } diff --git a/osu.Game/Overlays/Music/MusicKeyBindingHandler.cs b/osu.Game/Overlays/Music/MusicKeyBindingHandler.cs index 8cec85b74853..8fa2520e8f8f 100644 --- a/osu.Game/Overlays/Music/MusicKeyBindingHandler.cs +++ b/osu.Game/Overlays/Music/MusicKeyBindingHandler.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; @@ -86,7 +85,7 @@ private partial class MusicActionToast : Toast private readonly GlobalAction action; public MusicActionToast(LocalisableString value, GlobalAction action) - : base(ToastStrings.MusicPlayback, value, string.Empty) + : base(ToastStrings.MusicPlayback, value) { this.action = action; } @@ -94,7 +93,7 @@ public MusicActionToast(LocalisableString value, GlobalAction action) [BackgroundDependencyLoader] private void load(RealmKeyBindingStore keyBindingStore) { - ShortcutText.Text = keyBindingStore.GetBindingsStringFor(action).ToUpper(); + ExtraText = keyBindingStore.GetBindingsStringFor(action); } } } diff --git a/osu.Game/Overlays/OSD/CopiedToClipboardToast.cs b/osu.Game/Overlays/OSD/CopiedToClipboardToast.cs index 4059a274ad7a..455d93d7adad 100644 --- a/osu.Game/Overlays/OSD/CopiedToClipboardToast.cs +++ b/osu.Game/Overlays/OSD/CopiedToClipboardToast.cs @@ -8,7 +8,7 @@ namespace osu.Game.Overlays.OSD public partial class CopiedToClipboardToast : Toast { public CopiedToClipboardToast() - : base(CommonStrings.General, ToastStrings.CopiedToClipboard, "") + : base(CommonStrings.General, ToastStrings.CopiedToClipboard) { } } diff --git a/osu.Game/Overlays/OSD/SpeedChangeToast.cs b/osu.Game/Overlays/OSD/SpeedChangeToast.cs index 652c04335730..48cf6d2b0a11 100644 --- a/osu.Game/Overlays/OSD/SpeedChangeToast.cs +++ b/osu.Game/Overlays/OSD/SpeedChangeToast.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 osu.Framework.Allocation; using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.Localisation; @@ -9,9 +10,15 @@ namespace osu.Game.Overlays.OSD { public partial class SpeedChangeToast : Toast { - public SpeedChangeToast(RealmKeyBindingStore keyBindingStore, double newSpeed) - : base(ModSelectOverlayStrings.ModCustomisation, ToastStrings.SpeedChangedTo(newSpeed), keyBindingStore.GetBindingsStringFor(GlobalAction.IncreaseModSpeed) + " / " + keyBindingStore.GetBindingsStringFor(GlobalAction.DecreaseModSpeed)) + public SpeedChangeToast(double newSpeed) + : base(ModSelectOverlayStrings.ModCustomisation, ToastStrings.SpeedChangedTo(newSpeed)) { } + + [BackgroundDependencyLoader] + private void load(RealmKeyBindingStore keyBindingStore) + { + ExtraText = keyBindingStore.GetBindingsStringFor(GlobalAction.IncreaseModSpeed) + " / " + keyBindingStore.GetBindingsStringFor(GlobalAction.DecreaseModSpeed); + } } } diff --git a/osu.Game/Overlays/OSD/Toast.cs b/osu.Game/Overlays/OSD/Toast.cs index 7df534d90db9..a809c37800b6 100644 --- a/osu.Game/Overlays/OSD/Toast.cs +++ b/osu.Game/Overlays/OSD/Toast.cs @@ -10,23 +10,30 @@ using osu.Game.Graphics.Sprites; using osuTK; using osuTK.Graphics; -using osu.Game.Localisation; namespace osu.Game.Overlays.OSD { public abstract partial class Toast : Container { + /// + /// Extra text to be shown at the bottom of the toast. Usually a key binding if available. + /// + public LocalisableString ExtraText + { + get => extraText.Text; + set => extraText.Text = value.ToUpper(); + } + private const int toast_minimum_width = 240; private readonly Container content; protected override Container Content => content; - protected readonly OsuSpriteText ValueText; - - protected readonly OsuSpriteText ShortcutText; + protected readonly OsuSpriteText ValueSpriteText; + private readonly OsuSpriteText extraText; - protected Toast(LocalisableString description, LocalisableString value, LocalisableString shortcut) + protected Toast(LocalisableString description, LocalisableString value) { Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -65,7 +72,7 @@ protected Toast(LocalisableString description, LocalisableString value, Localisa Origin = Anchor.TopCentre, Text = description.ToUpper() }, - ValueText = new OsuSpriteText + ValueSpriteText = new OsuSpriteText { Font = OsuFont.GetFont(size: 24, weight: FontWeight.Light), Padding = new MarginPadding { Horizontal = 10 }, @@ -74,15 +81,14 @@ protected Toast(LocalisableString description, LocalisableString value, Localisa Origin = Anchor.Centre, Text = value }, - ShortcutText = new OsuSpriteText + extraText = new OsuSpriteText { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - Name = "Shortcut", + Name = "Extra Text", Alpha = 0.3f, Margin = new MarginPadding { Bottom = 15, Horizontal = 10 }, Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), - Text = string.IsNullOrEmpty(shortcut.ToString()) ? ToastStrings.NoKeyBound.ToUpper() : shortcut.ToUpper() }, }; } diff --git a/osu.Game/Overlays/OSD/TrackedSettingToast.cs b/osu.Game/Overlays/OSD/TrackedSettingToast.cs index 1aa6de423ef5..73fed25b1a8c 100644 --- a/osu.Game/Overlays/OSD/TrackedSettingToast.cs +++ b/osu.Game/Overlays/OSD/TrackedSettingToast.cs @@ -35,8 +35,10 @@ public partial class TrackedSettingToast : Toast private Bindable lastPlaybackTime; public TrackedSettingToast(SettingDescription description) - : base(description.Name, description.Value, description.Shortcut) + : base(description.Name, description.Value) { + ExtraText = description.Shortcut; + FillFlowContainer optionLights; Children = new Drawable[] @@ -75,7 +77,7 @@ public TrackedSettingToast(SettingDescription description) break; } - ValueText.Origin = optionCount > 0 ? Anchor.BottomCentre : Anchor.Centre; + ValueSpriteText.Origin = optionCount > 0 ? Anchor.BottomCentre : Anchor.Centre; for (int i = 0; i < optionCount; i++) optionLights.Add(new OptionLight { Glowing = i == selectedOption }); diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 2903c867f7a4..193d570a21f3 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -769,8 +769,9 @@ protected override void Dispose(bool isDisposing) private partial class SkinEditorToast : Toast { public SkinEditorToast(LocalisableString value, string skinDisplayName) - : base(SkinSettingsStrings.SkinLayoutEditor, value, skinDisplayName) + : base(SkinSettingsStrings.SkinLayoutEditor, value) { + ExtraText = skinDisplayName; } } diff --git a/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs b/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs index 64f938ba6c35..0b8df0ad417a 100644 --- a/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs +++ b/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs @@ -308,7 +308,7 @@ private partial class DistanceSpacingToast : Toast private readonly ValueChangedEvent change; public DistanceSpacingToast(LocalisableString value, ValueChangedEvent change) - : base(getAction(change).GetLocalisableDescription(), value, string.Empty) + : base(getAction(change).GetLocalisableDescription(), value) { this.change = change; } @@ -316,7 +316,7 @@ public DistanceSpacingToast(LocalisableString value, ValueChangedEvent c [BackgroundDependencyLoader] private void load(RealmKeyBindingStore keyBindingStore) { - ShortcutText.Text = keyBindingStore.GetBindingsStringFor(getAction(change)).ToUpper(); + ExtraText = keyBindingStore.GetBindingsStringFor(getAction(change)); } private static GlobalAction getAction(ValueChangedEvent change) => change.NewValue - change.OldValue > 0 diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 03a0942e190e..991f10497d3d 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -1620,8 +1620,9 @@ public bool HandleTimestamp(string timestamp, bool notifyOnError = false) private partial class BeatmapEditorToast : Toast { public BeatmapEditorToast(LocalisableString value, string beatmapDisplayName) - : base(InputSettingsStrings.EditorSection, value, beatmapDisplayName) + : base(InputSettingsStrings.EditorSection, value) { + ExtraText = beatmapDisplayName; } } diff --git a/osu.Game/Screens/Select/ModSpeedHotkeyHandler.cs b/osu.Game/Screens/Select/ModSpeedHotkeyHandler.cs index 998f94849c63..6d9f58bcfda8 100644 --- a/osu.Game/Screens/Select/ModSpeedHotkeyHandler.cs +++ b/osu.Game/Screens/Select/ModSpeedHotkeyHandler.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Utils; using osu.Game.Configuration; -using osu.Game.Input; using osu.Game.Overlays; using osu.Game.Overlays.OSD; using osu.Game.Rulesets.Mods; @@ -21,9 +20,6 @@ public partial class ModSpeedHotkeyHandler : Component [Resolved] private Bindable> selectedMods { get; set; } = null!; - [Resolved] - private RealmKeyBindingStore keyBindingStore { get; set; } = null!; - [Resolved] private OnScreenDisplay? onScreenDisplay { get; set; } @@ -56,7 +52,7 @@ public bool ChangeSpeed(double delta, IEnumerable availableMods) if (Precision.AlmostEquals(targetSpeed, 1, 0.005)) { selectedMods.Value = selectedMods.Value.Where(m => m is not ModRateAdjust).ToList(); - onScreenDisplay?.Display(new SpeedChangeToast(keyBindingStore, targetSpeed)); + onScreenDisplay?.Display(new SpeedChangeToast(targetSpeed)); return true; } @@ -109,7 +105,7 @@ public bool ChangeSpeed(double delta, IEnumerable availableMods) return false; selectedMods.Value = intendedMods; - onScreenDisplay?.Display(new SpeedChangeToast(keyBindingStore, targetMod.SpeedChange.Value)); + onScreenDisplay?.Display(new SpeedChangeToast(targetMod.SpeedChange.Value)); return true; } } From e8154080b3423de67d98e5885fe9992227524383 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 17:31:42 +0900 Subject: [PATCH 484/836] Stop websocket handshake failures from being shown to users --- .../Multiplayer/MultiplayerClientExtensions.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClientExtensions.cs b/osu.Game/Online/Multiplayer/MultiplayerClientExtensions.cs index 1cc5a8e70a80..61824914b5c0 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClientExtensions.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClientExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using System.Net.WebSockets; using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR; using osu.Framework.Extensions.ExceptionExtensions; @@ -20,13 +21,23 @@ public static void FireAndForget(this Task task, Action? onSuccess = null, Actio Debug.Assert(t.Exception != null); Exception exception = t.Exception.AsSingular(); + onError?.Invoke(exception); + + if (exception is WebSocketException wse && wse.Message == @"The remote party closed the WebSocket connection without completing the close handshake.") + { + // OnlineStatusNotifier is already letting users know about interruptions to connections. + // Silence these because it gets very spammy otherwise. + return; + } + if (exception.GetHubExceptionMessage() is string message) + { // Hub exceptions generally contain something we can show the user directly. Logger.Log(message, level: LogLevel.Important); - else - Logger.Error(exception, $"Unobserved exception occurred via {nameof(FireAndForget)} call: {exception.Message}"); + return; + } - onError?.Invoke(exception); + Logger.Error(exception, $"Unobserved exception occurred via {nameof(FireAndForget)} call: {exception.Message}"); } else { From 13138833948d8e07751c40e49948656cc00400ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 18:08:41 +0900 Subject: [PATCH 485/836] Scope player handling to specific screens which have issues --- osu.Game/Online/OnlineStatusNotifier.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/OnlineStatusNotifier.cs b/osu.Game/Online/OnlineStatusNotifier.cs index 66282e48fd02..f4c33c67aa30 100644 --- a/osu.Game/Online/OnlineStatusNotifier.cs +++ b/osu.Game/Online/OnlineStatusNotifier.cs @@ -109,8 +109,13 @@ protected override void LoadComplete() return; } - if (getCurrentScreen() is Player) - notifyApiDisconnection(); + switch (getCurrentScreen()) + { + case SpectatorPlayer: // obvious issues + case SubmittingPlayer: // replay sending issues + notifyApiDisconnection(); + break; + } })); } From 367d133d2f2c8c3fe4710e675c1e875c775ba268 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 18:42:57 +0900 Subject: [PATCH 486/836] Avoid requiring private variables to set `ApplyClassicDefault` settings --- osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs | 7 +++---- .../Visual/Settings/TestSceneSettingsItemV2.cs | 6 +++--- .../Settings/Sections/Gameplay/AudioSettings.cs | 7 +++---- .../Settings/Sections/Gameplay/GeneralSettings.cs | 7 +++---- .../Settings/Sections/Gameplay/HUDSettings.cs | 7 +++---- .../Sections/UserInterface/GeneralSettings.cs | 7 +++---- .../Sections/UserInterface/SongSelectSettings.cs | 12 +++++------- osu.Game/Overlays/Settings/SettingsItemV2.cs | 4 ++-- 8 files changed, 25 insertions(+), 32 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs b/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs index 56a30f89ac88..2382fe6d95ba 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; @@ -14,8 +15,6 @@ namespace osu.Game.Rulesets.Osu.UI { public partial class OsuSettingsSubsection : RulesetSettingsSubsection { - private FormCheckBox snakingOutSliders = null!; - protected override LocalisableString Header => "osu!"; public OsuSettingsSubsection(Ruleset ruleset) @@ -35,13 +34,13 @@ private void load() Caption = RulesetSettingsStrings.SnakingInSliders, Current = config.GetBindable(OsuRulesetSetting.SnakingInSliders) }), - new SettingsItemV2(snakingOutSliders = new FormCheckBox + new SettingsItemV2(new FormCheckBox { Caption = RulesetSettingsStrings.SnakingOutSliders, Current = config.GetBindable(OsuRulesetSetting.SnakingOutSliders) }) { - ApplyClassicDefault = () => snakingOutSliders.Current.Value = false, + ApplyClassicDefault = c => ((IHasCurrentValue)c).Current.Value = false, }, new SettingsItemV2(new FormCheckBox { diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs index 043eadf370cc..d460ea0078e7 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; @@ -31,7 +32,6 @@ public partial class TestSceneSettingsItemV2 : ThemeComparisonTestScene private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); private FormSliderBar sliderBar = null!; - private FormSliderBar classicSliderBar = null!; private SearchContainer searchContainer = null!; @@ -173,7 +173,7 @@ protected override Drawable CreateContent() { ShowRevertToDefaultButton = false }, - new SettingsItemV2(classicSliderBar = new FormSliderBar + new SettingsItemV2(new FormSliderBar { Caption = "Slider with classic default", Current = new BindableFloat @@ -185,7 +185,7 @@ protected override Drawable CreateContent() }, }) { - ApplyClassicDefault = () => classicSliderBar.Current.Value = 2, + ApplyClassicDefault = c => ((IHasCurrentValue)c).Current.Value = 2, }, }, }, diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/AudioSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/AudioSettings.cs index 403b4f237801..e4c64612f5a9 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/AudioSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/AudioSettings.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics.UserInterfaceV2; @@ -12,8 +13,6 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { public partial class AudioSettings : SettingsSubsection { - private FormCheckBox alwaysPlayFirstComboBreak = null!; - protected override LocalisableString Header => GameplaySettingsStrings.AudioHeader; [BackgroundDependencyLoader] @@ -31,13 +30,13 @@ private void load(OsuConfigManager config, OsuConfigManager osuConfig) { Keywords = new[] { @"positional", @"balance" }, }, - new SettingsItemV2(alwaysPlayFirstComboBreak = new FormCheckBox + new SettingsItemV2(new FormCheckBox { Caption = GameplaySettingsStrings.AlwaysPlayFirstComboBreak, Current = config.GetBindable(OsuSetting.AlwaysPlayFirstComboBreak) }) { - ApplyClassicDefault = () => alwaysPlayFirstComboBreak.Current.Value = false, + ApplyClassicDefault = c => ((IHasCurrentValue)c).Current.Value = false, } }; } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs index 34879ffa996d..4f402c1cb7de 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics.UserInterfaceV2; @@ -13,8 +14,6 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { public partial class GeneralSettings : SettingsSubsection { - private FormEnumDropdown scoringModeDropdown = null!; - protected override LocalisableString Header => CommonStrings.General; [BackgroundDependencyLoader] @@ -22,14 +21,14 @@ private void load(OsuConfigManager config) { Children = new Drawable[] { - new SettingsItemV2(scoringModeDropdown = new FormEnumDropdown + new SettingsItemV2(new FormEnumDropdown { Caption = GameplaySettingsStrings.ScoreDisplayMode, Current = config.GetBindable(OsuSetting.ScoreDisplayMode), }) { Keywords = new[] { "scoring" }, - ApplyClassicDefault = () => scoringModeDropdown.Current.Value = ScoringMode.Classic, + ApplyClassicDefault = c => ((IHasCurrentValue)c).Current.Value = ScoringMode.Classic, }, new SettingsItemV2(new FormCheckBox { diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs index 7c9fad624c4d..711e10da47ae 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics.UserInterfaceV2; @@ -12,8 +13,6 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { public partial class HUDSettings : SettingsSubsection { - private FormCheckBox showHealthDisplayWhenCantFail = null!; - protected override LocalisableString Header => GameplaySettingsStrings.HUDHeader; [BackgroundDependencyLoader] @@ -57,14 +56,14 @@ private void load(OsuConfigManager config) Caption = GameplaySettingsStrings.AlwaysShowHoldForMenuButton, Current = config.GetBindable(OsuSetting.AlwaysShowHoldForMenuButton), }), - new SettingsItemV2(showHealthDisplayWhenCantFail = new FormCheckBox + new SettingsItemV2(new FormCheckBox { Caption = GameplaySettingsStrings.ShowHealthDisplayWhenCantFail, Current = config.GetBindable(OsuSetting.ShowHealthDisplayWhenCantFail), }) { Keywords = new[] { "hp", "bar" }, - ApplyClassicDefault = () => showHealthDisplayWhenCantFail.Current.Value = false, + ApplyClassicDefault = c => ((IHasCurrentValue)c).Current.Value = false, }, }; } diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs index 1e8852d4b7ed..9a894e89fed7 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics.UserInterfaceV2; @@ -12,8 +13,6 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface { public partial class GeneralSettings : SettingsSubsection { - private FormSliderBar holdToConfirmSlider = null!; - protected override LocalisableString Header => CommonStrings.General; [BackgroundDependencyLoader] @@ -38,7 +37,7 @@ private void load(OsuConfigManager config) Caption = UserInterfaceStrings.Parallax, Current = config.GetBindable(OsuSetting.MenuParallax) }), - new SettingsItemV2(holdToConfirmSlider = new FormSliderBar + new SettingsItemV2(new FormSliderBar { Caption = UserInterfaceStrings.HoldToConfirmActivationTime, Current = config.GetBindable(OsuSetting.UIHoldActivationDelay), @@ -47,7 +46,7 @@ private void load(OsuConfigManager config) }) { Keywords = new[] { @"delay" }, - ApplyClassicDefault = () => holdToConfirmSlider.Current.Value = 0, + ApplyClassicDefault = c => ((IHasCurrentValue)c).Current.Value = 0, }, }; } diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index 4052842de95e..83ee3eb09aae 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics.UserInterfaceV2; @@ -13,9 +14,6 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface { public partial class SongSelectSettings : SettingsSubsection { - private FormEnumDropdown modSelectHotkeyStyle = null!; - private FormCheckBox modSelectTextSearchStartsActive = null!; - protected override LocalisableString Header => UserInterfaceStrings.SongSelectHeader; [BackgroundDependencyLoader] @@ -36,21 +34,21 @@ private void load(OsuConfigManager config) Caption = UserInterfaceStrings.RandomSelectionAlgorithm, Current = config.GetBindable(OsuSetting.RandomSelectAlgorithm), }), - new SettingsItemV2(modSelectHotkeyStyle = new FormEnumDropdown + new SettingsItemV2(new FormEnumDropdown { Caption = UserInterfaceStrings.ModSelectHotkeyStyle, Current = config.GetBindable(OsuSetting.ModSelectHotkeyStyle), }) { - ApplyClassicDefault = () => modSelectHotkeyStyle.Current.Value = ModSelectHotkeyStyle.Classic, + ApplyClassicDefault = c => ((IHasCurrentValue)c).Current.Value = ModSelectHotkeyStyle.Classic, }, - new SettingsItemV2(modSelectTextSearchStartsActive = new FormCheckBox + new SettingsItemV2(new FormCheckBox { Caption = UserInterfaceStrings.ModSelectTextSearchStartsActive, Current = config.GetBindable(OsuSetting.ModSelectTextSearchStartsActive), }) { - ApplyClassicDefault = () => modSelectTextSearchStartsActive.Current.Value = false, + ApplyClassicDefault = c => ((IHasCurrentValue)c).Current.Value = false, }, new SettingsItemV2(new FormCheckBox { diff --git a/osu.Game/Overlays/Settings/SettingsItemV2.cs b/osu.Game/Overlays/Settings/SettingsItemV2.cs index 48de6723ea0b..fea127200a48 100644 --- a/osu.Game/Overlays/Settings/SettingsItemV2.cs +++ b/osu.Game/Overlays/Settings/SettingsItemV2.cs @@ -112,9 +112,9 @@ protected override void Update() /// If set, this setting is considered as having a "classic" default value, /// and this is the function for overwriting the control with that value. /// - public Action? ApplyClassicDefault { get; set; } + public Action? ApplyClassicDefault { get; set; } - void ISettingsItem.ApplyClassicDefault() => ApplyClassicDefault?.Invoke(); + void ISettingsItem.ApplyClassicDefault() => ApplyClassicDefault?.Invoke(Control); public void ApplyDefault() { From a6756157d192801dc79e95125e6e52d2dfc919fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 18:54:01 +0900 Subject: [PATCH 487/836] Update tablet area selection to match new design --- .../Sections/Input/TabletAreaSelection.cs | 122 ++++++++++-------- 1 file changed, 70 insertions(+), 52 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs index bdc7c9bb35eb..9bd6d58aedec 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs @@ -41,6 +41,9 @@ public partial class TabletAreaSelection : CompositeDrawable private Box usableFill; private OsuSpriteText usableAreaText; + [Resolved] + private OsuColour colour { get; set; } + public TabletAreaSelection(ITabletHandler handler) { this.handler = handler; @@ -49,63 +52,81 @@ public TabletAreaSelection(ITabletHandler handler) } [BackgroundDependencyLoader] - private void load() + private void load(OverlayColourProvider colourProvider) { - InternalChild = tabletContainer = new Container + InternalChildren = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Masking = true, - CornerRadius = 5, - BorderThickness = 2, - BorderColour = colour.Gray3, - Children = new Drawable[] + new Container { - new Box + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 5, + CornerExponent = 2.5f, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = colour.Gray1, - }, - usableAreaContainer = new UsableAreaContainer(handler) - { - Origin = Anchor.Centre, - Children = new Drawable[] + new Box { - usableFill = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0.6f, - }, - new Box - { - Colour = Color4.White, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Height = 5, - }, - new Box - { - Colour = Color4.White, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Width = 5, - }, - usableAreaText = new OsuSpriteText + Colour = colourProvider.Background5, + RelativeSizeAxes = Axes.Both, + }, + tabletContainer = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Masking = true, + CornerRadius = 5, + BorderThickness = 2, + BorderColour = colourProvider.Background3, + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = Color4.White, - Font = OsuFont.Default.With(size: 12), - Y = 10 + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background4, + }, + usableAreaContainer = new UsableAreaContainer(handler) + { + Origin = Anchor.Centre, + Children = new Drawable[] + { + usableFill = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.6f, + }, + new Box + { + Colour = Color4.White, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Height = 5, + }, + new Box + { + Colour = Color4.White, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 5, + }, + usableAreaText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = Color4.White, + Font = OsuFont.Default.With(size: 12), + Y = 10 + } + } + }, + tabletName = new OsuSpriteText + { + Padding = new MarginPadding(3), + Font = OsuFont.Default.With(size: 8) + }, } } - }, - tabletName = new OsuSpriteText - { - Padding = new MarginPadding(3), - Font = OsuFont.Default.With(size: 8) - }, - } + } + }, }; } @@ -169,9 +190,6 @@ private static int greatestCommonDivider(int a, int b) return a; } - [Resolved] - private OsuColour colour { get; set; } - private void checkBounds() { if (tablet.Value == null) From cd433fea5056784b4c5e849f3fc282caa45cc304 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 19:01:32 +0900 Subject: [PATCH 488/836] Fix weirdly defined constant --- .../Visual/UserInterface/TestSceneButtonsInput.cs | 2 +- .../Settings/Sections/Audio/AudioOffsetAdjustControl.cs | 8 ++++---- .../Overlays/Settings/Sections/Input/KeyBindingRow.cs | 4 ++-- .../Settings/Sections/Input/TabletAreaSelection.cs | 2 +- .../Overlays/Settings/Sections/Input/TabletSettings.cs | 4 ++-- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 2 +- osu.Game/Overlays/Settings/SettingsButtonV2.cs | 2 +- osu.Game/Overlays/Settings/SettingsFooter.cs | 2 +- osu.Game/Overlays/Settings/SettingsHeader.cs | 4 ++-- osu.Game/Overlays/Settings/SettingsItemV2.cs | 2 +- osu.Game/Overlays/Settings/SettingsSection.cs | 2 +- osu.Game/Overlays/Settings/SettingsSubsection.cs | 2 +- osu.Game/Overlays/SettingsPanel.cs | 6 +++--- 13 files changed, 21 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs index 0f6716fd9c61..f30b82d618b7 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs @@ -91,7 +91,7 @@ public void TestSettingsButtonInput() { AddStep("Move cursor to button", () => InputManager.MoveMouseTo(settingsButton)); AddAssert("Button is hovered", () => settingsButton.IsHovered); - AddStep("Move cursor to padded area", () => InputManager.MoveMouseTo(settingsButton.ScreenSpaceDrawQuad.TopLeft + new Vector2(SettingsPanel.ContentPaddingV2.Left / 2f, 10))); + AddStep("Move cursor to padded area", () => InputManager.MoveMouseTo(settingsButton.ScreenSpaceDrawQuad.TopLeft + new Vector2(SettingsPanel.CONTENT_PADDING.Left / 2f, 10))); AddAssert("Cursor within a button", () => settingsButton.ScreenSpaceDrawQuad.Contains(InputManager.CurrentState.Mouse.Position)); AddAssert("Button is not hovered", () => !settingsButton.IsHovered); } diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs index 7d3596c25945..f815cf82e6e2 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs @@ -69,8 +69,8 @@ private void load(SessionAverageHitErrorTracker hitErrorTracker) AutoSizeAxes = Axes.Y, Padding = new MarginPadding { - Left = SettingsPanel.ContentPaddingV2.Left + 9, - Right = SettingsPanel.ContentPaddingV2.Right + 5 + Left = SettingsPanel.CONTENT_PADDING.Left + 9, + Right = SettingsPanel.CONTENT_PADDING.Right + 5 }, Child = notchContainer = new Container { @@ -89,14 +89,14 @@ private void load(SessionAverageHitErrorTracker hitErrorTracker) hintNote = new SettingsNote { RelativeSizeAxes = Axes.X, - Padding = SettingsPanel.ContentPaddingV2, + Padding = SettingsPanel.CONTENT_PADDING, TextAnchor = Anchor.TopCentre, }, applySuggestion = new RoundedButton { RelativeSizeAxes = Axes.X, Text = AudioSettingsStrings.ApplySuggestedOffset, - Padding = SettingsPanel.ContentPaddingV2, + Padding = SettingsPanel.CONTENT_PADDING, Action = () => { if (SuggestedOffset.Value.HasValue) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index 54ab537d9c7d..98a6d2600f2b 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -128,7 +128,7 @@ private void load(OverlayColourProvider colourProvider, AudioManager audioManage { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Padding = new MarginPadding { Right = SettingsPanel.ContentPaddingV2.Right }; + Padding = new MarginPadding { Right = SettingsPanel.CONTENT_PADDING.Right }; InternalChildren = new Drawable[] { @@ -145,7 +145,7 @@ private void load(OverlayColourProvider colourProvider, AudioManager audioManage { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = SettingsPanel.ContentPaddingV2.Left }, + Padding = new MarginPadding { Left = SettingsPanel.CONTENT_PADDING.Left }, Children = new Drawable[] { content = new Container diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs index 9bd6d58aedec..5cd09265509b 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs @@ -48,7 +48,7 @@ public TabletAreaSelection(ITabletHandler handler) { this.handler = handler; - Padding = SettingsPanel.ContentPaddingV2; + Padding = SettingsPanel.CONTENT_PADDING; } [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 00ddbf17def2..b5e9e2ee4e93 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -100,7 +100,7 @@ private void load(OsuColour colours, LocalisationManager localisation, OsuConfig { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = SettingsPanel.ContentPaddingV2, + Padding = SettingsPanel.CONTENT_PADDING, Child = new Container { RelativeSizeAxes = Axes.X, @@ -219,7 +219,7 @@ private void load(OsuColour colours, LocalisationManager localisation, OsuConfig }), new RotationPresetButtons(tabletHandler) { - Padding = SettingsPanel.ContentPaddingV2, + Padding = SettingsPanel.CONTENT_PADDING, }, new SettingsItemV2(new FormSliderBar { diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 022d7d38c9e6..da0a21382bcd 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -77,7 +77,7 @@ private void load([CanBeNull] SkinEditorOverlay skinEditor) RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Horizontal, - Padding = SettingsPanel.ContentPaddingV2, + Padding = SettingsPanel.CONTENT_PADDING, Children = new Drawable[] { // This is all super-temporary until we move skin settings to their own panel / overlay. diff --git a/osu.Game/Overlays/Settings/SettingsButtonV2.cs b/osu.Game/Overlays/Settings/SettingsButtonV2.cs index 28f569e03516..4d5e1d5c5950 100644 --- a/osu.Game/Overlays/Settings/SettingsButtonV2.cs +++ b/osu.Game/Overlays/Settings/SettingsButtonV2.cs @@ -17,7 +17,7 @@ public SettingsButtonV2() { RelativeSizeAxes = Axes.X; Margin = new MarginPadding { Vertical = -1.5f }; - Padding = SettingsPanel.ContentPaddingV2; + Padding = SettingsPanel.CONTENT_PADDING; } public IEnumerable Keywords { get; set; } = Array.Empty(); diff --git a/osu.Game/Overlays/Settings/SettingsFooter.cs b/osu.Game/Overlays/Settings/SettingsFooter.cs index 6ed59857157e..a39f54c549e6 100644 --- a/osu.Game/Overlays/Settings/SettingsFooter.cs +++ b/osu.Game/Overlays/Settings/SettingsFooter.cs @@ -27,7 +27,7 @@ private void load(OsuGameBase game, RulesetStore rulesets) RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Direction = FillDirection.Vertical; - Padding = new MarginPadding { Top = 20, Bottom = 30, Left = SettingsPanel.ContentPaddingV2.Left, Right = SettingsPanel.ContentPaddingV2.Right }; + Padding = new MarginPadding { Top = 20, Bottom = 30, Left = SettingsPanel.CONTENT_PADDING.Left, Right = SettingsPanel.CONTENT_PADDING.Right }; FillFlowContainer modes; diff --git a/osu.Game/Overlays/Settings/SettingsHeader.cs b/osu.Game/Overlays/Settings/SettingsHeader.cs index 3ed12f7d9f1a..4e32efc4f47e 100644 --- a/osu.Game/Overlays/Settings/SettingsHeader.cs +++ b/osu.Game/Overlays/Settings/SettingsHeader.cs @@ -35,8 +35,8 @@ private void load(OverlayColourProvider colourProvider) RelativeSizeAxes = Axes.X, Padding = new MarginPadding { - Left = SettingsPanel.ContentPaddingV2.Left, - Right = SettingsPanel.ContentPaddingV2.Right, + Left = SettingsPanel.CONTENT_PADDING.Left, + Right = SettingsPanel.CONTENT_PADDING.Right, Top = Toolbar.Toolbar.TOOLTIP_HEIGHT, Bottom = 30 } diff --git a/osu.Game/Overlays/Settings/SettingsItemV2.cs b/osu.Game/Overlays/Settings/SettingsItemV2.cs index fea127200a48..e6eddb45597b 100644 --- a/osu.Game/Overlays/Settings/SettingsItemV2.cs +++ b/osu.Game/Overlays/Settings/SettingsItemV2.cs @@ -42,7 +42,7 @@ public SettingsItemV2(IFormControl control) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = SettingsPanel.ContentPaddingV2, + Padding = SettingsPanel.CONTENT_PADDING, Direction = FillDirection.Vertical, Children = new Drawable[] { diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index f359e59e8016..c3e995b81a5b 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -115,7 +115,7 @@ private void load(OverlayColourProvider colourProvider) { Font = OsuFont.TorusAlternate.With(size: header_size), Text = Header, - Margin = SettingsPanel.ContentPaddingV2, + Margin = SettingsPanel.CONTENT_PADDING, }, FlowContent } diff --git a/osu.Game/Overlays/Settings/SettingsSubsection.cs b/osu.Game/Overlays/Settings/SettingsSubsection.cs index d614311bab5a..669425b667fc 100644 --- a/osu.Game/Overlays/Settings/SettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/SettingsSubsection.cs @@ -59,7 +59,7 @@ private void load() { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = SettingsPanel.ContentPaddingV2, + Padding = SettingsPanel.CONTENT_PADDING, Children = new[] { new OsuSpriteText diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index 446e24223bb3..e35df366460a 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -32,7 +32,7 @@ public abstract partial class SettingsPanel : OsuFocusedOverlayContainer public const float CONTENT_MARGINS = 20; // extra right padding to give room to the revert-to-default button in settings controls. - public static MarginPadding ContentPaddingV2 { get; } = new MarginPadding { Left = 20, Right = 30 }; + public static readonly MarginPadding CONTENT_PADDING = new MarginPadding { Left = 20, Right = 30 }; public const float TRANSITION_LENGTH = 600; @@ -134,8 +134,8 @@ private void load() Padding = new MarginPadding { Vertical = 20, - Left = ContentPaddingV2.Left, - Right = ContentPaddingV2.Right, + Left = CONTENT_PADDING.Left, + Right = CONTENT_PADDING.Right, }, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, From a8ada5054943bb6f72bf5aa379b418432ed5e8c3 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 16 Jan 2026 02:48:36 -0800 Subject: [PATCH 489/836] Fix double-clicking form slider bar not propagating default to other bindables when `TransferValueOnCommit` is true (#36354) - Addresses https://github.com/ppy/osu/pull/36346#discussion_r2692322683 The inner slider bar binds its `Current` to `currentNumberInstantaneous`: https://github.com/ppy/osu/blob/1add946db486c866cc214c5eb3d728f308aad637/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs#L225-L236 But the current bindable of the form component doesn't update because of this. https://github.com/ppy/osu/blob/1add946db486c866cc214c5eb3d728f308aad637/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs#L285-L293 Fixed it by just moving the `ResetToDefault` action up another level. --------- Co-authored-by: Dean Herbert --- .../UserInterface/TestSceneFormSliderBar.cs | 9 +++++++-- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 17 ++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs index a962cd4a6f4b..c7b99753011a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs @@ -64,9 +64,11 @@ public void TestTransferValueOnCommit() }); } - [Test] - public void TestNubDoubleClickRevertToDefault() + [TestCase(false)] + [TestCase(true)] + public void TestNubDoubleClickRevertToDefault(bool transferValueOnCommit) { + OsuSpriteText text; FormSliderBar slider = null!; AddStep("create content", () => @@ -81,9 +83,11 @@ public void TestNubDoubleClickRevertToDefault() Spacing = new Vector2(10), Children = new Drawable[] { + text = new OsuSpriteText(), slider = new FormSliderBar { Caption = "Slider", + TransferValueOnCommit = transferValueOnCommit, Current = new BindableFloat { MinValue = 0, @@ -94,6 +98,7 @@ public void TestNubDoubleClickRevertToDefault() }, } }; + slider.Current.BindValueChanged(_ => text.Text = $"Current value is: {slider.Current.Value}", true); }); AddStep("set slider to 1", () => slider.Current.Value = 1); diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 625967dc6620..84fda8ecc131 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -233,6 +233,11 @@ private void load(OsuColour colours, OsuGame? game) TooltipFormat = TooltipFormat, DisplayAsPercentage = DisplayAsPercentage, PlaySamplesOnAdjust = PlaySamplesOnAdjust, + ResetToDefault = () => + { + if (!IsDisabled) + SetDefault(); + } } }, }, @@ -400,9 +405,11 @@ private partial class InnerSlider : OsuSliderBar { public BindableBool Focused { get; } = new BindableBool(); - public BindableBool IsDragging { get; set; } = new BindableBool(); + public BindableBool IsDragging { get; } = new BindableBool(); + + public Action? ResetToDefault { get; init; } - public Action? OnCommit { get; set; } + public Action? OnCommit { get; init; } public sealed override LocalisableString TooltipText => base.TooltipText; @@ -453,11 +460,7 @@ private void load() Padding = new MarginPadding { Horizontal = RangePadding, }, Child = nub = new InnerSliderNub { - ResetToDefault = () => - { - if (!Current.Disabled) - Current.SetDefault(); - } + ResetToDefault = ResetToDefault, } }, sounds = new HoverClickSounds() From e05b6f44b9941ac6e88f7a11b12840b7543cb8ad Mon Sep 17 00:00:00 2001 From: De4n <55669793+tadatomix@users.noreply.github.com> Date: Fri, 16 Jan 2026 14:08:52 +0300 Subject: [PATCH 490/836] Update editor slider controls to new design (#36346) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (partially) Closes: #36233 Surpasses: #36244 This PR meant to be one of the last steps that finally make editor use the new forms. Initially it meant to only change one SliderWithTextBoxInput in "Effects section" in timing screen, however soon after it was obvious that there's many other places that still using it. This currently won't affect IndeterminateSliderWithTextBoxInput that is being used in hitsounds, for example, since I think it needs more consideration. Anyways, with this PR, SliderWithTextBoxInput, will no longer be used at all, as it's going to be replaced with modern FormSliderBar Comparison: |master|this PR| |:---:|:---:| |532203751-eb965923-d3a8-441d-a7c8-5c364a6328ad|535466527-3a700a8b-bc3c-4610-998f-a4e55ee03eed| |534509844-f00e4da4-53c4-45e8-80ea-1be62da6c83b|изображение| |534509421-a6ac950f-16e8-4a16-bca6-1a781f82135f|изображение| |534509478-80222623-7766-481d-8682-088276d415ee|изображение| |534509935-58954060-7ac1-4392-8754-a58f909e86aa|изображение| --- .../Edit/PolygonGenerationPopover.cs | 30 ++-- .../Edit/PreciseMovementPopover.cs | 18 +-- .../Edit/PreciseRotationPopover.cs | 9 +- .../Edit/PreciseScalePopover.cs | 9 +- .../TestSceneSliderWithTextBoxInput.cs | 131 --------------- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 2 + .../UserInterfaceV2/SliderWithTextBoxInput.cs | 151 ------------------ osu.Game/Screens/Edit/Timing/EffectSection.cs | 15 +- .../IndeterminateSliderWithTextBoxInput.cs | 2 +- 9 files changed, 48 insertions(+), 319 deletions(-) delete mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneSliderWithTextBoxInput.cs delete mode 100644 osu.Game/Graphics/UserInterfaceV2/SliderWithTextBoxInput.cs diff --git a/osu.Game.Rulesets.Osu/Edit/PolygonGenerationPopover.cs b/osu.Game.Rulesets.Osu/Edit/PolygonGenerationPopover.cs index 046f57c0a5eb..fe5e0581ecd2 100644 --- a/osu.Game.Rulesets.Osu/Edit/PolygonGenerationPopover.cs +++ b/osu.Game.Rulesets.Osu/Edit/PolygonGenerationPopover.cs @@ -25,10 +25,10 @@ namespace osu.Game.Rulesets.Osu.Edit { public partial class PolygonGenerationPopover : OsuPopover { - private SliderWithTextBoxInput distanceSnapInput = null!; - private SliderWithTextBoxInput offsetAngleInput = null!; - private SliderWithTextBoxInput repeatCountInput = null!; - private SliderWithTextBoxInput pointInput = null!; + private FormSliderBar distanceSnapInput { get; set; } = null!; + private FormSliderBar offsetAngleInput { get; set; } = null!; + private FormSliderBar repeatCountInput { get; set; } = null!; + private FormSliderBar pointInput { get; set; } = null!; private RoundedButton commitButton = null!; private readonly List insertedCircles = new List(); @@ -64,11 +64,12 @@ private void load() { Width = 220, AutoSizeAxes = Axes.Y, - Spacing = new Vector2(20), + Spacing = new Vector2(5), Children = new Drawable[] { - distanceSnapInput = new SliderWithTextBoxInput("Distance snap:") + distanceSnapInput = new FormSliderBar { + Caption = "Distance snap", Current = new BindableNumber(1) { MinValue = 0.1, @@ -76,37 +77,40 @@ private void load() Precision = 0.1, Value = ((OsuHitObjectComposer)composer).DistanceSnapProvider.DistanceSpacingMultiplier.Value, }, - Instantaneous = true + TabbableContentContainer = this }, - offsetAngleInput = new SliderWithTextBoxInput("Offset angle:") + offsetAngleInput = new FormSliderBar { + Caption = "Offset angle", Current = new BindableNumber { MinValue = 0, MaxValue = 180, Precision = 1 }, - Instantaneous = true + TabbableContentContainer = this }, - repeatCountInput = new SliderWithTextBoxInput("Repeats:") + repeatCountInput = new FormSliderBar { + Caption = "Repeats", Current = new BindableNumber(1) { MinValue = 1, MaxValue = 10, Precision = 1 }, - Instantaneous = true + TabbableContentContainer = this }, - pointInput = new SliderWithTextBoxInput("Vertices:") + pointInput = new FormSliderBar { + Caption = "Vertices", Current = new BindableNumber(3) { MinValue = 3, MaxValue = 32, Precision = 1, }, - Instantaneous = true + TabbableContentContainer = this }, commitButton = new RoundedButton { diff --git a/osu.Game.Rulesets.Osu/Edit/PreciseMovementPopover.cs b/osu.Game.Rulesets.Osu/Edit/PreciseMovementPopover.cs index f3739ab445cc..caac51632b13 100644 --- a/osu.Game.Rulesets.Osu/Edit/PreciseMovementPopover.cs +++ b/osu.Game.Rulesets.Osu/Edit/PreciseMovementPopover.cs @@ -37,7 +37,7 @@ public partial class PreciseMovementPopover : OsuPopover private BindableNumber xBindable = null!; private BindableNumber yBindable = null!; - private SliderWithTextBoxInput xInput = null!; + private FormSliderBar xInput { get; set; } = null!; private OsuCheckbox relativeCheckbox = null!; public PreciseMovementPopover() @@ -52,31 +52,31 @@ private void load() { Width = 220, AutoSizeAxes = Axes.Y, - Spacing = new Vector2(20), + Spacing = new Vector2(5), Children = new Drawable[] { - xInput = new SliderWithTextBoxInput("X:") + xInput = new FormSliderBar { + Caption = "X", Current = xBindable = new BindableNumber { Precision = 1, }, - Instantaneous = true, - TabbableContentContainer = this, + TabbableContentContainer = this }, - new SliderWithTextBoxInput("Y:") + new FormSliderBar { + Caption = "Y", Current = yBindable = new BindableNumber { Precision = 1, }, - Instantaneous = true, - TabbableContentContainer = this, + TabbableContentContainer = this }, relativeCheckbox = new OsuCheckbox(false) { RelativeSizeAxes = Axes.X, - LabelText = "Relative movement", + LabelText = "Relative movement" } } }; diff --git a/osu.Game.Rulesets.Osu/Edit/PreciseRotationPopover.cs b/osu.Game.Rulesets.Osu/Edit/PreciseRotationPopover.cs index e2cde1a3258e..959963ed338c 100644 --- a/osu.Game.Rulesets.Osu/Edit/PreciseRotationPopover.cs +++ b/osu.Game.Rulesets.Osu/Edit/PreciseRotationPopover.cs @@ -28,7 +28,7 @@ public partial class PreciseRotationPopover : OsuPopover private readonly Bindable rotationInfo = new Bindable(new PreciseRotationInfo(0, EditorOrigin.GridCentre)); - private SliderWithTextBoxInput angleInput = null!; + private FormSliderBar angleInput { get; set; } = null!; private EditorRadioButtonCollection rotationOrigin = null!; private RadioButton gridCentreButton = null!; @@ -54,11 +54,12 @@ private void load(OsuConfigManager config) { Width = 220, AutoSizeAxes = Axes.Y, - Spacing = new Vector2(20), + Spacing = new Vector2(5), Children = new Drawable[] { - angleInput = new SliderWithTextBoxInput("Angle (degrees):") + angleInput = new FormSliderBar { + Caption = "Angle (degrees)", Current = new BindableNumber { MinValue = -360, @@ -66,7 +67,7 @@ private void load(OsuConfigManager config) Precision = 1 }, KeyboardStep = 1f, - Instantaneous = true + TabbableContentContainer = this }, rotationOrigin = new EditorRadioButtonCollection { diff --git a/osu.Game.Rulesets.Osu/Edit/PreciseScalePopover.cs b/osu.Game.Rulesets.Osu/Edit/PreciseScalePopover.cs index ca4a99b9cd78..88bf92ecb532 100644 --- a/osu.Game.Rulesets.Osu/Edit/PreciseScalePopover.cs +++ b/osu.Game.Rulesets.Osu/Edit/PreciseScalePopover.cs @@ -32,7 +32,7 @@ public partial class PreciseScalePopover : OsuPopover private readonly Bindable scaleInfo = new Bindable(new PreciseScaleInfo(1, EditorOrigin.GridCentre, true, true)); - private SliderWithTextBoxInput scaleInput = null!; + private FormSliderBar scaleInput { get; set; } = null!; private BindableNumber scaleInputBindable = null!; private EditorRadioButtonCollection scaleOrigin = null!; @@ -66,11 +66,12 @@ private void load(EditorBeatmap editorBeatmap, OsuConfigManager config) { Width = 220, AutoSizeAxes = Axes.Y, - Spacing = new Vector2(20), + Spacing = new Vector2(5), Children = new Drawable[] { - scaleInput = new SliderWithTextBoxInput("Scale:") + scaleInput = new FormSliderBar { + Caption = "Scale", Current = scaleInputBindable = new BindableNumber { MinValue = 0.05f, @@ -80,7 +81,7 @@ private void load(EditorBeatmap editorBeatmap, OsuConfigManager config) Default = 1, }, KeyboardStep = 0.01f, - Instantaneous = true + TabbableContentContainer = this }, scaleOrigin = new EditorRadioButtonCollection { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSliderWithTextBoxInput.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSliderWithTextBoxInput.cs deleted file mode 100644 index 06b9623508f5..000000000000 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSliderWithTextBoxInput.cs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Linq; -using NUnit.Framework; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Input; -using osu.Framework.Testing; -using osu.Game.Graphics.UserInterface; -using osu.Game.Graphics.UserInterfaceV2; -using osuTK.Input; - -namespace osu.Game.Tests.Visual.UserInterface -{ - public partial class TestSceneSliderWithTextBoxInput : OsuManualInputManagerTestScene - { - private SliderWithTextBoxInput sliderWithTextBoxInput = null!; - - private OsuSliderBar slider => sliderWithTextBoxInput.ChildrenOfType>().Single(); - private Nub nub => sliderWithTextBoxInput.ChildrenOfType().Single(); - private OsuTextBox textBox => sliderWithTextBoxInput.ChildrenOfType().Single(); - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("create slider", () => Child = sliderWithTextBoxInput = new SliderWithTextBoxInput("Test Slider") - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Width = 0.5f, - Current = new BindableFloat - { - MinValue = -5, - MaxValue = 5, - Precision = 0.2f - } - }); - } - - [Test] - public void TestNonInstantaneousMode() - { - AddStep("set instantaneous to false", () => sliderWithTextBoxInput.Instantaneous = false); - - AddStep("focus textbox", () => ((IFocusManager)InputManager).ChangeFocus(textBox)); - AddStep("change text", () => textBox.Text = "3"); - AddAssert("slider not moved", () => slider.Current.Value, () => Is.Zero); - AddAssert("current not changed", () => sliderWithTextBoxInput.Current.Value, () => Is.Zero); - - AddStep("commit text", () => InputManager.Key(Key.Enter)); - AddAssert("slider moved", () => slider.Current.Value, () => Is.EqualTo(3)); - AddAssert("current changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(3)); - - AddStep("move mouse to nub", () => InputManager.MoveMouseTo(nub)); - AddStep("hold left mouse", () => InputManager.PressButton(MouseButton.Left)); - AddStep("move mouse to minimum", () => InputManager.MoveMouseTo(sliderWithTextBoxInput.ScreenSpaceDrawQuad.BottomLeft)); - AddAssert("textbox not changed", () => textBox.Current.Value, () => Is.EqualTo("3")); - AddAssert("current not changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(3)); - - AddStep("release left mouse", () => InputManager.ReleaseButton(MouseButton.Left)); - AddAssert("textbox changed", () => textBox.Current.Value, () => Is.EqualTo("-5")); - AddAssert("current changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(-5)); - - AddStep("focus textbox", () => ((IFocusManager)InputManager).ChangeFocus(textBox)); - AddStep("set text to invalid", () => textBox.Text = "garbage"); - AddAssert("slider not moved", () => slider.Current.Value, () => Is.EqualTo(-5)); - AddAssert("current not changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(-5)); - - AddStep("commit text", () => InputManager.Key(Key.Enter)); - AddAssert("text restored", () => textBox.Text, () => Is.EqualTo("-5")); - AddAssert("slider not moved", () => slider.Current.Value, () => Is.EqualTo(-5)); - AddAssert("current not changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(-5)); - - AddStep("focus textbox", () => ((IFocusManager)InputManager).ChangeFocus(textBox)); - AddStep("set text to invalid", () => textBox.Text = "garbage"); - AddAssert("slider not moved", () => slider.Current.Value, () => Is.EqualTo(-5)); - AddAssert("current not changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(-5)); - - AddStep("lose focus", () => ((IFocusManager)InputManager).ChangeFocus(null)); - AddAssert("text restored", () => textBox.Text, () => Is.EqualTo("-5")); - AddAssert("slider not moved", () => slider.Current.Value, () => Is.EqualTo(-5)); - AddAssert("current not changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(-5)); - } - - [Test] - public void TestInstantaneousMode() - { - AddStep("set instantaneous to true", () => sliderWithTextBoxInput.Instantaneous = true); - - AddStep("focus textbox", () => ((IFocusManager)InputManager).ChangeFocus(textBox)); - AddStep("change text", () => textBox.Text = "3"); - AddAssert("slider moved", () => slider.Current.Value, () => Is.EqualTo(3)); - AddAssert("current changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(3)); - - AddStep("commit text", () => InputManager.Key(Key.Enter)); - AddAssert("slider not moved", () => slider.Current.Value, () => Is.EqualTo(3)); - AddAssert("current not changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(3)); - - AddStep("move mouse to nub", () => InputManager.MoveMouseTo(nub)); - AddStep("hold left mouse", () => InputManager.PressButton(MouseButton.Left)); - AddStep("move mouse to minimum", () => InputManager.MoveMouseTo(sliderWithTextBoxInput.ScreenSpaceDrawQuad.BottomLeft)); - AddAssert("textbox changed", () => textBox.Current.Value, () => Is.EqualTo("-5")); - AddAssert("current changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(-5)); - - AddStep("release left mouse", () => InputManager.ReleaseButton(MouseButton.Left)); - AddAssert("textbox not changed", () => textBox.Current.Value, () => Is.EqualTo("-5")); - AddAssert("current not changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(-5)); - - AddStep("focus textbox", () => ((IFocusManager)InputManager).ChangeFocus(textBox)); - AddStep("set text to invalid", () => textBox.Text = "garbage"); - AddAssert("slider not moved", () => slider.Current.Value, () => Is.EqualTo(-5)); - AddAssert("current not changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(-5)); - - AddStep("commit text", () => InputManager.Key(Key.Enter)); - AddAssert("text restored", () => textBox.Text, () => Is.EqualTo("-5")); - AddAssert("slider not moved", () => slider.Current.Value, () => Is.EqualTo(-5)); - AddAssert("current not changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(-5)); - - AddStep("focus textbox", () => ((IFocusManager)InputManager).ChangeFocus(textBox)); - AddStep("set text to invalid", () => textBox.Text = "garbage"); - AddAssert("slider not moved", () => slider.Current.Value, () => Is.EqualTo(-5)); - AddAssert("current not changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(-5)); - - AddStep("lose focus", () => ((IFocusManager)InputManager).ChangeFocus(null)); - AddAssert("text restored", () => textBox.Text, () => Is.EqualTo("-5")); - AddAssert("slider not moved", () => slider.Current.Value, () => Is.EqualTo(-5)); - AddAssert("current not changed", () => sliderWithTextBoxInput.Current.Value, () => Is.EqualTo(-5)); - } - } -} diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 84fda8ecc131..cc0e7d5052e9 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -134,6 +134,8 @@ public float KeyboardStep private readonly Bindable currentLanguage = new Bindable(); + public bool TakeFocus() => GetContainingFocusManager()?.ChangeFocus(textBox) == true; + public FormSliderBar() { LabelFormat ??= defaultLabelFormat; diff --git a/osu.Game/Graphics/UserInterfaceV2/SliderWithTextBoxInput.cs b/osu.Game/Graphics/UserInterfaceV2/SliderWithTextBoxInput.cs deleted file mode 100644 index 2fbe3ae89b1e..000000000000 --- a/osu.Game/Graphics/UserInterfaceV2/SliderWithTextBoxInput.cs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Numerics; -using System.Globalization; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Localisation; -using osu.Game.Overlays.Settings; -using osu.Game.Utils; -using Vector2 = osuTK.Vector2; - -namespace osu.Game.Graphics.UserInterfaceV2 -{ - public partial class SliderWithTextBoxInput : CompositeDrawable, IHasCurrentValue - where T : struct, INumber, IMinMaxValue - { - /// - /// A custom step value for each key press which actuates a change on this control. - /// - public float KeyboardStep - { - get => slider.KeyboardStep; - set => slider.KeyboardStep = value; - } - - public Bindable Current - { - get => slider.Current; - set => slider.Current = value; - } - - public CompositeDrawable TabbableContentContainer - { - set => textBox.TabbableContentContainer = value; - } - - private bool instantaneous; - - /// - /// Whether changes to the slider should instantaneously transfer to the text box (and vice versa). - /// If , the transfer will happen on text box commit (explicit, or implicit via focus loss), or on slider drag end. - /// - public bool Instantaneous - { - get => instantaneous; - set - { - instantaneous = value; - slider.TransferValueOnCommit = !instantaneous; - } - } - - private readonly SettingsSlider slider; - private readonly LabelledTextBox textBox; - - public SliderWithTextBoxInput(LocalisableString labelText) - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - - InternalChildren = new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(20), - Children = new Drawable[] - { - textBox = new LabelledTextBox - { - Label = labelText, - SelectAllOnFocus = true, - }, - slider = new SettingsSlider - { - TransferValueOnCommit = true, - RelativeSizeAxes = Axes.X, - } - } - }, - }; - - textBox.OnCommit += textCommitted; - textBox.Current.BindValueChanged(textChanged); - - Current.BindValueChanged(updateTextBoxFromSlider, true); - } - - public bool TakeFocus() => GetContainingFocusManager()?.ChangeFocus(textBox) == true; - - private bool updatingFromTextBox; - - private void textChanged(ValueChangedEvent change) - { - if (!instantaneous) return; - - tryUpdateSliderFromTextBox(); - } - - private void textCommitted(TextBox t, bool isNew) - { - tryUpdateSliderFromTextBox(); - - // If the attempted update above failed, restore text box to match the slider. - Current.TriggerChange(); - } - - private void tryUpdateSliderFromTextBox() - { - updatingFromTextBox = true; - - try - { - switch (slider.Current) - { - case Bindable bindableInt: - bindableInt.Value = int.Parse(textBox.Current.Value); - break; - - case Bindable bindableDouble: - bindableDouble.Value = double.Parse(textBox.Current.Value); - break; - - default: - slider.Current.Parse(textBox.Current.Value, CultureInfo.CurrentCulture); - break; - } - } - catch - { - // ignore parsing failures. - // sane state will eventually be restored by a commit (either explicit, or implicit via focus loss). - } - - updatingFromTextBox = false; - } - - private void updateTextBoxFromSlider(ValueChangedEvent _) - { - if (updatingFromTextBox) return; - - decimal decimalValue = decimal.CreateTruncating(slider.Current.Value); - textBox.Text = decimalValue.ToString($@"N{FormatUtils.FindPrecision(decimalValue)}"); - } - } -} diff --git a/osu.Game/Screens/Edit/Timing/EffectSection.cs b/osu.Game/Screens/Edit/Timing/EffectSection.cs index f9ef46023266..325d0cfaf6e8 100644 --- a/osu.Game/Screens/Edit/Timing/EffectSection.cs +++ b/osu.Game/Screens/Edit/Timing/EffectSection.cs @@ -11,21 +11,24 @@ namespace osu.Game.Screens.Edit.Timing { internal partial class EffectSection : Section { - private LabelledSwitchButton kiai = null!; + private FormCheckBox kiai = null!; - private SliderWithTextBoxInput scrollSpeedSlider = null!; + private FormSliderBar scrollSpeedSlider { get; set; } = null!; [BackgroundDependencyLoader] private void load() { Flow.AddRange(new Drawable[] { - kiai = new LabelledSwitchButton { Label = "Kiai Time" }, - scrollSpeedSlider = new SliderWithTextBoxInput("Scroll Speed") + kiai = new FormCheckBox { Caption = "Kiai Time" }, + scrollSpeedSlider = new FormSliderBar { + Caption = "Scroll Speed", Current = new EffectControlPoint().ScrollSpeedBindable, - KeyboardStep = 0.1f - } + KeyboardStep = 0.1f, + TransferValueOnCommit = true, + TabbableContentContainer = this + }, }); } diff --git a/osu.Game/Screens/Edit/Timing/IndeterminateSliderWithTextBoxInput.cs b/osu.Game/Screens/Edit/Timing/IndeterminateSliderWithTextBoxInput.cs index 00cf2e349357..0e7b4767a743 100644 --- a/osu.Game/Screens/Edit/Timing/IndeterminateSliderWithTextBoxInput.cs +++ b/osu.Game/Screens/Edit/Timing/IndeterminateSliderWithTextBoxInput.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.Edit.Timing { /// - /// Analogous to , but supports scenarios + /// Analogous to SliderWithTextBoxInput, but supports scenarios /// where multiple objects with multiple different property values are selected /// by providing an "indeterminate state". /// From 06b89919be0366bc58426e7c2082d88fa5ab8fbe Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Fri, 16 Jan 2026 16:58:20 +0300 Subject: [PATCH 491/836] Add localisation support for some more notifications (#36353) Co-authored-by: Dean Herbert --- .../Security/ElevatedPrivilegesChecker.cs | 3 +- osu.Game/Database/LegacyBeatmapExporter.cs | 5 +- osu.Game/Database/LegacyExporter.cs | 5 +- osu.Game/Graphics/ScreenshotManager.cs | 3 +- osu.Game/Localisation/NotificationsStrings.cs | 50 +++++++++++++++++++ .../Multiplayer/ServerShutdownNotification.cs | 5 +- .../Sections/General/QuickActionSettings.cs | 4 +- .../AddPlaylistToCollectionButton.cs | 9 +++- 8 files changed, 72 insertions(+), 12 deletions(-) diff --git a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs b/osu.Desktop/Security/ElevatedPrivilegesChecker.cs index 4b6ebc9b5675..1ac0a8153a3c 100644 --- a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs +++ b/osu.Desktop/Security/ElevatedPrivilegesChecker.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; +using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; @@ -32,7 +33,7 @@ private partial class ElevatedPrivilegesNotification : SimpleNotification { public ElevatedPrivilegesNotification() { - Text = $"Running osu! as {(RuntimeInfo.IsUnix ? "root" : "administrator")} does not improve performance, may break integrations and poses a security risk. Please run the game as a normal user."; + Text = NotificationsStrings.ElevatedPrivileges(RuntimeInfo.IsUnix ? "root" : "Administrator"); } [BackgroundDependencyLoader] diff --git a/osu.Game/Database/LegacyBeatmapExporter.cs b/osu.Game/Database/LegacyBeatmapExporter.cs index 7587c2332fa0..0ddce163559d 100644 --- a/osu.Game/Database/LegacyBeatmapExporter.cs +++ b/osu.Game/Database/LegacyBeatmapExporter.cs @@ -13,6 +13,7 @@ using osu.Game.Beatmaps.Timing; using osu.Game.Extensions; using osu.Game.IO; +using osu.Game.Localisation; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; @@ -198,7 +199,7 @@ public Task ExportAsync(Live beatmap) => Task.Run(() => ProgressNotification notification = new ProgressNotification { State = ProgressNotificationState.Active, - Text = $"Exporting {itemFilename}...", + Text = NotificationsStrings.FileExportOngoing(itemFilename), }; PostNotification?.Invoke(notification); @@ -225,7 +226,7 @@ public Task ExportAsync(Live beatmap) => Task.Run(() => throw; } - notification.CompletionText = $"Exported {itemFilename}! Click to view."; + notification.CompletionText = NotificationsStrings.FileExportFinished(itemFilename); notification.CompletionClickAction = () => ExportStorage.PresentFileExternally(filename); notification.State = ProgressNotificationState.Completed; }); diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index cc0fd8f8a2ae..eec6bf9341b0 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -10,6 +10,7 @@ using osu.Framework.Platform; using osu.Game.Extensions; using osu.Game.IO; +using osu.Game.Localisation; using osu.Game.Overlays.Notifications; using osu.Game.Utils; using Realms; @@ -83,7 +84,7 @@ public async Task ExportAsync(Live model, CancellationToken cancellation ProgressNotification notification = new ProgressNotification { State = ProgressNotificationState.Active, - Text = $"Exporting {itemFilename}...", + Text = NotificationsStrings.FileExportOngoing(itemFilename), }; PostNotification?.Invoke(notification); @@ -106,7 +107,7 @@ public async Task ExportAsync(Live model, CancellationToken cancellation throw; } - notification.CompletionText = $"Exported {itemFilename}! Click to view."; + notification.CompletionText = NotificationsStrings.FileExportFinished(itemFilename); notification.CompletionClickAction = () => ExportStorage.PresentFileExternally(filename); notification.State = ProgressNotificationState.Completed; } diff --git a/osu.Game/Graphics/ScreenshotManager.cs b/osu.Game/Graphics/ScreenshotManager.cs index a085558b3a33..28795b579900 100644 --- a/osu.Game/Graphics/ScreenshotManager.cs +++ b/osu.Game/Graphics/ScreenshotManager.cs @@ -17,6 +17,7 @@ using osu.Framework.Threading; using osu.Game.Configuration; using osu.Game.Input.Bindings; +using osu.Game.Localisation; using osu.Game.Online.Multiplayer; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; @@ -169,7 +170,7 @@ public Task TakeScreenshotAsync() => Task.Run(async () => notificationOverlay.Post(new SimpleNotification { - Text = $"Screenshot {filename} saved!", + Text = NotificationsStrings.ScreenshotSaved(filename), Activated = () => { storage.PresentFileExternally(filename); diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 1d6b69a0075a..835dfef08e14 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -210,6 +210,56 @@ public static class NotificationsStrings /// public static LocalisableString ActionInterruptedByDialog => new TranslatableString(getKey(@"action_interrupted_by_dialog"), @"An action was interrupted due to a dialog being displayed."); + /// + /// "Exporting {0}..." + /// + public static LocalisableString FileExportOngoing(string filename) => new TranslatableString(getKey(@"file_export_ongoing"), @"Exporting {0}...", filename); + + /// + /// "Exported {0}! Click to view." + /// + public static LocalisableString FileExportFinished(string filename) => new TranslatableString(getKey(@"file_export_finished"), @"Exported {0}! Click to view.", filename); + + /// + /// "Exporting logs..." + /// + public static LocalisableString LogsExportOngoing => new TranslatableString(getKey(@"logs_export_ongoing"), @"Exporting logs..."); + + /// + /// "Exported logs! Click to view." + /// + public static LocalisableString LogsExportFinished => new TranslatableString(getKey(@"logs_export_finished"), @"Exported logs! Click to view."); + + /// + /// "Running osu! as {0} does not improve performance, may break integrations and poses a security risk. Please run the game as a normal user." + /// + public static LocalisableString ElevatedPrivileges(LocalisableString user) => new TranslatableString(getKey(@"elevated_privileges"), @"Running osu! as {0} does not improve performance, may break integrations and poses a security risk. Please run the game as a normal user.", user); + + /// + /// "Screenshot {0} saved!" + /// + public static LocalisableString ScreenshotSaved(string filename) => new TranslatableString(getKey(@"screenshot_saved"), @"Screenshot {0} saved!", filename); + + /// + /// "The multiplayer server will be right back..." + /// + public static LocalisableString MultiplayerServerShuttingDownImmediately => new TranslatableString(getKey(@"multiplayer_server_shutting_down_immediately"), @"The multiplayer server will be right back..."); + + /// + /// "The multiplayer server is restarting in {0}." + /// + public static LocalisableString MultiplayerServerShuttingDownRemaining(string remainingTime) => new TranslatableString(getKey(@"multiplayer_server_shutting_down_remaining"), @"The multiplayer server is restarting in {0}.", remainingTime); + + /// + /// "Created new collection "{0}" with {1} beatmaps." + /// + public static LocalisableString CollectionCreated(string name, int beatmapsCount) => new TranslatableString(getKey(@"collection_created"), @"Created new collection ""{0}"" with {1} beatmaps.", name, beatmapsCount); + + /// + /// "Added {0} beatmaps to collection "{1}"." + /// + public static LocalisableString CollectionBeatmapsAdded(string name, int beatmapsCount) => new TranslatableString(getKey(@"collection_beatmaps_added"), @"Added {0} beatmaps to collection ""{1}"".", beatmapsCount, name); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs b/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs index 1de18e44a758..5a6367b06b33 100644 --- a/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs +++ b/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs @@ -5,6 +5,7 @@ using Humanizer.Localisation; using osu.Framework.Allocation; using osu.Framework.Threading; +using osu.Game.Localisation; using osu.Game.Overlays.Notifications; using osu.Game.Utils; @@ -53,10 +54,10 @@ private void updateTime() if (remaining.TotalSeconds <= 5) { updateDelegate?.Cancel(); - Text = "The multiplayer server will be right back..."; + Text = NotificationsStrings.MultiplayerServerShuttingDownImmediately; } else - Text = $"The multiplayer server is restarting in {HumanizerUtils.Humanize(remaining, precision: 3, minUnit: TimeUnit.Second)}."; + Text = NotificationsStrings.MultiplayerServerShuttingDownRemaining(HumanizerUtils.Humanize(remaining, precision: 3, minUnit: TimeUnit.Second)); } } } diff --git a/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs index b6b78a6d00f4..d01a63f87ab9 100644 --- a/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs @@ -84,7 +84,7 @@ private void exportLogs() ProgressNotification notification = new ProgressNotification { State = ProgressNotificationState.Active, - Text = "Exporting logs...", + Text = NotificationsStrings.LogsExportOngoing, }; notifications?.Post(notification); @@ -116,7 +116,7 @@ private void exportLogs() throw; } - notification.CompletionText = "Exported logs! Click to view."; + notification.CompletionText = NotificationsStrings.LogsExportFinished; notification.CompletionClickAction = () => exportStorage.PresentFileExternally(archive_filename); notification.State = ProgressNotificationState.Completed; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/AddPlaylistToCollectionButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/AddPlaylistToCollectionButton.cs index 47629981f1cb..5a6878139709 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/AddPlaylistToCollectionButton.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/AddPlaylistToCollectionButton.cs @@ -10,6 +10,7 @@ using osu.Game.Collections; using osu.Game.Database; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Localisation; using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; @@ -69,10 +70,14 @@ private void load() countAfter = c.BeatmapMD5Hashes.Count; }).ContinueWith(_ => Schedule(() => { + LocalisableString message; + if (countBefore == 0) - notifications?.Post(new SimpleNotification { Text = $"Created new collection \"{room.Name}\" with {countAfter} beatmaps." }); + message = NotificationsStrings.CollectionCreated(room.Name, countAfter); else - notifications?.Post(new SimpleNotification { Text = $"Added {countAfter - countBefore} beatmaps to collection \"{room.Name}\"." }); + message = NotificationsStrings.CollectionBeatmapsAdded(room.Name, countAfter - countBefore); + + notifications?.Post(new SimpleNotification { Text = message }); })); }; } From 952fd0d493eb3cd9994ea8ff4e27b44e82c1f287 Mon Sep 17 00:00:00 2001 From: Krzysztof Gutkowski Date: Fri, 16 Jan 2026 16:38:00 +0100 Subject: [PATCH 492/836] Ensure diffcalc runs after mods get replaced during a ruleset change (#36359) --- .../SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs index 65e55ff27742..fc6ce0ac2069 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs +++ b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs @@ -206,8 +206,13 @@ protected override void LoadComplete() { base.LoadComplete(); - beatmap.BindValueChanged(_ => updateDisplay()); - ruleset.BindValueChanged(_ => updateDisplay()); + // it is not uncommon for the beatmap and the ruleset to change in conjunction during a single update frame. + // in that process, it is possible for the global bindable triad (beatmap / ruleset / mods) to briefly be partially invalid in combination (e.g. mods invalid for given ruleset). + // `updateDisplay()` will initiate a difficulty calculation, and if it is allowed to run in that invalid intermediate state, it will loudly fail. + // therefore, all changes that may initiate a difficulty calculation are debounced until the next frame to ensure the global bindable state is fully consistent - + // and it's what you'd want to do anyway for performance reasons. + beatmap.BindValueChanged(_ => Scheduler.AddOnce(updateDisplay)); + ruleset.BindValueChanged(_ => Scheduler.AddOnce(updateDisplay)); mods.BindValueChanged(m => { From b5a989d31ecea28b68da4ac1a35d2854c464eace Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Fri, 16 Jan 2026 12:54:12 -0500 Subject: [PATCH 493/836] Fix form dropdown open animation not being smooth (#36358) Preview: https://github.com/user-attachments/assets/07cb58b7-5980-4fed-bb4c-2443ba1e9635 --- .../Graphics/UserInterfaceV2/FormDropdown.cs | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index 91ea036ec6fa..9482f1f83114 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -40,6 +40,8 @@ public partial class FormDropdown : OsuDropdown, IFormControl private FormDropdownHeader header = null!; + private const float header_menu_spacing = 5; + [BackgroundDependencyLoader] private void load() { @@ -47,6 +49,10 @@ private void load() header.Caption = Caption; header.HintText = HintText; + + // there's bottom margin applied inside the header to give spacing between the header and the menu. + // however when the menu is closed the extra spacing remains present. to remove it, apply negative bottom padding here. + Margin = new MarginPadding { Bottom = -header_menu_spacing }; } protected override void LoadComplete() @@ -145,6 +151,8 @@ private void load() Masking = true; CornerRadius = 5; + Margin = new MarginPadding { Bottom = header_menu_spacing }; + Foreground.Padding = new MarginPadding(9); Foreground.Children = new Drawable[] { @@ -278,11 +286,26 @@ private partial class FormDropdownMenu : OsuDropdownMenu private void load(OverlayColourProvider colourProvider) { ItemsContainer.Padding = new MarginPadding(9); - Margin = new MarginPadding { Top = 5 }; MaskingContainer.BorderThickness = 2; MaskingContainer.BorderColour = colourProvider.Highlight1; } + + protected override void AnimateOpen() + { + base.AnimateOpen(); + + // there's negative bottom margin applied on the whole dropdown control to remove extra spacing when the menu is closed. + // however, when the menu is open, we want spacing between the menu and the next control below it. therefore apply bottom margin here. + // we use a transform to keep the open animation smooth while margin is adjusted. + this.TransformTo(nameof(Margin), new MarginPadding { Bottom = header_menu_spacing }, 300, Easing.OutQuint); + } + + protected override void AnimateClose() + { + base.AnimateClose(); + this.TransformTo(nameof(Margin), new MarginPadding { Bottom = 0 }, 300, Easing.OutQuint); + } } } From 676b7a36da45c3d6a474ca4b274c615e6053da94 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Sat, 17 Jan 2026 02:39:28 -0500 Subject: [PATCH 494/836] Improve input handling in percentage-based slider bars (#36195) Reported in https://github.com/ppy/osu/pull/36193#issuecomment-3703406223. Preview: https://github.com/user-attachments/assets/ac2b86cf-ad92-496b-b3dd-19ad47753a9b --------- Co-authored-by: Dean Herbert --- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index cc0e7d5052e9..e2284918805b 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -330,7 +330,11 @@ private void tryUpdateSliderFromTextBox() break; case Bindable bindableDouble: - bindableDouble.Value = double.Parse(textBox.Current.Value); + bindableDouble.Value = double.Parse(textBox.Current.Value) / (DisplayAsPercentage ? 100 : 1); + break; + + case Bindable bindableFloat: + bindableFloat.Value = float.Parse(textBox.Current.Value) / (DisplayAsPercentage ? 100 : 1); break; default: @@ -397,7 +401,18 @@ private void updateValueDisplay() { if (updatingFromTextBox) return; - textBox.Text = currentNumberInstantaneous.Value.ToStandardFormattedString(OsuSliderBar.MAX_DECIMAL_DIGITS); + if (DisplayAsPercentage) + { + double floatValue = double.CreateTruncating(currentNumberInstantaneous.Value); + + if (currentNumberInstantaneous.Value is int) + floatValue /= 100; + + textBox.Text = floatValue.ToStandardFormattedString(Math.Max(0, OsuSliderBar.MAX_DECIMAL_DIGITS - 2)); + } + else + textBox.Text = currentNumberInstantaneous.Value.ToStandardFormattedString(OsuSliderBar.MAX_DECIMAL_DIGITS); + valueLabel.Text = LabelFormat(currentNumberInstantaneous.Value); } From 7fc24c6566f96dc0859fd55a535518b2837a8b44 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Sat, 17 Jan 2026 09:30:37 +0000 Subject: [PATCH 495/836] Fix legacy score base multiplier being calculated using modded difficulty values (#36209) Fun correctness bug. ScoreV1 multiplier uses the **nomod** peppy stars (i.e the beatmap's "base" HP, OD and CS) in all cases, which was generally the intention with this code but it passes the wrong beatmap resulting in it using modded values for this. Cross referenced with stable and this now results in the expected multipliers. Results in some very minor (<3pp from my testing) changes for HR and EZ scores with combo breaks. --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index edaef0aa75cd..47be0ebfa4fc 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -97,7 +97,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat flashlightRating = osuRatingCalculator.ComputeFlashlightRating(flashlight.DifficultyValue()); double sliderNestedScorePerObject = LegacyScoreUtils.CalculateNestedScorePerObject(beatmap, totalHits); - double legacyScoreBaseMultiplier = LegacyScoreUtils.CalculateDifficultyPeppyStars(beatmap); + double legacyScoreBaseMultiplier = LegacyScoreUtils.CalculateDifficultyPeppyStars(WorkingBeatmap.Beatmap); var simulator = new OsuLegacyScoreSimulator(); var scoreAttributes = simulator.Simulate(WorkingBeatmap, beatmap); From eee88a39551ab9c439dfed647b756add50903a26 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Sat, 17 Jan 2026 17:15:46 +0300 Subject: [PATCH 496/836] Fix score tooltips being displayed when hovering mod status bar (#36332) - addresses https://github.com/ppy/osu/discussions/34079 - supersedes and closes https://github.com/ppy/osu/pull/34090 --- osu.Game/Screens/SelectV2/FooterButtonMods.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/SelectV2/FooterButtonMods.cs b/osu.Game/Screens/SelectV2/FooterButtonMods.cs index 13192df85d08..2da98790a7b1 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonMods.cs +++ b/osu.Game/Screens/SelectV2/FooterButtonMods.cs @@ -85,7 +85,7 @@ private void load() AddRange(new[] { unrankedBadge = new UnrankedBadge(), - modDisplayBar = new Container + modDisplayBar = new ModDisplayBarContainer { Y = -5f, Depth = float.MaxValue, @@ -343,6 +343,13 @@ public void SetContent(IReadOnlyList content) } } + internal partial class ModDisplayBarContainer : Container + { + protected override bool OnMouseDown(MouseDownEvent e) => true; + + protected override bool OnHover(HoverEvent e) => true; + } + internal partial class UnrankedBadge : CompositeDrawable, IHasTooltip { public LocalisableString TooltipText { get; } @@ -386,6 +393,10 @@ private void load(OsuColour colours) } }; } + + protected override bool OnMouseDown(MouseDownEvent e) => true; + + protected override bool OnHover(HoverEvent e) => true; } } } From cda52cdae80cfac6a96088a2e6eb01ba9ad1998a Mon Sep 17 00:00:00 2001 From: kwotaq <80002984+kwotaq@users.noreply.github.com> Date: Sun, 18 Jan 2026 15:56:23 +0200 Subject: [PATCH 497/836] Add comment for wiggle bonus multiplier (#36373) It's a common mistake by newer pp dev contributors to increase the wiggle multiplier not knowing its at its maximum, so I added a comment to try to avoid more people doing it. --------- Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com> --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index dcf8ac0fedbd..d311bcf93dde 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -15,7 +15,7 @@ public static class AimEvaluator private const double acute_angle_multiplier = 2.55; private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; - private const double wiggle_multiplier = 1.02; + private const double wiggle_multiplier = 1.02; // WARNING: Increasing this multiplier beyond 1.02 reduces difficulty as distance increases. Refer to the desmos link above the wiggle bonus calculation /// /// Evaluates the difficulty of aiming the current object, based on: From 7608ed4d87c6d5064592a73abfa8624848369e13 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 18 Jan 2026 20:31:48 -0800 Subject: [PATCH 498/836] Remove now unnecessary mobile hold hack when song select v2 wasn't default (#36384) This reverts commit 3931ae3499f42d3697a11ea3798dcfb1833131a2. --- osu.Game/Screens/Menu/MainMenuButton.cs | 10 ---------- osu.Game/Screens/Menu/OsuLogo.cs | 18 ++---------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenuButton.cs b/osu.Game/Screens/Menu/MainMenuButton.cs index 235babeed21b..f8824795d8b0 100644 --- a/osu.Game/Screens/Menu/MainMenuButton.cs +++ b/osu.Game/Screens/Menu/MainMenuButton.cs @@ -20,7 +20,6 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; -using osu.Framework.Input.StateChanges; using osu.Framework.Localisation; using osu.Game.Beatmaps.ControlPoints; @@ -258,15 +257,6 @@ protected override bool OnMouseDown(MouseDownEvent e) protected override void OnMouseUp(MouseUpEvent e) { - // HORRIBLE HACK - // This is here so that on mobile, the main menu button that progresses to song select can correctly progress to song select v2 when held. - // Once the temporary solution of holding the button to access song select v2 is removed, this should be too. - // Without this, the long-press-to-right-click flow intercepts the hold and converts it to a right click which would not trigger the button - // and therefore not progress to song select. - if (e.Button == MouseButton.Right && e.CurrentState.Mouse.LastSource is ISourcedFromTouch) - trigger(e); - // END OF HORRIBLE HACK - boxHoverLayer.FadeTo(0, 1000, Easing.OutQuint); base.OnMouseUp(e); } diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 1b3317b12d81..ecd52f95b473 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -17,7 +17,6 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Events; -using osu.Framework.Input.StateChanges; using osu.Framework.Utils; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Backgrounds; @@ -393,27 +392,12 @@ protected override bool OnMouseDown(MouseDownEvent e) protected override void OnMouseUp(MouseUpEvent e) { - // HORRIBLE HACK - // This is here so that on mobile, the logo can correctly progress from main menu to song select v2 when held. - // Once the temporary solution of holding the logo to access song select v2 is removed, this should be too. - // Without this, the long-press-to-right-click flow intercepts the hold and converts it to a right click which would not trigger the logo - // and therefore not progress to song select. - if (e.Button == MouseButton.Right && e.CurrentState.Mouse.LastSource is ISourcedFromTouch) - triggerClick(); - // END OF HORRIBLE HACK - if (e.Button != MouseButton.Left) return; logoBounceContainer.ScaleTo(1f, 500, Easing.OutElastic); } protected override bool OnClick(ClickEvent e) - { - triggerClick(); - return true; - } - - private void triggerClick() { flashLayer.ClearTransforms(); flashLayer.Alpha = 0.4f; @@ -425,6 +409,8 @@ private void triggerClick() sampleClickChannel = sampleClick.GetChannel(); sampleClickChannel.Play(); } + + return true; } protected override bool OnHover(HoverEvent e) From cf73f8f9e6c5b6b8cd3e73898ca978abd9f2a7ae Mon Sep 17 00:00:00 2001 From: MayoCollector Date: Mon, 19 Jan 2026 14:39:21 +0900 Subject: [PATCH 499/836] Localise "hold for menu" & "press for menu" in `HoldForMenuButton` (#36381) --- osu.Game/Localisation/UserInterfaceStrings.cs | 10 ++++++++++ osu.Game/Screens/Play/HUD/HoldForMenuButton.cs | 5 +++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index 9883ffe17326..08b6368571e4 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -174,6 +174,16 @@ public static class UserInterfaceStrings /// public static LocalisableString SelectedMods => new TranslatableString(getKey(@"selected_mods"), @"Selected Mods"); + /// + /// "hold for menu" + /// + public static LocalisableString HoldForMenu => new TranslatableString(getKey(@"hold_for_menu"), @"hold for menu"); + + /// + /// "press for menu" + /// + public static LocalisableString PressForMenu => new TranslatableString(getKey(@"press_for_menu"), @"press for menu"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 01314c5de6d1..2772e7514c07 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -21,6 +21,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Input.Bindings; +using osu.Game.Localisation; using osuTK; using osuTK.Graphics; @@ -93,8 +94,8 @@ protected override void LoadComplete() button.HoldActivationDelay.BindValueChanged(v => { text.Text = v.NewValue > 0 - ? "hold for menu" - : "press for menu"; + ? UserInterfaceStrings.HoldForMenu + : UserInterfaceStrings.PressForMenu; }, true); touchActive = sessionStatics.GetBindable(Static.TouchInputActive); From c0b644c90593b4e4e5fb2b6c02bae3ca793160f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Jan 2026 16:55:39 +0900 Subject: [PATCH 500/836] Fix osu! logo appearing in at new playlist song select screen after opening mod select (#36385) Closes https://github.com/ppy/osu/issues/36363. --- .../Playlists/PlaylistsSongSelectV2.cs | 18 ++---------------- osu.Game/Screens/SelectV2/SongSelect.cs | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs index 58d472fb993f..0431885d1fba 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs @@ -18,7 +18,6 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Footer; -using osu.Game.Screens.Menu; using osu.Game.Screens.SelectV2; using osu.Game.Utils; @@ -48,6 +47,8 @@ public PlaylistsSongSelectV2(Room room) { this.room = room; + ShowOsuLogo = false; + Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; LeftPadding = new MarginPadding { Top = CORNER_RADIUS_HIDE_OFFSET + Header.HEIGHT }; @@ -202,21 +203,6 @@ public override bool OnExiting(ScreenExitEvent e) return false; } - protected override void LogoArriving(OsuLogo logo, bool resuming) - { - // Intentionally not calling base so the logo isn't shown. - } - - protected override void LogoExiting(OsuLogo logo) - { - // Intentionally not calling base so the logo isn't shown. - } - - protected override void LogoSuspending(OsuLogo logo) - { - // Intentionally not calling base so the logo isn't shown. - } - public override IReadOnlyList CreateFooterButtons() { var buttons = base.CreateFooterButtons().ToList(); diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index b69fd8f89666..ecf8b3301bc9 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -93,6 +93,11 @@ public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBind /// protected bool ControlGlobalMusic { get; init; } = true; + /// + /// Whether the osu! logo should be shown at the bottom-right of the screen. + /// + protected bool ShowOsuLogo { get; init; } = true; + protected MarginPadding LeftPadding { get; init; } private ModSelectOverlay modSelectOverlay = null!; @@ -380,7 +385,8 @@ protected override void LoadComplete() if (!this.IsCurrentScreen()) return; - logo?.FadeTo(v.NewValue == Visibility.Visible ? 0f : 1f, 200, Easing.OutQuint); + if (ShowOsuLogo) + logo?.FadeTo(v.NewValue == Visibility.Visible ? 0f : 1f, 200, Easing.OutQuint); }); Beatmap.BindValueChanged(_ => @@ -755,6 +761,9 @@ protected override void LogoArriving(OsuLogo logo, bool resuming) { base.LogoArriving(logo, resuming); + if (!ShowOsuLogo) + return; + if (logo.Alpha > 0.8f && resuming) Footer?.StartTrackingLogo(logo, 400, Easing.OutQuint); else @@ -778,6 +787,10 @@ protected override void LogoArriving(OsuLogo logo, bool resuming) protected override void LogoSuspending(OsuLogo logo) { base.LogoSuspending(logo); + + if (!ShowOsuLogo) + return; + Footer?.StopTrackingLogo(); } @@ -785,6 +798,9 @@ protected override void LogoExiting(OsuLogo logo) { base.LogoExiting(logo); + if (!ShowOsuLogo) + return; + Footer?.StopTrackingLogo(); logo.ScaleTo(0.2f, 120, Easing.Out); From a60f262679206e7dd3ff0e8c56bc93e8c43aa36f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Jan 2026 09:26:22 +0100 Subject: [PATCH 501/836] Remove mention of no-longer-existent "good first issue" label It doesn't work in practice, because the skill baseline of an incoming "contributor" is so wildly variant that any issue that isn't explicitly a one-liner is automatically not suitable for *some* non-trivial subset of "new contributor". The label is also largely used by incoming contributors whose interests are not necessarily aligned with the project but instead appear to have other ulterior motives. --- CONTRIBUTING.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1d9861baf719..347e0f558a09 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -55,9 +55,7 @@ When in doubt, it's probably best to start with a discussion first. We will esca While pull requests from unaffiliated contributors are welcome, please note that due to significant community interest and limited review throughput, the core team's primary focus is on the issues which are currently [on the roadmap](https://github.com/orgs/ppy/projects/7/views/6). Reviewing PRs that fall outside of the scope of the roadmap is done on a best-effort basis, so please be aware that it may take a while before a core maintainer gets around to review your change. -The [issue tracker](https://github.com/ppy/osu/issues) should provide plenty of issues to start with. We also have a [`good first issue`](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label, although from experience it is not used very often, as it is relatively rare that we can spot an issue that will definitively be a good first issue for a new contributor regardless of their programming experience. - -In the case of simple issues, a direct PR is okay. However, if you decide to work on an existing issue which doesn't seem trivial, **please ask us first**. This way we can try to estimate if it is a good fit for you and provide the correct direction on how to address it. In addition, note that while we do not rule out external contributors from working on roadmapped issues, we will generally prefer to handle them ourselves unless they're not very time sensitive. +The [issue tracker](https://github.com/ppy/osu/issues) should provide plenty of issues to start with. In the case of simple issues, a direct PR is okay. However, if you decide to work on an existing issue which doesn't seem trivial, **please ask us first**. This way we can try to estimate if it is a good fit for you and provide the correct direction on how to address it. In addition, note that while we do not rule out external contributors from working on roadmapped issues, we will generally prefer to handle them ourselves unless they're not very time sensitive. If you'd like to propose a subjective change to one of the visual aspects of the game, or there is a bigger task you'd like to work on, but there is no corresponding issue or discussion thread yet for it, **please open a discussion or issue first** to avoid wasted effort. This in particular applies if you want to work on [one of the available designs from the osu! Figma master library](https://www.figma.com/file/VIkXMYNPMtQem2RJg9k2iQ/Master-Library). From e62a01cf773efc42be52cc0f5ca25ec4ceefe1e4 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 19 Jan 2026 18:34:00 +0900 Subject: [PATCH 502/836] Add metadata endpoint to refresh friend listing (#36386) Alternative to / closes https://github.com/ppy/osu/pull/36341 See also: https://github.com/ppy/osu-server-spectator/pull/415 This is a simple solution by adding a spectator endpoint to refresh the friend listing. A more complicated form of this is to make adding/removing friends only via spectator, but that would require osu-web changes too. --- osu.Game/Online/Metadata/IMetadataServer.cs | 5 +++++ osu.Game/Online/Metadata/MetadataClient.cs | 13 +++++++++++++ osu.Game/Online/Metadata/OnlineMetadataClient.cs | 9 +++++++++ .../Tests/Visual/Metadata/TestMetadataClient.cs | 2 ++ 4 files changed, 29 insertions(+) diff --git a/osu.Game/Online/Metadata/IMetadataServer.cs b/osu.Game/Online/Metadata/IMetadataServer.cs index 79ed8b5634a0..dc1d486b4a5d 100644 --- a/osu.Game/Online/Metadata/IMetadataServer.cs +++ b/osu.Game/Online/Metadata/IMetadataServer.cs @@ -53,5 +53,10 @@ public interface IMetadataServer /// Signals to the server that the current user would like to stop receiving updates about the state of the multiplayer room with the given . /// Task EndWatchingMultiplayerRoom(long id); + + /// + /// Refresh this user's friend listing. + /// + Task RefreshFriends(); } } diff --git a/osu.Game/Online/Metadata/MetadataClient.cs b/osu.Game/Online/Metadata/MetadataClient.cs index 0679191a52cb..e70fe6d3bb47 100644 --- a/osu.Game/Online/Metadata/MetadataClient.cs +++ b/osu.Game/Online/Metadata/MetadataClient.cs @@ -9,6 +9,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Users; @@ -21,6 +22,16 @@ public abstract partial class MetadataClient : Component, IMetadataClient, IMeta [Resolved] private IAPIProvider api { get; set; } = null!; + private readonly IBindableList localFriends = new BindableList(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + localFriends.BindTo(api.LocalUserState.Friends); + localFriends.BindCollectionChanged((_, _) => RefreshFriends().FireAndForget()); + } + #region Beatmap metadata updates public abstract Task GetChangesSince(int queueId); @@ -152,6 +163,8 @@ public void Dispose() public abstract Task EndWatchingMultiplayerRoom(long id); + public abstract Task RefreshFriends(); + public event Action? MultiplayerRoomScoreSet; Task IMetadataClient.MultiplayerRoomScoreSet(MultiplayerRoomScoreSetEvent roomScoreSetEvent) diff --git a/osu.Game/Online/Metadata/OnlineMetadataClient.cs b/osu.Game/Online/Metadata/OnlineMetadataClient.cs index 052b742beb2a..0853ccf9dfbd 100644 --- a/osu.Game/Online/Metadata/OnlineMetadataClient.cs +++ b/osu.Game/Online/Metadata/OnlineMetadataClient.cs @@ -288,6 +288,15 @@ public override async Task EndWatchingMultiplayerRoom(long id) Logger.Log($@"{nameof(OnlineMetadataClient)} stopped watching multiplayer room with ID {id}", LoggingTarget.Network); } + public override async Task RefreshFriends() + { + if (connector?.IsConnected.Value != true) + throw new OperationCanceledException(); + + Debug.Assert(connection != null); + await connection.InvokeAsync(nameof(IMetadataServer.RefreshFriends)).ConfigureAwait(false); + } + public override async Task DisconnectRequested() { await base.DisconnectRequested().ConfigureAwait(false); diff --git a/osu.Game/Tests/Visual/Metadata/TestMetadataClient.cs b/osu.Game/Tests/Visual/Metadata/TestMetadataClient.cs index dca1b0e46830..5ded0601df58 100644 --- a/osu.Game/Tests/Visual/Metadata/TestMetadataClient.cs +++ b/osu.Game/Tests/Visual/Metadata/TestMetadataClient.cs @@ -128,6 +128,8 @@ public override Task BeginWatchingMultiplayerRoo public override Task EndWatchingMultiplayerRoom(long id) => Task.CompletedTask; + public override Task RefreshFriends() => Task.CompletedTask; + public void Disconnect() { isConnected.Value = false; From 65f7037e84801df5bb39793feb7dd4fa783f8602 Mon Sep 17 00:00:00 2001 From: ArijanJ Date: Mon, 19 Jan 2026 12:51:21 +0100 Subject: [PATCH 503/836] Add skin cycling with shortcuts for next and previous skin --- .../Input/Bindings/GlobalActionContainer.cs | 8 ++ .../GlobalActionKeyBindingStrings.cs | 10 ++ osu.Game/Localisation/MenuTipStrings.cs | 10 ++ osu.Game/OsuGame.cs | 14 +++ .../Overlays/Settings/Sections/SkinSection.cs | 22 +--- osu.Game/Skinning/SkinManager.cs | 110 ++++++++++++++++++ 6 files changed, 155 insertions(+), 19 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 2aeb73d6c5f4..e342a4e6140f 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -105,6 +105,8 @@ public static IEnumerable GetGlobalActionsFor(GlobalActionCategory new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings), new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.R }, GlobalAction.RandomSkin), + new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.Down }, GlobalAction.NextSkin), + new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.Up }, GlobalAction.PreviousSkin), new KeyBinding(InputKey.F10, GlobalAction.ToggleGameplayMouseButtons), new KeyBinding(InputKey.F12, GlobalAction.TakeScreenshot), @@ -338,6 +340,12 @@ public enum GlobalAction [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.RandomSkin))] RandomSkin, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.NextSkin))] + NextSkin, + + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.PreviousSkin))] + PreviousSkin, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.TogglePauseReplay))] TogglePauseReplay, diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index 8536249d354c..8f0e6f5b323b 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -229,6 +229,16 @@ public static class GlobalActionKeyBindingStrings /// public static LocalisableString RandomSkin => new TranslatableString(getKey(@"random_skin"), @"Random skin"); + /// + /// "Next skin" + /// + public static LocalisableString NextSkin => new TranslatableString(getKey(@"next_skin"), @"Next skin"); + + /// + /// "Previous skin" + /// + public static LocalisableString PreviousSkin => new TranslatableString(getKey(@"previous_skin"), @"Previous skin"); + /// /// "Pause / resume replay" /// diff --git a/osu.Game/Localisation/MenuTipStrings.cs b/osu.Game/Localisation/MenuTipStrings.cs index ebab9f4d0285..69df795e87bc 100644 --- a/osu.Game/Localisation/MenuTipStrings.cs +++ b/osu.Game/Localisation/MenuTipStrings.cs @@ -104,6 +104,16 @@ public static class MenuTipStrings /// public static LocalisableString RandomSkinShortcut(LocalisableString keybind) => new TranslatableString(getKey(@"random_skin_shortcut"), @"Press {0} to switch to a random skin!", keybind); + /// + /// "Press {0} to go to the next skin!" + /// + public static LocalisableString NextSkinShortcut(LocalisableString keybind) => new TranslatableString(getKey(@"next_skin_shortcut"), @"Press {0} to go to the next skin!", keybind); + + /// + /// "Press {0} to go to the previous skin!" + /// + public static LocalisableString PreviousSkinShortcut(LocalisableString keybind) => new TranslatableString(getKey(@"previous_skin_shortcut"), @"Press {0} to go to the previous skin!", keybind); + /// /// "While watching a replay, press {0} to toggle replay settings!" /// diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f707f0d19828..634588d512c4 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1585,6 +1585,20 @@ public bool OnPressed(KeyBindingPressEvent e) SkinManager.SelectRandomSkin(); return true; + + case GlobalAction.NextSkin: + if (skinEditor.State.Value == Visibility.Visible) + return false; + + SkinManager.SelectNextSkin(); + return true; + + case GlobalAction.PreviousSkin: + if (skinEditor.State.Value == Visibility.Visible) + return false; + + SkinManager.SelectPreviousSkin(); + return true; } return false; diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 4d7c0117e2c4..0c8af4d845ef 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -44,12 +44,6 @@ public partial class SkinSection : SettingsSection public override IEnumerable FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { "skins" }); - private static readonly Live random_skin_info = new SkinInfo - { - ID = SkinInfo.RANDOM_SKIN, - Name = "", - }.ToLiveUnmanaged(); - private readonly List> dropdownItems = new List>(); [Resolved] @@ -105,7 +99,7 @@ protected override void LoadComplete() skinDropdown.Current.BindValueChanged(skin => { - if (skin.NewValue == random_skin_info) + if (skin.NewValue.ID == SkinInfo.RANDOM_SKIN) { // before selecting random, set the skin back to the previous selection. // this is done because at this point it will be random_skin_info, and would @@ -122,21 +116,11 @@ private void skinsChanged(IRealmCollection sender, ChangeSet changes) // Because we are using `Live<>` in this class, we don't need to worry about this scenario too much. if (!sender.Any()) return; - // For simplicity repopulate the full list. - // In the future we should change this to properly handle ChangeSet events. dropdownItems.Clear(); - dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.ARGON_SKIN).ToLive(realm)); - dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.ARGON_PRO_SKIN).ToLive(realm)); - dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.TRIANGLES_SKIN).ToLive(realm)); - dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.CLASSIC_SKIN).ToLive(realm)); - dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.RETRO_SKIN).ToLive(realm)); - - dropdownItems.Add(random_skin_info); - - foreach (var skin in sender.Where(s => !s.Protected)) - dropdownItems.Add(skin.ToLive(realm)); + var items = skins.GetDropdownItems().ToArray(); + dropdownItems.AddRange(items); Schedule(() => skinDropdown.Items = dropdownItems); } diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index e92d0d3d49a9..01bae6094d0e 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -130,6 +130,44 @@ public SkinManager(Storage storage, RealmAccess realm, GameHost host, IResourceS }; } + /// + /// Returns the dropdown ordering for use mainly by the skin selection UI. + /// Inserts the defaults first, then 'random skin', then custom ones. + /// Returns a list of items. + /// + public IEnumerable> GetDropdownItems() + { + var results = new List>(); + + Realm.Run(r => + { + var all = r.All() + .Where(s => !s.DeletePending) + .OrderBy(s => s.Name, StringComparer.OrdinalIgnoreCase) + .ToArray(); + + // add defaults in fixed order (assumes they exist in the DB) + results.Add(all.Single(s => s.ID == SkinInfo.ARGON_SKIN).ToLive(Realm)); + results.Add(all.Single(s => s.ID == SkinInfo.ARGON_PRO_SKIN).ToLive(Realm)); + results.Add(all.Single(s => s.ID == SkinInfo.TRIANGLES_SKIN).ToLive(Realm)); + results.Add(all.Single(s => s.ID == SkinInfo.CLASSIC_SKIN).ToLive(Realm)); + results.Add(all.Single(s => s.ID == SkinInfo.RETRO_SKIN).ToLive(Realm)); + + // random entry (unmanaged/live-unrelated) + results.Add(new SkinInfo + { + ID = SkinInfo.RANDOM_SKIN, + Name = "" + }.ToLiveUnmanaged()); + + // append remaining non-protected skins (keeping the ordering from the realm query) + foreach (var s in all.Where(s => !s.Protected)) + results.Add(s.ToLive(Realm)); + }); + + return results; + } + public void SelectRandomSkin() { Realm.Run(r => @@ -158,6 +196,78 @@ public void SelectRandomSkin() }); } + /// + /// Cycle through skins by a signed step count. + /// Uses the skin selection UI ordering but skips the "Random Skin" entry. + /// + /// Number of skins to move by (negative to move backwards). + public void CycleSkins(int step) + { + if (step == 0) + return; + + // don't change selection if current skin is externally disabled/mounted for editing. + if (CurrentSkinInfo.Disabled) + return; + + // Required local for iOS. Will cause runtime crash if inlined. + Guid currentSkinId = CurrentSkinInfo.Value.ID; + + var items = GetDropdownItems().ToArray(); + + if (items.Length == 0) + { + CurrentSkinInfo.Value = ArgonSkin.CreateInfo().ToLiveUnmanaged(); + return; + } + + int currentIndex = Array.FindIndex(items, s => s.ID == currentSkinId); + + int direction = Math.Sign(step); + int moves = Math.Abs(step); + + int idx = currentIndex >= 0 ? currentIndex : (direction > 0 ? -1 : 0); + + while (moves > 0) + { + if (direction > 0) + idx = (idx + 1) % items.Length; + else + idx = (idx - 1 + items.Length) % items.Length; + + // Skip random skin (confusing) + if (items[idx].ID == SkinInfo.RANDOM_SKIN) + continue; + + moves--; + } + + var nextId = items[idx].ID; + + // Retrieve the chosen skin from realm and set as current. + Realm.Run(r => + { + var chosen = r.Find(nextId); + if (chosen == null) + { + CurrentSkinInfo.Value = ArgonSkin.CreateInfo().ToLiveUnmanaged(); + return; + } + + CurrentSkinInfo.Value = chosen.ToLive(Realm); + }); + } + + /// + /// Cycle one skin backward. + /// + public void SelectPreviousSkin() => CycleSkins(-1); + + /// + /// Cycle one skin forward. + /// + public void SelectNextSkin() => CycleSkins(1); + /// /// Retrieve a instance for the provided /// From 763dbe149496eb643ddc91ce9d46fd7175b00f88 Mon Sep 17 00:00:00 2001 From: ArijanJ Date: Mon, 19 Jan 2026 13:34:25 +0100 Subject: [PATCH 504/836] Add blank line for codeinspect --- osu.Game/Skinning/SkinManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 01bae6094d0e..6239ce2b779a 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -248,6 +248,7 @@ public void CycleSkins(int step) Realm.Run(r => { var chosen = r.Find(nextId); + if (chosen == null) { CurrentSkinInfo.Value = ArgonSkin.CreateInfo().ToLiveUnmanaged(); From c1d9de7e832fcd8de03dffd985c01bd2cf50ab17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Jan 2026 14:21:20 +0100 Subject: [PATCH 505/836] Fix sample set index entry box crashing on bad input (#36390) closes https://github.com/ppy/osu/issues/36374 --- osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs b/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs index 750586dfe31b..b52d829bb0c5 100644 --- a/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs +++ b/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs @@ -120,7 +120,8 @@ private void load() }; numberBox.OnCommit += (_, _) => { - committedIndex = int.Parse(numberBox.Current.Value); + if (int.TryParse(numberBox.Current.Value, out int parsed)) + committedIndex = parsed; Hide(); }; } From 6d999a8d8e650c1b00dbccb4753fed7f29264643 Mon Sep 17 00:00:00 2001 From: iwa Date: Mon, 19 Jan 2026 17:14:02 +0100 Subject: [PATCH 506/836] refactor: rename HandleHotkeyPressed to HandleModHostkeyPressed to differentiate with presets handler --- osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs | 2 +- osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs | 2 +- osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs | 2 +- osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs | 2 +- osu.Game/Overlays/Mods/ModColumn.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs index bf58efc3399b..bc5914d41ef3 100644 --- a/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs @@ -37,7 +37,7 @@ public ClassicModHotkeyHandler(bool allowIncompatibleSelection) this.allowIncompatibleSelection = allowIncompatibleSelection; } - public bool HandleHotkeyPressed(KeyDownEvent e, IEnumerable availableMods) + public bool HandleModHotkeyPressed(KeyDownEvent e, IEnumerable availableMods) { if (!mod_type_lookup.TryGetValue(e.Key, out var typesToMatch)) return false; diff --git a/osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs index d2cc0e84d262..3dfda7609f47 100644 --- a/osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs @@ -17,6 +17,6 @@ public interface IModHotkeyHandler /// The event representing the user's keypress. /// The list of currently available mods. /// Whether the supplied event was handled as a mod selection/deselection. - bool HandleHotkeyPressed(KeyDownEvent e, IEnumerable availableMods); + bool HandleModHotkeyPressed(KeyDownEvent e, IEnumerable availableMods); } } diff --git a/osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs index 3f7a6298a1aa..7115ef16ff16 100644 --- a/osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs @@ -12,6 +12,6 @@ namespace osu.Game.Overlays.Mods.Input /// public class NoopModHotkeyHandler : IModHotkeyHandler { - public bool HandleHotkeyPressed(KeyDownEvent e, IEnumerable availableMods) => false; + public bool HandleModHotkeyPressed(KeyDownEvent e, IEnumerable availableMods) => false; } } diff --git a/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs index e6380634384c..610376de46bc 100644 --- a/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs @@ -42,7 +42,7 @@ private SequentialModHotkeyHandler(Key[] keys) toggleKeys = keys; } - public bool HandleHotkeyPressed(KeyDownEvent e, IEnumerable availableMods) + public bool HandleModHotkeyPressed(KeyDownEvent e, IEnumerable availableMods) { int index = Array.IndexOf(toggleKeys, e.Key); if (index < 0) diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index 7d2ce54074c4..d7ac8a9ff8e7 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -348,7 +348,7 @@ protected override bool OnKeyDown(KeyDownEvent e) if (e.ControlPressed || e.AltPressed || e.SuperPressed || e.Repeat) return false; - return hotkeyHandler.HandleHotkeyPressed(e, availableMods); + return hotkeyHandler.HandleModHotkeyPressed(e, availableMods); } #endregion From 6bf95068ae6357ac2784228a9a7790b07b889396 Mon Sep 17 00:00:00 2001 From: iwa Date: Mon, 19 Jan 2026 17:14:34 +0100 Subject: [PATCH 507/836] feat: expose a public Toggle method for ModPresetPanel --- osu.Game/Overlays/Mods/ModPresetPanel.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Overlays/Mods/ModPresetPanel.cs b/osu.Game/Overlays/Mods/ModPresetPanel.cs index 568ca5ecc90a..b5d9a8807587 100644 --- a/osu.Game/Overlays/Mods/ModPresetPanel.cs +++ b/osu.Game/Overlays/Mods/ModPresetPanel.cs @@ -53,6 +53,14 @@ protected override void LoadComplete() selectedMods.BindValueChanged(_ => selectedModsChanged(), true); } + public void Toggle() + { + if (!Active.Value) + Select(); + else + Deselect(); + } + protected override void Select() { // this implicitly presumes that if a system mod declares incompatibility with a non-system mod, From 91ee5eebc90238b6017b33b8c4d37c5dd7fd6bc3 Mon Sep 17 00:00:00 2001 From: iwa Date: Mon, 19 Jan 2026 17:15:15 +0100 Subject: [PATCH 508/836] feat: add logic to handle numeric hotkeys to select presets from mod select overlay --- .../Mods/Input/IPresetHotkeyHandler.cs | 19 +++++++++++++++ .../Mods/Input/SequentialModHotkeyHandler.cs | 24 +++++++++++++++++-- osu.Game/Overlays/Mods/ModPresetColumn.cs | 14 +++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Overlays/Mods/Input/IPresetHotkeyHandler.cs diff --git a/osu.Game/Overlays/Mods/Input/IPresetHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/IPresetHotkeyHandler.cs new file mode 100644 index 000000000000..5bcb43d162e5 --- /dev/null +++ b/osu.Game/Overlays/Mods/Input/IPresetHotkeyHandler.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Input.Events; + +namespace osu.Game.Overlays.Mods.Input +{ + public interface IPresetHotkeyHandler + { + /// + /// Attempt to handle the supplied as a selection of one of the presets in . + /// + /// The event representing the user's keypress. + /// The list of currently available presets. + /// Whether the supplied event was handled as a preset selection/deselection. + bool HandlePresetHotkeyPressed(KeyDownEvent e, IEnumerable availablePresets); + } +} diff --git a/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs index 610376de46bc..127d5722d104 100644 --- a/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs @@ -12,10 +12,10 @@ namespace osu.Game.Overlays.Mods.Input { /// /// This implementation of receives a sequence of s, - /// and maps the sequence of keys onto the items it is provided in . + /// and maps the sequence of keys onto the items it is provided in and . /// In this case, particular mods are not bound to particular keys, the hotkeys are a byproduct of mod ordering. /// - public class SequentialModHotkeyHandler : IModHotkeyHandler + public class SequentialModHotkeyHandler : IModHotkeyHandler, IPresetHotkeyHandler { public static SequentialModHotkeyHandler Create(ModType modType) { @@ -35,6 +35,11 @@ public static SequentialModHotkeyHandler Create(ModType modType) } } + public static SequentialModHotkeyHandler CreateForPresets() + { + return new SequentialModHotkeyHandler(new[] { Key.Number1, Key.Number2, Key.Number3, Key.Number4, Key.Number5, Key.Number6, Key.Number7, Key.Number8, Key.Number9, Key.Number0 }); + } + private readonly Key[] toggleKeys; private SequentialModHotkeyHandler(Key[] keys) @@ -55,5 +60,20 @@ public bool HandleModHotkeyPressed(KeyDownEvent e, IEnumerable availab modState.Active.Toggle(); return true; } + + public bool HandlePresetHotkeyPressed(KeyDownEvent e, IEnumerable availablePresets) + { + int index = Array.IndexOf(toggleKeys, e.Key); + if (index < 0) + return false; + + var panel = availablePresets.ElementAtOrDefault(index); + if (panel == null) + return false; + + panel.Toggle(); + + return true; + } } } diff --git a/osu.Game/Overlays/Mods/ModPresetColumn.cs b/osu.Game/Overlays/Mods/ModPresetColumn.cs index 0803389f4562..411b86af756e 100644 --- a/osu.Game/Overlays/Mods/ModPresetColumn.cs +++ b/osu.Game/Overlays/Mods/ModPresetColumn.cs @@ -8,9 +8,11 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Localisation; +using osu.Game.Overlays.Mods.Input; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osuTK; @@ -26,6 +28,8 @@ public partial class ModPresetColumn : ModSelectColumn [Resolved] private IBindable ruleset { get; set; } = null!; + private IPresetHotkeyHandler hotkeyHandler = null!; + private const float contracted_width = WIDTH - 120; [BackgroundDependencyLoader] @@ -37,6 +41,8 @@ private void load(OsuColour colours) AddPresetButton addPresetButton; ItemsFlow.Add(addPresetButton = new AddPresetButton()); ItemsFlow.SetLayoutPosition(addPresetButton, float.PositiveInfinity); + + hotkeyHandler = SequentialModHotkeyHandler.CreateForPresets(); } protected override void LoadComplete() @@ -95,6 +101,14 @@ void removeAndDisposePresetPanels() } } + protected override bool OnKeyDown(KeyDownEvent e) + { + if (e.ControlPressed || e.AltPressed || e.ShiftPressed || e.Repeat) + return false; + + return hotkeyHandler.HandlePresetHotkeyPressed(e, ItemsFlow.OfType()); + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); From 2a0bafde8ce020b3788c08b6a909cb7daf2848a9 Mon Sep 17 00:00:00 2001 From: iwa Date: Mon, 19 Jan 2026 22:07:32 +0100 Subject: [PATCH 509/836] fix: align OnKeyDown condition with existing from ModColumn --- osu.Game/Overlays/Mods/ModPresetColumn.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModPresetColumn.cs b/osu.Game/Overlays/Mods/ModPresetColumn.cs index 411b86af756e..35aff587fc3f 100644 --- a/osu.Game/Overlays/Mods/ModPresetColumn.cs +++ b/osu.Game/Overlays/Mods/ModPresetColumn.cs @@ -103,7 +103,7 @@ void removeAndDisposePresetPanels() protected override bool OnKeyDown(KeyDownEvent e) { - if (e.ControlPressed || e.AltPressed || e.ShiftPressed || e.Repeat) + if (e.ControlPressed || e.AltPressed || e.SuperPressed || e.Repeat) return false; return hotkeyHandler.HandlePresetHotkeyPressed(e, ItemsFlow.OfType()); From dfa7ac20828d1c20d26d24ebff6a824aa1cad0fc Mon Sep 17 00:00:00 2001 From: Linus Genz Date: Tue, 20 Jan 2026 08:51:23 +0100 Subject: [PATCH 510/836] Specialise mod setting hover text in song select scoreboard (#36391) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resolves #35992 **Changes** Introduced GetSettingTooltipText, which returns the value of the respective setting. The function can be overwritten, allowing to implement specific behavior. This allows you to define that a value of 0 for the “Muted” mod will instead display “always muted.” In the same step, I also adjusted the "NoScope" mod, where we had the same problem. Wherever we want to implement specialization like this, we can simply overwrite GetSettingTooltipText to customize the behavior for the mod settings of the mod. **Result** 2026-01-19-122307_hyprshot 2026-01-19-122324_hyprshot 2026-01-19-155307_hyprshot Signed-off-by: Linus Genz --- osu.Game/Rulesets/Mods/Mod.cs | 29 +++++++++++++++------------- osu.Game/Rulesets/Mods/ModMuted.cs | 15 +++++++++++++- osu.Game/Rulesets/Mods/ModNoScope.cs | 15 +++++++++++++- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index 477372b97dcc..79db2817eca0 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -59,21 +59,24 @@ public abstract class Mod : IMod, IEquatable, IDeepCloneable if (bindable.IsDefault) continue; - string valueText; - - switch (bindable) - { - case Bindable b: - valueText = b.Value ? "On" : "Off"; - break; + yield return (attr.Label, GetSettingTooltipText(bindable)); + } + } + } - default: - valueText = bindable.ToString() ?? string.Empty; - break; - } + /// + /// Gets the tooltip text for a specific mod setting. + /// Can be overridden to provide custom formatting for specific settings. + /// + protected virtual LocalisableString GetSettingTooltipText(IBindable bindable) + { + switch (bindable) + { + case Bindable b: + return b.Value ? "On" : "Off"; - yield return (attr.Label, valueText); - } + default: + return bindable.ToString() ?? string.Empty; } } diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 933e7f409300..094c476e871b 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -96,10 +96,23 @@ public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) } public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; + + protected override LocalisableString GetSettingTooltipText(IBindable bindable) + { + if (ReferenceEquals(bindable, MuteComboCount)) + return MuteComboSlider.FormatMuteComboValue(MuteComboCount.Value); + + return base.GetSettingTooltipText(bindable); + } } public partial class MuteComboSlider : RoundedSliderBar { - public override LocalisableString TooltipText => Current.Value == 0 ? "always muted" : base.TooltipText; + public override LocalisableString TooltipText => FormatMuteComboValue(Current.Value); + + public static LocalisableString FormatMuteComboValue(int value) + { + return value == 0 ? "always muted" : value.ToString(); + } } } diff --git a/osu.Game/Rulesets/Mods/ModNoScope.cs b/osu.Game/Rulesets/Mods/ModNoScope.cs index d0c9da669b04..bcbef8287c20 100644 --- a/osu.Game/Rulesets/Mods/ModNoScope.cs +++ b/osu.Game/Rulesets/Mods/ModNoScope.cs @@ -62,10 +62,23 @@ public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) ComboBasedAlpha = Math.Max(MIN_ALPHA, 1 - (float)combo.NewValue / HiddenComboCount.Value); }, true); } + + protected override LocalisableString GetSettingTooltipText(IBindable bindable) + { + if (ReferenceEquals(bindable, HiddenComboCount)) + return HiddenComboSlider.FormatHiddenComboValue(HiddenComboCount.Value); + + return base.GetSettingTooltipText(bindable); + } } public partial class HiddenComboSlider : RoundedSliderBar { - public override LocalisableString TooltipText => Current.Value == 0 ? "always hidden" : base.TooltipText; + public override LocalisableString TooltipText => FormatHiddenComboValue(Current.Value); + + public static LocalisableString FormatHiddenComboValue(int value) + { + return value == 0 ? "always hidden" : value.ToString(); + } } } From 4ee4aac70835cc08d48bffbbe9825ce36e52045b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 20 Jan 2026 09:10:40 +0100 Subject: [PATCH 511/836] Fix changing combo colours in beatmap without custom samples opening new sample set popover (#36400) Reported [on reddit of all places](https://www.reddit.com/r/osugame/comments/1qhnfdn/every_time_i_make_an_adjustment_to_the_hitcircle/). The reason that this is happening is as follows: - Changing a combo colour raises `BeatmapSkinChanged` - `BeatmapSkinChanged` getting raised triggers the sample chooser dropdown to repopulate its items (as intended and correctly) - Setting items of a dropdown can also change its `Current.Value`, because the relevant logic attempts to ensure that `Current.Value` is valid in line with the new items - Therefore the `Current.Value` of the dropdown changes from `null` to sample set `-1` which corresponds to the "Add new..." item as it's the only item in the dropdown... - which is indistinguishable from the sequence of events that happens if the user manually opens the dropdown and clicks the "Add new..." item. This change sidesteps this entire car crash by just ensuring that even beatmaps without custom samples have at least set number 1 initialised (even if it's empty and has no samples). This means that the initial value of the dropdown is never `null`, and that every time that the value changes to the set `-1` it actually is due to user action. Should have known better than to play these dumb games. --- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 5 ++++- osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 8992211ace3c..68a5167e2e80 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -101,7 +101,10 @@ public IEnumerable GetAvailableSampleSets() string[] possiblePrefixes = possibleSounds.SelectMany(sound => possibleBanks.Select(bank => $@"{bank}-{sound}")).ToArray(); - Dictionary sampleSets = new Dictionary(); + Dictionary sampleSets = new Dictionary + { + [1] = new SampleSet(1), + }; if (Skin.Samples != null) { diff --git a/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs b/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs index b52d829bb0c5..659fc6ff7f84 100644 --- a/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs +++ b/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs @@ -39,7 +39,7 @@ protected override void LoadComplete() if (beatmapSkin != null) beatmapSkin.BeatmapSkinChanged += populateItems; - Current.Value = Items.FirstOrDefault(i => i?.SampleSetIndex > 0); + Current.Value = Items.First(i => i?.SampleSetIndex > 0); Current.BindValueChanged(val => { if (val.NewValue?.SampleSetIndex == -1) @@ -49,7 +49,7 @@ protected override void LoadComplete() private void populateItems() { - var items = beatmapSkin?.GetAvailableSampleSets().ToList() ?? []; + var items = beatmapSkin?.GetAvailableSampleSets().ToList() ?? [new EditorBeatmapSkin.SampleSet(1)]; items.Add(new EditorBeatmapSkin.SampleSet(-1, "Add new...")); Items = items; } From 741620d89c62ffb3962cfd0469fb86466ad282e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Jan 2026 17:41:10 +0900 Subject: [PATCH 512/836] Fix skin saving crashing if hashable files are not present This ends up with a bit of an undefined behaviour, but it's already a bit of an edge case (files missing in the `files` folder that are references in the database). First and foremost, let's stop the exception. If we allow it to throw, it's impossible to exit the skin editor in this state. Closes https://github.com/ppy/osu/issues/36135. --- osu.Game/Database/RealmArchiveModelImporter.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index aefb62842210..af57d5ec5b3c 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -474,8 +474,10 @@ public string ComputeHash(TModel item) foreach (RealmNamedFileUsage file in item.Files.Where(f => HashableFileTypes.Any(ext => f.Filename.EndsWith(ext, StringComparison.OrdinalIgnoreCase))).OrderBy(f => f.Filename)) { - using (Stream s = Files.Store.GetStream(file.File.GetStoragePath())) - s.CopyTo(hashable); + using (Stream? s = Files.Store.GetStream(file.File.GetStoragePath())) + { + s?.CopyTo(hashable); + } } if (hashable.Length > 0) From 76f05a4837e3da5d912d629735d1adb6f755fcc8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Jan 2026 19:15:57 +0900 Subject: [PATCH 513/836] Add failing test showing incorrect behaviour on random select with collapsed groups --- .../Visual/SongSelectV2/BeatmapCarouselTestScene.cs | 1 + .../TestSceneBeatmapCarouselArtistGrouping.cs | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs b/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs index 02c017f57054..d961946c0428 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs @@ -222,6 +222,7 @@ protected void SelectPrevGroup() => AddStep("select prev group", () => protected void SelectPrevPanel() => AddStep("select prev panel", () => InputManager.Key(Key.Up)); protected void SelectNextSet() => AddStep("select next set", () => InputManager.Key(Key.Right)); protected void SelectPrevSet() => AddStep("select prev set", () => InputManager.Key(Key.Left)); + protected void SelectRandomSet() => AddStep("select random set", () => Carousel.NextRandom()); protected void Select() => AddStep("select", () => InputManager.Key(Key.Enter)); diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs index 2390261cdbc6..2829364c686f 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs @@ -253,6 +253,19 @@ public void TestBasicFiltering() CheckDisplayedBeatmapsCount(30); } + [Test] + public void TestGroupDoesExpandAfterRandomTraversal() + { + SelectNextSet(); + + ToggleGroupCollapse(); + AddAssert("group not expanded", () => Carousel.ExpandedGroup, () => Is.Null); + + SelectRandomSet(); + + AddAssert("group expanded", () => Carousel.ExpandedGroup, () => Is.Not.Null); + } + [Test] public void TestGroupDoesNotExpandAgainOnRefilterIfManuallyCollapsed() { From fdf9092f4143270964eb08ff9de182480b4fc167 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Jan 2026 19:14:59 +0900 Subject: [PATCH 514/836] Revert "Fix current beatmap set being incorrectly expanded after collapsing group with current selection" This reverts commit 9ba99660786a2c25e73c866d70a492576ca02cac. --- osu.Game/Screens/SelectV2/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index 4519e594c6f1..79acfb5f9e3a 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -378,7 +378,7 @@ protected override void HandleItemActivated(CarouselItem item) if (userCollapsedGroup) { - if (grouping.BeatmapSetsGroupedTogether && CurrentGroupedBeatmap != null && CheckModelEquality(group, CurrentGroupedBeatmap.Group)) + if (grouping.BeatmapSetsGroupedTogether && CurrentGroupedBeatmap != null) setExpandedSet(new GroupedBeatmapSet(CurrentGroupedBeatmap.Group, CurrentGroupedBeatmap.Beatmap.BeatmapSet!)); userCollapsedGroup = false; } From 8c86ff36a26523f38cfab74c0606aaa8550dc240 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Jan 2026 19:15:21 +0900 Subject: [PATCH 515/836] Revert "Do not forcibly re-expand carousel groups on refilters if the user manually collapsed them" This reverts commit bc4d5d07d7b70a793c2d3fc32c3cef3f645d3676. --- osu.Game/Screens/SelectV2/BeatmapCarousel.cs | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index 79acfb5f9e3a..e17fbafd646e 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -352,12 +352,6 @@ public BeatmapInfo? CurrentBeatmap } } - /// - /// Tracks whether the user has manually requested to collapse an open group. - /// In this case, refilters should not forcibly expand groups until the user expands a group again themselves. - /// - private bool userCollapsedGroup; - protected override void HandleItemActivated(CarouselItem item) { try @@ -370,19 +364,11 @@ protected override void HandleItemActivated(CarouselItem item) { setExpansionStateOfGroup(ExpandedGroup, false); ExpandedGroup = null; - userCollapsedGroup = true; return; } setExpandedGroup(group); - if (userCollapsedGroup) - { - if (grouping.BeatmapSetsGroupedTogether && CurrentGroupedBeatmap != null) - setExpandedSet(new GroupedBeatmapSet(CurrentGroupedBeatmap.Group, CurrentGroupedBeatmap.Beatmap.BeatmapSet!)); - userCollapsedGroup = false; - } - // If the active selection is within this group, it should get keyboard focus immediately. if (CurrentSelectionItem?.IsVisible == true && CurrentSelection is GroupedBeatmap gb) RequestSelection(gb); @@ -421,9 +407,6 @@ protected override void HandleItemSelected(object? model) throw new InvalidOperationException("Groups should never become selected"); case GroupedBeatmap groupedBeatmap: - if (userCollapsedGroup) - break; - setExpandedGroup(groupedBeatmap.Group); if (grouping.BeatmapSetsGroupedTogether) @@ -798,9 +781,6 @@ public void Filter(FilterCriteria criteria, bool showLoadingImmediately = false) Criteria = criteria; - if (criteria.Group == GroupMode.None) - userCollapsedGroup = false; - loadingDebounce ??= Scheduler.AddDelayed(() => { if (loading.State.Value == Visibility.Visible) From 8860eec9f9bf9972f1cacd005df64ba02f1a72ea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Jan 2026 19:20:44 +0900 Subject: [PATCH 516/836] Handle expand set logic locally rather than calling `HandleItemSelected` This avoids the implicit group expansion happening that the added code was attempting to fix. --- osu.Game/Screens/SelectV2/BeatmapCarousel.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index e17fbafd646e..e0f46af4099e 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -32,7 +32,6 @@ using osu.Game.Rulesets; using osu.Game.Scoring; using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Filter; using Realms; namespace osu.Game.Screens.SelectV2 @@ -495,8 +494,9 @@ protected override void HandleFilterCompleted() if (groupingRemainsOff || groupStillValid) { - // Only update the visual state of the selected item. - HandleItemSelected(currentGroupedBeatmap); + // Update the visual state of the selected item if it should still be expanded post filter. + if (currentGroupedBeatmap != null && currentGroupedBeatmap.Group == groupForReselection) + setExpandedSet(new GroupedBeatmapSet(currentGroupedBeatmap.Group, currentGroupedBeatmap.Beatmap.BeatmapSet!)); } else if (currentGroupedBeatmap != null) { From 46b2d5374eceedfde35bc172af0137495189f4fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Jan 2026 19:36:21 +0900 Subject: [PATCH 517/836] Refactor `HandleFilterCompleted` to (hopefully) be easier to parse This is not required to fix the issue, but it is required for my brain to follow the method to some degress. --- osu.Game/Screens/SelectV2/BeatmapCarousel.cs | 53 +++++++++----------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index e0f46af4099e..72d59c62f7bc 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -482,40 +482,37 @@ protected override void HandleFilterCompleted() attemptSelectSingleFilteredResult(); - // Store selected group before handling selection (it may implicitly change the expanded group). - var groupForReselection = ExpandedGroup; - - var currentGroupedBeatmap = CurrentSelection as GroupedBeatmap; - - // The filter might have changed the set of available groups, which means that the current selection may point to a stale group. - // Check whether that is the case. - bool groupingRemainsOff = currentGroupedBeatmap?.Group == null && grouping.GroupItems.Count == 0; - bool groupStillValid = currentGroupedBeatmap?.Group != null && grouping.ItemMap.ContainsKey(currentGroupedBeatmap); - - if (groupingRemainsOff || groupStillValid) + if (CurrentSelection is GroupedBeatmap selection) { - // Update the visual state of the selected item if it should still be expanded post filter. - if (currentGroupedBeatmap != null && currentGroupedBeatmap.Group == groupForReselection) - setExpandedSet(new GroupedBeatmapSet(currentGroupedBeatmap.Group, currentGroupedBeatmap.Beatmap.BeatmapSet!)); - } - else if (currentGroupedBeatmap != null) - { - // If the group no longer exists (or the item no longer exists in the previous group), grab an arbitrary other instance of the beatmap under the first group encountered. - var newSelection = GetCarouselItems()?.Select(i => i.Model).OfType().FirstOrDefault(gb => gb.Beatmap.Equals(currentGroupedBeatmap.Beatmap)); + // The filter might have changed the set of available groups, which means that the current selection may point to a stale group. + // Check whether that is the case. + bool groupingRemainsOff = selection.Group == null && grouping.GroupItems.Count == 0; + bool groupStillValid = selection.Group != null && grouping.ItemMap.ContainsKey(selection); - // Only change the selection if we actually got a positive hit. - // This is necessary so that selection isn't lost if the panel reappears later due to e.g. unapplying some filter criteria that made it disappear in the first place. - if (newSelection != null) + if (groupingRemainsOff || groupStillValid) + { + if (selection.Group == ExpandedGroup) + { + // Update the visual state of the selected item if it should still be expanded post filter. + HandleItemSelected(CurrentSelection); + } + } + else { - CurrentSelection = newSelection; - groupForReselection = newSelection.Group; + // If the group no longer exists (or the item no longer exists in the previous group), grab an arbitrary other instance of the beatmap under the first group encountered. + var newSelection = GetCarouselItems()?.Select(i => i.Model).OfType().FirstOrDefault(gb => gb.Beatmap.Equals(selection.Beatmap)); + + // Only change the selection if we actually got a positive hit. + // This is necessary so that selection isn't lost if the panel reappears later due to e.g. unapplying some filter criteria that made it disappear in the first place. + if (newSelection != null) + { + CurrentSelection = newSelection; + // have to run this here as the above operation may noop on model equality. + HandleItemSelected(CurrentSelection); + } } } - // If a group was selected that is not the one containing the selection, attempt to reselect it. - if (groupForReselection != null && grouping.GroupItems.TryGetValue(groupForReselection, out _)) - setExpandedGroup(groupForReselection); - foreach (var item in Scroll.Panels.OfType().Where(p => p.Item != null)) updateVisibleBeatmaps((GroupedBeatmapSet)item.Item!.Model, item); } From ea8788a509df7392d3c0767aa88982f37085650e Mon Sep 17 00:00:00 2001 From: ArijanJ Date: Tue, 20 Jan 2026 21:47:34 +0100 Subject: [PATCH 518/836] Simplify cycleSkins, fix some logic and naming mistakes --- osu.Game/Localisation/MenuTipStrings.cs | 14 +--- .../Overlays/Settings/Sections/SkinSection.cs | 2 +- osu.Game/Screens/Menu/MenuTipDisplay.cs | 6 +- osu.Game/Skinning/SkinManager.cs | 64 ++++++------------- 4 files changed, 27 insertions(+), 59 deletions(-) diff --git a/osu.Game/Localisation/MenuTipStrings.cs b/osu.Game/Localisation/MenuTipStrings.cs index 69df795e87bc..3f83fceb18db 100644 --- a/osu.Game/Localisation/MenuTipStrings.cs +++ b/osu.Game/Localisation/MenuTipStrings.cs @@ -100,19 +100,9 @@ public static class MenuTipStrings public static LocalisableString ModCustomisationSettings => new TranslatableString(getKey(@"mod_customisation_settings"), @"Many mods have customisation settings that drastically change how they function. Click the Customise button in mod select to view settings!"); /// - /// "Press {0} to switch to a random skin!" + /// "Press {0} to switch to a random skin! You can also use {1} and {2} to cycle through skins." /// - public static LocalisableString RandomSkinShortcut(LocalisableString keybind) => new TranslatableString(getKey(@"random_skin_shortcut"), @"Press {0} to switch to a random skin!", keybind); - - /// - /// "Press {0} to go to the next skin!" - /// - public static LocalisableString NextSkinShortcut(LocalisableString keybind) => new TranslatableString(getKey(@"next_skin_shortcut"), @"Press {0} to go to the next skin!", keybind); - - /// - /// "Press {0} to go to the previous skin!" - /// - public static LocalisableString PreviousSkinShortcut(LocalisableString keybind) => new TranslatableString(getKey(@"previous_skin_shortcut"), @"Press {0} to go to the previous skin!", keybind); + public static LocalisableString SkinChangeShortcuts(LocalisableString[] keybind) => new TranslatableString(getKey(@"random_skin_shortcut"), @"Press {0} to switch to a random skin! You can also use {1} and {2} to cycle through skins.", keybind[0], keybind[1], keybind[2]); /// /// "While watching a replay, press {0} to toggle replay settings!" diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 0c8af4d845ef..4ff4f409a137 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -119,7 +119,7 @@ private void skinsChanged(IRealmCollection sender, ChangeSet changes) // For simplicity repopulate the full list. dropdownItems.Clear(); - var items = skins.GetDropdownItems().ToArray(); + var items = skins.GetAllUsableSkins().ToArray(); dropdownItems.AddRange(items); Schedule(() => skinDropdown.Items = dropdownItems); diff --git a/osu.Game/Screens/Menu/MenuTipDisplay.cs b/osu.Game/Screens/Menu/MenuTipDisplay.cs index d9c90b069d83..a8513d4345a0 100644 --- a/osu.Game/Screens/Menu/MenuTipDisplay.cs +++ b/osu.Game/Screens/Menu/MenuTipDisplay.cs @@ -199,7 +199,11 @@ private LocalisableString getRandomTip() return MenuTipStrings.ModCustomisationSettings; case 23: - return MenuTipStrings.RandomSkinShortcut(keyBindingStore.GetReadableKeyCombinationsFor(GlobalAction.RandomSkin).FirstOrDefault() ?? InputSettingsStrings.ActionHasNoKeyBinding); + return MenuTipStrings.SkinChangeShortcuts([ + keyBindingStore.GetReadableKeyCombinationsFor(GlobalAction.RandomSkin).FirstOrDefault() ?? InputSettingsStrings.ActionHasNoKeyBinding, + keyBindingStore.GetReadableKeyCombinationsFor(GlobalAction.NextSkin).FirstOrDefault() ?? InputSettingsStrings.ActionHasNoKeyBinding, + keyBindingStore.GetReadableKeyCombinationsFor(GlobalAction.PreviousSkin).FirstOrDefault() ?? InputSettingsStrings.ActionHasNoKeyBinding + ]); case 24: return MenuTipStrings.ToggleReplaySettingsShortcut(keyBindingStore.GetReadableKeyCombinationsFor(GlobalAction.ToggleReplaySettings).FirstOrDefault() diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 6239ce2b779a..0d8220009d10 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -135,7 +135,7 @@ public SkinManager(Storage storage, RealmAccess realm, GameHost host, IResourceS /// Inserts the defaults first, then 'random skin', then custom ones. /// Returns a list of items. /// - public IEnumerable> GetDropdownItems() + public IEnumerable> GetAllUsableSkins() { var results = new List>(); @@ -197,77 +197,51 @@ public void SelectRandomSkin() } /// - /// Cycle through skins by a signed step count. + /// Cycle through skins. /// Uses the skin selection UI ordering but skips the "Random Skin" entry. /// - /// Number of skins to move by (negative to move backwards). - public void CycleSkins(int step) + /// Optionally cycle in reverse. + private void cycleSkins(bool reverse = false) { - if (step == 0) - return; - // don't change selection if current skin is externally disabled/mounted for editing. if (CurrentSkinInfo.Disabled) return; - // Required local for iOS. Will cause runtime crash if inlined. - Guid currentSkinId = CurrentSkinInfo.Value.ID; + var availableSkins = GetAllUsableSkins().ToArray(); - var items = GetDropdownItems().ToArray(); + int currentIndex = Array.FindIndex(availableSkins, s => s.ID == CurrentSkinInfo.Value.ID); - if (items.Length == 0) - { - CurrentSkinInfo.Value = ArgonSkin.CreateInfo().ToLiveUnmanaged(); - return; - } + // If the current skin isn't selectable anymore, start from the top. + if (currentIndex == -1) + currentIndex = 0; - int currentIndex = Array.FindIndex(items, s => s.ID == currentSkinId); + int desiredIndex = currentIndex; - int direction = Math.Sign(step); - int moves = Math.Abs(step); - - int idx = currentIndex >= 0 ? currentIndex : (direction > 0 ? -1 : 0); - - while (moves > 0) + do { - if (direction > 0) - idx = (idx + 1) % items.Length; + if (!reverse) + desiredIndex = (desiredIndex + 1) % availableSkins.Length; else - idx = (idx - 1 + items.Length) % items.Length; + desiredIndex = (desiredIndex - 1 + availableSkins.Length) % availableSkins.Length; + } while (availableSkins[desiredIndex].ID == SkinInfo.RANDOM_SKIN); - // Skip random skin (confusing) - if (items[idx].ID == SkinInfo.RANDOM_SKIN) - continue; - - moves--; - } - - var nextId = items[idx].ID; - - // Retrieve the chosen skin from realm and set as current. Realm.Run(r => { - var chosen = r.Find(nextId); - - if (chosen == null) - { - CurrentSkinInfo.Value = ArgonSkin.CreateInfo().ToLiveUnmanaged(); - return; - } + var chosenSkin = r.Find(availableSkins[desiredIndex].ID); - CurrentSkinInfo.Value = chosen.ToLive(Realm); + CurrentSkinInfo.Value = chosenSkin.ToLive(Realm); }); } /// /// Cycle one skin backward. /// - public void SelectPreviousSkin() => CycleSkins(-1); + public void SelectPreviousSkin() => cycleSkins(reverse: true); /// /// Cycle one skin forward. /// - public void SelectNextSkin() => CycleSkins(1); + public void SelectNextSkin() => cycleSkins(); /// /// Retrieve a instance for the provided From 0ea060c6127e5a094a7d5161d7b317b3e9534102 Mon Sep 17 00:00:00 2001 From: iwa Date: Tue, 20 Jan 2026 22:20:54 +0100 Subject: [PATCH 519/836] revert: remove IPresetHotkeyHandler --- .../Mods/Input/IPresetHotkeyHandler.cs | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 osu.Game/Overlays/Mods/Input/IPresetHotkeyHandler.cs diff --git a/osu.Game/Overlays/Mods/Input/IPresetHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/IPresetHotkeyHandler.cs deleted file mode 100644 index 5bcb43d162e5..000000000000 --- a/osu.Game/Overlays/Mods/Input/IPresetHotkeyHandler.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using osu.Framework.Input.Events; - -namespace osu.Game.Overlays.Mods.Input -{ - public interface IPresetHotkeyHandler - { - /// - /// Attempt to handle the supplied as a selection of one of the presets in . - /// - /// The event representing the user's keypress. - /// The list of currently available presets. - /// Whether the supplied event was handled as a preset selection/deselection. - bool HandlePresetHotkeyPressed(KeyDownEvent e, IEnumerable availablePresets); - } -} From 042f716b2ae70ea06ea469672a15875d08096132 Mon Sep 17 00:00:00 2001 From: iwa Date: Tue, 20 Jan 2026 22:21:21 +0100 Subject: [PATCH 520/836] revert: changes made for preset hotkeys in SequentialModHotkeyHandler --- .../Mods/Input/SequentialModHotkeyHandler.cs | 24 ++----------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs index 127d5722d104..42e65c884e39 100644 --- a/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs @@ -12,10 +12,10 @@ namespace osu.Game.Overlays.Mods.Input { /// /// This implementation of receives a sequence of s, - /// and maps the sequence of keys onto the items it is provided in and . + /// and maps the sequence of keys onto the items it is provided in . /// In this case, particular mods are not bound to particular keys, the hotkeys are a byproduct of mod ordering. /// - public class SequentialModHotkeyHandler : IModHotkeyHandler, IPresetHotkeyHandler + public class SequentialModHotkeyHandler : IModHotkeyHandler { public static SequentialModHotkeyHandler Create(ModType modType) { @@ -35,11 +35,6 @@ public static SequentialModHotkeyHandler Create(ModType modType) } } - public static SequentialModHotkeyHandler CreateForPresets() - { - return new SequentialModHotkeyHandler(new[] { Key.Number1, Key.Number2, Key.Number3, Key.Number4, Key.Number5, Key.Number6, Key.Number7, Key.Number8, Key.Number9, Key.Number0 }); - } - private readonly Key[] toggleKeys; private SequentialModHotkeyHandler(Key[] keys) @@ -60,20 +55,5 @@ public bool HandleModHotkeyPressed(KeyDownEvent e, IEnumerable availab modState.Active.Toggle(); return true; } - - public bool HandlePresetHotkeyPressed(KeyDownEvent e, IEnumerable availablePresets) - { - int index = Array.IndexOf(toggleKeys, e.Key); - if (index < 0) - return false; - - var panel = availablePresets.ElementAtOrDefault(index); - if (panel == null) - return false; - - panel.Toggle(); - - return true; - } } } From ce2d54f1189c4d92404c00cfe4384af3d5c81d4c Mon Sep 17 00:00:00 2001 From: iwa Date: Tue, 20 Jan 2026 22:22:10 +0100 Subject: [PATCH 521/836] refactor: move presets hotkey logic inside ModPresetColumn class --- osu.Game/Overlays/Mods/ModPresetColumn.cs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModPresetColumn.cs b/osu.Game/Overlays/Mods/ModPresetColumn.cs index 35aff587fc3f..c4b11bd6ceed 100644 --- a/osu.Game/Overlays/Mods/ModPresetColumn.cs +++ b/osu.Game/Overlays/Mods/ModPresetColumn.cs @@ -12,10 +12,10 @@ using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Localisation; -using osu.Game.Overlays.Mods.Input; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osuTK; +using osuTK.Input; using Realms; namespace osu.Game.Overlays.Mods @@ -28,10 +28,10 @@ public partial class ModPresetColumn : ModSelectColumn [Resolved] private IBindable ruleset { get; set; } = null!; - private IPresetHotkeyHandler hotkeyHandler = null!; - private const float contracted_width = WIDTH - 120; + private readonly Key[] toggleKeys = { Key.Number1, Key.Number2, Key.Number3, Key.Number4, Key.Number5, Key.Number6, Key.Number7, Key.Number8, Key.Number9, Key.Number0 }; + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -41,8 +41,6 @@ private void load(OsuColour colours) AddPresetButton addPresetButton; ItemsFlow.Add(addPresetButton = new AddPresetButton()); ItemsFlow.SetLayoutPosition(addPresetButton, float.PositiveInfinity); - - hotkeyHandler = SequentialModHotkeyHandler.CreateForPresets(); } protected override void LoadComplete() @@ -106,7 +104,17 @@ protected override bool OnKeyDown(KeyDownEvent e) if (e.ControlPressed || e.AltPressed || e.SuperPressed || e.Repeat) return false; - return hotkeyHandler.HandlePresetHotkeyPressed(e, ItemsFlow.OfType()); + int index = Array.IndexOf(toggleKeys, e.Key); + if (index < 0) + return false; + + var panel = ItemsFlow.OfType().ElementAtOrDefault(index); + if (panel == null) + return false; + + panel.Toggle(); + + return true; } protected override void Dispose(bool isDisposing) From 10dc1314f610842e9fb51dc1d00ba3c770b4e734 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Jan 2026 01:06:40 +0900 Subject: [PATCH 522/836] Fix carousel items becoming incorrectly selected due to bindable leakage (#36414) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As discussed in discord. Fixed from multiple angles. --------- Co-authored-by: Bartłomiej Dach --- osu.Game/Graphics/Carousel/Carousel.cs | 7 ++++++- .../Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs | 3 ++- osu.Game/Screens/SelectV2/PanelBeatmapSet.cs | 3 ++- .../SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs | 8 ++++++-- osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs | 7 +++++-- 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/osu.Game/Graphics/Carousel/Carousel.cs b/osu.Game/Graphics/Carousel/Carousel.cs index be1c0134784c..3b7e31b2ea12 100644 --- a/osu.Game/Graphics/Carousel/Carousel.cs +++ b/osu.Game/Graphics/Carousel/Carousel.cs @@ -561,7 +561,12 @@ void traverseFromKey(TraversalOperation traversal) } } - private enum TraversalType { Keyboard, Set, Group } + private enum TraversalType + { + Keyboard, + Set, + Group + } private record TraversalOperation(TraversalType Type, int Direction); diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs index 4cbe4521bb00..db34630c4855 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs @@ -27,7 +27,8 @@ public partial class PanelBeatmapSet public partial class SpreadDisplay : OsuAnimatedButton { public Bindable BeatmapSet { get; } = new Bindable(); - public Bindable?> VisibleBeatmaps { get; } = new Bindable?>(); + + public IBindable?> VisibleBeatmaps { get; } = new Bindable?>(); public BindableBool Expanded { get; } = new BindableBool(); diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs index fb31d7a790dc..f6a33e5ce00a 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs @@ -157,7 +157,6 @@ private void load() { Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, - Expanded = { BindTarget = Expanded }, VisibleBeatmaps = { BindTarget = VisibleBeatmaps }, }, }, @@ -189,6 +188,8 @@ private void onExpanded() chevronIcon.ResizeWidthTo(0f, DURATION, Easing.OutQuint); chevronIcon.FadeTo(0f, DURATION, Easing.OutQuint); } + + spreadDisplay.Expanded.Value = Expanded.Value; } protected override void PrepareForUse() diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs index b3fa2fa01e79..b6b0bac07720 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs @@ -52,6 +52,12 @@ public SpreadDisplay() AutoSizeAxes = Axes.X; RelativeSizeAxes = Axes.Y; Content.CornerRadius = 5; + + Action = () => + { + if (Beatmap.Value != null) + scopedBeatmapSet.Value = Beatmap.Value.BeatmapSet!; + }; } [BackgroundDependencyLoader] @@ -214,8 +220,6 @@ private void updateBeatmap() dot.Alpha = (1 + 4 * (float)(succeeding.Count - i) / succeeding.Count) / 5; } } - - Action = () => scopedBeatmapSet.Value = Beatmap.Value.BeatmapSet!; } protected override bool OnMouseDown(MouseDownEvent e) diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs index 5071fe4aaa1c..5fc6be3d6225 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs @@ -193,7 +193,6 @@ private void load() { Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, - Enabled = { BindTarget = Selected } } }, } @@ -211,7 +210,11 @@ protected override void LoadComplete() ruleset.BindValueChanged(_ => updateKeyCount()); mods.BindValueChanged(_ => updateKeyCount(), true); - Selected.BindValueChanged(s => Expanded.Value = s.NewValue, true); + Selected.BindValueChanged(s => + { + Expanded.Value = s.NewValue; + spreadDisplay.Enabled.Value = s.NewValue; + }, true); } protected override void PrepareForUse() From 6f146a5ce9eb903912895083f7e9a17222928ebf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Jan 2026 14:59:37 +0900 Subject: [PATCH 523/836] Add failing test case showing visual state desync --- .../TestSceneBeatmapCarouselArtistGrouping.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs index 2829364c686f..68a07cc899a6 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs @@ -266,6 +266,41 @@ public void TestGroupDoesExpandAfterRandomTraversal() AddAssert("group expanded", () => Carousel.ExpandedGroup, () => Is.Not.Null); } + [Test] + public void TestFilterWhileCollapsedUpdatesVisualStateConnectly() + { + SelectNextSet(); + + CheckHasSelection(); + AddAssert("group expanded", () => Carousel.ExpandedGroup, () => Is.Not.Null); + AddAssert("has expanded set", () => Carousel.ExpandedBeatmapSet != null); + + AddAssert("has visible beatmaps", () => Carousel.GetCarouselItems()!.Count(item => item.Model is GroupedBeatmap && item.IsVisible), () => Is.EqualTo(3)); + AddAssert("has visually expanded set", () => Carousel.GetCarouselItems()!.Count(item => item.Model is GroupedBeatmapSet && item.IsExpanded && item.IsVisible), () => Is.EqualTo(1)); + + ToggleGroupCollapse(); + + CheckHasSelection(); + AddAssert("group not expanded", () => Carousel.ExpandedGroup, () => Is.Null); + AddAssert("has expanded set", () => Carousel.ExpandedBeatmapSet != null); + + AddAssert("has no visible beatmaps", () => Carousel.GetCarouselItems()!.Count(item => item.Model is GroupedBeatmap && item.IsVisible), () => Is.Zero); + AddAssert("has no visually expanded set", () => Carousel.GetCarouselItems()!.Count(item => item.Model is GroupedBeatmapSet && item.IsExpanded && item.IsVisible), () => Is.Zero); + + // filter while collapsed. + ApplyToFilterAndWaitForFilter("filter", c => c.SearchText = Carousel.SelectedBeatmapSet!.Metadata.Title); + + // then expand. + ToggleGroupCollapse(); + + CheckHasSelection(); + AddAssert("group expanded", () => Carousel.ExpandedGroup, () => Is.Not.Null); + AddAssert("has expanded set", () => Carousel.ExpandedBeatmapSet != null); + + AddAssert("has visible beatmaps", () => Carousel.GetCarouselItems()!.Count(item => item.Model is GroupedBeatmap && item.IsVisible), () => Is.EqualTo(3)); + AddAssert("has visually expanded set", () => Carousel.GetCarouselItems()!.Count(item => item.Model is GroupedBeatmapSet && item.IsExpanded && item.IsVisible), () => Is.EqualTo(1)); + } + [Test] public void TestGroupDoesNotExpandAgainOnRefilterIfManuallyCollapsed() { From 6354286452d1238005a3cf8cbc99f3969b88a79b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Jan 2026 03:04:44 +0900 Subject: [PATCH 524/836] Simplify logic further and fix regressing case --- osu.Game/Screens/SelectV2/BeatmapCarousel.cs | 33 ++++++++------------ 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index 72d59c62f7bc..ba54fd269c63 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -484,35 +484,26 @@ protected override void HandleFilterCompleted() if (CurrentSelection is GroupedBeatmap selection) { - // The filter might have changed the set of available groups, which means that the current selection may point to a stale group. - // Check whether that is the case. - bool groupingRemainsOff = selection.Group == null && grouping.GroupItems.Count == 0; - bool groupStillValid = selection.Group != null && grouping.ItemMap.ContainsKey(selection); - - if (groupingRemainsOff || groupStillValid) - { - if (selection.Group == ExpandedGroup) - { - // Update the visual state of the selected item if it should still be expanded post filter. - HandleItemSelected(CurrentSelection); - } - } - else + // Check whether the selection-group mapping is still valid post-filter. + if (!grouping.ItemMap.ContainsKey(selection)) { // If the group no longer exists (or the item no longer exists in the previous group), grab an arbitrary other instance of the beatmap under the first group encountered. - var newSelection = GetCarouselItems()?.Select(i => i.Model).OfType().FirstOrDefault(gb => gb.Beatmap.Equals(selection.Beatmap)); + var newSelection = GetCarouselItems()? + .Select(i => i.Model) + .OfType() + .FirstOrDefault(gb => CheckModelEquality(gb.Beatmap, selection.Beatmap)); // Only change the selection if we actually got a positive hit. // This is necessary so that selection isn't lost if the panel reappears later due to e.g. unapplying some filter criteria that made it disappear in the first place. if (newSelection != null) - { CurrentSelection = newSelection; - // have to run this here as the above operation may noop on model equality. - HandleItemSelected(CurrentSelection); - } } } + // Transfer the previous flag states across to the new models. + if (ExpandedBeatmapSet != null) setExpandedSet(ExpandedBeatmapSet); + if (ExpandedGroup != null) setExpandedGroup(ExpandedGroup); + foreach (var item in Scroll.Panels.OfType().Where(p => p.Item != null)) updateVisibleBeatmaps((GroupedBeatmapSet)item.Item!.Model, item); } @@ -664,6 +655,8 @@ private void setExpandedSet(GroupedBeatmapSet set) private void setExpansionStateOfSetItems(GroupedBeatmapSet set, bool expanded) { + bool canMakeVisible = !grouping.GroupItems.Any() || ExpandedGroup == set.Group; + if (grouping.SetItems.TryGetValue(set, out var items)) { foreach (var i in items) @@ -671,7 +664,7 @@ private void setExpansionStateOfSetItems(GroupedBeatmapSet set, bool expanded) if (i.Model is GroupedBeatmapSet) i.IsExpanded = expanded; else - i.IsVisible = expanded; + i.IsVisible = canMakeVisible && expanded; } } } From fdd13cd7e1ab19d07678312553090ae4944f0a14 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Jan 2026 15:48:51 +0900 Subject: [PATCH 525/836] Standardise ruleset error logging to always include exception in logs Supersedes and closes https://github.com/ppy/osu/pull/36420. --- osu.Game/Beatmaps/BeatmapUpdater.cs | 3 --- osu.Game/OsuGameBase.cs | 14 +++++++------- .../Overlays/Settings/Sections/RulesetSection.cs | 6 +++--- osu.Game/Overlays/Settings/SettingsFooter.cs | 6 +++--- osu.Game/Rulesets/RealmRulesetStore.cs | 2 +- osu.Game/Rulesets/RulesetSelector.cs | 8 ++++---- osu.Game/Rulesets/RulesetStore.cs | 12 +++++++----- osu.Game/Screens/Menu/IntroTriangles.cs | 5 ++--- 8 files changed, 27 insertions(+), 29 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapUpdater.cs b/osu.Game/Beatmaps/BeatmapUpdater.cs index 64ac69bb0752..ff23bf124203 100644 --- a/osu.Game/Beatmaps/BeatmapUpdater.cs +++ b/osu.Game/Beatmaps/BeatmapUpdater.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using osu.Framework.Extensions.ObjectExtensions; @@ -58,8 +57,6 @@ public void Process(BeatmapSetInfo beatmapSet, MetadataLookupScope lookupScope = var working = workingBeatmapCache.GetWorkingBeatmap(beatmap); var ruleset = working.BeatmapInfo.Ruleset.CreateInstance(); - Debug.Assert(ruleset != null); - var calculator = ruleset.CreateDifficultyCalculator(working); beatmap.StarRating = calculator.Calculate().StarRating; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 222427cb60da..370ba838dc1a 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -648,16 +648,16 @@ private void onRulesetChanged(ValueChangedEvent r) Ruleset instance = null; - try + if (r.NewValue?.Available == true) { - if (r.NewValue?.Available == true) + try { instance = r.NewValue.CreateInstance(); } - } - catch (Exception e) - { - Logger.Error(e, "Ruleset load failed and has been rolled back"); + catch (Exception e) + { + Rulesets.RulesetStore.LogRulesetFailure(r.NewValue, e); + } } if (instance == null) @@ -682,7 +682,7 @@ private void onRulesetChanged(ValueChangedEvent r) } catch (Exception e) { - Logger.Error(e, $"Could not load mods for \"{instance.RulesetInfo.Name}\" ruleset. Current ruleset has been rolled back."); + Rulesets.RulesetStore.LogRulesetFailure(r.NewValue, e); revertRulesetChange(); return; } diff --git a/osu.Game/Overlays/Settings/Sections/RulesetSection.cs b/osu.Game/Overlays/Settings/Sections/RulesetSection.cs index 626264151f6b..fb9849fd35fa 100644 --- a/osu.Game/Overlays/Settings/Sections/RulesetSection.cs +++ b/osu.Game/Overlays/Settings/Sections/RulesetSection.cs @@ -1,12 +1,12 @@ // 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.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Framework.Logging; using osu.Game.Graphics; using osu.Game.Localisation; using osu.Game.Rulesets; @@ -34,9 +34,9 @@ private void load(RulesetStore rulesets) if (section != null) Add(section); } - catch + catch (Exception e) { - Logger.Log($"Failed to load ruleset settings for {ruleset.RulesetInfo.Name}. Please check for an update from the developer.", level: LogLevel.Error); + RulesetStore.LogRulesetFailure(ruleset.RulesetInfo, e); } } } diff --git a/osu.Game/Overlays/Settings/SettingsFooter.cs b/osu.Game/Overlays/Settings/SettingsFooter.cs index 2e23577743a6..825d066b9dff 100644 --- a/osu.Game/Overlays/Settings/SettingsFooter.cs +++ b/osu.Game/Overlays/Settings/SettingsFooter.cs @@ -1,13 +1,13 @@ // 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 osu.Framework.Allocation; using osu.Framework.Development; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Logging; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -72,9 +72,9 @@ private void load(OsuGameBase game, RulesetStore rulesets) modes.Add(icon); } - catch + catch (Exception e) { - Logger.Log($"Could not create ruleset icon for {ruleset.Name}. Please check for an update from the developer.", level: LogLevel.Error); + RulesetStore.LogRulesetFailure(ruleset, e); } } } diff --git a/osu.Game/Rulesets/RealmRulesetStore.cs b/osu.Game/Rulesets/RealmRulesetStore.cs index 2455a9a73fde..b93110426b54 100644 --- a/osu.Game/Rulesets/RealmRulesetStore.cs +++ b/osu.Game/Rulesets/RealmRulesetStore.cs @@ -109,7 +109,7 @@ private void prepareDetachedRulesets() catch (Exception ex) { r.Available = false; - LogFailedLoad(r.Name, ex); + LogRulesetFailure(r, ex); } } diff --git a/osu.Game/Rulesets/RulesetSelector.cs b/osu.Game/Rulesets/RulesetSelector.cs index ba10033a9876..220e9f544dc4 100644 --- a/osu.Game/Rulesets/RulesetSelector.cs +++ b/osu.Game/Rulesets/RulesetSelector.cs @@ -3,9 +3,9 @@ #nullable disable -using osu.Framework.Graphics.UserInterface; +using System; using osu.Framework.Allocation; -using osu.Framework.Logging; +using osu.Framework.Graphics.UserInterface; using osu.Game.Extensions; namespace osu.Game.Rulesets @@ -31,9 +31,9 @@ private void load() { AddItem(ruleset); } - catch + catch (Exception e) { - Logger.Log($"Could not create ruleset icon for {ruleset.Name}. Please check for an update from the developer.", level: LogLevel.Error); + RulesetStore.LogRulesetFailure(ruleset, e); } } } diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index f33d42a53eec..9062cf32fccb 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -147,7 +147,7 @@ private void loadFromDisk() } catch (Exception e) { - LogFailedLoad(filename, e); + logRulesetFailure(filename, e); } return null; @@ -169,7 +169,7 @@ private void addRuleset(Assembly assembly) } catch (Exception e) { - LogFailedLoad(assembly.GetName().Name!.Split('.').Last(), e); + logRulesetFailure(assembly.GetName().Name!.Split('.').Last(), e); } } @@ -184,10 +184,12 @@ protected void Dispose(bool disposing) AppDomain.CurrentDomain.AssemblyResolve -= resolveRulesetDependencyAssembly; } - protected void LogFailedLoad(string name, Exception exception) + public static void LogRulesetFailure(RulesetInfo ruleset, Exception e) => logRulesetFailure(ruleset.Name, e); + + private static void logRulesetFailure(string name, Exception exception) { - Logger.Log($"Could not load ruleset \"{name}\". Please check for an update from the developer.", level: LogLevel.Error); - Logger.Log($"Ruleset load failed: {exception}"); + Logger.Log($"An issue with ruleset \"{name}\" occurred. Please check for an update from the developer.", level: LogLevel.Error); + Logger.Log(exception.ToString()); } #region Implementation of IRulesetStore diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index aab3afcd248f..9b8252a4b743 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; -using osu.Framework.Logging; using osu.Framework.Screens; using osu.Framework.Timing; using osu.Framework.Utils; @@ -342,9 +341,9 @@ private void load(RulesetStore rulesets) Add(icon); } - catch + catch (Exception e) { - Logger.Log($"Could not create ruleset icon for {ruleset.Name}. Please check for an update from the developer.", level: LogLevel.Error); + RulesetStore.LogRulesetFailure(ruleset, e); } } } From 1e8ffdf12831a360ad304f5c3a10e7bd666b30fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Jan 2026 16:43:46 +0900 Subject: [PATCH 526/836] Fix weird typo brain turned off --- .../SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs index 68a07cc899a6..28cdca34e1dd 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs @@ -267,7 +267,7 @@ public void TestGroupDoesExpandAfterRandomTraversal() } [Test] - public void TestFilterWhileCollapsedUpdatesVisualStateConnectly() + public void TestFilterWhileCollapsedUpdatesVisualStateCorrectly() { SelectNextSet(); From f0e7817ddab1da454c9d6dad5e6788aea11f07f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Jan 2026 10:05:29 +0100 Subject: [PATCH 527/836] Fix beatmap samples with incorrect 1 sample set suffix in the filename being shown in setup tab as belonging to custom sample bank 1 (#36425) To explain on the wordy and probably incoherent title: The patient zero for this was the following discord report: https://discord.com/channels/188630481301012481/1097318920991559880/1463029073998774375 After information extraction, it turned out that the user manually used the "Edit externally..." feature to rename a sample to `normal-hitnormal1.mp3`, thinking (logically, to be fair), that the 1 bank works the same way that all the others do. It doesn't, samples in the 1 bank do not have a numerical suffix in the filename - but the logic retrieving the sample sets to display in the setup tab was not checking that, leading to confusion wherein a sample would only "work" in the setup tab but not in the actual editor composer. Can be tested with [the beatmap provided by the user](https://discord.com/channels/188630481301012481/1097318920991559880/1463110516573470774). --- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 68a5167e2e80..1b093db7b84c 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -120,7 +120,7 @@ public IEnumerable GetAvailableSampleSets() if (string.IsNullOrEmpty(indexString)) index = 1; - if (int.TryParse(indexString, out int parsed)) + if (int.TryParse(indexString, out int parsed) && parsed >= 2) index = parsed; if (!index.HasValue) From 66933070647802cc38b1a84041bea5e98888e52d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Jan 2026 18:11:30 +0900 Subject: [PATCH 528/836] Add envvar to disble error reporting https://github.com/ppy/osu/discussions/31832#discussioncomment-15555080 --- osu.Game/OsuGame.cs | 8 ++++---- osu.Game/Utils/SentryLogger.cs | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f707f0d19828..7c480e0bf79a 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -171,7 +171,7 @@ public partial class OsuGame : OsuGameBase, IKeyBindingHandler, IL [Cached] private readonly ScreenshotManager screenshotManager = new ScreenshotManager(); - protected SentryLogger SentryLogger; + private SentryLogger sentryLogger; public virtual StableStorage GetStorageForStableInstall() => null; @@ -352,7 +352,7 @@ protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnl public override void SetupLogging(Storage gameStorage, Storage cacheStorage) { base.SetupLogging(gameStorage, cacheStorage); - SentryLogger = new SentryLogger(this, cacheStorage); + sentryLogger = new SentryLogger(this, cacheStorage); } public override void SetHost(GameHost host) @@ -404,7 +404,7 @@ void handlePendingDragDropImports() [BackgroundDependencyLoader] private void load() { - SentryLogger.AttachUser(API.LocalUser); + sentryLogger.AttachUser(API.LocalUser); if (SeasonalUIConfig.ENABLED) dependencies.CacheAs(osuLogo = new OsuLogoChristmas { Alpha = 0 }); @@ -1027,7 +1027,7 @@ protected override void Dispose(bool isDisposing) base.Dispose(isDisposing); - SentryLogger.Dispose(); + sentryLogger.Dispose(); if (Host?.Window != null) Host.Window.DragDrop -= onWindowDragDrop; diff --git a/osu.Game/Utils/SentryLogger.cs b/osu.Game/Utils/SentryLogger.cs index 9b3b78cd0e29..96453474aa58 100644 --- a/osu.Game/Utils/SentryLogger.cs +++ b/osu.Game/Utils/SentryLogger.cs @@ -46,6 +46,9 @@ public SentryLogger(OsuGame game, Storage? storage = null) { this.game = game; + if (Environment.GetEnvironmentVariable("OSU_DISABLE_ERROR_REPORTING") == "1") + return; + if (!game.IsDeployedBuild || !game.CreateEndpoints().WebsiteUrl.EndsWith(@".ppy.sh", StringComparison.Ordinal)) return; From e2dd4d86b4a79232aa0c1c8e8c520dc4be7ec94d Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Thu, 22 Jan 2026 12:18:02 +0300 Subject: [PATCH 529/836] Add localisation support for `PlaylistsSongSelectV2` (#36410) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit | master | pr | |-|-| | osu_2026-01-20_18-16-38 — копия | osu_2026-01-20_18-12-45 — копия | | osu_2026-01-20_18-16-38 | osu_2026-01-20_18-12-45 | --- .../Localisation/ModSelectOverlayStrings.cs | 5 ++++ osu.Game/Localisation/OnlinePlayStrings.cs | 25 +++++++++++++++++++ .../OnlinePlay/FooterButtonFreeModsV2.cs | 4 +-- .../OnlinePlay/FooterButtonFreestyleV2.cs | 3 ++- .../Playlists/AddToPlaylistFooterButton.cs | 3 ++- .../PlaylistsSongSelectV2.PlaylistTray.cs | 5 ++-- 6 files changed, 39 insertions(+), 6 deletions(-) diff --git a/osu.Game/Localisation/ModSelectOverlayStrings.cs b/osu.Game/Localisation/ModSelectOverlayStrings.cs index 10037d30c301..5572000c9912 100644 --- a/osu.Game/Localisation/ModSelectOverlayStrings.cs +++ b/osu.Game/Localisation/ModSelectOverlayStrings.cs @@ -19,6 +19,11 @@ public static class ModSelectOverlayStrings /// public static LocalisableString Mods(int count) => new TranslatableString(getKey(@"mods"), @"{0} mods", count); + /// + /// "all mods" + /// + public static LocalisableString AllMods => new TranslatableString(getKey(@"all_mods"), @"all mods"); + /// /// "Mods provide different ways to enjoy gameplay. Some have an effect on the score you can achieve during ranked play. Others are just for fun." /// diff --git a/osu.Game/Localisation/OnlinePlayStrings.cs b/osu.Game/Localisation/OnlinePlayStrings.cs index 1918519d36cb..32ef5d66fcb0 100644 --- a/osu.Game/Localisation/OnlinePlayStrings.cs +++ b/osu.Game/Localisation/OnlinePlayStrings.cs @@ -24,6 +24,31 @@ public static class OnlinePlayStrings /// public static LocalisableString InviteFailedUserOptOut => new TranslatableString(getKey(@"cant_invite_this_user_as1"), @"Can't invite this user as they have opted out of non-friend communications."); + /// + /// "Add to playlist" + /// + public static LocalisableString FooterButtonPlaylistAdd => new TranslatableString(getKey(@"footer_button_playlist_add"), @"Add to playlist"); + + /// + /// "Freemods" + /// + public static LocalisableString FooterButtonFreemods => new TranslatableString(getKey(@"footer_button_freemods"), @"Freemods"); + + /// + /// "Freestyle" + /// + public static LocalisableString FooterButtonFreestyle => new TranslatableString(getKey(@"footer_button_freestyle"), @"Freestyle"); + + /// + /// "{0} item(s)" + /// + public static LocalisableString PlaylistTrayItems(int count) => new TranslatableString(getKey(@"playlist_tray_items"), @"{0} item(s)", count); + + /// + /// "Manage items on previous screen" + /// + public static LocalisableString PlaylistTrayDescription => new TranslatableString(getKey(@"playlist_tray_description"), @"Manage items on previous screen"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs index 84c9334b45d2..f2ed75aed761 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs @@ -54,7 +54,7 @@ public FooterButtonFreeModsV2(ModSelectOverlay overlay) [BackgroundDependencyLoader] private void load() { - Text = "Freemods"; + Text = OnlinePlayStrings.FooterButtonFreemods; Icon = FontAwesome.Solid.ExchangeAlt; AccentColour = colours.Lime1; @@ -181,7 +181,7 @@ protected override void LoadComplete() private void updateText() { if (Freestyle.Value) - text.Text = "ALL MODS"; + text.Text = ModSelectOverlayStrings.AllMods.ToUpper(); else text.Text = ModSelectOverlayStrings.Mods(Mods.Value.Count).ToUpper(); } diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs index 517807363265..e7e33855ac09 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; +using osu.Game.Localisation; using osu.Game.Screens.Footer; namespace osu.Game.Screens.OnlinePlay @@ -32,7 +33,7 @@ public FooterButtonFreestyleV2() [BackgroundDependencyLoader] private void load() { - Text = "Freestyle"; + Text = OnlinePlayStrings.FooterButtonFreestyle; Icon = FontAwesome.Solid.ExchangeAlt; AccentColour = colours.Lime1; } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs index 1815bd9dcba5..1d8dcf37ab74 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs @@ -7,6 +7,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; namespace osu.Game.Screens.OnlinePlay.Playlists { @@ -31,7 +32,7 @@ private void load(OsuColour colours) Origin = Anchor.Centre, X = -10, Font = OsuFont.TorusAlternate.With(size: 17), - Text = "Add to playlist", + Text = OnlinePlayStrings.FooterButtonPlaylistAdd, UseFullGlyphHeight = false, }, new OsuSpriteText diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs index f634daf48195..10c6ee6ef95f 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs @@ -12,6 +12,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Localisation; using osu.Game.Online.Rooms; using osu.Game.Overlays; using osuTK; @@ -92,7 +93,7 @@ private void load(OverlayColourProvider colourProvider) { Y = 20, Font = OsuFont.Style.Caption2, - Text = "Manage items on previous screen" + Text = OnlinePlayStrings.PlaylistTrayDescription }, } }, @@ -166,7 +167,7 @@ private void updateRoomPlaylist() scroll.ScrollToStart(animated: false); ScheduleAfterChildren(() => scroll.ScrollToEnd()); - Scheduler.AddDelayed(() => text.Text = $"{room.Playlist.Count} item(s)", 100); + Scheduler.AddDelayed(() => text.Text = OnlinePlayStrings.PlaylistTrayItems(room.Playlist.Count), 100); } this.FadeIn(200) From d4cf46e3cd1ae2a925328599b25e39c8169baedb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Jan 2026 19:25:25 +0900 Subject: [PATCH 530/836] Fix some intermittent test failures --- .../Visual/SongSelectV2/TestSceneSongSelectFiltering.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs index 3eb97cf2dd04..0737d0fc9412 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs @@ -389,6 +389,7 @@ public void TestScopeToBeatmapWhenDifficultiesGroupedBySet() SortBy(SortMode.Artist); checkMatchedBeatmaps(6); + AddUntilStep("wait for spread indicator", () => this.ChildrenOfType().Any(d => d.Enabled.Value)); AddStep("click spread indicator", () => this.ChildrenOfType().Single(d => d.Enabled.Value).TriggerClick()); WaitForFiltering(); checkMatchedBeatmaps(3); @@ -412,6 +413,7 @@ public void TestDismissingScopeDoesNotClearSearchTextBox() WaitForFiltering(); checkMatchedBeatmaps(3); + AddUntilStep("wait for spread indicator", () => this.ChildrenOfType().Any(d => d.Enabled.Value)); AddStep("click spread indicator", () => this.ChildrenOfType().Single(d => d.Enabled.Value).TriggerClick()); WaitForFiltering(); checkMatchedBeatmaps(3); From 04e378c09fd2f250a22890dd7825b32ce3da85c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Jan 2026 20:24:10 +0900 Subject: [PATCH 531/836] Add visual hinting of keyboard shortcuts --- osu.Game/Overlays/Mods/ModPresetColumn.cs | 17 ++++++++++--- osu.Game/Overlays/Mods/ModPresetPanel.cs | 29 ++++++++++++++++++++++- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModPresetColumn.cs b/osu.Game/Overlays/Mods/ModPresetColumn.cs index c4b11bd6ceed..cc6d5c610691 100644 --- a/osu.Game/Overlays/Mods/ModPresetColumn.cs +++ b/osu.Game/Overlays/Mods/ModPresetColumn.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -83,10 +84,20 @@ private void asyncLoadPanels(IRealmCollection presets, ChangeSet? cha return; } - latestLoadTask = LoadComponentsAsync(presets.Select(p => new ModPresetPanel(p.ToLive(realm)) + var panels = new List(); + + for (int i = 0; i < presets.Count; i++) { - Shear = Vector2.Zero - }), loaded => + var preset = presets[i]; + + panels.Add(new ModPresetPanel(preset.ToLive(realm)) + { + Index = i <= 10 ? (i + 1) % 10 : null, + Shear = Vector2.Zero + }); + } + + latestLoadTask = LoadComponentsAsync(panels, loaded => { removeAndDisposePresetPanels(); ItemsFlow.AddRange(loaded); diff --git a/osu.Game/Overlays/Mods/ModPresetPanel.cs b/osu.Game/Overlays/Mods/ModPresetPanel.cs index b5d9a8807587..4094e8750715 100644 --- a/osu.Game/Overlays/Mods/ModPresetPanel.cs +++ b/osu.Game/Overlays/Mods/ModPresetPanel.cs @@ -6,12 +6,14 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; +using osu.Framework.Graphics; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Mods; @@ -22,6 +24,8 @@ public partial class ModPresetPanel : ModSelectPanel, IHasCustomTooltip Preset; + public int? Index { get; init; } + public override BindableBool Active { get; } = new BindableBool(); [Resolved] @@ -32,18 +36,36 @@ public partial class ModPresetPanel : ModSelectPanel, IHasCustomTooltip preset) { Preset = preset; - Title = preset.Value.Name; Description = preset.Value.Description; } + protected override float IdleSwitchWidth => 24; + protected override float ExpandedSwitchWidth => 40; + [BackgroundDependencyLoader] private void load(OsuColour colours) { AccentColour = colours.Orange1; + + if (Index != null) + { + SwitchContainer.Child = shortcutKeyText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Shear = -OsuGame.SHEAR, + Text = Index.Value.ToString(), + Font = OsuFont.Style.Heading2, + Alpha = 0, + Margin = new MarginPadding(10), + }; + } } protected override void LoadComplete() @@ -51,6 +73,11 @@ protected override void LoadComplete() base.LoadComplete(); selectedMods.BindValueChanged(_ => selectedModsChanged(), true); + + Active.BindValueChanged(active => + { + shortcutKeyText?.FadeTo(active.NewValue ? 1 : 0.4f, TRANSITION_DURATION, Easing.OutQuint); + }, true); } public void Toggle() From 52d5c986efe5e8cc83cda011844aa4ed65c5a60b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Jan 2026 12:57:47 +0100 Subject: [PATCH 532/836] Fix wrong type in enabled check --- .../Visual/SongSelectV2/TestSceneSongSelectFiltering.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs index 0737d0fc9412..0e195b4742b5 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs @@ -389,7 +389,7 @@ public void TestScopeToBeatmapWhenDifficultiesGroupedBySet() SortBy(SortMode.Artist); checkMatchedBeatmaps(6); - AddUntilStep("wait for spread indicator", () => this.ChildrenOfType().Any(d => d.Enabled.Value)); + AddUntilStep("wait for spread indicator", () => this.ChildrenOfType().Any(d => d.Enabled.Value)); AddStep("click spread indicator", () => this.ChildrenOfType().Single(d => d.Enabled.Value).TriggerClick()); WaitForFiltering(); checkMatchedBeatmaps(3); @@ -413,7 +413,7 @@ public void TestDismissingScopeDoesNotClearSearchTextBox() WaitForFiltering(); checkMatchedBeatmaps(3); - AddUntilStep("wait for spread indicator", () => this.ChildrenOfType().Any(d => d.Enabled.Value)); + AddUntilStep("wait for spread indicator", () => this.ChildrenOfType().Any(d => d.Enabled.Value)); AddStep("click spread indicator", () => this.ChildrenOfType().Single(d => d.Enabled.Value).TriggerClick()); WaitForFiltering(); checkMatchedBeatmaps(3); From 98c6f6afcd911e8b13393149feaad90f7878e58a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Jan 2026 01:13:49 +0900 Subject: [PATCH 533/836] Add test coverage --- .../UserInterface/TestSceneModPresetColumn.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs index c202442f9cfb..d904511267c6 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs @@ -80,6 +80,33 @@ public void SetUpSteps() }); } + [Test] + public void TestNumericHotkeys() + { + AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0)); + AddStep("create content", () => Child = new ModPresetColumn + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + + AddStep("select first preset", () => InputManager.Key(Key.Number1)); + AddAssert("first panel selected", () => this.ChildrenOfType().ElementAt(0).Active.Value); + + AddAssert("selected mods match correct preset", () => SelectedMods.Value, () => Is.EquivalentTo(createTestPresets().ElementAt(1).Mods)); + + AddStep("select third preset", () => InputManager.Key(Key.Number3)); + AddAssert("first panel not selected", () => !this.ChildrenOfType().ElementAt(0).Active.Value); + AddAssert("third panel selected", () => this.ChildrenOfType().ElementAt(2).Active.Value); + + AddAssert("selected mods match correct preset", () => SelectedMods.Value, () => Is.EquivalentTo(createTestPresets().ElementAt(2).Mods)); + + AddStep("deselect third preset", () => InputManager.Key(Key.Number3)); + AddAssert("third panel not selected", () => !this.ChildrenOfType().ElementAt(2).Active.Value); + + AddAssert("no selected mods", () => SelectedMods.Value.Count == 0); + } + [Test] public void TestBasicOperation() { From 2876cebdd7d9979ace86eadff56bdc659c9806cd Mon Sep 17 00:00:00 2001 From: Natelytle <92956514+Natelytle@users.noreply.github.com> Date: Thu, 22 Jan 2026 14:05:21 -0500 Subject: [PATCH 534/836] Move strain's influence in the difficulty of a note based on deltaTime to the evaluator level (#36417) This PR moves the influence of d/t^2 from the skill (through strain) directly into the evaluator level as a bonus applied at the end. This makes it more clear what d/t^2 is, and the fact that it applies to *all* bonuses in the evaluator. As well, the peak strain value of a note is now equal to the evaluator value. This comes with a couple benefits: 1. The BPM weight is now subject to balance, and can be flattened easily for a more "d/t" like system (previously this required hacky solutions) 2. StrainDecayBase becomes a much more useful variable now that it does not affect the difficulty of the note itself. When adjusting this in live, your star rating would double upon changing from 0.15 in aim to 0.3, and now it is intuitive what it does (makes strain take longer to accumulate). This means that future balancing efforts can use evaluators to dynamically adjust strainDecayBase (potentially letting large spikes provide more strain for the same difficulty if they're wide angle, for example). 3. In the object inspector, you get the actual maximum difficulty value of a note as seen in the ObjectDifficulties list. This makes it easier to tell what notes are deemed as harder by the system. For context, previously, a note of difficulty 1 at 200bpm would cap out at 6 as a result of strain, and a note of the same difficulty but at 300bpm would cap out at 8. The actual implementation is really really simple. I'm willing to move this to flashlight if wanted (I don't think it's necessary), or even abstract this away so that (1 - decay) doesn't look like a balancing constant. Side note: this is equivalent to live, except for notes with a deltaTime of less than 25ms (since I am using AdjustedDeltaTime in the aim evaluator for the bonus to avoid divisions by zero). --- .../Difficulty/Evaluators/AimEvaluator.cs | 4 ++++ .../Difficulty/Evaluators/SpeedEvaluator.cs | 4 ++++ osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 7 +++++-- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 6 ++++-- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index d311bcf93dde..257087d69e60 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -162,9 +162,13 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with if (withSliderTravelDistance) aimStrain += sliderBonus * slider_multiplier; + aimStrain *= highBpmBonus(osuCurrObj.AdjustedDeltaTime); + return aimStrain; } + private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.15, ms / 1000)); + private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); private static double calcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40)); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs index e6197b177bdc..a35d24d7a8b2 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs @@ -69,8 +69,12 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, IReadOnly // Base difficulty with all bonuses double difficulty = (1 + speedBonus + distanceBonus) * 1000 / strainTime; + difficulty *= highBpmBonus(osuCurrObj.AdjustedDeltaTime); + // Apply penalty if there's doubletappable doubles return difficulty * doubletapness; } + + private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.3, ms / 1000)); } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index dbdfef4199ed..a97bad877dfd 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -7,6 +7,7 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; +using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Utils; using osu.Game.Rulesets.Osu.Objects; @@ -38,8 +39,10 @@ public Aim(Mod[] mods, bool includeSliders) protected override double StrainValueAt(DifficultyHitObject current) { - currentStrain *= strainDecay(current.DeltaTime); - currentStrain += AimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * skillMultiplier; + double decay = strainDecay(((OsuDifficultyHitObject)current).AdjustedDeltaTime); + + currentStrain *= decay; + currentStrain += AimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * (1 - decay) * skillMultiplier; if (current.BaseObject is Slider) sliderStrains.Add(currentStrain); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 33dc23b7d8cf..cbba1de1523d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -39,8 +39,10 @@ public Speed(Mod[] mods) protected override double StrainValueAt(DifficultyHitObject current) { - currentStrain *= strainDecay(((OsuDifficultyHitObject)current).AdjustedDeltaTime); - currentStrain += SpeedEvaluator.EvaluateDifficultyOf(current, Mods) * skillMultiplier; + double decay = strainDecay(((OsuDifficultyHitObject)current).AdjustedDeltaTime); + + currentStrain *= decay; + currentStrain += SpeedEvaluator.EvaluateDifficultyOf(current, Mods) * (1 - decay) * skillMultiplier; currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current); From d80934c344f4a240a316264bf96b35331760a6e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 23 Jan 2026 07:31:57 +0100 Subject: [PATCH 535/836] Add failing tests --- .../UserInterface/TestSceneFormSliderBar.cs | 128 ++++++++++++++++++ .../Graphics/UserInterfaceV2/FormSliderBar.cs | 2 +- 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs index c7b99753011a..ac882e867db4 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs @@ -212,5 +212,133 @@ public void TestDisabledImmediately() }); AddAssert("no text selected", () => slider.ChildrenOfType().Single().SelectedText, () => Is.Empty); } + + [Test] + public void TestDisplayAsPercentageFloat() + { + OsuSpriteText text; + FormSliderBar slider = null!; + + AddStep("create content", () => + { + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.5f, + Direction = FillDirection.Vertical, + Spacing = new Vector2(10), + Children = new Drawable[] + { + text = new OsuSpriteText(), + slider = new FormSliderBar + { + Caption = "Slider", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 1, + Precision = 0.01f, + Default = 0.5f, + Value = 0.5f, + }, + DisplayAsPercentage = true, + }, + } + }; + slider.Current.BindValueChanged(_ => text.Text = $"Current value is: {slider.Current.Value}", true); + }); + + AddStep("click on textbox part", () => + { + InputManager.MoveMouseTo(slider.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + AddAssert("text selected", () => slider.ChildrenOfType().Single().SelectedText, () => Is.EqualTo("50")); + AddStep("input 9%", () => + { + slider.ChildrenOfType().Single().Text = "9"; + InputManager.Key(Key.Enter); + }); + AddAssert("slider is at 0.09", () => slider.Current.Value, () => Is.EqualTo(0.09f)); + + AddStep("start dragging nub", () => + { + InputManager.MoveMouseTo(slider.ChildrenOfType.InnerSliderNub>().Single()); + InputManager.PressButton(MouseButton.Left); + }); + AddStep("drag nub to 50%", () => + { + var innerSlider = slider.ChildrenOfType.InnerSlider>().Single(); + InputManager.MoveMouseTo((innerSlider.ScreenSpaceDrawQuad.TopLeft + innerSlider.ScreenSpaceDrawQuad.TopRight) / 2); + InputManager.ReleaseButton(MouseButton.Left); + }); + AddAssert("slider is at ~0.5", () => slider.Current.Value, () => Is.EqualTo(0.5).Within(0.01f)); + } + + [Test] + public void TestDisplayAsPercentageInt() + { + OsuSpriteText text; + FormSliderBar slider = null!; + + AddStep("create content", () => + { + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.5f, + Direction = FillDirection.Vertical, + Spacing = new Vector2(10), + Children = new Drawable[] + { + text = new OsuSpriteText(), + slider = new FormSliderBar + { + Caption = "Slider", + Current = new BindableInt + { + MinValue = 0, + MaxValue = 100, + Precision = 1, + Default = 50, + Value = 50, + }, + DisplayAsPercentage = true, + }, + } + }; + slider.Current.BindValueChanged(_ => text.Text = $"Current value is: {slider.Current.Value}", true); + }); + + AddStep("click on textbox part", () => + { + InputManager.MoveMouseTo(slider.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + AddAssert("text selected", () => slider.ChildrenOfType().Single().SelectedText, () => Is.EqualTo("50")); + AddStep("input 9%", () => + { + slider.ChildrenOfType().Single().Text = "9"; + InputManager.Key(Key.Enter); + }); + AddAssert("slider is at 9", () => slider.Current.Value, () => Is.EqualTo(9)); + + AddStep("start dragging nub", () => + { + InputManager.MoveMouseTo(slider.ChildrenOfType.InnerSliderNub>().Single()); + InputManager.PressButton(MouseButton.Left); + }); + AddStep("drag nub to 50%", () => + { + var innerSlider = slider.ChildrenOfType.InnerSlider>().Single(); + InputManager.MoveMouseTo((innerSlider.ScreenSpaceDrawQuad.TopLeft + innerSlider.ScreenSpaceDrawQuad.TopRight) / 2); + InputManager.ReleaseButton(MouseButton.Left); + }); + AddAssert("slider is at ~50", () => slider.Current.Value, () => Is.EqualTo(50).Within(1)); + } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 14d8213d2561..8fdae0a5ed35 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -573,7 +573,7 @@ protected override bool Commit() protected sealed override LocalisableString GetTooltipText(T value) => TooltipFormat(value); } - private partial class InnerSliderNub : Circle + public partial class InnerSliderNub : Circle { public Action? ResetToDefault { get; set; } From 225f4d8814905d562a5cf603b5bf2736224a91dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 23 Jan 2026 08:01:41 +0100 Subject: [PATCH 536/836] Fix broken percentage formatting in form slider bars closes https://github.com/ppy/osu/issues/36428 this one's my bad: https://github.com/ppy/osu/pull/36195#discussion_r2698388405 --- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 8fdae0a5ed35..4bf547770dbd 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -405,8 +405,21 @@ private void updateValueDisplay() { double floatValue = double.CreateTruncating(currentNumberInstantaneous.Value); - if (currentNumberInstantaneous.Value is int) - floatValue /= 100; + // if `DisplayAsPercentage` is true and `T` is not `int`, then `Current` / `currentNumberInstantaneous` are in the range of [0,1]. + // in the text box, we want to show the percentage in the range of [0,100], but without the percentage sign. + // the reason we don't want a percentage sign is that `TextBox`es with numerical `TextInputType`s + // have framework-side limitations on which characters they accept and they won't accept a percentage sign. + // + // therefore, the instantaneous value needs to be multiplied by 100 if it's not `int`, so that `ToStandardFormattedString()`, + // which is called *intentionally* without `asPercentage: true` specified as to not emit the percentage sign, spits out the correct number. + // + // additionally note that `ToStandardFormattedString()`, when called with `asPercentage: true` specified, does the *inverse* of this, + // which is that it brings the formatted number *into* the [0,1] range, + // because .NET number formatting *automatically* multiplies the formatted number by 100 when it is told to stringify a number as percentage + // (https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings#the--custom-specifier-3). + // it's all very confusing. + if (currentNumberInstantaneous.Value is not int) + floatValue *= 100; textBox.Text = floatValue.ToStandardFormattedString(Math.Max(0, OsuSliderBar.MAX_DECIMAL_DIGITS - 2)); } From d3c9548b52608fe8b8eca60cc527af39bcbaf8cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Jan 2026 17:10:31 +0900 Subject: [PATCH 537/836] Fix legacy health display using incorrect bulge texture when at low HP Closes #36432. --- osu.Game/Skinning/LegacyHealthDisplay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Skinning/LegacyHealthDisplay.cs b/osu.Game/Skinning/LegacyHealthDisplay.cs index 0d561d6c8901..bd59eb342df4 100644 --- a/osu.Game/Skinning/LegacyHealthDisplay.cs +++ b/osu.Game/Skinning/LegacyHealthDisplay.cs @@ -233,6 +233,7 @@ private void load() public override void Flash(bool isEpic) { Bulge(); + explode.Texture = Main.Texture; explode.Blending = isEpic ? BlendingParameters.Additive : BlendingParameters.Inherit; explode.ScaleTo(1).Then().ScaleTo(isEpic ? 2 : 1.6f, 120, Easing.Out); explode.FadeOutFromOne(120, Easing.Out); From c2604e22c79ab2af058c895b9c242e36541ff4e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Jan 2026 17:44:17 +0900 Subject: [PATCH 538/836] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 4e0138afd1a7..a353d9bc8074 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From b7559f93f2fa89aed578dc5b83ed1abbff311415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 23 Jan 2026 13:02:49 +0100 Subject: [PATCH 539/836] Work around flaky `TestSceneFirstRunSetupOverlay` tests See inline commentary. I don't really have any energy left to provide anything else, other than maybe a demonstration of how this dies in framework: diff --git a/osu.Framework.Tests/Visual/UserInterface/TestSceneScreenStackUnbindOnExit.cs b/osu.Framework.Tests/Visual/UserInterface/TestSceneScreenStackUnbindOnExit.cs new file mode 100644 index 000000000..c74ce6636 --- /dev/null +++ b/osu.Framework.Tests/Visual/UserInterface/TestSceneScreenStackUnbindOnExit.cs @@ -0,0 +1,59 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Screens; + +namespace osu.Framework.Tests.Visual.UserInterface +{ + public partial class TestSceneScreenStackUnbindOnExit : FrameworkTestScene + { + [Cached] + private ScreenStack screenStack = new ScreenStack(); + + [Test] + public void TestScreenExitUnbindDoesNotInterruptLoadComplete() + { + AddStep("set up the scenario", () => + { + Child = screenStack; + screenStack.Push(new Screen()); + screenStack.Push(new BrokenScreen()); + }); + AddUntilStep("wait to get to target screen", () => screenStack.CurrentScreen, Is.InstanceOf); + } + + private partial class BrokenSlider : BasicSliderBar + { + [Resolved] + private ScreenStack screenStack { get; set; } = null!; + + protected override void LoadComplete() + { + // exiting the current screen provokes the behaviour of unbinding all bindables in the screen's subtree + screenStack.CurrentScreen.Exit(); + + // ...but the following calls should still take correct effect inside `SliderBar` + // (namely one consisting of propagating `{Min,Max}Value` into `currentNumberInstantaneous`) + // so that it doesn't have its internal invariants violated + CurrentNumber.MinValue = -10; + CurrentNumber.MaxValue = 10; + + // this notably calls `Scheduler.AddOnce(updateValue)` inside, which will happen *in the imminent future, in the same frame as `LoadComplete()` here. + // if the above mutations of `{Min,Max}Value` don't correctly propagate inside the slider bar due to an overly eager unbind, this will cause a crash. + base.LoadComplete(); + } + } + + private partial class BrokenScreen : Screen + { + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new BrokenSlider(); + } + } + } +} I attempted to address what I perceive to be the root issue here which is that `ScreenStack` is allowed to arbitrarily unbind bindables under drawables which are by all means still in the scene graph. The attempt consisted of scheduling the unbind until after children of the screen stack, but that caused 150 game-side tests to fail, seemingly on something relevant to bindable leases, so I give up. --- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 114 ++++++++++-------- 1 file changed, 65 insertions(+), 49 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 4bf547770dbd..07cdbfe50d4a 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -35,13 +35,20 @@ public Bindable Current set { current.Current = value; + + // the above `Current` set could have disabled the instantaneous bindable too, + // but we still need to copy out `Default` manually, + // so lift that disable for a second and then restore it + currentNumberInstantaneous.Disabled = false; currentNumberInstantaneous.Default = current.Default; + currentNumberInstantaneous.Disabled = current.Disabled; } } private readonly BindableNumberWithCurrent current = new BindableNumberWithCurrent(); private readonly BindableNumber currentNumberInstantaneous = new BindableNumber(); + private readonly InnerSlider slider; /// /// Whether changes to the value should instantaneously transfer to outside bindables. @@ -84,20 +91,13 @@ public LocalisableString Caption /// public LocalisableString HintText { get; init; } - private float keyboardStep; - /// /// A custom step value for each key press which actuates a change on this control. /// public float KeyboardStep { - get => keyboardStep; - set - { - keyboardStep = value; - if (IsLoaded) - slider.KeyboardStep = value; - } + get => slider.KeyboardStep; + set => slider.KeyboardStep = value; } /// @@ -125,7 +125,6 @@ public float KeyboardStep private Box flashLayer = null!; private FormTextBox.InnerTextBox textBox = null!; private OsuSpriteText valueLabel = null!; - private InnerSlider slider = null!; private FormFieldCaption captionText = null!; private IFocusManager focusManager = null!; @@ -140,6 +139,56 @@ public FormSliderBar() { LabelFormat ??= defaultLabelFormat; TooltipFormat ??= v => LabelFormat(v); + + // the reason why this slider is created in constructor rather than in BDL like the rest of drawable hierarchy is as follows: + // `SliderBar` (the base framework class for all sliders) also does its `Current` initialisation in its ctor. + // if that precedent is not followed, it is possible to run into a crippling issue + // when a `FormSliderBar` instance is on a screen and said screen is exited before said instance's `LoadComplete()` is invoked. + // in that case, the screen exit will unbind the `InnerSlider`'s internal bindings & value change callbacks: + // https://github.com/ppy/osu-framework/blob/23ac694fa2c342ce39f563c8a1b975119249d5e9/osu.Framework/Screens/ScreenStack.cs#L353 + // the callbacks are supposed to propagate `{Min,Max}Value` from `Current` to its internal `currentNumberInstantaneous` bindable: + // https://github.com/ppy/osu-framework/blob/64624795b0816261dfc5e930e1d9b9ec7e8bb8c5/osu.Framework/Graphics/UserInterface/SliderBar.cs#L62-L63 + // thus, the callbacks getting unbound by the screen exit prevents `{Min,Max}Value` from ever correctly propagating, which finally causes a crash at + // https://github.com/ppy/osu-framework/blob/64624795b0816261dfc5e930e1d9b9ec7e8bb8c5/osu.Framework/Graphics/UserInterface/SliderBar.cs#L112 -> + // https://github.com/ppy/osu-framework/blob/64624795b0816261dfc5e930e1d9b9ec7e8bb8c5/osu.Framework/Graphics/UserInterface/SliderBar.cs#L88-L92. + // moving the slider creation & binding to constructor does little to fix the issue other than to make it less likely to be hit. + slider = new InnerSlider + { + Current = currentNumberInstantaneous, + OnCommit = () => current.Value = currentNumberInstantaneous.Value, + TooltipFormat = TooltipFormat, + DisplayAsPercentage = DisplayAsPercentage, + PlaySamplesOnAdjust = PlaySamplesOnAdjust, + ResetToDefault = () => + { + if (!IsDisabled) + SetDefault(); + } + }; + + current.ValueChanged += e => + { + currentNumberInstantaneous.Value = e.NewValue; + ValueChanged?.Invoke(); + }; + + current.MinValueChanged += v => currentNumberInstantaneous.MinValue = v; + current.MaxValueChanged += v => currentNumberInstantaneous.MaxValue = v; + current.PrecisionChanged += v => currentNumberInstantaneous.Precision = v; + current.DisabledChanged += disabled => + { + if (disabled) + { + // revert any changes before disabling to make sure we are in a consistent state. + currentNumberInstantaneous.Value = current.Value; + } + + currentNumberInstantaneous.Disabled = disabled; + if (IsLoaded) + updateState(); + }; + + current.CopyTo(currentNumberInstantaneous); } [BackgroundDependencyLoader] @@ -224,23 +273,13 @@ private void load(OsuColour colours, OsuGame? game) }, }, }, - slider = new InnerSlider + slider.With(s => { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.X, - Width = 0.5f, - Current = currentNumberInstantaneous, - OnCommit = () => current.Value = currentNumberInstantaneous.Value, - TooltipFormat = TooltipFormat, - DisplayAsPercentage = DisplayAsPercentage, - PlaySamplesOnAdjust = PlaySamplesOnAdjust, - ResetToDefault = () => - { - if (!IsDisabled) - SetDefault(); - } - } + s.Anchor = Anchor.CentreRight; + s.Origin = Anchor.CentreRight; + s.RelativeSizeAxes = Axes.X; + s.Width = 0.5f; + }) }, }, }; @@ -253,7 +292,6 @@ protected override void LoadComplete() { base.LoadComplete(); - slider.KeyboardStep = keyboardStep; captionText.Caption = caption; focusManager = GetContainingFocusManager()!; @@ -265,28 +303,6 @@ protected override void LoadComplete() slider.IsDragging.BindValueChanged(_ => updateState()); slider.Focused.BindValueChanged(_ => updateState()); - current.ValueChanged += e => - { - currentNumberInstantaneous.Value = e.NewValue; - ValueChanged?.Invoke(); - }; - - current.MinValueChanged += v => currentNumberInstantaneous.MinValue = v; - current.MaxValueChanged += v => currentNumberInstantaneous.MaxValue = v; - current.PrecisionChanged += v => currentNumberInstantaneous.Precision = v; - current.DisabledChanged += disabled => - { - if (disabled) - { - // revert any changes before disabling to make sure we are in a consistent state. - currentNumberInstantaneous.Value = current.Value; - } - - currentNumberInstantaneous.Disabled = disabled; - updateState(); - }; - - current.CopyTo(currentNumberInstantaneous); currentLanguage.BindValueChanged(_ => Schedule(updateValueDisplay)); currentNumberInstantaneous.BindDisabledChanged(_ => updateState()); currentNumberInstantaneous.BindValueChanged(e => From 259c5708f1162bd3f3e367b207d0632258195c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 23 Jan 2026 13:18:48 +0100 Subject: [PATCH 540/836] Add some more extra test coverage --- .../Visual/UserInterface/TestSceneFormSliderBar.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs index ac882e867db4..e7019aabe199 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs @@ -169,6 +169,17 @@ public void TestDisabled() InputManager.Key(Key.Enter); }); AddAssert("slider is still at 1", () => slider.Current.Value, () => Is.EqualTo(1)); + + AddStep("re-enable slider", () => slider.Current.Disabled = false); + + AddStep("move mouse to nub", () => InputManager.MoveMouseTo(slider.ChildrenOfType().Single())); + + AddStep("double click nub", () => + { + InputManager.Click(MouseButton.Left); + InputManager.Click(MouseButton.Left); + }); + AddAssert("slider is at 5", () => slider.Current.Value, () => Is.EqualTo(5)); } [Test] From 978fc91b091c4b5a5a9235ac82cb7bd5b1d18d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 23 Jan 2026 13:40:54 +0100 Subject: [PATCH 541/836] Locally schedule beatmap skin change callbacks to ensure they fire at valid times See CI failures like https://github.com/ppy/osu/actions/runs/21238110652/job/61110112412?pr=36404#step:5:21. Hopefully works this time. --- osu.Game/Screens/Edit/Components/FormSampleSet.cs | 4 ++-- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 6 ++++++ osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs | 6 ++++-- osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs | 6 ++++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/FormSampleSet.cs b/osu.Game/Screens/Edit/Components/FormSampleSet.cs index f2d31dea060f..21be85423e44 100644 --- a/osu.Game/Screens/Edit/Components/FormSampleSet.cs +++ b/osu.Game/Screens/Edit/Components/FormSampleSet.cs @@ -284,7 +284,7 @@ private void updateState() triangles.Colour = ColourInfo.GradientVertical(triangleGradientSecondColour.Value, BackgroundColour); } - private void recycleSamples() + private void recycleSamples() => Schedule(() => { if (hoverSounds?.Parent == this) { @@ -306,7 +306,7 @@ private void recycleSamples() { sample = null; } - } + }); protected override bool OnHover(HoverEvent e) { diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 1b093db7b84c..f47a6b020e2a 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -20,6 +20,12 @@ namespace osu.Game.Screens.Edit /// public class EditorBeatmapSkin : ISkin, IDisposable { + /// + /// Invoked when the beatmap skin changes. + /// This event is not locally scheduled to update thread or otherwise marshalled + /// in a way that would prevent invocation of a callback registered by a potentially-now-disposed caller. + /// Callers are expected to schedule locally as required. + /// public event Action? BeatmapSkinChanged; /// diff --git a/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs b/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs index 814b5dc18edf..c293b1ccd542 100644 --- a/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs +++ b/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs @@ -24,7 +24,7 @@ protected override void LoadComplete() base.LoadComplete(); if (beatmapSkin != null) - beatmapSkin.BeatmapSkinChanged += TriggerSourceChanged; + beatmapSkin.BeatmapSkinChanged += triggerSourceChanged; } protected override void Dispose(bool isDisposing) @@ -32,7 +32,9 @@ protected override void Dispose(bool isDisposing) base.Dispose(isDisposing); if (beatmapSkin != null) - beatmapSkin.BeatmapSkinChanged -= TriggerSourceChanged; + beatmapSkin.BeatmapSkinChanged -= triggerSourceChanged; } + + private void triggerSourceChanged() => Schedule(TriggerSourceChanged); } } diff --git a/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs b/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs index 659fc6ff7f84..7e3020d78bb2 100644 --- a/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs +++ b/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs @@ -37,7 +37,7 @@ protected override void LoadComplete() populateItems(); if (beatmapSkin != null) - beatmapSkin.BeatmapSkinChanged += populateItems; + beatmapSkin.BeatmapSkinChanged += scheduleItemPopulation; Current.Value = Items.First(i => i?.SampleSetIndex > 0); Current.BindValueChanged(val => @@ -54,6 +54,8 @@ private void populateItems() Items = items; } + private void scheduleItemPopulation() => Schedule(populateItems); + protected override LocalisableString GenerateItemText(EditorBeatmapSkin.SampleSet? item) { if (item == null) @@ -88,7 +90,7 @@ protected override LocalisableString GenerateItemText(EditorBeatmapSkin.SampleSe protected override void Dispose(bool isDisposing) { if (beatmapSkin != null) - beatmapSkin.BeatmapSkinChanged -= populateItems; + beatmapSkin.BeatmapSkinChanged -= scheduleItemPopulation; base.Dispose(isDisposing); } From 84ec4bb86683fac1a72664b748e33eb209080e4a Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Fri, 23 Jan 2026 18:10:04 +0300 Subject: [PATCH 542/836] Fix score tooltips being displayed when hovering freemods status bar on `PlaylistsSSV2` (#36413) - similar to https://github.com/ppy/osu/pull/36332 --- .../Screens/OnlinePlay/FooterButtonFreeModsV2.cs | 4 ++-- osu.Game/Screens/SelectV2/FooterButtonMods.cs | 15 ++------------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs index f2ed75aed761..a2194a5d2f0f 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs @@ -41,7 +41,7 @@ public partial class FooterButtonFreeModsV2 : ScreenFooterButton [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; - private Drawable modsWedge = null!; + private Container modsWedge = null!; private ModDisplay modDisplay = null!; private Container modContainer = null!; private ModCountText overflowModCountDisplay = null!; @@ -58,7 +58,7 @@ private void load() Icon = FontAwesome.Solid.ExchangeAlt; AccentColour = colours.Lime1; - Add(modsWedge = new Container + Add(modsWedge = new InputBlockingContainer { Y = -5f, Depth = float.MaxValue, diff --git a/osu.Game/Screens/SelectV2/FooterButtonMods.cs b/osu.Game/Screens/SelectV2/FooterButtonMods.cs index 2da98790a7b1..112f53a53ee4 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonMods.cs +++ b/osu.Game/Screens/SelectV2/FooterButtonMods.cs @@ -85,7 +85,7 @@ private void load() AddRange(new[] { unrankedBadge = new UnrankedBadge(), - modDisplayBar = new ModDisplayBarContainer + modDisplayBar = new InputBlockingContainer { Y = -5f, Depth = float.MaxValue, @@ -343,14 +343,7 @@ public void SetContent(IReadOnlyList content) } } - internal partial class ModDisplayBarContainer : Container - { - protected override bool OnMouseDown(MouseDownEvent e) => true; - - protected override bool OnHover(HoverEvent e) => true; - } - - internal partial class UnrankedBadge : CompositeDrawable, IHasTooltip + internal partial class UnrankedBadge : InputBlockingContainer, IHasTooltip { public LocalisableString TooltipText { get; } @@ -393,10 +386,6 @@ private void load(OsuColour colours) } }; } - - protected override bool OnMouseDown(MouseDownEvent e) => true; - - protected override bool OnHover(HoverEvent e) => true; } } } From 520173e37dfa1f1f09114fde78546b9bf8458f6e Mon Sep 17 00:00:00 2001 From: kwotaq <80002984+kwotaq@users.noreply.github.com> Date: Sat, 24 Jan 2026 21:40:01 +0200 Subject: [PATCH 543/836] Replace Speed skill strain summation with a per-note harmonic sum (#34696) The purpose of this change is to remove the arbitrary note based length bonus for speed and replace it with a more concrete per note difficulty aware calculation. As a result of the summation needing to be per-note, chunking and in consequence peak strain reduction have both been removed from the skill. ~~The various strain counting functions also heavily relied on chunking and the way summation worked, so they have also been changed to match values held before the change as much as possible (given the different summation some changes in values are bound to happen).~~ Above was a bug. Huis page: [https://pp.huismetbenen.nl/rankings/players/length-bonus](https://pp.huismetbenen.nl/rankings/players/length-bonus) --------- Co-authored-by: James Wilson --- .../Difficulty/Evaluators/AimEvaluator.cs | 2 +- .../Difficulty/Evaluators/RhythmEvaluator.cs | 2 +- .../Difficulty/OsuDifficultyCalculator.cs | 12 +++-- .../Difficulty/OsuPerformanceCalculator.cs | 7 +-- .../Difficulty/Skills/Aim.cs | 2 +- .../Difficulty/Skills/Speed.cs | 53 ++++++++++++------- 6 files changed, 46 insertions(+), 32 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 257087d69e60..c8c7fb605f24 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators public static class AimEvaluator { private const double wide_angle_multiplier = 1.5; - private const double acute_angle_multiplier = 2.55; + private const double acute_angle_multiplier = 2.3; private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; private const double wiggle_multiplier = 1.02; // WARNING: Increasing this multiplier beyond 1.02 reduces difficulty as distance increases. Refer to the desmos link above the wiggle bonus calculation diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs index 3bb35ccf1553..906ccc1b46dd 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs @@ -16,7 +16,7 @@ public static class RhythmEvaluator private const int history_time_max = 5 * 1000; // 5 seconds private const int history_objects_max = 32; private const double rhythm_overall_multiplier = 1.0; - private const double rhythm_ratio_multiplier = 15.0; + private const double rhythm_ratio_multiplier = 17.0; /// /// Calculates a rhythm multiplier for the difficulty of the tap associated with historic data of the current . diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 47be0ebfa4fc..8230ed060b36 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -59,10 +59,10 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat double aimNoSlidersDifficultyValue = aimWithoutSliders.DifficultyValue(); double speedDifficultyValue = speed.DifficultyValue(); - double speedNotes = speed.RelevantNoteCount(); - double aimDifficultStrainCount = aim.CountTopWeightedStrains(aimDifficultyValue); - double speedDifficultStrainCount = speed.CountTopWeightedStrains(speedDifficultyValue); + double speedDifficultStrainCount = speed.CountTopWeightedObjectDifficulties(speedDifficultyValue); + + double speedNotes = speed.RelevantNoteCount(); double aimNoSlidersTopWeightedSliderCount = aimWithoutSliders.CountTopWeightedSliders(aimNoSlidersDifficultyValue); double aimNoSlidersDifficultStrainCount = aimWithoutSliders.CountTopWeightedStrains(aimNoSlidersDifficultyValue); @@ -84,7 +84,9 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat int totalHits = beatmap.HitObjects.Count; double mechanicalDifficultyRating = calculateMechanicalDifficultyRating(aimDifficultyValue, speedDifficultyValue); - double sliderFactor = aimDifficultyValue > 0 ? OsuRatingCalculator.CalculateDifficultyRating(aimNoSlidersDifficultyValue) / OsuRatingCalculator.CalculateDifficultyRating(aimDifficultyValue) : 1; + double sliderFactor = aimDifficultyValue > 0 + ? OsuRatingCalculator.CalculateDifficultyRating(aimNoSlidersDifficultyValue) / OsuRatingCalculator.CalculateDifficultyRating(aimDifficultyValue) + : 1; var osuRatingCalculator = new OsuRatingCalculator(mods, totalHits, approachRate, overallDifficulty, mechanicalDifficultyRating, sliderFactor); @@ -103,7 +105,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat var scoreAttributes = simulator.Simulate(WorkingBeatmap, beatmap); double baseAimPerformance = OsuStrainSkill.DifficultyToPerformance(aimRating); - double baseSpeedPerformance = OsuStrainSkill.DifficultyToPerformance(speedRating); + double baseSpeedPerformance = HarmonicSkill.DifficultyToPerformance(speedRating); double baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating); double basePerformance = DifficultyCalculationUtils.Norm(OsuPerformanceCalculator.PERFORMANCE_NORM_EXPONENT, baseAimPerformance, baseSpeedPerformance, baseFlashlightPerformance); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index dc4ac6c37320..9d11f07a7da3 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -9,6 +9,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Osu.Difficulty.Skills; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Scoring; @@ -225,11 +226,7 @@ private double computeSpeedValue(ScoreInfo score, OsuDifficultyAttributes attrib if (score.Mods.Any(h => h is OsuModRelax) || speedDeviation == null) return 0.0; - double speedValue = OsuStrainSkill.DifficultyToPerformance(attributes.SpeedDifficulty); - - double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + - (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); - speedValue *= lengthBonus; + double speedValue = HarmonicSkill.DifficultyToPerformance(attributes.SpeedDifficulty); if (effectiveMissCount > 0) { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index a97bad877dfd..ed106ccfe741 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -28,7 +28,7 @@ public Aim(Mod[] mods, bool includeSliders) private double currentStrain; - private double skillMultiplier => 26; + private double skillMultiplier => 26.7; private double strainDecayBase => 0.15; private readonly List sliderStrains = new List(); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index cbba1de1523d..8911b32f42e9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -6,27 +6,29 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; -using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; using System.Linq; -using osu.Game.Rulesets.Osu.Difficulty.Utils; +using osu.Game.Rulesets.Difficulty.Skills; +using osu.Game.Rulesets.Difficulty.Utils; +using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; namespace osu.Game.Rulesets.Osu.Difficulty.Skills { /// /// Represents the skill required to press keys with regards to keeping up with the speed at which objects need to be hit. /// - public class Speed : OsuStrainSkill + public class Speed : HarmonicSkill { - private double skillMultiplier => 1.47; - private double strainDecayBase => 0.3; - - private double currentStrain; - private double currentRhythm; + private double skillMultiplier => 0.93; private readonly List sliderStrains = new List(); - protected override int ReducedSectionCount => 5; + private double currentDifficulty; + + private double strainDecayBase => 0.3; + + protected override double HarmonicScale => 20; + protected override double DecayExponent => 0.85; public Speed(Mod[] mods) : base(mods) @@ -35,23 +37,21 @@ public Speed(Mod[] mods) private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); - protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => (currentStrain * currentRhythm) * strainDecay(time - current.Previous(0).StartTime); - - protected override double StrainValueAt(DifficultyHitObject current) + protected override double ObjectDifficultyOf(DifficultyHitObject current) { double decay = strainDecay(((OsuDifficultyHitObject)current).AdjustedDeltaTime); - currentStrain *= decay; - currentStrain += SpeedEvaluator.EvaluateDifficultyOf(current, Mods) * (1 - decay) * skillMultiplier; + currentDifficulty *= decay; + currentDifficulty += SpeedEvaluator.EvaluateDifficultyOf(current, Mods) * (1 - decay) * skillMultiplier; - currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current); + double currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current); - double totalStrain = currentStrain * currentRhythm; + double totalDifficulty = currentDifficulty * currentRhythm; if (current.BaseObject is Slider) - sliderStrains.Add(totalStrain); + sliderStrains.Add(totalDifficulty); - return totalStrain; + return totalDifficulty; } public double RelevantNoteCount() @@ -60,6 +60,7 @@ public double RelevantNoteCount() return 0; double maxStrain = ObjectDifficulties.Max(); + if (maxStrain == 0) return 0; @@ -67,6 +68,20 @@ public double RelevantNoteCount() } public double CountTopWeightedSliders(double difficultyValue) - => OsuStrainUtils.CountTopWeightedSliders(sliderStrains, difficultyValue); + { + if (sliderStrains.Count == 0) + return 0; + + if (NoteWeightSum == 0) + return 0.0; + + double consistentTopNote = difficultyValue / NoteWeightSum; // What would the top note be if all note values were identical + + if (consistentTopNote == 0) + return 0; + + // Use a weighted sum of all notes. Constants are arbitrary and give nice values + return sliderStrains.Sum(s => DifficultyCalculationUtils.Logistic(s / consistentTopNote, 0.88, 10, 1.1)); + } } } From fb8d198a640b72bfa84333d72843cbd5a14291db Mon Sep 17 00:00:00 2001 From: Dark98 <71676472+TheDark98@users.noreply.github.com> Date: Sat, 24 Jan 2026 23:05:59 +0100 Subject: [PATCH 544/836] Improve angle calculation to better represent the path taken on sliders (#35555) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## This pr resolves the issue with the angle calculation. The old system calculated the angle between three objects. If the last object was a long slider that the player needed to follow, the system calculated the angle using only the slider’s end point and the previous object, which caused long sliders to have incorrect angle values. --------- Co-authored-by: StanR Co-authored-by: James Wilson --- .../Difficulty/Evaluators/AimEvaluator.cs | 2 +- .../Preprocessing/OsuDifficultyHitObject.cs | 36 +++++++++++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index c8c7fb605f24..730bd6bc58fa 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -13,7 +13,7 @@ public static class AimEvaluator { private const double wide_angle_multiplier = 1.5; private const double acute_angle_multiplier = 2.3; - private const double slider_multiplier = 1.35; + private const double slider_multiplier = 1.5; private const double velocity_change_multiplier = 0.75; private const double wiggle_multiplier = 1.02; // WARNING: Increasing this multiplier beyond 1.02 reduces difficulty as distance increases. Refer to the desmos link above the wiggle bonus calculation diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 2641475810d9..3c926fe18e2c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -242,15 +242,15 @@ private void setDistances(double clockRate) if (lastLastDifficultyObject != null && lastLastDifficultyObject.BaseObject is not Spinner) { - Vector2 lastLastCursorPosition = getEndCursorPosition(lastLastDifficultyObject); + if (lastDifficultyObject!.BaseObject is Slider prevSlider && lastDifficultyObject.TravelDistance > 0) + lastCursorPosition = prevSlider.HeadCircle.StackedPosition; - Vector2 v1 = lastLastCursorPosition - LastObject.StackedPosition; - Vector2 v2 = BaseObject.StackedPosition - lastCursorPosition; + Vector2 lastLastCursorPosition = getEndCursorPosition(lastLastDifficultyObject); - float dot = Vector2.Dot(v1, v2); - float det = v1.X * v2.Y - v1.Y * v2.X; + double angle = calculateAngle(BaseObject.StackedPosition, lastCursorPosition, lastLastCursorPosition); + double sliderAngle = calculateSliderAngle(lastDifficultyObject!, lastLastCursorPosition); - Angle = Math.Abs(Math.Atan2(det, dot)); + Angle = Math.Min(angle, sliderAngle); } } @@ -362,6 +362,30 @@ private void computeSliderCursorPosition() } } + private double calculateSliderAngle(OsuDifficultyHitObject lastDifficultyObject, Vector2 lastLastCursorPosition) + { + Vector2 lastCursorPosition = getEndCursorPosition(lastDifficultyObject); + + if (lastDifficultyObject.BaseObject is Slider prevSlider && lastDifficultyObject.TravelDistance > 0) + { + OsuHitObject secondLastNestedObject = (OsuHitObject)prevSlider.NestedHitObjects[^2]; + lastLastCursorPosition = secondLastNestedObject.StackedPosition; + } + + return calculateAngle(BaseObject.StackedPosition, lastCursorPosition, lastLastCursorPosition); + } + + private double calculateAngle(Vector2 currentPosition, Vector2 lastPosition, Vector2 lastLastPosition) + { + Vector2 v1 = lastLastPosition - lastPosition; + Vector2 v2 = currentPosition - lastPosition; + + float dot = Vector2.Dot(v1, v2); + float det = v1.X * v2.Y - v1.Y * v2.X; + + return Math.Abs(Math.Atan2(det, dot)); + } + private Vector2 getEndCursorPosition(OsuDifficultyHitObject difficultyHitObject) { return difficultyHitObject.LazyEndPosition ?? difficultyHitObject.BaseObject.StackedPosition; From c25820aa571a16424f6cc3d6403e52bc4ead845e Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Sun, 25 Jan 2026 03:49:23 +0500 Subject: [PATCH 545/836] Use correct object for the aim slider bonus (#36216) Currently the slider bonus works on the assumption that the travel velocity of the previous slider is a part of the current object's difficulty because it is part of the movement from prev to curr. However, this is contradicted by the fact that `currVelocity` is a combination of prev->curr + curr slider velocity and is actually breaking the assumption that slider difficulty is contained in the slider itself that we take when calculating difficult slider strains. This makes it so that the slider bonus difficulty is contained in the slider itself instead of buffing the next object, which makes both the calculation overall more consistent and the slider factor calculation actually work as expected. Aim multiplier got slightly lowered because this change makes most of the sliders gain a little bit --------- Co-authored-by: James Wilson --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 4 ++-- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 730bd6bc58fa..4aa45f45293c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -143,10 +143,10 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) / Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime), 2); } - if (osuLastObj.BaseObject is Slider) + if (osuCurrObj.BaseObject is Slider) { // Reward sliders based on velocity. - sliderBonus = osuLastObj.TravelDistance / osuLastObj.TravelTime; + sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; } aimStrain += wiggleBonus * wiggle_multiplier; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index ed106ccfe741..11b84f2d342a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -28,7 +28,7 @@ public Aim(Mod[] mods, bool includeSliders) private double currentStrain; - private double skillMultiplier => 26.7; + private double skillMultiplier => 26.6; private double strainDecayBase => 0.15; private readonly List sliderStrains = new List(); From df1dc46603c21502c6b514f5c079bf649bebf1dd Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Sun, 25 Jan 2026 16:30:01 +0500 Subject: [PATCH 546/836] Move Traceable to difficulty increasing mods section (#35500) TC is a mod that always increases difficulty and is quite similar to HD. Given we even have diffcalc/pp considerations for it it's time to move it to the category it belongs. This doesn't cover any other mods that might need reshuffling too because TC is the only one that has actual impact on difficulty-based leaderboards (as in pp) and some people are actively playing it for the difficulty increase and not just as a fun gimmick. After a quick search turns out it was difficulty increasing from the start but was moved to fun in review https://github.com/ppy/osu/pull/3569#discussion_r300085523 but I don't really agree with that. Also as far as I know multimods don't do anything anymore?.. I've put it into HD multimod for consistency, but can move it to be separate if you want Co-authored-by: Dan Balasescu --- osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index b2a3da285c48..6e9afb493da1 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -21,7 +21,7 @@ public class OsuModTraceable : ModWithVisibilityAdjustment, IRequiresApproachCir public override string Name => "Traceable"; public override string Acronym => "TC"; public override IconUsage? Icon => OsuIcon.ModTraceable; - public override ModType Type => ModType.Fun; + public override ModType Type => ModType.DifficultyIncrease; public override LocalisableString Description => "Put your faith in the approach circles..."; public override double ScoreMultiplier => 1; public override bool Ranked => true; diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 6bb8a187e32c..b2f924ca3bf9 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -175,7 +175,7 @@ public override IEnumerable GetModsFor(ModType type) new OsuModHardRock(), new MultiMod(new OsuModSuddenDeath(), new OsuModPerfect()), new MultiMod(new OsuModDoubleTime(), new OsuModNightcore()), - new OsuModHidden(), + new MultiMod(new OsuModHidden(), new OsuModTraceable()), new MultiMod(new OsuModFlashlight(), new OsuModBlinds()), new OsuModStrictTracking(), new OsuModAccuracyChallenge(), @@ -209,7 +209,6 @@ public override IEnumerable GetModsFor(ModType type) new OsuModSpinIn(), new MultiMod(new OsuModGrow(), new OsuModDeflate()), new MultiMod(new ModWindUp(), new ModWindDown()), - new OsuModTraceable(), new OsuModBarrelRoll(), new OsuModApproachDifferent(), new OsuModMuted(), From 562f1f80046aff46a283cc9a4575301de8af2cc4 Mon Sep 17 00:00:00 2001 From: kwotaq <80002984+kwotaq@users.noreply.github.com> Date: Sun, 25 Jan 2026 22:49:51 +0200 Subject: [PATCH 547/836] Replace current AR and HD bonuses with a new Reading skill on the osu! ruleset (#33196) This PR aims to replace the current bonuses used to award high approach rates and scores made using the Hidden mod with a Reading skill that takes into account each note's reading difficulty separately, Important to note is the fact that as reading difficulty is now a skill the bonuses are now additive instead of multiplicative, meaning there are vast changes in deltas on the high and low end of scores. Due to the nature of adding a new skill new difficulty and performance attributes need to be added. Huis page: [https://pp.huismetbenen.nl/rankings/admin/kwotaq-reading](url) --------- Co-authored-by: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Co-authored-by: js1086 Co-authored-by: tsunyoku Co-authored-by: StanR --- .../Difficulty/Evaluators/ReadingEvaluator.cs | 244 ++++++++++++++++++ .../Difficulty/OsuDifficultyAttributes.cs | 13 + .../Difficulty/OsuDifficultyCalculator.cs | 26 +- .../Difficulty/OsuPerformanceAttributes.cs | 4 + .../Difficulty/OsuPerformanceCalculator.cs | 45 +++- .../Difficulty/OsuRatingCalculator.cs | 111 ++------ .../Preprocessing/OsuDifficultyHitObject.cs | 29 ++- .../Difficulty/Skills/Reading.cs | 107 ++++++++ .../Difficulty/DifficultyAttributes.cs | 2 + 9 files changed, 471 insertions(+), 110 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs create mode 100644 osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs new file mode 100644 index 000000000000..0a45ee5eb7e6 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs @@ -0,0 +1,244 @@ +// 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.Collections.Generic; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Utils; +using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators +{ + public static class ReadingEvaluator + { + private const double reading_window_size = 3000; // 3 seconds + private const double distance_influence_threshold = OsuDifficultyHitObject.NORMALISED_DIAMETER * 1.5; // 1.5 circles distance between centers + private const double hidden_multiplier = 0.28; + private const double density_multiplier = 2.4; + private const double density_difficulty_base = 2.5; + private const double preempt_balancing_factor = 140000; + private const double preempt_starting_point = 500; // AR 9.66 in milliseconds + private const double minimum_angle_relevancy_time = 2000; // 2 seconds + private const double maximum_angle_relevancy_time = 200; + + public static double EvaluateDifficultyOf(DifficultyHitObject current, bool hidden) + { + if (current.BaseObject is Spinner || current.Index == 0) + return 0; + + var currObj = (OsuDifficultyHitObject)current; + var nextObj = (OsuDifficultyHitObject)current.Next(0); + + double velocity = Math.Max(1, currObj.LazyJumpDistance / currObj.AdjustedDeltaTime); // Only allow velocity to buff + + double currentVisibleObjectDensity = retrieveCurrentVisibleObjectDensity(currObj); + double pastObjectDifficultyInfluence = getPastObjectDifficultyInfluence(currObj); + + double constantAngleNerfFactor = getConstantAngleNerfFactor(currObj); + + double noteDensityDifficulty = calculateDensityDifficulty(nextObj, velocity, constantAngleNerfFactor, pastObjectDifficultyInfluence, currentVisibleObjectDensity); + + double hiddenDifficulty = hidden + ? calculateHiddenDifficulty(currObj, pastObjectDifficultyInfluence, currentVisibleObjectDensity, velocity, constantAngleNerfFactor) + : 0; + + double preemptDifficulty = calculatePreemptDifficulty(velocity, constantAngleNerfFactor, currObj.Preempt); + + double difficulty = DifficultyCalculationUtils.Norm(1.5, preemptDifficulty, hiddenDifficulty, noteDensityDifficulty); + + return difficulty; + } + + /// + /// Calculates the density difficulty of the current object and how hard it is to aim it because of it based on: + /// + /// cursor velocity to the current object, + /// how many times the current object's angle was repeated, + /// density of objects visible when the current object appears, + /// density of objects visible when the current object needs to be clicked, + /// /// + /// + private static double calculateDensityDifficulty(OsuDifficultyHitObject? nextObj, double velocity, double constantAngleNerfFactor, + double pastObjectDifficultyInfluence, double currentVisibleObjectDensity) + { + // Consider future densities too because it can make the path the cursor takes less clear + double futureObjectDifficultyInfluence = Math.Sqrt(currentVisibleObjectDensity); + + if (nextObj != null) + { + // Reduce difficulty if movement to next object is small + futureObjectDifficultyInfluence *= DifficultyCalculationUtils.Smootherstep(nextObj.LazyJumpDistance, 15, distance_influence_threshold); + } + + // Value higher note densities exponentially + double noteDensityDifficulty = Math.Pow(pastObjectDifficultyInfluence + futureObjectDifficultyInfluence, 1.7) * 0.4 * constantAngleNerfFactor * velocity; + + // Award only denser than average maps. + noteDensityDifficulty = Math.Max(0, noteDensityDifficulty - density_difficulty_base); + + // Apply a soft cap to general density reading to account for partial memorization + noteDensityDifficulty = Math.Pow(noteDensityDifficulty, 0.45) * density_multiplier; + + return noteDensityDifficulty; + } + + /// + /// Calculates the difficulty of aiming the current object when the approach rate is very high based on: + /// + /// cursor velocity to the current object, + /// how many times the current object's angle was repeated, + /// how many milliseconds elapse between the approach circle appearing and touching the inner circle + /// + /// + private static double calculatePreemptDifficulty(double velocity, double constantAngleNerfFactor, double preempt) + { + // Arbitrary curve for the base value preempt difficulty should have as approach rate increases. + // https://www.desmos.com/calculator/c175335a71 + double preemptDifficulty = Math.Pow((preempt_starting_point - preempt + Math.Abs(preempt - preempt_starting_point)) / 2, 2.5) / preempt_balancing_factor; + + preemptDifficulty *= constantAngleNerfFactor * velocity; + + return preemptDifficulty; + } + + /// + /// Calculates the difficulty of aiming the current object when the hidden mod is active based on: + /// + /// cursor velocity to the current object, + /// time the current object spends invisible, + /// density of objects visible when the current object appears, + /// density of objects visible when the current object needs to be clicked, + /// how many times the current object's angle was repeated, + /// if the current object is perfectly stacked to the previous one + /// + /// + private static double calculateHiddenDifficulty(OsuDifficultyHitObject currObj, double pastObjectDifficultyInfluence, double currentVisibleObjectDensity, double velocity, + double constantAngleNerfFactor) + { + double timeSpentInvisible = currObj.DurationSpentInvisible() / currObj.ClockRate; + + // Value time spent invisible exponentially + double timeSpentInvisibleFactor = Math.Pow(timeSpentInvisible, 2.2) * 0.022; + + // Account for both past and current densities + double densityFactor = Math.Pow(currentVisibleObjectDensity + pastObjectDifficultyInfluence, 3.3) * 3; + + double hiddenDifficulty = (timeSpentInvisibleFactor + densityFactor) * constantAngleNerfFactor * velocity * 0.01; + + // Apply a soft cap to general HD reading to account for partial memorization + hiddenDifficulty = Math.Pow(hiddenDifficulty, 0.4) * hidden_multiplier; + + var previousObj = (OsuDifficultyHitObject)currObj.Previous(0); + + // Buff perfect stacks only if current note is completely invisible at the time you click the previous note. + if (currObj.LazyJumpDistance == 0 && currObj.OpacityAt(previousObj.BaseObject.StartTime + previousObj.Preempt, true) == 0 && previousObj.StartTime + previousObj.Preempt > currObj.StartTime) + hiddenDifficulty += hidden_multiplier * 7500 / Math.Pow(currObj.AdjustedDeltaTime, 1.5); // Perfect stacks are harder the less time between notes + + return hiddenDifficulty; + } + + private static double getPastObjectDifficultyInfluence(OsuDifficultyHitObject currObj) + { + double pastObjectDifficultyInfluence = 0; + + foreach (var loopObj in retrievePastVisibleObjects(currObj)) + { + double loopDifficulty = currObj.OpacityAt(loopObj.BaseObject.StartTime, false); + + // When aiming an object small distances mean previous objects may be cheesed, so it doesn't matter whether they were arranged confusingly. + loopDifficulty *= DifficultyCalculationUtils.Smootherstep(loopObj.LazyJumpDistance, 15, distance_influence_threshold); + + // Account less for objects close to the max reading window + double timeBetweenCurrAndLoopObj = currObj.StartTime - loopObj.StartTime; + double timeNerfFactor = getTimeNerfFactor(timeBetweenCurrAndLoopObj); + + loopDifficulty *= timeNerfFactor; + pastObjectDifficultyInfluence += loopDifficulty; + } + + return pastObjectDifficultyInfluence; + } + + // Returns a list of objects that are visible on screen at the point in time the current object becomes visible. + private static IEnumerable retrievePastVisibleObjects(OsuDifficultyHitObject current) + { + for (int i = 0; i < current.Index; i++) + { + OsuDifficultyHitObject hitObject = (OsuDifficultyHitObject)current.Previous(i); + + if (hitObject.IsNull() || + current.StartTime - hitObject.StartTime > reading_window_size || + hitObject.StartTime + hitObject.Preempt < current.StartTime) // Current object not visible at the time object needs to be clicked + break; + + yield return hitObject; + } + } + + // Returns the density of objects visible at the point in time the current object needs to be clicked capped by the reading window. + private static double retrieveCurrentVisibleObjectDensity(OsuDifficultyHitObject current) + { + double visibleObjectCount = 0; + + OsuDifficultyHitObject? hitObject = (OsuDifficultyHitObject)current.Next(0); + + while (hitObject != null) + { + if (hitObject.StartTime - current.StartTime > reading_window_size || + current.StartTime + hitObject.Preempt < hitObject.StartTime) // Object not visible at the time current object needs to be clicked. + break; + + double timeBetweenCurrAndLoopObj = hitObject.StartTime - current.StartTime; + double timeNerfFactor = getTimeNerfFactor(timeBetweenCurrAndLoopObj); + + visibleObjectCount += hitObject.OpacityAt(current.BaseObject.StartTime, false) * timeNerfFactor; + + hitObject = (OsuDifficultyHitObject?)hitObject.Next(0); + } + + return visibleObjectCount; + } + + // Returns a factor of how often the current object's angle has been repeated in a certain time frame. + // It does this by checking the difference in angle between current and past objects and sums them based on a range of similarity. + // https://www.desmos.com/calculator/eb057a4822 + private static double getConstantAngleNerfFactor(OsuDifficultyHitObject current) + { + double constantAngleCount = 0; + int index = 0; + double currentTimeGap = 0; + + while (currentTimeGap < minimum_angle_relevancy_time) + { + var loopObj = (OsuDifficultyHitObject)current.Previous(index); + + if (loopObj.IsNull()) + break; + + // Account less for objects that are close to the time limit. + double longIntervalFactor = 1 - DifficultyCalculationUtils.ReverseLerp(loopObj.AdjustedDeltaTime, maximum_angle_relevancy_time, minimum_angle_relevancy_time); + + if (loopObj.Angle.IsNotNull() && current.Angle.IsNotNull()) + { + double angleDifference = Math.Abs(current.Angle.Value - loopObj.Angle.Value); + double stackFactor = DifficultyCalculationUtils.Smootherstep(loopObj.LazyJumpDistance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS); + + constantAngleCount += Math.Cos(3 * Math.Min(double.DegreesToRadians(30), angleDifference * stackFactor)) * longIntervalFactor; + } + + currentTimeGap = current.StartTime - loopObj.StartTime; + index++; + } + + return Math.Clamp(2 / constantAngleCount, 0.2, 1); + } + + // Returns a nerfing factor for when objects are very distant in time, affecting reading less. + private static double getTimeNerfFactor(double deltaTime) + { + return Math.Clamp(2 - deltaTime / (reading_window_size / 2), 0, 1); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index be5e0385ee1f..bfbacd0a864b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -45,6 +45,12 @@ public class OsuDifficultyAttributes : DifficultyAttributes [JsonProperty("flashlight_difficulty")] public double FlashlightDifficulty { get; set; } + /// + /// The difficulty corresponding to the reading skill. + /// + [JsonProperty("reading_difficulty")] + public double ReadingDifficulty { get; set; } + /// /// Describes how much of is contributed to by hitcircles or sliders. /// A value closer to 1.0 indicates most of is contributed by hitcircles. @@ -75,6 +81,9 @@ public class OsuDifficultyAttributes : DifficultyAttributes [JsonProperty("speed_difficult_strain_count")] public double SpeedDifficultStrainCount { get; set; } + [JsonProperty("reading_difficult_note_count")] + public double ReadingDifficultNoteCount { get; set; } + [JsonProperty("nested_score_per_object")] public double NestedScorePerObject { get; set; } @@ -106,6 +115,7 @@ public class OsuDifficultyAttributes : DifficultyAttributes yield return (ATTRIB_ID_AIM, AimDifficulty); yield return (ATTRIB_ID_SPEED, SpeedDifficulty); + yield return (ATTRIB_ID_READING, ReadingDifficulty); yield return (ATTRIB_ID_DIFFICULTY, StarRating); if (ShouldSerializeFlashlightDifficulty()) @@ -122,6 +132,7 @@ public class OsuDifficultyAttributes : DifficultyAttributes yield return (ATTRIB_ID_NESTED_SCORE_PER_OBJECT, NestedScorePerObject); yield return (ATTRIB_ID_LEGACY_SCORE_BASE_MULTIPLIER, LegacyScoreBaseMultiplier); yield return (ATTRIB_ID_MAXIMUM_LEGACY_COMBO_SCORE, MaximumLegacyComboScore); + yield return (ATTRIB_ID_READING_DIFFICULT_NOTE_COUNT, ReadingDifficultNoteCount); } public override void FromDatabaseAttributes(IReadOnlyDictionary values, IBeatmapOnlineInfo onlineInfo) @@ -130,6 +141,7 @@ public override void FromDatabaseAttributes(IReadOnlyDictionary val AimDifficulty = values[ATTRIB_ID_AIM]; SpeedDifficulty = values[ATTRIB_ID_SPEED]; + ReadingDifficulty = values[ATTRIB_ID_READING]; StarRating = values[ATTRIB_ID_DIFFICULTY]; FlashlightDifficulty = values.GetValueOrDefault(ATTRIB_ID_FLASHLIGHT); SliderFactor = values[ATTRIB_ID_SLIDER_FACTOR]; @@ -142,6 +154,7 @@ public override void FromDatabaseAttributes(IReadOnlyDictionary val NestedScorePerObject = values[ATTRIB_ID_NESTED_SCORE_PER_OBJECT]; LegacyScoreBaseMultiplier = values[ATTRIB_ID_LEGACY_SCORE_BASE_MULTIPLIER]; MaximumLegacyComboScore = values[ATTRIB_ID_MAXIMUM_LEGACY_COMBO_SCORE]; + ReadingDifficultNoteCount = values[ATTRIB_ID_READING_DIFFICULT_NOTE_COUNT]; HitCircleCount = onlineInfo.CircleCount; SliderCount = onlineInfo.SliderCount; SpinnerCount = onlineInfo.SpinnerCount; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 8230ed060b36..245c4107e958 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -54,13 +54,16 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat var aimWithoutSliders = skills.OfType().Single(a => !a.IncludeSliders); var speed = skills.OfType().Single(); var flashlight = skills.OfType().SingleOrDefault(); + var reading = skills.OfType().Single(); double aimDifficultyValue = aim.DifficultyValue(); double aimNoSlidersDifficultyValue = aimWithoutSliders.DifficultyValue(); double speedDifficultyValue = speed.DifficultyValue(); + double readingDifficultyValue = reading.DifficultyValue(); double aimDifficultStrainCount = aim.CountTopWeightedStrains(aimDifficultyValue); double speedDifficultStrainCount = speed.CountTopWeightedObjectDifficulties(speedDifficultyValue); + double readingDifficultNoteCount = reading.CountTopWeightedObjectDifficulties(readingDifficultyValue); double speedNotes = speed.RelevantNoteCount(); @@ -74,7 +77,6 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat double difficultSliders = aim.GetDifficultSliders(); - double approachRate = CalculateRateAdjustedApproachRate(beatmap.Difficulty.ApproachRate, clockRate); double overallDifficulty = CalculateRateAdjustedOverallDifficulty(beatmap.Difficulty.OverallDifficulty, clockRate); int hitCircleCount = beatmap.HitObjects.Count(h => h is HitCircle); @@ -83,15 +85,15 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat int totalHits = beatmap.HitObjects.Count; - double mechanicalDifficultyRating = calculateMechanicalDifficultyRating(aimDifficultyValue, speedDifficultyValue); double sliderFactor = aimDifficultyValue > 0 ? OsuRatingCalculator.CalculateDifficultyRating(aimNoSlidersDifficultyValue) / OsuRatingCalculator.CalculateDifficultyRating(aimDifficultyValue) : 1; - var osuRatingCalculator = new OsuRatingCalculator(mods, totalHits, approachRate, overallDifficulty, mechanicalDifficultyRating, sliderFactor); + var osuRatingCalculator = new OsuRatingCalculator(mods, totalHits, overallDifficulty); double aimRating = osuRatingCalculator.ComputeAimRating(aimDifficultyValue); double speedRating = osuRatingCalculator.ComputeSpeedRating(speedDifficultyValue); + double readingRating = osuRatingCalculator.ComputeReadingRating(readingDifficultyValue); double flashlightRating = 0.0; @@ -106,9 +108,10 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat double baseAimPerformance = OsuStrainSkill.DifficultyToPerformance(aimRating); double baseSpeedPerformance = HarmonicSkill.DifficultyToPerformance(speedRating); + double baseReadingPerformance = HarmonicSkill.DifficultyToPerformance(readingRating); double baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating); - double basePerformance = DifficultyCalculationUtils.Norm(OsuPerformanceCalculator.PERFORMANCE_NORM_EXPONENT, baseAimPerformance, baseSpeedPerformance, baseFlashlightPerformance); + double basePerformance = DifficultyCalculationUtils.Norm(OsuPerformanceCalculator.PERFORMANCE_NORM_EXPONENT, baseAimPerformance, baseSpeedPerformance, baseReadingPerformance, baseFlashlightPerformance); double starRating = calculateStarRating(basePerformance); @@ -121,9 +124,11 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat SpeedDifficulty = speedRating, SpeedNoteCount = speedNotes, FlashlightDifficulty = flashlightRating, + ReadingDifficulty = readingRating, SliderFactor = sliderFactor, AimDifficultStrainCount = aimDifficultStrainCount, SpeedDifficultStrainCount = speedDifficultStrainCount, + ReadingDifficultNoteCount = readingDifficultNoteCount, AimTopWeightedSliderFactor = aimTopWeightedSliderFactor, SpeedTopWeightedSliderFactor = speedTopWeightedSliderFactor, MaxCombo = beatmap.GetMaxCombo(), @@ -138,16 +143,6 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat return attributes; } - private double calculateMechanicalDifficultyRating(double aimDifficultyValue, double speedDifficultyValue) - { - double aimValue = OsuStrainSkill.DifficultyToPerformance(OsuRatingCalculator.CalculateDifficultyRating(aimDifficultyValue)); - double speedValue = OsuStrainSkill.DifficultyToPerformance(OsuRatingCalculator.CalculateDifficultyRating(speedDifficultyValue)); - - double totalValue = DifficultyCalculationUtils.Norm(OsuPerformanceCalculator.PERFORMANCE_NORM_EXPONENT, aimValue, speedValue); - - return calculateStarRating(totalValue); - } - private double calculateStarRating(double basePerformance) { return Math.Cbrt(basePerformance * OsuPerformanceCalculator.PERFORMANCE_BASE_MULTIPLIER); @@ -173,7 +168,8 @@ protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clo { new Aim(mods, true), new Aim(mods, false), - new Speed(mods) + new Speed(mods), + new Reading(beatmap, mods, clockRate) }; if (mods.Any(h => h is OsuModFlashlight)) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs index 8577eff11ff5..e4a64cd81d6b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs @@ -21,6 +21,9 @@ public class OsuPerformanceAttributes : PerformanceAttributes [JsonProperty("flashlight")] public double Flashlight { get; set; } + [JsonProperty("reading")] + public double Reading { get; set; } + [JsonProperty("effective_miss_count")] public double EffectiveMissCount { get; set; } @@ -48,6 +51,7 @@ public override IEnumerable GetAttributesForDisplay yield return new PerformanceDisplayAttribute(nameof(Speed), "Speed", Speed); yield return new PerformanceDisplayAttribute(nameof(Accuracy), "Accuracy", Accuracy); yield return new PerformanceDisplayAttribute(nameof(Flashlight), "Flashlight Bonus", Flashlight); + yield return new PerformanceDisplayAttribute(nameof(Reading), "Reading", Reading); } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 9d11f07a7da3..87982dfaaa7f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -146,8 +146,9 @@ protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo s double speedValue = computeSpeedValue(score, osuAttributes); double accuracyValue = computeAccuracyValue(score, osuAttributes); double flashlightValue = computeFlashlightValue(score, osuAttributes); + double readingValue = computeReadingValue(osuAttributes); - double totalValue = DifficultyCalculationUtils.Norm(PERFORMANCE_NORM_EXPONENT, aimValue, speedValue, accuracyValue, flashlightValue) * multiplier; + double totalValue = DifficultyCalculationUtils.Norm(PERFORMANCE_NORM_EXPONENT, aimValue, speedValue, accuracyValue, readingValue, flashlightValue) * multiplier; return new OsuPerformanceAttributes { @@ -155,6 +156,7 @@ protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo s Speed = speedValue, Accuracy = accuracyValue, Flashlight = flashlightValue, + Reading = readingValue, EffectiveMissCount = effectiveMissCount, ComboBasedEstimatedMissCount = comboBasedEstimatedMissCount, ScoreBasedEstimatedMissCount = scoreBasedEstimatedMissCount, @@ -213,7 +215,7 @@ private double computeAimValue(ScoreInfo score, OsuDifficultyAttributes attribut aimValue *= 1.3 + (totalHits * (0.0016 / (1 + 2 * effectiveMissCount)) * Math.Pow(accuracy, 16)) * (1 - 0.003 * drainRate * drainRate); else if (score.Mods.Any(m => m is OsuModTraceable)) { - aimValue *= 1.0 + OsuRatingCalculator.CalculateVisibilityBonus(score.Mods, approachRate, sliderFactor: attributes.SliderFactor); + aimValue *= 1.0 + calculateTraceableBonus(attributes.SliderFactor); } aimValue *= accuracy; @@ -245,7 +247,7 @@ private double computeSpeedValue(ScoreInfo score, OsuDifficultyAttributes attrib } else if (score.Mods.Any(m => m is OsuModTraceable)) { - speedValue *= 1.0 + OsuRatingCalculator.CalculateVisibilityBonus(score.Mods, approachRate); + speedValue *= 1.0 + calculateTraceableBonus(); } double speedHighDeviationMultiplier = calculateSpeedHighDeviationNerf(attributes); @@ -294,7 +296,7 @@ private double computeAccuracyValue(ScoreInfo score, OsuDifficultyAttributes att // Increasing the accuracy value by object count for Blinds isn't ideal, so the minimum buff is given. if (score.Mods.Any(m => m is OsuModBlinds)) accuracyValue *= 1.14; - else if (score.Mods.Any(m => m is OsuModHidden || m is OsuModTraceable)) + else if (score.Mods.Any(m => m is OsuModTraceable)) { // Decrease bonus for AR > 10 accuracyValue *= 1 + 0.08 * DifficultyCalculationUtils.ReverseLerp(approachRate, 11.5, 10); @@ -325,6 +327,19 @@ private double computeFlashlightValue(ScoreInfo score, OsuDifficultyAttributes a return flashlightValue; } + private double computeReadingValue(OsuDifficultyAttributes attributes) + { + double readingValue = HarmonicSkill.DifficultyToPerformance(attributes.ReadingDifficulty); + + if (effectiveMissCount > 0) + readingValue *= calculateMissPenalty(effectiveMissCount + aimEstimatedSliderBreaks, attributes.ReadingDifficultNoteCount); + + // Scale the reading value with accuracy _harshly_. + readingValue *= Math.Pow(accuracy, 3); + + return readingValue; + } + private double calculateComboBasedEstimatedMissCount(OsuDifficultyAttributes attributes) { if (attributes.SliderCount <= 0) @@ -488,6 +503,28 @@ private double calculateSpeedHighDeviationNerf(OsuDifficultyAttributes attribute return adjustedSpeedValue / speedValue; } + /// + /// Calculates a visibility bonus that is applicable to Traceable. + /// + private double calculateTraceableBonus(double sliderFactor = 1) + { + // Start from normal curve, rewarding lower AR up to AR7 + double traceableBonus = 0.025 * (12.0 - Math.Max(approachRate, 7)); + + // We want to reward slider aim on low AR less + double sliderVisibilityFactor = Math.Pow(sliderFactor, 3); + + // For AR up to 0 - reduce reward for very low ARs when object is visible + if (approachRate < 7) + traceableBonus += 0.02 * (7.0 - Math.Max(approachRate, 0)) * sliderVisibilityFactor; + + // Starting from AR0 - cap values so they won't grow to infinity + if (approachRate < 0) + traceableBonus += 0.01 * (1 - Math.Pow(1.5, approachRate)) * sliderVisibilityFactor; + + return traceableBonus; + } + // Miss penalty assumes that a player will miss on the hardest parts of a map, // so we use the amount of relatively difficult sections to adjust miss penalty // to make it more punishing on maps with lower amount of hard sections. diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs index 2a050c0920cf..42a6d65cd51f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs @@ -15,19 +15,13 @@ public class OsuRatingCalculator private readonly Mod[] mods; private readonly int totalHits; - private readonly double approachRate; private readonly double overallDifficulty; - private readonly double mechanicalDifficultyRating; - private readonly double sliderFactor; - public OsuRatingCalculator(Mod[] mods, int totalHits, double approachRate, double overallDifficulty, double mechanicalDifficultyRating, double sliderFactor) + public OsuRatingCalculator(Mod[] mods, int totalHits, double overallDifficulty) { this.mods = mods; this.totalHits = totalHits; - this.approachRate = approachRate; this.overallDifficulty = overallDifficulty; - this.mechanicalDifficultyRating = mechanicalDifficultyRating; - this.sliderFactor = sliderFactor; } public double ComputeAimRating(double aimDifficultyValue) @@ -51,26 +45,6 @@ public double ComputeAimRating(double aimDifficultyValue) double ratingMultiplier = 1.0; - double approachRateLengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + - (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); - - double approachRateFactor = 0.0; - if (approachRate > 10.33) - approachRateFactor = 0.3 * (approachRate - 10.33); - else if (approachRate < 8.0) - approachRateFactor = 0.05 * (8.0 - approachRate); - - if (mods.Any(h => h is OsuModRelax)) - approachRateFactor = 0.0; - - ratingMultiplier += approachRateFactor * approachRateLengthBonus; // Buff for longer maps with high AR. - - if (mods.Any(m => m is OsuModHidden)) - { - double visibilityFactor = calculateAimVisibilityFactor(approachRate); - ratingMultiplier += CalculateVisibilityBonus(mods, approachRate, visibilityFactor, sliderFactor); - } - // It is important to consider accuracy difficulty when scaling with accuracy. ratingMultiplier *= 0.98 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 2500; @@ -96,27 +70,34 @@ public double ComputeSpeedRating(double speedDifficultyValue) double ratingMultiplier = 1.0; - double approachRateLengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + - (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); + ratingMultiplier *= 0.95 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 750; - double approachRateFactor = 0.0; - if (approachRate > 10.33) - approachRateFactor = 0.3 * (approachRate - 10.33); + return speedRating * Math.Cbrt(ratingMultiplier); + } - if (mods.Any(m => m is OsuModAutopilot)) - approachRateFactor = 0.0; + public double ComputeReadingRating(double readingDifficultyValue) + { + double readingRating = CalculateDifficultyRating(readingDifficultyValue); + + if (mods.Any(m => m is OsuModTouchDevice)) + readingRating = Math.Pow(readingRating, 0.8); - ratingMultiplier += approachRateFactor * approachRateLengthBonus; // Buff for longer maps with high AR. + if (mods.Any(m => m is OsuModRelax)) + readingRating *= 0.7; + else if (mods.Any(m => m is OsuModAutopilot)) + readingRating *= 0.4; - if (mods.Any(m => m is OsuModHidden)) + if (mods.Any(m => m is OsuModMagnetised)) { - double visibilityFactor = calculateSpeedVisibilityFactor(approachRate); - ratingMultiplier += CalculateVisibilityBonus(mods, approachRate, visibilityFactor); + float magnetisedStrength = mods.OfType().First().AttractionStrength.Value; + readingRating *= 1.0 - magnetisedStrength; } - ratingMultiplier *= 0.95 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 750; + double ratingMultiplier = 1.0; - return speedRating * Math.Cbrt(ratingMultiplier); + ratingMultiplier *= 0.75 + Math.Pow(Math.Max(0, overallDifficulty), 2.2) / 800; + + return readingRating * Math.Cbrt(ratingMultiplier); } public double ComputeFlashlightRating(double flashlightDifficultyValue) @@ -158,56 +139,6 @@ public double ComputeFlashlightRating(double flashlightDifficultyValue) return flashlightRating * Math.Sqrt(ratingMultiplier); } - private double calculateAimVisibilityFactor(double approachRate) - { - const double ar_factor_end_point = 11.5; - - double mechanicalDifficultyFactor = DifficultyCalculationUtils.ReverseLerp(mechanicalDifficultyRating, 5, 10); - double arFactorStartingPoint = double.Lerp(9, 10.33, mechanicalDifficultyFactor); - - return DifficultyCalculationUtils.ReverseLerp(approachRate, ar_factor_end_point, arFactorStartingPoint); - } - - private double calculateSpeedVisibilityFactor(double approachRate) - { - const double ar_factor_end_point = 11.5; - - double mechanicalDifficultyFactor = DifficultyCalculationUtils.ReverseLerp(mechanicalDifficultyRating, 5, 10); - double arFactorStartingPoint = double.Lerp(10, 10.33, mechanicalDifficultyFactor); - - return DifficultyCalculationUtils.ReverseLerp(approachRate, ar_factor_end_point, arFactorStartingPoint); - } - - /// - /// Calculates a visibility bonus that is applicable to Hidden and Traceable. - /// - public static double CalculateVisibilityBonus(Mod[] mods, double approachRate, double visibilityFactor = 1, double sliderFactor = 1) - { - // NOTE: TC's effect is only noticeable in performance calculations until lazer mods are accounted for server-side. - bool isAlwaysPartiallyVisible = mods.OfType().Any(m => m.OnlyFadeApproachCircles.Value) || mods.OfType().Any(); - - // Start from normal curve, rewarding lower AR up to AR7 - // TC forcefully requires a lower reading bonus for now as it's post-applied in PP which makes it multiplicative with the regular AR bonuses - // This means it has an advantage over HD, so we decrease the multiplier to compensate - // This should be removed once we're able to apply TC bonuses in SR (depends on real-time difficulty calculations being possible) - double readingBonus = (isAlwaysPartiallyVisible ? 0.025 : 0.04) * (12.0 - Math.Max(approachRate, 7)); - - readingBonus *= visibilityFactor; - - // We want to reward slideraim on low AR less - double sliderVisibilityFactor = Math.Pow(sliderFactor, 3); - - // For AR up to 0 - reduce reward for very low ARs when object is visible - if (approachRate < 7) - readingBonus += (isAlwaysPartiallyVisible ? 0.02 : 0.045) * (7.0 - Math.Max(approachRate, 0)) * sliderVisibilityFactor; - - // Starting from AR0 - cap values so they won't grow to infinity - if (approachRate < 0) - readingBonus += (isAlwaysPartiallyVisible ? 0.01 : 0.1) * (1 - Math.Pow(1.5, approachRate)) * sliderVisibilityFactor; - - return readingBonus; - } - public static double CalculateDifficultyRating(double difficultyValue) => Math.Sqrt(difficultyValue) * difficulty_multiplier; } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 3c926fe18e2c..00bb4908c6de 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -35,6 +35,17 @@ public class OsuDifficultyHitObject : DifficultyHitObject /// public readonly double AdjustedDeltaTime; + /// + /// Time (in ms) between the object first appearing and the time it needs to be clicked. + /// adjusted by clock rate. + /// + public readonly double Preempt; + + /// + /// Beatmap playback rate. + /// + public readonly double ClockRate; + /// /// Normalised distance from the "lazy" end position of the previous to the start position of this . /// @@ -124,6 +135,9 @@ public OsuDifficultyHitObject(HitObject hitObject, HitObject lastObject, double SmallCircleBonus = Math.Max(1.0, 1.0 + (30 - BaseObject.Radius) / 40); + ClockRate = clockRate; + Preempt = BaseObject.TimePreempt / clockRate; + if (BaseObject is Slider sliderObject) { HitWindowGreat = 2 * sliderObject.HeadCircle.HitWindows.WindowFor(HitResult.Great) / clockRate; @@ -148,7 +162,9 @@ public double OpacityAt(double time, bool hidden) } double fadeInStartTime = BaseObject.StartTime - BaseObject.TimePreempt; - double fadeInDuration = BaseObject.TimeFadeIn; + + // Equal to `OsuHitObject.TimeFadeIn` minus any adjustments from the HD mod. + double fadeInDuration = 400 * Math.Min(1, BaseObject.TimePreempt / OsuHitObject.PREEMPT_MIN); if (hidden) { @@ -166,6 +182,17 @@ public double OpacityAt(double time, bool hidden) return Math.Clamp((time - fadeInStartTime) / fadeInDuration, 0.0, 1.0); } + /// + /// Returns the amount of time a note spends invisible with the hidden mod at the current approach rate. + /// + public double DurationSpentInvisible() + { + double fadeOutStartTime = BaseObject.StartTime - BaseObject.TimePreempt + BaseObject.TimeFadeIn; + double fadeOutDuration = BaseObject.TimePreempt * OsuModHidden.FADE_OUT_DURATION_MULTIPLIER; + + return (fadeOutStartTime + fadeOutDuration) - (BaseObject.StartTime - BaseObject.TimePreempt); + } + /// /// Returns how possible is it to doubletap this object together with the next one and get perfect judgement in range from 0 to 1 /// diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs new file mode 100644 index 000000000000..c475b2cfd817 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs @@ -0,0 +1,107 @@ +// 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.Collections.Generic; +using System.Linq; +using osu.Framework.Utils; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Skills; +using osu.Game.Rulesets.Difficulty.Utils; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Difficulty.Evaluators; +using osu.Game.Rulesets.Osu.Mods; + +namespace osu.Game.Rulesets.Osu.Difficulty.Skills +{ + public class Reading : HarmonicSkill + { + private readonly IReadOnlyList objectList; + + private readonly double clockRate; + private readonly bool hasHiddenMod; + + public Reading(IBeatmap beatmap, Mod[] mods, double clockRate) + : base(mods) + { + this.clockRate = clockRate; + hasHiddenMod = mods.OfType().Any(m => !m.OnlyFadeApproachCircles.Value); + objectList = beatmap.HitObjects; + } + + private double currentDifficulty; + + private double skillMultiplier => 2.5; + private double strainDecayBase => 0.8; + + private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); + + protected override double ObjectDifficultyOf(DifficultyHitObject current) + { + currentDifficulty *= strainDecay(current.DeltaTime); + + currentDifficulty += ReadingEvaluator.EvaluateDifficultyOf(current, hasHiddenMod) * skillMultiplier; + + return currentDifficulty; + } + + protected override void ApplyDifficultyTransformation(double[] difficulties) + { + const double reduced_difficulty_base_line = 0.0; // Assume the first seconds are completely memorised + + if (difficulties.Length == 0) + return; + + int reducedNoteCount = calculateReducedNoteCount(); + + for (int i = 0; i < Math.Min(difficulties.Length, reducedNoteCount); i++) + { + double scale = Math.Log10(Interpolation.Lerp(1, 10, Math.Clamp((double)i / reducedNoteCount, 0, 1))); + difficulties[i] *= Interpolation.Lerp(reduced_difficulty_base_line, 1.0, scale); + } + } + + private int calculateReducedNoteCount() + { + const double reduced_difficulty_duration = 60 * 1000; + + if (objectList.Count < 2) + return 0; + + // We take the 2nd note to match `CreateDifficultyHitObjects` + HitObject firstDifficultyObject = objectList[1]; + + double reducedDuration = (firstDifficultyObject.StartTime / clockRate) + reduced_difficulty_duration; + + int reducedNoteCount = 0; + + foreach (var hitObject in objectList) + { + if (hitObject.StartTime / clockRate > reducedDuration) + break; + + reducedNoteCount++; + } + + return reducedNoteCount; + } + + public override double CountTopWeightedObjectDifficulties(double difficultyValue) + { + if (ObjectDifficulties.Count == 0) + return 0.0; + + if (NoteWeightSum == 0) + return 0.0; + + double consistentTopNote = difficultyValue / NoteWeightSum; // What would the top difficulty be if all object difficulties were identical + + if (consistentTopNote == 0) + return 0; + + return ObjectDifficulties.Sum(d => DifficultyCalculationUtils.Logistic(d / consistentTopNote, 1.15, 5, 1.1)); + } + } +} diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index 5e431dc35728..c98e2137ac10 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -33,6 +33,8 @@ public class DifficultyAttributes protected const int ATTRIB_ID_MAXIMUM_LEGACY_COMBO_SCORE = 41; protected const int ATTRIB_ID_RHYTHM_DIFFICULTY = 43; protected const int ATTRIB_ID_CONSISTENCY_FACTOR = 45; + protected const int ATTRIB_ID_READING = 47; + protected const int ATTRIB_ID_READING_DIFFICULT_NOTE_COUNT = 49; /// /// The mods which were applied to the beatmap. From 0afcebe8bfbe8ec17386197fac3ed90d46d2edf8 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Mon, 26 Jan 2026 02:21:20 +0500 Subject: [PATCH 548/836] Move speed distance bonus to aim (#36168) This doesn't solve _flow_ aim in any way, but makes it so that `Speed` doesn't have distance scaling (read as "aim") anymore which fixes some issues related to that like the length bonus behaving incorrectly, and in general `Speed` being an aim+tap skill instead of just a tapping skill --------- Co-authored-by: James Wilson --- .../Difficulty/Evaluators/RhythmEvaluator.cs | 2 +- .../Evaluators/SpeedAimEvaluator.cs | 50 +++++++++++++++++++ .../Difficulty/Evaluators/SpeedEvaluator.cs | 28 +---------- .../Difficulty/OsuPerformanceCalculator.cs | 2 +- .../Difficulty/Skills/Aim.cs | 34 +++++++++---- .../Difficulty/Skills/Speed.cs | 4 +- 6 files changed, 80 insertions(+), 40 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs index 906ccc1b46dd..1f379901969a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs @@ -16,7 +16,7 @@ public static class RhythmEvaluator private const int history_time_max = 5 * 1000; // 5 seconds private const int history_objects_max = 32; private const double rhythm_overall_multiplier = 1.0; - private const double rhythm_ratio_multiplier = 17.0; + private const double rhythm_ratio_multiplier = 30.0; /// /// Calculates a rhythm multiplier for the difficulty of the tap associated with historic data of the current . diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs new file mode 100644 index 000000000000..c34fdb3236a3 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs @@ -0,0 +1,50 @@ +// 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 osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators +{ + public static class SpeedAimEvaluator + { + private const double single_spacing_threshold = OsuDifficultyHitObject.NORMALISED_DIAMETER * 1.25; // 1.25 circles distance between centers + + /// + /// Evaluates the difficulty of aiming the current object, based on: + /// + /// distance between the previous and current object + /// + /// + public static double EvaluateDifficultyOf(DifficultyHitObject current) + { + if (current.BaseObject is Spinner) + return 0; + + var osuCurrObj = (OsuDifficultyHitObject)current; + var osuPrevObj = current.Index > 0 ? (OsuDifficultyHitObject)current.Previous(0) : null; + + double travelDistance = osuPrevObj?.LazyTravelDistance ?? 0; + double distance = travelDistance + osuCurrObj.LazyJumpDistance; + + // Cap distance at single_spacing_threshold + distance = Math.Min(distance, single_spacing_threshold); + + // Max distance bonus is 1 * `distance_multiplier` at single_spacing_threshold + double distanceBonus = Math.Pow(distance / single_spacing_threshold, 3.95); + + // Apply reduced small circle bonus because flow aim difficulty on small circles doesn't scale as hard as jumps + distanceBonus *= Math.Sqrt(osuCurrObj.SmallCircleBonus); + + double strain = distanceBonus * 1000 / osuCurrObj.AdjustedDeltaTime; + + strain *= highBpmBonus(osuCurrObj.AdjustedDeltaTime); + + return strain; + } + + private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.3, ms / 1000)); + } +} diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs index a35d24d7a8b2..32bf36b0eb96 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs @@ -2,40 +2,31 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; -using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Utils; -using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; -using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { public static class SpeedEvaluator { - private const double single_spacing_threshold = OsuDifficultyHitObject.NORMALISED_DIAMETER * 1.25; // 1.25 circles distance between centers private const double min_speed_bonus = 200; // 200 BPM 1/4th private const double speed_balancing_factor = 40; - private const double distance_multiplier = 0.8; /// /// Evaluates the difficulty of tapping the current object, based on: /// /// time between pressing the previous and current object, - /// distance between those objects, /// and how easily they can be cheesed. /// /// - public static double EvaluateDifficultyOf(DifficultyHitObject current, IReadOnlyList mods) + public static double EvaluateDifficultyOf(DifficultyHitObject current) { if (current.BaseObject is Spinner) return 0; - // derive strainTime for calculation var osuCurrObj = (OsuDifficultyHitObject)current; - var osuPrevObj = current.Index > 0 ? (OsuDifficultyHitObject)current.Previous(0) : null; double strainTime = osuCurrObj.AdjustedDeltaTime; double doubletapness = 1.0 - osuCurrObj.GetDoubletapness((OsuDifficultyHitObject?)osuCurrObj.Next(0)); @@ -51,23 +42,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, IReadOnly if (DifficultyCalculationUtils.MillisecondsToBPM(strainTime) > min_speed_bonus) speedBonus = 0.75 * Math.Pow((DifficultyCalculationUtils.BPMToMilliseconds(min_speed_bonus) - strainTime) / speed_balancing_factor, 2); - double travelDistance = osuPrevObj?.LazyTravelDistance ?? 0; - double distance = travelDistance + osuCurrObj.LazyJumpDistance; - - // Cap distance at single_spacing_threshold - distance = Math.Min(distance, single_spacing_threshold); - - // Max distance bonus is 1 * `distance_multiplier` at single_spacing_threshold - double distanceBonus = Math.Pow(distance / single_spacing_threshold, 3.95) * distance_multiplier; - - // Apply reduced small circle bonus because flow aim difficulty on small circles doesn't scale as hard as jumps - distanceBonus *= Math.Sqrt(osuCurrObj.SmallCircleBonus); - - if (mods.OfType().Any()) - distanceBonus = 0; - // Base difficulty with all bonuses - double difficulty = (1 + speedBonus + distanceBonus) * 1000 / strainTime; + double difficulty = (1 + speedBonus) * 1000 / strainTime; difficulty *= highBpmBonus(osuCurrObj.AdjustedDeltaTime); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 87982dfaaa7f..95bbbd9310f2 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -197,7 +197,7 @@ private double computeAimValue(ScoreInfo score, OsuDifficultyAttributes attribut double aimValue = OsuStrainSkill.DifficultyToPerformance(aimDifficulty); - double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + + double lengthBonus = 0.95 + 0.3 * Math.Min(1.0, totalHits / 2000.0) + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); aimValue *= lengthBonus; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 11b84f2d342a..6a131511ef0a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; @@ -26,28 +27,41 @@ public Aim(Mod[] mods, bool includeSliders) IncludeSliders = includeSliders; } - private double currentStrain; + private double currentAimStrain; + private double currentSpeedStrain; - private double skillMultiplier => 26.6; - private double strainDecayBase => 0.15; + private double skillMultiplierAim => 26.0; + private double skillMultiplierSpeed => 1.3; + private double skillMultiplierTotal => 1.02; + private double meanExponent => 1.2; private readonly List sliderStrains = new List(); - private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); + private double strainDecayAim(double ms) => Math.Pow(0.15, ms / 1000); + private double strainDecaySpeed(double ms) => Math.Pow(0.3, ms / 1000); - protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => currentStrain * strainDecay(time - current.Previous(0).StartTime); + protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => + DifficultyCalculationUtils.Norm(meanExponent, + currentAimStrain * strainDecayAim(time - current.Previous(0).StartTime), + currentSpeedStrain * strainDecaySpeed(time - current.Previous(0).StartTime)); protected override double StrainValueAt(DifficultyHitObject current) { - double decay = strainDecay(((OsuDifficultyHitObject)current).AdjustedDeltaTime); + double decayAim = strainDecayAim(((OsuDifficultyHitObject)current).AdjustedDeltaTime); + double decaySpeed = strainDecaySpeed(((OsuDifficultyHitObject)current).AdjustedDeltaTime); - currentStrain *= decay; - currentStrain += AimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * (1 - decay) * skillMultiplier; + currentAimStrain *= decayAim; + currentAimStrain += AimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * (1 - decayAim) * skillMultiplierAim; + + currentSpeedStrain *= decaySpeed; + currentSpeedStrain += SpeedAimEvaluator.EvaluateDifficultyOf(current) * (1 - decaySpeed) * skillMultiplierSpeed; + + double totalStrain = DifficultyCalculationUtils.Norm(meanExponent, currentAimStrain, currentSpeedStrain); if (current.BaseObject is Slider) - sliderStrains.Add(currentStrain); + sliderStrains.Add(totalStrain); - return currentStrain; + return totalStrain * skillMultiplierTotal; } public double GetDifficultSliders() diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 8911b32f42e9..474091045db9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Speed : HarmonicSkill { - private double skillMultiplier => 0.93; + private double skillMultiplier => 0.95; private readonly List sliderStrains = new List(); @@ -42,7 +42,7 @@ protected override double ObjectDifficultyOf(DifficultyHitObject current) double decay = strainDecay(((OsuDifficultyHitObject)current).AdjustedDeltaTime); currentDifficulty *= decay; - currentDifficulty += SpeedEvaluator.EvaluateDifficultyOf(current, Mods) * (1 - decay) * skillMultiplier; + currentDifficulty += SpeedEvaluator.EvaluateDifficultyOf(current) * (1 - decay) * skillMultiplier; double currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current); From f1f4a0001ba440b3e925928001635bce1eaab370 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jan 2026 15:12:49 +0900 Subject: [PATCH 549/836] Apply new inspections from 2026.1EAP1 Nothing really egregious here so not bothering with PR review. One dodgy bug which has been [reported](https://youtrack.jetbrains.com/issue/RIDER-135036/Incorrect-recursive-on-all-execution-paths-inspection) and temporarily ignored. --- osu.Game.Rulesets.Mania/UI/Stage.cs | 2 +- osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs | 2 +- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 2 +- osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs | 4 ++-- osu.Game.Tests/Database/BeatmapImporterTests.cs | 5 +---- .../Visual/Gameplay/TestSceneSkinEditor.cs | 2 +- .../SongSelectV2/TestSceneBeatmapTitleWedge.cs | 14 +++++++------- .../TestSceneHoldToExitGameOverlay.cs | 10 +++++----- .../TestSceneUpdateableBeatmapBackgroundSprite.cs | 4 ++-- .../TestSceneUpdateableBeatmapSetCover.cs | 4 ++-- .../Screens/Editors/RoundEditorScreen.cs | 2 +- .../Screens/Editors/SeedingEditorScreen.cs | 2 +- .../Screens/Editors/TeamEditorScreen.cs | 2 +- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 6 +++--- osu.Game/Overlays/MusicController.cs | 2 +- osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs | 2 +- osu.Game/Screens/Footer/ScreenStackFooter.cs | 1 + osu.Game/Screens/Menu/OnlineMenuBanner.cs | 2 +- .../Match/RoundResults/SubScreenRoundResults.cs | 2 +- osu.Game/Screens/Ranking/ResultsScreen.cs | 2 +- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- .../SelectV2/RealmPopulatingOnlineLookupSource.cs | 2 +- osu.Game/Screens/SelectV2/SoloSongSelect.cs | 2 +- 23 files changed, 38 insertions(+), 40 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/Stage.cs b/osu.Game.Rulesets.Mania/UI/Stage.cs index faa9fc318c0d..d5a92a986bab 100644 --- a/osu.Game.Rulesets.Mania/UI/Stage.cs +++ b/osu.Game.Rulesets.Mania/UI/Stage.cs @@ -154,7 +154,7 @@ public Stage(int firstColumnIndex, StageDefinition definition, ref ManiaAction c var hitWindows = new ManiaHitWindows(); - AddInternal(judgementPooler = new JudgementPooler(Enum.GetValues().Where(r => hitWindows.IsHitResultAllowed(r)))); + AddInternal(judgementPooler = new JudgementPooler(Enum.GetValues().Where(hitWindows.IsHitResultAllowed))); RegisterPool(50, 200); } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs index 059951789987..51544b0c3822 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs @@ -33,7 +33,7 @@ protected override TestDrawableHitCircle CreateDrawableHitCircle(HitCircle circl Debug.Assert(drawableHitObject.HitObject.HitWindows != null); double delay = drawableHitObject.HitObject.StartTime - (drawableHitObject.HitObject.HitWindows.WindowFor(HitResult.Miss) + RNG.Next(0, 300)) - Time.Current; - scheduledTasks.Add(Scheduler.AddDelayed(() => drawableHitObject.TriggerJudgement(), delay)); + scheduledTasks.Add(Scheduler.AddDelayed(drawableHitObject.TriggerJudgement, delay)); return drawableHitObject; } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index bdcb341fb4ef..db61f27cb2e3 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -194,7 +194,7 @@ private void load(OsuColour colours) var hitWindows = new TaikoHitWindows(); - HitResult[] usableHitResults = Enum.GetValues().Where(r => hitWindows.IsHitResultAllowed(r)).ToArray(); + HitResult[] usableHitResults = Enum.GetValues().Where(hitWindows.IsHitResultAllowed).ToArray(); AddInternal(judgementPooler = new JudgementPooler(usableHitResults)); diff --git a/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs b/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs index bb24560a44c5..73c15e0bcda6 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs @@ -247,7 +247,7 @@ public void TestMultipleHitObjectUpdate() AddStep("change all start times", () => { - editorBeatmap.HitObjectUpdated += h => updatedObjects.Add(h); + editorBeatmap.HitObjectUpdated += updatedObjects.Add; for (int i = 0; i < 10; i++) allHitObjects[i].StartTime += 10; @@ -282,7 +282,7 @@ public void TestDebouncedUpdate() AddStep("change start time twice", () => { - editorBeatmap.HitObjectUpdated += h => updatedObjects.Add(h); + editorBeatmap.HitObjectUpdated += updatedObjects.Add; editorBeatmap.HitObjects[0].StartTime = 10; editorBeatmap.HitObjects[0].StartTime = 20; diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index f3ca66538015..ffe465e71370 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -104,10 +104,7 @@ public void TestUpdateDetachedBeatmapSet() Assert.AreNotEqual(detachedBeatmapSet.Status, BeatmapOnlineStatus.Ranked); detachedBeatmapSet.Status = BeatmapOnlineStatus.Ranked; - beatmapSet.PerformWrite(s => - { - detachedBeatmapSet.CopyChangesToRealm(s); - }); + beatmapSet.PerformWrite(detachedBeatmapSet.CopyChangesToRealm); beatmapSet.PerformRead(s => { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index 3b8e63c5966c..da41349117d3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -151,7 +151,7 @@ public void TestCyclicSelection() { List blueprints = new List(); - AddStep("clear list", () => blueprints.Clear()); + AddStep("clear list", blueprints.Clear); for (int i = 0; i < 3; i++) { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs index cbcf16ec5179..411c6acc82aa 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs @@ -197,15 +197,15 @@ public void TestFavouriting() AddUntilStep("favourites count is 2345", () => this.ChildrenOfType().Single().Text.ToString(), () => Is.EqualTo("2,345")); AddStep("click favourite button", () => this.ChildrenOfType().Single().TriggerClick()); - AddStep("allow request to complete", () => resetEvent.Set()); + AddStep("allow request to complete", resetEvent.Set); AddUntilStep("favourites count is 2346", () => this.ChildrenOfType().Single().Text.ToString(), () => Is.EqualTo("2,346")); - AddStep("reset event", () => resetEvent.Reset()); + AddStep("reset event", resetEvent.Reset); AddStep("click favourite button", () => this.ChildrenOfType().Single().TriggerClick()); - AddStep("allow request to complete", () => resetEvent.Set()); + AddStep("allow request to complete", resetEvent.Set); AddUntilStep("favourites count is 2345", () => this.ChildrenOfType().Single().Text.ToString(), () => Is.EqualTo("2,345")); - AddStep("reset event", () => resetEvent.Reset()); + AddStep("reset event", resetEvent.Reset); AddStep("click favourite button", () => this.ChildrenOfType().Single().TriggerClick()); AddStep("change to another beatmap", () => { @@ -217,7 +217,7 @@ public void TestFavouriting() Beatmap.Value = working; onlineLookupResult.Value = online; }); - AddStep("allow request to complete", () => resetEvent.Set()); + AddStep("allow request to complete", resetEvent.Set); AddUntilStep("favourites count is 9999", () => this.ChildrenOfType().Single().Text.ToString(), () => Is.EqualTo("9,999")); AddStep("set up request handler to fail", () => @@ -239,11 +239,11 @@ public void TestFavouriting() } }; }); - AddStep("reset event", () => resetEvent.Reset()); + AddStep("reset event", resetEvent.Reset); AddStep("click favourite button", () => this.ChildrenOfType().Single().TriggerClick()); AddAssert("spinner visible", () => this.ChildrenOfType().Single() .ChildrenOfType().Single().State.Value, () => Is.EqualTo(Visibility.Visible)); - AddStep("allow request to complete", () => resetEvent.Set()); + AddStep("allow request to complete", resetEvent.Set); AddAssert("spinner hidden", () => this.ChildrenOfType().Single() .ChildrenOfType().Single().State.Value, () => Is.EqualTo(Visibility.Hidden)); } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneHoldToExitGameOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneHoldToExitGameOverlay.cs index df423268b609..fdd1a1172297 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneHoldToExitGameOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneHoldToExitGameOverlay.cs @@ -40,20 +40,20 @@ public TestSceneHoldToExitGameOverlay() firedText }; - AddStep("start confirming", () => overlay.Begin()); - AddStep("abort confirming", () => overlay.Abort()); + AddStep("start confirming", overlay.Begin); + AddStep("abort confirming", overlay.Abort); AddAssert("ensure not fired internally", () => !overlay.Fired); AddAssert("ensure aborted", () => !fired); - AddStep("start confirming", () => overlay.Begin()); + AddStep("start confirming", overlay.Begin); AddUntilStep("wait until confirmed", () => fired); AddAssert("ensure fired internally", () => overlay.Fired); - AddStep("abort after fire", () => overlay.Abort()); + AddStep("abort after fire", overlay.Abort); AddAssert("ensure not fired internally", () => !overlay.Fired); - AddStep("start confirming", () => overlay.Begin()); + AddStep("start confirming", overlay.Begin); AddUntilStep("wait until fired again", () => overlay.Fired); } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs index 48fe517f8a42..5f70c983d1c5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs @@ -133,9 +133,9 @@ public void TestUnloadAndReload() var loadedBackgrounds = backgrounds.Where(b => b.ContentLoaded); - AddUntilStep("some loaded", () => loadedBackgrounds.Any()); + AddUntilStep("some loaded", loadedBackgrounds.Any); AddStep("scroll to bottom", () => scrollContainer.ScrollToEnd()); - AddUntilStep("all unloaded", () => !loadedBackgrounds.Any()); + AddUntilStep("all unloaded", loadedBackgrounds.Any, () => Is.False); } private partial class TestUpdateableBeatmapBackgroundSprite : UpdateableBeatmapBackgroundSprite diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapSetCover.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapSetCover.cs index 54532001a945..6dfb01bb1a37 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapSetCover.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapSetCover.cs @@ -89,9 +89,9 @@ public void TestUnloadAndReload() var loadedCovers = covers.Where(c => c.ChildrenOfType().SingleOrDefault()?.IsLoaded ?? false); - AddUntilStep("some loaded", () => loadedCovers.Any()); + AddUntilStep("some loaded", loadedCovers.Any); AddStep("scroll to end", () => scroll.ScrollToEnd()); - AddUntilStep("all unloaded", () => !loadedCovers.Any()); + AddUntilStep("all unloaded", loadedCovers.Any, () => Is.False); } [Test] diff --git a/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs index 253cca8c981d..6548a26a5119 100644 --- a/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs @@ -98,7 +98,7 @@ public RoundRow(TournamentRound round) Width = 0.2f, Margin = new MarginPadding(10), Text = "Add beatmap", - Action = () => beatmapEditor.CreateNew() + Action = beatmapEditor.CreateNew }, beatmapEditor } diff --git a/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs index 9927dd56a05f..d1e14ecf0cf6 100644 --- a/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs @@ -80,7 +80,7 @@ public SeedingResultRow(TournamentTeam team, SeedingResult round) Width = 0.2f, Margin = new MarginPadding(10), Text = "Add beatmap", - Action = () => beatmapEditor.CreateNew() + Action = beatmapEditor.CreateNew }, beatmapEditor } diff --git a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs index 56333eb2a347..31828d1c4f06 100644 --- a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs @@ -150,7 +150,7 @@ public TeamRow(TournamentTeam team, TournamentScreen parent) new SettingsButton { Text = "Add player", - Action = () => playerEditor.CreateNew() + Action = playerEditor.CreateNew }, new Container { diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index e3ac0e1a3d86..caf8dc048a17 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -170,21 +170,21 @@ private void applySamples(HitObject hitObject) { SampleControlPoint sampleControlPoint = (beatmap.ControlPointInfo as LegacyControlPointInfo)?.SamplePointAt(hitObject.StartTime + CONTROL_POINT_LENIENCY + 1) ?? SampleControlPoint.DEFAULT; - hitObject.Samples = hitObject.Samples.Select(o => sampleControlPoint.ApplyTo(o)).ToList(); + hitObject.Samples = hitObject.Samples.Select(sampleControlPoint.ApplyTo).ToList(); for (int i = 0; i < hasRepeats.NodeSamples.Count; i++) { double time = hitObject.StartTime + i * hasRepeats.Duration / hasRepeats.SpanCount() + CONTROL_POINT_LENIENCY; var nodeSamplePoint = (beatmap.ControlPointInfo as LegacyControlPointInfo)?.SamplePointAt(time) ?? SampleControlPoint.DEFAULT; - hasRepeats.NodeSamples[i] = hasRepeats.NodeSamples[i].Select(o => nodeSamplePoint.ApplyTo(o)).ToList(); + hasRepeats.NodeSamples[i] = hasRepeats.NodeSamples[i].Select(nodeSamplePoint.ApplyTo).ToList(); } } else { SampleControlPoint sampleControlPoint = (beatmap.ControlPointInfo as LegacyControlPointInfo)?.SamplePointAt(hitObject.GetEndTime() + CONTROL_POINT_LENIENCY) ?? SampleControlPoint.DEFAULT; - hitObject.Samples = hitObject.Samples.Select(o => sampleControlPoint.ApplyTo(o)).ToList(); + hitObject.Samples = hitObject.Samples.Select(sampleControlPoint.ApplyTo).ToList(); } } diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 8bb88fc8e9c5..a5550ad3d9a7 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -337,7 +337,7 @@ public void DuckMomentarily(double delayUntilRestore, DuckParameters? parameters IDisposable duckOperation = Duck(parameters); - Scheduler.AddDelayed(() => duckOperation.Dispose(), delayUntilRestore); + Scheduler.AddDelayed(duckOperation.Dispose, delayUntilRestore); } private bool next(bool allowProtectedTracks) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs index 83a5d95bb4f2..19b2757e4c48 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs @@ -208,7 +208,7 @@ private void presentGameplay(bool attemptedBeatmapSwitch) mods.Value = mods.Value.Except(invalid).ToArray(); if (replayGeneratingMod != null) - screen.Push(new EndlessPlayer((beatmap, mods) => replayGeneratingMod.CreateScoreFromReplayData(beatmap, mods))); + screen.Push(new EndlessPlayer(replayGeneratingMod.CreateScoreFromReplayData)); }, new[] { typeof(Player), typeof(SoloSongSelect) }); } diff --git a/osu.Game/Screens/Footer/ScreenStackFooter.cs b/osu.Game/Screens/Footer/ScreenStackFooter.cs index 807dcc3fe0d3..d10a2d8fc48b 100644 --- a/osu.Game/Screens/Footer/ScreenStackFooter.cs +++ b/osu.Game/Screens/Footer/ScreenStackFooter.cs @@ -170,6 +170,7 @@ private class ScreenStackTracker : IDisposable /// /// The screen which should be bound to the screen footer - the most nested subscreen. /// + // ReSharper disable once FunctionRecursiveOnAllPaths (TODO: remove after fixed https://youtrack.jetbrains.com/issue/RIDER-135036/Incorrect-recursive-on-all-execution-paths-inspection) private IScreen leadingScreen => subScreenTracker?.leadingScreen ?? stack.CurrentScreen; public ScreenStackTracker(ScreenStack stack) diff --git a/osu.Game/Screens/Menu/OnlineMenuBanner.cs b/osu.Game/Screens/Menu/OnlineMenuBanner.cs index aa73ce213663..c94a43851245 100644 --- a/osu.Game/Screens/Menu/OnlineMenuBanner.cs +++ b/osu.Game/Screens/Menu/OnlineMenuBanner.cs @@ -70,7 +70,7 @@ private void checkForUpdates() return; var request = new GetMenuContentRequest(); - Task.Run(() => request.Perform()) + Task.Run(request.Perform) .ContinueWith(r => { if (!FetchOnlineContent) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs index 9dc283780a58..882c58317f37 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs @@ -91,7 +91,7 @@ private async Task queryScores() var request = new IndexPlaylistScoresRequest(client.Room.RoomID, client.Room.Settings.PlaylistItemId); request.Success += req => scoreTask.SetResult(req.Scores); - request.Failure += e => scoreTask.SetException(e); + request.Failure += scoreTask.SetException; api.Queue(request); await Task.WhenAll(beatmapTask, scoreTask.Task).ConfigureAwait(false); diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index 8d5e6c05c383..99f7f661cbe3 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -370,7 +370,7 @@ private Task addScores(ScoreInfo[] scores) } // allow a frame for scroll container to adjust its dimensions with the added scores before fetching again. - Schedule(() => tcs.SetResult()); + Schedule(tcs.SetResult); if (ScorePanelList.IsEmpty) { diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 0d75ddb0f0e7..dda62e8ba80f 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -528,7 +528,7 @@ public bool SelectNextRandom() if (!notYetVisitedSets.Any()) { - previouslyVisitedRandomSets.RemoveAll(s => visibleSets.Contains(s)); + previouslyVisitedRandomSets.RemoveAll(visibleSets.Contains); notYetVisitedSets = visibleSets; } diff --git a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs b/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs index 16df414037f4..2b75820587d0 100644 --- a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs +++ b/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs @@ -43,7 +43,7 @@ public partial class RealmPopulatingOnlineLookupSource : Component var request = new GetBeatmapSetRequest(id); var tcs = new TaskCompletionSource(); - token.Register(() => request.Cancel()); + token.Register(request.Cancel); // async request success callback is a bit of a dangerous game, but there's some reasoning for it. // - don't really want to use `IAPIAccess.PerformAsync()` because we still want to respect request queueing & online status checks diff --git a/osu.Game/Screens/SelectV2/SoloSongSelect.cs b/osu.Game/Screens/SelectV2/SoloSongSelect.cs index 697a1f3f555b..cf87a3466f60 100644 --- a/osu.Game/Screens/SelectV2/SoloSongSelect.cs +++ b/osu.Game/Screens/SelectV2/SoloSongSelect.cs @@ -135,7 +135,7 @@ Player createPlayer() if (replayGeneratingMod != null) { - player = new ReplayPlayer((beatmap, mods) => replayGeneratingMod.CreateScoreFromReplayData(beatmap, mods)); + player = new ReplayPlayer(replayGeneratingMod.CreateScoreFromReplayData); } else { From 4ff29339edeaa7013d9b500895758a1974e7769f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jan 2026 18:09:39 +0900 Subject: [PATCH 550/836] Merge pull request #36471 from peppy/fix-previous-username-depth Fix previous usernames display showing underneath other elements --- .../Visual/Online/TestSceneUserProfileOverlay.cs | 1 + .../Header/Components/PreviousUsernamesDisplay.cs | 3 +++ .../Overlays/Profile/Header/TopHeaderContainer.cs | 7 ++++--- osu.Game/Overlays/Profile/ProfileHeader.cs | 13 ++++++++++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index 1c2fdc786096..fd40deab28a8 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -240,6 +240,7 @@ public void TestCustomColourSchemeWithReload() CoverUrl = TestResources.COVER_IMAGE_1, JoinDate = DateTimeOffset.Now.AddDays(-1), LastVisit = DateTimeOffset.Now, + PreviousUsernames = ["ForgetMe", "MySpaceLover", "i once was a man named enis", "mr anderson"], Groups = new[] { new APIUserGroup { Colour = "#EB47D0", ShortName = "DEV", Name = "Developers" }, diff --git a/osu.Game/Overlays/Profile/Header/Components/PreviousUsernamesDisplay.cs b/osu.Game/Overlays/Profile/Header/Components/PreviousUsernamesDisplay.cs index 1cd09566fba4..f286501e6e87 100644 --- a/osu.Game/Overlays/Profile/Header/Components/PreviousUsernamesDisplay.cs +++ b/osu.Game/Overlays/Profile/Header/Components/PreviousUsernamesDisplay.cs @@ -127,6 +127,9 @@ private void onUserChanged(ValueChangedEvent user) Hide(); } + protected override bool OnHover(HoverEvent e) => true; + protected override bool OnClick(ClickEvent e) => true; + protected override void OnHoverLost(HoverLostEvent e) { base.OnHoverLost(e); diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index 3d9539ce1fec..67dce43f04bf 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -48,7 +48,8 @@ public partial class TopHeaderContainer : CompositeDrawable private OsuSpriteText teamText = null!; private GroupBadgeFlow groupBadgeFlow = null!; private ToggleCoverButton coverToggle = null!; - private PreviousUsernamesDisplay previousUsernamesDisplay = null!; + + public PreviousUsernamesDisplay PreviousUsernamesDisplay { get; } = new PreviousUsernamesDisplay(); private Bindable coverExpanded = null!; @@ -149,7 +150,7 @@ private void load(OverlayColourProvider colourProvider, OsuConfigManager configM new Container { // Intentionally use a zero-size container, else the fill flow will adjust to (and cancel) the upwards animation. - Child = previousUsernamesDisplay = new PreviousUsernamesDisplay(), + Child = PreviousUsernamesDisplay, } } }, @@ -254,7 +255,7 @@ private void updateUser(UserProfileData? data) titleText.Text = user?.Title ?? string.Empty; titleText.Colour = Color4Extensions.FromHex(user?.Colour ?? "fff"); groupBadgeFlow.User.Value = user; - previousUsernamesDisplay.User.Value = user; + PreviousUsernamesDisplay.User.Value = user; } private void updateCoverState() diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 42bec5002268..bdcec277af8e 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -20,6 +20,8 @@ public partial class ProfileHeader : TabControlOverlayHeader private CentreHeaderContainer centreHeaderContainer; private DetailHeaderContainer detailHeaderContainer; + private TopHeaderContainer topHeaderContainer = null!; + public ProfileHeader() { ContentSidePadding = WaveOverlayContainer.HORIZONTAL_PADDING; @@ -43,7 +45,7 @@ public ProfileHeader() Direction = FillDirection.Vertical, Children = new Drawable[] { - new TopHeaderContainer + topHeaderContainer = new TopHeaderContainer { RelativeSizeAxes = Axes.X, User = { BindTarget = User }, @@ -75,6 +77,15 @@ public ProfileHeader() } }; + protected override void LoadComplete() + { + base.LoadComplete(); + + // This is basically a tooltip display on hover, so we should display above everything. + // If this ever breaks let's just trash the design and make it a standard tooltip. + AddInternal(topHeaderContainer.PreviousUsernamesDisplay.CreateProxy()); + } + protected override OverlayTitle CreateTitle() => new ProfileHeaderTitle(); protected override Drawable CreateTabControlContent() => new ProfileRulesetSelector From acdb4477f75f728da8c96606acaa57e792e287c1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jan 2026 18:10:04 +0900 Subject: [PATCH 551/836] Fix logs failing to export after multiple failure attempts on file locks (#36469) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even if one file fails, we usually don't care and still want the archive to finish exporting. Closes https://github.com/ppy/osu/issues/36446 --------- Co-authored-by: Bartłomiej Dach --- .../Overlays/Settings/Sections/General/QuickActionSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs index 329324241845..4f988d667fec 100644 --- a/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs @@ -102,7 +102,7 @@ private void exportLogs() using (var zip = ZipArchive.Create()) { foreach (string? f in logStorage.GetFiles(string.Empty, "*.log")) - FileUtils.AttemptOperation(z => z.AddEntry(f, logStorage.GetStream(f), true), zip); + FileUtils.AttemptOperation(z => z.AddEntry(f, logStorage.GetStream(f), closeStream: true), zip, throwOnFailure: false); zip.SaveTo(outStream); } From 02b76db0941e336e10090408ab76e497069ecb78 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Mon, 26 Jan 2026 19:23:44 +0500 Subject: [PATCH 552/836] Move TD difficulty reduction to Aim (#36476) --- .../Difficulty/OsuRatingCalculator.cs | 3 --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs index 42a6d65cd51f..9ddd658d1757 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs @@ -31,9 +31,6 @@ public double ComputeAimRating(double aimDifficultyValue) double aimRating = CalculateDifficultyRating(aimDifficultyValue); - if (mods.Any(m => m is OsuModTouchDevice)) - aimRating = Math.Pow(aimRating, 0.8); - if (mods.Any(m => m is OsuModRelax)) aimRating *= 0.9; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 6a131511ef0a..17e5990895f0 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -10,6 +10,7 @@ using osu.Game.Rulesets.Osu.Difficulty.Evaluators; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Utils; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Difficulty.Skills @@ -50,11 +51,20 @@ protected override double StrainValueAt(DifficultyHitObject current) double decayAim = strainDecayAim(((OsuDifficultyHitObject)current).AdjustedDeltaTime); double decaySpeed = strainDecaySpeed(((OsuDifficultyHitObject)current).AdjustedDeltaTime); + double aimDifficulty = AimEvaluator.EvaluateDifficultyOf(current, IncludeSliders); + double speedDifficulty = SpeedAimEvaluator.EvaluateDifficultyOf(current); + + if (Mods.Any(m => m is OsuModTouchDevice)) + { + aimDifficulty = Math.Pow(aimDifficulty, 0.8); + speedDifficulty = Math.Pow(speedDifficulty, 0.95); + } + currentAimStrain *= decayAim; - currentAimStrain += AimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * (1 - decayAim) * skillMultiplierAim; + currentAimStrain += aimDifficulty * (1 - decayAim) * skillMultiplierAim; currentSpeedStrain *= decaySpeed; - currentSpeedStrain += SpeedAimEvaluator.EvaluateDifficultyOf(current) * (1 - decaySpeed) * skillMultiplierSpeed; + currentSpeedStrain += speedDifficulty * (1 - decaySpeed) * skillMultiplierSpeed; double totalStrain = DifficultyCalculationUtils.Norm(meanExponent, currentAimStrain, currentSpeedStrain); From 9c0b1a4914e9d3b3ef917d34ac0f2c7a6872ec5d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jan 2026 16:01:13 +0900 Subject: [PATCH 553/836] Adjust tooltip response speed and avoid using per-frame transforms --- osu.Game/Graphics/Cursor/OsuTooltipContainer.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs index 0d36cc1d0818..c0f9adac36a1 100644 --- a/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs +++ b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; using osu.Framework.Graphics.Containers; +using osu.Framework.Utils; namespace osu.Game.Graphics.Cursor { @@ -93,10 +94,10 @@ private void load(OsuColour colour) protected override void PopIn() { instantMovement |= !IsPresent; - this.FadeIn(500, Easing.OutQuint); + this.FadeIn(300, Easing.OutQuint); } - protected override void PopOut() => this.Delay(150).FadeOut(500, Easing.OutQuint); + protected override void PopOut() => this.Delay(150).FadeOut(300, Easing.OutQuint); public override void Move(Vector2 pos) { @@ -107,7 +108,8 @@ public override void Move(Vector2 pos) } else { - this.MoveTo(pos, 200, Easing.OutQuint); + // This method is called every frame so we can do this safely here. + Position = Interpolation.ValueAt(Time.Elapsed, Position, pos, 0, 120, Easing.OutQuint); } } } From 9a5fd0addb7f5d399cb95b57355beafd781732d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jan 2026 16:13:41 +0900 Subject: [PATCH 554/836] Remove enabled/disabled text from `FormCheckbox` --- .../Graphics/UserInterfaceV2/FormCheckBox.cs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs index dfe4f6c43912..1447ed4dd783 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs @@ -15,10 +15,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Localisation; -using osu.Game.Graphics.Sprites; -using osu.Game.Localisation; using osu.Game.Overlays; -using osuTK; namespace osu.Game.Graphics.UserInterfaceV2 { @@ -44,7 +41,6 @@ public Bindable Current private Box background = null!; private FormFieldCaption caption = null!; - private OsuSpriteText text = null!; private Sample? sampleChecked; private Sample? sampleUnchecked; @@ -77,13 +73,13 @@ private void load(AudioManager audio) Padding = new MarginPadding(9), Children = new Drawable[] { - new FillFlowContainer + new Container { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, Padding = new MarginPadding { Right = SwitchButton.WIDTH + 5 }, - Spacing = new Vector2(0f, 4f), Children = new Drawable[] { caption = new FormFieldCaption @@ -91,10 +87,6 @@ private void load(AudioManager audio) Caption = Caption, TooltipText = HintText, }, - text = new OsuSpriteText - { - RelativeSizeAxes = Axes.X, - }, }, }, new SwitchButton @@ -159,9 +151,6 @@ protected override bool OnClick(ClickEvent e) private void updateState() { caption.Colour = Current.Disabled ? colourProvider.Background1 : colourProvider.Content2; - text.Colour = Current.Disabled ? colourProvider.Background1 : colourProvider.Content1; - - text.Text = Current.Value ? CommonStrings.Enabled : CommonStrings.Disabled; // use FadeColour to override any existing colour transform (i.e. FlashColour on click). background.FadeColour(IsHovered From 7fef2ce1def802ab73004a081ba9142294b746be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jan 2026 16:17:51 +0900 Subject: [PATCH 555/836] Increase size of caption text --- osu.Game/Graphics/UserInterfaceV2/FormFieldCaption.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormFieldCaption.cs b/osu.Game/Graphics/UserInterfaceV2/FormFieldCaption.cs index 3bc54359b850..958d6e9e0df4 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormFieldCaption.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormFieldCaption.cs @@ -50,7 +50,7 @@ private void load() RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - InternalChild = textFlow = new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(size: 12, weight: FontWeight.SemiBold)) + InternalChild = textFlow = new OsuTextFlowContainer(t => t.Font = OsuFont.Style.Caption1) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, From ae43d3e3b1adf89e2dc59d9be591757d82912b58 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Mon, 26 Jan 2026 23:23:04 +0500 Subject: [PATCH 556/836] Use deviation-based Speed accuracy scaling (#36475) https://pp.huismetbenen.nl/rankings/players/tap-statacc --------- Co-authored-by: James Wilson --- .../Difficulty/OsuPerformanceCalculator.cs | 18 +++++++++--------- .../Difficulty/OsuRatingCalculator.cs | 6 +----- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- .../Difficulty/Skills/Speed.cs | 2 +- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 95bbbd9310f2..a8a024023d30 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -253,15 +253,15 @@ private double computeSpeedValue(ScoreInfo score, OsuDifficultyAttributes attrib double speedHighDeviationMultiplier = calculateSpeedHighDeviationNerf(attributes); speedValue *= speedHighDeviationMultiplier; - // Calculate accuracy assuming the worst case scenario - double relevantTotalDiff = Math.Max(0, totalHits - attributes.SpeedNoteCount); - double relevantCountGreat = Math.Max(0, countGreat - relevantTotalDiff); - double relevantCountOk = Math.Max(0, countOk - Math.Max(0, relevantTotalDiff - countGreat)); - double relevantCountMeh = Math.Max(0, countMeh - Math.Max(0, relevantTotalDiff - countGreat - countOk)); - double relevantAccuracy = attributes.SpeedNoteCount == 0 ? 0 : (relevantCountGreat * 6.0 + relevantCountOk * 2.0 + relevantCountMeh) / (attributes.SpeedNoteCount * 6.0); - - // Scale the speed value with accuracy and OD. - speedValue *= Math.Pow((accuracy + relevantAccuracy) / 2.0, (14.5 - overallDifficulty) / 2); + // An effective hit window is created based on the speed SR. The higher the speed difficulty, the shorter the hit window. + // For example, a speed SR of 3.0 leads to an effective hit window of 20ms, which is OD 10. + double effectiveHitWindow = Math.Sqrt(30 * 60 / attributes.SpeedDifficulty); + + // Find the proportion of 300s on speed notes assuming the hit window was the effective hit window. + double effectiveAccuracy = DifficultyCalculationUtils.Erf(effectiveHitWindow / (double)speedDeviation); + + // Scale speed value by normalized accuracy. + speedValue *= Math.Pow(effectiveAccuracy, 2); return speedValue; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs index 9ddd658d1757..43107c8dce1f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs @@ -65,11 +65,7 @@ public double ComputeSpeedRating(double speedDifficultyValue) speedRating *= 1.0 - magnetisedStrength * 0.3; } - double ratingMultiplier = 1.0; - - ratingMultiplier *= 0.95 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 750; - - return speedRating * Math.Cbrt(ratingMultiplier); + return speedRating; } public double ComputeReadingRating(double readingDifficultyValue) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 17e5990895f0..146ef8167dd9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -33,7 +33,7 @@ public Aim(Mod[] mods, bool includeSliders) private double skillMultiplierAim => 26.0; private double skillMultiplierSpeed => 1.3; - private double skillMultiplierTotal => 1.02; + private double skillMultiplierTotal => 1.01; private double meanExponent => 1.2; private readonly List sliderStrains = new List(); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 474091045db9..b84c85d38aed 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Speed : HarmonicSkill { - private double skillMultiplier => 0.95; + private double skillMultiplier => 1.03; private readonly List sliderStrains = new List(); From ea87e82a919f82a08fbfd8928ef89f4c880417be Mon Sep 17 00:00:00 2001 From: Givy120 <89256026+Givikap120@users.noreply.github.com> Date: Mon, 26 Jan 2026 20:47:08 +0200 Subject: [PATCH 557/836] Make reading and flashlight pp to be LP summed (#36464) Right now they're summed normally what opens a problem that FL rewards too much pp when combined with reading map, since you're memorizing FL anyway. Co-authored-by: James Wilson --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 3 ++- .../Difficulty/OsuPerformanceCalculator.cs | 6 ++++-- osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 245c4107e958..ee6e0dba8514 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -110,8 +110,9 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat double baseSpeedPerformance = HarmonicSkill.DifficultyToPerformance(speedRating); double baseReadingPerformance = HarmonicSkill.DifficultyToPerformance(readingRating); double baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating); + double baseCognitionPerformance = DifficultyCalculationUtils.Norm(2, baseReadingPerformance, baseFlashlightPerformance); - double basePerformance = DifficultyCalculationUtils.Norm(OsuPerformanceCalculator.PERFORMANCE_NORM_EXPONENT, baseAimPerformance, baseSpeedPerformance, baseReadingPerformance, baseFlashlightPerformance); + double basePerformance = DifficultyCalculationUtils.Norm(OsuPerformanceCalculator.PERFORMANCE_NORM_EXPONENT, baseAimPerformance, baseSpeedPerformance, baseCognitionPerformance); double starRating = calculateStarRating(basePerformance); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index a8a024023d30..8ee76814c37d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -145,10 +145,12 @@ protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo s double aimValue = computeAimValue(score, osuAttributes); double speedValue = computeSpeedValue(score, osuAttributes); double accuracyValue = computeAccuracyValue(score, osuAttributes); - double flashlightValue = computeFlashlightValue(score, osuAttributes); + double readingValue = computeReadingValue(osuAttributes); + double flashlightValue = computeFlashlightValue(score, osuAttributes); + double cognitionValue = DifficultyCalculationUtils.Norm(2, readingValue, flashlightValue); - double totalValue = DifficultyCalculationUtils.Norm(PERFORMANCE_NORM_EXPONENT, aimValue, speedValue, accuracyValue, readingValue, flashlightValue) * multiplier; + double totalValue = DifficultyCalculationUtils.Norm(PERFORMANCE_NORM_EXPONENT, aimValue, speedValue, accuracyValue, cognitionValue) * multiplier; return new OsuPerformanceAttributes { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index 70d61250bbf1..44c39cbb9cd0 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -20,7 +20,7 @@ public Flashlight(Mod[] mods) { } - private double skillMultiplier => 0.05512; + private double skillMultiplier => 0.056; private double strainDecayBase => 0.15; private double currentStrain; From c88f10ca1bfc805ea1c659be039f0003ed5d0eed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jan 2026 16:31:03 +0900 Subject: [PATCH 558/836] Standardise background across form controls --- .../Graphics/UserInterfaceV2/FormButton.cs | 36 ++---- .../Graphics/UserInterfaceV2/FormCheckBox.cs | 26 +--- .../UserInterfaceV2/FormColourPalette.cs | 17 +-- .../UserInterfaceV2/FormControlBackground.cs | 114 ++++++++++++++++++ .../Graphics/UserInterfaceV2/FormDropdown.cs | 68 ++++++----- .../UserInterfaceV2/FormFileSelector.cs | 33 +---- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 24 +--- .../Graphics/UserInterfaceV2/FormTextBox.cs | 29 +---- 8 files changed, 181 insertions(+), 166 deletions(-) create mode 100644 osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs diff --git a/osu.Game/Graphics/UserInterfaceV2/FormButton.cs b/osu.Game/Graphics/UserInterfaceV2/FormButton.cs index 7b95a7e976a1..3b4f0e34483c 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormButton.cs @@ -9,11 +9,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Localisation; -using osu.Framework.Utils; using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -70,8 +68,7 @@ public Color4? BackgroundColour [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; - private Container content = null!; - private Box background = null!; + private FormControlBackground background = null!; private OsuTextFlowContainer text = null!; private Button button = null!; @@ -81,7 +78,7 @@ private void load() RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - InternalChild = content = new Container + InternalChild = new Container { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -90,17 +87,7 @@ private void load() CornerExponent = 2.5f, Children = new Drawable[] { - background = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5, - }, - new TrianglesV2 - { - SpawnRatio = 0.5f, - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(colourProvider.Background4, colourProvider.Background5), - }, + background = new FormControlBackground(), new HoverClickSounds(HoverSampleSet.Button) { Enabled = { BindTarget = Enabled }, @@ -175,7 +162,7 @@ protected override bool OnClick(ClickEvent e) { if (Enabled.Value) { - background.FlashColour(ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark2), 800, Easing.OutQuint); + background.Flash(); button.TriggerClick(); } @@ -186,19 +173,10 @@ private void updateState() { text.Colour = Enabled.Value ? colourProvider.Content1 : colourProvider.Background1; - background.FadeColour(IsHovered - ? ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4) - : colourProvider.Background5, 200, Easing.OutQuint); + background.StyleHovered = IsHovered; + background.StyleDisabled = !Enabled.Value; - content.BorderThickness = IsHovered ? 2 : 0; - - if (BackgroundColour != null) - { - button.BackgroundColour = BackgroundColour.Value; - content.BorderColour = Enabled.Value ? BackgroundColour.Value : Interpolation.ValueAt(0.75, BackgroundColour.Value, colourProvider.Dark1, 0, 1); - } - else - content.BorderColour = Enabled.Value ? colourProvider.Light4 : colourProvider.Dark1; + // TODO: Support BackgroundColour? } public partial class Button : OsuButton diff --git a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs index 1447ed4dd783..2b751d98e50c 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs @@ -9,9 +9,7 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Localisation; @@ -39,7 +37,7 @@ public Bindable Current /// public LocalisableString HintText { get; init; } - private Box background = null!; + private FormControlBackground background = null!; private FormFieldCaption caption = null!; private Sample? sampleChecked; @@ -55,17 +53,9 @@ private void load(AudioManager audio) RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Masking = true; - CornerRadius = 5; - CornerExponent = 2.5f; - InternalChildren = new Drawable[] { - background = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5, - }, + background = new FormControlBackground(), new Container { RelativeSizeAxes = Axes.X, @@ -111,7 +101,7 @@ protected override void LoadComplete() { updateState(); playSamples(); - background.FlashColour(ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark2), 800, Easing.OutQuint); + background.Flash(); ValueChanged?.Invoke(); }); @@ -151,14 +141,8 @@ protected override bool OnClick(ClickEvent e) private void updateState() { caption.Colour = Current.Disabled ? colourProvider.Background1 : colourProvider.Content2; - - // use FadeColour to override any existing colour transform (i.e. FlashColour on click). - background.FadeColour(IsHovered - ? ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4) - : colourProvider.Background5); - - BorderThickness = IsHovered ? 2 : 0; - BorderColour = Current.Disabled ? colourProvider.Dark1 : colourProvider.Light4; + background.StyleHovered = IsHovered; + background.StyleDisabled = IsDisabled; } public IEnumerable FilterTerms => Caption.Yield(); diff --git a/osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs index 90e12b128c44..2f1c72fcc91c 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs @@ -33,7 +33,7 @@ public partial class FormColourPalette : CompositeDrawable public BindableBool CanAdd { get; } = new BindableBool(true); - private Box background = null!; + private FormControlBackground background = null!; private FormFieldCaption caption = null!; private FillFlowContainer flow = null!; private RoundedButton addButton = null!; @@ -47,16 +47,9 @@ private void load() RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Masking = true; - CornerRadius = 5; - InternalChildren = new Drawable[] { - background = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5, - }, + background = new FormControlBackground(), new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -140,13 +133,9 @@ private void addNewColour() private void updateState() { - background.Colour = colourProvider.Background5; caption.Colour = colourProvider.Content2; - BorderThickness = IsHovered ? 2 : 0; - - if (IsHovered) - BorderColour = colourProvider.Light4; + background.StyleHovered = IsHovered; } private void updateColours() diff --git a/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs b/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs new file mode 100644 index 000000000000..a4006f481e7e --- /dev/null +++ b/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs @@ -0,0 +1,114 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Overlays; +using osuTK.Graphics; + +namespace osu.Game.Graphics.UserInterfaceV2 +{ + public partial class FormControlBackground : CompositeDrawable + { + private bool styleDisabled; + + public bool StyleDisabled + { + set + { + styleDisabled = value; + updateStyling(); + } + } + + private bool styleFocused; + + public bool StyleFocused + { + set + { + styleFocused = value; + updateStyling(); + } + } + + private bool styleHovered; + + public bool StyleHovered + { + set + { + styleHovered = value; + updateStyling(); + } + } + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + private readonly Box box; + + public FormControlBackground() + { + RelativeSizeAxes = Axes.Both; + + Masking = true; + CornerRadius = 5; + CornerExponent = 2.5f; + + InternalChildren = new Drawable[] + { + box = new Box + { + Colour = Color4.White, + RelativeSizeAxes = Axes.Both, + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + updateStyling(); + FinishTransforms(true); + } + + public void Flash() + { + box.FlashColour(ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark2), 800, Easing.OutQuint); + } + + private void updateStyling() + { + ColourInfo colour = colourProvider.Background5; + ColourInfo borderColour = colourProvider.Light4; + bool border = false; + + if (styleDisabled) + { + colour = colourProvider.Background4; + borderColour = colourProvider.Dark1; + } + else if (styleFocused) + { + colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); + border = true; + borderColour = colourProvider.Highlight1; + } + else if (styleHovered) + { + colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); + border = true; + } + + BorderThickness = border ? 2 : 0; + BorderColour = borderColour; + + box.FadeColour(colour, 500, Easing.OutQuint); + } + } +} diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index 60b8700dc81e..e970459037f8 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -145,6 +145,7 @@ protected override LocalisableString Label private FormFieldCaption caption = null!; private OsuSpriteText label = null!; private SpriteIcon chevron = null!; + private FormControlBackground background = null!; [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -157,38 +158,50 @@ private void load() Margin = new MarginPadding { Bottom = header_menu_spacing }; - Foreground.Padding = new MarginPadding(9); + // We use our own background for more control. + Background.Alpha = 0; + Foreground.Children = new Drawable[] { - new FillFlowContainer + background = new FormControlBackground(), + new Container { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 4), + Padding = new MarginPadding(9), Children = new Drawable[] { - caption = new FormFieldCaption + new FillFlowContainer { - Caption = Caption, - TooltipText = HintText, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 4), + Children = new Drawable[] + { + caption = new FormFieldCaption + { + Caption = Caption, + TooltipText = HintText, + }, + label = new TruncatingSpriteText + { + RelativeSizeAxes = Axes.X, + Padding = new MarginPadding { Right = 25 }, + AlwaysPresent = true, + }, + } }, - label = new TruncatingSpriteText + chevron = new SpriteIcon { - RelativeSizeAxes = Axes.X, - Padding = new MarginPadding { Right = 25 }, - AlwaysPresent = true, + Icon = FontAwesome.Solid.ChevronDown, + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Size = new Vector2(16), + Margin = new MarginPadding { Right = 5 }, }, } }, - chevron = new SpriteIcon - { - Icon = FontAwesome.Solid.ChevronDown, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Size = new Vector2(16), - Margin = new MarginPadding { Right = 5 }, - }, }; AddInternal(new HoverClickSounds @@ -240,25 +253,16 @@ private void updateState() else label.Alpha = 1; - BorderThickness = IsHovered || dropdownOpen ? 2 : 0; - - if (Dropdown.Current.Disabled) - BorderColour = colourProvider.Dark1; - else - BorderColour = dropdownOpen ? colourProvider.Highlight1 : colourProvider.Light4; - - if (dropdownOpen) - Background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); - else if (IsHovered) - Background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); - else - Background.Colour = colourProvider.Background5; + background.StyleDisabled = Dropdown.Current.Disabled; + background.StyleHovered = IsHovered; + background.StyleFocused = dropdownOpen; } private void updateChevron() { bool open = Dropdown.Menu.State == MenuState.Open; chevron.ScaleTo(open ? new Vector2(1f, -1f) : Vector2.One, 300, Easing.OutQuint); + chevron.MoveToY(open ? -chevron.DrawHeight : 0, 300, Easing.OutQuint); } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs b/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs index 8f402e4da9e3..5cafdc365050 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs @@ -11,7 +11,6 @@ using osu.Framework.Extensions; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; @@ -70,7 +69,7 @@ public Bindable Current public Container PreviewContainer { get; private set; } = null!; - private Box background = null!; + private FormControlBackground background = null!; private FormFieldCaption caption = null!; private OsuSpriteText placeholderText = null!; @@ -93,16 +92,9 @@ private void load() RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Masking = true; - CornerRadius = 5; - InternalChildren = new Drawable[] { - background = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5, - }, + background = new FormControlBackground(), PreviewContainer = new Container { RelativeSizeAxes = Axes.X, @@ -194,7 +186,7 @@ private void onFileSelected() initialChooserPath = Current.Value?.DirectoryName; placeholderText.Alpha = Current.Value == null ? 1 : 0; filenameText.Text = Current.Value?.Name ?? string.Empty; - background.FlashColour(ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark2), 800, Easing.OutQuint); + background.Flash(); } protected override bool OnClick(ClickEvent e) @@ -220,22 +212,9 @@ private void updateState() caption.Colour = Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content2; filenameText.Colour = Current.Disabled || Current.Value == null ? colourProvider.Foreground1 : colourProvider.Content1; - if (!Current.Disabled) - { - BorderThickness = IsHovered || popoverState.Value == Visibility.Visible ? 2 : 0; - BorderColour = popoverState.Value == Visibility.Visible ? colourProvider.Highlight1 : colourProvider.Light4; - - if (popoverState.Value == Visibility.Visible) - background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); - else if (IsHovered) - background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); - else - background.Colour = colourProvider.Background5; - } - else - { - background.Colour = colourProvider.Background4; - } + background.StyleDisabled = Current.Disabled; + background.StyleFocused = popoverState.Value == Visibility.Visible; + background.StyleHovered = IsHovered; } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 07cdbfe50d4a..9571dd4d8677 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -121,7 +121,7 @@ public float KeyboardStep /// public Func TooltipFormat { get; init; } - private Box background = null!; + private FormControlBackground background = null!; private Box flashLayer = null!; private FormTextBox.InnerTextBox textBox = null!; private OsuSpriteText valueLabel = null!; @@ -202,11 +202,7 @@ private void load(OsuColour colours, OsuGame? game) InternalChildren = new Drawable[] { - background = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5, - }, + background = new FormControlBackground(), flashLayer = new Box { RelativeSizeAxes = Axes.Both, @@ -398,19 +394,9 @@ private void updateState() textBox.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background1 : colourProvider.Content1; valueLabel.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background1 : colourProvider.Content1; - BorderThickness = childHasFocus || IsHovered || slider.IsDragging.Value ? 2 : 0; - - if (Current.Disabled) - BorderColour = colourProvider.Dark1; - else - BorderColour = childHasFocus ? colourProvider.Highlight1 : colourProvider.Light4; - - if (childHasFocus) - background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); - else if (IsHovered || slider.IsDragging.Value) - background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); - else - background.Colour = colourProvider.Background5; + background.StyleDisabled = Current.Disabled; + background.StyleFocused = childHasFocus; + background.StyleHovered = IsHovered || slider.IsDragging.Value; } private void updateValueDisplay() diff --git a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs index b85ee3d2c8fe..8efa71f15fa5 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs @@ -77,7 +77,7 @@ public CompositeDrawable? TabbableContentContainer /// public LocalisableString PlaceholderText { get; init; } - private Box background = null!; + private FormControlBackground background = null!; private Box flashLayer = null!; private InnerTextBox textBox = null!; private FormFieldCaption caption = null!; @@ -92,17 +92,9 @@ private void load(OsuColour colours) RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Masking = true; - CornerRadius = 5; - CornerExponent = 2.5f; - InternalChildren = new Drawable[] { - background = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5, - }, + background = new FormControlBackground(), flashLayer = new Box { RelativeSizeAxes = Axes.Both, @@ -193,19 +185,9 @@ private void updateState() caption.Colour = disabled ? colourProvider.Background1 : colourProvider.Content2; textBox.Colour = disabled ? colourProvider.Foreground1 : colourProvider.Content1; - BorderThickness = IsHovered || textBox.Focused.Value ? 2 : 0; - - if (disabled) - BorderColour = colourProvider.Dark1; - else - BorderColour = textBox.Focused.Value ? colourProvider.Highlight1 : colourProvider.Light4; - - if (textBox.Focused.Value) - background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); - else if (IsHovered) - background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); - else - background.Colour = colourProvider.Background5; + background.StyleDisabled = Current.Disabled; + background.StyleFocused = textBox.Focused.Value; + background.StyleHovered = IsHovered; } internal partial class InnerTextBox : OsuTextBox @@ -221,7 +203,6 @@ private void load() { Height = 16; TextContainer.Height = 1; - Masking = false; BackgroundUnfocused = BackgroundFocused = BackgroundCommit = Colour4.Transparent; } From 1c537a32781f2b8f2d88ac27b44762cad7700b16 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jan 2026 19:40:50 +0900 Subject: [PATCH 559/836] Make switch buttons look more like old version --- .../Graphics/UserInterfaceV2/SwitchButton.cs | 77 ++++++------------- 1 file changed, 23 insertions(+), 54 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs index ce4b1e93c743..0ad912bcb93c 100644 --- a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs @@ -19,14 +19,9 @@ namespace osu.Game.Graphics.UserInterfaceV2 { public partial class SwitchButton : Checkbox { - public const float WIDTH = 45; - - private const float border_thickness = 4.5f; - private const float padding = 1.25f; + public const float WIDTH = 60; private readonly Box fill; - private readonly Container nubContainer; - private readonly Drawable nub; private readonly CircularContainer content; [Resolved] @@ -41,9 +36,11 @@ public SwitchButton() InternalChild = content = new CircularContainer { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, BorderColour = Color4.White, - BorderThickness = border_thickness, + BorderThickness = 4, Masking = true, Children = new Drawable[] { @@ -52,21 +49,6 @@ public SwitchButton() RelativeSizeAxes = Axes.Both, AlwaysPresent = true, }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(border_thickness + padding), - Child = nubContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Child = nub = new Circle - { - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fit, - Masking = true, - } - } - } } }; } @@ -82,28 +64,21 @@ protected override void LoadComplete() { base.LoadComplete(); - Current.BindDisabledChanged(_ => updateColours()); + Current.BindDisabledChanged(_ => updateState()); Current.BindValueChanged(_ => updateState(), true); FinishTransforms(true); } - private void updateState() - { - nub.MoveToX(Current.Value ? nubContainer.DrawWidth - nub.DrawWidth : 0, 200, Easing.OutQuint); - - updateColours(); - } - protected override bool OnHover(HoverEvent e) { - updateColours(); + updateState(); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - updateColours(); + updateState(); base.OnHoverLost(e); } @@ -121,35 +96,29 @@ public void PlaySample(bool value) sampleUnchecked?.Play(); } - private void updateColours() + private void updateState() { - ColourInfo borderColour; - ColourInfo switchColour; + Color4 fillColour = colourProvider.Background6; + Color4 borderColour = colourProvider.Light4; + + if (IsHovered) + borderColour = colourProvider.Highlight1; + else if (Current.Value) + borderColour = colourProvider.Highlight1.Darken(0.1f); + + if (Current.Value) + fillColour = borderColour; if (Current.Disabled) { - borderColour = colourProvider.Dark2; - switchColour = colourProvider.Dark1; - fill.Colour = colourProvider.Dark5; + fillColour = fillColour.Darken(0.4f); + borderColour = borderColour.Darken(0.4f); } - else - { - bool hover = IsHovered && !Current.Disabled; - - borderColour = hover ? colourProvider.Highlight1.Opacity(0.5f) : colourProvider.Highlight1.Opacity(0.3f); - switchColour = hover || Current.Value ? colourProvider.Highlight1 : colourProvider.Light4; - if (!Current.Value) - { - borderColour = borderColour.MultiplyAlpha(0.8f); - switchColour = switchColour.MultiplyAlpha(0.8f); - } - - fill.Colour = Current.Value ? colourProvider.Colour4.Darken(0.2f) : colourProvider.Background6; - } + fill.FadeColour(fillColour, 250, Easing.OutQuint); - nubContainer.FadeColour(switchColour, 250, Easing.OutQuint); - content.TransformTo(nameof(BorderColour), borderColour, 250, Easing.OutQuint); + content.TransformTo(nameof(BorderColour), (ColourInfo)borderColour, 250, Easing.OutQuint); + content.ResizeWidthTo(Current.Value ? 1 : 0.75f, 250, Easing.OutQuint); } } } From 3db3b603bc01ee38707c72f41ac9285fba7485c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jan 2026 20:08:55 +0900 Subject: [PATCH 560/836] Fix revert button height --- osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs | 2 -- osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index 98a6d2600f2b..777f63069540 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -136,8 +136,6 @@ private void load(OverlayColourProvider colourProvider, AudioManager audioManage { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Height = 1, - RelativeSizeAxes = Axes.Y, IconSize = 12, Action = RestoreDefaults, }, diff --git a/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs b/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs index fd95277446a6..bc2563383336 100644 --- a/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs +++ b/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs @@ -31,7 +31,8 @@ public partial class SettingsRevertToDefaultButton : OsuClickableContainer public SettingsRevertToDefaultButton() { - Size = new Vector2(WIDTH, 50); + RelativeSizeAxes = Axes.Y; + Width = WIDTH; } [BackgroundDependencyLoader] From 585ce682efd897db1c68c115fc1ef6375644e232 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jan 2026 20:09:03 +0900 Subject: [PATCH 561/836] Fix button spacing being weirdly small --- osu.Game/Overlays/Settings/SettingsButtonV2.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/SettingsButtonV2.cs b/osu.Game/Overlays/Settings/SettingsButtonV2.cs index 4d5e1d5c5950..18d1c47d7a0c 100644 --- a/osu.Game/Overlays/Settings/SettingsButtonV2.cs +++ b/osu.Game/Overlays/Settings/SettingsButtonV2.cs @@ -16,7 +16,6 @@ public partial class SettingsButtonV2 : RoundedButton, IConditionalFilterable public SettingsButtonV2() { RelativeSizeAxes = Axes.X; - Margin = new MarginPadding { Vertical = -1.5f }; Padding = SettingsPanel.CONTENT_PADDING; } From 69832272400a122d28944f2a5fa38b8c000357ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jan 2026 20:50:20 +0900 Subject: [PATCH 562/836] Various metrics and visual tweaks --- .../UserInterfaceV2/FormControlBackground.cs | 11 +++-- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 20 ++++++--- .../Graphics/UserInterfaceV2/SwitchButton.cs | 15 ++++--- .../Audio/AudioOffsetAdjustControl.cs | 44 +++++++++---------- .../Settings/Sections/InputSubsection.cs | 15 ++++--- osu.Game/Overlays/Settings/SettingsItemV2.cs | 1 + osu.Game/Overlays/Settings/SettingsNote.cs | 4 +- osu.Game/Overlays/Settings/SettingsSection.cs | 2 +- 8 files changed, 64 insertions(+), 48 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs b/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs index a4006f481e7e..7b9c5c49922f 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; @@ -59,6 +60,8 @@ public FormControlBackground() CornerRadius = 5; CornerExponent = 2.5f; + BorderThickness = 2.5f; + InternalChildren = new Drawable[] { box = new Box @@ -84,8 +87,9 @@ public void Flash() private void updateStyling() { - ColourInfo colour = colourProvider.Background5; + ColourInfo colour = colourProvider.Background4.Darken(0.1f); ColourInfo borderColour = colourProvider.Light4; + bool border = false; if (styleDisabled) @@ -105,10 +109,9 @@ private void updateStyling() border = true; } - BorderThickness = border ? 2 : 0; - BorderColour = borderColour; + this.TransformTo(nameof(BorderColour), border ? borderColour : colour, 250, Easing.OutQuint); - box.FadeColour(colour, 500, Easing.OutQuint); + box.FadeColour(colour, 250, Easing.OutQuint); } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 9571dd4d8677..95c5fc1b54b4 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -22,6 +22,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays; +using osuTK.Graphics; using Vector2 = osuTK.Vector2; namespace osu.Game.Graphics.UserInterfaceV2 @@ -325,8 +326,7 @@ private void textCommitted(TextBox t, bool isNew) currentNumberInstantaneous.TriggerChange(); current.Value = currentNumberInstantaneous.Value; - flashLayer.Colour = ColourInfo.GradientVertical(colourProvider.Dark2.Opacity(0), colourProvider.Dark2); - flashLayer.FadeOutFromOne(800, Easing.OutQuint); + background.Flash(); } private void tryUpdateSliderFromTextBox() @@ -502,7 +502,9 @@ private void load() protected override void LoadComplete() { base.LoadComplete(); + Current.BindDisabledChanged(_ => updateState(), true); + FinishTransforms(true); } protected override void UpdateAfterChildren() @@ -558,16 +560,22 @@ private void updateState() sounds.Enabled.Value = !Current.Disabled; rightBox.Colour = colourProvider.Background6; + Color4 leftColour; + Color4 nubColour; + if (Current.Disabled) { - leftBox.Colour = colourProvider.Dark3; - nub.Colour = colourProvider.Dark1; + leftColour = colourProvider.Dark3; + nubColour = colourProvider.Dark1; } else { - leftBox.Colour = HasFocus || IsHovered || IsDragged ? colourProvider.Highlight1.Opacity(0.5f) : colourProvider.Highlight1.Opacity(0.3f); - nub.Colour = HasFocus || IsHovered || IsDragged ? colourProvider.Highlight1 : colourProvider.Light4; + leftColour = HasFocus || IsHovered || IsDragged ? colourProvider.Highlight1.Opacity(0.5f) : colourProvider.Highlight1.Opacity(0.3f); + nubColour = HasFocus || IsHovered || IsDragged ? colourProvider.Highlight1 : colourProvider.Light4; } + + leftBox.FadeColour(leftColour, 250, Easing.OutQuint); + nub.FadeColour(nubColour, 250, Easing.OutQuint); } protected override void UpdateValue(float value) diff --git a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs index 0ad912bcb93c..3afb6d756bc8 100644 --- a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs @@ -19,20 +19,22 @@ namespace osu.Game.Graphics.UserInterfaceV2 { public partial class SwitchButton : Checkbox { - public const float WIDTH = 60; + public const float WIDTH = 56; private readonly Box fill; - private readonly CircularContainer content; + private readonly Container content; [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; + public bool ExpandOnCurrent { get; init; } = true; + private Sample? sampleChecked; private Sample? sampleUnchecked; public SwitchButton() { - Size = new Vector2(WIDTH, 20); + Size = new Vector2(WIDTH, 16); InternalChild = content = new CircularContainer { @@ -40,8 +42,9 @@ public SwitchButton() Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, BorderColour = Color4.White, - BorderThickness = 4, + BorderThickness = 3.2f, Masking = true, + CornerExponent = 2.5f, Children = new Drawable[] { fill = new Box @@ -98,7 +101,7 @@ public void PlaySample(bool value) private void updateState() { - Color4 fillColour = colourProvider.Background6; + Color4 fillColour = colourProvider.Background5.Opacity(0); Color4 borderColour = colourProvider.Light4; if (IsHovered) @@ -118,7 +121,7 @@ private void updateState() fill.FadeColour(fillColour, 250, Easing.OutQuint); content.TransformTo(nameof(BorderColour), (ColourInfo)borderColour, 250, Easing.OutQuint); - content.ResizeWidthTo(Current.Value ? 1 : 0.75f, 250, Easing.OutQuint); + content.ResizeWidthTo(ExpandOnCurrent && Current.Value ? 1 : 0.75f, 250, Easing.OutQuint); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs index f815cf82e6e2..df9646d211ae 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioOffsetAdjustControl.cs @@ -16,6 +16,7 @@ using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Screens.Play.PlayerSettings; +using osuTK; namespace osu.Game.Overlays.Settings.Sections.Audio { @@ -52,6 +53,7 @@ private void load(SessionAverageHitErrorTracker hitErrorTracker) RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, + Spacing = new Vector2(SettingsSection.ITEM_SPACING_V2), Children = new Drawable[] { new SettingsItemV2(new FormSliderBar @@ -67,30 +69,23 @@ private void load(SessionAverageHitErrorTracker hitErrorTracker) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = new MarginPadding - { - Left = SettingsPanel.CONTENT_PADDING.Left + 9, - Right = SettingsPanel.CONTENT_PADDING.Right + 5 - }, - Child = notchContainer = new Container + Padding = SettingsPanel.CONTENT_PADDING, + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - Width = 0.5f, - Height = 10, - Margin = new MarginPadding { Top = 2 }, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Padding = new MarginPadding + notchContainer = new Container { - Horizontal = FormSliderBar.InnerSlider.NUB_WIDTH / 2 + RelativeSizeAxes = Axes.X, + Width = 0.5f, + Height = 10, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Padding = new MarginPadding + { + Horizontal = FormSliderBar.InnerSlider.NUB_WIDTH / 2 + }, }, - }, - }, - hintNote = new SettingsNote - { - RelativeSizeAxes = Axes.X, - Padding = SettingsPanel.CONTENT_PADDING, - TextAnchor = Anchor.TopCentre, + hintNote = new SettingsNote { RelativeSizeAxes = Axes.X }, + } }, applySuggestion = new RoundedButton { @@ -166,18 +161,23 @@ private void updateHintText() applySuggestion.Enabled.Value = false; notchContainer.Hide(); hintNote.Current.Value = new SettingsNote.Data(AudioSettingsStrings.SuggestedOffsetNote, SettingsNote.Type.Informational); + hintNote.MoveToY(0, 200, Easing.OutQuint); } else if (Math.Abs(SuggestedOffset.Value.Value - current.Value) < 1) { applySuggestion.Enabled.Value = false; notchContainer.Show(); hintNote.Current.Value = new SettingsNote.Data(AudioSettingsStrings.SuggestedOffsetCorrect(averageHitErrorHistory.Count), SettingsNote.Type.Informational); + hintNote.MoveToY(10, 200, Easing.OutQuint); } else { applySuggestion.Enabled.Value = true; notchContainer.Show(); - hintNote.Current.Value = new SettingsNote.Data(AudioSettingsStrings.SuggestedOffsetValueReceived(averageHitErrorHistory.Count, SuggestedOffset.Value.Value.ToStandardFormattedString(0)), SettingsNote.Type.Informational); + hintNote.Current.Value = + new SettingsNote.Data(AudioSettingsStrings.SuggestedOffsetValueReceived(averageHitErrorHistory.Count, SuggestedOffset.Value.Value.ToStandardFormattedString(0)), + SettingsNote.Type.Informational); + hintNote.MoveToY(10, 200, Easing.OutQuint); } } } diff --git a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs index 50fb68870758..37c619f3cd3e 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs @@ -111,18 +111,19 @@ private void load() { switchButton = new SwitchButton { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Scale = new Vector2(0.6f), - Position = new Vector2(12, 8), - Rotation = 90, + ExpandOnCurrent = false, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Width = 15, + Height = 22, }, headerText = new OsuSpriteText { Text = header, - Font = OsuFont.GetFont(size: 20), + Font = OsuFont.Style.Heading2, Margin = new MarginPadding { Vertical = 12 }, - X = 20, + X = 18, + Y = -1, }, new HoverSounds(), }; diff --git a/osu.Game/Overlays/Settings/SettingsItemV2.cs b/osu.Game/Overlays/Settings/SettingsItemV2.cs index e6eddb45597b..46287d900f3f 100644 --- a/osu.Game/Overlays/Settings/SettingsItemV2.cs +++ b/osu.Game/Overlays/Settings/SettingsItemV2.cs @@ -70,6 +70,7 @@ public SettingsItemV2(IFormControl control) { RelativeSizeAxes = Axes.X, Current = { BindTarget = Note }, + Depth = 1, }, }, }; diff --git a/osu.Game/Overlays/Settings/SettingsNote.cs b/osu.Game/Overlays/Settings/SettingsNote.cs index dec2694b4ffa..30e9be64245b 100644 --- a/osu.Game/Overlays/Settings/SettingsNote.cs +++ b/osu.Game/Overlays/Settings/SettingsNote.cs @@ -44,7 +44,7 @@ private void load() { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Top = 5, Bottom = 5 }, + Padding = new MarginPadding { Top = SettingsSection.ITEM_SPACING_V2 }, Child = new Container { RelativeSizeAxes = Axes.X, @@ -74,8 +74,8 @@ private void load() protected override void LoadComplete() { base.LoadComplete(); + Current.BindValueChanged(_ => updateDisplay(), true); - FinishTransforms(true); } private void updateDisplay() diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index c3e995b81a5b..c22afa45a095 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -35,7 +35,7 @@ public abstract partial class SettingsSection : Container, IFilterable public virtual IEnumerable FilterTerms => new[] { Header }; public const int ITEM_SPACING = 14; - public const int ITEM_SPACING_V2 = 7; + public const int ITEM_SPACING_V2 = 4; private const int header_size = 24; private const int border_size = 4; From 42dc73d84964fda205fdd6dd94e4d02a0baf8246 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jan 2026 02:55:48 +0900 Subject: [PATCH 563/836] Standardise animations --- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 22 ++++++++++--------- .../Graphics/UserInterfaceV2/SwitchButton.cs | 6 ++++- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 95c5fc1b54b4..d6c7c367859d 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -200,6 +200,7 @@ private void load(OsuColour colours, OsuGame? game) Masking = true; CornerRadius = 5; + CornerExponent = 2.5f; InternalChildren = new Drawable[] { @@ -558,20 +559,20 @@ protected override void OnFocusLost(FocusLostEvent e) private void updateState() { sounds.Enabled.Value = !Current.Disabled; - rightBox.Colour = colourProvider.Background6; + rightBox.Colour = colourProvider.Background5; - Color4 leftColour; + Color4 leftColour = colourProvider.Light4; Color4 nubColour; - if (Current.Disabled) - { - leftColour = colourProvider.Dark3; - nubColour = colourProvider.Dark1; - } + if (IsHovered || HasFocus || IsDragged) + nubColour = colourProvider.Highlight1; else + nubColour = colourProvider.Highlight1.Darken(0.1f); + + if (Current.Disabled) { - leftColour = HasFocus || IsHovered || IsDragged ? colourProvider.Highlight1.Opacity(0.5f) : colourProvider.Highlight1.Opacity(0.3f); - nubColour = HasFocus || IsHovered || IsDragged ? colourProvider.Highlight1 : colourProvider.Light4; + nubColour = nubColour.Darken(0.4f); + leftColour = leftColour.Darken(0.4f); } leftBox.FadeColour(leftColour, 250, Easing.OutQuint); @@ -580,7 +581,7 @@ private void updateState() protected override void UpdateValue(float value) { - nub.MoveToX(value, 200, Easing.OutPow10); + nub.MoveToX(value, 250, Easing.OutElasticQuarter); } protected override bool Commit() @@ -603,6 +604,7 @@ public partial class InnerSliderNub : Circle [BackgroundDependencyLoader] private void load() { + CornerExponent = 2.5f; Width = InnerSlider.NUB_WIDTH; RelativeSizeAxes = Axes.Y; RelativePositionAxes = Axes.X; diff --git a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs index 3afb6d756bc8..802b91451a1e 100644 --- a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs @@ -121,7 +121,11 @@ private void updateState() fill.FadeColour(fillColour, 250, Easing.OutQuint); content.TransformTo(nameof(BorderColour), (ColourInfo)borderColour, 250, Easing.OutQuint); - content.ResizeWidthTo(ExpandOnCurrent && Current.Value ? 1 : 0.75f, 250, Easing.OutQuint); + + if (ExpandOnCurrent && Current.Value) + content.ResizeWidthTo(1f, 200, Easing.OutElasticQuarter); + else + content.ResizeWidthTo(0.75f, 120, Easing.OutExpo); } } } From fdf28474bfcac8fb68953030e3778302b719d1fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jan 2026 20:52:23 +0900 Subject: [PATCH 564/836] Add prefix for input device header --- osu.Game/Overlays/Settings/Sections/InputSubsection.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs index 37c619f3cd3e..0c089d30df61 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs @@ -12,7 +12,6 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; -using osuTK; using osuTK.Graphics; namespace osu.Game.Overlays.Settings.Sections @@ -85,14 +84,14 @@ private void updateEnabledState() private partial class ToggleableHeader : CompositeDrawable { - private readonly LocalisableString header; + private readonly LocalisableString text; private readonly bool toggleable; public readonly BindableBool Current = new BindableBool(true); - public ToggleableHeader(LocalisableString header, bool toggleable) + public ToggleableHeader(LocalisableString text, bool toggleable) { - this.header = header; + this.text = text; this.toggleable = toggleable; } @@ -119,7 +118,7 @@ private void load() }, headerText = new OsuSpriteText { - Text = header, + Text = $"Device: {text}", Font = OsuFont.Style.Heading2, Margin = new MarginPadding { Vertical = 12 }, X = 18, From dba17b1fa6fec3cb7b201f462d880dafc0f4125f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jan 2026 03:04:09 +0900 Subject: [PATCH 565/836] Standardise hover sounds for form elements Closes #36444. --- .../UserInterface/HoverClickSounds.cs | 19 +++---------------- .../Graphics/UserInterface/HoverSounds.cs | 6 ++++++ .../Graphics/UserInterfaceV2/FormButton.cs | 4 ---- .../UserInterfaceV2/FormControlBackground.cs | 6 ++++++ .../Graphics/UserInterfaceV2/FormDropdown.cs | 5 ----- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 3 --- 6 files changed, 15 insertions(+), 28 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index fea33bfa9d78..b8f97cab5ea4 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -1,13 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Linq; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Input.Events; using osu.Framework.Utils; @@ -21,10 +18,8 @@ namespace osu.Game.Graphics.UserInterface /// public partial class HoverClickSounds : HoverSounds { - public Bindable Enabled = new Bindable(true); - - private Sample sampleClick; - private Sample sampleClickDisabled; + private Sample? sampleClick; + private Sample? sampleClickDisabled; private readonly MouseButton[] buttons; @@ -36,7 +31,7 @@ public partial class HoverClickSounds : HoverSounds /// Array of button codes which should trigger the click sound. /// If this optional parameter is omitted or set to null, the click sound will only be played on left click. /// - public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Default, MouseButton[] buttons = null) + public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Default, MouseButton[]? buttons = null) : base(sampleSet) { this.buttons = buttons ?? new[] { MouseButton.Left }; @@ -60,14 +55,6 @@ protected override bool OnClick(ClickEvent e) return base.OnClick(e); } - public override void PlayHoverSample() - { - if (!Enabled.Value) - return; - - base.PlayHoverSample(); - } - public void PlayClickSample() { var channel = Enabled.Value ? sampleClick?.GetChannel() : sampleClickDisabled?.GetChannel(); diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index 012594b40434..cd67a0f93504 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Utils; @@ -18,6 +19,8 @@ namespace osu.Game.Graphics.UserInterface /// public partial class HoverSounds : HoverSampleDebounceComponent { + public readonly Bindable Enabled = new Bindable(true); + private Sample sampleHover; protected readonly HoverSampleSet SampleSet; @@ -37,6 +40,9 @@ private void load(AudioManager audio) public override void PlayHoverSample() { + if (!Enabled.Value) + return; + sampleHover.Frequency.Value = 0.98 + RNG.NextDouble(0.04); sampleHover.Play(); } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormButton.cs b/osu.Game/Graphics/UserInterfaceV2/FormButton.cs index 3b4f0e34483c..36c2ad809871 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormButton.cs @@ -88,10 +88,6 @@ private void load() Children = new Drawable[] { background = new FormControlBackground(), - new HoverClickSounds(HoverSampleSet.Button) - { - Enabled = { BindTarget = Enabled }, - }, new Container { RelativeSizeAxes = Axes.X, diff --git a/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs b/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs index 7b9c5c49922f..c576bad0f9d3 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osuTK.Graphics; @@ -52,6 +53,8 @@ public bool StyleHovered private readonly Box box; + private readonly HoverSounds sounds; + public FormControlBackground() { RelativeSizeAxes = Axes.Both; @@ -69,6 +72,7 @@ public FormControlBackground() Colour = Color4.White, RelativeSizeAxes = Axes.Both, }, + sounds = new HoverSounds(), }; } @@ -87,6 +91,8 @@ public void Flash() private void updateStyling() { + sounds.Enabled.Value = !styleDisabled; + ColourInfo colour = colourProvider.Background4.Darken(0.1f); ColourInfo borderColour = colourProvider.Light4; diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index e970459037f8..d7860bab4f6a 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -203,11 +203,6 @@ private void load() } }, }; - - AddInternal(new HoverClickSounds - { - Enabled = { BindTarget = Enabled }, - }); } protected override void LoadComplete() diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index d6c7c367859d..597a22773bda 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -451,7 +451,6 @@ public partial class InnerSlider : OsuSliderBar private Box leftBox = null!; private Box rightBox = null!; private InnerSliderNub nub = null!; - private HoverClickSounds sounds = null!; public const float NUB_WIDTH = 10; [Resolved] @@ -496,7 +495,6 @@ private void load() ResetToDefault = ResetToDefault, } }, - sounds = new HoverClickSounds() }; } @@ -558,7 +556,6 @@ protected override void OnFocusLost(FocusLostEvent e) private void updateState() { - sounds.Enabled.Value = !Current.Disabled; rightBox.Colour = colourProvider.Background5; Color4 leftColour = colourProvider.Light4; From 99ea19d55c5f45b7adbcefe0e208ffc064803f51 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jan 2026 16:35:46 +0900 Subject: [PATCH 566/836] Make binding configuration button bigger It's one of the more important sections so I want to make it easier to find. --- osu.Game/Localisation/BindingSettingsStrings.cs | 4 ++-- osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Localisation/BindingSettingsStrings.cs b/osu.Game/Localisation/BindingSettingsStrings.cs index ad4a650a1f3e..645192e6ef03 100644 --- a/osu.Game/Localisation/BindingSettingsStrings.cs +++ b/osu.Game/Localisation/BindingSettingsStrings.cs @@ -10,9 +10,9 @@ public static class BindingSettingsStrings private const string prefix = @"osu.Game.Resources.Localisation.BindingSettings"; /// - /// "Shortcut and gameplay bindings" + /// "Shortcuts and gameplay bindings" /// - public static LocalisableString ShortcutAndGameplayBindings => new TranslatableString(getKey(@"shortcut_and_gameplay_bindings"), @"Shortcut and gameplay bindings"); + public static LocalisableString ShortcutAndGameplayBindings => new TranslatableString(getKey(@"shortcut_and_gameplay_bindings"), @"Shortcuts and gameplay bindings"); /// /// "Configure" diff --git a/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs index c892e8fa2157..e39dcb59054d 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs @@ -23,7 +23,8 @@ public BindingSettings(KeyBindingPanel keyConfig) { Text = BindingSettingsStrings.Configure, TooltipText = BindingSettingsStrings.ChangeBindingsButton, - Action = keyConfig.ToggleVisibility + Action = keyConfig.ToggleVisibility, + Height = 60 }, }; } From ed0051d119d37e61114201934c2ed070721e680a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jan 2026 16:52:09 +0900 Subject: [PATCH 567/836] Adjust size and icon of revert-to-default button --- osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs | 1 - .../Overlays/Settings/SettingsRevertToDefaultButton.cs | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index 777f63069540..c45d76e331aa 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -136,7 +136,6 @@ private void load(OverlayColourProvider colourProvider, AudioManager audioManage { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - IconSize = 12, Action = RestoreDefaults, }, new Container diff --git a/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs b/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs index bc2563383336..f828287d52b6 100644 --- a/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs +++ b/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Localisation; -using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Localisation; using osuTK; @@ -16,9 +15,9 @@ namespace osu.Game.Overlays.Settings { public partial class SettingsRevertToDefaultButton : OsuClickableContainer { - public const float WIDTH = 32; + public const float WIDTH = 28; - public float IconSize { get; init; } = 14; + public float IconSize { get; init; } = 10; private Box background = null!; private SpriteIcon spriteIcon = null!; @@ -54,7 +53,7 @@ private void load() Anchor = Anchor.Centre, Origin = Anchor.Centre, Colour = colourProvider.Light1, - Icon = OsuIcon.Undo, + Icon = FontAwesome.Solid.Undo, Margin = new MarginPadding { Left = 12, Right = 5 }, Size = new Vector2(IconSize), } From c407e07514e83b87ef2b2082c11ecf6c41c1b079 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jan 2026 17:19:33 +0900 Subject: [PATCH 568/836] Adjust paddings to give more width to settings --- osu.Game/Overlays/Settings/SettingsHeader.cs | 3 +-- osu.Game/Overlays/Settings/SettingsSection.cs | 2 +- osu.Game/Overlays/SettingsPanel.cs | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsHeader.cs b/osu.Game/Overlays/Settings/SettingsHeader.cs index 4e32efc4f47e..c94ce8e1c83e 100644 --- a/osu.Game/Overlays/Settings/SettingsHeader.cs +++ b/osu.Game/Overlays/Settings/SettingsHeader.cs @@ -37,8 +37,7 @@ private void load(OverlayColourProvider colourProvider) { Left = SettingsPanel.CONTENT_PADDING.Left, Right = SettingsPanel.CONTENT_PADDING.Right, - Top = Toolbar.Toolbar.TOOLTIP_HEIGHT, - Bottom = 30 + Vertical = 20, } }.With(flow => { diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index c22afa45a095..5a57114deb4c 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -38,7 +38,7 @@ public abstract partial class SettingsSection : Container, IFilterable public const int ITEM_SPACING_V2 = 4; private const int header_size = 24; - private const int border_size = 4; + private const int border_size = 2; private bool matchingFilter = true; diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index e35df366460a..e6dda398cffb 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -32,7 +32,7 @@ public abstract partial class SettingsPanel : OsuFocusedOverlayContainer public const float CONTENT_MARGINS = 20; // extra right padding to give room to the revert-to-default button in settings controls. - public static readonly MarginPadding CONTENT_PADDING = new MarginPadding { Left = 20, Right = 30 }; + public static readonly MarginPadding CONTENT_PADDING = new MarginPadding { Left = 12, Right = 22 }; public const float TRANSITION_LENGTH = 600; @@ -133,7 +133,7 @@ private void load() AutoSizeAxes = Axes.Y, Padding = new MarginPadding { - Vertical = 20, + Vertical = 6, Left = CONTENT_PADDING.Left, Right = CONTENT_PADDING.Right, }, @@ -324,7 +324,7 @@ private void load(OverlayColourProvider colourProvider) { HeaderBackground = new Box { - Colour = colourProvider.Background4, + Colour = colourProvider.Background5, RelativeSizeAxes = Axes.Both }; From d6bf4fd90d51b9978a20dacd3959a20f609c91fe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jan 2026 18:36:37 +0900 Subject: [PATCH 569/836] Fix border showing for inner text boxes incorrectly I turned masking back on on these for better visuals (text masking aligns with rest of elements) but turns out this implicitly makes borders draw. --- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 6 ++++-- osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index 6388f56f6180..4de7e0d7140c 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -42,6 +42,8 @@ public partial class OsuTextBox : BasicTextBox Margin = new MarginPadding { Left = 2 }, }; + protected bool DrawBorder { get; init; } + private OsuCaret? caret; private bool selectionStarted; @@ -256,7 +258,7 @@ protected override void OnImeResult(string result, bool successful) protected override void OnFocus(FocusEvent e) { - if (Masking) + if (DrawBorder) BorderThickness = 3; base.OnFocus(e); @@ -268,7 +270,7 @@ protected override void OnFocus(FocusEvent e) protected override void OnFocusLost(FocusLostEvent e) { - if (Masking) + if (DrawBorder) BorderThickness = 0; base.OnFocusLost(e); diff --git a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs index 8efa71f15fa5..be90689819b3 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs @@ -198,6 +198,11 @@ internal partial class InnerTextBox : OsuTextBox protected override float LeftRightPadding => 0; + public InnerTextBox() + { + DrawBorder = false; + } + [BackgroundDependencyLoader] private void load() { From 786ea35274f31a93f483d9be896141657cd414d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jan 2026 18:36:49 +0900 Subject: [PATCH 570/836] Fix revert button not always matching control's size --- osu.Game/Overlays/Settings/SettingsItemV2.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Overlays/Settings/SettingsItemV2.cs b/osu.Game/Overlays/Settings/SettingsItemV2.cs index 46287d900f3f..3adeca4b2d88 100644 --- a/osu.Game/Overlays/Settings/SettingsItemV2.cs +++ b/osu.Game/Overlays/Settings/SettingsItemV2.cs @@ -86,6 +86,12 @@ protected override void LoadComplete() controlDefault.BindValueChanged(_ => updateDefaultState()); controlEnabled.BindValueChanged(_ => updateDefaultState(), true); FinishTransforms(true); + + ScheduleAfterChildren(() => + { + revertButton.RelativeSizeAxes = Axes.None; + revertButton.Height = ((Drawable)Control).DrawHeight; + }); } private void updateDefaultState() From b5e93b98c9376e4d283d81ff64f3d7aa3ff88ac0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jan 2026 18:41:27 +0900 Subject: [PATCH 571/836] Fix mismatching spacing in dropdown form menus --- .../UserInterfaceV2/FormControlBackground.cs | 7 +++++-- osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs | 13 ++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs b/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs index c576bad0f9d3..43c1c87f1c8f 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs @@ -15,6 +15,9 @@ namespace osu.Game.Graphics.UserInterfaceV2 { public partial class FormControlBackground : CompositeDrawable { + public const float CORNER_EXPONENT = 2.5f; + public const float BORDER_THICKNESS = 2.5f; + private bool styleDisabled; public bool StyleDisabled @@ -61,9 +64,9 @@ public FormControlBackground() Masking = true; CornerRadius = 5; - CornerExponent = 2.5f; - BorderThickness = 2.5f; + CornerExponent = CORNER_EXPONENT; + BorderThickness = BORDER_THICKNESS; InternalChildren = new Drawable[] { diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index d7860bab4f6a..009d439b081e 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -156,8 +156,6 @@ private void load() Masking = true; CornerRadius = 5; - Margin = new MarginPadding { Bottom = header_menu_spacing }; - // We use our own background for more control. Background.Alpha = 0; @@ -290,7 +288,8 @@ private void load(OverlayColourProvider colourProvider) { ItemsContainer.Padding = new MarginPadding(9); - MaskingContainer.BorderThickness = 2; + MaskingContainer.BorderThickness = FormControlBackground.BORDER_THICKNESS; + MaskingContainer.CornerExponent = FormControlBackground.CORNER_EXPONENT; MaskingContainer.BorderColour = colourProvider.Highlight1; } @@ -301,13 +300,17 @@ protected override void AnimateOpen() // there's negative bottom margin applied on the whole dropdown control to remove extra spacing when the menu is closed. // however, when the menu is open, we want spacing between the menu and the next control below it. therefore apply bottom margin here. // we use a transform to keep the open animation smooth while margin is adjusted. - this.TransformTo(nameof(Margin), new MarginPadding { Bottom = header_menu_spacing }, 300, Easing.OutQuint); + this.TransformTo(nameof(Margin), new MarginPadding + { + Top = header_menu_spacing, + Bottom = header_menu_spacing + }, 50, Easing.OutQuint); } protected override void AnimateClose() { base.AnimateClose(); - this.TransformTo(nameof(Margin), new MarginPadding { Bottom = 0 }, 300, Easing.OutQuint); + this.TransformTo(nameof(Margin), new MarginPadding { Bottom = 0 }, 300); } } } From 12eeab581ed02fd863c8be014b675f721b86a71f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jan 2026 18:51:04 +0900 Subject: [PATCH 572/836] Remove unnecessary depth change --- osu.Game/Overlays/Settings/SettingsItemV2.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/SettingsItemV2.cs b/osu.Game/Overlays/Settings/SettingsItemV2.cs index 3adeca4b2d88..78f3b0eb0aab 100644 --- a/osu.Game/Overlays/Settings/SettingsItemV2.cs +++ b/osu.Game/Overlays/Settings/SettingsItemV2.cs @@ -70,7 +70,6 @@ public SettingsItemV2(IFormControl control) { RelativeSizeAxes = Axes.X, Current = { BindTarget = Note }, - Depth = 1, }, }, }; From fa22d1f20277e23a77dca20ee0fa0cac36acdcde Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jan 2026 18:58:03 +0900 Subject: [PATCH 573/836] Use enum for background states --- .../Graphics/UserInterfaceV2/FormButton.cs | 8 +- .../Graphics/UserInterfaceV2/FormCheckBox.cs | 9 +- .../UserInterfaceV2/FormColourPalette.cs | 5 +- .../UserInterfaceV2/FormControlBackground.cs | 89 +++++++++---------- .../Graphics/UserInterfaceV2/FormDropdown.cs | 11 ++- .../UserInterfaceV2/FormFileSelector.cs | 11 ++- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 11 ++- .../Graphics/UserInterfaceV2/FormTextBox.cs | 11 ++- 8 files changed, 93 insertions(+), 62 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormButton.cs b/osu.Game/Graphics/UserInterfaceV2/FormButton.cs index 36c2ad809871..afab77490b66 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormButton.cs @@ -169,8 +169,12 @@ private void updateState() { text.Colour = Enabled.Value ? colourProvider.Content1 : colourProvider.Background1; - background.StyleHovered = IsHovered; - background.StyleDisabled = !Enabled.Value; + if (!Enabled.Value) + background.VisualStyle = VisualStyle.Disabled; + else if (IsHovered) + background.VisualStyle = VisualStyle.Hovered; + else + background.VisualStyle = VisualStyle.Normal; // TODO: Support BackgroundColour? } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs index 2b751d98e50c..0242472db1ed 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs @@ -141,8 +141,13 @@ protected override bool OnClick(ClickEvent e) private void updateState() { caption.Colour = Current.Disabled ? colourProvider.Background1 : colourProvider.Content2; - background.StyleHovered = IsHovered; - background.StyleDisabled = IsDisabled; + + if (IsDisabled) + background.VisualStyle = VisualStyle.Disabled; + else if (IsHovered) + background.VisualStyle = VisualStyle.Hovered; + else + background.VisualStyle = VisualStyle.Normal; } public IEnumerable FilterTerms => Caption.Yield(); diff --git a/osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs index 2f1c72fcc91c..0eb59415c047 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs @@ -135,7 +135,10 @@ private void updateState() { caption.Colour = colourProvider.Content2; - background.StyleHovered = IsHovered; + if (IsHovered) + background.VisualStyle = VisualStyle.Hovered; + else + background.VisualStyle = VisualStyle.Normal; } private void updateColours() diff --git a/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs b/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs index 43c1c87f1c8f..46042ea08c17 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormControlBackground.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 osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -18,36 +19,15 @@ public partial class FormControlBackground : CompositeDrawable public const float CORNER_EXPONENT = 2.5f; public const float BORDER_THICKNESS = 2.5f; - private bool styleDisabled; + private VisualStyle visualStyle; - public bool StyleDisabled + public VisualStyle VisualStyle { + get => visualStyle; set { - styleDisabled = value; - updateStyling(); - } - } - - private bool styleFocused; - - public bool StyleFocused - { - set - { - styleFocused = value; - updateStyling(); - } - } - - private bool styleHovered; - - public bool StyleHovered - { - set - { - styleHovered = value; - updateStyling(); + visualStyle = value; + updateStyle(); } } @@ -83,7 +63,7 @@ protected override void LoadComplete() { base.LoadComplete(); - updateStyling(); + updateStyle(); FinishTransforms(true); } @@ -92,30 +72,41 @@ public void Flash() box.FlashColour(ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark2), 800, Easing.OutQuint); } - private void updateStyling() + private void updateStyle() { - sounds.Enabled.Value = !styleDisabled; + sounds.Enabled.Value = visualStyle != VisualStyle.Disabled; - ColourInfo colour = colourProvider.Background4.Darken(0.1f); - ColourInfo borderColour = colourProvider.Light4; + ColourInfo colour; + ColourInfo borderColour; bool border = false; - if (styleDisabled) - { - colour = colourProvider.Background4; - borderColour = colourProvider.Dark1; - } - else if (styleFocused) + switch (visualStyle) { - colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); - border = true; - borderColour = colourProvider.Highlight1; - } - else if (styleHovered) - { - colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); - border = true; + case VisualStyle.Normal: + colour = colourProvider.Background4.Darken(0.1f); + borderColour = colourProvider.Light4; + break; + + case VisualStyle.Disabled: + colour = colourProvider.Background4; + borderColour = colourProvider.Dark1; + break; + + case VisualStyle.Hovered: + colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); + borderColour = colourProvider.Light4; + border = true; + break; + + case VisualStyle.Focused: + colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); + border = true; + borderColour = colourProvider.Highlight1; + break; + + default: + throw new ArgumentOutOfRangeException(); } this.TransformTo(nameof(BorderColour), border ? borderColour : colour, 250, Easing.OutQuint); @@ -123,4 +114,12 @@ private void updateStyling() box.FadeColour(colour, 250, Easing.OutQuint); } } + + public enum VisualStyle + { + Normal, + Disabled, + Hovered, + Focused + } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index 009d439b081e..86ca6fc42552 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -246,9 +246,14 @@ private void updateState() else label.Alpha = 1; - background.StyleDisabled = Dropdown.Current.Disabled; - background.StyleHovered = IsHovered; - background.StyleFocused = dropdownOpen; + if (Dropdown.Current.Disabled) + background.VisualStyle = VisualStyle.Disabled; + else if (dropdownOpen) + background.VisualStyle = VisualStyle.Focused; + else if (IsHovered) + background.VisualStyle = VisualStyle.Hovered; + else + background.VisualStyle = VisualStyle.Normal; } private void updateChevron() diff --git a/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs b/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs index 5cafdc365050..d4edcd2ff377 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormFileSelector.cs @@ -212,9 +212,14 @@ private void updateState() caption.Colour = Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content2; filenameText.Colour = Current.Disabled || Current.Value == null ? colourProvider.Foreground1 : colourProvider.Content1; - background.StyleDisabled = Current.Disabled; - background.StyleFocused = popoverState.Value == Visibility.Visible; - background.StyleHovered = IsHovered; + if (Current.Disabled) + background.VisualStyle = VisualStyle.Disabled; + else if (popoverState.Value == Visibility.Visible) + background.VisualStyle = VisualStyle.Focused; + else if (IsHovered) + background.VisualStyle = VisualStyle.Hovered; + else + background.VisualStyle = VisualStyle.Normal; } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 597a22773bda..501e3106b324 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -395,9 +395,14 @@ private void updateState() textBox.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background1 : colourProvider.Content1; valueLabel.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background1 : colourProvider.Content1; - background.StyleDisabled = Current.Disabled; - background.StyleFocused = childHasFocus; - background.StyleHovered = IsHovered || slider.IsDragging.Value; + if (Current.Disabled) + background.VisualStyle = VisualStyle.Disabled; + else if (childHasFocus) + background.VisualStyle = VisualStyle.Focused; + else if (IsHovered || slider.IsDragging.Value) + background.VisualStyle = VisualStyle.Hovered; + else + background.VisualStyle = VisualStyle.Normal; } private void updateValueDisplay() diff --git a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs index be90689819b3..78fb438828b0 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs @@ -185,9 +185,14 @@ private void updateState() caption.Colour = disabled ? colourProvider.Background1 : colourProvider.Content2; textBox.Colour = disabled ? colourProvider.Foreground1 : colourProvider.Content1; - background.StyleDisabled = Current.Disabled; - background.StyleFocused = textBox.Focused.Value; - background.StyleHovered = IsHovered; + if (Current.Disabled) + background.VisualStyle = VisualStyle.Disabled; + else if (textBox.Focused.Value) + background.VisualStyle = VisualStyle.Focused; + else if (IsHovered) + background.VisualStyle = VisualStyle.Hovered; + else + background.VisualStyle = VisualStyle.Normal; } internal partial class InnerTextBox : OsuTextBox From 6329e3ee1b122a1e6db0942f2e315820abf4dcd8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jan 2026 19:02:28 +0900 Subject: [PATCH 574/836] Add back `FinishTransforms` at what cost --- osu.Game/Overlays/Settings/SettingsNote.cs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsNote.cs b/osu.Game/Overlays/Settings/SettingsNote.cs index 30e9be64245b..825deafe2626 100644 --- a/osu.Game/Overlays/Settings/SettingsNote.cs +++ b/osu.Game/Overlays/Settings/SettingsNote.cs @@ -26,14 +26,6 @@ public sealed partial class SettingsNote : CompositeDrawable [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; - public new MarginPadding Padding - { - get => base.Padding; - set => base.Padding = value; - } - - public Anchor TextAnchor { get; init; } = Anchor.TopLeft; - [BackgroundDependencyLoader] private void load() { @@ -61,7 +53,6 @@ private void load() }, text = new OsuTextFlowContainer(s => s.Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold)) { - TextAnchor = TextAnchor, Padding = new MarginPadding(8), RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -76,12 +67,14 @@ protected override void LoadComplete() base.LoadComplete(); Current.BindValueChanged(_ => updateDisplay(), true); + FinishTransforms(true); } private void updateDisplay() { // Explicitly use ClearTransforms to clear any existing auto-size transform before modifying size / flag. - ClearTransforms(); + // TODO: This is dodgy as hell and needs to go. + ClearTransforms(false, @"baseSize"); if (Current.Value == null) { From 60690cbccc3082401da08a3d850b26887c8db3d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jan 2026 19:03:23 +0900 Subject: [PATCH 575/836] Add localisation support for "Device:" prefix --- osu.Game/Localisation/InputSettingsStrings.cs | 8 +++++++- osu.Game/Overlays/Settings/Sections/InputSubsection.cs | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/InputSettingsStrings.cs b/osu.Game/Localisation/InputSettingsStrings.cs index bc1a7e68ab01..661d583e8f34 100644 --- a/osu.Game/Localisation/InputSettingsStrings.cs +++ b/osu.Game/Localisation/InputSettingsStrings.cs @@ -14,6 +14,11 @@ public static class InputSettingsStrings /// public static LocalisableString InputSectionHeader => new TranslatableString(getKey(@"input_section_header"), @"Input"); + /// + /// "Device: {0}" + /// + public static LocalisableString Device(LocalisableString text) => new TranslatableString(getKey(@"device"), @"Device: {0}", text); + /// /// "Global" /// @@ -72,7 +77,8 @@ public static class InputSettingsStrings /// /// "The binding you've selected conflicts with another existing binding." /// - public static LocalisableString KeyBindingConflictDetected => new TranslatableString(getKey(@"key_binding_conflict_detected"), @"The binding you've selected conflicts with another existing binding."); + public static LocalisableString KeyBindingConflictDetected => + new TranslatableString(getKey(@"key_binding_conflict_detected"), @"The binding you've selected conflicts with another existing binding."); /// /// "Keep existing" diff --git a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs index 0c089d30df61..71d844e8efde 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs @@ -13,6 +13,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osuTK.Graphics; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections { @@ -118,7 +119,7 @@ private void load() }, headerText = new OsuSpriteText { - Text = $"Device: {text}", + Text = InputSettingsStrings.Device(text), Font = OsuFont.Style.Heading2, Margin = new MarginPadding { Vertical = 12 }, X = 18, From 6fad79822732e654b2fb203a0791dd983d32ceda Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jan 2026 19:58:45 +0900 Subject: [PATCH 576/836] Add insult to injury for autosize workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Overlays/Settings/SettingsNote.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Settings/SettingsNote.cs b/osu.Game/Overlays/Settings/SettingsNote.cs index 825deafe2626..be2489a92e90 100644 --- a/osu.Game/Overlays/Settings/SettingsNote.cs +++ b/osu.Game/Overlays/Settings/SettingsNote.cs @@ -75,6 +75,7 @@ private void updateDisplay() // Explicitly use ClearTransforms to clear any existing auto-size transform before modifying size / flag. // TODO: This is dodgy as hell and needs to go. ClearTransforms(false, @"baseSize"); + ClearTransforms(false, nameof(Height)); if (Current.Value == null) { From add67b95c73f96b0fbb51a7e7123de82d00ff2e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 27 Jan 2026 12:09:31 +0100 Subject: [PATCH 577/836] Apply extracted background in one more location --- osu.Game/Screens/Edit/Components/FormSampleSet.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/FormSampleSet.cs b/osu.Game/Screens/Edit/Components/FormSampleSet.cs index 21be85423e44..a96b255b5c29 100644 --- a/osu.Game/Screens/Edit/Components/FormSampleSet.cs +++ b/osu.Game/Screens/Edit/Components/FormSampleSet.cs @@ -15,7 +15,6 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; @@ -48,7 +47,7 @@ public Bindable Current private readonly BindableWithCurrent current = new BindableWithCurrent(); private readonly Dictionary<(string name, string bank), SampleButton> buttons = new Dictionary<(string, string), SampleButton>(); - private Box background = null!; + private FormControlBackground background = null!; private FormFieldCaption caption = null!; [Resolved] @@ -62,13 +61,13 @@ private void load() Masking = true; CornerRadius = 5; + CornerExponent = 2.5f; InternalChildren = new Drawable[] { - background = new Box + background = new FormControlBackground { RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5, }, new FillFlowContainer { @@ -167,13 +166,9 @@ protected override void OnHoverLost(HoverLostEvent e) private void updateState() { - background.Colour = colourProvider.Background5; caption.Colour = colourProvider.Content2; - BorderThickness = IsHovered ? 2 : 0; - - if (IsHovered) - BorderColour = colourProvider.Light4; + background.VisualStyle = IsHovered ? VisualStyle.Hovered : VisualStyle.Normal; } public partial class SampleButton : OsuButton, IHasPopover, IHasContextMenu From 2c56419fe91ba6eb3dd06bb5eeacb06365ef9eb2 Mon Sep 17 00:00:00 2001 From: Eeli Ogata Date: Tue, 27 Jan 2026 15:32:51 +0200 Subject: [PATCH 578/836] Fix panel expansion not being set on initial song select load (#36456) Closes #36445. Fixes a regression from #36404 --------- Co-authored-by: Dean Herbert --- .../SongSelectV2/BeatmapCarouselTestScene.cs | 7 ++++- .../TestSceneBeatmapCarouselSetsSplitApart.cs | 27 +++++++++++++++++++ osu.Game/Screens/SelectV2/BeatmapCarousel.cs | 23 ++++++++++++---- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs b/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs index d961946c0428..dc3a49c068e9 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs @@ -44,6 +44,8 @@ public abstract partial class BeatmapCarouselTestScene : OsuManualInputManagerTe protected TestBeatmapCarousel Carousel = null!; + protected bool RetainSelection { get; set; } + protected OsuScrollContainer Scroll => Carousel.ChildrenOfType>().Single(); [Cached(typeof(BeatmapStore))] @@ -78,7 +80,7 @@ private void load() Dependencies.Cache(Realm); } - protected void CreateCarousel() + protected void CreateCarousel(bool retainSelection = false) { AddStep("create components", () => { @@ -87,6 +89,8 @@ protected void CreateCarousel() BeatmapRecommendationFunction = null; NewItemsPresentedInvocationCount = 0; + GroupedBeatmap? previousSelection = retainSelection ? Carousel.CurrentGroupedBeatmap : null; + Box topBox; Children = new Drawable[] { @@ -120,6 +124,7 @@ protected void CreateCarousel() { Carousel = new TestBeatmapCarousel { + CurrentGroupedBeatmap = previousSelection, NewItemsPresented = _ => NewItemsPresentedInvocationCount++, RequestSelection = b => { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselSetsSplitApart.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselSetsSplitApart.cs index fa635f9bde73..31488e399a58 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselSetsSplitApart.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselSetsSplitApart.cs @@ -23,6 +23,33 @@ public void SetUpSteps() SortAndGroupBy(SortMode.Title, GroupMode.Length); } + [Test] + public void TestInitialVisualState() + { + AddBeatmaps(3, splitApart: true); + + WaitForDrawablePanels(); + SelectNextSet(); + WaitForSetSelection(set: 0, diff: 0); + + AddAssert("selected item is visible", () => GetSelectedPanel()?.Item?.IsVisible, () => Is.True); + AddAssert("has visually expanded set", () => Carousel.GetCarouselItems()!.Count(item => item.Model is GroupedBeatmapSet && item.IsExpanded && item.IsVisible), () => Is.EqualTo(1)); + + CreateCarousel(retainSelection: true); + WaitForDrawablePanels(); + WaitForSetSelection(set: 0, diff: 0); + + AddAssert("selected item is visible", () => GetSelectedPanel()?.Item?.IsVisible, () => Is.True); + AddAssert("has visually expanded set", () => Carousel.GetCarouselItems()!.Count(item => item.Model is GroupedBeatmapSet && item.IsExpanded && item.IsVisible), () => Is.EqualTo(1)); + + CreateCarousel(retainSelection: true); + WaitForDrawablePanels(); + WaitForSetSelection(set: 0, diff: 0); + + AddAssert("selected item is visible", () => GetSelectedPanel()?.Item?.IsVisible, () => Is.True); + AddAssert("has visually expanded set", () => Carousel.GetCarouselItems()!.Count(item => item.Model is GroupedBeatmapSet && item.IsExpanded && item.IsVisible), () => Is.EqualTo(1)); + } + [Test] public void TestSetTraversal() { diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index ba54fd269c63..adf65887270b 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -408,8 +408,7 @@ protected override void HandleItemSelected(object? model) case GroupedBeatmap groupedBeatmap: setExpandedGroup(groupedBeatmap.Group); - if (grouping.BeatmapSetsGroupedTogether) - setExpandedSet(new GroupedBeatmapSet(groupedBeatmap.Group, groupedBeatmap.Beatmap.BeatmapSet!)); + setExpandedSet(new GroupedBeatmapSet(groupedBeatmap.Group, groupedBeatmap.Beatmap.BeatmapSet!)); break; } } @@ -647,14 +646,28 @@ private void setExpansionStateOfGroup(GroupDefinition group, bool expanded) private void setExpandedSet(GroupedBeatmapSet set) { - if (ExpandedBeatmapSet != null) - setExpansionStateOfSetItems(ExpandedBeatmapSet, false); + GroupedBeatmapSet? lastExpandedSet = ExpandedBeatmapSet; + + // It's important that we update the stored ExpandedBeatmapSet even when + // sets are not grouped together. + // + // This is stored when selection is changed and used later to ensure correct + // visual states are achieved (see call of this method in `HandleFilterCompleted` + // for an important case). ExpandedBeatmapSet = set; + + if (!grouping.BeatmapSetsGroupedTogether) + return; + + setExpansionStateOfSetItems(lastExpandedSet, false); setExpansionStateOfSetItems(ExpandedBeatmapSet, true); } - private void setExpansionStateOfSetItems(GroupedBeatmapSet set, bool expanded) + private void setExpansionStateOfSetItems(GroupedBeatmapSet? set, bool expanded) { + if (set == null) + return; + bool canMakeVisible = !grouping.GroupItems.Any() || ExpandedGroup == set.Group; if (grouping.SetItems.TryGetValue(set, out var items)) From 4a5dbea2a21a26260d08bf0abc11f7a5c2014f1b Mon Sep 17 00:00:00 2001 From: ArijanJ Date: Tue, 27 Jan 2026 19:49:38 +0100 Subject: [PATCH 579/836] Use ctrl-shift-E/T for shortcuts --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index e342a4e6140f..2c850ad5b58f 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -105,8 +105,8 @@ public static IEnumerable GetGlobalActionsFor(GlobalActionCategory new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings), new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.R }, GlobalAction.RandomSkin), - new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.Down }, GlobalAction.NextSkin), - new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.Up }, GlobalAction.PreviousSkin), + new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.T }, GlobalAction.NextSkin), + new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.E }, GlobalAction.PreviousSkin), new KeyBinding(InputKey.F10, GlobalAction.ToggleGameplayMouseButtons), new KeyBinding(InputKey.F12, GlobalAction.TakeScreenshot), From aefe31d315ce7bd5dce11cf4df6fdb0a03ecc2bd Mon Sep 17 00:00:00 2001 From: Givy120 <89256026+Givikap120@users.noreply.github.com> Date: Tue, 27 Jan 2026 22:23:22 +0200 Subject: [PATCH 580/836] Make sliderless aim in fact sliderless (#29993) Part of this PR - https://github.com/ppy/osu/pull/27303 Current aim calculation have a flaw of sliderless aim still accounting for sliders. This happens because of usage of `LazyJumpDistance` as a main distance metric. This PR is fixing this by adding `JumpDistance` as true sliderless metric, using it instead of `LazyJumpDistance`. This can introduce very rare cases where sliderless aim is worth more than normal aim (because of velocity change bonus). The effect of this is minimal on most of the maps. It can be seen the best on this map - https://osu.ppy.sh/beatmapsets/594751#osu/1257904 Before: ![image](https://github.com/user-attachments/assets/e96773e6-3274-4ed6-8293-ed9bdfa213d0) After: ![image](https://github.com/user-attachments/assets/126e861b-c28d-4ed4-a0db-f5305225a749) --------- Co-authored-by: James Wilson Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com> --- .../Difficulty/Evaluators/AimEvaluator.cs | 27 +++++++++++-------- .../Preprocessing/OsuDifficultyHitObject.cs | 8 +++++- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 4aa45f45293c..24db5ef525e4 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -40,7 +40,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with const int diameter = OsuDifficultyHitObject.NORMALISED_DIAMETER; // Calculate the velocity to the current hitobject, which starts with a base distance / time assuming the last object is a hitcircle. - double currVelocity = osuCurrObj.LazyJumpDistance / osuCurrObj.AdjustedDeltaTime; + double currDistance = withSliderTravelDistance ? osuCurrObj.LazyJumpDistance : osuCurrObj.JumpDistance; + double currVelocity = currDistance / osuCurrObj.AdjustedDeltaTime; // But if the last object is a slider, then we extend the travel velocity through the slider into the current object. if (osuLastObj.BaseObject is Slider && withSliderTravelDistance) @@ -52,7 +53,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with } // As above, do the same for the previous hitobject. - double prevVelocity = osuLastObj.LazyJumpDistance / osuLastObj.AdjustedDeltaTime; + double prevDistance = withSliderTravelDistance ? osuLastObj.LazyJumpDistance : osuLastObj.JumpDistance; + double prevVelocity = prevDistance / osuLastObj.AdjustedDeltaTime; if (osuLastLastObj.BaseObject is Slider && withSliderTravelDistance) { @@ -88,7 +90,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter acuteAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * - DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2); + DifficultyCalculationUtils.Smootherstep(currDistance, diameter, diameter * 2); } wideAngleBonus = calcWideAngleBonus(currAngle); @@ -97,16 +99,16 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3)); // Apply full wide angle bonus for distance more than one diameter - wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, 0, diameter); + wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(currDistance, 0, diameter); // Apply wiggle bonus for jumps that are [radius, 3*diameter] in distance, with < 110 angle // https://www.desmos.com/calculator/dp0v0nvowc wiggleBonus = angleBonus - * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, radius, diameter) - * Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuCurrObj.LazyJumpDistance, diameter * 3, diameter), 1.8) + * DifficultyCalculationUtils.Smootherstep(currDistance, radius, diameter) + * Math.Pow(DifficultyCalculationUtils.ReverseLerp(currDistance, diameter * 3, diameter), 1.8) * DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)) - * DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, radius, diameter) - * Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuLastObj.LazyJumpDistance, diameter * 3, diameter), 1.8) + * DifficultyCalculationUtils.Smootherstep(prevDistance, radius, diameter) + * Math.Pow(DifficultyCalculationUtils.ReverseLerp(prevDistance, diameter * 3, diameter), 1.8) * DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)); if (osuLast2Obj != null) @@ -127,9 +129,12 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with if (Math.Max(prevVelocity, currVelocity) != 0) { - // We want to use the average velocity over the whole object when awarding differences, not the individual jump and slider path velocities. - prevVelocity = (osuLastObj.LazyJumpDistance + osuLastLastObj.TravelDistance) / osuLastObj.AdjustedDeltaTime; - currVelocity = (osuCurrObj.LazyJumpDistance + osuLastObj.TravelDistance) / osuCurrObj.AdjustedDeltaTime; + if (withSliderTravelDistance) + { + // We want to use the average velocity over the whole object when awarding differences, not the individual jump and slider path velocities. + prevVelocity = (osuLastObj.LazyJumpDistance + osuLastLastObj.TravelDistance) / osuLastObj.AdjustedDeltaTime; + currVelocity = (osuCurrObj.LazyJumpDistance + osuLastObj.TravelDistance) / osuCurrObj.AdjustedDeltaTime; + } // Scale with ratio of difference compared to 0.5 * max dist. double distRatio = DifficultyCalculationUtils.Smoothstep(Math.Abs(prevVelocity - currVelocity) / Math.Max(prevVelocity, currVelocity), 0, 1); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 00bb4908c6de..727b07c4af5a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -46,6 +46,11 @@ public class OsuDifficultyHitObject : DifficultyHitObject /// public readonly double ClockRate; + /// + /// Normalised distance from the start position of the previous to the start position of this . + /// + public double JumpDistance { get; private set; } + /// /// Normalised distance from the "lazy" end position of the previous to the start position of this . /// @@ -232,7 +237,8 @@ private void setDistances(double clockRate) Vector2 lastCursorPosition = lastDifficultyObject != null ? getEndCursorPosition(lastDifficultyObject) : LastObject.StackedPosition; - LazyJumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; + JumpDistance = (LastObject.StackedPosition - BaseObject.StackedPosition).Length * scalingFactor; + LazyJumpDistance = (BaseObject.StackedPosition - lastCursorPosition).Length * scalingFactor; MinimumJumpTime = AdjustedDeltaTime; MinimumJumpDistance = LazyJumpDistance; From 40e55ecb6ef72bbc7507cf0a3076f8392e606125 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 28 Jan 2026 13:38:40 +0900 Subject: [PATCH 581/836] Add type to matchmaking pools --- osu.Game/Online/Matchmaking/MatchmakingPool.cs | 3 +++ osu.Game/Online/Matchmaking/MatchmakingPoolType.cs | 11 +++++++++++ 2 files changed, 14 insertions(+) create mode 100644 osu.Game/Online/Matchmaking/MatchmakingPoolType.cs diff --git a/osu.Game/Online/Matchmaking/MatchmakingPool.cs b/osu.Game/Online/Matchmaking/MatchmakingPool.cs index 3f256d525131..54b1d443b579 100644 --- a/osu.Game/Online/Matchmaking/MatchmakingPool.cs +++ b/osu.Game/Online/Matchmaking/MatchmakingPool.cs @@ -23,6 +23,9 @@ public class MatchmakingPool : IEquatable [Key(3)] public string Name { get; set; } = string.Empty; + [Key(4)] + public MatchmakingPoolType Type { get; set; } = MatchmakingPoolType.QuickPlay; + public bool Equals(MatchmakingPool? other) => other != null && Id == other.Id diff --git a/osu.Game/Online/Matchmaking/MatchmakingPoolType.cs b/osu.Game/Online/Matchmaking/MatchmakingPoolType.cs new file mode 100644 index 000000000000..f151d6186320 --- /dev/null +++ b/osu.Game/Online/Matchmaking/MatchmakingPoolType.cs @@ -0,0 +1,11 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Online.Matchmaking +{ + public enum MatchmakingPoolType + { + QuickPlay, + RankedPlay + } +} From c1fc1edd9c630540b1998b79f260b1f2cda6e036 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 28 Jan 2026 13:40:33 +0900 Subject: [PATCH 582/836] Add type parameter to pool retrieval method --- osu.Game/Online/Matchmaking/IMatchmakingServer.cs | 3 ++- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 2 +- osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs | 4 ++-- osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs | 2 +- osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Matchmaking/IMatchmakingServer.cs b/osu.Game/Online/Matchmaking/IMatchmakingServer.cs index 7641c57fe94c..06689a40dae0 100644 --- a/osu.Game/Online/Matchmaking/IMatchmakingServer.cs +++ b/osu.Game/Online/Matchmaking/IMatchmakingServer.cs @@ -10,7 +10,8 @@ public interface IMatchmakingServer /// /// Retrieves all active matchmaking pools. /// - Task GetMatchmakingPools(); + /// + Task GetMatchmakingPoolsOfType(MatchmakingPoolType type); /// /// Joins the matchmaking lobby, allowing the local user to receive status updates. diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 59a26d5ba748..62228e60bd29 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -1129,7 +1129,7 @@ Task IMatchmakingClient.MatchmakingItemDeselected(int userId, long playlistItemI return Task.CompletedTask; } - public abstract Task GetMatchmakingPools(); + public abstract Task GetMatchmakingPoolsOfType(MatchmakingPoolType type); public abstract Task MatchmakingJoinLobby(); diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 7cfa036dcdd0..b36e2cf17766 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -333,13 +333,13 @@ public override Task DisconnectInternal() return connector.Disconnect(); } - public override Task GetMatchmakingPools() + public override Task GetMatchmakingPoolsOfType(MatchmakingPoolType type) { if (!IsConnected.Value) return Task.FromResult(Array.Empty()); Debug.Assert(connection != null); - return connection.InvokeAsync(nameof(IMatchmakingServer.GetMatchmakingPools)); + return connection.InvokeAsync(nameof(IMatchmakingServer.GetMatchmakingPoolsOfType), type); } public override Task MatchmakingJoinLobby() diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs index c29e126f6076..a1012b73b3d5 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs @@ -156,7 +156,7 @@ protected override void LoadComplete() private async Task populateAvailablePools() { - MatchmakingPool[] pools = await client.GetMatchmakingPools().ConfigureAwait(false); + MatchmakingPool[] pools = await client.GetMatchmakingPoolsOfType(MatchmakingPoolType.QuickPlay).ConfigureAwait(false); Schedule(() => { diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 2f8a3dc7a8f0..21fffba1f3cb 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -782,7 +782,7 @@ public async Task ChangeMatchRoomState(MatchRoomState state) await ((IMultiplayerClient)this).MatchRoomStateChanged(clone(ServerRoom.MatchState)).ConfigureAwait(false); } - public override Task GetMatchmakingPools() + public override Task GetMatchmakingPoolsOfType(MatchmakingPoolType type) { return Task.FromResult( [ From 70321e2f8927fdd896a13e917c9db1a1d595ddaa Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 28 Jan 2026 13:41:20 +0900 Subject: [PATCH 583/836] Add ranked play models --- osu.Game/Online/Multiplayer/MatchRoomState.cs | 2 + .../Online/Multiplayer/MatchServerEvent.cs | 2 + .../RankedPlay/RankedPlayCardItem.cs | 32 +++++++++ .../RankedPlay/RankedPlayRoomState.cs | 65 +++++++++++++++++++ .../MatchTypes/RankedPlay/RankedPlayStage.cs | 58 +++++++++++++++++ .../RankedPlay/RankedPlayUserInfo.cs | 38 +++++++++++ .../Online/Multiplayer/MatchUserRequest.cs | 2 + .../Multiplayer/MultiplayerCountdown.cs | 2 + .../Online/RankedPlay/IRankedPlayClient.cs | 39 +++++++++++ .../Online/RankedPlay/IRankedPlayServer.cs | 15 +++++ .../RankedPlayCardHandReplayEvent.cs | 23 +++++++ .../RankedPlayCardHandReplayFrame.cs | 35 ++++++++++ .../RankedPlayCardHandReplayRequest.cs | 17 +++++ .../Online/RankedPlay/RankedPlayCardState.cs | 22 +++++++ .../RankedPlay/RankedPlayStageCountdown.cs | 16 +++++ osu.Game/Online/SignalRWorkaroundTypes.cs | 8 +++ 16 files changed, 376 insertions(+) create mode 100644 osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayCardItem.cs create mode 100644 osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayRoomState.cs create mode 100644 osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayStage.cs create mode 100644 osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayUserInfo.cs create mode 100644 osu.Game/Online/RankedPlay/IRankedPlayClient.cs create mode 100644 osu.Game/Online/RankedPlay/IRankedPlayServer.cs create mode 100644 osu.Game/Online/RankedPlay/RankedPlayCardHandReplayEvent.cs create mode 100644 osu.Game/Online/RankedPlay/RankedPlayCardHandReplayFrame.cs create mode 100644 osu.Game/Online/RankedPlay/RankedPlayCardHandReplayRequest.cs create mode 100644 osu.Game/Online/RankedPlay/RankedPlayCardState.cs create mode 100644 osu.Game/Online/RankedPlay/RankedPlayStageCountdown.cs diff --git a/osu.Game/Online/Multiplayer/MatchRoomState.cs b/osu.Game/Online/Multiplayer/MatchRoomState.cs index 25de8c7fab1e..531395980674 100644 --- a/osu.Game/Online/Multiplayer/MatchRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchRoomState.cs @@ -4,6 +4,7 @@ using System; using MessagePack; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; namespace osu.Game.Online.Multiplayer @@ -16,6 +17,7 @@ namespace osu.Game.Online.Multiplayer [MessagePackObject] [Union(0, typeof(TeamVersusRoomState))] // IMPORTANT: Add rules to SignalRUnionWorkaroundResolver for new derived types. [Union(1, typeof(MatchmakingRoomState))] + [Union(2, typeof(RankedPlayRoomState))] public abstract class MatchRoomState { } diff --git a/osu.Game/Online/Multiplayer/MatchServerEvent.cs b/osu.Game/Online/Multiplayer/MatchServerEvent.cs index 529a2994388f..402de392a84c 100644 --- a/osu.Game/Online/Multiplayer/MatchServerEvent.cs +++ b/osu.Game/Online/Multiplayer/MatchServerEvent.cs @@ -5,6 +5,7 @@ using MessagePack; using osu.Game.Online.Matchmaking.Events; using osu.Game.Online.Multiplayer.Countdown; +using osu.Game.Online.RankedPlay; namespace osu.Game.Online.Multiplayer { @@ -17,6 +18,7 @@ namespace osu.Game.Online.Multiplayer [Union(0, typeof(CountdownStartedEvent))] [Union(1, typeof(CountdownStoppedEvent))] [Union(2, typeof(MatchmakingAvatarActionEvent))] + [Union(3, typeof(RankedPlayCardHandReplayEvent))] public abstract class MatchServerEvent { } diff --git a/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayCardItem.cs b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayCardItem.cs new file mode 100644 index 000000000000..65cb1987fef9 --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayCardItem.cs @@ -0,0 +1,32 @@ +// 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.Diagnostics.CodeAnalysis; +using MessagePack; + +namespace osu.Game.Online.Multiplayer.MatchTypes.RankedPlay +{ + [Serializable] + [MessagePackObject] + public class RankedPlayCardItem : IEquatable + { + /// + /// A unique identifier for this card. + /// + [Key(0)] + public Guid ID { get; set; } = Guid.NewGuid(); + + public bool Equals(RankedPlayCardItem? other) + => other != null && ID.Equals(other.ID); + + public override bool Equals(object? obj) + => obj is RankedPlayCardItem other && Equals(other); + + [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] + public override int GetHashCode() + { + return ID.GetHashCode(); + } + } +} diff --git a/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayRoomState.cs b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayRoomState.cs new file mode 100644 index 000000000000..95fab16a7b7d --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayRoomState.cs @@ -0,0 +1,65 @@ +// 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.Collections.Generic; +using MessagePack; + +namespace osu.Game.Online.Multiplayer.MatchTypes.RankedPlay +{ + [Serializable] + [MessagePackObject] + public class RankedPlayRoomState : MatchRoomState + { + /// + /// The current room stage. + /// + [Key(0)] + public RankedPlayStage Stage { get; set; } + + /// + /// The current round number (1-based). + /// + [Key(1)] + public int CurrentRound { get; set; } + + /// + /// A multiplier applied to life point damage. + /// + [Key(2)] + public double DamageMultiplier { get; set; } + + /// + /// A dictionary containing all users in the room. + /// + [Key(3)] + public Dictionary Users { get; set; } = []; + + /// + /// The ID of the user currently playing a card. + /// + [Key(4)] + public int ActiveUserId { get; set; } + + /// + /// The average star rating of all cards. + /// + [Key(5)] + public double StarRating { get; set; } + + /// + /// The winner of the match. + /// + [Key(6)] + public int? WinningUserId { get; set; } + + /// + /// The user currently playing a card. + /// + [IgnoreMember] + public RankedPlayUserInfo ActiveUser => Users[ActiveUserId]; + + [IgnoreMember] + public RankedPlayUserInfo? WinningUser => WinningUserId == null ? null : Users[WinningUserId.Value]; + } +} diff --git a/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayStage.cs b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayStage.cs new file mode 100644 index 000000000000..1a23b5224fa4 --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayStage.cs @@ -0,0 +1,58 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Online.Multiplayer.MatchTypes.RankedPlay +{ + public enum RankedPlayStage + { + /// + /// Waiting for clients to join. + /// + WaitForJoin, + + /// + /// Period of time before the round starts. + /// + RoundWarmup, + + /// + /// Users are discarding cards and drawing new ones. + /// + CardDiscard, + + /// + /// Users have finished discarding their cards. + /// + FinishCardDiscard, + + /// + /// The active user is selecting a card to play. + /// + CardPlay, + + /// + /// The active user has made a selection, both players should now start downloading it. + /// + FinishCardPlay, + + /// + /// Period of time before gameplay starts. + /// + GameplayWarmup, + + /// + /// Gameplay is in progress. + /// + Gameplay, + + /// + /// Users are viewing the gameplay results + /// + Results, + + /// + /// The match has concluded. + /// + Ended + } +} diff --git a/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayUserInfo.cs b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayUserInfo.cs new file mode 100644 index 000000000000..a5064676c675 --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayUserInfo.cs @@ -0,0 +1,38 @@ +// 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.Collections.Generic; +using MessagePack; + +namespace osu.Game.Online.Multiplayer.MatchTypes.RankedPlay +{ + [Serializable] + [MessagePackObject] + public class RankedPlayUserInfo + { + /// + /// This user's matchmaking rating. + /// + [Key(0)] + public required int Rating { get; set; } + + /// + /// The current life points. + /// + [Key(1)] + public int Life { get; set; } = 1_000_000; + + /// + /// The cards in this user's hand. + /// + [Key(2)] + public List Hand { get; set; } = []; + + /// + /// Rating after conclusion of the match. + /// + [Key(3)] + public int RatingAfter { get; set; } + } +} diff --git a/osu.Game/Online/Multiplayer/MatchUserRequest.cs b/osu.Game/Online/Multiplayer/MatchUserRequest.cs index 02704ea161d4..fdcbf756822f 100644 --- a/osu.Game/Online/Multiplayer/MatchUserRequest.cs +++ b/osu.Game/Online/Multiplayer/MatchUserRequest.cs @@ -6,6 +6,7 @@ using osu.Game.Online.Matchmaking.Events; using osu.Game.Online.Multiplayer.Countdown; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; +using osu.Game.Online.RankedPlay; namespace osu.Game.Online.Multiplayer { @@ -19,6 +20,7 @@ namespace osu.Game.Online.Multiplayer [Union(1, typeof(StartMatchCountdownRequest))] [Union(2, typeof(StopCountdownRequest))] [Union(3, typeof(MatchmakingAvatarActionRequest))] + [Union(4, typeof(RankedPlayCardHandReplayRequest))] public abstract class MatchUserRequest { } diff --git a/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs b/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs index bc2536848be3..9f4d7f1039b8 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs @@ -5,6 +5,7 @@ using MessagePack; using osu.Game.Online.Matchmaking; using osu.Game.Online.Multiplayer.Countdown; +using osu.Game.Online.RankedPlay; namespace osu.Game.Online.Multiplayer { @@ -16,6 +17,7 @@ namespace osu.Game.Online.Multiplayer [Union(1, typeof(ForceGameplayStartCountdown))] [Union(2, typeof(ServerShuttingDownCountdown))] [Union(3, typeof(MatchmakingStageCountdown))] + [Union(4, typeof(RankedPlayStageCountdown))] public abstract class MultiplayerCountdown { /// diff --git a/osu.Game/Online/RankedPlay/IRankedPlayClient.cs b/osu.Game/Online/RankedPlay/IRankedPlayClient.cs new file mode 100644 index 000000000000..ea4f9d55810b --- /dev/null +++ b/osu.Game/Online/RankedPlay/IRankedPlayClient.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading.Tasks; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.Rooms; + +namespace osu.Game.Online.RankedPlay +{ + public interface IRankedPlayClient + { + /// + /// Indicates that a card has been added to a user's hand. + /// + /// The user whose hand has changed. + /// The card added to the user's hand. + Task RankedPlayCardAdded(int userId, RankedPlayCardItem card); + + /// + /// Indicates that a card has been removed from a user's hand. + /// + /// The user whose hand has changed. + /// The card removed from the user's hand. + Task RankedPlayCardRemoved(int userId, RankedPlayCardItem card); + + /// + /// Indicates that a card has been revealed to the local user. + /// + /// The card that was revealed. + /// The playlist item the card corresponds to. + Task RankedPlayCardRevealed(RankedPlayCardItem card, MultiplayerPlaylistItem item); + + /// + /// Indicates a card was played. + /// + /// The card played. + Task RankedPlayCardPlayed(RankedPlayCardItem card); + } +} diff --git a/osu.Game/Online/RankedPlay/IRankedPlayServer.cs b/osu.Game/Online/RankedPlay/IRankedPlayServer.cs new file mode 100644 index 000000000000..1e3f56d08106 --- /dev/null +++ b/osu.Game/Online/RankedPlay/IRankedPlayServer.cs @@ -0,0 +1,15 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading.Tasks; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; + +namespace osu.Game.Online.RankedPlay +{ + public interface IRankedPlayServer + { + Task DiscardCards(RankedPlayCardItem[] cards); + + Task PlayCard(RankedPlayCardItem card); + } +} diff --git a/osu.Game/Online/RankedPlay/RankedPlayCardHandReplayEvent.cs b/osu.Game/Online/RankedPlay/RankedPlayCardHandReplayEvent.cs new file mode 100644 index 000000000000..9c4d0afe31b9 --- /dev/null +++ b/osu.Game/Online/RankedPlay/RankedPlayCardHandReplayEvent.cs @@ -0,0 +1,23 @@ +// 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 MessagePack; +using osu.Game.Online.Multiplayer; + +namespace osu.Game.Online.RankedPlay +{ + [Serializable] + [MessagePackObject] + public class RankedPlayCardHandReplayEvent : MatchServerEvent + { + /// + /// The user performing the action. + /// + [Key(0)] + public int UserId { get; set; } + + [Key(1)] + public required RankedPlayCardHandReplayFrame[] Frames { get; init; } + } +} diff --git a/osu.Game/Online/RankedPlay/RankedPlayCardHandReplayFrame.cs b/osu.Game/Online/RankedPlay/RankedPlayCardHandReplayFrame.cs new file mode 100644 index 000000000000..de6b312b91be --- /dev/null +++ b/osu.Game/Online/RankedPlay/RankedPlayCardHandReplayFrame.cs @@ -0,0 +1,35 @@ +// 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.Collections.Generic; +using System.Linq; +using MessagePack; + +namespace osu.Game.Online.RankedPlay +{ + [Serializable] + [MessagePackObject] + public readonly record struct RankedPlayCardHandReplayFrame + { + /// + /// Duration in milliseconds since the previous frame. + /// + [Key(0)] + public required double Delay { get; init; } + + /// + /// Dictionary containing the state of each card. + /// + [Key(1)] + public required Dictionary Cards { get; init; } + + /// + /// Creates a replay frame that only contains state entries that differ from the previous frame + /// + public RankedPlayCardHandReplayFrame RelativeTo(RankedPlayCardHandReplayFrame other) => this with + { + Cards = Cards.Where(entry => !other.Cards.Contains(entry)).ToDictionary(), + }; + } +} diff --git a/osu.Game/Online/RankedPlay/RankedPlayCardHandReplayRequest.cs b/osu.Game/Online/RankedPlay/RankedPlayCardHandReplayRequest.cs new file mode 100644 index 000000000000..1bfbfe1cd4a7 --- /dev/null +++ b/osu.Game/Online/RankedPlay/RankedPlayCardHandReplayRequest.cs @@ -0,0 +1,17 @@ +// 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 MessagePack; +using osu.Game.Online.Multiplayer; + +namespace osu.Game.Online.RankedPlay +{ + [Serializable] + [MessagePackObject] + public class RankedPlayCardHandReplayRequest : MatchUserRequest + { + [Key(0)] + public required RankedPlayCardHandReplayFrame[] Frames { get; init; } + } +} diff --git a/osu.Game/Online/RankedPlay/RankedPlayCardState.cs b/osu.Game/Online/RankedPlay/RankedPlayCardState.cs new file mode 100644 index 000000000000..bd938fb9db23 --- /dev/null +++ b/osu.Game/Online/RankedPlay/RankedPlayCardState.cs @@ -0,0 +1,22 @@ +// 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 MessagePack; + +namespace osu.Game.Online.RankedPlay +{ + [Serializable] + [MessagePackObject] + public readonly record struct RankedPlayCardState + { + [Key(0)] + public required bool Hovered { get; init; } + + [Key(1)] + public required bool Pressed { get; init; } + + [Key(2)] + public required bool Selected { get; init; } + } +} diff --git a/osu.Game/Online/RankedPlay/RankedPlayStageCountdown.cs b/osu.Game/Online/RankedPlay/RankedPlayStageCountdown.cs new file mode 100644 index 000000000000..541fbb31c357 --- /dev/null +++ b/osu.Game/Online/RankedPlay/RankedPlayStageCountdown.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using MessagePack; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; + +namespace osu.Game.Online.RankedPlay +{ + [MessagePackObject] + public class RankedPlayStageCountdown : MultiplayerCountdown + { + [Key(2)] + public RankedPlayStage Stage { get; set; } + } +} diff --git a/osu.Game/Online/SignalRWorkaroundTypes.cs b/osu.Game/Online/SignalRWorkaroundTypes.cs index e50989148657..70c6fcf2b780 100644 --- a/osu.Game/Online/SignalRWorkaroundTypes.cs +++ b/osu.Game/Online/SignalRWorkaroundTypes.cs @@ -8,7 +8,9 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.Countdown; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; +using osu.Game.Online.RankedPlay; using osu.Game.Users; namespace osu.Game.Online @@ -57,6 +59,12 @@ internal static class SignalRWorkaroundTypes (typeof(MatchmakingStageCountdown), typeof(MultiplayerCountdown)), (typeof(MatchmakingAvatarActionRequest), typeof(MatchUserRequest)), (typeof(MatchmakingAvatarActionEvent), typeof(MatchServerEvent)), + + // ranked play + (typeof(RankedPlayRoomState), typeof(MatchRoomState)), + (typeof(RankedPlayStageCountdown), typeof(MultiplayerCountdown)), + (typeof(RankedPlayCardHandReplayRequest), typeof(MatchUserRequest)), + (typeof(RankedPlayCardHandReplayEvent), typeof(MatchServerEvent)), }; } } From fa5a278cf365633f81837ef27ea101d922d7f640 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 28 Jan 2026 13:41:35 +0900 Subject: [PATCH 584/836] Add ranked play match type --- osu.Game/Online/Rooms/MatchType.cs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Rooms/MatchType.cs b/osu.Game/Online/Rooms/MatchType.cs index bbfe25c8fd3c..875748da1ad5 100644 --- a/osu.Game/Online/Rooms/MatchType.cs +++ b/osu.Game/Online/Rooms/MatchType.cs @@ -18,6 +18,30 @@ public enum MatchType [LocalisableDescription(typeof(MatchesStrings), nameof(MatchesStrings.MatchTeamTypesTeamVersus))] TeamVersus, - Matchmaking + /// + /// Matchmaking: Quick play + /// + Matchmaking, + + /// + /// Matchmaking: Ranked play + /// + RankedPlay + } + + public static class MatchTypeExtensions + { + public static bool IsMatchmakingType(this MatchType type) + { + switch (type) + { + case MatchType.Matchmaking: + case MatchType.RankedPlay: + return true; + + default: + return false; + } + } } } From 8202ad18d06ad759268e2156f89362402dab5d31 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 28 Jan 2026 14:00:44 +0900 Subject: [PATCH 585/836] Add comments --- osu.Game/Online/RankedPlay/IRankedPlayServer.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Online/RankedPlay/IRankedPlayServer.cs b/osu.Game/Online/RankedPlay/IRankedPlayServer.cs index 1e3f56d08106..2cdbcabc8ba8 100644 --- a/osu.Game/Online/RankedPlay/IRankedPlayServer.cs +++ b/osu.Game/Online/RankedPlay/IRankedPlayServer.cs @@ -8,8 +8,15 @@ namespace osu.Game.Online.RankedPlay { public interface IRankedPlayServer { + /// + /// Discards cards from the local user's hand during the stage. + /// Task DiscardCards(RankedPlayCardItem[] cards); + /// + /// Plays a card from the local user's hand during the stage. + /// Only usable while the local user is the active player. + /// Task PlayCard(RankedPlayCardItem card); } } From 0d3b7ab6be75c438b58d20ec966ae745a525d789 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jan 2026 14:22:31 +0900 Subject: [PATCH 586/836] Remove workaround for dropdowns animating weirdly --- osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index 86ca6fc42552..96dda47958a2 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -53,10 +53,6 @@ private void load() header.Caption = Caption; header.HintText = HintText; - - // there's bottom margin applied inside the header to give spacing between the header and the menu. - // however when the menu is closed the extra spacing remains present. to remove it, apply negative bottom padding here. - Margin = new MarginPadding { Bottom = -header_menu_spacing }; } protected override void LoadComplete() @@ -302,20 +298,16 @@ protected override void AnimateOpen() { base.AnimateOpen(); - // there's negative bottom margin applied on the whole dropdown control to remove extra spacing when the menu is closed. - // however, when the menu is open, we want spacing between the menu and the next control below it. therefore apply bottom margin here. - // we use a transform to keep the open animation smooth while margin is adjusted. this.TransformTo(nameof(Margin), new MarginPadding { Top = header_menu_spacing, - Bottom = header_menu_spacing - }, 50, Easing.OutQuint); + }, 300, Easing.OutQuint); } protected override void AnimateClose() { base.AnimateClose(); - this.TransformTo(nameof(Margin), new MarginPadding { Bottom = 0 }, 300); + this.TransformTo(nameof(Margin), new MarginPadding(), 300, Easing.OutQuint); } } } From 6bdb0e1cbba7c5b983267150c2cbe1d1fabbff96 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jan 2026 14:22:41 +0900 Subject: [PATCH 587/836] Fix dropdown margins and animations being weird This was attempted to be fixed by frenzibyte using some hack workaround logic, but this is the true fix. Things were never matching due to `UpdateSize` spamming `Resize` transforms every frame, causing the fade out to complete before transforms have reached a final state. --- osu.Game/Graphics/UserInterface/OsuDropdown.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index ae5501a3dd7d..bbc826a7a7b7 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -104,9 +104,17 @@ protected override void AnimateClose() } } + private Vector2? targetSize; + // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring protected override void UpdateSize(Vector2 newSize) { + // TODO: should probably fix this at a framework level (this method is running every frame which can spam transforms) + if (newSize == targetSize) + return; + + targetSize = newSize; + if (Direction == Direction.Vertical) { Width = newSize.X; From 1a0193001d5b42ff5ee08c0a4d65d99cc1f8e196 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jan 2026 14:42:41 +0900 Subject: [PATCH 588/836] Fix "ALL MODS" display not displaying in new playlist song select Closes https://github.com/ppy/osu/issues/36411. --- osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs index a2194a5d2f0f..53714156924b 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs @@ -122,7 +122,7 @@ protected override void LoadComplete() Freestyle.BindValueChanged(f => Enabled.Value = !f.NewValue, true); FreeMods.BindValueChanged(m => { - if (m.NewValue.Count == 0) + if (m.NewValue.Count == 0 && !Freestyle.Value) modsWedge.FadeOut(200); else modsWedge.FadeIn(200); @@ -133,7 +133,7 @@ protected override void Update() { base.Update(); - if (modDisplay.DrawWidth * modDisplay.Scale.X > modContainer.DrawWidth) + if (Freestyle.Value || modDisplay.DrawWidth * modDisplay.Scale.X > modContainer.DrawWidth) overflowModCountDisplay.Show(); else overflowModCountDisplay.Hide(); From 0c90cf3cef170b673713942d9372b2d1549f42b9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jan 2026 15:01:23 +0900 Subject: [PATCH 589/836] Fix mod count overlay flashing when switching freestyle on and off --- .../OnlinePlay/FooterButtonFreeModsV2.cs | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs index 53714156924b..4b94e8c36c3e 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Localisation; @@ -90,11 +91,6 @@ private void load() Masking = true, Children = new Drawable[] { - new Box - { - Colour = colourProvider.Background3, - RelativeSizeAxes = Axes.Both, - }, modDisplay = new ModDisplay(showExtendedInformation: true) { Anchor = Anchor.Centre, @@ -123,9 +119,9 @@ protected override void LoadComplete() FreeMods.BindValueChanged(m => { if (m.NewValue.Count == 0 && !Freestyle.Value) - modsWedge.FadeOut(200); + modsWedge.FadeOut(300, Easing.OutExpo); else - modsWedge.FadeIn(200); + modsWedge.FadeIn(300, Easing.OutExpo); }, true); } @@ -133,13 +129,24 @@ protected override void Update() { base.Update(); - if (Freestyle.Value || modDisplay.DrawWidth * modDisplay.Scale.X > modContainer.DrawWidth) + // If there are freemods selected but the display has no width, it's still loading. + // Don't update visibility in this state or we will cause an awkward flash. + if (FreeMods.Value.Count > 0 && Precision.AlmostEquals(modDisplay.DrawWidth, 0)) + return; + + bool showCountText = + // When freestyle is enabled this text shows "ALL MODS" + Freestyle.Value + // Standard flow where mods are overflowing so we show count text. + || modDisplay.DrawWidth * modDisplay.Scale.X > modContainer.DrawWidth; + + if (showCountText) overflowModCountDisplay.Show(); else overflowModCountDisplay.Hide(); } - private partial class ModCountText : CompositeDrawable + private partial class ModCountText : VisibilityContainer { public readonly Bindable> Mods = new Bindable>(); public readonly Bindable Freestyle = new Bindable(); @@ -178,6 +185,9 @@ protected override void LoadComplete() updateText(); } + protected override void PopIn() => this.FadeIn(300, Easing.OutExpo); + protected override void PopOut() => this.FadeOut(300, Easing.OutExpo); + private void updateText() { if (Freestyle.Value) From c8c91cedfa96852375ac612d689f9554e6d5c575 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jan 2026 15:58:55 +0900 Subject: [PATCH 590/836] Combine implementation of mods text drawable I don't want to have to update things in multiple places with different code in each place. This also closes https://github.com/ppy/osu/issues/36412. --- .../OnlinePlay/FooterButtonFreeModsV2.cs | 62 ++----------------- osu.Game/Screens/SelectV2/FooterButtonMods.cs | 24 +++++-- 2 files changed, 23 insertions(+), 63 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs index 4b94e8c36c3e..822af03c5fbb 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; @@ -13,21 +12,19 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Footer; using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.SelectV2; using osuTK; namespace osu.Game.Screens.OnlinePlay { public partial class FooterButtonFreeModsV2 : ScreenFooterButton { - private const float bar_height = 30f; - public readonly Bindable> FreeMods = new Bindable>([]); public readonly Bindable Freestyle = new Bindable(); @@ -45,7 +42,7 @@ public partial class FooterButtonFreeModsV2 : ScreenFooterButton private Container modsWedge = null!; private ModDisplay modDisplay = null!; private Container modContainer = null!; - private ModCountText overflowModCountDisplay = null!; + private FooterButtonMods.ModCountText overflowModCountDisplay = null!; public FooterButtonFreeModsV2(ModSelectOverlay overlay) : base(overlay) @@ -66,7 +63,7 @@ private void load() Origin = Anchor.BottomLeft, Shear = OsuGame.SHEAR, CornerRadius = CORNER_RADIUS, - Size = new Vector2(BUTTON_WIDTH, bar_height), + Size = new Vector2(BUTTON_WIDTH, FooterButtonMods.BAR_HEIGHT), Masking = true, EdgeEffect = new EdgeEffectParameters { @@ -100,7 +97,7 @@ private void load() Current = { BindTarget = FreeMods }, ExpansionMode = ExpansionMode.AlwaysContracted, }, - overflowModCountDisplay = new ModCountText + overflowModCountDisplay = new FooterButtonMods.ModCountText { Mods = { BindTarget = FreeMods }, Freestyle = { BindTarget = Freestyle } @@ -145,56 +142,5 @@ protected override void Update() else overflowModCountDisplay.Hide(); } - - private partial class ModCountText : VisibilityContainer - { - public readonly Bindable> Mods = new Bindable>(); - public readonly Bindable Freestyle = new Bindable(); - - private OsuSpriteText text = null!; - - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; - - protected override void LoadComplete() - { - base.LoadComplete(); - - RelativeSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] - { - new Box - { - Colour = colourProvider.Background3, - Alpha = 0.8f, - RelativeSizeAxes = Axes.Both, - }, - text = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.Torus.With(size: 14f, weight: FontWeight.Bold), - Shear = -OsuGame.SHEAR, - } - }; - - Mods.BindValueChanged(_ => updateText()); - Freestyle.BindValueChanged(_ => updateText()); - - updateText(); - } - - protected override void PopIn() => this.FadeIn(300, Easing.OutExpo); - protected override void PopOut() => this.FadeOut(300, Easing.OutExpo); - - private void updateText() - { - if (Freestyle.Value) - text.Text = ModSelectOverlayStrings.AllMods.ToUpper(); - else - text.Text = ModSelectOverlayStrings.Mods(Mods.Value.Count).ToUpper(); - } - } } } diff --git a/osu.Game/Screens/SelectV2/FooterButtonMods.cs b/osu.Game/Screens/SelectV2/FooterButtonMods.cs index 112f53a53ee4..f9acf6cf10ce 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonMods.cs +++ b/osu.Game/Screens/SelectV2/FooterButtonMods.cs @@ -36,7 +36,8 @@ public partial class FooterButtonMods : ScreenFooterButton, IHasCurrentValue> current = new BindableWithCurrent>(Array.Empty()); @@ -92,7 +93,7 @@ private void load() Origin = Anchor.BottomLeft, Shear = OsuGame.SHEAR, CornerRadius = CORNER_RADIUS, - Size = new Vector2(BUTTON_WIDTH, bar_height), + Size = new Vector2(BUTTON_WIDTH, BAR_HEIGHT), Masking = true, EdgeEffect = new EdgeEffectParameters { @@ -257,9 +258,10 @@ protected override void Update() overflowModCountDisplay.Hide(); } - private partial class ModCountText : CompositeDrawable, IHasCustomTooltip> + public partial class ModCountText : VisibilityContainer, IHasCustomTooltip> { public readonly Bindable> Mods = new Bindable>(); + public readonly Bindable Freestyle = new Bindable(); private OsuSpriteText text = null!; @@ -289,13 +291,25 @@ protected override void LoadComplete() } }; - Mods.BindValueChanged(v => text.Text = ModSelectOverlayStrings.Mods(v.NewValue.Count).ToUpper(), true); + Freestyle.BindValueChanged(_ => updateText()); + Mods.BindValueChanged(_ => updateText(), true); } public ITooltip> GetCustomTooltip() => new ModOverflowTooltip(colourProvider); public IReadOnlyList? TooltipContent => Mods.Value; + protected override void PopIn() => this.FadeIn(300, Easing.OutExpo); + protected override void PopOut() => this.FadeOut(300, Easing.OutExpo); + + private void updateText() + { + if (Freestyle.Value) + text.Text = ModSelectOverlayStrings.AllMods.ToUpper(); + else + text.Text = ModSelectOverlayStrings.Mods(Mods.Value.Count).ToUpper(); + } + public partial class ModOverflowTooltip : VisibilityContainer, ITooltip> { private ModDisplay extendedModDisplay = null!; @@ -356,7 +370,7 @@ public UnrankedBadge() Shear = OsuGame.SHEAR; CornerRadius = CORNER_RADIUS; AutoSizeAxes = Axes.X; - Height = bar_height; + Height = BAR_HEIGHT; Masking = true; BorderColour = Color4.White; BorderThickness = 2f; From b9d5606fd46682d5a680c8e1e5ef6849b2ff8edd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jan 2026 16:08:02 +0900 Subject: [PATCH 591/836] Limit maximum size of mod tooltip to avoid it going offscreen --- osu.Game/Screens/SelectV2/FooterButtonMods.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/SelectV2/FooterButtonMods.cs b/osu.Game/Screens/SelectV2/FooterButtonMods.cs index f9acf6cf10ce..55f3b6fb0570 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonMods.cs +++ b/osu.Game/Screens/SelectV2/FooterButtonMods.cs @@ -312,7 +312,7 @@ private void updateText() public partial class ModOverflowTooltip : VisibilityContainer, ITooltip> { - private ModDisplay extendedModDisplay = null!; + private ModFlowDisplay extendedModDisplay = null!; [Cached] private OverlayColourProvider colourProvider; @@ -336,11 +336,12 @@ private void load() RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background5, }, - extendedModDisplay = new ModDisplay + extendedModDisplay = new ModFlowDisplay { + AutoSizeAxes = Axes.Both, + MaximumSize = new Vector2(400, 0), Margin = new MarginPadding { Vertical = 2f, Horizontal = 10f }, Scale = new Vector2(0.6f), - ExpansionMode = ExpansionMode.AlwaysExpanded, }, }; } From ca7b850c8c75da7a67c48fee2ec4a7747b68d803 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jan 2026 16:37:39 +0900 Subject: [PATCH 592/836] Remove leaking knowledge of freestyle in normal song select component --- .../OnlinePlay/FooterButtonFreeModsV2.cs | 9 ++++++-- osu.Game/Screens/SelectV2/FooterButtonMods.cs | 22 +++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs index 822af03c5fbb..612eca9474cd 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs @@ -5,11 +5,13 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Localisation; @@ -100,7 +102,6 @@ private void load() overflowModCountDisplay = new FooterButtonMods.ModCountText { Mods = { BindTarget = FreeMods }, - Freestyle = { BindTarget = Freestyle } }, } }, @@ -112,7 +113,11 @@ protected override void LoadComplete() { base.LoadComplete(); - Freestyle.BindValueChanged(f => Enabled.Value = !f.NewValue, true); + Freestyle.BindValueChanged(f => + { + Enabled.Value = !f.NewValue; + overflowModCountDisplay.CustomText = f.NewValue ? ModSelectOverlayStrings.AllMods.ToUpper() : (LocalisableString?)null; + }, true); FreeMods.BindValueChanged(m => { if (m.NewValue.Count == 0 && !Freestyle.Value) diff --git a/osu.Game/Screens/SelectV2/FooterButtonMods.cs b/osu.Game/Screens/SelectV2/FooterButtonMods.cs index 55f3b6fb0570..27e0ac68f91a 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonMods.cs +++ b/osu.Game/Screens/SelectV2/FooterButtonMods.cs @@ -261,7 +261,22 @@ protected override void Update() public partial class ModCountText : VisibilityContainer, IHasCustomTooltip> { public readonly Bindable> Mods = new Bindable>(); - public readonly Bindable Freestyle = new Bindable(); + + private LocalisableString? customText; + + /// + /// When set, this will be shown instead of a mod count. + /// + public LocalisableString? CustomText + { + get => customText; + set + { + customText = value; + if (IsLoaded) + updateText(); + } + } private OsuSpriteText text = null!; @@ -291,7 +306,6 @@ protected override void LoadComplete() } }; - Freestyle.BindValueChanged(_ => updateText()); Mods.BindValueChanged(_ => updateText(), true); } @@ -304,8 +318,8 @@ protected override void LoadComplete() private void updateText() { - if (Freestyle.Value) - text.Text = ModSelectOverlayStrings.AllMods.ToUpper(); + if (CustomText != null) + text.Text = CustomText.Value; else text.Text = ModSelectOverlayStrings.Mods(Mods.Value.Count).ToUpper(); } From 7b7777bb563018b96e1de0311b0f5afe182be3a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jan 2026 16:55:43 +0900 Subject: [PATCH 593/836] Fix `FormCheckbox` playing sounds twice This removes the disabled sound, but I think that's fine. If we want that, it should be handled by `HoverClickSounds` (which I'm currently intentionally not using because it can be a bit noisy). Closes #36503. --- .../Graphics/UserInterfaceV2/FormCheckBox.cs | 28 +++---------------- 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs index 0242472db1ed..2709dde1649d 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; @@ -40,15 +38,13 @@ public Bindable Current private FormControlBackground background = null!; private FormFieldCaption caption = null!; - private Sample? sampleChecked; - private Sample? sampleUnchecked; - private Sample? sampleDisabled; + private SwitchButton switchButton = null!; [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; [BackgroundDependencyLoader] - private void load(AudioManager audio) + private void load() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -79,7 +75,7 @@ private void load(AudioManager audio) }, }, }, - new SwitchButton + switchButton = new SwitchButton { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, @@ -88,9 +84,6 @@ private void load(AudioManager audio) }, }, }; - sampleChecked = audio.Samples.Get(@"UI/check-on"); - sampleUnchecked = audio.Samples.Get(@"UI/check-off"); - sampleDisabled = audio.Samples.Get(@"UI/default-select-disabled"); } protected override void LoadComplete() @@ -100,7 +93,6 @@ protected override void LoadComplete() current.BindValueChanged(_ => { updateState(); - playSamples(); background.Flash(); ValueChanged?.Invoke(); @@ -108,14 +100,6 @@ protected override void LoadComplete() current.BindDisabledChanged(_ => updateState(), true); } - private void playSamples() - { - if (Current.Value) - sampleChecked?.Play(); - else - sampleUnchecked?.Play(); - } - protected override bool OnHover(HoverEvent e) { updateState(); @@ -130,11 +114,7 @@ protected override void OnHoverLost(HoverLostEvent e) protected override bool OnClick(ClickEvent e) { - if (!Current.Disabled) - Current.Value = !Current.Value; - else - sampleDisabled?.Play(); - + switchButton.TriggerClick(); return true; } From 6d54d20943242a9c41bbdeb9706440ac7b7988ea Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 28 Jan 2026 17:45:03 +0900 Subject: [PATCH 594/836] Apply default value changes from review --- .../MatchTypes/RankedPlay/RankedPlayRoomState.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayRoomState.cs b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayRoomState.cs index 95fab16a7b7d..e303bb0aa504 100644 --- a/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayRoomState.cs @@ -27,7 +27,7 @@ public class RankedPlayRoomState : MatchRoomState /// A multiplier applied to life point damage. /// [Key(2)] - public double DamageMultiplier { get; set; } + public double DamageMultiplier { get; set; } = 1; /// /// A dictionary containing all users in the room. @@ -39,7 +39,7 @@ public class RankedPlayRoomState : MatchRoomState /// The ID of the user currently playing a card. /// [Key(4)] - public int ActiveUserId { get; set; } + public int? ActiveUserId { get; set; } /// /// The average star rating of all cards. @@ -57,7 +57,7 @@ public class RankedPlayRoomState : MatchRoomState /// The user currently playing a card. /// [IgnoreMember] - public RankedPlayUserInfo ActiveUser => Users[ActiveUserId]; + public RankedPlayUserInfo? ActiveUser => ActiveUserId == null ? null : Users[ActiveUserId.Value]; [IgnoreMember] public RankedPlayUserInfo? WinningUser => WinningUserId == null ? null : Users[WinningUserId.Value]; From c47f9c52599e11afab91bc2c2a6cb16e29b4b371 Mon Sep 17 00:00:00 2001 From: BoomboxRapsody Date: Wed, 28 Jan 2026 22:06:54 +0900 Subject: [PATCH 595/836] Localise "Custom sample sets" in `FormSampleSetChooser` dropdown --- osu.Game/Localisation/EditorSetupStrings.cs | 5 +++++ osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/EditorSetupStrings.cs b/osu.Game/Localisation/EditorSetupStrings.cs index 8597b7d9a143..9469c8e63fb1 100644 --- a/osu.Game/Localisation/EditorSetupStrings.cs +++ b/osu.Game/Localisation/EditorSetupStrings.cs @@ -188,6 +188,11 @@ public static class EditorSetupStrings /// public static LocalisableString AudioTrack => new TranslatableString(getKey(@"audio_track"), @"Audio Track"); + /// + /// "Custom sample sets" + /// + public static LocalisableString CustomSampleSets => new TranslatableString(getKey(@"custom_sample_sets"), @"Custom sample sets"); + /// /// "Click to select a track" /// diff --git a/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs b/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs index 7e3020d78bb2..f6139da317bc 100644 --- a/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs +++ b/osu.Game/Screens/Edit/Setup/FormSampleSetChooser.cs @@ -13,6 +13,7 @@ using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { @@ -22,7 +23,7 @@ public partial class FormSampleSetChooser : FormDropdown Date: Wed, 28 Jan 2026 22:27:07 +0900 Subject: [PATCH 596/836] Add assertion that we always get the up-to-date beatmap file in a `WorkingBeatmap` --- osu.Game/Beatmaps/WorkingBeatmapCache.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs index 0bb61798dc94..75f1bd2a0739 100644 --- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs +++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Diagnostics; using System.IO; using System.Linq; using JetBrains.Annotations; @@ -104,6 +105,10 @@ public virtual WorkingBeatmap GetWorkingBeatmap([CanBeNull] BeatmapInfo beatmapI beatmapInfo = beatmapInfo.Detach(); + // If this ever gets hit, a request has arrived with an outdated BeatmapInfo. + // An outdated BeatmapInfo may contain a reference to a previous version of the beatmap's files on disk. + Debug.Assert(confirmFileHashIsUpToDate(beatmapInfo), "working beatmap returned with outdated path"); + workingCache.Add(working = new BeatmapManagerWorkingBeatmap(beatmapInfo, this)); // best effort; may be higher than expected. @@ -113,6 +118,12 @@ public virtual WorkingBeatmap GetWorkingBeatmap([CanBeNull] BeatmapInfo beatmapI } } + private bool confirmFileHashIsUpToDate(BeatmapInfo beatmapInfo) + { + string refetchPath = realm.Run(r => r.Find(beatmapInfo.ID)?.File?.File.Hash); + return refetchPath == null || refetchPath == beatmapInfo.File?.File.Hash; + } + #region IResourceStorageProvider TextureStore IBeatmapResourceProvider.LargeTextureStore => largeTextureStore; From 4c2ffa0f79682255e95a579cf67a796eb53a8270 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jan 2026 22:48:18 +0900 Subject: [PATCH 597/836] More aggressively cancel debounced tracked bindable updates If we've run an update since we can cancel the scheduled debounce run. --- osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index 4ef484cb67e0..71d34404cf75 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -82,8 +82,11 @@ protected override void LoadComplete() modSettingChangeTracker = new ModSettingChangeTracker(mods.NewValue); modSettingChangeTracker.SettingChanged += _ => { - debouncedModSettingsChange?.Cancel(); - debouncedModSettingsChange = Scheduler.AddDelayed(updateTrackedBindables, 100); + lock (bindableUpdateLock) + { + debouncedModSettingsChange?.Cancel(); + debouncedModSettingsChange = Scheduler.AddDelayed(updateTrackedBindables, 100); + } }; }, true); } @@ -195,6 +198,9 @@ private void cancelTrackedBindableUpdate() { lock (bindableUpdateLock) { + debouncedModSettingsChange?.Cancel(); + debouncedModSettingsChange = null; + trackedUpdateCancellationSource.Cancel(); trackedUpdateCancellationSource = new CancellationTokenSource(); From 10651512a52d6a6daa6a258089c223d3fecd7dd6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jan 2026 22:48:52 +0900 Subject: [PATCH 598/836] Avoid triggering bindable updates if mods haven't actually changed --- osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index 71d34404cf75..2183cf00df61 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -75,6 +75,10 @@ protected override void LoadComplete() currentMods.BindValueChanged(mods => { + // A change in bindable here doesn't guarantee that mods have actually changed. + if (mods.OldValue.SequenceEqual(mods.NewValue)) + return; + modSettingChangeTracker?.Dispose(); Scheduler.AddOnce(updateTrackedBindables); From 5dd34f165fb59227cc29869ebf74d917bb35b037 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Jan 2026 00:23:48 +0900 Subject: [PATCH 599/836] Add failing test coverage --- .../TestSceneBeatmapDifficultyCache.cs | 50 +++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs index 7a05a3da5ce0..b63c0a81960b 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -15,6 +16,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Tests.Beatmaps.IO; using osu.Game.Tests.Visual; @@ -34,6 +36,12 @@ public partial class TestSceneBeatmapDifficultyCache : OsuTestScene private IBindable starDifficultyBindable; + [Resolved] + private BeatmapManager beatmapManager { get; set; } + + [Resolved] + private BeatmapDifficultyCache actualDifficultyCache { get; set; } + [BackgroundDependencyLoader] private void load(OsuGameBase osu) { @@ -55,6 +63,36 @@ public void SetUpSteps() AddUntilStep($"star difficulty -> {BASE_STARS}", () => starDifficultyBindable.Value.Stars == BASE_STARS); } + [Test] + public void TestInvalidationFlow() + { + BeatmapInfo postEditBeatmapInfo = null; + BeatmapInfo preEditBeatmapInfo = null; + + IBindable bindableDifficulty = null; + + AddStep("get bindable stars", () => + { + preEditBeatmapInfo = importedSet.Beatmaps.First(); + bindableDifficulty = actualDifficultyCache.GetBindableDifficulty(preEditBeatmapInfo); + }); + + AddUntilStep("wait for stars retrieved", () => bindableDifficulty.Value.Stars, () => Is.GreaterThan(0)); + + AddStep("remove all hitobjects", () => + { + var working = beatmapManager.GetWorkingBeatmap(preEditBeatmapInfo); + + ((IList)working.Beatmap.HitObjects).Clear(); + + beatmapManager.Save(working.BeatmapInfo, working.Beatmap); + postEditBeatmapInfo = working.BeatmapInfo; + }); + + AddAssert("stars is now zero", () => actualDifficultyCache.GetDifficultyAsync(postEditBeatmapInfo).GetResultSafely()!.Value.Stars, () => Is.Zero); + AddUntilStep("bindable stars is now zero", () => bindableDifficulty.Value.Stars, () => Is.Zero); + } + [Test] public void TestStarDifficultyChangesOnModSettings() { @@ -122,8 +160,10 @@ public void TestKeyEqualsWithDifferentModOrder() [Test] public void TestKeyDoesntEqualWithDifferentModSettings() { - var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.1 } } }); - var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.9 } } }); + var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, + new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.1 } } }); + var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, + new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.9 } } }); Assert.That(key1, Is.Not.EqualTo(key2)); Assert.That(key1.GetHashCode(), Is.Not.EqualTo(key2.GetHashCode())); @@ -132,8 +172,10 @@ public void TestKeyDoesntEqualWithDifferentModSettings() [Test] public void TestKeyEqualWithMatchingModSettings() { - var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } }); - var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } }); + var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, + new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } }); + var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, + new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } }); Assert.That(key1, Is.EqualTo(key2)); Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode())); From b705313d3f3bcd950bbb6076de995c91c82cbd18 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jan 2026 23:09:08 +0900 Subject: [PATCH 600/836] Fix `BeatmapDifficultyCache`'s bindable tracking not correctly updating `BeatmapInfo` metadata on invalidation --- osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 25 ++++++++++++++++++--- osu.Game/Beatmaps/BeatmapUpdater.cs | 6 ++--- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index 2183cf00df61..291239e350e6 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -95,9 +95,28 @@ protected override void LoadComplete() }, true); } - public void Invalidate(IBeatmapInfo beatmap) + /// + /// Notify this cache that a beatmap has been invalidated/updated. + /// + /// The old beatmap model. + /// The updated beatmap model. + public void Invalidate(IBeatmapInfo oldBeatmap, IBeatmapInfo newBeatmap) { - base.Invalidate(lookup => lookup.BeatmapInfo.Equals(beatmap)); + base.Invalidate(lookup => lookup.BeatmapInfo.Equals(oldBeatmap)); + + lock (bindableUpdateLock) + { + bool trackedBindablesRefreshRequired = false; + + foreach (var bsd in trackedBindables.Where(bsd => bsd.BeatmapInfo.Equals(oldBeatmap))) + { + bsd.BeatmapInfo = newBeatmap; + trackedBindablesRefreshRequired = true; + } + + if (trackedBindablesRefreshRequired) + Scheduler.AddOnce(updateTrackedBindables); + } } /// @@ -358,7 +377,7 @@ public override int GetHashCode() private class BindableStarDifficulty : Bindable { - public readonly IBeatmapInfo BeatmapInfo; + public IBeatmapInfo BeatmapInfo; public readonly CancellationToken CancellationToken; public BindableStarDifficulty(IBeatmapInfo beatmapInfo, CancellationToken cancellationToken) diff --git a/osu.Game/Beatmaps/BeatmapUpdater.cs b/osu.Game/Beatmaps/BeatmapUpdater.cs index ff23bf124203..72c69393dfae 100644 --- a/osu.Game/Beatmaps/BeatmapUpdater.cs +++ b/osu.Game/Beatmaps/BeatmapUpdater.cs @@ -52,11 +52,11 @@ public void Process(BeatmapSetInfo beatmapSet, MetadataLookupScope lookupScope = foreach (BeatmapInfo beatmap in beatmapSet.Beatmaps) { - difficultyCache.Invalidate(beatmap); - var working = workingBeatmapCache.GetWorkingBeatmap(beatmap); - var ruleset = working.BeatmapInfo.Ruleset.CreateInstance(); + difficultyCache.Invalidate(beatmap, working.BeatmapInfo); + + var ruleset = working.BeatmapInfo.Ruleset.CreateInstance(); var calculator = ruleset.CreateDifficultyCalculator(working); beatmap.StarRating = calculator.Calculate().StarRating; From 8e5eed63e1e4647372872111fbd8eca5c807354d Mon Sep 17 00:00:00 2001 From: Tim Oliver Date: Thu, 29 Jan 2026 01:12:41 +0800 Subject: [PATCH 601/836] Update iOS app icon to iOS 26 Liquid Glass variants (#36510) Removes the previous `AppIcon.appiconset` bundle and replaces it with all of the necessary asset slices to enable all of the Liquid Glass variants of the app icon on iOS 26, while also preserving backwards compatibility with older iOS versions. LiquidGlass --------- Co-authored-by: Dean Herbert --- osu.Desktop/OsuGameDesktop.cs | 10 +++++-- osu.Game.Rulesets.Catch.Tests.iOS/Info.plist | 4 +-- osu.Game.Rulesets.Mania.Tests.iOS/Info.plist | 4 +-- osu.Game.Rulesets.Osu.Tests.iOS/Info.plist | 4 +-- osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist | 4 +-- osu.Game.Tests.iOS/Info.plist | 27 ++++++++++++++++-- osu.iOS/AppIcon60x60@2x.png | Bin 0 -> 23955 bytes osu.iOS/AppIcon76x76@2x~ipad.png | Bin 0 -> 34568 bytes osu.iOS/Assets.car | Bin 0 -> 5609864 bytes ...0-5cbe0121-ed68-414f-9ddc-dd993ac97e62.png | Bin 394881 -> 0 bytes .../AppIcon.appiconset/Contents.json | 14 --------- osu.iOS/Assets.xcassets/Contents.json | 6 ---- osu.iOS/Info.plist | 27 ++++++++++++++++-- osu.iOS/osu.iOS.csproj | 5 ++++ 14 files changed, 66 insertions(+), 39 deletions(-) create mode 100644 osu.iOS/AppIcon60x60@2x.png create mode 100644 osu.iOS/AppIcon76x76@2x~ipad.png create mode 100644 osu.iOS/Assets.car delete mode 100644 osu.iOS/Assets.xcassets/AppIcon.appiconset/300076680-5cbe0121-ed68-414f-9ddc-dd993ac97e62.png delete mode 100644 osu.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 osu.iOS/Assets.xcassets/Contents.json diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index 885ee0620eed..2530f34939b4 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -146,9 +146,13 @@ public override void SetHost(GameHost host) { base.SetHost(host); - var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"); - if (iconStream != null) - host.Window.SetIconFromStream(iconStream); + // Apple operating systems use a better icon provided via external assets. + if (!RuntimeInfo.IsApple) + { + var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"); + if (iconStream != null) + host.Window.SetIconFromStream(iconStream); + } host.Window.Title = Name; } diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist b/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist index f87043e1d1be..a3b9dda48c2d 100644 --- a/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist +++ b/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist @@ -35,11 +35,9 @@ UIInterfaceOrientationLandscapeRight UIInterfaceOrientationLandscapeLeft - XSAppIconAssets - Assets.xcassets/AppIcon.appiconset UIApplicationSupportsIndirectInputEvents CADisableMinimumFrameDurationOnPhone - \ No newline at end of file + diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist b/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist index 740036309fe1..83cb8f2e8ccd 100644 --- a/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist +++ b/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist @@ -35,11 +35,9 @@ UIInterfaceOrientationLandscapeRight UIInterfaceOrientationLandscapeLeft - XSAppIconAssets - Assets.xcassets/AppIcon.appiconset UIApplicationSupportsIndirectInputEvents CADisableMinimumFrameDurationOnPhone - \ No newline at end of file + diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist b/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist index 7f489874e745..6f0ea841076d 100644 --- a/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist +++ b/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist @@ -35,11 +35,9 @@ UIInterfaceOrientationLandscapeRight UIInterfaceOrientationLandscapeLeft - XSAppIconAssets - Assets.xcassets/AppIcon.appiconset UIApplicationSupportsIndirectInputEvents CADisableMinimumFrameDurationOnPhone - \ No newline at end of file + diff --git a/osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist b/osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist index 162ee75c229f..1ef6b69ff395 100644 --- a/osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist +++ b/osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist @@ -35,11 +35,9 @@ UIInterfaceOrientationLandscapeRight UIInterfaceOrientationLandscapeLeft - XSAppIconAssets - Assets.xcassets/AppIcon.appiconset UIApplicationSupportsIndirectInputEvents CADisableMinimumFrameDurationOnPhone - \ No newline at end of file + diff --git a/osu.Game.Tests.iOS/Info.plist b/osu.Game.Tests.iOS/Info.plist index d2d0583e46cb..e08b9bf6e66f 100644 --- a/osu.Game.Tests.iOS/Info.plist +++ b/osu.Game.Tests.iOS/Info.plist @@ -35,8 +35,31 @@ UIInterfaceOrientationLandscapeRight UIInterfaceOrientationLandscapeLeft - XSAppIconAssets - Assets.xcassets/AppIcon.appiconset + CFBundleIcons~ipad + + CFBundlePrimaryIcon + + CFBundleIconFiles + + AppIcon60x60 + + CFBundleIconName + AppIcon + + + CFBundleIcons + + CFBundlePrimaryIcon + + CFBundleIconFiles + + AppIcon60x60 + AppIcon76x76 + + CFBundleIconName + AppIcon + + UIApplicationSupportsIndirectInputEvents CADisableMinimumFrameDurationOnPhone diff --git a/osu.iOS/AppIcon60x60@2x.png b/osu.iOS/AppIcon60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ee8f3efcfbdf5da411c5b8e77d6cda8285aa7c68 GIT binary patch literal 23955 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 A^Z)<= literal 0 HcmV?d00001 diff --git a/osu.iOS/Assets.car b/osu.iOS/Assets.car new file mode 100644 index 0000000000000000000000000000000000000000..b87f48c6ea4ac0c73c110b21495befd3e35da146 GIT binary patch literal 5609864 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
OQbVnC51uOskBcPQ>snv+PSaCZ*NCd_A4Di8t z1F)-Rt{Bpcc^Ux0aTMlma!+tNz|DlR^(V!Jf{(zCDT3#h-LpEv_z+ye^N-mfe(%li3R4EJ5;r>x^f^@vRI_;Ug(+fwQX&b=LsD6TB3#nRH2&!3u_*FJTS4OrIAxwqZ1oS%` zs=#X-hfP_6AWCYEUPKqjHrn;naQH{#c~SeYlM8u35EXG8z^-RO)Co41iIC|zaLDF7 z!xj=mq@E4eF_3Zol$VEML8Y)PJo!@Kwl9+wYo}I1CuN|JBRk;tpPg!U%*_@Io~0U~ zWH?lT*EX)UMy3N5C30nq7yRUAvmAT3rGN?d_WYYEPq{=^1q9b4Rtw;qOhSgH9<)Wl zAG0aJDy=O~*vWjUqGMrHqb}y=<+KflnaV}G0cErUC9DS+AV>fT1EW$H(#~oX;B-wT zO<#{~LbrQ3D}GypaimK0E1cx%P zUkwUsq6oRCL_4Y~BG_OS+$g`f`6^kF;YQ<%B3wWuozAb$o)*xEglyRP5#rNGg0cKm z;cJ7(ptnioQaQgJ!uDv)UCPq0E%fl{*^|hF}&kFwq2>wn!&Rv(OXP03ifo z$Ie`0t23?8{~qcm7eH(kBsKQ5LE1vNrhuS!Ka85fm)T}n+p%|(?P<+ zP(s+~+2Kn+gHRoblCLzRagM=p@V<^txM_VXd;&(IOdY}>VtEi(?g&BXNlSYCh0L$c zo)++kgnZcYMZQWT#kUA(bbVFVy25>AhtD%mT6VSjYwg?JPTez{<#h5e!e~vF_0W!s z+KhKw1Cbxm%}2X04W$Y71~^mHS5$t#rf09S-9tJht@uJ#Wd;ROcSw+;h2=M$xkreXMr{YM-356AS^B2!mQvy(?u4fyV@}79Y0Z5LG+9f zbqh$p1ktJHpGBH{&3=X^%||kwx5$kV5`_@}q1GU4wH~7dljIm2=IN#iF3#?Wp>(j_ zSUGuvfC7cEf31MWL;Sdlbs?MG?M0W}2VjHTW;v`Jl#%pT38uYlZo zU;|RVx!E)Lj6w~h7;h-N#U-*ap(R8ofarvRHP6hI3ICtt(FA&NSg4H474>xDA%V50mD|2P^YWU zadQK-0GCsuNAau{7*+!`G-ik;?9&j|Q6N^#sTOktQ^s0y)!Z&d}K@M+1Q^8Niam zUoVMS%0Cb>m?wc)kO2T-*nDRK%Iwi%-3;;!Utj>ErTuJTMxIKC63Eq|$^&yf2~Q0G z9?PrQ>SU%kyXcI}Iyx__uIOKDWhhif9I&5Cj?MJu?13PgKQ)XGzTYZU@yolGvGW4qp|^cXR);m+AQRqo4hl(?sW-Ox6vCUo;h8>UE{i?SmtKnLYj+nx4lY0iWuI0(pO zUz%*2lL%NUB;3>H%L%4|iI63)2Aj$TM>q^DdqXK#;tQ{ks53AT3~OC^mmSoG(!+w; z4=ylhpqUC7?PmkY<^D^@UebD=iu1_?TTvVyRA@>Fk8p!cJ7)zT!~uRj{O;_U&EU93 zD&9)7xl)PH20&q(3?78AshOHlkh>OF`#U+#DECTZrZAlIdKpdCx5};^rF6wcHQ{fk9CVKn8+oIVriTW#AU}iLo;O388han>zT8=uZV+xnvLt zs+s}q6M+I`n0ThJ5WpsjR>cOFD3zU1JQa^-1ezFVg~+|ng!p#J-5w8n*dQp))d9ID z78!9!gA2K18BCKN%{Fl|c4dxYbQ-e(iJSbSsCVm1au10pXsOZj=Qfvtlt+rRT*d!-LsvUus#6*u zC#FB89k>P6nj=NY@tMG-0&Ug%m3WLGlq)&9Q%mHP0#8*?A| zkG<+(VfEzNJqet9y?ap^Qz^4xZp0MuQzpnNhJHi0 zFfZIEj}0BLpoTHKWH>i^xDsqp09z>p9*@mXLzbo|hzf%D0D19(jPRRh8Dx<`4q}#T zdjZGd2N8svRuAeCFIo)}7gwZTd=7@g9S_65V6z`eimd~G1SG)8P!l5nD}V$(d60rj zR*LlLSAR@$H9mt7=`{wmiG}*8#wQMD&v_TVGW0VMVh<=MKFHuRS)KU^3p0T6N|Q47 z-_+HS_4)`}hN*A@oLKBi%Wxs=*3hF?<;7Q_0kKH%g;UcEgaK;j75$#sN(Ac>O@|;} z+xL=lF?eTAhyT9=%UP-VytxJZf6_`L(f6#l6+238%+>2#sea5CL<=X}r=(^-7HjxpGrlQ`MWN z+uxH#eOoJCX$`{7;#3LAqyTdenSusp;HTVi<;NwgS$I|YHXSH{OKZImw!%G0bs3iD zj;NF0ZS}wS!awd?1Ft);49{cokH3M+Q4tYBd928}(+5;zJxS#!P1(>&dHck+U_Waq z-#>$zumN|f?}}y@XWHs+g|l@HjanDqc*1XJ8tg~SFy-A-_ySz+7<4oz7~&5H3_nrk zKG-=?B@jn`S9vtadI-d>%F;CYN@}t5E*ACX{XFU3=eRm_e{`qlCPwB@Cl)c%O;p2W>nuXO%_F?W9=7U(1{!8P}4W2Kb zfWj`&YVAFxhNm%{v@L`=F-wv6VN;$RdVEe$L4!oh(`ntEvz+X@#(Z!c=0k%+gk0Ep z@(eD^^gnQ90*#J4rsKHY3%8DBN^DtcbY{_j1}z%OD&auT@qss5*|S44`Ezh(a`18X zr2B12`P?^On^xjx=RiS!q*#~lSPcw{0e?CnC%X)9Vv4hH2ERY8PBqN(NGgXS9+MAL zu;I18M08KWSRcDagc&9q*=;+fDE?MAt_g`JAW*3}!1}6(SO8yO3}d3Imp+3p*mT{U zCQzYE9-X8lKx=MYR#$u&ycP~qADi$HKJV*pNR=Ek@Gs$oQ;Kq0AKT#y;kRKqCe;eZwJ?i&2P2(1lRsvWaGI=?3D<6}hNrpUylHAKh&Dh)*{gd{B( za!xTsaEpWHl949z3I+)#wIFy8Cm!i$A59a-mp^PX3bsFT!DkiIAx{=*c-5up>R7+w zGJExa+Cbm)6V?{V08>3IZ+auhA&PiOapd*`l$vHT7&JRAvkC6tf=W;uQZdZyD;|a-ql!;@a_X!@CE3+6oD!M0p9U z8VyAMN`@BU_ZB0ao(BF@zpvC-*=jOfUf$Sjxu91fZ-SbW{WcZ9vd1wxE_n;y>P&U+C zs&sUwz7I{H1P|YZBJ!yo0z~10-P->pcl2hTjO;i!8?2&hRTqnOr0DT_N~(D>4`aVV zndfra&fKCPdh9p0_Mk@d<}6LqBi5+Rw1PXfuVk_^zbsc5+kCtJ$kaF-g~t> z9HXBq)4WE4MqAl3%S*iidy%_;QtB}w#1JOwk#(trhd(ry2)z;i)U;u=d%{FD{Be*1 z)Ga9O82Ue{4dkLS=B`_@s$(nw*x+4}cOKjb81CZfUO@a2DoEgdLE=fMSR}`K3FTJW zGzm`{7~7z2%kZrsq|;JjdXvtr1m5HEf|Hv;WYCW^Rn+YAAuJ?j5@4_l9qV9h^{_Bh zPo(Bv)2xAu)abT|0D4L+cWVbu0T|r(9X}EY#wnB_^f<3W-|o`B`v0r zPiA}Ok2UL8Hx_{PnJNp~ym1yEb!|&8`vw@DCG0@wg+MH9qi8tvDuFmQnz;=1KV~hTTk_S+9sMML`;xEa?K|kS83QoQTSr|h=T12}p zNkBTwwxl^`5Q1lpj_FK);xr#@BSQXllEtgqG7*v`bgGP0i3;EyEMr>03w#8q+Em07 zL#cRL`iE(pNnjJO;jqb+D`tl-b?CI09baoJqH~r&d=SK*RKbaaqeKL%^RRjFw-@A< zjb6>=I|#>RAC4rn`h#^0cO8X2!-BY0+DNs_4&GQ^v&_VPGh zvP=4Wjq~CdQ!DyF3@!6^5dykbjaGGjM0DS%rPr^md*Z#HH)PQ80r^;2;nNNv)Xa1W zR0YhZHdEPx=dcPE=)z0CO|t{= zewkT<_?!tZxM9IKkfIVe80FRwD77ZdDnr$X*m|yw20x}?f7ki!+%v0C;pFi5N^Q)2itk|4RfUqlCAjvqdq) zgE@e~ACzf}t7m396Ti}-|#xDC2UpW9DtR`h!vb7zg=GqxRYCX`LhtQe%fTgW-AWR#z5#c191BhcD z3vrxTO&yeCv`743qs=Om?b2`&pWIlri7*7_gP@7N?;s+TL0IjQhLVp=gWC#}1Y>>1 z{_A@ArC=mC(X=%!cY?^0pv!3D%L%s#3CFlY)W&KufZ6ctc<8oFen1;SFDt~t``jpt zIXwIBKD65#ZJfL-O)5vD`m%EGvsZ^rXRQMNYEqZrsU$kx8{9)eac@N)K`JOBdSW7g z9LdxaMv-4Qv|EjyoBqp^kb23fJa_Yo@J*|M`{KboNVP4U7{aE=4=6+IWrbLHpBrT{ zhiBj2hjwpF5gs>;Mqmi=O;4h1I1p)9MDX+MDyy?Z-iWN4J1GMwpg`qi6@q_@7*qq8 z(5kf$*<-lWN|9d!rIpN82!T=RR&3UWwNNu1%}WwXk}@X~%hCd`6j%zM9hR_P7QEezM=O_9Sm^ZqA(0&s8rnbo)|rBf&FaZk5?ByfUJ4s9l9HKKt_ zvHErK@`HgZK}hOv%UpN)7Mme+{HF)D`Uu>hn2x>mB7r4&ugy=2{np7FiDG;}nbiw2 z2j~7xIi+d)?dK#RkbrUwr#1Wq;liZmh{OB<`vB_@Bm+U=E|hv}8sMY@3V4u~n!exa z%{hEp8xY?;M6^$_UxGfhxUfPD&mg>p|EL|Y2ICXo`G%c?9)j!?Z9zia#yNw(5hl!Z zriEaq@D@H|c6c&QZ2|xQ6kyK)2qzHkOk|l`dr<(j0000VWH1A-z?rJ5swx2F=ICPY zBx_cyn`fa&mZe zb}_HcF7_V1m~-9igK@Cdx>$QO2OV8mT_YL280~UJhe;e6sz$9fR#A;bjVjh*2&$@4 zMF2Dr0RT{qB8VztR7HZSs)_;vC?Ws=fFc3_fFhy@04nh-XB(3C$`hD3D8D~0lp;B0 znKZ_@&bKoKiO|G}n9o^dGFFP!BC!EaK7{YAxvr37jGF|{*vxq*;etdbG~^skf^uX; zX{s9%zDa<4c@XswP=XNQ!sY6Qzz>3vuI&ZQ2Ej8&1{S*_Oi7@GaSH&}F{_MqKAdaM zWAGn66G}QX)F14k3lz-BB3_uiqc~A!M}cl}LOU0Mr5~h4^1zaJSK>VIxnTt=^)!OZ zJTpHMEqXRf%o0XQsRma1EoAE(F-aYZ5&o1ai?XH;Z>*(8vG|3=((-K0fo#-*aAiV~guiOiwVRkzAW4z}ICc z`z##(ND8jeJbYe06bk{bD?ZA`ES+;fU?$KDLQ4#WGL8-Qe=6YeVN(s%E|VZZymj{b z*gVD!yAwgi%4`{MeYZsjaAul^=b7iiL$Cx!6<>p#Hm~fgGS-OhbJ|UoJKb!n)jX9L z$FvCz;$}|8{$^TNz*kcFt-}<%^^JCO@2d!RH%7%+6FUbQ2}JtvOK#hdGwbDM<9YR= z5tl+2=djzRp=dnsyK^6bi0;P@05B_o4CXM{x44bq`D{X-EeWJW8Vyyg`_p14T9|HqN}o_09;^VVtL}KNFzvEnCg22?@{9 zjCsU(kUcFxWzmB2LXFlH{Ef!R2w?*FHbN(z`T)K>w~uVK9^!N0y9feevGR8W?NhhV z$T{h@S2bHxu|>6)N@3WpYbkvecoAM!z?t|4{`ic&ne_;n&WZK>p>YD1Dg75NArG3Hk{g7|lB5bh-k;8kX)7CID~S3;NOF zZpEPqAUAx3N>zF=F5M78+JYBu{*m~N>p7D!$oaS9hUNm`9pP0w!*bL6yXfV}J37c_ zq`>~bB1_80EC99FGHC+(!bL8nS_ESS1x1*1EHo%~f$^k$pOl=>Z+-`g5Lligz=`(jg>1?#Ghvqy+0H zg(93$w-@vB2Kz9MG>XL3{7|q*J7uyMlZ=Qesfi5YC;9tX6@47IVrsngShj7W#>b$$ zrdF3eFa(M5nFm`=-V-G|0&2XF^UTN~Qhc1&(ER-w0RN(3KrVXHL{vWD@+M=SZv8o} z5ytgwVjkH~o%62voePoqHf-tPNXME&17KSWfD*dLX#P8FqAn27L-;_c5~crY`X|SI z?JnO&r27sD$qigDK4n-qty9=0dBuNV4~K?MilNN@60x##XHgQ44Xem=n`7 zVfxKWR`q7w_ik~c>->=$H%8zLe&=V_8fp+22D9FN;}rkKd6B1-E9>Q8X5~x(lY{!f z?OiRuJM8(}zN2(4FTp9gMigl9hB@NCzTy4S?<>_9Zs=Qeh3MGQ;nj8vk;Z}<$OGn$ z2>}wz+%Ji?KUX@*&b*AzX7vUnOVJ(auQ>Ro)Vr@N;m@s76mrP=;7i>*`*GWC4^uZr z_A4=NtYGma%zHc!A?*eiQI`}i)n6XY2xk@tLx_jrM(S7 z{tF@#!$5te$POS-{c30UrFrKFV^>M<{h_Tv0MH6gy&w6J`NE3Takt}rPzyUi3cr>u z0=g!PdyMGeF_F=VjSsY%kLK2<*kHWsp;S%p?0azu07$m6IEME7x0~9D{R5cMp=3)X zFh3hBxY4{9hDZtEQf6`KonG>@!O!l6&Apa`F)1^-n%VWpv_I$V+m0YW?yGnCZs2u{ zfUc!i_Y&FKLw;(K3Mq4yUDVTmt5WL1IjfHff=tK+;9C5w%R9E4k3T8JtHHR8nA3I@ zF{PoA&#_b*#{ucH+VLgtmt~OUc;UhNLc_2?HU%w#+AGh36w~N`Eca?d@k*vA4SgcA z9HZ7w!J6?`{!@qDsxy7j4T#^$grURxl=5MqTa%Wn&-5ivFC_xmg!KzG7yZCS{B*ti z?U4ZIv{2v*4lX+AxV0>QsElL!ZxUocRJ^7}`f`LO5wu-kw58IrGUjB{L91le$v}@S ze-r2`q4yX9iZO#Nz0~20Z8w{E`0iA7=!WoifQ*0pL3!TQhL73S3bM^dXMH2D_7&E4 zgrEPh=fdkl<3yW382W;3)sQ~v=df-a(Qc5S(L02l648E@aBaFp5lHk(vMMDJ(}ij~ zn4}Xzm-Jb!u%}r#v>K1qWnuDM=yjHOuYIb*TvlUxnD+-O;Ah8=#v%5nN@NvSfcH0h_V~PxhsJs(2g%x|sbGZ;7RB(}7+&WOv@S zBeIprsYHuP@58o|^5kV&D4*XFC0ocp~mSwAzd?7+T|H#%m8rdx8sp9&7y zhPi`yx5jkp=I0Lk@>SFG##&U6n&)OwwB?=ql6!oPdS7*t* z;vtNNhaA9d*(A{M@^*Y)zeW%bwMko^-o2%ww(MFSirv1|<0GDEg|syQooKtSg2Q9o zVqrH&LtSmh!8egjoUc`0?B>fzGpZhe7g#Y4gJv{Kc+?^y&H~{eEG`6{)spad=cD&u z-j2y3SV1=;s-Gg6u#_7%B4V~@KBk$Q>aR)7+ zYRF@C40B5KX|0c+V@v?N(%n)WQ|i0qViv}_t=zGd!pHF-5q^9$h;_^F3Y2%XkgU7Z zJIm~R5rxrmL1##-4g0}(4*=Y&atAwDA4)YnI&gLd7uKC4N=@ZKd`W#-A#2C?2(t^P zS7*+i62!tHnOI2HKA=Tk)9NFPfh31< zG|bgHG+8N-%?ot(PnWp}grQ&Jo3#WT7h!!~4$S7dC=H-EHF0ouPpZ}-A=GvdCwAx| z?Z6!D4AW*W7O;+tpfyl92l1Rp@^4E&zb@%jud;#K9RsQ!S3nkq;i@s%au6781_7Be zSs-h8RoVV#f4P~!m!kRR)#l3Xn-EFf6}gcv62KMB_7L=9IZSza0~S|Kh;!#^5A0! zvKHpX25Ng84$3a$PSG+1FP zK;=o6^S?xKozQiN(v0KHFSnva2eC|qbBefh2BJ$1zr`%vl@V_ z39YDmmla=Q%-uve`Y9K&RH3UUcme9Gu@i{(eq|ewHyNXCa8em>p#~rFdl#8P` z04m)EKIlBj?+nXggP1i=>8Axlbb18c{Xop`&mF~DZ5H%P@r%_Y+>{(Ny@P$^i}fg8 z7J+?ccwKu_N83Wi^t{7HqCsj522_V|kMM7gKtL(Z8jI+wUhT{o_(IGi z_ zTmrJ_EP6ozwg+#x^9={am2RHW+-8^A{N*KD9HmAF48p_3VvJ|b3H1Sv-$k{-U#f0} zIPDDfR;9H&3UUex5KWYo(2o5%LNt~5h(Kkzr*gTB>-I^~#B#hqaO_2RVuNk0@zMko z#t;NIoWgd zwPZU4Xkv9*1~jl^jIYZ_p`3MiHH>Ha%%p(jmu*r zvj#rZmFij@gkB`PGk;C|EyUo#SQw#V`*V<~nMBHgb<0f1YO>}K0FEL=Ejg#q^IAk0 zK8yX)(LbtE`_hmOK9b}i1S6i1l>bu!mEO|Ub0i2~>U=8X8Y;5Zf$irNh22Z@fy^2g z22N0TLO3885k&_Q|8a6YZ{tZT5=wlXWI$^$Njb&;+<&*x-o-Iim2w!O)%GdN@HLAf zTChu#Mcft8HU*zGR{3c+$x}VEOCG!G^+3QZ0SZ~tFf@!PLF77cs_8bsFID3uD4EtM zoJpJ-`e-HcFs8-fx0W$|FAOunQ^Hl8zR~S*#sDcyMp)0Mp#1k1B3?|e@+KP zmJH1z;b*aZ*zt}McOll0yu&MF3`8b<+BYD=NFp5M_W(lIExE(uU20aXNuH0Jyz#Cv zz+yq!Z`4dJ-; z8}y;u6R;D))YQ?B&LR!Ks5&yCx>>Adn5TMXmpn>AKoS-(PAMz(Nx})k^c$+^ZU7Dm zM7}kycwT_>;gl+*-~ecnDo4Kzn8YPm6)>BoSQw6XrbWj{03ikWn?WQpVOg<>WUa%a zR{@FPAKt1p)rhoMG8;C=zx!J6NHsefN>rFE10L41gcWJRYA0sdC1<&x@1ZXUrl{+O z0}-YV<7R|}+0!WfTLe=< z9o5N&DfqJDZMeP)o$rsqRdD^FUP*n4lTjRjAkq?KT|>^k;>ftAb&gyiZ5j{xfPBa6 zZkA#N94c{B2)sKBh0?90ktUZT)ZYx|^1Cw3D6n z22o~D^^&7v1#!A}pn7XdB}&XAP*U!vE|`H!obT<%7;_OGX~Kl$P~*#Xv?qY5x(zIg z5}`hf(T}<_ypK@tB_N*`Cis(!4yl6daG(o45UF2$@iKW7(=CxK{Mw@j=F)*{HH$#( z(GY{yu#$j0lLT=5_qd)QZ57-w8k6Pl!7LMy-Rzb}X_7>m>szpFM1BV}@$S}({_=I8 z++4t=X)~daumoocYjApq6*oLPt@B|0Qm>hCF++C=Gl&jsV*#3a;G+5t`wDnt^i6Vh zS&-|4IwBpm0OMYE(*#T@xhkHOP`VGq0(D85HR{u!c%>*OaG)*qRThk%k$yZ}QXxMI zDC~ONd&N@i@=qgkN>-2DY6NdywAkv7aCkNo$^&RqF1m0=4f+-?_5S>M-6*_butMHX zla0ZZ4qjedRDeip#e6GQ-#VmhQ0vu(1aCG!6LaH_ftGHFfO0%18A zqw`UNCGss*-vq}mu1`MD1_!~iCcvXEsQY)pl^d63^JwDfIj4mCjzMq__D|xf?4%C5 zB$}R1-ta0ak6gm_)W&kmJ9|A!uOi&!?Ts`BbmGh(g9OOw zBGuGCY4|D})OJP#>xE`b`iJ$CUY1+Hj;>fTA))bLOm8xI|b|%Uj{%= zbn*}B7|#l}NK{($$fn$Ue40ml(*(c5+ItmBpRTZC@*5&1N+avy&G1s`f0mR6CdWz7 z3KLXP3q){LDi^w^Qn7u(WbWylJ>Yg9%eplhTv6m03t zzkg_PoJQi9D3JyUq>t_dA#l_m1AC$|0yK|L zW*RC2N;*UBCB74~565%?CnRF~%3$C7V6;6dBuaiejo(L@4S*o7s}6h}3&@?B)6#~u zmfkI%X^EXj_18*6z-3&y2EqoBt-guE<)v>__U%*~cHRg!Ni&r(1Z=y(|9iXQVR97J z4hkUN6Ya6$+1ZHhFB$?wIv}l-gPDMZ(31j8KRbw23&YT)qZ=AVp&LR2Yx#5|PY&Q- ztzC{uC#^388wqcbjeIhw(?jd*vn|>XPu-H__tww^(h==f=o>QenN+8%k4H0B-Pi%k|KA7xmmKHqYHei07KdOPq)lb{_j!&4x6 zd(Pz@w-hMJ%>E`<@4N>;qiMl3fF{=Xky1rLCzfJCjl?6FmmjC{2GQSG?D2UT%0Wvw zKS&PURF9AQpS7k9F+DS@BXAyyNgMmSvJpP^ghCi>Qube}Gd>}0g1Dp`4Qf7@ntH8< zKG9h4m6JjYM*qO!a4A0@1#}a?Q)tEsnHHoXr_S8~ZRey@_r_#?-q`09vX6 z^oH+`*S`_4k8;zXhNIep>K$jqUYd6|<1|X|>68s`_yuu)bT!dSosEY*nabhIN!?6v}pq5x^%c%{%^lnEg;Q#PnPFpV)M5$j)YUui;oBeGu z?)*<_lsiFOCMikoMa1`Ld(6=1c;gvOYD`{N5bmX5sbGfNnNQSzR0&cPv2gRKzK`@A zt44mc+s@uPAn4t=`SzVhhB0U{?832;kDe>a8SYLgIJjPB^ zml>5bp$kderOyISL0hw)*>US9V;9G2Ya>9l?3p7YqO(V%GxLU$UA53CXlzm|BF2$V zMdBf;o>Ti{Yl;r|mw>ra54f$3Hckct1Lc>mdF}A!NFkHq*R{q(y_M5NQ)!ii(}TwD zc3D)nQ#&K$s3hHmtby_LC~#PlDvsT=;EeAFiQJ?%J;RzFS zd>7{5y|qY=&ojp0-nHm$Z*fUH#ucy_d$6tpjQLC5qe+55K$i?)y26MirQCHsf~~P8 z!3+%ufa?Iec`CH8B>smrh=I4n=K~GPZQ|*u1VbapG^!wEhVgu+Hg-;{NJ^QYE^QV$Sn;O`M~F(h#6x3#9d zU9D;boRfKCG9~J$=U?Ih?|Vr>O>e_gKjo+cbuVgOX@Dan>KOE6HZO)cRXRG^JptUQ zLhk00cqN_PK;XC$;UVF5Rt3;K`eXnkptlNC7j;XF;nia;ug1rFr##RtNta$2)ag4& z>dP=Mc)GuXd!Mbz2niLrv|JU6nj{Z5GHmbx( z5Y_@>c1J5D9Kz}XN4Tj44W|X6#&bt)ZkC9g!N*rMx47|b&V=1Jv_Z!=8-XWM4%q)I zY~1EMxd#rDWV&k3;QWj(_+mMRy20#6ELDE#b_m8b>UZVNuIIu5ObuJXHp^2!n_9S{!s~OiL zZV;vk9*d|D(`4U3g&jf(ug*Dn$rTWA7?&0(KKPn8>&e?ey%M_X)0@0HY)`Cn^_%90 zBorhMKj zB*V*5fUGn*Q+x{CEgC?0RJkSizHgvo375huTlw~KDXji1Z*ChXScy}`Ua*ej3f6oq zmf^J$huCGVUC@IDY&v@5VgWvG z3}Rddw*qbO*e2H71uFs;Qu^Y*X~Nx<#g~jm~IOQ41eK zstrw;cZXCI49svhr;zQ;80Ctt9K|Zbh^EfB4v2%nH_az%8aMd2|8u=5uR(N6BB`EM z_Pe2sg(S|QNTl4{1SKNqWZ|YC4`R7@)Q&yc?Rqih^pb`gWWLw1&=TfuI5>5>H~L9f zd7D;?GkjM;6bjR=2ESw&ivj_z*yUjw50o#e0&ieQ1m zui=cSsRFXN;wlDGm@zngD*Vpvgp7)+4FX>1L#F*}samiqts{Tmr?y8eS+kY=LTPkM zDh2LF#e{`Vp~MhQ&88U+w4)Kr!D#&ZWs+W!6gYrH4A}_pQSuAGPzX!So-C$i7e97{H7h$>$$$x}zcx#^@-v0hs~b!8eN%{TigR zT1;A3R8y~od;^HLr&^BZY+HI!$z#k&5xn1Ps{0NUhYMNKK!B6tL>{)QAkv6qs7$sB zp9lamVMG%EB~c*lQq}01I&6?}^B5xTrS8JiB-vlwN-A`nGw9qBl(A-$C#0%JlX&nC zcxCs-UG6siQz+sTusff@-8%C{nOEsh!g%SQtWJ zH_g3|P6;(NS^FdTgkUdJ8w)hL5$iZw|4qOM?M}LByR5pT3k*7YNK0KxF*;ZR*epV& z0LcfWmhRo;&&Tl1JK?Md0~;Ov?497CjVXH45PWJu78MEXDlm6-XtCbI86Zwx29PimMH%&lj zK%VBuRG7sl`(BZo?mRpDx5)N;#ta0UOMtKxnpq=6o?=l(dc>5fa6rnL8P^mt-#VaO z%5ZYb1p*ccJOPd{&9Q**H=-H>lL#ByW|Tyc0h3R4EbI2*33^ixyCI`h-$>Zk1xOZD@zBDj zc+SlJ+wIW!v^is=DQ5yxr4wC@} z_D*491&tvS5QvP|T6lw+tPvhhGJs^uWe=&OYGD&kbpx82B%xv_3~spGCITlPQ*aGw zD7HDO_D|5j&&ogYMj0#1cF2}n8JK;%AIAWXUTT_gjHu-I25%@fQ(Z-k8&ix86z2zC z8;D%|Np8XHD&@0=lH2(?H(P*_Ug+~*ZcYiHOYNEqu*9XPT7jlElz0|C zuV4~Qf@pc%cy-o%mL6P*QT+7DU%yBsnZ-emKx@!(!#Y8ynLf-k7;UCAOb6a?q*EJtU~9S1ri6C4QEfrD#g(h62yU>;_cnZydB z1tv6tLOq3q+%JzUvLBkI4zi`ZCe=QZ%aJtXXgGRct0SsVhB>s+w*JQT@?^i{>_(Yz z7a5+mf`v&&t|_$VnjZMS07YtoJURxwklaQg3PXg%48GW?|C+sSsJuH7?mTJYrR^5c_fG(r*qN{p^|XF?8nCg5j901l^Dn z2+e>&6w+`QrfzSDx$tRGx~dcV<6^)sIFpWPP{i?lAr3PG`YS7gwin@%2GwA!T2o>t zMBp&3hVW8>jtl=i{LxhRBaJ@L{IlPNIsVq^?=Uzh>4=&wW~}q$Gz-6~v4Bk=ck}SM z$a{Y7H27Z;CrqBUq-479%QU!b+(O0Y_2JFrH)|s@vk#!EqeBi=f<8@=XvA47==Zr& zVTI1B7E9&K=rd!NUh^!z!zKUF3X4Wui9ES zZOE{G!-zwZ3U~z`XDTPHr6m@WN`ZSF2#?NkU)fcI)7M>DlFiR*GTkf!WD?G5r z>2stW!|)58Al*k>k}D=Vx{%;Tw}2PUGOV(bhU*?2N?~RAtK7O|i5N)W&rpUPbI*HW zS%7V)2c;rba%S}XnMZv%9b1~^2qubGTD!rU8BKwd}<+A{WJK$R*)!o2LwU; zF_;|kK^?$BWHTbm?rAoGn$z9|`1ghcZYgj^esVM`^kolgzNudXBps>(C7@^zU>ik^ z;?lkI1w(dLT?Kq9|J+4RDA3Z-C(lMFyAoyB)KzCnwl*V zaL-pdfvTBTFvkd+nF{a-s-5p8^$Zbrl@&9hUixRdiHisapW)c{VEhnfBZFMU&B`67 zRoIs#tgC^Tl#H&ysx(buV1o4`z_HKMk&%mt`S%MG1^*ae&%p5^x;6F^(5(PnUzlr+ z&<=8}f=-8S(Kf$$UR}9s-o@t=NOmO4?4guv4SCN4-{PR<4`f9336IYS5 zUq|FuIeXMk(Maz>~+3UETSZT$iS1{LP7<;z->Ar%AzZP^$LhUEhw!{|2?79V_>1v6!J zvA4OR_vl|x66pYDN7KIbG~?q~w`RWk09*?MysL7}83L2n;=Q0kXQILdq4+fs+8~_w zRsbR)K>C!Fl&2vg-T^MrYOm1YH}`dWr{_EFkzY(G7t1z4QE4zXbke)b{g}tXloHa< ztK$f)CcuXK#37{~lkkkZJISHCBW%R5wxlI!#Ah-CPhxbQ7;PKQOnO?TAnc;LHLzL| zQ7)xS13*DOP6)tFF1;_R%)?jnRvC4A(*rmyn?_TH><9$ZMq_fYlFw|=Hsi(bV66?f zN5$}9F7U0*7^+7kW)&6081)E8J;XoUpaFyj^MsFK{uZ$da}tuD1~S7-VmU1G9^}7P<&SsaS9$t`kN_!$c01#8hL@Y7QaMg>Jl+)Re8TB)p!1bRzE_Ctp~d#QKiDEGea9{ukm0-#HIXdWV11F#HOrI}KAc?M#{Y_On_0o!{j zIhCp4@52!dnuqeKis7)PUfie#ni6ipjnWo(v$!T&p>u)yC9O28{NaV69VcrlNs&e? zh?FMzLH`pVAYP#3-ayyYI~HHeQO~c|@JWi@#=#)Rc4jGG8YL6CI!s|YE&q7fJ;!Oe z%QMaU_7Jcm*TX;++-o{Vn=V9>2V%<<5K-`{gso%!nt<5h3?2yNiB8)TCmx4OTN6@kfU}dd zmoCBnP$6>z=yg^cr>5*fzwPKaL)kD^5EHR<5kHUu#7g>!=g7J<8e?Bf*EI-tl)Dh5 zI}q`wjY?n}?lf`LzXW}ywp!jX{?3;DD(&#}7<^-W>?%|hnVKko5NS5dwV4RBKR(y9 zXdS}fzhfSvDZ~XUmQhOQswllB0Cf{I+?ra8Q8C~!Q9pO(SfWoJk-57Dux=@amVfzw zorwKk`sc<^Gzm3Y1E%OG?x2EyN#X^^Z5Q7xops|mv72tsPY03DJH_E>$+~(i)ggZ< zOB)wUhFSs$Q)%VM_V(ZO=WO(`q@}^YjYj~Ts(`N4;uU3GPAjxsw-iJ6m(czc8f$y<#eFb!F$BRUcPz%VH)q+~_c`Tk59 zBr@frgMIFFZ1w|xL%TiLh~>Io z(4~64s^j?*tXsH47$WS%be5^rvB0zx2sp*JlW5F5?5%P9i$%^fpI+A?kL=;I2HPO(gCR4P1v*+?E5}^(Cq0!Cn5Cu0v_R; zF!mf^iPc&GIjhfl$gYUJ#-wIUj9{^>nd&k)49+A!eNZ&ew-O>5>ufCpLRC^PD;A(z z>bR>X5l5l6EiKdE3?xZgP(jx;-0mRZpv~R756jSS7}I4w_}LM;Gf>fj&r+vFesUpG zv0>ynII&W{thn9unu~4a)&}`r^&eQ~r3rDBUwe)E<7Nd()r-tXiDyJKR8xCdyWmYY zkhoQ5GFwD}v)B-hdiZ~>2(!bc$U06FNfLw@Fr6?`WO#Cwb666%&ID?bd%W>MNCA|W z1S)E1VBghxS-cr)n3TcGKbpJ*kPY*L9V71dLP`7H6Su~(H%A*OX)C%%6sTH1ksn3G z#gSC*SLV{pZBMW!n}DSlp;KX`a58MnIGwBRS=1S5TN(qNx;3&AJ;I;|3bSlBT9cNE zG=rQjll)JsitXe%FdSS$44CRus16qB;;|Y10reB8;uJZ~w(W>2<7)pwLKspE6<%t* z66C}M)UgCKRk0uZM^m2Kdb8#>biPk>fr@SmhJ&U|U7D3nB8G=`i9G1CI&&pGZKw)l zs85uQHtGi`Y1Ba4-ANcoAc-<2=-R_SX>>^%?1lRHp_=mtOS~IKDOouY9BtQHgyezC zCj(3z(WZDXz}sDCOd!ea%$^wfIKM7(-U`a!Ro(NRnMs}FpD zrjpsv-O}P_XZSkB@YXT2M0~Zblbqz0*vM;F{$p}LWAZyWT2aDS;@D3bgn7&DSPUbk?-4_%%1yE}T95!|xZZx&YrZu0iExN^H*Lh|dZ*@PCc@U%=ucVH5f9LM( zn8^xQ^IT(tz0^pJ!kN>?Jy*SlJ*u4vh)UCHSd!vW0DV#_PsBPQLrL8BFQ`p3(Q!0; zk_dw~*$*|EwOs(gO9`=;Q&?rhpoPF_Uz%ccNTd$C1R(eW%u&>$u@l-~!N(oyC0PDC ze!#76zBRfooprd^=3sn%$3=U`BLrJ(7KxiuuYB=`Or=3G3X~qNx={?F=B;bR#mbro z|CvH8PRz+pv~V3tt8pTW9EgNWbqJQ6^~4vwYvC$42)0;!*$9EQffAP&hxlG+`s|Ry zdNv~G3hHWu1srzsx9=pPP2>F`68PnhgM>F(r1M@mNkO{$QJrvmsQzCkT_Q%@o<#4e z_zct}S_8&2TwrjpX+Ar8vu47ES0h^R0sXuN0dVK4Z%6>cT=9oZP0_C)heu}H=TUf- zUvR=Hth?*V6e4uvr;Da0Fp{7^A(o*rJMeE7KQ^IsT9l29F z_KR|s)u3gll(;*{FJcu4(>gs3rWA&_FrN^?-wM{uj~rO4)Z-?YgL3ibq%NK*^&bAi z245H4%RJk2s8vC5k`fAH36u9pH`}T5+$fN_94n1Y7C2!KyUa8w z#UBA&3LN#=Qng~B3eTzJ$GnKO@5hjwrCu-e0Ai);eldeYNhx&!RFIdFx#H{wqvfkm z9W5!KAv&m}kzZPsxhwFLK-d^BV&|L9xEF`QfAeJ#_%CI0RiKorB~^j7U;P|TfiaiG zJ!MYp68xPMet@cxXPFzXz-nb%{`FS;%mc%oMq&FUiBQ~fVa7Mg`qGS0^^Fc;Uz{|IX`GD$=vPC`W#t?fdPh6%6Q=397t`TteG6b%)T3yvZ*Tih zp^%->%J8T~J5FbD)Sy5VL@C8E+`b$Gp82H@J!toH8`3mF+!R1N>3q@Qe*-Qg9aSx* zqfk)~!5i*R`+7u_pg1E=>WjID#`0|cmMN)_&@*%MK<*wNN=h_yjeWA zF>BF=aznXOttMJ3kRp>Kp5$1K%b&?k0XxJ5AB**l6()>KSy|OX9@YsJb9$V|%rHFp(PB~=>X-poN1EYw#Zbu1kLbNzRmwRj$y%JNl&1-WRV?$M-> zpm<6UQ>c~UK0TG+!U74(utK(?2}o?R91s4<0qCG8XV&W0ZPN=5U*Nk2N4`Q!bb-7~ zS@o($!C8Zc*N-6S2tX>8Aq_X*_d#VgNMEI?#qe7g^-+Op10NTeU{p@)QTnSL~3l!`#l zTDYpop+GLGF>vFgGPo@xUh;w?8BOD;)Mo2`ky&`h(FiF4ah$igh=X+)S~U978u`QI z_<1p4OPdxUbQ4V6wx#Q@k>h@8_l0vv2t)sRe@#k=H_cDuPB%YlaCX6;xXmOGL%a<= z(jMXg;3R;P)e=sj-3|-}cm(`I&%Ctpdx{yA=#pnL0Qm}hFTm)jF4t=fNlR<1x`|;z zI(-|$4DJXs;|+kS*9!GCdq(pxI{ToYpI@1ZW)Cr(NYJ;-=mc~-GZ*2r*DAqEnCjR+ z?Y7f+sb!4J^bM(PA4+Ml=o}6?Vvnh6?LthE)#QlV8)+z$`^FR#v0iy4WXLD9f*e5o zuy|-onuIsr{`ab)gKm1W7iIi4#L;a;T`1}Fv-BLph3ZlAzc1?mR$S!oG~k4{blPYYm9>XpJJi&wp(4h+(w;A9 z(>6)6+CcIL=a6Oy>J*MCKihI0sLE%Dz;9ZxJBJw}R871{o$qljM@|=ItSx7pQe--= zW8Zd62EN{%irSa*-dg<0q7pX(V%nU8uOn+uL4aRr`PMQ3X2XtLX*2-Syilm<8*uT@ zk(fuT?uZU%p~ipQw{=x1fdh1-nh^f`bv5!^F)ARZ9Mc4 z;iGsqUgVqt5b;G6;nRTz47pj-{N{welDz=M2_(!rAA4`cZY}aNBH0L_kbAMc0!CasKcHD%XG_ui$fzALAHzt?ATO&{Nit4V(?#?`y7sfvFqB^ zQJs8=elpG&CJz7vOw|4d7q`<8mXN52FJYAfaDy*AX1#dQvdqJvt|${5u%VE80LZKW`ol2S; zuui>y(7O547w@vtswXT0jew%>Kc2%!c-wxp1M=bIPc`$wxF8cf51mpKvVDB-R)?Vx zx6u4wk*W{ggrYYj%RGq^)2xo~!Nsf@G25y(vx~|$ z+ZJqL(uE)vu%z^{QJ{y{LVzJFwZ*%YzY0#BB-JS7xSEIF-cz0?JQ`mJg&W?_nP@O2 z=@vEEitgq5%C;RlAS# zZZBO8YS)31T?GrTPe;jl?rM3=ga*jOm-_Hlx*m_#zN zuR)8AOI=+-8KxyMiBqtKX1dHj-7`?~N zPoYl=0@R@kC7-E*+|1xq~17r zW-gl91N0w0NTeElFx*~qk^;yrr6ksmVC6t`=xE-;6L6_4j z1AK+Ic|B?Z&RYW=!T~~h9mV)h2CiA0qeNVuOu}pAZG^l&b+Gpv3<6#7ftQ?d6$q+J zN>duO_xrK^Qq9swk zZ_R|t!Zgp7pfiRFQe_on1juJ}TiR_uEHYnXFFj|$zv*nTp=UL+u;U*fC8WJA9#4PCxx>87)tjl{*~#v1X2St(BJG*o@tR?y-|;M6emrKO05;^{BfF10TJ9a zv&Y~Z!5P|7_z^x#B5%^`7^&wHl{<1hI|A39ZqK*TVbJPB+&rk9#3x{adm=zfK}W33 z0|oUA<)yOv!XZTT!DJ1s@uCD6OI=hZHy?>rOnyjDCa`KmPy<-W=gLGO(GQHCN-an` ziw*+Y10sh&y4hl zdhfsuYC5x!!!z|U!2|?Tzf|2<2wQ5E z+3N&iB}kOoa})xV09akhQxtPMfZD9KS6P0KAg5!gzIQC;uMrgi)8+)Nj6u&m+YhQJ zXOfyU)pDmiaozbQ0NGXWOa(%uiXFJyber&TJng7g)oLJ%Pc_kcFeKgzLoi7NcNw~H zO@&tp*kDf|qmn3ml3i$|@rAKBgDQbl)iCdY``fKah(b~C09nY_Q2~k2C$Q22Mbxa} zU!6zxySw$wRY=PtS%@=$5cMXU)dyqj3vFIX_{S(42~F4GSoG#--XhcRv0G1@UT%*5 zEIAhz-5KCOGh-Y!e*h+PujjP`|rGGbuH}kC>dE(U(PKIY94vn&O(3o=>${ zc?9(YTB?|?4~Z8($+qYbb=zNpK|ZmnF2t3&$W~^In0i7Yu_Hn{n&_Va>X_L>UMMMO zbg0jXa`#TXAJjdRZu+giZ&8EO{-Y)UTmT=kY(HY zrCHao(3IVUZgJ4xYe^8D?9=wKQsqa1Dwib;UEOBct`V|~&_U8A3(8)TXk;V%B3U*~ zL|+E1k_Y!<3CII>++E)2M!yI5*mQMz#Fo}GNbl~}{i`V zB9Rm2d&(F%N22R&A8C@HXZB#Me6N0{6d*j)VCdI+|GLFloRmJ*2iCO#sJ5So+Rw8dJzBRD&-|Hq8P28$sTyev>J+#_S^z2^0r z=+>5o&XD+a=reY98C`Cn&{nl)2Vv>xct96HOeXSAc8WZLZW6#4!= zOT;mav^}Q^;(v6FIw9FB}l-z)DS>4c@S)T zTJ6;{SusjDaM2vZ4Bmhbt_RSea0Agevgxeh8%d!fM)4#ghM+`%{#i8mAgx4RMY~5pI1K!&IR}H^ zU=vUkjr+}0W_=^7u0}IdFy_b=&W>JJx2=xw#FDYrfYtH=dE22#-9*hS+UzlJlcCs9 z+2ZzR!n4-8vAkmWfcTFkTV|JW`ZP9RDcTx?C{yPTtN;Fg2^A}m z>^)%q)*1ZA4F6ZJ3ZjqLA|r-H?N(^a)BxQmRO^^vvy*77FB|s>eRyF0Gr>wl= z3-^KgJ9PD6q0!{DR7@s^GdRy+q3x3!A+1g<>H(|dg|-N~p`a3G8hmH=3G_;IT5*Wa zE!ZGP_?i1WZ$Ug8H#3@jh|REtRrAa zOsqZ3)~Ww$B(+EloQdQ`6Jq?oL{r;OFgkNl83@;9Vl&V3vgaguZVO_)V~Som)f5W& zqlLh2F@#k-0AB5$!?D>BhD&cynlfAhZgi>uq57P}Eb%?<=W7UNc7$Mn3Au}19U#-@ zCkE&a?l)$O33w3(>uOR9>4|zs@wibYHr1#2^?ha9l-UW7$qc3&07%ac&4WIoj8U)s zD9s27wG+k28Il@UG>w1tfxCt2{GI{1gTzRf(~#5h_*dtocv>+tFgyWsWv_T4q)y_6 zd%r=Z!vNF>At!+zci*RyOZ|(&o*b_EAPB;(2ZWgLt0_z_1)b*mX#TiSILJWFj51(> z2!xnv61R0@C^#)r2u2+?F4cWUjlx(Mft!7SYZ`V-7C%_(#oQ5Vhy99~)ghxtG z^ePfSud+SO^O)OLby0^=jB;Ki#qJd*hJ>22&VoR)RRnb1!~j(JrX!#cgAp#lZ}N)2 zVad?+thsmumZl0D6(&_dkXI>M^ZH>B#?wlL)7GLS2kn};*G48`6c9X65=cQy^eOlp zfXi?x1+B}&Ko^F3&O<(hKOf0hYJVMic*|c4wd%!4tv9Y;staF>HV3 zt!N!vsLm!jER45L;<$C|2$8&1TV7P-HYr8fBaOQZPxVvG$Q*Y=g7=aT%Nc4Q$TszL z7Ev4cKzF$+HI3Mw8WuJ8%ks;VRLj~I$X|CLGR|w@-)Snxqb7pYqgJ@$rMTktbQKU# zo)5$=Xt!%Xc&aDoQozJU;7_*-zAEH>dWuZ~!x-Puz}F|#41yD}mchno(W+l(#B8Yv zaObV?ZlV}P)kNEJV-u9y@~(oVaow$ONb<}5=r8Y`fopCguAN(gWmHT_YZ5s)IM2#e!vp5wyq4Hhi^QaJDF zj}Tm8rPRKRQEX7>1&-Q67u7By+1pFGiXg0HlyRP7C)xRD?J1xF^E3ePugv1CN8wM1 z7FFNw^L_t&&+KsQ+ubAy|`Er@xp^Q~P|qjXr{{O+Yxmfs9LW5lP%Yy)t;>X>cb2~m=pnC>ox zd!Ogyo)bYGV1Npsu6pfOTd`)?e@CA=V7t%wjk$EX9!)5iW%}B=)bG^`zw%KVzJ>A{Wc1COelt92)iVLc)w3{yvYEWAntc>wJ`x-%h}RSqOTmm=KBMwID(fWO6l3Ze_d6By zQs7Dg{ATu~7tZ2szCd++lN!8YxN2v~IPU(00GucvjHPH8w5psQH+~s?F0BIZZS`=l zkP*@V&nnTldBZq+nI2)7V=wC{kv?GnaO|t{Re}w6-@r=q;ts>R*s~!TS*=HV+MklN zV*t4WVU^FUoyGap)p=HwXO_5Ki0(dnPY(a`Dk*=r(qmWPBBo{jd7d~pc23p5W@@j z+XD^g1U#N5C=T&1gLk6T_GYftW$19$$6lrZHWZ5!;h#N4nfd>$=@GiRqdtEL_Q4T*YS=5MyArTf1?GPIMzRMe* zvQOO+2AsO4QnjsgMZjwZgol~2B?5rZZUi#^`-Ezcnl6yIraZ-uZu4D%OST6aBmP7?H>^_BLn ztIvhpw@0Q8o7)jFABavU+e|lTiZz+OJeWom8(>IK?^X?NW!_p)pJ5ok ztRCQsR14>YDZ;TIRQhR}3fS#q4u0@fN!*9Rfs0i&^@#boZw0KwT6l9xSVoSL{A}+J zL)y-5I1BzhDP+62mv??7d5lVlyd~6s=`?!=j+I{;2R$DQ=GQ* zgq3a&sk$5j9O7Hl5*$LOg)QTrl($$uq)P@+PGsgEJX@3J-FiYMMSMeS@*m-{Wp?!F z_ReeYSlPD5y9{fWA;1Uge@Rho5pU|t)2be@oe26HooN|BY72F}H5vKbmJK&;=5zr< z`Tx^a5DL!4!Qp3sra{>EuORTqxuS}~N$p!jtHwv;eh@GeQl0wuQUt`YSdu4J3$}#7 z?aIv1q(yVuZ8RNITs{H=4c^ZPvQ9;~K4Bz5$U;&mxcL7uys5a76CimXsWm@QbNC` zVdPGmF4JW9%)&jE$!uX9di@1q^qBp!o(V)(ZX2AS?Da&Jw;`94O6SgebWChJfFRYP z-!T?Jn7Y~L^-#&l0#X}kbFS99Ckf^m8FqSSEEtdnvF4r3`_9M|kYgH8NV@@f9 zZhQoaA<;EApBQvHfnFT>fKd31qKATyat2ZjA?)$C>c32Y#Sk>2Qc3x`iL{w%S__|T znu7OWeSD; z7urvokdv)CH$pAyMe0cN_HP|>3tK5U2bwzSxje91eyuWqn^c3XBM-rIp}kU9FeVi* zHOHdo$DotTZV~anPdC;gokY7%g$i+L0sx(^)UiPVCIgF)F31HuEQ!YjL0G_+M5*Xkmge+9$ zuWT5b&3Ep3B2b3O&m!8a@l`!wZucSkB(wn$_%$;I&aTkD`|iai&joG{{c9_o2xfq> zg1hokIool(iFAiQwUFCF2;jX6JvhPO-ajI^E&rXT5@W*AR&fhzo4t|<^}H~4%n&J- zNEvq;Q<0Qdv#s3nazI1$L|!7&wU1YIm4Z7B?JbgvmFa$8ZU1n#>GY%ti9%u)Z^P_g zNQipo^t%EPG&6}J)yw2WvUXkJ@?QkmBWOTefQ4vzVzki~@yx<2&o_c#G%4z6Zy-mY zm!;Hb7{!8}X`>)QUd0b*UNJnIK&D&MO> zxr@z9tq88f{6f+WDJH-;Wz?rIdMgz!t)eeTO%6m)NVixL6GE7JRh!zPUdgi3lO9rk zn>o3DGXcqXs>3Oc!uB9pys3{CclDgou$Ik@XGptFi$LsM7P`;~K4du1hcs%UM3K?> z71$sW4(}r-+y{Ab2mWBG5I-Vcs#u>j+Yd@<(0&Bauw`1z{93g3H?+#Da@DUFPo6|F z4Jh?DxBuZTLSCx_ckYsl+ki1~MS>Sh@t{~?&~d;X)xgtOPh31MdCyCUyXq5rucZk_ z5nXozZ|fxqWePe*L9kqM)f%ccxsVQh$eNi8aaL@W6>pGsKaH0N1QoX_AL9JuZvH2B`qvFq`w)-BiH0|deb&&GWF4|* zY+w>PK##&gpmt1w`1~qqr5>Mwy``vvdm#0CSXW&DSEsOe@ry>E!9sV#ek$Vj|SkO~l}u!$5j>60-F+ z2;X{0bLeWHo#gH&#tDkAIZaiBA|4h3T#6zOpydoAMxf{8T5q{j=||WP-UAR~jPqiB z5E)^2mWb7r%k`L0&?*53N>~Jv-E;s!&kfZ$vT38|CjY}A&Xl6{rV=_~9-wr&wob6h zfHp3;Jpy5KU36q>%xp$rv6!P^t&)38!wqCkqAFD+Y(_Xckk6IRpuVUvoQX`IAXTZB z%d!9+4L^Pg;OB~Wz0$^)5O~8rNc0lWlD_3FH9Ods5EhX}^@wxAC||cfw=*bZVv~U@{6oZ|D3yFf ziuvCa(`3RliW<+{utpQMK_>*m)JSd3nS_61(kjMAORtNZq<6i$V;BV(z<+Uv=k=q*$(GO6zRx)PlvvOpMla%@>quk~8^e<7&+Z{Ve7D8%BSW zNDD|^scin~^2pe0OM+*cGY$eTkusa~Go|PN>reb`hYLdZCg#vagsYWLazEpC(RJl8 zWhaUDl)DGXoG%n(@2qk$6_0C9B~PQj7eRcrqv%0stfqpm_iYCr~za zBr>N{PC%*v0001hzz4s;nX0O&Dgfl@>SWI(supie*2=|NYwtA<*627mI5=5z?!7zL z$Xsn&N0KB)RaJd5cyPX%PvHLM;$Y5wGY;m>!NFYZS{+?kd#tfWtsSXtO`Bm|j?|bm zrW6gLRbvqmQKKpV8dMblM1UZwh=?Mp005#^6#)?uRR9oCRRj?M1V8}*00aO40N_BP zuyJ$>=j}abTBsJnxM>KUwFJJmhj|GWyU36G~<=y%+hnz1yIg@Mu$z*tnfy3 zHOk^Vnvk(T=0akHY-Pxs@`gAm6XEa%lekVBOjW4Gt4kBh54-5#z4N2pHRh8ga$oDw z;q>Vw+Og&F!ZY>a13qL^)CR>OL|vYH`lTFg+IPu`23`<1@z1JFb>{ED6igeu>cUM%J@Q8g`apf9 z@SRDeW9)qV4(GbVOB2Qq+_K?pdOb}eBcCNYnqv^~_Qm=aoREmIQ;soRz}{pF)e{GzJI;+^N_Dk}^uKU@Z+NoJ(wp}yb-eqfUJ#tL8&1sBzBPu_L z$DVy6$g<~z92MXu9a5*;zt?yrIu$y6|3c=mP}cBu0N!7UUj|=&2tXN?bG8d_{gFCj z3t_K=?CV^}qn0;F%>|@^Jt02YD?wXfU$^kJ^mMvTB9h;bSW_j@jhg&&y1}_UQu?mQRc15p@yo=$<=tThIMhkxs0oq6_S zwX?TAuCFP#x11_@h^@!`fZslSBL>4w@)yysBI5J^J%HmK3gXmvbUisrfo=XRj0KZ+ z&2odEz3hJ}H@NtLnt0XA{V0Q|K^XiAJIw&SUYf0L*XsEwC{cOzE zBaB#Ork#{=`A)rC3971Z&*%yU$8ZKu)7fur(REfr!V5$JWV&?SAx}83JDFjWRs`lB zwORAsT3R&W^uQH$P`t3Jn4S-JT2*Sv1HQfbG$i7OLxlPIW;;+j1HdWz{W-5tjf!NQ z7q5mU+^)YWW>$X>uI)rJ!wh<7BZov}+zefz-I0Z{kZ#&N9S!IN%w!yA&^9CsLM?WM zREw+$yQ(_Z@!>B_*o^bW7~H+q>xyLz&GlQsAaMQtM0*tz~MaZ z>w|r$;0%wjdR7SOsNkgCw`F91Q>RC)g9h)wF0ow1LT$n}0IsPv;YCWFYv%lNt2ix% z(oTyiDyGs#P%XgAf`d7kskw;RL0Cqfbxawpnff&lU*Hm=)^+pa?M2)DY?kA!Lqcrg zla%FB_`9MPZeA{6$~5!`6%xRb2&Cx5Aav}80k2$IBzyT z9sjORECR&C+*_E?m;hP1gYdLolqACEGmfRrBJIW0k;ug^i?GcFcxZO})HX@vo;DcT zX{OT=7^rQ+FQya+-2B<8Dz#5iaCXs>gBA#)XF;bpAk2$BA6g@06Jm`v zS`H`e{9{<3-5K(mK$rK>XKm*dy5iZ~QcZf(sy1+I^Vq54W7+<$Vc9LFr3X2^JpyZk zXDihBG`+m%zW>}=-A?(`f`7Kth%f82l^$<7_nmA(=Z};umOHUn-=5{uThF~H%zriL zkmaCO(%j5dwcqRd>2`NgWU)-Sna_yd1L_#x142+;UKY)1&s`(fapDCBAwty4{bLHqvd1` zOn0(P>HAz)f11kt+@!&_gI-N1U;1K}0pWyf>EfKNQn_mPno55DloAXZCdmW+vq)R| z+qJ-BntySRX!95Fu_iLxAc+`uLkPj`u-EfOH5QMprDL+)uHVt>_qpbtJF`0x?0||B2)M` zIhE4bfcR%o+6TC)*0?srcuT%_7?^VJ!HtrKPJ)oE*eg+sR(E1i7w%BoPqt7cIWMMH z_R#$*=;M<3!|ums;z;C|4$CjNlxXxdPikWC(OIr+2;)>(aoq9EWd{NKnM1(Pae=jT z4E|IFDFL`Brhqx0js{=vmj+8{LGVD9og4at=@JJjbe#E0zTzj|hca!F=&RFX>rpr{ z+er0DsG1X}OXDt17V7~n{Yh`0 zq#_^`Hp`7EE?7yhJ}- zsDhqZt-+wQ_V(~#UD2i)zo22@WBi7Xg&?4NGXS`#5mb&jdO$4&8S^wFsQi7Qzm+c?~Yc zcyD9r^V>afP`eJ3;KbfR3`xlR@x$oLQ$7M9mk_KV%g>4zDp?BAJp&>fAGxHA313An zld$gbeDk|K{N7z8JVA=t(9)vq^*acogyEyEY3hk(S*?6LR0pmgYMgW9eDF-GN#UPa z2e>KmmrPkvdf2HY35dGVty#}my~x7m>_o!Z~tb7X^jX7-C0Z1e)TV zpAOG{@#eUS0^k*W0Mh?}|8evx{5N!8QefqddTSmd;kh$6g#2pwBWfg*l4eZrrea*% z^*|-hg^RlyNfXRZyY=cmr;{1doP?>}E-Om?el2C#%F*(-z1dUY2zvmOSnN$+Rc=-3 zspBy>zbI81u1(Jv5JIDD6}e~ThJKj{t&|Ake` z!3R>IV^f6UMf^QC(C{P`cGr^$uVoeehpzJnsUPxl*m3d~C?%k9H*AEK90Ul0jm<(i zChXnW=%vlP=XVIIQf3Z@-zQS5j}k|<5#AsVQ4Cj1eW$+ZDr368P}|O~Pn?t!C*rKa zv?#PiXsUts*opwiKk$fPqicBbRQmklbWob~uoCb{sqhF0#byDSn6-6_@PB#) zSzRY*P*}9eZV%eM&~JS3uf170NuF*zwG+N}ldD)Y30)6$iLah$b^{B>zUh9!S2B}9 zqT*Sm1SlICzZW-;R8sMb6x8(-d`c4~R%SwDs$rigG?5{q%FTTg#^hX6q5Kn!8`D5U#9>= z1UIF&?9xg#I*UD9W@g9LnBh+iJ9nA$6x3FR_fM8syTgcAOOA6HlOj$gYFF!MPK`X( z1SYv8(N~%ey04!USfaf~n*FuS7&`(L-(PO{l5c>xd{L4Mq(du$GUeZ0ye3Pd2V(m+ zoHO~TbOr_i%Azzwzv)W#k95_-B%?p6_f6DQU%&O~)-93fOLVf&J3_1Ecoqa^EBNJl zGwOxw*|;V@oZfxL-%!Gk6%+xQr~ zM3ywZ=+dD8y0ved{h)_sm-EzkGqM15t#)go0o!}~kAviy^Sq8OXg{SRnz=j~Ej}CI zEF@70sI-w#Cu^wn3>YJw#qU%A2~5}8CKrxk0MRiFtX1D_o9$akx)A!_10xIvg`N~= zgmZ*}Tecz-bDv2U>1d{sHne;YpqY7OZID2MQy|IaU^g%N(nuV}PBO_-3UqzC{NX1? zYNWaFRPJ6k%p&7C5Tw=Y>tXuOpbsGn()}QD64i%>Q6qwQ=9=3BJIx=X=V^hu+MNu7 z2uAdxb7+7Y`6b;FlNFhlg$47iNz?%iKXNMGaArw*Cdn=~U7jB~dFWX6i@&+bwVjzo zve5@`UsP-z{ufrv4OKtTr@v0tNk?3v1!w^PW4B-+sroqYNS+E`I5=zrb%lp!dnw4c zNlCtvP(U(&TroF>Zv3dN65Y1vMR=)V24)$(ysGYNPum_58h23>^AsGk29QuH$*bc* zXjb@J5=GVIn?PpC+uqfXkPBFIJoL{q9tKUwCp8JkZ^hQ9 z=$subLQd$~mwI3{T>+^Ih`=D71kQq+&#EEBOV?R}^H+MOIG9z~0f+E}z5>XKYP5mc z^^@uT4a43`r(^xVAyZ8R=VvtdoJu;0N)XlAS+cOqquI>-ai>yVBLtiXvKcM{q+458 zd_jgyp0C{gO0+|W>{q=03#sE2Tz9n{7aCFR9wpVbsdM0hOGb|c8=V%c#CuRvmBSI< z?lGaSK}Q3S2}M53aL9M|$oor-YfLb9$RQm{#_Tbj_!?0yHSt!Rf2U1@fEo!6J5@A+ zq%4x?5t1h9Pi){~6>1ahNIYv+Q19L?sWVu1VocJWL=n{5#%zhREd}$j`K4Wn zrI+*muZKD9n#~DGxZ1&^S}pd5bbl3mt7@KjuZoW;Zp;S1cUa|Eukq14ALu7c+nD_O zFYwxYTk}GSO||inRAH zF6F$Tvg4Fcgf(0=+*1N9v{?~106<%#WS$vZLZYrgw)?H3$c6|RH9k|ryFZe7{X?l> zuEAg|UBji)`z@gVv~tcSyxVjAEv|iOZw5^QQHv2eKC1zqF(hf;9%;41DfIRFv^Ch;=hHHaJ^kjk=hnbB18Uv^5O0(~ts|J4kA{rbM2a9hzQS1F#W$n(V@7J|YFYno zZeCK{jXD}5lw;j#__PQK>;ajB5KWockr9QUZPA6PID66ZG(Fp zdXGs}^^VV|tQNrwO*|;dkhK1EQ|O-6@ew^u0Gfp%oon-zDgHx6#vhnTzQ++$q~}K( za`kiZdP=aAAu=iPfqLX@lfuwSC;*{))5bx@WTSIZRDr@<&ro|-!Aw`7Hoz7Iu zI?lsTLO1gDlN@IVuc;+PI35iGe@xF46464GxAKK!$-nWK(!XO&b94 zAWL#yAOQ|n%*??O3!ykuD*BrBoaBU9&KWd`;lT;OCcZGVPb$&tU#n|zGy$$?Eaeb@ z@kQ}kp(ye}y_6oLZn>#h#bV)-)kjcz;s<%=@7DiWV7GK002v6-5g1PREz1Df`Y#~n zPZz+{^}R5*d@6jV3d>)$)3Cu7(;HED>FdOMCco`a^AqW@1^(7#t%K&xstk8VelQy;ftr9OfIM0E;{ue`Vuhd{1TACx<7 z0-ORzUCYfkOJRiOUTmLKm|dRLJ4-l{K<#bRn`o7e!Hy09{8O;qBSt7fQ~U&-Pdh}l z#i75CRyy+Wa)p;1A-1Z+>t=+6TGEHnBxc~1AM5n+GjkyVvRIm;(V|EdaK-~Hj@ zsVDC80w!UHlC{)4Tn!MX4tZbLc;q$~Buk;Js7WW4i$7#@?MMYdT}XQNwyYxqUk5s}U10sP<5y%3Us(2}HZ=i_QS(%tkfFY6Q8C^HSaq44@2 zfie}&qJO}1_xoKd=Y|Z&R9;WW5}Ll4KK;Cg=QizwcuG}=Za6nA+c=x0D5ATPer&@u z33tkntAO7lj8SY-IKmh6KEB8hw&G3D_t0z$hlW_fCrEmxB*ADWX88d|NLH++g31 z*vHNV8onSX_2kgRN2XFqD?Lf0*;?pUbU@T7IJO2=jK1yga$zJcrEFIi=!GQ`_8Sym ztFI3JG2O;_?1A=E`L@bKFF*PG3fU1D^!uw4U3CRh^y{ zLf-)FM(O*8cFnYYTc_qdyf2uqr-xvROzc zRYJ5$h9>da5=g?0_pe&hFsY~zZzzfhiBlpe929JLgPpbTaWTL0Mq&UKF~0|ljV=QA zWo;*1+(V!`fyTq|KBM=CK>o}97axS7Ge85pwIl{6!P6rhIiW)UPC&80ClVc+{m-&P zn#XnDQ7BI&M4FqSPygr@2XTeaRw&%v-J0PcL8}rEIVC}cc4pHHvrlm1xQVcJl>0^$vgD25d-=Uj8ktv~To=_HG@x1&DjU5z zu-|_IK_bXp=?M(|mXd8Iqti?V7Iv1f~L2aL|9q^(7a- zqDR&s5$rD*ZnLXjrivDqjQDS3NKBAAsUB+d6fhAU!sP3X1b0=(8vb-aY7K&( zU@WL-VPK^Zsm!OFCA_7+lU$8oksFw{LzN8-ve15U`wo@LX$i2TtC!CPg9MKVG^6=G zk2~|dTf^96u9oYFUEBhPdHi|V7s72L3+UleUZq?R^N8r8*cuoT5%~-CR3$jo{zcGy zb`TM4+97(-Yc>#-szYI(QpzU^V!bCKMW(%mTxQuZWAIJ&O2U#>1UQ>%^NuWn%FhmLi&#L5=7o;K(2-E`+Bo9{)=}I4-yk9t>DFJA(Qpq&{0<+ zUnJy-U4VQ&*x&s-E|Q}Rr0mrE?kp^hDzbd$yMH0O|AcOrN=^0wXtqhvPf<&g3LY_{ zbI?*xF1KAf(r8q$pCu4aQ#w(^<*!#jeOq0$1!I#sVdx|FJ`EpLsq_uKn)>`*b!)mw zA=O>8GoT7yXFxx^3+Z$Gs!Na3Q6Bze@ISxVpWDT2r(2F5w3?js`PsjcaHTn$LSp7r zgfWr??{^eSdRUNr#?$^0v+gnQ=f^0A=Wo-dR)r+NTQBAR&`{rGaBExXQ2hFf2%AI2 z=4=Tb`9I7{(Rchz=F=56X@v824d-C7EdUWr2ttE5n9+U|nRWgaM~7-t=CJ1gkf6m6 zf2QGLgluN>GEyG4&-l&Ux;_T)FWXiEUDz7i zD5ED>Ya}XBBIb-Gb!F0p2QRVyu_pKZaD;%r*c7oJA>YiMS|xSWnWSjxZYq^jdum<% zqF=z3>$OZ{$K|44dtPWtqb{jhA_XXV>2>JI6u(>t1}iuvgb`ygq0(sDX$NYD0eLqG zPmOhx=neKo5ruLJ)|9}Yl7GnuZxq()j)4?Z6x!;fjKH3G$cv5pT&%AW;?))9C)YGr z0_0Jq#l&WWoyBkum!Mw}K`#??S9F8#Q z3uPzyR6ueNK{W($g!cP?(H1#jR`~qm$+CNKoY0>=jWbdXkcLJ7bn)$n+E5pelAOXG z&^MNl0kj?)OpBNhr%7po=K#vEH~KQKIuJ*kQJvCdX#@evV=;_!pTJhh;~tdiQ65YV zX(Y;Il|UM=XpE&q8}9uA$@f(t(ARWcWJ@nx>;;Q$n*iP_)e`EPZcYo$dyM`H4Nc)65A-4lciP;&VuK};5Se{Wt&gPSh}#bG`^r}uFb8b^#lPFSo1|^?+)0Z#f&nt zCs!;RJbj1Y)zEN#o5wBX7ut3&W(CtU7ry4c<{daG<)Gs2K}wCXF~ygi(5T8ZE9OR- zsy3R9hgAP4GWnfunMpL{p4W7i#2aNx0D5|bIYxYxWAME4x?cPG7tyPMG%kt|>b)wsjG22?^_tM~Xl1HqzlR93AY8x`;NA zEStSkld4E^UN8XB!f<#dv^P0nZwMD~jgv~?kfJe77t5R&+(gI6G&H=}X$97UhpOw_ zf%kGFMc@^=8{zYd>I~`;oZ4$$|I}3BMbo;>!#%qIuZC8X_oK235=Nc&T1uCNkI8^; z3(l5Wx#!3vx%@`mfu&K{<@!>hH$T%uUNYiCiD5v~f(gWPP+>FtVMJwaXZRl4= zySDOz?v<@wrM(pON6Isns=v`Hw)8vh_RB~8za0hUqXg4E?JjUet8bd*x;XOJO z%e~jg{e>%z(H$nq9HVJ5IBY;~cm7I4-6X2tDKe7vRppT(0C5Lj8~Zu}iTckp#O6JS zz|VhNDQnOy-*Ex8zK`T_KG)~t=3wzYk;y>BnXOp^k_iBdO zG}1=mzvP%G`G;Ar8GmLmD#TBpZs=1@oxb6^rWd;M`YY&%{I)61RwX~dGPfVy*5ZiH zYtV6J1f>cND7aB1@JR4?i)yD~+z!Mx5v1vUJ>V-Ql$DE*&acCS)CNIi!421CDECF| zSHG>sv6gs>^VZGg70irU_33}x;e#8f!Kx`01xm6Mv>Fj2dGm2NK3Z`nLTHE9JRBt^ zWgAxMt=^Q2USbo`cC?W{qeS-ou;6hkeE|;l+RO?jj zHODM?Z6Cpxhb0#ijL+5`9o2Li6ItV!Y~IY=nb44ZK8p-`4O9jA|u~< zizhjgwcb?$gSM9JYTa&t+4pOBCD?D4ZV^!yUc#rW2d+2{j88HWDiWXdo9U zs)MU8pHl?9$s*JXWPv9cQM6(@(mJ4_ci@^q!OIq<70_Yf=erGI4xkRIQ+~g+7`RJO zd%i&YxY}o&4pLSNRCpCtBH;F|k~tTb#N{T_Cxm{z{vh;;&#MTnM}Y}z?L83cK{&PG z1D0Ja0--*pU!O(yp1YDQ3K~qh(t~|nX=HpR$f*2L)RgDZpb3J6CHkSrVsc(6ddZngNQYQ3oIZ8=Np&?~g*AxfRMbQLkOwm78-k8EzvH!r zjHBN{0Fq`8&Fw-7KR<=~D0E-uv@Zx1Rq`{#tI9ELokI0fCef`ldilSIUs=~w+1eIn zoBq?91N~-SWv*DpDC7iit5*C)!B4V#gu=*(^O7is2EBJLUNIs&bN0AOpu_F@nYui3 zsWN*lpMrC%wL2Zj)y4i7K%9}tz_LU#6ll$kA^ekiC&Pns$8Z>B3Q;<=4azY0?CUJ@f=Fb+Lldhj%JQ}>xGcHsY;tke73Ebg;iD|H+ z7~hyOQD5q1czFABu=M|tS?L&bp%v@V^b$*XlLCXy%JJz>q`4a1VaWs#N3`Zj zuFD=yX->io-tR8JL1gSE$nS0(Y^}6BUy!Px9>2Str}E?G8+km1Ma9DTzORS9x`L{c zWp!uYkx@T|`_SH}n`%J{W$U1jskW)V;$E*jH>B=cq|>Eck78llZdDX@3ISp|7+Y01 zixz!cjGE5B1LPH+5uYj83Z5I3t}dj857}q|u{Iy=iMy>lvUuxsV>+paoEINj~ ze7ky`ZGyz+^1$m=KUXf&Y9!$BUE}E-OV7aapf8 z;iMC#facEozDKL@?U3H>q;l_tB*m>Fa0<>NIdqh->R@0bAVKCwIQ~b$hWA{yc3lEu1Ym9y{u}D2ou9Hep+Vx8=%VXOP!9Qx} zEnie!l_6PWlzAn!<~a&F($}66*in-lgi|2goGA$g$IR`6-&(&dD>l^7as6M)4%&8# zWG9pwzNpV%C>zik|T=8 z0XybET6({|4&(*_i1hv4+w{lrET=NTdE=+>2O?S9x=@ zDfbMRt>u#1EhmGAx9c?)l5cK$;vN!`_Gn$BR-G!uzX@}g@;}?>*Z~9zvGhjLYJ+@l zd71lONn0^G zWi*&zdl9LK{w9}NHfzQ?`&O`u^0=W~9fv0hwOHr{s%6F-Sg)ukThQ%gYh2O?>Yb`? zZWJ&?d*?I%>idnq`tU7g;N!la{#L@Ky=hoGrg+3RMbqnot$k;sg@Yagu^2uy7Y3Gs z|7d)rxNLJaxPe_jNW>~T`y)qF?ulm+geaj8hn3={I!mZuh}koJ!;gZS>;9P3@DLO6 zDVTLN&cVm&FunVZDicYR@POq3)EiTs#a&DsTyk$ka61%Ow2c5y|H-YN=_x2j=o<%B zpCRzXqvyvD`yrDQ|LsW_u;Hg{8aV$bp^mxk4^?^A6iE3?mbtP6EU+2M7&7KRZfb^x z+M_Udz=L@!K7~-bIRI{r&Zjll55%{JxZ}_l5wcJ}*6fKL;oNYDll1@vZ*wsHcD$mr z@MsV8{d%D8pAcD}rmLXXJ@*AZjac)?(a7XzTGO9)9t&YcyXN5}qgoW2n2P^cLK5pP-kkgN^_bG7usZ)loRE6^mF0bQ#h?AeD# zlFE)ua2N`>zgr~J@n56QllpD>!%hMit2$R_WAIJ2rsAWQoIC&19VQ6BqS_NnCyRHi zr+JLnmMpv0o9j5y8ex#PC1TT)@DXWC{9xm~IJWv{0YR6-@4aTlh~i1Tcoz+R9-z{ROJG zGSK(X@T|(2InFOq9*gGqC}<9ll7y^-(^X^|qAADfo}j)x9XBUwWILx^Axj;q5iUAQ zFpinDZF)s<%3LE$T{4FmnmV_pR7Q3S+wB^-w=6{U-3Q=PS~^n0l*1+!0cs%*J_g$64(7VmlagI@eGCcuZ#SqaLL(!_%b{sMYh96LQDV) z;y`O~v~|JvH})qy?rr`|Kj7@PtRZ=|;Epi#2{BC&Ktk$ZV9z(~DSVaWzQ$fve06aV zY~5{2sZwPn^V%0y%cBc|>#DHaVgB4bvB7s2x&8pYp7(vJ8lR)mbRLbrXu*wo>ayyxGlF9}WlVgwn zB2~16=EG+)OY>6z*)0KK>N@Cg)8vql`Q1YTF4m+%z*$Y(tky&ZRnhk}NXu%@oPJ&_ z5G8$zE{JZS(o6gVI`X%b%k;^J>7rgbhKx({Q=~rw>8T0&C1O6(^4Ah*`V^?hxZW;IW%!xs!L#TQ0-4kqJSEDK*o8Vj^;5$3zFVs3is8k4Bc-8Ah}ZW zxR+iPp%w_oj7!bu(0gtAW6}HrPSC>3G=FUkKaG4=v~U7<(GM<*sS?eHCtnud`exxQ zs0T{&4y*4JkPUWd1RqYHK7IT z`r_zz*E4AXYADwsJPOuMMGTrsu{xJedFf&?LI_A{pI$FjJXZF3nO(qs0ZzjMf$+HJ zQ^^NheFPxOfrkIIZ}bTRT22@yBKSD7_Mk=X5P1LjJ}uy%HJo-|s{{~j?Yl%1)^wpk zh$G@LW4cC6CR1pgBs8oj!kn*@4l)(SrNOXJ#qIs30m)gD0jKhLA|zS`AI`$OEd_mP zBXn3Z++vaXA?ol7< z7Bp*kx=W83!;wUrKpDB1r@~S8&n7p*k08(!7Q$N@e-8n~k&qTwdK5wxQwBwz@xbMt zWdNn^Avav;j8}#iuffriTF~DWc`H$m6Y&k%T4yF}bEa=LfS-eJ>4q+;)4-31Qemco z4M3>*&I}GCJjY2a21=6a{NNpQQtnc$kw#Enokp?W-I#pIJ`Q7u zHbw8Vu`<%du1KCO8go=JU!hr)v`J4OLTMuKs!!=vI;H9D4Vvr}{D&fP;9RgCC|T(~ z$h(;!0!u_K_2_}097jJ*^4ThxYZ77G!&PgY)sjg|xM)Zp(3_^2Se?yKOdN(`Bxjx! zm~Ywp-C9~b3qg$ZeCBjeBc%K&{BV(;5~QDmaYC1(#Z+ni8V%q9w|1NU)+!pc^*#d> zZ_mUxl66Q~!cV%pek??o-|J+=>`ZW#ohmaZU4gatKlx=U*UfRi4LSCW2=ZN#TWvY# zn%kc~6$V*4k{iLHe2L}hu6n&j-9~k10O~+SHExfRd*rQ`sy7MAv#X_haDOmvQS$c@ z<_tE!d@a#O#-OC_nrut*^$O>QC(WM>ua9iX9_Z0XQngieDtGrvtT%jId08kOcI36v z1tcl3Y!wG*CLJNtNIR}g-Q8l;gkbfOA5m(OE$# zpiF%rrLGTwEzgD~>OJ_HI)QDLQOx;3exo6b_$WGpkiEMp*oXd#G8VmsGycp2p18cV z>QRH2JX9?%Mk*LRmlf_}1KREk--7Pj1j0(+WJ`;?sdtV;-^qR%99VdQ~Eew74w8$y>yTS2L;VJTKNkw^qsrR2## z>(_*s5?@4e-qRQmGSdlkk4VFZ@Sl7Co^zB)f{AuotHD+XbOlc=YK7^JHI^O;j0aSD zbNGsZywPI2j)|}R^R~|9D6ww0957+8&o4cXnMk7ktnlc@241!V_tszGP(t$E2#LVu z1~+obb4!Zdm^IOc{gfa0dk?8Raw@VHDfFu3$7RW;dYPdjq&P+UP}Lf;p_wF)Fz4@& z3ZV&y$vaE^w`P)kCv`u6`FYx|YCB|uVW)}ng;8;=zLFW2kiU`!tSn zSQM2_rN#F5Brk-IR6P_1zd{K-FW3#M5(}#F%*%tcNPOT`1{h9!x zSS=6%ulDOoMDZ~*ndKi&`(<=~Q$6q6@0b*r?8#tN8)DdHI^z|N6WNE8mtcrlo}|Rb z{KgcrB8ovQ5`Ssf7b}-b%ikdJ?-;7s(Ywy;LF?F0;6c1^C>{1DR)#@{+0a{Hp1L8| zkPgr%#XP)w!nznVR7q;wp<`E0I+?lO#5ZBGiQ&lsgz99MKrfqWN-{>@(7q%hkuV+3 zyp1~jy~5o(&n$MCpSmCfzN!5G*W0H@)3%bAr4o#K8d`?OG(mu4uc)RH-g#yjAhb&7F3LNdwf9U3kWru_jHg60>V_&AEyJRMpAcNOp# z`NduhMlCFX4q%IT6tsXj+&Bmz6qJo}$~W)<$cxt_rF#qDY<@<~wZaz+jgpd+zcoyG zsO`Ll>|_PL$a>D;Mt^_JHG?rMQ~mPJXAU_wNI3^iEA3aVW46>G2Fpa}NS7y4A8?x# ztOWc?caf(y_wugC1t{<&90#YNe@X-0iO@5Y!z=O7qpv)?7!-f68ubnWVsvTi#h^9N zbO^2ztm0N%Lx$yB)GELVS2pD`J_pD4+j$(m?F$nj2dGC1b9^%BympOF#k^fy>XF)si}TcFzz^}qeF-4ijh|lqcWZj#<|x+)&BdA9GdC27PJbwkm$ku; zVc`Z-aOJ8F?%b#xZk!MX9by~uM0Sl>LtQj#c@qfVbif||*ZbAGVa2WXS!f2ji<(D$ z?84Tez5>lLK`Xz{qZZ)V-j%D|q}2GeviZTdSU2sAf@wbCAE)%!S&w zti%KmL?E#mgv9RkhFJxIe75%j_dHuf_E_-dlg=L%><2uKFcsqER9`gV9sZ#$Uxs`; z{&fcQ9i?bOoP8RS=}u8iD8I8Uza?FEHbO}#dIt$0Be~#7&sD?Bs^ZA2=M-#o#3D6y zP}VT!_)^1TBL_$q|F5Ge=&?!U_GW3FlTVoun=ngW%T=&R=rAZ@BD-oJS=>QkY z193Y^aV!1DourgAa>iu{DKX0x-`~IU%@TJXd_B^bVZHfdX_%W^&Tl;vNS<1}~3;wD%ab@)uK$_hu9xq=B?b5fov|AiAw3KHa( z74LnWLQLHB8TqU-cEMu*F*~`(2gEz27&QHl7b!P@_st)mxUmSVkcr|e2s(HbteC8l z+XB@4SSr%e-drah5IP&7YRJ&EP-5k=`r$+5ETpv~2=sJ7e`xR#1n~r3kQ4#jn68e> z;Usxzi8p?Q!>AWGp#1jf)a?wGsiv3VVmXgO-Gp!jDhV;mda%TqyS0i@HVSu9DOb5f zZ}zP$eXAb|QdDllBZ~$WBLZzHtm%6|2Zjh`INhE42de`ORQZKx1+2iIt1jI|f{vT- zA;mxXeuOW&mPg!o0ojO6%fyuz-FKv&pXb8P+hgEo?XW<7Q|@Y>gb&n9bp%xU0F(iq z@pZ|iOj8PxX$wA9O>k4n8?~Ia=;T#`lfAMJq2FA6xxhABnEnNkpGnZ?g%V#LVOuW* zLx}rHg2qo+c=(wle^1v(Y|9g6$M)>4l}n~PI;zQXf{ zNGiV`Lf26r{6&s~(b!cObd@&i6j)774*wuGmsPC5ke@{uRv}kk2FdcZp(t~Wh)?4_1x{ssK zhmQ|Pg9|M)fk866peuyv?W!*M$c5OMxm)myYs>v>pUi#mVw{?|r`F0>ZB+U*`1V0FfUDEUpj}-#VuT>C6@}{z(B+cSC?%WM-uN-_$G!hjm zzLF>dyL*?6tn4vHqU=$rgsGe73(r=)H}iMkFy^T5h3P5$dp-BjuZ=OabIvBfgTOnrNGfNww| zqb#hL?r)7umlqnX5m?``+-R9*S_1hnc1oBNANu3sOVa(}V0yV{#;0sWgfOW%^KP4G zn={eV)&la5s&~?uh|jg6C9g#`4B-T35dcO(8Nn~KbUJK&3V=dA)NA8}dm|B?i;yii zI@Zm96?q9tjEx#{85Mmgr7^fnu(SILKH(v%y=eG+mp@@7ndmwO6!0Xn22hqf!;>n8 zZY6>|6_pg)iJyE@gccH7yUf?2yg0>}8eyF`+e+L+mk7l87&(X(!_BN!sHlIrUd9e{ z<)@0ZB=^M?RegRFK>SGnxNLi-Z+8ItiH6dKX(X2!)@gPb{id=;F{R1f^FPg~I|6+} zJc@m>9?HQ!w8i%#lakVU`$Fnm$*g?{NUu`Y-D?ZJ73Jhnc>Taez1TWH$n(?NSQl^8 zJdQhlq0EXCbM6>bNy6ShUPgXt>ZM0zp|~W-&9r`h@LZGp-R~FYYU30r>3GCo?9>12 ze!%T**C{9>e%HVB^K0BWFwk%~EGkKFds5qJ6afC#Xc9F|qXop`=ZNjbugocHT`hqe z1JLlrjNVoAw$S{p#B(=oVkzv({VME+M|j~cKv#DJ(fvHQIgoeMOV2K&1jtHDt%h(; zbJB)y=$kPIOuVKpdye&SADd+@SS|DgeT|S5j;q&q&n(YJ54K!oS{ck_TTwK*vXL_7 zIH@<87|2r*mjzII0U8vfbZ%ZS0dXWU59{D|(11qsLs3pLxSH?kfo=2Y#O>!a`*;!- z*w`ee(8i?vL4S2if(R$E6v0L5i|pRu_*WSQpI}PO%|+*PsM)^!at3>*nwNU-EM_=- z=7L%a1FLLKM35I5NO^*|n3Mb^Uvj00FzXf`5u3HeG;)G*E=l~I&*aNz|8GTxbEX(~ z{~wHil+{h_Fn59hfilzetOsoX-(e-7SCF8+@tUJ$bbq$n*ufjvt5o0B4Q=Z9q~Wro z_M$KKi-7px$!D%Z_uou;Q=LI2%dbVmT5|`0ma-P^dW&P>;nak$^&I7g9^ydp z!+p5IFX;cc?(_>>Q~|yr0KW@%3Tc0q3hkBbU1l{Aw-ZiGS3Y}rH|E5AdnnWX>=}WWb6%8$ds{zG0uOoZJULZ9=Jq`b7 zeBhlBdGbjB>X{JJl>`tGXLF~z&lVnQNLa7b9p99yRq4hz9d9Pc#xKP&OUp{EawN{9 zvkSN{`wYP#e#3*$UELV;M}R3MKlmW{GYq89akxcrz@axH(VCVjX_%SB4_n@eTH?Tq z`qA5Iaae%@pFY&Y$QB4DnM+8x1$|iwglF`3`+&IsUnZ9~v0hQR;u%n7QvpL0jG<$s zh%V5091SS_$uFl1+@;bJuv4kpd^C(*_AXjUH8nwhF@P}@-{>1mgACHEhGJ8;?F_G_ z=aD^i0OZ;f0n>^QHsOFZd2BBClySnaM^pfV4T?FIZOVv-O*P9OyP zv(p1hCMYk?7oJlLix+1j)Ijs{>H0DnnO}X}T;*){2?iNKzy|4YHvH2~BGJ*zUK-)< zM@|ShMYt~%)W^rf0{RtS3pjOO1Q4dm%AaD5DD(5qi=4%>70bpH)pM!3wQ#B}c{tSc zXjmEUPg-!YpZQtHV}GZqf4S4pDdJ$A)XKhE+L_}h;G*c1rDyEju+;I*Az)(dSN^tp zu1WxK-wj}KOV7)7b&t}D7zE$Vd5Oe}ZMZdoa~{|^LFQ>PZKYzx)#mbnGY|(jSzYJr zuU$-zbcFO5BS`9bQ*I69!lW9|5oDBL**kB0-%JDXK~$CCa`Q(o3Xjhrc^TmvA!%KKtEkYk^T*QaY9A%l#F6T0hC>`di^hCGZZJ-(iB z;3^ysU4pXwyBjcFM&a?$t^W(`D9vt*=K#C%g#cA9-> z5cuUFwS`r{ggAynu$8TpEX5JBtVxF)u$EdnN&NgN52`%iRt}uj*>L&gbh|}am|%Ux z@g8{%F5g)^aUFEf2!zAql04$gPS1BPorkWe1g(#XuHJ z+~hTe^M4G-bh7-$7TSf^FV}zBt{$Zcs0F4O2cYl=_(ebuik#Mz50nJx9wCt=a}^W@ z7`!H65F4It?>iUiBz-r-I$TeORV*P@<@P^MDGG6KI>@jgL*S);D$;r?j+JGm(1UGh z(2NO0YX$wjYTJ`ab;SmA{^aE)S8f1u?6{~<=3zIBv(tcb6|ELbKj@N~v|`iNIY}N^ zW)uN^bbP$#;2qSVPaXm?My-7n*skYI2r(Eotdj(rl$xfwc-uxnOvi2MG9^5sE5Bi> zpNWTsCqaBleg3CVCoG{kTE?r2sDG>nc?ouUsZ@Duai(r=IYk7V#&5VOzs)sO@zzVQ z&t4Z!KvCgoJq~rX%P*8O)(~`ycp6I-5}tbtH#V1Zj+R z_QDBU!|x+huC;bT+~H{-XyxK4lNN{Kkt-{IXVK%=^eb=3)s}+&tN@pZZkZvXd9+1L zjtnAZjSElYY!NKNU?%$+RS2H^tp{A&PQ~MmZbKHETGMFB8qaM#l)VgX?F^eNt+H64 zeP9>Vq0e*e_V(HrFEyT>__pk@$`5GUdb#rmc4cjQ;k0vD3jkEAfb^3t%8ZM3aOt)2 zi8M4dH!o(XsIO{RSYtp}#u1kDN`M<45N~IE{K!UHQZ2#u{rVT|^I14{Lv_iz7?|FaX_8{6=O>}nRnoG)M2{2Lk*{AItql>^ zKbX>=k5$Dgv4|J3oNjm%(Se+Q@XE!Uv=P%bl68@tZ3Gj-=XdkB=^nImQNioLp`22?t~qxVbeEL54b@jr7usK ze}H^@vyS|#a@SMvE0MhXy{ydBLLMCB0> zf|If&wXs`v2{a!^F1ei5qkMB%RJkJ%vq_OD*0)rlj=a00Bb`4k^Xv#gq_u0Z3@%~7 z8lO>CYWE#e1r;IBYDn&BH|PP`U~fFcYg9&nqeuE)&QZzu{1V#_V3n9=jQ2)vN|A zaobIv2m-d@OrhTfu}O1IaE zAL*&@G*G4*x#c&skLA@ZY!&{|mArHm*H5$#HZi|PWe^N!p6wwiP$|=I0$C!9d>AsX z1bt8NLgc{jqD^CiB=JmM>3=B&9G|E3&~RC&S9m>5_H^rbE*-_{ODi51IM zG`x*sk1{s{*aNO*=n3eve!xJd(%Rma_(K?NVV(xBjgXUN*IAU@8E{MgfzpFH-(~YN zrq-tSxmUS>{xI+xc;zv*lM3#-Xw&&rv?tkSrk&_j^vsA36v&)$vrGNLC(xV!8D+#% z{%TT+ZlZ~6H{|0Qdu~7n!Ortjz%BBjzkyXICl=4sOS%(~UJnxuNffX4j-&|fed+64 zn92Rc;^M-w8-BPUvAW=?G*=ccFQ6o|t4De+Ik#X=s$#Ek=`+hTUu_%4k%krfLRhI$Aq<3$bOCEc#V;H zyBKBhGy3{NX^w2qQVo{ZZJ>i0kR_R+QI$S}+QE_He@hD%M7MSQTTnF}u?20*Ts3%l!ExOMRjo z0abgdV`+UzAZuZK^2)PJag|b8oUS&_4e1PlZMR@{fmce#U}LZj=mho{od1xzE_iGb zZe5nX^#W#xU-bRQnQ~Rs4KMEul48B$GEbSY)1L)gWS^TwmwO)vDoSkZyu-W`Y>F{<=$I)k~t)^ za+AoWBq|Hbex2A&c7=r^+jbV=boWL6Xuc6&GI$Yz>K$z#sC9nSdPB0MJbPSVjjC&+ ze_5H)g-1#k1a8?iSBIKGoHux~neoceS31}15^t@9^G-l6Qv$T5t|4_uC)w0B@M<%) zVH#p~crxtx0RZd}pq>B-Cm^a6az+R_PhhS90000~PzSHTovNxTiU8#3>SWI(szy&W zYxQETd9dd=n4@bS99+z~=A3Je(XpDQHc6sUqbB-d@XLHBzrYi4bg<{e!NtCqS2s6n ztvy%QnAv-+x#p@(9Nk$XBW-o1){(@KjHpJDs2W8TRaI3)M59JkQB@QbRS^YI1r$M5 zqknad08UYe(bB**`S*XSjJ+-^bc=rs$%c+ z$%&eH3eX;aio{rAxq^^vI5)!|Ai@%>BHn$Jd)SS70N&3}3zo z#x`;;^6hwMZJFp!fQ7MEms~p@?EqrHxvWt$ina0|OWV{RX#_P;p8jL!2HX*`CuCP3 zkKfr}51u_=q!qA;tmbFQ`XYB^jG_XQ5v`LwhtWzmY|qP(*N&HSO6{?3W{-6}KYM5F z&3V6oscaf=ab59zPVjg6R~NDa6MJj+(KB@Hi9UX?o#g~1EfV_b-5r7y3x0rA4@W^R+OcG~QJ25k)P@} zU0?;{byJtkgl0C1p(k24@9}G~qm>OVo6EfI+P(d384soFsceh!-mb}QC+vOf5^LS% zd{3xfV6W+Wg1m7J!nLqr0OAmhJj(8PEGu?%aq6ao}G{X=G%&%<@W;@ zi}t#|gv!A7k39-`=fhT76L^J3#8cmy&54tZ<6dM0=^r>kY>~GiT}_LDUOuLZV)q$t z7gYbdCnwO|iKh!K)Y_3Gbf%MB`(38O(Zw3iMsI>snlTK0JR-P;eHd5-t}FC2DX%|_ zMFtol0ur07Hh4ZU{~!GG0vD70DzM#{ZUROUR^Ec*z(IA!beI7Kfh@{90_)3Uo! zx^n;BODkl?JXUf&b-Wzs-RP#L+-*y@Yh7KFAV&A2C;9gKd1rZCuVRf*el02YYX;aS zV5@B(AoW}2dAz_^1>w`3(r`=@ekRCC3I1yp_cJEXRl8M%V`EiJ#V~wD{)TLcLgq%| z+P+LTeTQVq43PP^z45f=g#H5=L4xKKyVTbrzg!MfVJl}vN_)YEAznLfA(pWu38M;8 zb`ai4Yy2!=r2^AU$P{M{e{+fAob+TSJld|)(l?%MzGvb0dlsJGbK&|{p5k@5U4`>I*%%Xl?73{H{L zFGhD)@wFoF&*wgbvtnDfEY0oYP}ilj_I!CLF$)xO2V(lKG!81BRPtPa!Y$p@YFtuP z{VG^X*WJ+iZ$_SB;ks-T8^N2a&j|NV(4GD#A_7eSm@fAe@S2<<)rbF)>gtq?C6e)= zO!(879qmETVdu-`K3YDy42pb(OpPpi-7&pQkPcuT#a;rNMO)@)1NMdw^g>MY_ZTG+ z?Lk0OGw_0{5jWZD8?XOT;M3tY1iCERtoU(MdsjJ-3)4eF5;;eWzp7?K*TCUU4dIIN z<0k5%58~ArDwZQZEs+|HNY{>5(DY|ASj*RZjRB%KDzDzh2Nkq9(kT}_Uc2a- zkw%2}E5z{^L5m)hiM&7drk{4V1?uG0)g`OxUCNuS2YIS8f~BZfYH>+4vaLB<7c`wJ zfh#xYQuZw@)es@%L}~rgVF{NNLJDnK_mWb&nud!z$Be(9!>avM1cG)4r9*VtP464W zbs+v~A1;hbklN}FGzQk~-8o5;7{FhN`AIZcd#9LEBilkBiUhwY9 zpb4{76p_yL*F#&?0aaVqbpp)V4pLtw47;HEEp57|*=qbclup}dxS5Jo{?}{2l_HBv zreQtL`mLp;NMdqB0aUN{J{8hRetQ5vK)}CoPE2ho3cD12@Iigv4$;T8&1Gp1P{Y54 z%$?z~3Nlt+nh2YDqX{siPzzxz07e}c>ux@G@ z|FY4pj=KqAw^r<2f6=ef<^;$+!eE|ox8{GmY(}nKv|#`(n3zmTd+BUmD>rH@$U?r? zy~WUqQcNA0qeA2wDBo4J%6DfNm5dL{uO&r)K)^C-eZo6>VZftbx6JM79UHT*S5LU@zKLOT6^Rkm0 z5iI=QT0-f{$I?bd)xQq}wW>>q?b*P7grF@eWf$Uf$%O_fZ8xWAmsy`BglN##QP^$L zy%|f`M=oSV{ToE|iof4Oq77JAM^9~zj!|NYqIWUUKQdeV_7X7ev&rzkYBa&ds*ri<{Ec}JlI$Kk8O{tA7XbPFtFSQT+YBB9;{?=pRk`mW9KM3a zIm_ycbD-PO@SuSnM;o%5svTO(G$dy%{iGmGdm5`~2k>wy$>4pf?%!86KaR#pGadM> z;NzMg0*-2Ef=S@;_6t4uwEn%y8w8AjR)r;uAH+0 ztnJXiE3GxKXZhPuGfe{i@UIzLGp7&SD3TdRWsNc)`SaE@%oDMZI#J}=>+U#5C5aFs zoZBpfzh+?~o_gjlr0 zp59mPve(d5A^SfzSwjOLU0o|d#)BO;tp(uHOqX;Ye$B`%*|*ZfgNIED|4+{;%`(69 zFOF7Z|5EWy7ewQGn_!QH048(M$g5fwXZriL?mAz1LiSxe=rV|CQt}Yi2!F=tL1i;d z@LU;8=uRC`EiACcW@gx*onPjA+;`P}=}IIpj!>(y%Zh&YiGa^*dH)CH(Amx!{$=ev z60f@$-NS`>B`UFOgE294MBKYU1CA(u{yu--$GnTi z(v_iaVorrN06t#egTXYAgjUfllx#>W5y26DUfxXr03}4dOS)Nx#s9f#-EU-Acp2 zXjVkeHh14Nu^$2mW_cr8=A5}QC4$RHG(DcUF~oz2L!E?h&f8##c|`7>U2v_rrP1tN zv_f-IC!8~Um#i)0_45M&0000000003z}Rb_WIXUwC=1Kqc)a$TOS+_UyNynB1~Tb| zuLxB=w_gd0*HH2f!l2uFCXOD>+(_&vr2?j+m{MfJ>Aik6(c1Hz_r@`2?viXbI&r>j zIuD}}LK6@ET!ErcKi~bZf3)xr5zS_>)s7v%pS-Tc``(c1i|JPNH=A__oUJXx10#?-1UNvp+Ii|q||e@ zz!v3WH*KoL?^_>>KCyLN_`M!A0@o^$nXVgf;0{0BHJgsSKySBANs(#)xfj3WQtr%E zV!f2873+=fQapBc7eRapeZ#cv)D^<635;%x5c+FQAblie-eX4nXI22YR-iO}1JU&e zxv0zTn`qG97j4m=+rPJ;g3|Z)FfcxSM}hVEerma(mw~eYbX00+vcG^0ZyX$?jkPdG z4<15l5zeVfg0V17K-%$)OT1z`JrGBA(kcy{!{ha;q~n8XsYZYG!A?KsDs#F{bRC`W zl!Kir^r+_?@uhTi3pHYPUO@-EE)~OVo3^Lq5jE_rf$%{$(em1g%m9Q!fU}f#c3YMU zqeXYbQcA*vuoMKb;Z$KcNMGkN3H^mt-h?8>8;=4s3TU~-S6Z4zL;tBFm>#>$nT+FR z!Zm8fzDZ@O&9Qfu;KwmbDgd5g+`4&JoGdGj}&HESB^}zWRiY*^jG`^0&1AXu*O0fTUbO(>big)DEwt`!3c)! z?w%0=$WI5UoU2#hj{*^Sk!kL1VJ7uFR#v=Bq_E-!0l4*&FYD~(N^mO+RD#}-P?S=8 zGYjsE;4=JwN1cH?LZiCq3IqrPuPX}bElZdfO!(drKLJpaxz*2=7sIAr+&8}OxTyw) ztzA?3483QrANGKh4lLcPI=xWFE!mAUmxzBvK%(-$eOPS@V*D+l-T}}>m8_*xf_+mo~<(3o?l_jrQ>mCs495nr4vY-vo6{RCs6za-7P6qr2M(q9l%s zLd;sLGqzC%BO^=qLDRlu-ec$Kc$DTfjd_(nZDuH623tn`ydqpt2gG`2zg}45d1FGv% zxWfrgU?A<7c}D^YVLEuhG^&rvyUn~06)fJEXGb0eO!$kn2f;yEC_E+{BaYE%z<2Y) ze2nPc&F1V_{?mRiErDLxQzasJP9P-quT5U5yjpHEO%fI|uLg%d!E%%hAOXR~WeT8O zm1J}sWm@WnUQ&D#%kNPN>a$r z_>2~ioWP5GpjsV4eZr#j+KT`-FM9{+) z`ni<|P&}R;mmA&aIhO&T{PoL>7V{10PmNug8&UuR+r+?yv-zwZoeLA;-QyaO@(*VT zfx1+@feT{9TJq~#$b7ivd)j*YkxxG$_ayL1S-F%k6{`K6=wm6%m|R_v4yWYxrdVm_ zZ*sD*n{5e^G+06wT~UhmM2awU0zoe$`wSNH=AOtjK&V*3@2O~r{0@{iT0P)de>k^ zGDCBLo%&asjXIbE7KJFi6Jd>_d(^$%)p+zOmvB!sWsR};?FP#7ceQ}!Xfu~O zm+)`KoKxQ5OpI;cm(DgaAQ~eS#hLKRiZ7Z+5mR`^7^ta#x)V(@r0u??NxUE}TwZYp_3p z?2x;MywM4DW_*J{PKAw&C^vu!&{i0n3p&FbrUIa!QCxby z8$~*B?IosNSVty*KI^1rQVnd~^L8kv1`*f4Y%qDT+M6S!|DczPNd{i_9BS4B!coDn z+@VOqySe;W9cmM(0fS_~iF(fJ-6`!o!c)D}`78D7u5W9q4fD9c_t@~prxb@1=FI|d zHe40Q-FiT@LLe^HPCpEKFo>Qj2fq`P@X~TV!D6>6i3#PRL^Tjt%Wx5oisH7^$4BUv z0T~#4kyUWf8*eKn-)S#HmhG+uF@@JbNV-tQGLBtvchJi{2w3P}Yhk-3vqw*snzf)#e%+U&;Xav*oey&C>!K( zdMa!In539_RHjGW=Kjj+S%YP*rRchC2^4_poM+acX@7Qs)bR}uQs*~fP+|#i`@5n; zP@G%kan*PStvw)%;=+F@fRLg_>`NV%49062M7rn*pkcgh*ys3)gIYoppDlx0J>mpt za==hzZoQ9?#Z(D_4e+}m$Lyvsh7P<}4+~0k-uVha-8V;Kj^hzq*bnTR7blj4}Gjs?8bN?+8CMYF90aA^pjucP-Z z0F|`g780eln?tRja_A)1ic`f@(Ny#nJtgeYn7BKH?YlLvYl9LUHl_4dOLr(P1xB%V z0P|G2%Jp+^th*-H$g#y@%A4`1$v4o%0BRGkxY`h0U4#3M*UJ`rM}jU7LNQn`VwfYL z%gfOv?_Q>i6ss@z+WRX9x<%d2YS}4TOS|f&2IjL65C{y*K>H$_cbR~cN_~wny5`{i zTHGJZ>IS$a#@$KrOpY;T$6hWv`gh^+yD?jnN~)iqZ4FJ}hB&g{fGCT+LxnyqoP+j& z`U4IoNqn{B$^?swwZULbXsj@Xc|VstRx?h6)EKPkxekGP5vd_rjoH55+(jK#n7OI~`7i6h(EhzGyMNQ; zTc;Vdq(G5*0p2sPOAsUModE1}o;wt{)CBd4^I>-hWo(d)9Zr%#Rpd{bvB@Qs>qpen z;D;HURB96`3|o|QO{{K+l64>Sv0$hWY{viqgCEt8MI*d=f7I0oP2i_?oaOItu_;Dj z__2MpBqZ0|fuhL*OmjNw7sWv(O(DJdP!D{_VPpQ~$ioX~zlj*|eZVwS7*8AS+$WrI z@7Y%+wnB8^(bx%d>MEjE)>BIy^^L*q*COTPajtJv^GsTFhguDJr=vkFFJ~CZ3q+fs z`1-(#;qH5ioy%@uRSI$} z-D5(mWoPX96mPuBEMMyG6(=GCt29ix*j_d2_kqfR!1)>AJNfXyK~;ZEXG zaI-+=FWJ&%{Od^iDV*iL1uKHhZ}MuV*( zF@HnE6K!Gp_(Fvk>SA-$OCFd!@BMn_-tQqrp`H5>i~RA$y_8uU{Mpha$0SG$iwBmZ9db09~& zk$O+UdXv1PTdSMcenpK5sAh#{IOnZBR-92cF{t>HumY{13?8CL+;;@PIzZ`Zmz8Wx zJoIR*%1fkZ>``;d1UR_dS#MA(!v~akf6{y}n$KoWyMF*Ed zmw;WWdb&xW+{@=7!%TvjSQo-E$pl)zT|K9O zC(4bpQH$xLVD_-n`f>}yvJ=V3XoZ_Ff3VxM%CV)C0rPbM=kO0n#Va5HD8#WGZZJ_+ zzGz9=BYG+ae+ItgZqAIFF@R>VVezDFo>zS)L9&Z#vCif{lPG=(gysAq54@k|EXuUR zoHW&`22I~3yf!^43HROgyg}lzM97l+K)VqR`7;HlhLAiVO4jcO&tpm)iaig3p$JVJ?!g~(jKW-nyNG+V5H;m9<#)GdP+iu;0* zyL5ej7$dsN8Ff`b3)+eC%l}W7W+4UC*w?%M8~WkIz*OFwb#V1tV*X`_f@o$Tpt!oG zRTGrxJw@d zKS>>;!2ai%;5J9pmz3u?AZ#ihj_rsYMDIqZ+fg!56;82L<3q^8h;1f$DjKfbQ z%JpdmK(dY48ez9%*$P%y(#M|MM@$So8R~*yot6}glHLm65&uAc_8GKrl@2c+O+Z@P z)}shN5&VuynJD0CAyl9`nZ7wFNtOc+N%Zn|!CWA<&n{*vF!A{td4AU?_pu6sz3N(fcJmCqulGtN_xor*$I4k|Su?VXR} zbZp;kjp_4_V@n#%Sb@_Ck+9b6ego+spa(m2n|H1#;7)E%aLDg?EZ|sm=|5gvh~q0o zNXE5?o#B;PUvy;k3&}7+UhxXwjYl@kzfFwugq_TtnGy_F$0C)P<|%^#GRx(KM!z4O z5eSiJH8Z)2uz{x&S=*XAU|!<NT@g=_>kEVSALyI?$ zZ%;Gnl3XZVvVz|0e{7}PZIOzVdafqa2<%%bLFWMH>Q(9`p}mFu)HJbyV;U>~Ye!xu z`UVK!<%y0-QeI845}ekyd6gH42zbfsh`a!SoBe)oFeAk{nQ>m!@sDaG13kifC_k=p zI;cpMgyj6OBpsRl-b+~R;90wEM zogzVO@Ru$b=1U29A|^V$zntUdg2cn5boZ@{@PbQsR4b1#N4{E4EqrB~0f=BDn?*9_ zJLKpQH?^l8Bq<~lrMkkr=X-=hWA7HAqOeHp?RSc3KzH#2bVt*F&pSpXAk@nc-lOG9?F z9e}8mwricC1D(;;g*R1R{WzeEO1?kKi9Q1I8z;@{ruS0<;N}ihW~A1TCxg_nG)8ps zn*cA>h|x_#k%lhX|2eRZ=Y$0$a0ujh9h@rutktZWbH9;NlEOEskPUML*pbnJ_yDsj zrJ%%LWs5lP>$U?8_yN;MKvVbg4}VpctMa38@P)*yT7&bM`l1aV3jOILX6LK1x}OkP+w#)Gm={=#=n*tQM1dn1c^pn93ygUnuXbW zB&LvxfPnO@2NORW3U6MWty?_;0py-gM*poK_4vPYssRCtYOfj{f`C(i?af?*`r)UT z)j5UDZAdiLm_ieGpLGg41uEcoG^t*q_ijVAI0E+L<@5e&HH zAMA?#YxtU=_07i7!c%(%3R`fXabeYYApaHXMpH4rjnnpKKPC5S zxKpJVR8G@98>07DGO$TG^=oCF=bngFCt+Ddg%;>~{()rv(r3Z{HsR~)$c47_XxmCH zSa-qG5Rp;5`w^G3;!9Uei?{RProy;*3jnq#B{*k%Q5+S!tVwchLL{D#bRK~!E)z=E zG*j?VD`f0#JMvnkdhO~=*osYUt{gb)m8&bcbW!7RvjB2e*HrUM!yvdXVQ~Sxl;*ie z*kS+l88$SB>o$^(w-76Jlv2a>+^){cBBt>OBV=7KKXolC1WkN#LS0IU=e&Hoo>3^j zu+pUz)xJiZy3Rnd0YUG-6>k8i#vVp)vOp)%T&!|ZyLw#bK74T2wwSJ}L{h)ylpCI< z+}dIR7IA)cTDGkt4Mwel*>!4P&TW=@{ha)9qonkNNCYc6PD_?braSJQuPhOSCi%^vth%XM&#H<1Tj=H3JPR=zOB)CDRZ8u8xs)~oreRpBK_euvrmIM z3AF6|fRC5+Gh0a@0vA&V9jKBoUWd4m1$(j{m zK_etA5lEWMtb?j8?p%S_VP#qFx2g8*(+L(R?{xR*^8X9zly(Ue6%1dWe6sVs2nv++ z}txBx(VQKT7iOfLV%`x1Hz))1Pf ztn2Zigk>q$zXj*WF7z3kc%^Ip#1STRxkXh^8&AUTmpr*v!UfG#iOsln=iWV@u_c$D z2aX?Aj@z)68W&V50%O2spaWo98IWRwTfpk^Qc18$?D$RpqMYG$&?BuYnllnMjTBj# zp)Wghr=1Y7hzg;(#*5U;5HAs=WTKjA*Gg$ zKzk_Wq`cJ63o5!*-+SVq0^(!o3%3K(wy}4vsKk5Uv33QOuyg+9L(S zA`ypjJNhpRQnT$b?P+X$keT{3I(htLW*B}WKu7dwk}f#;uK9mOfv=fDUQcs>CKlM% zEo3&@vsp&7VlGqnWSN+PCxGCyCz*#HH(rz+emw*2Aalv+AWhx4pRqv>rn?y2A<$m= zzJ)$uIp%_!3buX4%|XQixpkh`Ytx-EOgj}vO z3eIH8xE_&|kU&o$o$=~+7$RCGWiAO+C=#8L6}TJ z7W+>VA-+RCAQR&RagC}-_+JkiV9~|IjwgtcoR>nj$isRzR%d`1^DjwEc>Bh^icU-N z#7S3?Ld)zvYmK*;7I;7D%j9X@QGht`Bi;0X=7TJ$<1ls{Tf6~AB|EN_wkOJVhS>Uv zyuBvp96}4<7^mxKIy3>HRH)e}QU!(Nm5ds^SZzG|et}4+Q?(K;1K>fbX1JZOD!c#- z9d~XA1Hmi8d1lX&h+>i=^f( zp}5GnVpVAf^SngEY^^Yy9L~spL<(}^>#!!)`s$Oj*g)h0CU<|(B7Bta-0LD9)j`FG)cM;!!}9$BD>JI zA87xel9Lh-2(HWScRF#5wOwtIU~gQIQpS_)FdUE4ZiOa}mcCF{;Z3RX7Q_+QB0RHz z|GG^13$A9DyDp!T@*oB9S3;w89oE31&~)U_c@sAmWah2qh^c*?5g(P@od|lM%uGp# zQy?PJbES}C=Sx!S3ecHb8Kd9EzBZMNu=Go75O^fhWKrmGQYcP2CxrQf{()=>yMn|O z4JpM-R-x1ub>x7YX54+GkLl*To2@Ur8ehzql~v-*DHB_mm4b(1(NG6VpaNj6L^=GQ zeh;vIg)o$SI!kBJ-p{c3etK(7Ps1A!WIIU!!c&3dsUG1#@j%Znfxvl{mH>b`R01PF zR^@oIdF0h@nG-7@v*22rk^9&obLwxi%ndkp5Y&QdjJX1^m9XIGL{C@fbNTvt5$h%8 z^Tn3ls9I&+|7Jg;vf4W^g&$fbi)A2Y9x)4MUgrnU6ob5CU*Yi>ynmzJz6=N*b|15E z1pHFSBG!oFr}t zAl@lyj8jl-ug4`UM3p~+wO_cUet%ZSZp`!b>1oN{7_>PQD8ivaF6v>w$eluuqg8nF z>CoCs$ab*ZGUDFso>H2xf25S4bHMpHlWH}9`ry9&Yten1uVSvPs=MTEUMaH;#E@iQ zC<1;3-jWb1Yl0$uBw+2F^u+w+P$o7!LC@FilLUW(#P|XGxTbSC3348MJHU`qRmwBf zOF3jJ(Vu=-U2pQJ9IQ>n3<)E8ZtfaZyNr z08*nQ{U=KYwVs)1Jg%*WRW4ro^)Q*7j(YR-2EL|u89J6<9B*+Lp@)no&00Owj=W1@eb0FkfCsuOMXk!C>*K8*x* z;@adU5_}HaNVZa9Ud1GakCy4eX}V{cOOOAdXqe4DotE4Vvamxc*_J zo$$tQEitQ$J;z(9)v0)Vt}3zL{E|NK%;(Q8DBA>W0t5%(K#V?!JBl3ZS1dZ^bGZ8! zZWviVgISfJ-rC@LSx`i5c=;%II!F=(SH@HXSt`iA(~#Bo33=7qy@Vk(XvF4=-wi@S zq*ElVQ<{f6F=d5XFz2dtY)V}c8D2xVh}{?`?KQKtOLxm=P{!ucuhEqN18cF0x+j~5 zpC8G5tdT6Pf{0&XsP1EZ@I9_vO0qag^1!M*>>tcpqJ9+-GN)U6=P$UKF;`c3Fg75=!R{dRBcse|fe&`)sgJP-QozxFt+0<9kkFS+0Q zw8I|3BfwjVGER4@!|4D4%~prkbc=}zrK=oxq*$?xtijL@Fy05FrYvR_S37?$19OLu2da#x*`6bcd+i1bG($=d&7+mdO(bxacib?)N`hN zY-!IggVF|kVOZjpI~78;V4r~1C2-FY#(J+QWI6M};$Ar|5(fZg3C^_)G+TNgMzp5A zK6NMv5tS|@o)Gg0=jvbIsCWUEbL{`L;C)qs4I@!#t;G@bNG`Lz<6lc!ETJ{W_vrYz zNsA;R%exP}TTxez=m{5bS%WLF*32D;+V@>#|Gg0X~|Gc_ng7zXW6Z{aLL-vZ0WLkhG&a7X-lK zDoy#N)4-CfymIB~pF2BQVHf?8+ZC&fY`$h9tBxp#Qxdj*h#CX!z&{qLSiW>XxvMg4 zPvr(^fZA7bbH^`0A-Yg^0upRC*69MHE#<`+NPBIxkd)c+HJh#t1e!cPbI;N>aGSMFcP3h!0-Q6%8NV|Q zI?5e_NPkSBhhjHRBVBW?X~Ie{-v|LNUOM9Da^D4A%$crkWcM~GGzcUzZ2)1*Ncu3% zD=EFNae9g>fZ?_7#%MxEK7>qi*?>(A4;%@%a1z*Z~ibs7J0o>r53}hJ} zNk^7jO)fp1(k%jryh2S-$BM&Q#{+JWQfQ=&rkwi5bZ9XNsU+)@b1m+;!s&_)_jZ|s z2>6xPI7|U;dC5959PvWYCLyFq*fs@`!KT3Hg0t7w&d;>Y3Ydg*wq@EXfDn^OFa6Tc z9e`)4W3CKXK=Y#~%6;i+70L^>KcOl4WbrnyTsIV5uS|AZg+;4FUaAslxMUL4X!(So z0nV4q3*`%Ha58y$<^(N`3#EeZtVNs)8uCNwwk&Q`uH`Ilm$U#W6CgEek0frem5{cR zvWR0?(M-Oj=RwYwSSyQ$t-$Qd1y%c5!XZ}TRHP$Q z05W$9?OZ~aSrF2JupTE%Y)ti@ZhM^Qjtc?c1?VmvYKdvX3tQn*KZ7Vv1twBCiar6+ zvIoI2J;!s>s#NMoSdKXyO}7wp$r~B;_s7rkHyiJ5hA(pUp9Z@f2=wWq^IP2ng$O?& zHH`^38)6Ic0=`z9-W;lD0vgKkWX)?zFH?S1G5TQKpd;FVj#<-DV+TWd&rVxIy2rk_ zppY%ePz}6@HYZ54wZl>Pt>oY|XG(EQ%hAHS04Mq;6FS&9ktd$OR;n5JB>f;aKFLK< zhsGJ+dbGbv_^&Uv$wDWT$dWX*Xu;j^&JpP`=0;#kHm+;vf60MB>4HFdv{wi{aqp1bs1+-trVmqB;H1e&dcQ3SC=qt$Y>pJI{IPgH z*Z3)H=}ZNQ;!(m7+*#-#g~4{6PrKwiX?g6~@*?DNX#rOuwGFAbu!1P%L*Sf~<`>a` zk_g${p7H@*s~`Mz5YU@k?>pmqOMC`7l5+Fu2ObCZMsk0>?q!;0g(Auqq-8tYg6j!j zmr~D5p9A~?G$A(Hk*~QUB8on+eV=5#9nWesU98Fgwm*}k0t}dUw(_ zud9@?-uF2vk;6ol3`kAJ9z+7laCt8f081LAh*TSkS#=r!kYW0PF@0m9ZrQDSY$#GH zH}^R9&-@ujwQny3FhdYb4;r3gJm_~$r9dl&041=Qu@``M!chj`tMi&@Nc8U|_PSUw ze&f9jx2Ma_69L_s(nz4)_o;5FM$|If^Oe)>_;H~rb!bC7exR!X|4^&2^I?dZgbN|G zPgAf9Ev*-Cu_lHSG#l6+{M~j*%HQ9`G`@|SRklkiEV#Uub$UzBiaB8lS#R&R-~)#! zUS;q%z7A|;d5jScb=0Rk!St!HA*&&dbt5?dkwED?ctQs56p?aS=a+bGk=k(9r;z7@ z0Lk2^awotjiCV^P8Hrl6#?r(HN*gDeL@-5pm{?EykzkpOg0AAKvoSpGXs8E1LI-YU z0Byi*eS_9EwE(I0maMt|2As|x7TxN#*+mJ$x4RsWSt^4%{MswSNRsB&{Ky#F2i@{G z4R8`nW-V_5f=9VxYdf-ioQkwTyrK*p2{Fv=SA8f%l2$@)hMrcR0!R^hrbFi!Vyic% zu2C?+da}4HEHfNZELPG#1E<$r%oa{13*3CO_AB zYCriz=SZQ<_qM%KL^4v6b}OB97SDleAYdsybxhY{m*5<10A@c=0F}HsYRXKuL4yh^ zmP-3kElA(7Nyh#mD?oJ=iwnY;u_tx+z@;kbW=r|~OGAXM#YGBmN4`4{Bmzc76{_B) zV{F-F)IF^sqKOsNI!R_7H79PIcpaD>(cK;i8^bNY>ZL zpm%PiK_O!YPKlh{d@~PV-DtJ*ywbM45T=gY99RLem6b=NQ!@=3UsqiiAtjAd6b?`g zV3aqvAR{_iG-|{110tBdKA))XvhNUzjXU&?f6cg$zz?#DsUvZ9@Rh;knonmWee|Do zp!@RnWjP#{JgM;j${uFEGR-?Lk-0@H&96c@58|mcYe|m^SxM86tXh*RVN!f+G)K>=5oANqnYM^eFzOFY(6Z2cUVbQEeNIX}Z%vo=exGq8bMApDX zK}nX0i+2q4pqfoCi9ZQ;8m%#V<4kz+WKdAk7%+=AB1}b$)2H2 zATp~;w?yW;@Op#a_{MFe%NcD!-bT2mQ6BBd`sTJ-BX=wvsAf?@@O9nFBwsb^eKG9r zP>8I|ei*7i0ye{jUV?c@Ld`46DF<6^Fmq-IyNhZ!T~xJ&ikp;j%HV$qZs1V2n7gv0DaH_WQ$;X34M$%hc$%2&Q+xfiKIm-oYSY(}aTGcc$}UxeYT%PO1{Qb^ z&)pzNI!KDG0^U_h>L$x8n{}Av&LLqRMX-Hi|K}!g2H{2FwR?Aj(!EJ^>zu7rEbbPK z0>jqaWjECi85%b>VRup=yO!0O$s6Yv!K|zYe<4!DU{PDd{K{mxyl}AMqDtZzIgB@p z^KU-jks)T<2gx|bopwQev0QZT4#-LYVBv|88BH_F0FgVTNKX_43`qgd*y`ZDW6t%E z)HIm9xgz2=>E>%OM{m%A%YeW)jg%)C8MK@#QYBF=z=A#Wxa3 z75?jP-0*BF+9adL{yJ4UPrxKY>2iQxs3~?euR{uzK+!?pin3KBHabACMs)6M)KG%dTL%_Ph!- z8>ga?9>`1{((R>|VH|n;);^^{dn!4E-s*_6o~ZNrOrA>}aH@k^7ah`nQV1a&335k( z%p(ZUrQ#-URpQaDE?ABH%O3v;P{y~&lNtOTJLTG7X;CR14)Ma$mk)qb6h05)_f1+% z$KQDeDC#UfcJIKi$TB)Udb(1JmcXi*4Ke_Ynlgb{h!}@>qL~|BfG6}$AZ{H%hSFNY zmR=<{PN4fvW=;Z+y-y3giN#Os&To*jk@YUU+4+#*^}J^UeWrOyM&5Gne}&C(Ijsaa zXbFGMERyq#+IbJ~DOjdwlAu%YT(A`A?t*d;^@MBMkzLQP+ ziGpNRUS0%T*VpXq6&JPVM=0vp9K|XhdNX9Y5|()YisUK~+r=bhZ#V65bxYM%BxGL)wauH0-B6Ts9<`f2_unJ~Dg8U1 zxkvNCCAK6zz*ft>iXTuxU#A%9IiykOFhO#a4T@#S*YFL!`K^S zxmnTj5ef*%Fuo23T&M1^K3xnXheOjjxk281z>M6E^ZHT??=Wlb$qX2Sx5f#Q(zM#_ zL9k6B>32eWAso)ra*8FNsLgql_-ZKXfznaty#{@_rr!wJ&t$-A#%YqL`H{y%RMJIa z)bybste+#K%AX1G?HF#<8!9^)f|OGVfs<#mOVOvmpXkLB1fJlU1SPFGc34$x9%gBj z;6T>>Z%>Mwh-{%7?Q#<4HjD<=evi@F-NJ$1=(T;B7Y5x&{5Py!TY=(`lPGMe=1|q& zFz+OTbcj3YSl#>gVS*MeYymhdk1y|;fm|+D^L@+F(XRg^(w3e)&~05>ol#&|r3yB1 zd_V$#6OsLs0O!;t42yo{{0(M|V0J9r41zV8jNe49rDbT zL6M|6^U7fvF+L7&oBwa-P40n zF28l9x8w@$%maB$^wmOX_Lg7V%_~H>U(Hu~En;%OP=IBMm`Wf5O(`o=r>>3SI!OzW z*y7kuz8|hNVtUECC;@y+Jyk}RPp(!mc;{~q95y;3jaVcn*N#$jb{cFk3-Bjx)qH0n ztJwjfiO^2(On9f|hVG`y0}BFNy_M+t)~m0@|}aVQi;T9ilNeOn_RfZ7qzk*!L$BnwtY6 zp?rVperK@loe-*eub-4iUmscd$+(dSg36Vm`ZELu4W#l-l%0muaHYb1pq<tEa*Lt7?qf5SPb~TJBE79t|CQha2@?X$$T)zuBgDF$T_;JqP$BzO>0`l> zUxJVEZmAcFe3@klsd%#rD!!2NhmBb+PriHZ-1F>9>sY5aG313x&BTdv%}s&+@~W{F z({H%ZFQqUA18Pb3>|`L(rN)7gR5s79X@%Ip#~xee=^5m|4oQIO!wXp@Gt=a3M^)u> z-(oRUJ6rkhBz(s#9{a1?m5?=%4Zxzl*E)n(|Dj0^wpmufaZ@{U0Qrgk2pd;PpM&8eBGqO>5#PB~VkAN4zf_;%m zx_mhc35Op%aKZI~(6NFD)V=`TkD1QFn6aq}U^a~KEBL-999QQwZ5 z;;D9j+NZ{ZM%11XpqQ^_F)LP+rB3x-IvB*mLRGQNuj%s?)w_Ek_8*rG(re zG>)O2NWP&2(_vP)QZLHj2L2`lJa?G!)Lo9)L}%;!wPRo3cA+BT@)iX`Wae__5?$fjBnq$-6OZgZRyJRgG2hbt<|I3z zrJsVb4?pfF3@SYU+D}E+Z`Xf(nP$}zPAnB9OoC&?4+@)F? zZ0pQfA7mu=9}ObWE)j(b9T0nxEnfA)#k50&0(bvQJ;%eVtI{d_uzysZDmKS6;1dD_ zG36+W|3rhJ;%Q#Q35vqdBkhv%;bYou10d|bZ-5jYq1|JMu*6-6e)j-MK()Ufj8umG zREJI&YIO-)kkUeW*L+gs3BpNI1EFI2jd*Y5y{s}x*#@|4&gBd{|8|_nP%b!d| z>UcPGm3SBIwtK`I5Ve>c`cvw*NO7ywng|!?PH-Mr4O0M$hAIfc;C$elMakAL@+dc) z>AL%!vi!^A#ZT7HTZg|F^5a_Fq@*hv(dN1B`maHC1!Ba%zk2R_xhXToUqpIg4A)4J zem0fH67NJfeLpFEY4Y0n-;4dt=W~yt+Od)1u}UpFuFD4b;Tuj_*b&WDM!s0zm}@LE z@8EL<1ffRU7ZtUWYjK=rHF0~8>O)99#cUzU=5Lian2}wGB!3PE3a%vdP?bhOB^q-g z-XOw1u$x@9V`*AZFo-1uS9L}ie!GB4 zNrSF8U*(qNuORZesL)iFckCbYU#p!Pm=X-X2^{>=*yWO)Hz?%Dlt&&771^h)Cn9i# z8}Kxij*fPCAXy>NDer4NLp}(70RT~D!iqVCO2`}{f;A}fSZ^MPJ6&48@+u!A_0o~0-Wn(mmEaaBYVN3dZ6b|bgNG{r78-N`51%%@(e-G zzW-I9uST(fjy@|4^wZ`}n)-~#-k$S;yKqjD+qTBGiXq2WuL;7Xun+eRU7d~@IkzoA z=}5dXduPvx1B)K!vfyBVAg;{yP-{n`ihz4dw@tEuk$Z7Bmgz*kZNu3mzabJNpP5e_ zm2h5h*-^Pq^Khg#GZ^4znDkRK&;{qXe>$Ru-~n?~y@-voWBa2=I1%Us;m@6cyvv*j z;CUfppiM)OaRwdLG!>IzPzt#~V{9-vJ%Agp=yJjP6OiyQqm`1STv!GTM(`~Rp2@oM zJ&pt=%e*|pBPAQN<>Z$6oC0IHrzAHzi@Zk<@eA(~R1u(XDbR9{%xxj#KpEMXuab$M z;rCI5KzHIj79oHEsrHCHyVjv4;>7%r5>3Vae1K5c37Lx%(f+(3E!V=gP};ak;Qd+k zz{1>PReYGBLnPk80&sY~A<063nM0u66Cc)SWu}N{mr7>(Wie9E5eBL29HWMcyr0PW z0ecTf#nn$pw1oaW>NYkD<}S>AHxl4nZ1~zq^3#Fru%L!nZs&(B+fhGb>Fz`Bzk>l6 zumHPi5)CDR^LPANO<+kkARHb;608OlxnT85Wf&3r$W-#=l-UG>vQNvrD={Mq{Z@Cg ztu25Ft#ptcbHMXC0c=cU45W$((bZ5^X=on4(UP8l(D%ZG*WDl=tuqh=#DC&{r zJMDksf((sC(N!Q{28kk3NdkKl@c{0EFVN{>H_8)(asY}VBS>?NoL={pu-87P-g=pE zBqIpBdr_uq#ri76??Z}5)uPVH_%OC}B5WcC6%F4ZkesO@xEy@7DE<1PtA;fNJKly> zMIn67PWrI_BS2LV>+_)x<=)?_#Pj2ujEo|;@JJo@>wL8nB|pEhU@_2F0!5skk$&Lg zU52ltnd!N4sM3envgqWiZ9Hq%6u`t|A5xw$CG!IXRHGMZ7;5BvQ#J0&e-#WdBy8PPw3pgdwu*!JN&>)As?ZDKetpy#S79cmz0Qu8}s^bZgYe(C>ZAj5FY^MF?L}m0Nuj$^7W+? zly4?Haq~1am=Xqum;=nUxWz{G`j5|>e9qyPCKT7x;^b?T%$QFQ0P1MS1bCCc%1aQ< zQL(janY9EJv?M#3NT?n3We5dwz`qnR(9ssja>+?+cCl%6!=vMhqGa^O$?3)a)ls`T zQ7Xw_`omX#G(?5S*z$45V(k5H&7v6U!-qI0wf7CnLqV?A;A-FQU`gM&KV)um+FKzq zaNsjbCfqioIkl&`^cz-#`4MWi2Y8!xLWudlv(6ftbJNy5vf(+mP1P!y;m1!6bAsz;iqIggQ!)ekq2p+=$uuyjaK&r>wH%s61L_tIf+MG> z#`Y-*E-hHRgCKb=W!l2)X^-LY3+1-H+*Q)Cos0Gy8o?8fN1g>{p| zz&O`Il}#S&j@n`+XRGPKnFN4OlI!kYc%D*ZcgR=M?Z$U_&zQn?iQ&)-7! zpTYU6=t9CU@SwU5r>}EB$J0x!g;R}p86v6}?89SG{0HAG>k zAao^-2k$E&LtXScUz&np&MCke`XU!=-OI9Xj-Wl$3u<9I0myOZe?!Jkc2fzl(j`pE z{VSAPB)>)Jm%CAPQNrVj2?uQA;#-4SJo8qbZgagUTKj75&t(YE@7jbGdf&5>fM&7> zOoLUmA~fOu&4|iZ#>DewV8h(bW)I-pFuCpgQAvg5PT6$#Q6MOU3U0pg>nqAH7CEBm{({T3RQMj< z96%m}fbV%-?FA#@FG9dEJN*gNP><>3L+_p&P>vmv&|g^QlpFWBtQVE<=F&*y@tkVt zUM63pQ~7*Ax)Wg_gq!YaQ<(Jm>BQHAu9%>YC6P}W;rJN?rIEmH>pN@&TUW4Crrcq!%Gt@L2-p-b3I zP<*#BoObY?_CIJEoz2rl*xJy!ehnm6sXn<>3E-4P$SAx(rU958D)4*PK~#e}XX)Ns zSe26gl>(rmp^_-8b$q}hP(pio&-|I(yN$jWU8ynjxrM!z?x0PjUd>|(+=0LnXTX$c1hz>2j-fRAM zk|nh#oWbYuqf}((ZsQHtBl1AeNRy3H4e_Mgz zmiOqTuD%{t{}D^%)6hNE_%Wv#I&XWgGSGx8Z;wAsiWdjy9=JVYsWkKj!M)txRYAv0 zeYF6>FjAm-42ihF+ZdGcx@D-LMJq|BKzE4KAtb824>_T38>eDaa3nCTMWA(vQmLVz zTwNrl5itEKzo6{n>H2_UOpH+zBOoutS*)baf>`BH8d?1vM_zc3ge?LgI09nDSV{v! z<;@ASDYS`^1INU**A2)>wVp9t@30~T%q3N~i8$6tF&$~KCe2|+2WzuGEf}>~TBJSO z@*hkLA@cihM?{oghua{|d{$UueeP-9wAhFlu_VH{d3n+BktCD3Fe(w)OI13%Wv)mm z48hkQU@pig`Tga|t>K?7BPHMo#XavFBMMQygB-w;Hhe|kq=e6um&@IDNOJ+?8Pc?+ z(1`I|6)r9PSi}o}3H^Iz2oJV*pfT_1>yAn=tQA`sWYR*3JVbUEF3?Tm{mj8e&=B+$ z7HHAeBEsLJNtyGqY%I8EU-0A0Wi_=YAJgnkV407EKwj1L&9Wt*M9S(27K6+!o`TKyo5N4r2@fN{PhR_4h* z${ds5$k5*RU4_gRFWimU z9C`MtB+;9S1;vFm3iT2~N}y0593NqF!(gT?N{RAMC$6UsmvzhHa)PMjfq1}1c}y07 zBSmRCi{ix3z&B8E!oogLg~Yu&glU_YDc4M9E+vYB?L$GRXWw~|0=z5648PoX49v$> zXOe}J)uRyYVuqrjxv?-}nf|DzhcH5B(ylRVk}1J;CC8>xH7qm9v`GnX>c_+PGUiB< z$jR|QS+A=w2ca@6&86}}Z*-?I)(A2JwK$Mo=IhPpaCmodD-vgn%;fj=e0;@Iat ztFDg`Te0(sgO3|W2;dgA=XO;MZqR97;3y5A!Psw2*j+$2lnc}m@Y_#Afi#zU$9D7J z^<5evbkIkabhF53J}q7n_L9TL3O5u^PALlZd_W?093ee20e`>31lUN};XPxk!Pw8W zTm=PE3M4QyEysT$REr1XHw)o_x!nZ4(Mo6x-!F14xbLv;EV?zpeY!JdYsskJ>823L zX!e;))UKGJU}&pzpuVdF>$~!xB}D2>s7vJ=V{*SbHok*32#{k7`n55-rMGB=Q;e0s zYeKM3&9@8^^vv&e#c(JKTyqu9ET&b?iU;W!?OT8zXtf-AFmc>)bk}et!PS_j_$Fxb zxI%^#HY0hb-u_8-9I6@sIE#KAeTw#aU;H(wyIKX|@0lU?rtKg1%d{R9dnwkZnbw7j z{moD8iqnC!?!2ifWk1dQUlL&U7KHS$Odi3kl=EY@8cy>t#+(AI|2@4j>F# z5Q86ZWJIG5(oFHPKHrvsawuz00 z7`v|21!ebZ>^di;Sf7(y_lEXQD(n{Xc8#)j+w)me!!3{~w?c{p--BKtZIwWyr>mFH zp^#($zAWKneu z0S;*ytrNJeUx0TPEz#1Dkphs@^M(K)R)7h~8Qr2*mt%~)B2Q3;;N%umW4zx*tpHxC zIF6}7l1`(cVQR+zmiBiQXjK6KK>*gdml$XdFK=H#qrsYvq{7krWBv#JUxq zPUBt$tEcR$ zLnkAlJxMB1gv+aJv8i00U%z z2G78is;a6A2;}POV9unf79RkcwQ{lMo@YGodEWslJ{Mpj1}ZDXT}M)N!H ze|#U;AHeO&**-dX0B&w?Zr0h+7;Elvvo7Z09`k11q`AoU#+%%b-gv|E$ctPUV{^f> zP9#i37ehf6tJ44i0C6S?K+qABAOMsSP(VNc1P~^Jp@@JCBnW^=2?78jA^-pY00000 z0MNEl&4?M2JAl~U9(R&YlHeJQt`y4N4rXnF_%IW1QRfGnWCI{-*yt&LU^Hw`QvpJ>MGFa;RiZuDy(){8FH!mk(ECi1))=V2*~V+zBv?p$`tx9-vajnj)l*~;UC1@^SDz2c^3KCj1jhs1;sA90gHVk>Aow;Jkzd$M00+C_? zw=+qjjO+C)tbewsGi4UsQPT*BgCSrp1Nd=BmVn>r#a76kZD3#G9VE9DMIv*vlT;PQ z2RJ->UM+EMriE76=8s}`Gb?tl+nvMzJ|FGLvK&7uTECw3pS4;=x3^pZMBNOJj*wo~ zWeS7@Y%@AGA~paSU3!v+cA>qmi{iMUH8f68Uz zwlLa>5b5xzZm62xC5Dmv4YsO>wwpoqjLt)w!4vk5Obbet`5)Z|2-7pq6#Prd15m;_ z%-UB6FT3=gp8{07RLw6&41m-<5!y7D1#W6zLsTG)`a4{hRWczkJR9Y>?P2iYK4@WO zn`?4CK_7W3Car zZFqg<(;#H44|o5TgMJzp4=n@>66%=n!hNi~@|X=s2KVzP)?!$}A!oS>VXbnnl$FJK zC<`PHbZ%`uS_N?%{*w8AX6kg3dO%|kj#NOfW1(3>$lM*%+uJbTqk(RcJdZ9(>Sy3X z;4^Gcp6zldwEsMJ;#@(Z449aYFaSuN`pL(h=FB2JNvk0=y{8x zWO_P?)5hLa^>xzQe@@YNQqo!r;YOM)Mz*g=mh9IPQh^Uuq||xTP4uwsZ^VXIh2FXD zC%l|}?J8^FEUm#!-AL%k_sG!*mmMO58@Pxp+^T1+vc!+5hL}q%$q)VTKbzV|VjJ4QEJk-u zZ6J`1&R&6bU0|QSaSEKHuow;OjdObH@(LuI;Q`V8rZifg*69;h`#m=Z&AH^(RWZ)a zY%sB?CL)n0H=fu^6v3da7*SD-C5MmE;JfhWG+7n8RAgWW*n0$X_q!n@^_$}|(W00l zFA3-@qpg9E4+Q`K000000000002a8Ve24u*RF#3T4nbGnX`EQi==z4DqLZK>cVNd? z4T(y!DzCTTkONI zG9!=c8d=On{&zxmPtze}vBJdzF^88-Ff}$`eLzC-j~seh6=@|wu*j_iy#tIqUR}$> zpgx{;AbZGJ2`1QcE8ZiVPKmdmD= zW2{RRk9Fa|ekW83*nACgMP9DGfYf>R=h=XZ8w00Zv}&y=ii%6Q}+SwrON#y z)^jTkR_X%w+f-^1M$;-H)8+`Vy9PIAcw8)ov!XDjh#YgzMPafEpj= zTCRFr_#sSgFE7n+{RABn`*R=kjRD753m`e@5pro%lMDlqH%Cxu!Rr5=G|2{jD*E1U zxyt48KB^O;nW+H6%TOj+*uU@UF<{#g3ZD8Q-(G`S?xG=5o>^R)Z)t`ji9po6pU>J^ zRLeBB(ovf4DA}$Cv7CLyt`YEUHo9~+dt%fKW{vL-X z6=+>*dhr3sD$$lym8^B>akR2ZU%Is%+L&_CI2s+4i*D5=X|)gG62(bDa*f4GTNVH> zNSdBlMQi7xWvrU8v&`;S2;DHLNsU6hiKIi+pYisay((z=pD7!x^*h42+_z?i(06n& z?XlcJ?fGkzAF>OIx~l-C;HmH~6rhdet!(<*tJjyj~Hg;FFLl$mHoU zLMY5>_Fp|?M6aL~)MWFSf*+qiv6pHg5gevNjMoCue$q6G{aN>=ctK?}6nFi1ch=GB z8VpbSUIXa5@MZy>FG86~n>J@8MH50i+N_Tn5b618A89W#@#Qssz_U#6q%?F$1=^Dz zL3aZX;0O%OZRG!EQp32WG}lRmM7*faodFx&KMks6i!MTWq4EsJaC8mrTm$<)*tOx` zC^h#s#0hrS|CAM8rf2}VkZdjZJCw|t?rRM;Nb%a}s;N7Vd!+7R))*S1*FdWT!#22s zytrn}^U%i!ir^a#LQE-CQM$*63+&Y5@^Y>M%Bj0qb46UeSX(Y_#F|BD>KeRII$Bi1 zTn#VtMiI=hd_qyrauvi)HLN8pQGZf&9su$?4JHy3XIuzYXg6$R;M$04!3GT<_}<+y z`!j&}BLOs>3+55}mpdGwQiiDZhYY(XfpbEiNAZ!T;>XtYyxFddEr%K){enO2$a5=f z72y=}4?YKqcSlTC7J**Rgq{zYXi9`6UfqkQjlCR#7N?9o7uBaB5K9qqtI`h7ZCkmV z6I!Fj@CJhuxAxPWS4aY`g<4Q&Ja)wo<9{gM*tMIwQ>7ejq%;WyX?Iw0xiQ)EQH*YpMwN;#j+>pSp^9=ZgISXxVBIhQk8(u*(p z@S-m6y7&H{Aw**QqcGvMjC!Gf$tUp0BJIK#KyVVb`O+-|;{OR6(?y8|nx_vXEUyPRj*k5jI^fEoK&7KQc zc7xHrJJeWdqGY1UZHsu?sPci3Iv(NW?q+b6t#L!O-GX+{<6C9Nc+srFHaDpmg9efJ zn84Cs!9mkHyhYCWCi$cuWlrHR2)YB5Bmtxpq-8E8vK;}jDRcF&*{lJshR_7m7y#v| z8(i$1bSnpxirNO~tWgxl*o3mmEI_7l6$qFhD;Re2QOpxr4KBVlBp-}Z!%!y&I=lc) zMs74$eHjPm35frC^e(XMYA_Of^EW1Zm7;}B7h;LFAY`2vRd9Z@nOGU(b>C(AUNKb{1;6AFO}y*N1Gs_V!BV05A;t}*3!L3_^4dtu%$+TXS}to zAEDw^j68UR`r`s^91KR-hY+TzjE!MG*w94yE?T(JUz?kgfC)U!Th{Hu5A}jAx_DDB zEI4MtEp_<`VQED~aqSm?lqt-YpHrq_it`xzd6oJxPzjV_na8sULFd|4sqV669!k!P z0%+o;4swHuPp>(#b&UDhPfi=Z@`7co~!)$DgmJpMg4IhlF3z{`*6i9 zzrK)L)6Jmcb`FZPnD?uj&>YQT8Pm<+gaJ%)z%USYv6U&$dmx(=R1JXkF&w&~iU$}a zw!MQf#6tt>5|Dy8mlPeiihNZ^NAM^?>HcFr*J{;1j@?2E6p8F}G=V^XLKZGY1!Dae zBkBP#b}&nYG| zb%CGw8|-IUm-_)X1KpV=@%SCYYy{gpuZ);rK|lw|lFa#}Q$jvzWDYCe1}!a$ryc|T zZ4GBlGsT(Jznr4+a2nxb3%&*28l~w*{8#&p5~!3gIW#4PQNz%;u}85Fd2BCNHA)Cb zi$Wrhha84&Xdc4Rc76Is&MdGmE^#F=ZeHRqvnC0YkZ&?gfp>=q^o=xAK}@5lil)K( zC?R^x$pHZetgYp0U&q>{phOZz!u*P@H+&%9k;P&~67JP&7#V4H1A77wR^0${1DJ=NGOvGjzxC5VhNM1MiUJcQPg<~spY zidLK$pH#$tVM%crGvL-INEPO2VBwx#?-{WbxH`HADg1u9(vpSE&?`q+pZPq}=iK?e z&=&VhwIa+QNPz3mx`uTq;RJf3DMO`p)vBVAV7X-QfHeZ4*KC#b|IRiU;atpqP%uR0 zhNXO_dkIP58jJD97D2KJ1PNipe8I&AggC+dAVaF`NTJ>VxG)sD&JPPeQ^XlYgUTK= zSmG6l-fBxrO^{+*k;HMuz2mn5SK6gcZO0pKK*xg-2P9~yzie5B%PE;4=+lb+crg^mklOme33Z#r>((h0|B`8T-(FtWnX{-JB~`^KWAj;Jma@!nw%fC5Wh@5rT~!`ESb zNwnXxDD%f6$n8JfDQL2fw*PNT0NSh8NC&Y9ei92eXH`vlPX#clLV5uyP~MRQ#(!Ac z?6!E>*Av4Pg$g@HtzTx*0-pjH=kC4F{Y2S9LCDNFLc4=Wn4 z@hppC(Zy_TLOdPZ3)$nB=-1}xYeOFyeXs#^q~<@eHI)BVAIM_o+xcN#M}Un+kd(LB zzRTVOLi2P7aa~GRSD}lj1C#g$)c#IWsdm{iPdYXFNV^Yn!Yj0M zxzHDpGV7O2B*JtoN+P+#eNoOR4sBFB1oPE*wr=a{)K4FBL2++DgqyTqv3s88U(St- zh~nl!GmD$aE8zEaFF_6F^vujcM36o1hth5!yFH|h(JGZbTP?)6lT;oO_~plV>;$6| zl(fo-C+@7@8sn#?8Nm7*;Ej1`bKy%Cv0v1AbPT-;uAka^Vd7cdBo3r zfr};2hZblZM3hVln@kab4UA(^;}hOxz89Qd>`%t8jO%ck+zKG?{lO-=)J#IK z4@<#lkQ1&Hs{N2GXhR5HUgS6}O%?gSVg05NHvAS3t^u+i?zZ>O2uBh~08b-ar2p-x zf#=_CHwY<9!G*)6KnBG9BTl%bLU37h?D}DnZ`R(($S|8XkqmS}pn}6+9&Eb0gH;U< z1zz7M)HrE^&5ciP3ptWk&PfAg6j~zqOOpYs&8UMs4p7Z)s+U1V=+H~R#P!!OkSWne zH?bL=#7s^W(MdyaCk`Z;3iHhZYo#fj=q4-nr{yzZ{!H;ZF-r0599M+DUPmacVN-rD{KM?>A4T`4Unpf@hwFy-bT!8 z^|P*uO5gq+Jza%1L?-T=3*{7h1!3<{D~rQh(X$mAu%%zOyoWdmjhM;4-d<3t!>O>d zUzz970iCjz4s&(<(~QFUN<9CQ#Fq!GEik3Z%stvkYQ>gjBk=8x25jZ3P5^Oh)!9tp z<7?BS(x4ulA*DZ$FEoOa2DFV0S62RsRJ3XBuowUiEpcxOB&%=e6DZjD;!7ydG1Ux0 z8*L$;B=j_%QL&3UR<&~v4dl8%Hg`x6<+hUqNOp*6AFx}Q`Z1tiw-l5iAou`)-IgQt zKfsfM_>oJ!zIHO1-gk}~dowijx`CAqQo8EymqMv+`8{;ZGwqYRfHX0fr&tq6Ao~By zN-Tb~S3CPzj)jTOMB?e}l z+?m&D4HPxEAL@J0LuoS{t0f;?&jF%9BB9g@>FP_q%L#Y7T5GH7|XOZsf+zC76x_%$kO1tV;v4HoXEoP|K2I zu2)-+D!b68TG;{`STYw;SuMjgLv}bP9ADEc*P!QV=97Iu?oxJZ7Y}>UEP5pQJC{W# zKy;^f@l#;ic#e%ds?jVp_GCk(Xr`Yk!+w6E1gXJ={NcpG?ZpbNma|pL=qfKdKIje& zdeV-QNS<0KWtF+a-1Mo3fcO*f-)kA#OV@4tsh``+hm|q!1am3^Z#~`E>y988BLtjK z?s=^^0{)6fi$9S`$sgx-|7y6l2DtV|DY;r33mg90fGR|n?Fs5t7kq9%;J)z;2S&Ed zX|<5V^;Iy)`?53%p?qC8Jy3P#x-+t>1IsBZOXZ@I8JPmkL`LpzKdGEOnW=Uam{+D7 zELGmSDBN58ho3Y(5=k*iwgBKs(&1<5*9;%w^QB^PXf%4jGqN@(V%LQ8{*P_kHUt5Q zGE1-XxlZ(T?D*a4QG=K`6kzG^$sLj8i4ayL@sSs9G-$U=)!3=6$%R-LSFilWF$~_=l zP`v;E03+C70H45BR8>_~0qD)u!CX;QJLjR=y2luEuC69cJ3Hn{$2jU3C*vS%twxINCS+ z=HO!Pu^iUeG)b+s9VV)(s;a80sv1=VL^Wy@Rn-`ysv1>QRRsi%Dk7+=Dk7?iDjEZ- z3Qko-#3F#G9035}&EQ^j=^Rp~x5s3K%(1R;G_`q+^g+k5la8RtR+Ovo#nS8udc~Bj z;+(8Yf@vtsrZN^yZ5#M^>?bby13@J4KG7iLP#Xmqgnx8vkjfh`=C^WcJ*mQ%W6z=j zJ0$EglLtINN>D8C(sL!v(DWoyZ|?YAqPF=sL>75f?8Rx#7W-KwYv0Iqaz^n}_i(gX z$wGWZ+%no@vx+gxRDdP+V-I?0v~|wQ<7JA1z{i!}Kv13VxgmTh0)O#o@r0V>xzzW@ z4#NPn;pIT1kH*0Qluqdo{EUY)mdMxrfJgM2`u;5_pJPT-;A}NXoGq`XitL1mQTF*!@DEiu%B>h#4h++^&N9W6MH!UQrw1MBV2RuUJu5lb@LU0pG-N!~qqw z(hS9WDs-X<{t9MiE(9ZGQLK!YVGXFrtZym;K#6m7FqmcMGT5^H%kXj-HkXaE!{-X* zFZ6?Cjj$y~i9)DP&zy9#by2^-Fk|y6=_R3EtPk~YDM=sOQODpwPbHntVf=ut*%M3{ z@ZI+rU4nV%#iO=y(7oiMh}wKS3XU9E&ye#2l2{-vfd2tFFd-T*-sW(Aq99W517UkX z#NedeXi@f&A2|OJ-x`A)7~3|^58ypJj zPHTKN%3I$mxA#_weQHx!^DuOjvXM#M0`6HGh9d1@)Dz|-q^7D@Y{6HNUFQ41<`uo~8H?^{czPFua{zci=a-Q-4+M>Y>E?$eLqVwTnGf{Z7FsZQPo1Hw%IWZl4NN0{BUev2u%y-Kud^=So~dz%t}FY2szXG{wV zwL@_Tehca{MqjGKT18-pfJ_2VqR(k2*tqA2Y{&r2^OsF@HIf$bxhXO5o6btrnn1no z_w1wikInspHo=Syd7*22>7^n&+R|Dm@mKwC%&wpVqTkBaWU9t~t>@lAIY;?|?wUX# z17e~kU$~|v0*(WEQZ6ay)MWi@W7?{dO4f0ezv8gF@x?73kLn(p9LgqNt9Ckgn7KpI zJauJE412C}Ov~vXCR(AO1gr&!p_t+gH>|?gYqrm`{avP45F!S0 z(+QTYj4JOOJXp>KPTi7G+Zbnv?`+8)N(k3^yNMbf=xLRH=ORjTLZWDpElLy|K-J0E z-i!hd=LRtb=;^#fZbJoF*ba~X?~{$w`>tsn^+Q)lW>oCV`Z(a`WL$;~zKGhSX&;!$ z*vK7PjWIWW%x3g4Qg9wb+T44{uI zb^bDIrhc>n414ZgXV9nMRXr$TgYq+Z>d8*pNOMr%@Kq-)<6p0=yG8BW$I+XED0q3r zeNzPb3n$I?k)>Nh%S)GlZ*faY$qh^Dstuz-uA6P>vWDI{B$erf>pEv@jyD?#|2@O3 z5B{xq1qUob^}V~{|ES|Q!pflZxT%r9c!eQEO1nZEgy=45B)5S8MycG&;WcjsO(|Y~ zy5&q#obt~nct$Qh0I}~sSZprorokSaPvs|qB&|WL1q6>VRK0taF7P!I*W5-pb+2+; zXW|a$DJJL>!J~V9!14pf+fD7l{%ytsEtIG8jaVuK*n+|4hp@4AedimRGTT7^;4i=Cx?~dt%0f3q8W#Uok=W?oTBCzNuBp}r;1_10cC(&H==Y0RQS)*ii zO8`D){9-oZp2-MoCA8i2An&hni~WwlrXsCMVQ)|k{)m63WLNq+*W@gf1%S>0jC+BH zM8DYbU5Ko~;5Buwx17)KRQ__tEnJ9D4FkT$=m|*$GEW|Rp~C_!Js6@c5&{fKA>|s9 zeYK5Q|3|kSmD8LJWL65(hz<*cDjH+0#Ok6(e%u|769n#Y$ zkjc5iX~kCpnQr}q89IB z1M|6z$|P%Mn-}uyj^xYKyOM;4&{FRdbYTqZdZhy{s=MoM!ID#oz5T*wijUp2l%jEZ zR+imnn?yUJo}PB{hA)N2qH9-v!spmJ6NfC$D}t@$p2jYg;sZ|HjBVI;LT%#`lEJJn zBKEpJ%*>JkF4FL`QXG)45!MBr8e$twv1T{O%s#FV!<*marC{!&K!aZLb&rT|la$~* z5OU@F6?8X=H>K)5yv+6vc*59vOxa(G$BqxS8H*?L38~c!&luUg;y*MbcZjN^EHNpe z)o-=*x-3VwEy*8l2X{%x5s*J-N#%{gR~&1tKKSs!IS;vjsY4aE6MHPq`i{NFiVfPC zRBm%L`^_ck`{P?Ht+z~HNNrV5QEz*KID0KV=xMVw{;N)j-1W82y|iy#bYX@`I`bWq za8T2rU~OC&{RHmupo@LnyAic7`TNvPipuUr>hgt*kmsP?A?zeuMY!CzDl5czU8c7a zricZwS8=Ta8u)1yin!Y?&8ftA_6XzBzH`JYI)LA*$RcNqOjebsZ4yswV*JiC0d^A* z==uCp&((ERh~$oN>~@v6sdZUk!TvskFmXA%nF6=Km4=VyKWh&63}9wJxo36ZR#w%I zD2?!t#3O=T^Lv6G*m&BL3A@2z6H_>X|JW6BDH(Yi8Bv3Ixb5f{m%ip^5649+BtC+f zv!T|}Ao#Neo}q*TR$qz0Ru6lJ6;g#P8IziPh%X9Rcnxb&RRu02DRDiEn_Qs~;g!Mn zXJXb^IO~9)vp7|V^+be$`biL3^f(6JQ&X4yMA;Rv)+mm4Sy2`E^%eWOZ_60Jsdg#c z0|0~eBaoP8L9s5@U$MN_e>ry%GApYfQFy>coyLG)dXNrd_Few*tiNuqO_fbt<}lbKmltZ@(MA)D(O@Q-Tqa$)p5r6ow( z{Y|k&EE}x>w|K9gkH$sz;v!M^U@$YAYlrK0%B6YC9Oz+G^Q`?;BOH<^-Q$ESNpJyh z+N!`Pc9E(KOPp`sqSR0*nSU*wi%pUXBqY=p3-F3?uYFk|^vW_1l9DoQ)8Zmn{wY(k z4+|hp+5-E*{>{=T%C!HYSye)tguN=FAxMiiL|+<@~@JSl3N%L>21}N@j^FS zA=t|{p4k@_qmVu{7sQz=@p%f6WI{GuDSJt)@npG<)JAC%wZJ9YG#rR$yI*lCqTr5k!c%N|+AzR>`w-@PyPm z?ZJDqvw3^(O=zj%So@V37Q11}zSsaKNjWo) z!D_t#`pYn{yZ68+BO|_WP_LoSks=#{8P0LQ8KEt&A`F?}zV!@2%aYdpCCFh*S^c6F zf_F<3^M4$G{sH^RMK!B^{*TiMKX~unfqZld71WK(+49cOj$dU{2juogli+_4ed|L% z8)OG04`Ee7bLE?*`mfT>Gcr9HPkijw-h;0`2k$ht1*HF8;cIUe z!gaIz5Bh@7!jewz|5}=Kq~}+&&hft94F0VKKX?Y;LC=Zh%GL^eg(T9bk=;E0@%#Q; zf2XmHmSVg%?38ad{>3qU<4}I-2stxL7>A75lEJOVE640}1aXV2 zdPALw*5{~qpM4d%8O`2{yEik&$_gAqxq3LXy=%H4CLCF&j4HggJJ? zZlSs; z2Tng5vJGIo3}vJh|M4)kGCqeHfz4~9tCn+!&-VhSc*8iJMjWsm1EWe-cWvnNOtTcE zDU#x!&WPHw&-{-Yv{f+Oixr)|_|R(w^e?UJ3??2fYFR*gE40j;hrJ-Q8CI**2lE2y zSSzn&v}X-i1o<;FEwes3bJMZn*|mb5Kxl4NZ7z8maKhaaAwid=kvt2Z9AFRnM`ckwrx9^*fuBDOl;fc z#F?1SrvCfxyH#7e-}c+>y7%<&bl*PbRG(@DD94H7>bV(}y>(>sXWz_X$G3M_;)qQc zm&l9;VE;O~RT|~@RPia7e0i3xksbkAe}IbGnLE0JRk46#O>42M7gaDyC(XiG45>gq zcd5@(t=VT#W4M%0L>JxR%ZQO^#k&c&r(Y5y!f;#ok)=vO2$lcl61%TaR`Sa-n{?5t zkUYVKzGQtWLzanp;Q>R0*?InpoRNK=?U~+T*|e!^9{qyK)FZX!u*>Z_F_k`3O@310 z+O4i&ZUUY~U(cjx8abVn(1FQZ#ZZ8ogTK>+?l8liZ9qw5Ji#}qjdZTLtXy^>xgPs4 zL%+JBYkv~Bl`d@)!54N-mD4o&_z&7ea5;<8t5&Se4}S+@WBy&& zg*WBv;vnoKH4tL0zR+R_=oFdv3N*kRB@n(P>iqmZ+F2ewg6o~z!{u=)6fhs|d_2+Y zV)$)L+d;=)O0Qmi@S+TPRep$e56&pFr!BKdoH{PJKLkLBTx$kn&1)LdZlDXG-Ao@0 zX=5_kiL|DxwXh`>*-EMQJN-*>IXT^lTeKu4SN8hmpRR z)vK;TbOy1DC=ck0&Ybcf{u?-25FPOi6*3}GkT!7NtF_uzX8(Cht7CWfRK>EyVduGF z#9;b|a`ujnjYGL%9>xesV(no(3(dm5QE4W;+(MU4Zl)BoIQug^0}8jl!I=ohP5lgq z5EDnO&f@g73&JorM**Hs=fgPPz6W=C%(^s|S`sdozY~0KFCc?~YgBNr@W?3Pa!&Pc zL|TEl*wXB1`tTT!<)Ah#xkH*0p87*liy@04h;sx~AKf#zzbw&m^5dNjO_c^>-gB#F zV5Jh+mcephy>5!%YJCkAI{brirQ~Pp&!@m9u7s3T`(K4!p$w=MKCF(y&Ay#&b0u~R zTX|OjmtLd)4Gd%^IkRllZf<7z=cX3^ZK|e7R%OFGsKu;-=pO&NC1W}QCuA*$GB;U4 zQrIGV1pDvU)aQ=|6OJ3L~cuxBjf`aX25NO8DoT*?95*OM&*!u(Hr}fAtNui_M~jvWfQaopSg~ zr`|hdTs(O8n|ss8VO%ZkdR4`RMEQhTZ9ZWd7hWwNE3}AXI`8)yo7jtd z*4QpihYqD>+M796Yb1oqcViSF!>TdXn&7HbkRnYNkjn(DOjs6-puOfr0nXu^jW_tm z@;u!gJ^k5?6LUP9Mv{X(+HtO#N?f=y>S$^1jcZ|gluGEuLlB~(aInKGP7a>BMtXO) zy?@^E1ImpFAlJ2&G?~44oHsPw8cFL=@e)Z-BAU4C*)&asbeRAVX7};b!p!73-UU~& z3WU>SS$u+1>R2(zolN3RaxhqUYJy$kvw3GT{U#EfSA{?4Sf?^m&w1)6o#F8QG!hmUK+W=x z59;Y>b;?X`ts7Z6&49Nh6~hfPFSoR^rDQzGKjoLSet{Hw%^=r;B;}MiX7gg6q%HIM z#q$wV0-5jKA8D*+?y0Y~DN;Q|?&FYWd?unD)Z68k>!+B%(>jj^@d( z?WAicWgdi3mT)W`Et<7j@aK-JNjZNORr2p(B>FjOKT*d`qzM2BoaL)O=wMOr>Bzj` z#2uvVmISjwGmp$hR+5DU6i!K_@l)9CM$$iV#9vJ{cHpUnZ=N1KE zY$e&v9EZ$)6S#Sx?(iy;s}MkfwV8l~)Bv>mjA8J2f5DoVmIfy=MDd)w7Pmz+^X z)m$>HVuDLm#^qBdf8<-X{-fkHRaz88xL6}Pd=$2o``1E)ynf4%x(<%PcK6qj*jbgR z!fxdK8L^fa{2%)ZWu}H~$XfdhF_oZ|)j@p3p?{PmKCbe;qZKM>w5VPMHq7g!acI42 z48KjfexeJO6IVWtnoV(iwWFn$A`b?t6ur(HbzO!6(6>*Tq^0A1dfY+8+o(@5pV1Hd z_r*shVxIhPyN5``okj=$BE67kh6eb9#N!tOzT6SH=5H}+BQMkSIPT(b;Pqi5skWaSyP{c4S5XgP|8ngkn9{P#?A6d- zv@S$maxFdK4LD<&DnI6dz8TNr_|;50_6(9cTsZUC{yKt6q(;`xVM$Qg*wYj7aIgGr zDU_x(`uulLfg^h)!@I0^?8F5hH$@VZ2QGEigGH9p0E?|6;Mt&qsv4We7}FW6=s_gxr;EF&j! zE%{3byCid-S>Haw8A0-9s(`3FBdbdPse_T2SrE~|%UI>M8r-8?ltHiQTPJOVf3=(| z_?yYG^`(QWRO@HZg`EO@mjpr=n~%x(uR4~v$CU~Zx)fWZc3ilhj%92_%bpe2D#`R| z>&`{Tx^dyDV)>#*3=BIt0a%j~id--#CQ#b@36oFo3l!?q@-E59#`jXJ84x)ig$R-7 z!mjzpi|k&euPqJ-(6hW&y&U0=bq5M(fsB@pHI_ycGkB0={-BmjE#4U`iEqc`xoCt>41R+ zm+4dgPE7~Xo6_E{&CCDYW=~yz7#S>Fk0RBx!rjf0voPgb_l^fl2)l_-woE<%6nn8? zh%jl~rwcsVH5mY=kHU8TeH`0YvLQeW&Ezzb=rJZdEoydEX)~t#=wULmcx}}_`BG#ID39Qz$J}tnZ0mZt;Em){^7B#zz(=-{8PVyi# zvC(YzY&Kvf%kW?WJ^#+Me8SvR#G~b7a5e*j`gmoPVrfz0XtYb#ne1N#TU&AY`Es-h zMe&8>lek^FrU{+rh<~wpHm>1!Ak)m1-DyVP+o%vTCt-#7@z0Y&jjdDXKjpivuf-kC zah4NFzw%b{k4IGFMX$92IrVb6Z5c8teJ}rRk{g-f;D7J{2mxfIO;6Z7UD_yK=;RDK z6kC1K!FbRutEU*~RgRs7U7C_P26@PplmjbEJ*5iAW;Gh)ek_-ht)0pHm#jZ~l{OBX z>2Do$m74lJ^d#K_SZ2?@T-11d1^W&hnS@_DnQwp`TUM$gWPxj}t9N!87*@8Fvb0zz z4ky>pgY_h;Z%3#rDqL*!9XQDqm|i$7K!&$(T|J!jN1Gq%d1(=H>!+U=F2kyurG4U4 z>!78)-i22$sv7|3-ve3**5YhZB?>_>oax2t+&E?Y3l&R86Pn&WqFcuGX$p>Rx3AR1 zh=P|iYn&glJvR`#ox@btAb*RbUzb?ty`S-k=3z&13|C30^57f-X;d3==oAFhLi7Q) zQ%v&|98>Cr37hoOf-E)>Cn+`)&5j$p(R8Uhjdj!W)@yD`+BW4sR&+T==NBZyV=FAQ0a!GRquy6#I`Ov}$fAep9lgtatLCx&9xk0t%*v=-S zf-Icv#Oih+6k$*>q3WfAf}-ATz-xSuJlGNTtwda@;HgC4Aa=N?<=}w7l3ae$kL{YO zbWm-_uRr5?0znzvyRaz&bwMX=>`EvxtU@5QiF|%z6OFfhfp|9*qLZxkaq23Ij7Z-G z*4y!+*vuFB_~F3SSU3hbK@^d73x zdra6RNaL_S#`9aL2TT(oiac^NBFss%M;du9@G20d`m6j-xvSkj`Vo$rwd0O6wZ#jq z#>x(P6aydely(%d(Jv{ncTP5VgG4l77(pmg91y*9XkZ2LNb*Utr0-&(YOMGA^#UZ5 zSIWms!SkZj?Za83(21#A8D;le5E}(-=&RQ^UuP{!GoFi4tZ5A`$x%VM%M(dYW+TRbkk=)3iA>tPkW+zip)alg&fd zG94s9N3?~Z`K`Y{rpQ1BZ@TI{CoB+~u@d5skhSyIOL38#?NiHNSU~VQ&j22x7K`0| zV2R$D$+-RSw91f&saw7=a%9ikHWXpN5M{!Kv$IxszvH(l>kfNb3|n4omEC6VuGX#1 zH5Zq~O=4ke!WsQdiEfPvVNRb{rhx;#x^Tn%PB396g5h z6t+3~uWyt6zrTZ(2MmgIT}SjOC7WI`Oq~20&V^_K3q~taHg`TGtpFhXHaR)h1ZSU& zuo3q@Fg~4oi;42FhG2;c_<6l3V#RE8t&^dk1Y|1UZRQ>9zuF8(Yp0*wVm9QL-#$ytk$)!?dF)@f+qU0 zr&jQCJAF^Geq0dEkD5A7l8TyudH3nfgLR@t?&u(1`WHpeemv4dn=|_-`N`^u&q}XR z?TW)Qd)F2aBWip3lWb}DY!4CdV4o!|^{x6Y8!C6Haxqr*z?76NONBf$MR4LiJTvc0 zxgn%jPx)RCTHtXf`l$F$u|{d3%8KFXtAntl&)E9Be<8@1tlML`eDfGaH+LON%N~uw z)W{AqnP}}j3jyvvh9>9Cm<)UqIqglA#Z9!p22qtlPNfrGw|zPSGldpLV8Z0doF`*Sz z8T}}Gi!`}QG`SglH!cdJzOVMVBxB=sJHdkw47uA%Jbic#bf_3%xq=WXXBO-yPC{XD zBCOJZYU~ul(Rl6O<}X-`HNFl)G@OJ)f1~Hxk4nXBgH5`4o!?q##Ik;JG}7LphNR^$ zLLpVJ3}_ar+-~M#eytZW|N7eiMZb{E8PU1u1-t)dv|W!NKJqmBgeJ&cLb4m}dD{Oh zw##?pC-g#sp{cIxG4P1f*e%q03R&Q0b-JLe$bId|XWpVsjnWEh`-UjG(ZMFo4goKx zuk9h(J5sk|1)V?=9c}VBAs`y(x4b{0o5VIgnRftNIYBD4&q?WgKqYa8o!<9WpUz@< zk)TGqau>!%nJ@&M{S|t4?kPH8C{Gvh;=9=1izOOlKW}czw<2RUaqPU*=|#m1nh5Km zr~851h$Hb{4hw~Snk90{E{CkI<&+pY@|JqN_uD4_+aqfpf*oy}HOEEWRQOZcEN2b_ zB>lN!>9YD`2S=?>oXIv`t;62O21d8hfVs&bcayN@Qf8Rl5BH0HFS30)v5b!thtohV z(5ims`02Mw=o{J!+KV#EMy(Nx!U$?ld|KDj@3L^ARSau*%L4 zXR!>lkL+1EMI!*F5s_LCxAJQ@?;ihW+@1E^YWV=^1G>kd4GVhYmZOjFt}F3l4iiJ( zTtEA9?;1!Voll~KA~>luiB}R9!r6DH`U;w?CxR-xu^#p>q_Wrd#ibqa1C8eLUYNTl zF_VBxIo^AKBhzU%m;TGS=$y8lWxkJFx=!9Pk%f)P#*DLOrI(gs{^1stzCMhV_p)su zIf?$7u>@N!)H}+(49~CDE#3s7@+jf_QvvOfcX4sEn&uwGsr;xUwYeV5dKlE8$F@7q z{#kKoa{ExCZL>&vzhHo^VdenYvJJ*dXEemVlKH};uV+ZgYJ;ISGxOwg3x@7*=3m4S zHdW^K-R_lzfA3Cfkikl-HlR8J4sK|EtPTSV3ENJxA>kKLF9#(*08r`>i={Pzgw7#Q z?ID(Pap=ztyj5Qf=GvJp=K}=JjV6Pff0Tp3Q1~T3fRah5LdCMKT(CAtue74Jqc4G= znMe>Y3y0Bd^~(Jdp*KnHJMIEy3m1%@Jk=V!)4yN!!UAt8<6%5Q84bPsDkJSNtvRHq z2$@MDwa0Lf|HOOuYMt*bh~ZAT5@ezN=A{roeyF)8h6J;?L55gk@CuNTn} z*s~k&Wi9ht9Xc;}#J?fcuTg1mX(krQj`oeQNeq^f`=oX;P#IG zL1b4l5mM%aEXqIpBGln-ojZ?1w0}*5K1xMj{%fOs&`wBr*MVETbbnHal(Bv{%Cma2 z)?HJj=;PY+*jA$M1d&N)2Y(a7nU*BMU-qPW z=@l{AtKQzPDcK2P8-`rh-z`#=2xE>_@|a&qw~5a=xR5T%Flqu8(>&01w{&CXPa=lO zgTYVyn{BeBt-Xxj8BnAK;VC3Dat0G)M;D!KTLeZ>0DM{g6Imqj)nML4VE;lbS!jKH zmohek)%qJ8pN&M`GhCkY%|K?=rhE&yRTv7}Bfcm~DQp^1Byc$Feo*$1UgNTFmachd z(3dg?ZYdhK8p#BvzTpa_JjmQEf)uOwm<c?hCg%p{TdTdYh`nLw!tq+1=N<&V&~kaNx>x9xlQM$!^$_gY?NN#lW=km! zs8k^SW}FE=;k_Dk~-%fAMEl3;X#+@I!JVT+m6r6V}~j%c$rcnIcXq!4?QH{=#*qSpD2MjC1> z@5oh8-rGr_zJYu@L^5Iise}wXc?C%hx!CT}%h?7IR8rEc>&BN#r zsd_Z%iIe4qJ6~=&y^BQVMWV-a5K4pZ{L-}-l!y}QXmo+O)C8|(acFsO|IP}K!Cn_C zXQ0H)cP+4;9UcmLH*-Tdr6DV)a|`)H^8uYBZ{apYL4BmmD=gUfL7ULStOQBS9D_YD z#UiEy2FHk~F|M@dL0UWC@av6vkXV(iC~i%&mak$)sgO9+qXhq94NZT_@;^^Ns4nqE-&m%jFS|~@z}fR zIKA_SJWL4laU!USoJQB8A(r=!FS!I(8OwvXIGn?{-5A0cCo9`<(DLg99));-=qv9O zKsQY7nwq{DS<_+96#$MFMz!4MX7)G15&a&KPYf#pU5_p#7gWKSa&ZTaPMc2pK`J!; zp~PbE%JtQd*I1#|VwQzW6-b3xgGO$NioPJ|6$>`phev#tStUyss+4iz#vI=B6>$Q0 zjnXzI2;~f#%hZ9}Sl-VpL^=M-+OXGI8cHIBJ`6RLF1=?iYxP$n()^BGeqj-~* zuel1w#Ck}wIyF6(o0e0>zqWd!=S*?xpE6Vhh#YrcUcGA>`5{a`&qq<6ic6z`i1;lI zWA7z`Cc0>%F&Ejv0gC{_%?8qO8Vac)8m}V^-fYPeD)Wfp<>KLCoJl`x#81MNiDL!@ z`c@-ZXp>GWJ&xOQK?lGYm<5+&HFztpdYy`sc98$sjUx4C zJQJ>e4=pmGw!g#^p^CmwvD#XI8I!AZgf1j6Zo(aZ(J-`vhd1mi&KbU7_JW_z zpm$A^ouQ-uz@0V_KR?fWTv_GhDZZ}MO9T%WZ792(lyNMT;!X^zCkvZY9MrpI6JC9q z$9`oK%4N6J%r}Au$zV-M%1<#%CJ=NXVz9R$3H`b6>3#Nd+um>xgnA{3Gm0LSZV(ww zFDv37NCzA6kPXH8?B)C*s09~GuDB(w+jKZl*P>bR zz!ZZO=3mmz|IF23C`5neP2%K^fC#fkP=0uRaUXU*@(j;Bj*@g+ha6BFNSw7)5U~s3 zLsBRkf@g`^1&q9Z-&^))88JP1@A)}^&KYLzslru%{IXH=mj9gwD6+&9SeWPnAzOoo zG!Ix>RjD4_u3%hU9;gFvW|LGmFHRkh5L6b^B#g_GUYf|Bk815MQpC zytdd`{YCdfkh}#l7M=A+%?w0R0htEyjtghmFU0Jy2tpVZ5jRyNeXXO)$Ew1p97h4e zwBH&tQM_WDR`x~um1kmJ=}xIFOgjeQ*j#8fee;Oztk!G_Zb=IECxRT6UuPm*1(Lgn zZXNz))?OHicP)9=ztPe74D|ar6%W0{dd=G({lDLX^wDitlHNOdreC=}hRrWipx=<5 zhRqcgn9 ze?Qpz`Yn$AW3FIy?aQjxN9SseSQbHu>7=O}Ee5!a+V_`tYV$h@kwbpNi!=%!1;yEQD59l#onrId6 zKX(KYKYY^gf|LIM|D3mi(c-4V>5(avW5xGJ!6JXd*OWEMpvHhEH)A4S)WUw|Wj?DY z9zTd^sU#*E;vY71la@P%5aI&M++|LESl%ey6YF+Z^-y+zGG+_}-{izJyeCTPlk*ny z*-L4BKKqAVCASyLsc{!uTuJafdUt3a`xT84^_=7I#H6>jT6d(pmiaA3?@%NrLhQSB z2DtazQp5&G%yg<$g#I^bB%R`G!`&0SokY!KOVPz3Y`}!$Acx=R&z48m{vth<{NR=7 z^7DHj!nxFId#< zkP9pkwm~y-a6#KFHXQSt_e{PRKYf45hOoBH`f0g^O}f8|u(Qp=dpq^wSHf~@>Yy19 zNIdg}I$3bZkYS*Shaaw+@Fp_z7b0+QmJnCeHMQri4Bc3wDx*cC$5A4idssgfG&mZD z^?vWDFLK3{H9S2(HBk4|Dfr3jigq8_NR9UCalvDp*eM>Q39OCt*Q3V+m=YN$8$$Hs z5j*1c{^9?Jpn6nzpb)Du|LCCc=M3le_w05D`_8Vjsh3I&yULis;RRA*`yek9cwTu~ z>HQx>ZSrE$&;^_BOn!R-gwN{R`1h?RhX#?q?WT; zk60@a&0OdbJI3Fcjg2L_YBB<#ALW4n9D`lB%LJBR$TI?-D{Ze<9Zlm z3jeWPBopTHe{(wL_S-mz!C{qe$MWnd8C=Y`N$_v9uC?ji{#15&;X#-0whW|_d1r?*$LmIZj!$?1xDqGd`EB%*Gx7IS}USt^;7 z$+bsFyjF?3&nRTeNsX93o8rRHQGc`^dn5) zd-+p`?TX(^N;5oUDW^Se_Ee(irAf^|@Fhl*Ps}EF>UX2qrnVV?e>H>XWWPq--lkO! z-zA1?FZK+Hh+~^ByA}0le=k&TkGYY&C z0~R!_Hj46D+WbUhWJ95~c4|2`)z5PPO4W7^rQ`kPds=l|c|?k#Ip@n13%Dt~}4b zyOi!H#l_(}Hxz=j-BxD47_@;wB@co3b}i8xVYEQT>+}mLGLpdC2Z229HF?heLlrZT zkC$r;RXlKyI2Rj<8-KAsLkp$`4#)5=mr;ioCH*j|r)Ttmu@S@dP!orB1C0S^ZWDUm zVUE9v)fYp&Kh+8SSnxgQ7nilX6e+W4NLiV;^#$DUI+eCzPw;o$BLs+>>PAI)85ZW| zOYaR~{FEOcHJ#T*JrtZ~Il;Gy1Z)}luSB_X~tfW-N?5K(vE&HMmbID=h|I@$eXY6yYd*%SG_iM5EdSEB!>G~~eHLt@#cfinvkwQZjN#7LKZO{J z`NAASTt`Vss7@ep+z#N;Gd%qJd#bf`0y)8ET|pm8{<_G<%?|i-8F?O(KWN$$Z(@-g zBA~&L6`t6Nn~2lb^UWui7j1k6`PnoeQZCI#vHdwVU($fWdbiz!Sfl}eo5mPK;o&5= zsDnt4rc@*4$rE2Jz|VWvsVWuQ2$JDpqp#*-1w!dpS(-=b%};u#fUfW=U`&{3rJo11 z`NuuvVa?RO$L3(&p8n^P2NlIA4`gxZ?fe#CAIm%bk{0U&>5wrcAz;)Pi&VP^Kep$P zR-&X3i_Grh7!B7^%(W&bb~*+LUm|?S{QfPl2#5$k&o=qxdOYAQ#BNW0Bl*~Mf-7Kp z<|L6~uTEOmU~vAl`({O(@oyQ9l8^Sefw*TnEfjaLfM8U3W4s9`tJU6h|NXRk zG4d8=H&FoB1_$-sf}hfTikO=h)aS366Mwf8wUn`r0_|G`HA1~ZpdISCYGe4`*gxEX zY>e92Rw}Ru2LJav`L+S!40!PZH25^jhGQxTS=HOBKw+;KxAQ!EPo+T_N7c^_=p`qc z20?6lFq;RIPMM$t%jamZH}W~7^oe7dEvjzHqFG49(UA4Nl~iolSp2!p{l@#zMS$3< zfUV|h97QC_%{^IG0o6-dIV1+VWGwOQGQ~q;U{gWzm>*~3fhwnE`9j}aons~EK#x}U zZAQ|vS>M(`Jx&=M@BWa1i)N$y;Fy1e4?z$UWs*-Gm{^=zn}G4BcD{PR49ok<;_qs0 z{>F*KoW>WyS=+b2>rO`ouPI)>$##L%hk=J8+XP{2N{PK*;J3|>_!t9GarGMea|~|) zJKGDpWZU!Iyyf+-Ygo)uS~GwG+^`)-sI>~#Tqn#gZLC5 zl9KSZ4)YbRaM**OzkU#Oa~)Q2Y)yp3s=)wL$G=!BM3=ky=!oX6zYWS*n8Gw_?|+`* z4B=gfylAY&A#cw&KgcooSx9fuMcav;@2sfqAb62t4D0JlQZ;|TwUe9q3V(_YPuAhm z-$dGzsE$*F#F}~FyWa$Cql!zbo+g=W_QP_kL^j1aurod93PbW)6L~ zX|CRpzPvgi-_+MygzOI8$9=nCybZM_6P;04WYs0rlU2yU(aNfIN+d&A7(8Wz)TLp% z)U@nsK==nMq5#h+F?L^j_4iJ;e@p4;_1H(OX{FM8f*$h-pR6+ZP&FQS@t5D;#63Nd zSgIa>`>nbfXiPtr4@LSsHcy8PC(RHz^+(Jynt)*cHq7qjg_>H!eFlbbe_h#o>9iY^ z81U@oDi1F9t{P_JJZ6G>+fI=;dUKI*%TD3@Yeay9QWl$|>&Wv%Kp>316da5L%v_B% zEdDj=xCAQ)LM<4frYD?7CuA^n9^$SiSuM9t-%aWe-CP}x*8XuXcAoaPe7DnSBr76g zAvekCgGWI#zMp^ zlS2Fips$#AE8e4XeB3gVE`g#6@f{R7X>J)bph!lSXM~lm5L<#dkM6{<`%(6dBio~u42?i@?zzL|x66r*zAK^L zdR@=2GjDy~)9 zGbZ#h)^>r~{`nTpPCqwMTZFnm0!QR&l6#4kNc}A5Cd}ud?|SbcP0>oTfsXY@?-w;P zzrpaG<*l^(w<3gUaqt0@R-@A;`ilc*C!h?lL2aqSJBfWe0zXwyW9iFkiXbus{wGmz zuS;@>I8tH-T8_dguBZZygrF9C8diJIRLu_dep)kby0w$TUo{1S8F)cu$h`FW{Yg| z(TF_?0fdL{Sxq($K9O3Qg&VyzH;+11?7M%voFOvQ@_ei^L0;%}N%$>B# zv9yl3B+Cu1;PGB2(ya`CdIK*Mp~5hZVFtJO969p(948l1!6j2IMhVS5Me4&gZ}=vw z$2_c1(z)&tu-hivcBL=i)Ikm3wReh=f!#G2!U~Qh$Vz^hJXA)h#*vUur$D-l6;|j! zbSU-_N>55%z?CjqfbDNOY|`HtSb_DjRe@P{5x??&4CzFx9~MPu(`4oc^N<`ujj?DA zwH}052VQ|O{sCuFt2oH7M`R>qI`+AgFiP3#wfu;FvBzizo5urQkoBS+a`UF5)Tz;6DGmi^;^Oc9@I#vzjtco|{%3yB@B5Szfk*srS#}~xyJjjd5h^KvU=m@hhPQLGI4>T$ zn?dyt1AISxL%9HbNx0C?mUb{44gQbRa~rBp#kAGL=FHz@aLYD_0xVJ71J&Ul66#=h zEGu<{3ONZE;ARVm4^ERP-rPf|?R)tuZY3p{gFgvu4X0eM`0OGI+5X@}z)1%q^#~eMYUjpbx2xXL;<*F`4Ok z=8vJ!>AJ?@c1Cv_-H}@BMXvDmh(4qGKY|fh zTG!i+efvi{U_`vq%)zT;8YTy@Kz$c6cEGFR^VgstIkk}qR{tSVZCSByJ{saXEsb6> zA8&F+w9M>8^+u>ZJLazPXnL}hX8$1OnDI!9J#f*%H>)9~kUPS9%1>3i)iI+F9!0f8 zbpAdJyM?A(*ZT;B#9yzphV%`IIMZevT!)gH;3P{9(rH*bW6p;hray5&xZ9mja#D1_GenDA8V?MK~Ok5EI(Tn>T))uX<`1fmx> zNZECFgp}`Eof-`@QJFIk+L(?Ebb*|b7P4SdWWTUP=ux_v#2Aw8U3-l90kp(h(~R9d zOkGfe>c64tNn#Q-N=GR8A4lWgz4p5NB^WRB2i!P%gZ{F0226WI`bQC%s>{zk^lEA| z<(!?H1s>!DDMo<5A^$+-JdB{?B^CEo;74Go?!zf$F*V=E3H?5mE02Eq2x$Ek?-J== z;I>U4!{mSh_p^6IydI-{1bBi>`HxP^ixpPM=8ryKxk5|8mgd6G=YYKA_ExJ-1#%{p z?qY3LTPQK{Xq9-X2)o@lEV80_^svPo+{2&M2^-|A*RmLYE zU`+S1rV>}JjIY@B{_5D7*r^MrBM8nZD3!ADmI;eFK37$0kEs@F4_u~165O+IH@=RaVDk$f1T-pkIM?{cK~1fA-XLn*I583B z_^wDTW6#ov^pEPufxAiubnz+v$k!E$LS(~$C&B2i*|ZPNrGyNFfnoOaUgybWFwc^L zbZN+r^;a(FzSuCq%J{qib{R3gZLK@JTmqT=0+pAJJ2q83YlHf-&=#bgf^x~o)7HwD z(PwMh0#d0OMTXtU@bkBRqh3UQK*s~IAXf{9BV~QiXD(TVc%uQI@xs>pWK%DmwJe)W z2>vx#;A)}lv63d-Yk&pV5{UQgmm&J^;FcNKTYix#>laOnJoH)FJTCr7aV4)tS$#63 z1UF;cirOT9pzzF3eNt+86NK>x$j5RaB#Xcxt76E0Mk%0_Coz?}8{)pCP>G$n3>_%) zjw%ZEiqpXn=Zl^ckc22HX;zM0t_L3{35lOqgplZ=3^ zq7OhyKRHtE0$X3Kir-Rc7JkgP56>I<*C-QP8N=kfBG&Fsay*%HJJT~9YLf6PMZdb6 z1hIZj7fL0IeD|=s{sQ#2-&;;`<*3;>Oo1s}7%65}|9t1+=VADd4sr&}El(U*!XK~i z2KRWhwiIeER6`;@+OG=OT0HN0+8%HiKHc-^(*eRUtX|6HM+?d+t zLwcWM)iHV;L+sKjJw8=|5394;X_UcBHpHL^n^63CaH4g#5pT)_i{s=Y%0F8;ri3te zQ;@=!T4{&!SV%OG%;qJ-jW5e4q9Pq4y0Hjn$=)%{I<%B^vEC!O1fvDpF{Kba3L1zTz;s#3 zhIe@~1eKrIg68#7$}Uwf7~a?^{;nt(binth(J>-Y?^vfN$9I!n& zN?d8H@uZ&|+i9A`UUi8^Qfhv38g4#+Xj?LhUrOldJJZ}WgvERxIRD@o!>_lb_NHbY zkOQb(c~R1!UoYFh6w9dIg!_(oCUmD)I9Ng{yDg*ETwAegsHQXD=&>=h3}0H(*r9Ht z2=OMt56i#til-aZJ!rgtFwXJJ&+x_o*aoo~jZ<1G-g;kz@9GNzA)4``uCRRsHK;~y z9yhz3s(>d4x#B-?WK61+ZOr&NX+(n(kDqMcf_grr)&R{Zuy^>+lix0{xUY; zc>t_TvtQBXQVIvdIL}BbWy@MCu!!4W=7@@BU{`zRIG^L?_60XIH2C0VETsoum3nc}os?&WAa+`SQ=YU4{(!&mFtR5sI{uYf* z=Hh^(W~A3qTMM#BEqbz3Vz>S0ZP~oXNwU;&fLSs8Sk(s;5vZCpPUrJ^b1@j;cgPv?BeNAdfOoDm*Ci`DeYG-f<3bf>R z-F^cU9JCb6bW@2SS7$D$*>%<2Y)uR$mihbG+xh!o-4$#4g1Iq#;VZFw6SsMKuW4ln zp#~dV!17?q_UefRV#i4MMSo=(l20Y(OtB!KOr?}T&j~J(vyBG14?-{7tZjDBraRwj zKgzhP^dL6%)tSML@f3FiPjA}4HC>{&?qG>H*=$~5$JCI0_|s*MXy9qRs&i>$i)dKw zX1|Bt)Q*!#wmH?9BJE0w$BiP^Rp4uyLJZyI?kO>8FwFl(o7bvB;)K_!*gcPWH3>fX zwq9Wa#UGLo&z#!A*PQrGb=K4o2Or*O2Z{ey7_)}TAG_VX6Qv7G6Ufx;V1X~vg=9Fz zWdC(d*$a6Y-E+A?s8^=JGcRW$&lyEz|dKiRYQ$26J&x*JsmRYe?@Q z&^@37?e4b1yk!lj^YDTBwE@@exiZ$(N!hT{rKUf}2)Xgw=J;citl_%rD+>QHsCH-Q zPTn4|3F!IKhTrzr*d1^KYO&SP9zdxF_Z--OoUkKaCDk`!-dGOu+fRMWvV*pHN5kL{G;@RowTwS(@fcr-i>KcSPQ-}2LJD4jklq)JI!JG z3+-s=W!jc-)lk34VM4u+^G@GSp%v+ZtA2IGB&N6SZvGF>1{`Oe#RS&uW=>^W#3}Ku1fzrXs)?eb2G6eEKCx7%SaPjjBX4QrZTwS4UFM5E}ek)t)ctrl} zAsJx+g@Ni9VYfVbr!YYV;cV47`=DwPpg(pDqIQ7<)-y=C;2Cu6-&!(R^y58%@HEvx zF+VP84Pp?qGM;*(0ier=l(7N>auwml@g zKEfEE+td|JFrhol0kb^kB$CfED$Z}n?*W(D3<2WyX%Gj|AcvSp5Hlp&Sv^St{bvs} z&fRqa7$<$r1Q^KR3s2)vc}fs4*`wIMP-9Q>$h=;RT@3n~Mi2!^oZa4B9DFZ8ij7a% z94P)ZPsvXM;R6$_P4Hb%n{xOE+-FZHh5dT~{y0NrB&eRE3w#em>Goh2vO@>}G1Hr+ zf%Sp7<{Hh&zB&$~feheKKs$8dI*fZDdeq5i5c6FQCTIr^17r{dqoKbCst%YA204hq zgA6pF(m?|t?34y{$j<-^_&Pu@DBW=g^Rp*~^s{Fy8WC&&q`-CbMel=j-UFgQ%(o!Q z&mIH1&mO*)+Gh}(r_Mg;OVlCI|HOTx{_NSB**@F_jRdTSr(v}Wfo8gGV*YE`m#hK( zpeM|h7n*mF>b3UQ?EY)$&z*jd#zu=70;mV9NaGpQFSG};k=r04dIx1yYTbg&WIMj} z_a5-SIsGpptfwE8j@yn(@eKMV*YWlIANg-VjGsM&|4n=dek~98WApqQkV>xg0I2Oh zAAQ-$Ck)7-!xj0u52TPy2-!9WQux1Nd`bL&ptpSu-1&FIxfue=Urwff4;cDyo-+Rr z;vdMYxqTm$4fxU^gdHTwdw|*=U+W%-3wQtrGWdGy*b0mUIqdoB5Pk-@7fhlAKKEd+ zx6SW?EJ`PXLG@9SR3x80lQrg=f8QT*pFyyCn|mOc&mLJ*EZ~=dnu3kWUv$iGKuyYD zYkwuy_dlu<7k&>I(`sp`1Uv%2_PluCp#S`eFGjaDs+zPdeZSAYR_KdXal;mM4dP}O zOdu%#8=DN^8H9DhfE$Ea@eDd6Y=G_sJymT%e)hn8nO^OB;>{oWchIJgq$bJU57>85 zFs6;dqQDU-=8M&O6(Z(!S3gJrL>>xBXP?pwaxhT43}uS|9D%B%C&>(-K~&RQUl!<( z@(h~iYncDn3&JLTKmr-;gT6Eu1*-po{{KLH>C?SI7Z$YRvIhd2D+r?NsP&U)f-3$W zB%OCWmH+$4@3W76?9H+FjEr!OEixmrg^=vZ3b&EHM}%@hXrioAIbHYGk=Tk)&KG`^%^PDffc|pQA3(bUjw~K6)w5 z(g|UA=8r)ooD*)fAvsc?@2({9A9Qa1yBLs!eDD=kF2r!=g@+}Qnf2NppLY&h<#+;P z?26>73-A$`8q!ap{DO;D=&1gS)p>pmD5C=7wLiBxqcTfz+xaop6hlE*%O{uD1U&8IdxnG0bHEjmY=^x`PHuL1jff&T6y!Nnx%A z_;ZFqr-$(j-_cp;`GPqfVg^OvoAgqzuH%KpC zKPI{TbKZ*F9~B^rOH&-V&~wmU{oG7!Ha>1V8TLp_oEgd~NtA&Q`CDL_+evjoniy|t zarUDS(ky!z7RvJ_J^&uejjnO$`CMiKM&W|TvILKxsl^QV#3~6T(!{xF_e#~V!XR!? zJlq|Zt6L^LNx4?^D{Rl!PXYh0cg|I(5S;5-8E!s^*9K>F{1t zqz7L(nu$%vyc4*4)9xpiT^fXi6Qd!2h6+9W$w_u`iy34*>()N&o#jz{FE-+A0g1SR zon`3aj-3%C-2<9%EmwPdj5UwI<8cvm&1ZU+%W=%A$0*-QmM7bSTzov)NwEyH*-wjR zhFFPYmw)760j>;KTv96ij9Hus#%)>W`8!C^^}sId0QjEx3qStr5V4?%oAdtVhvAji zO6ic>eItPR!qD;nV#9*w3tVvB2R`5-@?veZ=t;?#rGr$v& zf0#AsXb%nTiI+NRz1I$?Pt9#lwy!f|u0v6GT(lLs2!0F1EtX0yBlaRnhKlP7MPNLj z`QSOXsp}o89PMc}SGdxqaoij*cblc=*_$&pMEln0v96v}i201N;PY4RN#++{9+{ z44=j51KB_2Iw|gJ6j=#X<$79d8cBs+ULw9nU4TQB4nv>4qg@mBEH5~ZNUeuLQo&J~1Vm-X0Ba|`1= zMkBv)8nr?3`yCv705@!lMKWV_pA$7Tyj$tS`yujYPj{a9-lw$aMN16vHy>-(P~S1X zfx?!8Aq<;E42cD_7S&iMPzh*gGiMKU9T5|T9ac}h?poXd;1K|m52iG6Y=-h|8bY>+$<%m@n>0lU zG(48_;sPm_m^}Q8P{@7P814?uw+|^FU~<)f>4SC1PGI{Nh9Ga)aqoS>m`$_DYvY8% z;{b9<9E#6oS5f|t(y}X!Nd@{pH^M_jOt91@pV3y$o;MoU1%Qnm&o63xv)5tvEW&T# zFuK7ne5|k#Sx|LWdy8i1NGLYi^*vu8O$#83@BC_AmjcaEsEd!&ZC!kLxZNU`z*a>* z<+u3$iTORnX^wp*pH#&9g?3EiZ(NQSAtII#&vzJHndlq;f3>&Cu!S145tUog;68klveWSDZTJFt5DL8 zE#8z)H2X4EIS!-;z|zA8USR$qZuS_*%fms?kAV!yYKO9QZWD!RuZUsOTj#j%#MOp1 zl>J;RxdasmwC9rJSf@_6MT?3;KI$E9SR29@yW~1z#ec>K`a;}Hh*;X3xKPF?!UCt7 zw97L07Ws`Qez$!fXT4!D7Frmc_u9F zmgF*m1uDd{xdT#q7AZk%{CY&ZvaBumgcY9-Nf6$Aj&5;lVkh&?fC+srf@c$+@c8#d zyV&VgosJ=Bg6Pij$v@E5bNd`6)F(6?HVVI?n1~8 z5i0Bm#k7RqOEC+p{8-BSSGYKGwKb7O7q6YP!G&>)>omotC!LCUVVVDN2JKEH`C*@N zB&hXP1Yr-w09&f;`F8hi*|VNtmzLQq``sRa5xk^=-DYnB_8y*>`Hl)iVR(XKWxI`g zKj^+$E1&}VajC;?PS>{iT>nYD|Mp=sk zOZi-O`Ryd1J*mZiPctsYgj>XLnPptZyKXBJ4$xPqpkYFj?OIXT5la25Hqtgqj;w@) zkMyAZfnR>vD?-2q4DOCS{;;3dI~G8$j(FfpQDcu4Q@m>_Uz-CSYY}Fld}0cpt6>Z< z;%74I(dU#H4CfGCO$_tPVus}{sJ~+w)Cb764I6U4HWccn`G*njjGlSOIUWCZ8a4SV zww`90`rdKY^Kr^Jj>62a&i(Cffr18MyV|u>9p4F&A$M9kkUz8@o8^I5Hq6(tb#6$1 zs(EGl8WD&+hF03BnVw7=)+QNsyg24Ws^O%g!W(N4w3LVg#}5|E)L$cJ%E}I56pIe( z=!@|iXnrX!;s2c%zEwGNrjFdfZ}SQCxk)mxga-~>Rtc~Q=8xW z*JHenT21MUbVoyhMSc<=)pRMe8;Fl=V;Y-}{_u{n$;<+#i_Rjj@d#WIDW8_(A1m#m zkX2|s?)Y!O{S))|d|*EEFX*7=eGf@wY|k$T(*XOs8$Cv_EDeT~)+YxbYN49y3M4cD zpU;XGf<3cHT7(AHGT+~yKijwgtnvhwB`Oc!+L(|h*RKP8LNmcX|W>ui`l)vE& zp}V3KuRPq@o8a9HI}5}5wE*&uCCTh6Ep1|(K&tWLBai0$uT1`Oik|18A8kTc0VWb0=Oz_Ww0r+FaS2RXmLe<0`Ljb}eXoOzK zgwRv(#W)W6?(;*q?LfzpH0nE_A-yGs(+VV1A3zcnCs2-J9~{1e4_8^e zh|QxR#Ks1SfmXEto#e&eBj*mC1=|9*dBqQq9rQ)x4uKlGPfwpE?~y-z;s001peh{^ zKM{Y;Fm7QUHfs_0zTc(_IVN@FP)`nEBY2&5FCvnkBs9iIkoe-4V3=nxQXZVlJci3e zXh_M^(^tcJ8u1G>VGY2u@027C8xaBzken0)U=c}gV*93_+NQ*6h?`=vc_{_2a6d$2 zX2ype6Y<8Gj@U}+Jn+dy*JIRtuM=g+)InB0Bn}V0>3&!^`n}oJLA< zhlj%ff((S&y`J;v6I1#a;tt|)5hUQTvpSWkqj~WDGaPxFKO9Z?j`uJlu<})1vY6>ag65uvd!yB5BY7~j~5t-_Jv|0{j)TlrFF8DVI{B+0d zEC;$PzNt98h+BC1!*}?I=9U6l^kIloS(y7w`x#OqKgxtPoq=Ikp|5|1P>?=Y&cJdH;UqYT?_=j&fk{>g2lzXIWC*Xcw;;xVIG~J5qa26>u&E1PMDhNM-0k z3FZD6PF5GfbMKEaDWnBh$tLmA8zq61t^JtZhF^yz)X9w%$_On4-)D7I0y`sz9!vsh z)CPruLu5b~kO;gNw~S{DaPOGsDq!#xHKx1RGxfZ%-0u(Y5 zw{jqw8~pj_sAU)8&&MAa^%T%%KCo`Jz`Zfx-1JFKFQW(0#8zE;Yy))5m3mKBwvLaQ zh{x^}k$J1n%vkWp5+5!^z)W~xo*H;5ngsnsO12pj;rQS#H@PR~aL^I<0*8^6#S$hp z$?>E%`oBZ&ODL7or4#eUU|0-qcWI>(W^BVeFBbw7< zp$xwzH#`FIk=>?*@{;_cA0(qcj)tf}Q>3!*gW|N=jLE^5NR|70bNg4TDdYOkoL!*E zRX7W7>lG{QmU{$KyM7>o+iqPyDl|b>qUKSrTA^@jfRPinY_9ooz3e_GhF=Oh8J`4T zPNCJb+cB7bbifD593%lw4WAD2CmISBT`~v9sIWZ4l!a}|?i_`IfM3wujnj~TY+WE- zM}Mq_us}Pf{mTd%l+~kX!@#L0Eog!s!gK+in1uMQB8oSaf+R>&!jCB#XBsk5Syy1< z1%RXQWH|hVAH6V%|92qHA&SW&YiJI2t)DSkntFi_b89ME`#rR#y~~RmS{~h=JB-R) zgi=8gu5$q4xTK_wz4^o1H6^WZL^mrw4kd324GANh3Vo40p7?nTad*`UzT~<{J-G&! zee*bAAP|-yBaJwnn32jQ56+6cOObB1Hj)T4!(tB{(f~X&nuLjzseLF|=R~ zaCOHM%RGrEjCI;<)Ne0XFtkAAoAF18s9hC$Q^+#E8kNKc+L|`#dkMT)-M^TRFA&S? z%<0h-~){CQQ1iOdg7tX$20b}V-q^Xvv!kM33}+X2cA_ly8^Otn+2P2 z>~(>26IsKtc@c5Z5wu{fk(!-1XR-O&bKJKPNjLl)L|Y`#0Q2dDJr-m!s`51y{Ph|g z_*Vw&f&ed*TCjnsV&o7@ma`52Ba{$}5uBP{ni`&>9cxUL?Kpr0M=3?yDr*uLx;yN8 z9@I7ZaQjV;-O=y$#M6guS!cr)+uXe zh;O>cvXYkl3ZntzSD;qesPv-|PXLio3|pg2SW`6r(i$RV3cgI+lBkYKOvdgBog!HYG6Dk%d%`#~A= zRyeG zWmrLFY90z~UYB+8^JNR^^X~llxQnb#u1MITF0?@avgHkvub4b4DkVZrsQqY+$51uT zfe6@BiGsEyp#jugCVpZwMiOX823kNqa=RAhljBj_3?J%={a1yom_QpW7nxGz47Zn*cgSukZdLZv5p7$bdj;8_kb22M!cprxs6F}6}L+T z^36SHkN~aW_gsmiBE<9a7|{?&Ixok_BE^ISIPXh%cRolh3i^x3pPH9LQe~kYbk7yg z)q?Udh$w1^vgQ)b3QbR3X9J#$gVnl$+TpK=B8X%z*F2CCA9Eb4E{kmz_zVlwf}m|I zWEg7<)?$L8^4d^rG@5kD0~JUeo2*K@0AF6&V_*yfKlCOFiel$I>ufc%DWDR|-bQ>L z&Kd*ROlmSERCw|8anvRo`6A16Sqsz5rjXkkuh z=4}~7SyMHBk4dS5x@rQI%Wy4$5flLq(~INC4oz4;%ef{^&dDNCSSCRQy$%W#v;b{9 zi840<_iRxZcG<<7)^65fA^-6;V(whpf*p76U+ zUhv8z5esSFRP<}88VLx)AlMdQ3;brlN5ebiieKWds(?9Yg4rV%<{aF%QMo?5At64F0ey5NxOkxN9UkBfOLhn{m_GZ0Cj>&Oj>96(c#KC$_82(n$X} zAc|rdLzB++=mNfq#wdA2UlNGe4$aL+%x4f8uQXBJ{|yT~V+L<)pOq0PRZx2QKgmk) zm|%EqzXu9=hAi{SE8850Qa?KF`N#<%b%~FK+NiU)Vu>p)+?%0@iYmEN z+)Ta@4JYQAA--ffn_OgP4V^rooIu5omyDL6m&+j60wKx#pe^UY#yS&t>;nWF-ebUz z!C8!e1!H^i_}qU$SXQbuo{e8VQF{ed6b=wFi0u{6HNu`F`)zLregHU z*J}b`ueyha8VXaYshx|Ox>ujq`d5W+sd zmhfO(EDWof63KEswi*W>p$G;t0CNgM%Uqkn6IeN3Jq)6e3T`qJMchm%i~$ERnk!k~ zB;~uR!Edn57@H(X{LUdx2M?{(=1Rs_I0GoUmMMc(N{TCxM+F36p|^GB)4S5y8y?+I?ft7zF4rFx5`PjQ)*M{Jjdua9$~;M1v1f%no!CfY(OX zi9b=3wLI80;B1%%F!HCc3$YN``s8B$XTcgKys!%xR80Pt9WS`j3P?VN1dAdpB9Z~? za0~FBumy?!JdOoWV9d@|1fT#K{Ki7%47Gd2;GKm5 zZEp;ij0OkGgd~K4MO57lRwCl=FkE;PV)PZ+kf(=KJ)}BJxJ*v^U;*|1L{2&pfQ$*V zA}U#sEisTKZy=Muhmvj1gSQzm23`wVBtV!sT#qLy??s>%5&+*Gm_UADREIrS;Q3HHE#erXkxxBHLjJWR zQo*o1dPsC4kn8{;o@u(0#bEw=5F;L-zTOx#lE$yP5|=KAGaRnK7F+@PN;=GyAiQ2a zA4Ab^MOns#^{IL3ejn@`Xdv#z`Tc)aIraJH&%?{l-vQwH zGxhn-raGAH9QAPY=C9DFQ>V9zn1JH+#f7`^zcTeT029{YsmkO?Q?3b9KZPN0s~}cV z;kxJg34>HB1B?NfAc&1+-EeZ0OKwzL3)jWu>cXP(*+Y57;}&`U`Td42HbN>EP~umj z$RYi0KeN7aKY4r1Q0`@$ld)8{kw6vckT$?T!J&@#Ie|)f9wXUb8mhGM?$0WcTGd_b zBc7Uny|Fh1lfnFsw9iEazDaIChCylg*B7hT=P_bcF13*aE>GHo?`}1P@@^)IHi>R+ z4>b-J)?f{L>w;%(27gCCZ@vzHm7n>SM)$?D?3Q7S$CzU#J23vFc?{mUV)@<=J*)B( z%zB+itwn+@%e^ns9P`T+5z4;$uCbGj+CIISI8)m3{o#PR`qM7OD^Fnk z{qySzF^*sVd%((N`DR7_0M5tx7duubwfx8YqG{6Gt{_sdg6;%-T(%5k_XIYIt((yy_pW;!+PXJoXz+OH$6L~49sXl=HQthj9)(4 zW0+!WQ*c{kw1C!}$1HB`Ehd{yt?(Q4Fk)@I6NAA)@#0(Pm;Z zwo0dr_!=inOsVh-E?{%;CuAeuu6|1_ul3!x@7WifA5<2^ z4T#pN+az5GTV!Gn7(&T2fGs&k;HW9v1;viEw-5gl3-8s=xc!vTI*%qns?3POA{DOBwqf)y3_^wk!)`uGjj()N0tjhO6;c3R%&7z{Q}bQvcwR4<7)OX8z(ilfC?V>eCN&(ML$u zBU)mkR_Ry9XAT+)@95#*NuBvkSL_!ry5yy9i{0OqXM9DU#@kKhaHNN(Fv-OlKg87w zQ}m>$Sjjx>cqHr<%d)xDp;zr=4BNxIE6jpN(cVu)Nr^f8;18*gv@WTC+l7aA4SiKa zyJI$2;fq|F(?!>eEcdJUHetDyiT^}MG)0a(%Cadva&gzQGPPQ8YcrZ}KU*)FAO1UR zWvR~}c`snf*`S-DQ`X`20FyBVhqRozhnhX-;5XnzM$swDG-*!Ltqsqt?V7LNo}>4A zmBW4MWB*mR36VCk+Ot2JJom(Ezwn74xot6UV^7xQ|U$bWMpV}ddx8JQlU)1(>G z5%g&pr-T9a*42U>ekw{Clgq{D94Z98SpHhwoNNTCoX-wqZfqAM(ej8S@4F^HN3IXI zv@VuqFOT{&DyDHc+1;$6%KoBfFAfi>OZ@7>vhmpT&XL#FUztjcRj10npGVCCBQvsU zdKa(M=AJYfIZdS9&yyWzb1Drlr!78|A7to0(&=k^2o?q*kGx3DZ(Qr=+4J|8bC^~t z6Lm~)rs9en);JCmb)CbF{EC(IEI(blW-1WbPxw3;PlpLsy>9k(>>@Aii)v0!>qa)3 zE46gY!aYt)TQcw4S$>d2{&*_SyZspUjrsx8yV@g&@=@V=A~J0!o3gJeiA`Hu&gmBR zU-7}Z#B`{l{P=%N78m;t#LQCuc5}U&u9~dMXnbped~RIKh2bgw>%O||r!*U0|3o+R zZ+^(H+NTWD8()-~XZ9s1Q|Y^Zew3cq#f%598)(RO_hM?PZ!-E4l2jwADt;Z~21LIweM&cyX?)_0mQI!xf18DlusOXr@|!m`pn_U zqr?!7!gxQY68HG>*8%mg|KDZ+fOi;}JSwSn9d|f`WGw({{7y5q?-q*W|BFqczMuJl z;^^)a@5;;rR%rTaL{P1Je+@fZ9KQZ?heS}RJ97KoD#fS9|LFQt=Q|S@?>2I$+GdFu zUg&)`dyAJt-?i*o0!KF8ahDx2OwrzfQZ9JfFl+*($BTS_Lr-%VvbYqHmhlfNPH>{( zd9veS&C9R9P{W+Z!G8Sm`hBb|+oCcpyU_b6O{bfWC4cFdWo3AkJ1epI?a14C+z4p@ z&pn~RG-9}HIgik%3nnhI))fF*-`}x4@liT$^SCG)SMeMhmvmWXwYJwg#el3Tz?=WZ zz-Rh`re=Ge?toL|J7eZeT&>32Kgy;og6|0{6+Joka@BLKQ`rdCbypRi1l<@e@b^yi zsGdsNRl1A3;J+}D$2w)fs}`Q?QRw)%Mi zziV?g6@lbZt}xj6>(xt-zqhT~j%=+mTPEjS{NSj|b5Sw!W;-{>vxnN4HGRL1+>=7l z5PXk)b5QuO*wYs)M*074j{lN;%5WtuTp%$tfo56u@s*>nk4Frb+LO-c!e*=|Y;CKx z1SgnYTg(UKjn{m#PLDSF^c{=)F8sE8Pl@#U!~QEcWcqstR;|kH<`2?Vo0coa>&u); z!RYZ)!AI!3rgxpg9b^X#;YHb#n7`EbXfJB!JvRJWwv~Lr{lPBjgugA_xVmOBJWqmM z_X~Hs#r=3zDviLePBDLg$c1^9kEY<#y?)DHN5}IjcjURG^5V{$9c4Sx zBa5GP*NbQ&^u~h>&n~B`RKs^P7&TMef*q<;%%Gzms-M(6>jUb$sa$Vr#XhUaGrG+4 zrD?z}Z_0Z>3OQrdnZ9>_jmi->SoNT_YU`GbU+mn=!*NmgD~pouX7TP? zf2mV>k!@4_#gjjwe;&JHl4#_FR@=eFNi{a`Ikh%Ed@wQ zU>U%9$urT)@zpD?>RC@`7LR`~?!e;6#t91CsTTTwSWtBX;k4U!%R9QEa4%~Wx6Wis z8H4p3egiWJA0?}(Zjc!SYz*g&Z?CzhKY>3-1*X&c4^#bTfLlssaf#lzGVAmDjzijR zZ_Py5403Gr2ISDyTS&}?Wl!W=)hj0j4rtP!0ao{0gT<@H!5=>|l>JlCy_UJs`{`n) zpY5!0_`uf^-yqv0<+G*v$F5|Ac&3nw?!}9*g8Ag#Mt)vycMJ3K3YvNpJ+$CcsvsCS z-=`=)cae9GrU|lcV}&99l02{ssQRbTw~KKy#~IoKVLlg%NtD}H@+@%s1Dx|@{YBCR z!*5hM7`}DCILj4Zz7F2cBXZL(K0$u65#R!7Qbq*&`8Tc4*As55=r1tbddS&i$DA8( zqL}_&(4ApV;;&AR&=tgXR)f)nnfcVLf^)iWww-!fkMWMPm?Hwi74G0|EG)%(o83VG zp#W)k747$GVUfr()cH5`PRe4D?C@DdfXv`Bm9#|4W|gEzhZXxbnXr(RykgHpiU0KO zGk+<~dcCQW&+GUPymp^kdZj4+4`La0^=Xl!ZQM1vc-vT@+g)z+G5V&-OwB``L0JRg zQ~Aue7mY2J{f#Uz+^{0OaoMWIH@&A-7=^T>=d8QQ*_^Q<-;*VOUCUp(DMj2na=b6& zT{(}pb3c`yyBhq=Qs49bewIz`iHclTz`>YG&xjg#?^gIWTW3bdZ-id#lw}Bo_Cz>! z^x0Lj8;kp-rO&u;Pp=jT|Hef{`X#D(_%~a^V^O4u{=|;8IainrvQIFqdwplmqoVoE zV_V-M+br;=;#h_zQ z9cA|_R&cLgD*KD#;n2iy9n&r1v?44ZVNWh)$()LwtC-nR;r<#ym;AfZDu9%ATyRY@ z@aqdw`{j1S!TZK@rz@R_rK^Z7{4Mv zbTvw8L-oYS1}4l`8SoLGyTuZI9LAib4K7?@&f_ZVkjM^Tc}Ou8d4t z(8FsGB9E0B=d;4BPSP|{4D4{zky3MsmYU4X*!*t|-!6Wm?HYIUWMH^{#pX5F1V&o2 z-S5*z`W`??!6aSLb;}zZ3J82Qm|yk5^pCX3Bh`uD;U`(q#9qhoeovYT@m+l;mV2*G zKn#TInlw*~a`;onTDJUGU=yE+miX#`Mc0iz#Ihe050^J-TK3(hx_)vK)%5CdI^<)w z4Ku_wC0;&I^GEhaeVN4&mGCe+p-JUx7j##hPv3|iwTFVuSbmB=>DCJ9(%GO@&Jt1g z&t6(JSp@3tDQ5acXvNN`Rf=%|j;k+Iws(wr_Q^%JS6+7cj8i}ln#7XJc8#(i zCtroueaQa$S=exg2-}tS!?I50S0LeG%1Hdh8H+cow>O_Z!^`>{vs4nyKAnpNd~0iA z>(%*!Wj2G8cm3Nx*Xpy6T64zs)W6y2KUi^zyd8G*8cR;gS?ywT_VZKU^D%f`+de4X#^MTp8qj*dn|pjvls2n zRJeh}`j}jI*|1AQ%63jQ5nfpcX~&-xPHYym{}?s8_*`PtPwDO}FBjG0}ZX{54Evx5teC6(~$I|7j?>@4oyPu`nCx_~pk(%`V!-^-; zE`9&={B6)UMr!)s53j%CIrGzDR($%uwaQoTWbQJTw%wwZ3kxibh=Sx%XI|BDY#0;7 zK!c&2Gz8nUFEl=KtQ;AsVGh49mM=b)kmde<*U`F-yRcsCXZSG8r;1mwjb^xyT%b|> z;D-*y@p#Gc|oR?iodq&P-^-Gq2anMSAo&|hcF91{giw9gmh4Ew+EGOu5}VAcOw`hieGud?#-7p~YVr22r2X7Dbj?xmkL$t#ON5mRF}OYAvuSS83{ z_8aC`os5~{|L!+x*m9Npy_@x@)|6Kp-}s2)7g#&_tY%8o(;m&IB?WSN+SchCSo(^& zG?thbF`B7;O?zt7@#>;ziKC}}pZaff0(7?Zhl_Scnc@rIiTtJ5;QnLR0Ci zkmMBhTNz(5-T==T%bdDR+Y~d{RkZuDE#>Qot>zE;CHQRccAD4gzqfk7n@6DE&>lCF zRNcGc;u!zp{NWyPJ)iH+Kwo)Q+DJXLs7=?pF!?5#ZxxPB+kK=IR{FHQITG-uG7&As|=Ctz&Xo6O4zCFg5|FKRIeW?B2X zq1(AADiC>ywN1Ty^XSs%1G~4LA?mD`S3N=|IjU>!0)CxShe6NpB+r$NQ6F9wlcO~g zpfx}0;X@CE?AJ6W3<}F_)<-11qBVzWi_`dbC#lc6wa%$8Zq40DTfG{!G%Vd~Jhmpl zdQ#NS8yMVSN4H0%bRklbuYO>ZeHG$f^({~Oc0^a%NL7FU1+>eby4N&sf8%{!vVGC} z8pk{q^r4?g#?%d=`h>#i|MKKiT>GAM!e9;J_RR^xwt`gaBI z=rC)LCN6qA==}aZ^%A(9znDu}6^I7_uf0+$Eou1jgq|h(+;ccSQ*M*RQ zZRh$0`p6Pp#H9UF&H$rj)KE&$osdt|)}8fhw8oiV?YVTM>0P9ev$VElHA-}XVWw7i zlBaLdrGC3ALVQUkcEQ`jG1S;oS$3> zg||7l4BjT(Y=F^agWH0}Qbv#Qulie-be`D^LMGK5Zl0(h-%9;)^KA_08435Qahv@; zzBlM|E#>%r^Tx{WMa8H0MnTsyoNEcxrxtQt!GHQJLlb}#cpur&4780x)u-{i_w z!^a(~T17gfvm;aln303th8E%kvVLNe>f-9CHDV3>4HFan6Z>}S2EB*<4nsK|*Gx6ABNjfbTh^^+-K z*YS7=_tVcqZq3vGe0he4tZ56}iSVz26>3J@6Dj=)Q~XtX5+|f)g7zkpD0Zz0@5x|l zn0%hD*sRbf>G!Tiz4pQhSua?*HsBMIQa?0mrWqAL+&8kOE|E2zm1%4iC`xm$CPKMSA znRL77guZ7?Hd|*4=Zn-DnNtt@7up0XS}_#p{jIi_CH(diBOO0uPSDSHSc&Yck@u4F zdecw83j2iMzNvX%*|}=8U&SG=m&8=D`%uUJGMS-=;+N?&$MY% z;U!8h?C-OCy2UycpY?q#Gglwp9d+UmHVWAOZcgWMT)?U{g%nS^?Q_Jl(RrSAOOvy( zTw-d}%o@UPvFuRxE^hY0l8r!-;&aA7v)YW~AB;^}yN+igqjhd4I8G_mLXSO_wW}nw z_Yjgd?WMDCD7tYfnsUw+r^d5o4Q~=l$7I8_DTfQ)zR)695C8A-&)eoxQsN)hh}^1@ zGQSEdWOJ^GxTJsMLwaO}quZQX>$X|871301ot~e1_GMoyylmUjppGwa3g*)aoeJv6 zxSV%-0~b4qFoFGe3e_8~%FVg`Gc3q1FPW5aGrB$V#Y4iI?eJnwMAm@z&0{8J_8Yva za493yO%ZB+&Kpy5*Ps1%=MGDEZe$ZUoUpw3rd3!Xa8g<`RQC753yVu>W0GA7KOOiq z567&2Tn(8OipQ3KHOhT2H$|&-=eyf@kiKd^nze`T6J2|2MD^MOXNQpGEd=M?7DH(|;L$l9f-S zh0i3EPV$eHTZYg2E^qtOttw6RFtKN}vwlcI1qGMkk>h7M_Yl8_8}YrQ69JB zHoH*e_S8eBmr-w5WLr!A^u?L52q~LnZL{!NB3&V_+jhOUnub+b4Ah*CDE53yMnP$& z1NhGF(ph**U?QeNPPtyn&#-%_63dkHzj{^Qa;Rq6!Z+5l=~jzq*j~Lt5UM$@Kh*Mg z7<_iWC{^qG+JT2tWKJKgXp8`kxf#}N%^UKXHb~MFD?FM0>X9r<$}kJ3CC>P%MEUzw zi%%NFXq>=b?(m_-xn#xOyCMp`kD!h_-zU!zOPfvy9XyMUW9~0brJ%(L?;X?=K9%y) z-Um2sYUnq#1dum7&4!$*cuKmA-s!<)aQf4{mKapjg8(eSdWf=P=Dah z^w{NHgpF^Qb=p@kw=4Q#vw5+EBwe1-{_2qy=_hp_lZ3<4!h^%=Oq7A~8*Li5;UAAO z;Cv_v9_R8?2C?)a5gta$0^H4vB;O#rOwn$=sE0KbQjXoq_E7Cz^@@ZO^WZ*3(p#dg@>NdjVb~nSMJ>L0Zsv^tX z>xohEbg@bvLt!4Ioa8v@qM&lqyS09%WE6(^iT<908F)5j0}1&ZA)NW`MhyH2z^IlaNPf4#)wvoQL(=1P!7x%Ye z?x5$-DVKhvXJb+{)x#P;KL7P)izFR1bIT_#+yx&@~+%r5FXlX&eu=$BX_Etq$6o)P=%)%wJxA#?YnCbpB#xap;Zfx7$Qi zwTs|>GIuPD6dYShN5+(`s6N21)-&!hQjfyBZ4GLz)BQ$b*tF7(lsNeQ@C`+M7jKUH zy1?Q**=ZV1LUIn7<$6ekzzO-yMZU*Z>-^t!$r5SvHzV)DdkpUP37Gf z=)R(A7Hj(A!sYpETqI9Fwds5(Iv=2vIk@c|X7^jm8I`Kh8%GW_3>KkE0O4|no%Y|U z`p~ZuH{w_v-1hWfpX!*!A-7&!Ht32~q0G+nC1^OqdOvKtc$hF=WMpt|SNEq5ey7ow zTqYO7A^Pq$POJmY`sMj*dz3R&xV~7UBo|7O`_D%$Lwh>n`peX@_(sF0Gwj~H2Zl%` z{pKtso!$Y7-=uu18%6{vKe+T@@d~U75i-36l|IPrtrfxi zxLg&w#_`cy_o0W@?lht@&?Ty8D^+5^sUI=ynyXm`?=z8I@m6ZsChFh;+ zq?qp=Ok{wd(*6GD#hD_?%j5DPBFc)?;wl&Z7RCmy^oH0Q3zsfRtUG!4jz>sH8CrbP z1Md{9d!IA1-mbVqL%%dVn8>*^ZmKXXJ*_ZOs_eI)#u>m$>dN?pVYgm zA_#WTw8_s?X0v6f>5(jTKnyfDYcwiiViIgla5t+x#S;iGM->q{!`iR(*_evSbH-U?e6dy`8NF8zx~-) za!5krkHIb6&*am5i^EIiU6{SL+09>X(&hO*cbLhWjID~%U$?m~#a|(9r|s(`KgZ5r zhify*t6z$XN#efyG&{vq%DwGDQPMqbkE46Z@2M`nJK5uM=rl9CY0_FCJHPNmMvF)C zy3;}nv;8J-#+}@23$J)(7Tig*FLZOM&M{3_EX+5ypE(SZz_YWThaKaK4#3&9hERLm z_Dj9pb1Rc>CtjCzN_gJCmfkpZkMQ$<>ANXlrRxS5b6*j|0WqhOSXDJzK( zaAOGe<(`?z7t<+Yi)qL`bL6?nrDA!pxU$_xd+5Js#km)E`t`ik&3383MZ{#sOiUa4 z!Z)m~7j*WivwI6u95_;wx#cZq7241ZuS|n|>Qk8VE#me(jS|!m`|A4BUZbSLlYhd7 z{|9P7mA_Hnnma8j5>+(^XL?a5q*SZD>BZqL;gCC;7!=aXy_?2g+`W6jgASynK%6z3 zs$9!SUPwTyxpB*Oxh&8k%fs2uSofZ&#=n2Y;;8^RL}Q&f=w#*!PD{A*b2Pie3=$+q z>8qZZLPQ>Epjw5=Pnl!4*=E!b80}af4m%=15#O&1jc2#pFTIPWk%+)2nqp*6=@L^$Z?(+47t0 zXTu)Kr7wqqB*C@1d?(wqcpux-uYy^e;4JB!@g_5XQn^KWC_G4SrKE4YCM+|$^ye}J z6}BcC4(b@@iYG!;E_&BNso|195L}m6Q6J3{FgxY5{Ozhc2jssR4vm}D@xu`)vYRk3 z8llAid6n#~ha8K3$Bz0lKTuwVW!g42eS5njXn5>f5A1T}*jxdP@V!H$g{7gFWL5oq z(7E@M=#az}J>IVXx`a*z$JTfxZ7*$M3ans?_b~_94@0QSMEH@oAUHm^?(d2>{qu@Z zutVQ~7FD^^ViB`PLV=iOeR)0B%(#_Axu-Z;ec7PSL$th#V{71fU@MPzPI+ z0#420ane=6a9a)-s!cB@(V-)k8%g(4!WkimSU6kWGT0mOv8L0NHeQU=K!mE*IPSp5 z>Kta-gK4uddz%5LvQlRz6iRmy)ZwLZZRU6hq=Rn|XP5Sc7~m3NGv`CNuwE% zx9nWNllo=xxOLCaHe^8e@V9@l^UBZx{cE9(q4!MaNx8Q@+vXH+TB?KqP~!K>hjsa1 zAp2Eq6P6FCm^sl2@>DjoZsY>7FSGknD`4rwnuCz9 zv>az|C>$3h?1F2^aph;eNQVu?|9?h-oUTX0f?)$e2XWp3AhD*h&S~jts=CMvu@c?1 zV)?_0@)$lE6_Wif-z;R0PEZA^s5b(;7C=HJpY?hOLX3m0oM)?)*lwA6D@vW@dryIa zA}s*+BpPd3kb{lKqHVeDEP-Sgp2QflYgBCU$W+w7XocBJpy=47O|#i%0hyRj%#h|k zo0vYcNX)ZR$!~z{=Z#QyLD_tG_B*l?e0SNZ%EO6TJU=4^>vq?cgdg zw$=QTw~Hcg@`;orxqWh6`wrgJIG5-~+FXPpnh>nKmL*>wMh=pho!&@>? z9#fD>WS2U?bLs+^Q5D6FXy~8+1|C}tt>HSet-bjLP`}*TOh*!*A}dOuaBw_0qACsQ zM{npG;3&vpqhfB&30;0f@Bi({gS@m&=L*NNeZiuq6)=fxNT_D@RrI%_I+k=64~SK&oUq zoac|-_)!2&b7(VIKJ?$|ox zKN+hCKeW=(lKM zU>O`v?pPZr9255)x)$IKOKBtqRU{c;n42z5GBR`bv~YFz!+!q*>wCbFr1}*xEBJHy z$c3_H);1$$X$BU3ok0+~jUhiS9ls;9b^nip*wdDpUbH-ln#uqVQAB%wS-Y z#{m0*DKW;}s7LT`QG>Ys4?f}9L<I?kaZO-O!P^~(HAW5EZrGF2TQ#|zmW}X zCwYJ$$9)>bn)x-BAQ9PVY97c1HVNpCSb}jv+k?U~k5R`1uP2?up-MB|LHI<^0PzDI z(qG#^@K*rkv#*{reNcv|(1uR4ex$i+BtacQksc^UCBD&9oho|+xxfFe5cB~v*#yG8 zqZ5o1WX{G2(Zga{kK{&bOO~r#s@g%ng$U0Vzg_zL4hkl?+FXOAMRq`-?hSZ6w4aF{2WvXD{uAc?~R}aK9 zPqq?DERw6Lzy}8*LzE!~O%@*m^OL4vESF4FFKD4UWa7Rpv>eb~XN#G^3=-j!3t9(3 z+p7;fjQ+Z8I2wKM@;MR)N#kkd(lCS+n`K9}f#$tnSx5uL!7ZD05FUcBMS;+IsAo|B zBqI(LwFIA-m74-Jnf9f(fvo6dUArk*yK3lznZloSW`t?jqK$+gIG7iIk8LILm}?H} z3D-0knD{7l*#!`;3LT9KYMXIbQ*O6q%*ivx@9N$q@-LKw!c$fV&olUlJ7WeEdZSi~ z{CZp~d4xHYyM(@mTf)T;EhJ%uz02Gvc47~o2wECL@$;O)+!4Pz*_+K(eG_dQ$D5Xg z^q7HRvJgPT##>DM(bfd$XC0QbTZ!iSXdFL&n>MGL#j0NlLr1&At>d$ql&)WA9U%6QdH2p(E-OU zfe@;LO?@Kb(oTYT-vC$>e}COsM_Tf@-%gZr0}&KBcvmn!V^GHtx-{&dCvLAFI%UU4 zrI_H+fBjqd$V~OHL}y_Le{i-cWgP114sX0R7g$*o8USq@@>)WrzDfoZK#31dJ+gqz zx!o;P7Si|uv)>!yi$_@+O#Jj|=XX$ruv5|ph>%Dlog8r~W~8A9ZYxFD zNXVJ4z{GWIZQV=EQOp^U+p8p?!WO`7k~y2QfvsT6<0`1tyfQ>vXynC$7J);UHSGRobDZi12UWp zlijsCUXUS*t}5rltoCndMs5o{+de&hme zzTV;DxW&9-0Qc#&T5BY|bfPn{HIw`YkSNxgg;BvKM~_H3f)GYeVp*B#Kv%R5MPuK*+*_eQLsKig@gI$gf09Q4 zBfCV~(fjm(o1(K|NMQvmlaCdD+8}G5T z>v=+ z45}F~z^JbNyQ#&Rr|IP?s6ps}a#!!G`aoGk=nlGPL5^My2-_cx+zp8wIYCmRfF0Bjt^F3N> zK&3xe@5o>HskY2;ne*kIV?s;EURd z%t~J@ujuQ%9wBWvGdl3kcfgB>()527VZ-pgml$%%Bs2 z&$lJF4YR+q%RqHYoBf%saI7g)TudtspTdFH1`Rh3!qSkcrbqy*(65q{Emd$?r_G;FGJBjZ?NV_;4Z#OV z|HzZPs1w!yuRimKr^7b6NdmUFlxDvo5771mj0O2`W)=m^vgoI8UZ*TPkSZ;WO|V<- zR-BQqD-5MN=LGm5T)!UF>44E2)Jjf$5;%Agl%PFhTaiU{#fx%WDFr3bV$jcs+cJEp z?JUtQ=QLPK6-^7C49M3Vy~m8d_MK{WB~E)i`^_mzMJ_?A5T1K)UzoRQJ>0W9h`q|# zEEQHQpzqP{7(pHSq0=t4NS~?N*o0m6u&~F8pEvSGGJ>>iN2+epXLhj%KtK|A}-V3}DT1Mwlh0d!ao+q~F?tDv{L1EftpYL2rb17L6^4 zdjmnjIt#jk-I(#nQh*6fymV`tXH9vb4^JYbUJ4#o-wMV4T|Fb+4drN!*2?`F7NTXW zQfBqj&Yb)pUq!E5-HmJ$r1n6pIh{jZ7PLV3Nm?8FxUtLXfGpsOj8oGHCJ@0^K?e;( z3fkw;UjzMi$J6|R^seLpqINd3Yp^j^S2I8aRQ@(R* zwJ~PkH0(4-orJ~mh#r9{fkB*=WkMXhK1vIxr1^ zY$P;S-~{=ok12d*+?I*et56`nWQ|Uba{S7ey_~x+_eSPHu(!()eYubo>66Pd+mhPYKsR%Z$;D#7>Jftv}1xG9Tje7?$K8yt@?p9eA% z;n090Lu^ZuCU2F0dKT`%>gS)2tq>H<^_`|6Ic{l z$}L7Fz~_&}OM z!V|$yJm5AJNIeJ;kF`8`p65XE&X7BvqMY30I2V2&_#X!Wq`)f`A}v#uxA6jb^^j3S3Y#*ipk z&kW-i35m8YzID| z){W)A26Wj3wDKp@ULOeVsiQsiLDa=9=s4(R`UK`OT5d;rx@JLvm^U+y#^Td_LyPe$ zC64kyu_?>bfx>-9`=>H<$XezhY$`?4t(=jnJOukxTSp9;ylRF@iWilkG9-Ux>Q{I| zjD98iJ$x#Jch73xCA@Us!>`hB)Wwn^Lc@#$z}6mmpP@3yenJd5Pxqi(Fija`RlFbSTJB@;-)XtDL|-V$M7#rXH!3*avng#!~shP1(*Z-S?G= z&jXC@8z;XFgM3Cwz2#hFbu8^$eCn;{H~`5ZP3}7O7oUu@o%!5CpG9y~u;GLGDQD~z zpEU)NrGmZcw{**5y}D)=N$=^V1$Ld*Rgc;TOa%&8IPt@(0#2`9u6ABYL-jgp|NI8U>zo2f)Vy!2Iha7&Ftc7L`2xTK!(d z7CD&M4{7_a^NM=E!w>WOi}!f7M~Cp@3C&k_JGl}#t^)f`1aCvyV;)#hT9Y?~Xm~Za zWdx<52Io%fmOpmq^`N&ZTJR@pwZmVyc0qf>Jchu^E-Q$FrRJ~PQbG>>iOMO9xQ4Iq zCExZ#M!VC9=dV-A0e!53e)o)>D8&>FI4nB%^`j`$#khuu{D)gO0L((50oVC`MPtwI zi(75Gf?C)yqJ~*VL6D)~rX-bcAt1(O0nsR;iAqJX!EPk)vL>^{jQio)3*Le}{2`ka zrQ4_x@oo2_#&2a|!t_@>sa|JPMlU3U>J|*W;H||>^ki6LhT#DkUuHkxXwiy4fwl;@ z_DVaneB8zzYlHIi=%^nnvNmMxAX8Z@Kf&kX+Li;&LamzdiwRvSa5Lt69ka3`Jg|N{ z!M**y#PE~IDbdc3iXG1aMdiKQ9lB2zIkIL%RG~?F|A#LJqzMa)IIY#{ZZ# zt6+q-i!+NDJRmMG;{d7f5Q*rDq74_GxHwFz5vtHdUe~}vc`Wm~j%#g>di1X!iujsp zCF$@-I6*o`oEC6Wy&?oLTe1_wMkV)Md;dZ#@}pB$#31dV)9|Q^Pk+&=-Q;2y^EfeO+IwG5Kii^9 z+5M`&IOH|H761$OKC?rm{73KMhzlrY|42dJ$Ao${=t5L;&z6perw9yT+0N7jl2VVm z4E+knoWUecQg5$O*QJp!CI*xq`uU_Jdh5pY!Lgio(?SJr+4$iatE4BS4}%2P;)yV3 z4snK~-v_<}T_Mj3>k@ja2IalE~Z5gg579XVWC8TodJX7%}~XstwTq1adB8LL_9}p9G55E z;CsH{tTj*_&y^8zs`$r2J3H4_*U(GuWSo9EwS)yW2ISMP;VmOfmVpe=PJN6(THzhowD-NV)ena6 zKcu4&LP?$Swm3uDV}3fQaG^VC%GLGz$K%cVhWBE}%zvAfutL#{D`CuHSI8}CnJp<10r?G*A625T`81$mDyu0*n0qbI+^>Y!o zqmz$yq(jmKV`u{7#1O7$XRb8bhS0>NgnZuGbxA9X#B;|&T{R0uF*aqMTu z_7S$}Y*Ajonxo5gq3QZdBGpt@1F{oEL55@hn6C4V+-ick+fe3kbUUrH(F1$Q4J7Pv zA>WJ`WChp5fJ~k{KLpCmvb}&;9HvF`K6;x!4Fr(qWjg51Fl_fogOV*R3rA7FG<67x z^FFVS&2s5V??0`Y80ql{u#$G8HXFrhdr=<96waVKTuqut>I zx8ScNN5ugw#yOm!C;?wn^BQ;yr50*7EbXrqF0#Wswiz1$V00w_pIPIJ7^8hwW|&7o z%y?D(VNxyqffM0b-Z%i+zXn!s43Go)4$Im+%UM$@vYRJ_*u6iGV^rh?fkZN^Q*`3# ztgfM(tMty$qdxnn!g@%z;dtDY0-`M$`J0r#FkbN9$0a0p#+sgX?B=k+3#^BAup_jB z9^AQIo}CZQ^ko+4hm^H#H;(ht^_r2gQO!V(13WivsIg8WksYGn5?d!?BF9bRC5!9% z4Pq7emKH$dq;^nMaVu!7hHKBi_$D-@RTh9GGI&vhh_5)jr8$623^9X_xhEVxp)Zd} z>3zFX(;b%z$tKqKb-ygoCSXtxUw}_elfdx!d#t4%`HCM{NIRXFvrqS}V<`|iBaW2} zcQvKOs)t6Ajc(y$uginS$WPiwHl(7;y(T!pECKeB(km399x^-fv?4utzR(E7^yRL zK=@`xyWWozlCDEPAPTq8VvwbwrIN*VG7A8X4>`dgG?~H%z$cl->Gb8FOi3pU24qfS zOb=_JvPlq!qXIkx+1e?lkc4hYkbmnKdRCttan@BrHDo{PnZi|nwAWU zmY^z%OPP^X=vcD~s^2U^AX^3`tLF%;TZdedp{kBqD|6QvL1GBi839ly`}PW*pWoTV zXlh%G4e`pctrQid@|pNuAB>#>0*|V5!M6?QOXGcf9cF-}R+sJyaYRA@OnGx?f})c9d!mV&3T`FWKearf zsI%3^#W@!L3eelddY!Y7;8=){8C<4ko2A%Z;-ECAL z6~q0kXGddZEHi|AUP+=+TBOw3C#hXu^en% z$9B1191|VQLzRClT$+nC0GY;7ZS&dTy!CB<# z@xe?X)*`nCz5{?Nmuek?yD{fYMH0Gk%nbK(s-a~&B{W>XFy@kg5g=Wxn$0AS&!2!J zhJA49E+gQ7IO$x4mG|C6E3`J@mlGEj_a2&P8#SX6jv3n~0zF}XB9-cvod zDT-%Lm~UzMMAgaD0EAil&Zw-EX*d*eP~ra~_gT@L9ivHm=8p*l>Fn+YLEZdmwVV#I z3TGXm_?Vp0bvxky$YZ8l27Jl-*wIW8fa+0X+1Rl&6@khv>4tx+eYa z;iGwnS=7SaLG$XhE-YcaBC%#Ys>DCsM>E+lP*9Jt%^|Y!y z%@^(=E@-WT%V35JDC#V!@i-C+$Df+Gs(nd4$i?y~mt1KbcSl@KrEc2)LO8wE`B75F zH*-SKF?dKfAB?J((Yv4jc@1O*LV5U!0JEQgw|gh@$iy9}$YN*;{{PK)T?)=zt~C+z zXA^km0n0}*{KYef%qKbwU-g3-D~`7f`v7+82;@xOTNBU&+jMro(`MpZNrKDvsAFP* z2AWFv@a+rnlufqyk4%FjzbGNpR~~_-HdRA_tEj|7X4M~&cnz&yhwZSCd1j~<$D6tP zN%|fWW$3;@HT%*iq8oEOW=|e<-5%qH1B_!y9M)dVsAJZ0MfVauW3E%x13=362b-$) z*xIMq3ZIKk<5t8T!49Ca1>q$d-rb=-rL)kxh1P2JDQ)T#EC*2}Ug$-PgYF$IPpIbG z7;r_`r^>651fjr^aT8nlHA8<#e#-$h@KS}k4E=C-e)>P5Bu+7{ORsiF7{*1Q+s9A- z0hJY6M+|q<7BFF5-hak;8Lv=QU;soX&^s4+N|_A~aY<+kq`{v^i8azLro#yT>x{WFU6Ty_Ucd3I`_LwUa>kUA)%o`ogSK64gVXz zdSbU}&JGLCO(OLGI(N|TcNe_UD3P4IYFT0TLbF(G?H8B}4H2wzglV5tKtxw2wdPw& zG~oR?1f)&)O3nx+gKnD`J+Mv*+(_~>gW+pS>vU%3!ViM@fuG`MMQvoXAT)<0K06!B zs7Z4`3T|s*n!3kT%V;TRscn=URqSYA=(vJj*GwPDU!|yntNh5%_0Q z!Qi1K+^6A^@hc&gwZXvvmYYyRxkXRI^JIJv(;cV0DME>3rQJocBC!SKaq_FWw1C9n zr4-&l{`uHz?+w>}w__~Uqy~ntG zdUM6JJ1d!#(x~mI;*EHcFy?M6@map`vP(WIM&dK?A{7V71Cx~2K4~JyARgogWS=~M zdKHPC;L^|PsP_srZ_eP;T>d`>+wlZVMz*d01!%3^R_n0&_Cj_Zhgm_}u4d&egs1rU zYe}6l3)$Xa4-#^+B6Us&nC=<9Nu(d?6jkh*+j$t#WN~tqO$P@zN*oc{FNm+8ZL|-< z28clV%C=z2L}3SB&fvsmN>m`A5kBA8PtDtZ`nmrIj5zhjU}v#y!LkZ#h0a5O2kZ1j z*uQHD#`#FF7`wE52FzPE$%;8MJhSUEqoJe0vmCjkxF~S%I`CBKhuv)`5qOAzoo%Eb zMiI6LBMb{w5wrxib6yFuo1ma4hca7(uHvVdl{mZ%myo^?juC-!y57SW0`bqozm9MV z;NjsKcz@=2KAGk}d?E=W3&;$(f}lHxQW?M- zqKQp_-zL@^qhg5Ykf#~B7GfW>wR#!lIt8%dT9!%C?K3$jZNbx6sh;4HhNKU}W6h;& zcm=w#hezymgX?!+jeuGoG=aX+i@sn}hkFRCQ0T8h^+vfbZbw=HYLF>1iLW9_P*a|4 z9R$}LvQKkiP32+p1*WcuTrobC!Wc+mA{;Iyv93W&;1I?_g46&pSPG=B*Ts}JS#r!n zkHYV#e5TflQlP8)k^pozM=^nD9Q>GPuTbw`V<>cOz@)~1gFe+d8UZkml%Pton;=dF z#E5RLiJB1rM8wu@ba=A5k^IO5>IE5gJGy2;o==Iq5an#Rtq`D$&hZQ+2+!ilh)pI> zIc9LD;d&ybu^3NGEI919P;{LMw!J5crRvGb&_lD*{-bjemt$?pkGM?m%;1?%!ow$o z`_^kA(rBvv?59b3ezvgO>lgvO9_20OqxE9FL8U zbxw0E(B#$=Co(B*0PcAdZ*s^_GHz=EQCI)hNeu~o|EFC$411dmmVAC30 z3n=@Q79ztajy$QI5Flw^CQ-HjqE$(Ap+KG_30N0IA=cYAvjN)*0kDhDvalppaT0b?Y7W#-qfH?8JYto&#`kmMT%aDNZ<=_AXok-l(MmIy)AFW?av(w2#Lamo9*N3kf6H{A!l zL4R01;20&3wCauH;MI|=RB0DK(isUTQYrq^j~oecW+~4~hSTVt!Ns1_gMbhYzj)@- zguoT$O=c4=00AnAtRaSR7HtZZ*UTXrz8aK3hH&lbUVwpNzs~fp!LZf5UR=6O*B~E@ za1g@&@e3ywSzCBm#{OqS1@SOhs z!Llp;Ug{@q)CtCIvr6@PUs%T^%$b zrh{@yR{FLgHSM9l%9b1}MT%&`x#P{pVOdInpL?=1Hh7c^rI`LA@SzE78g}P8gnB27 zM2)AOU-Xl}d^v6`hSq7(s(!sLG}SI6 ztUvdiO2w$85UEQN=BL!61~;F}g{mdg8c}SBNyCjvNdBp&zw716L`!eUO3mnONaG{W zDAd`|N2g;qNfwo;l@xv0EgpKbV`784ppECz;`rmJ`~WSwz@jvsIR!80X(MwnhvTN zmn@7yVp$-}d?k`XG1Ow3vWA$F^xShz(UH*!pK(xz@;I))GY+%A^oS_3r8q71iNWz5BDgTeTcAL&KYy( zRce;~mxWtsv9Y@qjUWhOBnrC1H~S3%j2vceH}6(! z7*PrxpOUO%3K#2asS-gg4wb5=s|>99xL$&d{Cml@hT10ZJ3{LE4TheB>`)21B+sz3 zbiSrp6I?!oaF?%g0`e~Ma-8pZ`$#o-dwv1ko1luSR?PC_=`4NeSAe^25v}qI5tv~K zGZuIhmV|>J)XZPUcb&eH8X2LG)|O0%>vJH=oA@MMhm1yo#`F;cN!-$2o@2q1ZfTNQ zGZzCDiruk1SquxBnPhabcs#%!IzmxsUFS1FG0Y*~Mr5prjE0FJDznsJ&tKQ3vgcDIR zOlXM?kX$7b>y6hxow~9sv8UiYv?f_uH0~Q9f2HOC>|+t&*%n;kGz(&xB`PJNETqpn zy8t@TF};wbQY7mb&Zk~f^GEX@eXn%P@|+=T#UJ2vr2CKSk^s!uDqT>Rld-_}-+2$@ zEA7@K@%OT^)1(qjV*GyOKz&ODGJ=xPDw3AtbD(_n#-9DP{C_o^AIEr zc>qc;ef)dJienUHMumnVZUzgS6#DkD7; zk=-+ONX*tJdju^%csup7_a)vQz{qaCKIAA}FvsOzEZ}iS18X0g42?vYwjrk1*K zBw}`WGOCIK06+?WK>!FRa5Gg#w8axhaH9YK00Z#A3_rn{sv-aY0Ju)(zUWw{!{`TK za&VBtgMD#wbF$BF_Bxnr%+(~@Hma(s8jTt?>c7FC^e9vBwxEYmB{5=9nX+ zEA2=ewi*Ql02P7?Ab^Sp0Dwpo000mX0RYh?000080000Y00008001B&000020000A z0ssI200002z`Pj`DUoGUa*K<;=VY&L2-TZewQA3!cVMVtzJa*JbTVJHVE-xLo&dHJ z40Uwc?WfwnoraS9(pe)#5*>(bZKZ@05s6CY?W5dUaeH!WKI9KqpJwwhEFElY5Xiz-X~SJzXGbzQ-*Iw}v)-8TaMiot z&9EGxMI7UYo|pYEcB;FK&dAJ8mtjQ)>^WMD=jpJ&sU7F#aFlXiK5#lHL?Fqlj%>qt zE^5kHl+F{(I8pjLvEkf?#{^y|-Cdc(1!)5QKdMy6zp=T_6K$rpW-k$nyd#<*6-v>z zsoMUALiXGnj6_W#ikUJEu0H+{OtcUD6ZO*mEp^Efemd_Nn4&_!L`@l>F|8wChP;p~ z2eI&nZ-;>8V?bFNmQ|Pk&mQt4Ps0qM$R@hT+q``7Cx3-evru;i*JGjzh0Z%_YR)^) zS4Pc0H%+ZuDsbq{dB?3US)>iQK7z7vUfJrv=P0IDz3_}2@KpaAT?FbFvf_|&iqu=J zg(rlvrs93=nVT_wz9O4tFKmfV3w}aT{d~>l&nXQ*^Yb+8MB5viwjG5|I(La>rn07=u!6<sMpc(RY_8qc;z&|+eeXo+IaE236_GlO_dNh%L9H?65W_Jm>ah^XKhb3~Mk4z{e z;EiAHH^3AJaV`4-)*NHxCwbW1Z;mFGjZYEbKwOaLg%g3zKL{jW3mqy0lZc}eEBb}1 z;=evT7^>1t{cFysG0*6;#Z#C6-NKP!AiP~VkZ6g~GYrRdS5JV*vWZptir9Li-2=Ug z2<*nplV1Z^qn9|PWIXr)<((ZZJMdVJD$L61=;`^vA^f<{0J9UI7PTS;uqQVY8USlc zP9=j=GECqgTcQGbJ_7XXvJ-LfDUIN82H*F!mTkR^lD4xVwqmxSS{xja6d5t<|8+3s z%-OA-_^mrd0G{F|@1?0uSODSTNbGt)o>#=(7b}}sqc$B@!#pt@Aj@P6WnV6omjoA6n8KUN*@&b4g!#`MFZ_M;OaY{e20zf?-*~M z1~K!>Nil4GBLEWt5!4SDFGPy#W^>yq<2&yF78?00WkPjhh1cT|9?OJyiwb!m=GcLe zv}SDMM+LPVZ@C-p4=Z1ss@(7mOU>`iZW`CkA2svVD2k9d=hsyXO873SiU3k?t{W7f z&Dpv=r=oS8!EPZXfFx1cG3|E%o6C-b!LGT|MP*#fCN&*a#t zbHL6e3B+!K{OEZspLjzM4_Hr4^f1=tF)jxgyUXmJorGb{YcrE9F~a0@p0OlI4{m9i z_)2;^2Wj*ym~x?&FeX-j!{8xyAR^3YMZC^cs@Cyku0l*G z4k11`A$7g61i6O;--jL4-^0xoOSEy5VO(&Pgzy^)!$$~Jii`0Y?1Q5$fPb<~n!YIS zEaE&6L~i|ce`pUN5DzSAmWxNS&@C7#HSe>+ITLz1_~IId6MkR z*r{tm!`eCd%}n~uvZ_+`lR(?qzrj;!)!PMY6mP1{yRndaUxYCsU%?EUrMYZ>(kG-Q z3r(A|LAfH}+|>jzhuzAaM{>xd_Ow#B3R3+<%OOnuIP<{_q!&{)ooKWF^|3H|dhqWo z9wEG!PBFa{LYOFhYNIwG`0UW?joA}??UcY5qCS-?ByhL3^F$Ahr>A{hQud$;OV##rQ zu!X+;-9Usm=1t;gJ(B+)+bMBXWO4>q@3dF8_sRgOf2epJTZ5{G_F`WO)qA?|szqx> zB~99{&JQd^CzvKF+Vua{0ZRgO&-}pFfna(s_G{aKrv4k+qu*Shc$`Dyiz3@!nJ z`xC?auN`ax$k7}Y@EQJS!D+GOK< zn#HaSXVDo(FwNKb!Uz`TnR((r*x^kE95x{t*RUh!8aJzxNU!Gdl$KATWkS9HKSP(Fllu3`W5WNa5+Mug8CXd_=T1<6u5=6hP68p;p$z@(} z4-s%L@SUF9T%6rT$Vn&nwBJ?%pGiPqLZO~%2 z{kYLMyYE`!I*@~(Ok?DOme=q+L0;f15}V%FQpldT;Dlu_w*RpLf==0~3^*0~hIhGO z)Vb4d0z8nMK^Q#X?I1ELBsOksc+J4ms&U0a5n%m)&pz_V<2eDHoYPoNhT|uH6Qjmd z^lXfr)?48HgZur=cb!m`o|nGs{Qv_w*9z%l0`!5%wd}CgawdC}1g11>(9*V<$5=4W zUZ0@5(?po_Ld*m&hkBTpj2i4a!GV1_@T?=Y%_Nz5Huo2 z5_vNP-M6(Rh#1Y!h$+{S`vXh+Ie_BK2uupxHU}Z%V8R!(|ER*`!svIT^F`PMECJ>5S;01y{J_GYgEX-%;sBHDZ4uIxNC6 z$7EWHAGR=eCJ5S*kt|<~p!@AiN=em&S{rQ-C*=b4EX1Y2U)W!>cjT_PItqsNXVb!I z$eA}d5%s4+-x~=td1KO5kTGb^p7BC(+I`q57d>Da@Ect)_Ap6qs`XEPR^{H-D&~Y; zMbCM|@dIG;>@hTt6YrnH7NFlttp_M>@t=J@b(I9XnN9HsQTGtMA z3wc}z_%35Dg7e1~wZTLXm}Wr-xykf^IzX>yhDpu@VV7fWrW%ZxXn@qU|#2^Gt zGPClrx^TPxTpk0Lu6#Q%S1iIVKW1U(m z|K7(tB1Vi}!ZNYw6`)2V)pVq#;VaQt5=5w|85XCL!K8Xg{_eXK1dPZOjD5iRJpc%A zjxO0m8&XesNSOOT_$dBmk4vn*T{snGd7hU6*zIh4lXS@AN|7NE<|b5Q5r%__&e4h( zy>+maxksyrk7pH92^hZ#ytk7|a483I_X4T?e5i(K33!gBRCvYY^fB35%+b*QtS77s zz!xml0m$5Ca6S-Rm!j$gKMS{`7%;Vmf<&I0-fxqO>w-tgmqCMEcuahNcYI4df*?8r zkZvb1-vHnxGME6G9i?uK+8*KEvXtAt2#F}2p3RW5oRhXyF*R0u-rr;t!a2;Q9bEsuB!lvI-P( zwe*+WNN08=nQwd8Hw|y%MV}?z%)H*;L=cB19SKlv6w-T}d@Usn(gE7kMn6DPNEwBu zPd0NQtPx-fvQN*34HKF(R`-U;BzF~g?S9xMm9-#WodrohT4TR8Asmv%DrHzWP6x9C zY)p4V1yX&v9jnvooO&*#o4PJ4Vl2__9nCV&IesX$874HE=2 znU8`!p&-Ac*8IUzNcB{9x6zGY?R9wf6~FmaWium6f-D=R;>TKe!*CFg;B! z0}pYK?m#=nmGe%{3I@DuzBd-7Z}{vAvE&sPEOYxZI$EvhT3)^zB+)hbgz&#wXjje5 z9(7C~$a}a3=R|}>*YYH5q+L{kzBNS#n+d8lg&NEvD&1ZXTLdDM;5-==?75Ws+Z@%i z62vc(*Ht64O&!w*;-j0)o0?bR;JAb*9~f232hE%)ZxFuVk2v50C|fy#JhKX=Vzy!V z>l=HB&9fKI#IW{qQpL;I@y3(FFY4Ea*SP`#1dk}lv`Yg4TgvYX_7r=<3dk#?7ueg0 zLQ6v5;Z#M~^BRnod|FT@ox*UX$z71fB|sFUHH7nJBaiENNT#*icerYoeFGG(heN=n z0)KVMY*NScfxL(6;M~~U5{De;=7hq{Dh(ahNlz>RAC}PeJ3;4wR&Wq=FIMdtg8QcJ zv@0pU_jg$x@~u$A%j7iHI4+d*N{OREn|%h1%U=WW6t=O8XI1n9`9~RmUm3{9(n zKU4`jb(N=GQJm#{bbV8BF2L4ooG-R*XUDc}+qRP(+qP}n+Ocih_747i?y3Lb)~)+6 zRr4~dr=MnO)#~n{^fO$n1c)u8Pmca_ScVkm)MA1`oW$H!&m`e}S#D1(xxg54U5;GoPD z7b6XsVbSdU)1M$rKSJnl84gE({r9!5U;`(hr@kiSY}(Q1mrHkm;)-%()(jycmGxzmI#Xou*-_^MqddZ5gW z(vFKdd^hV(_n&mp4X{|fko-w3_{3_UIi^8BtlETrw^|~FN4GE-`(98)5#V`)b0$?| zdq?XAzRMS&6Bp2o0fCNb(l)9aSUX63OtvD74=eVA=w;?FpmBx17rpg$Q{~f&-Cml= zK+9vSR($ZE;1V5T@_M|-F4?^@3137L$~_sC_S#7q*&0T1`=3v-H2C;tjzI_AUCLz; ze8gukK)rpcAoJ7qP+0#~ifPi+8CzpZ3z*zbfDeL*y^zg5;fQLJf7lGw6$goKH;*qrr zwT?Kxelgrmn)N4p+L6%mgN3aVvG!W);>CRCHCF041g}5WQ=Pc15A$1>1R3g@y1$sQ zMPi*oRQp5@r6CgyzgG<{%KQs{UKv?<{ zoyu%=B^BA03rfN+^NM=K^zr|pbHX`goj77Wi>8NzAzF_#)hD?>GGjxOPOpm^s2c*b zOT5==PheG4OEN$gWi9S z^+K7=Pwlg&a-YcsuycvBxn;3HbhU6YTbJCp`4=_(EQzySi|eB)duPCj@%hb9o03vaVo4s%>sNnHuL_0m z9o1_!PYvmb_0Jo#^n1+i1J;62?muZA!I(qH;Ao=+$Ol1vrjzgOmls2TY~oM7czKi7 zm!aWdW8`yF8%I~dWH?k;2q+Z}bx=6WJm<9LbU>w#|AdbkipMiy@|FDFh8;_^dQ!~Vg?j#?8!#hq^{TyYo|50wtJd(zNaToE?( zDFF(as`!yn_tO-@9{;79&A+s!b!N7CXy0cRLpAAzX5E4{niFMF`l4rDf7za ztG1P3XKCY5ojB1U?hX;!G9VFrvwFvN@#bJH$jrL6M*!ef(W_|+ukC>X~-$RJ! z;3dxe)KDiAC_GuRrtqgj@E#=@w7(F~&hA#LS9CudG5fP~4se=}iH*emIrpYqxWh0i zT64&9(v#-s=05Bcjd0>g7TF;hQ(KvLX0TD`@lh!Wsjo~qjrlqX{d{Qv<)CJ?eT`7z zAI1ev_xq3^vy&F1znL);hDCDUNz; zuvejA0o9agJ(i^L5EXDsN=(R;e6#qr-&T4{w;H_x?a(Nd6>LYo(vSPrCm?`m4~Q@1oX>)#(HN1)wFS#*D71d&Qv=z_oOenWfjZtu54v7hN3 zL+fD!dAHbX8_`R-$-Cn}zu$9!35;r;5xoQ6K(z(4zT(vK7=C~T%Yz1e9ZuirFf}M= zAbybMD5}T-!VN+!^=kQf_n$kZ{r65?h}6pSV4v=F2=4aF*#AoWKLvoL=Mb`pffAC@fbzKnS@cxW;`o`ZvbZv?eq&``~I^#J;!LE z$QGHAS-1(b%ndFx)62&2H6dzi1AC9YxU-JV$r{Ut0_LF0fK1^05F1CaN9IotyFqch zE5oWDnpQR@qrc~v9se?wAfK<|q?T^3o+R=QC&0(qAjexW zmzKSaNL?J6^hs1g-ijI2N9hkA_UkPj6C>-?o&h745rsUymEw7zTJ-|tux<1Ulfua) zA3a1RN?p=(jox!Tz)S8y1|r3s58nEF=Wiw%hjj2d{|asVQTfF-!ZHaF#!OAbm1nC? zSUZcm5|&7LcXkE1@gZ_|FqupvpmqcsRkM96$Z{4Xx$X~AI23hQF!+mnEoDLhY?!*! zKa#r^Vr{@PnC#V11%)q;MhICGwc#bIuJY>mbZ-Lmx5TN~*>DQ!;4`=TA-jY#HB$HM z(wkgbSDJf&CU*a~=uDi+X{^}ju(zjdqAP!PL60BEc!PBuK|QV5m^4W zsz+0P6H2)`F%B3<5uUqKn(o=;nKVEKz-s^C_;bg?#0Y$ow&O{1CkxD2>2cgVGHtMf zE|v7nNQ!BlwL6-r?{!uNxaOW~zJz}uqJ#(*E3coB!k7WcyhOyn_YHu?E9jwk)&jA8 z5H&Yvu!oVf$jVy6auvR@!>5{+MSPP+_JHoaWAmk#;roK=75|CGJv!9(e(zv|co0@U zuTGNT1EC$g{HNDmbGqUz;EWVrr}MmzpBJbhED=@wGAPj>!IFq(CpFwlWSRgQ1^<-T zxP@+m2J6EmgpC6H79XRhTK1Mqd>!aUS6$igkAWCUnWgHJ6U3Q6K3(6Vwf{v=mzXQo zz?TY;3gjvRpN(&(4BLzKjhT&+l%{T0_e5R=g%J(u6>|SRLh(E@P;A80%2}6O3ka6G2@Tjdpaf z_B?a7gVusSMddYnF3=EWX{EE}tiPUxS~L@tq~` z1PGL+gCcX?dQDxJuNKs~pGI z6t#!Iyb(b1#2f=~0sX|Q@Pk6Szq+3sB7jF4XvPLW9F^9EgSSG-Ina>yHxYEt>K_JO zk+!Kry}b#PJ?V3y2iCjzrJH~@10s+fZCK&Y3-t2-7P{4gPNzm()ckhwzuD%kN z66+@`u78ry=6>mn`ZVC+8paV%GnUYt@g6;amh}_bHHOyVD{OV6@LzknU;&!S!yBy! z0n3#Oe!7HzporYDBF4*DCJ;_BLWQ}B1Y5IjYx&lH-3Lc4$-%S^F%gB3Xd>{rPl{il z*NE0!9^z{EBGN~8xuNiTwJa<@NaYIopsC3JE&UCVR-|(oW`)wZ*%9kL<27IOfKW)a zg^lV&jI8g@7t|{S!?nx0v^5B-OR^*);0Cq=0SB9Wz6;(TisU;{N#rH{#(sGZ>Tv#kqTxNoJKPJx-uDwDB?fx2hkTC*6i@cLzZ@p7F?ROPe_2eU9r6u>CE*n z9YghUqdfeLZz@1+huNm>A;om?j0K1_SRXiOoP+!Mg-@w%_5kvO8{Q4*By2AV>@drm z{m3s214+$uz#6+pshZ9^vp7B{3joG&*ccjcrkphDXfzNh8k1R-?$M? zzIDZ0hRKmzb0km?>u8V>m*ws5Z|`O*KJ=;^=P1S>kFnr_&l&#Uzd;e=t_#-rxe%`7 z1}eqLbfNe;zaALrQ`bX}PLZKf3`QF&hHp7)*)qbkGWw)P{B_ccCJ>5+>0K!KA?EED&5ew3$cS zKPqZ1|Hav&0a#wG;H_&T_kzPEhJb2EO;?(5aTVwL;7$T}6B&v4Z-0?u zG1S%y`_e64D4HbmuEn~XOxl5q%8SOvc!K3kLg4oU6H+BX)UFGs`C7GsU?C8_i-$95 z!@Tm0$K34D7Y9261E*^1Y^!EY>~o6Bvx)1VUSjBCw_x&fBbU@HIO`VRcF08lwKJ4^tdy z{A9xQTbk-R$bYLvd(2h{(OBKplmrzus_it9KWO)u(Cl4WAXljE&)RHa2JbdjnN<0g zIUw)_i*eg5glbFxM1oDd_mLn`oR%%Tl2M3|t>$z>gpv~7ewNG+qHj`g>LJaaC&Ugi zN_4#jw0h%EWh$*xAuv6ZpwIhj@1d-Nf0W_9G zSQ}cROJCVe;b0Bb>7A^n>}&|z$+@5ABN(JL@xrMcJ{XC&5%a=hOpRlrQfBFa5=Em{ zonoISDNs!!O|9c?<(dU5YRweMiE?KDD$#@Vtq0yIHOaM6i;+uwixx=!V_dpqt<~VW zo90sXf_9O>ylp31k|qcAtp|jrRre77+OeA|P#3)7l{vFYay)tY0O|h2_Xko%f;+!Y z*x-9^s-wsQXYXXfshw+x%Xto+=pF8-mR+2nDj}A+!&_M+iHIerLVB;KlM!dgVAVx~ z_xEt9PR@hu+#rz4uXF=SOsx#b_zxt;CIS$OoT%v5_KTucduUo!7D8555@s~B+ZfIZEFOVDZls>`^{aG8SE}R;k<-Xn3sd+|lMaTkxq2 z{Vu9nF+*Ha!!`xvERi92`vPqK5DZ%Evn(V0JEs-on6!$pw}CRnb}oi9uYL6o$1t;>O(x`BVBfA($0|8%gB{3OdN`i!r>CdXC+c8WCqokAPFV2 zwoZ#o&Kl(0Y;1hjQ(Nc*UeaV%ND6F$?^+WXX^_00pYfYQRIQ`S@yHDam~u00%@n!B zS9tn5LO{|E9r;Gj=-j13*_@K7u#z$}v$EmK&iFwSz20E<&;cfa>OBF2%QvDO1V3{}t{bn!!YH#JjTIC55}ioDpZN56oC*pq zfy=_77hX0}?2$0xCBsLM6LRk{17zw#@6Cs+COokz3eu~I)La+qL?*;F-nMQs$Bn%x z9W%0sTqx5FSvL$PPaVNeDbtH58km9-sl2NLwPc@t1~#}qWj5?vp$#*2vB#Q9@^B&h zocbg;?DkeO_KuelSo3N0oX3dFM%xHg<&$Uh(JJEdSmVdd zm^J53dtZwFwk1Hq*nx*r^Oo^WtNHcmW^5LNNc2Dzc<-B@ls|J$=0vtiY9=CGZGcxJ zua;N|dUVoR4z4k9Syl^z2*377U&6}#KyC9RLV%z+>8|FRP(1sEb)gbV2?4*XETF1Q zEp-XJy&!le?8egnr9Q%jxq1DR@WQ?SgAR9NQ9?T8#d)7&pwb`0j}=*(4_+Me>jH>{ z{v~Xi^#b~*BRX!SZUyFFDqUb0!zo&F&B-CchvD+u-uLTtv{7z7NuJ8p>)_<@*akVO z<)0ih>G3i$AeifvAJvZ1s&+sffF_r+Wik{+at0 zPHk5dX9CgqnjM0=5oG2kTO>rGc;pY408cJY6#xFoCDcLRc&@4aCAm1S&=dn=4r&X} zN4aV?Ai{^+^Mi`+jRk#N(nMPN@XwISKMBld#YGM%H)Bbex-=1~`%3)<$BVl^)P!RT znF)}odR$czwWrSRjn$V&8q(rQHo%bX#058#4cY?)?1c5h*bpKybBmr*PzzcGMNfnL zur=%Hnu=SrG~JLRj~!?8Jyu3KJoRiAkKB55gtb+vgvgLs?y9wJT5O*T;m?dfXT$~=`P2i1e;4{uCX4>|juk!th^;R`MDjNcoNA8|6%A{pyka0F|*Pjys z<*?o+1VCPU=%Et1+lokmV`&ESAf8a%hi{foLE_7oTl0Se4UjT>UV0HQ^h_BbVNm?) zhY!ogfo0Fb9qK}W2ZODTu8F>$kwNUmSU)S}b~k5?FBA)o9KMTc@sZN+VxOPI_iEfBc#K z)z{LLmhpLph;wsuBv%nIU$-J5)9#(*6;9j1Lx<*A2K+`s&ozsKp$8q653!?apAagT zP_@8N5pHfPoY6~w3PL(^mum(c0gC*k^dRaJ);t;xSk278iM}V+E>;1bW)6{*eb)PR zgc%`0 zn0v5cVQhe;kWS6;&x4jGSsBEw|3-M)WqnGV^Ku!3M=`M2A?nLABFbj_r(Ey5%pDUL zo=l#1tJJ5Ngi5||q}^avqYBbI+;tm_jWp7x0l-$fI8jA9YRJ$p>y* z@40Xd#4@P$)DaY)M@DDWgtU9vBtJdZu+8267-LW;e(v zJQ@}*!m#%s|1(+H^OBK4iG|6|nE=m{fX8}5jFPz1u-N!UUOQ0C*V0MeelUGH{K)o4 zx+pkD`qhFPsiu6$6%v{vbFkeCD2(Y|{&!P`S&y%~L^T@jU2U#0^81VwM<{}450u@o$3MMKKW*)N~zHE`au;l6Vm;{RLQx{5RL*$x6A%=R3)l0R?SC9jKDx7Ak z7qo4?|4Dt-UPb$uY0M8Y zQp$nkmf5sEtly(~1lpjcCx#EJa_xMycXyCiAlh^f(Ovu1QxgnMg>+La2Ug?&G!l|0 z(qPzAXwLSiw5q$YfwE=?GRB=FI$snwM1FH0?S!?1Oz7(G&yFD0A)tbiJZ1ob>=C#!%QqK zrHx|ebqk?YDda1Ff#nw*?>udya_E`!f(0@2Bf`U4y2uP~>d3_l zGzbMYc5Q%WWO8bJTC!?*r`884>}h+~)^9$TN2e#B$vTzYTT#!$;?`$H&5?bX{sb54 zcm!Y>`Kcpi#q5)!vUUoq<)8%i|bQjM_D1kK5Z$kx)Ny@_Cf=ZvP3xna-fx;`AkCPqph` ztGV%!ifO;SU6ktyE7ICBI~ihAf|X~450#zs^$1AP{Q zU+G7hbza1qF&#VAcRj((1BN7+hd%i~75_Lgl{?3LHRo!?FB=7yK6?36K6}HRFW>$} z{FhEL*rBd$)2e4NP3iJ$p`;9g%YL9tz1Rj+d-)a=z>KTZ2(LuE@@U~;I&Qocb8{J7}mX%cc81l0rO$XAl_pHzheg*?z;)$^c2z> z#S-`?QRA5=X16~cD-K#HyPq0r#BOjem`Fh{q^}#A1JJKvopK}uWK?;D{@aBg@u=PoH_IY8_16*J|r37ij8f#|}&^=4@WZc-G93-EcUQ!Ww({Lv07(KtCYnOK z9q)Oxiv`WOy2nFFy2crPk@Lv9BjqM(X!9DvGhAjW15mEDem2tzwlQY%1I_g5@}?CRnrP>4>V_mxu<@_*-VXG-`&;NXo#e*HOw zVO=0TCX-uSWc`I{n3d?Qk~bI~vlQ0HB>sfpjxTl>17r$tc{GN^K+h*_CpnH1)15aN z7J>Oeo~;dYSh}~_U~Q{rViVPONh#!mbLm1k_!aGwQfWHjl#jFas*-myFEp^t84+xv zss?*VLR!_RoDmuqjl@JhPHB^_@-Wq~DNzw$I=LgFrebV-qN^V5A?I=cnH{7^1~zM+ zVGOEC065rzCXe^dgOd=ZvylFcNo#?bFR4QiJlGz%eEG=ns*3j zefR?F2dd$mO;P%G)PlvoxE=4t#~b7(AP7vRkRJ>n2fyp9AaE0`2Dv?wwbkZo%gs`pt(Qm@Jfg<*ynUA&;#Y4wPgl ztUxMs{oeGH(%EqspN|KmM4G-)_E7CJ7QnSKE5A9u7So>0ooWy_MlQ!))LwBODvdk{ zE*#q8&V2yrO*2q+wH5!=+g}kt&k#yd;4po0m+7b#56iRb9fu}Cd3tp~?W-`|aa!R# z~zE@a&Gb ztA(;QaS+dAfT%aq=-W3Yh8*mB#%}!v;_7^9H(_kh z3VI=U)I2^|me*fuFnN zk;9tw#Dx0y;Q_vf!?S^^^z(@a>!p}Z8Q7=6vm(Y&Ac!gUZ3jQ0eRAPzh8M(F5u_0fts_oE@)!O32rBZg*U&n1Yj0R9zapLmZ zfn| zPRZSjp+%AxFZyIM#IvrQHxPwq7S;#geI|9`kV7(%Fp~xj)<5v%rk_CeR{k@d(K7if zo)X{4L>%`A7HE(}@Vhg;*P7sJ<17@)a{~AC@f8Hw3xNwx?a+@zCK<&gYFu03H-mtx znO_q<5K%Se4QtsU;f3}e4mv-E-@p@>E6uNvdC7SI^liawlnLm*`1j<9Ro@yQyG{?b z3SQv+HXZ_8Qla8_Kwa@@#K3vHUla%g6&^F<;wn%)+0t2mn6D}TR%zp~c=}~07g7!d zek?M|73OyeQrwpw@Ro~XqQ6g4{*IDdhk)a$Sh3U5DFtZc`7sBSLl_h;5!pgvBRQ5z z0UbP09As_v{*KJ2n;CBw>xCqZ^IfCAdIUn1KVp}udq>$X493OYI7a@YzNEkCyi9wa z=p9n^v8c=e^)qPH`4~TbCt~1nLWdr3{a0UQy=Wj+yFh2@L%e`qg@cc-3-(4kmRmYoW7JQ=XPgDsPIoTfvU)jhUXBxR_x@-&zGQRY$(37l#|2Tb5M% zawTHAxigcC8UlbY=w} zcKOuRYqWpGEdkwp@ng^ybX7y`@TP6G98Kp*9Bc#y@VG&!OVg9s+LGWDc9`nUQTu;e z2JgsbfHhD7aw(Z__1^m7R4;+Ni{zt@7=Y9ost7{WOkBn5nLG0T4IU7OBT|O?`LBm# z!n&W>y~(mg0Tg}UU{Qsp6Fg=@;I;%<5&GFbnkC>t4bZwi3@t>}+`+h$U|={T>2>uY zf40yD&AEk6)tk1mYhpSnD z*S14cu~+rOV}8*GyBG3u!Fb!|AwO4q`AgKOhM{7H+tUEJB2c-nN*HVTecs6(=V~`Q zHi}+)Z2X=AzLm&*XxfR|ULtH(C4%AwANf1Euuha2#*@)Ie{+B71EPAt2|4?|w)gS@lS&ny)t}1JGG}(c))uN0vpN8fcvU4RR8;{Pt4JY^g zx=IjHV59+-_z4u0!Lc*X^T1V()`-+hB5YbE0_6oC<>dc{gVT6EA>}yKm2}%oY}&;2 zYvL6pR3tBFZOM_V>HJ$U{V{gyCC+;nyF7eqEX9GW->i&0my+^9g-4s8i(}d%@9gyi z8it7Vse*1P5gfV?F38JX{Ku?v2<0z6k{$H?YGFc1HzxnwwS!fYVh#opbn<=e(GDXN zSSz>QGX3=lf)1U(4hD-CF{ypMo5h=F?XK!fzylpL_kAmS9TFTx?p|yeNf6^+E}xXl z{(S-)r&WSUiJvK57{n_)HvG7b!oMsa%QK^So}%2z_SB(XD&Tc?yTyi1C8oIN8XM(5 z_t>oEJVhWOD8e-pLQ>5hvv_V1$=ooTt9bE%XtYvi6TpvZqHpsHRsQO|l%o?w+?O;@CXHH_JXU1QIL5*RX3iPc`@?l=9%wKPoW_TQnM+gSWf{NLs_I2T$RXmjC z4u@Y-A>`L3k$Eaak=x$%vgk!dm(i*p*Fk7A_N2|G;--^t5zYyt0R7RwM=PBrbmZ7g zLDFAXroOLfsdw97#Gsm?heY`8Hu0&bMIN{(Ry{I_*&`Sogw}~v7hO~|bRLVgJG1MO z7~%sWTD=X)6BQ*G%psdRrJo(OJQnsGKRWC67~}vFprhQH~lI8-tWaz$u89M~Rx!bfZFjhWa-L zET`oX|cmo|fuY~p9Rpno+yeA8TN^C**+TU5 zZ?34$wsu_WX;L*lEakTKYDnm9o2Y6bETo1ny8m$d)tW3ONq(5SESI?@5#RadQdl3} ze!_;clw})$zFF73tnd#h%{tb_q@>n39^O-Gm3kTcnS992F0m5AI>e0oDjwQI%Ir@p zQS4y+n+I)A!T`8Q8C1&wy_~59Lff;F!4EoVgW77E8?(-|$KIZ&fQOgP)GQtKV&MQ- z-4Oo>o!@B{feUTgR*8vif3B3T)Rs`t(y@)+;l$IVu;;5N+-Fksv#=mRZQ@8DaU}B> zH|ww3br<@Fo0vVzu4jZuHYqn^qiDA&;AP??U-A8m6nIXMS96$m(Lc@c4XYs+7LS9e z^_brsJC(ic(&?<^v>n(VPo&eaLt+I$KIfbPF9AKq%CQ11)Npxy8`PZGq%l7tsI{ev zCKZ7h@w9)79fL;>rGfY!zhcDR|CE@JLm8Wh$11Q2-TL9y>Yb;PDEPI;>$Au>XFOx? zjLCIjG!7DvPmor&migYc!f6iLFdB|8&y`VFx{cKfWioR&*s<+;mpt<=|S8oPe+yUQAC)j! zcz1r)5!0{>UC7-YK9Qh}qeLxB{W$WnyAzRBG$!5V#o(WaCraA`JFAEMvMB$8kKCeH zxu!A*ig)^;9%sM(43X8mNk-jeS=YZUkuxF15BIhuy6h;4mN~;@O}UFLUrx>I zH%7RdI&j$#yD>^`jQ5+}3L;yL6^QYHsHCXS(~{Ab=!W0+vW=UD0qzKo?;bSrdtE3` z`HT)~vXu(n^zol5rqcZo&a8li{ln@l?QxUv0=Ph9P&!!FVzWy*2MuM@4s|RzHafC*xEucXM3)piQq#m@LJBY<>4vSrV>>xu2OfEcJhD?+|6(!VG z8CNn*sPPKTKX~HJbR{f!lC{C^)r^!Hs~&*9*G6(=$+_ptGOCOaT{c^biMOlRPdU=U z`|UT88o(-v%7v1wX^$q3B3B@@f_zI0I)T#PIOlq{DfJc1dxFj2cj)S#m9u$gP~#lM zqT5}robQ%~*iIB;fw6D_5$5o$}1{APPHemGrmjuWW*Y-bhB(ab{?9%y$MkABO2 zSBZG9Kz3wJPWjUrhp>h10@IITF?qX*8d*E@D2X>E)@VU9URv+Bi)6SqyO0xPNyy}5 ziPkx+^3+y9ki_4X`x{K_c(exUV(Oz96M6(W&m>(Jgfv_Ig8lKJd(8?dUS)PiR_HT7 zsLzL*!7tdFS@UBf$UaimVjLDxBaKbL<(Z_4{rp@j9uG~zt!UqLt0U%d6}f?qpvQli zZdxk^0g+iR+upa{82^zMon|nf-J^CN*v3PlR0Oq$!RrI19EsPD$Ymk?jpft)@^{Lo zMW|cd@GfppM)bHyO(BX8=`=@`U12`Mm&&a`)NQNOHdU*CEJQzpCwNpx|i73E?XmeX`+q(#)f-w%FcleP)s#=S1Hd1CLfY3|t zC3P7W!e+UzIS?~OgAc$_ly}2&SjvbHvXwk3j?N>Nd z3I0$$c7zK!AR%V?0ISJx+zUy^mdLFKg^W#O)YpRA92M&Y~I2dXbNeIq_5Z0Wq^d5KW?nL z#|-hhpKUcbdItYi|8MJ6u5)O9kpKS6koVx&#C`YK#vDJIZTQk8QFTZ`9e*cyKP|W$J81uGwmSzy_59G%5(31mQ}+AR)vGU2T*4YvrC% z=1V_H7V_&rY77*9nrQ~zRz->R&|o5TqX|HPubt{*v6J#Oyz){2N&rk#?bnmPgw(8M()5yCGv^`cY_c!MR58Sw5F|GLTmbvl$_EGV%4OT3X~9cgkB4NaLTASx%@c#^#AA>HjYSap+)hQ4VXe&IY|6@>5P@GApcJB##4v zuw~#}k5~RI_kCkpb+4gPmG{{FeTV+<8VDhG<`6Jljd|aBkY35|&scTYN9Y*T0E8xR)BoJ^p3(4!hoWE1o;(-=S zw&H9ibnbd)+0bgxWFnx5Gz(g#u|xkzx}5F)H!esn2NH%Nos$FV4t_68Tm2;TR70~Q zd1DaZRFA6^9S^Qzsff6=8YHXZL+xDB$S+@sm_eh2g9*Y8hD64oeION-H0gaOG~y9y ziA6O6i;fUJw*;Od6RyC#ORqTW6fivjTtbYGpw`iyE_(XC|LYyg>-E|2{A2WC2ad&K z81Yie%&46H<>duD&lZ;2O?w=8x(&LJ36vV)_DWa*O$oIUia0I z&@@|Rp)JX=&D@oqw8(VD5Cxtq-cr?MtR}6!1)8-2KWr%27&0hH<@owjD3E#jC+#&; zz_eJ6j&czJt)WAlp=~h5uSycUlL~$$F}0APJ<|7XlFOsX8o;tbQ=D?0OOJTSQzuyn z&I<}IY#|Ge{E0-6UvxZ$K3;NoCo9o};`=?0A*+4T4Q8}1NS2Own6O+7vW*I9EGeys zsUyn&W{TIn&I*QoiMBA|b}CsVYlwe-F^_%3gBXg0r#d@|H^Bd$fod*>#<8*|-X7|; zPZnCzz?^-4zbvGmV5gSfY*f;lbo>mInn@Eh=63%jnDGr|R_IkwWX&8|C-p0)+wtYy&PPie!W6+0=n0`WVmbszrZ-?KX#siu^UQZ<#nbF0_)){{BE|j!q zo!8LAqD(lh*xeB@-ZxXyhC99^?b`&F4^1XCG7IF~Lli=N!r7;Y*0ZocIq_{xy6hI1 z=U(WIW2L!tX}6Emg7Z{M1UBx#Ozo<1j*O!E{QgdU-&1*nLmXzDN$AEc?*FOwh0cOX zY5|{rj6q<)JpXTE^dc-=K~!%$l1WhU&L8J$p4%rr`L$CVdm&iJ2%;ees{aFo9zB;Q ze+-#)Fy9FWTGZSH-m+;dihFj15(%oDSM!WWgp^uM2ri=pO4MokL`n2LJX(uM;ml)o zBTikG+E0E-eT%^VSABEU_eK1j(+xoH;j+}Yh8W&s4z`E&+HT`@VCd|N{($7z7PjGF zB~iLcCyPe=gJF(i07DU(AD&q>z}bpi7_R0D^_+Fmv`k^yvivy{LbMSn2bQS%oHd+p zQdZ_uPoN!AOwpjyex<%%zH`a5ae;PX(CkB^LDnFO_*%^O@NZZw&BU9Qz#WLubhOyM z;~K8@mn*J@h9V;Ca>_q-SZw960J$g;_aIUa>o_k|m{v1k9b;KafRJul!OCUm$0< zdxmVKIVDVap)mJhAbM@K7h{!`=Ww=bg=UFrzR3_!wn8l_73+@Kd;iS2iej~)1N4BZ zGv=vS;G>Ld+G0V6T60C1U~)~)xj?GlZ4KXd{m_we$84O1Wafr(lIYxZ_v#``=g%`(O15mn+%cAwpgln7u{|k>XY$ ze{4IsSLdn{UOGkISf<%Ku7*HEOy!>Mx0_al6rYCi5Cw z`i=zfrmk}5!%Z&IH@5PX47Y!4O{#CvsBcdSj>L`wLBNB2@$McD%??0wpQf+v-~_9e zdhEy#C2Lt6_UjI4eka##lR;h#*t}wkl9G=uoj_CLt@M=jcn|kDwUEU*8&aO)K4JNN z<7S2&<*00whNG&p+@4ub(eiPQJJKUU;&X;qvIJ#}Nr+h$E7C&?$gS|Gs7qcepnmj; z7DFhh7XUBL7aw5f1@VX$m3XBzFKZIRcB`qS+b23Z0e|zk$j|cXJ*h!`W!`-ldMZwQ z-rW9O&fM+AZOMxtZSpI&O6r3^g@wReY!uaWZ)0INN%H)*@~23Cz=FKG2}Vl~?(@?& zBwm`IZ$zYv-F3ntMe*|hpF;L8(>V|}=>L5uIj@f{bgGQ+N5=rO?EW7&GkS1PAX*qg z<$rEw3R?~MOf%z>2F3rpg5V71Kzip|kn69s27FA-a##Dazzaf0_imS6jLK>UL9$!gtk774fIbTh&(40?ANK`YymNN>g zqM?!i0fqmwPy-SHMpVEHJNn93t(1oo*M8R-{v$M1SbzD5y#HV87o=da4##juFo3#*K zDi6y%l`tJd5GPA&DWi+q@J_h)vdg`f9!>FvaNyfN=WEkm86dJw^H4NLIUQ|7_@4E$ zA1H}l+~ksxjbo(u41v9qa4aTfK4c@y60@vDpZVuTI&U2yBQlh5Ux7|P_#7I3Ld299 z50e?3`BuUGTIAA>3K51hNk{nPm84&dwqj@5;&MEQE3Bwe0)_GhUOj@!wW6zY!jBk> z@~4&c?z_l|w~ARlW7=U%>nji8<3r0za@~2fMJGtLv(xb@`puEy zfH~Lc4I`j@Xm)kkM{>5qlIy4Q*G)OWILr(d<^loGCbx2SK%?Lz|zn? z@rHU=OvahEWTjnfTc;Axi(zJq6z(R_^db|Uvnu|eK7fNYVQxYYd($6zCfNGduP|l2 zU6sloZ}o{?kYu~4ocLwhB&qxCUP%rF@EN14q! z@Zia@Smfw$LY{7uM7sXdrBv)-aZw38020{qH z?~=@JOBzEbiK!*e>6?@Xniah+V5g=BJ6U#3dqpz+$QV$Ol8(G zqs17M{}dsYCYQNjNuRV@#+VxHgXD`1DT;HMTz6iv zo&m+<&p-s^j@7%ILXI#O;!JK%V>cqsLYW_-pcZ~vR;6QjozBQ+<0ofj+L{`SISLFbH7QaMjiRf{h`i<*ci%+i82n95yo~^=r%pB6o5H0{;RiB zb`hW?r#|<=leKb>r(#2G+7G%g_#jM)6Z$uJ%FLCw_iQOQZyVVe}&r z<8_o znJk>`q4PDM?M|srdx(1y3ofYb+Mi(82m{ON_i)6nKLQg;5NO!TDJs{$ZZz=rHBxd^ zJNHOU(E8KC*dNy&4BTJ%#`L8|ieTGbBcs6=aw`A!PhL)ai2i4jTF2Xt4dq|}GSXc# ztQkSRW&G<8dO<2Xk%f>8|5J3o^bR_yW;=(828*{D$^CHRd^O85*dVrl7B&AGxInw?BJ?Qt?+LOUD8vY(W!22gxsD?=0^#%n1#lW@D`kV@eU|hdLu{_u z1n_Sx`ytQ4lO1UYf03;# z7;o!D(&5Umm2|2Hm6Aoe>3VobsSKs5;=itorqRt0zj%)Ci4MLwgLFM3mMeu?cxXY~ z2yYH}3%WCRXc;nuCs*WUyW9=|cjawuwPLSo7Zs(L5A1s}r}3Q}tbK&b2gH`yuXzS= z>#BUtBa?8_Onv@o&RYDG12i$4y*z*9)Iqoe`?9=?1Zl3p{Gp+4ZF*TZ8}dilgP0mT z6E89g4ynfRZzpd*j{qqq@)Y@zMGB;fDidxe~=g#^!-b87d}T!+d^bJ zp~Ad244_RDLBl{Y7q+4?D=PGyv-0e$b80;;W%zR9=n}9GuLzTIbAwbYbUWHy)-5y1 zT~;ykl7TlJ6|=P6OwEyRVrOwUp^LbM{p$Gv$8gW*+I;E|RTn3|p0YYhrJwyiH7)4=sn2dh2zKK1JFI9fYhbJOG$g3rVSG-!&n zXrVi}qf0SLQY}B#u(kp#Dr~s|akcixZraRQHcj*ncU#JjWDj@xzVWj0`mV3OE?M}g zDSRD-L2wEnXBkD@2G?lNsI1GjKyx8Sy0k^EyU6541E|&!8?tRQ!LlF(>7*`UjA9+S z;#N()8?De!6`~kwm}4WTZMefX^?r7A8~uCdg0(~ga#>n`S1<6kaB`fX&-9w}uVqLsErf~BQmv1XFYl;8^9(>NtvMk$(|Q+#RFcuQqsiBD4fMnCqvE~J z#&G`%w|8TMFFj4r=xlhz#17s_@uhTh*%=p^d5bu-CQE=YK+inrlPbGm#?0bEcQYNZ zM-pON%2z=VbX)s?Y`mg{6b2*h{!3|xs@MhIDA#W+L-8PgjTBDM8=c|u7Q>JQ_7&7S#*GJM&BeYY ziekf2XbyV?PvG!-abiIfFoCMmqn9!a@caL(I{2%Yo8g#f?u&y}f$~%LRd&h7=17`X z9dTAzU2KS>yxh_}+jxgh6^oR)9uVjG=VIl3IThD-4;ucAGBP0-s6*;_v4kEEf%v_d zK%@95F5MAbzXc`meM}M1c|~T|3{T>DYp2vQ%^A?O7W)|lY%HRgTeZry2xHc1FDjyn zbxb>=YY1Wbrf&7U4rxX3I5eN(0D0Ie2LuvtqW|CwcM_oThMKjoe23@BMs#Azc((td z>^z<18&1x2?kcOh&sKJp8XJB2wM?Qqbta% zV{iVsoIcaoJvIe+p-SWl`UP8Ox=wi9u`Hv6aI%?B83-5I0&6IU8AUPYmI?NK?AO9O zp7vv%s&bTGuUpFR{$ESfwr}MjyP4JdQ}=|k>HxZ~$KLlg#rn2$Pb zVyvF0af9_tb@-|=5>$3=ok`uN0J_l;6&4$#xBMzv`wte&GiAM%r9@oK@S$`y&*$4e zaV!*h$rE1NjNkf8VR&s!*?Q5b=v7?sHu3d!0UT@RfNrG#4>zy4o(NH>O4Z+vznc~` zWryau1$yU{;IGuba0`9cuX`fchdc2oT`kJ+lqW?}UMGBVhwT6?oXmsv;-HsuUXQIC zLN9p~O7&6C^gQ;{NZ}QUvY&O^m!Mt{MM?__uoOT+F!N%Fz!Tod&%y5LclY-!wGddM zYafGNA#Mse%oy&0O~l!7gkxJ%)3;%tkIly^ONqH%Mf5s3>Mi)7g;)z0svk|#k{Pw} zkuP+6%I}S_+8UGI1i6dB))I`=B2++HNhrZ%zwxH6fs^A`n7YHF+={>)WXAGHK}0qv zVuZ_J)?_T!_MH=p(cc^kkk&+B%`JMe*lrw~cPi3R^j4ZSp_~owx6nazAbMS8k!Opi*EY z8a)g?Q3#e-P~3pm=54q7(ne2`fJ8TFveF>k^fW!BA<&b_L6F;DJ77wr+MJzyqKk)S zpbsgMJ|zYB*6ZicXQ1Fjh;!>_)Xd4`B`@9QI<5aM#0i+aSL)>a_K6Dd(-Kr)F)~?^ z1=-4Gm^n?T&!)zL;jqeD7V6JTI7w6w`TM~8P0}I@q8^Npj49T9N2~nY9dr{IGu#ZA zhaBa+kG-^b<;*QA`M_Kp-l2 zt}b7at(h*-ge$+AkC<~E z?wO?Eb!0LYpN!_9mYmZd4ZHu>Vrd7%sWSTx22M~zk>zbPx_NZYb6(`f?47xkrn;-Y zuw%x--b#@jVdXydavhu3?=*_$6|=T~c$*%X3k!*&q!AdO2)RWWxJ{zrYLEaPog}g$ zENWGbtUK>AyI?6&F#WGXhQr_RhJl^EA)^eo!*Ds7^IzhPEh(_CW3Fk#z$xlrs|Xf{ zFYF>sC`VAsRNRD8qS!L!EoDPmXV9;&avbv3Q9cl_M4~!CfnW%JpL)XQdSuU{NiT0# z&Q}pkEG#10w};{|wnx|<@bpk6R`_m`5VkJdxNujB5T+~59-`*%lSeWyE=|*Y9F!%^4)8*6kASGg75CyB}ojmXlym1rP~lnEBO(96iPt1(S`^ zCdxED%UKb1Y!kOD6NK!J!tViuyKV`p zfpUsQYtSx`rXHYk14tiX&_h!+P?gJZ;CV#zI!91+kYrT0n^;e#~Qd0~<`}&K{ zK*uRnj^@e*imjr$zcS60nEJ}pvGfd?`Cc4Dki#$$9;3MmbFtXz$C+cmHitPr$CR4a zIY9Y9#6j>x(*U8P6|APba|jyr?w6jP3{|bx|#NfALm1!QRm$s)bqp={JTsD z8=d0p`MoH+_f+Mwj~=(QIG{f`-((F*-xAEfQ0Gr)*Pft3O3f;xyif2ZYYr1E*+k&d zBpbF8f2%BYi;GcBJnqTt!DK-qj=(tIhW*t&-K*6eMp_t~IWzvn;0U2~jn`+Ae{`|~ zip9sk)a#8Nfry@%iqSO)gI!sCEtD78{4nd*u^Y8gHp9xB^3VsJA2%D$5cD+nZ`2!W zCE8g>q+ntNhnf-Ve?*Av7bxwcIzcyg29ve^^#ix66!N9C4&rvcBZwqQqF;}Hd0YIQ zgaaAob)xP!6oB$>Jy&?HPcoL1m6$fjJMZH`KA6vUWn6X0S|dgyEJ4_vbq(}IRHNJ$QOL{$KQ`P%%%Gv!MuES{Ft*N zrg;axf=@B@f}z4%h-Ir+0ZRhJC^an|QoEgrK>WnJQcpkeprT(`$&`bR)ct=6d+-}npo&yy8AuqDe`7Qp*g)$(UmT_EWDir)MN zzO@jW1)HRNbx2P9$ukXRn-;H6RljLf5Tc_m zxDJ~I{AGuvhXHUG7}j)VZi3?LPzwQXH0qwca;LA4^o$t5vH*f6D-CTnH00 zGUMxFBiZU6H4G@|CHn5`c#+ z510=LCLP|z2_!3zO8Y6HGy$!0a%qC>!ZTOo->h(3WfE6!%xR{gPE4*)TC2ev%+7>c zh+t!tCCtA;;7(BGW%%!}Oo#z;u8eCu%cT(sOIidaY5-4#ZzuO3wB}opycq7?)@sU) zr7kZ^kY&{gO3*4HK^{GwnorQDqJIf>P`|W*V00)VLP&_a$j#f_P6J~4VNSQ#lclRh z(@F+bSW|tt-OUHfUp;Agy1S`XpI^#_B91mGOiQq^(b9U=2|5M`Qgzs4C7%|e{7%Ds zI%$6E5xuo*9m!AXd2N!-HluI$SN>)CYiT|qz4!Ew%6q)Y8$dyv2p=`cjBAXaML~3e z{>TVobrN8t@8NT8nq4|fmIYr|X^WBFUk8eun5Sa}pCzx=`qQmjq%}lyV%S1(a!EEa zGO-Q$A%YM?_dfmWsyyXVx8ZJm!m7MMXhsWErEi;w=eHOe(HSt*%b3M}ouGuCdZS^a0CrvyPGfht&ot z|1;n3v7L=FGZ<50zJsANiZAX078gnhwNoWEhg~7Gpi2IIUr^b@HWb}&VgcUO1WRR` z^(9A_?K{hI+{;5mab*ZEFa0uog zbK6Imi^E|_l^DUn+tH98567;Var;u9CWeh<>`M7(R@J1T z{KeAr=^8E15!3j48CfAO_pi(eicf_7JUBs?9c5J2Sy$Hy>ps&HB0D$Tm zcyM_nk!VTichG}?lXy?CF*Nmvrd#yjV^6}@Fvssdvk0ocK&JVm)f|o7v$G^EDM8{j z%>ngU`XI62ZAOr|J|depx6!sx@|p(QDa9jfCp--3@1mvHCarZNn%UO)^BxSwTorL7 zsEQ=u7sS#`I4&g~DWLuolp31Vb27JJ0L|$sw^bvfhB`kR!u5AI;!BXh0h47R9q!$- zQn5vQe36?B5bG^(#H`b2Gsf-*RD2?`gVNAMJFwoE-d8vDy#X%ui)1Q8oY^9uPt6Q& z@&HxSkj@m}^ddcNu4LqT!a;ul+n*5Aic=hYEPSwIBu$Of)ywihCyaEcVdRozxOXQg z>~NbC5f|>kK>|ER6^}wM{~4N@Fl~T zESk`&ymah3Erxd0;i5aS&tb|B`>Gcu%da2DxGiB7(aBoK`Zm$cj|V2elY8H>)UWfV zLvs?4C#}}#Kx(vaY3nTP8woSr;&riJOBI%Wr}j)1>Cy9{0hUUJ7hjNyZ#V%3+3R~$ zUAW3;Y^o@lyz^lcuzqqYnh0FKAKwER zPBBuk;LjY4C0WbSxFqahG}VZ!xE-jN0<=s}HT z>(P*OI@w7%gb@e1Ef%=MOGQNjI<-T1t)%&7W^;1u22vE5c%Zed0lFcSRmn`66qI3C ziLa;<5~t9SbF5{OoD0Q@{df5!HouZvCI0qPGaRhrOGxhLeATwrtVIp@T{-|L~++HSsY-i0^R|I6$!NP=9~&Bt9ebi;;>qkpSVG00Jpqh7zJ zwCy=SJ8MS1u5hAotuo9G`vV-NydkqJWJcHSLwfpaZ~BL)+mi%@(#9pk;I!W1Dx{%^ zt8xdILlj0vDGL`~1F($QdSKTjoI-Y$O20lX7JGop=qsKu-yBvX59J*`K0I@U+o6w_ zU!)FX`EL3Q8!VZNE7i+w5Kt54qY{NEasw(7^F@EgR0?w5Z%a``rV7HnBV{T*pk)<} z^Z>K=@9;pePZTXsmxCrN++uYHk*0ijHduTU!8q^w6rt>u-)6Bc`YyXBU=*PRjCG9++$O?(JC`qkdi!k!j4CKHGuQ_X@sW} zR)V1BRQytix-9Hu(aZ12t#-%Z3&Bm_)b)v~0)Y#Ix=y*324q zgU-^GzgP;CLut3G`$54V3;P*zVyY=ABBVnE9z6eYw!j&c(?+If-(Tj2b{01eGs_6? z=jnHWF%4IV!ln^zK4*akUKm?#X;v89k-i{MrP)Ip8O3MyoVq&iQ5Lic&x!ZZ zTO-;CYKKpWTi&Nz#D7+?-w6T2m4bijNS;gA=!eC_58bSgCY!${T&30hfZ9KivE+DF zVwDerjIRS=Po6F3Kk^_BL%_+K3V7d~JI|Sz4fB9x_Wq7WgX@Hoj~_}K2QRBP)PF*x zzU2`h2C*lnk})05*ITgm$+;w3Z7;`=kL-mq81ARYQbLSEirGYSSl{4;KfI~0M(MZ; zPd3@=`3>8}aQ0ks2Z{6>KlFv>?4cQc?<<_1p}K30s)}q&eS`%s zCwd~UlQ@$KGZqAM5$KmnDxa!#m-_Gzik9OOngG3NM5JH}$Nu*zvG8>RenUyk0Yumf z$<^LbhlJw8$zUrA(x)Qjd6?X2BXdOqWUwXJC}|pdiVhhmu$-vK@ko)VBUC8^Hq_zT zPNIR@GuKg@X;G4?n8HaH$^Cs^b>8vo5yU`^pn(?%Zs+VSb%6qR4l2g@JM%F-IrXEG zL5O<+ig+>})^PX<@`TkmRwjMnWQJi@QcKNUK;Hv2x@>#Ks|$uEE|&0tgT0!5tVWh>ymd5>Y|uY}CTDd;JRGQO8_P+-Ycm-{wu^ zM}im=9506H2$wr|0jbSvM`CA~S`EIk5<m-mJ=yJVzVkBE`!$ zk{WFglVAj{Wrzg29a^KtLbEAa_{gK@;(`1PVGRiVL9Gd~d~^;yFO5^? zW~Rq{dR`Z4c}r8G+-;^HUj%2*7n15sw8%pU7ugWlKSpu)#}G>JCjyNcrSzn1Kx7Y1VkafxsRbEHB}x)L^@I`Q|++=YaPv~sSImiP+w)YhUy7o3*0 z2gRVv&4H5K2_O&o(#^UQIutUemT_s8n!rknhNkEUh)8j3GD;^ER?N;E7IS}muS8aq z$@ix?@i{#}833HW<#xv%eN^AT(bNHyv5;5L1eA)=@QPO9?UPHphM8e#l`%Oh3|%pp z*6e2jCaF8JpboUqBF#ipFN+QV6+@Q<|F}n4r+9>1ltw5K9R3kL1&HSLaW&dIo7!b8 zQPpSE(c>(`_u^m&U;aHSY%609dlN$vsBupog0#<=K;G{6pqlCt9|dzVZ1W1kh7d>h z>pw?q31NH*xGKLrPezShqhnzZut_FmrdOHY zG5BNh4u!tz{0(TrVa-GJnB$QhULb`0ThEFYp)b9iKRpO9Cy9+Wef%GNp3+GIqZJB5 z<%B5k3t}=9cdqM>FG^fL@BV(jl%j2Q=S+{S8gGh?$ckFYcPLqCk}x-o1_)4rsx-bm zNt;E<&n~g)V7@2RU~aqA?YgvXNMn=Dp(Bcteg7kPf&ybLNPKw5(fwuWzIT?b z-c+9p)xdenwA0PsyE;Q;{{B)NGp5y=7P68kW%fE-ocZygEe^4p&g7QQCDf8Qk^_E} zS&t}!en=3IUyVQH#7CpnM+$*D;4jMb1_%{Dxo0n=g%%1#BG1e(|EZ%1u8ZMSp;@j1pDf{;~#uyPOJmE=LHzI5dJq?ZpLU6dxcmpG-%LZnQcdU4+WE~L97Ys|T!O&vWB z50s+~ze{9~K0rLbt4rx+@2PcoC@6D5H!)|O7Y-N99g!PbI%e%M;BWem@fHx952>05 zw>Vs2i%tg^z6Xv}W+(>SsbM1?W=<#Uybcs{Ju~`Ba0|qV92TGOUm^YoKjoc)JhRAj zNalh9!iD6p#=QcjUI36kyK`G+S=2iBwt8Ic)^hh) zx99+hY|HsliKbl8r;eM8G0%B6#Ygz1#m&#Pik}Ur<8jf)Cb6hY$qaFS{bSR7&-=xM z5h+%b8_797-X(ObyL#VYq3A~ERS#8RyjYU+3;8R4dqk}%QO-e9`MF4GgeNiu?)fXD zhZf2Z#9u(0Gl5Rq4l(-%71P-Ra zEE9p{&UNby=P1K`=6wvMoGeK%zrN24fjNx`C*0h(<@iBBA-MOhn!39w!axPOsooscEPp?wHhC z(Og?Zyz8OSyE(TPQSPUs%9?UmrSu(z?YLDAwC(NX1b(jaFyN31HYC1=haj5GFU)uf zbOvHd3hn`7NWHUL&J1a-!HJB=NF&m(eU7$QB%r9YcYptv{@C&v+u;muDa61rdR-eo z`m*2Q=dtZzwMt8Qyi||N&&f?jBOS)p0Ny4Ht>}n-h2ZkC6`t`)Yo;|%+F!00zI$3z zqH_c!QT!2igjlR1e>{$WTBCC9b^UVll-l&U+!H4L!P0$8VAoU1rt~CXf(V6q+J8Lu zvI1kWX=0B~qknM4H=S0M?nvg1@j>W87x?+-1Xbx;lfvpR@7(IqEjWeEh#9m6yH&N& z-a z8U2Z}9i|=&xfRm*5j76-us;+58GZw591F7|sI#vX+9L$(ZAoVs5n#mXKaWKx2!G7& z6j;okQMDC*b4k~4&4#i2%K-jaMbLBAC``V7_QSqK-cW$gUL{yfG>v{h7VsR0q!6p+ z5LCksk+~yg14^(Xaf@xJxjI3VqzYvKK4eF9b+d{x?PwR`hY(z7VDH9Rd41)^>j*L7ApOBu69WiP7$rk6XdxjKi3|`$L8jsXgF^U7 zZ$u>a42N!>JjphK#cJ?D`GoKY{YbwN#USNGZrVT*%vRacI%!+82uz!6EGsmyabG&#IH;D`-EXRY)!H$^RWZCWHG!3|a>F-H2 zia2el0!el?)K|JXvynKI(AP=l?TS^UZ2q7H*|t@ z3I>H0-am=_XxvEK`lZ#Xs?#59EESToT)Vd0jA*?^pab~9*^CGm= zJb!~m;*0Wzs2RIU;;;glA=W~SP%JDyNW7Gev-KP)lpD0B;Oc{hDD~-Kj|2ifBGjh0 zWo<0RAJ9s5ly)DQYlEkQx_lWdVB4`dgIqn&htmZFv)fE=h%)Uq~)#`LWns#S%3uY z4@(}dV*0&5eTmPll^_@!z4~{fUyht8w)i%nGGaz@V5$g#mG!hr>if_fcge)st7~um zNhh*PnqzAb1iz8WH%G-R))Dq7Q0gfU=WX?_Tk6R9`eUwImx~I)$X%QBJYNe*_E)kE zIG+_qm!;cM{nz;so(P!IUiy8Y4Wow^4?B19I0F8{@P(%SyH6_BOCBi>l1SK7GFl;}e^kY76i546;X(d4JKGbcQ zGZ(y1XG2oruXZHM_lpopAJis6>vwIxn3WO6SSyGTd|d$mePBbMWn%FO4;hgCa}@u$ zV6#zDP;~CM{Q&|K;-TAtb)sklRV$YO5|BO=GR2wpF7hFpPrcLeK-Qi+qO+rO{T#Ni z5oVOL>c>APrGUF%Ja`-)HmX^!9030kB z3T_B@!$C9f+Iw>Za3;6ns}D=1;bjy%3%a6SYncVMqEHG55@On4ZS%rLMIG3r@sjSJ zv!wey@3cU+d)=bD4K5;xJX=zZjDGAhRsR*^{_ttYh%FQ@qsU8-0tkJHpNqj&OI`M_ zX~dmNg)<~_Cj6mhi_3p7sM-<2K+M@zt}@YDUF2oH^B$SsoQ4FUmhsU!qN?D&N-L6Spsj z#M-|oQ3#9r56nb2(H6>EA?bCwKzq)nUJ4Fm7Nq$CiM~|Wdcgz-1zj!TT8A>wO{qcQPC(Es<9Qj zoicZ#P>P*3N}en%V2u*R4&o)S9X{S-cOLojo^PkY4M~7JR5`S=C*sg#DT*%i2{I(u zavU<+0;^$ZG?u16)#E-OIj@+;nTmIlRgT`gL@UCMHTs*Cre#&PBusiu1=v-!z8S^8 zN6;}US03yQs=oSlhu84r8T!rVOh2p0poCdytD2#TGFE>>UV!js#7cO|QPF_x1ppIR zt?9C^{rQ}e6fCwAA;QyU<7JWP+CF%52w^}Uw_y%C^OKXy%1R-% za_*>+D%m0H4Q_{TV(IHWQRsG>EZO>+XjdL-a1Z-*+ zV@LfRdt))QFKs=pIoKwXSW7C647t=&(L2yjBJMb1pW_}?4yl%|Ep2Pi?-Dg>YC8%~ zTfWv1pogy6Gja_E6GNZ=&PPQagdA&enkY1&OS3U@2hV=L$H@&7je02=Oy~b#Ts2zJ z{hZ%9=ES08K$7PbH%aT_Mvx^6vPM^j= z1A@F*d1=*{9YK`uZwF;ulUy@Y#2 z(&Kn&_iIob{xdEI^8ko>8yj5vuhlB3{Ywz_d4uR>HiWyWvOF%DB+`2&M==oD09!nG?#1G)N5 zGe{#^ctMq9zuyUyv8!LNwafo(MtYI_GJ$q*q|o;$RzoN%G}9p-5{;KS1dshAxO2Q^ zU0CamD=vlsIj@4|VcWn_WtpE_RZtN9lLSzM-`CgyRYeTGsFBD{y2&^tde=bg_n?Qr z5e{`B3VQYPkIgR42qnc`bRLm6bp*>D%c=Vu%$~%(H5JS{D2S;RhWq%p>^Qq zz0r%SM1ARP8`kzQ>|>D1Fz3<1jygvYOhdq?@R>-|_(tagUNS7IKc4Or#Hx0dW2KIH z7+QWd2uX;J)d~96rP<6T6Q8-GZY~H zIk!e`)8qGve*n#w9T6dZ)D?W)k$-GizooT>5zkW%=17(}%o~t7^H}_>0quDPna7q>Nxv*R`iy{Peth$&ygj@@eqSojIiH7vm*No$VB*MYkDA4P==T63WwyOS{y@s z3;f97i+p2Nv#okP)O})feRam-RhYfsseOqZ71rFt1Bwl+4Yn|oLs(y^qO2AfGLS49 zSBIov6Y?6NH3mga&c~*q0)`Qihq&aZp9Xg_hZas5GYhSF3@7ErBoY| z7=yK&P#X_sUvbY!Fgo1%0&lL?*s;a$3<*fAtiwB@i3fw_bmy>zQK=pvysUp~tmdz? z1sYb%_5J|)BSaTf~p5f1lw{Y(1Wd7HEQGulXRyIy~U|Y;QmB<-^RI> z^KTQ8baQ^LE4qx!i<1QOq#hz&!^4iCb-Pz#jPAeAjd0}$1B3|~If)^rETml=yY`+i zx;Qn02#}>NTkadvyZ11|P39Opasf)LH!a=LUOEQsLdpp_96D02ER z<=)f{t5K8s_d&Awal&ZM(i+24@7i{iKiM0jw|>Vkh@)NHQZs{{ZH7A8CP}@u3x16D zAfjCx2qL7y)3`GL6}^*3bTQwX8EcX0Q#h7L4Womn`ny$<=|URr8Jq;!er7ssIE(eu%6 z1M3-T@@cLZHo!9oR!vYGbSbxcM(7g;M!|B60e{H9leG}^16+iC5r>Nd)ABRUKh1vl zTjgNJJTVWBLv<4QH|JB}@_#>(+Xcorb<&1izal{&$jcV!Z#2#A+=MsbcJIkW7pVa4 zVfyp08Jm0?AKCR~;0Kx}mFNN%Q?;8pEdt1WOl=%`*oDyYnUQV4I=9lY{FNnC&cWOFjR z7B{@_?FcTNK;k%&nhTJ*beAbf13ac(E(NR?k%;a}?KYI8z?;a;1{_5&RXhA1oQJb* zPT9%@;=NfqDL9Ho*BcInlzlAReNiAT{s*A7x8O`oW*n?-I}(ZVcj$!A8*vcW8pHs3 z4k1JKDzb$>aZ+Y2F^4H*UFEg%t>D6$vz@XUf+zJ%sQ?^2ylPD=qevKM-SIbhV< zOZ!4zTKHD(8lBy1l?A_MY57S*rGEBY9ZFnI0Qc{$j(eIt5Su^L3o^7J z+CnbfK>Kaz-*2o04yvN9Gm%VZ6FjB_yD13Do7CzO%N0)T03!_lhnr z*O#&BgvAL+z#Zs$l&r4GfHQSkWKQnR(sb<6q^lQTLZG`9lGaYPLJbzgp+=3ev}gT` zog&OZRlME_hgknl-!dT!+)?N{&tEEMMQWJO(EgwV6>G0RiMahl4nK(=4ff{j~qXAz%a5~9S9gfle$ZI;21W$P-PCv2$t&ij+h8?il6(_wv z!cPfFr3l`x2gG?mLpi9E2#b}oubM`O6M(!PM-PG~p&C{4bzFcwMPd_#R?1I)w#zac zKx8ahyMn~BlY1nc5?@o|5VkxDZM(?`>%T7hz28=^V{m_Y?Io1;0P-zk_Kp!>%h4u5dGB@RVz*wp4`j&`9B=KxIZ7Nv z^p~MlNWw<@+@ZZ8Sp6M|4Y%KpCA9d~g&O*U+kWI$C9c5m6b;$T`kw?N|3`v{8W%*1 z`UNe+Q_ozeyw?bx4+k>&hkkZmW*g78%Pg6HiGbiUK_n-L_2YZ$h6H%)Y>A`?+U`Zr zZ-VIqx9w029eOS0LZPX@TEIFNvuKeFK!>h~+&sDZ(CuHiBHVFOZQ(u34$=$jp%s$@ z>b0=-Z2-FdfHkD15#QbCkVj^lcw9V1l)2B%NwJsQxj?bfa=|TlAptoY(dA2K@3oyX z3~kAHOtjO-7dA5|LVL;c9s@(C!_mc63s^J@wc;%KsSn@7-)%6#z!4X0qn%T&?tAZ z(_{7@<+q#o%CEuhHEkyb5!W1TQd*X)NWotXUWKdU%^Slr2llB}fxhe_ zXuWerA6=m^pLJc2Vwvp!;yf-+2a)f*h9Xf*jVQ(_bg(M3lS0DF^LMMYk zNzi7(sWq=-Zuf-XgG)VwEB2ikj-?Nd%K-m#or=o8i;2$+_s!Mla{abgU8Y!yWP*0! z2xecoJMeI<#G+f&eAP(4P!EOD!)zGc|1sM)NOJ}_9#|U!*B8E3+8sAU! zZ#%>_TmsSFV%@vP7y}fa7pNGu-wlp659C@D0f{`e(Ozk)@vWm^n~QNzV9UR9`rT(? zWh0>TzO)ntFnI}Gum+y=oP|DdkTSLFB zAq~dv+;=J0xzG{ti+*Ec2Z5okX@z?Yn7@%KHKO`ae_*6>oWV-+H*DJoWQ+K*;k2QE zBAPN@ETGeMW9PGD!|k8HBOO8>hJ(e{xu3H+zR91ic|c&Nkf8lg3<4>d1G)NiG&@TB z#&{YBIo=?-Rwg-Bgz3WQ#`5)q#r$%>#DEL`Hv{}%$ip$PO{U0m)I) z{yp?ehagl4>`*9+n|NB%HVeNqne@v7S#LTcqMxR^=m{1fWTVJ6U`h#NF9 zMTD1F<5od*7-PQVtQ^DfIUzWUU3ZprWd5xak;9; zG5WNR{8RU{mTWS^jIptaFsE3MPnL&Qx+o^t{y!;Y&pd*cqmNE~x&DG0el;k)YqACc ziZ?@IGgqWV%&#C(hCqEy5bC0Msv7idDdcH|ld`e9U>W@`&X0qDl@u2q1xe`2+Y8p& zs4+p;lpe{@pSIXC2(ZR-BUb?zO~O?4W-5v5&qW<;t3pYiOiAw=v9v(z^t0H&S|VVh z-|2u=#+eltsR)+oS4`i5VLD(y*kKjcpoDM$C29x@KKp9 zz}sX*p32s!^AzMCAtWK!f(ZcXPmAr670FtTFFjP=v5J z+8_|CpF1{!9twuW6K2d1jrSW_VATAR)IrKQ1x2Zx%h~B^V9zx6V5gbPNtO3_8tj(N zYYW(R`}0jb^QON{B%X!FGG|W64Q+^GM8S>+v@_OzrUjrWu8l$dxWSNA2sc@X-tQN@ zz%_^HACfw;2_f)5lw2&uoxSsXGnk0LP$0nNOP?NR)e%D1|JtA~GlJVJ_=7AMRb>aI_N{U;hbzdpZyXp zJ}yw-ET#ABxgbU(e2K4#0E;Ep#$=qojA>cyxNv0v$^i6MsEr|h`3)=>`5hetHqu_yFzGcS zna&%45=o5#QN`IT# z@foDI?l;X~5Vgll$lXxC&(^`VlB_hXJ56C6*YFHr&xJpp353_qek>H@DRepyU1OP? z@CdL25krOv_U~AL7D--7bTnddg>cdc>wp%D#Y^0!Ym_5@w}Kh5NrIasAj;)S7ta?Q zhTQOcRf~dHu(#iH5{wVPLJYtrS*Y!tblfx+dPfciNT0|mU&lwdVlKy29WqOU?ROD} z{k0UA)ioq4h>?@D`wju_&&bZs-Osl0*qy4q+S$k})86ccKRgz1)(Fk}%`i4b9dV)M z3x(>Z0DLlL!S)oW5OlSt!29De4G66Gh99v4DI&I7Z8E=4SO!23CbCkr_f#rc^guO$ z5{PseMLV2`Q4)C7aoFoCkrtt)AQ5P7!Ix$zz{-ZWfujkeQiw(-m$wjdWt;stWCmKl4t+Y#_Bq6urE@N*6Q zRZ@vzw}W&|11&}Qgy-Aq+ir5Pu zI3#czxidRZp}k2b^N#C-!G;`APX>ef+GS$TMLR6Pkc64SL1aIpk+%px*jRHJm9zdn zQ}e#*yJEv^?Wn-K@fk{MFR=&#x?*%@;r9s?qDe+<^)6R#e9dJ3bb5XHHgR8Qo5?V1!^e$gg9ChXou#&cfQzvEY@E2^Y2>iElq? z-$VV+f)~!bcSjZw#9z}9k^#}&^(E*Cs=*@gDuKNP5IgdCL#qp@1VOVE{~eV&iQ_k% zdNb@F6tf)YUt9C7sqNh7BI+1HCZ&>?ZeJjbVj|iya`k~EpiHO+C6IaWVdK9in!5~O zq>B)4^E&2h`r~(ac>f}@(cDkyGbxoI`e4jPim!D+m5UseFGsVhjY_&VnRh}FNyWS& zG4&|v)b=Y2y40QKtzqm#n(q2RTA9EbG~s7ksWGxs^Ox9&(BKXQ%jc_r|1q**bt!V& z^1u??Xte_w?)IH&MRy5SP%Z-x+P~Q}m(lHK_b-E4&kzEkh%Tc&clRURX?DNCy)z zRMRo$CQ9_6#KZOSsoMvbIf)2n(&rTyzqni`61iBDN+iAc5K!41;FMjsAFstbUy5^^@ zjb}RX{-CsHm#AnRo=Uv|@nrY%v?bU!Z(YZDdMIsLp1u`E0secMM zA6uB&RV*Cy#W%Z^y|EYuQs3qGX8ISa8Z8fFVu4QLw9$3j#ZmS5SzZf8n2!l&D3VYY zA@rc8)U~@vFCCv=h~+OG#i_7SF@UJ0JQglCWRz+B3v`>ID+6vNC3Jx(TN!S|g99_9 z_iQxbbiy=jry;j?ES*dm6lXuv{V-BXZLXCY4kcXb#_lXW?GPzg8#nSCoO0pF-oFkQ z>_S`+gB*lns>-erOwuq|L)0{E{@9NA zui-x24AVRD0S;5JtP32M;jJNfo|vN<>6Ciqoqsm|4*GA#hnFtP5e(Sk0tW+sHG&fs zVOfKLS{a`=MM4cfS>7@^5I-ZknGRCu4f**bO18i@(;aBH}8Mm8CoEy=mbh9c^I25_&cG^;E4@Ntbm*VHs$xQ z3Yo&Nv}EVKsj$ZkMO;$O%pgr*lXIFhbkaRztH>gUk|qSanJB4rKs^GV3#|tU({YhV zAM`^CsD5H7njzv1JcF4L)xN(4YanhW`R@p=8L)ICH}@Dp>$h)cvIkj$ppw~nNLv^R zS7b=vmh0|28yH~E1KtW5HPT5kS2(UWI_1=%XKk-W*zEDgXOBK{jW zd9Oj?s-5)}CE@2{pP;xAsW>DP5e@X)ON0OaW{Iis0o+SF#H$$w90YR=Y`CGKKimAv`2UUkgZC;WT{3SOm@g!`RU>Z}4D}6Sc6c%qTK zWY4|24n~s9m?p-ks;a80s?P_X&g*k?v&X@n<7Diy*U-+6j?A^k#l;@Y8g*rjnK9;w zLyQ2+om8dU%QsR{sq5)}XdAgTZWN>T+75P|>z03v`Q00000 zfB}GQ@X1*MGnwb!(UVFbB@1z9HSJkwYxKzZgR>0kz?P&QBl&p43XXKH8G9YbmQx(j zq3mwWd(S<6^-w$Hf_xSf)uM5(?UJA^vN3XcJde?#ka0w&1BwIq27>0zH*}KjB*P}J zUZ*O^V3X|)seA{@U9~tj;iiG91FSmBejX%_CyN^K3%y%)#+&q6(`>uJ+{@pu3(y>K zpJS&asAg1k{CgqtzOfuU3Gu z8}DODKLl|rlk=bEfl)FRKDFr)v~>~t>mFxz3RG)n7iw7yO9VsT=2pg|_nRN9-SNoL z>ZX3TE*>!3rH%GZ^&VQK9VeAozghE`VTNnva=l<(PSol)(W*6>B)GqYUs~QvHo+we z^cj$`iG-SdXERNZw{@o1MPXC&%0s+5oS!JQg*Pr?{x0h2S9|5V++NEJ$j~B0*Uo5hJBt#qb1O5Nv7&vF#bvUR9=#_SLUyioWT zK+6?YU}vbBZ1)pkUe*~+ltP=LC=AO6!gu>tEy2zcgnqYjS82HDKb1>e;Y73MaZ;Av zhI>TGG@86yyLn$TJB?o=BZ`?4;D}*u3vybvfTyyiTfB8Z^i8uP!X!^H0l`}JuW>>_ z*JLhF4{?SP#?Xiy=Nl>}62za3Bi^Ls1?=(XL@5S%|dGZHYv-tAF2zdf@Z z3}LF3vdef*pRA0w3w912Bz(!Y+Aeo#nma54K=9+k5xAFK-vgsLSAiQJZ`OEw#; z)Zfp;s9I35(n&{9@WwTa1%B~+$yO}YJaSP$;4nrVY)Ne|v}v%Gb4Sou6h7dzvqw`ifr%x6x`ut?9%e7|?&N zw+~gDVV?V?k%#kkH1rve!KZ8~tr@$~q1<-^1^}RD^exmj^AF-Ig#~q0aPkvEGVu6t zx#q|4q>g7f*KG^oMpN5G$bX+cyZH`R%YPW$@oS?MBo^^sqdpMIG`Lq^D)H!4cvy|- zB_YRprZgrTZlGA`A{eDvhIP0rRgDNxC$@qIqE3EuwwvD$N8S}^Q~NVrrl7pg1|XGy zuQVH1l7F5xQ2)d!2~pc=7_UQN)1f6yrSRzZISUPW64-qw76>3wIB1L90fi_6ps)_R z|@06-|L4 zvWO?FTB}J1`@w5MY?=Bdouv8TQ=^?T`7r>3HCx27f4oveh8@3^v*DE;rwAR42f~AY z#30>s({w(cG>wzx?#{i$1G@v|LjQ6OR0oN%b}=J+%$p{|rX)_7xz&ksgIx-Azz7KS zyZ@WOQ2Sh}C+WY!767rJ09P>hLp~?n7TV)IDbZ7aRGy%PwZVf;S)(wavd(RZ8YmZP z>sJZ4KW`92xV8cu^~oTz$jqKAy}d!mD@yEj3+1+-bT8&0BvxdutNu^Bt8inSY|wrJ z?#e=qpA{Eyq^!NtK28FbEWA-BBXxmyZB{1-f5z&OC{{vZ@*aG`$m|C7e)Rp)G~g<0 zK-U_}_lx~k&0obIh*t<5`* zdJWWkj`EtqPABzwgg+m;Sm}47}c!X}-fy$7MRN=&&Eb9J^Dae6apFV6z;!PI{ z`i?_PpT=-P$ilONSuj3qjLxFBUe0=-MYlPt~sr`hZNmdgI`E6kD9$pPmc$6$q@- z8IdV%gAZO-a}%?t6lXPS6sxamCLtX>4zH?m-}0!3sOCg(6ZH{K9s~*7umMslFkGmn zwuuvqPc%aKv5KT#$`JfSb=u>xO9Y2fo~~94*jxr_CvB+6h3+b~j2H>a)uDut>}nuH z`|B#Gw6}&v_^r(*YxGdhQxPPVxE|5!VYUl~I==lbrfxvF{9WXE0dFPRi@v z-eF1*uX}fuA;nk6bAo{)KS>Qkme`nLfL!v_RM1Jkf);>3uW$7$9tpnYANFq{VUh}e zYeb4g-g?bsGm@`LOVx8hr%A=pIERb&$ zdI!ptVtwDAaJ_r8H-Q@N9(+5y_Vhzr&baExveZ7mP3l*|_BxGv_l87C|KD`7tKgMS zOUUZPll<^dzF0`;dRY4p3{cBcZIVLrnPe-+WI-%yfU;&i0-hF@66)FNfc#e`IV}(8 zDwE#8@}vxS9!QqNTn`up$QcWVgrKDMH>kfD|p%{zk!PZkOQYP$L#!UXkBm$>ve#wAXeg)(~zDZWjVJu zw;^C&h7_Gd>p0m>VZ#9(jz_-pjPmB=>-@{A>GG9A%1t(}gDrvY2fO6GmJ%1y7ocbm zGHr6_fYYP`zt>9zvGifrX&u=ggeX!Q7YSzWw4^S*mjE_hB?A0lr_U!`9A9B z2>AwLJ7rqNTW&?SvR{*DkWgkFvY%0E#R>AwfB&EbUCvtm^@L0d`j+u~@}(ezBi-XaB~m8A`P~ zhavU@iZ$uBm`v>YkhyL+=z}UFeOmgV>h&V>pzG6%H`5j$A=cZ?nLor*!J0ujwqSOn zUjk;Lw-AE+(sd4eK&LrNG5ys|N$-aS=-|wyq^=J*#q5HSVv$iz#RouE8+|w!Klau8 zeo&Sg)UiXALz%ZAWh)|-(F4n875pbbv!AU;|t02yGAzdNVj4tAPRdB^G)31b z;z)I!AgGy1h_`?m-GuENG*uIPC+LR-mQPY@W=;UAZh}X3QqjJpreGZ+E>lF7I4k_{ ziZ9%BA^qL@Rb5~Kq%sb*)O|t#d~b44?QE7p(sF_+;rL%B*+E`hSSZ7>6dEM--q*m0 zA$Td08NoHzTqqRWomLE`v=4G-q7D*<&U-H%OEog{{vcTS0n^THp}npL$QM3Y2iRdb zO>o+xi8~-tWUQ!cVUB52CSkG5g|5hch_DP|1IJ>LT1{FS3y}u$C|gFRECHGOrVI-V%WAUccoj>f~sh z*FeD1c)$_IjPT$1D$9fOsg{QJ+Zo0YlOzbm44#vcTa9r{WZtk&Ecn>v2>tvNRc3MG z-0q?L#a51j7gH!)y-k+`*-Y+Hj_S!@FYlJR5bO88MS=z>TnSJiLhzb8l!wlGr|3K* zjA?MJ)&^iwALmF%x$_$db!7Jwe#i)~XeDrg6G5h5NjMsT;;Rk#AFZ~zXp3s}eC|dz!)M zuAgtafy9lS!ZHAC(YUyTgeQ?Z=)q`)!lZ<0K=I=uFUtNfiZsUSrgNHDur7(xJe! zNvcwd<19m_RH^_&NyDI&jz*Dr$jf8G$1*LYV!xh#>Y?a7mhm#`aOF95*TO>jGFZ(CWfdo4X0y1%#BwJ+=`WFR+`g7kd)&Sjtx| zRVN5mHI?D&|0raQh=|P$`Ko#$`nsqZu{caUnukv7SP8{IuSOdBUk=Gob zLOft@wV|8%wyx1aEclvmlN+k#f2G0Rrf}x7F|ptW3LZp#&B{u2M^Gth zRgQFFH=rM!418(W2BZ~4(YFriN`%`zpFl^8lr}&S#tzhXN8k2LMN!L3>$Db4vIi`% zQRW_v;3qS8b+)N?+OrUYi4wd}x{H^SUhMQOUX!wYU2J1Vhgvj7kI6)Cu*#2~0R^tj zJq_cAqrieV4b5(@ZGg^HwVh{fh^==8(dh#_uWjWfu+av3_+h$DUK9WGr5g4e;TrrE48^0^GdvqwCYtv0iXGTh}OAW?bevOPUIFQALr`pp9Sk(hI zkk+!`lGrM;jI`*`*Q%HcO&~4Ps_@#m06h`mUI?_*kZh#0AKEtM<7vG8%#+^Ke3r7g zuf{ATH}(r1^?V)Pa=#-7LP}&~v|9;Tg(PXih{}4J0IND+18G?nTq#=x%Saa;daVj` z(FBr1Q}uKvHV?a3B73r0gjwqlveO)DhpF;O4bA>-Mehq@ohACEJVw z*KvqsZo8O|?UryWx+lwz5F#Na11tMegh41daMAQ7^P7Dw1J%kU=7Dm@ zflLWbeCu?$G^LR_ z^ficf9d#1#9v>QfV|1`)_<8JI?e5=MShAQlVw-G`%7=uYSG?+OCu43Yv%UMLE4x~` za-Wp8+zUCNB)s|V4ibkV|2edT+}9FrGGVe#I6YUET*_-_XMmd0f?7duyv|*ju-N8f z8YevKoJws14d`UVEoGK>|8!|rD_8DQUa6Iq1D1(^n?sx z2x}HN*+5_r7Q0PFzpY7M+I&Twu+W9wj->?R(G{3X8Ub4;2ppY(x35t2#w2(71_m`% z6$l9zRruR=(FjTQ@o6wX^{4h4R52SA2@L=0$5vB{%nB=p{s8^aNx2ZjIM#9&&dzSp z&&zC*py8>UNRX|>p{t4^a5l-g`%J1OydQx7A7k6d_fui4p@|XcVT)!Z2G$D=)(sdG z{-G$$wBEQ;ePK}fW2Kg)WwO>9}@36O57O4(@$p|NK98BV&)Wt({u_ zo#1s!E$AY1XnZ1P5FGd;*}LmJan}6Rc44kRF56e^AJAOe2>KO)?5r|Ewu;5PChA5Q zXSyX;RMkQIu1tcbvRjS@Nl+4N=vf{N8oi3-Pn%4OH;q02U*L5B*&70e@(xA_YVYHd zLx=Z-fw~&&gUM(Ic;}japzbt3UE?= zS6vh=(Xq~D0m8XCU|(b+q`Zm_=QZ)Ir37i9=4$>}q@SA*nj?HmNx+*H70~kWeq>HZ z{`|^;&SL=kA~M3|Mw}w9!7#tGrdDsCZ4#OeK%_UN(PL;>g^s|8a!%+WCh7JtyDe@7 zbwEt*$JlyhCA@r+S~1C*E*F7IOsIm05m_Bw=(LR~wH4l(k8j_DLl6`7?P|^e5K~ z;PzPn-7|EufQbN6ZOy=#(v@2~K-XlP$sUL;$~Kwr-TS#@HAF?7oYYjNuj2u56&QUA zW7^f6wCuIg?jX5R?qh^w+%#i0&zQa ztzg2xI3d*5+HVylfJ}V$^kX&1itK!g(FWLJS*T5d^|IOKDPTVUqbFM#nQA>F0E7x|C-l#8j=KH z;S&8V$%&Cwq?Am!bKB3(1O({csB^knR=8jId}AZ1L6RV~(Tunfnw}BF6LxW@Y03pP z>jXaRj)fCX9Xu=G5{v=B`&hz1^Y_|d;SMMs}@Rc*v!jqj2RL10b`rl!2amHWf zDM%hWlwRoY2Lh~-oETXrMa%(E(ktR*nEG=FX|VS1%xCW%@W4+;>Nclj=SU<$Ru^a% zAs>ft9g4muET_k=cRstAM%iOOU$6O7ebr_iEfZ~)q)am+u;Kp1khzXX|Bu7=>@U9c zN%8o@a)Q8PRh=IR;{XJcKD^{1d_;{rjJIwr#X-IZe2Bo(j6sVmK4`PjVAT`Y!``Tl zMv#+S1J(P;%j=T0^1@|<-%<1a}}kQg;;p%qIe9V z{b|H^ZaRhK5Rw-~5Y;DOjuXkC7&NgsYh|>uAyA{P*ak6@gXFMJWEY=m+4}L?;-f&H zguL+S{YNe=iVw`9S`!Z2hsrNTE_arnuW2dms^p?Tw3DD(wmsZmIB0D#p}g*pLC3kX zs6Rfg@nPt<*KhsYiRt+=-BKK@1mGO!!fwx9cYn(_5?85e2>KVRHQ|;rB9NN?a#`P~ z3|t9Dyis{bVIuyFtiRt8Wgm}1#;5U}<93m3hOp$}=_8OP1hcrd>_aO*JriwLFXNfy zX6z0}-S#i*871Un2)78bbgN2+`G_3GzZSxGI5q0I&P3_(W4`1+I^XC5rnG{!Hi#w- zZ6p@GIrfQ!`r{#eh-K$t7Df`ct(hoq<#2}*e|jd`t{y`_l_u%yaa@9L(`c%|n`&L9 zUhAnC_X~NGTq50+nz_X_|B><}9l&%3qyfPrK;xuC3d0qkt;@NX zX@=sD)5d)MX$d*XT5@@_SY=ZY9m(zcZ zTfQs$pi!Zg;1j6bqGm!!-_y$F5JHvBZM<-T0Z))Y)2e3P$Vl|X^M3>E$9P8|%tQ;A z&xJx7!&RWIm$MkClbV=@(IaDPjC!4{QP>CuX6&CLxz;2w0mYoj4=y8dQx+}&VA#Rr zh5x~QIYo`NQOlh))PIzOc#AXa0c6O>-+++l%9*`MOKk`}|D_}|d7`1^bnOD#-B3eh z3gcmUFZjZ)CZP8e9px*i1rO&Oc{i(;t0f=;$?LG2J#U4BvcA=aw-P$&8&X zY{N)?boH4vX!EbY`7fCy{0kX>6+}7~KR!nOEkWZ4mPFH3>2NxLSSCqNKsSF@1B2ML z%8=!gs{g`jtOwZ@)BsedFdifD4R(L4((r`+>|3dXuQT#R`2SDGgN05Xu z*jzR?kcCd(n!nhoV(=NHy`>rFA>f;N zQL^$83e$+xSauBoD#5Zf0ZwJrs>cqdg^1?7-`|9jFh=iFVmA`vCV3hIHiH7J0uv_V z!GxzIDu9Lm$_UFebjbym(DdNVjhHYPX=47wLKTD0A?>X?eTNC1?Pd-h7Z`*ei)elJ z8-cZgbBL=rF7T|)h}(Hbp^#SSnMAJNLC8W^xeQqS<$x=k z;(7rb`YHqHkcrDb+-q3GajEcdUk?Y9Q$WtQBPd&_B}J_&^(JMSG_gl1YNrHs$PBXU zZPRSJC2p}R1GaL^4+F~1|BD~Kn{!W-?yOs_N&$q!1n#o>M>5L^Y9QC?ex#J@Zd9hT zx-nL%Crc%+Lu`k404!p2B$Ovz`viBcr;5rT`cI zumr;a7fvOIc#gGv?nvrPHVNpQu58%-ogi-38<1M66G#8c$J`O&g3s?ctp3|rw>xw~ z{u6@Ru##s{(zu{uiAauufLxlAA&WbM43l#K5QBjTvJF>g>OoOE9OUNrfswci`*z@F zz(-*#H}Xo)*fMgZH8#U}f|edu@pCF0{*dd8C<+=zHy4xzJab@~9X#?>quJNNAvsk* zO$y&&+@4&*MuJ^J)$98jiR5`5o>tk3z~dvy?N8*4F}bRaWLJQZFl$xYI(YdkQotMh zx)gXRX7ZxP%z;0YRS1^~o**Dj+5Qkk)eGh^WDir>GQeOkOQ)nm(WRRdN%jH#25yZr z*wk{>Cen;&LigbZ#Y&JE4bh zed&2^yRa0yy}i3g33-O(6+{RERGV7GR#vlrO_MHYH&grcBHsE;kET6qoTNVDCAT&s z)u%kHA6@VaVG}oe=5G%S_c+Wuu@aZxI-eg9*pb)J$9I?-+z7B|VrcT32uq04qz^T^ z(qo|S>~_f`|ELj2wG-=%?fcp$-+dPsuKiOD|R8YZ-}H-6ONP179JDW=~fU(W4p_q?U>R1u%mE<3!pqDTLN#HZ-wS1jr zdJkhS8|e>)u-9T8PxKDe&Cmj{tEzikp;p95%%NRjx&WZ()o>2f#MpmG>ewRKmE=80 zL9Z|ZiNl-RI+xUU)iT$;3gvnZC#Kc)-G3wrUxW9-%Dsq@m_xt9H1tFPDlqv#lbJDc zT)+j<9gv7AWWFT+I!o$poDR7BLHParxF{~AP4z>XF)K-y6y%&+`s0=<54pmFd&}Jn zq`UhMx9XV32VEsj|9w|p^xG#-)ZwoAeJBnvRZ9sAPr5TYRR;m6j?*?x($WsKs&P3n zdI35}@@K3<&FG&2hgfOPqt?DfMyi$1?u+N4D;jNr-Vr4$lx&UE*7NwPFgCzcEhQ{G z>CWg>9R#2{PTMp|OFPu6#^uE51?V8jrwm;xT$QOtMyf=rX?&<9CHDaT(=oglVtGtO zqnV&Po|FkB8In;Pzq?Awx@OBTuvf8;m_xiVnWek>(P0IoJD&j%1bx8mdVf@{Qd*jk zUR9TNlxgs{Rc#m5zD9U00N++d>?}Lbwlnwl=j+tk#>)c|v#?<4DteWOv$waWhHibJ z$-Kg7(6f=h+Ndx=?V8c9*JVP9m-btp#`1!r2xc2~>FE~pEQALki!7e@i8p}?qalUC zrK|K>B2I5_pBmcwKqK=CqoK`4es!Z@9<0%t_RUZx&NgaK6{~XpIfF*vop2Nr652>0 z)wukeg#l{<3Zp>^gL@&(%K0uN5VG;AblOnPR!GCLi8TN~u##v)-u}y|PN%!>fD7Z-K%X9t3lo$Z;EDi$ zTyOQ%OqFh^Z-uYGr);lK;LkHbwxh@8wP|@|>__RYQRQ}^e_&M#HcNoqv#&l&O-WAq zPsiZdJ$&%QYsYjl*ELFVHu}1;JVQU;cAh7xuT9G%V?RoFjViYT{R68~uvr46>xIprRELE%fWpPjZ_G?f0IME^e!;X=i_>P^PCKG|F3cTawaM`_9BP&xnjY84L zA34Wnw-eVwbg)OM>lIsa| z=fz?F0>K@V3Jb`^=~=l}<9~Q~WD9U3B^WGVZ!M-2idF(+axv~deY?+6iz2o9O=10B z28$=W)+j&v!hgJNA_6=9T6Bj3WpA>L$`=+mu>_)yP2=AfGdXO$a-pgLLGWz=wxAPL z`eJ%s=T2^fZLp~N`3tOR!|>@CI`@v*ds7az(uBa>>RDd}(p1b(T9v?tTR91IXu#PF z_>x;l$(H^o1f775E9pctEg`LcZ*hWE*4q)LNk-{|Hv&KW&;q z315kFDq0H_xz(oc$8>@v3xTN6Kmth$qFLTe)bYI^FhSjH0DB=7^QUV81lZq#-1&SD z7~c-p3f|OxWW;4efe8feiI55a=|xY6#Pp}pq{s{!=aEyZ26X=20o%~Ws_pe=j$@R1!F^e#m-pyi zD>0TsH3_AOfJd-EgN`IGHQHtPw}#NtVqs^y5ls;&?eX7}B7e9D%G2>yw2Sc+_}F|_ z5C*$9gulu}W^n;)w`?!}bg?G@(u)=y64Rd+8OaUTvH#eYRRfxT=fF1UWA*l0GsiJX zyx_hp)608wuay|fDznu_GQx*&!5TNV-=>=O*3y_p5ro<-DRU?;o_YIl9m4|_twNK` zLBseW2%C>RIT~NRLq+hbOe7ZZ0r4eiV$;q`;T?1OjV5C9N}?>~9N zU;1|CeLRDtrW9~rAJG1E91~xFU?ieQD@yV5R%xV(6z9AW2o>e81Yx#n(O!|z>UgN2 zvB^kU(+KILX=-nnh1&F1CR1w8MQIbj%$Hh4)q)IxhqD2y6bOw__qVzJo0K;@^aLRM zh)|{eqApPim-k95O(Zzyl|ZN{e0xL@{n!D74sM&(HtlVtqF$Z)GqyzrjFntJb8JAzMP+Y>5B508UROf0!R5hvav|c*YJO$pkX01J@hvhNaG`o4b zW$9BKSOwY(eg=a_qyNX*$UGX8gYl_O>!J;_=^)z|S=fGr2S43{K#>aZ>fX_WGg!g|(a+)JlI9$&9!u`qZZb^g+{M`#)M;m`twn?irsEI;nN@}{S z4W6G83^O}{;#f$!UJCQgTmx#8C`HERc>9&X6btpvxdJ)@sVl(WOKN&6M*P5Dq+ME3hm%)9ld?% zm3BCzTP2wWJZgTZ3r0GU)Gu;P{hqtzTK)6|&DXo9H&93sG**uM?8FJiVMX;LBsfjv z*G6WcO&bUnu~EMWIBY;MPceSr$3yTr7*Ny4c+G)})6mhih@^Z0`k8WTOMC5J5qY7F$K zs$qq%O?6t1K;jiuo2>Au6X}{UCN)M6yv((}*Rm!ei<#vj;x`zJR#xNo8c!@&8f1F& zlI<22=$MMyvmr=F=mdCg{ZME8m#m}W6kEBxW+x}95twmdWoY@G2-*cDp`CyK2At^{;a+<6Bdr=y_jBz`aN1?}t zC9ecm4j?e<(iGi3xh6)A>Ma#$1Xw0X^hbpi z4L7jROHPGv+vuhDM213`owbd!ro~`u*6%>6kV8tTKuEm>cKlDY^hH+V-f28e2}6Fw z3!4HZ{MAHj$trGRTD)Nj@24u(8LcN}odhycYBp(K`zjpQ>S5lH?K_z-8Y5Ty_3HlK z^$s)ZB3vyJleL8p+eQ#I4O#U04w$x0XLd^Cm&aNeUd7u_5s)em*X%(s9LUTh)L4g=&SjtEd@zNmr~{_UWV$qe?w|Kq14wtwM1u zE6A6yTcEWmuQ+3&8(6U+msUI^gk9>!H8M_6rOq+EN}~m5gB$^e@ijS7dFQFqQc^r$ zAz14d?AJ7gCW&ZKOn9Ya78v#?r=JW?Q%V0@ecLN%;MlL?Z#M$G`%Rh6E6ZcRnLXQQT5SQ5Bx)EewF$O0QXAi1FitiDojfPPI%eL zgZM*nQHixc?ke;o)pb!Lg;C*qVhg9HsS`=`$}>#@Q>}kII&kq6P2bmWkJ}+((4y37 zCM*Ffh?OK>ED;^%Q}VR8wo4Q_HzaYT+9yK#xjZD>FIt*bt3`2rBQwcSkk5-SjKN^E z;+C zzi%jxM@fiaU%k>(DnXA{S_X3OtHJC>1-k#V^eT)NfzjI9L&Z4sE2zYY9DrR^%yns3 zy;%Ub+!2c>$F-#+Y~U=9?Ll4w0ijz<*xLW4C~A70ncz`+w1Yq&h^peb<8RWLICg19wQrQ5e-dbY%B< z`1PPqTX1(RW`aN37|)WmsQhjJmFj~#>lcDyT%V+RJEL;HzcbO}!;V1#?!6YoTwY8d z&QQ*gpzi}f;8ZXynf}QFdW6=t%IXx?Hj9`bx2>NSA#4KHND*utQ@8ErBVi?OT@hVW z1)pksPrb;sHRtRX#-S6m9T3yT(`Pz~(vPATStwSwF3xxdQ%bLkE%@-GF3bZro@+o})%{P6zU= z672pgT!KY5d?s%VQf@yKaha;CXKfVgJ8d-j!^rex0IEP$zo`4KNUGF?s28c7nF9WL zLj{r>-9%*$P`34WHL8pH^Y65WD&K$eu8XRDV)`7ZHsECW4dMlg>4^4G6gol%O)RYs zoxley?SUUko@_33>?#NXxgHR@2{ue*igmx+0J^n#a(UpJTN+#&d$GLpDBV$hg_sX@ zwBTpk8EMHUS(OqKr@yvPsvAV9xJ=w8s2gFI4>``Ry6(Bbw!-+CJk+n^C&kr-}x%PV_`>kA$a25W7iin{0G9_W|V1elPgw#}N8`65A z9xW{k3PHXP^A_cT`w|JnxjWUtZS#L?`^h&=I|n3zs_Hoza|bI#$0y{bO52dum0C@g zAin_Hhk1)~LC!j-Qr{N-?snodv?N9#%FCLBa;i~LJN@8;ZmN?DqTd5Vv3~_MM#_Fg zne9q9brq>p(5gxbGJzgQr4Tu#xE>jgDruvRwDhhN8d6GJbL>x z6XZt}G5Sw~jpV-BX~FZs4rx*11LM|msB*Tm<%XhM5x5{Sp?VT4!$=$ z0V*lS<(N@ID5xr>F@y(J)6_+UcWjG$46i~fm9ez8nZ(tQoE3wo3uN#wDa0Q}Y!r|4 z^sa=Y+WBya>D(H_?to3g%G%Lq2v!L&Es+9?GT|J3X-!B5YHF*xbRDn>Qh-<43SZ%7 zkW7_EI-m@#Z!j4T*JAVNJ~+7OY&!a+DIfRQ>d;~(B4nWv*5ZI+llt#<@F=Kq$fz2V zXzHVx1K^Q<<#yedHA%dl6Xh&^Dy3yAL71DfwHd&iBreX=1D#h za_m}dntQ2%y#LF^8WVLbAkstHvCwCcA@Gyw)G6FFHvdX3+bFUL=T;eYnlF%*z=8ip z>7T-YVZuyGkhHg_w7t>if($}Khr}x;qF@^~rq1`42||R614#ey^mhr!&S!kU54+}d z=-YGgaOZT&;F9o4hE_^0`*h2{tT;uMQ zgPVbR-EBhfzq`qL=!9{m89 zm*;P$IxaM$T1A1ml@Xjsh=|sJBm-PQ*u^r}FRbHcq{WxZUohb9X;L~3X75hwxhu>gNNMh29x^2OI{A(csutCYgEQ+!-< zHTxzO=+myM2_tZXdavW8zYj=%X(-unBO7I+Yu5XI-Vk7F93}non*dxF2jrDso(9=M z2QenV323a3(sowW5k^es3>BBU&g3|{G%Oll#=MJ*VZ10IkD*KuzEU;zL|Is4w zM#~7&>Ii!sv21M31ag^B87?VR5LRzQ662PN*#|vvC;M!vMG+Jq41hvUn#{f7HM8h| zJo2$b9D_>y+`3Of=uZL`vsO-aeB`G1SNZOT-A1{eb;Gha(1Ca1Wlf(M4peb;7%39} zN42OP#v@X=a!0D2R*Qp^=#Ef5fncRfI>~0 z%--NNTl7I1`B@@sI$rxdPDey*86jLkLrM1u4`A^#6c+#3vI55a<1T)-iUWMrSO#zo zEjGC2zzQ=QSV-dXjonylf0T>rVJreqvf@(w8IW4J3Ak zTW^T2t>y$i`BXpB4UkPu|LRj3P(KHlNcTSd3)vY<|C|(Qt(-<*3#dE{GjF#7RofjbBHK(_MT0*(z{3&`7Px7ta-B zP}HlGhQWm?N09smnge)w0{w{zIv;F#<~F01*(aa&sFGbrI8`AnUa-Bb`nkZ|QOjsX zK*`(p{UnL30Z=nTVkK%Re^PJ_7=e&zES!tqsMLMJek|3Qizd$?zj)Li(fv+i;@dQ$ z4Q9c5B&YWKHWwJ|*G$0M|>7z*nQ)3aQ!yYOSUo}P%WfYUF%6BheV?C0&O z!sjeRfLFFH*WE}qOxrWvthrlx3Z`Hn3wYLm z@djM5rxFZ*!thYv(a3#5mxReya_d%J+2%Ye}64- zke6r7e)vK^*0ZDBy_5Hp5?~^*v?Kyw6Hsxj6HI2{f;Q{^XHkUA1ib9eU^=O}laAl9 zy!_6++sN(ckVZG;(a1%CYTodx${Do|)AiQK-FlNPx-Cj|2(H+PVo!BrxgvO!rw!z| zJvs!Hx9q|=R(#Kq=l4dwjJ+$Crsiv6O021sYRNqKPX2j)0pfJf>{aesz4a$Q+vc34 z4C%5FLA~O{zx7o^Ig&``k>No=Gus@!uzrFu>R2Ih(x^rwYj9iFeyx$}DNZO0(Z-v``k_M)%XJLd}>d6gG8 zbVgs7JSAMbTak_ zHJDHB<=-ITh9LN=4<&8O4uwRpyijAo_kbiv|Na8HvjPARv|}Xn;mnkt(xoJs)wT7a zBI$_w(Z@#rcygq%Q|K$|mOIvw%VRX9u2vc2&+G7{j{vA7N~{0Fpfd(05+{qXd<^b# zU+w2s=0{XfkmI4{c*|jvK5vPHM>P`xqYfmWNn|KN8Uk!eQrctGCJ>Bhz@meABz57i z^Vs6ZLs=|^EbzD(-2blg<*|145crMcebIoi@74x0?K3{IQvdZ&_0Jtfi$%2y*e$cu zn9bY&h09MnT?Zy1zFQt*y!}ibKoN#w4urZK>y7_rZt#*=8epbN<6 zU$yz5m?Cf&Z6ns91}nt9U~`D^6*fz{z`U!B=mX2?Yv#NnATbtGof{{SErCIq=3fFL8w-7a_iCKE{a5e(fD4NIX;!=+nbe|^7T>j~Pe3pU3)kPt1I$8*8i2i1x% zfs0aPxc%IJlefz~L2vrwBEkUxcD$V+xy#5d!URIBn3SJ8wIv`Fxwyj8mxXt3#{j@t z(VGy7yM!D`cZzqq9R$sRK!06<#~c?{T$AbP*|CTGVtcq-wg!=>d0e9Lt#?ESP=kr5 zpiXkJ;bO6}G6$s8eG9T;I3?ot=7H-xCUF)&n&=?9?;8V**|eY(U`zToT;T{-0Pz-KcZZ`e2-gr-|o+>+hr{* zF3cSpU|(l?*N(iAzWAg7R6S1GHZ!J!hPATw^LI;-%DbKLJX{!d|NTlI?Q$#fO5ZK; zqSNKk0`)v7^^~RfsY);^LCBv5Pt5j48PXxZ4@Wda(GEMx_=M~d-x=_p_D8?4m~g`& ztlG&2bVmOUMOUYbGTJ6_0lx;geFCwuxL9q4>ZTlHNlzF+-vC6%;%MoGB?Vyh8K8n$ zU#d~DOujuYwDv{l=6p@oPJ@7iiEfR=A@O1|%+P^y0mceEf79kQ96p374pfD#r8J-^lj=_D}FFV<{v`)8n2q;`YSG{SaBZyc zsi?~rWeX52ybrxN%XwYz2c4!yR5Lx=VJ`WB4o%8|WS15#&?cDFXh!;zB&}}>j(7L$ z9IuCi5dIIC=ZOuH6z5gvQB}oMtSP_BmVzU8=rngw@g$dnq@>}qo$}Qm8ThO& zk>$h-s>A8`M?(L0{*LljI_-J$Rfhyfl-H%eTHTPx@@EfF zVH%O~S0oFRhESko?`p<8WC%84-^`}GnjP9MI7Xq{GJp9S8!`Cx`v6&!v zIZoC?pg*%S3 z>l_M<6RRrJY-EpTTEZ?2Po=nijBgeEat-)#hQp(BO8r7!RRICb%hd=vuruSJX&~Fb zV#0gHn6x+JRu~c=0ziXj4rYU=l}P%AuaRST*9w2YfhNBK$$7@1^G_6(7+|y}Q}&_& z<}goahzQzjDtq=E0fUNBd~%9R_)VxP}_=b`+T;&+x9ZHOMMb3 z#)wCIK+a6G?v!wae7rex`(57|nR)T)<07Y~<2q~9d~ohfvKJNH^x)DVGN1-7C;Bq@Uv;c~5sUQ`ScRB)k*;8eAU4}jWpo!%#{>FvvJbTeX2{wGD%IWp-5e1A(jvnLyol4CDn&{h_cXY#`Qs=7s8jj5#km*d|@P2Ukxf9({?e~Y?GJXsS3auknH-Try|mjQaM&MlEkK{v>!i{#}`?t}9+?UohbjWB|43<`<7xLpU ze~lq!7Zn=A-bh^rl)s4uM`lAiLiJqR4{l+{NShkKQ<)v(pgI*spFI%emijD`yo>CO zNfL9@w{HT_=YFWNlM4*nmUKeDj-X(pDjla{(><00Pd8leHM`IzpvMvJC_wbomO2^! z(7u?Il!#!|cr*r>OG+|2gOD)f0FN{uN!T4>14fJ*UZ3#Q4WOr2NUcyj87!avC8ZM6 zT_jed(Fz~9vi%7jEHatq$VaG6#)qnONZ||}XU6H0uq=Wx0xe7^1r_HU6~1x73zOdS zsxuHEN^mY-&~~XiMMwQbq*tfO+T=Eikq;PpQyZ$wnDRk*nhddM?Ne`5q~$x!92$@- z_NpgeO7>g987@Cs%q<4zCvcY|jOjTI%mO)4Tm8EO^B5h#fYb88M+V$vpbz=}Km!=T z{a2@OK&J`R2W4VKV61DA-M4g2g`11#1*CE_qh*sAV8m9_#Sf_52pwWPeTkH>+p-F} zw$Z6GT;}DbeKan1c^@Q%{S5$--?wm0g`11#1*UQ{qh*sAV8m9_#Sf_52pwWPeTkH> zUkU7~PwaK*OgBDqzqhmxzI~0!?JE6MB1#C3ZxL}(b_7-88A6BzfGj`We`J~?-9vBy z`EYe$lxmiTp4iC>EN%x{ux4ShNpwsml2H~G5fdFaj_%b=j%|h@(D3SRP!=7+&WmwS zPj|f)r}mDY+F*YMH3J%G$|n7Nw*x)xQR*jmqr~AjUaDLV4mI%v@ZR&Vi^I;)gyv4x zRKn4fu|VE`du8y&S{L3JO{F6)_QFQvk1NfMwZ{&rX$t5_Cdb-<%)>1 z?&Gw$e!I`Ng9*Pua-*jda867%r|3yNsz|4TMuU+dB^&yVgV)8=ydV|jAMAoF8ElBN zp=6msf*qI8IFL^2ot;51>2W62XRdm>@2w;W0TL*bK!`p{t(z}c44jfsj~KPjBw9nz zQ4Jy?LR6bYxXGB9B_k;&_6tN>fG`r?ClH_hIpkcE8E2KXUt@G+TF(hGtJlkCn)GKH zO#dGfR(ajJUrX^7Elp6?H-md8cBAd=8RudjfL;~FXdrdK(~wCA{Rvxd5>_phe1h$W z%?2RLwa9+_ZHG}b@0O`J5(wi#Ejl9DYK0^Rj|hZ(e=bNGZDSqoPGHC^vN9-=v^8|g zGH=Ir(}C#?LHGv?!4fi}@v4nbeo#%M8%52Hdask>bfJAVGQ7AN8g_D`0R#{MOwIbI z2sH&z5gY4AQ{A5VwXB~64q^%WJ&;tv1A!#p&jm@NY^=k*6AUwpR0fHJwuaoY%-gZe zbYOZz5dOhJu!M|gylNwqA5;_RMp1L4-s_||U1)b>P|Qe!kDr`i00BgBOvH;Wq=^TD z>*Mx#fBz@OFSPMK?~n?s6_auwgU8~pa5egHRD_G1&Xp`;8FJf`I{UER7l5XiF$rxun=0V z&Arb?^%f)f{&y?jK3vLBoYT0f4HVG%<0q^Ki45sSln9FtPQe4vxa5#w zuVgBrp8%l8YF9xx7dPWfY%wZ9W=x1^JaNGp{Hhdal{t#U06>BO0000000062 z&&+^-`nvkkV>rARC$XEq68s+iJW8P|29Eu0J zwS7oV3_lRah-2e}%AMO|eErTniP3sj408Bbuyc>=rCR(N$5G9fW>Zvwa?e(kHy5dw<$zHgHgg7(Nq2v~v3MI9IlZO*s4LigSmflB#(kd_4H!u!x@HX4V2EMnGae>@aG$?fwBI6MpI1tO0< z(YCh?HY%vIVe=qsQt)KfZ=BG5cT#LR9JjE{SXPU?azDVqJjEK#y4^uuDe{3{WiHVgeA0B&4}HK&gvBta_qcp7opx*rGi;u1$~WG!faUclj5v;i4#;$f2NnP}?IK^_+iFu$pqA8Vh5-?Zi^jMT}3jMIWif&wBP8dS@9sjlD|@|0RR9100000 z00000b^xu#OaB0KuD#Zt2*SUK>2|s6pDUM40ADaTlFHz=H zhxV<*Kt4>s4MGB1m-!Ru>^$oGSGtj)s-WGBw8A%}6YYkqJXu2owXuSz4pm^)B`;RV zz>Y9trl7Pjluvj^AvrVrRc464xaZ8j3mj>?POpoSFK?3rU+k|o#=LsshbBqk{M#Ns=aatCB@ zqa<`UjxJGF$FAP8Gp#}kZ5Y!;_~OYr-&pd1rQ6;4)-Q8jUI}Z z7!F9j-h=UW2K@3Ofs1GQ{Z^868A!m888*%L;*a~o7e;f(fH0s`g*a~#YY>Nq=zec@ zq@_-Y(cyy=@UIQf^#%#OqN$&DbT+uOU3rm{ z0Wezh5E{XTK`4_3rB7B z9j^5_0pwb4jk7PiZ#wdtMfr@h!wLf=($}GJnmz?nn=sPPg@~HKZ?oHA%nZtkT42F( zlI%4h{$?x7q<86n?b~~D;6|5B>dQD@hR&g8h9h-RT~o36*+BtD6Efm3M9Wls!tPx4 zt)0ohZ%T-<$MIRqE1=LK-n5bR)X^e*~=GBe$bVrRAw^l_-d_c%<~9wf&k5)SEF;Pf&C%%YMc{B&E5O`s8lilsk!|4$o!qgz7v~@taIECU zCPZ@Rr3eFHrQp|-M}7P%+l+$I9gFD_%fdhH(tho$AAKuqYToQU`Q&~XOZ5Z8+r&T= zXrNbqE`-8HL{;5AqN^uddX(b82N3uMl~X>r@~L15<+h54gZ{Kg+(qo4V^>-!h2xUT zP<2^8@{4I_f}AvYr(ALoyV8K^U><8Z`oZsj+3MwKaV22ElK0C}OHj*~DL}G|qMIL_ z6m~`k8V=yG{O5+xwBoC7h~!rbTG?c{&AkK3M;KSRwosy#qpIAxAr7u&*a4ng_$26{ z+E$S-mKCY|U&xH|I8ympzH^clH{E%xU`x@V;bI+5|&>oTqjWrn408X=u7YU%_N2p=(fNV_8OsD=@0!``4r`IiI(9xLAwPfNYx;+^@O(4PQs#k>g zT?BD2*R8z%N2|g#=aD7PCQWhFWhXrw=#$1!r{)_|NQqH&dtkW}K}RM5!1=xp4-aCy zz#V3qLzO7fC5ty4qxBhOnCoXqb}Y?btcJ;2exiFs4bO5O0oZ!LRChqOmXrh6bLH+_#KBkl7mqQMlBBGTh1c=m`n;SP>Ug%i}_Ko0G;l|$2I3kJFEAe zdMFt3a52Bj$&5y$cP(KWiMI($-u60%VB(pxUcVT@)^b0*iTsQwBv2+M(b*0P2h?b*TBI2gg?D4Z-&iqNnNt6-=u%r*F1nj|m#VPHH3~yiG+X zdBSpTslV^o@=y;d%#aV%RwU`W-hP%0A@(UCa>xC?tNia{8-sX^$ICw4~p}(JDbo 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

w@d}oBkSX6W*NyQMy7S3+?8be96a6x_m(R}#; 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

-WZNeZGKBmxmhsd)1L3RJ1vZBI0E-)jztmESGLE&%-iB+?})b5zX5#0kFbpT0s z@*I5kBuy7^Oz1yF=aJ5|hOd^IrV~#8LY`EZ7qWy83%KR$1F4dnLhb|E08)}**CYZ? zr-QZ!LklIrA46ITtK5o2vhd;#*(&?WHW`RA_6q9#YJxQDJJw3Lw%1Hg3ti;2;Fi(; zfZ`an$#6~oZDkMl9TAR-@DL!9`OdyYpK z;7}aA0v~BrK<_WQkyCw<3~LFB9w;Oq_!HB;KgSJQ%X$9lz_lbfi$<=rwO z%1y$FZ-MO(`A=$;q?u<*)PG25j8bMYuIELUd4Z&O<{_6K}WbYW)u zc^zvW_-A5Ky=qH>)r9mu$O}83hJ+xu zJ7^-M3Ys#=MU`-bW|8LqW9!WSq59vrf6na2V8%KajD0Qpnq}-u_MOOBvXshJAu(g$ z_k_e)DlMN9DwQ&WL@1=9&DcVz#!^kTxqa`)_o>VxRcmbd+ zs0l>$$ctOQH;U!U;UTWf8K0(Cdb(7#aQ8wN9_e+yi16^3xaSFfRc#@Ytcl#wU}*a4 zP0nMlEv@-Gbnr-GEiiH_FU3;CS_d+m^IgU!+-O31;d!nOqt(n$ygTYF0Nd2WakWVO zPkOsgAE@?X@i~z8E{zMKZb_$fFVvrc2&!B$*fA`AN&sJKkz~H1*aN_-3;0+ZJkb*4 zi&~~eG)i(^JIJfL5HcIRFogItI0YO!>m;@rUh>{-Ng=iv``P z=qA{UYC9_{JWLRs5uuo|cioc6SWGKO$CiRb!d{Xatq_~&|3(zsPh=g19LIv*Ana4H zp@nPT3{Kd!U9j3rg;Bt0@uNJvr67ZU2Jmkp5xZ1aAccpP!!?NG_f?0l)e@;77^1rF zKy_0h=^%|!Qq(`4Z;^VpC}-bbTK3hq1iJFHf#q1)piR6^0Hjk+CC-+jiIHlKfry4d zR#Z@{bZ^F`b;lPrv-$F^E(lFA98NK8w$6|%HYQIY&*E8#_(-|J8J6tao8>dBxx(UM zNW`88w{H_9CY^q6p?4be*`yql8C0qY`jp^l$n zE=r+9BvfR|w(Z%zyD9ed3RZ2YGom)oE=0Oh-pF13G6k6ret2q!_TcS>{;+wGk+jZMPQmfy8*sceLeO4kov2-hHpDp+?FcZ&m1Z{&+oQ-f$QIf zq3lv{xU{wmL1k}47N453Hwpb`nGX1(IKumH+M~`=;7Wix><*0L2^*{xlEI7H$S#dv ze$k)%L*0KJJUH)3IxAyd!E?x{NI(yx@o@HIeV8;0C%pIrg1Q))g%DCOZ7GZVHrM8S zQ16vReKftukq6!pY3Ulne585LV5$)J38Z_>vH2kXq~xc1*udcHWiy?!p7;fK9I<8j z7!O5=39)cI`c{K(6pd<4LEsTEygJ0y21r2QB^?u+M5Yht)-B>~k7&3uA$K(03QPVA zo^(Bv0GqQ^)sdJ^D^FZn)DY=!6_vd<0-T&Rxi91s=0p83@Kvkz5csfTmK$@mU`;fC zjn)s^NXJw<{xp5QkBq>v;eaIdHdiSXVlNNoCRtK3jQ|&5uB6>o2mJtGmSuSHMzHs$ zNp947s%YsLDf65SxL$HBn?%(W#frc1zZQqFC!a3usvXhV4W3d2W;HIEC1roPQ_VCb z<#$js{*u7=N#tDOvD-Rc2YG233aP!M3^$5x?JUZ%S^4Z`am{Xt^c3UA{9t=x%av5I z+e3}8bQc!lqt?%ZlR}BklF#k`R9&_?yhzr*k`bp##|S12She$+SfP3Kk54SPZ)Hc+ z^mWB>`K2R1$)e+1uS!f;x5^gfDni=V4z*IFZ(DVNX^}eDPEk?^*e9|M4u(|Q_8cx6 zzdoK|8upwlhX|wY<#TOOq8`W{Ewq?oO33QkA;vncV459D{d|R8ULI_i9*9m9l z38Z&icIF>xMlDFkln{8UL{#Lw1ikc|-q!wpeX3)lOyf6f`U`NSy&4+8b=0R+s5k9n z_i1v>>p*&BX`S3JAO>zbqx7YP)4r0{mwIE~;c3d&KU3|e zDYR0fU-q+Z+*TfC;NI$O{Me{E;y?D1^$y9hCm^z-mVF+vMZKs#pF8WK42%{7>WnQl zpyA(XO9GpdvNdCTN>z31oK2cbP0ulNnVy1AcLjUS>|@NV>VjVp30fnWyp_31-0nw! zYfaStfl6y1f8KcW%v#M5G^XO^Tw|GKIxR1swL}C6wz5s^vxvRp~)YwEwQ+Je@DFko}mI zAzj{>@?$bjL!|KMx#U<*c_{j@4t$cq^w9_blt5-u2~|xU!IXr6Rw$M!TCRvYUmPAL zM-8?h5nz~>M*0|00}Vh>kr{znP4s>6qB${UWT*xdJ{7Ww6-=TZ{9; z9mbrNm7Wd&b=Z#OAVaea`WNxkX2)e`hW8M(|HYrK0i&G@6{$2L0P8P-cfAu3wu1`o zs&geV7$((}BGs1pNMt>w^~1o)brUGs*GkG*y#D044=_c$=!NBt7|9QvByT1WCY~!c zYSzwXoInjzZQIk^t^2JU@*Y?!@X&=72>o2%bb!O1zIRfbGfDtxz@Fuk^`2XEd;JkipIB)_M9T~#(}0-_9pzQBa;R%jUuo^vj_tOX@gIa2t~ zx@`5fzq>XJFdrJA*!%k3 zUwR-(am_3NN{6EQIZzcygCCw?^ue)4@Axc-*qR5REGXm$MSz<&$qGYMf!tp3zJ{Zbe_H4EqU_TuQJzfNmqVBakDYcLVHTy+Gd@=Kwab|o+OgP1&JVq2(w*9g((hE zBAr1ultJ!(tB$`H5GELiK*sC=6*8rZMCOGVo3v5D<7k?(oI&@aph+6CH&>g8pgt*q zn*X;)h3;lVaFLco_a8?`1w+#V+vv-ri%7B% z7j=JDBuJ#7kYaQaGd{}c<1ZG8DN*Q&( z`($LLa7IllWExW6g8H(7fQf6~Q#>_go$Mao+Wdf2nQM`ahN=gb{K{u`g$NSs?UDsI zE1A66C72mN9mjo|1c}stuRpOxej!tKO1FWj!Qw)?;M*$tYJ?@3@F2ZLMpmyYo8reX zb0yy)JXZKs|K3_1{mUt8clgtis8Sv_(cONz0-(fLalH=MtPqdfO~2b=F5XX56PQi4>15y zvVUc=cXH`hZV=V@kfMHRgR3QQgpBl*syp?bHskG(bf*Q;#Z-eJSC$eEn&4Ov5D7I1 zo(;o}e^?FL{)&*^q&m-kVa8mo1QB4P-y>89k08Z0zn+l>o)Gs)D4j818a#k%Q=75i^>gg4=3U1jzd8`k z^nG~0VTOJYul0B1@ZZ~vjbXU2c3Y4Ax4*ES>oFKu+HGn>QfS0Rl-9q$kO`N-w$mm% zK301qVvpBa_>RW~&ll{O5*}u;S@LRd+QIC2l<*!UJ`;)wb5=LV+Nn$=k7EAS!Lj%u5HTd7Lf%OebA-fyO~ z43}hJuE1%zX}a|K*Cf~UEY1!H;P)@pWxiXGf0{u6tA!;9g@&P3?9NV(1snf7yFL@2tqSoP^nEo zCk}6$ejrP(O##t8i-e3}i5YB?H$xukK+L6x-Kr4x+|(v3k*D7JydZw==?~dMu|%~- zjxUdy5Q9_GDMwSrj6BngA>PkopJ)kW=Ay7xa$^dFlg6p56V*1~xM-=Ngc+^%AKhfc}ag3;f9D z4iKgT)!$02G;$43kcOG|+9&XxJ4_3h{B^NqnHkT~59yTZOYa8%yk~I}U5D@@g5__j z*`7anmqigP2W<{dUQWSYTuF?Msj88#AW@W||36z6CxL-$3QGmy1y5V#$|!R}mc8fQJcuGA<#yv3Xp*Dj~)Y&Zsk zw87BuK_1Uht; zdz?rAg6dO9rQ+)`G{m!h9GUCToD>8l0woKBl6W8vmfJ}Ap+z^8rmGOi#t1w;dU1Ky z3)n7xF-$*igf^vn=C&+e5Ii)%vnV2Tvtma{FIndL;U%>aR2ZE`6BaQ{=@11JV5nRT zNKY8R19FuL=7PpVk`lVDj-pr-{H_4`{bB|5YiATqSKJCuG=`B2b>VrN6MP^Qm^rn~ zrAS?zai#Cof<0E01A+$JPR0a!;WvFOOVmfy(%;vVccc_Sv;{TSdf$aZHrmZQOUa*! zB_QOZeJ!N~kKh@h;u3kD5u{y5(IIM4B4|%sNR}K3f2#&TWH6-74_Ru-WHHl!L{(jG z()-r$cC<{fKQcmX&J~~pn^Mf5<6elJyPn{yBkUT;GKie06f4V4CTm_c3eI*i?&ZCX z4K+!~upJ9(3*4h#c*!eMjbL8#ld;V053ES@LId!yLuA2R-#LkX|7qcu@NcV%r8qjj z=|9<{P2R51p-W!2!tsW=~ z%tWK~d~v);SS;x&e|i7w%-yMqozcPeNz3!^SeK0dxxmwoTV5D-<=kHROYx@GxE=Le zI87|{S=C5Qm45h%YvRrRjV#i3E)EzO=&3O|%)4U*0r)WkJdivQf{urU?i~+M?Yb(s}0jDQKhx=xtO*t|xf&t*Ap2Gq9e;d$%sX@aCSF4Vq=LG0^A zIMBIYVd(5W#B!P`yMFM!OZVw6>hcB_*oo}^M&~O>aju91NjfN+9;{9b)WnV@yVG$n zu(g>q7JBj&ZtQtxCheRC*Esd1eg84-*zc44J(TNe=ab1DSuaWu_%8FT90x|Cr+6F* z7c@V}=)+uLb3Bl9~QFTk<@OGpN`EB9)Vg|Or& zKEu^hxo7mbd~2ZI zcqN%K=)PWtmxMoz3jpesl~s!$zch%Mt@Nw!vw>8Z-?M7NDL@nz>?JZknhJXhW?p5P zO|KWY`0;Eq0Gjd}O_O{WL-PUR34DO77x(khFKhvce?-CPQSeie+|9vE%rI$5qo>)c zHvr^Ks(=;yZrsk=o4-v7>zHPS3oxg-6fMbSky)vu?M72hTzM!bnct&iYQjSUn}ggN zZ7T<2Y^KDsN;y>7ng;FxRc(kGA{O4uE8d{1#=JRpqEu^}rMj1aENDV&- z4_+lJ5#iST&cX0(>;Zi2UvNwJr+(?vVWY3_9sHqlB2$08tm}}F-xFuPN)W z4qb`E2#TiN6bhlIJuKRZLvf_J54`-g1vKptSbd2-*&XJ4N6 z!3hu4m5NE_xVO6=ceP2Nx%0X_j;gT*nJcurqqFWf&2)7RJ_ZOruhLkzFr!-kX825)CX>a+41_lRlfX~X{Z~jlOK!e;Z-fPMkyAX!;>Rnm81(8c zQFpYxIx$pfT`UIV&Xt2M)2H+0oShfW0dT>tbkIVhnA^9x%CS-X&2T`Wo6|Fja%}Ga zs5GmY6#~NC=M;~5YZ@9mp;$yy3n`hp#XEc)k0~PBl_}z#UuXFm#}mg;a}S8qNF+g! zoiIl1D)w;h!?Ys0z%>@aC-_-gG!p|e%X%m?J-2-X(P!aM+pW#C)N6TuMg@z0UK&x6 zQBXMhiO)i;jmdz>Tw(E;M;t3HlEO+v0E-JUVT7kc6q1fr-T_&imIX|)F=nhLi}02~ z6Q?xi8Xu-_zb!kb8KMBO%m`0ErZMg=su@nFgs==Nk5T~jBz2Sz>-<7m&cBmWzg%6k zewx5zg6cNzF45DpQ?OH)CsMA`(z3^9GJCAQ={E=7%(%alxp!vyNPLT#%MOU!RVdsN zeYMk?!+y%M^|OB4N4v;-@b7tKj~XRCN_lyvnxvSs{h0dI2faUpN&^O$^jZdhb+!QT z5ft0~?}^nz^PN_f8G~as&>+pGHqWfO_V5$AyuMHk$%I0R{ckRy&Cu2E+DvS@lJKO+ z%vgg@dCMXkqAM=M(CT;tlz0&=VykPrRe+|3Dck2BXF3(NbJK%c)C|Pg*?RvwXZKsE zapb2E>FjM&xzYgInwiEn->qKGsnWD}Bb*Hu(DrzTPiV)bVoaVBKPF@*?W$*=oz5oZ z8|QQ-Bb3Z|C%q7ZPQx-}D-=-=g^!Tbv?YbI!^RGHyl7MRts2|lnh?+PRkTw3{rV{X z$)+w}Q@{0lbR)<6j-t(B%d(L+H496P&y`)%G%pAHvC_Xcmns?fC`buk7e)}<21Bo; zgEBDzHehZo)mGY?w1CCpp}xmx5KOyLId&`yR3|eX0Z>U-ftOx0c_zTW+l{< zb7*5wZHhP6s2uuND;~vh6^s%x)-}(4HuPdXhIl>%6HYZQzB+ywlbacJvyWtygMsyG zQS!2)N5+vg=lU@L5nIs9w+oL$D=3t z<$}VP8FCVdTA&9}SQnsx$nxnT4yQlJ=*H|9me<{`nPYPgvzJ8#YG3vLy&c+Pymoqk z*w)zd7iOl51O92kT7Cy}GBc^1wP0Po6k*oK|G$~)RZ1L=*LzPVva z@*gH%<1XEhoqDfkxy;6_)CkIxIu~mAWIicBj`UMw!U*1E5Rl}Qv3d-q?%x08wU!pM z#|c@T$sbF52mnH4g*JxCSs3aJo-~`ZTG~Xpp@wHgi^im3P`W7JLnyomERnaGfgP(J zZ?Q>lM@d1XW%$)R2wbk_YdKtag$L|A_wNf2OBM0|+&6^aJ-xc*<>&)=|1pi5QmMlM-<)$_IYaPrS$0GkidYm3l zN<_ljJGsxNhXy!FCWH_s4QSAyNfzQD?b?xq>t_UzWy*p&JTso{P<`?5IuoC=%ziN9ID)r;st?4E>jL5jrozuxT;(9L_?S}^TDmYHUn{g+>e z(|NZ3I_Vo)(s5U@KANPT|>9D zY(|1Q_c!u)eGX?I`D@0vq3+=d)R}yH|ADf*B)Th@C#Avc;eT-7f?;U{Y_;)}Amipq z=+fTcRtgC;3OCNTS1c(-T(9~gqoD=_&NB6A25Ferm8Hf-qgb>H>-5iHSv_iFHq|X& z5NJ2mT)j8*=sKO3&KHcYTrkx95Bz-G-d9=i858i!x-AQvja&(tL$< zqkHFWlx45GbgF3%0Hr495cBq%073KM<1DFc%p#MhZtk_Jr+`sRbd0d4)Z$V`C*ROzkX=-TE4qXt@8E z$kVTMOp=*?a-7?JwWTa8eEHtJ*y*`s`x(8Qby1*xN(cWouPN(`;)l!!T5cLf53|X~ zzxDzM8wc-aMK2Q9N&37t$pC7AV<*dczs2G>0%WIe5vYZrXA2xZX3yfkpijV|?qw*? zF(x!UpX9b(FA8>In0l}T9D<_2)p=Bqbd3Nwp_w+kxq2XXn=}xRjMwR%goAoi=?*1m zREK`GvF=Q!`7t)aE9pkq@TOeZ7p(I!lIY7b%eSs35FFX}Whp2<2$7Q4uus%{LV=Tf z5Zz|rYYlo8Cb2z{St^CsFhkHNFf~h(F)M1;=#g8vJX-?`myNNsTBPr=TnT)7wbP^f z$9F_twePyTj~OarzOy zG#<4ENZK#bw#eTn0Q*H#D$e|p*EO@>(%#y$LBpxUosV;;op1h9oHWZg+}hS7+C7ti zZC-tk*s394X@gQsbpoEYd@u84NWF%So5}2*nY*%LDbST>@h6QZ4V~R1{ZC(lV`d#} zeQm`p`^2B$aUB^-_Sn!Ov@pKYI;aK;jh|0#^J=N$S&1X47qOAoANV#5npfk(pL?k| zkSLM%Bhk7Wu&_e7iHiG@QRVI|I$Enh3#*%*tEwR8kOO-KkVZffB_z!ivG+)ob61_2 zBeZUI*LlwmxBFW2C6HTW79y>7)=JJ+o9H$zg8wEn09?(YsKiq=^T2>vinkU0u{O|; zYD0$}P`$obq583M6cmKA?dGnW|8qaA@88^kSU#?VWB*!Tt+ve>3#)XaMqe+xMn|M9 znN5`W;hALVWVRbEhyb;x?uVz=hcFOnkR4^vYa(F>VBim+AzBc+9j2Q^Ra7S4K|+b< z!010q89e#;dN#1GLCGWqoN5vpn}DUs=KO~Gr+ARm5Jchu(L@}SyAX1~O0@MQo(Xr7 zwvlOUp_^bZ1#}d5TQ=-%m*Me9tcpRtvx9}K%2AK@H<}FI0Xkj_`+LL^8uiBFrIAj& z*t^^m>(Du z?!cQ?w>REyUU0Zmt%9tsXlPjBS0sew-mWUyj5UFw9NjOz)BCNTyJs(Y@xRgB8>Y37Za;l_ zKjKSqI3`!pNa;Bziwm`GV{sz()HvGXd;Gf}XxuyjcRqI;OG~d09)RZs%0r*pZEcgr zk+-_P!M>Av6yLvV5$7yQXr7&GdwSpL&6-io<&o;|Zy9;;N4(0vBkk2sht~xZZNzVX z7p5H?>Wyw+yx`L9qh}P9yr?Qid6F9VYyPF}U7^6_%k%e-F+i7cebw~kKg_P1XegVy zo!oMigLads?c|b)cyw)$)UH^3;jD~FeO>P{%7DWmaAtL`WHl4{>#@g|V#%Mw>NAGU z%JLcW+P`UsQC_HaCmAR^wCii0a=*K)sWx$*<9_4KkuO4D(UJm(@Be=3 zt*3k>k0iT_2tOwAz(>`lFJR};`-w$0&(z}8)hj)bN5dtJ8-f^bP_N2lqP2S1cH*as z5=;urxlAHYAh*P;bc0{0D?>yuQb#>h)let3%b$H`7R^=%cK3hq)Q=LDu8&S>r+v8Y zwOHnRx;fkLvfQy8b-YGu@+neLn@`rbA?t_cv|?q#2Ztp7cI~?oM#i@fJoG3}h$|g9 znz6!{t$L9iQ&sWC>eeJp$hxL7oP9(JT{L!~( zUVLB`|7<@PoUeA}j{chI^y2{A12>h<*^`+7Y`j~WajxWev_;nffEheSu8 zaxA_??jRrBxmtAlMvre?;*NcAqvbXMFpFvy^?B5YCb{@vR*45|b^eRa}{YQSgX zq41jr>dpC$p#)u!u*lh{d!qZ>%?~_{cl@S&GwsRR53m00yOYKPg71_vikCgElG%uEFEML4&xqXBO7F0fr#_P&7hbZ>otN7A z{)U$G>FfPOMcor^S8;>hlc?Ltd6%j$=8l}R zM{ej_y<(3e?*ajR!z3yeU!iAU^WlaH9j7qnzCv1$IUj(te)TTuvfn@D>m57^cNYKp zJPdqR7&M7+>z5+~yj6Ys-D9&Wir*zmcb_Kk72x`9;Ka;fwswqeGqfw*4%d zzNZLS4~o59?UK5bn=B~W?(#Wk`sl|BNr4-L;L(-o3+J7ajSzv-3eO?BuxK zjNM3P_EJQLf{v_0?Fxz=-TXC9@qN@kSsmZ>#^CjFM}>`z&3{>%S$(hF&c4n2Z9JaS zaoN*DCdBvSsXad3F;+xXl7nT;F{71)49%B=J5|%4SG9<|@Ae+M9&*$@V_L`6)uClp z|CV{DaCR{I@1v?;?cG}&Df&)HV*LUGlb`G|SH^Fii|UB?!PUs8e_i^b`c!i(EUEO( z*lQe{Zw`^?h;G({8{DuOtDE?S=N&Ng_u5@T&-O2MbEIxIx5;M}#)wR}hLxr~m{a@q zaZOz(-}?}=5#P9bRes=?k8@GsYKv&KeEpSkPD%W@u``U$z?hu&^L@1+MQ(5Z^Ej=y ztoM~m!zGxC7w+S)ns$F{6K?T4pyXur*FTMlaqmrxOtx34qkI>@pmh`EXJw=KF7BgG zk7_2jv0qhdU&hL3Ug#hr(-zb_T}%kz^Q11$susU3;56YI_0@q@R5UdT0X1iQwB zS(m)rTIT*p@VqR5F^e3s-IySU+n$|0IPqE@QLjQu@VVChx?o>dPvV zTFd|BZ)h6^*bxt&Fp9T{%n0hUVla;?hRfC59Y}wy^Q~Quk?JAh^Qa_sWANW+=mjUl z-ND7C%tFV^(Gw*$a>C1QlC^$DWh*{HLhd<6@wq(vtK~zu;I@!wR`Ld> zAfv!i@$Vm!94p2)n>ou8XBK0{y9;Ih=1nW~gk{ajMUiaIK0Wc(`$u7Pypou5i~AoH ze3N8uoE z`sRpr@rxcxQ`V0jmr4^0z^(eG{3#8wr{29MN;`@*o`l=pTWVdC$o@vZ%X>ePA+t_Y z@uu9pJN;QF;;;3rl;ipD#}s;=&L2}Gx7jJzcy>sylD?yLZ#)kXPja<;q!;$6LO1>E zaiyW4LrsUn>qkxQ35r`R;a^!9@*Ez@6HUyFA?Tk^OcQ>zypFr3)fV0{e>thBe=V~{ zyC`!aGcIo@9EPz5ELQ+xGXV+QWdyF=rN;8w2NUpBtX?O+6raSLE`B zWk8n(=0h_oZ)vpV?YWyDzP~f!yu1DQY4y(l0z~jvZfIhod&RTu%O9BvKVn&W64EaS zGvyy(;#1^w(rql%<}Vn2<06*)KW&?=vC=Soy2tW)Z&+LAKt2C|i4PtMiBy zc6m>#_4$7LY|fX#^O)IG1xAp|)+NzNDe)S!QBkieS4d94vOM`TexAT`$H)Ow0;M^o z3On04iYj4e*1Y{1UpglMqDS4%GZ!)Sy_B(RVKgsv%U0*Ob^_>`JBx?J%DXOvwR-29 z#TA@cG68_r%YPPw)Rv7wq8+pdGI5W*+F zQ~H_4RKZN3bRo2ag0GLolUhVu^U~|IDeVOEK}59#o=!qU7elJiMA|ib;Hn<{r5oiZ z>x5YzSlBCx#%2I~OV$FM#;;&Q1EN0<{s9YnxyEp`hOZ%^Puyf4Q&C&o&=88u%jm8c zP6uOK0kT;}GOm7Z394(h35r-o?%l}_pfS-K_yenBy<)fU{LNDTl*OcN1MqkkZ~Q$3ZxGxd*EsTGIR--NvQT*%21N8< z14R+veEHI{{`zvAhn#M;E)r~lQ9eD989RKh>2GL9a^!+veW@kP-ccH?MSo}!s{KtzC-+##5QH3b*H z!X0DY+gzUg*iuleKqf*-Sr+kPXMm5=U*h&U3_DP1E8Um!?>rR*0G5A zqg*@yDw43L?;67k^o^&@69FW!Oy~4Vj4uU+p$63;ttpUJ4T>=zIB{Q#f?vNYoc7oX z(2bu~X+iE;3YGjOAGk?XQ(I*mx|jRWpI6EjBETlO>(M3D21@-B|*~&jgki|7q|hW^Pg|2CbnYYslw01vwR= zG9C`j;cx?#T=N6D6LD=;3y}WuG3BR!m@2{&#=%K2-Dp#v8y zCq>#?@1-TOBVX;!=Jx2-q!ldOJ$T&nlN`rn%FJqWM&?h+$nMAHy^z_v3Nty2jXkDi zsk0GjlK0L(P~GMe8bk2`-7J@|#xg0&zp%|2X`r8br#g$%4M_{*nx|YEYI{fR#US8b z7On~5h~1jSonkan$Z$B8YC`^88p5^|y5!KRh4WT)IWy&~HuoUAZ+J`;3aZhjEI!sQ zn-l4vf|;lcK;TmqwRG(R$#fpz3wlpL0HQN*_Be1;f z+GSm2k#e?UV0BsgQxw-IHq+S36IMj5sYJ(VR9>5I)6SHvAewr9Md_j)x=eDhBB@pr zxc%;@7vDh*!M*t*!&qF5)so4QWLTM}cFmwJ%;gb-LE#!fP#XL*cC5-LzL)Yox!FU` z9K$00+l-)x+XgQ`=M^MkhYK|jj|~OQ`T6ooB&W2+3XhLJn^@+r?S^>OSclxZX6|~r zH4^(V_++wgB%Nt9y1b6oZsMhz$t_Iskj6V=)5W`x%o|8~dUifP_~gwI*U4*-`(IFi zuxwHFT#30RQnaKa^}lqb^7NNfgcPx%xn+RF#odkxpa03(nGq?hL*SG^KCF? zy7*M*_IPeR$+?iQe7dmobmwgUt~E#pHs70XW%SuiVbcbeeD^$=7o$trGkm+UJPQxu z1%Xlk+va-9kb6Rb zx17l^$T0$I4X8lu>Wb}>Iv?y53^gD@RkEe*6C6t@#tPhStZpS*&j;A?2}?lXG?8d7 zO|PjEgb{>)ddTRD5{sF>2$A9@ej&I;KEXNAV2Wa~PCciJA{(NXa{=Jn%6@bUKfwMx zML%Y9sAr6Vw%;5D6oW4Z^;JumP8I1h823N@X8}duUqzxJ0uJqxf3p0nX^rPvb(9L( z=#^uU-1&&%L9uiolP8)cE$@{eXZVl%m3*7K(%iQV8uv~~pz61=0&ho}@@O^nO!PnT`QPGMTe!Y8OTd8{vOkYD!1a#ltY$Srr-YaL_w} z(H0S|seHEmnY-iC*WdAySK+#;(6K4RxU6TR1HgOQfL?maBh>tkNHrJIBfJs(EpYIT zM<8~(A_)fsEp84;qhSM7>Ql`*pZ*v73HcClz5ty| z?6}tk^|2mMWh9$%fH@XEiDU82$Jo}YICSS0Qsl)p=Qt>qZFXujkWx0fIWO{OCJ#F; zjC^+(@Ei}iw3_;3_RpoM6~ljj_lZ%>0Wu*gYf>0M5JJ}x=}o6d0^4C}hSK12CMTt| z=K(z^fK--0^n5&XMal14*TIn!{`3UmjrPhwZW#Xa;&RvsO%Uztw_#vD*m6Up#0{z5 zbrt8Kgz%Sl=DilRNwX~tXkzfpn~QZ+N8vOB-yH)l9&>g8D2Y2R`&ES=9)hNDmh-o5 zUG`>9lQ^AxoDC1ih`ku#U<-Z~2A9n#tW!A@9I8zgr6hJz%a#Nr2OeN#BOBoK&*x)B z)@p=a-ONqJ_@E)|%MWfKU<cFchZ!NCdvP|eGnq=I6#VQ**cXyPc*m`D{E zeiGF-PbfXXPZWks@a$vj6`0b+JKEP*j|N;$Ap%JpF)juh$#>L)CE}L zUf%QL!q>LK1LSdCMAa6qVZ&cJ5qJl#vua8#1>qcU5=FL{i@4;1t9HD->UT=C9!z6 zaC^g+t-DoOn(aDLxPl1SLQb73IO9mhIi~e)M&sYNJSlUO?1Hw(vA~ z#hLnOmyQl9&ONK88^uZgBB=MvIa%CUohvc7yTvxcR)In%IWqk-TYrUyuFoS@E zz=qxLw{-51R|%pB`717!S?w!$J}$elV5rmj6Ze)5`5{+sbVWAOYPqkA;9$M*Dt+OB z+M4jNa|Kr4BSW^;Y5w-)jmZv^P=U#x-t^yfMZ2CLNH!Mf!gFq8;PGW^#8$(dYpjT^=RO3juU(MUo#xKD@8ZZ1l>C%n zHXUJ6un+G;_y2?#O}LbYAP^DFhe6;o=O_%Y0*6YMq%Gaf2WF+Ka4|z2zVj*76(_mN z-q^u54~4mkgt<^0hHEO1GJVOhM!dx%?n-imkJeuW1Zd^Yvb7CAYYssCV#OHq1}F0$ zqq!+e;{o|0_A9u=pOck7LzYll+WG7|#SBFl%YQq{mMzvmOKJeEF3?XGBk(~~kBHiA zS!hJAOGAeb63mZaZ9-7e5%48Ff)gwvRGY7vG2pt9kMR?(C5W83-2HfcH`oJQs(}9U zk_J4a6gUin_n_e^wAVa3B=nsh z!VZ!ACHWwX&w*SI-FTkInk@I9=(jx6K6zkHVG#e3>I&rH<@U1?b_M!|ja4d|q~oD1 zg9@+E16X5&h`jV_g_AY++O_d&#dWd+t`Z;><8195#oK~&5)NpLC195q?mc85Fu)x%Gsiq6m-sy~!6e-43rZ_lD-^;DY)vC&V z79hsufcW{3?@r}=$;@M7PXQw7&5z-_K-JjAT|1+vw$9o2tul!5F)y2yhb|L^RYhN2 zkC9#EB$QV>Uv%~iFpLmp~b6!_s*#S zzLp`tbOHoAAglV<#j3?{HRQU@PXh3{NZLzWvy@tygZiy7P&E@EJl1B-X^XPR}QEnRufqp{{z=5 zxJx}xtqD?9p~o@nR(lDb%}5d(eWKho@gsQpk9_nfwiS5P3Ek3S>2zH>H&=)M@kBJd zLr@TnZPgilUPHL+`hadan^l&8_>|hIJ;t5U52f1@C#^pr4;lKJ%P{1=Z0}i7n^ga+ zOthy(w{7p;B2$#ElGdO(rq8bB8UXvrwrRvZ&_Y@uOia@+P!y1ad{!7~qT<|c*W856 zII)Z=QK<>?F)82Xn&+CRAAAEed!<;KH|Es5RWPPR+$z+#Vrvz7l9iINpPj&z9b=36 zMv0yku*kb|LV4!lu}ry7Rca&OMXxO~F&I5b`l+tEj0=!ieqgL*pG*Snm`92X!c7Kb zZkSsjpH~aAh1KW4Vw4Nr;QqO_+uob@ywHi5)F5(GS`*O(_^MuKZJ6 zCIu5<+5XWk2=hQy%@0H9O4vTEoA@%bes==Ne&Mdq?wFoVf`&0a@-5|}$m?^YV?+;P zx7o=3TX3J{6bkRU%X|KD@Jh2lQyR47i8IJmds}(>;mt$3(iGv}li3+3P%P}j@V#yq zS0aA@lKt|J9{cy|@XAQue|?8oYimQ!M-AWSIj$YkU9TrwqQr|Is@L8S*E~!Gorxq`@s;;=0qWhJ3U!#xoq7D8TVURnaC7vD z3H3R;f3$g|G5Nv;$aQN^@wfB5lq~{_Uv7 z0rqIIip3z14eh1?nh3A%Bj4cQG*(P|27u{XIF=G6M_!JNg!jNJ+^;m4oQb=(=|@#| zIzabx6aDI&a*6!wVJNz=n6HN&EF9RwMb4L76z#r?xwt%NplPK|HWy*zn}TVg89;6e z%M4KI1Z1^Yc=)_Qu`k|O0OB)5UuyL=r(;3`?s@<(t`5kU|79KsCBZ zb@!v_8DL=&NO;fsyoLJ74Yp!IGejou;ki7Asm_^cvgG2qyCmw#df>wdR{mtbfxDMG zAC!a+>*qHmEm1(_rPGO*&$=A6NtkjadFK1RHm|6`DA?}pI&AeXMHw93s^PZN&B^H_ znw{`sv5aJPe>A38+}fG*7k7ufy_eN9=j^fexw8UY&Y8L>gUTb~XD0DH1^3z;jaue4 zVMRNORj~&ld|QqgPlaDEhBayqd?E*Wjbc9`!&-3x?hThRH@P&4gP|l@gCISe#)u^L zje`8CU)V_V4Mk=kTs0x`^-w0d8SrIwf}G3Yn5s4SU-5Ot!)MD{u&JooQp0Xcolh)j z4tg|_$K2?6XO-Nz@D1I?H>)g4CNRa8y_M{yEQ8>87Gvvu17cnBW0TUggBBugvoc?C z2B>0oz@-CtoHeIEz3@r5g-fXzuGE8?d8$V?==RId(0k*jap{It%*T?G;FgB}6neFl zg}Dj!z~A55$_Rvy@I4b{<29b1L@l#uuI3NhHw#%-#IUJfm(nCv!V;x< zIqjy>E;p}HC*#SRhn`bsmoG-mQh$#ZHPFlV#i!}B-Z@oK&o`z0uRJhBG`$PPedxAy z@g$8plT(zorc7B3lwbd#vTKy~TTPTkAqj#j9?DHG{+%%TkIfXF&^OKSVfz$!F1_YV z>vzlMhZvfOi_{mI9fEuyj`Fi??}iL5Aq5lFf83S@Yk@^IeVFO<USEC>vZcIxC0S6MaDi75G+>KkUVLX(p!upNnoB@;f);?s$ z(!hM-M1W_6@&~LDlu&B&Pcx_=|1Xa3ez|#C@w#m*cE|6XE?t#}Mr{;AUH;8iR=kx> zF+ToU)02Kc&J9b`Q?p!mcbB>VU&!Fbshb;c6%bW}?fGye4TK9#B#TILhfWwW^=Oba zxy3}K1q4w^+E5k{h~Z@Ep=PKIVpY+|jV*w=WI7#JRRl{05zT0Hk1NE@TGy2IrvCY|CN4!6~rKri~VWB*J)wANGm@rS; zX2h}&mB=|ly6~-Cag&iM9Okn^jqQ5L!w1PT1UXtUB6$a$oFukl=Mn4oefm40|GJU0 z;Y2c@4QGtoUh~aY=+U%`fJLLS!XmyHyiqzU^A_GaF3Q#%VPQ5MC_j&1}6P+Ek8ej2LX*a72tMaf#x=hB%>{ds3d4{~AUZYsJLuR32K; z^9J~>L29NMqAk&z2Xu+Qto`B#qRtW1CEh8nyY44%K@@H>5au*QolEGcw>Bh9&YhhPh{UWZ}77nFWJ#Xc~*Fkboxv3^S1InnaVA?4Ld zn$)B-++kU{|8#kJhdD>9UPaQ~~N2_jjsDT$nqhPW#5)!%F^F=8*F>|Pf_>7!*$j|n!4JJ zt#FRo&Fav{@_UUd`p$?pVMZ55qcqk<&BYcKPN)mSO2}d%O#=h$Bhs{hIf+O*)g=93 z4v0Hdfk}DRPaY%-Pl^C!7OzIav@jw?u%g^ROC-b>??H%IapfxVaqczIAR>Jw&I(FiYy$jxq}=ZQKg|2N0oqB49Gh3p`B%&OO4bzV@@c2qXfF3+HA5L-S znNajS&~t8xmeTWuqAmoAmuwqU_-fzo!t|Y&#uX%L&M4cOU2EXM$WEIBs#%G-dy8fF zJkPNuY|QIJA9$Wi;`LOtQtu&nzR3_Aj%z@_)dik|lXx`!c}8`Ro4nlXL5G=hUQeZ% zeS~I~cGIiKiQu@t=rXrX+&5!Db%S1eSeUt>yy-pvyb7&>d{^~CLsE_CrxwvG!}N>Z zY9^=+m*X_7crKvVBU9>zv=(DgSJCg_7X0MbT*NK!y)C%$TBpNxBLMxU+Ut=-`p(ax zI@|JHoq#j2JyWJheM^Ep)>%n;dxl(jx}?t$s%g&-Ehw0#+-OcVu*Z!16lmF_QU9eg zDlXBA=&b=|txZnXVoziRZpx57h?@k1D)~O$D>JBX05CkHGDV{9lD8R!NA_Vt`;*g+cw7}mX$sZ(M z_{Sw|a)8QM{-^NQWi_J4yd1b58gpu(L>jNXxl1N{h4<&9&e}aZ%UHcTT%7P#QC7No zhd)4cp8G{rp1Q~YtNvHFZr`+SR`ZYJxiDwRB-Z?=lLUp7wGVVXK!_an{9nJ#4P+X*RTmIRZ_ae z`a2ZJLar;LfHo5f7zu|C-j+s^r2kNTK$<>cgkEff2z5Y=nz?4r!y*qi?ojJN2Yarm?ZLGa;O{2zGushv zMH3^?*OCtF$@{EqKngWB9c;wdfv+J6ox$OqlT=;n1pWRgCM)O_<~G z%2k8xA(&dI$F|Ud?rPcRg}XjRtE+XoYlpEEj4GJF<6eo<`5v&hVH$1+o-a)OkC>Xy z@aHB9;6?sW;v4DS*jAYx)KqMO8;sZGoF7^l#%zM7d-jBQ=|QdUWHy z3@?KJ#opAK@sw%Tnw{dFN(Yc1`F~^CbLlnsS=PVNY&8xPbY=5o)_lJVgAZ;F(_H@7 z(!k|pv@D`ZSCNr$LUYj4nv{LLR$lexa}FCgm<4An+607q=Oe6Yn{O3ms20j%vg|$# z4}gZBK#|dgCMw$fUQEy3F$IY@n_sgH^>JZm{Re?)(BQZLf(!P8= zn7s0ot}-8+3rKkD_AsgbE$0{moPwp`lGeWw77@{|Hbb?Rjm6=!hn*1)zjH?<%ujf4p9bN)aC*u<9ENZ^VH7*YY}bXn?Ig_!mY zsA|v%Z44fXMtvHn?%Z;v?AIQ3A2;QKNT_5c=DpYP26mR~UC%xw5#^h*t9lu~QTvf^ zGF~0xnaWsy9_*1VY0OBLmBhhWD3J;{ifOii9ghay5G946dINBVOWOmKYY9Po50Wg_ zRZ}MjI<;^;O;${ek|^Hi$t&1+TUO;+p8*|250@6e1~;m<9!@ar}tqYw8#1gc~>P?6Hm8 z$?Nx1vKv}C>^qkmWhbfcF6O8ayJzF7x|znEnSMg_HkUz|N4=0WHbo6U&K1L}Wcs0E zZsZCe+=t6@+V=AJQE>rN#H;5gY_5L8rtfzXGF1qs4^!*S>M=#{r}>NG0wL!=$y zrIAD1*pv>=Ginjw_HAALQc92BXh*cZ#yXsdg>EfOI{%z2nwW5ooNsc<{&fc~at>Jd z=UA4r1*vX8=|BV3!N;rks~^QF!-a$HW&85Z6Ks+8N+$6`Nr%<`GOqayj)Rs*W`-sD zF9z2vWZmbHTRDV$hK;4?V{L+kdfmrFaRFMM0F+-**>Er?01GrA{;|}xFD>r83P2&R zecj6S&_89!fWl@wLQw(&sG|&4*&&H?BxX2^lMQGO03r1b&_8&Xb^^sTQO=>S^U2;F zr~%snW=2Z_gy80udFj9}MzWX-9@_*3CGv?zSzLH~Ri4P}KY8`N9tc(xcMHHA1Sb-K zOd|2MJgk0$GZzWz(pz+J-0?b*37ZE)&CTpVX#6F}_FZ+A5LvdB-=~~cT#+xF_ryN( zTPPA1DG;pi*yce@|2ecI2mXcyi%SO+g_;PQ&V56QvZ?I2CdQ0MrX>K{TUgdh`g&|r zyjKAOH2HpYY^aT^@am9Lho1Q z7@QIMVtPLow}tAxlnr?BJ>d%#h%Q#nXJkUzb`;!%I(&$>XIu9Yg}*c&h)B;jIiF}P zd#x%8&xp1sMQ#{sWqHich}xlalnMKNpfJCBUhWN8oZbeh( z^Gn!g(?gdA+)^++k}bZn9j!Snd4Jm&9<3ftaS3gQ3+9%3WdYgLMduYS76K3|tfEJ{ zrN=aZkS?i<9B>7TQ3mF`0U`}()a%Jy-$ml~sX!iB4yFi9b^?)e-(MSlc8>StY8U+7 zwSOG3!a!F=Oe*=qjyGnx)Qr#^r02D0HXDvm9v}S86k6hD4Aoh0L%DD0uw?}Az5#T? zmaCR~UA;VmWp6+Q)n7Q{7WY#qvNB#Eu34LA8PgHqPM*KszZGFG33_f^5=^o#xr^+AcA#8oaGY`Ht#uvF4!&UV=LAT#I+`WS`7c z^t_0M*)gXXT`9sanS$o6%aXp&hOhfgW+M~(&`3wk6J2zX{#0w zOY$!Np7Or4d^9#tp@8>K=Di6_z|T0RQ3Pu~yBZnFJl@DZ9aI}lK9Ja;k`acU-F5Iw z)3<>@zgHbwd(!f*-P8!N(hhC-!B12FMsKL=@R{k@M8PSnAGmee7+XbMc7DuFBfI?p zxMvm?cBOX50D$)6zfZ2bD@{9q0&;*fyVf+H@ie2~S36|mwC<$5%m{Jc*0w}#y>-oTxH5={-~=>wC~|J#pAz{B$gT>zE>M8imuR$5`a zlk&hpeDgH$Cj#(tp&6fnHQ!^xhgEPA+B~LNE=Yq}C)}Z;HzBQsG;LdklUe6nHB+_H z-)9-Q1h!3^A*WnXLDLy?`MA0BsF5=>&12Uzea2ImeKyGashu%c4Qi`~=tWA6>gMw* z-Yr}0=Q=#1=|qa$W8Nr^6zg24k~WnIosNMZQ-#lB?vCLijFfGh_hK9+FlGNS3VdC%gu2b}yM4M4uwd^QET3z+!H z^z`w-NwSBNniN@bAMwK4wJRTkCsr?BHwf6v(<|TT)@n9~V z5gMq(Ltg$EonJwNI<;Gf)j6=^DDpKATBn)p4(&VBz507IEab29ctTZQx2m1S)sNjc zyW|n|cDoEQ>dn^}!p+Wgz<&%uaLQs%D1k{=?XE?lB{H6^%ZBx?^_w==snox0P_}&(W@$|F5i*i1HGosaf066c%EB!EobIwHzMe^(8 zMhGBdX~;Qk!R%k3IkSP~jy{&utF<6zroYqJf5Pkc0sW+}t(d2YHH2RHP70H?ZG=6D zN|-bn;ja)IF1em~pU%xE^d5J6`vG#1_QeKrT^Bfk!}Kzv%mBJ zUD|ZYMf%(bn0JPEe%wz?0CDRiPvE#Eut0}a@hzKRZst%SMt@uADuWPG?_6=dJ=@HS z3?09Kgujxn>CttBcH1#Sy>ATDDCt-hB-$-6+61iXr~@Tyzb;8MaiTo3iV)7zWdbh> zx*@QR^$$_FF*v@^W{-+i2a7=0CuV^OtgFowJw7^?>%4GPVg5VB7G{P)vaZl>CS=ZH z{dJ%FKMwbTer-|)%Ne?AdCK^dodmr+nGtWlH!zAeXSF!ij7}4iXpqq<nhbHudSC<;G2qSr@mU zs<_BpH0pFo7Q^dxj-f({xr51EmYcdC0)^NV?U=Ar#B_<4n3gk7ciuwoLE10$u+To?X{Q;4ps8kNV$3Lgfm)L2hPTsmXax|Ve6M^CH;mGkJ z3YMXKNoHa1+>=-1kj}0N>~yh|nO*C8R~od{H)>Fqr6yIQ0UL!BT4|+D0)XR_^-M=# zE@?%oq{rHdvf>y0{hMC_*2uxG8Q^I>!L08zmP7U3bFkgf7UAQz=gJEs95FU;VRBic z$)ObF3)lTU-*-i3ZMjDNbo>=Gp&BzH;choduyR0~^{UOqYFmsTd|pSYicz%V>9bCG z=Vr9K!*Q62&IgOW!;k|)Vu+PwfeVZOC42B5{ZXwSwAU6&lC!$ zO||+z$!ST~Z+Pl&6J*Z-_`Kxbm=&Q(Jv${BDzt(uP|d?&zB_Ceibvc*n}}uYaDZf) zVol^@BogPxdN{2@v&v!?XR#wm%vYYHBI_+ix3$dYnquGoweM4L@vFJ5QOENT)4ZIJkY2hQ%X*D6 z$eZkB#~C7zZ)#xq^&^+C%%% zfullvZw#Uvxv#0X*g_kSor1a99!mk-4gAxhiYRJMwBx0hrWMq87Z>fFVyfyZEEhcW zJ)9?UR(e*DCAh@*88~TNXGxSVQIx)AeUDq~AEyDXwgvb(?YP?PxoAa zaY1=a1^pO?7XlFi6HeHwK(0$(Pau_CS3+~^!&aa*6ahH@R*K7#3EmW(CIB9*>)FI~ zRB5cYV%JKPSMLn|7jkU=>)}uRs9%+eQj=)62AGtISiJ*v>?ECzEL^uW{&VjYKCdm;PTAE%zPJ<*eY)kQ+%ZZfg>@r#+K@#s zq4T|Iw)p{Up9lbfQVX#~NS6=W=E$CSqU&y>pLgCVC{^Bp=4$%Unm%(x82NLP(g7cY}wC6o_&a3vjbReU74P~Q} zm0v7CC4x1Dg$u9ifN_&^_=i`4igQio4qJ|4T#MPP3uk3_&XwjcdU|tzVD!}GU~-!; z0yVOpOEMEMD{Pcstu;g#kG&G@YiTeB8go5tnIvNyoO~uLa2ycPL`cj+6M#k}fV@5A zJ&+RYY&R5!fEFmi4eNO?BsSNUY=91rrPz}PnF65sQ)K4UI|lLx`tF9g0Zhx0)X)*H zd(q!>kPFCZ-;9T(nD@}dLD(DGw?K99sqUvkR-$@42=(xQitNT|DRNu=|0WLP?bjoT z1VjrX0M%Y&qnxm=dfC=u4k!$Dvzee~P(kg{A%Y6!6MBfzxyYdwM) z0y(@k8_WMeWE6hvs%mGcZNeQJI#zo@t*o|^wd7$x>|T)*!^_P;Bkm;5*vq&HkE6DQ z*nd9a?Ph{4>z=ru#lfDu~BocDYKJ)F{?uML2D-K)+2>MezKK9P8< z7WI6|?;mpMO6Q$x4Tf8OXm4d-W#)%ief+4`bzipxf6|Bj9Nt0ZPWq{)XW`br0mY1& zY5g1HQ!)CH?&>gO$%K6xlW`pVyVD~rA0<8TWJzE>e9?^d_XA{F8vkM4;M#G~>F@f9 zsajLd4lebpNtrOH2KRwQBsSrI*ro1*h0*SJq3dOfvN8Yay_zx0#(*ozTxrlNho5iw zy>64Y&dZ{|#6d*c9bT$6C*Mm z`3n71*mm{ACH4Uaz;;N=%9g$W0e#Y>l-VSm681`CZ<+!W&WO28>S+sCChQpcR3#}v z4H3q-gzcn)`LO+8qRV;i1B|n9+`bUF3B!Q&>OCQZk`NP3naXU|W1>mhprE?GBvFmN z7w%3e!BD;>Vo_XY^Y{qzcSsg3@$b4_gR-&ZIq;5&0ZB^!)Dj#6zf|%lrDyaeU%ECi zqS>Zmz{*7~)abM1=o?9Mnx?F9gUDr-)c&~>f+OP1S*KNmXR3wTe;Q85c0)I5;+JG` z#G*ONnPYpeyjXLTzsf_dJV87MaeXrC6gh;LtTlkpobZSgI6dc`5`oUWJbI7ii$d6n zu5}{atn9@r{I?2hYV_lPDcLCYj)h-Ht_~)l^RW7b7PI2vM3aUChV42BVP6Sb6(%zO zvVuPdIlnDa!&oM{o9qLlb$@cf%O?3wnXC6_+1pa!8se{v;>US#`1A6( z1p)a4(e;H2)>w9`BvUJw?yG*+gVd7mAHUcmw~LECQ6Y>>ydhFwQjWlKPQ!a2XYGPq zy9UWW=V>_I2zWhktuL#W*@BoiDbne`5c<^!RuEA#9n*V+hE3z_25^cNy{AlN|6P-v zt%_qKlFIR>8O^0R@~YW64O&>cdnr$m%;%2C1LX%2Nx+l_xolerqkc>n3gM2XfP-UexF%NK-`p z&uTRn1Wp;d6ykwKt}Y~@uir07`_p%G04KF&t%oX0BQfc2YyZ2IO;z9%(wriW$Wlj= z^e@vslFK;8EEi7|CkJ;_h`PAjX01nog*7QB28~?{4(eUtXyX$Xd_G~TTp32)n4sHX zOl?D##)*V1FSWf}DlaJ#1!y?XqOmGhxO`D_g-XblK2KRMn&z-vMCVTR=Rj(bB5i## zZDVEyN8r(*2_E*z3Pxc<0h8D)=*&2KPaGGFdd)XxmrVQXM7%20rZCcdx>Kj{nBO%7EII?HlS`+Jf`^D$+yg5^p5`}V6%~V^mD`l7Jjrt4 zNcZ-1=&@UI&Z5McEZ^YjK@7A4iqwTl84E}23EyP!tJw$N$6UEmMp#k^aJA`C^4xhS zvuxj(ti{o;8{OzdQTdi}Mcx1Wedp2$LqrvJf>LsxsaYsNG7=A*hQ$d&YT*mxUOS%& zNO^Hyo-`RLe9-%fR`ERYR(1s|^$YJHUnhG(P_Yv7sTE(2afnqj6wmS~a>WdX8sd%v zZYRm9ZNu4KsQ3EL@}96vZeX*MZZa}Ozd4kg9aY_f&dJYqJ?U{p>+@n#d4AOj95>2N z&S^!dW^shuTJtis;geoR4w4yl?P*>pJ1{}hC1%SM=FN`lr5U8k;*121-zR}Wc&ATi zc9t9_v_A4Ktw@=x5l~&ciTJDbWP@7k1BMIR){JlR%1gO*U&FCm#!g$}dTk$AKFA)s zVhvMX{=Tp?(dd++k2RM(_3Meup2T1<@B!a=vx(V(Xp@9p?iRMZU^%?4GHB?-2e}1F zZTx>qp+PD|k~V(S5`|t^zB=Hn)jn#Vsx%*N;b-3dw$^FOl<&Yz|K%p^?)#2yU%$># z;lBhfup@m3rz!;EWS|R>Emct?=4&<(Rcyl!4Kgslz*xz!VdP{yiM&l*F4@LOqQivVQP1dS zSh1}{wd!W(&rjpi_4RtDe;}nQx|*5Tj?)~(39hh<=?U~O%_>6k^6{eWsBLiw3$Z2S zDA%I`dtLXG!eil8pr@3U)I^EWn8Q67ddDdAO`74RT#4|nC?``D> zlr*7>mRn$B=>?&dn>MqZO+Adt*JfqevR}FFWe78jg@%eeV_%TUQ`TAVl>6u@ZNNI|~DGA-?(N9Sr`hzlx_-rVlS?yP5*EU}w zbbS79_iNJrxs5UVI|ZP`8OB8%j56h>y<2!kS&2gN8ERpZ-Y7@e_>4)`9!lX^!1NSG zVTs9LV_{b^l*Q2s@~VfcqEg1)Z1vtUD;k!$1!j{u40^|SoH zx}gf=hl-U-KPgjZt*8}b;c}%15P;!A2Q$PS4)I3Azhd>OL#YF&xTD@ScP1{UdpiqR7QLM}KaW@wl)th^t#mSFiIdoIV z3nL32VxB3CnMh;G>b`uGBVI+}7XF5E5Y0u1-i`fIIvCdj*z4E7sfBJ@fH4SORg`Fh zwMi1wCo_P5g2T|=FyFfL#}H^m7i!`;^}w0>vvmSLh?Nao4(Pxb4USxPcOKIX8~Z3$ zLuZ_Ek&}1D!){&Qb5=HSz=v%zNm1F?5WGDs%CeSlz zudB&cjEzo7wo?KSOSF;!e?Mx9&?PoTWWNxQEcSY(6E|98?hbF{629@ga<(cn|K<@+ zK&Fk^Mu>Y6XM@ryg*RA==ihK6fNEaRieG1iLoET}lTV4<`)N3KyHG^d=PL70x~pX% zFEG_%`@C)fS-n;Le+jR~3(>2FapQLudA+$GP=YtC*){#RTG(kRg9 zc|@93i}Sz6W=Ao%9RUcNc0TLRc%#R|gx&M7!XLvc_gt~|z^NAApJey-JyA~%DE#?@ zfnsA23HLi{_*v?p&B|Bg$$YG|6-bNb-;08;{dW8vMa%EPdTdISQ10-jSBxU8od&h;b#K*zxn^dKr?01jGt0%e)t z%mbdw_S~%OiA>B5<*6K*@7ItJunish_C=Sffqvk;?nI zS@wXN2>3!gi7}+NP%)BHK$S93RtmW@nSqG0F3{czwE?`$52|Pl-1U&=%KE`gKYH(| z+Lxs?E1J^GeLy-vUu4Z}hCC)xwm03}jo_sKheL(@9A?r|Uu|&g1 z88`RC7dsF>RM&D^BePU%Yi%IHQGO7#!?R~N!3He~=1gFkm=$3E?0t%w@)W3IB1mAK z4WE-O(7M)@WcyO^IO73~ ze!Hj0bi1d1r;XfGg{6ELmb?_%=kGJlea@i0kCng2*)hlewrTd+FQ+{qM=P|EY+f@& zE<2K9TE-2N;-8c`AzP-6HtRK${k6R_G?lOO{rdJVfTrF%G8&VWqlg30Z0kuM>A)?$ zTatS%x*^QR3tPvm`a>Vo4JAfDZ7uxT8!ib{Ufiy*ayeakv}wJ0-c06qR8;D{5|w30 zQSs|WDD1#=FGbsF4=lFwR9SCK>{k}Z?I^U)&U55jt<);RW8Rt#w zn#7)vlBwzjdS5T)2JUmO=s-`4xjrQUC@+w|V_V?wCtuTMi#rURY3lKy04o~{2ncXUZ3`KuhHh>0L^sE zvyM`Y_-uhFoLa87-tq?dGl2Yz& zO37r^JUQs&_nHRh_7@|#(}`|+nIB2!L`8K`o40mSN;U+Lu_@Ud6xd=2S!9Rh48mMe zP~};`c|PlGT}K$67Ihb-v9qw7__4`=5m4_k;hJ6=+! zAv1bN8~qPUFGqb}ZS`Kv#AxcuPK?hnah-TQQSsSS9P#c>)IOx$nsj~fteCk5N7CueaP4B1;W*`Pc+7| z-}%{CZdW-+&SH^MrsNb|e{iRQxIop#?!0maGDJa}bUuwuf8>JFR`H7&nd$H0>n;QM5kSuRB&7l zah%_LV)cXOnpf{y>$g1t3+u6hF~79f&RUnkzdbpo8F(F=_4BFV>Q?Pj<>>qVfcmv(JH6pm%>HqkI0!K@<*!m+B2+FAB6sL zyYG@_wv*+XWMn&&gTlhtnQWk`I{mHjfa*8|b9z^$PTcXT1c6^-8fngalKm8O@u$}` zgPeF&DDOJ(fg~!#$!%>bG1zF#DfuP$3ZA*QCe|eIxT&N z1@H(X-hvgv_`~U%XxM~y9@yrD3vI*`(=aqASZBi(OGG)gFMhWAzc)cfxBiz9P5q@A zu0MI;S~+d^MZGx5bg~N-ews@fjlCzoXOzrOwpLW2#*kC!;&`!mBtKsLrMW+;KXi(<6LkC3Y*Gj(Q$Kq zGsl7N3cEL(QaqeecI&hBXhc2uYXK$FnkI2>y!^}FB~MvM|=3aso+@?#r>d+ zm-Y+Gm%xh*2jH9aAI&Q;w) zi-M=3SCsotG7UpUwJqyN^Ohu%45dDUyeKIDh6BPenMy?Um&n|np)IFZUs-Z~E$@RcIRH^13-dYK)R5}kj=>(Wfss=gTG`Y!zd+3}%5{q*m2 zz0S>K%#S2a1_VX(!I?Z3x-?s7IXBIui~r zRLH3-3-l%eG%0y}OSgRm2I}|EW%gk_FaU|(*2#Bju&}~_e1cVF&Q}pL>@Ge`%D(9L}t;%?{!Bs06 zuJLcwVK0!(=v-Me&Oi_ErRH6nsgb=pxDGkws{EF%(eXxYOfNHe0s}fx1-cEpyS)$; z>vK%-+&(~ep(&TpC(j%7W+{U}ATNffLNr32g+Ou(+Ybgl>;lY5<9nJvfLsjAQbctE zIvqRbT$Sa;rp;NfjC!D^{=ABctf4vbBOJG!hx@1u9$>MQF^~%?S%dO#dOY;65o{x) zYEJ`V-6fNWN!)h{AziF&&Ym&yi5Xjhe@oY)z)_05tNxner2jrxal$#gS}cqgxPrB+ z)Awn-i5c|~-q*PibuQNb<>p~x>8r#(ISJ+i9kAD%U89+v_~inZTQ&~i%he<)#XshH zRl16diA{F8I|N%LhhC}Ebb;@Gb1YgFQ5O{EL9L4fpS^>INAnB(Ici zbP4xYhMZ8*eKa~)7ZLBQ&%3zTeUbyYLq+EAGp}0aJlRJrvFXzerpP0&AC|-HLWjT7 zGUi`Lzi&Sf^rE2r?(1HC}yS*jtL@pIeN|1`oa@0@p~wx0rD^KpS8DA3`8ge~>2nu1>=HP#pTfNOPh~CF&&Q zLx#j$5u7z=#Q`q=Nod#4cOU(#RR++qlOI$YmiC*#aEBF|}K@99CxR?`gX5Xu9UQ zMh{XKnQZRtYE_-TSxjxtMf_TPT60F(mOQ2yGdHuLp|HbpXc<%T2eZ9EP&*!?X^E{64p?lj4qAFtB9*=Msd@XG|AXS{HZp}+m z2@=)0nCZGnDjQp?$%avwfZI5}yDBuz(ZS-jpkQyY^d6d+(|^DUV0)>n#si#qL&~VD z1Wg!n7aZt1N(pS&wq+|D&s?4tBaJ`PcM-V@mmvxtmj*767a$H3r2j>=EPPa8?HiKI zN^=yp?I8&XezJ9NAOI*6xtFf3ro(JwKWu3LbMG@IYySt^s&SvDZgk}>TBalXrAGT) z#Dus}@JNk@5RJ$X+LfE(5hO&lQHpw?CS~;4cDMvI1fYOSW4IR^$FvQ8zD%HJ4!utH zp(dw#>`2akZ}v$2CuOsJGIsmK!rOuYMX#9*a#)?)d=-zkfV_S@f;ARL54%cIKI9+|wt$#B(p98V^+`bLRe{wbXu2|eFC;dm zy|znH1IA;3>3ap@-N53h3|c2B)P|D@HYt3q#Np|3#(EY++_pni3k4{F0f=J74>}b> zd&Hm-9E#Bcnc+I<-zsJzn&AKj9jShjt2Lr-(C>~2tK?|0aVI!>>oZ>@b!8`Yy(urv zJdF;}!E#0S17vHw7frZ^vH!+lI*9|^c+PB9%0Env^u?|Ap7?0gK}i8;M9|kJuc~mf z3Yaq-_vy(yMj72vG4_>a@oOHS89>>haO;i{6-vpS>9PFM_>p8b`w3;olhzoV>Xf7s zX#_f-X4L?ASsn}-kGE_%#BN@=zt4Eoq;wDb4h0)Q&MS`OId~YP%h_B_5i@t|89P&$ z_J!$-^1{{Y;-{<$dMU3s5>o5YnYXYfPxf53>y;T~G9u#lB5cz#5x7Kp&`F!hU+^ox zwQJ3GDpwR8PCA-GxTa>|kb+K=j;2SV<+p*T;?+KM7dpE4#e0zizJFg(EiPBhSBRmG zeib9yr1q%FMU-8rsHWm_TW%&r#b}r)2j%K-r*Zt9d1hj z9VtaA=PwIOD;Di$c>(zC=^(3}*P1}T#J1GW)nmVh>Hu-cEd%fuao`qscXUZLrqe@5 zJSmTM?aoTn=P|nuusurWbei%eAd)ODcJ>p5KV&|fpIU4!#H{2U%~9j#M`Il%5wu{_ zbzMR($NL=JV(J&%Jay9Umdd{Z#E zLLffS)TU)q54u|Y;}&k-hUid>`zVS<*dP5*7}+OLADJv(0)N`9+mHCbqGp5i#Kfc1 z$&YhiefDnegB>?T&*TIf!%g}U(opqkp8rE)&wji+FhL}C4{ z-S_^#hhq8?7j>s->GtVuSu=>ehT|=n6IHi@d=9)P4ygJ`2j?W@T!@Q58~<0z40f#D zPc~Qi>afjwmg<3hHxr1;_XmiPLm_vbe!#^k%6H{sL=dnVYvhEWLZn(D*G>JbjfMW}PB-sP4ty#qv;r5B^*r{qJJUAqNL^59Ee$aLnkac{@#1h{ z`s~~h=!wH7g7M4RcO9&=rK~Yy;>9LL{@KHp-S7sVN%w9+FT^*Qx!j4Edr5yr2QsZ< za_YZX1^jwiyuzL5QhB1!7WFa@=ABP!u|B-<^Xi_P6R6`IBL~7Y9v(u(3@`Le)+GG; zj8vq2e&esal}t+5{`&Xg?|Bxt#fv(+kHgm_Il$cAxQJ9l5v_ z4N}4n=$M&WKfBhj8cuc>>Z*>wA&=Q^H9Yyb5*rZCQo4Dd>+}1>|2jMD^Zs}pubiH4 zz3V;Nk@Nkjuj0>^JFZbr)!0wH%f3z3x)+@FN1DaQG(7H|9)7#usQ;jaMe7!6@orhz zt-zH~qKr|!#J(c?te*6f!S#!c?_bkq+#N>vwL9fn(;D(;2ePlKuIGr1T1?12+jC>; znsH0Rw}%Gl?capIR55}?4}JZ$zx;7}yVIzY*A_pg|Cial;D7X9Imd>iD|^=;h@EXJ zxT_?c)GJjV-LkD%?L6Y$JJr~_bNV%e z9*)g8@Bj5T=fhnG&zxYTx}S}SVp`!%|J)^9*B`uXkCdE>Mtv+$qh8XwGwx7_PL9kUd~>M{j`@3MZ#XRsIDUEM=}P9Ix*$WH=Z@%ifxtnm zc$8J1!5h0vtp>uM+ksx%gM{h#J)utQUzamz^0On~PNEKswV3U)1*|5n#FjcG&DC=t+r_Q<$m@6ZdsNQ(?L1X;FZIY;H$Jg> z=D<6lnq%ti&ifXd`XO`0%Mw1f8@q?fb5|_?o@e?fMHSyU(OUOWupiY{KX&uuvv~O5 z+~Z#!{F`O7JU+JU_0QRH?%6vh&n!4{A+9-W++Ci$QFsf}x&55~NKzC&qf z#rq1T#5qn)*1j^}yw!2cL`|EOtK6l?ZB<*>7YIz2Yjn7$Ghe(_HmxJ9&*m!xUi<4Z zCaEj(`-w={)!y#F7~A3LU%DSxoikoB?Gn|SN`_yOV)m5|Rr&wp+>T%R8vpr#@C}}~ zqmxrfB=OnG)JizN=%(x+&yc7_|BP2-&5m=zEj_x0hoo=cO5%>8ILe7trO`gKES63=Or|N;|@TXA^kC zLPIYr`27U#Aj9c-7}1K@!w$bBqGzRgX7Fa0@TnEY6$v{%yP+Z2>3h`GR2u5fme9q| z7Ar+_Lit@U9o)Wjs!pD5yEdq5Ft{Z6v|8QhF!*EsMf1SEhB;5kSns7Yk#6-PVpD%^ zj7YYfmK;-9?%F(ed_+wi|Hi}yePq<+WPNLH&gohG3qpT$LXvI|W+a)M(}Jd!#2iT4 zQ)l$i8M>kT`vD*(U=?Jx_5dsS;vDo+W+y~Zypu9jQq;nr*aElP4eXXMe81h3Ek zr>XZzWo;x{1tY-e%T?*iH;hm(O(c<}CvD$r=@WPCmE67@v=l{JTR{Wz)HS2YsR*BDg zixBH`^1oQLxcR1~_h#jZ`M%3X985lJCOvFde%@Ao%jbn*lq=@^thJiwk$CH_j(@EJ z45qa_KE~@*==YHi^`$m~Ps!J1L9cXT=Jp-=@Z9)F!ph*<9pi@!otMa;f;9GN@0$E% zYr^NsD^qfcE?xSL8-BP)-lMiD_UFjyC6^1;D8-ZP_d-$cdWr+@tai;gA@0DQm5fDT zE*V870r#yO>!<&&eNKMMxY#qqdU{Sj5+yU474?4US;jTPq19Rg_c>~cxAWIXlKdID z;EyXx@0$O*5QEI4ye~oi{ECG>GxRP5x*&y&hh-Ua3KHP=23c>{um!}0`-NvG;_Ybp zMzUWW{Dth3SC!Po8e}AJv^U1oBZ$kVL{?K zt&(90)asc*hu^yUGp#`1w+;d?-Jy&yZPIT|Jq>4gQ*!HVs@4 zXcb?$)A4J1{9x~Q^}800Ys)j=b`WRp1(4lH&%Y#~j>Q_N8yQ01vq#3_%I5k^)(!$z zT?px~a;$kGV?G!YX}E;Jg7WTb$R zE^lsFpQ>zyf2v1D{Wx>xE44|OF(bk5JjbRg6SuV2-zpb<=bC{2@8K^3ol0+^3LM4L z4=`k2E#Qk-u;RgvkWSUjp#Cr3N{Gk-JheFgE6y+0$TGsm_0%-hBIJLS5pj`6V6_@DMX44EOLo>lltfoC2R6MJ{Q zoT~H6Tj^iHsYRii43`|slmcDot9c)r9*7h~s9V0}TKK#;vtUiBbQ1}@dCmmp8;wd( z$iFpbq3w)3w+ohC%_E?t$D*JFfCABG-NALpKkD`vBm1(@iK3wlpPa%e{rtLZ&C*X; z{X_L3>Go9z?D8JlhAFuKb)8X!jLgjA{5`d>y9Zi$&lbxhF^638H=JJkUIa&ovfE}K zNH>Y!h$mbMaBIfkA}(-BeO#<98~z13VY~fW$~!f==_2N9Hut(jeT5#9QYL$fE0nH8 zcin~C&apsJIk&7;y(}%wb9$;JH^lKu2MdE|OX;Su-Vlpt?W?U!$|(mihWP;mP$+#Y zh-k8(ZxTw{_^9);%XRJ^Xkh=G;pC15tHS)g`9&lJ=CqY1Ie7MC%PYL#>lka66kr3S z?0i4E-6d}N#qhP-&RU1+7tq>&B1Zr!b4M8p_*u;u8zPAU(qN~9wC25fnh9#v_C$>A zT(8nNIHyr|D;uns5%e4R68K{ahymc{Oo;HYKdM|CsD}~=0Wx<*P^zGqV>5xia2?4SJ?!ivg>&<; zZ%h>r9%)y8=s&!R0tmb+6(h*XJ?Rtd@CklEcqRo_2buk-SY11WQ&6tCrme1Te<;mhz$$2CbDbaE>ca5kDGURDGHz|M&J< z{GK<{H|e%1aX_cs?a!n{XUBl8S%~ITIq&G%@Omm(k1MK;ednE43-X5YR)1Vuf+3O3k z^Y29J&b;9A70ZqtuYR!(TA6U3KLelrlfM2OwYD4d{ET_zM(~Uw`e#&jC`}AF-o83&s(a2I zP=?8+0XM?vC&f5(2#zhZL47W{SE($4rC1P z29k}XOWOiSNLDoca~(ISs$#o~jlF>~QHR(T#T1pan`0l(Zx`6xJ(DkrI!TPcn*o*GpT#54 z<)XVk6k)pxli3^cW;pB4rX_kgEm>1HtdygN^B@Grzga+hjiCzg>Gb|iVav>dVJE(` z8<$aO7K&ktS{eSB)CS2Nl#`T}h3ggeAqF~v#A2!90ZGcQOIecr8K4M!2Si`>eUF{A zu!8B49BIM+)vMe}a+#8crJk3y_|oVcF`joM5=VrFM@}L4LY{Fn%N}%M|DoaM9C0^D z!Raq6x(9tYBtGDG5k;{P;9H_^GmMlJkRiAF(@(J}XzlVm^|Og>-=dzP+E%6-GBm@#@c;sKH|X3WyP!0APl=gK1+(Ehyt?P(REuFTYTHG6a`~9z<*W_c z6#lpL)#tMG&;9oze5bJ+roWVAKJ(<#?p+sN>fFI30l0f5R4}jxa6Vny%9POUHTG#k~DSjtI`v)WRoWyfo5qN&%TPAe8p5I z41b-Ivs=2b4jni9FBaK9YXEH!#b^ThUfVk_&cHcHRw2lGRSa$n-sKQBSkez8JZ#1^ z^X@*za%-yW&xVmKkPH9YDBDDxz# z{MF5e=1TK>l*CavL+rHG3j?nQwoPn)ejEB$bx#AR5 zdgo-nr`y|#9U|V>2Wuo%r(oux|EN-Cd+|aLNOu+CC5rseNYMN!>(Oy-Tz~9g#2G>@ z;_>c>WYseT6dgQT-;nbn;f^#bagI2br<~kZ^lUBWtrYIB^#b@s5k8>HX+&lm;j$Y7 zQ{ElUmLDE7B;c%K1n>2`F~no44rTbYH)ZwlYYq0?gM_mZ#%+Yuz)CDyO8ePFcQ9KE z`2*Qwe~@dzOn%R?5xJvYcEe!DbPS`l!{J*v%t>hhA`zoOwicrnv^;pPc3JPe{Q2#( zamhQ2XEq93E%SDgymz9Db~eC>&Zijb2)WB`*8xLL>w??7 z7Qd%N>78-!+?@;fF35X}cVq3>9?oXJJF~fJGGyr8N1QQ{i={}`QSPm@Ua_=xe5AND_C)(dPz1o^HH+92q0tu)1Swd zm}2cLM$$Jx)-ufCSt&R(uiPd)VL@mbW@q4uuhggqmze^Cf3VrNY}IBpU31M0wz|%w(>Dr z#6t=XboK>fCMr3eC*eUld7lMqszPW^c&uukH-0u72~(&{tQaJ9v!zwG^%4MHKJRzSX#JBIil#Xokdd6OD;6W zIQtQM+cI5Lpi|I6j__74wV;2G43@A;+STLEI_4!drOGJveNRURiIsVUX4wSn`i(G; zQ)ZlShtpG=;Duy9k5&ag+?2rxwvvO1&I0@U1u44Vr-6Q#)Ne=yK;1e7IpH_-#Q}Bo zS2hIc!osuf21_Z)XxSj`M)j>Bv05GP-x9|)NU$pdi)w~cgA3T9a`;Pf_39KDYX6tWyx_;a=Kg6*}RH16B%8rm?5+0 z1FbYSrOMclX<@@=Be8xIAah%k|2ucby>$Dn1<;(q0`8ulf^!c-Nml`IB9xK{ZN_tJ zg3ZN1EbPpiD*<(ie^yNtQ#LhC_MEnd;Bfyul=5Wz9Mnx(Zt@{%Pxw2j!GM!B#S~1I zf=$lEf-v?7x(0O0k`hY=lnjw*V}a&tL=Rr$VadY?Us+hrk)zTMyl|8@i4H(Xw43aK zW~r!d&o25Bs$BMi;1o!lju=ve&tV~Y4i5k)ictih*gViOlK6NGSb>4|tEF@7$@RxP zJX-IMuY_~|V0t?kxR4&L^Gbn!s<<(jfUpgt00<^%m?(P(pFVEtBlPuJ^-p$6yeQx` z(WmCOo@_+{rSTx!(1oC5kdL%Ir9Og@5*Bt~YPsL-bfvnVHogLSMLIzo{ z1jZ`d+nYJq5)aqk)RrxHp$jmEgdW#CKRJ#>p`D-}C26Q$5pCX&ufm>%P&(by=nSWG)yCy&x+6uvcisI zj^509!kp=_l?tODR{l~LJwWBZ%$JPdNW`S>Y0@=skf)OhrTxs ztgS0f-Lqe;K>f(hqi-&*;u&?6T&>0|CyOFB)qrZN)QE2ItB7D1fpb z0nivsr=YIlj9u&=>Gr5FkJx=L0&kzn z5XDIBEerI>lP@>`;Z*Xhk^h3pmB;jtrHNTv&0h!mg*1Ji*C=o1jsuQuMuYQ&lE9O% zZVGyV@Gf&)yHxbbw(>C{_rGP#8QS^cQ%33SDG?%#GB)sZ*Q0pU$LWI9T>jqc51o_t z_tY~0dXI+jeaS{8-C$W2*J5)qv1yc-4F!vD7i3E$#z>g(5GA8_7Ypk3-6cp5q9M+e zSYAz|9bK*;ZgMpnr*Wman8pXPPituhxzqtf+pcVTq-fcEJX%cUSiMuaS)8<+MR@V?n}IWly;oPRPcbyQ|CvF`w!fp02VaKM(I73vF!-3y;FsR zfjbqRTV|w05uKZk?Ozg|t0g64iFmWG&SnIK4dm)7YU2-NBTI3y?Z30(BT}@6Hu=UE z@MQRcVsY2+e>0rk>XNJHm+k-lXsZr{;S?>>LhCQAfoK`a$ADFo*!C%alK9hbFMnES z@%a@{rI?LwMD3yWM*~H$1+=HcLSfGD8#&J@rLl|&ol(9`AY>-O6bpWb+hC#lH?mm&IbDL)Z^DS-&Ay#FfX z2$}buDO0&Xl@(Uix_$-}I4}I)nKkjBl@w(v2OoKD=hELC< zrKAo%JajUvUGC)*veakBzua2Css!t!yX^!rNP(6XO+j8OeW#J=5X+I`5N*oIq2gM$ z#UK+qtt6A9{A6Hk+1ARRQxlK~C7?qQm4cfD%xAY?fD5vF_om?e4>a+{8a5yv%&@k} z45+n`ETx12+R`rh%cBMf>dz?OpJN)DLl{@2eITHy`F4R6xwI;Mbrf**E`o88Xh}$_ zukt>{8xhGu8+7Of6?7?guofKRnk}sk$A)-Wnw2z_Zr3)t-$-s(@iCT~UZj#=0{i%t7|lUGg* z-^&y83lTQUOp*RVbH_$`IUhW0cu#Y_q6am2V%1fLkty8AUYBCymd2>s3KvfU~k^mMj1zAmZ5iOL=#0 zU*V3r4Co4$Lk7E?!2n0Bxbt?DeIqCg-2+J$0^&Jp_4vi$P^CgsvE@&UmVEOtBdrZI z%7D;_0^$|G9X51LC?X5ywjYtWAJ!}(kSZmVC=2TiRZ11-g0^);Z4%6R(YrA*;BIu? zzs^NJ@>$^zS;{`Wx1|KcCr;2o-|7s>G%$qE1goafpL2k{{rD9@fxjq`7P!_@ZI<~V z@p(nT<__kKcqyoACex0{mCwR&kE*+BI=VaD_E&|?rg;^dpMsLpM(Y>QSTulEhqUhj!uP~pA%uo{Paa;xMES#`C-;+k(#h%Av(kW6yZ^W7x ztkk@Hk#_!JKtc@hrlumJ2^uwM4BN|7R`Op{XyzF@iX z8o+_yeN)U+D2idaXJYqmRtcdx`#?%-6X+>_r4~merqqr%r<`fc>cZoiQTzOw-^v}) z_jegI@5ek9Q0!y)M)1@W=N~H{Y&D?QKHHDm#77*7#CU)+KM=noa;3jV<0h3~Yt)7P!AABG0#k(yUMxw(jDH^CTuDyubhcBK8GG`W}wC<{{T_}gxRgwdt% z^0B*ZW388OXygx1CkmkHuQ>r>Z zcHj;B0-kusUH+k7P2{45@CZWo7fh|%kLLh+K<`59VnTyS{LuS~0o?YdnICqqEUG}r zfFhPPS_~OR|BndG4pLFJG+}~O@#_`W+uohF*W;QC9P^F8JnFmal=FGb&ocmsjWZZNx!nU{sKlp#ap9RG5tFkybJxKHlL`@TL3hDuSJ&# z&^LDRa|ASmbJ5nCTD~SFv~$`)d{a47Q3fCFX^o%FGxbL7yIhKDs=+4$ic)e88d?L; zw*=jIv|NejI~oRc0V9A%in{bt=_WRB0FS|Z`s3Y7h68gDFvcJ7!0g1K0AKrUTKMWc z3oKp@C`tdp0$p~5(hb3w)4Oec{Uj(*2+Bc%zY!>U=Yk%--V%uJFG0^P-E1*h4ywN& zed{w+4o@|gq=-YmoJE%yLBZYhaVmu(Dl~EwZ={CvID;-xo+3(0Ku(dMO)k%=2E57y zq!9xI<_r$MCZ_x}LsX$#hI;Q7)bp7^-Ln?r9JtfUfby>~AU+Em&k}epAo5IGrrti< z<08_tf<#`Sa<|1X3PN30cov-r1QDd|<&px9E@-FS=#gP5C6%CzG6H?vRN0{O#7~vx z%On8F&GEwA^jnX1jGD<8O0o8PMQw5=3o2A&wRB9RzWo4ra|cg==xWI4ADD@Y zqYD^`evHgdK~nvhaR#wy6?kz;82~xqHJLbM`E|g={9{=2B+U}`BWPE5j@m~Y9PoI& zsO^YbR`DaX|3S~M=`1pGH?8z$lMR>RAPW^J?)DNfc_l^tQ0_*p?#M5NeOqh5smILb zJ{W)hcD9goJxwxi-wr%+`@Y8U0owW*9DRJmeenH^cE$84Xa_Q=C^;`B(fxL0jr6dZ zRwMpi{$`HW3!G4+7X6C1-LV#Ng%2z?8o}b!s>^H!qxv9<5pTCW78+9;QBkMNwdeM~ zRL%^8(6LauLG7YN1Py4`12DGRe<8gS`yqJG-#4o@n)N`Xn#+kZ<0IquBEJuG7M8kp<;kGKXWagC+`YpG!fn@BD(fu=u|8^CH^YTNmVQJ7v~pGL&?z6YM|3D6>(Yk6rJ3vqfGP=mDzI2s%vasChZjCVxCBGsV2-;Iu|@kz*$g_k+5{~N zDWa}5Npua3b7|~ELQzc^{N<3?gXJ{C90Q&aISE%GMzn^~)G(R zxQtaWQ^=E97a`h+7D;gYWTt`ufPyCqL3o`I9ujp+5gJS3qA!D4wiG%;BNqQ&T9-c$ zI2a*pxO8a;`{~--?892L^Ln z3`HcZb$hQkr(>z@6lk#(_XCD(Y&G~z`qAY6+FBCL#Fuoy*xN8mbbJg%^uSj_EnyP9 zT4PCdsbQS~6D|mNu4$@n3Ix}jR!WS(t=H9Isn7P;gdp6A)b_WK|@w4 zuF#nDo}*sMh=MX&c8#rNjnBvC+;Oo_IaVd<6CIwQEafapq3S2JY_w7NrQxY>m*r@X z^sV7@jY7@NHTQcq0UXI@S|C5thScB{bM=#r7&%!~tQOzc0*u9 zQelbPRWI2;B#~xvuu6DF;aY)}>fx%g3bU%z(m_uWJRnD$QE{9Wt50E^L&#ttuhxBz245XbwCcE07}ZAxJkW zp;n(|bV}iFQbL9b9H5;`g^>cA58y}P>~~jxn5G%d^k}~yIb|^OCv12}KIP9G5dd+v zZCN|dC(J)F=3Z$38^wN?R>(ZocHe5S0T4HMYUkXzIpDq*lmWt7g>dI5+;#qWTv!!J zm>d6oWw+&G|6k=oS_~NmxKWA(k@&iKzDgN*=XSBtDUd; zP#+k@j|c;Fz}zAv{sWd`il8V;(;rt|%zpucl8r%56T7ESFcWlsAXL|^UmY!B=ng%( zLPJ>3-zgv@3_Dt4auE$POzTxrSEqIfpYRBsJ#GyB$^@j6)V(}b5IJZ76l)di5sZU) zgi*u0f%^{B;|LB4Kqizo5#vz~ZFs z=G5KwGnwD%pOV?Ev;rZf?n8)uZW2(fqWj*l#a>-^%?UGN2Y2!C5Qa%)Q%Gm#+nPqN=M&G53|0sNJgZHX#{6Gi zTLP#Dzs-BSx;AudgFpJUrw!HcZLx6Ym{*%_H_+m+A*r~tqAefNyZP|!!J8IMV=uXz zP;tyY2*B(gMF71&Zgt6TpTC+#D{3p!oB^G1>hXzbHy>hVIJ31ki?G}CSrcjt{ER#C zdPtEU(9WzPHSm+Pi=FCd7Jg9Ieb?VEH6qiD4zF~mh1e>sHeW&15?`V7fp1l5W@^E! zzun)UI4GebUP#<3R6xMoG(#xQ6?%+D6^(#1FoKKoA~}1Yy;w@783YfaWG5>jSZx3s zp9MH<-h?suMu9We!AbVJ30y4oI%^6~rrh4ghTmmP_05Z5JEm9*mdJys%58~NIPzre zTIE4W7~l%6?*so@qO4d`k2-lgFXfjb>INGbu~esYN| z{Qxe}7Lw@#I#mOegCT^BicpOOd_KuYCZI#?n;>6xPm(eiiM5OtyQq8rhvnBQNqTU) zPuS~Q4HWedM%E?dq_l2Q15?sFyd}Os#j5K>7UnzL=CPh1;=nCkuH+cc@l3~F&DY@z z>b3?SRIq!}L{cS-9E+kOi&0!@HoGKhXY$V@KEfQ6rkZ z#6a69M^;6!4(C#lus}G0+ToDqE!ZUq!!5i>Na?wTMi6s6(R;>ZpI08lD&r>{rn)jP#gu{gc2%#d_Q|kHi(;;9+ZT1yvxh>Q`LV0)KXpvNiQ>{;5Jan!d%0%*7WpKgbQWG*|Fnd z!aEH;ZF&>3`k&QA)WR={0rX3o*{l)IZ<9O65)TPCA5-sr=gL1n1&Tip^^;4xa6RB(_&F%t5f*={J<3|?t3t3=X-VX<<(=b)rX)R(vsr-^?aH2PWXi} z{|LNYd@otzfgaAfq$? z_!H(YJAOwWSo(RgP~|hV{f+=*0|32n=-|o1S92j#?%*JVI2{a61&L`ILVvnq`k5l4 z;c^^{M2=A)We1HBf!0ZEUe29M0U*%5c#7r_0zQNH)epQ8m#HB>HrN1l>=zK56Rd~i zLwq8l;Zo)S9#XyC)o2YIPHb?Doc$9dJj8&FB&Oz%BoGbNVPe1;6cviKGffnUxtNjNB8T$PW`aiG&)fH5N?1?eCCb%2vETTTAu9yX z%2)GTv>K*Da^%5Dm7A+C8bt=VTdRVo8BFy$5Rf7yDqpGq#n$n8U0H;ON=p* zke_7}L@h`)+1>Vbtv2#Oq12HHxkhp9@MOIe{+MLLAtXV5?Saj~90#dH-aqa?uI>KR zQ@}21HK~Sn*vZL=;<}JUtAQ2k8;F`RziL1?z>PR+S=gp}!^+0E{Etx9a zmyg?pSOf(flYG`;>P2FFjHntb<{j3!A3Ln*ms*%nz6QDmQ`Ye?ZgSqtGzOm#cv!O> z(yt`D&_9;g^>v>IBW;7CATZdL(}=Ohlz}J-^CDVbw1xi>R;(OoH=K{ zi*ILkW-oSTXLjC;-`k$&0>`cgZ0EFW0&%mAl=m0n`szmoS zSuq1_M zg0DI#RYL>j-3(?@vKLU&k=kkb!d8TS@(+4(mm@U;Vv1ug%@+dtj!8sbYpaVWSP=z{ z(8ST9Ik|RkyGa1go~Mdbg@O;eV?`OgiEu_9^(X?@4SSMCGh#`Ru z!)fMtJyWOQv@TAoaFKwByr|^@RKWHXD&7UUn?}@A(&xaLzhsbK9k8)!z?K4mr-)3_ zkpFa*Y9oNe@E1d$z06F#G>yg4l+dF%hj>dgst}QL1FA(dh!Y~$YLe51)SEegmp>54 zuv8FUiohS;GCu9#6g3@J#HY?LV#d-ZE8sJW8Rc%>1+$)_TI;E(AgHZ zt6>vzWU6{_owQpwT_>b$cpP zLn@Cc+qz~Y%BR;-GGf50Gc*aN-p@BGjzR!H@S<`(Vd8ICo}h83O{Kufjgb4)@Q?~0 z4XU6tfZp6(Ic9nPg z;g#`72{4oNrTTn8Wh`98*|*b~e!F=tZ`kxId*Joqrn@OZrBrjynM4A^{zB2g#9AgI z=KbxeBLe@4#+To6k>0+0RWHzd;Vo`wtATF~9z9$7&)Yra&MY@A zuO(;!*vkD@Zda?^^@PfQVhynN!%mp(gR&dg9J`g;n88*s`+HQ^B+PgHG$*a)r(>=?J!B7N8UwVe`XF;{39u*au(+>RJ<_-IypUJO08X{7?#X%J)7h;`-Oa$sxcpiUAW>oz22s?3mEaunwk=1CDY)5R(SCR=r&HGocH zH3*79mRAg5`1+_ddqo({5)Kn50GjOKP$?0a zR3gv-JWO6-Q4JTcRh*x^S`QYkRXi`4#Jj5*tFAitzJPdvN4?-kl!1>#WaN6wH>cqi zl@ZJ=kREO~L0}RjhJ4J)$sTUA z;zZZy?Fh;#3tpz8T%lqg{3m;-;fful)D*%9>mY6fMmQRh$Bxk(TJ2%XskP%Nj?!dW zIO1@-;@*M`SK5)flXPcrG0Fa*7^vhFo=6T>wFV6PM@!V9RKpZVa>1m{qaq9>(QuE! zE@a-IC=hPlPzh0Qe`XGj3^p_){4Tpt#RE)5nCT|^vQj=dBG4*2Tv!=VK=EEWJT*yx z3d~hHTa3pmTN{DxGbK*$4z{K&UJ0;vQC~xF&9W;C!lB+5IV@#O6kVhw?~A3dD;T_Veb90oVsyO>vHVY@?Ktft0AsiCJ&nx|m)d`l-<7ud>a20c!rHq*d$L%0=@=Oh=Yc z<;&|}xjpcUc+j4-D*Jwug^TN*S9!i6x5u&^0eNoqmVx<35?eQ(<}OL(w4g@D8&^{evbpr8BsSJsM0ug zIjUg|MK)di$*g%=#sypISMTNn$ZN4DN;c1d;LjW-w3+P(v)+Z?#CC6u?00q* znrkz}Iw0dvBEKmz@s>&_osz78_@5aIq8`?5@pdmY#EX5t(`1*6Op4BjVny5(V|nrA z{}Iu0q4*N|&9Wj@FLI3=SlQaSnPl|(3i0Mas1}IED3fDS^I~0(1X)B*%I83D!hy{( z74(T|MTzzTXCVT{fV9{CWNxpV_v^W9rJ3|S*KEzQuuMsIV-~s~*kBY+l&_)Uuu8RU zQj^~cTylMISugDL%7eUf$iwGC6;;wKTKI94L3issN z!mn5x4_+FAe5qoyr*9`xj3wcGj#&R}Nf$^c1p!l)rZ-=MxYavxasbC{T>=j@@0K|Y z$HjIoBX=g6G4kmIyZN;sbV$mxoJkGrMe zpimj4M}l$NgF}k18`!&+NY`?30SxjygMWT6kp*-v>km^|(webVB&x7m4M^2EAV^fl zSiV5#xK{}le2zwSR<@sG`~&sZp<}Q~@lFUv_Bas$U6jEYsF@#Gj6G@$c$%g_AYh87 zvSQ5%sgVO%mY|cV78{IVNrFxmPU=IUMWD-4VBd! zr!R;*zRlH-mdTD4@u6u=%GN=_pIpk~5wqxyK5Lo2b{!&X*!6hO2{p&Kz<|9zi9UdL zX7F<9l;+#=5FT@IQuwswfIsi>C+ikp#-VY+lvXT?W5uFNw7EKAoVkqjM9DlO@q?88 z@?WKc-o(1me=+KM!lW_`@Y%7q7K_el?(r>Dr#U(_?+g7=NE76H5IuV{R?&tK5#B>M zV_(4)M?4tX=%p#5Uv|KF@WGNaT4+X=a=l}*nWpiwPp-f{o|E}I^BRnbiT7GQea%zbk&or`UDE>9Gjs}EAS`y^B>Hd!^+g)DxfflSn{$nTpL z9|*8NXx*e(_9_T|-2pBM$sU4{#P{?%+FKW&Elqeq0+4qPIoDYRV)60bDKit(Hl5bO zM|ISNoS;P%8n%Auv?~Wj5j+Zabx2=71fC$p2Py4U1{E#gGpQs7;%>2^s8fC}J}XJy zc5k^uH#ezLs=0SWB2juUsnW=GXzgkKW5@*xOx}8TnnhVfY~oU9cD9AQoS?CV%vSMf z4=0^sCAJ)n1{qPv2q#Y?HDzYig(dgCXPbB=F|1PUz8_Z z38FqFdQWg9k+g5w0L*0v=+6y%=*7YmC+-_Z;H=valUL`EVg}{@7cpbg9+?3$9_}`4 z5*;G^1h}{_AQR0l6uD`_dD4v(`Fuu`zq`@==hvc*n?GPdb+wd?;xbPnHl<7)6D)sVdk~p!(d2Q8Uc~FYsFJ5I{%+ zfbe;B7yzId%7CUK-@ynNS%3muOJE#;8t?APvVlHf&{uaE;*n4w0nhtV_lXLWs!-pv z^sDzYF86SxJ$PtE-dNMCrRSV!)v-J^Y6TPeslgF=&6a&Kp&#ZdYpq74Q zx*Ll;AV%G8udX6Ai+Gy7F0;tlCu%CB&a#nh!sU}fQ=D#b6v3|?b0RZ>91hw!iC&Mr z%nrStWjx4MK-f0H*iWvVU#+V(&2W`e0e=W|?LhDnalMMDj}CoWdac^VRokj(rl|J_ zi%1?ncU8=ed(3R}wA=JQ*zkoJ@bVquw>n+&c02Yd8_&DGj@co0>KtjOVqb3U8q|yX z!qAJSp_d%C_6``V%K|%ThJYx+y{~p>3(EfkVSP66{MZ3VUx(J}HW`!DO|r=>HZYBe z^KiJ^bY9Zb;eN*+J$eMGe_>49s-TE2V2UITfOGpanb9&Dnql+ye&~Y|C>kFvh9czi zCBs)=rHBEnOGEtK_?E!X+LeL0VD_X6@d_3fW9$wFzQKumz{7=})ewlJakbbSJbHyD zdd&7*YxW|$yVI(m&yWG5J9DP1maTS}l(}`{5^x8Y!Ti1ltWDNW=z0 z?6?t;uEsV-GBpv*=%RhCVK~rvG?MsE)CB_=L*9GMz{e&b#bO-WFCC+3^FXdJ-BRV? z{ZTboO8c|asdSpK*h8^@y0McG@Gla0xJdA^L+1Lmu3irN36-_!(7kdA{*$I*uHOzy z&A$9kS>6vMux8(s^&4|z&wpE+IW%5nI%lZ_ae>K_c=AZT6{IpD5g)TJ%vdj@smfm9 zMsc8u3COtDIY0LlPuvFffmwTqruMP?ml_203~4;h#d3P1SsXO2JkS3*GSi93;%Rnk&7nR7kyaHj))7)!4XdQD^bEd}=y#pW22aMJs1 zr^88(F&8OwINfrHAW5^~S2oTcYcA>Y6{MK1T+nQMrQD454?bNMhLOHrGr6^b7j}yX z@vaB;0Y$^&u)+RvKv@XjWP#<-8dbaVY7(wJ+f|XU@lf4JV$It&Obz5_&q3U^>Z21% z9|?K4hd_#NvxJ#X#$=bw56xKZGC&&p<=#U%cyJ0`M8%_3SYY+=Y7*=cSxdW@SU=WS zaNDu>kEUNQViBz=G=OzUE|_|F-qTu1^?6aE{q?eo319}v4y&eI`R!IYJQXwx1rl;& zQLAE?HgiRG{)Ad{4Sp{e?feoT+CHLV!93yVqtLmddVi(Q1~jg%Jlz@C_$l{jR`EyI zEB56tBima8r$t2($9Muj@RHp;H($c83lmlB$0Jy#l$}MjZfdX%>(E#?g zSp;=jnJC9?IFDFAa-PFP<8?2 zP#E#J3W9dx;47jvq6kIQgQFkw7fK}M_S#PLf4z(V>_6Ah&T@W<(P}Vr{ znuiz;mrXNxEeRtI0-cfU4jG9VtsWYH|y)p z^mtOO)SadJKPv?J!~_Q>mo91S5&8PUJ(v`T+uZ;T&QQ_TPKS2g=1ELKrskM-uD#Y8 zU&7Dg(^1|vT9(5j91pafa9Z#_T2qp)pPtl^SDXn=s?O(=+yI@$LsIRS4Bf+D3(!V& zV90DkrWMrMTC)Uy0x;GUn}W7ZApVL^na0RvcTg}T2C}%_*2#NXI5qbID;MI{nJp%H zGxpV@hAP!*I!xkE${ z>{!Qop{S+cm>Wd@+o;RP z1yvNvAM|ips~40lx{V(N#%d&@dHt7RiDp4DgZQ*tW8V_yXJt1Zmu!C#O^YM$9Oqsh!uP})`8&PwLa!D+j|X(bz8;Ew03US9~Xv}9%rpeOB%m1HmQ z8FpMa|3B9qpWf8(aJCg+xg?F8rN0dMisuBqCJHFku{1s9Bi05wdBM3K&^>xz)pT># zA`$IKC)716mEaXAbJ^$6B#_K?kpIU`=RU>h-S?Xh0ZEqK%`@>D+U0^0O0A}nVcrzxtk2{vJg-2iD%FJmu`S8xN)glj5DG<_o z``CIoau~e)6r39^0PYUg1K0%cyBxkfl~MdK*t*10(e>CNr6>ec8Gt@O35;Ap#M&7w z+7d~rgpWGD3==qa2e$|Z_X*l|WJCTqru2$|69k{N5WJIa&f1R%7cO;&qmG(?&v=f5 zH45gwHEIIqS-V(VnZe(SMV7?yu0kIg2H&#DQY*zvVG+yFx_sF*|oF%J7CZs zLfA}iyP6mKfYKt-Bw+^CA#ucMoom{fjalu2)Qe*$lQQ)VO@=$hoBkAON1ZY5#;GV) zu`k6Or6t;n=JnPvp1MZ;Xeo!BnkK5l;hFTYu>~Q&CB?Ngsnu6f|4G=0K9bn1!*~Ay zlWW(dJr`2N)Sq+_xBeq-F6YiY)L)!c8K&m}os&DtYQDc-S1tnhH9Nj$Hb0V`CJiu1 zu-iGs8x{vRsVgXc;G9wn?}I1wdUw|tH#dz5b1}$pU(bs(9s(W}psA<0s34w&9vdNCwrO`0on%wga@&4_dAw*tjQY+ocwYh%_I^Z~PNr z@35xc?unP81V_D=wCPqP*b36JMbD^qYS1Lu`4)7&ZtCAHGYv!lu!Epg$Y7<>bIK?Q zNI!^)#*0#sNP>|lDiopl1uBaCC(k=t3WaA(g;TMFK9H|74+{F8EOBiA73jdOvEELs z-VQ3pJ%;4w3nR{BlLXb~i_mqoI(G91b11b*=_~Re+hBIsI=cmQH0bV?By(>M7&R%4 zw&btu3W9b>;PfYRo3|XzBJ1}`U!jiQ!-k^@_bxL(dI)xoNtO5%+ghr2R1~X$En+8o z=_+KyDIh!&`|fRkaK2yy-SnDx;mm1k(6P*a2kl*n!O91~U?RIF5pps{7E7Bsfq@is}i!CQ{$3!HkgiV$sU4#EXuROeDmz3>N+ot3oo)&t!lU8&Y4 z;4uJq&Bt_2_;E~u9A}^CbzklhZ(Bjlfmk*T(r-%A_yV)w-pZ`v=;}Y!> zC4Z(_Va~{@ucmSz6lL%g=4;KidX4~Ri=m#9f1kTAp4NZ)OJqG0;v2iSQL}Y0Z zvYRL1GACQ1Y#ZY_@2#bU5a^xAm+-Zta|fV1v(st*T)WRbU7y#_GW0ba)#Vx>`USZ} z17~|8>CvtzGb4LF4T6O?e5R0CQroY(;$9~g5t%Tsz*PxHd`i=O54tC~ zHR1g{P9)quH)SyyE9EeDg5oSC3?YH~&dbf53!thaGO}2@5Y^ou3<}vbO#(A_0TL`j zT*#x4dJas}BC~E|StjrtI!!sA_*x4*{0%09%5D~-0?p=xG#CniBy@XXrF=4=Iqrm{ zDpR7d9gbU_p5rYiI`@Fg6LIC@#XYE-5Ya>x9@T8=s7ECA@56;~B>WYX&`9+cjg%3J zEL5h>g5!km@1wif?3KvvAPbDE<|oCXgTva2cuzF_gcx;Vv;{{vy-q-8D4vEIQRVbT z7;#52&Z8-izvlN5rPtVt)tP`Rn(C5BXAy3@pu4REdadl=ISU<&)Q3Wi*cp3kf>_cSUm`E3HEtaV-jW` zm3qrvyk;afB8q;PjET5+$QEIsPNk8>1p|7Ra;K?Il+|s3tBI8e77k^!tlN@g)RL#-2Ie4X;RwaAl2?|P%e)y=QOK<4h z{lAPK3k zUYY-k6K}r>0=P&rYZoU@Sh#mMVBE`x&_;_TwYcc0B?o-vQ#QnfP7F!Jhr zIJP-AP5CB2Z{lKAYHScEU+}t`c{!p(W)~8U*nRnbU#zIl?@YX274`3c6zPIITy*{Q z>(_U0ZS@w@<6(sn_m3aFtawDe3##9(6#J%EHM*+#y6JWG>k+EAP83ubpXmRIO(-&% zd9nd`iTzE5re>t^7DH|&$Di8*tik{9W7IjliseI!lbM`74~<0T;Cyc9`PCf`2K%Ae%4;^n2Jo)yN6CujI za`cN;!@mC>x-?MiK7SwkYv6cv9ykm>REg7RYk+wDeEag%%11Tr8_WxzLc$QnFSGJX zXH$gth`)7;`l4~~b5-%FRehlzw+}lCMQMjW*rGpMC&~<@wWYYIwIB4Dig^5q)v!NF z@Vw5X+jZoRFwcf?z2I_hE$pA0px#Q`do>HUSH3vVK`)}t< znMXW5b@|1f(Cw#w&t-Bm%13H@Oir5L8~7I8KJo=f%fzYNMb5B1$#UIDqE zo1bpfzKH5B(EMe)UjcN6bL9HizUtJx0MOfp++UJPs*>NfS7Xln+Nr!p9Z#U zZ=4DK!RE}|2&Bghyf_zhqy5jdOL?$tRA#~!&bCnGH1_M8-^M|~>)&l3s{F3C^kY6U z#A&}CV9vL&Um~|&I=h96O&r<$xb>j-a)^PuFw9g`w>a{CbXGgk> zBHs4@41N}=5+!&bK3VK{{$$Q2s+`^l?QfUg2<54*<)cM(N$IV!|Rnk&xN@=_~Z;w&%C=)ik-a z7(=NioUgd~-9|y!Y0-mkLFLeN~UTQpCdtbF^LwtgqC%?Dm>9+UHO`ePxslRn^&^ zo!hGy5>tPeHt+xP>ro574em3M4d9O6boOJwFT2yfGFAhkjb5nBZM~3q1;hmJw0n~ey+&RFHi1^Pf}eG9 zMrQT8pvJ})PR0?F`OvfA`lX%Ez@-rx12o}=WDNfh^q;8b4dVr|^mDa+DaQ=1X+9Zg zr7fACdbTcoRT{C{teq4S5)ylke=FAUz$;bRcN;<^?5FUwnJwGtl|uvHEXXA(n7Aj$ zUUt1<-16zHd6e1Zgrv8O$)4N%;Vb<6k-_4w{ILj`F<^5&a^jB5*QucsU0<&mnW(Om z`$va{E$-poUrZZCfL1csrKf|@b!uqr$X)$EikHVLA3CVTWRyw%pj56Q-o1T!rvBX- zF^E}^ky35^i&obMpH3Y)bu9laYZD)%X~;3dHa#lHTD5Q-lhm^Oana}7_>(7|?*P>Y zS0jTgPF(a?#ME`0Vr2)+2HS%-Ie~dz27fM`ubCP9pcXDGi1p~o+0UhDm?sCt#NKmwjA3*`@yp-hv((l zPH9c|1p5EGDbRc(!$I5k!G)XJg^v_dBy;Z#XR8L}4ZIVX7d!OPh@Vld0bhP*=l&+v z+cMh!?wNAX`+;Hh#)RGPs~?{1^>xmA<;Ku)b%;hFFYe_f2rOD$VlADs+ahe8fIk+~ zx@3;6f4WIM7pNn+U7VkG&ZltYU5-eWQ_06=e0z{Zx(4Sm-_Bb8tmnS+wVAqmhdv1# zLH`S_5TA8c=}3mt2|2UfH!oS#*6#Cn)Q8CCBOlovkUREa^YMMKw0u?AWv}mF9!6R1 zx}5jjh_vi0Df@Yjx|}SRHhSpmOjpYZPHZD8!EXQT;Ds*Mm#DgL-VLLp`%kvLxi~Cv z(wM0)bHCkwGLLnlz~`2ZBLZ1hXLOkmW7Q?~OoB9&{>)z?rXc6Q8O`m5y-WU`>Tf)( zZzs!j_q^Er(PYvF6yK828JRH)6qmAoRV{%^aC)xg^?S74JKnQ+uu)PsG{yMv$ykcg z@O6(n95gpR&zIWLA8!WhNIswDkB0#m0o??$WDf1)c&eQL+);jaEPI z-aNLV9NJ*ILKty387=dQw~d?OH{^7QNcXgLz4h?=Q832yb`*`BFS(&_?&0UCW=07AVm^uom;FmqAq?4^48 zNQLHG+yENL5<4xStCie|ZR&*uP>Y9mOV2N=_(jUKY|dO7YhXEQ#KP0~tT&>}t8$^o z8n=3!c{)$BWxsaZ8PB5cr%cYg8*Wt>l6NU5>b#M1Fo2=plT5Jglz6 zD7EPG*Y$CGceY-k5E%Rbv0=JbWx+f5zx=O)EuU2TH$vYg$BeRU>Lt7@G?Vfj&YnB9 z=TXDo3HgT)LV$mdGc{`}n%QGQmsR|Bj`%fmyGs000}q@}Jc~@dzW1KkE8(~D)qbxw z##&;kUx^XL$^w?&luk5UPMBdR3f(8|v~=G)p?!>jto+1mF_No1C`h~Ac;wP*n~(1t z_SL=h8TQ6EDULx~$>kEH#CbQ(AfgPOzqwX-gf3!BcF(lxVwdcz9!%dP%d_mB4AWe8Z6RWhAD0+T1Be?F0^u9q^2hK}Z zmnCfX?NCkGiZrse|MxM|zgUHn(!;Lh6!R$3SE$Usy{MCKGTyFz|Ndagm{eRQV_>;> zN?rH!giErsZE@CrHJE!HTtfovk-$aFF1;l8fd`|0?ayn6w#;{2tU`h)wfB?p=n*X9 zAP*NZ*i`>tqu)r^^-TD|st0|U2S0%VOq@5&6v{oRp7ww4NbYl8`6}}$s)9ZmjHJW(6L0J~ z)F?Haqv)M3iLGPmst2F2`F59;FqsP|9=44ILn z4!R(QIHxboP-6d(Fz0Hu6VJ1#W>?*(R80rBo0oTmBNh!s#=rBIhTn(OXnMfOrLx_C~p{3npE=Xq4NH)ngjEas?w(jNjOUD)=W(O z{xh=AD4I4%14#e62v)+-XeKoWX6X(G`-uVBuLHE~@od?0jDbkxG3R&*8S%lPhRH}- zW(xf|Cu0x9YM!9VH7P*T9#FL>OXhPUI|Xkk<9d^w#qanS%Rl$RVUmz)8rDTXB3ixM zDFAfLvhu9xR-Aa++w;zkQ5tTpb71%96DMX!FIH(3r_`nF?{rn;gQ~y@U1_BOIr$L7 zN>Kf(!W->bcMhKRbm3!CGumHls;{&u)AlA}4GNB97iDtdlG;4TK)0FZRCulhF~Kkc zk#6GU@?Wm!9t%8vAHlg`q+V{Huvz4uxt_dzIQ2phXqioin?`i+aRE2A9>t9Hcf?(v z(d-Gf60IO{vZ=QwFJ}5Y9>SgI$9uNg2@UE$k@;e`Q%&Q~hwqS;)6T1X@;*Y`S@v2i zrtcgPUzhgYa;RpX)B3TX_d1sbcN{z&-DBA{98dri=4-$Uu1sQA2e%e%0if{#02~Fey>QejBJi^i2)P2NpjZKQF5=+9-3ZMM1zlh%8wuf^ z)A|QM^?Efcp^va6A}=rX@ic4!~avUxWY3M&IbQx?zLPi?;menA7J zse(@8{wvb8$cM*^%HUG3O=W!%QGM1;tji=?2gD}qmt=~95^{w@6-=MK==N5RqQlv< zxKR_M=j8-zNARg@xiwJaBW&q`$i>weC44Gq`o3zna^pd$BJGi5p7hPvUqP0RY4x}v zN?(e-EpqIz7p_?_2KfnfI2Lvff0=4O2?U5i<06=!MqI5=_q6+PiI+7+NQw^nyq6^C z53Davxh0HLRyWs7d!h5v|H;JjFdHc*JO)-FzUkfJqV|tH(m2oi7U!Vz{1}Gbm)2?< z{h<0Ode`}oVZ{{Csh9Ka9Ln$GiAh^sAGVl$W%j-F9{TjFQ5v|qQkNB;n24gd*bX83 zvXZ+J!TiBNY8OgQ*mgdsCOGE1xhwf4DoX2O3Z=I{kyD14?zo!PWavGFM=Xxg=;_1)npZ1@Z*vS0=!fBaGg zpXC;bjzJoZD*g%Z>X#SbCtdr1L+chi+`CnXjes}0j&Q>#@+kX>r=)hgPn28WfxW~} zD%)k?UyGx5!>lf|xuen{6j|}rW3cTT8BX$0+}{3ySnB!`|B>^Aw5fJYmup>l0j1$k~&$);xl zFNC8~*#%Sav7!N*Y_c^+_jiRrR{jUBa%9GJvMY(;G#X`xe)>S+2V(ZAai62wLA7_ z`5#ej-hQJOc9M+?2z!z%6y<)+;QrNFd97B?3GNTGrz6e=9rxi^t}fOfDfY%%tUZ3Q zMkfu5Y)YeY5k<~N`veDfiNZNObA^}jUcN`J1}4V8Auf~A;`b%k)V&Q>sqEI7q5j{R z$T>NqW=q(3V3qWb0rkCL@wRWVZ>mn*EKZs_TFZE;xP4E0-H$%|J=J{5Zu`rnwH2wk z{5xwO%=mSMJ9ndpx{|V97Rp-aD=j+a#MGb4Q;DO#nNm6pJUOO*8_I;>ri3EX?Uwhp zb3l~RRhhrJ{0kFe7q%S4wm)M2(yz#?1C7i9{KZ2)ZdtbyoC5|eR#A)yB9@tL_9*{tyHc2*xs>>PF(Bx!(oZ4s$8-5+Z_LJ zwl2x{xDXw<35@Gm%f?akIs>^vME-KzV4vbD#eNrK0xhs_w(1Q}`sF|uALjH^BmYS6v$%aCO^_uMA?)J0&0{d2!LZ(E;B){WJ0z)H#0{o%O3D=G&Tto!s&rZl>#rQ>fI%>WvkJpBmYR?bdU4wgsr#i%RdtU)`u) z+a{eCWOqu}a$>0R8j66X0NG6V&j$mljcIL+z1x9cOBIYSak!%P z^r9@DEtq@p2~4Y}-PZsDzTSN+_CVwtn5sjZM!#=ft|xPt4DO9pQDd`qiz@=)MMr=z z%uD-ivhCLeo%;=SM1asY;EZEnj5rI9A||2;gOf=!MAwMb3UI$IC**_axy2snxTG*6 z=g&Q3l!^i5P9{*&P3k4cGt8j<)6{w>w z;{!9()$m~iStgYT`DXw&G-6ROs9pXNSS=t>oGpa)od+!fC6i0xDlVB|BRTognFV*@ z6+Ogb<9pM+mQYhcR83*I5=~PLHXuPNaJ3JLOb;e0*f}k^+*!M0DM%4*ic;M9*-+wD z4eeYXa)YKL$4c5;qHzhj5IQIB<)INc9LOM*!9xIBus#NMmIAOl2qA3x*K573nQmqhR&gowFI1QquV+aJtiTBimP)XeUAx=m<$|G zxMai7=*&4sl)~lrVg*6c&PxHPG9@WSP-CcQzoKYHh`Qxu26Zh2fG23`o-BxUgF8l4 z{74e(t#peJZ|{?_N=NS;`~JZVun3|yXZg}ep>qd00gHxQ8bgWqtz`a76S)7)s(n8*~`GHc&0a3ZR+6>Yy5#`($jZ=M{ z6dbZp)9Hx-^`KgoH%dgnfZ!HUEGF0(sh;3gQxMbh6>&vu?4)=zTN2lIaR#B>)ekVV zH(r3Y@4|LGAyo5#Z*z3M^^2{ik3W7(9W1U~QBoq*&QGO%Yqc|8H*-M3gdTQb3(pdr z^&O>sA=#?IaEOsZi+2j(;ly{4&^HH>lD3X<1^AN|JMVy^nak9zB{4uzVl@9abWH&G z)cDT1E;kt8%oE<#{raa+B_D-__}&)?Hj$585xq(l(tzzDip&eBQ-VWh#ori%dvyQ; zOoJ+-2;?Y3c?ckXgg-2{+t!3r?7)!~NU97RC`R)XpcFmu6O{vRm4WL}+FhIC$6IL)bun zUGYWASRAtRvNcfjP{NzUvc&N84p=H0#`3j@M-3z8OX>d!3#=IkrDAP z{E-f3mtHW@P_ShF+xQvmR7Fzkqv^GXh~=THs$@a6$S*J%|L3|2z|e{Ym@61(wA%%&t$ zkS+p?LTSPX!kJIYnnY7tD6ioD@jT^jnDW;n6iQZcXQAt1?6Y7Iz11q?-asJtxEPKc z%9uD993vGQQE;9OfjT#oWRgTPt6HISr-5{V1ii!RnYF0^igRy2p@*G`FbxtYFgK-) zA=+1`Uxvx1(oMLRv=fbwxAi% zzSICm5IB>>(-A}^VEOU5w==^*nSJSBq2>Nn=xAsf895PTeS+p4(S<;yM_BKht5;chJ z%zI~I9$=hRFcd7no~u)6;>l5FXc^@R#8VEZ5LxL;)0A zm|}=8eFgzRzJWKG;ZmPOJ?p8dy4_3J#xbH%OSH*yx5XU&Ll|!la}-b80f}-f=%5kF zVONw=X7X?1jr^}DORF}2CRJQ*#7p8J6!>4UlE~iPUxS4+Org$d$pZn(UJsNUQIoFf z1LtGAFO1I~$Pg-%AkM*125ZYO_cL#txy>qdqmJr_I}74;xn6l41}~vrCM^M~A#%A# z#*T^fkiEV=`9EBpX*g7U!2i#geVAeFgTdH`EMs3|hOuU+qQs0XN?B4#;*7D3eJmAH z#!_jy%hIA!#!gg}O5K&QBrSIhsU-1u{?EJrd4JxV>zcWK=X}54&!_c%;CbOGwe}>F zKlh9;7jOA|<=v%B)!DyucEZB0YRAl>x&u75qubU+z=n~g#Oy$AP}YAM=1F2Y!$EllvJ=@$4dri}~buv^;DCaO)fh zxS&7WY#f$Y;|xEFiHPx_yI~xBlGI@7WF`VLCXZok`L1RMQ$;i93?OSoo)W>2h~|24 zg|k_0me)e9J+k)hMqp5JMWBri`?be6i%~pcz~!mzO9WOosZSGX`A5YulZYLXU5IjQIHIF-iwBE9{{Sg@LUM{Im_bgA4 zecZup;?UhkkV`czsT+CGQ5;ars9&bd*I+mVTo2{sP{<;hCuZ7t9bdX> zVNzSu{5AIUx96F2>Q)hZc$s})Kf=f4j_dX8E;%!9NTb4qF_S(~qu#@_q`iTF zlsLtAmPBP7iX~apM7C;Ore$9vN+e@ZbPW=pn?LjNTvJ_cjm;Ai?Y2PKUiWm>7lM+~ zn|kn+oX`w|vWEr;0W1yb?x=vPqS#yC!VWE?CJ&`E%nS^=$AYR3m6x>uEt92eEo#U7 zB_nl3q^ED%)|ap#FzRzmTeu&l8y&U?twW#17$cxsJ z)kU8E+oaFW-X_BzQ@2$%9?oy}!%X zl(dYAhsF^xcbP!XuN)fRsk}iZMvz@FWnQCkf@bb{Z%BC}2gbH&Jp>%Jzl*hla=ke| zu8ZdTbU3>$;+k3@5`phyN%cHl1r?tt7ivtL z*Yc+}0v!Kf&Mgi8T6GKwU+>FYU#>f$lT`nKuJm%|WNNZL908cDoj&p<>KL$#Bejv= z2?xeSYSC+X4u3|(*1zfxV{iA*DacJk73$P~?+6a_YjAP%(zN!Z=^c~WJOV2DNhEIy zFFT1VbS78vpz_b$$roJcNvwXyS8_dk>KZ_sUPSOTOJ9Q!Jr^nj_(O;m=M^_|ZD=D1 zwwyI7#U$c@5Dc&vMY)9&c|*MRSJ6yNesb!N>|(b>R-%oO`6LH**h=II&+wz#d9yd= zltcSYbul()-U2z84w1Y`TBU(CC}hD&SlBEOF+IVQ2HNYDeKB)f0{`ra#<2jw8GQ_8 zE3D5|L8a|jzHO*Qej1L}$Z*&OJUC{9-KM&EmJ?Hk?dCtMjn0D~W#`s3?!0UAlia>&^q>Sf?RPXnP^ zB{z;)&&3?eRNwigO@lJY?%g06P~hJ5w@qI_KSa?yY0yR0>tjRSU*q>Nn*PZB&5eI6 zz5OfQ^oz)hV@TCHF_ld9qsmk4_g1P;PG}j(`t0!%)CtYp4FoyhO!Y@siMlu`zb}*) zWcWy35CV+NLc(n!i5D__^2lvY8a1s~DPOYR-T>h=u3`^=*>FAS0{KF!@tGsO*Mrr| znZx>EgCkX>ulz8n zDU_Mi3nlVRff~9&D#}-IKGM+!>3qJ*&+E#SP?t%@;+XewE>3zJ+2@K1YpzXj77BOv zr^+^kSl>bY`6@(0TMRMLs^r2y==;N3?@=SJy%?2LyO*ju-KvqY&Bc2rp7x=0Tt_l> zH0To99OZzq4~gmFD{&OtHhq?=dY63)s2+uomHu*|a_$fJA1(h2Em^-iq;5JMdFA{m z)oG!KlRK+AY2qEB63Qp$(P9@cBxHzRoXyB5bvG8#O_6paz%u(l{joNR%3r}w%?N?* zux~rZiFr#vbD&C`TRY6SFnd-gk2;L8k41*H)DLI+X#x@@(A#KXeG{PU7s=6kAF)>G z81smx;}Zzv2Rzp-s%|@pRv(0oP`y=!Cvm+6Wq5t1cl{KFPgH_4G@8 z03vg!8nFk@#vm8WE}iyb-94ue(WB1_F-hIRdElCMBv{?eKWCe{-y>P_b!s3+9spqD?JcI6BL~?<}b7t=-8`RU)&N z{%C?Y7FJ{e(qsi2uQb60MSz^U9$5!6GXdcN5PCajh#-dI$XgNabjXDve3)?x$R4R{ z>^i@-1%8<^lX1DZpSx=y%B8E$^()*tPL;cwHJcB&Z-n=2$Uz2+%2SR24*~{|?AXnP z0L+D*IU&k}IXK@?X9s%#p>*Lkg3uL5@MWq3BM*tbQU2-5S=-j~EJatIP?;pejodyM z&4n4P<@g0h5mD@aq8>Pdx=KCtr99ZL0`NLt@qLPiL1@cbJ(TWBGs;0SWMBywX*c{D zZeFE`qX;_%n%jg`a?1m4Vg@up|FYC`4==*Qx>D*+c+>cpLUk1~_ zp3Q@N64}M^7C*mG@RXV$83deNbWhjqERZ^(TgqXlKUauAB( z=Qs;RMls2VF;YZxJsG>3Qv@2A5}Z4?q>BrrJTdX#?@;hfFz(Iz3iw^FLt%|^ zHe*1#dFDD{6FVd!9A=G14o@KUM=d{)I<(GVchFz;TpQ=SCyVpM0<2r}3D`#iT9T3s zdp-Z^PSMGNqJ^J2e40-M`lsH5^S;tBi&(kceuV8xgN^yyB(`zk|E%#0r$xx;bz|T? zbR`RHXTn&T1Jc$8QD20;L$6&)VNX}(WNOQj%JP*(9e!fJ!0$Ea=2iz+cht}>@FD8N zDV|T*!iLkRTZ6i3Q_iXrA)4S}F2u95Y3m z2E*&0!cC4x&}30ioBjYR!dX~f0Mc#ue|<;57B~?rYbtUyc=OhRm{7CZWi#`3 zgwr>hRr~s-(1nRFXWS0q)tCR@HCEw6|Jme=*eFn05bU2)v$AN6nvt4o0jd9Ql%9v@#`4U~c5}`C6^b zIs()$zFw_$cNaFct|%C*$!n(Jh=pq z>&Cn`RKV=Ka8oD}4>rphyLdhdx6I7B73)*=8SCc@9YE0L$h6uu-_}}y?;yNJO$5dyaFPV;0C9fNuv!_pQlOawXv#{Y-h$jV!ip^0dYG|$acRAZZAnJGzDHNo z2aT*x46fyOX$Z=hKwVM@oqd?AB(Ra@9q}0%>)>4E%%x|09fv!MUYi zOg|V|imXwvFRwFU?!{+x4)^z@oX)Pg!2}#U($pFWS>r>a8dynf63= z9!Ve19tt+m+ecJ+ljl~SS=5j%rp>OxAhyFSkZWd={H4%FBGTj~qg)hplCh`S} zXaVej=D9#q@(7;}gbY|)Eo^UmHrb0mP>VqIdI|9>;E+>wc6HBWle1PxP+tR2y-?hjnA$@=MG1#SmZuK8;ePJ7VBQd?Uq6 zhj`+3A=vBvcJ2tDJxWIK`G_7+H+f6@{apEWlS5-RsKI|=-<~zxER%viN`*hE*?l%1 zvn7_hon#0-w!Yikl<4YMT}UTGye*O770+XLNO8(3L(jTD1Rg@~P$Y3Q-ZQSn)n1sC zANufqzLR;%^;*fjp1u!zc~^lJR+KB0gx!Zif=ocr4De4N+zSC04Cv1RUQ5y5)@U)a z#X+JKhUd#wVKW07aoijN{(a9(8DJN#l>V<$(=&ddTK0E_c-6-;`5M)nqNz!U7SN*j z(Ru|B8DmI3U_FssO(5q2GqFtb7TRx?;5ZpYMS{ADeh30V!x9in{CUDM=_=)Eum9lI_}IiFv&R^F#ek}z7*kq%miRcOFe?Byb@pY0j$gS0#H6)54Tu!ZcpOHN=4G-zuw@B5xOnr^ zwN$Y*`BfTds=+@RkFpG&aybR6ez-d4Dt)hp>xoH7i=#AS2kX~#htQ$#FqjwBL;X1K zDFyZi9LOglB&gaHMe2mTdH6tCuHrSqAL&k(x0?<2&R zmS*gD^{=T~q{mo(81Rfb|EcG*j;++T9Ob^L4jVU-co1WX$<>H82P;P?vM~rc>*3bORo7jQ9_Xwim7$2fA5M??(Ur2A-Q2DZ_dQD8LQneOzSmI5WCWA zztbR+?HIA66%nco0@Ebm0ayT`7rXiufw{qrVY_v!Is*ANAfSYiH>b^zp%xS>MYcr{ zGhtP3&rqRF1%S5>Z8zgf-|GF-oFK~ag?ka_yOCyG4?agxc3gF7=J{*@su;vHOa)lu?|%(XA~ z{OFIJ*~i|4@5B_d)uNzvb(*7-h}3@Er>I@SS!L~A?@kQ|gKEG$l!3#kxycNh_RbZMKj{Y}%1V zakepcINz&FU_X=f);kS&WMI@jron5f*jpNMPJ?KPkP>xdP-RJWk5vHD-)y+v-;#xq9&OckKX_i zrfeo-`KY4Jpv6~#c)Wfg+)is=o(p1E3Dv+h6mN{%E#)rLMm?ygOgIgo@;{*IPL zMAL|p=^Qbf1bQfSzy zvWwJO_g}`V7J-RQQYrBEM)9jSlVL&0MOMfm9SkYF`}9T12O8oC9t|;#dFv-L0&q3p zqfGUHuoqP=PxKBl`|dBBNGX`ZmjiY{Us+9NYcd#`POaFn`zGiO!3l6PrMD?KCMui= z3|)oJ9@vQ3y2CaNt{8%r4*Q_C!$!PFu;y4MbR2QUq*Hb2!NWp&#VGS#dlHK*t6*9&SmtUYP>u zoBzmUF;KP#cvAwHx&bC!z^kO&1+jp4c_bjq_AOLb_zSC+ioo%hG5d}NKp|A-3!-_8@VrjRFe#O*};UqZ7RZ-fY-uuq(nZVhpi^e z@Dn&nq<)~#@R3brM4_sM>Q=^D2(8!yp^8JmYcIgzh$`TqM!kbZn0}bDDte5)_}I*$ z@|WDESvK8>nSa4%*V-1?Log@al#frym-fBszv@Zd@HhPHw?Bw_Q{J$iJdpAZ1Hm7T z8TZNC60=J}=%5OF92BD`O?#sV_7}e^Cu9W(x8$mq#Q_&i1-Ut)k4N~6?{tmRxN7TM z-K~uV|6Mw*+BOQy8X-ruS$SfRS<%VbfaPPTq(U9X&+~39F*!Os#ZN=^HOre$xuCl>8h;YtnmRSpI_`A^(NBkKL zs=&uOKy6k1I6xI&G1hNM`8Mwu?#z=~)KOrlY<6g|HF{J5#*SEtQv=OpPCHZ zjOL-+o*x<*UFrX|HRe+HqnbQ_x{^!083+jtL7AQnxlGv7bXWfo%p^sZ27h)l>kQ!#E7=TVrg#mQLCrnD^cM5F!-$xFe9*O zG%!N&m)SR zCr>e}S4+eF1q4w7&EjdZ0rSsKW{Iuon!pAEqz*$dYBI)w%Ip_@0DU+O)M7S zC#+6JRy!?@}3a;&kQRW_hk zdGzoqs{Fb;-Fugt%M3_-ZJrkCN>HDHLhH{ z5^MQ;*pg{rvL2wcFJXvcDFILjA#?&?9fi*J`pqoz!x67*W;#t{gn5+f*PI}UNLlod zZrK>78N}jI1C8>#nzVPBC-y4$`OBN`jKJTZbw)zJvC_=%R1$uHrZ_`O4x}QE7+k&4 zjC>3v21KRSX~FHjn|vE-z(elPhN3(0`t%-bo#fih#vzulKr<-EjWMUx1bbj1kG8Xo zT{MiPqrrke8$3qM?L1;XLfwL4yUc1)3O$tHRdSmK-_|K%|C0`3C#kW;^UClIFB2mj zZlUV>?1jJe`Rj{rRwl!B1?^pS-yL->qf@X;AM;jT>8>x%thGt~`AlC9s|nSpCja-| zRx{PyNxbQqFw+b%9OeNyksCIsYxx`d9DhF{tlmLy909f3v7hhN4Xw?1>YFK4SDR|*v<(3Av1mzGHwCl@+PvQeBmG}$m^nqFpJC!GvGU*CX8XxiV#AAE^Z1H6aj@uq>%!4Ww3+ zUlDntdPt9OtR-Iv^SUk=Xvw#G9#anfAW!UyIU=*5r|f~1%i|a0bY^TbeY%2EGZqe{ zE1Vw%?ofUD8-*{JD}g5+9+^mA$9m9|jjQ}8s~evQs^u2JJkpnmk~Tlb45q^0fBn@5 zm~ze)48QM^wC542Ms^XFGMTxLtYiB#AI^r8w+@w4wY1JB3@hf0=L(G0&fsDG)(4?> zO*8eALvE`o*v?>kFEWJs$C+YU&EFwwR}!_mJa^Ak4hH}4I6~~ZTc3cy+xt|uL-YkL z;|R?DIaze@-W+;}@bMxwgQ&bM$7}E2Ah#dthC3qHdY@FGe5ujSt#5GEKIl*)an@}~ zg6k!u4zJ{HafX$OI@(GE=Gx483*eRW6A3e@w`oO(N}RYbSQfR9`mU5eE$}ennuJPJ z6}A+uF5vPN1#l*|m5Np_f17P-x!H%e=O2P2jpr#XEbq8U&NrW{O1Ar3t~8#*1`DsJ z>8w~G=3g5AJiTSL6u-21>P=?pvHx-t!wq-;9CW;OvD=8-O9lgly+h3nqE%d#*yn%vo^McccB_A6gWU zo8YRfoP{Z!0(oV#!#L^?|0jP)D!k2z%m~Uz)12P2!hjnu>R8=;8^yxZSRx0@rh%~ z$@gT~MJ}5Ym^q}S)^90Z_iNZbjA?aQCyDM8DQo(h<(+{*>&0CKix=d z5|e4t%Kru6s?kL9V}u)G0>PCqZdn2^6VAphK0&>Qe@_AQNK)IZJ;bqMsB`0Z@6SYKAHoTDDbeXf-61%$hLGI#MJ4>(LL zmNri>)#OPadb}UuR^83hQF~(c3Ud!m;)`0cO*JHHu>q|>u=M3ww@R*}zSj^_xaeEb z&?;WRVQ!*HV6*Zm^@U+!YyGX#FSh>X6e_B1Q`FL!9f0Z!2nwe8fH1nR1_y z`k38rXNIr`l^MW4Ii+8)9pUxW7ZrkoafhzMbxlu+H<)>vUqi-^181>;smi|5fnFw5 z<4z8}e^y#>5<4lGj6fk{a0i6a z-CBEffSW6718c{1&3jxuR)ET)Qs*^bta81NnVA3=;Id;cI9|fM%3kS&EE^u`Kn0njt;WTahf3Sm}8ry1d`&@0G>e!L~0YPghp*ZvVH_hgIi&haCSVt@tZMg zCHc07yk5L&@S&>D9K&pw6X!AXI0E$|Yq}``ScJO~H|5M2p;_W*BBcmQMGeui-~~sj zz(NUl5eqgd16#_&$h)D0UhQB5C*_za`F8Anohul76iAQlEBNDn#f%eqIY_?#@myNr5yTTmsjz`wFx}+g5Du7S z6v#1%)B;!(`?8{OHinu})@9ORz5A^_OrNAN8h-CT1&{(7!y_uW&#L8c@Pz!988I@!rBBHy?~5yt)zXS^5aS98ob>sc z%en#nlVojO*xzm$h?S0BUCD_;iA759L#x~;JRdF4D5>iyy+OQQI~hgnpO2*hOCZv* zxGYZDLw)T)p0uQnD-pGhE;#W-k8$jls*dx@5*ZTLqbWDr8gw+Sbp%YHDo31ns7=d^ z+}Wl&g1*0HIY~a0AWs$xULq|^zv-8edgrm(E4pzk_St--tO#_)G^O+0&K$?xxKS!HT>Ki*mWl+f4Ncu>_$K#eTT0oe)vA@u z`lGTLK62x7;{AT{jdZoYgP!YN&Yf=!-T#_4TF}?~IGMj_nMqfgWYj;GoB!7q1u%4T zkvXDLC7>=J^a}0a0J0L(1l@ISuMM6rWDWXN{`Ft{rXAm`QzTu6To-pjph*v7`m33O zo^mQrZY%DfC{E{}Y;F9;G}%{%wnbxIp*R=#V*n6t)&Mpz z8XF5XXhN5<1Ql59S)fshoDAbCfen2eJ+RGh*_eBFNxh_GKkrBRp4m>Yp+wXU`$K{k zGHMkPLZe3p3J! zFrd#~u)hd#KVJid(2o`Ry&9(SHDK3hu~uGMQclyag3b*x2F#1mOlfoy0`B<6s(F`8 zdOKA;r1D(mJ}VJXG&KQ?;eiW$xg4$ULdO;k#Wv6^&k! z7gwVz+~C)r0c{GjKUTTNIz7x6Zg)K(z?F&WiMQMOFaZ-zdKsFvj_Lw=J9T-)q-6J( z)M@rlQq--8kG_uumwT}CXHS>n50{n34Zbft-e}UHoY>89$HzC}Cg|E4yXrM>zdH9` zlG&jyX&hO{|YRO3qy|} z^;=cX!Z9yP7KXXh3*bH_%A8iI8AnrIKR~YjB+!;uG@V_sC&5@vs&Bptl^>^b__S!bqhH_rJ1|IFv%*@CC zeo924o^BKSQ2pA+M&05cMV`7$&}-ga?C+z=JSERQOEm5qGhTyZ6GIpqLy!d#)=fG9 zd97|)oA!9~=m1;h00;m>xFbdOLQt}xdIUuRcoh7L4me8-VNZ>7J3Zb+ScF6+8JiI4 zr>F+vHgQy%ZoRq#qx6H>7}}3+xXb-+ujFnxTNXz)tE4Qu2%0qY5)~BZBw>gRA{9p% zGqs`F1?7Uh&j8c-O~3i$bpa?g`X}jX_#i6pp`_PnCWZ>v z8gTlyD}+h$DMq>5JLraxkJq#0GANGw`l7OCUiIe5fLnCK3+&d%xZz!QVEd5&758hD z?ys(Q4PBHrJEYDCPEkLPiwjnh;pCT!^rerWBqs=sTKSR>6W7EY4aWLBt(H72$3kM& zUbxD^T2a^Eqv!I*Q%_dju{NkcHS55g7H88de{FuhhF>ixjaF}@?n1m`RJ@JZSD|AU zMlmXS9&$RcJ4R^0aQ{j7x5#vQOfAj#s5lg3Le0hsNCUS+GRTEOXJm4%(NgZF3h9B+ zs@l24y-%I230^!n^rpYCFHa7An(dY%S1is)K&~A(sO8SgltWb~E#0)2bVF__ito>F zxhunL+*9;dWX8AQr?YRNOMcMzz5&wEQ-R%>H8I-DxH}aJ7G=KkC>;zx$J}IARGEdG zh?}gj?Km=jAT>4W+_+}Xy8h`Upt!}A5 ziK20}stYx%ix20RIqvOiRZes5DrS zY@Obyns&TWx#}#wksP&QP_@x98?MSO>MN0wa{DXDzt@9)D%&TZ7i@+{7*lLy$WT5j zRGyVm^ginMaLef7Ds^6Hc#lgw04cuG0-tF^pv-3Q3{)OnsXM9!%$?ad>4pF-Yhe_l zYibB$5fC6n#eoH~F|}?$K9(=#bc3q!*J|Er!wQJ%Ar(zMMh#VHlrHv*DZZCOrW8+g zY6$zq1c`{DJ}7l2Pu>ykWL*SF<9HDmt^=YE0AKe(N&KuE*EPs{wTd71QDE~*?Yv30 zdjyt}CwNMMQav{7Jx`Ehvk!Wk%4s?u1r@VLh(AJ+n$}ln-I*xZiW4M8u@(y@J6ss< zS!v+R>BRQJaFKf1D4+Sx>Ofa zL&7?+!!tOxUase1fgYh}i+bEPFDqZKWYfMIIt?or^Xzla{aRVM z6FN$5orIid8Qd)+hO=#rg=^J&w$ZpNY!e>-ZVvshZ>{dbC(s+(G0*7!Fl$*=O zB>KjRJz?HvW7{=Ofb=<=fDBM+8nf^?!l^cJb>l@*y6>?OB_WbuOWTdI%e@+!H4qH^bpt~fr3F$cpTw=K2uHx*0Fu&js{XIImiw($&HnvpxcP7c4I8!|_RsaDXkG!J`w`58K8|Na;O z{@H|6km?ID6XI-E7CJ6mLS#m2b_K$)P=rbDWC#&*)lmw>_0Ue{34qx^{GXu@&+*W)^aLrC#JZb(3RD7?yK@)5S3LH zO?u<1Me16qBX(J!`0kZN_JQf_dfJ=mq{FqMIGmWkuU@6JL1kDued`n5mroU{F1An$ z>q=6~;+u&-L3!U@;u)q)5Pj>12mSk^iECKa*`9D67Hf644DH33qnPFCTPc-CvfKE? z`^+jEps)n~*3qrUVea-xO~^}yZLMk4DEWzgq|fGxaO*p@iBK733EfUP@B3ulS;;dj zX^{jlO$U6$B~I#@)tpiDjX1)BejS_$35nbRUP)~KJiMa~mpwZkvF23YTIp1gKiZhleq+~ z(r9-6(PxC%nr0-*@TBg30liG~66Cq0Xj{r?s=9U+37ljD$rt_S5MGJvQ>i^0GumLH z>AJGvLilPCuwFnEL~mkNstCd(HJSn@f~N&Cz_P2DNB`Mt7`WnnxLZH!pfOsCdqj5% zIbRd8^RUV0ORbi+Rd3H+26@KkdLusSDTc8SoheL_0;Im)CkvOv;BtXQ6B-=B6$AaZ z!3L0^l{4&lKOs>U6}z{gB2)dBc&by!mjy>jFcXWBgcUj`tHiw8NjQgVJgk^HImEUz zND_KY12#^AFC;!*l8RP{zRsFnqr+ALpffzc1c#hOBZa=j9R#5h&g3zm``b+qZl5eT zOw7&SZ9miPDLhd{c)V;N6P#OfB7l7x5p)tXHSJp_L$YAbKe!X@MZB@kZrV@><;Jor zHS2s)yIwb{BI>{wsa?hTJ}rb;+*7;Lwf>!!{|BZ z8s}<)2{6u^aUUyT?2*q}jm|o1PO=Za5HORs5xhR9K1pH+N3yONuUK4*P^9Y(>=3hx z@^4B7(QcCPVc7^vXcEgXfV`vXy1cMoiZ7?sLH4tix?$AYZ1e#(Mh~~dTLq! zp{GDlcQ~fjhu4TBB_gFq2Q-2?7jpem54{;riE?-v08Iiu+7TfbD(;jXyX>U7NH33P zCn^ZkioEMjU6K5*a0hXP{=gvENeVIl2oUv5#GU?81gro!#Ba(DDSP4^W>x5=j$O-N zYfOF>z%l?-a*Sob37q?pB1b(yxAd_axBZlrj-x%JF^OxObej<&Bl);fd@geHIVA<9 z-BvgSxadBT}c3D%u5NXr_bVE+w+e7{(wTI(E32JQ#pgjVQr;XW{lnz_yul~(+9 z0cpf_m)UbiHHz)hG5@-%#`6)~M3RZ_Xrf&yt}u`TkMO-a48lBIg?b#0N;M|A;8C#H zntjRk8-6#m4R&!E%VZtcyWpFo2@^Q*IzNmdu=d_Cc_&K9c(Sns0)oPgE?rQmlfaL) z#f&Xu6X{S7fvXDg83?atFR_}+=3JXEr&>CK$$suO22Q!bK2n^j8W-i~*T>oA`1@jI zHvQj(SC339a(t~VVH&1rtUE52jJpppH4sD#Ac8lCM(uWLp)Tc*(=C2 z<4@;9+DM{d>Ar2BjUHe!U$X!zW_Xl(r8I70E6&l(>hbIHM*6kQ#JL?X9EVRSV@3J$ zUnRtZ$`~#k{-qGM#D?TGh%VBx;^K*JSKl!Mwg9AD^8>I$MSl7BUos%bh;NvwH3#n- zNhW?T*e7`5vpNmSI;ht&?u$A;6_So<2Uf*kqpr>R4M&3&_R2Q0Fp=GXm)~55{rCPu~6DmcBV|j9PYXb z#YzWa`c1!dzt&-m&1%MvM|~x4t>65Te+yAPg!=2k2@LNMB)2CxYGT6?o94(wz4_btG)uiHbW0{l`n- z7kF|im?d96%IF_5(7M`qsrMDsAMwYpwyhVZkAY8%a#k0EvMB9+xrP>tBZThbS~9Nc z2N5SdlFc6q_h42E7dG>-Ta9;L0U5-f=@vsG*`eYU=Wg*!kt>$XF_J~+pQ6wa0B`qd zen(aOq^B@~eOLmr9@IM+9}Q2@zuZ^m63hr}>FeJT|GnE>rTVuYqt_&j)1Z`owQAA@ zuxn?%5lX6HnLnJ`#ef$@r>4V!zmAF%6H|LCwtEst-$4;K2b>N7;C}k=cby%2qMSqPW0oq+31b)xHSXY zm0wBIQ{qvSQutgQ`soz@>$k1z_td~7|BVZsbu5TYN>R`VeljQM(-~CaAm3`_y_J?% zz#?35Zg_O0UT#WAs=P(tZc%YqHZe#BBi>N-pqy-FQv6$?;@zfl(Y=SC3sBP~fCn)! z5)4A30D++dM)VUiCXM1F>A*b`;IJ-~j^QW4`ea}Q+n`vf5g*UM^nJeNRwma**O;z^^m~k^O!S612dufCq(WP<#}NMu1vk0_0`7QP<0cfG z@O%1VwUtc(Qvd*f*a{yb*!+bnn{;n2OC`C@8~^`{+FJeJYhAaUD&O~{64s&Z7XHQmiv{1jZfSbIa6f8h{8&Qb z=UcN);0jEkL~CDs(DUZYbd9#~s1J_ZZ$W9KRvmouZ^4%SXw$)V@|c3)pK|)({R~U&8;9D7PoFQ$6^tA; z(x)H~v?y9BDE*ZSZ{Qn#V&%N3tQSk9Qsbn5D^0S0GOV*fiNEnRC}Lwn?F=We8|3yywltiU-@{*(J=6NK>a~QK=#w7O z-u%|{n{k;>eJ@^`8$0iI7j{^Wuxsbn4{eY1+kPCibe!J#&y_dQNz!ApiqSeDmEs}s z->ZzbtLh8}iMh?DT^Ju*f7V^K>7x4py~5s&85TM^H&P~{adPkSxco< zVeM{yA~G{I;%4L3ds|su-wYfgu590Q3C@1BFRio`w9b6L-+M)Te~)gdTj4yG_{?%) z|D$_^9(s1C>L!QtvafOH3na9h07rAn1 zc*AEi6f}Hpo5-6sno6?x^}K52>#FiUqrX<(bi2QZfAUPT}E5mnF~7Sgg3T+_}ndcta$X-7ya?# zA1lrrpGzZ0v;%P`P8{b(d8v&zH)`X$$%433KmC^~C!VU~p^B}nJIJsP`Ym_1F1VJ7 z86?YWn;cD3kv#VB?Dgrcmx&WN;NY3*DXQuCvB}@r$CoU>2WE`AeHK~07hkebsg!9O zeyK=)Qa&H_Ua9-!G03U&WY{JG(du>5dx3@K?nBVi``c-r3h+bXZT7Zuw)6N>KdDD3LfO4Max(eA&Eesw<752ZZV|6F15 zTQRRYD{)c#Nc%v5my(ukzFEbO{2zHOkG_6=b+$s=!IsO8tBt;-`fUIGBOiW*O|2f5 z%=~2ZM0jW3vFlo{O%)=g_kTz_54I+@E(*`22SP|f3q7HR9*Q(6LocEPLu_K~lCG@HW7lO7r2l((OQPmJNmGUjg|+TNQOC-w#?HaEE6EA+ zEz>JUeui#IRd|s|jZBt}-6J>0Aa!oBt(7w=J@ZYSRp_PcxPznk>)gC`Yq4MF1I5L+ zEO|&O@2dI0zu)K21n3@pn@BK1*k3_?u0+yq{$Ynl@-9Tp&&+Qz_6k3D@4InWqpfvR zLu19W=)UA7w7i6<7QQANc0>!q@e$ zG~5a`|KOQE(q^k*tEItp%veldeZrDXDT)Qx2)R;9zcrqud@bI;0ZZtAs7rkw|O+*kJMX+6HL zn(UX+?^iBN_oqhYD=SU!d-VB1__p4})(3f0CEA-l4R-$Xz3+MY+j+Z?Pjb`$aj!fJ zd~M#uxI%rCfE@pP*+#rXofDq_=@&dpZ#rDE9jRSuf6pUx)?$VJCr}82pKU8UiVX3;Ba&K)x|G0QUg`RGNB?ny3WVQX+hjX*QY@_()75&P6 z`c=rbI7nPqzWV3oyFCEr;j6S4TPaMfH~bKfsGpqMkjF#b-OvBtw%_%0+w1FeR@Wn? z{Q^aq!>xCWj#fVxA9mWZd!r(LV_?EFi+^~U_W!iC-0RJ}ei5Ps+|n-2xPeoyF$(4F zwx3-0#8!2+TV-;u>^|9Bd(F{c&TUn%FJC6a=`W2whezzm8a6%hG1TFcXdKzJDVQv& zxabrvFJPK~OfRb5Hqh#3dS{L@*Y>?wMj;QxMea}RWA3TF)b~j<-e0*T`SZ@v(;r{` zy|ckJ{m6Zr-mA@xdcA))-;d=h=$kd&*!iaOM&~8di$={qd|E4c@lES5{hMjIR=^B~ zq#qbm-qR1gdOwy#P5)%Db;G~jXvEm%^?STmlouR}U&p4wdoaiMSiiY?heB!O4Oc6Q z=y5ZT(ki3Q|E`$*xbmy;c$;T$ym9dLQ;2{Y4)2GL`2gPSx0{e z@cHgTE^?>$>USa@zcUPoKXi4eJ*yD~<6hX=!5qxyNIyC3|UOnp5j+@$dRQvxt z+k0D@`h<{;qOgT$!j#qhC?4U2}Y-L6>~Tt4hWmyk6P1_uJC3(=D>I$&Viy?$z4i znvlT9j)@BnRG)d0PG+dYX6e+KnQGp9IbA`peJqEwC>?G+(>> zC?K#jmWw|d{!Xl{5+r4<|KgtN5tBE$6>T4u56iToPn(X#3~(Mt@I1LDEREPNMZ4DR zjT_jUo_j6p!S)@P|E#w^F|a#x_2zggwf{oa=YXUf{*!{<+sS@`*AtVUTEJwAYfkJyQP77{x0Ssx-5i)$A z4DzFl75}>Y=Y=>(1!D^MY}Y?{V1i$iOE^E=*$kiP0oK8#*62M9ww&w2d0?8FOVGpZy*bH;BoH7h};_I7SxNzK`78!Va=(H?=wIZo*?%-aFvB!tAMeY~2W?wEhn4C%$is73FEB zZ%)KzB{oijMi%%&L<<~uZh;|_Qd`J8SMC7y;N&N$iImcoJEP#Y3wNr(cNiaG7h34L zqRWx3c8HL>vx1p?yo{*OR@&DqrxPF)*2!FBuhT9=T}J|z*!A+R?27Ei!GnQ>Mpu)- zqOKmVIKn45V!~5S&AIM5C=0c}YNAH-&W|D*&Y8}Z>W{kyS32Y~QCgEoJ?e>8LYIrI zpHfyZ8d$T-&^Qj2U&*4zy2==WjuD+3K|=C)5G6+Jow?;}$vT=}5O+RTY6~e}tlB3l zFJ#djE$d!~@Cp`U8&TIE;b18HvHb9i^m0T@)Xj(s*HO`0oq~uV2bxzzu&0Pa)gfIv zp%-{!>7-|@wJRbG8Dc@dls%_b4vQfyPc=>+L23m$H3(Zq&KBvc={Y8{7YbY&oHu34 zUk(PZQ?FLNa56pjdx3;VY1Bu(qk@ebpE+7SR%lpqxqsc7@Buy>+>DHWW;A^9W7Pm< zrLhy0W_7zSS>@=YTcqKPreUH&gZWMW+?iOD69~2-q!0hVc=EZj^AR_Qmi~j7Qtc_( zMJwE2usmk=cbWV5PUi1NvcI1fe>!$9Ex+~K-=*5+FU4GeZ2bgXDv|HPJuiF42z~Xt z#1at40V!w)QK$ck$Di!gWM29(ZU?>@1HjZ#bjGI6?W*^k&|Ov1WiYU$=Wd4U+)H3R zmUdLZgnmAbB$~cz#1bj`m=D@j2-dIol1XstQ`w^A&q-aKwR?(>!N} zBhw}vCkCWBwEz(L&__4$v@x@j&Sv#_kW_ymhQ8(6_SwRpOZx97mT0Mf7tm6% zV^a5XfQVp5%okYZ{#T9(rdOv-Q}v!rkAbKpdqhQ#BF40NXYEeaH|aRPullTH8DJgJ zLJK39z7#GZMl-6A~yr;tw`6OTV zu%55dDAd(yk#Md|p4IEVVd|qO1D!FA=@k?>o76n8<~JBItkJ_2TActty2`v1qa`+a z=qU8`&DPjthqISOfu7|@?0aXok;o{xQ`m;DE_^}VwhqeqWvYwHW!e(E$ zmzyb^Y3|rZOcWx$8*ERN)ElW^ZDo0GafP$ZP5++E%1GM$;?cVA{YS=Y&+?d$r6ntQ z%hTEKpE$pL9vpuH!olGc?Oqvl?$Mom$)P;%T?xmzw+faiY4lctMZXjS?Gmlh!)Aq{Y@ zE#AOrEqh@Bryo{0Zvd2YgF>_xvgQCM^R;^bL)&iH0dNfQFcJ0I9I#(4L9jRA=0hmn z*__I4J&PMBpazW>DfPBFRgkGP_q^VowER`!?jrJ!+m_Hdh+ip$R$`Ekka8mubAgh) zV4Zxh6EG0?c~KfyRRCLmPLtLnOU!s*`;I6q?(sN3(W6GGTGr72zMymqk2Ac<=GxdKtlIen?osBcl1ZuK(&S}-y-z1Oe4Wj> zi=Fr)b`Na=Gyj1)<&InMjnrB4v&>UXCIU)nw5{jL!Q9iXze%h-nI(EzycXl*e-q|5 zVuP#AqeQyFiK=z$c!uX1!h1LrSKzL!ir?cd{biaRPjQmhmcN7e0O&fF3 zhg1GxS!A1ntXxUFu=8~;U?r5~A5wnXuE$xI&_YA4UGWlct7lFC^&HaxfGh54vv)pxSIz#;9MUWqL=?xLN?SP;MjS1zNX<4@ z`NuQXRrO;3uWet!w7Ad@E{S3TfDZH@MXb!C#M`mJeK}x6bJckVS@>YtA4ju5*~TMm z33LkwLH}EV15HQn811K6wV?GMi2nm%? zVhv=6i{KeL*VvGvl^Tbe-LPDu!R)JGFa;UF&jCK4z{xO^@K2)U$q7f3ck>kNsH zB@WX$rCqg_Bq8HZU06Oc&YomefJ;_?o7Y*{KD~BA6W3ivs19VEr#&q=K4SHC1BAqw zs;M{@I%JrO#$-8jM+>O#N}F>CD5+5poI5!VJ+|o91pYF086vb=v*Y{)clf zcupj|+k6(NAzLLg9hU`~06RDi_Fh@L7k~$57Z>iq?$^U?ZRGU6gX3D-B_zR&=S$Eb ztMDtgoq7m9HE(VdC4z>ej#qAUtHK)UNY4bRnR(aBe+bqu`lpX=rEQ*Edccjb0p&5i zl#qDoU++9`jOVzUzzJB@h><;8C^!*z*IcSqMn6Au{EYOz?ag0h%7K#)7J5sh_6HO4 z^MWINgt=-`Zfs9=91oD6%q$k8Hd_&tNtd%;mf${k3p_JCwXP)wy83Gh2!1XrTN~Pk z{CFB&dwxMDC{%k3(dC}`v*y*(m(qT2nCgfl-80NysqU7Tls->d*^~8ijo^8(!B?rh z7Wdg~+k)Bc_iyfhx+cGJPkQyAEo_Tesabd0%V=HdN(b^q#-=pDN*~&{a{R&yUt_pkHFh?!lIm0tcs1P0v2n}7bouS@6T6i!~!uYfWv&CHNl@H#$b#}4zpOHmbb z>}K{lc)Tv=W>joy5Gs*H249eb`iNOTIG?XgVW)zE3%bBzvY>|ytD=_pp1$yuZ2*wK z1kug&J&Y_ZnHLOC&~e|lt0nmd9$i2JR1%J--Nk^0ifBwNZQvi$5)zpP0Gav#9wF95 zkZFQUz?sdq_NK8-!wvvjvy%CsAWGncTQtNY&gHDp5Ei5z>!LkLdt@x+i+vgaK)Mj@ zu0ZaDS@54Icx25AphLRK0Is&oCjrP9K+4z+F>7c65gBn9-J9*FJ3pgpZX!$<8!|x* zj6QFeh+tcE4y8<;M_Gr5c2Q#4nRA%=og(SgZQRec@3Xf>r{&7jmX?RQkc9GaMgy21 zx%3nnghpW($E4FvTX_AJt+AR!_19-TsA#8OCR;AvpUJDJF>}jnF`llw@7sL8j58_+ zesSr^zBa%P0!wP!%}v_kZKJO{Y;;-!>gKk%>73QVRECd;VjsX|>-SXqHV<9ru| zW5!#}j8R|(+NKfrh{N1;2;x{T5!|((Fs>*RHBDGs5>E zr40VB?hbiBXm_5m;zcmux%6~vqtYW<(T~O~%pCyLou>uw1Sb02DkFK?07YO*RfhL7 zcPl&fdfMP^gk17@JWAjr2M@+b!_MdnzunNS%@5}*i=f6SJ{O<^*?g4~vEdp3*YjE}Ya@dj3t9?b6;M%g?yelo8renM8f9 zxk=#c#K~~v?%KDiEjRzBt82OlAnBquJ;spWPJ}2=_RmLUCCBfiyyB-Q^g$q)oAH!_ zvZXKm0R`c9D3-^{U&=i4OPtdb=-h`>>r_lPr+GJZDP~XOH_>SFObSuJN%G&(W#D`1 zz?7Zm7y1qoLS*F*KcfQ%IN@a!3kf{ihX!ZeVFUoZ*M;v>AfFiEVI~k?h)XQc7CynT zai|Mq0iFWXuq+OJ-f(QF73pr8AJ3QLhKnP1ZWivX4$M{DVaS1Rx*xmZiwR_qa&d7) zWO^kswE&EEU2p-5?SMvHA_p+oEVLmnbc0%GQqmxKi3h*dirjetgW~pvauXp(9MBEq znZuP-zzJpR^D9S%UqD2y40J;}RyQ8@BcG6bJ97lUD$H4pg7>wt-g_ZdFhrEUH?<=I z%1ET$aLv7jYjJI0do>B6ha(cN$;1;ur;;9$?+&W1sMpKqWIgCd)l*mPnM!Kg#nOq? zlgbO3^EwSzD^q~p(zrwABJOY?t}&y%0GrIN`q25sq*`ZHj4`bhkrJct+=$sz>b~=ZOD4O z@CvQX8}1c~z7?-7+ zi9kwM2dO?Vdd>44B))7QjVS->_U{Q1P>Vc(H!ck>^c41Zv#WObaCrfrJy9QB%=n$@ zfbEJ_hs^K1sIQ4Gs-8-9N`)Ru74B+Rsdr1mSJWy1mEZBFg>zm~yiR!ZiTM^PwLrJp zo&IE&_kBE@^*v%(j}egA@D^XmB4ZlSKghU)?5&xJ9Q0JCFuv{s*Rtl&d;q{9e)to! z=5j7u{`Y|X>C|=QrK4N(eSI;vD7sw0t2AK!OzSlz{K=rESV?Pu!;R|fh+QZco{(&_ z$oM{17;ex0yNukEPFhyt>=V7Az3+II*rX%sIBokG4zD2{L@vr*7s+mu7j^({Jt07v z*x4UQR9ODCZUE%VN-_|OU#^UHIEZ9zaxzkJU{;5oo}q0d&U&3bG z&SJW%xj%~-qA5t5H|w1d+G0$aHo_`caHL8O-cSQn;($aY9IOnKDgsRZiz(MK-2f`8 z$`l;x^G)pvM}i~3M0~*Rxfb%RZ)mcsf(t1EKihZBZ8woCs>P|c9C2c+Dq${q2$Z<# zG|?H*kp@Q#Ka%Dl%-t;5i3(?f_NZb|4$IMxf`_SsPq@S!AYR4rB~9?K7fcP45<(3m zrjn!wH-UgPn1UQ!bR!U67v@+JG;33I9?dK&Jsm)1{)<7ykT<_Vay038#u>0D^`e~% zYTi<6{^&A|ndgd>L4;vN{&V5Tq3`l{(eG?%;WF3%fi|fWlH{jt3=d0JnA9ZUEiP`p z&n?dj3rUO@#tH{Utpd+4zb!0`o4@J=kWjDV^iiudrajudDM*uvD@Y^K#dpI5jyJl zd>7><&5MyN)g2SGuEvDQSERH3hmEnjgM4iGJNcdl*=IQ}qt+Ie^D%->`BPCA0W+^_ zB2*!2wBk33ayBvO*2FG4i$)37j;%3W?8s4fR~U&R1GFhr`=Q;`kfK#M+|{RTZ)+*S^ure@0EOu6C^qMSOSP&)--Up*o9V<(PzNA-b<; zAOO6iLHg>_ZKn()8%5%(wpe1a5>8rmMnHIFU!tLMjDxg7yXul&ue6mm`> zo25`h9M}lbta0u`K*<2S-w$fr1ukRIk24Xou{h?bV`vTzXs>+$t&o{BL4G7}V^o-# z)CvYuWv=Xz?%T&fTX6C=OVoH%7+k8ihtE-vLyX9|EDIj5%x$L zIe@kkG97(c{$H$Z5BdVK)=Rm@+3U-U8$++_1Ku2J7b9T&W~b^&a#ms5h4x&WhH*BM zskL-Y4xqS6M5+tb?>LyaPDT|$o8noA9zyxBRM*k63j6M7+i!S%v>h|)6KHBmR`}H= zM5i?kmG3!CJ5PV>oPjE&?GDVew?#Z?=G|U4IZQgA6=iS-(30S!Z1EC@O#v*;F^hMz z$@I-N+xwePegM~EXS^~`AJur$;d7XVpfcYp625XkxynVZzvi6u>q?n{tN8{0LANC`9;;kX?;BpHu+kzY;)z9U7*QrOo zpaU41@iwwQYH4X#euU}$HVD>ctbBH9le%1gi?5ILaGr3XO7n+j4m7(B=&Pt0b|E6M zknC9w@|{acaQ@NAUBB}CN$Y6>H$iHUPC;F~Pt!zE%liRyBQPtO5xBYNyNYevslCE( z%f{>a$`cjPygaIHPGa--$q=wU;hhUr)98WNHv+*hL#4w@5u@SDtQ+bJvR*)W*J`8t z?>p;fw)u}_?O)J!XwGnAJ)E6OUpXU5vSiQINBEx21qi!v5IJ=;b;GdNl)t^`s&H8i zh^z0~=0aoxc#V}~nAK;86OtCq$Y231(L{ZV-Mi9lv^v}us@2}ag#|^2N}99$QB(>M z9T6OS6s7x>k1X*-Jsxnia2TVG2^ByWprbw*Axwb~z&uO@WIM&;k_D zj$O_;sta%L*a(nOOgjVv52ob-Y_GwqD8>-rTkzrQhGgN!vLfwsnJLt_5V&_D*(Ka^ zyc2^y_-~*?WF){PgN51xtpA$`fvYmC5555rzI48f{Jg(>oVL6`Mv5;D&Ow|&qthQG;tWXv?iJuA-BENM5PGrHqxTVZZUuJzzy_uF7cICOqgi@C{mte&$OR}C@ zsnLZR73{ZSnq2FiuzjNlOj;x?la$joo;h26=zhPW;jLIHKO$SvBTuzAvC2<2W*h`rWW&Q*u+6`pKG?N z*tTV&W-Gr4Yr#;fn)JL#Dj^S}NGUfB3>{ra1T^xcty_;rAp&i35=Vc;w~fC}wRBA# z@?ZiE%4eB!qE2?nb@47#l-5ISBLlum*;jhX1R@79!QR7Vf~W{TB$4u+^ddsps*Q#< zYgZi8@`g#hz$Q5o^DLj1(@x;A?93vrm17 zqY4OyGfa>|#2+st(8zIqFLYi3GA8xX7xF}!n{3P1&nPLm{Q})(JvO@;b25Tl!4@^X z_pg->l6wI>pgB90kuWA1p08cYU%N*;x5~+W6ANaXp0&sc*_vLM2=_qQ5~Y}(1&9CQ zA3*(l5BgAHzPT*n)xr^6OEluO30_zX()N!}qF@XS@tN-;+>hh?kV#pd>NAbcG z1n;66X$y{p!1&&#GIiJ3fmMQ}KJ8lT!c(0pOkjyh0#Pdo*_u}g!3cy(#3xO?fl8=U zts$F=>QwAEZav!TaAi40D=vm0G*T1!NhQjW63)@!ViKUFvmlKUo5#JMeZp+?za0RF z&R$NK997bJa-x`rBzGk$8Z0uzGZ*I8MSmJJ2 zAR{iSroZCdJaA%T)DNM?Lm*N`rY|YwM#RhvTyRK`{RF4ophi6qY&_kd_AsKM;llB5 z7qXuQq2m2PX_GBIUCM$1)u8l56@jgT?@qVsg`*S2CUYB#OP)0p6-X_4YpE1I#)-Xw zv%of?fDS%!l&$aW#t0c-r94lW6a9dyyS8tghPq%{PYfz9hBh&n-@`A#Yz>^+t+kk| zTpF}up5zz-n|2++1xKr-&h9;&bN5WUg3K)Xeg!5D!09QIT&cW9g|jo}x|To>T5F2T z0S159pllG&O6VW8d^5#j(6MqVKsqk6Qs2uP&9XmI!y86?fo>bN#+m&grD|_qD&?t!b5A4jFQPBrj-# z+5rM@hKeh{agB62(Js^l<^}0#1b|o}aYmtkk`*)1*p(^T>Tu3#2S&XA>XS5LnOsxL zv_O#%jo3vIZFZ+JM`=#Z?>~qGArP8<)}*%L91c0CnxhtqVV= z2+TkS9w5qSCb7k93lAWG3@ze-YoA=c^E7vOi$>RLtNiXu3EpOcd{Kt6m{MtkOr(v* zgJ>j@JIG|Lm9~us-Zmj*;N`15kbG$BI&-2!+;`s zqILxQgbJ+_{Bx4ZS4!Gbi&5d{Mj2O5(74fx;osq1**~K^5&y`oZM5M zt|9T&5vvVAQp?JwrC@~zTWZk7ocaK26zyT&2F3RlgQ@>mBn~|Tl9T2z0E3?jKGSFfz1Mw<__gG@l zr|~*#>dd8O_a!nljEd6Yey=>;yARkQmqH2tiUScdb$*XOvvE`%Jj?#sw7!Xuq+8*z zyQE2$c=PE-xHqLnJC*N~{kOY>wXSFGwj#T)Qi52+3(0o7JDDwKP4 zpqVq&;@9KrR$cQ7-0+*-A!9ojp;X+0E3_f19$bTq1Iy~y_X1`GP}1}{>BgE~yL$cV z*%x1yEK6cgnIDO&-Nb5b!DZ>toj~p`WvVf_lYt`@(QJ0&R9`M?pXcDyvUF^zdc1_) z!i`Gb@Sog}uPHA&evcuz6K=RcPN>FqyPj`@zDCss(rRAPCk6m53jiWZ9`>(JuF+tC zmCWCNh?4JVwizFhlHYYz&bIHC&L^7-?{~5M+}$I)G?=^j9zw70wf(`^LL7w6IEVjL zcN;A^gwI&HNs>=@m#lu<{~BO-N=hO-_R}@Pp!C?16OlRwn~I~AAE)kT4DwD%t%Z9q z>B#-;1R}lYAR^igx^IS~Apt)bps*GNTOyng!iRFO>skN^5$9?^VpDzLOYh1H4G(^# z137*;$b?ByKI}EcUhcsIjNQ38Mfu-eVXy9Gbke9In#)CX#N`0mv~up0G928AC+Tr$ zUYv`4!0l{sBoi?Yfwf3dupWxW5Z^{1^z6jX*?>Zi3}Em3o5=wwIzn~)5*ZO~(dEMd zYdZhYvoCq)ZSGD$azgTA6jVJCu|)_m2Xo2>SJRJ6)TjNoM{4iBs+MI|=5HnRD&Bbx z;5^Y0cxbR>P$DF!HoInrTFVFZayW{`jjiE*Gd^I=p1KNFEfcHilCzhN70PXj(SddL zP!}*S1Jvp{CVZ=gQdNQ0SEEdQd#PDO>v`o|cJ_hK@T%-fEj~U^)QI{VB2Km3nd0%@ zHEv@nq)vsOv0VxT+L$+)W43W0vYAX-j-}$FbA-pk8y4zb3%2C;Ogb^M5|j=c_%FcT z6gPEIMRS{1^6ZS`G96h0MmBoZ^F3wnyj`O8xw5b33&Hg?(yXg{^3G{#zVv|kg%h_% zrfmAuE(Fi0tUKqfpS20y9vPn!_${j&I5>s7cEBUcq9zoKO|eVe-45Af4wjc>IhiU8 zNddW^z@ceDvuYQcz%!!V=ov|JCtn865OV zJgne>c5U{_vj^|U^qS!IWt8P=qa{r5qv1gM$kCt^%BH)M z%XPCt@8(a?aIiV_y*Z#o)8d=#d0c^@BfeAOFxr9UzqzKfJf^z*CvW9W)YtjLeww5`)0XTg~6HKxLOCS1kE=wifyO$el$=SH>lF z$Dz)dsG}8sW*-l3lG=wL=y0Qm>>$MUI&J0EY;#fPS4b8!`?VV{&;rl;0vqWxEkp_c zxEKMsC-o5GY`6w^NP})s1kpOe@WdC$h~paI&n)11vvca|z^Jp*h7YVSc)b#q@cWe@rtlH1m|7JTy?kj-0d5*%VdUAh7|J~ILwW^|_V zhL9h>I;s{#?q%X;tOm@YR6 zh(k}WsNQGfsg4-rXFU+z=;N~MF8hP{FRG~$Bx4>2Bka7pE-8>N9^$aIdU^ARHH`jS9S&^&cNz+ z*?kL7{w{7WX*Z^<9IGmGw#&@06~Fm3UVCh*Rv)}{FkJW~Z|P*$Vbx6m;cm>Lp|@3C zm@J0^y@iO1^vk=l-;q>y-MqpLCOcv8>jM;k;D?8wpuD|-@D;Q9T;K@eAz5%9wZMS~ z)~FWJpa&|g+&^RAZ?W8Hf7wh?Li_E&3aq6Hv!#5MBs4{QI+!A7j+tjeOcJ9L)|BVF z;Fi>=3s-!LBjNz?mh=PFG>hBnqoc9v8DSjgl?TuxtgxMDw^m@T4Ur~nBArzIQ67p@ zz>#}dXrhL!q9!V(6g#d*^2=~wIzli4zf>Uw+u&w5{gnux=Wb|0c7kD%93`d!y^W?~ zABXvgsFR|_(dyWkmdbzMLjyODZm^jlEPU5Gy`hdwKJDrKe#Ts93cJrfTHaCE)y<=SKqj$P6?@Q5MtqK5ZUU$}$sk*Cbdoxfu>Kz{lS=zqtT zCTho2IC5G^pCO;TtZnnmP+mAz4XM$Uh{mj|Lzd!pn{yxb_yp%h;kyk^J5&;%m#W%i zw$op^*iT(_ATea{dkaL^q0?yB(j8X>|!Ue(E z0=pl60T%hq3;fq>PdW3mA!gD`9qNBwZ=L!2)GORIcUJ(TmhN^>O`;b$i�_-Rx8 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

Yr82LPZNzN%T51NUI*fym10&{|qrh1WqsS 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

35wSKW_G<*hd6tL-D6(Zn()hnH$!p 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�Pd;U$EJT{8_z02-^E`?oUmH|5N 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%0DU19fPYC7&0;w>u%+fTV5CxSzUpy!|)?CnH)o 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

B$EPhG2r7awqV1zL1*mDSTK!|Z~^zVsLKnT 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±8 zNc(_(+kDM_3RYN>-LDcu(1z^kEVt8qh|ECk7`g-0*;Z$J_)w}y>$u6~@A#;GqK0Jv zv9MSye)QluvC-DlW))@i120vX|H8Mj&%wUvSn}WNEI&+>MY(BPr>Woe89;$&`J4um zym5N=*LUOvhs>;G8KrAf1=HQNlkimECL;aOklajaQ4AO9?mX7ZHd#sKs-E6gOe#J% zgGy(xZT34JoPdkmuEbnlw%|itAS_`p%7d`rr%ASr2}2SaP)MtIvvj!GkYfO@>=5~2 zSISxd#23>wa?gUS;DQ;zRJUv)JYYZkM?&Gj5&$TNtw;4^J$8BP|CO9 z3(H)4zoh<1NbJ24YuJw;N_pV?lu3dgb|N?A>%xI-u6+X|3;%(~p4Pz3?pM!~Jmh`$ ztGs`ok6zjTz4`dRces5Bn9@0_%1n9EZ17L)X)Q0C>K1oj`@UUd;j`=^HFmKb@Qk;A zYfS*;Mw7&Bz;C9IRs~L36+&SEN(vClBWpkqO^SlG=T| zd*^03LJrS&Dr%N6u{%M6HONvqqTXEtx0;2x{tW%xd0IRP&@C?W3- zjlTcWk0(pLzQ2-XZ?(As*W)VnWZn|cG2@FB1TnU!_ryDfUt>VDB$5DeBlzcX$CV1b zd&1~j>e7m|l`w1#n z`dvBg;DY5;B~hishu8A!!C{t}<#pZ8%+cZv_t54!h#aq4;f$F)(g{B$Xz$0WX$y4i zI@W_Yl*Kj+ka6zM7gaR479hpX_K;jhoaf0;bKkJv5~;|o@c73Pa2;C)08prSt*g1Q zl0GD_Es%gchoYfxq@4v00>ZRMCWdfl6)FxM9E9j2@hkPUm!vnyPN6~az;FI_A+&i6 zyfYw?a75!L2`1kZQ#dDxrEyso=T$uhDz)QB@pwx|_jv38L)KWw^Bh{=J zk+*RIhm@H*Eh-`@^qa9fb3AnSwBELbaC|h-qny&i^W~d#_wl`vKacMZYVT7m&b#ie zp1)_(5UTAj2Bt)g&i0aHKZ)<(EZPrYro7)wi5^LSTNne_-#5Qt{=KhWYfO}b{25JA z3*29TkTf>zc-9GRn}<$exNi3?3N+&sgs~mQw+%_~6ycv^e8Yc~Nt*UXF@gk6A)*LS z1;ExiAQ2A)->3pO_BvrFV3Pz~uTg{mazLv9>C0RRKtcgn`@0A(mqdO{#WI6WnD9(_ zwKQn+csVpJA8-r?6#1EH?`HX9uqt_XCC zNaBap@^A1VjAh{*zFg~-n@jn5epy34bePsTV2yDB=%3cxu8aJ8EJO%A<-^_y1s}Em zdPLU4M&Lvk?RydYZ944rkUm%PB2wfRiTy!nk1qpd65;lPpc&UcrfrtSVJCm@63C_b zH2twhzgIqD$C#15o0F*^$SmS{?08Fauxg%N{07Z?bhsbn4vQ22vm{>`{z4Zf^C9M$hVlcv>1qb}ibI&+gC;d3xdDV6hC9T1o zbsiV+i7nd>yIx#-xuaTUj9_kNWxP&;xa($B!V>2K<{>^07oqz=VkrW1Cw596>M1p$C-OvL|I zt_>GLfHi@R?;PbC(7M;!vvr07jB;+Y(4T=6uzWndygU)3)qex0?-px>U=sXdVu^gw zEtS)s=-6I442om$L+VH7I7IhDavAzG0mL3 ztrK693Gk>;0wBMdqwj~X2Pci!`bgqosK z*h`h#$_DvoElnS@?;dKINDS{U>k8t2$6vG_LX!J-C?dEc?_Js2qh}3f1(%07HVndy zWZ~V9c3-4|tDOl}DU9H2>~Im88~u;6pT* z>a_{P{4c4rTbH81(v(9mRocStZSJw|JB_;2xKM{~VF$IjMov0BJ|F z>OHjU9R40YoL64Q?XP+N6a%93Z-RI6d9&Y9*9&hgV=_L|-H#CtCHSB5QPMWkao0dF zQ;hYb;7~GvnWZ!wgKYa%O0th6mwuTn%BdsJ5~e>kl*G$w=eKmG#SJ(uUFvW@L(h-- z@!8Giz)|l^@RuW2S?(@#T&@fRU~vf4jpbVpOX!ZS0V6yX`$ucZc1yctt?S>Wt?y}k zG3X9xIIs)$jm03jfb%|vy*=Qoe!*idUK%i#8;U-CoQ|X zQ=j2uaCxfHEIQ!%b98sc5ipX)i&+~`kM%pS##p?*bJ4Q>#1#MBtCL4eo^=hpKK$mH zqMZl%7zfCh{rd86yySPr-}Ii6lxzj}#eMT%zsJ&lMR@!b@y?oD(i^-OV1~}R=gKSJA4Deb{fwbFb(g$FQ+zuUGreyg zU#{Btrt75eq{r8u`UshTw(L53oNX@Q{c_i3yRDpi>8~22Rh*d3iacZ;5*kR$>^j=} z`ojmos)Op0H=UDzBqZ?f$QS=zHr-;J_~$7uE{O0VtIh?zCH?rW2dMOB4V`hks9@`9 zeE!~>u1I@Q(3t&|u(tT{lS!p&`NQMyUAUrVfBbN#akfie)+*_?(VhpNx1Wo;EG?j( zLHYy>eXf6D$UmA_b*cCHVE9pt(ntUovU~4iyO%;vHYLORKiP#l`Cor7*oAICd$hH1 z^!o1_KOR2Cp?b`w&M)ib^MAM2Yw?J%*Jk9af`3{*D$i+D+)MeRCDL=@fp6%jCHd#? zenE|>a_PLi(cg3vFRO|BIU%F}vQBkh!*S^@UfZFa^*fjJZtNu4-}rgf+b=b9qo?As zKk|P;I!-oD9@c7i=C**X(XC$$gf}xd{tvty9>Ace)olA=M{>S`5xBNA3wip(B@^=q6>Q#czLYx<1)3di7q^!xC59ryZ5Ki}sI?A1sEnU_z$XUFa3>kKSBT z_CMxXcqL!Rj1L@jC$SP-%`W}=eEYQh-f}>fF3*=e{p)&DW-HZEv z*oG7JJbozXVt}M`=&$KTZ+#Qnbia!$O-kHWFHCc4y${_x;%u_Yr+m(Ov@*(*j zz6DqJ9ilje`gd?$jDY#&PbGSICOAH5OSPpm*48P_8y)iTbemQm@(nO}w?6qt133Mr zD0&HT=;-I37sX$nzesLg>TA7`NH$!(w~Dp1U1DfPlipm-Us&@86$Vi9Y&4z51;y$ zgYfHaZb#Ugk0ytc51;&xdiaEHGb#O_4K87Yc0%T&{O`1^deo(P6=g*Q}*VDCE*W}j5Q=wi-^o$Ce%33QNiCNowtXh}U*Ov5Q$|d{3K>@Oik-l{7(zU49n>U}0YY#0zP2C?`4J&RT|Wuj zL*EX$ZfkQgWz=RZ^x>=a;u~k>ZZu_vbhCG6E}7<-3OQUkcgsU8fbUXOA4}0IY&iG0 zVtkH&_e6x(_TOK;QQv9TJo)2kCZ8_47@b!=XeW~p!AppmF2~0y7t7o)P=BGY`SY0P zvBcF3Yp}-V$+P=ZGns=w{u^d5xQX65FPy{s^xb;I(g^;Xu0w@Lid?sHfXV z);aea6;b&!U2POF-{@u4%bK#N{fb+kQTpNfrO$;?+O&zaCl`5nG43*qkFp%S++DLr zLUxzHLULC3^gil2;*I!RQToT$X_GUl$15%I(LSqv6iMd=MFYUh>8;tzWt4cnE)((qdC%a-i|yf&j~;0mp^tj@vP&3)r`L z3&{V9zuVos?88lHeP(HA_6LKl6%*Hk2sJ>D8-e=%i~A@(=P$4c@}@GI+!>t`39wo{Gd&Nb9dEembR z`M$C)y5ziZ?2wypn7Bge8<@?Cb9`%W7GFqzPE$AGg=?hu8}zp=PDx64x#O&r#(k-q z@b5{pQLkL{&b)WCI=ghlTGfNnxR>FkmIrtoRyRbnc^*&~ig+m0?olV;6=o{0#%(Gu z)Y6T^6xH&Tv5lqF%wvsJOk)gN4UNU-UcX6ipSaHaQ{G+;y|%h?Ved%7{LMy6*HcTE zz?<(JlP{@@|6FIb$VfbyY^I#35Y!wm5=4txE(yvwmZCM^@+~%ga3HxwBaKz=K?T%q zLox1taGbpj0-*dfApg2EX&w1_`odj}k}};!%J%W*t?CbN#IF`Dyq?`M?tZ{=(wl@t z`Df`S@s&Epds9&u#lyRl$WcCFF6Xx1$ZOKK=@0bP)dC&wp6t4H;Y#-9-u~gl=U)a} zZ`_7Jeg!Cg?zcLpWHsNz$fKkzMs|r_p9@9zP`)danB2G zFDgI1x8*P36=SINS#Cv`CnrQ`Pp30%-kVi%oP4J(x6~MW61$Ib^-c);rF*M8?tZ9z z2+c0sclc!9^pI9QRfGJ;?YH?&(eRct6_KJnowxIzN7bp-o?E$fz|Z+b)a~@^DJ$0! zLk4d9rq_;tUuYZcXcV|j7Ou>5i!D?g=kaVD#AHJ~;#<{i(z10OTTAQQ#_2aG_g=gn z%c<4qYB5wC_ice6b=>S!vr%sMJnGqY!=+{UD#os2uH9Kxw$8mj+0jI;^On-(82iDE-s94qFW@b@dkDwD_O)2+MGhHk`7lg?cK z?e#$d;}|%Nd_LrYdam>&EBmIjh_GBeUO2=;zug5QSr$H+-)``uX^AJ(^WCXtN35J% zHd(F3I!5(wW0kwks;ZZKgS)Bi|CtDIMrOi_yopwFPRHg*rie~sad!FP-TNtQx0{^$)0 z_<9_2?GRWjj40)TZ^#nRs2D5YB$A{AjbVSv_nM($_&W)h`ovsg=xz-jgri8Jl9YM^ ziSN$C^C5fM&Ja*uR%gFU_)Ry1!N3Nc6|Cq-lrX}N{f&3pc88_>83;0%{#rao{nYwcOmBn1(Tg1t z9uHRP8StC}j1NdPi0$!TAW5~#Q5SjpyjKZxMP3T?q5;K?F?j-{1&A&u-i;i{KiPqE zT?h$<84HVOAav4P*1S7V=gLYMDc~O`$I;0{;oK~hN$>~=_oR_>sm?LzIGD*emG_W- zWEEP-CMf0_O%_;JOats-t6V?b+`7+l*KbI4c~mhT#L8Yq#ScmbqS!WZ84nN;DX#Be z?qc;7&_5uzR&+-&194uVS18}Z1b42<+rLdv*d*z>vK8-dOKY0Sl0llHAO;BC!dN>r zNEd{$_$LoOqIZs0%a$&8H&p@gKK$H-_p#^`!Yf3us)2Wg7Y|Y1kWpn{V6f_riaoV; zA4giC%0<_jKnhC2gZERlc?>b#kB)-B?GW}twU$02T$BY1spK5$&on@~962)pxwi!9 zy3im^sh#bDtAJ`pQIDwXTEPHm&zRRTexQ(p#+R~2tH2UH_zM9sfs7)G6f@PvR*@oT z6a8SKJ%2VRb7wT$!M<4GYW+t|GjO+xZ*Kzl#?5g63^eZl1!%m%|CQTGk>4RdPT#+P%w7X*z6_MFJ)sSx>|aUw3jr^%9><~g`p_9Op|U!YuV5Le zr-gR%0B{yyV*x34+$DMNcO^Z6Lm+;!5Vg5)0eCC^``kX3a$zyW`6``aDHaoB9SGGT z6l=Xr-`96Ggxg!giB;e<9U$->ga{A>lz>xF(3w=w91Xb1f@h%$1X6$;s6_y41V9(4 zqaZ8~j4w+fKp4DcEG4k{2%Z~+A%Gcrgv9oX*YJ=k)7(5UZ({EX1V5`ebH_l-kRxuAcB zfE7f_zA^Qb9%)}_MhZ0}i({5Zg8tM~tW4-hEHvh+=#?CxP6r89m-X&|$rbmVLc!tg zbA!BcAwdvUw44odqDeHqFP~+lRJJUrib^yvf7u}=v)SN|r`>(g5N&UQli*mHdH_w^ zvcCH8ONw+Pm;G+u=0c=vwcZvUUW&|ghGj> z04l33)$gFO;(NnJD-Y|A4tU%(0g6viYG0wq=nicCB$`Y$p`~=p)@#x#6L+=4{W25q zg-iia3jHmhX|R*Ylv}%xA{5A?zLv(PSwv~V)%B?)pFEw@X$q#PvDav>h3}czc$H}A zkxUd!6&1skYiac^q;>@cB1^?W#d1FYrVT#x{Yxi37qYJ+-{ZBH_*9d^3!%KQ`OR-D zBHOwP;&+#5g_E)@MZfpFFXeIRwyc}74mee=d6EcW^1?Op4Wv{FKU&}^IzpppAiDtG zuNE~jDzR%9_jYm`hlL+*^&TPF$eZ1YwRV4#Rs8o z@kqI((er>Sm-HBnIUmrE--t~^F=@wILDxb{QnMr~7#4sqo}lk!b?SDg56d`>XF;Ow z2;8zRZ|PD?=BfGC83Cpr%5An!7JT`N>(+Q9q-hxt%5Z)|UvGfn7id@bs>M|k)5L&0 z9&Z)$S@ory|3%SxM>UbXfB4R1l1vJaga82oBs4=0MMOlI&=JspD5xl*s9-@vRIE%w zFG@fZRMa4-xU!1auo8M%)Ywr`1D3^IzX*tmF2XOr{5?4*Cv)b`ec$_epU3)#IQPm_ zU;xpUwmQ+YwjYp(CLty>?#D@ahlErWDqn zIh52KioAGc?#E_hdOew;bF>h$eUg9m?AFqRUcqaN##1%wr^OH+}WQG@oh3~EpS9iS+@*N2?uTcL*iAo)>kgS@z_R~mdY~AuOxR$}l>31EQ{fdCu zd&z%s+G$S4vW5DZ*xnTup3e38Bkct*RL?loV?4@1FaBf8qSWHE1A8fNH}17!RJY8& z+Lme#N_I~zjOkm@)wbnec~HM!oGxk3f@ou}C3O*g&{jQSi<61k`b?mYUdHGCCc?8; zbk1&pU|9R$Np5Aup#w3;=kg0Ip(r(BlkJ@Vp%>qX;r^&>b<(CwNT7iM@8}cRW`XT0 zYH1+>41m_r=riT!OFf)dJPLj(}Sx!0?$czi+LmRH=4j~qk0xK~gMdM4=!edkyN}+Xy=u+z9exi0 zIfRb`bt@3Vzjkb%{(5|dI(%|cjhX0`zN?%|BAk38Dco+;+Q9P|+P)?wp8?DLLDifU z7)FN$ODSR>Y!-rPjM%>T5KEzJ3H3^W3130aKJJA|X2A`5G3&Nd>tSRKg7O^TEda?@ z%ttYlP$dD4eEb0qe-(_w?1p1#l06cnOG2LTCHxLNo}oBtt>HjpBTPjmq6)%?ZknJB zx02hdTVG9H(On##OlHrl0lab^zPcOwD|pX>D)33M@&!*3)ptll_n5}N%^66`=Lo@M>cLfssJLGcW?2M1({6@@bJ+RF&3WLNCUWoBF=qS@v!!Ysa1! zsmJ9zl)UYt-2H^37&y*S00nO=x$59vVXh0GSZBYz-N&}k%EAr^zy%Qv(2BeD+*@_( z^p7djplT3y(cePE*%E;^l%ll#q-#3Mg8iSJ%q>(`=MbOX=fqoDd>>^!(yQw%1Wxk9 z%f)8ggU&lIxetHjYvK1&s{xN)?(gJ2H~ru~aPJB*ShVt4N0cS}?u&swNwJl&ZKr8# zm}HTq{W6SJE^4HsL6=_4DO!)^J^E2?x__iaKUThQ5eD6W53QFUvy^S=!_)14trGSj z6{%t60)Xrpx@_JrCF|G)-Zf9a@9x_}3^AP=A()zafKE{iDUBnkKQK6ZL9T#wsZCpP zj*@XzRZsnI3Ff^w&JniEm~7UAHClxrS!nrxKVzQ*#qP=2@AMeGnUIyyyKqyQdqX)* zw(CMWq!a@WH|R8wM`wpD96v6evkwv%&dj~xp@S19E^>j20Gbkjf^IYRw|1_7hxTGF zW>p{10vtyDUES|H!L`?|==g%PyW-}$m>nEZ0yXI+J)0^1PO-zK41LGUaxKwA6z}eVZa5&n zS|($Oq|blO=P}B_X+to#Giw-0JG3Ow7;YuuOkR4b!9gI5-Ip z4kJVI3#!V6sfnWuGUs8~=D}R^b@_Z=a+mD=(P6t+@ddFDC8zwHHUFa{xkwSK+z*I; z{HlC#Q;hP`YF2bpsitGO3hmAIwxQk|ZN6kkx{k4RMbL@+;b-1ij|aJl!$;dUS1F45 z^E&M8`Kg}Sg*2R_sLa_&<}_qm^f-Cz@i-jz_0dff{ED7&jQvYy#%P^2Ud- z#en-w-&jVYbt7W~^uB-p=lPM+jgN+BJ*!};`Cj6pU4PRnyBPF{F3M>2?9Q4k-HxO8 zziSzwd2l7o5wqJD?{@IkXE1BQmapbM-~H(I^qjW!g6uzx4-NX{|Md}<>}wTkaeRqF z`%{*<1iZ9L8zyHk=7#0!wh%M2=&}%DrThm$C$ud=)=Rp;5FSsW{xF;>duA!9lGP{A zK6m0Ak@%5RYgGqYKou3&e8KIVggdRCjdU=HZ)@_??US zu{KXe$IQ1hZCfnBGo#7O`X2Ah&P?wshf_5c+j@R2Y@FkWGNOTf2vQ!F*2R>Zn9*ZT z1#WK5oUaA`edoO&1|MdZ>QQg(8ZzF8HehEH8I46?y&T-0O;H?T=WRh4R>~hN za03yz!@I&j5UL(Q*lZ+-2&Hc3Kp7%XhB)0(wihp@Bxx-MEh;v$%tFGfdjU)Rrtg%( zQRt`@FeJ(YFdH;o5AJP+dMU^R1@^>%1Ex;Pem3cij5-iv7Hd+hSe1`ODu5PVXDFvd z*TZ`fGb>MRT_{uD&U{Fy5~) zPu0YYC@h92`|Tl3L}y25A8@SM{oz$mq#wf?>yYfdlJ#KZQU^ZJiYgbgd$S^I3wEBS z#h&%u((?TCkQEmehAS|WPc77Nm!HFRKEg@X=@y@KpLFhqtlHx66SO07c{cyaw`Zf7 zpgReAZ(0NtZkEQCSNqMPkzv-wQ=*U`<~w~{X*m@3Nj*essH}3W+IwBv#U4+5jh;9w z#3RR{k9H(0j?QDS*uN(gR!ALOTB;KmH*dwE5Mq8ODX+2n0Rt_JUK`q>|8^by?DhtU zV@GYlWA5_ABKpd?ebIu`D$2L4M9FdDBn~B^F>$v1^OJDrUilIIKeF<8Bv>;#O}%XU z@r?c|cBrC#ulr&~g-e6OdMu<>>!G<=;8E+ZS6XOSV<_>@vJHTdDcV_mb1jUVzLf`x zdB;YCO z$GZ9zK!JjRk28&9Z&!CWAu~Jt{YTiqT{-<1^m{C7G}DPW?D*U1)g$ehtU7ZtSnr;7 zV9k`Z5oAFC5vlo&TaPk}kLG2rff_u1(m=IBlxxtFL;1nXN^>nADn?qe&38#3m&^XD|Im#wYC{jC0WJeH zNlU*hXXLQy`O9&b!jX<`3)Pn2%-Yi43Dhy9BH?ZBtkmO-A<`Ckc+Wj);)W7Wi zF%Bsfdr5_-8S97&{>Fj6e9fpXIVLK4D_?Nn!80=lOy& z3&At(0U66x;@1HW+4MpEJ_I zDP|C3l3Ubjl&y}|p2qZZeY5i&Bk1ojchhiy@^bchAwE8b< zi|#**Z^{A*DYB6S4uKbBup(M|;NCeBU2JEu{kkem;5npV(eIwMy;7Zn%Jw9kC#yRe z2y+H9zK9GDZ}AlCwB`=DxBkI^quodz;5@dPn)MNBP@89z(b>|qfb@;ZNT}K?&kTw( znU2Ko#F*RlCo=K|@ZKfj8bgxTsL8*W&e~HZPyCA3*F;f7s%W=8E*8mb<1NEZk-H*K z{3%%HrZ7AhV>w$he&uB`EMtG(xZAnecc!eQJV#O&fO9L;@XaDwgOjUd)0o9ApF<3- z7b}p42YdJQFGYh^m`uOYk-yZM{#P5^r*~){p1vWS9y0?In%37!co*jz)CeW^YPdkp z@%b96lJ=OlHbEK9p3^t8uBH07E{OYiF{X3IZuCol>f4wOsKR@_?<)oI(%HXAc3sUL z7CXb4YnD9G$2aj_W?KOB7ZteV7$O!AEW*m;c~~Eku}CwM0}b%79w}HA2F{?o8x7vh zofBGtq6nn}VR1xiq38kRz5z+p#_}|t8d6gSa0`S6LZSbWAWs>v3MQoz;Qlmbz%1lK zIF{Id5zSu+-8O_?p(+a8O84z_DcI0( zjLv1mk}`jqHf8@Cc>B*9+%ym@KGh+bGuk*CQJQRjI&64q^TU8v$(bzTT5JBu1bj&K zFRtS%X*nO{5vKau_F^}2ty#8hj&aKe(^mTh)Tk{ea(EagLmbPVRm){oTE>?J|F4)Q z?d5G69+N(6*LwoAAD>qe9-XpUv;POG4*jN-ESQS3@roMN-dAaw0wyn^mcn$VX;4e- zXP8(`H}jY6F#5bxmQ0ptY27_?r)_>kabRumHw|2fyt<$W$}pTs^hqa$TO_TM*P$-- zU!Wt-kS&D7CI7w0t*}SpRrSLXi?HUngjU1$V=rWOve&*}%6B}FZ>{9nez3^kbPBI% z{gN6Y`Qd{;BaxR%9`JoJgE!ew@%y43lY)hmns96P(efR`7yfd&19BT0{939VZ5t!C zh{6CnV)j}P!^`;6c6E3H68gp+n3rX~=i8?UrHZ=f{Jd2DY>9sG;g%)6HS33#_UVi9 zW$Fbm+mEnjQ>(`Sh9E+&z%&D7n~DlqsZQrj3erG-8zBr=>MuUUGcHE zcPG7#svt_Il;KGqYq$;RG(kQS@;TL+*MeRZ^lY1IhNgBH%=`>}=&J zCQhfScfE908X@+%P}2dB5rEC*X(rzK|J3x+h75V#6zEdRp?&n|7NNwDgX!2PM+`wT zLoyFqSctPsc)a+?_z#Y6=(@)L8Z;XMpJZL~sDlywE7uUG)xOsJ{=qUw!wS$Q9~~(N zdJ&(LAMu6po^K785%)3S3W}E-^)A94K8Z(eiSea7_x*RuPZ@uki?++BK0K7`}{ru+mWA@4Sc=^N6V6$hwOS zt&8b%4cXCc#WH(FOK#gA4R&rj6#?=2qJWkNG%EiHvi?t+1!{PyaU)pqNf zc1NalhgC%$LU?e~X3&w@E*Ua9Jg0MXPui=j{X=Yzt$qx})$a8d7(b=iLYJ-RX`28K zqTd>m% zWj3T62#;^_USA=VpFv>c$c%wCP(?E;td?7t|2IeY>&pf@@Pc^6U+=Un6z8jFvQs~v zSeSN^*&(WUJ*susUfpV(h;jsLW#o2vQ#VtY;g2mZ1?S|T%HbrgMifabWd{@cd&CJE zV&FThl_P%GFI1@oVCr$M+%Ew2^Znpu<|_p<8#M#&mX$q0g-4Lddrj8LwOo-%J3BRCtntr2jc;u6D1wZ7l$`LPq@kcJl>z zQf`)xKZ5NyqcBx1Jc(T&_yE6Ia4BUCk~%ox+__tCuy+Z*`W^Uhf9JlIc{bcv22XuC zwBnn^^2MXcPZ|ywP;OT}c2c!9qI5SxEtc` z&C_+u?Ygc@4y_sU$2y)CTo9ajx9Z_0=Q?{o+)<*8PUYEr-B7JIC zAXgAV-=#vZfVX&2P>I=aV`0Ov@V-XjOyT*^{B{P=e@AB9=ba_PvKH}|Fz)YD+5{|6Q;$jB zjPpV2n3kJ>+F|Y_wczoRlb%4_ur#9I3W>n%5ppG|$ANdhJDPagV`b!Tfoa&>j5UuKe57>8Qms znjZJk(dJi_p1b2GouXq3)S1gaubwa%9cwP(a~>3!E>kV`CDt}rTX7D$OqH-8CHDf1 z@ixEV<2%8m)tFghTjqS>^eZB8_!Y8t`o|0TWM<66I^RZ9!mE!f>03kvyxXc~87JrQ z)H>D`B& zC<2UR0&aK6HS*dwoy-uloxDxcOa<=Q&H7V zxcR?Lwycu4rpbB)Ave#Nh{>96aoo^KaSG8giZC zgYMn9U7GD=q4W{!LYA)EN-`x4zm{*5)Wb?OS0@=nZmr_J9QK3Em5&phrX~%iFUxxO zvFwg4&)2OBFhaIt1SC{PYI@ej4G^N)T2P|&dB@&KBJ+feky^IBxd(os zNJ^*k^^tK&<;H z!|!&{rDyO7l(1Y4+H2UMjDWQc3&MA`7ufUFv%^VYz8Rd@Zn>?(2mRP!`h4XCYq~@a zY1Ad_-OzOreVbFZBL_;n4+W){e9yqxj~Mf%(WJBwYxcw*_Sq2K^`r5C_s=GIZN1o4 zTJz3vSN!+m?CM6JFydO7t$YQP{=#~mI4|L5%vIOWEv)$CLt34K_6PYWr{?%{VO;O} z=)(&IP1(P+i$eCuNrHU_?ak&oMnGnbEuFT|n!ec8II~xoIej|wRuHm)Im$0lmW}bJ6qVB2XCYKyqQCU!I_uJ z%vGp@=Ol+mZT_?>;dwA1eOK%U2};jdHBSq=X07yB9yEOQ)Vs@8_w_s=*6L;J1Z53T{H~(+9g={S zT!(J|N)W&*-4(?B>n?=MSGrmkeGZbi^qX^x)~m+gJRb|GcC^Tl*J^C@DIH^8E@aqS zk*aC%$eh&Pm17xuv{v;)yN2L#nPlEwXjQmZI<3)Zaj@yacbFi2xDnmbuQhD{Ny}MH z-ef5@T3=w=bqb;I%soy$I~tli=gmQ158jcQ$v+_{^VM$HqU;w^W|Hn$J98Du_k+&J zBW`^$Fy9A%w8?Z>sIX#=Y&;yJsQmB@`K0cMlBlupE@_FhQcD{zD;&F5$tv6CapQr!Xy^P?m+jR_?{y~) zK8{`?`=4T8&qjrG$e+bl1c4)nnz{8c%9xKT=Up?$C6M|lqSl7`tI$*to`@>ghyq+p z2=eu3Fbt{uJ?0OSEvGB&KoE(KEaNpKl2SG4l?~{m52zL6Z#cl)8Q+a5@0&yZaY!vw zNroBi_&D$X%cUq}I1XlFc&LqE;)pwB)-+vat@ zN}xtN5Yn}w4*=R8ma#?qn)kSJ^YWCf^e5W;UiLc&YTbZ3Ht`d{uRAW>u~QpCa^-7_ zFS&_*i+=K{bH~tdX~~<4a+U(VsBJhmt=ujMiYsg{*T>nQtIA z=tged$&l)-JsL?9PqS8GuF9{8^WDNQ6v&9S*6ze9j734C4DDI-8_9^17 zJJA-y90;K`V|tSbz>@sq!#}P2hMEnxt<|x4XC@x_j4J-7|0LsrRCI2Un*BQKm*k9U zJzSz|G1ztQZ15HR6ym-U_r?r>6I;IYsR$xSei_9p{_1AteZW4o8w2t}>4lCn=WYK` z!$F_cf~!6r>lBH{kNffEy+?vsiJt_lFL{RC!bQ$c25l$X;!U{>X+GceRC!kGF|l8^ z%ndP&OtMI8xted`J5m_M@aI3{hdnaW-Y9`L35&aUP#NX>yQ0MWOhR$^sFxr6YZSyWnc zd*ILZ0w%nmO89-!zl_I_6s)6)KX!*p-M>TTWnqVaiVs*U{DhUF0g>0Aroq`FID@4t zCc(8@aE3WZL)9>>I0n)Tpj`}1b38QxA3LT(153cHi+aZ8X<58DzQQFlo363JFKj?D zXZRzTU~LFboB^v&>o6Eeq&h>SX^lC^!ySxCNH)})hi_Qp18hi>Ls?6M)TO#zti#k3 z&;vxdobmr3OH}Di=%+x#f-C3AioaH8Gr zo4d|<&pk1kW*Yq@{$yqhVT;mZltM3>BR76h^GUG*1N#`dv3CbRDSaq#VE8$#^ASJr zh5V_BW~Cm=D48!u-pBykYZg$0y_LH&bee4VshuWGw4ePZRKea$!71kaG2!DIa_8!y z{fe-gkN;G2B#+$L2W(5OXCw2``&@oxB5~adDQkh?dYnByiLmEmT5Nh2vhh8XCwfqj z>NTMVQBv%sUeuvI**f8(K)TV8R8l8IpVydtsYa6Z6pIV(Cz6YM)@A_)CxA5H$NUDE zW8PZlfNt+{$IR|~DyWkCE`q(RlJgURWnb+BvsPK9KQW8UUvSV``*26a_rTb`JdZv< zGq&+?sB#m^r7=*VK=UZQnXIE6hDh#F~*Ect{MoxsDa2Mu;VZ3~zcUpE)w7iCZhuACZfN z_-kPM+l|}a!Fa?}Nkb74kDiQ$pcJdNOe(B6npy_&basXQB>W?!ge|E{*|NQrVpNhK z-OOJ5#y{v!D}=#Ely53P`XEb9wZ^j*TC!Q#6Ba&>q%H=p4WSWp{JkR-6NJZ8hW$Zp zL({4tp3$AzISor%nsEp_3Tj0_mIdIp5CyL%EMG z1=rgcIJ3E?Q9sp1ow;-WD39*>i#kzr)-Bi0EVvkNn|E&(xpv(`ZI^?g`M#4w)xpAl zVOB}tUWI}7=>D`8Efi;G$GDWtK?%<#vb|5l3@q8~HvVPx8yhc0Wc`)=kC;w>_Wg5) zyL2z{bYN}woV@|K^{lz9J<+vYKVn;XN3E2fRZF*2Pj=iZT%|qQuy%PvQ&+J0kTgc4 z@}t8(xs@5*qcOwA2TM~sR&s7|m+bKL?_1&!JdOz|^1_!;SC=1zK2~q7 zHk?w_nK)jkog2Jx)TwfD-^XmxUa!Al3HHw^!%m2svDKOb%jvYgg>9boY6umvBld}UF$cPd1ui3b+Q3SEi{M@asdbqNf?)J1q3i>6oBz1 zUhD*km4s^~;FdFU{qz07zUoW_Qm<~ENdXvb`Y#fQQA~c(|8tk8&`E8-^ zH1|IoMU_dz;U)J>py(4z0vS9$52T2|EmX`70;}d#lmJmbl3_N8po_p81E}8viV49N zq5rrf@M7bQh?VsLeh6ZTW%0Cm+RO$AsgR*hj*NKO63-(;9UPns$6y-NIL`(Lr|EJ_ zlA_t62p1NE4|#@o2;zal8f&T>Pw6kg$J1Wsz?85Q)7=(0&QJ~@d$t(C0}Alk2VaET zWFs27ymEu`n>P|kb1ES%X zC$2B#8RPQ@UJ)cc-5j)h{_;VkmZd9n>-c0rX7IeKz(EaN-Zq675N6J_IHWf zBE!A{iv zF2!+kbPt&wwLD43I%{r(4t=n7U0E~xP0vVbE8%R5{dnPpa-`lc*#iAzGErooRpUQ7 zW%UFpG=zoSn7;TYVxw~G#|jinSu~p05bf?q>h!#w4qk?XJvf&10V{YBq98P1@rk{^ z3Yt38>AMfjG7oGcG^C+*f0Y1B!ofJ1lR|$!RR1s%W!?!EXY;&E$7NjP|tYk{jVUZ%(f+9Uj@EYcDgTh#AayOdnB;fVw3gK4<5JM zO2oSbLqOF zR8#wA1|)Dya9iej61doqqMp$rp$j=~H{#IC$F}DDT%p=;Wr4GJFDbZv2rv*r{uFs3 zSdCz_QMK9+yyrko=J>cP+|LZfAIX7Ckqgz`tcBuKJG8@Cr> zvlbqm$sIEwKoAwbLRV>NQs!*jk*+ZF#f^op(in_lz~zfu-&^p6Bw+>6hM>LYdY+;j z9?Vjn+885rA2VcULclLN8`M6wrZc#3X>dik&yA}sO|wTe>;-u-_n*>-%h{D=d}!uS zdG2<s(m^9#Eb6_>?Axb=RAkthgRbd-I&z~V(qsFJNF9P9gOCLZ?pz125mo2r`UUR@?fwJQCsqs^P z-#|Of)@#q)@h$t-T~#MCt|{a0AwPRKb&!9y?R7ouYM5>QIA61e$UWxs@}sfK{9K7e z6{N}Mxv$Emaoi4|<0k4wHL#*iw}s z1M;&$s&r?RoL$bV4im2VZNB+5PCEabrNqpA@zDB~7~YP(!H2TvzJeEiBT)S;{*qgu zr)Sy!bLw{T(MIVrmqY%pMj#ZHhh-QK+5g;&oi^XI{mS_JWT{1#VSSrxy5D3IK|DIb z>7je>Z~{C=P$mr=+NpP=CzT-c)o`#qSboEyq4eRru0_uC>b1k>gJ<$b{GX4BGnB#1 zmk>4&DPGu@as*=Ji*8E|m&IS~lwj=bWrz&}#)&vs^ELCiYPgMpch9Kb%^2H(dd5tJ z7Ia~9vCGWGvNid;4c3%hGCPC(9N1fl1uB2-$>$jb<{jMx3jj21j&+IfQvkYC3K&n1 zQ}X9i6l_>+4sk6MIxw~jRvtTyGOQ>{nnr0`cOmEi0Ivmy1siV$u?>!(9E;4480Hyo z&QSaXJ}{LA@NEl61PO%3a>1Uf`IsJjczF)=*^EzOcL;X{l+t0j9xp2Vr7<3qgazKu*kB&0v@&e&M}+!&Fw-1vdqvTyx`l zK`jE8_M7njK#FhDkqPBde-tH)26PXIel&_gRqZ6t zINi=Xp5g$Z&xBL8*Erzxq)>Wb2-p-R%(FHT)dtOrHoT3#|MW@qb_iihO6Vs8Dr12o zp5Xh&-Nl2QIQJgRZMk^p)6oCozP5`d?Q6mlZ+Dqm1KG{fww5dqmW%h^3sAN;_kz>)`5+Ci7F%?gW=qC}wpkl>F zV_1hYLc7@w504sr`K~q_Tf|Zl{x_Ph8*}zdWrT3zOr%MO5V?e~=5h4@7PA}HwDA7x zSZ&#MOue|Sa@1(M;h+(qk{H*y=4Kw2KKf_MX%TZK6T7;2xX3qayV~nX zfZf3Asj}Ary+N;(Fh(j`ZEtR?Wtyf{rqZ&gr`}D&bQ3q6raTVt>pfdz`hB8mIlv#? zDp^i4n0>}acg9IJGoo%@HJbT*>TD)Vw>?hWv&6WblRhDn9`oNf(49k+b!ZZkSvMD5%a=o&V^Jmu#SIx7YVHZx#;j=sMney$%1bB;0_5G zOc9hk>fwW@NV+dDrz@=pDhPUps&onW9of7t!g8*Rk07m^H4pS_gD)>N=Gir>ZM!wE zI#(>>;r~{5FS|3e-vY_*^w=!lofW$j9Uj4r*L>o;$2osWNVWHvcXU@==C}pdA)E4W zGK{nn6*l~1tBfu=K!`f19ND@`64M4u<$;VavkM8l6l=y3?knq}j~q2i+|T+a+2R1f-l+od5}+kLun9_*-|80z2qvOW-7pRH9#$bAn(!XusY zoT4PJQ%|#gxU+mBPDCeOs_s{OqSe^Xd-S7ZU35Q1d}v*Kf_koUr}?`VGW7-j zSmpR|Qo(kY3Bom8$bZ ztuP0+6Bdli3lY_jnFg-D1I4K`H&mr-3E*^7T@0PFtEEne=n=uT>@(&;{mzqq!J|MP z!NhWBf>(W6hT%J>F7iII=s0KeErA4X0`)E?wgY%{PE!>0io6pKH)$(!YOUP*QiHa{ z5Wm%77I-S6(u3GMycWerJ|9KUymJ^X@dFnriakIP$HYxh1)@Y!_rd~Kikga~SAd+^ z@0!abC-1iu9Eesk7=(5fZV3m)gE0o~uF)9M8Mi}4wsh<`DZGpZ4Y}ZU zr!8=ut>#!F2{(ic@}aUKaK#lkWIXH!qM_nN%iD%dqM%WB!dp+=boLcTqLq7lcig~v z8WJfsBB6!Q#VEL3g5`yRk>Rw^ue9ZzzPSYa+>R%<)t%k6f<;MrXZH%iw{ZP@mvQo1 z*1(kOr#7UnN_{amZ;(ng(AXWw2K5M-}4tO7te~>OsIt!qxtteM5Iis#A%CMc3*Lcaq!aIk@O{ zq~f2}e)VS4yruJmfe4|Mtg>m`LOyHR)lI0LO9rgZTPk8?$SRnrZTu*Tjdf>nubM*= zDeW!cdELP=$__PKx_en1-Smdrv(_*1G%ACHmvf~<0)cq0Y= zZX>MBH7^K<(Q}YWQuxfmq5|+4+jIl~UfdV9TWNwV-&YCNFwUk;(noXk#H&z)u{ z9y(E5&p05KIg2}DRayX(k5c?bOFV(Pvw1czu9d{zwf4;k!|mp&`@hLQAb~qQUbd}w zcAVgwT>HZ+l4-42L>%h+#(OBSDQu8wRb|mzaiT}o>O6y&0m~flW7SQx$~m1v9aQVK z8(n>O1pyqG+-=Qc!K%?K32sjw=dHwYL&1`Uuk!)s32|3X-P-bVG2-LcI(!ob`ogKr zwCRh`%*A3!_wT>-02%ZRVa285h z0vIhb2b`yF5j9`O<0cnVr7f1Z9Ls|yK^xul)d&1RzNI*ySp*9LKzTlzMAGH)HP#&x z1Q&w722_1N1XziH0Xl33ftC=A0$FmQ0jA0Vk_TZ@7UttIxYVaodqCn!s4@)kfRs!85Y6rb;S34hBLnc-o8=*xCJ|Q*7NHmf zdE|hoZGM^=yA4VxuVGKGVNz(3tb{kYL?2Fv+F!An=E<6F`NHdMYMBgpR}6Axo5l*r zQ)&^8pQ0NoxVm@twLE{+ZrRVT&{E)m1p=sU-#8Jh@SLBz1m;PqzA6-ps>Bo4m{|*Y zN?eb|rRWl#qgSX}eYYwPmFFceW1Eyca*1{)KW~wB zrC;ihIrK#*saqis!Tj#yE)neVHPRpT8YDQ#7DXC3R4(`1^pQIMyb0Xe(9VcSZQHwX zUEu;`Lu0bT;O#7QGjx*Ce}%4v^>j&Yfcg{TI}2*aaHqsYlRSp#RyJ#oE?pLv52} z_`q769?`Iu2P;DFA!m}vRWCc^k(PD5`u-n2bC0oD12;Ubai$vyuBmREKjWYNB*U%$ z#uZZhw3lvFpTZ1>;OlwM9NND~H(X@>jGgl|gacNE&(Y>SnBsOU8Wzi8UP}y|Np+60 z1Nj8J5vaBCHvsDhOaU{0b2>{dm;Bo~^ zwV8r*U;zah;Nz@fP=U(#n1d*mB1u=V1Ywtfo}qVG>rNu&;b3R+4mHI^xsl;PCm_|w z=$`@MunadQFb+P-%GACDYc!pQ)wj(VIs{Gn_qO9QOF|&#rGXec<~3ZQ3k;+ z*c!3aggTLl6T>)aY1Hh$m0~N+WxAnKJH}pHr1EUS%{0XCYVlWF`sAeYI*bm}`n!ow zpEWRq+M0*R3Wso`?fa$m*9S5{R@^QCwD?CA+Af>(!uxO4*$ce>$fK|bKBlRh#n$Y4 ziSME<>BF^IhF0L{Y9EHS{Oyv72#WUXcLu{-R%o{@VNe*4fORU>o6#Q|Nn2fN6vX|k z)}7NOU6*mLUTceQ^>?}J9aZf)?FR6<3H_&)-IF~xi8P1*a&TqP=Sz5=BV8-$ow4x_ z6&vcZcNYcRwqA6LaQe~4?KE7OlLDw8iUKOCQATBXoT(B@Q0;0of%5;B6!^QxSlrZV3FG0hqk30fC~)?sp!4l- zB<>-cKWlAU*yT}d&aTB}HnsBFRtM|4oQW9YYPHn|s^StSS8x5$Kft>`*sslq1wGi8 zLH-+$6M{#$4dLfx=nCYtqVOsbwYE4cRajl2H!<3jcMSFJ-?DpPh2{vagjqlhHsAdt zx+!?DXM{7j>8mjLso63tG1TUQGVQ}CIHa;19NzP*@E^3`eVrZH0G$7T)vslr6m4SR zi@|5zseLkkM-MfsZ_=dCvM6ofuu1r5SwfQ^AQE&JQj0}oPk!=Fw37@&CW~&dy-QI`%O$7!qUO8T%R|5+#kT zkTgWm<_=>QBMOnmQfa4DD%IH6La9{BSdx}cp^XwhzwaO4bH4Zg_qk{0oVj=2@7MGB zc=S?0#=KFo45HDFs-hj(WJ0fCtV251>*8^Gz`A61Su$omn#L4Ztaac3XMq{ii)715 zW3f)AaSb>GRp2|lC(!krk06M^sJh`$p6UHj{4kGBj$|FkIfR7O!1Wi)8BKtK6>5N) zTp-sR>i2<5a{#q+z=7nX(2iwF$p|%8sKGl4T$UHGr2;5)k^#*MUMd8m zVy9lQOyuklM`UG9)K~li)=NBAptW&qJp+8uxIw~vJs1$HfuM6KD!Yng=aslrXR^oq zh(AtORa6kI=lnxR)SVNmF!`ORslk)N4E_a~>`Oy}n$4xVRK|^Jl&l%f^SXf2Ar&^# zM^+_tlIi8B*!S02v7JUUR%8pMHL>_P-tS&$8uHX0``p`OFfLdgbt;1&4*z5|2`fIa zB;UG@NL>Gr_{B|zDRq8$#4+caZHLO7-=;LPmY@@uvTZK012?kpZRj9I99u-Yf z?9@Ptkt)N{!vzz}PHs;$&w1)rFTg@xn=jkMTF@AcXqlD0!Wkys%g`9My_B^qlk{;M zca1=nze7@RB+j>+G-`i@O`KQ^Yg6QWRX&G&PcIE)B+riNvh4914>f+z1nc0#lxaj&i%sR(?YS_>jf0j--bgi7JXG3@nr3AAm4c#vP|Y!JGtc= zM+YPB_rrqst?40DEBwcm8{UlEGbm6gJ#Ooc?-^p z4hbORMn`W`z>$ye)5*39K)UtemR!|TZ znPvhFs$age?6wLC<$xA=%C|zAg|zPknLEdvP*~Ddp*>bZ(*#AO#Z{t&T;TG!akj{C zhvPY}ghy>wIuL~$s{*2B$9XtxI!=I<45Dv*i1L98oo`m@HDLal|?Z*TZM;d4rjNr|54i4y-l?vrRtrW-bS6LaM4`b+Rzu5nq}Z z_Cm8Sc6W;c{&EfVM)0b*AComMDhP7gnN*(R4hD;#=Qv4%1Rks2_&kBqi)%~)m>K`X zgdde^&clFv7k75ApY?%GR=cW*y1sqlh@l@Aq%l_%0%4=67`K{9?Xlw)&BV}1+m-2F z*;P0p0T<~%Lz9h~{J zGv^HR5c3)*V|a5Xrdl3^LZS27tSITOaKmgs@74GKQKFbd5ja26L@FHRL}z3};m8LA z7W;Q(#^G_k_&(HfI*r7;_KmwV3VmK3%F2bWe* z8liBl@tki|7Xuh?Gc&AZUav9h_&36v-fwJ_)8W@!zzS4%6yqJ)x}3&TgG)n2I>^-WQp@pn&D3a?0Jg@-g?k4Z~U= z-=_@=1}y$1Go-dSwB&J$;Cs5AExHd+X#sgMI^u5}H@EtqnCEBJ*W+cgwgFg~#+2ga z+}L?9032I*fTe!}R7}%P!E_)BAO@6oJ}CvXSHvt)u@T#Z#TY6XY87A}--g9Y9A*i( z2^)2T>XE&mqvslnt7>%$QCo7OF2SukdZsbkB0s#hN#DI#FLc*%hL3s$f2)E1F_EJk zPLN}4ue2g}+Rt_2Dn=6yr{5$82RP5`d@@Yz;7^!9zf)ZEYA!jdII3TCcP@~{Paz2NfBAEp ztp?Liunsrq-ac2LfDm|_Wk#eU!w?l=`YFY@Q6Q@?2}>1~guEaK%s;Y79_QI=nYB}+ z-92O0&ePz|K2E34u`$HMm3%A3ikg}+Cs926C|0h>L(Z6H#Y6Ph?c;S28ior@2RpsS z2rmZX)9(ajKDL)mLB1Y1!LU){f(t6p7#2+v1SdIJCn?Cf{3TLz)bMGtr)Bk~(%(BO zts>0<_U2QxWlSS?l{+a!$bxOwlFW9A0u8PV0|h+x?%d2jXE-m-WvXF69p6(v&z6HR zZ4Nj3w6wHa&1ri%ta z7=pf6)LmhPUVg4ZOQslulnTCYxHF89smW4_cCb3^i3)NBcb5NKNs2gsJ+UH5c6>wD zqLEG?_WlLqOCK;(6#?9(-q7;8>nRHS=OLbda07ZXW2#gO6}c3NajNH66VDy|3KjIr zXZ}-d$$?v25`~URc#Lx!dKa!g|EL&g^Goq6hs^~ZL+9{V7Cu83{^MADwGSm9Sra<% z4(IGLtxwaGF?QT~V`%*4t++XGo8@eK?*eE_hI%3vTSggXLUP%MCRH6!Ehi&!J7lf?|2kzwg8`OBt!&zF%x zE$U;X^LtdPVtj9$+0%U7ZwqpL<^Q>ub+1kSv$L8D`Oba-UKj4?GzFNt%GCME1#B_B zbo;hy#MzLyZ&gAI5x!Bq=(;GCN59xy@+@Pqe<N%E*8JaqryPbMgnhF3J>X*G@Z;PfJUik1Z}a ze1oFV&2JH5<};Dr`CYwlFIaT0wXSOHJ9It!T_*R0ALf~Mi@P$*nS%w5qXhOkflUh$ z#}0h`V6N#0>BAu35b=uV9PwHtp?`4*n*TFgUpaQt;PL6LgP7n8(~n-*d^;GNIW_*d zjgt~F-t2ob135eSdHSLI+iiCW_4VXwsM)J;FGrgrw2HKIF3@&1hRz;jm-}ce;sl9Ta>uUp~qg7 z&bOQmQyy_H#&kH+58LV&r8r;l*nQn>M_GzHx(9g_GDIM^r-b`XoLzJuaeq}rtumas zb1k^U(8WR8(#rge<@1~Gm=@nnm$&>$N%P#9q(A3$S><(oiu$*2DiStHcOx6(BDXum zNjPPU#481!w@F}j|7c#l(tVFwJD=9`J+X`&WvTIL&OJdAeWb9k>$&;P)l7wd_SIFN z)jwTl46>qKr48&)xU)XQ%jCG9)J=~6@v7|6Pm9m@_WO|aQLzEv2~PE_18#SXvT^4h z$eZ7CP=4?;<6kGQ`QsT=bo*Cgozwwr;nqVhcDvg;Z}3YA&|%o!d>ONeRoMA&SIF!y z^-YQ~KPtJ$es!CgzYFQuc)#%uF?U;;HRs2tR3A!4QD)hYx^|v+_K$)74(8ML z_H+lE9rN5e;lAg+*VX^M8L|;8Fp>6iysi7JDqK5e6Jn2nBjD#|{Jym;;J{dZRhuHs zP(LMMqW7&s^BdhN#Nn;7p^;H1llGcRM-sOT8h+HgmRP*!ksQ47)@tzSZEi;h|IEj} z9^Lz*l<1uJ#HZ~}`sBw)_7mM-?9TYU-o52mwcIi9?dBUk{;?P^ZgmC6-qn6l=`L?b zzKv_@{R4NQ%i}T*>>t{kn+NK@?e_A^X-*F;`?2p;#&sHDFoFC>=QjP1$(}zi$F?e# zrujQAj~sTnIsZEJK-;sJ3lcWJVLcQYi~G8+DOcVaXJKG)gxc08m>?c5D!F^*06*`N zrKO%ispjk*NWNdTGe57wFn^EL-~#$}oP6^pTVnQ-^ZhX`6GYUU%D(TXI<J-d zJ9@XE-e7(ctM+bkv`4rTTy2lG#S2oF)IT{UUvc;*A3YlF~XBgLmnIG}7 z3mXNDG~C>5&`rCZ^kkoM?8e{KPeqx@x({vc-&XGL8(%vm z@%qiXGTSzjkfvi+CiSO_Pq5*xrPPSc8K2z_?X|=`je%=_`~0em-~X~W?Ga@|;Kzuf z|1@>IVv_{TN3R9_dhVcc>UZ?U^SKW{X6_y}PNSFPH6 za{Zqxffb_o;$Vd!Q19MipwVT1b;V!g-FlDTy-&u$@jX+7OTY2cZ59pvS8xMgObh~_ z#eRCR`Sq}|4(*l4e7Z_7&H+9~i!db)BnV;`zDa)aeYY09h1 zKjjXlgf#97d%7vi=I!#~H{rU8FAhXQng_;1Zhc5=*?@J8Z)orTMe%m7=zgQocP8{i z+?Ddz)ROEg+bAza&sMXSUhGyu zO-QINjez!psaLi8qud`qy2Slub9`T4(EicAYu2~K)t0NfN`K$mj`JO4entE(u~ET5|R!0WYMeR|SaPp1}v}jBBd(*2hs*`Kz=O{a zBUXFN$EkAmrk{M-$+gu0^5eSBQmuFQ{q25z`{U`Dfj=5Frtu7To;>$;>)zhGrWilN zC5IYn;sYngNupvkb?T+ws4< zDl-1H7UZI z!q%6Hcon?wxkloX{dQFf&ifb_w3W3eMkFnX2y4m>ry8rD3j@gqB;v1LTuh79*kfv| zWWIl4jx%R{j9rywr(Yd&R$-{`p~3}IOo!tBmhtz_i~aUz>i5z=H~K^(?%aOWHD{-* zxo!L9o_NwZ zv)Iy5{a<%-A`2&9#u?Ah(Wt#;XAS&v+t^P(Xms}d*Eoc^rLkd?vftDFV-7+#xoyW6 z<4FHL$*A#(E55eKV(G~YD31^%k6$&`3zIWi?1>UX<; zxhZYPz4P_#p@Ha2k%X2H0jPrI_cM|-Oo1MgOVnKKixT8-8s2cP+_vpO@=bn@gX|*PEd6hc_i|_@n;A={#!lz}iEH8(*qIBK{akEHALsJGQy{OSAct zq>N9w4evjraWit$A7lds`4y2lrMkG=(OF{{tR+R#F?C|c9=W97X7kc}5NjFV57!w@ zL~DPX@N>l$NEdjzeY<#nb6!zyvcOPczt?&@ct_;eH)8XdC*ebEX@NxO&n?`QVDZw)xDM?0bWajy^NRYhF0lQvna>B0gT=t)U{m2Un5RM2}xTJ8Nm1 zH68Hkew-?v#yVH<^fFFT6l;}PtZCf$LUVL6Z{od~Am%^scl(0xWt>W=_n0Qpq<^HH zs0=HUy3v?W3%}{O%JI0Xxqb9|TPX3q74zHe#e=tCVTp!1BE5GlDfVk|?&6atW!ZvY zUin#w`1Q88(FEfA>p*SQ!c(zt9tFG|_!Tg0#EuSK-OK#g-1(?@-$9wGRlBpueTV-z zA9t)i*%uppV4Eh*A@|Oe=Se8jn#i+mxY}fWSG!wZo;$0Z2LE@1BiwDtQU8*jQZ$R- zCZ_g614QZ#4u`eY$V_G)Xj8eBaXw<#-OW(CQ|7FrB&q|U*-em{Ll`f(ONV#& za^DjI!`N@NH$b7G&@-j_m-R|*tW>OdA9XOo7F3GwXENU-B{Lz;f;k+dVf^GTFY~I( z@k+R&VfN>#jr>n5%JxI1kp~_3xakEJ5?_0hg4)jUPv?cqrJQE;A(F`Z5g z9Yg8gB9x2ilNu&T;$n{3PQTNaIZ>tqhS+@XP+lPc(TglkMOV$2f5{~FN#sMta4@H+$jAV)s=84^h+nh=esA#i7v!gVT>-52m zE;~gxKbj44x=3e7?3exONXkY~cT~3q{bXbOS1QhXXShY7f@F;r)~u?1HCj5H2tW@$ z!Z&zojfsaa65s2r>i1Jdx}O%=svLQ&d#DV?=0}9pSAl&2ISV^0*Qnf_CXi`ISnPLr z(6x5JMJPRd_KgP9cO}jE=UO!&^qRc*oK58m%Sme4!>&0*W3!B@Pa10Q+(CgqAl}iDDO>;7H^ThF<_W zz}P|fi$0v?u$~1Mr9v$@urdoAvUJd315i*qcqkLDa)e@$V4OH$;0Al@2+9=M_IQyV zB1HztkO#kNxK#%tnP%RAYZFeCg`NCw#prdk^k-u({~E?je9ld}5wGT;cdGa?=>Ou-fTV&?fbY zcTscFmM%aB>U#}DW`47YJ-yUq@;V6 zRKGC`z)FIZo049Qo}d16>>w%0Io0ayNC5q0x>yscr1C0VQR7+uH!%}__TzbXHdofs zA+0B;-0_g;773b?NqTIPG1ZmtcQh+`|9un>w7Ya9no7Wu?vdcb`G*Tm=Td%W{}fTY zye?lhwvg%Ie8r2O>)qcmt;{f+WuA8XMc$ol z?M~l)t~P-BqvXG(w7i0A)0Ja-LFtO1Tg2fRtvwnD_uX;PIYj^&FNXguyd>OrU?jat z<5*#I=hj?_53A+<-hvzNCdo{~$Uw0q<`}{iI2~WL zXWKFVU~oDb)6Aw5m0R|-#$wVKVkoEdhJ-#qjAaA4>HU5&jQ1m%uAiu32{iTf)L92 zH9mIbDkup2^K$RvngkG(I;kSg7bExq5O zHah&s3oW3NH?T}l!jgO_odr=fEl!(7pCEOT0C$ux;j(CfY_B|Q2uI_xcIcQkF&r{; zH<=2)3_C{~b;hUn%rTV;AJNeRu}4&y3Qy1ne4~Mm`sv(IT_EpQ!Z z+~Y~$ypXnJN9H^BXE$}x9`&gx3?;CQVXdFH9Cuu5H^QI59IuZ+=BeghQEWQX)@Q^y zU$D|Wc7lYl>vfBJ6@BEifH6#ul~u zi!1+O>ywNrWM~*)yvvy3*3SO7b8|hAvmW6a3PY&YJEhvedrtUl5DSwdh*ceSDk$B| z?(m8aw=&9(5sHD>Hont-SA3;SEfDG$o}%(TTtjOZljo;(Sd%-ssCmDMSKD}RJh+oP zH8*4=m|he!TTw;4jljzd%juY+MRue%bZ)1gDN$^;ckQJN9QkGEEo1xdm|qjVAJuox zomBlBC2sheo#e_5a0_W)ZYadP`UjG z@JBoRLL4!}1k?z_NC=x_`%MV+&tJ2;aXvLK7zhGq*#vl!9y< z_H@pptOF-Zhyc)@_7Jsyt4CVIdY)?PkwnAJgM8%r`74nLs4C2m^YIQ%>4l${NU6P0 z!Jvg3r4s2f)$%@I`g+#gi22TpJs$gcMT*dXk@gGv*0U@i7`14VP7XNC7uLW<_ppq}CdS#=tlU{+aVct&4@~fk_7N8=^PP)T(m1S`g{TFx zJt0p)`+JW?HWN90G9Z1x^anxfsf#5ik4qlu-Y;;suzXOFLJ1_@IFZA<-;3P(UTMy& zogC`t0E0u1kUl*mN@9aK@^EU+IY0HzBZC=1i9q>BnTG5*jcCiXicELD%fLosuUizZfs4w9@gAFQ z+HjrTM~vXVM!PXAm=~fP#O1g0QXDL!p4Jp)FAILC!6uDaIxla&e-y?YFr1&H=yfNocwF%r=ER7t6so=8tAG}lm`;Zj4x zB>SIAj_=NLz!V;Ae55E{2Luke9L50E7RkXC!I0)l;zh}8W*T|E1@ zW9?7+zlZzhr5*{^zIem5r4MFfJCAj!u2d6JL0z0&jt<)MHiKt;23V99jDSMB)o)Ag z@Rrqso+s8`DFU83YjO(zb{c@b-`B2UhfC5*EFL!qawxV%{t6SKA)(-Y;W0-DeH@r3 z3u-)o4LIR2jkyJI|4wD5X|FdS*%>&vV$1=_=%={#KoKk(6NkmnMjGr^ zEh7SoKx3itq`;5L5KXEAWDv63T3Ix z0h~w*QkuNH88U(JOLr0(z@>%VXy}RFxv7mrwuJ}0tEbJn6i|cV%WNrSf>5U|?Kf61 zhwN<;3-(gOZYdua61eJL;v+sj-R!~F?%5k(i5-|pk;@|1reE`R%pi8q6#G9aN6R3& z_!FNagg4Pppr7!Ulh7K9)goPyRs0lE02@v+%hZ~yin*CTSG50<&ROlI9(7&tjcRa{ z=-heDCBa$-)}06dkeTQTNSKAqJ|a)}|7M!jQi@B$unA#nGoN zZM^XuNpyR5ilW(;&XO;X!q7oz zU7|}{CuNajh2hQB_XUPCnfJmQrKOz(U6X*a7&j+;{7p0P2KBOO0#lYt;V<@XEZ=Pk zqv~b|@={BS(0hx>T1y7Abv7x>A~VZuNJflQfEDipv%Q?W_zQYhAP)dk%Vk)DspXKHUQRLX2S*#EwmLj>Cy zTTVX`3-4_x3SN&DFYdlS9~2_Ll3S2rh-DUDG{OCATIW(K0ed*#R0e&w*QXtoKG^@# zxz}l9I+czP7N1<*=$4`k13f_qgfbv{SX%|K zcM=|1SJM+fJwM?mD*PoAw4n<0plgb-A(Czl_RpJWt0VX_sQJJra~WrD+`ZVA7|Ucg zE{THBY*5zyjJxP)2IA>AS%HB&aJU`(s_^6O1ZjQ;mSc_x@Kaq|=P{HfbR-la@x2t) z=hM>PLvmiVbb8him)yj7F0+A@)gxIWM-pe~lMb*D{qz?vs6DN0g%2Ybxxt6Eg@UsR z>Qdr?kGDU;biMA9dg@H;e7k){a_k8ZG{lrK725;^um;7dz<(REO662fxrAx#n&%HG z)DDkC;CRQDbqSl5R~%F|uE=J*kv4{2S;P|y1cgYs{P$rZ%>=9?H=)yo}!z=$f z-{T|=r3`B=rmZ|ONOenNS-ba}_EI%@qDlLlkM_`xIdS5p-UyJNPRV^aUZse5Stk)* zzLGPqA3_?8R&1>KQa2Nlu>tq~BzJ5kLIpdXJJqqfLjLDyxAD z4D=e;(1|eCAE|c`{xgQ4Loi8p-bnY$EzBt^LdLep|Fp4BJKX}_i5kisVsYPo`)>9g z#ftl>Bf~RH;rUEN0@rRZAPadYj)1C`xpxSx0(L(;K-eWm@MGZ7h`o;NdBz?c(wjcj z8}jaNvd-NDUrJ>Cp7WRxfP!NUEiUvtr`s-E(~xS7n>`}5K@K2b5c=2lN^0#}HaMu1 z0l?IM+ogXDRJWX6m0DXSFYkWzeeGKLjc(BfM_JP=&bhKVfFv78!2_4ir-dTm|2XRr z_-gdJ{0}Z#nII?K9Uf-QZv- zVls|x0(Rp>$2^?jzEiL^Rw$1oPbrK<3d}(rMbhAeJ_51QLnIFgQ@+#!gaKfl!M=rW za9}!R!Ldx>Hh^pen6}t;FQD0O;4_iA4b8DaGF$+kA>g{hy29+@3d&7&qf;ffZhl1_ z4G#cFtSn@r0M2B=-+#$g`Q`w9{q`R;5uD;9uVjuj;vT4J2z{UIrSB}-@iF*GGRG|n z{fyAeC=g%;a_m!DpR~Nwvq-u#-Et!mzL$c^X#O}YEh^x6BFa%<8#8$@7M;}SmwnB7 zY!_JT8V>KKsnZ0B+s)$4wZPc>))8QH-UGY z$i(czE`S%}BXDeEmR6(@yVSy`y@Th{5*EoVr#^nnsm6t~#b0*J`xHitw-pj@>qs28 z4zJ41G^aiB>d*S+Jn0g>sRTF*F`RKbJ$KoJq)V~rU{icbs%yQpWz9jJ=8v>2E<)t!_<(N_}CfL(IE`buWrX&k}EW7m!E|9^>-Ej`5O1-Vw{jKI0u=9N%p zQeh1H6d~&yzGZ%uo~6iYE}UO4_nj-qh-*C|HpKsYGbZXD0k$qDeWCgtwODdnCCyyF zVebqvS66n{u+#dp?vERInhF4B@@e{dxHeK-Z~e$_W=#^;Xm)o-Zz=5<0$9pg-`@*V zaKL-2aQn&~>pyj9WF#s+<5-Rn6Y~yl5hpFVqqb5Y( z11*t2B^Hu(YZG9AWo5&G(!yB+@clHGtW5yznn9XBro6!56jQ|zEAdm)To>- zz@Y-kSl1p&B=dt5&`x&;gzgm9O$VmE6L1*c7>^eQ*1+#Pz@L}a5ii&j!kx;kNJasa zvJug^0gy5jJ|GGZ=y@fm@wqNAi^cWE13fo)Sj5^hfX|MUM+RUOAHMB@99Ga1JZfkD zML~-fNTMyR6d{L_?!R&HV#a3g!mX_ix0dPPqa;TRK@+^1SMMG=Qe5IND$Jk%Ln}gJ z=YSKVvIVB`ha7Ha!SMu^?FRWA*a7M46elR(+vfU~AewfmzsX>$TR>~^PQa>4&5<7@ zrH*6MIre3^I;z8PHcGa3)3wap$z4fN0Z1i^;C!0uVi!4C>Y8YX2J7{msEvb+rcZWS z1wEA+vq2-X5t6WXLG$ii@xfT5$!Ga%)O;8-Fb3KEt^C=ZZM1aAXMf0!Wk_79A?1e5 zlo#75gDC~jcijNsmnok5LX!L_c%mq-5Vx<0#UGkfR0?2klkAYnPS|z2!`MMpM9OgR zB;4{wBerAB+r5VgrpE*jcwvJbm3mn5P6f4~E002l#t>e+4_-SZ$i(#y#|Ssg57LgY z*)Wxz^IDJXt#_ZhN$uRtjm_h^yo>5@ly}rc%2(HqDn+VkMAvH5#SvT&SuoX<3}v0~<%k!Q zr$pmiNare^TVTha>E3MuSbMlSI5<>dJ4%+mWd@ydNoU~c0ywAcp>vp~k2;wC)PKDZW^waQ!0o4sME1-^ zlNK5%1m|~2vulwI@7qL%>`p9M>l?s6o2DlVk}V7&XE(AxfL8$#=|T>nfemL8*n5Z~ zRctAQn2YX{J$TYDo zZ^{I;v2+zE6pILOhf-zM3;OHAG0F6OVo-oHc)SX*#J2RWGx=5@`0K9yY>iMl77-?r zbKA9}+rM-NA(LVrsl%y2mB!rgCR_wh&kYa5>_vwqBw-0`SLNvW!;P)dFp4pO`<3o% z0cNOKvxKSYV^XM|aC!GDtLZ&~&(5wFX*`?W-S0BMTtaNYjwO1|8Xrumo^-@+PEaT9 zkD|UK<(&c*?AbYyun%`o4c}OUBg=5n$&D`e&}w^+jI#|d%NX@wjxUF={3G7*`hjW{ zGa*+X=DENIsH@#7PZMabD`-a3F?vt0nM{&897a;g4Tvc5<5ZOO_g6U{T4|U?BBhCU z#DA$E=f)@f?FdFB2B~1AV$CuSU?fgjtL_7pq@czca4X%C`aKs0EH_6Oip(Syw zWef^l|3%V=85YmLQvVmjeN#$NSu$z8lO#Y_SkHK}E0uD|@dGj>C3&KEaM}FDjVr|x zyOAIF8;aPS8zSgQg(k(TIB&o;57I#_jBvSXx4QGwRB|LnqMetdv|^u+k@8dh5r=eR zE@iHT5#L(q3iI+K`)o8jIG5^u+yj`*(QC$YgCA%Vj%@?~247nW?n!l6X{YbmLkmNSKRx)5Zg#94YJ9ZE?cc05kW!rXL~ixt zg~_$;roRJx%-&mMe)g^)B3=26?z>ZEa`cE5b;Y&Io~d>MTK3vP&Eg|ZssNZ87&Q}Y(XwjfH!)mFX$*>yE~$ciV|5Pt^in(9%#1#&2|z=Sl8Ew-pRq2I7XXr zS>)%9*fAoi!3@#s4E9H^53Ph_SiUOd`NfysGYQ7;<*)2#2nar%2~a6@3lH4P1TMy0 zgT7s?3+$vE$^-J5&XMC}mj1n7xn5rSI_*XgjNnOVA<;J-pV3)nH*2R*JS|X<<1-r| zX8^im;X4O?z>rB%^0ilK=dI|PDuJ3_%7 z(?y=0IOI*=-m169`h`XdeZCD7}x8rSZQ^R zgShq;G3#>qbd*~!7m=}4^>moxtaT-4n{#=Qg3{GYua;=N;@#V^G9ypDX;>5Go%!d@ z63&)(-jz!^*+%#OMqnt_f3?tu3WMf}om1@FTE^LETbFlJ%aZrLxTwp#8zEfKLW)_Q zZn#cA2EZ1|jqW@Sn~OTPDBGSfM0G7Vqj2~NnaA;S`WB>)&$^fTnE$LOX?%v?c-2uhlOj&HESUtQ|#YCu|E+8 zD?;|j62#wmhJU9%U0%-{JkPXsMzZ__4#H42bOU8f&LVY6RBxr--nnTz6IY7fL zA>g|!{Ud5Lf_PC6&5jAcE3#Q6VLcF-1-|A1GtA+?f$y#!B=Fx5m^*p4R&V#4p(unA zA1si}PnOXhL@L4XoakcoKsgLx6YFHHFnSokOg7#L?Zsff!L|c2lYM%d&lBe2`AF@X|UzY1pe^_7B~|Fr1jM!T{Q4C&L;fa&D~>?^P$au z!aWZUGM@6>=KNrZ#1)qPa zPq~O+OjLua-|x>pqg!(TfsV->t~-<5DIc(;xk;%A83NVZK_n|U2q2|8dd7(kf5BO= zmEtH01DBrBd{lBjPkpq#3C26nJW{-xZ`^J#_?!x+jB*-|b1bH?uFDx2zT(%Hq$e>J zgN^=bz&2J&sV0G}nFXp*65a*2;gzdsby&kaj(3ycq8^(?$>#}A)Uh7g>N~7N=oR(9 zDep{9_l*i~DM?gDj!j}AO#xd?}&T#dzsMbKr}%N$u>ZTOiK zgkf!|(NyuZUl{N+8Vc|-f`_Cxey%^9ZbtT|Rel>eZS5zMut!(S!$#~}vH*1R_RdIT z&92l~B$a{r350ro34a=+;Tk6_e~?@to-G?(T~HCzgAMhZ84+Q ziN3RA)f*Sgt(KL=AFbJ(lmDkUBJ{cxs%JCr0}#w!q>$=M(c$NMs;;;iO*c4w?!b?V z(yK)0;Cp{M$|CBof-I+vEO$9*$g;KdC4qUs0!aZS|MFQ@XAJe3>+-Nh(-TDEc^=?8 z+o%M5FeF!q+4@p3^5=oP;;BwK(&k|l^J=l2oxuA~o7$%df)JTtBxQ|xZxSO3ULGNP z**f%e<~GAUNfFrhj!8_&KnDKw8K6%K+rnT*q~bLYlNFMLTtB8(+h22JUEl7?MefB` z3(&IG%@*&)8@;hlZ|*V4zE?L)mJ{ZRQu0K1EwJto;;~&!lz^GDSlyz@-pPQCdJH?Nv+Z&)=$PGi?S~%Xj{KJnSr$#Wb<*VdO z1k^04Jj(Opjn{^DT`%+E0a{gjr5@E)DdLLR!Xt7gSPM7q-E+YF}@KuR0f;07B49a#9S7AX7^5>5qr#a0j60rO-a zK=t2YWk_VSdS*k9X&;c*JUo-9plyR44p;lEb1qFM^}_Oyo9!kTR|Jq6aV*`f7jdM} zb<`7}dKKA_0i2cx)ns5*D_>XuvjR&aQ{au~?(5sphDz!nA{4R(|Q zLA#k@&^QzR4==DnUV)%gbwuKE@Df!pJcGmo>3GIY=|&_XKms%)i=N;Gl0fUs1f#8V zmP9tq1q?)%)+U)R+6Eh37&eeK5b8I@ho3Zrl|%Swrgyx!`&q2YtqiQ!B^SDk~!h5)MF+&@*-`vM0p%T zB7_Y)10VLi$v8R{-49@;9&Ps;2H9#pCX^1kP6L6q2wo86X20@oLhG{`Vg7OHHvo6AAjfvH*M_+ki4xZj`9JBLPCZ2jbu zvmqUjL6>uci9$mhl5UyrRRs7`woT>y((AxPtJMzfnB&ijbwu)N^iJQ5+Q|2m)WXq} zE|r(L6NH3Z=!JtYFW6KDe#2VGF`w^|^F@#;Nx_6}Rpmb&rMpwHc%dzA{vFnCa>D(4 zP_0Jx)g#zHaYTfoOHY>L46y3-*E!Op$NE#4fX#x9sW^L0WbI5|!5%uoa(uoL*2{F7 z1=c^RNfDkW#x)w{aO41&j_H-3xuP(UAr_O+E{UsFlR9veoKuqP*qiek5eDKLx=nD% z?%)$X8Dp~>jD~af(w%KeIB*F%LkF3`fX`VWRJe4KZ%(&4`5?J^5D|5M=FZnzJC_h08oD~|w$Ege&*PG9{+%-qB zb$^%mt3+lUF>f#c9_H=2lIc8Hc69YO02lN=+B=zcbm@`zkM+<6Q>*4tsQc=S?_7~x z+v;BgaIhin8Mq)skTYaAflMWU8Tzvtb6~1pYX=0p0z?7e|D)8;AuJC83K5C>B(dfS~9fHJ~CY z<;nAWcxT@8b!T>Gc6R5!?{lu}cLA#6Q08Ll+0{_1zoENU+s*goQ_gIg9$_=nZ3h?< zyQz|=`8W}=3ruqXddy&@mk@$%v|u|dz#k}#(&A1L1u#&*09fz_G|;>X3?u@f%ffcz zd03eK#GkiOlJJ{)$Y6xMpAQbu5~2KB+0b+t^E(P*YQ*yngRb>MOFZDV*35w{2!+7+ z)44d{`2gVU%4}os-tGgwBcA?-{S-Rs-`*;9ai5!3W!CuFp#*ux6Hh3747vk>sl8CY zI!_WY$>M#@;Qi{nZ#nk7>WDpBU^6&&L$l(Qv@mL*kTj6n!)|l=B=L!Hz91`+*pGYs zNFXewLKpEA4u7k{YqyZ>Ws9dEP}EQgYLk4SZz2{aDp?9rfFTPw$j>CF3BIH1-L&sT z6}6s~7v&RxEMS4KI-U+tgOyDr!<}O4lUBOo<)$B&62@vK8q-}4qaoEzfK#;I!#0-< zYf}N-`YWn1RCgcLURWVY8X%b;`5jxROj*rX>@or0C4bEHBdX3fA7P-bW`7Tmlt}LG zuM78gLc_y&f|Y{;v8e7*w&%D(ltAArBp59yKDNZ5Jbwb#Mc4)4iyG`C`}Zcwrn9gC z(Owj#bC`*}ym*_Bj~CdSa~b!GqZ`|6ub>C*SDXNQeq6Z1i7EusEf*dvbvZj3zhGY@ z%f&tfWeJ&2^$O_Rl}MgJTM|s~BZaPgH@K7&p@0Lk{B%Rdpoq3GM9?m`j1mxjJLAw< zK-v*iqTqU^O^M7X;!yw1;;z%ujEqbrmz)pFM5oogE;9Ibio$^QBia(vy{>T`G(tWZ z_Y)O9>jtuoVhFrchhPI;Hd_09`c?@!J$;LydrQC!4s>AZ*Z)yIc`5FhBkY}XT?J&UQ(&#sdKQDlIwZ++sR+20RcniL7NDPR!- ztl&FJCBQt@;5{G{zj68HqTOCzs$np|L#+hW2tz|Vk}qtzJ;pO4pML1~SU1dte>TKo z=GnLT7DS;5Mwso*c%l#LYeAcU!h^-Y13Uvs;C;~512ZX57JXWT`{({e6kfWgE(TaI z5fFVhioufvUsEa9DO_=Rk^i@~hQhP1V=PeM^KQ@#nx!werhtylhQ*x+lboPW^1jH< zKu4Ib3C#2?c>MfJ@q>4_usyvyjkW~a=o-k$!r41yk;7sRz+GEJvZeTJHEtpc)P;j{ zg`4Xpf8rjvLnYgsF)>?TR4d0X!x|Sk9x|&3d+&XGMJCg%+Pi|w-C7lPTU{s$;^!8r zBgz}X&Ss;1xoWoN*ykU2@p{zAg9;cAY%aY#Cm&?bWJiC=gO~SGbG!1q2Q@7g#}R9h zctOT(?`d137+-rhIg^>J2~rd}NrRsTuUO2@=Og4ol7O##^2^*i znW@GI|3G5AB|24_t^NWTHTb3cSy;m-aUOvtiiC$GBq#*P z=6Nh~Y@2yN_msOjAO#z%^tMpj{jjebfWpGkER0i*b15aT^T@f(ISc!`Sc+GYHy=gZ zw6~njkWCPp9+Y_RFezkF5XHKRtBfO1#9g961yS&_>wBavkMF?vDUw8^xz zUt9re-?n@S$cjP%N^CH8yl2 z@|S=gQ0UG;KcCK?*aNs3AppUul*Hfr7Z>a{GE$G8*;sbkn2?w-ehc1Aju{U4)=mN$|Zi;|Hh1*s97IILzs(pBw(wAXi4RvLH*A?A*=`zO5I!}&PJ4CynSu8u7E<{YVA%7_w`^me zhhtwi-HG>v?##IybISggYwPL24#O!LElHFHIn@hHj3d;}m*l0u$@MeEXZ9zOGoeN` zRK9(_){K0sTyP~2QV!D}#U6Hh4eV!h6lP$2wXJ?Qe1s_`$Qwsu>H%KcH?1q1{u({x zo9hlg#c5{Up!@-i9>!-(C}=Z3a8UrJ*CZ{VcgV`nNJTqb-@^60CdQ8^5q4_m3Citr zDIVc^#lvt7ZyGuL{%VLOhVnDLg5vPO>UQyDa5};$r&L?pAqrH6SpO`mF!7tMh5sDzLF&^0!HKxkwIZgh6?d+f2cz0PIZ~ z9t%8JkUAG>ipl1{AYfp9yCnb|>#_STyD`Q36RHA(cCEa^t)C+;fBJgUm&O>ATUKyv zRfb?M2at(moX~=MEgv9Zm<7J{8vyhvyM3c#dd&QIr#s?185kW&nG3p_9+aL(VvX z5i*zr8&tvz6hB8{z)b}Jk|N;Jctm#-RZztVs+>@0iSm-N()cyeT8%qF53}6M-l2+^ zG(?vgiVYw7`(SGfBMA>_p%Qap6L!eJ4s&ASV>{$nxCs!ky9=Q8G56(e%vus6>gJrR1UDjB+-tvx#yCj-dw8hQ)4_CdVcbsrk zVUnNIEF>C-qxBdw2Om?+jQlq9LK=Fa(Sc48lO?;ZK%-;|IrAbryf{I#l`+NWcUI^7 zvPBlVMld3{B2GOBa_u=flcH1){mLaiqVevQ?9l`^JL>04ib2tonL?^_!^9^wW$`cF zX83k}i$=F7MCPrXLwY~(q-_QW<9hW2M!}dB&A@w}8t*gACDWp-zJXVimt7+!rv3K& zMv=uv${g8Tqto$-qinpGm$dLt zaEdUT3CSmK%~wFsPV!lQ&_KB`^%V%5_%n52;?Ob1#y`@iA;3UB+MT)ag6VW~D|NRm z?y>F)d(g%52+#}S^|v3mR*!kSkv9zZW&oSv+{M-FNp3*RWa^LUA>28zvDKxN#&a1y z7!SscaS4K>*kc^vhe+>m^-Pw?n?nW#t?02Jz}G|#Is=>|w%UOc>1b}A6Ym~EKtTv4 zDS(--*~{oJYfoS#s^^HHO>uSTH=8wuucad5Jx4aG8q4!qmv1U zL<4wdE^1E}x$yd4EkwSu3m{HFe0J_Yn&QH?ZS|ccB z>|Ave`~AT~gCf`;Baybmi9^P(J}k_;@zu0KQ_I57_k*7%o0zD5UUO1tr(dI%nb2IM ztgi6h2G3p494uhOkRH97t8YvJU=%KB?B(kZ*?$&X8!4>RL+@dBYsd}L-C!y}YPdi( z5+_<{Y1KszPqcr{6>O3i3qKM4b05z{f#M{Z2WzMAb5e~V@6m!wcQW>ng+dq4`EpPf zi@91^Q~Vu7yS9paUoixf1CZ9}f1b zw2v{OCi6FRKJ$In_d3Ji9Dd~AvGdf@Gf^d=fw?HG`?WVW6Httn7{gKW20iI<- zgzK_g{R}`_p-X;(&Jc(=Z&t~;;{5rgOy8P$#|xMz@(z~eMPoY#=sdr5m!vBUi7h#O zpJR)2w47$0hpN~@4xJr|{qJ-N|Kj6&jI3J|IXAT>*VH)C%k7vO&B&icFENhCdNz*X zlxRv%*mputu` zf~5lH0Buo@AGisGR8Mq|;K|;cax@UBjL&%%_7%HP?PRLA9$~w5X4mxC-!mJ>(Gp?1 zP1k?R{B3(*@r_ah0NUq#P9@GN8537rC4svjlOne9z;$Y7bkvCSqcA1_ zE^EUS-c+_~0at*3(`Y7$+o24?cm*OLSu}@dfS4cwYd0kz2?{{Pnree*)p#oSRtZdJ zoEpUuE$~7ouTr?%OyQj*6w?m=QXG8Y4q-{$esr`6nhE!(mb`s37~G>>6OeJ2T;~LZ zV|!%vP^K*$#xer-F$_JZ2~-FyQW8IfXD6d|5m)V0d7E9SVrk#Z85l`_ zNdB9`ylu=SLr***G8x9ZkG_POa4Nic6yfji`7C3h_O^~gezHIm%N(6X(gijW)uIsJ8|C@)D*Ba9iNJk3{AssPf6eHdrGiqqUv(+q;o)rK zr`V&=s(ga)A}bg^8!4t%Eic9+mCHYfp+=ZSv1^CNR2cU=rjgOrWMzy0K;juv)xKW# z>UNOHqD*LuOEj1Br>6~+K0NFW2=1S27Uvzt;dHen*_Ue@aLO;#%RpkXW!echoOFLC zS@K&LUz_s2?vKkoggvLdjMcxP0pmFw4*jj1)X6^ixn2I*gtk( z2+J*&{h;_%ZPJOPn4ZW9nu*fJJa*&wSxnSV11S|oLKcB85uAZtq5Xv$cJQtmna;=E zG9zc;9?=TwWQ;TK$iiEXy}I8(1l1D-VaF$k_=AImywDD{eb!^NXyh@-X@A0#c1khR z`aX9ODt`ve1X|AIBjQz(WZ#&-+#eQxI-E!mdA4noD;=Ooyp|KRGRg zp8B&91(X*5i#vmJf?D4r>bE|LMS;CWscrYbmm7FY%t9|K`R zXA>o`^vw9{&WWL;}~od)JtpoJhZ+T|~t$$>&{6T!^6fkDmIQ#<$jd$}hh z2Nc3^WbkbPgQp8YHu}g&_^h5MN{BkXC6gBpi=)sT?gv{^ebT~8jW-*U$U3q$L;1RU z8eOUW>Mu5J16K28EFa&2*r%{I6n#F^fY#KQ9%&O9K?1j&F}MHNil)QhVxyUTX({ND zI;PXaTHl#+25>!d^#ylJ$x{!dCT=G;Zb35=&saog->5tSv&y|W z9Tn_~7yr=Bn_xxsI_=*jNxYTjokeJFm7-)1(<#7383UsX5^`{USDbBMl(!T^;?~8s z5J?F^mr)@xiSz1)idoZj7 zgRZ1WWJ&As(gpZ92N*y#8yd4jAoeuoy;iq1vodLw%Hxm`rz|mKv+LuzG5*bfNp(7g z499r@@XU{T) zk9Pavqk1eoB3^c#8SDU_1;^{NUQT<^9gJ=`ZsxXbt4c z94?_sZ0IW_*=QD1DfBgQV&d0RsU+~3P}Q6S>bqX+u*COyz5jC3A!-9 z#+Zdy&C~ht$VjmnM?fRa-i>EogDwa5xH}T)0W%;Bzl|tJYxpb+qVUX;gG9y*BAEj2 zr&15VHnmm~Ry-hH6pw|*RRJb2oC+x6tOgq48pU|QcwU*j&>!o&=E!@CZoY(Lk`Rd% z&`u_xNP&)%ecw|=uxqAh!eY$D*-$9Dumvs zVF-cFfqGnc2jqE=aJsgWXoAg=yzbN8(l##W9KfxN(}BPQz7BeyRH!3Ka&pxAi#P+Jo#SXfB|S-KKY|8S z0T=htoUzS+k145t)%VKpBekW+nwgKuQD7o9&fSOxv?jUDj(ENDmeTZ^zNKcQW@ z+hk#t9+alSioYh5l(O-G5Owg(-{8NA)9=gU)n2YG3N!pQ(>IiD8&kqfg5m8&E0b_k za@5~OvW#zbp`+rqM>liJSDj zW`U+Kvz)01OlaS=t=_Xg85!0$tI84zGxK@)C+YmigN4P$#iT5V+5EUYdI?+S&6^6R z8k zLvYnSk1w7#>lUR`!aDs@2CzC?gx#3>c-1A{9C6g*$3EuZRQH}(N9%qy3rwxs>7L6H z6~a^f7l74cwBKr4hufe>suHGw9sM5JZeF-TK@nVd-jFQcyZ!(P99``CJE;0CvhH|B zR`I}U7ir@}$wttRE_10Jf!e%+XYoMaMTMwjCjtu(Wp8ADnAy047l7)(gy{30>l({{FlpL>}yV z2Td9bkXA!&zPRK?<+8yHEc~q^=c^*D^IYMfLrBh?rb;ylhVvc(^(rGM{a zBb`4a^&iD3Npf;JDhzQC;9QKD?z?Dc@WH9q7OUK@iiLfeoc=5Th?1rnrivy=1sunT z?&t};aJq;YA<04l!1v=0NMhz>B|2qZF3P`PXbJqNo}BF*WQp~4`r$Ho7P5JV-z5x6 z$tfyQyX?IL`Ph4Ds!voi#!F{fVB{UKQi~EfI_|){)A?~z2Ujo45hT+xJ+#aru)mwm zW)$m$&eYH?WEud|(^`?@Xt+X!)G8!xRUDy#t{F zL$=&L{;xHR6rD4+F5M!tJKv>;i9?*@(i#^r{{IWXa^bd!2jqtYC=FMbU{NG(`(*TE z)$n9{1OFX?{}r~hYL$Y=dG@hmc|fsZjz*cuW%f4sk68E)oktEUHbs2!>J37AS;AzF zqH%HcZAGnJnJ*uI;)QHoLizo&Czw~M*}P_X6x`di;OsPvIgX8u+PnE`#*x@kUUT?O zeUD7jbVnl~db(W0O@CvWO2(V*IJZP9_W4T7Vp=30L-qOtO5euIKj0|Y(qTp9FL1!r zR-$lLEir3x%pv0B;;kZ}Q*SjaOFPXzK6oe1-YBb6cI}*FW?MYrY<@Uw{mpkZ!tw6) zA6UoN7|~=!7~1uEVBHn!_IcQz0k9M#?)1>I0X%gvG>`Sk?jPXG-!N0!DA~HvS+G6` zU!PSA=#ozdt~Qn*#hu-JY-*w0wU}C%J-2Qhesn$o4U$AocUUtTwrT|GLjX>bOBA&O z5cBB}>NKz%CjsXFGC{cm6e6HxRa)37MI|{+@;fXp$*bkTE+NbTT0C>7gW5SVT>ga=}y4SHqX=1 zr+Nq4U|$fs`if0W&_=7Ut(EXD+23?b8g&o0yvatZCZ5nY9ELNKcBj9iz(3G2{N0#G z3T|;u@)8SUd&o~^J400-Gd2SU6db~LUV|4pxulnb*F7w|yF3MedXChF&U7xGI$^th zfP^=2dv}Z%A1RbN#^7*?nZ4!n1f>g(?=EeATBt{1x1Ngt#2F?1_P7u)<*{U_2aC7t zj6HhkE$$HCB)2%d_^+6Bq23kmswc9;2JuDB06I=l7g!V6-WZk`Cdfap(}HJN%u_C> zu;;j2V}&DN=n4hcjdwKA$c3ExYg})gZI=JVL8`kbdVi4-ebXPFc`YFO_1PQkAz3%iW4X4q z+SckAXZw^N#8;672gzqdDPnKFZ(uL>p`tJlC&~VNYL?I*;vQF=>0`=jp$pwa%}=s1&*(qV1&bHK_eQ==ONZpjy=)?Ld?LstY(eeoEV?FFkSz#o zLQzuVI51I~(GpjF${Mn(YDMQA4$q$S{Y4lo6iBIlHr{Z}ya~{OiR@>87pG3cfb#SW zA0$+@di2_2?OT7!I_WTK5UGQ=@avE>ZGVkA(!A+t%Ee6SvE{eJ%GTU1Ijk*f&KJ+Fs5#(9P@Vu6ks=m1d*+89iV0QTK0vvW=K zJ|Y({dpb)T*4xPYGB3vUOx;f1ys1jTmE5naQ}0{B^5KOJJsFa=xW%s{T(eC619itE z2gNXQ-d8Bj-5=)K(3SXXR8UAY!)wNC4)bU;OtzdKq@5P+M^Uqsi$DE7$7HK9Rjju_ zqIs-`;Y)i&O+J15k9MWROLYo|(s~;C2toBqrrbS}PsU%7I&CCnTE?J_WWh@d4Yb{I zs?^#y&7MAC4H?}O^I0_L=*A;Yo1CjVoa_NpxJLL1Txm7ux;-302lF*z!~;Yl4M52l z4CM#+xtnpx?M6ydI%((XD-k20K4oVtkJv$;#CZky(^2oq?*3)ZXj9n(oOEptmsd zf`#K|A{*b+Q>J%kwWy3L$YxXWlhV3mEYKdClcs#enX+hFLafkr%v#n40oRYtaoKg73N}n^ayoxDx=+O(~G2JZ$3B<)nTW#svX8{)eNdd;&YRfK$ zuI?TYx|0m?Z+qw$6Jrs>iP8V;$K~oxCUvqiR=9<7eOn7SKb7yMeJn>zBEqUjN}4Qf zZdtkp0I<9f<=Rwn>ito4 z6e$^Sz?vx_b?Fj~>~Bt1m(FsIZHHMPU=tXg51JvG0J%b`4uE214uV_-TqZ&%@mxhD z;Ee!--GG)zSfL(F)*CQ?=G48Nk2~3W6NmNT-7$ol;Bk0ZYz|OO6Nr>-2wWt0lLJIW zDY+m9GXO~{Hxk1F@JtM@6$!Lj%Am=vfE)}(x7%A0MzljtugD=9emYbGZ8?q@Fl= z^W4>09ecF;V0hto3n{e@Cna>%%sJ%0ndjwlzq0u}p7E^9ad^Z;2f>YF%(qo?40O@t z9(2RgO`t}m&r0)TSdMacFB|O@Fp<_8c+S4J3~^k~DVPz3d~*U5d< zTJ7rzi#p?|W0K~;;AfTP;Pc1Lp@z*73Q(pk zT|j1{<=F8(k=f6C8!dm9<;Ynru;VhC?IQq+BVQse!KeD74ib^su6K{50gri1sLW{@ z2GYO}y?hE@)H|d}EYBE0he` z!i+Fz*h#A~#0RefU?$pwj3f7(M@^|4C*;M52-`A>E>DjK-|+$8$Gl zihzT!YPp=uaeIlh6VPoA^a2-*jR;iV!S+O_oo3+<Oh&}d?DWj6+? zHS!VDvJ+ci7U6TjbBCSsPkNO1tnFBm`MEP&KZ3SpzP`;~$>t%WP@&flk|&&4cOEeHyrj6uba(Afy;x!w&3UGV&_gqKpn0r5G<_IhBQlSR z214ybU>Am$=K;+5!CF0mvqYX8Sm_9T@o1x(RPNm@6F{nvbdiQoI`3*K-dx%W|ad-X!1;?Cp5dkB{A^Zb-XVYeBlheKrHkCw_%Vzx}yxd&0yq+;!0q_ zJhH)?dTjU&xL&jeQ}auim?s^{1jS0_Q0#BLuuolejKAgJ&;ENgTBuSdp^v+91jEgR zpY_F8TjDEgC(Zp-_u1lCs|0(*s42>mtp99QiPXDOQOozb&SWk^aRH9Q_PKAa7< z_{&o!0KZ`h63MMpzxOC=dxs&-hAT1~TJJS#JYq_i5N9JFvh;7C_ObQmKBp8&+5YLs zJ3+^j@Fx92UQ(+(;#(#nc+<&z7zaa3chuE1MC73M4STUHt_7EC7c0AQs>TSPio8DT zFcJaeG5Qf-w<*qzk2`3fx}OQaQ<;luT2$-#h2YC`VU>&C)Ooo5jI6~NXkX9-{cLp% z?lBuXOvB&@E6)VBg;J0sgj@v$g{8i#e9eHwMs|abT}=7-{KV}DwC`<`aI?==!%>|L1jKH7)#JVAW{MGX#!Sao)6BfT z_C|Kdd{-P(p`f(@JkzJ$!N7_5t_D_KsK=U0Q2^(*w>nQ?WmPC+qN*0&yNisg-tk8X zKM&c7NH3SVWCoG?69O4q@{1dIInsSYI(HHV+~#JD2t0;yOCrHKU6L7oB82R*npVq> zHXaJ=o2+$_drRn9i;Yx$cJ#XE=SIHS&>pL7i$4SL0iw-8J!w-_B1N^7=E)*uNPDiI z`=oXwozV@XWm~U)Dh8jM^H*KFlDdGInjP`(=@ws7|)|NW0y=C!;B z{p7FF%HGy5ZN@_)tq10#^IJqJqW{0REoSZmHWuY#qB?OBJjCD1dePkSf7M*sobxC+ z;#zx8dqdh5sgHeIg@hE8oZ}181*82OzwO(V{UYwWSidAkj9k0B^|a4&Wx~}DT>>?W z2f-1_A(KiAn-tb!$_FN}aUnlcet-O~Nh8E;LwDk3Qc~(>Z!| z#84F4L`Yk{t$Tjq_5vkDH*+NFmEFAi>>5SMEA#7?Drw36*7tYxIc;8fj=5EK=2+^X z^NkwgleKZ7wA592Jy@(QfpD~6wYc(Wzu-kf`e;(q<%MS!%KGu7d}2yx?tj%y`|YB4 zUo<`1KfVmRptH#%>bXM);=&n&(c3$(F{a8^FGq}ii8{1Ld!?lI8dur#ci5w4a9~hu zvFqZ@!K7EogV+1b8%cULR@?-0+v2dGkLTtJ4aHnTpy%nGB{Q7|j_=f0{CVIV=cY_( z-PQ^j{5|=}g^RMn6y}hrWdLFiLVl?&PA@3&n?KO>Y1Mm5F zTrszr(m(GN3OnUtIcIBpo)bEFyL;yHEtRzHh!u(5F&x}D*km`gNgbOb*Hru@zxn!*+4(kWSCfNgpFTxBDJ`AyzW(}t8g#*Y@7I@8i-|6LtFkpC z&yJ}RDWO*P4_^jwtFNzoetrJ_8-w<^lPi?#kP@@3#5nKKr@jr|!Jmn}te~>3wv6=dCHi z<=mqWX76{t_#HlGk@vaI>du==JACv2`Qm87$A&Mm8O1wH?VGb_9>Of#?BWjZxt`ni z`@)V^neEu|UWKRpebKw)zanwR>~iboc6Hv8?UB|E`Z59;hlDPO$qucZfACdCIg=pc zvvwbLfsp!pc7LjWw%*F9Lt>-B4LoVf8WWT_vi18{#aU8wB9Gf2Zwu^h!2zcKCOtxoPv4N#-$<`3^&C84;0! z*0G=N`QSkMU>U8YVRH0Dg=-To?^xsUM~$!I(ooV)74!1*9WxiqDRM?)$vXFkq=ue!KOcJZCd8`g;wAdK=9!+rLVSN^ zc-_&Hf*&V!JM&&@+S+*i_g@k^pzn`t54el6>ZNn&P=NN8|6FcpCS1mNSU6 z-c{T3K;+Ut`XA%f_t&P&2(9-zwHN$u!kQJM{4ST)W=QV+9jEcbVy5%cbaOaTTx%0G z@v81!QcIKe)fg8_tes+J<~7#Qte~B`-}n87#Aj^Q|L&t=_XSN}K087Dz4@u&4d=?& zndiCkKRU(Z{jSnRFBea($pMqQorm6icT$)%+u?BO`i}30ls}~g-0QaP1*f_Q^?H(# z@z!sIFW-N9psj@Wb2O@`+@1x0wXgpt^v_X!*(D`jqwA~Hf3GF?McJP0{N*NP`a7W0 zZ)Zl}Urvt$pWVQ^b-! zTZ|Xg=eArc9vh}x_cOUqi6yT>6sVd(CR!(z?%l$aoSZ+N>^}a#E*`_YaowNgY)iIMKSEBar;TO(2ulA|u9sZ|>h`(bX zIHq&Vig7S|oo{jQ1;5q8Kr*G132P!pUF`hc@F6}+!@{r@?NdlfD@gNE@@@Zn!oaOV z;b8sE&0oQOKo_aAb6`d=I;#8Rgm zr0mjr|JS&rxMl07($?8R7X?_@nTgw~`A=W}7yE4L1G}{*`RlK{`t@nM&piIVVWzjX z`Z+7)R7cJ2A6nH5+Z7p5?OMIt3ny%HQvM;GVSS4hh%eU+%h$^i*Tj{>0e4 z{5G{QUIBq;sy}XAvllr`Q%Y);wUx@we6_ua$o^Gu>luN$ns7;VrwwP!^jQtF#L9?Ia4 zgcr*+6^&k)&vk%|>UcTfd4cmiVvm-LzD@2}HGN~T_O*}n1D)^DZH+1k1K;fP9VgTmEQJEfyRLe~y^|MG>MDz86l{MfHh;q!82 z@E*94wj-D4{5c|_`%HlSWt(w_)lfCr#ZAsef1T~cz6?pgZEs7axR}S(>UjlOT^k>` zS*-qq9lsrMGWgWmXRWc&qV~66KKCj)bq+aY_#A0D-bWEzTfNYAH|9c<#h}#plszXM zn*M#2^t@VQ7hAnq>oH2~CLQh7?X%1c{Nm72;i?z)fg^KwpWsg0fn$F6{`~n~M(L{2 zwWc^fuoWrhrkVdaPRx`Sp4OBm61Jt>3#r0VYyMItcd^ohg(HEE@LEeY>$q@N3*Jen=oM)Lm*Lh==( zPj6rQv!mf2{C)VTb}S?8`%S0s#vV_0o2L}NEysYaJX&6Hfpw8;gyXWz zl;u5%nw%Wgd#}ugZJ)u#qXB5jr&pevzHhil-#93pvnG{c@MO*KQSr_Pea}~a7p|<4 zKKs*-&ix4g9VdUnjPz0IwA60Z+gmPpd};eM$E^79?~dS+d;i;$rP28x)V}}N(O;%? z)2?g6>V5BOT5#qUoO$WLt^0Sq*!ITsT+ktF?=ofG_UYcAKH^cIM(@k)%G8^-5&n|U zILo=T>~XJ1BMp-OeyH%I!#Sf0H;)$*1!XSit0%r}Dt^SzegQ46e0luCQTd6c^UGL^=qPl$$Sk*6e`uE%)pohWt!2)=#l>W{J1Nawn^Br$e0=RpNM%dF zrLaBdyI1T(xMm1P$z2Ek-yuU9fc#*lbY2x+XaMJSgFWYgSQO9O*%7jYL$>hr0)P$^ zaTEmzNDDL&3Fwj#Jc$DXtb5LF8U<)5LlPjbrUResq4R2tgYroKJ<@=kC9s;CF}Dwq zE#sv7`o2?F3!U*sou{?W``MnnrXg;z^5PIf@l}`#{$R9n z_jZH<-`rF*C#NVr+l6bDfx(*fVA-nRvuq%srmA_x_*dXJIdWXVvYDyb;(s?DO1u%2 zX#g@Xz)T$Aodx<00bVfMLg|HRC4driWx;twx`2^9;G7p@sg>@y)BUi$5e3XW>ua2) zxvjoo1St#cqQ~{Q_ax4^JGOPlo##rf!_PS3Gdp5~?djBS2%F3((r4aP1(nOWPYV%y zx50msf4y;XO;mI%7BAPXMPAT!e41n6TYj;(i|S?7eWhIPdm(D1F*6}l8+%Rc=g@zV zBy#*k;~*@6q$%;LkM$o_Q$cG!iQsdDoleaY`@}I{R&HP;nw#Hq#bm?W&_ATu5&0Jp z3SI|#QcaV0!=_a`)G=m*kHr8`gw$+(ZsxZnK^ zX>bTAPoWk;Dn5b?l13+Dyf+M5qgJC5jiKMy82MR6unuB_@L*}Mn-24NC*-&XxHJ>9 zLnAX?5H`iEo`@eVuKB_VuOmWgrj}xXiqlK4-HZutzSWZ#>~-Vz&Y#wcAt$SGsEO>+lbB{FeNn5 z3J4x%*NX!}NFAWm0uvy>5_vp9U!}DZnyaJMYex;9UD1VjIlYY>MQrO<-g}-F5p1*o z6KQ}e9{g)Hq+kGJn1IFkLtZow1AsjkCUWiH zuyi~h@RfXcqIOQeIuSzw&8QUnO(r{cnC?D(=mEVs+G|9sagZ@PUECy&l#P~ot*bpX zh(NK5{F?kd2YX?}Q_{T|fSQ{+q)x$2IK3PPmgC9JK3s)2YIh-Y7+)-w`J{F%xT@bn z0-M%(m%=0^;jQ^65PAgIMGd~BbdD6!^=XLyj2o7%bvY7FXQ)5q6mz|nss~?1-W5Bg zpbEc@ZzU{^WVc>I9$EvOju_tu;A7%|5`Iu@4JT0EGItqyiS|-Shm=9xvZHrbc6l>& z$Kh#F$~MNOn_9l6rjUwQnqb5 z(Lj6LOZG}nmUlij?M`{VryExuX6MEa=Xj4uk;3y=1D=H&87UiF)%jKs9c)|yh#E*0-`nD679 zyS`;$W4{wHI}sYf-dJ%sipc1@+rOPVFXQs%qbVSGjcFF&n8G4jIn81#UF~vbf!1le zFWXyU)`NWEObuYn69|g;Sl1f4r8XxBEvY5_=;%KUgi{|NaA-zN9`OCZegd;pBwW~N z--Qv1BYeG}%hAaKG~f#KB036_-(>L0)M0ov7FL~5NCS0%C3|i(ikXJkZvZ1x0b3k{ zgVxRfq#S?_eD*R0h(jc6!F@L)xKY4M9G3uMHF@m_-+aKlYOF9|Q_rikSGI9qFH>Q7 z9E6pTEZj+EtjnOts**seJVOgvYG9$x!-Kw2jGWY0K-Xg3by0H=*|bur)!c=3=2`=r zmiM&Q)LP+>jb`AmVLq?rS%m-^k)6A=_Zd+y1kIFI%E|-gG5{Z=%|{k$R2ZdtWX4|# zaNfjNKMxQDB7PPba9y-xOGjF9rw2yfZ5zQP6#WPoD=52=gULtcKUGhukiEyoz{5MF4U)PKYPu)*WqQQ-!XyuK%AUJip+2we z$ZZt=7V+?=6n-2?)~6si%u+^iKtA~_b^+b87>LV})~%ix%VyQR=Dv!}P%St@Mr5ny zOgC`er}q!fJSfE)Mg_WnsA*ifA%c6Sku;3D;reF5`XHms;acxXdih0madj}8JzXfh zkSo=r3o^jtdMo^bY$$V0-O7gI6UoFoj7_^X7w}@LABp4C4j@7(cL_MdSoINQ`}f>4 z+|fmnvz*)&J@vh`i%vV>GAP&`d9BgERh$WD5Js`1H zQ`F)?vt)Zpay>{$9pjte^W0tIM8bZIS3WGK$G&bvVsnW6Sk7XuK}2aI|1+<|ZAA*3 zRj;z;60`FV@ssJp;@+Vc_KrdilvfL*y2?}M&(Y+-Nw^|P@us}`$8N5=#W@3@@L_pP zGETloS@)`Ou&nfW9GSrz7b!SRvVpQZuD0qa`-Za<>eJZHu)gNcPex_F#lD`9mhLs99(AGK;rO11 zK~>n%CtD-NPz3O+Ll1J`<&MEjz?T5~bA>JjAcvauSKn@i2{ft)bk+?E0Q}(_v`(7y`B~zj6COm0Ae(NNnKFi2xpz3CKk;>GBDr@(AT=4`Z$m;f4%@(Tm$wxLyu_kbH_maMmU8*7cPMuAO%2jLgh?c z&u%=f?E?!dzzM98XbI3M0VzE6B?C1!VrUnLe>!0yJ##Bjc?dyfp99R`DJoh7v`HuZ ze(1fhn$#!Uq4UmeJuCcj5B#Bp%Uq;|Eij5uq0sbw=r2PHn?r@AY7#s3@yb%`WgN=lq<38A4SjmvP@l3iVqBl>gaywB%|Y^8B(acMeo2gx(+{Maii#sbOUc;#qP4C*TXTT_!d zHF%1i7xa96l%2c7#_wVR0}BbCX8j`LBROc?h3NIvGU3M)hFxWw09q=h}A z?^*<3XFWUr6;Dt4jqd!uz%1cY|Jxe9Rk+-gaM>tBloDT&Ot|*(rHw<)R#|nAR(T=W zbshVGg54ARccDfL_QH~?CQhLxHRe_C*;4+Ij3Aw}3njewhdLCGQWd_-QYiG-J??a+ zvHbDPEuU^X9xe#HQWQ)5%_>p0C?b9)>Qu2}cDz3RsoWQ{q?IyV&5!gna1DoPIpl-k z?n&vwR86PYtAw%5IjWU>l|$1B-IA@hSMWOU50;Z&&RzHQx)^}5(&~3UE{*!^|Eo*& z3y;;z-erRzENO9-;F`1oe_vIB1k6OCjUhj9+y32(`_Y`GSv&FPzS#u_=Pn%l zsT1}d0qoASp7EVKF_Zbov4aC-w2y{qLS|0`!DqFX&xIJQjv7&4)1h=esP=@OGQepj zx(RkO+oj9ni@yL_A-0vks3a*4y(3ATXuuxKASnysloQ}B1icp;GwzUN1hE8xX1!%h zcq9iTIidfu&||=Y0zL4@w)2n#MgGxAQ;}sC1FPT zIVQ*viv^}T1m-D{aJ>v%h|gf;y_y$IPkck=JSJ%R;9d&A8kjTPrK*I1F_^Uc_sz5o zvlvG{vV}JcrTLX>kJ^UYmJr3WwX^GY{#fQJ)EM?i$+yrMpzgdwmr*IPZABN28U&AB z&M(m8UeEp^U)rT3R{6aDJ0hSBE4B~Sy*PwbvHnS+#pK0N+Z+Q|9X#iG#2Iiz<%CCZ zjr#BZHW?H$tQjH(d#}cd&T#Hw<@znKQ~P*{8qT0gpv8E%B?WP{HN0(VY9bw9N%kJg zi^VhsJx%o~fdLxO@>$(b{g#VCf}%h9uf-vKF9VwYH`>{Ch20q3?y;ytKVpjpH}9Nj zu5jsGg+`neUJ?Ut#+Hi%^)%vQ1)rjaf@g-8eLS4kZoR9sCBXPewx94{k#e=PXm8x5 z8EA;6y;U~*VPKQ@<#Ed`uH3Ujk8LLtJ{nDv?{r8};J^vW1kkLfHP33@@@QouCiLWQRF~~f}K*B#r`V`mc zVjw#wRl*-Eg=R=Wbx?j>aN)s!d29X*Vk`9`MAmx(p|Mtz5XXB(bzzscPKe{2RKT2+~ zA+ZsMFn;`HJSU^%RpzS7$2RJ|kL@u?!gOrgC_T0up&WFL%24KkmwxL)V zHsapZ88)WK3L7MPQ zB$q0mCy5;3rR0>u@JJrGN>e<1{zg}1eYkA;77&%Zx~j2$f1eba zsPb1Fc83udPq@F5Av!2v@WB^~vla-L+QT|vOe^RNqb96 zU~V#_C70-<_nb*g@wEJlL0BO6yL5P^Zjn^Z=X%Fsc4WpeD7_r&(n5OTh3fD>P931h zuyLk+g&nX(Ytp7-+6c6-Z)gpTqkX13?GWnLo;px?@%9!v!vJ_%Vz{y=&*}1#>Ek0p z{f$*NM=u#-JC&A~de<^z1NC<_0**oBPvW}n8~*Zi|vrC^Fb#bg8 z7G+=O{iU7$UzCKL(eW`@zg(VioaXvL|ww{z^ej$&Ejo1U6u+Zx^l&aODoTV@>S@JcmNN49cDYXG;Xl zxgFTnJ=a#{!>1gPuH=31l9{wp!W4(yDx7o|`&EuVW`Spr?+7}2CQ9@A)(OE$*iIy7gnugzZ@Q z#`Z(<(6pI&&7?_Z=ip}=y&v4Ojn#k)rh^KIjo4u%G%*z|2K_PI5}m>O8{ad@xY z+J*zX)Y|z{B^3&_0=V=$$G#Oeh24Oq;5+Zq-Pc_QCvd87{;E;huj@qBOBIyby?VG- z6YXxg>Q8_aqpI}?hM!YK!BO|7yaqqrHCZ}eu8GkNRgq!)=30$bL@bQSP$*S?$Cd~R z4iqUqWx|3Rh|C=3)`F)eNa!*|=m5COB9IgWq!Ph!dHe!opbn%lAUEl;cSk`U6AL8H zrbi$EU4R>hk=tG9JqH0sKql1{bNZ?)x+tuT22+6!lVL%TIgz9i=;qhSTS2h$lzaH^973}?6qBH)*ndh{-hv{;P3Ah84%YU)!nlgR?kt<@>^`9R}r11_~ zlg({+KnFjtzMRbK`y+Qpt+y5O%dlUkz$X?nuA3eIlCk)R1H+exqb7b1gOWJG=xv5a zbn!Lm(*L3hAnQqvzR%{g0{AMH^{%*=Z~Hf)T5(!>8*`s8s(v72uM0 zC8-tEiC&4B>1D96*(uHfN}aAg5m3c~Dx$9;BBouBDCCapl#cTdF{wh zLh{eeiLt>yvjelQv@Z_6AtD>JruD3$YFK)I@2@NFCk6$SGC$j%w3J*LGKt9H zuHlNkNL|gT^sni>5R2Zum*5GJ^huIPYlIO}Uwt&cJNfc%gTg{Qn|_V?|FCeNv z%T@6NEPX2M=H!CqV_qJO>q`P>xBkz;*!#47+tlpc2e6BL^}+=pQTcGr*A>iUdCR|j zQJrJVKQ^BWV?$92uPtKLbZ^!&oM;mmnYwF!k&(SYGg0BAf7f(5G>$Nez-Q&bu0$AB zDEzSLm=AOjzYIv#_ItQP3p%ZT`r#E4PKG?pXFpSpDM#p-F)-pkOiC#*zx&HPG zTXuyv=BhNOI-;}T2}5X|I2(r~L5LEDhxpI~rtBbTHkpwK2IM+9`!D=M&`%p(GN|)V zYFy#5UE##vHe1*pG?pnllfZXeF6K}4^2^spoI)MhQw-zg2y4QCke)Y0W4z$`xjh6n zx_GRdx;2X=%mF&qs05j!-U|P|6XAK>k@43z-Zd`gEP=dV(+A@{9;O588(#vj|UxtQz0*8kXxVni^)P z$g8s+-3H%-0#g{=34Gq&JzW$4Z_$m!=p{L#80FMSy_*ROa&ENaOWq3_G(KIy?Bse2 zYrRKITY6ob2|?KW`9g0!-J6vRKe9oi(H*43={f!k#3OV;LE+ISWcqqNn=iK7P|f4@ zPu*+lJOgg0Jh{2_{O5;vD+?!%ni4pW(?}qMc z!X5S2SL5B-+-5z9#cvwyx6~*IOk+@< z&{(!Dr%!Ow9&97{EVxOXnA1((wCx+M9&sB>2}f8wOX{>HRY0^5JY^i#=7xQw$~RdV zJg~GB-P^)MOvJUO~LsNDgE1++*m!xQnXC`rs?78ma|L5c#u7ovTE!PxPrUX>+9(J!f&9 zs#j}S!`z0o$dp0X{BBb?BN4{5=fXyUK&I<_Yl&*KaDLZHByP%U``iVM-#)+xsd95S zZ!gGl;HX;{AIw;RzsSNkSe6E-Gaw-^7oiZboz_5hkc$0>Oii({ueaW?<>NGPR9EH% z@i^C3JOZ4rtqG(6ZCpVKv{4)EW6R0#h$d9O5$GKQ?PYx&hR;Jf%qRdm5SbqcH6#cP zkb-4w`8S}5gp?NNUG9P3Hh~Xl)G-MOX>k8su$EAI^y6(|#lDa3vQ?$fxW*Plh(Nay z=+EQ)7dGKh7s&nj07em0h41*SU}Qiq#ea>~QvIrTdEZXADYLojVEd@g#QmjI!BM~D z{I}DA1WH~ELJVi&0A>2-cI2}p*)gyUD>|d+Z7H{>C zoJGm&?DPiK8yGEo*ByFlv%3rw1mtdHw0ZOc?VwOk(jyw3kj*u)!rv>fh%O2^jxG|M zaE~tNkR8|jU!dknBs{1h!Po;?4PU{XB{$C+tj#O3IVy-SE9|~6*ReyT2|T5%-8=mf z5mCUmeXs*=?`x3>ckut$k~+jGyF&ONWSBkbkqPWp4W)!;m=?1PbyW?}DpBcWX6bd^I5k>=x}>*vUAtv2o}5LM<}K$MVp zGcQSO7xGh>#Ie5O_eE}AtygdEr?(T=Qt?&~$_IDM%khYmYYG+S=LRVCv(l0TvXrtc%Z&Z*!KvO>Jv-|?S#AYjA_)tl5hxK^GTb)x{*&h z6lnhY=tINH`HUXO=v?)v=-te%Cs}=nEL?;5D)i7iT8RNYWm8>>8%v(ePny3M4hnGd zk%b5H;ze20nyUB3s`uFkyKjk9KlpA_XWOSEkL;n|<4ZLnaiFeqX{u%E#R4z}QY1br zDsMonF);K@^=9`H9QNeZUDu7XJHkxB!`THJ0;r099IKbp8KEBU`v!;f(yALDTcVUx zZDd5shi9%J%3&m(BQMnf&m9n@uex%uqaIvQH>RHp0`|zSa|l&eZ76>lyFWpKqxzwG zphpiCG0_JzREDXi9;14yga=gN|0V$`}F$z zhUbA52^Bw-B1RNsfQak!P$y@3-`3KUH&0r1uu+5g0bX#(iCEv^X={~<>kH#&CMjmz zdlfd&MVCRr^Qi?lW-gpp{NbjyqXUeswlk}oe=NcuzSCp)h-^*E?r^+J{eiTZ5D4CNys4n+!E`1I)f2{!cCFA6Lsd z_x%}J&IE@5>^0<|=F4n*+H&kbj*?5>0MJWhLNuIa=f-#KC6oxxh>l22o zW%ot|PNJ4yV6TZMONw$v-~l5+X7O)9*m64DbFlH>s_Id@ z&Z-pTKX5;j06%oy3x^dB1#C|#;$qI}kMdcOpn^BhRt69hk^9Vs8$0+j7s8_@%=k#DZN{)qBHhoH`^-o2M;Pdl@7K0*ne7~ zcU;l~$U>fNr_oHEfnqekOtj4uJ2xAaF-4pk^;%w=^^Y0&MVg{M%lhd3>zw~2QKj*V zf42M=jc5x;|26yAq2Gq0)-V}$^$}}9b^U$IrrqSJlQ38aCh@9z;{2b)`InH(+y%F} z)$&V&;9^ZxfQpA1yrb5 zvxEpV84SDKpkvD|<^NkpLwBbE0TX=^<0M^ti4VjW2bTbK@B^?MUsRvL*hK;H@X}Q5 zdNq{7LAYn8y#k=$NYLlQn6{D9fa?uQLtqPY zsuCQD^LkDGhW&NJn$I`bmo4CVwa-rzsVVEn+^K(YfWoQE^~#|0Z38Lh_(3MIH_7+c zh0d`mYTaa$Up`MNz8Ml7i5t$JjVQn3p%dqAXp(R!?o&NcEW*Vy^OoV6iu3znNEuBpzO@phgxX2<#R$N%fimK?4)^dUF-DF*&igB%)x}2z^-%u?2ORCtjq@!+1xC~N`(keu;1=$Zao=S0D+pR~m9ldI; z@sk(o?PA8pliP!-!;Q`)@FlGNw}&RSbblB#p6mo{q{dtbTaa;j!VZ_-$<E*^2dPOh@hR!o&{J ze}+cZSIun9qC*ay!eX67)Vkqpi^co&-ai|IuFxe!#X-xdakr%fcY?PsA>I|iwIq-3 zb5aeqqd*Sk{~`2yjK@`k_eSN;l|YyzbyNK#G`X21WPpPtm22L7_o9VaUvv^vy}lm# z-o40fPTi8!qm>vQMVfP80!_de!Qjjn?Psr3w`TkGu;DG06Ds@1s&#ZB=hwaaq=J*G zuzbDL$^w6-xI8 zgSV^lz-2PP$9+FV{^KC%C!*_M?Tw(K$&JX-0Kv2=Gx&M|_#Nr+g^rS;e@dX|xnMsH z)9Bvt`l8_{Y6`0t^i!uypiRgKAFVU|{}qrHd_vFvrSEV<;_kM%?_pX~=xT<@P>Aj8?@I0?d6IB(0sqb3TREv)@wdK!5%I301=%N>pgDHd`QA)Ks?8Y7 zOSvo05|u`Iao$w=#0H7@gH?&QTf!PeRCU@$6BE61V-9|Kw{~o)y1NzjwDvoJBfN4M z=_kZ;VJT`*dN+G%eb)ik&04zb5=Xro%~x@9y}6eS6?2zh#;TlFliLpqRMyx!i)=3M zVBIN!ec08W25I1JMttpJ2j*yr)7bJGL?o0|-`=>yE6>;<0?Iw{6MDY6kl^26x~Q_A ztC8tlb#U3!qvoR&{$o3NNhAHj5B|a8kMP*0VojT_)W#FJTc!w%_KU&YVbbBLg^{;) ziB+*f4NSCxIlqm@HG7eZRdM3Pp}#*%*H_Jx|76~c_4aK}sh zMQM)4Q4RLEMx$qZoWtk*HwA9thiR5B~30}Hb(xqAAU2VHR6sEN6bZW zADH~W=rPDg04KN#wzY8{V1&0n#Nc) zXG%v;Jy~n)Q=A2c&5&{&wAXNt*vd<+XEaN_)AUANt%JDFl~C3n9I^>m@8Wg4?6S|I1nC>-+~e zqh}!&S0QXxBh(Uw*Lc7)SP~K7@C&VOS;35F?DT)ni*` zdFkcc@hqSUGgrs$5yea>9yoqxGZv|KW)q$rJ~yjor}G6Y-%-Mp8?|X_-5#VSor?aA zr0{9rM0%1?7ob=P8Em)kmrvA!lnPK^<}V-Tpbl`7aCF(N6>8l`^RWY|Ukj?IPz&Tt zM0yN5Kefk=Dm4b%jOC|j3VR%vgKalZ?&iruweegXq|F1zwVdTKpx+Kbv8XpW1Nz=zELv#PotWo17n6Pdz&RAHuMVXqMVib)Y3A^iI<;Reg%UXe2oh~O z#=%7KtPXy^2Kb@Z{%3*d&NuD;{sY)wvCg=qvspo@AunNQSjclf5i9*_~jM;6ak_SWV?2I1~?U5uheGnbRV<^_e{dlUA97o;ynLC5K!C zcE>G#x#m%_^vUd?uWKkDOWF=QCrNj(``Lx_M@;`1g=G5=+FUE&x?4GTa$|tBy2>}2 zY&XknH9M!wT@e4N1IOk5?igMq@;*UY6pP*NaasH7JLfB{y{BpIL642Gd`)`FWkLdi zINGJO@s|5fJoXWPV&BE?Oxs;)aaws?vFnT0xV`XkLSBbC7F1J{S!$T9+^e}Dld@4z z=qN%0qjN`)BV>6Fy@mOiK>if_G&Y>q7Tf3U|yIT)cq}#OAEZyUH_HtV{Oktkv6GOZm zKrS6|K6lcfA~iQanfp~+YYo@BRvKfpl3ElTa=vE9gXk2g#dRXBwJUHM*X6`|+E8J- zO-9|-Dkt}4#X&N}JbHzx@gsgz1BYsMe=7IZZMP~1yQ{fdmd5>q<;2ln-EnSYdt^_P z5&5@t?1_@$%{i11h!dAIC<^?<(IS4obkE!_uKX5)1~pE?VUvJ6z%%;TzGHZaNEkhhLtmQV^Qnd zeyn46)vo6{nD`GH0!r%4{flcfmK?(Ha<3u5f>}Ej5Duu`Ro?xO{cr1qs$c&eNqiry z-?wz>J=T=|sx(7jjYBO7;5WN_hOjhWmv3q{?G*-QtyF5CFxP#))c}L178o|=Khjic zkI>wnI0z|NJQEGd1J`Y#^V{LqbfqnHP806HgR$-KZcSJ;jL0q`>Cs3>Fj%(K2+E_Q zhqAFd)cSaKi29F*W)k*=%UAe;zm1g66rmW)zhW#)N4QmL;TA1KGRo98j&X2{2B)2) zVz$okP$zii2YM)&AtGJE1GeZku0a>o$4cp_1?I2ks79Em83~zKZv4$08Q#|$n>hg9 z#DOjMpix(^G=aFm6k50Q@7mZM11nPqZ(YYwS*U|v+bjKZu6E&s(}GlkwpL=!Y|Fy) z^((B)x~vB*`&dp_7J+Glu2iKD|fAu-<^s?~!HI`tOj+^f9jwMVA8 z$&a}#F!Aa9K@G2AU&ig{OjO1ERM>947!nyT1X-kUkujst0b}b(bzi9C=7Kz^( zJ_m_OB|)3IpNO&zPrm{dUw1l13L6@=3`BS-33=#~e%mnZw;+iYeEVYQf}IF{rn-b| zcDcIn53@Zbwn4$@y6~0SA=i^af~?pkrPn)%kQ<%a&`FH9|4Mhb;oG=H;Mnmg-ZM8z z%+b|bbLTheg6fESpWc2wWV8m@72Zj!5pn(@E(HM5N4d+GwT*CKl&re2v54sFT-Ahl zDu4PUs!I_Pvt^n)8rQ#GjiYRStsJ)$#MA0a_Jr3z5gSqoDdwBj6uqr4#|?w_`@^2H zQTaEbjrJ{VVX)mY=2qaXS>Wr!Qle$gS#;JBca7mS+%#ueQhQ&22q2tS9wB%Y9b$MZb9iZx{=r$vjCJu3&NrK<76j$qlnR zU=kY)l2RO@wKd(3=x8z`dqx7yP7HJC0+d3N$TxUn1h4R~B8&o2VdYZj=wYZ{h+aQK zh6sG1V^XPmH+rf4LgOv11_?E*pVeqa|>ImGsTPR6>PI69EOPti?J zRQ%p``qv4^fB@0-1);a>mml#}7Igy^^C!si#JA`&05zx+9wTG#?Awx*gYNXR z5bsbX)9m=#HBC7SFVBQpSjrYrW7h{f7jL!F(RoN_C*q9nrSB#Q*lH1;mkTsTe4B5ze>A?oy#!zBWd_GN!7AwEiI)$wWCjE24tBtcP}HO5JvgEFdI9S zit~9Y?aiK8FE60IH;})7!ia7$d+b(OdpMD6r1c9*qEKIz4nhBf+Y%D5Jse-mxAgrZ z!1n3qu=#6W;|qE|gV}G|cTUK80&K^+Aj3rx3P%2~?=o0dNdiuq^MUf5TGcAKVK)I?2a+PLSM8)*C2;jA$otJ=J_^-BiN>+Fp3H z>gc*=N6eR8I3h@iHf{Sbq}H{!{PeXryp`~qQr(X`GBg} zvAfx@1w#`Xv#j9AugN8`WTo}{M?|@M=0ERP1p$9Be$OG{lfIf@7Cssp+JSgA9=CZ@ z#aDcbXtp`Y6HTO&thz)mXHKlHr@Z?SAp06yTn zE7*oU8ukSyn`8@{3gPhkBD?F!kn{An{$Qqiiqi7xl)ksN+RvUAp3u<@*W4#qpQePl z?OiA-TsFzNR4ScC&pK<8VmC320%|?-Nsh-t^(9Mc7T;f%_?8v6%?E#e{7qnle5k@J ztvjD7q7%ltBN?z8kegv~p(>vO)mHESLUkraFZ}r9d=N?p^4hDc6YX8NBe(D!8_ud@ zp{w=mnMgq(aGd+w48@_xu$Q|)$C__SXdy{isKXjxw2lakECDU&k^lcTvcc+nu!oN289)p+mT!fI?>n9c36K#8xWn2X zK8H>dN#bxO#>KfwP#V%>ZZxHizToj+oZu)CmQRJN$uX-Tj0(Aul6J+D~r4v{y z#2aihYH}~PEIL_4_|KMqa_iG-%s~vWJVB6WOOx24Bo#$d5dmew!U&?BVYTP*5C$c%{cz(NaxF2-X~n`SZ$(= z9MPG8o<~1=Z&g^zlH6QeIkDago=)wdaK}!>w1sA$yl8vaPlEN%oID>Tp{o&1U-530 z3hvSk{q-eawT5+>?*4H<>J4p!sZVtxn^do#e95{!=`}y9I=b*< zN{;emmqDxnhM8|%gB7uDxuEU7x-qck;|C-la?W~=M)xJkpW#)J#^A)5Y9}Pq_|?4R zQf%~BMo?t~F`>KcQe$?Q>5nyepjy7-6#gU`@Ie3>U4g~xDkl(yH(72&3OJI%z&s(8 z2(_*K)bN)8{Qm6RkPzu-vK5f(4U@#fNbulqUEp*fx}8An25*n9YEaj33j z_p~kI>uV%wd`B`aVUbBiWUEQ`$D|cF{dwjK`BgozGRJCr?21Sm+K|CJ>B<6)MJ!EA zHS9bsk*A~AE^nqWG}O0|$>NRuH1b=VSBKp`(b~!^o)+`to&H0?)sbrdOTZE~+eR9T zPpQ3YSmxhgGa8LDo@HmR0a-p_RxV4sOunEZ;kP|PnWq9>uZ%jj3HoW%%0nIq7Y2ao zPl$vPFexCwD~fATbH~qwI57j$(^_t|m#L?$%$Mw=D*AX841<3C{~1OUabSj<;{mt2 zxV^C7C&oJiLtTRto9!B~mrpz%g%r1SVDtkx=gniJ*xD6(>*;Hzd8>x2wE3TM#pb?c zW}*Jy=)^yDok-&rkw@%pkIH7PbxU&Ggy_XKKpIK$=0cP#`TArt_!y>owCeEQ=spn8C}{m0h{zDe}*B}Xsm zt^KYTkLn1^(O&j?ps)k}vRQx)BMK=)W`tmiq1!Yi3vyON2@FBzI(X6oN_U3-3c?a? zpey`0+fNVY&N9Kmi^Zmd8AEu|6Hhf2JCHi`5a<7Ou^?(Oxb7rtW?)+aME~&7!9uW> zn&Rk#o--pd<+8`1M*!N4l{N?$hSdyNh85hF12#`lpqsx1n2%`26k9KoUtu(@M#w`y zNos~|3IQ?`fgwDs^gtdKLT71)qlN|to>yeVV>>(>Hwj+1>T8idCRZPOD*pk5;shHi zDt`(7Yz`u{`|YS$y79#${R%d(6_uWD(!{X#dS zqxnhHQbv54h0<*HwPCJv)7lr8m%YmHfCV({Fi5#K`v)NWp!a8)e9JO_x|=xNN|#>F zNNyn8Ru1GFpLf{V9`MG?T)TmOO1Y!>Q_)b4x<3XI&wN*2t_e!$EQ=8I3nI2M9+G)Z z<&`8_VI29pR#x;z>a^DVVX7%5T>22iB;ky#EDA&?ok;epi^9=!8N4F6jAe6%yclY* z)OQxd7Hyt5EFz5cnoY9`0lhIa_Pu*1%@Dd+>sCDGMc(El7_*~l*-z2z7Qsfv9S>vg zBy?Vk%-i@|gTpG=Nq8EM#02rIqZV%2^W=B6hQxnKVAxSMSzr$>cQ>rD>N9ofx?(J< zwmdn2IqY71zAwow$4Z}rgAvJPoSkC2)BIZMEiKISlyDuNBe6S%4xs#`%|S?p#;V|} zhh0be7ba`&iH}grBDXmXdf3D6o{p~M%+1m@GWXtIq7zA(fu~5gliC#$t zB*PfwAwb#aMIX(|P!}WG^0vTTr`j%i?epy^fJ=@2=BroUaU%pj?*odFZMU3g7hX|^ zPvvO^RCT%9pJWQc>wBIAT!f5b32VuSZdXo$TZX?QgJqEDe9EK4&pxk}RcRFV*{C3= zIkWq4p~$}|l&>uq-G9~~d+)*7P{x&Pp|$yD2%h{&Z@$DHJT6 zttU$f8f=izc+`FVmN}P3T~JzZh79(25u;>da9|$YiYcES@B%LEJ9+Tb5i~Z}x{Cy1-a& zMUe#?p>vlWFZ#afUKZVHE=0HriST{`uKREZv^!+ZZtJr{P8?r2aES;4pQ4iI;_@wmw}FhV?7HMNwcv zqo;FWuZ7EG*(qJ4P2u%*-^3Hl`P;$wD@U{Lrr5q$rIN1KZ(K`=1S#(-#UqK@<%Nji8(qH0 zA3&GW95sKC0faT`Kwq9LW5XpZ@Z1NadIMkblpQoX86MKQ30gp}mUBZN?M+6v&n#O!c9G4@EHwQ#!u z3NvU7B28uhbCs-5miX720j8mCK1vsu;9#U!kux^c)~;kz_b`#6b0kkA@eN8!W+jHS?YyR8jQ`w-N9P`GYdjpVO#fER#xv^!Jdr~t0Mo=aMbkr$ zaPLbx$p(wl+cZfuZ>(l?R4YB*q)|*qCTq$L=`L&v-K#l+n-q!e{lj$qhzPIoom02U z*qZY@7S8WDF?&RQwKQg* zv>Fq7SF~xb>GF{b$LDmo_dX>o1ZJH17P5lhS8=h~k0^7nD@r_edx8 zkIGu52P_p@J}I!S&;0=S0mIdcO4$YL9}MrS6qK1}T&bqasb9{@{2 z)&<-|PXzupd8K`8RDc2Pe(&hHqJ;+A3x00Q=ONx_i3gl6KV@{fhQ#f%n9Q5wn3$NM z@tprgJ3rZMfn2-dk>!$uvByc&{?33m{N~;b_g=S~YIBv+vS2-eS4MfeSPo`Cft;_+ zZN@z_smF1m74Pw%?k~2txf$X3k}&IZ@_aiXVX6}IsE~xNZ14H%FgLm@wRz`IK)R_f)7!gDP_+T=>Oa}~Ws&0k@xzn%xCgM)- zPIH#_kFG^-<~i{J4KkaVTKqv0)IUv9X6VX)(NJfIrwK+zND3IFh`|h9wx5Irk)*H# z5`@z_sy-0lxJ!~T@2t#l0$rSk2k4}Pr!DN+Wf&B z6&bJWkgfBTvk`?8RPF4DrO~h|FvSP%4B+CtOB_Hm&@z2uZr_OZbk-Er{ADTBg$uE52a4aWD z1?x#o+4r?R#VwT{zQ3MxuIQHRfe}x0_PA9y?-cGgWC@zPgMyyoFk-6a9Udl3nf9a# zpBZG@YpxeND{f2G;iJjO%y^8H4C9S)p`sL+q5>D}p4uaj$Z{~q(Y2Bz8;{CYMg z=ZP%5pGlmYuu{&LM$`8AAKgrheKVAikDP1LciXc&QI8H$bgPGHd^gzDQLA0`nzu?ouwTM=ee1eqV#tXz1;y{gl-|@JgL_az3e%-zlNU3 z%=PSD($gIk200nF_Fmey#(QlqaR`UImJJ_9UpVA7o-J-n(?y$@+ zL7c6N{5roylYF<}2EvyVg_*yIR`Slew}HA8?5bUOrqZR8hy0sk)#9&ldTj4FcQYAs z5}6X2#;{UX$ne-cr@hsnAa3(JblU&B)0<8&vE!_&l%y2RM~xlE)yX1WDetbIJyRE8 z@#Aiw-XKe^KYzD2i#4Nj9kd(%YGwV@y-@JqLv@B}an<0Uvr;ND^SbJ+P3(L@qPCN+ zL$aoCw%2*Bs1q(Fr@6jKr6z2vi3`b3v$XVqNUfkCU|2oFf!!Z1mFsy*2B{)gganBQ z!W)0u^4_&`wqtiM5B7XwVK|b^2lGI#K)%?YWQ7j6Z4ba43jU>o^V$%}0M6KswAqrt zMg+S|N8N9EP;;S2Nxl|fFO|`{l?f4`cBJ3l2aTsNen)y7K@0=j)Rp=J8bo3u={x-i zC__*JZSw@_|HsssM?>|;|NnjOj4{Jt>|-B{U5qumu`kJrJ`FuP>VG051#&S%+ zZ$(aLi3C;bw9ARkqOpfNA2@>RcqrZlnwH@YFRG*dK{Av2Aoo0E%1D56S`)G$k_t8Q zGqQ~{u_P?TL`;~S=x?iwRgcWl{el!*=;n&5_#s!tnW@xNXg$ro_(g~$F{CNs3g+TA z(r^z@1G4sPOFrnG60;fhuuCmu|B$!fbcUQegtEHUw%sDkX0u2*#XTZLKb$QyY^}1< z1(#^|O}~t%;2|CvrffF*fh0}%Fg8?xYD?)hwO+`Lw}3NMD)uT}?ug`r**5lv+&{oQ zAvW={-#AL-Dw>qN^tAx|Q<}>v9+NNh$ObkjQ3&Lh#e;HfS7iyCkwa)^qlw|iDBbQ( zPiMCd^dk)cUuGU}ys|i2kpG#8q&rM>FLVr_du}80Aw<@Tz0tEtFOH!jSe53R1=;@E zU1!o6Z=2~t-C!Tlhyqx-8`yRwJI(sISC^O}ooZ>&OPc1xv{;O-Ez~Yh<}DL!n(3o! zA_eg!w8-h-n6CX)yzbj#5wmT@|W#M344CbgWMGsOFnGc<4-i1vMVLhCF7RHu==)>+y0aIIdewJzE#|& zM=sz>;w>~y$Q}Hx?*Hr1Xkzg+#T`PPGoE~?{P$DkUy;;iW)T>^K>LXSXZwu|^=r?- zS}l=Eg^_ISy-|S4#*vK18K^34IWl~Rer&tkKjI9;Beer!Z)3*0J!#Fa~2ml8TrOp%JKLjDm}+(|3u zg3$L=VUiVQfe2g&x#Mm+QeW$X{n7et)aL>V z$H+z~968{%|KW&dRfZH9vcD5j&9zS-Llfo1LV!^>%Q>Xq$b_$JKbLHBpULhWOlBm< zp0~5qLJ}HW5S)1btIWT}u8iyax%Wpbzvo#wV7`#F=;^KXoJ5p78ksBe_w+AmfrILV zK6q$8^wbG5nh-Nhdpf?q%`O;Yx*7m52kIu(e$gaY0s1BU1CchX|b$$l}ro zPvlX6P^FKUP8Fn4yN;c9U1xB9#Yr(gMJB-xC4}!kOc2HG5!;;dc@%2*n-9*`3e^u?DG?1j6JO{wDC#1syqKDr zOqA1;?GdzS*>TtvG6|$wd^G{~ziYm#s$3Q@0e7{lpP7(Hs|;OeKh*6`R!cn3>md5~ z$iY(oJsR~_C6UBBX7DHGzd7!z#Y8-kI$>Vaxx&sbyJwN8b2NYww4;8lVZ2CFhZP`u ze*O*4IeNo9qc&Fc{4*`FQL)inLcY*5M))Z3RNs8yn2jY)m;Fk0$DV?yCP2=0?zm;W z$EGkytb5{{zO@lY_#ttqaVpJ9mY;Y?2AmWGp~7q_AS=rM!E|e07Bsv9tZN1Td@46n zJwV@%t^T~NI9{rvyy6u+X)t|Kcco1)bc25BHi_)qAH&ay(v`C@A zFGCGC5?EJ=tROUZDJ=>>A(17Mi^L?izs840 zMWjlisCaYZvYvU8YiGhXVb<<$=(rRHnX~~`K8$UI!Pmkp1&SPr#ARl|K#)I*m}&@U z^#|%Caff)GR_R9dw8;ooPfM4*gmX`d|J^Sm_+F9-kbI= zJm2`-u_83J?NYFH+7?qvVk$8Cw}B$=QQfJBXrP8C&1ZIIdI(%C1}qWrvpBR^^$4t& z&kpdSyp|IRzX|?_*S~~7z+agCnak^^CmwRO#Xt39}XDXC2yNt2xD`Vn$;opDT^ z4E5Wu1+to|Y9qum zdC6;^ey_=|UOn;8V)5sy$WTc2({oLhlj<3vcP}4*UveM--CtfSIP5V_c(tJCz5T5r zE#D|_V@J%f+dUoBi5nL1(bp#okq<$BXHI-&gw|{mwJIAu+gC_QdGqg8duX8>^==zo zyeXJh&ahc7V?dtrVDQh#PVe^P$InIw zGFDN9i#LN)O;B^Q&%W(0-S$%w_B^oG(XWi#cwe47zGeceK3N@n^Uw&JQaMJYn``0* zUZ3(8EE_(?%o(oa;T2d{TZ*2!|2%SV-|Xn((&Cwiu5z-9OoO7%2*rXoJIy3xxa77= z>GGIqQjO|$8b$Sd_~>(4uj98TXGh*0^vm6!rs4E!PEOw9)Q5nV#&D{B@&|d0kx>VMmg_m(TM|N_m7Rz!DOVAINJh`FqT4d_(_BXDsnJyyh zdHZmkLN?9wM9V9*=Fj@8;ggoaBN;SBCZ~6yRXKBv@M>bW2*dX7^8-8dBgem|UuZFB zXsC<0-@45Yt6nS)6)u)x9odPaJPZlb@bJ$2DAjfTzRcyWCACKqZ?=XGJlOr`@ax_( z*ISn7>1HW)#V53e9vnJ(b+^&fawb#slu*>Yl`C<3-N9$qtDB}*HV^eZs1Z@NaT47w zAe5UpHZ*YZipiw{zW!47G5Du5(?0pw%+1L-jhTSGY7fMJNiF&QxjL-3`B6i8=#Rih zx|SA4j}x&rkC_aAJ-B@5-NX1dmt7buY1t>&`e3PsSpTwC(KBTIjI}a`sO`@czeCuz zs%h-@dp3)uaq|UQ?*-M?Y&-mXct<=FkAC8w`fl%dlTnq&rq@t0lUptcT~`)wO(shn z$t;>089Mo(wk&k>9vEUs}$s^4sEp%VD!U z?_QcVDD~|WC>5G%RDFFpoO+#H(;1vM<^E#jKm0rXz%z49@{?ohIlRZ>{?;>T?#&8Ka5^Uq4D@Ws|q_Op;ml%{gG8#j$!xG%o9NE_EE1xe;wM6 zeQ>KwD!^QWiS7FCCA+<5y!^A4vj%~r@z%Ufc$?GWjmRGH`C`XczbN-oI7O(%h!>ab zeu0A7qt$tdfwFNw9m?J30<-<(gf9d25?Y%ccIbV(-{pNS8(MfVhrpT%XT3)!2UU~~ zl^C1nYafW!I$Zk7Su}v)I$dYD|ABWe13polz&kly{Ehm(zBx%SH&8ZKUY+mTKdD_>)f6nP3bssw@C%MmEE%VB`3WMS8-hcIdGmYr-HBhp+o;hmw!!SoZ51z)?C%8uPVbp#3$GnqeA0AN#%d@K&b;&t{keHV#Pxp6x zi`2*3x)4>3xE;&n(o?#B=%Fr0Uf(Twz2GA8`;A)1t^il5!$J#(>u@22qH660EArvK zs~C=t1eUNQq`}#qr#-rB+oIij$K*)wU6L=F+y8{>UwM@~#R<+jVxK(#AAKz9>uB)( zw&7dRcjxXCq?c_&rbFizLqaBt5Xxrat_PjuRjKDsPIx&deec~VWEVB7d}p_iQFd%$ zA$_+;T57U>`0AivtJ)sZ{C>%q-fEk_H&dVUSG7&ZTJ2$3ly28Jl9KNb%{;4e`mXum z0pm#7_?-iXKLzM_EHzzIU>M!JW}sm5L9n?sgd+bRV{3uO?{eK=8D>#XjMP}oPx_++ z=kgZ&Ya=j4jft9DS{}-QlJY_`(?VUQ)vsIP!?h)dHA3v--Eykr6bIL9fs={{T6b>O zoxUr*q<;!~+y7v-m8xdzYEAd0mf$~M#ljvJ|7Rn^p`K)f$ zmx2M+CH26WQ11sq?{9o94p%v;_4W=`-1J!H`oZ<9h$oR;5c8;;C(XR#!>`>QrCKhm zM=5XORl5{}+@t(7zc-hHT_IHOF`|5V*-YeZny$4FWUlm#vPYBHJ?}+c*psrwn6ZEA zFyVt$6Ll!M_EW9kqK(#$H#%mnPVn*1tKj>stPR6E8?=(xOE=ql!zAi~sH2 zbIN$aZ|cFWz>By4)8lbXr){g0bW@U!Gp#O=WZ@Kg_=6*9QcsGEUXGwI96D{oJX>^l zQgP<-e@(BA0;Ys4Tlqb{OR6_U3J1VmCZ(NDNv2Qr^ezdj;HJPuHA3bf4+<1fy zuSyuK$C4WC#e{r*=qb4Ow*~f(wx29${C2Bu@QU?{w3u0Nx?|G8S-NS*>zkVsm0Bj} zI-`%M=l{IkK2y=N&18sk?F)Iw#wF$qBBjf-QH;c{&Arvkd2*(^WpGpeuIJ`I=jmem z{(t3l*9ZCR&8FW}B`u4qmT#--n%G~$qx#iSRM55A2)0PB`c;Q0Ur?wBx%c0IC&fi$ z{EV9&!|Dm=w@BtCucKB@jo0Asymcd$kkgryUN&9+NvPH#eW}oJCznE*y}%@OJv~wU$@1ZG750k781WWrc*&-!!q8;w1aGzdt#L z;qT@(4!OTziBvcXDUh-Y(%tJ<)%qk%|vmDetV+b0WX*C1DDxNu*~HCx*s1O=qeq?lTM5pQM{A{a9WkCj1qqei*WJ=MYej5nLxRUcU=hEV_$%i#d!tRG1^N*b46&KDghTC3duB;?b*5%cUSLhj<8qm|qCA2&&J>C*kk zckcB~hTC7^{y2SM57u4>+38D`4*4e^ciu$%#JleShUmo~2df4ZfR+Z-66M^a$*!i8g)(=Y5TSW~pPwu&rtknE`Ua6+K&BQ6M@p|5j z6n;@w<>O3lu)Ooi%{E{%bW%tm^Ju`0tKL3S%jb7H2QIv8iW`o-wl z5p+;T+IC`3718m+J;%2=llsOnpS6?A7SIcslt+Q5uDaixHrJ9Kb+r1v8cx2r@ao#i zSn{Kdl9>j)RrW27DEVK#Vpk+jR}%(wzfBol;gnsgJs#u8A~=O!Pu?V3b?%*Fq~Y(Z z{rB7Vp={^nKfBGB9*3`W&86rk&_6Y}-ng!>-Jg*j>W|hN9k0>j$r+dSwb5lYqMmD< zpQzQUN%KF%?;6XVw~4ydO{AY|>4a zyfgc^%V{ntMKpq>6lJ*GX@adQ6HNZ%0g8jg%QD#aGsdR^ z*0`aF!Zp{-bNy6JUb;n0+uxkcuW7E$kOwId|nqd zo6vLAOTbPkyF0O6{d%`wCm8+8{Wyqj%%1(=KZed3I}rQb?zhz1qp9TJtI~<$@=to7 z*f?H3?okeZZ!G^W%{bztj?L%NXZfF-3Vl&+4N&eEAAzaa`0Gyben$z@zh5;OzHhv7 z@Pf3%&}eghzKF={Pkr; z`=uKP+s&VTv$F_R%vs|G{N)8?5vnatszna&sMK1!8uzPl@3n6UdO3gPcUIWdYIN4e zx3NVe2X_WLSX=LZBHLB=gHNY*pmWg5 zqRZ^KU)KHuAM5l?ch4=aV{n<%BFvgry^ z;_1wT1i2y0SdJXJbt)b36#1=$6$F}w6z9ORj4$Ywo?4{E2(=`~72b;ju^Cm!6pdtYoz~bImH7N{F&7*jj5{C< zB54GRqzE?OBe84LR}R>K(;{D0TUTCqrfvs>A?wp1(=&B8g>61?LSi`WF^|ZlV0S3a z09GS$cvN~xWeb+S!-D$-a(9+hwaQ4eI39tR=h4)g1kjJ8Ibc_I5x`+eaLe(D2$~sZ zUHIM1QBr7c9>^A^PN^bo!fZY`$b~A5nD7dtV^Zfx8hTykgCkk4{3V%3>u__cqk3!^ z`=*Hd?!w;StQ5^!K4~oOC&#>_`7-UICZEcx_|wjqxz?qJgq#~_n?*{N&uQ|HoQlH{ zo4VM|n9irnr)A%13uwvnDHEJnuctw2QDLwLYN4Ukft1|Y-$*ua_#z`k0XeHD5aCT$ zbyhk&+}=L8XtP_!;{Zae&Te;YZpat@E8w=f?^mVX^mxe z;*RH{MqJX2d`T={z!-Qit#>Nh4PkwdN;qp8V9}R{EC(u~ubd_zX;N)b=OrF0Kpd z8k#}O#ST)M_&ZFjh}&_Od9}a;MVm;$3=Gv1E#E1Y5|WxX6%-Ik*Yy1FZNhI?sKFiy z*~CMwYs3OD%ZQl{T=u32(0`MJ7$~wr-7r*8o~1;yv8VX9o{6ycr11SV;AQQb7S*_6 zFZ;TZ^+jdWs^y{E@PJr5gR)Ig5+_UHKk-phPCLV>_m}(C&g_O=OPSLApH=7;ESV5{ z#kQt}#$u5S&32V#POy^6_)}=RF2?<1W~?CR1-opaw!$d{!4c-eT?!!t-r6VK5E4)I zIHg4Wh#L<7H;JEV;Q?p$MK2Af#J4H`ZesUY7SEw^LQ$*Mn7`kgLrA0qu^MzLh=YIx zkR^#`C3S=Xb~}|DkPKLt^0r)HcECysYGX3Sult_`GXP?z5;wHGB6=E%b`9_Tlt=>T zR{L>X$eN1qqAMO!L@CaI+vdQ4AZy4NAU!0Y195dwRFH82)cC-Lc2p^9f(HdsRsv{% zWk&#_>nxTt@Rq@*U^3(~z&aHqM4(B!(v&1BVr>|Sb}Qgg>D{Q{xNvJa=w)9}!mzbr z76e_Je&AZ4s3eNkvo|^xP9l-ubqGyTMR5bo7fDoQJXJ)0=p24nLVHo36b3`ZWU>T& zd6f9W9)TC@?ode&Z)3!un07MC#m8p80)rTuR884`F7OJ~Kksi249w(4c~y;JhH#W0 z`Ijw7wnezx>pmB8#MMs{>qI!IH6{|HgC5|B2%;`Zy~~3f5J3d7RD-tahnv&SO6ZB0 z^5puXI#cRH4g(iNMuqDlnUPDBG+rea%%vHgxGp|Vf1#Fa-n-_x9jF7UQRM;(G^}IS zNvfahlCXtKli-`yB0URM&_ABPL@%3g0_h-xA)5f`Y}|x-qW{Hi&Vfi=`?GyTvU{id+9G<| zq#7V6^^Juvo`p=PT1%V2N>H;LarjI1CPIl-x#=w_G^hBieHTj14`1jcWCh$i zqJ`C^Jvm`E&oLOWq}*7hbTC0O)&>|a*!=Z@<>Rs`7Y%9)S+xU!xzc^~OH=g7J^ zo}EKf#L&v4M}3Tb{efe|5>N2IFz15a#w=YI&#!#h+5MX%?y11fGuQFLf;vin_}`{y z9V=x!nZB3|aNi;g`E4XF4O2y)d3Yr`h9q0|B4U+LqKR&y(FxM~{Qdc2kf*0-%(EwU z$|Mb-8-4T823NJkae8;dFfr-u)(EoojAv`A5(w6AAN*fiB}}@Ij*A zCp>U9broERB_Ut+*qOp?Wq1WkVjsnF#PPsVoqAUfjKP>`PeZg(mdDJOdm{ zM}DFcL#z|_>3!#c^2I7k)MoBxF+;)B7Li0U$+_LES0uaAr-%eoNWVit5)^)lK-fb8 z4=B_CH$R@~=6kl#8Jq4L0Oggd~;wKmruQ5Zo&^oLDGtcp2pgon6CJqn5al+^G zAQ_&Fz|5910b4TmqQiJQ|Ni4>*3o0F(y)DzREcEHTSdqN9){fgxx7(J5!i=eFDX!w zwJ!Idz_~zU^& zZd##BTDJ@MOZGXFGi2F~=wm_MZv$@#Ay!{hv2DiKdez44cDA|-s;ML=&cdC*(7e5d zh9qYkjJVS;UG)&{>QgQA`)pcCk1$qd3JOB(<7{WwHjP(*k7(FPxY-OyRP(dQybVWW zm&B=qv{z%?+y0q9C8a>Cvs=N`xZf|>D^6_-HmqHcPQCClX9)2rpy#^GiOA)5k#vTc z!z{ja*~3^6*4cI5piacCS_gYTw{xBs!5vbvkJ+_ak4+oEfTtTmBm~N^48;@BO2Vi# z^Uwu@4EM18i9JFzS`LMuf@h?vfq$oKc~{yaVh9zh=h)UmxYI1*?w!WyP@Y$2AXHON z!0t+B1z$)DpB~G!`!q##8*-1TsOV@_-7BL$ZL*>f;v|`EFPk&ow8B%ugAA?0i3=kY zAJ1-H)oh|3#>u1@+CA|8bxGBAu;Gv+(pXGC{Mjm7M)xi z#Fc{ zCa}u{<&*e%1YT99uS~kfs!XK_niT$?D3w`xvJjPZv0IO- zkT09ZRp5NQdwo-}xQ)zd6!q^e?J@sk2qG)8Q(t9NARRc+1p#|~5o#EmuZqZUXV#Em zCg_Xf9+#Hix?$NxzyQsWfFGeaT;Rfoq;Bv60|p`X2%bvEaOB{Ye&8tpy~zVVsfa3; zm4;2^g-K~38=I(#XI4m1t)9sZ|b602t_gbxv=5IW;v#c?2Z`}qR_3VJjIBazmwv^$iWjRdi8M&F~Ap zf?QAOSOfL>n@ni!G!?9J^CDwk(dS*=`})!5@;(jq!1>uOM|X~x-Lol<@2@-dEGkfL z&pDJ7cDsT4diPqGBPFn9KLBY*!a=VSjl(#rB$oLn)9YCU#q*XK7*fgEc4B zr~d*gH1tv7@io%`GMDHY!WVRze%v!EQ(lhrwDJP)(2#`(<_8p-UuU`QLG~bIlx57Y z!Krydi)jU-Z?X?9m8Zq4Q^U3);`7~Z-%_ROUtkG8ZG5ETZn}Zf$8n`8|1Mb&sxl^uYphj&j}3eBR^6)4 z5D`(Fhdx5^PRet-c4yO3X|#MnJ`I#7As%>7yW>Ra@Y`wiIUSL?%cLNYA+i{+C66nGuz>?fjM$sVl zDH|ZN@MQI+^{Ex>gPR_jU|{$a+bJp_PF{YykV0oTK62L?M}`guHC z6b|Brld{ot1u>c~9w`*T9mkR^tMBa*K+$F3i9MhV2lEL-K`1X@DAg`pMMT!~6v!ZR zcKrM8hC$>ZF&ko&0{fSqG2t#+-f zE$(uDDuM?nPBc}BQ=yp-i}P)L;O)DWsKj3V^F0lXd~x92L<;svjDLEFYyO@1JJe7} z>7fvxV)4ZW5&ztBV$=fVR`6I{YUYOGzSh2p6xD z_$eK{zXdy$(?rqo1gg`uJxP0Hv!=7$x()10(NE3)`SVYOsUAg2wm*L`y7a+kD<0QO4PmtFYxisHu6;fZYW|=ds^X$(0aXvCb z)z|aJ$Xk|Br9NHL_^;skKDAUDnqYPKrO4mzZ#pgk9c`%AD5Sb#HYVrXo`J}uvaU523dQbd|rXtd4FMkaGc0}9kUzoD@GU&47UVhS5m=#8){v<6*Pl~+1vMBfY#z0-@3V! zP`%LDG?^INV==F8&DesGY>0LiU3Yy4&|!d?wW_^DRg9gH9hfZP{m0K&4vF#54L%y| z^H`NXHYd4$CEtdNw`v!#wSRgxX=zl7u6UVjUow?`Vyuxa(ywR98E%qoM-xi{pDQRv zugJr)ca^{{>BiV7+A!?ZbiONqqJmuS=nXouM;YeCin60H&?_uR5(hVhpz*Slv{z?2 zJo|maL(%C2pIy>EXBv4YB#6aoe>rG8ojinkh&}I-H11n8`yG?J6rca0n74UrBuO}Z zNK7>?9xoEU;DI?);3VgNqjP37?OJ>F_X-NUR()|}T5=_iobE ziBn`eP&mkttX=kut5yx8qbgjYJH(}3gf&qYn;c+hHjHhBTBG{44>ZW`G)RYKXJhPt zx>_%pwq}QVvH2&-Ed~u{Fe-r>j^RR1ub^#O53#eIS1d$wG_p%d9%ZEITg7<&$#C9Yh>DGBv2miMgivL7=3gr8 zhKhQD+~!J%tA9zE`>^h5j7a#8R&v!%>6SkAT$d(1>Zh5`r5~g-Va_?1u>PG-&dnaK zoZZJbYPxV$DVqREd>0&Z-C8;a=%HKJ8&cMP(*hMwtB8PqeWIH#jfFX~mFxySel;;b zLQJ6kUpW)kRmK%c)s>vqk&P$r-h2)~bZgQR5YKMOP=OML=%fBmAtN&#)qW=XBRAHQ z#7TJU$}MMsf&%n|D+BM36bi$EY9P1^-F^w}sV+h_OY1o+!j=-HDM1rFAOzDNzY|## z1CTo2Uk-9srsV@`XyG}~7Ki-ik!yv}v>~=d5Zadk+LYOeG*-kimJNeJ90@@8^)J7b z1d{4wSoB#Zl0JG|NRjHq0J}wzbwcZ}INDlZ?1rc?M~V^MHM~1KD^)YJhmg;T{heNM zed-7KvHPr$5e2%Mw$nOps#AKzKOp0eDDukW=zMeUDNXfDu}M`zXSvlL}kC67KH;}J!$EYhp?iDIg3Yz)GAFSM%|>|S6}s5 zd8ZfL9{QDX8TpWCYtx)sO)VbCO|)0E8Himb6Rn<4GGPL4DGocelH29MW41&UPMQjw z)01_|!1$cceCAwToP&a6RXNe}H*=|Nhc}63Kol(~m zPO6-?1G!PTz~fnnU8&3+<*DkV2i|zbd#uf%*A9o+6mAP#=S@b5BN(CJ!i=6m-nW)( zzO66I%PfYwNz}igDw$SB@sPe^HMh1`LTB~2o~sTU*dtv9(FhAGEIWZr^q>?EW#CCB zyxp0EWgpZ}i_hp1_}DY|t@f3Z6xL@!1^x%E&=XC|D!r#_uK-?b-0&wuJx693D?Hel}exf zIQ*5*NDUjErsml&s7eW6t#_ePnR$64(*s-g;$fB>ar0%jeCG27`A=v80izoylcJGh z+;*d91-mC-aJjOyy`@n5I;{WNg(Yb}SO8)q%J!BT@V6b<{qGhw_i*>fk@b);NNM4w zlCR5`(b8i~sr+APS#|m3j}eU7hxmgwDLuW%O}0s-o7i4*LPtV2J$Lw@$u`C zB&x^sg;n&6e;r2YF4SL)o^5d$d?IMGyf%RXt3sgR$F<#P7Ye8--g?9bSlE9DFx*p! z3L6C;)~Ad?WmEOkrTy5D9c9d+(|7^b(IcGrTzxt8%QdoR&cKzRCpnG zUVt@osG&$1xw`IXhI_SN7y4iabX3882)u)8#>TVQI(f86?QhTc#weOnH?>8F^fF}R z4;rd;GQ1cDz{x0vkLO+Up-w})hGK7Tv%_iLN@K2dpJb@7_JC?q-w}Dyh5hjvA})Q> zxQl7E6R86geCTlBzJd^ci?WE_Ef#If@+;a`O-;I_0sqE5JGVr*263wRq1v1@b2h=ObXObMb(f}=NnMVo>7<7!_VS!P;3O}ZYzEM)H~~BwnjPTzq5~1gd6qI&lwi%lf$t>{!^r5S?XaSHZ3ccvWa{UvX^UAoN$!d zGkz$VgmH`VhqYac<)9O{h6PtdrUrW9y^_4Tg^sds-}X}Hg3*SqfnZSB8vbPVNtxW9 zDDpzF%*yLH;qVJCo|p+?`}J&qR@{G8t2=&BI~LMqox)plVX4y6XLf_9vIS9=OHq32 zS7>2Ww;!>*b%@A=4Nn!4>J#S?-G(E=r=Kg8XuNvVX%13dF=|QaXQ7@8B#fvKixmdb zP8d%!0507kNmj}s7mb5k;w;kJraZgpM?4-t@ol+d+NyS5D-ix2Kn)^IE7JI(8aG8?i{)lC ze9Qtf1eyiZ?g9p&gGy-{Set*&RF)BXp%Qab1ik|{Bp@Dmi5F@-Lf}ZC4P#(gCAQYv zJtDLr;6y{OWPy*u!(`|pH=rBihJ|v;Y#y|_iHlM&D9AE-%GbTSsBl;KMo}W3$tOa1 zJWsxWW9y^U(|`t^&#>(e;@T9A zE9k1}Qi#6i`>uryy?1suLIDv=-w!((hQWeU%*0Dbg|e{#<*GVbv!axuZsLrkToa=8 z)gIjVZgZWWN$1S}g2Szmf8|~?Kh;etPgjxP%IGDvbj;6CR+R5k+q2ZI*qz-{xwfMo z9wZAy6;>`y^GhGwqus}|d#XZrGr6+R72l=n7ME+Tz)<2QF((J!k?xiTH80M} z)EKm7!p98uN49wMnzy^8o#tbotM?!{uu+=Xa0H0l2f63 z^E%dr_qY)IfMEJwhQKxXSnG`)+4jdsj=h4c{MB>}Kej#bgov$?Knx{z+WgU|@JvQ) zz0NOTO*k?@9J^WAL_Z!XAb(RW(LG7fGgILqudM2^IC2R806Wty{07lSko~S3m(i=J z{fD3LqOkHl(voMb7YAv`2om($*pxoVidLCa0| z=a@o*YS@#Uyc#~VMX2P##n$icFV$Ix`SB3b=$jLZJ+r?TXBAq-*l-HtWA4asR7%*oVgt_ z$!R}nTlEQ)i26=-UoHmmb*n=%sQ_;HENsDhe(K?cQjYf-Mg{)Hk*OKvM2%%V^9z@v z-d%08Fe%|o`lOYS5{^ztJuTp<_tv&!i(iCw07UU^?JG}m_rU$s_;VoWhXR+oSOcx9 zs1cOJqUx;g_lE7lA%qAmM;Gk&q0aL!zmQ!6ufXQc#aA zbeummty~-yv1K1DB!FFfT+;!Gm&bk|R$UEClH_At6GFGjL2nePVU9pD6X7R7(gnbZ zL{;SNlS~8kEB{%96GVrVTuQ22hY{|uQwf58C}9>z7=|j`-qCkJ4{_CFmlN1#tPL|P zi=4k(L_rMOD*o7s2cg)1#2p|2!8u!nn-^Fem{_W`D2rnwsq6S4@AJFV1`~WUU+6%W zwx@r6S*c#XJ8QT5HFYB{YaKlvi3C@IlR3c7IlGX3PcYFgq?9Z(|48|itD^^~b_ZY7 zfCu1)+kxjeL_gCDRGxL|cln?n`l|COB*gzs@Vv^y;+G5QC1HwuOdr|~=Af#1COnOy z))l5cutS1+j@VA6^27yWP8Pmt+}%euImt2!tELbOOCsk^QEgOb!Kg5-Dv~ksynCCo zQf>NkLH$l!^{86Pd1X65;#C)NCg}jR--0wt`P~eY8niD;H&v<}+pC_I)v-^ZN=NGo zr1`4OBq+zzrFWte#r%Lu8w1J=X^Wz{(y9o(My|QYd&<|7m!}uEUaG`04tI{i;L^5Z z3;UO%CNKn^ugW0Nx^c&p_|NrQFL6+og_1%fCFa9}F5=bNCWJXLlt?(Z&8XQDrjaR_vgdp))q$O6D_C zgPyV#<1g9?BdOGl47Vm(lejQ*C8txV+cYckKVMWc>Z9JmtIj6J6_nO8ns1!3sl9KQ zcSs)>95!>Bo^0Q_y|50>QW7yt>vj4Oq~lJT0hgki?|q*q>^vZF<+8(wO#t-_LG(9) zPtg*@Sv43Q?b9)36EE=yfdG9$ac3=~DvTVEHmq_V3W@X1m!|RfZ&z~h6xKO_xZ4<9 zkizab>Y${C7@fOz12@o^a$@e{z{+eSO&8+yTWouovS>f_6=U`&ZL^E(WiR;qVC`j5 zJ(X1u$&YAI(FFCCY)9(jwe|Z>x@aZ}w4lICz~NtiQx1ST#4blu<+rZeH?ErFB{+!X zzYbgEwIULPrrQ7|0T6u$$40?;5w-(?Z4ZWzqS(J*m!k6(fmja65T?$Ea#Axqc9YRu zTVXKo$JBm!t0@ElXJjUnQg9w992i=;=!?Quu{l98N-H>a97>mm{tWzw@R>GbS}+j`crI^1W_QNld4(ux_df<^JP zt(P6u#GA2So_$w$dS3LN)S(?GoV!}fL-Iz8Wkj0uB&ep;k&s1RrYbX&oFA%6JbiCL zgH#Ufp_h1YV{SmE0H1K0mUiicYl3dUX%~*Y*ss9`C$C4p&X;Td$;goPnI;G(x^-Io z%(~C<=|>jM@;8_qAnA(QX1#P`x3Ny*ql8{S209Pa0EKmed4pFnn$|Q@*P(59pes?4 zN0~1xC9Qx5dQbAJX2Z%Il7q?_yp!n&0*zwB1;Il7b+uepYQomHR z-=u!D)wC~p32$hgs*zfJmM;Z6nYeS_3AP+ymA-B?DN~IX=Y&#ck!PMm;ukBg?y-=H zZ|8W+27I?4Jb*e(6YwZAE1~e5hGvyU=3{R!9$VD@3hVmXX%CT7S1TF3oip(SCTtrkrgfC)lxy8I z6DNiAYEzKyg0Ji>@}WQ6-YcE`B<@CvBcN>qRJN6FD{;eWV~hCjoA_3sIW)StWxQ1+ z{`=%t^g@n(7hvYv=$)yPIpVK~ML-iQG?$V-zl=iSPGC9T(Gy{S6FL3FU^-=wB0Cgf zgO%%V&w`UHhs%KXGpU95Zrj#HsZ;w49!le=e2-E=Ng>jOre^>p(7FSno`S$Pj^It!w#9$ymg@h=OE6lulr-&LUF4ZvwiE9|~e4 z&xoitesrrjg2XEU2S-H1R|3QIyh~;;@%{@F=D=9G+Uqo8X6cdKS&}12!d5)Za?3!% z8OF_t>}Xj&byqB+gJ)mMp)HS`b#BQ53c@TGv2~FQS04qHQ-`SnL3$gCJGVpAtsWzJN&h-D{*9SWIvJqwQZ8v#i4oiWC9OkGOgBZ(bsk1R(Z+cCI8NK?tIsY1@xkuk&5i=5Vdb{U_O#$|vmam|cNsjGC_`3kZ$A<|m{Mk;hVe-l; zwkDfFi%ZKvng1hl=hNOr(sshWy=9zSf@iy^<@QQ%q#6d7q+EWbilcu z3+Dp#zO=8*rfQ;O4WCGpPY~?UX*k)U6VVmzo^sE9%ZB2}6fa@NZF`nDs?JvjWn#~Z zaY=1GJsnMlvagzdD9yHCU{72+Ww0}lp#gC7nAZZW9m5(0jjBOH-I_wJOQYLrmQ~)U ztjswz@!x#<&Y?&se^i|$O6jI$U`fG=3+d;>uMx2P4(mzOzW>M6nTJF5zj6O_X2zId zFvil@$37v(zBBfHS0rhysgxx|DQB!>A6p?YAyg`~QL3>ol`WM@HI|BRs!=LQJbu^p zJlFM{|Ic;)IiGXx`+eW<*ZW?X!`)%l1xWgk)!CI8DT&DEu+~9pg<0Y1L=U9DAN!nQ zWmff-ja!J6E?P@Jl$N6}3BYxQ*r6;!pKO$Z9({BQaow};J6+J4{=#PN;-ahiH&2#T z4?3xUR*IKIv$0kBP=8-HVZv+Ddc3=}*HA1wRC1l?_MG_Q(laTWp)u17PRebZpWch$ zP-35f^4{2JD`^d_k_EOX@9#9ToUngP$Ffy}S*rm(!i30HV_iVs&fYr+qcHpHh!!bf zu}^jhKLsEDrMfBycyU>X6JF4~lL_a{C61i>^To!YWHvAK#A_$~Bx7`)7HpsWA;z)N zg4XIORTuE&HAyVL#7FoH>j_)RFcEvv!rNu1{@g9Isp2^bzmHyvqui*#oeu=u6GNQJ zt>5Km?esFT3O{Zui8go;Xub9IVmlwIjFl=`dg>&Az2xguA$zW6+I;F~`P8>koL0k) zq9W9GL@|7E``Gj^iMZNGfjM02p}9xCS$J3ypodeh%K(l9B32g-QdepXOSbkysn_)p zi3l1RxZ|z$sLps6i-&(KGo~n{nY?>8J6*|B1!Ai}h5BH+PXyk?#+X9_D7Kpd?2L-c z1$HXbJZr$i3vDPO!mZ+VW2Up<-Ne>VlA?T&?Fw*+ zzi4Rn9DN$UXnSKE|U8;FzyLmmFWgNFiG{dUZj5)_OSG zcFG@j(vcAgdaRTf`QV#?kd#n;E{hYUF!3j1vKrj|p`vuVzRGOY%Iq1|#i=hOxu1nD zNQ^vQt#d@Z?_|R+ZkCkq`Jec-G(zr^wJ%%;7Ew&3DE~|uQmx81;IfmsP(WXtNUyN1 zcubNtK0ax$QjZ<^N$@e4kJOkR+0Gw}G~T^H+i5}H&V^EY4Kaj_b{KPeW&0(RcFXTv znk7q&D@{kzw8Y7A-1DQ}c~=i)-1guG(wE%czTRb~2eb+7OGEv=XakiKh zy^k!vCc!Sep57dxf$^3B-sKto`{9BQ7`HO=X^Pa;?g7%Wiy>le%E{)z1RZJRJ9{mo zH)}uf6Hg`Oo7leNMj3?&z9)yuwfdJYD9q)#%-uB-MiIlyKNyDaH7^!y!$_qo1U-`A z*VG-Cu-;~G`F{s zdol+xT;)1b$t%*(OH??*!$+e|;Vi7kfp2nT%JP3fS@DyWJTWSTo#-C@DaDv7DI>na zq|5T61)>GoGE^=3*j#q@8tnc@#CF-Xu)jg+AnKE)L~*9|(W>iIL0_!1oyiW&AxG%s zKvGt?=7R3wIj`l)BA~+fA0!n>v!$Q14yi632+a^yWfi5w%*$SL-FhvNm?#{nzwy}_ zzR7b8_aQY>U3|}^^A#+!UW%zUjvFFD(-@kAGRx3pLV4}c1rgBN)5cf_Z1r_Z!H=nN z^IN+IQcHxlCqvOF_C-|+(}8-C?Gf-_lR-EdQKns$b`*go0V7*j5WrOx-~x&50s*U+ zFPX)FNni_$fX-}?j^)G&6V9T-CPXnLEfhNk&LqKkm~myyv>vJTG!gJ3NDiP?p8w1+$8~0WD5#953Jc3lu zm>DX;2giu}N>zy;m{Hzzwyjxaf9J0)*;OdwI^+MWfng0gNmO+q6DALqb5EFb0?&>J zjI^g_Gq=%K+WBI0**Yo2LEs1+;NOZsy3ylQrM4pi?n@1BMlG^`yL1xyrift#f*o@R zqaltGI7!YLs;~{hboel0WVyJkh=q&<{Pj5k@`Nr)Ci7NOu7h+hl(G9d#I_bb?09*c z)fjGAC0;_gkY0g7SH&;shNaRQV|xUV8*^74V%QS!ZU9ig5#BDK79m<>;2 zjs-_>3yY8i0q-b9^QDp6@3oB_FB_N{Ha3fCUF785 zR0>80qg{(Ve3^I-`h?RHNB+JNE5Sq!$J`G7a5!YZ2eIIuP~Z8U`fd+OR$`fahKc`gR-Tmtfhi>#3ybCOh|kfa{vH$z!Grig&ZZElz8hTf-^n8Qgi}zV>M6o>319TNYF;blz2@&9+fp=-GsyfpZtUR7?qfyq zBfu*}(|L%TX5tu0xy^{J>D?7{roMu_HjuybsldXCe1loy?8`JBsEfB9wm9l4?dm0s zQDMLJBm(({tb9!+{`*$S>8`_WL{xD_EE^m}89O#y4omN4As#Q$va3h%Muh4#2~rGS ztKB3e)qT0y9jTM8J&qMN)k#fm)AC)kx$L6xH%UOU3xVs1PdqrDabfrF;oyauQB z=&3G|^~TfYx7CXzis)%Xs$P)_Fh~UG*fbk$rN~zFo`8fgl>j%p7kW(8{LLl44x)6`k8W4p~?u5e-kN4U_|= zj^$<9mqZ(5c6ASR=GLhgLd`Yr^%NY4T?5uvUWvEA`pg({lDlasg@?k^UHH#eVjfwY zsrBn0IH{l$Y>r8E79&Y~J>&j^0yj%Iy%x15?BZw<;KVz2GeZ$S)B6IL6B@54GnCaOMYVBJtfjW5s`S+@PTURm?smoOo_qC zlBI*a_!%BXB!e(YIuwpqe8{CKGbH@8i_-+-%fI*cAPuYyPab>BIeYfut@EY0LS2=d zQ7@ahlKCm|3H*^A6zQC7_;@wQ?yso(dt-Cmv-Ww$n27Tdmng&>gyVAVCy1l!whxGXjXt5zkn;UTUQ_;-obj z@ELZq%aaMoFK)~VVZi~6_bV|)yssrz((Bq%g3wfCt*}X4jzLDob0d~;n}n_68vH9A zJi?)Fus&za6Iw4El@jPc7D=M0mWV~2p#VcjiG{XTh7}PM7?wh$MO$Z^8_2L=A>I^w zOVtHlPrw(A`xvv^0eJHHeqjIckpasP{1OA=1h*U>e@);#a$e+ZYF)|ks4o^63ccB( z4$)CwL@}=DBc(za1*c-T;hotTJI^${IrOwu|6B}nr9LlUG}orIq+a1eHg1`kJ-1VeI~yz@9~NM#E)rP zCagV?e8EU3Rx32!Y>w&v{@zJKoI-gsMRV-!fGq>`J|Z>eokD5}?BUBnB8sgCoGvkQ z@$qJ0#uw=b$+otO5}m#6bLhY@qj_ihKJ>hDvje2ITvlFfa*_;^ceLax&v08yKx100 zLNn*8G9#$*0=h}q-bU=#52Dh!DV2qMWt`B}$eNa72HI#lgZB~wTjvgeEGzXy#u>#V z$$iN_vl{XmM25hZioKKtXzrwY#<;l3- zifYY0^LQteMS^Au;W!LO7C1gpr5;C^iO|qg&~F9etlzV~?nlL3b%)XvphH`h@WZ+VJU^ZheuWV#eEUT19uwv&VY4M0TcT=+_+? zNurDGy0nCfY?R*FdDQYECEY^m!n$-Q6+BQJtmOtsGQ9996(~O2yt~CkdHhWfI}FbO zE3>yr)VKcE1@PR1cqqm_KP2R$62Hnqyop<}4U#!8(7g((libqpi$m0c=GRuh#|G?J zvYf|K{ZO3Pq*Af{`Xj}BltUp?ZGlHbJ~aEb2<^;&yoex=C;wVpvzBbd&JT=dVF^8h z5wtUqJ^{8g8hXWpW-;y_yI6nK_Z8EO(w;&D^?yQ}+n+DZawQ*3XB`Bi;_(9H69(A~ zR_tDw+E+=!1uNvdMF7(A5Tk-%7E{nk$V)N~iFQX7i&m&d_iV*04|t*raXQ4{rFg;J zPwlHQ6(aKTCj)Hp*^wH{Pw|=iv))t6dP96jH59U|f%I|dF5oQUy%(dmsNGf}#5LM> zeddbB3>=M}u99#k{1?i{V;Srbs94}UL9lZh8AjJ(LF`7O8JXyCS#bh!5Ae$fX5#J| zkGDE~O+l;kzjwS%-lwzIRn=RB5mSt%#$VST01A?+6oqx3{(>0f|f^zmo?(z@4)tV8u56{r4w8!H_ao1MWHZU39UI>i)(<$i+Q7Dejcxu>pk8Wc237%>b3)AwZ)qL^izuK) z;jJp#+S-o$9mk@hln->yij}EEbC(ayV%SP*bvv!#w^ACS1Q11t8Nh-2gPoG zf7}~r*CQOd2W_@owD7Mq?VA`lHzc9=6GMoW1W8)ozmy+nth&p{hgGhuEwwfb%KlN| zy~(EMytHXXUi1PLPTGBs(|f7`oCEH|;Ho_MW<~YJaCz`7Nj&NCXETx+CEaB9yYnUA zcbS=2FY<;R-_zd_fFN6gMgU$Sw~atx+X1mVE&A-1jXJ`=C(&Nee2p3+l#_)X$#0`m z=*CY>8<6NrX6#jK6C@gKF`l((gn+k)>322WHd*YaGsjwy9W zq=y6 zS!s1qAr#M77ePd*GFiT^LV-`Pp|MBuPp~W}DkeO1*|7nFi^P!j$QIeBM(PXmlUs~F zQNX+g8e$i-s8W(`d~vb_iMwd-<6T01gA`aL7TC{NW5=<@)d zGwLd5t0kQ%iPA3O!Nr57G1e z80`(}E*cmV2tv1A}xt;zsocNCN znunfYB4giuqmqJo+|uu0_o=m4nl17~Z6N0snD%td$6;1D{mLcucrZO}=cVRyu|ip3 zZsmuNca`VVoKI$XcU|CFPa*b8`2kPKaak*42f8GvP75O)#AnStT8TeUzXJ=7SZz7U zfG8w*w~#uyAtcbf^;y*O5I58NsjbsnFz5ii2Rf`5PnK!GZ|yb?rm4n-A!?F~t} zt6+2RB0qQ$0y}KvmCLR9iT|6*qSw2(qL!CLsBeU6vIN#5>XsvD!c=G=jBJ5ZoHp=h zW0(>U@hEDo62-ZPTI^Pa5lny*hVsjSBaGz;@bJlRsc17ZfwFLG9=_rq*meS#=umId zp%->gmohj#o2px3%#+TT%}pg%@~~=Z(B~x-~0eKOWo7%5YH_o@LcoH`xylSC`FJ z<{Wiw0@7Xr7Wgy63W5;~J;g-UA?w#LX>Hs4)UmexBZvs$Q_0R(Zcd@9xj8Z~NWTAA z?J{crvNv~OAX`8%ygJmSx?*KCSnDZL7@nS&-Dizf&@2P1Z z=Hb(oqA@m&=UeEGW~)Aq`2z8HQKHe#z5WaZ$I~q0M+x3>$L?&i!b7bXoFtXqh)$$e z>ZUM$%H`*1rx!=YId>@jdqT8u@s5<#vV=#S+DKN+O5-w z)7SW2WCk5fhNJ~XT2|@5IvBTOL@_J!k=+{=gQ?0?Ov&kD!-BIhV~i&zo*L#}XhhV2 zKT?O@kCVB{&UND%uwmGVZ!`&lEAwQ4I6tAq`+9fFB?LQY0(cchAa8vdc*-r{VGegZB*Me-ZMvkZ$V@SjeWMgP2U19zn)cA~_Fm29A zg-u0qU_6JA)-TVTL5)iR0%i^J#C4b8riGCN!w_(e1mDGTjM28@R^Sbu^ECvXg94pk zTf8@hh6QP(0EegXAo4X40Ru0O;b}mkhfO`3iHgT|l2#7HXF^w*h}RGlNr%yyke(Q# zqddFQo6JgphCEQ?DBk&%_Zk*4(F@Z%e((xd-rVYQj^bUA3~2s|YU*E$o(Bu}tg|pB z_9Bc5llSV;a#A9B5@dI!0ppi*!#pVAei>X2Uv-6&~CX4rkmcB8hpWS@#GVp`+|c>lJ0 zW{L8?b|ep&{!T`~=!S+q(B%)m%ouG zbt5?p!slR~X6musu`Zy@L=pt2Q4WkkQVaW#ia#e#h@G-#kBC>|P+o_$R(uTkqL|i1|B-SW4eK4O$0F5SU#Dk8`FoWx+Tl=_%~L+MRoLucEk!-c37URqj;3qe!epy zBP*^*KK+V_R~Cm0s>LaE$l#>crGwRzYp3%5HhLP_I^h%SoW64$w9sT-9U8|#@kvKm zZ7{*#TV-m=nN)wKYfJl5d2_x68I=QxUKTR4>dihE&95A$uwZ zuZp2ka4}Cv<5VF~eGs&f(UF>HYBYkG0o%jia~L?m1hx$L9ENhpm94)&HZ22S5Y_V! z9EI5jW5^>B6>eVoYu)C*|6SZ8MD%X@P(%a8N(!Ic$gFSLuw^v-(c_umG0hjr67`Q*w~acLZW9mKqe|f6+A!_KWj^@(0qHoBSV(o&!Ei1 zRH5gv03|oLo{tJ5T@djHI~nvDURLV!?cgnW__NK{b#a+#Uh5ss$^S)p50dP3PO4;? zmBt_hBE{ekTLhuF8g^21iK(_vVpOUzPGy+kbO%Y}cC|xwg-!LvY%Bk3_lm04I4MDq z#=G&YMmkQr)<~>QA%iI6pp*0oIk()KpI|(T*2uJnnt>nO)*CPVmJ^vd}#TGXir%Gv6uk?EHa}s_L~r)F;&}e%3M4 zRtokVug-I9v3?kvq87G)N`r3d7Alg|0~t)Hc8u~|o;!5xC?8o^lP*_N?KY>AgT{u5Gmfm*FU zb)|php#n*AEA|$KnSiUXKuRMhJJIplB)AICHn)Nv*?T7O184Rkxs98!@q-NM1AOkrH zybDEAUO}&*lD3`T`1)}tg+Pr((FcmHjcGgNiy%qyM@I8%mi9?fvuJ0Z9O@x3H*30f zyuAu~E+5tygBnq$1Hr}F$h7Pv1oT)Jaf?@Pd*T|+1iF{lxyT@Y9qHG$+LL0{5atHo zGZ@xlKk6Yj{6)f`89M2)1OB_@~=9w5Tr{`@(P}b zB0Tn@$k zmIzlPB}q!!zUDkpVLQ7{Hjs0u=(1g!ztW4xCai^oavXNllU_QSEupftj!tVzTW~ye z?_n56AN%gitSd&zYGhSau{=%q`WJlF5V-E6>~u|7z+HaV_UNWTgC(PVj_$fx9O9j^ zV`42=Mk+939wBuESBLeHn;<=y(zVZ*GvbOcg_YkAJ}LCCo&BV!^6-fOFyg)7VnIdX zUxZ3qqfu2~Zl3t%CAiw} zHX5gPop89CB^9I{$O&VAR6Opf(?!p=pUqD;J)fnSB4FGsTJY%-ffgc0)4n^Zn$ukQ zbXk$%9@1C%;N>%w|DfeR!QYLhM?;NgzLpqEC^|bk9(GV_PU_;QXLGZR(A-1GwQ5^?-z`tQ0LG;o;=|X}oA;bDlNsv#FC3@Z#S*L@k`9lvuY)-CE_#>y|s{kJkMUUbjUHOnj#8L}M&KOd1&pNnvSz2%J2q z7ly0x)N~Ozo0SeLS4$HTTemQG)t zdZ3VVWTsEm&~#7l7M^WDIFxOpmD#ETT9SU?rKKdfI=2I@SEzLvK?-Ia96I|DF4To< zB(cIhPY$6|r%z}CbOe!hn}G|d9y_Tt2xAb(ZS+W+93oApc1_{3DC_=WXzZl%e-)}P zlu$hX(!pMBs7km>PGoU`zMP{VN<1Ug5wWqxZ}ek#f=-^o(_F!7+a6p2GLxI zfO^Wv(?6!Ox`_utDG!2#vQ+@=Na&$phptJ90QV2eB9@w#W}RES0p&3x+a?dlq{Q;c zw@l-B$DWNU4qjftFs}8Lg%cB{>gV)1ZN~j(Yq4vkrW)z=%qdbyj^{0WpZmTb(qV}M zur0hhg8hgZN{O9wV;(_;4r8DBu3ZS5vo$9R9&erwqb~4i+rNy0C1oR|DLpli2Ev!; z@~7aeDDL7sW>rPa1ZQjnUT2nrXYXP*KFj-uqOmQ!bO+EuOm`KsK_eo|w)U26ZNDZa z-00&DTVD#dR(OElQtD0MkW4rH)~)m=Bd=&pSQAKpLtzRwwY^VGFSz6W9O$3DaOzL( zxecwam<}QkT&Zp591!zthsSeL-?*;-9pL)a^PV2@07WPO9nY~yfBR2b90JvFFQEA; zv1Q~t4q*bdmhA_wI0EOFWGJZugR zdED3v)JFtO}b$9xpny=x4a`0Pz!+ ze8l=;KXM-Wsg$A`m3WMYIXZ8S-xIRqr*ZE9O%#OVOVGC&u#}_146t=mW{+YxKQUBI zgnu@06k)eY@?sY|*u6`n=7kE#0XF)?07NL6iXSnoa%8xs&pW zF0YhjA4h_EJeLp~9l{dzP|ON_eNFZi=Jdrt=IydywhgUco?uLN{G7>x5&hD9kr_`l z$U>)31DHT(rFi%%kC(z!p)%RpK0ZWA2(LG&%6{T~g;MU=pN2Gw*b~495?4PUE*#fb zBZpf3jK$xQpiVuzo}MeKl2s$GBFs>Qs?^MijvYTa6)U4UxCB}`@yHuTQM60`-BQ}A zJ!aB&F)wWTex%B4DFo&6E$QiVhbEI&1$f5`dX8AFD!8DOwiCYC;to%WWy4Ua7$IDN zeajyb;!r-xGLpQ=%S-EMN$3!!C`M@u#BFn`v}0bGf_6``Abc@>t)Clm+BDrJIZazI}+I0~RzI%x%Vd?VZs739B+dIz7o>g=^W(-XVHCLNJEK!Z4Jyjk0mKrgh@5612K3 z3BuN?OVdg^Y$X&lZ&WC!@WMzCAu+Qz-2y#qbna4v)uQM_N_)W0GR&O^t9o$*TOSeI ziiTllPV8oFB~TOCmna4XHsF{#{fAMf9z_g)JF*8y}LZ!^;PF4#pf28Mqx) z1vZ&m{G%Mp*MDvx{(Req0QYAt^)9Avi=_)#@KrdbJl+8qo`)l@)O3)7H6hmc|B_<u=7_UoF;CxpJsZ z+f6}o_tAZ&24DUohCWS>Y5U#ZZ8p7wmv;xRs-NGv_iWvmM4iFz?uVuiiJv(kzvmXz z_VRi_|M$V3sVwu?*Y2w<*1Rk|QrIcuIjQol<^Dg)9{Fv||4GlK|5jqSu7B3ivp|NUD2Sz~a| z=Ew;dTcLpxfpTZT<^5;RJKD-_9z|5%(06yS>^T*z-NZPJTfDsYXEd!d`*-BEZ&H>` z{uvMNr)m3h*wSS7TQSd$F(F63N5n|oC&NuQCQM=R@_rGSxo`XJSd+UZX4aK%=l5|% zcSaZ!Z{NGLapjdvbN|QIpX*NvzLvXNd5>?bYcoXC2Cq9!_LFO!Eb6b>Tae4rD@5ij z#+nkUVyZWrRg}HwDryu5#g4s-;l~I)u6Dw-Ysf2%TB^)&pT#!)9QrUx`Ed8(=<@ZC zziQ>)og94pz)S7+!G9As+pZAav%0D5DM!LYd;*FDLE6x z$9$6WMJ2B9J3Cf4=(nNdl4a8HXCK2mA7!Eae>@y5QG!1{?UGK|^!4;w;`{LJ+K)3) zw_TOAdg#_=E!r8Yl-7s8XH=bfBi^vcrznJ$tX#IPdkY z+dutz%rWVsS5V-giUrHjE4!^pYd`M=&(sKb^F>#SnOV5MYj$b56Of~ZS6tiX4$>?Q z^2{cWBTSs*%b~NsuLo!PzHO=SbD{>O&5me{9As^7?U;TlB)!_KS)Oh)_4(`F=a}J3 zw)eceKFaCsWQ#I&D%3MN%NCuU{0a?HNUr(od^3~0cvN%bOvXNYu}9f!5gxui2D46& z`8tzhqS{^r$^L42{QXj0hrFO!eDh1gmG{OZA$)uC^ZQP>ZGP7G?=MvNDLU`JIMCyi zU%S^E*<};^Yu^p^Sy>O1Zpyw3-+J%D_DTPll#0=4m)E|8?_@OLpoS8;J6_fKO*6s| z?AoFg-`pZJ*CTityX4bvlMv^Jo>Qwk+|AqTAE)s)RqJxYbnZs2!LLGJ^pQWC*yNw9 zv=A33np{a4$$l1bZ&#bui5~k11}d2{w6mJ^6}x}>*wqUi5r?8uOfUQNkF0(Zl^5bK zdnvqE*tjuatancS*}Xe)r_K}@TxoMVEn0h``r;nXUD3y)~om-{D4gNTkW>2Gf?K6O?= z_q|$$qJP*JjB@DCZ(Yt~7a9&7u9R)46bsHzu6}N}NhTf~YcOwWT|Dpt6ixq5o!Rue9u&*w zJl|Uz%a$s7mNXYPCpRK5awtbtcE-ps|J%Y-PvruhkO9y9RY_6R-ZV`)`T|AzzcIlX zUdw^eC4)EM^YZ0KiSKf9JbVJiU83TD;(qFO+*tfe(@q_C-^PFx@MH=^hsc{cC65H# zl1FXR*?~@N#pF?uE15cv8xOt+A)LA(BC;H1`T}QMvf>mm?teH!+>^Psk)Dt>0OW

AIh_dp(IgDKUA~} zIrC{GF-L+)NYk{1A%wc+#RF8Uv&*xE$aJR%ssg7|0eW;wZ4o6^ zh~6fSm9xyIK#3M^{+@VT$dr|P*)csv&qF_+zX&U?iOmqfD-z-$1{*G0L1y>%JZBEN z`1asyGlf1l5|ikPx>05~f=eoN8pcl+i(cQ^Wp)Z;^y+x7Zgu!c(dI8HH2@_QMo-c~ z-q2bRJog;UuUd-oEsp<_a~56_hsM^DXiP#eIAnHwQus$HzyU^zyHr8c zVt4k!a&A!n{bRO#LC;@(Bxnlp(?x`?qY7;s?J7FRMgmU(`tS5lB=AA{CqnZg@`XJl zbW#thctE5$KO-<{@Q@CU3my`MJGbaL)q)tA5>|y~|fGP7Buy&=5R<1c@}TgDYqemUUohRiJLTDoWXnp<8Hl{c$zaxL%g&9Npv^k%aJwFJ0`jLjPC{-N3E+u1h z4PeURoK5T6?FX<_IEHSNYmzl|tHmyq-Oa{Zb|0{GflPa2GuC3I1~pE7;%lOZQh~~; zrc)YP5(9>MMLo4E^)4b`omJ~}0@5N5$EY6nXJn_>CQy}EH;Y>RKrv>2)i1dtare+P za;Xh+S#EAegYT|gjy}xNo;)7JB#paGVbzl(-DNyTwI;M{8Czn?vC33g=a{Zn@5cRZ z&zIMQ=DS%LU#ojHmAy}LPA3hzMr%1E4RaJe=8-pa=WDRcSt*r8P4ZHKtMu1NWK!N> z6{tIhpC49`DBC`6J$8zjH9T-5!TSVakYVf?nYD4Sxb^`z>*4%t)!}-ah6vxQkmhd{ zkP$3F-!l8N4fvJhqPf?XjN#ZJ^rOv4=gub4V34?^ULhm;?D$cJV(`L#cM-!k64Nq; zjh>Drn^phTg-8d7OXQkNY7#`UGSv;~F&Q_n?Iu>nG!wORe`}i*9LBt5=fpY7-Gcc6 zr_O{;%|~_5hd)XswDM1ny`#__BOIR%5pb~O7{7bw*q0IZ$cq6b5?1M5r=Q(x-mMp| zrn}2#wZ%Nj3_WPzA^|lav%Mw8-NdwW33;*$^;@Z8)HNwigXX=cr730*a3#1*TRHl{ z@EUe4*hGi)80aS^+9C!uX)})_etXFjHifQ&G?6e;zx+@OB2yd+%mv>lKpJY!Y)P_Q z!m7OEW!rs@(X?5ZL`ub}+?{YU0mL8#5@<%COBk@p65)sdBkun{mpL*R6gp4^KM=4D zPSS#638P9~L~t527M=k#bE}2Te2yg$Dhe~~(SrnSb%?-1kp~Pq0P7&)Z~G)uz%2#Z z59XEsS_l%I1f0+(_BQ)gZxdJDB9`oJf7_?8Xlee$yji~L_CIWm(t>>hqPk+w+wIygb2!sfd{4HpR}b8ei)z-0s_IV(5kbIwME? z(cC6qK|T@~_B88Nlj)T7>PB^bT?gj~lewb!HLJj3SHqWO?E3NW0qw$lg!>5RtfRTW zgjk>oQ{@P2Mur?LRn(3;Ji*W=#Lj)=cKN2i%hs7P)iU?@7%8oG0t>U44UQSCeU(LY zkIl3fdUdU$u4TBF4#ISGxpAIEnxh;~)K9M5P_s)bt2}yIC$2v^&sTkEv_-Biz|tAN zeplcJOlj7LWCaHQMWj5}t#-YcEV3?-xQq~XE*kb7rg_L?z18XrB~)uqLx$W3hPhC* z#+pcZUwOgSjz2${}aEr-%c-on)auY6vXB@L!ByepxB=cxe-zHi#n*1MYvTk!}{J~v5 zlRGzk$~lr9=(Wh|Rc#M1#(37{Gu%JENUX4)bh%0AGF=OGf({w7Of&mvEpW5usRzy9 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≦U&rFnEUA=2ZU}npZzgdb<2pMJ?YpUNEYC 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༕r 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

?#WGOiw5L;@^59zVV;XO5@k{S?q-CaaQBM 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%0A#3VQa2>vlzS2TyW@Ic3>nhj&fGM=yU4;-%wd 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

  • VsLV;tTk+J^^1$7@$ySf%QlP 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 z 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

    J+y3*6vA?~cK* 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¨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

    ;lCFK~g!$rzCzVQ(R4PA=*Jo<#&GyY2l{m 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

    dOh1ezsk6!)6=4hQz7` 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

    Q;_*q z=QBl=`7qGAq0{TE&9CL=y!^?-x%y4o#pu^+hxH<2?DB&m%4Ttn`j=Tu9jSoF>Qzav4q3lBy6O|A{kr+VsCtfW z{+`kc9LD+b6UWG|9%pR@A@3YtYqdcT;`~Fk% zO-|hB@+ZZH_?o9*a`mKx-yC`_eNUz?@6y$;63HP=AFw#pykqRy@P&&9(LP}pzg{Yn zp(k`avprL*8gL0yGeVuPt1eqRS&gPgoyb!n>P{T}SpDMA*XB!g%=b;Fem-$I7cC6s z$l*^ctyRO-GaVA7hkiGM>*m_Fre>LD3f~A{{(WD20evv?0pGGC4r6rY@atbGvl)>G zT%<3i1?~M(HnUipJo=PvsP>z<`$lRccc%eVyY)`>BReTi&$Se(^LudM|MtKCyRHES z2Q&tw_nH|ROWt!!A^qD;od5H9*}`GHnx}?zr*$IiHXlEMgmNJIQ7hW6$I--RdGzIRO zh_DJ>;n+F%W4uz=HI|FakJuW>De}?%9E4;RvU0xdNF~vG34>o}U1%|NUYgu-;HO>M zx8k%nM!(HTZ_cdtoNbx4b>?2wIbFXir8dpo{+USke{U9tXgfE}esl%KvzEoj0p9%h zDi04Wbt|uTO9?)@olDc>VQ0$OfYy4z`=_S9dWT_WJrDGk`%F!#lIbRjT}&5CPO40g zo!i{QKcj}cki0r*={gk9?;O4KIz&#tZHIwF`?`kFdiJygG7s=s8-hqxU`B?K*1h@f z>)p@ORyRK7+1aAR3alW~0od{68DS%@1`D>S@T0JVw}iYN!G7$AA(95OGdrVZc3S2{ z`7^^kuy|=MPcDnA1WuuC&oEiyKi9R<8yBx!L}K_60o7??3cM6o`l;3iF8 z`N;JK1l+}9bT3moX8{aMpi}?}lvd`mv?LXlD1;yxT@+u6vKsFjji=a^j?WG3!IM8^ ztp`;VLOJ%ErM}dOE2UUQ729%n}_D0Ne%)SV*+UJ&IY*x48kvVCCQ6S5UENr##<-8QpK`JUuSM| zQ{tb`cZ{En-8-|JH@Dk5?&FPa+vD@8?>qktqt$5Zo>96<80*ow+4fXI^Su zsLt3Kh#Ry80g}KHVqhUBN8l|3s7_aO@KxSOeK{&S^>j>o^f=~d!e$Y+RwZq9SoM8; z1Pu<91y?dUY)Ehld9FPj(R)sW)=hBESh_42?#v$QWF!Mv7^*FnUGTF zk3?dF0>o&2tp=U3;1^|s`wW02tfXT-#|!+{MkEwRh01*@;hyC`{B&W)b<1|q6+Cna zm&wqe0O}CF-j~UM{!C^zW(&`#(g;Nc$n?gN^Ac|f#oP_x{UStR^o1%_~Qy*2Vcnb;N5@-5YPegcE=)E?ir9Ymj#1|KXiD92ic z#WNUsYqdjQrTs3rFG?V$!F07@l5Q0 z)4u`nC#S~d=;LgnRY@iyZG*438f#bZ7zkixy`7VL?$xx1ZOG(sm7#_ku8KXnCJmA^ zA%^`p{bbDQu$$rPE=2Hdmz7}H_TXN#r{BU7P?snZWu9#z8cK;S#<5k-=Bkpj$0qRo z)p9tl?-}37J5slHPH5K<{*XFAH5dMesae7rf_7mn1jxm}5?o#hCL8%)>CbzJUBrM` zxJ-~HB%FmH_jN<(#Kmh*h_6oaCW991Wk}zi;*RJnCvY zYO9>s(l}>5gI!C^`4uLzI)5(hhVOq3YFQXp%ui05?-wbqz31oUANiJR_ZKRKR{_3q z8ntW9Ll`io0^(#Wjo&ha2BvV0iz){~HFhrXr6MApgVNJEB#Nq9`l*YeY8+(`2|YY5 z7L7Hi-qnAg;kwJAEVae{j**PJ1qqs~f;3PBSUkNREw8)AIXiUrF9<9owb_f9TW9vacB?jksKe zts}p)gq44uGiR>A3Xe!toV8yG%E>iNL$EwtQ*p(MmSAtI4%V3hwZ@UV}O8x zaIi2aG{6K6UjaCid@!292+U&tCl1a7KGjD2u8oW_zCmH_E7R5q@)}%kNpB3UMM#N^ zhq4Bm<@nDC;4VR^f<_(L)uCWa5Al1r!8;z~5s{&Z#Tx1S=LNdMd@PIzfSyL#q7IWe zH5X^OSG=>SZYU|6g!x*LLz9~TSLcq+ErI~pm~`t0We86%^g0dk!L@(E=Gc6io#b%Y zxIw!Glsi6eZX~R3d`v&Rj}^p_P!%VJx-dQ!D?4n`kp#9SRo!Y+5ZD>YJQX{d-T|1k zI0sxVvZtFkxe9!={GB8U8Fxw3+UBeg4BD<$lP=sOTdCJ~rWAWGjBYV)(b(8{w|9@fGK zf$jzwWE+PC8Z0kY-=Y3QsBmoay-+_s9t9jIw@+jCsU_v`^FD;B>X-pXp^#kh#>tpm zaig`5tuW(QKcyd2UT2LdKlO-l+L$acEu}Q3uc@S-V?4Jz7F&~bB(yPaxvS(F!zBQ0 zD6Jg{&kd6;jlIX6Hca6%cj$;;q@9>1o+5c|$b%2X#qj_Os0}>c;cI}V2^1EsE0Xj1 z&X)p$xbY_$A^qZeBtDB3_Iu6_Po<^4-`*{^_PHON!T&?;&lu^7NK1IW7KU4oZ%Vt% z8>DxnDK)laR_?P(kVWoT1-1Vg6Su9 zC+wjssYy~tE=qZnP*xD_U%TE|Sm5tMhw0sEDejO-$U5dL2pnIS{gLouem(UkKpDhF zbz%wi__;(!U{M~t!~UiMAf-UGDzKk-@TT129{12!$@1Gs)?X&F6kZ&;HydEw+S++B zA|k6#i)R{J`zO0R)fODe7GTgTCV1>5z*evWt}>hjZ2laP=O~9oKjX*1cAi!Q9}9fl z301;LDBS^iINFIGQoV${_vMp)S-;6ca&}BYY~VOGK!uDFjM+0R3(cfZSBT5Tz&}&L zF2I8Xp1DHPKfzfJ_}9tJ%E+NS)7t>E!_+}X z2?!5?ic99?u_7qMPH?!JS|TjHhKMxy%yQe?&eg}f={9rz+$J=BN3&Zs4`>w8H+6|_cN^RfEUz9t@>j%{&syQR6j{;1maDb z-B2z@N2T#hKx+<1G|Qq<7=bsN-hsZML!%H{mB->GOcE4{rg=G zUO%tI)is;NVqV4$r&!wi%NF&9=IQW_BL~& zd!3g@j~bc~YQL0l>=#427e-aXo5v9`WVUzIi*yZ6BsJ zBzxWr_$!))ZaG^d$^TTaBU+B);4fDcc?3^Tg6#faXm4f`YWw0!r zz002a@Ms7ScTb8f?3jonX{ElQGsKm8goHXOfMp8MK_6O?LXDq-%ce6MQ1n#@bdLkA zm8XR9Rqb~F@EJaUG(c&az8ty^83rWHV>?vO+M9fvSXVD7T?nf1UdzaRw^forc1=*kGFbSjg4;E)P?zQ9K@*VtG=nyb0;{)GVrRZ zjcgeNb+_;zk>$*iw?7J7qw?8u{z@U;x5!+{7~J>DCt~011MazR!Kko`_b0B#c%IlG zboz@ta;Pd~Q#~^5#8g^C#xZZ;KJl#!pDXb_8*F(&tJm?@fKjWPn#!3FWlav!=k1Vn zOZ&X5n}e0V`vaeH1kLzH$uM`gp%~GCm`16~OHs6nD@Q?LR5Ah-JI8Dc(A3C$lkvXH z2)xp|Z;x`0Ws?s;B{wY<6iYOu@rXEo*7;*8!g@B(&*2D&uadC>A4e8AX6@(3_B_=l z6%;_BcCo1I(rSpppt@S@BH4k`06KIDy##AyRqA*TIrkkR9))8PrC*_e11dTKlsiv! z^tp>^` zQ`jTWT>824S9#@^{n{+XV#;R&yECK|d$8f>y5^U@*|Kp=$QC8SGK`$NX-tz@@-}!i zmC1VV)sQxgU2|`+Efg4wt!uXaJLqViw&t4lJpw(a4<76La}X6TN1=x_j~3P3N8R{b zFIMT`meF{NEBAsvH4NX&zAVQ{$U-Of6MJSRjkgAHVb14vXI|%xTR`lFz5ON}RRsf2 zv)36IU`b^4l49@r0&(rE(z}gD5e#I)EHh}v2)yMCOgJO^y^tj$Vg|89z`_&2H%;K% z(BPlJG1BpQ!v_8-F+4lwnkL2dZI^dkma)9PN2?ac=cSd?Vc=Oulu&b9vV#!7vKLyh zE4SeB`+;aXlt6ziiow!Ehs&V)+X7gDn}lvvBW*MTIs!W}6R=6E}oLn>Rjn^i~mE&rke-OikJuE(!i!i|mp zg7B)Ft7>j@MG3vSJ>RRTV+dwP)CkL=#CMLkfT&hd_HRHffnych2P|>|dQ=E3iirJ9 z#anzrN2ZK`jWt(KSA%bXSPTE*EoGX#2GO99{9unuH zE}NGEhF*Je57CG@K36Bfqit`4*UoQ^!!zU?J$8g*C`!L-wUXk6ra8*F0!_&y9I91q zuVTK9@cXJmrRf9vPds30W@%et@`sQgc0-Dm=Q3*7*=|Uy)a@Fz3W_UXj?vJzH*0J5 z9IWH(Vi8*ohaA$_SsB#!qqtjCc#0wDRt8|nP8a6C;R`|27gj{{OCtpY6Fv@wU*xpJ zMOq~@t<@FknF+`@V@OFS<#(u&(<81#G+Imjv)YPosSFX3YEIh2R=6N-W!F~0-eBsi zI`VeAvzslb9-qxn9nbXnSq|CO+0DnG@r&YqP_V6{mFI@UP{7!Pl`4wB~Ju)yT086((#7 zVEa9RQ@!hN&j6`P>zPvLUMu0|RH32mpB#UK|ikRwRtFLC@T-GuepsS&gVfrTeD$4;aD{pW%lzy^3x7F&Qh zu~gz(BnP=jW^E+$a}ZxRY6}pX!DhoqOC16&&)^9n;Au%5eEKkO2V@zC2>UT8F#t5< zRws|H1VN^9E8jcJ_S2(!Wpda{tWGNU(wE^IQ~aYQzuGb+H=l7zWRxM^Q26c8IWA9u?x{;C4$NW(@is~GcUtJV zxJ?QLT{I~r-ccGSH@3O~gc*qk8Nev^zC^#ZiP*rFJQCEj&DVnpQTRa|^(Z<#7>XJW zDK>Ws8#%6aD$$N3%#@|*JwwDFyWnY;A{0`d!^fgdksM?ETv%u*5uivH=Mnnc|5l3N zWtjPTF&QlA2S3}_KI?o(#>@DEyjD~(lPZjLH>8-%Gi5TilZ5$PuCq>wF}hOnJuVf0 z7f=Bgv{YC-eQfFCa~+PI+#8?{+$xz<{Pjwx76yq|QWr3)%?hVN-R7sf3lsORhdaI(U=!LcKzGdPq~;wBi@fQlX!mvG5p6 zaXy76+`j&?&6ZByZw(a=vEjWuwS#S0-8}IpJZDKNO&y~c(oCxA|3_(i_P!MGsLAiu zeS6uMA!f4G;^d|CEcoJV+`02ddzKW6P;bbw*+g>j@F;;I>b+Mu{D`M&qQ?-0K^(XG zn{07#Bbt*f^kf)7T-}GON9CPz3YHh7*x!G{6J?LWglh!Az z7^LVQy5!mc;~^(d#mZ=Ueq=4Re(mx#XehG`%7r1RapQjuM)?nuP7nlS(z-`{ZZ z6DXB#58z#!#gGi*<^#YocID$Uh+(6`GhH|uYoGQ%yOCT_Y#k2Gs z3vpX~)rwm}O2sHFA;Q240Zesdn^3_R5Q?`uprTN^L#e_R-Qfv8+zW{rF>EGlkEoSA zB`UY@Fawl>Q1^UBi$6>{uXXHWh|fb+{%!araAMk7IO(Gl{y*@raL zgFSC!iDX@a%8c$FZ8}tS9NiNAY*XbevRBmynuw8tp&JGFBlGktX?mX(al^Q09>_EQ(?s`$8{SQJ%2VL8vDEKrKSBImYt%V$i8_rLGZA z_)yU!-5rw{J&8%y*SiR+q|>WJvCA|NoZOR$%?$BMVr8g_1f3B1&{>lChV=WECMgRo z#OZ#F@xAOF`KZuMt10~x-xyoR`L5{4%*`^K60qXQh$Dqke!lByxRBu>VaU+uOO*NO z5IP!Pe;PT95_n%qTjZkEpzD}@4!qczR?q>=O`Nj=Py>N5gtd4QA#Yz99y1O zSQ&FH)=v8Ewz|1F3)6!Eo-bE1|0D`Q)2c8Na0_;7+yTte;+9 z^CUr)L3-#;ttE8(o1zI?sWG<7B~9a2J+W_g>OBvn^sMh5zJ+oW89OJk{xl;p28`k_ zQV1`0_DvS;UWgR`5}CR(A-@vn9Xm@&`#H8YwXp~LBc$EhxBJQ9&swWNlXHYQ!>sC? z(_3x018wV?5dUneNC1kbls+Tg&#^u1%sbhD78n9qZncuEW+V2F0EdDdpW__H>@2ey z|KCbzFKl;KH47c(B!_k~L^(fA6l0{%`^c*ao2p?+uqZJzg~|Xkvsgi8LAVC?;({o;%#Ojc5rOl8utf|8+=&Gq zF<4dU#aIA_899J85rBcASCC>mU_xOVk-6bvcu=lWcog6plK~#K$|(3;T>u(pjioC8?+{s0&m+G2^pw&&hSJogLQ+< z5+eJ^NgF6VwNJ(^Z;(fUD4-hNVL**xRSI1P0y3>^eGSAdbGE5{}Vsf&>k;iBGka?g|IfF|?V_C+Y4@IPS#-in+ zLdv}|I^mB0xo~}B=v7x^3soXk`ECSvAogl#NS46UCBym7DOEB97sh8ONn&}2+X(qD zAdisYjtrB_C1{<+3FV!DOWU19pDE!2pa_>EmZ4=3Kyf3mL|XxWYQ1Czie47tr2EI~ z3Ok*e{;5|-CkIZKR!Nt<@k}5VWSLMe+$M=A-*DoNkKX6VHMaSup-%jM#0V&q&qEv! z9a95*pxVRb?+K;AvOL$DAI64w?4auJOa;9#5K3DSzuCr62+r-`#ZL~UV@l?x62(0v z9{+qKn^8#RdicIH0Mb~d!O)9h71{lS4!K|b?&xjD4D1^Wh89A%1p(y&%f>C4(F ztmt&cUM#djf;Mw9+jtVI()uV|tbW$l`bE05pk5*eD%b*uIjzD;pHfj46*J=!GAOx{ zA*GPif1DNkO19kE!|sGQWy;8U(aN!b@1sX_xa+mcY2_k{Pg+*%ZniMi>7!}0?{DHc zw~kjM-q^(K7FGI^SY{VM^HSUuaMnxm=Lvm)CLdI+f{a~$Oj@sUocVZ~pLR(K_s=eN zQ{{;UKkOP{%uwqa8s@A~TYG$BF8FEB`Heg0a zhHZ!^c%^wrj56`G^C~=)A0osBC+vavesEVdI2GaxNz%K|BuVG`Bzv`{6W3gS)82+v zYI>vPqJ(%2%c0Dbc4&?P>T*$CgJ4`Ke+q~Bt*JEACA1Gpru&>f z3NWtd1Zj&&1BCau&-QuPw1IFyZSKa*@7yF>a{ak`4lxyKdds=4y9pT}q?B%uC*u?M zFtd{kUB$Y6rTI#OXK*da$E-Jnhz4LO|7axKpmphf1d%E=d{VP7rP<$prpTTZMDXS1xW1v)*25NK?NJgclTAip zR(c+9R)pd<(WE|y<8&-8{97))vS+75;nW+@0yS=eXj2GBsXg?Z8!$OWP<}$0I6$CZ zEe)*{yZNFcR5J2W6iT|;^wx0EjwYeYz*%gg<8wAmQp}KZ5iluo-yyJXW~k)PZE_V> zpa&Xm_KUS|0+3L|ffmrS%_UnoaR7MeXxlC%O)YNjY+k5$wt2TA8rbO9q0&+1?qThJ zSTVy#yqHPZEEk8{J0x`SzuH~sw)dMFoYe7Eacod+?9%-3*Yk>)_bf`}+WPaG+Wmx3 z7hkJlwWXl$?qS75=$uWgc5ysM^4UGU(>T7D6`8rO2iMLixP`@RbpU%N$0_~24o1h& zvFNIesEc;aq)T=2M!`~#Fm>f5TMM2w)$MRzR}2f@{vwyjiicL*Z8ihRypQ4lSNWQ) zYnABL>*z&&jPt(Qbu2mU`_Hp!i;=;_&VN8b^_+;%bLVwU*+u1PR9-WMP~&0{ zE*RdYXZ7|Fxc z{8yW<&;+fNDe?iF+>(dh&G8;zaoMWY0m;R(<@(wp#d~yZGl@|2>a)=e)+|<_JJ-Uh zMszR$bExIpr}f3wS>?Y{>>4;j7XU~AUj{_PAQNMFR09m4FkDE8BFNjo))$H=K@(RO z#Y_9OUhVP2OrqEjxG5JUSdCk9v>~pE?Oe%^MWY z)h@pHdCl{Ecj9%Fz4^VhA)*0vuU5u-vr7sg^0|%uUTcQT^uc_t#I5|owMQhAanc)~MhR1%Qq%ix+RB}Lv zBu-8BY#v5OE8vRKtOLn8!TG6bVUOVp6)cRJqZME|mDO~bz1gfxF}?KALEPp~m5&A! z(?#dy?2rx8QcNx2f_?+B8}<=Pg-IiL-j_ex?I9jo`J`0s19rPl?b^=LkQ_!Wn40DU zKivWO-pjBI_VxT*ciwpEmXsZ^)M*|f4U3R(vV_7w9fQwVJ~7-xh5^woU!>1yg^u z$POV%FNS3Qo8rE_aMR1zqZH4_6Zo!1&JBf!oqh{b5WOxawQU?NLp8+f{|E82f3lcs zZuv>mC%+Lt)+^hZzL4>*R8A|=OZ9D-68Z4Mc1Ur}{qLIY<2Wp!^HwHtS@Z$lc30ff z6a$(g<~NF(&MS7C#gE=Uwu(Xuo!4zxUEkg2KAO_!Wzzn77`)j0fWT|rgq8=^@?gtQ zL!e-l!b&LFb@xxko}L*GVQUM66a%qyA;M>3U5BF=L-OTXsIY{xN6L+!^X0+M&nPN6 z^Dn2bi5*zG>Ah&X3IRj5E8Q!-X@9cTe`>B|2XEX711Ut{D%QXfB!t6&!c#0@0B&sj zfdbfI8q08RDqB=_EM!z5BFnKkMO@`62gUZk+*PDuV zxZ|Tvwj$HJ|+H zVTlln^+^lMym6qJZsi${cxEtTk!vt3T)u_C{1dyHv2ln+?52~9Fi}H@A-cen93A6T zZPV{9#yXd7eVRK^SxlZ|%ke(eDqL$Is;M$+psWiehC*))>~_I!WNOhan)egs#~o1_ zx@3i@#rd2Qc-V;sZ0pMn@$iCtj@k=5FL%}*sl%_J$U78PZsH1+VZZdG$x#;3N-9(D zqPqqyz(DWVOs-~7{fMqz0F`?`#}gNcy^(!Sm@O(LIMX+x!taX7Szuj>yfwyd1G1Do z;6`hBLq%|n+{I0{al} z20PowAoppSfq|_?lY%$j`A>7plNsAXK$l=OJ!EYW)(&`}iptHP7F`e3wG0a4-2M>_CWCY3A%W8ex(ouBlK zRytA1;Ezw>_}-0tA>oOQ&XDZ^S~8CGRUBRmVa!FHsHBAT2wx?k5>bSrA}GKJHG0z) z4;Y9!nQm0B=u`v)CT&8bOx0+I==frm)3xQ7pP?`40O1#-@<(#tc6%k#R-E_LZ@EO7 ztG+cwIb4gS?3Bc2Jx_Ktv%W<+(C=S-H20{-w+vvy^=a2Gs_{4ZZ0AO6v?9rM!%pFM zK$uQs9reY?oR&!A@*RnZl-^7YF#?|DS9?EPzpRbavO`caY5b7$NXxh4WF|+Jxdrwf z%Qkd!DJnSib`R`vp@3jkG;^xq$b*oSL!H7ZWrf?=(=3$4nyj4~c9<>!?bST}*p$In z;O}g(qmazQU>f>YhW*l*hP)2;wA-c}L%7se47(#6`(~CZ3cn3-;%h_!`iD{2fqh~~ zSO5!OF2fp!kK2V5h0HrjC@2szd!;@=XI!l(H%8hr z2Q97@px|%!BOsw`^ZFa=vYrYe>b||l6_ML-HlK@JChVrHL|LYuh0aE%ftdWm-$~NQ z-(}Q!+n=EA_qz3}>+Ce3am{mMRFcoTuK8rpws-gLjuxx)sedL`msfzH4t(kwkM!K= z=(6gUBWtA7zzeSxPn-MO|A8y;q}Leo_fCpsC6P14Hv0@pjb*3FJ)$7n zS9TlF|7Ab<(_$mR5E)u;g%QjA^#+XYKh?AF%w~vT4zs?)k~rugfzMWD)DtL1U>A6O z_>_d~sg;n@hws8Vw&Tp|tS_O?NQw|j&*t_-jV9iKB)Y1aZq{BML#YdahaO52s`J(l ziG#0>Zafet2Gz0H(b8FCg>-oG9 z+7kF|U*_peO+OsEEOMwaJ}MvJQrwW9W&KSJJ9EJ7@1^HWwh>?aq)vsX#GI+ArV12d+t ztqD~qO|&~~)cSQZ7N!R2NpmSR*eIBpmj=VmK+Oz{d;I9!uS)IDVknf{IFP^tMDN%Ap`VQ%B{K|E#pVS?x+?1F?u0|Cj;2>|e zFQz#OJTu>QO{-}bnW84XIi@@5i`ljNJvMZH;G&S| z$)k(LyO8of=aqNlFwpe#1TKGTQ~$##%wM=#{`fKdgYaYJBlm zaALl6p>iB`=r^_p8w3gK;U$~$8ImX_0H{q#UJ-&$TQK%DlhHsW$TJ|kRYScsfr=d{ zL-&Bc9?;KZZSB*&FAld4$i`MU?;T~xcndRR?+tJ0+6IG$jA+1ag`tx=22Mf^wd|qu zKoA?)d4eGujr^hUJcSxm00{_V07vwRfgy{*sB>341sT9))xA`^zz2K_rxU7yhk!Lgu|{lAZI)n5oi-k{+a&VCj9mWhO|daerB$wnyJL7 z55!_|gJ_Di9KvpqdSidGVQu;xauPnNC(^)hswUXq+eT&voYr1+5H1Zd<;O}$=aV2< z(Wf$YR5A|{bybfaGw8(UErj3$2(=-^;xK@IPC}V|of&U#`w=RKL~7ChN79+cL-qZC z{N6h&24f%l*eT1{*BJY*Ar)GToi=MFi92I#C5B`vF_uuD79nXLyGmJ7QOa1dlxmb} z2=nuO{O%w3aUbV#|Geiu&Uv5b`}K5oac8E;x(L2EjDFRB(Hs&;E>YVf_KqmElRLtE zoV-6v?S`=_D-P0}QgAf#@5*FQoPY|$XQzhcZyOJL<+?e+TFP6%M-brdTxFYiX1A}eeq_$-r#6CPY8+*HaL(NN`XsTfeK0CoA@xG(#L8UmIur?`O{M$P zOt%WNDRIi%1mMW;#6A?dNU_dFVGDeT`!BvYLjHD68CzIwiJNZcv?a4ViUDXsfL|AX zya>w{TbCc$LWb9}&j7%X0sosCtOMX>AYeC^odh*y0xTEck2<_%{CtR~{zZ~9RLCnp z2|SGuN|JEC9PP0rmWDmAb{6HPfa^lzyxcpU0_&ZXAyj<3Gy)61M$ z`b{QeWr8EwLLawyDK-K?ZDH)>I4C+BWD)>jL~8)K9HK_R0T?6;!%hw*Q?DS&mgrU$ zFmsl|rAl2Mt+52T9R zp`LKe5rImqbcv$KpavU98n9Q8LAP+CeaVFlamkKEojFIWdL{EjSbrlj`B-R;5Bo+^ zlX2VjB9qxvd}pY0KN0$AP{AXGav}wwU~GFndzb#zjPMUdiBL86?+|>Qy-pxsVGrDnL~AGlt)hFXD@m6u&A! zbZHYwA<|`lR>3^gTaTA+U)Xb!bF3(z5{B;$(p~pBdxr%ywM2pt6-Le|gmy z+i?pv&{=R5UEPk^j1b_@;cXruRMYuRo1dNdJmw%Tiobqf?WDo)nQiMIx(!a|r$;nD z-JOS(hZK-^7#GzNc~e~cA$>jy^UoZyQ7XInP-e3nC$auebhBJ=E80uiFbb zuNzr9nX$XNrmn;Yi7Ur2@{{9|Kx{#tv9b_HC|k1y8|~#`Yy+Ln!HCyk@KvTsxJ7w! z3t(sgU*wclEZeD8mqt(wF{$0pR<%$|uBN8Fyev5co)hmZq_IHL%waes2tM zh0Mjsz7Q-y=HglMPC#V1Jj2WCiLbNp-(o5XuF6bhCU%&awXUdg=q-zLU)9L@6bV|C zIV$hhZ2{;uk55A+A?;;xNI;sl7f0Bv`#>W4FK0`jm#X0aB-NLQ$5Tt=!44h z?D8L(E39YICRym*eg!Jp5Fh?rfu5c-FS@@9N^!w9Wy@%XU->Ds!ihYP7p6?Gk!1Kw z>?Oxhv)0((hF*26 zTjSBJfs2V5w3x$PR&GOW77`v1RfJ{>5s{Gz77c$XpF%F80kUk(PF2~+@&l?T+dZax zb{-L)oQh~Be{s8TNSg|(EX3?c9WowEz?xd9^8RCo3zU=%Ggf*RDhweFG|*Fifi5m# zEM9j+)#i>|o7wJ=JW)%-8W+`L--$Mgk#Pok(P@Hi*hRuCF!HaiScknzw!yfPABL_F zIbcUU+zFbo9y7)>!2>ne3Qqd-%)xYbyvx;ULordWFC`WJgxY{XdxfFLQn}XP0i6Qd z>QKoS>*pX@?xT(=vGnT4G#ulZS4=k921yn8cvxLcru>@jtZq$W?$(#fbhnSQpb$C8 z&1Rr3XZ1rPA-bc|;rL!qT8b?-&Rh-r@gPHqZ>Z zU{?>U{80nq=+O%5sa2sS#oxXy0_@40$Ba(^OC0C~le0l837{gF=9utq}mSqg0gfiW3V>^$6wTN;xaMr7+0R5xEz# z0;v>m%M%H2#pp5tpk&!@sakD@4>-fcd};{bI#56Y{?vs}dBmkYU@ zuibX9sM%^_ik(bx{e=7TYM4^FhsbW@T?(Otu&@fO{Iwfy4p-Lury#rO&LwhCw5ea_ zeYNlvb1ib81^x@R>=`(8maGB>69F16=^UQ5Cz!-5X}e0xGM#&SpX@> zJYpB))dBZLN}ciwVFwD|kj;3kh+LtIz0<^XXMjiXey#FCnrl0SL(^Rvl>zWfVn<@7 zoKsbG6TjT^RKB_*6outk@Xq_7BaM-NB*bZq(|LF)9IaWW(rr6*{3hk1)`L zH*=`D=DF4-!E(*B0zZ$x!1(5ezfN(73Y-}6dO)EAB5Iuqy{llHLSBBRFeRjVFCZwq zM~;qfPu*r%>hyNW-aNWhv|da+W0EjZm?d3}JSeF#Ua+?uzUjL!!T50>BP2qU-2TG; zw~=n;mf4Ew0U&($%c zUcgf$E8579_#j!T32{06!rtFayxS&N_iDS6B5U%Q!Ps~a6lUyEeDCgcV+XMcLxC@& znlY;N%_mnzED(C}{j(NY2aJyh&}Kb04^<=hv(tg_Lu!6QNw}wxNDc z#`=2%e-+97Zm?O6)ZN0d0j|S;KO9iV86C;W3F@yWFKjlxW~L-q^L|tzfi|WValK19 zXF<<=C>FC~t_JQcvVH`iwg34Bp?n5V5R<;TaVeLh4A^;p7D9+EAMQu z3yL5P4>f791B5}A8+XZj$g(m`fRN5sIMU6I1(J7yR7qBkD(eNC4GGdaF!EToAgCA*_>k0AzyxSx8`Td{6~YxbRgFB#f|^GRcxS;WYbfZ4o*jcp#Du&|QcRcF+OqvR5RjvKR_mj=}(cyByr1fJ%NI z|6c?akn9q}7Z||_1x`-x72V_6v*(?+#KD~}K#srW!If2F%B@D*+$x(A**l99PJL~Q z$r&UgXAwtObcV$|MjaVnm*rD?)KhK$lO8F(PmgDd(A z$RWE$e`XkXF%&RFU)DA*5@%h*ttvgox#yo!)a6TlU)=!XwU+FA(wYXbAE0U9 z31Q?InG-gyVjn}{@0qryuMWka4E_+izyifXPmv=-><(ZhG7kr0bDW> z6-PO~ZMRV&Fsn%?gjA1RUAn~7#x90Oyd0<{xxcx}KN<>F2NfrBcaD`RA>|AmKww~(5Q42GAy^P+kA+I45E-E}FBEXrBEwl_mD75m#C4M+>9$dmMoB_#0NLW{Z`f@|$Aiz-u z^~5$MCIr}``_b4h4g9SZ3uKNFQX7LL>>3zYcorP{XdtEgX!QL{0@auSs* zw{2VM?jv8tA2Pc*@yzGQY!uK>Wv62wA>$$tBqIk8IxNY6FBk$r=+-!Z2%*It$UR*? zSeOiZz}Q}pjYQzg+9k0{(#aqNX{{#0s}j(+lOZdM4rHGaNu7OO>uti=J<~)$I7Puj zYQhYCxuH+t6a{UdN_9wsj8q5+xO@lLv>TIDK8}1uzW{$i3Bt zCh>%hPlH1SQfRr+KEURfm~;WwY3OM;FveVlu5PiyH0-T=!ak$_HK%oY9iEbrW`6f)MrOeXCd`Rb==>M%lTwp2 z(c`~gyC`h;W^V+`0av{WzxtZ#Qq%)((g z)@A1vSjX{O>+t*&kb+QXxLeXn%c^l;43Mw3>dcSn7!^z%P{-NXUwe9L?edGiK|%|q zc7SkMdR%9vS&`C-jP%ny{a+a$F+kD?FrPM4$WIwF*B7Cte4c&YdD6sJwJE9cTf~9t z`81Dh8$W){%D3g&?HP$hZI&}a&mZv#MHoCJUhE{k z+g|n4>jc*p1GjLv5kE;TvRUGf6abESRBdW z;T6sd^*8MkeD!5D!gUj~ll>j%u%H8l?x6pw- zN^HJ8@feA9LtLO$LVxrTo`XQJI%gzxBfkipdQfMJEY8>vgP$WUHM_ar0cgH%1_K^& z3xD&AO4G`(iW6{-rU^$ExK}wy9FMa~&A!ZJtkEKh!=+E>2Y`ngX+6}8@SyCg{?W7a zvm>&v?;rCqME=Md;EG5w`vp!Zg6OPoO@GV8oFyFXGCp(UR|nOd!wOq6K%vKKH8$j5 z%-eyzl8yw|X`ngO%;Dzj&O>^V@k}K5}S(rBMCAvaox(pWFPeN%5G+%b~NUxi%B_?0`b-6!e@$OLgdSvp{@hWn7cE zhxV%T5dIEeZ7&bsQcOl{Nf3^Oz1W=aDI>V#G+wgHXL)WDGOyK8w9h;D(YJ~9GfSKI zTp2m1t&%foct0qmCskPPDpye^W1HN*n}DZB$bOaZoH;QO%*WORCtb7&jKEL5rnaHI zXE!>!P@7s^u>$z4>B&{DLE2oO;rH4je;T4}YYR7*0J{_+w%3il+_5UP$4(-r^>)J^Cz0qk-gw6N`wtWo?Hq<$5V&u`9h& zhoaH@s83V#5d(~_;%Mrlpj?2tqx$Z`cZVqh=J6>fF}67!yPcRGrW-R+!%J~Vk3SX3Qa0f3r<&;*L)nvb{M zKO=6(nm4w;171QxZe*+^0jWv=a2OZ?%2~1@@V(kr&jU<^s;7P7dgQ`Y283XvgyX`u z20!3_X_cn z4pcPsVCnu`QBXwM2;PS4Gq0mdcWe(>E6+x)zXMiad#NEg0zk^566v=)jfyqYZL!w` zaFK5LFTcKSqhZIye!#Ly3T4{GUkP}gG%kbbs1snn|8k)H4^~OWi@S++%Jph4U`g5I z1+**KSXE-4l3`368%;ybM3wXjhgQhW0?AfbspFUypQTO%t>tGz#RFt=#xndG5*S389;DLu}Fn2Ea$`qZu{yvQqcwpO3JXA>q~ z{9seJs!31o-E%Dpsm$r#?Q$$fh;(NF--N_2JP!xab;M-b83Bo0!iY0Vrqfta)#B9D!b(>nXgjHvpqkK*ga{f*p!7;ChVVM!bM&EM6t(P zU)$zN@}8Ri{BewXN{X9yC6l~Rzz10!|1bi7tLH=0Z5;VVBk8V3X2Pe!6Br*PTWJnW z$-I$CjWh~UCK@wmd1hPZHRgN+s`Q{4*Ks7|#OQUNI~}hdCvzS@Xy!aaS2f4%C=d~s zx4f3mmp{8i1c5b?+BQ?(gG%+Alf-I2>P<8^5 zvfzWmP!bAaxgoI@As3AkFe-~eB19KMmF=zsVRzRrELXAZuO3&c?He-o@4juN-mRi; z0X!_-P*5V+t!~Lbx7(B>9Pk)U0N?}YykH*%Fle`7VqA{=CGcfZrZuN{yGSxk29+DJP?HJM4|v! zDAj?@kdo{s+HZ;?*0YWu+sQck?Vk3!0ipyXebQVe$<+VZO-lNy}~(#2X&7Gans zN#^V=eR4-o>`NRnW8 zf_R|tKNhssRm~mrS-FSZWPx*&JrJW!nSaVPC85Voc{o;cVW;c&s2$5uj_Z9w!1gcT zjn#S4*{2An#F-J0S`9Brw%>T-r3`iAu<@e2D4*Fu1=?ofS&Q%YtGZ_gH&A@tkh$b_ zQ*ml~<@^BK{g-9(z67EI>e8vTo31KOdV59gnc=0KamR<+R`B6P+Hb=mfucgoF-OA4 z=vd#ox~5)!rI72S*R%+ z7!rfWy@BnTWC{{Cf(Gzya^F23sCdwt1sS z)L?}IfG90TcBlv7RO43cX=E}iB{Zsvi&nHbUx*mXj+q^H6ETh--u;a!=SEj!jVPkm z&-gLRD22iHECqJlsXL4rc~S03Y#3#4q$l%fb z73>)cRTZQ{zc(0J5p}9lEPGC(=z8NUq~%dRtoF@FUznR~sh(_H?2hZZA-0mcM3yjf zQ6dY{9Q#QYKdP^&>{NG?j6+LTp#b2+GG|)2l_pTOQe*v^7^jW9i$7=~*R#Kkv#~i5d~ch0{7iWp$*-FYnMlA>Xqb>>b-lnzBF2(Ctg~ z%Yt?ETsLI+((5VgPQk@T+XfKnDuD*-)F9%s19uq{8aI^hPpQT0s&cA;n3?BXB@6hG z{p$W_O&6wILPcbz1Sk^mS>H?!*k9#jkSX7*8O)6dSO9+5@L)FlVsEl+(Uy4lj(?e!PV3KY zTKx>N_`9poj1?4eHQKbgLgM|KK1~KGRSta|78%r$m@W(UBN9^81vm0|2fn{-tO_2!_te$MKW8Se z&@1!r?3IOFC*EK3=EDnXhPS)ZQ{(NnBX<3(4o=v7qYt#L<^fI;-fne`Dosi?T73z} z9Kpjf(9_ScM)=QGCs7|Iu9C+k573Eg4mcTxWRZZoHZsOPGG~#CKk}d6T{W2>Ne)Dk zbay(g_H{bXgFkzCHCTzAKGzNaKI;WX0g^R8Ou0pztcl0#fvsnuED<-drs#L%mW-r^ z21G(<`XI!b7Veaw;$VKz&SAEy+1C*Sfb;!0RA26QZE=p=7$3u$pwBs+8zr_ z?nh(5A{YozW$R*x_C#2cL$Mb3$Zv&Bq}>>krfovHB-{$88ACQkAw9UJE}-=%Y!a!1 zoq<>Y=P?=;0nuVUg|<+(#rfD}^2r;C)`(E9KoiHDgG~sN`&>b{7Z8!sNW!>sa+*Sszq&o%hAB5eq3bSD zW#Z@PG9Q{JU@xabtX9&gY2vGdPz^~mcB_p`Qi+fw&hYc>7kn7btfCoJx|vSL_`R?v zA)=cMCK=8aC5FZ|f_Ve1>Z@a(zT!7`4-FG1K!q{1E*l?p{uu6?lR8&ZKeMdUIa%q^ zYj)AVjVmB6DpD|jxx;%2UFU=!j?Kw2_70-`j9(E`JMWs$_9kTZ%2wc=E**~5CZ+V^ zI6K}C*@N^ezRdwt!XXFZaH40l)}A3l;#L{FG{pT-8U|hOIHv>({qk zZyZ)XS*!xK^sSk15tvwT!Se5u`w#A0Z2ix29$6skU!3|=aaiu} zg-3`Yu=nzwFq>tan(liVcE1EAG9q8?LvwQ- z(UHic1DuY6{5HjC_3sPES8j6k&yKGQS`{6SPmJo{dvLq%=Wgc(av}46!@X$txqrjK zWA+<6zHS!XPlUv)lL@Ca)|d0`O6Dv3lJ(uNLicDT_oE8;bwr~cr>L#j-d2A6;V!9s zH(5m^xOP6!@9ndgCsah2w7z=R-~;+q5wGq0uPk%iUR&jFJM?pHTEoxE+23{Db%rv# z8Qzs}qR`l?^njQkOL=JUjIN}_tV>Q6ZDk7mkj;pwyeXn`;lD~ubMosu`Z4>gmLC6` z)b7C^Ye+ufXDT=GKExMQ`t{nqg1o7gY#~j<5Nhq#mTBRdS^JTacF7sM@}tBbAv+{2 zFeTMJ$=3NR?1C^ue(E)p>gS{1_Z;}DeqrF;-%j=c8;Mg#XQfDM#yw<~B$DZ)r0N@k z*5CFv74baT+lAf`Kp%MawODl*N;2$8G$?G98g%rR&+RhrKeUZo5f_;|IKyB5#^2s) zt8;Ps%#SPQzPvB~*ITsFe5c89gp`smzAB(o+GlphsN$Z!*6PO@6Vcn#kNea%((P*R z)sToT{H&&tV~KI%mvMV!SH`O&YnlT+^4=z@zWe*_{Ov>ao!@q3O4!a9s#Fo(+T@icr-yp@8bGwe21swbHy|ZtCd3f*$OIK{*-c5C_9G8!tn>vadU%I_6{Attu8h|9ND^3gwHxzj5Vbfp?-p zXW-wRA77rot?W>?g2Z}GF)s-`@bU8pHNxO~0TkMRoqu|%k*~sIw8W43^LBQ<+2Rr6 z;B=e7L?h|L{Np=&tUvZXI%Ox?*_-%q(euS6*E|23&;7an#vFS$Nu8d1+tYw`SXn&f z;pL~FK38nGSDY>z^R#w9zh6{&D9%^i@v6$;~qxaxw zY;kD(e!k_m)75d;zwB&{YAUbYooTLUaxlR2J*#Yob+E07wdcU7M8TbBA4w3}_-wBSX&Zhp@b zZzf}zgOtx z5EC}dKe{9U<#^p}r{`p>yb}4mJ7YdD3|U_>;ysBfc(6xYC8Uz7y@wfpd*bni)1NAn znTPWiR;iQq29E2FrrkUJ9xG{Y0i_r7>pJ@k042`$&fl@tf?GVGXjO1<_=VfQudEU$ zZ|UsGEh9FCe#x^`mC{gkIAt7vasNa=`1h%Sky=E2xHpCH%I54^p2PT`#E^fwW9+9! z?>+wAUt9ZQ{&ZHRujo3rM<%$YAk7 z{q^}PjbE`nn*U{d%hid6Z+?v1=U(9}AbvICdPhOGY!Jyxt z9%C-IEXd@{wJiNKd^RiUP@QyhJP&o|?K3Ffrl{^=?Ao-@vzYfu)we!mi8;i7xW3ZW z)^>H}O7O$?7Wn*`JhGWD*ZHjEO9j%ddvj?HnJ-Q{yS)jw(iZfti=M6}vy9?@wSI9N z()||w>*FoyU*o1(vTu-)X6b}puQhMYo(I-_IX5N~j#QpkeYPV`$*>_}gr~5~7eq8C zk4O=J<%sv)Cwk7{d$#oxZzb<{=hD~SCVfq;#hk`AoHX#VJA3_&smgZs?yE`fb_KXY zEB@)+@u2+(}%%=12U*R63Hi{T6ik-r4LU_p4r0%g+R5!gzPaOYViFe>{EL zvh&NKlU*Hu*w^@|tV`#jg_jG++$z5%TRj+9jGMY?3M#rN(1mM+w2TYnnw=sByg zdL!m>%fsuQhkZ}UM@Oz5D13*5Ppg|9K60(R$VG?x^6{YNX@75_rv^lr7(Rz@`;a#| zgtPi;Q-^phcd{SP*OwdkdZg@vli)VR;C}>5tL5#t-h&%DQzZb(iVg zcw?9lV`43|G{Ih(f7g59(eRD^+X`Ipf_HDeR4?*zE|JXk9m|TG=ZO!jv5nIv zL#+DPozkx;`$uZZS{y5{$ozcsj3SJ;<0F+Gm<0JaHJ=9V*i}!x3%*p>F1YG zY2T`|bN7AHyOMRH?`o}sinmk1YN)31)xqQcF3f&S6IwV9+-`Z($WA!(zV-;uch#5v z`o-qUefljU(P11(g3Rmw7dr`o1^?+`Ar%emC0irU@XVf{MlNfkDQAB4R=M8#Zl4)7%gcQlTDe?P5wVdu)LeK&U({tk}YEAsWkE}`gm`DfnCMcd2heZDMt z&mp|QtLKw15 zzngADRRnx5{Bzu<7V1&??-a~^AUW1 zUV-}W;T^}Qn>)VupDJ*%JPA+_+^eue;{JavzIEpW!~u#r@{pi5N}K&fWdPWRjkzY1 z)|_iMsLr*d={Ft1xiZ;1{H&FZoh95W z#+Nk#)M-22W{};*riyc~k~lJuQnCcgfBkY6*oNmO;wjS5B$aI-fFA@%5YCBXMqDsA z1YEI0ISO19uR&W>oy~oPi^Zr`+JLpx zNYdde;v)sxtjQRvC6)Gzo$=_LOm{3YIT9ST=Um1>Z@iGNjS&lB4vp?kD}oovzF5Fq z{gsU#u@bx+r@B2Q8`=M|z%qbXeqC~pZLv!O<|M`3WVUC!gYAG)G;H91%cPSAAlzHX z5U*Fo+V)cb&n3gL$Em@0L1^@jwBsoE@`cAW-uzIpVtK1Vb&^?HW>p0CHFlS3)r$M4 z#Tz;TSbdcw7XdliqN4z1M*t-#E^dx|37&JjY7r>pTgUTK)|8X^OL{?@?xMxz1HpP1;$bT;!0kl_-;+ziQ*Xv(aHizE~ zYNx!Em$G~fG+&*=3cPv#QH)`x_Mb>0io)MiN4Y-lX@U2?`UUm(8r=b0ws>X~ zmZlKDY@j|=42ihz-^G(1_TW4)x`xQtBJ_Ma;)0mAkW6Hsy&iXX)FQ^}N`?-E_hTX6 z*Z7r*KFV^PaA~26r;0(!j|7kMm=hy!XP)o$8oW3<^`A_T2_1Q~D!B(m2COns)jeLZ z=h!EFkb4EwRn`AWSfw~A1 zw-c^e-zf~*C5WI_yoA-b!XdoT=Yc+F77D5z4y4VucBvX%91w!}W{d&Cu)p-t1bq z#RwSlg9D7oNrFRGg4&mXX<4$Y4Q%GSw%iLR0BIP=W=>(K)D2!Eu_HnO!CrV02JT9L z!8BMoj(pFd<4cK*vVQ1o8}DZ_+yx@$SEUQ9SpG*SOrQi9XRvLFtmjwY4`r;sLqB<8kxQ|97wpc@R9+D6c<)9@^i;>hI1I$tShYHGy9y0|AI znoz*Jiq#2MilEdoY*$70b31euQNtWprl?_<&bsZn3r%M(CI2c^dJ~YO5^Gd&QbG73 zk?u+*nuIYKib98)50Yv?DGh5kZG^!tP`lfyV|c6?5y&)q50i`4&W7fSi(wwSh;-i3 z2sdee&?>!2mU=OMX!$0g|0w#L11#KWAacEWo8rMTy{K<70lk>+RWM$@L1=#W91*I( zW|S~sA!M3$w3B~)Tk8r{)&*-E6Mn!ixlTW9qUj4kjJ2++Ew7?)=8zF$lZ1=T)nHxK8taity?p@(;UrQI_$IR-o_=TWwz!LnjX(0ERX1bhElV{C& z8sEDq-4Y;SHXA?tkeZk_&o*C1ZN47-H*y(XAF{){25N81-V}mMC%#Ncfj4P}etjE) z0dm4}`P(Ch7!Wx%FAQvI3iA_e=cve#18$5pk;w>PG+tx~Q~^jC@P7iFC@irUXw(30 zJz)WXArIiGIyuM(xF)N1vFtwSEYb1?N%V|toN;G^Em9y3k5Z#%8^{2ksi-W|b+Lys zIDB*_=v|tYi)X57bFSrrL5bu`QedtH55|G{_uoab0SyUcT_HF@;`SJ_e^dZzIpD5Y zU@;W7A`*AV=cVA;cGiY*+N8>h6UkX(kWzq&7;8e*)i??|fXrC7oMm8@^3ZP;@n#Kd zp(#-lc5rKhk^K!4Fp0yLyIp=JT6CIWv1b|*GPKiuewK9SZq}_NX;hT1E(7Zz5rcf> zyHzG`*qaVO2=`EkL~3H!Wu91EYJ&hrbcMCX~7~7p0zxiUj1A2s_*D1PJXc z5d16lnH4ys8AC6mqX#nYKY!;B-U$Dlqh>a7$9R~NlQ|aJAq;%1DHpT0q1=dVm*+RV zdTyhDFOcyQu?FvPuRol&sAZK3SmJmKUKaINZV=tr?%RRC;ohW@-b662M8{cq{v7Nm zHi{*dFW2<}WQ_Vq)=05q1k3VF$qVgXRS%I?OnB z>Y1i&)4#Hx%Zlb<|5I*d#S->2&YOvpZ5cANzbv6N)f}voqKrm`OLhu58ULvh+VLxHAzcbIHk^k4 zDXcMb*ukFgGrwpXF5yo0qaULeGydTIwrtS(*eT`IvPi|IbXnewBewsf*GuKs0)@Ed zCm9<&aQ*4UjYVYoqKnZ)F7M@bPJzh6kEXY-!jbF9I@J z18x&wm7W9YU4SpV>|CG4>MZ#e<0e4nAA*nNOyn`5_9yXC?2A1nuJ?1N04X2j z7;;s3o?A!Wk_t#K7k~;W4nx$S!d8XN9t=$0$SG0&&)?`*H--EM#@AZt5-_eHYd1&k}MEmkulT#3QS3 z=O|yXM-+wNs4_QEC;M?5oP&AT@>g-6vvGTm7*tS=v3Del;VzdTK*rkvd>(l^LAs*z z9YN$k3hj&HAVPitK36FIqUb#C_7GZDkOW!ml&IhF%5nE=4J=$TW6fV&UAyumx!6c~uW<@JtZ2G=t4cz=G9b9Xf&DGk0Q2{Mr267*1VEgzPwSxqXoQb=8 z^KUin_!VI@cXME%l5MC?CIP+cyWd7q;G4SoBAU22Y7Uau+d#1%b0)&DO8os~-sfsNU|ogJo(euMf38|C+j8Ld^6-RpPJT9ID#@TCBMDM&dZYC2)=?Ehw`WT z!x9r=g)VWs3N_WZB#w~6&6{y~LI9$K-=Mr!YOBw!75xB`Ijj6NH2jmjS(ly<@Uif7 zEO8q&6oj-0-pZ~7CB>=vNU9Z{3@*R|Y*#C}uMSVs2Fj)i7S~HU>|)1f%B?rIHY5&k z2*mmvWe9dC0an@MR{p|03$*SP=(&ZY_A6YR_7rqY8G0}h1%%~8?3WigJkbo`Knyx3 z#LQb>YRec2>L-v54aveVs}=DbYav$|sHgj1_f*l&`|7)#_fM#>G*CQMgp)MXNWOBe z3pp$R5-i}L!jMHYm=+FxIVB|?2V_#aBoFY_?D*|3P!d&N zOc9_AEQJ?dM%5*ehq>su5FOm%vJ12(WO67^J3!nkImb;Bem$N2RFai~4RLsb63Fct zcbYIvMyN_aXJTw20oUvn!sVk8hy9Gm2mNu4IsLhzfwLk?rCc@!_ggjT&zbK=hHRmX zxQ}W;M|L}Hps$ikI-hBjnZM%DhS_gl+0x;`HnI(5c4=pZ&xVfBc|wviIU$#_Rtj%D z;T&C#!Y7YAVl6()ThIQUIpiFd+~XkvXEAA)TXe4G7EB*y8ZijT zZlim1a@f*7uu@y75x)Bqv%_sqUYX>9YbuGLVt1mk_k1pmsf zDA}JEEZE@eXW0XWp-P$e>}QAAXs1tImD7G$F+8JzObN&~l0&L2{C+v=^7)GR$8;>9 zYN-5;{`-w9@5kiS>P7jD4UzAIyEj(_*P?)5|Ikd)$HR8%H-6mfNat6W#nWsMJFu13 z9hw3Py@NQQGEIy(cogKw@}JIY##O(z>jIlZf0=LXlY`d~V$dFtn|(AU6>YG2xF}*` zC@g|$a;mw)T_%8z=`cLqEP;4xc;(zb2{l+yj(F;peY6n9HeeBiJF)PLG{AbWZt!?P zfWITagKdk%E@6k(k?eA5O?DY}$Oe4w4!l=`Z`-dMi=rMyFUSijhy7E#MGM?34m$T5 z%80n4PXjFQ(tj#!1#Bur*5{?aQm!JfUD>W68v`W>kP1OLRTWlP**OFuhuzFpq|}gQ z{4jtBScAc8(!n4QTqG^;jR^!mlmvoZP1bW{tDR*Z!2J2$TFjWWia|y*uzoaQx6{nl zKzs6k1lIR{c7hR@=7gNi6`D8qk4Zn^Q1+yWylKyVqX5`o>zps{L273|1@<`u8mUzs z&eW}AWM5=o(P~%tkp@H)`8wgpS#C96Nt+GQ=P1ho%W*?bl3@t6eU|>li5ik0!8sd5 zItak5GjUtJYc7|U3j-R7+Ne(8gtkQFK3hbusPYIKe5B~`I)Ql>ke!dseZ|`Seh@YNy0jlBNy(fc}P;`Aq|nq5mhYEKFo<*~06D8>TPuBH>yK zSSGRS@=iBJZ8jvMD(%oBO!_qTNRC6?91{92BgnVkf3HaJx@+lXS!MIqp!QmbW9G5Z;8= z&9pGGchQ}(76!nemq*4BZquo2eU^fG)WHje+C5AKhjEH2r%`s>^uqKo7dS1q6gdfZ^TKb_-(2mHbT*_v`5N6DG|Xp7Q~<7M*2K zK;EgL8>HGi+5qQo87W@!JO+^m8aNolu2=Mxum>Qm$g37>^wq zmjl7389J#0>$HVLaRtB7fxYT$vQL7u^A)I^m}1`vR`@Wj^&AU+lL1^*G%6HuBbnfL z9PzlE_JS(0TxMqz!Yqc(rytzSI8;}Pc**fk0|V)<%rT3zx=MxWns*uhLv|^}Gni!+ zw94y^=LNZWOF7(Ibe`LNO2}?3 zN>DgP796OR`v7OK9j2+s#OQb%`PZDX&xb6`O`aQI*3KPy&PSB13e z)I#+MOuP}KPjryqVR^UDC=~Ap;-f3gs>pYZ12MF-v9F~4&|5wz1aH!>J%9e@c{-_% znEg>$aul`0?~?9rr)pq45)2OhCMrWgn~{7)f$wQ35p2l<(qim~c=AygJT6jcU%lc#r_=vD)c9Fl zu$C|^IWKy;f7x{h0Bd|lsfa&sSnGdfY2`6BIz?;(aF0vY{RwWBZ+^!mbs3X>)NAx$ z95dy#p4FQH5kacYnl8pus@?fcn1XBgT zf7$@bzwuDH5#*N&Ko`I!8L-D3Y|w*3cOyA#NQN6Ewrm&Zspxb!g_{Cn8g>tC(%Wtn zD6cqA(w~-pq_oPogGRd*k6L&fGDO*kL3fIr)IO*n`C=j1jO>)|NGrQNK=kjI>LzRE zdYql4RSk5r2{hu3JR_y8xEgYI5y5L@%ANP=vtQG(L#&G+;V>5V1XzUf@c2*6Bj?Jb zhe1&HNJo|14qw4$tVq$#*Ze#5?gB#0L`*>H_63iStB8FaLyXNJZy5z8GB&&}1-=A; zr+M7ILc_!(eSgGPqg|j7}JZCHEAR`ISN!P7jpF*jA%;(ZZWI>((X;5^NSWL_*q(lQ$z9_f@r0Lnf}z^ z(&tI#;QF)IIrt^VvLKgn8UIM9`{@>{buSPTWRQC*pZ=gP!%uIDDa7^YylPdr-@A;B zl!j2OHCzMS*X<$9oq+qkCABeSX6$)JukvI@>}GrLVh4YB%IT(zqyUAAmJ#R`kp4dv zlYyZLK{eZ~K~bHz5whvPvSIDk#T+eOGl{H`P z>k9_#Kcyal(8wNz!*JmATWDPE_QWM;^?bD>@gWf4)=N#Q>zk`d-pxmoD6@iTX~f}YNC5#NotETOqKSb5STGcDV;SJ#l=kL#}ZNnnI@0mgqwY>5TzgJ zq-CG6E_Kt)@Z}dY*Lsv<;J+@Yq*=TFB%|WTTAv->k91uhdS4}ern=C-WA&G6Mz+kK zvzdPT0|zzNYZ;PWms(;7ma@6 z83Fc^HxCeklMlo?E`uqb0~7@s62!<;$>+}u;I|PY8_W35Pk=#+N(i9yMi{;NzTG?f z%Z+h0hn@%HMj~_`;%dj&|<@3<2AaqeDwr7@|bd1Egu#vJDup8sU1RF9`~|J#ttCDomnrYD{b0Nw+&D(ZE{IT~3%2^m1qxy`r) zasuoW%{cuNp}kmtBnh{xM!Ny?%Mysyy_#|4K8w-#U&qEK^N9z|R8r+G+|x%8{B+=? zt1OD?KAzzyM%PrVB7~#esm&n@EfFTpeW*Lr9&-Nf?mx>v=$hd1 zssVUm=v$J8v59=g)kh&2-nT2PZO;1ZzCPF`uh5?Ei1mTb@)W6OdMA*Zwl;*;*%SCl zD(GTJA-B^V&0MMJIYNrDc3gcL#M4WJRN2HO8@wKj@U6Z1( zhQDTQZ~V3uKSNFApkRegBlgl$IjJ-@tFv+BJzo6u`i+9iV_kl0=M)`Yu_;M=ex~);H@<{K9LU+R}8@k2saMeW8b&j0)dBp*6{b5^vmG-y1D*n<^NC(GEZU`T43rRJ~!H_!j(v zXyAZ4nz|=RSsGB;tx(Y8?eMd4N83(JTE&ZkxO4~kTWJ5eR@S$nDGZ&ebwShdMx8~Y zw}VYmMY2k+eVO-oS|ywlAR+Q>diV2KyW%sjanl*tymgbB(_?aqDdKMhivBn3f`4CE zT)nIEZScoPO?bt-@9>YW``UHFDeF5LQaV269^!Pa;vwhePJ#K+x+>(mxZpsAJ8#v5 zWTLVW5U>5GMg^edq_h;Kn7NloRxWiZQ`YX)rL5s#cVHn_D6{<4siovyFcv`cK^o8% z;*?BIvi-!3Bh-sKomXy^AtuTUfKD|5LQg6J1A54uM+*>^0MP8g$#ozLmKUa6a01&Q zxLHo(>jv~~Tst4GKsg1)`M_Q7@b6FO0Ye5b>I?kBvj0m8JY6|Z(s2IbCFFgJgMU0W zpymD|6a9sQ+Vk!fsRC1B`{)7hvFkGVx_kxXG*zg`DOEo$6FthX0lGQD5b>EkfEl)& z2MYX35kxGKe=jK;n0nx>N0$d{O^NjNST-IM8gtaaXtgFl)t6Io2{`@_iS5H#v6W5A z5v8GJTW1(BGFj<>|KeL-G3*ctKcK+srVK5L@SlbFKf&BJE)X6M+t$Kuzd6TY){hM2 zn2xjoz}ekKJTDl;&G(sRwCT@I8y9R#JEXI%${{Ui%D&QT!w#8zfS9~J@m zP5-(%^kK{LN@P@p3M`{6j1|#Mr=^jOUfl2&Qwo5jqA46U9hmK-DB^G}qy<@%TBh+0L8GIhJp8I*6h!}pOp zsm`4-B_DGR*K=e7b}_xTC#vRSsc~uZZPiG3voI==_Np}PBr_6mKq%9#H&&{2iMh8N zK)1*50mWAYXuC!`c%^+TV#9g$B#%E@pYA<9G^O~!`m7- zeI5z5GwBrSVP1&RM;-4=O)r zRi_?T3%hnHhcCUoa7W`VJ}|IV$F*wV5#nldMd1eVA>!iWhvJv!zlSTYcEAv7`kM}d zVK^uW_DOl)+jSq;iui904KCMu+R*;jChRJ8Ieq5JW7>xhOcF&+{W>x3{K_WI)4Dh9|%tDPI=<; z$4KG@yCN9@NXk2`a66Ju#0uXKTJ04mX8}A?q$;KmA~xp7*l$xf4Ao^OqI4 zJKm>S1~I__XTLS0!42upK@aA4BX#pFz z0U>69D~VW=4R%!>8JZ4m@F|O=2|klc!%N5So?fc(RR}Lde5y@ z#W(eJ;^|=WC8cG|wZnGyy5DF5+MJtefsO8-tX$uJLS7jYS5fgsGtW@5P~yVr*z&29 zUb5J=&uHg4_z4WrkT6B=qSS{@08zyJ}Iap4XC> z(uzRL%U3D48NIows>N~i!Q~%WcU=mSKL(qde=wQdc{HiK7*xGLi=QLpc{juZ0He1w z4|4{+Bco2AyPo_>pt+h)_K`nA1(Oes50&P+t}n6h_1>XUNKQSa*8|P3z5SjND`QaQ7%y z%P9BnnH#0*AGyeb71?zgD3u@eoPWNq`3Naph2*kYi7%*0eIuiIsmNuc`xzJfGsk}?JyQ92yuZ20)N!q(ZtHl7S>5o?eTpyJpt7A&Weq8Vvl!b@2n;qYbdqTK%q zTEky4{{CkPtlrRx4{>>a;n~Vr$=!hVySIVAt66K`6;eLU)N~q0|3P|kz2eQ2LLQUD z@)J_83i=Z?(3=cqHJ?s=M8J4SmmuX@x5N$-SXc|(eti0B`1Q~^f@HNf^NUl_tsDM(}qK0M2npuz9yz;j6C0-gDGejRj=CNy!K@bd9RhW^kvueJIZ zZ~L1n?~&9TQqIP6AgFn*=?0Xa4Cm{JPZLC^7WKYj}7L-8JL$9LQ@EmcsE?eGPZ`LarkB2%bBwS?NzX{2QFP3kz(m|45b1a)> z>oy=!oD;Nb$2twXa$w5AB2%^0ckTy7^eOBTVDs&CpCZ5Z0ttH_y+3Z&1!y*%^fw8^ z&h;#`=Nu_Z`>*z_L;v4*9EZuM6Qx50DQ8n17KWRaXlOmSryMnVZ^7|o8rOqCe*B9~ZDg=%#a?X7ppr8Vb2WfC^>t`Q zN`t-RtKn$D*B?OxHSZJF{@94lUm7d;GUWPwAjJ(38d;vX=z0KyOwOmS{hdeZcWWi4OWu>`M-TmR z9y{i9uTJ9|nU*Y8!EnN~6AWRMgE$SOKVbqgq2ll6=c2PFor8r%+hB zCZma5frtRPOmd}Q^{E(KE7(=3gB&qr(74EQO)$;?M_I($<%&?#O`c}Dz?Cq@hFlpU z1N17It3(D8$!zCh#_b!}cq8~Hp6eC`AJU_QK+<Ijew9tkg4X~Qt z&ktK2bZr2KwSli{g(y%Wt4`TOi8rJ0-y!vLD&St=Jl(^9ERdxvz<50t(PU*0#6&w|&e}BdQdhjPOsg^PJ)ML~dC0li`CJwJ4Q9%&W9l{deP%HF1A#%-_5nocMizRM43 z=^tS~NudO1**^PM7=g0dqqLQz5uf+Mw4Xg@;pvT;%Ym@BT&?nROj&B&6E)?N6(ib8 zvAm_ZbGcb8<@hZJ*QxQwZe46X|8$(vl&UwoGQLY-WtEp2`V!JV1$687sQWI5bCDf} z+i=00t*oea>=uG&w&~2Hl2UgrVyjADDqcIf`hRq9m%J^;A?Mv?$Vr%8!@T-RvOaJC zPqKU#mG+D*6ROUxj!$hy(H*yYx}o!Y>$6Y85jmF|pP+&eU;eB|jsy`JbjQaBt)nnX8~e@yQ^ ztaDL#ocQki#644^xX(#O%|3NdVoxR%yS3F?SN~bsHtWIrb&5X*4APzm)woBKbRR2q zDzS+gjH2=oB>@eRQD4S_YIH2n{$Ed;Myu#VkGhI+S$+15diuBH(?zm^uJFmt_^X_l zlm_+XT`EB7vNOzGTNB)Gvg(lNwC7%IO;HCTE0mFiBuVDaAZhUdUsGl}BTRS}uPD;% zd-lI*$tdN_gfCpM`kr>Y8^{&y?>2Ay&}D`c1a6g-VGeWu&AQ$`rJRmhwF1=DRdTRa z^s|rXb8VG-`iQ92PiGpT3xwVYT3YymZtqG%p#Hg@9z)n3@(cvFDTxm`fWUGZa9_F` zQQ&Z_$QaSgp8SNP`sN_nFu{M zxZ2V?=n}nGSycvKZ&IIY6oIB>3+y~O`#6uDrGm-wp1059#fOIaj%b!^6UsyQbFzCV z582$WJm4)wxIu|>M@bR^pKH%X4ARlf7t6mcZHdXKD8m~gmFRBCd%P%ZVTPH2C;1CD ztS5E`_e3Os57v9%B0}rhD9qAp?OTOrO-7x~DFS7khRAhXzl-m`X5RI<;pAbP_x~}sc-8?u`sxgJE!^GCr{FZ;? zfzt7m+gxK3+5Fy=W+>0=EZWtYO2{>4Wh?o~ABJ?_vo+h%5!?klFM#lW2@ zwp>NgVNyDBsnIxw{dYF(=P)DXNIVNmWN3@}QY+L%MUUg}b$7-P^NoI{D6HMXbo8$W zN{8J<3)fx$Z0xq_(vl=K{k@6=%zoADiXSvGT3ObX@w<5%nG|k$r7+F>+R;@h8p}a^ z$Z%Z8j(U`*{6}onbN#G_MD6Qo-chS~(UHezxL^9Bcdf*3V4cf(utVsf8`$g9f_!kP zTT_pW`<_H&8X3-iXj#e3kkNX@CTVyq0luqT1&SrGsRbS8t0%HnBz`rw+ zTk^n&2Q*>;#^nQ@nZRTk@P&e8Ss};p;DjNJmgo3o)lM~g?JvvJPGvIPmNd(Eb;ipK zpZNV!<^gR+BRD!?w7haEXn)y8W^B(Pojh@o@Vyk6nGdKzV3Q`ol@A>F-HlM^!s;Y` z9@I1+2ixTWuM;T32p|T@o`x^GQ~EU-C{m%ynu;ce!Q>o(`)Krb%iZd}_V2uUNy0}u zW<+*?7x&XL@TG~HsL=QoKd}I64xuQ>k37UJD3A8ORB%S5fIxeLvk;ep2fX2);wP3_ zOhMzgjou(~6WoYjgBCvH6-R0f@Jsf7U#Y6!MoKu@7Zk4b6yz5RbOn0QeYQBWrolOH zIAJdLo@qzsyoNE`&|dsZDHI1JHi5Vu(uyiTEm82QIXa|jt|+euON#*u13W=x#PzVj#;xmB1xVx9AOB>`tFQZ${$e}bGDCm&_fItMt>fjc3c zw}A)*X(V*4U~6r=Gf}aZQr)Y>6KBt;i5PDH{f>PZY+}1+oHElRGSB$y6$Yqk zq#;+*hNsicf1H=5&7nuf^Vz1FijUQr&?ag zXKMzpOlH=8+1lUxwS(LJ*Vsa`{?#Nv!1jD}TIH<>-Zapf3UpDAv<#|yG4p~2R<@6* zkrWgKFYN;OW+e7>J8v;;u!)+5OKq#!)OEKUl1MsRu9$4DG zCQ%38tVmF2OrKd+CEye;iAgI!Ykm2??uI@eoKCc1lYr=ttyli)?mem4+>=IxyW`t> zCN7Z(o7P!#mF`$jjezlbWEKyQ^@D4WEb#BI?Z{-XjKryu9IymMREQDd4gAriZ~>SH ze24{_P1-J#%W75K)fE2MmnnRs80UQ<)x9^k^sJ6ed09D+gpQ0&&Nf1=ju(fA#r8hI zUJ^(0HzVhAx!18tJ&I^}29D*ZfDi)whdgG07WcU`E)!Ps;ZI!9iifFML?IT?h>ta3 z-)?~$)}H~RvE`bCRRw&xQN_!!d$^XyTj~pf_+Pn}bWO+^pgZfY+9?>6=d>9gHkY}xFbt18w5Uo_KdnBN@tzF+*tc2V5=fF2()E<~Sj$8N z6a~sI*j;*Z<}fvYcq%!kzn+Z)6AX9CVNB^tF|`Zq5&37`a>9e$7Ql&3Q&7fSxb0C0VQc8V}Bw>p^m}OG77p-gikKk`Vx38 z>xmg5<`z(ZUX-Gwui2v)<%VW3%H(Pqi+|Ah@<{h*NWep%BtNJ{`wk(GEEDxUg^U@| zyq6CZEE0h=x-if86bN4kp5Ci?iG-W?*gZFv^`K;hssTk7rwXw~>VY)d zNb;CY@JQENZvj5K6c+*L8tq zeaY3?f0S0J3Pz=e4@r%(AHk0F3go(+Y3|i$-y>Dte&1o3p-wMWXL$XwQf=z%r9<2j zwcg_K-hMC07q$oZ^O?Xl9RSi;oBwxJB4z>hI6!zs6L@kKFbDX`;4M4w(I^mf2#PiU ze#kSdEV8Smo<_M4{P+TBw$79@>u8g%nHKSlTD=o89SovB0h?@VE%fORf?WjZ&aShS z<$3A8Pz%E6n~WZ3BXUj#E=VFtg0fSN5;&<)6AJ7hF@7E9rD%Nk;{m>HfDfyKwN!us zUnZ2pP}8&`iS9|jQlOPo!Jb0K?SyWR;Cpb1a@BAs%{QWBIAxy_85X*){&S|)*Q*=+ zQlQejv4r{81M%GiHJ3&D&sJ)E#)?pi*d2Ibf#FOAa*FEZh6Eq=4a~saT8|#}QvFRw zLg$@JzZL3Qtk+ehd6x?I040z+L+8=JCB555HI~tv)ci|OU?PdS%+;5rD-*Zf@E7Vc z70?g6kIfucc&I*coQoJIwC;L66XM>@vCkV{=T$avBK46VB073;H5Ox}V&SQT339>a zHwI-gtG%G6iH)q$F{SYpFpj9%Zt%;Vv?VRRG%c$w>)q)6k%YyNfofZvd;m9` z@syGOaL<+A{|?!D;wyW>z0EIG%1ZnAaymG^mD{fW*?tKvPM3}3$2qf_c9PE z`T;XK3e!Dfq)R1j0&AEgif)N!PsPlmM+5+574RqaX#zE4!U-^C8k$8q5F;(D?SBNV z#IdT!Mk2w_{!bnJ`>}|ckI4IjDqn1NEi5RRV4TZ^7Nz3M9wLGf>;{ z1M;Zzx>PWN98GyPKSYP;8b=yiiv#Ts9%S{%8T|gs85pkoLq#p^$#lC^>h{I>pesZ2 z+jDI-{mwnUq?GIWKK<|aj9(^-S~_Er5>P0+mXa>M?8{d;kib3E!?o*A*)DD$>{EXC zQIVr+mczMFFB$!|OBPV67E5?3Hjpx~wjxQDU&|g9rzrln)!|?#gQJVL?<;8c)?Lz@ zaIYIr%mqz0;D%K#w{?K||5Nk6Szr;T5L`Gj_VyNn-lm+ogc5KZ7(#nSf?)(G>;Zv8 zA0?mgz&HIl$$OSWuv@(GJwoz0g#<)Fd`n2YnIs+F2!0zN<2MEZL0I^t6p@MmCmUs- zF_6oV`|tP0+l*}xN1n7)Np(Mn?nmgIe<$EQdAFBadfOj_Yzp%zH+EM7TL;179!WPg zS_yEY3J>T{%VA(ybTkOMVZlYV;O;ErD-T*=2#z3|J?sTv(O|kJ?6{60sKtg65i~t; zTPkq8`#6Q3AH+z=kzM65y95jADBvvCDo8zMhK5X{VdChs8{gxZyPgTq`Ncm;oU(LkuWiwXG*ll|s`W?eak%e2ZAPO3yM z&pv?CkP#z1#nNk~$-`Q5LMo?iGE1BN+_UJ(E@O7C-twi3>vLZf@N3B`M%YUvY|8y& zT={k`w1AD-#%S$%t=!_q|Hru3 zn+f~NX?=>Kaj1u-V;%{UJcN#_|9VMgZxcnxlz^zvgLBGzX^L&FycWKW_2o_e!qH4> zl1X=j)C2Qq-g+k0+(2uZlZAT8i109lZibHC=^^3u<2*eKkl2|sdp$N4_Vz*>vl*$u zpEUy05{ESQW_3k-uC6Za&{+hWsufq0(VFnFt*L+s4Y3v9Z~F5!O#TVvyO_@d}01oHjb3;*t5`Xx9$VeWp^ z3~6uWq+RbfADX5qh30yflXBw;oGXZ&q`k0rpnr6E6IQk-I-=Rz*OFsMOkfyHoI_dU zihBop)fU`~X4F2{aqM}(I3Rqmnu8M-7KzM{CqBEvyt{|_-vedw9;D=6g3IKEwf|Uu zJF~^_>(`E)cKNLlt)eTan$qUIgC{RMZBN*Lid;QV=k_Ev6QQq=$3p!0Y5zil8*l0I%oV~LM@D;0Ki`1dlAEsZ_bx> zV3VY!_x#JqavsnGI?L3tBTr6aKQ3fKxrx`in+~A$&(7dXDSMiWZEp3Xaw5eB>((^Y z1aqnq_ZwIs!Jbo|%1~$c>rpV8(vr3;7@(p3F~I-y_>T_@Hc|?0q1T8HU0Lla@~vsG z4uu;dj}n6Jf(x+VICi0eE<8`+o66u<2f78$^;RM1stCc;u(lj4(gF%dBs2_HE73eU zcOt+mIK*TD;++PnL52{YxiI}zfcq(D@ZpdLcZHHVSq;DSg+?fx{}EVea(fGbYw_^w zSIQtx#pC8($P`Sbsp&b_S3D2bM)QQ!dh+q55-P z@TS(s;WP*i^i{;^ywbS#GciQn$j*_Xe}+L9cFW{EAhH z&)#nw4f}5ojkov;@JDaC@^$dQ_vbMNWYpq=t;(9xm4cw2M{8W%Y`$VRe!gm*FjG5L zW4}40mK}^~2u-%~H1^6;VdNiM$T;87TQz4IcFEcN%?6-UY(@-%`)TRPXFhMWHk19| z#daB!T0oo0LPS3Dr4EVy3?21njw4VRv+7M+7V(Yx{{h&f2K{&Ab1qb~z?+kOC&)W( zW_rpuk(Q25*Zx+^U!v8FAS>O8iMhi&+h&EiFN9NjMs3QUk z(a%c$S9G4ztGd6GVRdv`e}J?%$eEeBK>0^8Pp~ub-)QvNBmpk*NS@0weB4D-mzLo; zd%=ia_A>|)O3C^|wOQ<~&0Jc6I*IE>HN;wE8e;ic$$EV<1q}P5pL?=~sM^Q*yRsI( z#+LOeuf2crx59mG6902cDliz4LgAzw_e!}DEPkfQcAL@JGhB1-_ZA=b2xxe4+HK}N z=gs9SsYYSWLZe(iagsbErE2E%bGfx|F{O&7S#n`wJ>8X%10o+)sk~wNttKjEXVGp) zKEKjoAsThw!tBR3U4q%%=zj7G2qA>(R4vsn;xi7MUk7kC?Ed8{c*F-&sH+9{daxWN zv}Vt5iF+6V==d%V)#yF4SM(**nz3*7dA1Xf6q0oaZQlW|bu zQxbeXxibpg&h>!O?;*Jhdw9+tF-9w+C$sJidID+DD;R8e%1CNV_4C{z#`F4bIP_l7 zO@kaQ0Cy=A)<|@)uypq5f^tKO8G?=Tz^+JcBt-~AFkA4;07EmU@JZ<4RLl_!1vZZr z-1UHCsUid9f&uSR1aO;D*uvtgGl8|gk%BBh5nJc-a$fJd40oz<~#2aa~3AzI|LJFjwPIeb}Umg_EyK zk7qm@6@qa0l^zKlrY0K0pldhBshLU#SSU}OCB+wML^&%RYsz)APW!CK2u@kd2(3E> zBzjm4*K$JpM+KJU*mtD$@E)F0;TZvkteBk5MQlWzta*07+;%kyBjr>~>nExK!-wQ; z5h=67iJQi7Gt!{1zU%X;h?~~yvGX1!L0bg4Bg14_UfV+u@CJq*oRdgV6ZV9i=uRc6 z619i2{+a9<`uYgsI^PA^-6^*Y6U^XfMt1@Y{BcmwGroTObT0V1M{&H{O;ar<(}mFs z5Svsb!Vfdb9}MAa;c}9Jqh|E36s++Y-?hO*ss9}Hws5TC1xdR2T_Aph!!7sx)0wr8BsMKlk^4w-C;SH_c%uzH67-6AW<6qpL=A@tu~y^$e<`U$6K5>7_C^iq6TrwUaSt_PFo; z_{nk&GrYFJCpNNa#o(dl_l)bnonEy?lOfGmqe-jw5Ar|)Sk8K@^Q|jFSg`#YLX!H% zo7Lksjd-E@Z)-|;Z;GS%yfU)&qX#9eR=a%aM9rO&59?b&n(IB0NLHyx2LcnxTtaNd zgBvm#+>J<$k*$w+W~Exr&Esj~j(!G&`KnoztT>Z`6JCQs0Nn)gcZeh>3>b<4fC1(; z*M5H~fx`h{2r1GA*QoF(D&q$g_(6q_%j1L)G)4rQ^|5#sHw1`^%49p3pw@xa{o6=Pas1AC@QPzJFg)9IgBxRT0NSCP0VwE z@3-;$FzlY8=WJ8NmR?ze6+~XOORHmSBQT(8c-JF9%ae3eEpp|Y=IU3twaXLw(T{v) zqQj~o^Hu%9ym-&sI-nbp9l`Bl_8w@>FScwYCe&H}!53D$+S!7*2DP+qcVkxRx1%>8 ztT|EU(&_T?II*>-L7;Ki;I2@#QkGda2B?{tiDK*5tJu3&c4H>Fw^GNbW&|&lEAj?- zhgS{6VbXr)%`7=s;dSrHA6V&$@fQ3Rc=t_~8Z|~t8EnMQf!Ako#wV#u`4^dXISV`J zT7nJXMy<*@yU0;i4VBjW^<(@ouiZ=D75z*^dhEvuaGm(=9s^ZJ{0*Kc-W52V=g=0q zkFrAqo$lYL+<(GX_%(gXp05#gMm={jZigA`85vF%$@stgCy zb}C7lRjcTv3SGU&!w54{Ft7XaMiOn<<+Ei|&t{o2tIY_sC|p&g8kx99;YIti-C+2n z)XwZGdh0WFRkk z=q+`&r~(`;g-M0mqx;U|5}=V)Iq2!_&3A7~ zVDo=Zn}(%yDgl8@a&rOS<8@}9))aQG>@){7Yq!QL6xa_hGc{|h{tmVUYG;=rNK@G< zhrY!#?lYk~3TwZxf45er*sMIICDOW5#QPSa*V+vMnr@1~vq@(%%HpMipJrmey6)M* zHT9`JbxdKQ5^^6=HK=~R-s_o$3d<9@?EgVDIFON898?7oOs8@B2DY&+Rl1_AYH^Ab zC;HBAEvi$xq6WK~0RiWO3_uK&r0e{-kOBw_q{tmAJyR>V%ers?KGWwi<`_??fik0BB(%Gvw^$_Ck23$uV ziXmSE2u~}bm7)PMf=vK-MM!6BV4e8`UZo$nu@p%Mz&xr*88c>yrZJ`6Z#U~uXFd=_ zFoU9;cJ6gF{5Q+6$E7%UMqXWDAsAEfm@3&l)(8oVD7>%?1=cS8!d+N)Hy{jVoDlNA zTF$PeLW$doyC|(`+KX?NL>>p@QHZ4o;%2w~k+&{J;gbU+nOt>S`bc*Ukwc_&LC`MR z`hqM%y5{~@$It7($VFRv76yq8%oGG;t3M3avG|cq@jd`Sca3-bp80mgdby4a1n0#C+)hqBB48?_ORz#cO{OP+BmX+Q(t6jgS!;%!x$vY$dz0)C6KbA%mY z&?~qTfy^@MW_Hgbp7ekC9l(gseK2Ec>6O%d&q2M7#kcbtmEnOQwU}<-A1D<t;16H^ zF=NI~Jhx60NJeApfV~LraWz1kiHegUCLypa7lL@Rw_qQo{1FvCmW&2fCLTKz;MK#} zbL7r-t1khz!aXD0wrh1I3`a{wx>BI5rr=j9rVIxiX=D6vmSJ~!`fDR;tVo;nkPYu5 z32=x+h~pS8CZKmH)a}X2aOBgKkSr2SD4$$fp$S_WM9`G{&i?Tu!BRx~i{d)4dcJZCNXKAG)vej$G>o zyI(8P?0IVcx6nRV2dQ9DmUA>=FWpIg-d-Qo+WS5efimV=Q1tq8U$~zdw*fhh0FdqTGC{!v&Qc8wxq3%-xm)>u_a{=+{7?QB`}E`pJbmM$ z{nAI%6N+?|#M-^m9h>EaarMzl-Rr>*6Cb~D;@hdK?%-<8bV3|bzYzX2+pqA6OS00h z&_D0KvnW5hEy~9nd~FcFo|}{Ad>*lGLsfuBXicyw@fmDTqq)9})ZKDZowUw9Pz@xo zx|Qy26J!RSMP@x7wxO^;=aMx)?)9#9LJ3k%^qrowEj&JuvX_zaSxaO@~nJ~*LlVsb$a5{JMSzIl7ZC|Z12;6Ex6@xj`$Qe#pVJa#H>Spe7ff5 zNICcT6Ohc72MEWvZ7o+sT}=zeIn!DfYL0R@zi5My%O6|G1=mc?CgB69Y_KTjc$AEn zK>h5tp0^{{+>UYC_1p|C{vuMYXHJ6C2FV}@U^-JwNazP%LY{Q8l zEaR*P@JkmyOcfkb5RPIQh}&4v=M!!rVNbPGhWQX{#g2X1Y)k=CJZSqJR~#>sTiT<# z_wPudoOhJ8>%)I!*lrWH)Lgln5>eI_5U&T9fCv;^A(kKjD@g1qnEm|=g{1o`VKob( zmvqivO`4W0hJV4<2zJB*0-+-K9>R*`iQr-abcW7!n+KBUjDO*E&y<8c1X3QP)>Tn| z-5eB09rA`18mziAn5HLOvSnWALGeMrIT7WThRMT?XxdC+)}C(gFAO~%h9+acFCXDw zSdw~NteF-r4KQ&oG{(*79+%0Z*0_Z|S>7VMV;F_fMLTcBX5C;d7!j+|_$P0q!)5*Y z`2QRcmdL9=2|yGu##*X08rsQM)2#Ao^PVbu4C`;k*)x0zcp$2`u7Xc}<$UHwJHt?R zhZ>~zmaHV;BC>qO$Ctry*zn7TT#h}hM6-v2%45jgD~rOuAdK2~2<&u;Zy9Y0a^W1m z+o=`&w28zK?I54Z>xe)sA%9=Dz24xU7wcXL&+)`);G%4RkOc!7gp~_7<*C-H&uLHD z0M1?At~tIQ+l0MG^y~G}YDcEcs;mGnZeWy*Ea3ieI}@{3%P4O4A0}pvOdDa86cnF{ ztNUoukOX6g8b=d`FvySkk=xRP-5>O5x5Rm}mPs!+!ru=bZc;#sBRxsFd#|ZanB3!u zcF0Rp!SE9&f0u>8iHyh%tSe=qZddLXx?h)rvCi)}dr$=qYKeQQ?_LB3UzB3%yqUoN zL&kGbLFq72@Q)N3&jM%)6^wbfx$0KfC+G_Zg@?BIVmliSbWL zN>0ZgxiR0Zu9X*bAwSjPMc(j}p*W{vYm5JnjDMDUJ9Ja%CY$l{YbPFDX?Z=6d(Zr5 zGR`&KZaS&uMRelMsw*umEqg6E3tjB5N}o!vbu9y)C7w3V$sunh zuibFmLcA{F9v8+J-2Qbx?7x}0#Tm{|B>*T7v8cN`Rp!fSwwLi5ei+lZN|w7h;Qv#w zK$v7c!t!~SQnvE!=0jtsTL9qV;zQ0XA=6BJZnOtMUZ-k1$Ny)s7kr#;?q^htI3{17?N@KAgCT^q;q_S(o>uT6Jwbo6I$ zHW=02OLaL^s;n`E>sET_mv-iwVvnU}(0;UGknON(u7_9T4b=<%ciCTxt<`So|J)rq zWYWR0`fA^Kd?;s&3TmA~l?i!9@^);&(WLcbb#OY;e(ddCS+XKf52I~Qmj*qkcwZe_ zGc;AJ7lHZNdHEOyhLUzxemB4#XRTMEs?Yq#WDRwlHMgM0=4RM!8Zmjmmrm$d*QnPN z2wygp{~)!Pf7yCz`Rt!rOOJdv-Lrl%J?V!Z7fk|%2lGm|?VCK@_BJK_-}}@%=r`{o z&R3abzj$y^`OGe}>$d;JnB_^PAN|Unz9@D}8t9F><@hy)ykHU^(f0kVI&a$5%HZlh z!?K;v#I5NkzB8{n)`n}g)toX_vD0(<6Ipqq<=3d<`uhqd;;pz?luulv>cp*|SS*QJ zki*(`zris4xm@XYm%x03Um=wli7FxVI|}a$tX%p&FOq`oR}(iy%_tH(WXUV{mwdA$ z(`;AI6xc40-br#*(>hdtw>@C#(~!Jqd*#aLN$ijRW9i)gnf(7heqGzl#xUnOZ_eZ}#|W9TLZ&3AG{-1u zbfUzyIiH8*SmsdC;hjV8QYo9`h)h&;G9{^eY7XzBuv}#O_q#)c zZ?ut{DtREvf6(oKmFji6|2y%mLRq%P z^RZUr5sw75jGEo=1x{T@1`A7Aezyo+4(2gq@kI?zHp$J)Yi4GY~WM3?fkqj-Qz&yL`?#)_Uy3 ze57=1SH7e}vrb_1Iqz3*3v~LTKKAZ8SsL)a`kU{Ox{^Nm8F$B5-n%I(<-SlJO{#x! z;E-Q)xJSwpbVkZrL(jSWu6Z}m_FoUjvHMFe-L*Lz&(r5BMz{=)l237T_Sh;{$k+_( zz$A`d?0Y~z5Sw&=Bw+*elbUTeJDOtHUT*(8^? zbzd~b#X`Iy#zwxJ8e~-PcWXrBgLC(5kNY)xWvTlPm)*0Pu>HNSrRSjd&#rL@KlxR) z-OecG&;Bcn%9D&aaf^GwFHhaNH?(6q=gVl`lT>=z!$ir0%O4&Q>~?rj$BFIEyFW@U zW=1y?g96{Awo?1g6wuTaEHs)+Z+IBqlKyb_YMBYyYLUPWHrF}qY;kNTzq7#a(C>l? zo_5lo%Bw=r#oQmoEITrLxW8`Awd}~A=ZRYZD%Gr|?^X`lk+OCdYZVTcH~OAnjlQ~A zZ>#tBmh`uHtG)5YuYk3uu32d_Z}v?!d&HLYxP>;0tJz(sROF=S zncjJPtn@W_s=FtA_HTSwXE+l6LieqA`wsIxH;=UB1RGdOI-Ndf+rQAW5xW>1CNi`c z^1s(hx{sIqPD~?iOc3#KZpeI4fuKfOO+55fP`rIcL&mk+XcDS4eazQh= ztMBOK&(#CVuD3q8RyxM*tPi=nE5Oh*<6uhG=YMkwHWm`}kDEz%-oeO|I}2qRVTicB zdd7|CpDkB)dtKc)tGx1i-O=;7LTk`;IM!h~>hJ1+hN*;n$<$F?ldvJtUv|CqG;uRp zSj?j37I)da*tJ6o=o*bW`qp&r)$r?mS0`{Y*{om!-V^o8$PIf_5U#$+4|v@$c{lDIK7Y~QnVXdzo_*xPW@CTr}7k9_^$sWOFI#?L|z+dOHm_dbz*@*U#4 z>eGLY$(;Id(vv6xoIdo|i~T?`-n70vt>VIjMjyG8-1KV4HUD6f!IzaUjW$JGfA;Sy z6yY6iG&<-N*|vWAB?`rUSUQm_+xuPQnd?HYL<)_bRW$ zXdIT_uxB$Q;P^`I>X!S-&x=#uzoVDVXw+{m17FAC9k5~_bn?M%DW-cyKk2UGsh zifa~l64qMdZcMrU{55l=u6^V8ET?0RQ}S=|=2ML*{Vb6W$9~TM)^rgUutu+E$vExv zd8=ANpNhe$eBCck1M=pjxu!;JbGr<7)?AokrJOzPY5Q zvg3aqauHhw{Z;lkf5*1Sk`4@49mCtBd$Mp^#dV6~E z?+YMXtwF`IF{rXk^?z~)4)}(!EfUKuesz+W%nL097eTlPtMNI<%4sg`3Sm@F=cIGx z=6dj!Ld?p4H);mYAam;thpQ%ME<$PBQq`^4c=qa1P;A}bLbLc4_L0A*YOj2M8k;|8m{x)OBp;j88~7Bz<`viS zE=6Oecl+^zYBBj1Dt~vrgSzjlGV-X0>X_DpoY?(NN1{I5;4p zcuzKozcbEaqHI>>Vs4mD#PwH3GacN6&vov2xxpQd@kUzvEoOcl#b*5%b+9AFeemCy z&$T~%D=06%&Uy%022zs_{EAQvSXMf6}*Z4@Sj9ZiP@9r7-sty0&0TtoY{r`_ll(l7ncZYix(VBp4iBN1$ zkn`8&>l!*l0_lZv_j5!d0``>~%h?E9nMzTkuwuesqI^FtCj^}Hj2cE&4coK~;zZG& zh+dS5mve|d_`uJwe2tr17>)g$=w9Qea2|Klw@ZLIBduWQzVo>RUWht%(O!X9N<9`GvJORssZ5iGL4P3o1Eil(4*f+~@FV?#TOr}aDUOUvY3*}n& z6F1Uz$y@Yu^ko;nY~-2Gigbe5ItpXoClxpwH7{S<+md6>6! zGAX{4f5o7_VZ`m3Wo+)*{%dwaE1(Zxl;=}cfj%!NRGK0SW0`PIpeQ&5bR0(ggr$I9T)&uo505&|ucR`NTdI2|^B(>$ z{Owc>UUGT~!OX(30#T%+fGP-q)(Dd%RGT>hx+?gMjdf!6pfFNpVn~BRLU*VBX{;A~96*eUqq9s?GZp@&04)=JsMm!FI$WunU<)*C0WY#!n$7Pcyc}wU#bMu&0~Gb#?C3?h5h#`?g#sc45y~!@@rfc zQ9?ibkRNdHrc=RS?%pq7rf0e*H#5I5^=IgA)kyINu))umit=@eX%vNLG;~Mihj;u@ zR65MWcE;sOlL#b5nG(I&LZr|a3{V#va^Pi181jW{F+Fd3@*>qj@i8s1vfxjd{uM&? zd-E%+4BL3qD`O!|jYgd$dj*3!qaoGs7@nnCuR1OrOw9A-PqU|0hf zNvudrgKoalYnJ;^JHv0ll^m?_o0)yYQW zO_is)gn&kUNmrL-gs#h`7|9&d?_5kg_;_+ZnTQ2Qi;VW+UJ8U7)%eG-tbWvD?-v_C z7LB(Hdyr7voz;YNZ_dKN0q7TDNE1-{GdRxd*66b5xnpE*IC<mcj`fpMIpNMc1{`!_;nP7*1Ulfz9U--cy|&u zPX~OwfEX;$iJ+X6Az7e_?wTYQ8PGicdeK7&mx-iDN=d1mmG~p)B-`?&SQ)N^->#XF zPZtkyUlp?i+mJLG7%QdA}t97ZJ&McfJ#g)Je5(CCj#EPRXy+=I{*}`R|zT6EOslbqq&xlwcZbEQPqLYO_ zL0?0YTPvh>flpOv>L`pgqDuy*JOtgHg9G^88~Q;Mdr&k3wt-KY!R%GdEZTp;KL3bSzCP}}0m67uC*6^^~eui}K^hdU_Gny~8mmm-_{{A31M9}W%o0STYotD`1{ z3QOQgxb~7&t1_*BZKx();fAhb43PfkAXe=^;} z4Mb6+ORB_!Pthd8he)8&#mo7BC+p@sLNs^dOQKrO;e+|c<|oMBh#eQT zX}fv{=-J9#pUF`+25m->M>ua&iv}@clPu3D*U3n8QScFI$xkC$EKeuHwSQ7W>#}%1a|ieQ<00^TCP*9-++^vm zm*#F#1*C0R)vdUFz+V6XyPU}#CE*mx%!)5Y<;o*0WltM? zgLdt7cDDPEerK_v&+J~t&X_Soo98Y7H7yE^`Vs(#_1Rg52(Wlg68LflPD=TVU>rfS znq{E7y1**}>$es_E(4zKl`So_XcJo^sAp>#GG_wkFYLOXLZqm&CyMjXS8rz9kTfoz zMoHZhD&~`kSP_tg=HLM=CYGv=e~g06L{W4MXwm?TnL%g7ICOwVL&d_3n0b5BB*DHM zFiM({128qYVcn1!f!u_JRPqJxBxJWE{6_BE+l5m29hM}=8f=x2rRp1tw{9S%(SUVx zr{8Q~!-=+Z342KcaT=@tBLmeOzOA05GN*vDbjwVK2eBLJgrMSCiBxecQD!k7_1?X) z;l5e!@9aYA(6gVRsz!yq=CS=b%?Zr_gXT9$I`|;?6 zu$1C%sk}*T>&QiQE_OXME4D1iiOAloLBw8Pg#D-hBNR?N_bTiMo7kSqV!N-rsg+ga zoCr@rnrc&B@#3WO2|)F2L!->#I;Jgzm!HYjVu+77{*Kz7^hwHyA-)@0D8uzyGJV~+ zr?D!hNp`xj%$C+51ge{sDNA$W=oz&?$8a;A$Qiwm?+YKaak9)3Jfa#fzKvGf)jiAtCTK!V3j(WD(trcH$BIBUoZVnL`iS1KFzAUYPqpq;jX4J4~i zmTf--SnKy(Q>-=pmK`$}d-C5^D{hxw`E3@tKECs}isL(}AN+dJ-zq2hdcFYDK@~xo z#?4KFFjm`?OIAr|_vT|+hJ~?UV%A@2>#>G53@ltv2p60pm7YDjE|tKlSL*9Y1%&Sn z5Wy5~x)>_a&#oP`iEdN+a1eD+GdC-fV0UhwvzwuxX0=z;#)vx6+GjrUUFijVFOVIB z;CiE}rGS$xYZSq<2G=u-P(-6uLET$`q#*;&Yhckp2ZHepwO#{2TELHEs0h`*4HEFdk***fg}X11`aip z>_jZph~RQy3)-SMEm-Ir$tRj60kiDu^D)K(NPT9WG{ssp))3W(fOWdEw)B}w7#xUx zUW4LzS%^j`JJITTj4{)rp{-l0at!U=tYlL5e{j{Mbp6~T&Yo#zq;x;PP6+%^L9QDj zMhjRrIAZLyOO?OQe`;6Ftx3*P)A({jLz48%1j0U_wyZHWDEvS8^X}=FZ1~N=WJq>z zwi2gqqVuXeVZXY2oXsO?UUn4hB@U2P$UnGbjJKkze1&Z}B`n3txf4y72~5W~;(>kN zRm<~a0VA6ixx`w|L&XRvAe3DfE@BLg`njC2vgXB9cNy)%7`lgRD&ro)QAEok2 zaTdJ1h-A5NZYH-0Lwo-CKSl<9Hlh=vG&{IDz%;w0`hy!2Ks> z*QEsohAj^@3Mb2T>OTuRpXd1X7;xax$B|1Gkq^UL;#3LFb4~Z!ep5La>Mohu@gn$M z<=nndamg1`P)R*qBcwFS^2%AzIA7EfH4RIySs$h#T<;BIEd4j%??ZPL$|D0=dvE8} z@#t~6`(2Lq;-*zNFW2bjr;A*6`@1xM};#ye0LNvHGKncY_L=cLI^v zW_Xcmj;~~Dp@?q;{)3L_x#Povz{0cHbmp>U75${NX6bb?iR%m^3eQsn(iFEc#2xt* zhf-PLHSN_{b}bp8>NoRLwaMsx8eLe%3Vrf=&FWb0|Cfu320iV_yN)L z$aV203j=6J8bC$uZA@~kTTYim_&53S;3Rbt5bFT|%K{0^)AS3~LEeNPyC}PiAEb&lW;BRMqMMEW-G{)hm+g;v1wG z<4M-HLN^kAdv0RyY=MLm)c!T(#=mB)z+Iws4uE?&#A=gf^#U1Kmcl1s%mea5FwhV@ zO$}3ZD2o>33Wd%=K6qjfS`$$i3H4>cEj1923SjTu4oNQ1j&YjN;xfxzpXe6`SN%iO$sI0C_ zy=bqqJ;z*$6wA;w@-HV3UoPe}UvUW2-nTdO^2w)TM_et6fE@uOL|_xeH_-gmOKGy3 z)A3P!yFS0!K4W?IQJ!`|@Lr|tuLux*^m^8qw`+wSH%}^6Ry#_*QM?HyrkByLepn^d zi%CZor$DX)^|WmQOU^sQOK42OxoVf&;c(t#q*oXA`D7XW3e31XWA9s=OfK7RNhXe) znFT<$%sfhUIcyO8eV)@VE4|z1Q)pVW8^JU~Bt_B$*Jce6WVGC_YfinnZNsYwLSH$^ zRw)?-GDSW{zyq}8cf@8TNbDfH2UkQOgT_3w20VrAP7}>O4&mK7x&JmRmT1?@8TW;{ zl)PAdMW%#eN&f0F{$RbUnnKb(nfYFH>Zm8x=`Cx&jp|^(31t{Pa;(AfP*%W=EBH&~EqoD@m^^Bk$}?0CpQJb`$jI%%S_BcZY)0|E+MzZ8!6+`WTzRYo3v*h1z`}p2o#{-Da&FaSVaKq3ebcQqLrXc zS7^)y*y$}z`lJJ$6drU~RxE-q;?5wjXVe;+IeoX2uu7zur|a*|rqs4AuwU35s9k)k zIgavliI{U_r|(2|@C7dFwiJ0e;jtIw1}($6D3C;BLq<46)dgo(Y%>Xtib8`;{a|e| z^bo;KC9)JJb2r_rlSgB^)e`BuI=4II5oJ zY6RHXUsvgrCc(977GTN!Ae#YW!@errbIw$*X@H4E zDT{a%ukuLO5F+|hMl0@Go~dVf<|L{3cMKDG6s}NHHkrofz;TOCgYw-O?>a6(r{3bM ze?u*7a^bhr((SlJ9r-2d4?mH>`0sOrGL>xrNfKV3+E$XFKOSWRj6<|Qycp`K?P0mW z=B{hI1Ov$L$^;`+hV7c^4;HN9;QTO3>Im~_X3B(_XEB+D-y4H5YoPebt#RbhE6spr z>VchZFsRF=8~e2h<4#N&;Z?~=`_%Q4rQ%4id;JajwC3iDS(SzFL&dc6pq~b?4^4dF zBvn<7K!m*Yv98!unpfzJ?iUJDMsiCHj$;b01r7f~1=x>+s5ezoeSvM77wHnuv%E9| zNm&O!I@^m+H;6;}z^^%*@@o3k2zJp8gUP|;*UUw`p=Y zLt2T&$77=^4|u+i%Ls4AUOev*A3cE>$44mPUtY3xv6ddRubknI0x1ctCBWc!RWH;7 ztnxR1Ztm2jH|?$*VVp4Q5kS5NVhbtxZ9Qba^i{LM6pOT4OhJ<;jDh^KLFbFcx2&Ad43NjdAu{n_rIDts8ymZQOKuV6G_L zL!ffwBHNVa_(zl#e}^aF<4EZBapd_5u|YnoVy!JWX8_U3&dA?2LU0U^Bs0x|Rcmki zvzZVUkYG_%unTq_1~@B$^YSnoYjAWNL9s-z6lzt$Y!~1; zt$szybAO=Li*|nPaA%mVo7pIVdR-|-h5IJ^NjFTpPMF2J2#8yQbTeek+jEnlJJr@1~>Kt z$}m)GalSl4SN@)e#xb3$F}cB;inL%3*i>Ro-JDGA$6VV`rQ zuewYeHlyr7L}|dID($WDOc)3_v!p1Baos^X?QM2PGmkvlo|%=A?>Cjuhh6>wE}?pE z4PP4OyE3v!`jmokqD)TcXwHE13lVLJBzYe~Nc`M$rU+iscEKbn_lE51X=Eo$5tGBB z7Pf3$DU|-|60egPl%guRV2T*a57Wz z*5k=?U=k}(Q+AJSZq@U%SHF_EqH;Sh(Fkd!k07-|=YT$F>dNQC&~$oZ?j@1aO1DUS zAqODpXiukjc_PDy%MArD*siWbSlbCQxy4dz(8!oj24*e>%TJi z00?vXUucm3~xvY7_V2t`i5WGE{2PA4ZR&GAnQrcB4d}Zevp-Lo|?Y>fzxK4Sv+TtW4- z+YiG9DV$klmb8sFA3);SzMQuUTi1+B1*xl2_5ATnwnj3`)fuWXUD#tSYaykQSawT6 zWAa|k?}32{ORGV<{|266FAb(MB@GEv{r5cOuZyCIV>{sh+8=1UdTqsV<&1_bVA%#x zx=}z~q!aM79@vFv8lWiG5tJ-ISxcz4;r4p~OGTijq#EWsV|0ZRN5gC>IG|cGwkwTW zj~U$ehdr@HO{*b#V7vo>u1p)M?f{GLOCV-EPJA$RqpiUI(G|Dm_ltPF~>g&S; z4Nx38m`^zKb~tMbixY=295FzDKfp(E4AokKY)L&hmd`&+3${}8Y+QQSS^Ae~Bq_)7 zVkC4u_Pn9+=ms7lE?)(4i@Kgw_CmScC;jwLXeE)P7Eaj#EARMnmjw9#KvZ9Fh&k8% zZ%ko_E!pWgU?X06M2wP>UDOTXv)1_dKbr7ly#PJ2!4k&}Rm{Kd>{nir0C%!zuF?A@~gZtBvN zG%CfuZQeMku|VAN>0(zrASxQ@W-CfCqM0{kq@uM6*qz)A0Rx#MGLu6|qC}{^zA-@0 z8we!ii{F85mMQZvBvdJ>&o-WDU2(##Ndw6{_{IE<_rl$RcSseJ(D;suv}w$TKKdxx z16aZ^23NoLP8J8Xm0e&+p69lBPq|Bg8I z6imfc=Q^1KuG@e<$i83gi%w-+Pd1c>jiLa?ZCks2ocwpEWFW;19~DJ)gmB~KCr8AR zJ2X}`K6;L3ncd^zR*07An;v4c9Yb54XWQo_W<}R>>z~3|ZYzqJtoa1~cnL>veOv^bKWV4D&@NPy6m&Unzy9*5U>HrwtWRqpwrOmO`1Sbr z2_9|=bhi$1a@NyX_W$dRUrgy2ucC1K|4M3)?z3PWl6qW1Q~AX9ud)+6pqWzo+P>@j z9w@FBNF80);BC6VVn9j*99VIOQ~|2&9+n75F9(#x!A%7dUBDFrnq}~(V6kB^oJ-9C zmZkM`>+^V?&DsZ*R>@9VCc;s?2t$ZFP9lK9Oq_Tj+++lzVz~(TQ`Ip5FhSTCINEIP z!s75Z%%K~v&xV7=Uv0c^;DLZ>u!aL3)uY8X=ySJ>xEJ%_BV&n|vwj@1H^e|FV~{3$a=lIalZz%0wSd1QtD`5Q|A)yraF?E64g( z{+MUdE_RW48Yn(nbnftSv8B2K>eBOT6s_{B8b&fQWSIy(rw*2_X2g*MA}~$?~m^6~>9fL*UO=7u=#fgZTtw^Z<`}A2#qcMf#w> zalX`zAlHJSMIri+bR3BB&Lb}42$C4B_BtLZftTYbDpzzi`@*~*T|w8GCUQI099dB4 ztQeQ;7K+mW2X(xzYB~39w|`jaFZGqwL|T`5mc&Ve!q11jK#T zxLg(&Jit^ZHyM13=YT<|j2_0r#~9bc2tXT{Cn};@Ud$5SMAc^e^btYb-&zfxR2cKU z;=EKI>eSD*lBHx3ncrxV;`(=0`9CLImt|>P97MeZTQ^3Eh1--8W8Ekdkc4UV|3JWI zQ&i{c&*M13h8qh2U`XgT@8^Xjn5l;i{sBu{%>FmqUAcv%PJ3I$S`2o+!YIull78b( zy^_QzpKr=iH221P15yN*5b)YU1Ew2fc}+r86Z90|LMZ%hJ>Z-hAVh#ZKu}I$x$#$k zbvIy%1aO~iq@3d|zwvt`dSY;YGj*{-@(Hg7eSQycPTKO+f5kvWrodOyABltWgcvqR zjke$f@bxM2a==yC(*b}fy^a7`(qtg{qtwm{*lA-_Y`~d)#ZV%acL_}~fpx&yW7psQ zR@cU+vEYAmk*zkOic}26#uox=Iau!PR@T$|(c>$%<-I@Ev|El) zxKE^+c0YoosqFa&h&jD=)Dau!{o?1_fE)JyDVNbJdpDP!73B}u@7ZfZ8R=D0y+!WZ zO>(#)y!vbD@njI#XwT@;%ZmPH>U|=k{doDxF~)9lb%QY7Vn3~I3kke+tl}l>i*Xu5 z@IH=?F?p5&pIi5lIU%o2UPDY2i!a2ZilyZ#Z^&fw>C-|Lb7uJv4)Mp?4#l>jd1(Cg zVQf_oNsl_(XdY}7?(MiL^sE!H%CwdSRab}pS3;D#YXK?D61P9I&-cBb3Qh*^c{Xot z4*kufYl0(k2Cp=b8K8JTG)m;;;m{LuiFHo+8rH+ffZRa=i70QmKj3KRB}EsrW_>SN z?wGJ9eii;f!aC6l*ie7ae&5*(tJzUtWAZ&v*X*WNnGByiQYzg#Sk%#_(+7%jmo1-a zA&zs7OD|-L2s?=#MIJS5Y#o35#*$WY|VCDI`{E@cv%LmBE~<2Om58WuD0_ z$BBCKeVX`sr4%r7s7-TYIfy{zB3Ehi`te*4`Pz-jZ3Y9p&V@{4y@%cR`1S&+%v zX*qvHKX)}(PAu05u_*-;%p#$7*X>&6-_?%%deiO4@Qb$!1b?)cPjNk@-0cnL?dga} zn%(Y0v&fju%PWUn;f^ zWjX8}#D?icSSVznV;A5pJJW#Yg9klKUb+HG7%8Wm&b(bl_qlwn^L4HVi552Qz$HBr z9boxwp6i4Ge?fqg0VIh)Pw^zl^&TGp*wEtL*CsI#j5E@#E<9^?R1{X|3wSURMJshY zCPggo5Y9{d_H>9=MLeR8QU9^bIVKxF!#|=#Q^T!SLK1QcI4OVF8h_97$j% zOQ_xk+TbhzfiTqsgtFW@z~{O)?CN4*s#OY1noXn2|QPqiKt>c$Kc&9pUa~-bmY>z^yxJ3-g^4;Of&`NbMY+# zk`uTg1vlH%RIC(VEQxv?Hdp${($z0PZhF_9S0agtTov&jRi2#d&`E16pKp7_Hh*;E zinU38V-`T|Pt!-zb5mm%^zYf)P+iTi(lHtefP0t){2hi9796Hah<*3`Z07)=_(E;2 z^IOcpOl32&;$UB>H_^JqOL_lat>Db~e2`uYcIfwzcke#sp;|0STZoXvWuwE|imqq^ zsXD+eNl~$1Y@Ul9jZz{(AC~ZJKACylz7TNcL?wzJy2lvBi&?*e^~mI{p#(8xUKZrtJ$eJcpsnwrz!JFTPqd30Mh9@_ZK$nD zfol&^BqQ}oPDpOl)1FRS{efr9Ka*S(m~tF#cG zJ~+WFPp{VpwIFzCz$!$O^p7-Y5&?)Ja5@CY#~nC#8DOb^#bX3=c|!&?Jh47;(__4) z*6M$4rFT*$SebrfxbuNEd8Lve07V2ek%2=600oAn(z03LGr$YrWFr&8#HvDAN`Qfs zRuBnLL1?}_1tc< zsQZX955MUKn#RZV#y=}(hl;db`cPlt6BGgzVcgaRKK$aB7Ze?-8wVQ=*4Een3-l#gr$H_)lO-w}dH!bvjhm|@B{=;u<`Hy$TUV7i9 zJVY!eLlnz?v3_sSUG|rBYozY?-}=} z9*)zu9J_i__=^0dCmNd>`hQOrY>(vu?!Ca4xfR0KMOyw^VrgWxRZJsWTcDKE&oi{OLOcsS5v3#@-Y zyi;k>fj}4F-Cn=~2c~2IkO)}p2qq{&^TwSCcZ)-YzBMU26;FvKu!1k`c+&Z=IC!CV zQ>y926p?5+u#^B&P8e;A0&PW55DLJ6Pt9105>OA#f`<`X#39;1P-6fd?cxG%5yXhK zBOvQn5cC(z*bxr78vu_J$Vd#b>y8+8raz=Sk|oNl4&OXQ9aW+z%^fKGV9ya*NJNla zt;U?;qpFCQC>q-pq%uf0c-9FyuJqk!yXC6TXD(TS&s5?Of)pHy7&rbx&b&(>t3JaX=F zUcsCSXau9~9c#TN$)06zYez&H6+jZuRCNOts9n80F|S{ zvHh3Bi*C279`)!$zpX;uBb?=`m{;32DUwm5ZZx2RA|*Bl!DeBNnY$D@ANLQs%2y|V zw#$?zRh@4W?JUWEjifOO{KT)S=SHN(8xQ$i2}SN!qsed7m*O z6V?(BE!(oW$~SoukrQ%Jhwq&X6r-fJ*#F6k8fkc&838N)rA+x(QYy(ZN8%e>3t<-3 zXes@|8KuiXSp%0iTfBPGV~>elZNnG>HNhO;iOL?P5avzxAv@qJhhRXQb*C-Qv4_#K zvGK(PR>j;V!8V5tUVTxY+npA)!#B|Ml+*U6i0}GN)-)KaTOPg}0sIR5d`SJLJ>qtC z?LG|P%1ti^s{;Q>sdJmKJPqK_*V#fe$p;1icNTw=#nX?MKDt(zoTw*zZR928T^qT; z2S2Kv^{fV3jJT83^Wr%DV+e1#Hx#61^Pis1wfGW zyQrG{mHMpFmEyyeZ1#fAcvloq;jJoKCSA9H!-l%)Q?^M!C>Ea3EL@!dFuYAI#ND7t z_2hyFDbPlu1yXDpw*%3JU{RLKDCdb^n9uGD|5U5ex@XGmoHxuez;F$+u8f$}X7yatBfETbiQ7ci zp!iTwzV?e|pO#YN$Ik2gj!e`3qa-l0n2v?!U?7$q2-DP&G}6e+08I#d)NW_I^A}oy zzi9cYsxw|#d?dJtU~h?8pU>L+ z-Psb-fXu&&wFJ$O18Ioz89ZE^LeECiP86Jeu!?>X4=KHCuC)P zyndU(DwS5H8Ds1ezUt>eo?UGw`<2N!jzI(FysOz|1JOYRW;ZC0hylJor-2}Gm8Ws$~2`=;PrH<=NIh={MZiG$j-?qvKJ z`;wfTI+kQ&enS_ma(fapBxv6dIFLl9Z}1%D=nc&Q@>7OD=DfhN>pm)GF=CsMvsQbz zO6nprb=erSw@7ER{*Lb4{%w}DW8iO0-oJl`wivF0l_|m7Qh#0vaq8<4kq(zs?1rtl zqVqYiZM9Q}tTsNmZszRNJRzzMUBPhs!c@1wLz_SMZ>IZ_Bw#>5%*r`jO;Lh(v^EY` z$j*}(Itv(NM_VxMwbdN|j0W*f3>CT?sUxO7zKL)V-WM0{RVHSB zn05GOhCC7LA>J3GbeP+lT=-@p6A;%k0(j%VQKeWLZdW;s4bntmu#R3})g3rsfwurU z_R2`wQvu0B{AZGu?$YJ`(CkL~zXqfnRS`%9Bz}e@OyScpBwaJoq(AT*XX!HprkGEu1EI6IrWd${#WUrANY-uH-gX5r^|*atIVb2+4y$3-4HSHg;bG#K zSDoOWOOP+pWr*o8)o?0?;a&BB1_LQUJ8>)`p|!Ce;apENcF)`A!<7GChhhG~G9#A( zK!Jq5^r=E}KfLUP7q#YYU|_=qxhDJIvCUKZ!=-(Yd~D(T zjT3aYLwr{8W05l(yzpb6`yCRHe^3Y^?>)a=?Y(Z7je?2>t^WoOzeg=Ye-2f6TzXmN znRd(PMa5WFkI-EokW!k>S8Hk`rTVEn?w6rQlOjGDCs3tY-DYV2<8)D|50)T1(yF0z^4w>^qT8?Ea7011}*whvA^c5g_T{5*1EDczBVPDcpN zlOC0DrBDmf5KLPeuZ1IV9p#}u5Gb4qbJ@1Z&r4sA_e`?5u|16t*0vlkZtPn|2|GiI}C_DKaTdFH_sE7^yg9Z$XrTl|K5~N=o%{ z2(_o<1;Xz>Owo;5pS!82V1sM{%0mabi@3)TAkG818n7k%+^Y!(4KsUPOny$a`@Bu%krt1BgA>m5j`bbZ;VGE<$E}hd1^Go|(Se z3r;vmeqil0rne?ZU!0SC&tPyy#J46A^{d1F71h2w?@Np3{>w$WMPCdOmf_|bnkcSc zok0{Ro;QXI9}54^bsAfif$(?96h{VVH?y=ADYb0mDEo*jDAWK zzKH1-T^0jU(FfL5N&n~sJ4xE~t6bt4i}^~r4{o?NlxWXsX_D5M)&x_t{^HT{XSk%zpWaqw2#+}`Rk$OlbZ{9-gd1<2V5p~<-U$_mD8mw)a zBrV(C@{ClaIONiI_<^zZPJ1B|dw9 zzt5kZf53CQ+)uabb!mM#VJ-#O0G@$|FhnKA)4*|y?-^r0 z8?i_M!mi7;hW<+h)v-Ao{*OVqmI-Ii(UD5|pBM-sF+9$lBIFMPMGRFD6{?SktrAKX zyzl6+WI$4e!A7p1;7aF{@(O(QQ^M}sirl^VKoYu>h$k}i4nRHc;9s|+hmWGfJXNlt7hy>8;VQJO1>k&@bxuJwrnZ) zlxEaT+Lk6lUCuMf=vy3OoPP8M_dt zN?Au`s)lb@nxC&=hgix6FDYwaOlNM}HDBImIe?W=nzA>aOR}-H6??_>yp1_E5lKLI zR$t`v9LbtJt&Q+&#%FSoYPXwDtf3!TesA^%sMupXjeU)Ub0C;rH-H^q5ctduWz zJ>~i)Y3Dzb^3-PvAD;*D*HYBhfI@gQooZmaJrbeRT6B_NNjP5z4l9_YF|`w>`%pO# z=x5{6d8^zUIkgz9KRd3A85KN}&b)?CG%A80)j+W1;am@^z8f&6j{lbNJ-I)$k%4nVPChX1h`^T0z(Y#LiPgo)t_8{*Av#aRrulq;+w;A~>B)Ppio8Q_ zvbvb2i9C{wwYc}<28gx=d&8xX>`GBr>bZJ3I_yP!a*ovC=Qy}}U$S86kf+r7aq6}D z7k*5cA)DW7UlVSAO^9D;i)yZt7oN-im_)C?7q)BJ$e@du^|$QxQl*V=vT@^x9-RuM z@U!1q*Rl^wi9^@(0BRaqbJwMjw__k!%0tTFYl-XcH2t-ttPx8H#Pa}b`3o6rZ1Yu% zZEey`FOFw)lf-^1|qCK8Z25)Tv5P!e4rECi7#d5~|!rfqJ%hvygzvH>I<$WzncKTe6H znenunB=}>Ogr+CQ-AUs2Z2_=op|F*M+CLX?S6!jsX)P2^Drmb6f6+nCavw{?1neTU z*k6w}N9(Bp^m%^2Tw`N2so-sdlXTN5&o0x3mwZ$HZ13~C9nZ8ed`ynQJ-dFLm1C5A z(Q$QRbypV7p^@VLPL~?{z6`$(F{VbzeZhUbY1+YVA|Z`m?T?ND$#7Mf+AD9pWxi1{o`hwDj8xB&NURy zch}C4&Lix?G1O$oHT5 zuyK-*fBP;bv`F(rWag)K+|>QT|2TLB#2$`Gf1=Kzq%`qOhqa$(6GJU!$*06zHy%TL z+~d$!mfig_U-4^A{(cCMa%Xdp@jK{%;U&5Z(XBmM8Uq3z%QY9OBH9sK*hsXDdO*X7 ziEU;Qlyo{uU9x^SIKw14P0zMm$ED1tzp2vq-OQ%{nvk;s9hD>s>aY|+8}W|Frw`u} zwqL_nd8yepvFr2HE7cdK4q7wYw)3eEVr;1Dpd)O94JX`L{^IsCqOy68`@fsLmdeXV zYhaOJ0d+~nvQWJ8oCdcSClM?sye{ec^9o2_!|N!tlLsqEy1LE~-=kmh}YuzlH)9j+2PW zl|cwzzylLxst!Ki^c*UFGlK7*2slAdNZ}EAbu=hO?#%%jgE+KEZ_?+nO|l)#_RV+H zFt>t?AL5{1!oU#45NE={#EB^^y(KT5#`mIeCK|f@w~hJnp3Jo}k@f9j!sJ;a9~Kk{ z_icQCG={Qcx?BLsuuOn6a!_rFs&p~-l2&@rPM-WCWF2^ryrUf8&rR<#XmuM3J}zyH zpxI^z^Lo@ylFcoB^RG4@EC5gPjcyDpMYVCn&3!|eCn{#jrJea364uOh@uGj+#zJ6Y zCkOH8V88N(nkd+yQv!w`MY5CSb-glDO+F}UhBi&7er|yFlCwz@>E9W?WJ3|-sq|)B zk;GwnGM90*E@N0dEX6O`w>1$95+!+^6beiBS<}cCS-TJ5fZmnw3pIXJ50XmBN15{+1G# zI zMFQ7$>#W9TYE~m%{=eJO5+#LFqV8JV_$i+r6`$)rTC93U5|2P1Zi#5Tdm3QKflnxCk%uukhPBP#pI)? z>{BK_4NBU>>9G|NjM8L(Hi2S~_>4skZ+$LSI_Jl9Q zjhAT~-{7(PW`B}Q*A@1yC;8t=xXUFgEcDUxH^AZ+j>fY;0a@M8o78VyZCwR z+$@2T6+|IZDE2iFQxL<@Z8S&5MO4{BTL6L&^TiL@?kpwMD*>meD1u|xEAPuKj~NwD zkLL$1&^)z&yicO-rME;9C8jg?nT}*=GCgte-83pPOL9-scs@ii70n1Ku~sm8edt@G zpMc+GvoR}-d~r%gu{Ov0ETfO2`qY(@r?Qya9VwIlUIRlVtL>|ffTK&`3&!@E>KMIK z#(ch7J$gdS3~AHlbbyBqFVb2mzz?97!dP0--qN3R{uU>ZzqL*n@0ry73bG#<=Ly`f z*%G&@=@gdxkvo>7(^OxK8Ts0XlBr3mITdSoN>O1`X#qoLOsry@f^;~WsQ**g%IafI zNzS?TvEe**p>f(QDC-w0CVNT5q(SsZZKq zVlH%ej<4NyP>GAK-z=j0l|Jb5n7KdPve^nxlRFcnOJPc8j5fKJbwAhDeM`MPLS9)= zmjn(bh=~dZdl1K7v-z_cxV8g)0c-+>b0-6oJH!11m_lH?nJ2?jD8f6G2?ZW3%Q!4< zQZZFQF*>EBoIc>NWt3(c=rR>*<@}KT27Q|9g>Xt6NIFu?{j{kI!ILYYAaJ+5Uv@#}dE&%GU#e@n17utdX|TED>XajPbmItkyRkq69l1qp zrI0oyj_e^IOCinU%kM8sg_l&Ztz;J%H}6hmY~EQif>Txjmq+L!Wd(0ogBTkrHE*e7 zz1qF1>8AOzjsv93P+KLMs7^8~d^ZbIi}zgUBCFJY_4Yz@bKFo{LM;eH?Zp z5&nd8?fu-84tKhm_W6%y*Js2id=ia$?3F7oM@}|U%ie2g_|cj|kPLiyTK$|JNhFsw zF+1iW@5C{%x!^*R)z=fd6@MRlGmypwvUyDwxe^XmKQnE3V^7k4Ud|MQ!&1@C>`J`li z;O5xm7bL(4i?qv+_{1V8|H%loCwJ5^GX%kwz88FFZ1Ps=rk^Dnzaap;S3kV|9=@SH z)wch8TVD8~wT*PVo%*b5&qg*VLunWx&k5)!1A;5E<&`FEnd-HJPZPb4O!9X}E>@lz z^1>Ql?jgXX8y{W(@U05oM*?JT3`Yt~_yN8J0-hHK{b}I76#bh!5afWK9AK=*r`W=w zC=9xRm@`;6f|?cL&U-%^D*q!}pQ9)-6Di%JIgR79`Siw2SP4VnyO}dSm zFl(3GBa9{^TScIOAb|~n9SmUUd@VFA24=Xiwi$@49!@;$Md)A*D)jXxI#U^1L?SMT z-+l{xMASwGF-jcNj@{uZHs4@ENdYerTUb#5_ntn;ZXsMa7&&T{iEPBA+}?~Kmm|hR z#Zd`Hj)4@`uXM4XUle{|9oE_pahCTWrswX{&Fk|Oz@H8{whWzqmfu>;ui0IiOQ@iVIpxdva3h)=!P;TR|y2tQoZGT_o3c7@lfQy%rO&N+z-!; zd|St;C4H4)x6E6QP?)BvFkS5{7MOo2Ptr@^(`q=&3rW`&=FOFe*?2pG?On>!(x$6a zxrrucC2lmkw|l0uw({i%(W`3Ge%LRYWNZ*y;*L4&li-T883ym4inZ?!5UaDjoGIi< z%cDAj2m{RH%Ji+7Q{X^kfi7uOxi&QTPCDIqp_GMYuuwbGrdq@|I^S}`o0zDnQbwaB zmxL-!|8A&BJHh8R!XR0{1W{^)D@%c_P(Befj&hVr;g6Q&^Zm@d6o34*D2K|uZsN^0 z5Y@nfKrYzai&Z(-rJfeRJ<34ZwTP%G+N$Z)Y$ES4juNUzsHUZAl=E(vmD+i7=CxeR z`B<3HQdVyY!A~1HkcuqTu|X+HU;J=5*sA$$#|bS6IhsF*wfqW9j6UEF7uO!lc1gBz z(m)`>X9>992aTZ)U}l#%p=Ya~^Ql2upg>XJu^bOvc*>W#oSc_9Ez=)MHrtGnq=~Kn zx6*xkUNbK8L2h;Xk6Ks_Imn$lxbxi+zx1}#sq1SDk9R(Sq50OUmm0Svj*kg!0_y|s zu9et)xU-piPdF1o@hyGA>1VQ$4-F_#c%t{p#{SQHv=#ze0b2+58bE?Fh|Uv0OY$3B zNuakRY59EIdVQe1P0#*5PjroT_q&!on*XpOTe|O=Imf6y-G#i=sI$IM>TcF;nEym~ z<$=%1CD<(cOw3mc=H(qO8vMJ$yV`-7gfC(n<2I*6fkHguder(3YFq_|jZqhN9e@c> z>cHDI;6(-)X2N*_ORkN^7t0I8gX3MiPnK z#>Vh9`p`w2=BaBzHA}d$p24I_zR0Ws0)_Ms9|>@!7SGIhmUV?I>e%tBn}ugu;vLv0WHrEe*-b)`O`PWXht6w6kerUvJIT ziqvRMOt46pZ-$^o?g(rNv||ia$ko)nbY7RV_6WT|8W|}2m?Uoe_44h)NsTayZfr~WQdZ6Dhc75FDaFtvKDUq!9>iFJfxN>I*h)sHJsq3Fnz~_ zy?@qV`~t>TXY02WN3Z9H5PVNig|}(4!f0N6fw}set>lJM2s1uy(5UTlhEXaMt=O23 zkRoljIdWW@tt=a3ctP)d*ha|UF3EsE7Gf?2OR~g*pHJ9!Bt_mSpJOSS|5%W!o%^zz zWy$X8guQ4AvWGMyA0XYYM%uPiaJSik$((+G9x$={BG-CY<4uICY-{z+g zChZBFVH7^8%5TWdYBmeE4+OzKf zmJ?ln{cabiSIyrzCc3Vwx~|j4M8si%Xdb*Da2j!d=1ydzQM`5(-vM!!2v|hkq72ku z7DR@Q9#nESTl=%L!`;|s-Kv|-Z4H^sZ0vfsa)U7T9tr7piSo~3IoB}& ztq#n|6ccH702}y7p;|paqZ9_EKRgX|DfymLpzJ8VF^7&u!Z{)rBy}7iBmzw_J)g8Q z{FKXAq@6rsasfW;GFTmxb#FLLlyXJ;`X z3xvyOou5*7b=YxBCh^U9wnl3|NytTdAj`@`nU5jF=ZkhuyU{THG*Lt~^>nQuO>@&F zxRfYI(vd$?F!ba_MfIx+gI;6_1?2Ph{!9+1tf$%1^mhVFt=ziK(q|H<)S8oIZWHM) zU7u@j_AQFEXeFg;I7De|cM6)@u6?q-!7`{fXwhaQM0 zAV%na9D<$GmwQxVyQcB6@lKLGdEms&h;?>~$sMYaJh{-I-|$+{kIQ6Cwl}@=7f5>%f znJ4%kD&2r85S0|7(yt2NX+Nz?V{T}BHE^C`~~o`sbCOMy*q=M(u&{ccn_9 zp*i<*JZgns@&9`qc3t$?B`ve7cJIL0zFl{lVgeSkkDb_%^4q+tsNg4CwIQlT;ia9c z>HZmNtg@0)|CuFVDPq%UOwG=`>fy?wUcH*x;M#n3_pXo&;T3+1R&!ZPa+bI}{=kKp zp_>+4x48YRaCH;bcfx0kmZax&{=%l?jk+`cP=+fe?ngUlg`QD5W!cUY|10+cc}4Dp z(s}FWpsuPzOU$Kz=E~Ps&hb}P;wB%?YI=Wd4;FdZ{kTuk>h@x>-=?3QEX!SnF50b! zZR@WMb+CPfSH>cm+to$85PG@csliQtc^mq3KPu&AlN~~6PQ-7X@7F1Jdy)_#DHg##_2RGpuW9W}gN40XrxB!o6yMi- zFU2790tw{#a0|`tJOhjpgY+ zY3C{?((=1#-3!g7D(_c04jECuF%2J#;%=XnnyMvOj|mbXXGm9X4%<`pf<15W+4-Mi zA9wfh6cp6A>I;RSznhRh!V4t|#b2Q39zWQZ{V!f2-w4qlcC)^>IzQCR*L`BUKRG|h zKj!a@q5lNWqR#f|5n~<0pfAY@apzvlyAo^EgKrOgBV>6FEB)gU>FbNVlFvxLL$t_0 zSGQSqOX26(El(aaw{6p33-}Xiwi$amZ@qG<<;}|+(TVUgJEI10TQB~#6!Amy4i^;Z zzqQc~I6F&LWF5*p^5n8x@pNWzQR{ft&If=0aoIj|DbS*IWg|Rf+N#iv+F^V$C>;{{ zsE0u*KCE=_>tCB3DzVvRqv=DIw38+zG|h zb8X*3bGT%qx+8Xd6_WG+G!L(OQJVWSN1HHQMe(`a_g{r|yPU0yl2>uG%8N4MKwLattnoW|UZ3$-om-DLlCW!bP#Az0G!^~2u$&7Pr9^`PFF zrcHyxLt*a+pETZ_lFXMCdE(Mupx*uClk&IueO0pRZ{n3MudZ(P$a3-bDOe87e>5OJ z*fsd0&Ut3^Qh0@Dtw+z{OHQ8-xIH|b#N5+M$Is4uSp5cHQQEfU19hrV?(EU&fFYOL zl(0qZp6dfEHL5tzqp`9j5qGQfbaP+I-O$dW?Pz!&W3p-2-XrXTdS#j<>(OELePVHO zX$uoNy5xZ8i#k8-O#&_to*h(Eks4apizsb)yDcDFC9xQ~xPquQ4E&(!RVO%ZSu$B~ z=(^~&@9(kqp>|ZE5K2>O?)3Qnb#|ZHBqzd9C#_Us=D%{Ytat{`#R^RW__HH{pTk)!+!Q}->n>SioBN>{UX5T*cfs>VV*Q} z&+YH~S7Fpa$|9e{dP8PSz!z%Bv~7ceLk@wvI?nu5Y2A4C=YXo|BBR84*)D$Lzy1FE zz2D3dOTM02sVviXef}!^Ri9T|Skuv5qnC`=k&i~vs%r0jeV}99&Th{1E7OL+GH1H( zWUco+|6)#|pn0KcbNM>8{>cm-eYlDf)UpI`zVpJ0tE!_kSA2HDvD5 zuH1NeY}GuGkhy^0 zXQzz1Rp#^!_q@oPv1zHG?eXYSy@uD%tm}?1pDOjsRCS4TIqOuk+wSD6H}#*^tnz#9 zb-dored?kL_T&U0kCeN+3RSMS?UX6v!%tp>%&V7sG7fi~9K@-!Rgv*;l!{kXBh_+J z8~)fN^xQCIZqruWO$eb7D8nZcDN3VX5RBt z_TM#h<;j<}n|W-*#?G@zSu_C@Z1l9!5LaHC3vc8c*LbYlTln|*H0Yp5Di~t#^;zEX4mc-}+DPZId0tr+Me@y#E~a zIrWgc4XJX4az-uC8h>!u;JM@ehYV>>ph}z{i%91m6eEx1-LBu~g`6e5YAb0q)_%Lq zGWDFn>;G&FMDJwSO%3D)x{RhuqS{NJf8cG9Rh?$sU4J)yoU+uK^faAlPc|>T8W#{V zlDwMO>iXkR{p#A^H$Au1H^TNj{}8D;^4T^xXfm?cJ8$*mJ)3pILTh(_%W1>o7yj+| zZ@x2A_fap}|2HK#@K12vMup!0SjX6%7v9~wRhQf#z3u$!ksD%M-ScBO25Q|u=$32q zvct~{CUd9U$G;WU{j)jWZYhrkiCMLp)~OJmYu-6kIFeeRBCbU#yrTTExR+Pw|4Ke$ z;O|M=ruXo`;e;*ki{59l!Z!bvn!DyPr%vAl^)bsLGpHK&TYuU<7iTr%gUFjRDV(D31TE!CGwf$PMK zy$_?F9!~j{`5>t#u%4|OqsrXfWixtr@3r9a2n zyShY{yF`{e2n}j?u<)p?P$tOu?pCdAakWZ#_xngjo88x@Cy8>e1*7uVjo1aP{b5!P zkSD8%_wF+@j25D=ey-`qq}JWbBLhb$?w4yn{0-F1`_n+FlVW*%(71SVG`i*?@|In-zO)AH}a=Rl6ALvwBU-E)7 zUN(OHcQF&m0%e1Ln061UHAsP~cBKOAwy*wscTQCWM{POLztBG}J@q2#h$u>KSZ&wI z>GVFSI@|y5+l7A|s*0H3gz?CKY*Gyi)YMcDw_u>3enB7i(dn}lrNgL1*AfJ7(+V+*$HfIjOLl7JNXY%~|K1SO~gqhee`7V*} z97kT`!fWZ&U;UcVb}rm=w_$&ykdv9x;T%ODVbizJv2 z2rqz7;FF;MkI`;QS{hoK@9T?zk2hjySgdg_F%c4@Vf$7_xBD)5^ z&mk#n`C-A2qx9A!Fji#Suk87U3*W7l6!wYCV1*c{BN1g1L{~a6j=5v9IMwz-Dj)Ca zRGMqY>ss0x`ZC+uaw%4<(BBqv_E?kF9wwn= z&^Y--S8m&nLc$$pW^J^cBp;E^XOzhuN#4QUl#I9WKnspj#ItNKKG(sre@;bLn3Ln2 zz}Cb8)I+9_y~rUeJXPv|Dr{4~5*BbHy6QccW^#5sSH6OvlplRB+cwtT9q)3>H~yf= z+kuFABk*uqp`K5yb)x@kz|C(ANOn^I+N?cFjDG175A85v2;Y&ZEFKh#-4+K@nv9NH zrsUK}QInH;1zaDp)kn_Q|=$Y>YYGL>lMTbZ+@)5c#L z3m@SgK1;jr#az2vUT~B%a1o{Bkz@1>OpD#qFAQy0x9_9`X1osg49j69?YR+w`V+|6bDfjXag2?OwC6t1?X#}aeR;O_rPIYVZFYAE8 zWHAg-*9KRx;4ETM7HTF@C}2ziz&22`I)Hr_cb_?$kB z5g2Ow(W1cy8?3~%zY!H#Qp42Ci;it!4JadAmJ@`kokaXDyB^`XuHROE&6l0?(igGa z=V%{V8oaP7Ri{;5?n8`AbIk8y@fQl4Q;%cPEFIit9k-I3ZXHW{`~YulsiKN}dufT2 z62wbY#*kv$y)uI6gLcxWc6Am7)8y-Ub}=nLtZeri(V!KkW6<{I0U3>khM4F3?%V{Y zz4Y{v_x0g#BSd94{-*PTjIX@yk^2rx?PP6pWCOdXF}4I7am-DGzaVbPjz zo!-0W+2ckp_Ws4s%xQ63P1F z>rg&}H6sfMzFz-yn2JIsDD7S++YA#(gyG6LLmA$T`;LqkDjUU^V1VzBc%yZn;iWx& zh;N2)N)J4tU1)&jLDL#Yt&e&8x1K^pmn2!3_oj(cAqk$a3&g=4p~$0*eTZ@qJ0Xi! z&^JU@=gtVa+o|fcYV4|>kn(sB+sDA+a2lPG{f#a=w(uCgIVi0*Y%EQ(6`b4E615kE z;2SG3jucDAFfSkNv6h()bAr6G@_f8Tqi_Z6v1`o^}}Q$i3OYDU`pK!DrR}Yr;BUT2Ss^HvG@2Mo8w& zov{#Oy&JmJ9pvLCYCF!KDK1DtnXG4#em~mcHInuBYRZ)f$rbJi!DL&@kya_|@8X|2 z14ppyX!mzar%au74s%)tqQmVy=o(G^elv{nbX&wyo8r=b?G<-th>ZZKQ62arVj~F& z_Hq;M=q_*Q`eGe(ELg!K!$Hl6`|Frwr@d~XTZH3c&W!`c`^ zDO8^V$KZXA;fH(3AbicXh>+3G4JL@Z=Qk&t#fCxK^?i6ov?=;+NcnmomEPt=DQy6; z?a=B|kuH4^LHX-@O&^bvz`^WOzmm7@v%clV-#do~f`W5ewwMQzrLZdNO~ISz5olTR z(Gr<+Ss$`#;AEEmEd3%SR4$-Q_Y8iR{!opXKh=59xn{|WjX#|6(r3 zJvFT7y{x?UVL~+PK1Fq(u4RrbC+f&4X`=1(quMudqaY;eYi8Mszr+Yz%l`4RSF_4AVxu)G?#c;b!| zDmA-Unj{`rQy9LNy1$-zwoZI72)Jz9cARgXB<4wSVH3h#&u%}~wRuHuEOIF#qmu6=-?lFaW(a2 zJ^~~5xs2`U21oV<_DZJoW}Y5RX-+0z_gOc@$?YtB)=}X%HMM3I^2wnTGbpLg*$pdb z+gcR1H>UVQJbdi?c@j_tv_;f+6cEb; z{#1mw4p@@K2+#nNCiKm)&LHXwz)c4fPZWYZ5Z)9%!ge77u!38m9=b z9n7xhe?xMYK1k|xI#Oy0>FQvbLP^J9xFAZMAA}kus=*4QgW?EtBYyKHoVU5Ok0cJ> zOo!#o|Du*ml+pkXFTg-OV|#Q|kf@BZ{pn%IR4Eo_R6ya;P^AEp5i+4Vu6KsG(aw(W z*VB*_l8E1ICH}-FnJsD!4r`oBhcGl=Kmq9+Saswcs@%=y&TVG-@}ncwmu9n^qg9oq zoV1vGf_|mAm}WT^%eRasp-C+==b3Vc?~LSI^z4huKj>U{dCj7)v|T+gQEHohF{?As z(MifVNt`~PT!$^85`8+vzi7tD$myZd3T+lcHn*I+v+Ybj@%eR1y&<#VsGQ;^Cm&Q; z!IQ$_Ac=`#c$kuB@x~-hU!3uoNTnrF8dE*hu;G;qoWb%Qq}Z) zjYsXiTa!t)YQ!7ziOV+AfkHh4f5jxb^K+VLiA(7==-7gXtzlx~Vy1~>#=xu4D`N0} z1|qSaSQ6Il?iw)wxrHlcr&roFtD!5+Al!oLm@kaEJ9vthmGyFS>Nis=bbIYWbY(1b z#YGjH%e;riDM4^LcB!$;wLwRr__3X&CQ`NqCq#P-w= zM!372q#u&^&~<-Hr^@Y=lnQbo-P~MFo4Y~_oyMQ9klvpG4PEF}R}=F--ITQC{U$}U zC1bc5;hkwBCpyc&A=uikb9;QYS?yWJUbAetN_4Ypgv#M>-2A8cXB4BaNw3*(zW`2- z(Qb(6kPIT9cs$Q!$e6!*tqbN{P|y7%^2+$j9f+<&AzYGNoi7%+t03UhFWMepIT%Pr zO5v==%6~2zo-e%I4RqLk_nw-$Q~SL%?-An98mm?yLPy!JIdmo9S5BZ5hEj9=R3tL*Sg?QFf9pL-+I_y6@l;GSW z`>zv|GPf#eftql_dW((FN5Cn~O<=L>YM$d2cb9)$NWcTiI_QW3TFCn8jPR3?3%j zv>z}lJmzOGjd$9a2ocEGPc$9^C3?_Ny(do!Z##t-DQFMdohEOvT~1xU_7a$sK&PH> z3Ol^td+$=2!R@1^>4>`Is2lw+RI|uC^gdZOv+s@>IkbN#lptcnU<3g~O29fQmN$F!95A?Pr$vHSj$I`aN z@#Q%d+wc$!lO{i2nRKwv+M>T}E8|l$#KKP@#+PNc2jfCG9gb=RB`EJqi=d4E3k*S=% zt*y;w&(srt(Ag<`j$NN-P{V#?^Ib%j<9jiE;Fop~m)iylKrU~8+G^~-j+B4LAvFa% z3BEiQIH&n3_LCKAylgY?szs73d#q1gzj7J9@CTHH|0BEpO=4yf%N}UI&j;U6B9drx z6#><=q#yLPUqvbx*$JNfWrLGq3>>{hMSWKQx=H~4TZR#|V<}2tr$3+sqB!9wLJO8+ieCFp02Il-u3+3= z67f?`ClyLM`KX8g{X`+{+Y!$CfBD?AL`p15R~{3Jz~GQDg_4iP$s$(B6f*RvNPK4w zX4qH)6OasXA`pBF)Pg%$Qeq!q0}Rl8lq7OMTq2n z$CsKkdNu_F-~jXZv7bE3?^4vqq}duIp@otxx*ffsh=d{N(6@$@=cy`c^qUsNp%gTV zzcAAQ%f-iG8bws1@@+)I$!u@7t2*H!V)u4C4Ga#OdP)hK^=hmFg5;K1QJ#l1fP?y! zsP4B`D5xcYuK81AM=oE)_^L~pm{Q&AE+-!1iOR}Vh5bSDtNR3_hFfc}S*`Z#w8TzP z95=BxVCEI7Z;ycYaO`7HA`{s**zda7p!F)6rdbPoHHN9{abk!|?HFa0N^gXj1;u>7 z_N0sKb6MQDEay5`JQV%XI$;6j*Tx!1d+EckKjgC<7C9S9!4Xhb#W9@WIzlg-Z9@*C-V?!o=lmcely$d<%C)QucBRYsv274eO~5lQ?~L{F4fk{s z!6jO$w-qKb=Ig22o_xkyft@6d1u`vFY|(NekdJoeF)>Dch`;A9a!2xm>$qKw3Zemx z(NB^4dvB8?Q>I?9PHHv&tuIcyVFjL09CW*uw;Y@)68&&NPw`NEV*@I@Z<{L?mFVIs z+PV~A+GaxRmkBQN}bpU!(=S>ffF0N?pbUTOKi1zqgLV2 zMRc&+iUoLt?4Ki%l+QE#EIH~##{mZT*}0x5|94Um#8u!l)*IOCH?!84-Ig|*^QBsJ z*UJm#T)Y`OK05yU^_MoQ1r4aUwS++O-~Tk$UsRkHLd*t|VkCHPIDl3H!I@Aa7qmC4 zZisXEW2q786zNYyt%pHy&W|Nh5UD2)5_<;C#Sy7eQEE{eYWoqW9l$LS!^XX=K>-Dj zZiQ$e@jIB{n-Y{G1rHMi-l+O*OhAKuk(did3vAA=FKL`aE2hoJ1ZgLnuN66KfnMCv zjvoMW?nyE>k&I`AdOOC?9g(Vl0zNSF0#BKuQ%Fdaa}XR4~TNJjuTy# zbx&m2p7T%xJ%64beJs6j$=OLH5N#hxkvLrA+(b8Z}o@ z@503$BL#>zK}6tZRX9E6NlCP zw)o8>3}z9U>9-AwMv|WrwufVK3`HdAkVk)z3}5fLJl6@nw9nI9uQc^&k0G4Q=-pj8 za|my;8+HV*6Fr?#ilQ8-L6Pal{M|AqIM|#hTG1GR(`t*LbL7Y?0XHg~xf8__{|* zKq9hY5SUWHCqRQKAhX^u$BuuLBq0g0MQ-z3`EByx9-MpNGevL+Ep1p1Xem(YjuRBJ89^kb^mhm#&Ea^1vGc z4?$?m!LtR)>I(Qf z!jHNFKk^V*JfO#tioeRRBQFH1zvc~?=fWurh3OX=Xw=rKdV2^A{PTt~ZM@-K> z9Jb?Y5;LD`|B;wdHpSzk5uabE(b7vI4n`hz$L1eZ$C&T_y5$NSTGd-Z@ZZbm!qkU$ zMrL4***u(3g4rzp5X=w+cn*K{gQp^iX3h$tjTehyH{~wlsN22&Hz-P>N&ry zrRU)MJ-GzRO%TjZA*d0o=p1?b(MM~cg!6{G8N2oTRrg?$)IX(pGvg1A5uxB*sS{(2 zXVSxjr$h~5j#9?9>&up(h+7|y?#LeL^n{l}_|7H7vQ4|SkKoL;Q@r|b+v}E|lqk_J zeVfYtGxJ&S)9>ItF6Cwt(k@vis=H271!eqzO;XY~+KIm1>xL#1%n}nb3vK&yo<;$g z0(2Ce@!yC3%Z1e(>GLN&b!L7fUOxC)YTW%-m{JY}K8kjaB|e%vDT3jUQAx#k8O{j> z1gV%W@r=20UrBl(>HE213G;sL&@OqoW|QJaQq+D4{Els9&e{$3+)2++K$;UiS;#_188GfijbqB5#BwAQ~WgYlI> zD+KRp0dZKuk+}oD1J%c_i%PDaFb4mq%(hj6jr~vv$PW0bQ?b-`__yfL-z4InM>?cd z(JkSR1);n?RBB=MP;%Ac)X_6bIEfhZ2Z6f?F1L#aoABqCHn zqSI0Iw`&PYLQMyWFRKnl3G`VEFCCytfPlic!0@7!Uirh;*jnYCN@CfQCH=PMV$)On zKj^d|L*U3_M|^=s#VXS;~xvyL3@am$cW4M(=`tZ z9<0ia6wqNbNurXZY0Ji*L-$G>Vyfd_r9(d)H*~iv^6k9q-Zvkf;Ni3w>4ayMcZ*ru zZFfVe+^r%z3oTNEd${TJI0 z!I^aXz3iok`p^sMULjIz2O|{>2!2T6l#f{CKl-3Ay_IWm_UK8{VG@@w{4dKO=+=)g zzZptheKlKLS$GJamvN}8R{??5>_zED*~W|c!|HhyJSt*_Uq$C%bMgHnxS+TEtdfJ zD&AQd*%Oj`SoUms<~jWWS&Qmm_hj{N8V8A@bx;gSB?+@tbHwHh>GneJN&ud61xMHR zWEbOUVY#eJ$Oc~fea;E3#U=G+wY*=8Jdn{dB4y3$W0kfyd@peww_MPMnw|KmCbY$g z&czuVm^?2(^6}sNamjuU&|Z-mlfQUuJ1?wlXl{j_MN%MavuM+p+UCDFX!!4i)U<>s zc%S+kBle!!_MhtFy9~*;h}3mI?)DCegxiQ@{MFJ0*)(%aJCe0~}XN~cN z!fPQ&ZynZ>-7O8_0Rm}wq7U&bDUk9S5qk(TH6SDct}%v(;9|f(4qo-)1t);wM8~h< z+>*W)BTLuElFMn=2(lejmPebtBxH#uO^AaS0H%<3Aqa-IDF;EQY)+7~5vx;yi=(jq zv4#J11!g9huy0SQsr2q#41~i8tCtM9u(Hg^8!4lS<-Wd8O8(F0 zDq{jjG;QAkAAGhHZo%CQI1t75xFIY)^O_1tTSK6k&P{#{{aG%94?uu3tCCD96 z>EVEZ@WNCj>jugpT@lb0c7f3#?YaRWWo3a*m{dSfs9V4OiV(hEW8>)Ew1&Ei zI;&Y-&e1KwgECF&Z!^KBUkNN?!kVY_dxF(d>8b+1`+v7O=cdQ+)Bw*F+6`)ybvK)( zOEkvc330J|T2zH;nKu=7cDu%N`l?N-G^Ky(q-8d4j>)>|_4Lx4*!81HtKNU5$gPqE za&9HdTnb8gtOU<)0w%v;-c)H3mg$i9e&sTdAOZrtK86mtSkpYHR3<)!29)+I$z*Co z;fKrJV-L+~goK?k-1;!@u787YM-m7jK6=+y>_$Pc4V(?fpywGO7NVNEgBdpv*o}Cj zc#`gzqDnl?BbcxVm2TF0%+L%=ubt5pi`VJbiif@ZvaxwfFLq~wsFJMmbi~qu)T>OP zM>tqABStwpJxg=vomSJ72q$)r6$x4@?dX3VxOH@c4xa_r*>R$$lLAM;uT-A$i;LZa;w00}IOO zk|-B^Z4m&cgL1%oDf>$rF)Ez>shFNDwh#;EbTv}znIW( z0tL$fNu}8`KMkt6wp>G>olpQNH5hjjZf#agwQ6b{}s@#t2`NWHp0fMYWN$) ziE#NbnI?Q5;SOO^#!zSxP4cPOB8JXnqcN@RxhH(j5Egx-d`ljZR7bxty~5`*x<@j! zpR}jlW)#l#G=~|f9Iq9QDtEnBMTx^|#&I7W> zd?4%_SW98aoiNjkjuu{_$tZ`)f6j}yT_N?Ua%km>MCq66h79{Rs<(99qD)j|jWHzs z?09*$!w`s(sq;`$iOA9aqK)5pL!LVzxAF0Lp8J6(B!=i^0w{lMQF1QcB`LzWWDhCU z*vO^h>|~k*zuD#8vBwdZyDHzQwUK-c#BYi6kXUmM@i1D=cG$4!$ux+2#UW%hq~Dp z%4odq9(4RJ18k@-L!IgUZ%U5r8`p&l*cGZhUXRm%B<|XWXBj^y$R#qs$w1i4t)9`W zDr9z@R{e|b*Y&tC&{S>%JYfk}DrAtmY}PF`e%m1-b#cB?a`|J*Igf>pn1B231=ea~ zgo^Mw4t{KOnq@{A8Hgy0u9`b}avr30Z26f6a7Z~&E1 z`t4!7KI*>|pZ}o)qT!kxfQ^GuWvEaOJY%sU2#Wja$E4=@Qe7Hq!Q9-97wG7G=v8;4 z1Bg)+-ocAF>C20s59&gP8La(SDWN(%SWa+sf^dWH=)fHFxm7qwf__KuMjcU>Dvbq* zT)7<9Wpzjg1!r04brIMjT$1!U*XZt;ug}EX?5x}t5ON=)0b2%*^i2^G(s_?;koQ#B zKMi`Fj%g}_{&fmBVt6}}Ox#D)m(n69I^SiB zm(y;k{TjUM9+S)>4S75Na5dv?7TVM#G8)vF%4&r{xl&VXhxoe9WXsje9yiGDp-qK| z6Lv`NdK2jv-A=;o8O|5L=Krt z48>MT1zty--oK=;jnuk4YR$vXRoTE+8)$XzGjL9y4>z7}+K6Kmb?A`l%}c#<&>wx5 z@g`G%cgp;djwZ#SXmt_9tZ%kpIm6iEXOnDjm!I!EYi1|?$jjB-`uJa+=cghoR+B~K+iE9EvZSD@>)(J< zzWlbHG||c~T~3sOW`9WJ4a)EvV5?@Jj&yx-8@e$zPWoN!ALfn!;~pVTOkZ?w;?^wh zyvDJ9phz@tYmzNF%W&Rt1=c9N`$SH5kNBm>Hm$Yd51PlV0{skpBR^md&X*bY zY?mv&66zUjC;tieWH8*b>QCKE@4&ioU(s1ZjuYr?_zUm zcLmJ%Y+3wUFduhfer!dLyd(bK)Y2)NF>_iDDt_wsgn8n@gGu?MC521qKbtux=A!QW zO)xs zK@Uo!R*Ap*d#|DjDyU~IDMMDKtiMw~42p%JVmx}C%u!VsrXaIAsGW54CacUtl$k!b z>*&hH-DyrKL1oEr@GSTy%x`AQarqJ)W?X&!J_I|dqdoanC*!vvW^ScD0s#6He=N8| zEtjGdQ506?>P&W65*-RH&|VkP%s!*{ndRkeIp+yGM)n-5I~fag>f*D9>?@?Iydh6) zQm9i3nF~B(a#V~|WE`TiX_=wM{g%QDbW>X81q$$>Ra)$BNMIewk=LVC}9Qriu!sQ zv=#s!oqG?sU4NLK%}@!Q=I8GWIdHcS{`p^(^5GLKwopT#G7;}84U0H0&9e8;hO^4u zz|w7;omzdEC*9ouKx%}mmyfHd_A{vs^4A5jRv=Sr$9nZA8V1<%Y|p|?Eqsb>en3u? zo;rT?N)|wmJg~@7ZK?abHr%^!<(f_1KJFUWma?ALZYwP?wC;$n%<@gtF=A$l3L+Y> zLymMBG(PD&y=E4rv`yU8&nFVppfz$9!L2g=Yb^rP>$b^2pPzW@T`I18;J?!@@x4?$ zt;!N;SsnI-Mv8;3C*f*>8SR`(x0C&~a+|_tjK$xgt)}-CO6<}kn@%2jtO+*J>r;i0 zios&Wq0h?NQ{Qj*Z27x<;VGSH#8TYcaHX9JyW|S5ZwVNcd{vbg_)47hB-_v&$*0;W z+~K*$0Sj?BaJ=%A_EO~I?cN1`vtBtJUJvRC@5xc#77DxC>Ge{6o|M`&O=)NLd9FG| zi1@H#vjLojE+^4?d>;}}5`?9&ly8y&%?}K@f^9r-1sPh4G+#-Y*czWp(XIl?QYout z_BV{gVa~j3Lf=^o+dL}&vyf_l*+2z)JXC)mC8ElyBr-l-xke4VpY6YHM=kU1a>V%ehkQnGjpWnxRx#Dnl9vS_Lzo~id9(a4IC zH+5Bh)|+W5g1?>Ge+kW3p^$Eerjao6=>^?$od;dl|IleNUmcHP+4oU%!~)shE-lhu zB+5YXCd|aO{o%}zSH&*W8)vM0ZyuI*Cx&TH*)$WJ)THYoEmJ7u2~%OI1=4C-YB6NC zxnA|?&_w&XU8+(FyG@Y)bZ6wuM zAYa#B+dS(anGlBYhu>EAJpB`{<}i>TMZGM)RP{WPwqFnw-h;6&8Mpi>?MZbN`$BrT zp0}jEu;)+3+Dq}s9^>87w)f7}7wW%*e@8qYk5=!dd3Lbm_#EQN+`3~a!7gPDYFz^{ z-6!oZ8v8R}f&A@=(eC(mdzRRW#-ef1|h6VZP z6>@WL9XPv-BDffa{=q|Yw8P=yL1t-?Wsg4!raf1d%88H%OC?VrrP8H}Of6GwrsIa} zl!p&H7T=aSbBL5r2aFWq^iwG)zGPzRNt}!YO{AgsdDql49bUA|<{&>y)o^ZhMS3W$ zV;@A)8F;^P*glUgw9Ia8)u|-iP+5`YK-WIN}H&8rP_>M`%n^gzzc zfuaVuG~*R3y>IGIzdJ=0Eod<3WE!Bx^pxPlhZA!UqoMIGF-m8p@}v2!rE|ipe_IU$ zC0*OTqK`G0h}u7(fqGSUVzAB!hb9sf+A+X3-*`Lkz|}$l2Ufb&j#b65c$vy26$LGX z@T9Ou?B7cSO}U}^zqv-PO;hTZjGTGa0n}x0llf*nu8qvc`U`Z*&L2+qol{O@-8Yn! zXHA*D1m9>j{ZT4ZtA`KnT#nw3diS(9Z3o2oQX&G}T6Z5137M;zlMCaXAI%X365Uh9 zK}F?vwl(OE#PFI4=^NsWhRz;g#%;FOxofDCdB~jhzAjv*RE8jU#y)&DlXx93tTW}L2J=)4%U=@*fqU6doJ`ePH5f9wrDxC zVD#8R`j?IB%|Cj&;nm=u(e|-NiwS8PmQTeQOrAbCI`ejF@sIJ$YwaQV!&9mE`pSffTMt2BTiQaQY+@L{jZ1rf4*?Ib{k#n`WBP-mF^W6B_Jr~`nMg@6c%VaRH{~OKqUE#Br*VVN(iDr^n|RJ$hi?^Qh#?%cdRhn{R&_JXb8T{y+QlNieYskY&6yZk zDH|(%Q@WK=<^0^}DPrjg9nkq)*ZF=TQ-PwcvGsyHhxp7G4h+64C&8$YK13_5i`iRz z|KQ{S6$M|Sf?XEz>}l3kIzuNc^$HE~fge@~jC-<_Jde8@5JEQE(K4p^UW&)XE9lns z5)YytZqyGnMM-m_IgWUKMNKH;DODt#U0%=8CZVPnyl*JJGDA&9jep z>LgAe}^3vh6@Ak|F7=n+M zBezH5i_%^T!4M=7DS|yz4%spp8tRo?q8z)+Hzuz#I+kPARlQ!Y+PY$5{V z6a>{>ot%F&N{l}86jVinKlkD3T4*I3y}%G^;E-4x{=BlZ>%JkIF%4We(*p29pf1!C z_ARPB`M}Y+={yYo;lq8aWX{LQg&5M>|CvWm9mmb$YNxUqU-Y6s>e^QQ+LM!C>@2F0 zp3>vk;-W^CZ!ZkEHQH%>^J$km6Gco8(FIIgpuTM&uRdl%b{}x-`m5q?BX1*R>%rE1 z)Nz}rNTUQc=VYPT(bD+5vEeMc%)@;}3J7(q+uRvGeFUq1GWWoHvy74J8vUVw zv>UWiM&vqe^}AU-*=84QMhE$Q0v)q3<<*z8kX>M@6_(aayJ$u1b>(2zW>P4h=&Up`bz`R@lg@$1eY#l zrXD_7zJBHCgV6Bj|IFuK7=DwF6YjeW3E~3f+ajjMyRdYFG!_ZUJ?l09o&M)L_E)MS z^rDi%!bxO{B)eKuJ!a#~PESb8!6=^PrlQ{tj0DUnI_p5Qig`_LRc^6Jw_(2v0YxqS z6;uhPXWY2UXo>CVLTC_aLR^80KKcn3UcI-C43^9#2ztgInkWY21i^iMbO33Nfuk|- z()>2D=qVg%sGfGO#JO3#CYl|!nAmTY#pM-9H|)IiU(1WGXEz+zEecm7?!^8x?H(+m zH-1V5snp>`<$>i2toCeZ!#jaXFOC7$Eehh6;HEUe8zyjIG8Upu(aj;^TWmW4&{A7$ zO>_atETL+X9M4#ANQ%GQrP$yLV};>T!V7itl+8vxL&R+@(X$>XMpA)HRY*Olg+I$f zr&WPm)m2>LCN0`?Qn9v7{S>aMW37s*x5k2usIa-B!=6=SOHeW9d(!T&~e zNDZ0`8ildh?j%7Zso6%OmAgTGlGSc%;EWJ0o{{=-pB!Ce5nQqZwS#Flr)JIAN-*!c zi0)t8XSa3qq;>G`l~2BBR>vCE$kByO{Va3A359ZSepjTLo3HDwIm&kL0U7N=Fz>3D zdhVs{Ne-6UH^jXhYrc-v*MEHEo~_11rcBg0?7Y$Ny18PdiQaNC`yZ6q!gIqp;^|eP zux9fOMpqrKm2CrAy@Ds&b1IXyNjZVY3HQovBs>wSpy(`tj&!BjUuI>51p`RUDd*68 z*w1k8L;5EcA-u4W@k58Prr-RqKHdB{9Ot?Dm)hpYw|G5WmiuZ}B-N2f&mPZL+bFF)KLE@gic|PWJVae7D^w=SiS1sqyK^ln4xm^GN8ppxxgf@M$uDxAA5NF-dH?UCEK958 zx8n2nPH}zm3;fgtskwd`PxN2Ujs)QMY2j8b;35(fMvo$c$TGkZQR8c}{#I4Ll>;**vWy7h`Dxf3(H;lg3 zafO!z(%d2;Vd>EUvudbdTv-yZg&zo zRB$@y)!GH&Hkyfa&sJI}f;U0>5uk`+FO7|8aR)wH8P;$Iv3R@J# zujQ^Z$>=px57hEl5-lP>KrK5i_>DScaJd@e9ig2}Hq|f(+T4l#)K3z(2hX4OOeU<9 zGGfu35Rrj)k-fc8QF`m`vON<#x$J$Rna8zahAQsS+*?jCrJKnvF)Chi$q%D+xnUjrto1aKh zDV0lQ0MxSONT2ZUfUQt)qqHuBe3)e)Voxg;2bq3kD;rkzF{%at5CC;SX0-X; z-f_wCdn-Y9d}rrExbke?ovbDDi}v{?Q86eJJ4Kg`ouCHa;DvQY4etaio{)meoCC|` z&KaC*?g|@jJGmx`U|br-G7Rb9Y)4p6kp2o_WQ{N^q1dYsH_8Cr0iziORF;zsxcLyF z)$Ys#EDtb5X6+~iLJ`7LhGN55IroXx{^D0Mb`0tC{KMUmkK+06^GFCC0170~cj4bD z5voWGoY62gDH?(^T_8gax}Gd(%mtUypK<_X6OUe!HX>;ivnSZbXc3+hj5X;(X{ybB z(4Z`)iH8Hs?hMg?+*Wfo{Vbbe^s@m}sT>A^C4U;WUY>g^Od13<+2J^%7d`Ml<&$bb zEYslPKMa-=CKiFjszsqR)^bOMT0zpp>k4dK*Cp+e8V{*-_tR-Ru{m^#lQX-i zcA%)XC3eCJ`4EHA^}ddrt^8%suVdELvN4D3>6dTb&o^~ER94O7(L3~+6e6vay|Ox$ z7ve*5)uK1SZKr@j;38x$-LZY5d{ovEH=UpLo=7k^Iqgro(N21@o0~|^CcN4@l}=p9 z4E*C7iOD7@`He0=I^C4w(yBeorf!i^_NWrJp4c=O{%SfsPr*`Qg1-r*nl}f^dYP^x z4Qpr@} zf2u$w{VoYX>YbV~?{OMhk3}eDI*jM-3AhAO>C5!jZY%nLhtTK&4ANnf^qQw{4sU2Y zvL%a+$4dX=Sm!(tu})3!zGdbP*%rgm+IOr+aZ=}1>LGHy2QVJM>4&@BLg{lEroLFg zWaJH=+-EL*t~2`9TCqqiKd;VMjo&HwbCENk4RF1Sa~sx zy?6t(*>>Sn6ujC9%g&ZkblL)FEtu#QW0ZDPRh@(_FSFTQ`2YmnBxZc^0?t&9FX;G) z=X4TSQwUH3MmMQYlE3gdJIoab$!H)#%6A7J^MOg8AK@&%KE9_T;j>W#EYY<1v(YZ? zP=Cf;=j2uv##V$t4fwKBm>>Rvm@K`N8G@UPuxKDj@Q5~LN@k_HaWN3oBNVYfTmgn( zf}oYff|z&6L^z=188|EnhL4G$b0nC{6~>G$xiZ70SOsmidhAHqIm3ehGo!=5whR$x zLfm6Vyr+_U0sLBDa9-)Pfj~?1QdkO`M#|l;Vvrr?)7!k@*qD%ehAkRbEA6^P@5q zv=XyLJP{f3Y(#{AP35%`Cm>>}Ky${4PX%J^m3H!9pYwaiT! zm(5pK#>ot&ExVZeJ{)(6BGf|(>fAF>D?MHh^DE#}sjRcv4JSsmLv~mRhRkP)X7>AQ z9$~sqE4a%nWwEvXGrrIp>62#Byl-6jfk2b1^g6wuh*L%F=xxEKiTA{k(J)VqV4cU# z)2*S4e5jaJ8;|#y)4}Gidc`A!gxAdJNA>s22wt8Ya}N!WMbj)tp*>qWXPDmL5A4p< z9?M#tE|@ZONQtVRk~Sz&@yD<#h0lcbtMSxg8%W2bqqAHfJ%`?X6INO};d6iMaqpcP zUYBd_FUx-DP!m@Qb&?|P{jwg|%M&I==PuBXg>ReA$vBgNIm$z5m~_7KqPArF1vE%H zB=I04bQPa2taW)YWjTwjceMe)Suy0dJ8RvLjM>coFb>yw6|LzsTeDxZyb)7~12ONx z`_#VX2a^>e_V@eNw0}}y8SH)H{C!Tm;fExIG-W)jt786zK5|ZN`cB+bYQaQ+Y_C(z zsZ?h3nsM)^5DB2UH;RkXI`fU*b{LlJ@K{Xq{`<*sH0>Rj(p!s(HQJU8RFHp!&bcB( zP~+~uMy9%Ny)#aU%Yu+w4o5||gvuK})^n)qnsJ)%ORdS-7BP$xpK<>JR~;y{3Y4;i z{s_qwpz|cO2oiq9fG67stV;wjF%HhB=Hfvp%qMvu*;mmazs;tunbf15l58#}p#HGc zqpL|#`4FB#PAE=r`=vbdt{ff~AkoZ6byCikLckt zpk>&pei_Ba;{Pw_8d#0-&g~OZ56PUa0=$;vNp?w70nsf&f9Im z_ZP47nZeXh)l^)wwrJ=@B`=DbRnLx4a6!_#(YnZa0b zbR_)0Hc!k}(VN_V<~n}q_xjT#Pn5=`St;bzIg?LOR{J&tqZ$mdl8u~E7Cv-qD`h#| zvR9tx9iFk%{U+7ZY!gz9@41kBE07p{GI4TuICo6s@sbM@_ISNd#?`s;UG|F8N?xXA zw^h0?79#^dha9zwxf$nL^HqmygjJjN87s(B8M58W5ClEfHJd%7t*A~>bJ3S)N3e0U}dIId)Rtk`aIv4WLSL)a62DfM5garP_76#AUk zRT_EwO)&xn;u`^In@s&P7i;rm0}P|?`t!pR3caPT=4nQcR#+_*$*upHU}*kV+ZK;` zJH5qeLVi;4?!QrqCKOMfd*>*5rVQ4lEyU5^V{W(HxvfDP+7;+gqc#i)chDu$f|N2- z@B|BD?&@5V$`Y@v|2u#KQ&^BqE&6l1box-7;otAeBwzhmGQX84+x5cxm+~<1PEq^* z-19vF%`I|M_x$bT-2D5;odYVJQ+6KfY*-CF67zJ4$y~VD7j*(tZEmO>j8DW1EP9r> zpOlMv*3Yb^urk99a+VT%@=z6cV#(gRmBsKBS|^}4 zmlA3?4mSuaV^tdYz}5eCm##>TZ@h7y1^?U*tja_@+n3 zF`5j{I+ggxS6zWtxm57 zqQn$TGk-_=Mgg&1OQvH>j$dFYe6^Jw+h>uUY^V5fHAzKQx2D-tW>XuWk}_+emw)3D z?Isd3kGnpB;DHFGoF_T)!QvD&z#$4ahkLB<#@uWoNQp0wIE)(h?H_74-=epU3VhTPt2r0$eB@C5%1at)Raf$G*)Ddo!NS8L5IIt+Hq*5w;@mQ zmDi0na2Fnbtjl;eCu@!Ajy}c1z4fA=%l9xXIK#=$KKeR3gNc^xJ#mFg%hM#~5N3 zVcE+oKktLC2xp-3N&b56#wE9MCu<&(YyK_&(kssM1@7Z^E#(YyK;BllLsTdsLXDs0 z%(b4b4eqiR)*h@G7k*=Z+wO6AmIkrx0Z}(~usih+0J013N`GT)cCEYv#OD9vHdo0` zoen$L=QP26a_hf%GS^X+c+VJ!QaTx!&0RHTAy7JvgeLOIYxrg0I#V(nSNFd=Kzr8D;-&;}Yu z7W}u=RaU@j;hRnqm&o1e04GN?GDK0?Tr|d&B}7iVQXo;WO>axFa;v+EFI4WCFA0}z z(i&8FA#e$dYDv{3vN*SNo^2MFt=H+#gZZ_dRzFXnDHfmBFL@<0;i3{V1VLaPTl;|V z1j2WAgoaw0&S?Bu)u2AqT+m&K$Q)fDt|{Fqb<|wV8i2K~cEZ6o9YazgKASd3JgMvo zIH-CTDfD3xs;Z!qa;m;@nSu!@x{oI2#NB^4$ln}FitT1a^JK$$YG0l0*y7QWx5mPc z;CWBFS|C_o$jZf8hu=i-@7)rtA~V-FQRNqHe6xottsZ$KyQ;~?vzpQEIb6~xcc=np zJgNw>-4VfC*X&3<<8u;&l`&U*YRMwwEw7Hcr0;c@p~yNIU3=IcJcN`tfEh86rp4yUMEd>kfnK~3qN74pUfa)R9>;RP3V3QC#kv)GfuUt zs>{Aj@>zFzXBkDa@DLvCjbaQDgbUK@4mCPGN1l#G2O3e#7mhj0i<}311`==Nd6~`0 zh%}<@^Xa?QJ2GTv$Vp*Y)Y>aMleZ=m%I9H?u|J zZ=kh2R&&vx8OkPsZJsZrI)`4~!(3B0q9Bm(_@>BiZBxcb`t zi9fX$)?tDIe1o5H-T2!yR2jpcM1kqjloQGTt%u~?0EnGkh4t$VUc$g@lmHC~ ztf`WS6S4fJTaj~@$ z${*#(j&?{tU&y)EUSJoT;MApbUcQ_3bvP4l(P2CQ(L*8@OWUjRH-Zejbs&$Xnu}kk z3sx#)3^ba(n(&(V%RDFa{Kuf1+l){p(2-8-=@H{-$8wEi$TJK2`< zqdK%bnhlQ2Q>hbnv3U0+J;ERAa_4VEqV`k`E4}Ei&U7F=QugPu7(2eMFr;tyB<{Yu zj?^H$^p|6L5Di{it^c`q=X=C&y#cu1xKHkskH_6&bJx)W=MOuQ2_NB`JmPQFK0ZII zLvXjNV0lhOpk@CWQnUC-CrA%?`dn)pjoy1sD{-1G(9|o$#A;MP7;&Ptbz5>~s+QdCsbksWE2s z(>k_=z-+T^c~yzR7J39Ahp>UDBS7qT`pVI)Lh8} zisu>pdP45rzN%o%Mn8u^6+OAY789z;$mk477wC#43uXkdDrh(cXp0z7nF`VN%Yzvl z{JxCLT@f^m06oYEp;^I9Wtfx2JpQ9Ee?LAAXAs^jD_@X{2Fx-`yZ7*D8f_*aF3$mW zD1h*GWuWHx{=|LA5ETtn;1%QXR=A=j=`&A!~o(}#>eJB51ZxX#9}r) zs*Jo>lnYvcL;C<3+Y@z6sBshmOmBlZA1nGXkrX(eGeA zKRGwGZBQrhy5ux@q6*wP<+^W25M(UQUQ(x(@=}aB z$Tb}Da<~Dlm)_`#V~uw33#}{=B|jsIREuWJcn&U7`h|18lU|UnmJElNmks?()ZK+X z7jkZD?5<$SWNVSxjPZyc#v0ik*3_Do2a$ONIKV3a|3k+&9)y6NY`kCz9Zx!L*}mVo zfJ3_t0I;4Ymem&3on6Xs0Os$zy_~T8gI9K3 zc__LWa`2J0?f?H2h#uIo}};oXw$2zNb9P)|b=xmAMqbU1L<*$wEfktVR8@`nFK(C;8nWi{N~V z9(`2r)yqe$T}nz9g5l(?Uw1teZoN(HuX=^8S?{AMyXPIq(=oen_2>DGhwha}s}!Do z8uagpzkgC;{EpYxHs(M6ef?T`&bBd^+%Wh|Wb&#TaXZDmY->t+I^vRIG~opo91OnX zX*C@?QPB&q=Od!eJ-z$VF)8}zol|q~OhX@Nk$bmS%KpFMF+FZFCtP5tw1%IBX4E*iJF0g>IUPgjCU>R%f9;8_Bx$_-){ zh`))on6G-MVArj|yG7{_BYg#d@EWJbnVX;SE`2D-;GfC9F?5~Zx8u8PV)gCP=gj{4 zj;}MXoU4!AlE1t5BQwWvgW4*e?c^(4K5YDbvFrHN``QM=fgp=(N`ue4AN||W%f%=P zrPm!%dU(+5q}}D#GG%T|KVsAcc1Tc zx9)psxToT4Z;t9nnxTl%*U&U$n~{Svj-l$Y;GDBrQERqu)_Kt897LF0Sh0r7F1)jU z=3P?Er^(I&+;)>wTXxbaOeFZ%pO&po)=19WwQ9MM!S=OEJr4}jwBIsCcFRhtf6uAb zrl08Yi0|mWbz&&Zq>bCS&7Lv*9&KJ5H^vSaKNrF6B0x_?#DXX0=dulHDjH#Pp}P-m z*dn94BEoi5ZM{iGJSKM59+4+Ze{;F|afn!>G_iww&;kq-%*m^`E_^ir; z=#!}DMQ^WskaAMfs!bf8dln@qbIlrBeZ22$wt-&oUqpZ0qJn?3z46DJvyb(xR{7WVg`Y^ZT85z-1cZ{J zUVDFH{z#Uy`B2_axwEYN3J0z^o!xX_bXxFY%L@%&1(~4aswZmR$-8oA)sCF4YkpNO z{B=Q&7fJU{e|vbr(D4Lz!xf$AVS`U0P^e*kNYGcIC{^ZflE;oaXkk`JlB?&(rx%io zZfV6CKRok(ZsX(isuxzRP}Hzi`t0F!N3w9~{H=?}9}HfJJ;@82E|OMIXM$(_EXev= zh`Ha_g3(;XHB|XKu^hi!T~txKU#EYK#Oi3d(v}m4zW(^DwBzEIDy`Q#d-(FE=?h0E z9&CNO7_ru7#k<}kSN=pN@jfkWC->m=XWJfDsTF!c9>s{<&iOM)uwKsHG=iA~evnWI zy?)}BV0hLkLDi?=W6|e-CoQJ0JUA?7-)}Kp`#~BW*-s0**SeTA&7&_D$(+ko9QjaU zF>%o9!~Xx&Yndro7=gmREq<3{vl9mW`!9`c@6M@By&gSB`1E8UY-`wl@70Yrrhe&l zm)~}Gs$IFa_#5U+(|+$&O>wc$Lhji<7Fr+Nzk;Xm+-LRL+l+~|wjH7kCDxc9yUv`z zU%YC(>BZN8l9#v7+NW(NmFVgoC?CCq8GTqKlMsIK;ya>tSJxixoqr^c(5tXd2I8Wz za_-CrOLr}Ovo#)<4pGb37flWLOf1Y?7d|~y+D|09E-Om>?*b*V?w`85;d+xv?)!Q} zrP{QbAFsV`zP91_DY*R(a$Cb;2hQxh;Ct~6Gd}V2By(&eX{)QT+0>aK`Q;{V6~9_7 zce}@5)>Xei4oY?SvoBzs@!ua^D{$Lmt~?JKFb(kjvqrB^5;3f=@UZ8a{MmD-+Z*>C zCmdEUFCX6huDtvw!)V>`k9CjdyRoOwlrPvm4Bdoxx>m;w^s`&6dKEsh{b$$9Egv^& zUhu8+c5qO=-Xyp3%J|OOry;(rz9BkIxw{_uY0Ipd$jrIr}Irsp9RY{IIh2e^W456C#OD0TU%x_Ifq+xOWEPYsI~XY z{JDw0Da%j2lAKAuM-KR|q9<|s@9cQI^$O?32(5*~38nK-_g6pCbT`&Jw`X!fA%*hf zQN`Jv`oD%;dv$^fe+6r-n82RP{#B58w8rFk7Z01;lvBb( z!rh&2YfgPd&TS2qQ5q8kPYXpP$H+Su5*ALl#5}0AUGv~k$DND(PqreT@1l?$zfUJF z3Qssb7%lr)4$r}qD;`Hq-Eoxce|9l&ZM)$)^^XMe zfiV9I9s6Dv=td-aT>UcASXx+|U$xiz*Zq@~ZzkO2;fmdFz_BaWXUx=McKkVcEqG7B z=Hvh7zx-h<4$`Q>kCb&==cEENjyt?Lvodev=5_xZZ_t)~xt5hO8}_s8Q|b=?`{%@# zdmXp`XBf(Eut~AExti4+`|Q+cTA!aoXHVa|1CiHMe<7)?$2*>WywrHOis)wbc=zYq zvE$p7%oY~Uf3x-Er75r<6$h;e^4mjL$)?LY8Mncm5@v8-o%!ep>WPu@(v)p}jb1(H z^wIRdGc)_A(z%`^BW@uVKCRh@+4gSg^ZrvuQglB1uT1-J2mV&=J{0uw!~Ws}xj}Ka z*43J;$&k*t>u2frPOa?aO_}77t$~%Cr@&&8RRq6m1=IzkokF@uaugKIHkg zpJNU`g5!j@1G?9SJ!!8Et?jNj^o6_AiPt{q=|S-={Puq5+SI*_AhY5l24i?P@4 zl*#A#l07%=`4XJ}`C)i~m(i+}|0C%%g6N|`EI|?8{IB=xe3%b&&A!%N zYu)$n7972|b@aNmYv}X#E3Ku?EuUQ`{xvrGV`jl9d3Z>bn}0VbBK6#ymm_8B}W_8<~!|^;Zvd6H)t!C8LohTSRwIe&!@z9 z!_K371V`eU>38O*pSHd@e|r(*{`;RJU$6bAw<|SqN33@${k(;8$x+=t?8`lV9cB{S z)$PV>v8mE1#<9DuaqG&^ClgU01FyCBb4uX%lL$(1X)p zhZbS3&u3Y7=RqC3nyMmW+>`+CVNh6!)hpe(r*y^84My~C0_GoAvhaZ>Ljw^i<7-VU zg@+g!{+18jZIg9fRD@N>V`mU+MB<(FK_)sE_umReKCz>sty{kMFe~#@9DVOG6XyNN ze|hTlJZ#&*Yf@!oJS@eJeBG%{icqqme03Y2;hjW$60g}LwrM1(8f8+A{9`QAGm$*n z8Tc@TRvWc-A>W!8Z0%o<;fg3pHtS%LsurrGLzjXtjXL7G8qQ)a2Hdu9bzl!BN&TU& zqoad<*CiWAJqssEaY99vl^*MYZW%!Np9uJU-d*cPIw+dKLC&{=N}Ii$%Km`}TD@e; zJi5+t1In&JlL+U# zdE8sD+KREl5)_N=DmwQ!-n?4!DM5@;z z3d`a9JeB)YA;m|jf=g(a8Vn~sd^%8>Yowy5X#~G3aih>5$WCHFoN7ZMdx z+3O?)=+Vfg7qi%0(Ul4|e;K`j7;|K%DPvPpDl$~k8O)_G7o_3*A}J5}WFBoW+_dKS z4YSOnx6Pail1|7WkVk#4PCK{vTv37)L&w`_$Da)ES43EwsdTNPs^e>g zKIbWvqd{eR#@0>8!n%fWhjSz3ujuKZj&a@k^^mAIJ02}sE?u@tf{D1Q^iXqhht|`Djz&^48usSKI29O2|fpiUAO9ppLB^*^$WqKeaREgaMX)%U!Ghld1HZhNv z(`hJdFA5WF*KDhvbA?T%);Nd`5hKL$KK$2wkYxfZIU{EG?Ozh0EX-FchQtBKmQ$cq z;Q=F_I;_$KR#k|TIAHtoWpjjkn2AT)1*;!_Ip#(kA48#C0Z6Apk^i|AXx+(2dG7og|PR-nHipg zis0+LrOAQCfvz)C7C(-Ck?c6M_*UW9>os@JDO24b*p31M3p|RPoxG);Mq4&d__%yO zx%jq!X~&@c6)1c5KsbaR2wiGkwwV2T{?gs21G*kg6i0>oU5(;>7L@c(&dbZlV$V z({WCIJoIW5sRhReUzig%A`r-tILJQ$g=K}wvcuF;A)|7rUg}&j!s)_52c`N&C{9pT z0_}p~yDO1aWyrM~ypG9vV38~MVS$lWz%7So7h>gx5I;gDqTzV0yP%GW9=(R#l?jY_ z5>109^r1<%$FoL=PNtunl?28b#5MuVYn`tUl!dd)x^oP^C0A1iAUvzB?jHLnv|p#X zFlgaqT$c`e_+6Ko<-7r{VC^PuI|rOhJ3M?Vr=}&bWLaOAqYjN+6d3b9w@OXh1E;jL%@mAa?gl3q8sRa~M8OF+9~wAuxR1GyOLM#n53FXg8*>hK!(5Hs zO89x^-T>>&%V8L${yyV=CYkehLzxbReZpB>pu~zbir}Yc>0Az@ImQ~H5wPHHWHg2j@$sZ@aC?lme2d3ZuhVkM)vufhW)GK5fWmG3*%PYx+1U{wqA;P|dzjn^{=uAcS?8 zswd6kpO5OOMq1ohu8~bFQ6HDMpYZh!3PaQLTKrafvx}d{eDIce>f-+H%KrE3lI6Fw zylhkM;_IG;kN7_yyB1&Q{+UvcT~hw>#q(Faox#S>4KScRDPKmt0#bLEUk-k}D>m zra6AT3{*gs+@-L?kAh|mu>azsB1JAO=*U9E3VHpiglfAhYe91%inW51n$#TrFKBm?csY!zM7}%6=Mu+)5yHaOdIc?>D zD+@V-0!bm}sUc<>kEt#A+gbjm6)vO_KT2V}&hr8=YADpS{SEyMwO1ORZq_PCmPt`RSWtt@fx7bRsOB;TNv|GyR)S?9;)* z0<$-;;(ccKY1`^}l{B|xat?vUV>n$qqZo^^(RdcmO`kkmb#h=vhpfcblUQ5wOw-h) z47cW%oCb@tJ9!N3r>;6jn3E-td+gex6+GYh13dp;HLD2HE5YnZucS!o4~6!{-Z=~{VxNN_psI*^-{NeB zH0rFBLt`Hz(wv=C!II|AHzt?pdn~ZOAx9=gOPU%Ht(R$Ao-4fcR=<7Nj*>fI6C1N~ zNRqT!w4wVwY^Jzz!lXAkY3cz8UH)ViBw%a zrhr@bSIkP2-h=I)iUpcYkG$AA15U3X|F--MoTH{9$TAZT9go|UOs*c7I(q={8QZ{9 zin5|FgA;ln@M!nnlxJ0pORf#9>>&TXpX{3Z8%9v;dkJhd2J`J_BZ>mF5L*517=m;_ z-?qs)#tW`~pd-J2@jVz-INFSxXDUOlm`g+3Ct7v@*`sJ3Jl~^Boqaro@cBq?_M#`} z>y47GdYLk4;d_1z{WWz-_0RW}i_ecN_TW($x#o57xD$RQSb2DU#Rli}An2+IS$D;+ zJF|L?&~4XJN1eBz#g7S`p= z(*Cl})9}#?51k2QJ6F3C7&-HMjCi0y!?%T+yesHnWZu)hX!_)t)URn|T2l^240WO* z9K$_~Jh@st<9Srf<3};}hYS<$zu#QO2bBfcj?o}lC)8vmc0^W?rfudTNz%KwwaD%! zTfNOOX6I&#AjRxk*QVso9^q+9Z=NCBi_QxY*L5ExQdjc5XBE=D3B=$l717$_?QYm) z1cyeD&CDiMiB#;}N9;P9U{7H$b9~ylu(>OBc-Jvb-mVSU-^Iw+`ShD;6 z;vKoe;L_4`y%x0ey4TZQ(zAqbsbo%I&}~TeXiaE|n(xYpacJWx|Gbc|T^!1#GXbxe$Q|74 zO{yWYIM~q~AR;skvDdTZageN2;4zM800)d3IfMTwZIsRT!6u&g?@=(PgdHn@-(WSQ z2Z^KJaIlq1;SNIE4#erO$GlM<84T}d0Vkx|h-ZuV=i4Rkk}#%Y;(h9F{L{Pjbf>Ds zlaCBQlY=M`xKqW-NV5|=9To3?hyJi(zr>`OLCf|Tz|&3vUnh)gyHv8dw(+g5qHTVcS*WI;`g}kpDhsG$q1H)6w8o zLq@&;j84U0Rdrw%mM8o#)AMK}TZ#UxnD4F85cQbFIFm6K-%io};3&u)G0D!pNvE5&;Ww~2_O-uQT!q`{8Sm6W-9qgcZC;dR z`?swgJ(M_eO2Wuj&{0?xIPgApaznA&V8OqYPnFiR=*4f#yQiVGbg<8#5rBGLwJ+|8 zC|HxahD#YYS-IW{`@El*hC2KcRJI?s%v!HKo?F-O!F0$w&%PG-ZFHtAIAE}6D%Fa8 zhcx$mA9RiA;~H{+_;TlfmAgp~GuxQqz+tRwUf+F{L~` zQc77lwd5*P4rKU0%dCCCOG);6>1*9@o?oOlO0jzIt%<+h1{))qyYF1a{{NKeS z0yZk*yXr`cB%KDlVrH>y(B3UJAlE2~$%qPzE);VlAF;?BgAo8~3@Fmow&*Q$@o^R9 zK0pwSv)>iMznmd@BRh}*Jd4mGAjQHa1|%nJtaz`jMhzNIKIYe1UbU}iM_W;+Vr|XD z2lD9C+e{!#6MbihwDDmsT@lL2Xim%^89Lhx9-FK^_#)8#FAZAjs7mD2#@e2n-Wx9X zDkSL!rJ66_^_TZjNZU)`&(Myhh>4uPag=jj@jz{MU&t8Wt;W!Ul<7PW3mTq7y#r%= zdrhs3=&4-zhQc}kDO^=~!$gzGOSP7SmpZ|o7>CYgbDo%bq=4` zep^SQB`f=8?rYH;r7SR;%rP}c>~bX%!{)u-g&*sfPbbK^P+y5IsXwm%LhlyT|ABKT zPe9s*9K?BgNZKIP+c<+r&Uz@%CemNM3+8qI(nvE)@OOMuhO5}#9VKam6K%9tZT%Gu$Yo)`D<3zC-yEgNLn>arN{Nf#b?WrP zMs~Q0R$0ZqD|cVz`KsZ8jWGO3+iCmw)KRS>!C@b|6L}jVJkD!w_v!wR(*MZ#Mr;w~ z6y{R-i3@!?4|>1lZ^OE&HHWVjwoVQh6u08p>XI)f2exSZG1UJ2v$R*=qvG5_8&w(g z=a~l=b{rCC-&rSM@i9CMn9ZAyY+q9G)vT_aU63DuxN;S9 zV73CpUID64e2GJvRT*s9Nn5UI0k3P9F6l$l8o-XoPwL^w1 z^ik3~>v%*g4wWCZW$+yEZy_|*fdGNH7tf%=mAR+|KGFm`Rt}#p^21DcCSj&Sk%b^y zn7J-;ryrU*V^St z&`@j4i+I%91k8H_eU|WdBRbCpugoNxhyE$uOwgIG^7*6-e|k@eYT#}$)zpcMgRAc$ z7YsSU#p19Kt$7t!$8;Jy-Hd@P_Q@;vd{nSs7^_#;NJMoAj?vve++aL z_odr+WXWNV*E^>pX_J+wITyzLicE?2+oAMo=)W=;|&Rw7Qt0o|& z9nKVs6b;qMZ6{Q8qYKiai~sCb0iwb>?C(@9IXaSJSv^0TEoU$J3j^rd%vRBU z`djAKkXX`^ZWLK9deS45`7TgiQFxrgK_rG}SciE$0{-IZ7s)f@18qLyP~xl2iN_TzgFu zx97xrz(iVUmiK(Q?7N{vnXN{cp3Hp5maJ7-0c~$OrZ!TVu>SN42(2D}{lz@}lP~a_16*N~4Wf0geaMRZ3R&B*-;JVCXmx_xl+){r8?X@9 zij<4V&V*itsnV%b(38MA?S9tZx2qsm&zGq`%ehi{+ANV<1nbMf2rCK#Dzqf}UvV?? z;&3V^|7+28Cmp*oN}zEa|2Zb1ojiXsec&wpt)S+@#DfDQVco@mfnA znt5E+M%3XQLp{?Fr{#q{Evm4DTk?GRR+v{UUS@@DNA~_l#aBB)lI_>L(r)?H9kFA- zw~QaYC~(_HM^7ClZ&( zZ&P>yKM<=ZNVq9P6?JVNAIq*=kj47tXUIK}Dp;eYxHk(Tl-o@t?Noh7UoM7z*u0u6 z0g-Ko%+y>#4Ys={T+~f`G9~;;uwLb}i_u)a(xb!X=n(=*I;5y8SxX!-Ow9NfT5oi( z@nUm?=EB+|i8_ntRhA|QY^m(hFrs7n$AX{z9Wao^v(TRcJeX8ix??JNxUkj)^5V_v z^6L0I1K-!zq>?~QbzyIN_T!$VjxOf`<)!~=)iL9~1#+{;xZI^5IZNMX>n&vkioOxu zah)bsZcohx*9@jJD5>ttO;EOI0@vs=yf1Ezkv(KjgISjh|L^a|%clEuH z0m>LN(nprth#T2pz6@@?$&u&^0w)CX%aLzNkiNQ#zlRa(P6vk|IFt|u@Ujp_W_Ftf zv7F?q45XHZ-*O14W;^1Oz#nUZjsmvjwgCRea3}CEfo8n;Qe${FhA^&yi(I*92jm`R z+PaKnzz_2g>oVJoG6X=xq^BxlJfGJASFA z3*>T;;m9pA4KJ<_+V{3J1w_T!dY$6SY^X`7oP*VNtdrOR-|UDL;wEFDF53H=4%7wptsAce$6LTv%%QD~A^Z(`KS zr&IT}X;IVztW&U6yk+~>%+T_0dJufh#*%Xl;5%6$F)jq}G;AhQH$SV{a^T9LXA$e5 zHhbQArU*wVLIc0E&SB90w@W_1OoJDGlApc)Ag^JG+55t?=Q;*9-|5aiP_a2Z*XW-O zS2CP-uDh)ZXcgx`tkQ^Y0LfGOa9BMj;0NJcAhAo0X zEd||AV5d-7b^%*7+kB)AtP+-9{>CnECg6Q%ik#pNO6a5*-O|T?f=zyXT!SX))5p(poK#@-^|3o%DenJQN;QBY8|}@04)$m& z!WKIIV#~NPEgo8^7k=oU8D32FQKf7w45|*)gt`G*U|> zJvoJ|TzL*O4lZ}Ud~%d$@vgsZ8@P4t_Bs)3#ne-+Xt<8m8{kG<9Y+GEb@{NPXdHTs`+>@*Ml#=kw~dnNAi9po$VRuD&^VOpj5P9yOzq_?WQDNEkN zQfXQb#ep7MHLP^ToKC3u+8MUz?hbo^T9#Zo%d6#9D|#qLNGr4rrVXxNPLUfc@E@Hl z1sJ2@6|@J=3PWzsa*@})HNip_y?6>+`a9?>Ob?FaoG)r8S``zuOEL^MEkt-C_Vliw zqma63*k%vg;`l9zE1;lu6^o$dY_k*JQwNtd2lbMA3g#%?nuV9qoKZTBGj!8=jCo1a ze0NLhl|7Q<7iu!oj-}lw3w!~1urFXa%IUUV(3d+X`EZ$5j31soPJ`m&ruu&iQXEpBm}!r}v) zOONr?517*sK4*Cl+CNoOP;jqr%G|a_n|E_xwcyE{J`7Zh13x^V#XzwUY~&48mjTLr z2nJoqqmCX(zyg4Su3aXC8KYk93nr>*UM!2j5;!>*;0UZVr^0t;K$$1?43x?`wIQY* zyYd)h`g{i^%?!EbK$B?GCHJ)&Q;MPP4l1i(2OFdhf8y|B0Te(M&b*+s{Y7X=h&AS* z&+K1JmNtBy{<+iH>@j*ZA4C~to__DdqhA)y5mM$$Ft;3$;h!b`4Ad}cPd9Lou2e!q zU0kX}=Qu0Ja3L$$FhyVrg#eH#Je=6%lTtY#UI z2TaBJG)>)_vMukOa@ltt{VFDR9qKJYZN=*tIfBpj!_FE0?V{LlouZyFmAYeLtOCEp zjI|dl+BG5{zpY3tbeR?FXT+)ri}URx$(>v(X~Hn(P4%%~ILr7mEqX~o%0_wgZwfDy zHCTNmSwS}DSp&+>jqY;)t6}{8#%W`fJG4sR={|Tx;_`&8rK3BRoZQP(dk+Sg$GLhz zH#-=QRyH*x>hPuPn`6+nSq*h;-|@(HI41$FB^avQuaxTi6>XlLLcqoI59~=OZ!hbV z+Sc$_AQ!q`=m-zHP!va}9xKrE4h-)pgy%`icDET{)@xz9X08gwD|wo@@A;uIs**6S zap9|qIQURRKwW4o$RFCT<)H0E|bTKi{4|8I2|Jsw!4QY)b zi@{X%32%lQptj3XVaXW3IN&V1>L}6olqFfqmel16qd$47Kf^t_Uu_TOexxQ_{tMX3 zSRXO9KU58Xr0m!BAmz>C**b5!>*89j%wR28@J5%(Le&>nAkdU|zsu`eu@#Oxb%$I; z`CuO=*bpiW(%pfm;s1$&W!ot1`*<`+4yBjF=q7_vM?guif%XT1Rmah{#{r4En7v<> zXAL9@^5KUAq&YT8ljo5-7>a?fB@c2yxEYYd zSonPifM8l4YP~{w{5eZvg}%nh&!c9l4g_bi??RMn1XaWw(!{mo(1ocKmVOnl>z300 z`B_UA2DD{l@b?N|@PUywWErMQK}~UCJ&xvQwXslP3tllQB({5{W zdR|~-qMey9NJGXdXd>o`d~WQgVJJ)X_BGKmIVO}Jm|Q752^|MY7r7BmZf2j3b=3#g zTyEJLG2kS^G}1CooTWZw?m7!S|3>(|8J-RA@-I19*XKuTJ{=!WOKa{anuo?YxvQbc zn9N%$1E^ZNb-YU!_SDcfZA%@?us(CS0hSgvNC(P0N;iA!ctZn)ox5e{Poz_>tK5En z^CqS0cA6^nP!e{M9IJb*5!V*un-&lj?#Bt&Z#~O%(I$E~UO8s&pVI^w(X4C2$4orN z0bA0GDXGYj9dTOup64J?)8+&#iJvB2(JcZ2F9rl@&&2+3oa$>;?++MVudu9BiQ=hM z!dZdBhnV@SX0W%-FY$1eMlWPL=OePglD)T^P6Q>@|L@)=@-R_cX4FH-ccH>ZujLXEUcKl^7_`dwO5{$w_dNUJm-bi00{_A2^C)q&9U)qX^tmGxqNLFLA*U4k#&dnbu&pGyke5K{r zkDEkh)U&s>!Yrgm>I1D&xx@a}J>3?T1~+Q1^ZuU*RsQQfciP@ejh|C>BlJ3OHuRdy z-_vq7ofDAIcVKIz^}wdjF?D~fcHZ=KR_7)Cf1=kLdKS@jJ|hvAQ{%X+bR%0G-`IV) zlv0xqF9qu^c4B^?G+mfd__fw^G<0z=yHgLOa2G-kEPmXUvCXfa+J+lYNpgxotLRQu z0R1%j<)gu&1_%!$nQ?N) zJlvwcybKeuVi=v;spUhVf?Rzw3iyo(bE)DH#TVPAB zd5iV%wR>Jf-^hbrs9@`?k#P#Ra#ThC6@fs-M9i8Gt6?@%rRLdhF42B4-ab*?wH%}a z`nlr-cn!I2hne^{lfQsBWB$g?>#qX#R0#nwGlXU)kEpaM#}>9MytQ@nVlN2`SO&lD zyYUs?3Q`d^QigfBb9Q%TZ$e-T1i_0?PEI#ZAT|X2TG3A0M_3}Mj>BEEawq@8Qiyva zB>iCg%$F8+6Sz)QZ%y?Jn$0Yy*J`BHKb*BAowDRWvyPK@L&JEH>zY))0iwDZ^{=2O zh3g9O{`t%+3EJZt{jm=2VS;mlhZoS6mNQ)z2PgpH=dN)9><+ApPel5)IO0A+8~V+e z&h@6B4%Z3#7oV1E;!qu`zncA#J6LvI#35yZQE7% zG*Ov!*LL6Rp)=a?{;!+UhqK%VSNjP)1rORv=I*5D43TL6Sy(QQ1Pjb0K zKB!;GbcX2&Uw!azBtg(URvP@~{%GI0Nnm`)c0@nSOuqBct;th~AnSs-`h@vhjJz&FQ9jqe(@G-niR zubUKN7~(mlh@JM$IzW?AH~q*l-`OxTNK&Y9cg>zxf#ugXc4V9m4kUZ06?)uM+-7;^ z05|JYBF2EH0Wu4-uf%jjQg&0dan)V}AYZhPHykm&Zb)E=RWD|3+gdS7@c-UA>!~lh zu^Z^UTQIY8{2dw|;`)9^_VkTT^nKFkgL7+Ke)&AW?pGp{Vr%WsdR5~=7}@ZU(OH5X zs4ZVwSK5X1(HRit^kG`T|VZ-=E+^qZN4R>S*p zN)vU=tb~wU2-7N0pI4>>Q!-mgE$t8==-ct0ZPtZAIB!P20=imIuRD(a89M5!2s9HA z#xh(DjMP%Y*f;vn9U;&c2ufkIgK=5q7lSQ`sP&#%JkS}hJiC1p$0vg#fmHrxeDgh9 zYtUBE3(_tRM2ndqEzxR06(8d&QXp4!*MlrYjPjK}Mql-nEH1^xVA9ZJll_K)@%+Du zb2ylMu5^33Q8%A?1fl%L60ThGXaXI4SL@#DTg~@*w^Zw3%Nq>4i;b@No8%r3;SFN0B>ch%-8d877X1H2T}oSd zYPB_a=wsp0v9*n{4OA_I!ndb&MnxLYdXy{29~KbPauoh5SEgLhIUO8rQRm9)e5+YC zc49b&vGR7$FRiG9>LPc2qT^_0`Xlm-djS_pH+*kE*HR@Z4_gVrXTn->5kwG1JzF;T z@W0EicZjnWj?}jpPCZyWz2pJ&^rm*4kZkrOefu4vTb4y`I;-?9HzbS>vH1%RLQwrZ zYo6895; z@*88lZ7a>bES|^H0)~MNOt*)4&sEc0U^xe>W+ggFtieN-&4Bj|MsKcO3!|wp`z0~V zbV2>EV&9IP+mQCd9(!x=2bcA`aYtqdqds(Bfz`*~l{&^@f zgXA0iNn?3ep)IBJvZ&{`vpg0RcOiBJkXEAc`^#g@baA8q6N_8)P6jTw&3ilQ{agD` z_Ym}efZP^tys(Pji+SD?U8t0*rr^{SuXG8?3M}Ze&)0myY^{oeuxw@O#bNcrS$BV< zT>l6v>ArcmW}A_lAS&~49&I}YpM)8MzN&FvMaIoKI>$+ zk^B;#_2%sh->o?ly8?-kF!8DFNRHd7dOt?ad5$sxQeuvG=(tyz`=rSReqvsU+CzAbx#A7W z#@f9Lomm>>$mro!@aI%~80LkjU12{H0m>r=Jk_)j+vbWcb0sH{=nGf%Vc4JoG2Bq4&gdtmK5*7?Qn-S(YmFxzX_INDT+hQrf18z4joHPB-FQ znWjDFK?B}lIzrBk?igYI)0&h9!w2dzC`nae`I&(_3W2lb^J5xVU4(Cm&z6{G2OU_~ zyiL>RKJlZQ@f(Z&?iOO?IQ2gNzOlAj-`7lohh~#I*77~uMl`?r#;L0A*K(CP4}in@^Dy7ZbXHw!Jkr7Tpre&{&_R%fUE`F`?9=dt;D-0#PB zFw3)A!{tTR4LKCEauwu!qbcv$zXKN8ib338p!QB;B zA3;r{K4{XpP}+xl2D4ISV!`z&`Q^ow_|;;~WCg_|j-L}}vhpD@(Lz17C*;WsuH~S_ zO5xdEz2MRMkDLsZE%D^L45Gf1(i44^f*IDyYkBCgzdwLi#``z7V*j>by};@)6KRLt z2LIPyU?Ik0^74-XrO$IlHaV*z+Y5ub6!?_W+lEmUcCLGZHfq2t_G5l(FVbmKA`zy^ zbzJADU-4b5!iB_q18A*|k+Nj4JX48%q;R@@&Gla8Ea*F(vf8ZljWFVu;kvR(N<94c zIo%_$GClh};Y04zuszS@W=#?Ex8t8pO{`Y@Pt@Y*Va=!Sh#C}57rl@bRp3z4V5Dd2 zYhs(ow+z(fIiShcwNpp@eXnjKJ@mP}BEJ7P_-mrrP-D`VMGETC4cm{dDlbuJ-I73G zCCJGw9l&<9@pkd;eWSS-e6Arsl;aozA_e9_b%KJLqE1*lqRSw1ZC8+zHuot>yJmF_ zM@4Wkm66MpF^FA{5q3{-bER7KrpyQ9CE;v+6rTZ9@)mn_+ZCiqeS2!!MR}45Kep)O zXdtRP>SK9VgK+Anw_`+5goLYXN4I1vx~LzqZHOmW+P`D3tg#G79>y;d)nT{M<8^Fu zcNbz+nmR6saIH8k2CP3FyM3gbJ&!8ksv(PBbBJa+*F=zK%->Bkbqxb#_bVI!O2b^| zxg5L5?q}=ezNRi*1)CU$EZZ&>6OUvO%6h8Ic{*=?Ms21@R~kUHd&Nu0QVyBZGD3K! z`qSl_r`_b4@>}kmGpk|o@awNjCwRNv=3bvdt?UE3v;URe`GPL}F0UW!4X;opjuPsY zDbK!El4fjTt@=GA6$nffazCCvc&xztvmvJ{Ucppy?ev1X>F+tyg-d&7j@D!SSzqb{ zKlV@{KJf3K5A`_6`t?Py_#Yb_`;a|DxoE-CQGC%@#nFlcb4Q1$`f zn70HR2B2(N_8tNLut)*as>2c@;BEqhY-5o%79C>t5emgxwg3%pYBL_Jn`zd6|rrv<&(y*EQ$80 z_>0PDtu>D?Vq+wR_yL7otN&y1+`HGj$|B&-*9U8!NUmD{}Lz)Ph$hMsGZjp`zN zh(Q}CUdGRy-J9|zb4AvRs`CjyJB+4S5h}gs(r&hwr;n{Am4%N^1$b!ne6=ao&QzE& zN93UIhU2k|fo4t)1cOYqeO3|ncgV^+oZsr;(oA83nUBMq*!6`rfuC7f2tHijnlL29bYTLCXMKMu|cS(oMLlMw8_fnji+RImz z(Hk2BpjdGxzg70sY6)X1o=dqc7(Jh7XXPMueNEK`yfq`Wk z^Te?Z{{Z}FVj5>t=H)+x-PI!(Yqr^!-!JCgU8DMrK<@V+Xy8*)m*tz&?Iy)ZgjM@B zrsmvs1Nv&2wW%EwC=7*>SvO6;-&c1gZf{eISU6W{K7l+GS(KTW8&t(rSLmcVpU5CS zc?wgHHjh;o*x&})j%dbwr=}?qld^urshKckLz_^K&5?f=!ISUt}@b=*@|D5>d z(jxldBU>&%>pw-{P)GxJj_i6t+hARjRi8?Llu+?CP%)DUL$9-BhP9~9&nd#0?0EI>8DC~sFEBxOF z;9otS#V4{SJ2%})`ll;Gt7A->9 z@x2SCreGI-=?=P-iL>Y%=~*)O`IYT>48^_yqBH9MwQK+3tDMz9m!EPW_4f}&72M8k z?oPboZCgpZ^kpK5wC^5KM1!l#(IRgUpn)*3;N)^Fn3lJZp2SgCz`Lb7$^@wGO7{PT zpfJ0eR7q*BDyMHr|+2};gINj9i0 zlYLN=?SKev*iUH^SBmt>+!huP6RLyqA2Hd1Hv({=NPd203Rt6}&Csrm(LV$$tR~#E z!gX*Q#4za7&@yK8{^v0&MMIMH-h{~Ig zAsYn^Ef)F=9>&NhoydSsviPW$`Ob=MdLRda%ENMgHL90RG$3zY(?=rnM+N_8P?uyp zBz+y};pr871vLwA{ebz3CD@b&$ zHqeSndoblB)Lv5s$sa{Jn7DjUsXLE8}m4 zMP!Cnm(4+;vR{d33*I5!uA&GX`nsx%VxVBH`5Kqv%T(QqM@v+Fs)5=e^M-(Y;0|U$>0eEa8Y=Pz?jmA3*ws>P(OjO?$ z9Ci@l-5x(n)9$nv3r}OGxYA7i%W$1Gkpp6bDt;PZ)kG93;(Wd|tGOOws(fKNn;j1n z=u^h212|OKkaap1(y2UjrO`}e1=Ag(V#y~=Q@zJ}KV0!IPSzCKmVP?z{2;gdTi8R> z7qHmXD{1IO{=wz4L|Db=p^4`Bm5zD!c;STQ(XE@s%#wz9* zkYj#%FYs)NqS8(6+IX7_qjR4aZEKmnJCN;9qpAdbSvQ~WSmP~3POM2>qM4@!J*LX% zhm)qcwQ0(8H{ffnjgeT=r`aBYreuwObAke+Wa4GH-*= z`sI0xvufa?A8IbEQeo{2=_Vdrb!LJ!l7jXr)Mrn!mFAf`|0~p1>LIV#7NhL220}nQ z^8bi>?{K#M|NsAFAR&l|y%ICjh`ouuiB+^p?9tZjFe`Sf+AXaTv#7SHwyIvlo<()( zj!mm=l(wky&HMWNuIu;wGvhk><0R)iAGzOex9%KZl3AURGXt)G0V4_Uh7e#rLttL> za5n(oGIAvlHD3b6&B6D!@uhWOf)L1zH45mI7ahZZI9mWmRRSP#G+||ohhsALjvbKQ z77QAcoPZ=cA~*OEL^i}8R|hRJ5b)Lk;%Qz2FxXi=1b~1m3qUu{tI;YE7(*=m0Z_4o z#IqpUe5&L;#>L-%_*0ts*lRwKD?WmpLAHWyUH=sjJ0^zFRzWbJHRF!Yyhypo%||Cb5uT4A>KrF_fjzF}*a~2wR9QSSMeXXhAM{%HkpmP;On* zmF1QsyU6{sA(lQYn&IUkLE^RIO2~4~Sv>boC{P$KQYEDEY0V7ReE5hpX@Msw?YxD= zS26k2)C;U!Ar%!_PR%R1*q&!0Y&?fFU8w6nX|7`)oT-J2bH0XvJxud4lYcX+VlZ?E z&=jvrA#qfV7_wD0$HA<N7$1Q)sP7}2lA zu2JH_Wmrh(p+t{~IeryLvcKZbQsjUP(-1SslG0DjtngwV0R%%?8W_+y759eVCfBki zR4Ann?BEj*P|3oXa?Vz2wD5Q~E!u(=j*8mU8aSiCZsB>vT^OMu6XlOI+ z2m3RWxIUMm*2>~X!KOB`4L>b&n^6VI+$$a;tTP64f>V4oTYiBIn9Ny7-&OeiX@yf~ zAw*#hmAb=#@Xq#Y2nM)Jd z7Q_<7_+@?Nbacc$x36oeT5hT=m+Kig3(wGh9kh80HdFA1W;nY;ay&!*Z2Z> z;}(GV$pNf-0Hh-TC@KU<$^cCXtP>3*$X5Rd7~#e8C7rK}3CHZo?Ab#AVf=n<2%#NT z!4GLl6=M9lpa!(_F9U2a@CFp*3Z@%Cactn*`JlB-&@7Sm{)4q3V6DndCXqpO3eA$f>u3q2w$iyF6qp_lgq(0&W#z8jDj`x+Trp5E<7)gei!EMYK|?2)SW648K)?P3iP}M5HSd+QGjWYd%hZyPUx{<1nIzm9H z``mlbL`G5*CS%+hS>f4(Mo{G9WH(Fg7Il<{rMN+hvghWgOn8RwRT1v?p4x!*lVC$ z!te!q?g@Mu&;KoGY)Y`M@=4ee{91{0H^2m#O+4bn zMqgQD!B7ss?=~UX9akYw+iNQ;i5VE+ZO4X_Wf)=jTH6oFM1jwJdvi%wm@*JMm>&t2 zd3hUhNa()9o1h6K)tRBfNlJyl$%3OhY;G#UDQf#ptjF0|$17M2FnPUm=-3EryiV^o zf*CJ*S#L{#7&NPx*$4L7>=~wxv_P^eAFIWou`2L#JLLv|Jh*VFVhj>dH?0C-@^-DR z0zd);um%_$igMil-l%U~WEi9WMpOoP8aNbt$!JMVe8v?$d-Ft8aqYD{k|qn-6#(zB zbUYY`rL9A!Z5+X5R)7crHpiF@%?*H1eOP#~4Fe}8Ab4($C9}k4Upg`FwYwhdjas89q5Y<@C!%V#nEmG(Plv9>#GM2 ztWj*xY7y|3DTzIcY~CCPW``E}B1l$Rv_pU%IrsNo(#pkisXelZRGaAAXBk61Pb-*O zd2-?$VaEizKD19i$aQ;VmCoy z>CjF9b4xt5ClsRlU#-Qtgo!}n?nkH%i%kX-W{Fskw!gCGCS;Bm1ZmNh^BQgP**i2w zf_S%4;s9dt{lE#nnCYK#zgHAp5sOi4ArEk>C(fbUx^_Yvw07&w(Iy2sqgpY=R*=vI zT?Qx0jh|cxq#o=?Mo>tH>?%+G`k$aLv)%%6j}ZRone=T9eXna?v+@+4s)c8W93x+t z$WSrlg^hkBhfEwcL+Km_8e?f~p(MYlGw`fLi_hlvhK(|q-x6mNoMFW$ z}-dbkJ zfu(rr#_PQ1a)^Vh&RhQd{i8N3R&hA) zp@>#S^j&%=d(UvatReUdf*iwT>UgRl8n8b9y!`6ZRa;NeBKN`O5c`pTdd0H{qRN6l z9h(o%j_9s7W9di*2jf%H)_#(@?29Pl7Sw(% z%425ge^J0Nmrs(}cVVLg?@t}IZeJ-ry2Br#4Eln_GRN_-JF4 z9&iutUnTP$#%!~KI2P5J6(kIv#RgzlkXfLpRGI;swGVl9h{~)KXX90)mgkJ-I zL;#?hJirns$hyG?8ZUrL%0Yi~AsFR?WCSegGMe!L!LYUA2Yn%uzB`RyF3)z>O1~Te zjVa7Pu8`CBIY76->_k~sq7-iw0W>+d&W@x?aS{Ja2M4;JK}K;xWdB}W)4X-5Lu?H6 z_bCV~laStCAiE-g!_8G+dpYHVE);dkCgYmd6Peow^u>wUN!{(qKc})0LVMoeC{Gy%-;e z>88`FIo2O?s-OpiAGpAZorq!Ew=&5eWh5@{3Um6h(t)d=;Du7>+n7+M^BB%Kjip81 z*DSpyD&IdC{nT!$^PFh2Iejr28*Wb6=Cr? z#_Asgxax*$@Qj5mN8RrT2vbEC!a)CfKtZ75qgnKPG8%X1>gCWMs`$fkQ+&lc_mmGjirO=TCHRU{rV0at}o~9eZ^JL3J z@;c^K7f6PHs_XOY=YwVbZo?_C!4q{KU6h-POOb>QYjQD&{vsPVFazdg=&@khggbZ( z22`^G(=}&jd4L8uwHRRrw8N>%)^I7Di^H0sUK&bJD*Du-!+`t~75&(nNhv_9secO! z#7$>OfOA1$;xA+z5{#Y!O=RAHOnab+9<0rotg`p3U<3k|C5{YQ;ea-Cf0zsc_&2e?oQ9I=6`<3|BMwvC=yWD0)p74#&(MRDd2?q^=C5zq=kt{zL$DiJ&jh zSSFgFh($O`xP6TqO13q>#S1*jWS5NA)L}p?izLtIP;X?VNn}uR6HphIPtx?+x;JaP zJWnyiV5*7sAq^$p;h-skLi~~#nU@06(K36jT3w+*H#K!7Wr|)~D1M29Po>}#y#>VA z1xE-v)phLoPdS7~LrBna@mm?KT;CRtUl6-&5?r9vENwD~wO6z;D489Ul;&xYo96*K zp`Oiuwhken+|D}&ia{~zG1&qVIkHp_0}-B|I6-UCR=5oguG6#nH!8KPUr`22NxfXJ za6=yW5xt|6(GsNNIu{#|!D^Z7mVR9~0$w{BV`DqqwrH^jL0*dq6D2=8ffF5wT%pUE z_L&dCC9TcN=y}_(RN*l)@y*urT~YM3QLwMu2N=QGy0F`;o!!w=u^T)ZHd1qLp_ROR~)(a!CG0bL3T15WUdo$>5`kFdgTThT=GAvXL8X+AW_cq1h&7 za6%Jbny+9EVT)0GH%LSRHz%{EDcxlsPSAP;Gro|T2sT~UZFVji(@fOW)@J5r(QFYD8Fdw%OPP9#CC*tSXcv|_&-M!pv9SY!X+ z(f*#+Re$xd^=^Z^M8yJpub}6`N1wi`8^7GCPVGUp@e*~J4%n0bOm0+UaXK+Q6?3M> zlD(C8Bm8w{M}9-w4HCxM4GJ~4TYvA0xX)W!eQiVYu;?|GEdL$1n|t1#x;*q<`C1V7 z-zR4qSAYI`@ry0Dxj5NmcjTFkv4Aa~s(!=COm8x|h}YIF;5J!+X(9f1{`rYV^`8my zYFad}8`V26BDh|~R`0k^Nw%zCxf(hB=+_qq@I}@@I@DdGe9j}|QnmYg)%#m!E5+Wf zgYbi$rxAZspCVngf?!XhSZ2!W{l2nphlE|b^z|bO-YhFo*2Xz1eQo~vNu>wPas_j2 zmT5@An&#%q5iRj-zYPr9BB@!wzx^E!p#`{}LyoiRK1WO{*ax&&AD`IE$qIUG9(U^x z@71j*8VtFMzZ?^*D!sK|hb%n)(B!+}^k8|B?{oQO81-Fc=apQP(Twy~V%J{v)rx2h zFWvA1RReWC&#yK#10Vwy?e0g(LqE{s`DOF^pzt2p#>c17JixvDZ(p>k+Y zS#QQSH|14M?pb|B$LDsx?A)Fn$zB57GSN@1ZiW*kZpc|%EgyM1K&@^L8fmO;f!_?7 z_aj>Jjed<+F5+)>d%p%3YucQ&`1iYF<+bP6bIl!9!M^Jkk3(BMa*qx!1s1kVIvCDb zn3l{P`Nox>#9=+;?YGTL=x-8Ud~bdv7yrUwjPbPcN@BFv#k(*(Ia!F-&mU-@b#rgn zKti?0iOr|OLqf#nl|R2Bet%`=?U$ljheclfEx_nfrVlGWKRBro=b#P5JL$lkTB8aqd`-*LB0YMcw9?H? zi*_@1j&rWcEHwxq4xS*wt$FX&c}P>;!Bd2?++NW6MvZO36DdO+BUwD*abrqd6kWu; z<{Sl=bK5)%moXl!I-Mac3AIDu)K*@@m76(`Vibd{%ja+gEu+Q`-1%izpLF1DsY0Xm z1~3&eSXhHgKl9WAxP?A#W(_J4truKzCgkYMpd16=G)G?t43wkhpo$zMw{acqIe&5P z8@Nmw*Tsa4Vg5Sjry3*68K1EX6e;FAFz4BYjT@&D%Wg zP?f9ONxm?USBv--Q#L9;QvQ*EFrmo{QV1k*3s|VM7Kx8l+D*T}RdUm@6479Y@Qlq; z6$lfI4kV&)FJ8fEVxRx$_^6* zqllFh@tKx*D`SnM#``iqi+M~Rq${JhJ0SC;*>3*cQbyInMD)U!w1M1M^bUjd#B)bB z@fBB}piq|eS1nsy%4f2dL!LZ8;2LZgjHbDc%+3?`HJkrTj{Vk@hWs-~`2oNRhW9 zyMwdt{|CHZuG2~;z>?rVY93jV0Tfk(T(IO_HIf!o&;pe@HDk#fN+Q`oE|x(HJU|u_ z&&dmIPjwxbjvoXaG`{CTQpU{zG3c}`!Q?tH!MZw<51wHI|0E5)_P%h{@yJq(27Dky zv4U7oge5YNV@BT90egOdS%W~iH$jYa@`XY2xlEcm_`E2kfK6>u{!zDmA!D6inJL86 zhA;pQWOySsS$TE>s-{sQ^g$>mDCUOtOM7oFgE?hbW4Gy21gpkZ96^JR6m= z2K9}xta|agD+^CC0Miqs^IuHL01_+#_AdtCY@2Ry=#Qt?L1=W_9(J@IqOzltkihYY zaM;LR0kK1?S$Tu4V4QCHUkM;$OvHO2JC2Kvxk4d{e4r>$EzSvSh_RM1{~oip%!igQ z6s2cz<@r@;gyQ1R(~ER5GtS5g@ik$Uz;3oPFb;mqoGoWq z>T`2KYUtN;?wk9ggZAbU*;>?@eT60vzKjck#>!cwQ!%I`Yi%0T6OoTmZ1gK1StwDz zb662#G7a9ZEi*tSoHWLtw1t6h1rl4}hdj3V3vussN*)o$EzZU95g_?DW2@&BS6V2F zoTJ!g8Ublaj8;CQ>^K6s6t(e_?GaWw+yrFno$-i3`b}zuTT6AS%ASYC;)d{^d|g7P zP?n>^LA@hjDG2>vIsg^f*ED8N^Q zdDAcJ=W6-CJU8soJ>Z3<7rWUYoqTMYEw8ps?71$7AZEDX+H^-&bnz6l^d#Y`t!aZj z?Ts_M%BHG@b^jgl%Vg1V(Ok1uQw6;{mjS&fsyUcp z3uXt%B86CjF+hrR0N4PMH_)qb{8bD_mI8LGfluO~`HxcM+foi7K@U2CfPs%^fuLn; z1hlX<@K2YOu!KAk+Jb6gt<%?io5ywP}e8)XfVFV>>;;?9g&<)_7)Uf@usR<~B@9he{LvmT%?$MR;2~b9?N>q24RY z%PORz+$#N@1?M;gk+4GxjWKNJ4VbHK$gwapC$HGJ`0epW?E=2>iS{?Wg_=S>pFKTA{*IT-vN02Ny)hFi1~O zg_BEUDL(d!*Rtg;>~8oxsN0ncKPhKky-U3D?7aS$8n_+QI|Q6N2w)SBR?(Z*SbwfR zYF~Izel>3h1=iBGYiEf;xzYC~9}yzhQ|mni>TH`v<+)nSw6UE8fz-52FZ+~2?>4iX zhESC3WE#r6*)ALyvJpsaesJtHd>JRLkL3xdK&bjP#P)=qx_a{nGqn~Nd`qun<~q{J zGiOLSNk-;@B=XeY3Fl&hquD*I(XVXO%RNFUxYLuKAvOK1k$?@)RMAlYZvLkezasbV z5Bjd;^}WN~NOjJseOkxuC>gAdM6fbw;)$pFI#^MI=j(32DYTOJDAos<=BO+QIR2FN zcS@zDKWXx4cllTkOw`%=95-5bPF4{{xVUj>V-4bz&bbg3;)dd1_z_lXoZOyrXmE5t z=ji$$4G_ZzjF{{9-#Gq++=ID-S=zXK(GhT;vu zK2E?U;TcCy3LRv=hO81{Jy|3=DR6if5F@J|QB)ZpnPhn`7O)YQJWwPL4Ss7u*yh2w zLz(xW9Td={3X6tRCRqRknzt7vJ3wF7Fz<4gnHzC2NNXPGOOY&KO_eSZ*t$BTbZ*V} z#LqCPy}5;0keCw!q*F*P!-M}z1s!JtJ7xqPFoM^lw*bP>Zg}X)I?nUV6|oM)rADbP z8jiH#Dc}pH?oBWpI^)&eOqa60Pez0FM7>h7piE#OS{9{8|b98{J%kw-9QGeAG#_Rf%({AAHvi2X}8 zv4zA{NOliY2|{fFt`T=zxo}PtCeT!l%U;>@IY<|VQpD?d)jNoC$nS!wv;>e|ui>vC z%N3DLZ^0`Koz$0b`#7PEOTBa0n0C$jv`-`Q9C(&(o_)3X&>8SG>u|;U8buz+A-hAK z3}YytVQ9n}g61w#=R(lWfoh!f_J>6XwG!Ircx%Ya#M_LELQc2>9}i8&h=c!0U5BP4 z+Bv)U?aKQ+^+!Y@Z%_%Ynfk>q# zXSSHai#R5!?Q*&qzk1bTzw|F|Io9qdds}y2_LtnksZj6S zs0#y^o);Ko=D;OcP7Y|#;ZomMm8~oc9n+wbo3PWE$1KA!5W{O69XuL=RUED5S^kzND6WnNJ&KfFcQT8LFkP`%s@ykw1tWJXvH!;d_f7*m@afy$nAJuQo1`JMl~#!I8b$;XqL&<%_dfeF zYP?|;BN`FI$3!Pa%E8usQF#0CfhNB-xtigtpq_SwWB&*GSrbDo!7rS0%`b6);z^Ve znJ=QkA7k0Iw8(6RGi5+17=1erI0n&1B*~HBI1_S)5+mE71FD7+IYOH=`1|tesrR8}N!sHd2xx-2w&31->I;+EFy; z&_8(}*-v~sr;DgE^rR<&p>#H0qy!I5LTXMVirjBT_>Vwn)i@y_jJug?^uYzEj(KA} zU7c0KUB%rTm7Xal^?}49`ws(UN5{dF56RWiC7g^VXVZyuc^Bxny*S8uW#bcB!iT3! zB!r$z)z&kBTvu<93SUdLvUAaDltKF2BxxwSxN1+G^}4!;NhYK#&yEx8pexYklO-rm z(?{65H1nFnbJAFx#3y%zM$)_L)q2`e7Sz-TqQ|=4exK5u(Nm@9j3HB(+>?@Gqiz)s z@&nZ@*v_InwZcb4L(SbLsKw}pDQp`5Ts=vBtqQE%KK1RpYl~i^-3?(#;q_pH62WK9itM!eouc`bXe7yVP&Nrq?dFVI* zUL^Fz_eN2?h1L*%Xt#YWmH=3=M~L~0fVt95v@caci>n9Kh%J&d3V?8hG4w!jJfN}% z7_$5=zy(71j~n>y$`1UtrKL-g2S5a2fF!(V115WJJ4{9fw5y$l$(Dl#?YV&1z1u&K z6jZL?5NcGr&_z9EudDu+!vS~ zB;!M1)oGUD8o!}hp`$1<^0<8yhe+lF$gZXTd$()$ucREMa4T8vzT-H?Ce< z5|Z++M+v~S2x|~hgNvu$Ky{IT#0a8qG_IC=-HH!;0Fs0@@hoaaSv#8&lR%Pt0sBvIbyr3CWWv2={WS|T>+C@y0+N*3Fj}lWNPNH{ zha62}5Y)DZiW+^3(D4UfiGs4L6QTipGElAzpDV}#qY`hEV|iG5)v-m_K>3#BFt7nZ zJ{*I&fiC)nW^lrS{m1q3TKRq+8#LpD%$MIR0e&#JD^WpR?!azQGeBaH! zDE4ZKQ$?H2f#o@J=A6MeD`G`-u48NK2FpdF#*LvxgKYM|86;&w&gQDzo~tvo06{76 zc&QPZ^T#f}vV#PHRTR6jSB4h=e~dGN0VOpFb- zM@tS3)T-1TmQ~&YkH9v(Sn@wiW6AoUd~}S!>lQmUO4oyozN zhqYS>S`S}hrud7@+2^U(qIM~Hue@?;{L97{e*6LPV%7L1lrh{T#}#KLuo=NR}`ra0~uiI6n7J5m;j=`MRV zs96t>J0mH*VIp&>n~evK;&ylOJEU6=j?*KsVPi23R9%N>N>NK5Jvq&LEcpm3nd4sFa=VD$7g1F$yPuS3REF) zoyacQ>~@6)CVvW|vBe*jUpdMAAo_L4s8DEC8pQT~B^W61Wv%)r4hCk(VI<%O57iiI zUGqQ1u(X|-DU&4if9rpS;15q({`a`rKne&Tp{YC|m|PS|Z$IRyf`}PozRVbd1f|ft z>RNMK+36qH1QPES2jc9y7t_+y4V{#K_dQwIAr;({mHOuC@TS5;R-n@Bys$gKtbzV- z5$bK;Yr46+yKBDF8Qt)#7k(u!D!TQA`}ejlgS*Ptt@J|Ivkk#l&9XVNqtZHn>r65ytBGmxV9np<02!`dTj7;G4>m&{(qr=`)% z_bQ;WH(M1yqeF$n?9152CEpQtX)u|XbKb&|vU*f_%*eUo`MjgH+y6bWq2Q>Vg4Jlv z&P%P@9My|?}x?u~4?i>-!LwcaSVv)F%?@|FMn zz<`SJGaGCA@?8f9AZrfx_W-S%x)eWRgJK)SMGDqRJ}1iGIqgzae^a{5OVxiRP%KLt z+IU_1?vCWP?MvxbK(xM^k3!gBK=j^nm!6a4=7%XOE>{uvyY5nosgEd`4QF|b6-O+~ z+W1`&)K_~_!RMae{VsBFN!%1`MD3(JQJaC4WRwHbYg{oKnXW3u79 z2gy1HhxjjKXq`TL8Qz9+ZUp@ncaNTh$bw2$MZ9=Ixt(ybOZ4=trD~#M>mzxTvbYSq z0p5gbqo{D)O1OSbZ|Y#J{pVNtQp8?VPFy^}#-JUYfl;e#uIfoM{;`d|qI_!WvC~Co z)4)>)<1=~lUUAER(n*fU*ZOXLhilqYhZwl;_c}MIEoT<7kctyiSy_rY?iHzwHu?7(dx4uab_W$Vm+rqY^qpvFy)%5@ z#^-(F>o5DwkMm>q<2vo5UL*^^ze-&MeVM3$oq}8)3A)+d{S&1b7$$%GZ*C=r4;98WPLdgIYTk0rw7>cUWglBi$lSLLF7Lle0$Hu&*`^r-ZIe1sfD zx1anbVQGa!uTD>J$)wk(X7pmuRU3(5zhxRL%w{^ce}u8;8cQDIg3Q+a%v(T)aS!~O zJ~^L09lkhH_FL_3JS4#6Cj*=eRu~wTU-v(yc}uWq$TdXR!^V6xEwt^ckZ0dZlub?g z)YH>G6g#$gd2B&+RY!w?J#jT>X)bZ7nrGUD)YY^V?^}jB`K4Oqv%Zlv>gU7rz(*ZF}Tt+2h_nK9m zy5!-~*f3n4pS-CGrlx4+{1TxjYFOs*$or$Oa4reeDPL%ahRSP5BD|H1@9R}W!hDiDp!T~ zE-WuicAtnv;zKGedEb1=Ga9?tI~WmZ^yzKx_y2lk-tUCZJkpreWV}2qdT&pVXY-U$ z>fDmne+3AQBzi-qron>ls68g)Di`^=deD-!CawFIxsaXs4CV79bRi(~w}aJaCC z-JHW-My7#j?XM7;Pt@ooPm-XIKQRmmErqOu6XO@?bNWV9;y&hzin@c$I-@j?Bfj#N z*Q|@c5BSXw=J)EX{W5fP!t;hUyeysO-tk-yl*hB%)q;-b?;`AY3ZE%7D`NJhKdKyG+{I zHO${{KOv^qu=V(t+xYmp5%RN&*0na3dh+sZtTim{`FwfA3hskdpib8QfwgcE?ml}% z*zT8g zhwsBV3g=4Ga18-AJ+?|~KQVcmcMM3_I&uLB+}mw<@yzL@sz$rdD6b{oTbrus^e|f7 z9d4o10bWY7JW~d1rnmgb0zs}>Izt1z4y$ZS9-R%HAd3811&bZs-Jm99{e`bX!;(86 z3veT%#TWI?o1VmT&TsVQ_PI0*Tnb3@mG_m_?A84D>!L(fm|3`Ey$=?h!#DTyTSxqm zYTD-%wf+>&+H1ldQgK+}qIV~&mjA1VY_DqdnJJqP81X6m7;AYxb-jL_V4K(*hhYih z*21>qw&-zNnwVH>kc`yw;VE&USwNAj-h* zT>#RQ3;42UQy|!5LFKV@5;K$4-$piU{PBAZn#m(Nz4)Ph@uUY2)p|z3!#n)*_2?NU zjGx!0)9w44JPe<`(=19@ddgEc(AhCm_UWxh1vxTsX~E`a4g+)FiozpG?%KK4M5HuM z*&WL}J5~+QJ#K{Ci_+-nhb8BKdkA>$#P@jD`l3XmbmRF!SPBwSaR=*?dKq-FiVB zG2Xh$=t$jOH2|?deSUD(ax)PIZgOC`Dw!;~pZ(LdXv1;aRDN#i&$|8D%%#h+CzTUU zS1n8EUCM&aZcj*5T5w!GQ-@0d7cSal3;8S-@U&jM8zrSJ%_-m1nt!{E+$wqhx6S?D z7!B7sbVW&pej7El(%Rp2ELDvZ@Fe%pGxS{VwYIV^Rhz3fG(J^>YU?-3h}S^_?@x4) zK7VR1GdCH>?AUG?+p`2aUFmxLOypu@U1UkNV*XdKX~FL-_H4c{>6{T-Or z;|U@j<342159+}EkWb|NH0biJ=Sq!RtbMZm&vj9--Lb=y!&EQqF*&BHTR+qn3$AcQ zBnZ}*Dyv1)t*qJ-IHSX?rZRnClc@9KzB+kZ5K@+Nq)kw}QKJXM&+adzY}?+6^8E%& zxPId}NA4Te0u^uVM43*M*5`sg^-JQ;QeN6VLM-A^um%}+r$us)?M0lJe=DE(Miwka%c(BG zgfCYSUP{{M7Q9|Y%y@YJK=}^K{^gXmL&rCkr}1j|QdL=)H08!Khty||XVO+P8b?!H zwar^6?mx+Ue?=llcR%K@&-PyjryuvCOz@p)3iYL4e*!6KESu2~4~&T7Ac?I@Q?~Si zX4^B~f~>mIll4zNw`;}f7H`0Ubd&qPI@jm>f01z`)TPF*_V5WiC3FljJLv8@C;OH` zT9KDGdxayWV|(qsH5vcuH1E)^ZYp5Md4{k3m0uk`eJ%CZ_%TOGmFzxtt!FU+aqcdG z{}Fp_-WztXzznr}LgK<(?Mv=ADc;G98i7{b*5Uh4YM!KYmOX5|SlRPj zBw_qBYgHecy=W-HT&&!$Y}3G|(&MPi?|h7U&%^X=_rh0tr`$K={Ug^x#h?9^H9zSr z2dHHZ%}=dY6!evgQWu|ZM@%-%IkSF+KIm;bdR7gTjh5XWpZz1z#!DH>+^h;uh?DHQ zTj~+G-(Z2XV{Wc1)6iGmV{Y#06ew_&kpHRq_0Gfa zh;ZH~>w0TXBG7+dX@5R=b=faQ%2xUDA7j~{w@)LsJ1yexPOLtF-<5e&vHkP$n@8Lv zRWP6E4`QaYP>`iO+-v9lSHF+c@0FBZgSTW=h(LnA;Hj}$pOb>$GdK-Kru9w-p3xjX zhl$V1WP5h7)>3($#Fhs7R2yCD+q3k|v&b@;?ei=jqlTOFV__m%-89`+ruPWqb7JhV zaLS%a`-PWgcl5oFiB>Xj1)Wbn1k~<*me-8DY$GN`ENf_KOSwM##A*6r_SREI)%6pq zLW;v5SR0>DrMi4lJY4x4zpZ_G}SSD5O|)=c(*Y#;G+Q!}hXE(aq9lZn{l2F3Ncem7M<%S$dbF z-R-@p?DJD5#UU+3>j(0?u3PXObmHKt1b0)xw|sElmDyJ?pHM#V^>Q};a@jBNFLu24 zhn3PuIC$c+ssUP;$E@gI9U@=03=^6{BqR6E5!0%7b>~X^Ux0D~fU8YjGd%b%NH>NmB zPrJB0S(SO?edWsPs)XyQqn7!fa{X(u-z6I3hYvd_*B{PKHSV0%EwL4DKXXs$M^M#8 z-?c@NHF2YWqlplE6S$2y`(~ijIL+MSTO&RA?z@>VgzUj;fiKB0{51XwXQY^#PWF8uZ8H*nu>(Ksv|@3~E46S4o;6Udk4acS)8xBKQ#vkTtr zPkkxdA=o(==I176HMR(CLPjfGVpb}f`Y!l~t;wyI)vQxfWB14t*j2Yt$CWB|&-D*{ zD@mEr)u!5JCKqE}*2=F2drrXACe4dxMBR#}3G8DZ%(SNs4u{Lsxu>_M#+WuU&h2_ zW*wf&wD~RU^!TIn#OtiJ*>n+c3g+{~T!1OcQfL=8>3g9VZKJ$B!t!EYet8f)`DHWb zr*tz%%e~3=$yPOr}9;2pxH z#alQ>6Mr3jc0%seT2+Z-@5_=s)&I7n)ka=AsLj&%0w3{|Otz&rT>Jk0SL4P zrhZK_)$Mxlo2lM#LNlyF+;!u<-604C%nLGQl?ZAt4cIFHe=>$_K_IU`2wZH(N(sHt2y0H9YVVTfKl_dnzb@>=cGz z4Mq-qRt4it2&!B(2gF7;Xw*oM+0+FkVT`yQm6ZoB`$I3}bxEZzRlH#c+zvLwf()1Swxm@ZL5)4c#VQ)pJpaVO=JG#~{Pw_hNe_0M0iVriT zCb)S38VMaHy~1Ef{H_;;d>goC5+G#LRybWXcni5f?Sp#6f(G=1``a6652p>%(&;H3Z`>;nYpxc zqw2p*{vSnW9uL*}$MNT!IkPdC8Di`+*0ID`vM)0jJ0X=yj3rU3A(cuwGxjCMlBLj) z%57Dtw2z%qm+IcMk0q&8Xj50_=lAFN|D4xzzTfBbdB5q=Ms9gyT)wBXH}0=(zKX?< zHa^ji;sa^R*r5iW({mc%lGSdWS;?FX=F|ytBYM3apchV?NbN2jpe&U{vcJ^MCz>Bo zy%^$;upeKH@1{lts6eI?3*rU$*cAeX2hWQnb=WOXSPY6Zq`MJpmEBhiZ|UA%@-p+DCph=%UHr{yAXqj9%mBMce_+3%uSi+)}@{Dk?1 z|4rh?qx4konc;VQ>>#-uN6qt-F^+kN{3?JEGd=!9v=iQVz+5GCUFRS=a@n+|wL93wr$3+FP zTH_40kHGr~q^SCHbPh)ih3sIyA+VrIvCs`$7!mn{*IYm>Tn5q(0A491bw&905cpw; zF69SYDPX_VrE5?Z+QupiU1URw!SHVZ#NG~;@TR8;#u}nlco#)F-<=})LZCat-mwlxLO^slBE@22cPySnk~3;N zFIOx|+04Z~x+)TXF7%U!?$1N7DPSu#i5V*c;otfnf4EQGQO31v!gClm>d3FHek&Nt z3fjFc!0*HS5T=->&g?L4`<5}+yCc|C??`-?x{j|BmtCxKWPjeOzcTr%<*_HW8A&x* z#yQ$UE~z+TO7aM|)e0BSjS{F`o2Ph;!^>1(Qs$MzRnzc6B7uHPTVW`vjb%gdmcyp< zvkW8>^;U1vh7G;Vt^Pt~8M5k|!FL>AK3?mX4;$D2fX0fjMe}BdCH#?9VU92B9HyF7 z1WvKFteP2O!==vWo=(?`?kMh(fAjvMWkKmZL#G(ervDr+^gLt~qdVmCcYkF%-MNH6 zyXgs3uxtlU>~4;+W*+ViDbd%oNmg}D1CWV>a&d`yyO6gb-iWxaHZd{DDzZF?+D)9k zKSB>1*D98CRQj)LZ^zLwcpza2a`f1gp==ae<2Pz}CowR2QRBJ7-z}bN^uF@ao@3@0 z!+n=*JowYYab2K!pvL8aG@>Ehg}6k)RdL9h$hKklcu>nS`kg(U_OS@v`plSQ_8S8_ zoqG$!rQ|M&Xi~N&Nvx|cLSvRUWHI@-A{xBeHE#$NUs1-+{#!4u>@B^cLiQD_ z<2d#@Kr!(Crr6B7a+VTfnI08#Rw0RhVKk!NRgty{ccrEnB@*BI)jh0D2{-p|eT&kK z9(VRc<_3M-6vq9qL$QG7)li^R$4FcmBT2eP0NVRf+S&4JM%5SvdBnbBrv;bW^j10q zoQS8mQL|g>-!E@O8Kjg%VTH|nLb{yHry{gIXw>6XYoT27og-uIh4Kfx_2$fd%1)$) z-a0?2f@t}&D}>A6Sh62F!3LDk;i0=Py{a1Hc;-}SL70G9@OrN7yO+FAzJ*XghqB+l z8Gip}v7qp^?tgcce)JuiDb=07Ydn7p*CR_s<9Bq9l8G`0uf>#uSjjI>*?=1KdLi>H zJ@fT1DtLooubpnpgdsGTE=insS9Pi{<|-W6`oQOdK5uMH5;{b5OF8w@#Ck`gcC1(* zNGWWK0C3|R1^wF-F2+J>&QKJQ$U6(r1IP#mIJ_pZj}fF6#B@tYYa1NpydDQe4u@T$ zfj$7)8Q{>1VGQ;i!u&E|WW)Y^3jO0D*~8@(@z8MuN@k<40-(M^=x6C24P3Y%IX_cb zl1E@E;zW43zk-84H32ut5<>-J5NE!@;J%N|)lFYbYF@qX8~5zEYsL^{>Ou!oB-;rt zG7boyh+X!HuLyOXdU*hP`2!QUh29=cUb%^;k+Nub-|Xq#(84oM#oEc@&NXX zL+h^WeQw>4*FO}Zq$aP<4Zb*=F`>_pg`y**y$#_r)SV~jIJhb9$YytMYeTIrF2nYE z9^LVv$#`Vl>|he*ip#dO)`78ARjUvpU$e_C9wAe-jnQ@MlZ3g^DtZsDwcu;v@*EC3 zu!Nc*$!mCN6dA8D)H_7GGIKz~Nb12%cJP~cTWYIFCG4s6K2@wyZhCRMW8XyEjtR@% zDPf(1aSVC9)avBK5AkjwXo9Hl(%D|)A-^=oA}(_1p7h^GL{}X zpJh3b?7Mxaa+hs)Vc3zD75dgYNxO>fTx!yeq3aQHK~Q7w{cnEYfVXd@cb@hWP|)Fa ziTee6l+_M>EgO!GKh5o4QR`w=nGa*zOS+8}tkacNsb6Mhk=7Mkr?G=e2W)*Qg`<@f zRwHVQJjINmMC&B#3P>aj$REh(kZ1N~o3L#^)Vauu3J-=ayIdEP-`2A?#VG5odWf_J z{DUZ#5hV}O!tHX$T?}4awmf0k9yF8UcP=KRJFkbXK*uaT5Ji-0mUKBZl~XRX&wkm< z*;%%K=t$XcXpF>sqK3IRerRN60@FWBUDBa9K4Z6TmN0(F?CPYST+gBT_(y48X@~PO z!mW-!6#t2x%21?O2#oJOn|#}4TP88lp)7J6u(pf#9bc9m*a#oLk=|*N_ctsfmOV7P zTBs%eCuw16b8)v>b^yaJoG;b(TYMco`$nmQuvaRRjoo#bd9%pjyt&8zy!ZNoGTSSw zz@DPDkphc>7=h=9Gxf<}dOv90g>)-aG#-azPP5Bk+}=DQ^RwJQS>lX6d7Q$FGV&C>iWs%*-H2ohhtz zqO|5V5^~3wok`Y83PG2kZuuybE9j5zYtU^5kH9zBcWX19~LtBHF9GG>XK|-o}SiKRN-#iBcqOqpUQtl6h)Z*qdryK zT%F!!`%XW`V#YHNR$%yJ2SBy1V&{jH@&R;NH&c72-_(D6v6}m-mz>dIAi{kC&24SiNhZZg6&~xz5Z_|1BqL?% zV;fqj+?so4dLNm!@9(olNGS<+jX*Y|hrn^F+(sx+nx_(4}xx;7r zseb3ZIJdvKek`rT+`Wj1$0hhu>!<1^~1~-=_R?w)7kSkW{%xxeP}up9j~`<*S8bkSYC!4 zsm`;Ye+jP%bQhmBW{zTkPDEP9x6<2Q-Cw{+Zs&HktQRcaja$4+K|70Id#k5x8}j7< zD?v{^bZqv*?LafETyX3-$%NH-&Y2&zh?eSha?J6QjEmU@n}D^YTTu+ zJ!c2!vEOjFy)6{0ENMf~{aENGk-wWL`9xt&P|-MJXuCf;3MAWuP-hB{38g83J1>Cf ziwM<5q=`XbfB*epK!=;ZG1~Y|Ev8E_Vfpg8p*Ru(*_5Ek1h$9yW>j8ZvLFR>YS`&$ z%7_U~I#1>)VOT%N{O%b&_ApIylgwL5mIe{}ca!-xr&Eg13yrJVcp1neGk7CgPQL@s zJWC?nDM$AMtEANJhH3vn+sKc_$cen ztlQZ0o`Fn(w(Qd+HBl+jA9_EE}-&GsZ^~(k-!$-Q)d<{mj`F0A-w(&u&hz7 zpTD(ZV}Dl=ZQV&{jn3l3aYin;RHO*Wfr0X-b0bQ_d?@*_b@eE7Dqhah!8GgR=;0hv zP=oP0nRb4FpMHEV$w1KecIMfU`&-?<23#tTuiBIpvBq%Y+0-jFYczlO53>D}HfhC@ zA|G&3v!0-ga~`g6g)E@=w@5ujTB;u_0Oj3F2`8VjM>Bb z2b!Qhy)+hQb*#?nYO{W#Q#xDW66@4;CK|ED+o1e){rI@}`3U~wJCB8kiQcdIrw*@F zy%nP<(D|~CA)Q)oiA}heS2JOn?9D2Xf?FbX=ko#TwfcX;wh(MKa?YfxNy~=&wk(9jcnGXByqF{; zg00UjQZzj!1aovp7*xKMz2IBb&%aq}W!TKWIk2!&cj59%z+bj~?UK55MO?N&`FVsg zSYGi0%=@Z>&OMLq7A>_v#LS!FnF$@C><#_DIQ;z6QV1v!BnFE&*)-;*d-9Q9de}m* zXJk($*Zf)21-osaYKD#iyB0Fq&8`B3qIHD+RrkRhioVC7>j+W>`1*GpA}0SN*tRqTRzaVY zpb3V9^!85hr)0^b>oKGNY1~IwB7qiITPJ8k0g55P#r1?_X;zzf)e0}7#s2wYLeR(s zo9V?Avh+VHUBHmGzu~Z*Xk_)h)w;*gX+tTDG4^xNpLA9*K~K}o1~KtP(cMyq<&jTN zgL1d+-$iB{zm2cAZDmG0RJ_>MyoSK&s#lu|18XbqFtQG7)gw6@nm(zp3q1B8jL*Ob zGK-&i#OSSIFOSgBJ7C~;G<39P_^p@FpJ|0u3^5j_eZ73K*aG$$6|JKt@mDb0QF@)e zn0M7M5nc8t`+iA(QiI&#ry&bo*`jfk0Aa+SbskRc)YRMLQ*~Y?j8Nk83J~XYUAS1* zQ-AfDmymB=^s(rQ`rm)S-^iD9P{u5oO*LVrJAtaUdxL$PWcIQZx=V0#%qSM6<*B|h0C*#R>H=fMu!1d59C>PrwslJl^ ze#*enzr(0G)55`hN9Wl{Y0Bs~WQ*WRV&T&iusJ(CRM+bAs{%vyTH!H`f_SA4YoF)$ zzcw8e9!RuOJatOTBAZ~Y`z$9wA+k+FQMCS6WNq3LQM;DSBemu5AEY(R;kE;a*i z*3LMdSs182$#jkH%Fog=i-{u_ShaPZWQBNTE#EcZ-K0z67ZCpD*;Y5^@5m2L_*$j# z!=I_vx$Q%HpNeLboKupAoHE!W z_$6@9jC4m1O20*OKex2vybfFf(hVL_e1l@ggfZt-sQ;=mr0^fHwv zSn7=6;?2Cmp?sh2Pu~ecUg(a~p8gG2L`|BNd_aQTe=LB$Oq3;6@{d33RxdWyup85iFP#`9j^p+ zD8LZJH@zhrmH=%i9lv%dgI`jSWraxzA(=)gG**alkR1R*HN14J09 z^S)OA(Jq2H{EUL09oJRINXY0`x}-#+h+#%BA}{0sccyfo3hxb_XU_pP*{B6&Mg)x2 z(Vg%}40_xLts}6a!Y+i(aozqrzIa31=P|i8NdPu@phs)LNrHn5qE)0x7Uu&4@k^^s zk!}q7GIeS2_2)z=(7y{_yaNnw$xozqt(X;kA)k-@CRTQP z+B>ddWM`yfE_ZMI_fF!vsnRjOR+H(H1nCP=#?awW`jZPO7p6!v;4&I~)%Qs9!)ycL zN_@P0k>H_W!W@0G;mhuA`IO|jPj74=dC&HxrIM=23F$eTFiH6cKlVH0zkm$ zJ}D=xTiTWvLI&G|ht%GTPOopO#z?;scVNwG8zi5B!+u>?=&+IO9yff?>nzr6T70%JkF!65l@yqHF)7P>IthWD!3#vvfJ0Bu40Hz0FY*N zApnFEM<^n1y+6A8zc0%|4$^*S-8;Yn{aJtZV-~)Qi%b{Q{^ImSw}rTC-kGoa8t`L- zBn6%UFQ)RSWgg1Y=ASoIaiXFKx9=K03!k&T1++s2t*>tIV_S|jTNQ0Jy2a5U#sG& z_tMNtP=_Y{0N&0HMuu$OpOr@lSovQUnY#R|55i4x@J)#YNhLbn%nk>rdXoL@JNDM_ zqeB_CU5AwE(p);bq!`$-z>B#9S+n5T!dKltIlU*$$>{iM2|hBr;C=T;qsX2`y)G|q z|EP5(=n+IIc_N#jPyOW@3Q9{j3CQ^(n)869?u@74$UF`60K#L}lr;t_J@P4OjcPQ5 zG2MZQ*f1T%zl~2qr@O)hVbSE`u;=HS!iv7q+;^UQGWK=EitPA{yh4uT9g!m)VliyG zq^88Hs8;Uf8A83_khE2EV`Jy>8{8dl_cmvbQlmoDTcJ3&!ND=R_oATq-UusIt(<)l zx{sWs7RLFVPNJ@i)6%JVl0BK~l3(ytdAXNy17THeWs4qrCuhrH>Xk497T3^y3-Q;> z{-d0BSS%`LG3Dnt+w~3x`LZ*w zcLfZ#8YqYf%*zWzP`fK+NG2mA}~8k=GluDR}Rro5z!n zr5C9}mI*ewR@7I~gKue7go`e^2RFgGR>hZgeaN;_Zz1g^sLoFG-ak^os!~%qV098y z8*x4*R{bIv5)1EKKVq50Rb*=2!N__OD~jLLv;>*lYts2RkiDX2{|)1CIb8#{ZZ!$g zae!v?&N`<+;+3|R^Otv`V!|^OLzmL^PU5WK+=|7a2`1-=KWSY;4<$b+PmijwusdwE zdqIEwkkzx2(^39^8QCeRC+icF@a8RL24xsgKE{mRDyY?90Q>i{*++N(NZm7sXh3$e zs`#YkiOdB<+0R`7@g(na$!F`%QHYyX5A}BHUO^4nl`fr$yqPzBGcujoH^H9!mL)8z z70aa0f$vdNdBJ|o@6Ebv>%x3*bczrfy}C3o<5sO_O-qbYr)0BZyD0}`8KY`eTPf^L zP35IxNsA8!T?JU%0X@0|%*%shM`!{WwT^Fb^k#?i(w7pTipJk&3(w-f%UX1GHmVOGYYiODM_EFKN-ClL z+T>S6aP6xv8v-~YyV!3AP0Z6>KPOlXgDqv%2-z;LpN30)*_%EHt{{8(S3~qCYHJjd zu1i!T?&U{3F8&68(NhXbr{l?&6x2X(H6hpNcdS!h#YTCZl*3G@!)Ga)54V}#Qb^!y zN|EMFl7JFQDv2{vh}*DAUyabI^H6$~;Kr8zItF`r7~4|K^2?ixsXk8Wf^IlH>wA8n zocEeojA)O-~{e$F}^y2sIjrO=IkqZ_Sa#G`(r z9WAPFXBW>^w3vV5xe*kT2gt+}D?RV@IP0$5!J_QvnZW397RaKxZbD*}O%wa| z^-#-ftM4N1?08YPopbT6npGwB*l<262S7xa9s$)7wm$iG^rR1VhR-ofI`mA&26!vrV99vG)3ts6+p4XKxKP%TmyiX`K*VkO+ z7l=IE(9-M8N%KOD1v%m#G|8$jv1WxNpxEd1sq>C?wEg`}hiI%Pjszji$WphE-7Np{ z5T&bpKt1e|xl)~{>fr-khTLX8CzSK)lxWJw$SSsb>%oikbG1(mb{IZfvvJ`rhPjTO zttr$58~emd{#;yLx*&m=xqcwizpb%Tc(47$I|TTL=AzobLAcnizxcBP?48eSYs%c= zCHoOe`pL*2vb>J@hqUb*1)5Vx4<9(zm8nZ!y!&-QW(Ojke$WB?A@i8K9nGm8<1C)v!=%rB3|~=r0;=RI|0;i!CV#iQVmMVz)u?pCl93^1!33z z3qZX1 zz*Xq%AUH^%mB48~&m&|~Mi~~af_W1mk~jvoJ!>0iwb zj}Pl&q*Ro%$o*GksDZlom9wbNhsJW{?YV1$W~e{?V~(BH$Gp_u{sm@hkom>)vrL_c z?VgJBcSK!R>;ydy7YjPf7ycnD+KLF}Qv3R*jaT8Tt(6h_*AT~KvKfsdJ@ZdvWS?>^ zV~Cw)o>$&oATV2y<14J@1g6<|U+huqULCfXM)p3XU!@ag75^~L%JMRg)ovb=-pZ(W zNDEb|H!SKZq~|TcIg~p$`>v|I)|`5_->&mkgi2N^>%CQn^&Xr#e;x|?tE0GYHh8k+ zit@MS!CK#$ltxg7&oyS;A{5by;OkgKe8xRr=Kjs8%#M9wy{kIZc7IhStxfKm!ry4R zHxsM8vWm_O>|4&aJqTSvsPB!{vU*!ER89k_COq3LOv3ecIiOLlN)bCvPKGY@ojxqtEl z=@<$tdn--YLV0(3s&mz$1(ly#8F3Z4SAFll-EO2xR*a(cT(*n!5{#}%&0%I#)?|%j ze|p9YE0d&F_cHe9e(*v#zbSK(U8_3%EK{`deSb8F2?sh2=cAqMRwL1q!N%;_2Lt6! zMdXumpT^05OZDlN$@Wa_*Us@&K40r3;TaB0F^v_1e)g?{C?C!c)Y5uMa|Jiz^%P!e zt()oZbHS&9Y>9FOM+5D1*fqKetehluRz8% zMmLEZ*8|_I%vZJSQO)Bn76Jo!Xwi_d9a})_znjQOCO!G(^7#_XvmLfg zhOq0yNS6d4iMV7e23z$hZcy%FHD8p3u!CVf0KN6#R*-}T(zRfVb!5pfh3$5{M9y$9 zluX7X6b>K~j2Nv|fcC1-+y}kWhG6@g48|cxz)LFM2}AQHNunqc27|qaBDK&*xt>s8 zC)mFd`osY*9SF3Tez0+Dv!N#A*w^=%S{-OejXEruQNZmJgt*{lf?B`4>buQiz>ny# zQ#*~fP=o$qNoK9k)eVW;lV0l$?*9-a8auTdlX{pRUfth$CxMLDqhG2`%?ZrjdQgWv++O9L{kqw5Yq29@$N= z`pZOVfw;Y+U86#oM^-qQNEorPRtZ`6i<85ZY_0r$8`$+0#SxDBF3Ux`H3|AbqjXS) zwPh9;epGkjnMQ?owD_)vD@s-_tg?+$&nnnQCOx`0CH48TOIgX8PLGa|{);KZNhj5@ z|KT}e%J(VcRwR707R-bs7O1?LeQ%mT84`v8tBdASv~R?u^(8#chFiQn?a8?D%|`%t zp8@`%AHCSQhDiBG?W(S@A&#_}xIf(+nUUy98j3{P=R^9l)ExZ=xdXSjzpNZJe5#-I zx)`x=sy?wGPKEfuRzH|`=ouJ0{sDimH& zJpXdxBmUuF^@dFi3fG?*Rt5I_+|;0PW9NywV!;{@r#%;yL3KCe)19?GxBgqRkQtv+q{K+ z72%4)%t|asmPCF&g-2B9Gr5xd)d`VG=S}y8n;LtI4;6RkVLJVdV|Mu)rLSrv9Oif* z!kG~Ku7x}|)UZGv7FHwxr;R=5d!)cf-vg3OmU zz3lICnnr)4l#W(_oaDTrz#b-W!r4yK`M~HHt$WY=PS3^RdQVGsOl)r~;LXnzcR}|! z53Jxo*d@}u^QxcyL_Y1p%F(aO6^5wl{^TbeB>KRdxGjMkYZ3yBHk+H^6*z zBCkqz{pjL-#==caU^gKPE*FIk-~FuhM{!2&aJ0ly^QcfoFbtTUGVf)w+Z2euXR*{6 zVi)Et=?3^F%6oPnPLFzt z@d9K5Z#^PqgK<;%wFVT-SJh`H2Lj)FNNc~R5BQ5H*$<>ap6E5QB>!aut|45As_=O; ze#Qu!?c~YcKqBR$HYBMjMOp`r6KG0coWj#0LSL3aMGR>T;%k6t{SD$q{Y&WRF1F+k zLyCp9mqa0Ou>$xz3o4;P*22GTiWZJPR?>fOENbAeby*Q=m;l001;HB)FBB%QEU>Mm zk3PHUvnPeGxz?y2tVNLcKH3DucQO7MvH}*u6AGQ{QdnbGZ+(4azqsR&X>x1KX%H`v zKM>!wx{I)V%A$XzP&N8s+Tc&~im=Dqj5ODj#Nc?#A6dUYWN-6!J>eYBDr$MRQDq7T zHzfZ%x1~Fe&8Dp>iAp4pJeDFK0#Z8HolH38q6b&Tm>#sa>P^JZNay7*{}(fY8V;A} z$78mInyF)`-#We9mldI5SU7Hz!%e0z2&{cxZ!+uY9o}n~5XEwqH zWi}ENtz2gmEKP8Ocb~`rf|jJ!XEbI0Y*M{P7S@i2tB5 zH730-zG(>_2w!~uJZ~o3Psxct14Y6|1n@q?1;{UdcAMJ9^vjWfI^)y^ ziJLs@%;sRJPg;JWU0)o#|D2%S=vZqPyESHZ|5%cO^X<3|A+~i~Y#N3eNj>G&HTz6> zzMI>vqk~Yk9T(=R@*8z8`fTTO6{sXhgV;${ymt*KlHXLy44x8eU_{AeQlmpjY^9<4(xl?RER7U zA{vRbnj#LKUbs!M9{+7S>{PS z1HkS_lh`yO#Dmuo`t>E_2oGQ)hQAol01wy7!W3trYBYzXOQfEyB6z+SEy6)1-h_4x zbX5U%+U%}r0T@b<@sjhNEs>Ci1jB`~jrpaU><>swMJ%$fDV?`=X>f{_1mWRccnP5d z&uBoJ9RSB>?>3fdAP&M2$aXb`?2+5gn&$po-WDl*k0Y9W4;;H+MwSbB&9D26OB9#R z#O>yjR%eC=IpwVL-B%9+i*b;47X{_rcjzy6^BfS)BwfRmO^aM^#?y)(Z*UmMx!SAl zFzK&eww`{ExRH(l*PhMm9Ma64E?JfVxMzqp=7 z^?8kRf!Oo6`)<9@j`NnU0@yVZ4)ain%9`%(42Nu`AT%}YD+IcLq#(3k*7V}n4rfsH zYljzuUMuq%&vYRAQXTq6Wud(dMeI{@z8k*bj{w#$i6s*f0%Z4m=P?LOqZk=sBR#(s_RR{K4>Tpo%KLT zbhMrz(pF}*FU?5waz?2%yl0IsLJvkBdGLyn=}f|WZ4S83h29*4UzS3j3znFspRH-A z65LG}TRzgjOc(-%ODVh^`Dzl&j@jr+I3o4)Cv47bLphB7(flp%^l|oRKK{Vrrclq} zr>^n0xU|cS!<62j{QmH}EQP2|HVHMt;rKjExDFy447470mpejIzF{7X6$$IMU?fTu^<@0D&tI)0TlV9Qh^{Q)=INf$?AHjesXh!GQBhPs!~bE8X>Z(Y&m&VZ3awwHh6KT6J0rqoo%V* z`z0?ijA)kU7-D9}a%n%Tc0=P(ib%aYeUmMrO-goOR~~eoMtIyP;E*mD@C{N&DCxt? zIrmucRR{NG2b5=m1;K5S-$FSw5timQwFWbo;Z+tuz0YfwC(NwnkmY;|@MrCfFUr3j zIyosM3C)vkj2yqAdfnj0^nIiB*+Gqx0U2{t&Yd};+9Ez*^P^GEv(G7R!eaPM#4i1g zRXP2u%?7L6xNdU%`E63<_b|_2MEe>>gm%onY03IqRSitdWXgxM?F3WvfJMi@+N>@T zlT@y!1W;3k`i48I(y2J(ah2?S__KWTp zXJJg86xj~WUUIoHGvb8n?aEYCOqFQsqk9a%Ix5t<@ryB<|CAtF5*qGpl@Z9sU_C6I zB&2&0q!M(6FoyDcKJ+=!ZK>3Q+Jcwyr~l}&vVp-bO&wT7VyQwe^_Lzu&(M%Z9Pr2r ziO@o(c6*~gi-2kkT+GP=Khp^9dFUvEop%UK&!*ue_I6ym1~9*xHV`Y-MVx%ud)Yg{ zlOh}FUpkUz1y|9f?c&QyxMoiJQvw^aEfNEb&ScbYc97J_jSO9pV8X4OBK2-kEHB?g zH0x=haQTsBPaRfF!^Gb5+;1=StPgdqWgg90CqKi)MUag2P3xlNE_2hub1}~PE$WYH zS&#g-?V)iqYR%>;-RLu=)Lx6ZgEdF9l}D-7%%VVZVjxiXAg5#?WW~Uu4a2v5yNM;O z#6kESSpg@K?_Xxx<+-|SunrdC7$M7QzO54%ExfYjZxrL3mG3dH=2%Zwtn0WmFLc;9 z+`o!=Kx!S9!_vWxljZLaUiew%mz3C%!_`YQ1mOWMu9xmN*p||#CP}nj+5cD5d`V5{ zp1+tKrOzISeQ~?yaOsr^%ppfs=DG?!pB+O-dv3O`Tflj%c$%6Ica*iFDe;4^NbSnU z!*e-K1{Z?X_-YJ#QnTXi9sVq_#NL-<9mvt@ZQOp{n$h+2b!}OMWdU-Uplb#Hlx=&A zZd=jF@}e_PvO=*J2{%c|*H|C>y-7Ma;q`v`bY7uW7Uw)6xp_*sLPJZnY7Fhie3QT( z@Tv^F1O!Wbi{(v{+d9)hThnHK;Ev%NWpJ4%dY7_nx5DGEagUANtX13A$D;cN2QT}1 zh{cQ^QMcn|hhB-g`wC4%$r2fv6|+^vd(WD=n(j|{&A#DFg@#Yo9lx1PKEJtY`NMg1 zuhr+~qALxz-sSkdz-{U#q(l%cA_3J@G;}UPjd-i4gY?dn{nzkX1~}Ld`RAnzg@p}9 zAL2Ges>%X-Ac>|3^@&I`@0I<4B_|yvQZI;wgHN!$wE;(cEl#%6m5}aw#L;6hv))yi z7}6kf?e+(3l5Ail`fcG$D)3dFrutf0Ia61peJj3LTwEycO+58gX8V`P`xiR9>D%X_ zQh*)?Up&zg0_*A$7M_f5f{PvC8&nC)i1!VWPzXE)aKjfpOq3FYV1$c^PVDqgk|(Dp z+bkjGC#3>#R7oH1B%>OT4gvDshU-6}CY!ckRxt*j zC5(1V-~zyYnA*~=IO{OP)yXbFiK6E>t_PpcS?9RvVGzma)4(o^$cXXYtex8(r;?&X z@`2^b!JHlH^L{ZiCAF6mr7LRXAIe2_s0!EV$Etg`_<}fJe>m=|{%(JkK$J>T{yg(S zU82do3aQv<)z=4p3+eZW&X?C$@;xJ7ndmK68I4sdY3kl0|G=xmhALLMXECu+s~o?z z!7Ya*=Mj#|E7=tW7OyCdV-)%wy5OrE-r7D$TWgcRi$m3&HLmFMtlyPm9#C8Qj&vJ% znRPmdTC~3v3@-LqP2bC+g)S)-FITghkBD94Id)4okxgC=hWk<=b515d)tb|2&-JNM z9^2`7V+7UmU2d&0&j{cSgsj^<%`aU2rPIWUdgj^`ev{VXUIp$q9lwShWv6B%XEWpf z9oc0&Fm~Gfxllw0Js0g0cAGtP|3KX!2PPOHO{^pbnmQh4>n-j)0O+T})5i7mlB~gq zp?Woiou{U$XT35lYc%-J!ftc{FZ0;|M9`LA46Gx`AOYN=4L(5Z0QtgTJQze2%leE_ zTV&VYvWrx5-A<4vFt9o_(i{6W`()6N+*(d1IU{xG#F28OrV2#qNgUv*PO|hDg^g!H z<^()j?lKP#4*q3RWei zjjO^;Ru_z7&;u1u$d5;(-*vE7FS(AHIQx=dnzR%7>}~yWfTN%5Ee2bF5B$D6u6xAe zd~4w}ud(O~Zu+QkE#~eAzN!}6+(k9w$=H^OfZbm&tgbBio_{Wj*)F#NB7M%_6%q@YaP+JhB_B1Pk>{%9tYClDS{f+1~CU)~* z1VJpLAG20=;kI*f9@(ofy?ou3vGQ2q=bm2}{p5f|`yU;SNX4##=x)V=`5TAj{l~6P z;e7PMhcc$kU+xwt+0 zU1CbT<`zo5_KA-k4ewQUC3LY?bnH;OahvN@upDzl8XV)A*Gd^sdM1-wz;OCv$e8it zynMV|c4~mQV9e)9dQddga`@L!Z)SS6u|-KtFC%N{3QQ{%EUj;lLR-t)r|;e9J2B5` zD*AXD5fiyBB<~nU!VNJZ9DTr1>yfrr*)9K9(7gJ2ag8Uij{)?5od} zAwFKsN#0CaO9&h!rU(u1vGx7E7{3Y1KFw!Ihe9hp)&Q}>_&G(>kl^gcmH*&-M@4Q*aIq5Bg`6{PhG(Y zT4W>yO#q-Mrg@HLCh5&RBmtry3Xzr$h7=N!=IH2+l`0b;59J?+k()gRbnCs>1sua- z8YC+!kUeF9nL8aWlk+m)*0n%i?6O$)VBy%+S$F59Cd;h*1G0w5TqicgLk*a}IMkaRc7{VD6^S*muu z>VvEBh92e!HxcuXRy$V{`1HP(LM6;~)tM&c0otcR{ALbuf9VxmtZZD`Am_o`%C&B& zL(~+~j`VnIw?}e2MuUw0b?Xc~vVZHq*A=a%inxh(jB|S2%@N;>y7yDRihl|A_V#Yr zf@FvIRE{5gCp?a?EgE{#^k62hJyhY~LQRRzHt4SyAwI%0m?vb6TuvH1Y4u|Yry5^L z+7D|r*8&M@`rf3i_!&zNwKLo-$2;4FeKWoFI5>WPOFLJKJtjO7o8Z9LXa93Cwa{<3 zlV#lD`5_~D-oc?#C&qalMmyoixl;E1-41uU_Rl%b3VHJuV(F=PM~hW0jiWC>ENq~u z+lNahXKmJD`igoY*-JMH3x#c-Ugo-vJAK@;D|{4$3iSNvWIsLbe4%*j1_QPJs4(bM ztwX)!ZRpn&WCMx(j}_AfNiVFE#|@Ak(RV0%9W}Y_uhg#e4sTW3v~~AmGxJV|-60FB zzY>{%E368=XZ4!SRkzFS_t1(jr5Fqg6gLs`spF=zv6RnH1Lamw@;~5au78EDF#FS1 zuGSf>VISOSs`&S}RT!UE!oP8BPO56@;`oUWs`a8J2?MxecQpy9SHA2sDog5?{k2(e z!1P(O;9Rbbi6}9q>0#!u*`~#xNgM_EKHN>1PLQ^PH zbTHThbP#DbsO#Y2LQ27>a>!hS3WSnp5$YYH^#Z~S0^3=`Bm>?ES7N0s>ENOqg_>Cg zJWc02kQ;}g!^K+vW-V20PkW#g6FlB}Gwr8(Ozr-JoUk+fIa@Y-5OLYwNan!!~w z#1d6sgP~pClAWpe2#sl6*K`w};qdg5XDXBmNP_I-!trppn6{a7+U7<`VM|-A^0V3M zX5oD9@FC?hIziQwi4pLFU=!s7)bmX>)K~Jrt0gjZFTu-%=jcTPFVB9NSjxFgQdTx; zCnl_M(RO+-kY_;(yg!n`+>(%;UIJk~^gou)E2@dFZ`*s4kVb$cw9rH7J@g_%=p6w; zgQA39L=A|FijWX`Zz`S86gyx;MGYMU=_>Y6MgORX4He<#S>HD&b2MvCX3d^Gzx%$f zCo z5vgb~m~@$Ueo3^fCNeeBWXO!v{-dZ_(o3$xL}n|?HCVDve*LWJns&B%QYXn}e7%(; za7KvbF;G36;yYSa{c-+bs!~qMw&4ta*KM_{O=r@_N^O~))&63?doJZaOSggv z)ljP)j49tI>eOK6%U^Gu`592eTb6Vm+`M=>7Gg4%Z;~X8Q!d+>h{66y{JCrgc#1&gWh??s0mK9GcrpYj zu^1BE8dOmkhj72d7{Ql+1R(zr0l|WHvSzH)Gffn!6L>@N z&abCL0S%(E{ukaOz&ZfGXiM1>DTIP*T$On4=t3OK%o>i{k6_}>bv3hDY`o1}ahWd) zqcGV*Jd7ZVo(jeMUiMLG|Mll-x>#Cw(wTo zx^!D?VOl7b{7T*g;?Y+Vv6b1zBw-}qD&1nbHVVLl$-=?{2^ZUW@Y+@$?SpH#kgez) zKEcLGbUo#|NVHJ-5`kWFTxzB4L(Jur@l?1S&7CAxcle4O&)qfcNITKOve?k^fua-# zO)!Xzj%Mpo&(O)#gBbODax<2Luz`xyd;B zFp)s%AP=p6Ln%AaoCe`EXn7W0Lr_*%^t#$`>SpLI_)O0dIE)`X8Rf&mX9h9OO9^m_FcMiIzRg zx!5C^Q|qmRCEZli9BL#rrh0p^bT$4Q7XLTH0=r_(X<+New<EG0QZQMcYr2r_ z5`qR`W_VsBg6Rm3m=oCPH+5BJ-ovQWX|&KmL}nw5T7l-K1Er2NH9V1xOYRXk#gm7~ zG#(k|PUh(&%H%NoTv(WPB!)ufNYT(N7o|LKBHS4UvlND8iXiwI+)F!D@RYoGA)_r2 zf7-pybnTZgLR}tBjr_Jq@t)(nIS6CY)(M5FK#Vm6annQg02;T7jnaMzW4~%&`wyHE z;Lq;0y}a7`=IEYzCQCnbSj^Ch`9Th2SGAjQb_viEwO@hOJ_?F>V7hTwb>J@9(3_akO#6_(TPl+ zi>oc(r7xna6c1_4tKWUrg20Y23S0(Ks~>+cPgcrZ5kru=?32@@H;Zy0R@D zBF5n1WG{ZClTL#$(%np}^d!4R(bR*uo25v;*?Oeqk^^lqj9qUR<{MJrwkWjwz$MoQ z%0{AD7Xnt1e%{4TyR_DHR^7y0u1gS!Mr%QyKuc*c1l-xRTA4tWMxGNoma!F{P;(v= z_^4)Y!AH3;zox%+HtD;{2`^Hpq@e}X=FEiFwt4BUy-~Lk7ZXsyn)$q3yMd(~AZyvC zKy>6znOo94H3*=7A2y*CZz8B*${5Zg$oB&ni))iDK&yt^UCx&wxNa>S5*vFl;C5sV zfLY<$DQeP+r(XuGVugQfn+l>r59+sXmKs6M&IhXgeBVx^`>+zHsw^kMP(m2ytm>U08tK6}dGj6qa==cSow0p@#Ao|$ z?I@YGgA^z=%Q@*o#lQs5Zw5w1DUqpxFM5kwdem5jPjTCobU6yVIOpS;*c5epTK44z zGt_U=-}eqWw!PIoLsv^|)uiCLsEH$VJ2OO~s>m1aWyq47^7*U%Ji?15t2d$F`d%^A zda*I72&IkLCs1C_w`Er)IO=2k64Om_f5^@ZT^{1D*WNh&xG+mcr6Zov;yePgaxkK6 zhoT_z;hG@ni$~*XvAO(FT(-3(5J+i_WaR$FtafD;Gm)YP70T7@*8$Q7e#i;xm> zNXYg)lkIH&fkHINODr*0dW92kUbF{%<_jQG{m>M~z;RCj)q0guTb1u{_fjUIppX~Z zy~`_!;?nI_=G8Mpxo&_lYw&U+?~3hgHB)>W;<^ugyYrU2gsoJcpofh>@r@J{+--xh zt&Z~mE!E0xF>)6Jr(kc>D&i@XJS=)3v(W3OWw@pM{Q@_{F)&f1bI(8MaD*M%IomT; zjd`bC;za703nAy4qsu~DyL>42RJeh*MNUx2A3U)3AAA&RRfhepZj#@7RR7NJqn=+b zrm<+`N7HC8hz?1~n^wH!Pi0ofm68o`yVSgOfTqL)+Mgx6O~i&QS^&dq&CQJ6di?d> zQ*r6(tazBKSE2h@XPL9Kd6(#lvx`-%gX5oOuFZVJN`#z`;5AI-zib{fKtmgV73w(R zS;xR@ZAnhkqDuJO4l8VKP~-CXPg+ESyIPXpH(P7Trk#iJ`FG(jQEof{rGDplu*EnK z?W0nV2W=-_kaP+G%QE4jRZ~Ty#vrN6x0bK-_NCy$hrg(vtanT47?tE4qzj&04x%#1 zj5as<(~Z``fjIEjZVdi+qx0P#QrGdsmS5n%y!`KPhvY6ee8;`E-5OZCZ#&-Slav>Z1}r;(wv2i>!?t!kWx5qjO{rQ~H#AX8*J zgH=6xT}T>3PK%^_ZlSjlsybn!S*iXRNCx8&mWA{V{XXj$dzxMCPRY0yc`T@xX*yrD z6cpx`&M3qWWrvf6U4oW& zIyMQWa~uglg_-8FIK}v&*laI})E4BYE(?=Sza|qq|*cr z;|p+Qzea349%i;BxVyWK$K<7Rs9o6&S>6aDudJ7^>>L)HetkUV2Fen=ym-QKF}Kj} zXpzpo+=c;^pk4OEEE%3ps_hIdl8zCX%`!qjVUHMZgf)5>H4sHx`r+3A~Nf|PBbS!Sh!nQ8mIvk(& zjDzNEawO5?f?s`vI2^$4Ddc7NX6+uIrNjSnRt-*Qa(kp*Y2ofvEVb&nJ>ysJcc z$N#$_U=G)H9)0wf)Q+#8ejX&qaF;@?AOiOOa%lM!ESqDzTQ^vwdRt&v+S=oc@;|>S zj-2|jzzG|sraEiu%33(aiOto}J)B%_3(tVk$;bAlMsze=l>OCX=F06)NAo0ap%+h{ zZJyoe{*vVBI+0QT?upi|ui=$0dP=LGcTU*;K{s#rvUK?VGg;6=*}P<~woE*$@-y1C z_3X;;`Z%`H9-;JGfw-yx(a(|sF8aE~hn0DbXUotEq;XuepEL1MpYRB`RJGvb=mI6p zMHcv|NmAp>5(;gQs|dfCp-GW`xyFf-w;@9>_21tZ$hy0)yvGQ0xinNcQ&fNWankI) z<5;zWi>~b?t>6$Bec?t2g%Q{@#FKk&k!pyyeh(j)d1?v_J8s{=uN#8wxk~BZWjs@i<8ib2`k4BrPa3a& z-?^rE;by+vgpq_6@r=g-g-o?)A4@K;>aG-9^FAWtN;Xaku%?xLBKle1HuBk4*3H}h5sU~?}^=!u3Qld{A2G+bf`@nwoBCR#PcIWaAt@E*#>(8kTJAUr_X`5{&ACc9^8@;WdC0nC7uu$b1sXvwBxwOChKc4=6{uZjLoPM**4ga{@bRMao?$yB3WJ@<0sB-&7wG> zJaXUL(rgXkHDBaVlsNzFb&301i*|5IZ(6jjvg0j>k(}u9N7|7eiq3so_$X@uTizAt zXJBY@;d1e*<3A1a6he;3eR{I^{)VA2QjC6jUfoql%TZNifLZxB%k^F2Lzmr?``tg< z?6TM2mB;QMkj~25^Yr2P=%?`L@NcifM3}!y-I{{G6-ZitJag;1?pv)Ltk!|}Ctq~B zDP1wXkGmfV!C#qQXO}%uk!XAk7b5F8Nle~cnM_jbznt3gfD)s+1c;6g@2a}EtjE4R zDUUG}SG~z>45_yn>~9rP4b&AgOgQx`p*9XneZe#!gUp%LH5i z>T7^iqwNRqn!FlgOjdRDS5o= z^=2uv#=x2L`uELM7&TYmGw754D&<&#O=%1H;$oQorrx$kA4O3 z+MD(FW;7jZj$N+u6Ypml%2fVw3v_$ZT=r2&`QyO=pFT#w(>%Y4SH{I8m-N}4g#DIo zbAw@3n2U~~>@i7P>i(&ieWyL55!a<+D~})F_&75}(dH`)#bGA3$^O~l(Fd7OYJ*hj zbk53m?hLK_-kYcQaGhZne+3R4k<$h#IsMjf`{tG2&n1^Z(}UINoVWM~CAUY{#zTW2 zZD$(^zr-yN=f+Ak2cLx92>NL-^cQNh`t49}!s+<+U@o++tfBs5OJ=f%qte}#iP+zl zZbY#9tCZ^mtUoQZbj3ce2<&dUTu^zr^7`io(`BiAUy~2PO?gdm1%i`vwDgK9hDEtm@1r}s*<)3!lZh8Muha)FJb_>KXjsi6UbC9~d#O%H#Q6N**s!<1 zGvvSeJIpZtyuCJ2E}?g^>xqBv+oC-cuYc?qdem@xcBuHs%+%w#uenkYDkKSEVR>3( znKQPy%uHmbJOuYE>CdC&2+uZwf`)elZfNA>SX^w@56HzuMg zi*Ekc&sfNIzAD7rCU45td%LyipZL3soBK~)KKyz0Pz3JOws$LecB21Pn#L@}5MwK% zE@1b(yni7B5_Huv-=E?tG9K}lI_8)76Lm^rEy>0zZYiGYt9~XIr`d5eMrl(6-?@9E zyueWg?+3=P*UrL}yKS!}KhZlJB;jP5H?NOBTieAhax$|-Q%*-cAIpu9_w;dk_C8}< zP{h;ag~FQ4kDhH;jA-0h)?>cIE8&K9AJ*E`KVx@*#@MH^z4v5Ix^B=`CAY7aybrw9 z{S*Cn+i&ApbxaX>!ph2!P~ z8Nc6W0?+x6Wl;GE`8UaOeKrR(WQiWr{-<~PV^K(i-}7B<&Y}Dn(R(k&7VRge7Vbu` zu1-xQnCoS@d4Ap=nv~$as`JYFVaX__kJjbzQGL){SAFYZVazV8Mj3DXmK144$jIoZo)gQ{xwxXn+Jm#VjI2M+S3sJ2(Q+vVO|?QYqNw$;-|v%qf9SnG_l99`;Z@`Q*5P;bupNo?1JIRgsT$#X zAPG?|VapB;5p9V$vuKvlocw6Y5#2Lu|E+82{ASY`1_$)-hA+IDF8B5-l1^6cP4eFT z{HU3zj7og$fu!%P9VzMb{Yr24nw9T;RI|L;uj(jTa3JpDHMxV6Z)y|2Jbw97>Qn>g zyL*CeVCmjdCB7$OTjNG|zDd6P2z`Mzo^n&O-)>J z(|=%;<+OO`cd3g=aXND?q`*_z@F4E)G_4LR{uu*)AV86@+W1nrC)$~xxYQ@B%&2& zbn?>6?ECBu{A00OY7Qr2P|>SRhMb58^5S1lp7SPQ{=Eq+?R{X#$<6w9r=m(gqNK=H z?0c*Aq*Q%&W4#(tAB#>|Df%)FD8I-wJRQC8w@TLPZDN>&Yt`akmZQ$I9V0HG3OhfB zcrbn|G_|&y&K`9!D3bUYuWzIl($KBdrrI1GIAe0&V_|;(+SN=jjh%V$JGNo+@qD8H z(6**+v57+SZ{8Vy{8t?yXgRRUK|QS0=!?p!`%S-UzX+Gp>cS!O-%+0a=7v)Ph&y)1 zCsxKh-(DEGvN$AQE_6Inayhi?q3q&ESM^lIlEAjxwsjf`KN~wVzKpHEd}n2Ta?S>y z6k3-j^Y(Dy;DJfwKYzO0j?0_8I=U3P;a=@;s2k~a&{O!>yM4^Et4vtQe7cTna?Y7k zmkTT3C*BfpMB5$qWnam?H1#P}ZLx#<|2HgKCkNqMA8ZkgH8K~;F_G;AC+T5vCi*M( za9w!%$kVZd4CW13`AL_sF1QMgNwhHAs@hw>eg9UB_@q@%J&I^fwYb!0Ps`*=ns*jY zk$$>o@GYLD)nsZOA@tdDC*Um2kMPCG+%3FIk9YUe;PhUm@Ulc(O5T8|ZD{(wXn5Hq z+w(;$qHM}+KJ*H!Az1aMHwHG8#>l$Vj2LXWmO0O-_%g0|tE6+TDR)t>cGy|KC{L2M z%#+UwVHH8$i_C=g-iz z9f3DY(o50r%E?OtF^2te=eg)7H;>U*7Szq8{Z8_CO6@WBWuGkeyfjA7%hM!whhI`) zT#`4|P1yJL#yoR>ItX>wjU!tBUX`q6TwnQy0zH^!#3md5ccun2_b&H2^(s(j1(P=J0J`W8J1|Cs zWblHHv&r0*z$Crj3cmn@_%&HPe69cX+F{YnUXR-l+Nu4nV8YCY;KdW*=e+sRs5b~G z9H|c@xs|fUVQwscS615poQw9S5n#;|oB%ArwZP+Bn&eurW(g%wfUhDn4VeSpS2d5? zK-@G0JDz>8VVi ze_38PgbGI!)!**`t1BXjr4jZ9+j=#!j@y})Nx;r946m{9K^@XwJmFA4I&o?SpL<4g znO)D*s;Sti(r~jLMNS;N(>0bgyaMr@iu)oxx>&B6ww%)((_OUNtBp6MwB6(tC|Mzn z8ivmTPBD4#L4w7t)WiBrGZy894SZ>&7acS#qZeF0(>%3f)k}<=C1qlHCR4Ab5F;QF z$(v^i4a~Ne;iRUOhcbs+>9(ThCJ^|ZFxWR0f3^U$H}agFyrF$sGoz{ud4yLoCphNZ zeyG#OC4`sFO?Zg_(fMSZHW}*6lEnr;2~_#Z2-2cE(2i>ET~ha7zbOCkji%`Flg z+ac8(@Pr-ue5W=}DkX;R>8nxNG^cxu|NWHMW8rP~g!$|wJ}w~qy+BW@YqV~^jq6QS z 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 w4GXR7kE%8qJX$U77WU$3 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�Ra+apo{xkm9U*2q! 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

    RsEr4^%|I|I#U_kYT5T+s8 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

    H-fg@{Pq}PZL(^bE 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%0DLWM5qWIjtRu>M5vc*SsYiYnDW=TGRpXGDZv$P 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

  • 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

    wDpcl$PQ)S!q+Z5>FGAR5yaX7b8VGpJ-mMVL> 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 z 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%0A_7l%c+*u6_tD4R2@0^tg7#Pr2H+bjFEBS+ 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

    - public IEnumerable> GetAllUsableSkins() + public IList> GetAllUsableSkins() { - var results = new List>(); + var skins = new List>(); - Realm.Run(r => + Realm.Run(realm => { - var all = r.All() - .Where(s => !s.DeletePending) - .OrderBy(s => s.Name, StringComparer.OrdinalIgnoreCase) - .ToArray(); - - // add defaults in fixed order (assumes they exist in the DB) - results.Add(all.Single(s => s.ID == SkinInfo.ARGON_SKIN).ToLive(Realm)); - results.Add(all.Single(s => s.ID == SkinInfo.ARGON_PRO_SKIN).ToLive(Realm)); - results.Add(all.Single(s => s.ID == SkinInfo.TRIANGLES_SKIN).ToLive(Realm)); - results.Add(all.Single(s => s.ID == SkinInfo.CLASSIC_SKIN).ToLive(Realm)); - results.Add(all.Single(s => s.ID == SkinInfo.RETRO_SKIN).ToLive(Realm)); - - // random entry (unmanaged/live-unrelated) - results.Add(new SkinInfo - { - ID = SkinInfo.RANDOM_SKIN, - Name = "" - }.ToLiveUnmanaged()); - - // append remaining non-protected skins (keeping the ordering from the realm query) - foreach (var s in all.Where(s => !s.Protected)) - results.Add(s.ToLive(Realm)); + skins.Add(realm.Find(SkinInfo.ARGON_SKIN).ToLive(Realm)); + skins.Add(realm.Find(SkinInfo.ARGON_PRO_SKIN).ToLive(Realm)); + skins.Add(realm.Find(SkinInfo.TRIANGLES_SKIN).ToLive(Realm)); + skins.Add(realm.Find(SkinInfo.CLASSIC_SKIN).ToLive(Realm)); + skins.Add(realm.Find(SkinInfo.RETRO_SKIN).ToLive(Realm)); + + skins.Add(random_skin_info); + + var userSkins = realm.All() + .Where(s => !s.DeletePending && !s.Protected) + .OrderBy(s => s.Name, StringComparer.OrdinalIgnoreCase) + .AsEnumerable() + .Select(s => s.ToLive(Realm)); + + foreach (var s in userSkins.Where(s => !s.Value.Protected)) + skins.Add(s); }); - return results; + return skins; } public void SelectRandomSkin() @@ -196,52 +197,39 @@ public void SelectRandomSkin() }); } - /// - /// Cycle through skins. - /// Uses the skin selection UI ordering but skips the "Random Skin" entry. - /// - /// Optionally cycle in reverse. - private void cycleSkins(bool reverse = false) + private void cycleSkins(int direction) { + Debug.Assert(direction != 0); + // don't change selection if current skin is externally disabled/mounted for editing. if (CurrentSkinInfo.Disabled) return; - var availableSkins = GetAllUsableSkins().ToArray(); + var skins = GetAllUsableSkins(); - int currentIndex = Array.FindIndex(availableSkins, s => s.ID == CurrentSkinInfo.Value.ID); + int i = skins.IndexOf(CurrentSkinInfo.Value); // If the current skin isn't selectable anymore, start from the top. - if (currentIndex == -1) - currentIndex = 0; - - int desiredIndex = currentIndex; + if (i < 0 && direction < 0) + i = 0; do { - if (!reverse) - desiredIndex = (desiredIndex + 1) % availableSkins.Length; - else - desiredIndex = (desiredIndex - 1 + availableSkins.Length) % availableSkins.Length; - } while (availableSkins[desiredIndex].ID == SkinInfo.RANDOM_SKIN); - - Realm.Run(r => - { - var chosenSkin = r.Find(availableSkins[desiredIndex].ID); + i = (i + direction + skins.Count) % skins.Count; + } while (skins[i].ID == SkinInfo.RANDOM_SKIN); - CurrentSkinInfo.Value = chosenSkin.ToLive(Realm); - }); + CurrentSkinInfo.Value = skins[i]; } /// /// Cycle one skin backward. /// - public void SelectPreviousSkin() => cycleSkins(reverse: true); + public void SelectPreviousSkin() => cycleSkins(-1); /// /// Cycle one skin forward. /// - public void SelectNextSkin() => cycleSkins(); + public void SelectNextSkin() => cycleSkins(1); /// bool IsDisabled { get; } + + /// + /// The height of the main part of the control (when not expanded). + /// This is used to attach external elements. + /// + float MainDrawHeight { get; } } } diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index c45d76e331aa..cb839b92e796 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -136,6 +136,7 @@ private void load(OverlayColourProvider colourProvider, AudioManager audioManage { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.Y, Action = RestoreDefaults, }, new Container diff --git a/osu.Game/Overlays/Settings/SettingsItemV2.cs b/osu.Game/Overlays/Settings/SettingsItemV2.cs index 78f3b0eb0aab..0a3830334e2d 100644 --- a/osu.Game/Overlays/Settings/SettingsItemV2.cs +++ b/osu.Game/Overlays/Settings/SettingsItemV2.cs @@ -85,12 +85,6 @@ protected override void LoadComplete() controlDefault.BindValueChanged(_ => updateDefaultState()); controlEnabled.BindValueChanged(_ => updateDefaultState(), true); FinishTransforms(true); - - ScheduleAfterChildren(() => - { - revertButton.RelativeSizeAxes = Axes.None; - revertButton.Height = ((Drawable)Control).DrawHeight; - }); } private void updateDefaultState() @@ -108,6 +102,8 @@ protected override void Update() base.Update(); controlDefault.Value = Control.IsDefault; controlEnabled.Value = !Control.IsDisabled; + + revertButton.Height = Control.MainDrawHeight; } #region ISettingsItem diff --git a/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs b/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs index f828287d52b6..fc8b49265688 100644 --- a/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs +++ b/osu.Game/Overlays/Settings/SettingsRevertToDefaultButton.cs @@ -30,7 +30,6 @@ public partial class SettingsRevertToDefaultButton : OsuClickableContainer public SettingsRevertToDefaultButton() { - RelativeSizeAxes = Axes.Y; Width = WIDTH; } From 892e34b1f82db28ce8c4bad138d9fc628fdee81e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 4 Feb 2026 14:37:35 +0900 Subject: [PATCH 624/836] Add automation to copy labels from issue when PR is opened https://github.com/marketplace/actions/copy-issue-labels --- .github/workflows/pull-request-copy-labels.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/workflows/pull-request-copy-labels.yml diff --git a/.github/workflows/pull-request-copy-labels.yml b/.github/workflows/pull-request-copy-labels.yml new file mode 100644 index 000000000000..b1309b29c59a --- /dev/null +++ b/.github/workflows/pull-request-copy-labels.yml @@ -0,0 +1,13 @@ +on: + pull_request: + types: [opened] + +jobs: + copy-labels: + runs-on: ubuntu-latest + name: Copy labels from linked issues + steps: + - name: copy-labels + uses: michalvankodev/copy-issue-labels@v1.3.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} From 1230da33a5529e71550db8190f9e2ef6e82743d3 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 5 Feb 2026 01:22:36 +0900 Subject: [PATCH 625/836] Implement sorting and display styles for currently online users (#33649) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Adds sorting and display styles. - Saves sort/display modes to the config. - Improves performance, especially on the 2nd+ time opening the overlay. https://github.com/user-attachments/assets/e32b50d0-58a1-4eef-b18c-988fb497e545 --- Coming off some recent feedback in https://github.com/ppy/osu/discussions/33426#discussioncomment-13431275, I decided to take a bit of a detour and get a little bit more functionality in. Sorting by rank, although it should technically work, doesn't work right now. This is because the osu!web API doesn't return user rank on `/user/` lookups - it's only returned for the friends request. I'm leaving this open as a discussion topic. - We can make osu!web return the rank and osu! will require no further changes to work correctly, or - We can try to implement additional paths through `osu-server-spectator` which would blow this PR out of proportion and is best left for a task of its own. For simplicity, I've re-implemented this display mostly as its own component for now, lifting code from `FriendDisplay` which was recently overhauled. These implementations should eventually be combined somehow but that's dependent on: 1. Figuring out the styling - friends can display offline users for which it makes no sense to display the "spectate" button. 2. Figuring out how to handle the different users/presence pathways. It's mostly a code complexity issue. --------- Co-authored-by: Dean Herbert Co-authored-by: Bartłomiej Dach --- .../Online/TestSceneCurrentlyOnlineDisplay.cs | 119 ++++---- .../Visual/Online/TestSceneOnlineUserPanel.cs | 111 ++++++++ .../UserInterface/TestSceneUserListToolbar.cs | 2 +- osu.Game/Configuration/OsuConfigManager.cs | 7 + osu.Game/Database/MemoryCachingComponent.cs | 9 + .../CurrentlyOnline/CurrentlyOnlineDisplay.cs | 158 +++++++++++ .../CurrentlyOnline/OnlineUserGridPanel.cs | 62 +++++ .../CurrentlyOnline/OnlineUserListPanel.cs | 67 +++++ .../CurrentlyOnline/OnlineUserPanel.cs | 51 ++++ .../CurrentlyOnline/RealtimeUserList.cs | 258 ++++++++++++++++++ .../Dashboard/CurrentlyOnlineDisplay.cs | 239 ---------------- .../Dashboard/Friends/FriendDisplay.cs | 2 +- .../Dashboard/Friends/UserListToolbar.cs | 36 ++- osu.Game/Overlays/DashboardOverlay.cs | 1 + .../OverlayPanelDisplayStyleControl.cs | 12 +- osu.Game/Users/UserBrickPanel.cs | 8 +- 16 files changed, 831 insertions(+), 311 deletions(-) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneOnlineUserPanel.cs create mode 100644 osu.Game/Overlays/Dashboard/CurrentlyOnline/CurrentlyOnlineDisplay.cs create mode 100644 osu.Game/Overlays/Dashboard/CurrentlyOnline/OnlineUserGridPanel.cs create mode 100644 osu.Game/Overlays/Dashboard/CurrentlyOnline/OnlineUserListPanel.cs create mode 100644 osu.Game/Overlays/Dashboard/CurrentlyOnline/OnlineUserPanel.cs create mode 100644 osu.Game/Overlays/Dashboard/CurrentlyOnline/RealtimeUserList.cs delete mode 100644 osu.Game/Overlays/Dashboard/CurrentlyOnlineDisplay.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyOnlineDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyOnlineDisplay.cs index a1d0d408114d..a151d22a9afc 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyOnlineDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyOnlineDisplay.cs @@ -3,18 +3,16 @@ using System; using System.Linq; -using System.Threading; -using System.Threading.Tasks; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Testing; -using osu.Game.Database; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Metadata; using osu.Game.Online.Spectator; using osu.Game.Overlays; -using osu.Game.Overlays.Dashboard; -using osu.Game.Screens.OnlinePlay.Match.Components; +using osu.Game.Overlays.Dashboard.CurrentlyOnline; using osu.Game.Tests.Visual.Metadata; using osu.Game.Tests.Visual.Spectator; using osu.Game.Users; @@ -23,6 +21,26 @@ namespace osu.Game.Tests.Visual.Online { public partial class TestSceneCurrentlyOnlineDisplay : OsuTestScene { + private static readonly string[] usernames = + { + "fieryrage", + "Kerensa", + "MillhioreF", + "Player01", + "smoogipoo", + "Ephemeral", + "BTMC", + "Cilvery", + "m980", + "HappyStick", + "LittleEndu", + "frenzibyte", + "Zallius", + "BanchoBot", + "rocketminer210", + "pishifat" + }; + private readonly APIUser streamingUser = new APIUser { Id = 2, Username = "Test user" }; private TestSpectatorClient spectatorClient = null!; @@ -36,11 +54,34 @@ public void SetUpSteps() { spectatorClient = new TestSpectatorClient(); metadataClient = new TestMetadataClient(); - var lookupCache = new TestUserLookupCache(); + + ((DummyAPIAccess)API).HandleRequest = req => + { + switch (req) + { + case LookupUsersRequest lookupUsersRequest: + var users = lookupUsersRequest.UserIds.Select(id => + { + // tests against failed lookups + if (id == 13) + return null; + + return new APIUser + { + Id = id, + Username = usernames[id % usernames.Length], + }; + }).ToList(); + lookupUsersRequest.TriggerSuccess(new GetUsersResponse { Users = users }); + return true; + + default: + return false; + } + }; Children = new Drawable[] { - lookupCache, spectatorClient, metadataClient, new DependencyProvidingContainer @@ -50,13 +91,9 @@ public void SetUpSteps() { (typeof(SpectatorClient), spectatorClient), (typeof(MetadataClient), metadataClient), - (typeof(UserLookupCache), lookupCache), (typeof(OverlayColourProvider), new OverlayColourProvider(OverlayColourScheme.Purple)), }, - Child = currentlyOnline = new CurrentlyOnlineDisplay - { - RelativeSizeAxes = Axes.Both, - } + Child = currentlyOnline = new CurrentlyOnlineDisplay() }, }; }); @@ -69,17 +106,18 @@ public void TestBasicDisplay() AddStep("Begin watching user presence", () => token = metadataClient.BeginWatchingUserPresence()); AddStep("Add online user", () => metadataClient.UserPresenceUpdated(streamingUser.Id, new UserPresence { Status = UserStatus.Online, Activity = new UserActivity.ChoosingBeatmap() })); - AddUntilStep("Panel loaded", () => currentlyOnline.ChildrenOfType().FirstOrDefault()?.User.Id == 2); - AddAssert("Spectate button disabled", () => currentlyOnline.ChildrenOfType().First().Enabled.Value, () => Is.False); + AddUntilStep("Panel loaded", () => currentlyOnline.ChildrenOfType().FirstOrDefault()?.User.Id == 2); + AddAssert("Spectate button disabled", () => currentlyOnline.ChildrenOfType().First().CanSpectate.Value, () => Is.False); AddStep("User began playing", () => metadataClient.UserPresenceUpdated(streamingUser.Id, new UserPresence { Status = UserStatus.Online, Activity = new UserActivity.InSoloGame() })); - AddAssert("Spectate button enabled", () => currentlyOnline.ChildrenOfType().First().Enabled.Value, () => Is.True); + AddAssert("Spectate button enabled", () => currentlyOnline.ChildrenOfType().First().CanSpectate.Value, () => Is.True); - AddStep("User finished playing", () => metadataClient.UserPresenceUpdated(streamingUser.Id, new UserPresence { Status = UserStatus.Online, Activity = new UserActivity.ChoosingBeatmap() })); - AddAssert("Spectate button disabled", () => currentlyOnline.ChildrenOfType().First().Enabled.Value, () => Is.False); + AddStep("User finished playing", + () => metadataClient.UserPresenceUpdated(streamingUser.Id, new UserPresence { Status = UserStatus.Online, Activity = new UserActivity.ChoosingBeatmap() })); + AddAssert("Spectate button disabled", () => currentlyOnline.ChildrenOfType().First().CanSpectate.Value, () => Is.False); AddStep("Remove playing user", () => metadataClient.UserPresenceUpdated(streamingUser.Id, null)); - AddUntilStep("Panel no longer present", () => !currentlyOnline.ChildrenOfType().Any()); + AddUntilStep("Panel no longer present", () => !currentlyOnline.ChildrenOfType().Any()); AddStep("End watching user presence", () => token.Dispose()); } @@ -90,49 +128,14 @@ public void TestUserWasPlayingBeforeWatchingUserPresence() AddStep("Begin watching user presence", () => token = metadataClient.BeginWatchingUserPresence()); AddStep("Add online user", () => metadataClient.UserPresenceUpdated(streamingUser.Id, new UserPresence { Status = UserStatus.Online, Activity = new UserActivity.InSoloGame() })); - AddUntilStep("Panel loaded", () => currentlyOnline.ChildrenOfType().FirstOrDefault()?.User.Id == streamingUser.Id); - AddAssert("Spectate button enabled", () => currentlyOnline.ChildrenOfType().First().Enabled.Value, () => Is.True); + AddUntilStep("Panel loaded", () => currentlyOnline.ChildrenOfType().FirstOrDefault()?.User.Id == streamingUser.Id); + AddAssert("Spectate button enabled", () => currentlyOnline.ChildrenOfType().First().CanSpectate.Value, () => Is.True); - AddStep("User finished playing", () => metadataClient.UserPresenceUpdated(streamingUser.Id, new UserPresence { Status = UserStatus.Online, Activity = new UserActivity.ChoosingBeatmap() })); - AddAssert("Spectate button disabled", () => currentlyOnline.ChildrenOfType().First().Enabled.Value, () => Is.False); + AddStep("User finished playing", + () => metadataClient.UserPresenceUpdated(streamingUser.Id, new UserPresence { Status = UserStatus.Online, Activity = new UserActivity.ChoosingBeatmap() })); + AddAssert("Spectate button disabled", () => currentlyOnline.ChildrenOfType().First().CanSpectate.Value, () => Is.False); AddStep("Remove playing user", () => metadataClient.UserPresenceUpdated(streamingUser.Id, null)); AddStep("End watching user presence", () => token.Dispose()); } - - internal partial class TestUserLookupCache : UserLookupCache - { - private static readonly string[] usernames = - { - "fieryrage", - "Kerensa", - "MillhioreF", - "Player01", - "smoogipoo", - "Ephemeral", - "BTMC", - "Cilvery", - "m980", - "HappyStick", - "LittleEndu", - "frenzibyte", - "Zallius", - "BanchoBot", - "rocketminer210", - "pishifat" - }; - - protected override Task ComputeValueAsync(int lookup, CancellationToken token = default) - { - // tests against failed lookups - if (lookup == 13) - return Task.FromResult(null); - - return Task.FromResult(new APIUser - { - Id = lookup, - Username = usernames[lookup % usernames.Length], - }); - } - } } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineUserPanel.cs new file mode 100644 index 000000000000..4d81443f29c4 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineUserPanel.cs @@ -0,0 +1,111 @@ +// 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 NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Metadata; +using osu.Game.Overlays; +using osu.Game.Overlays.Dashboard.CurrentlyOnline; +using osu.Game.Rulesets; +using osu.Game.Tests.Visual.Metadata; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Tests.Visual.Online +{ + [TestFixture] + public partial class TestSceneOnlineUserPanel : OsuTestScene + { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + + [Resolved] + private IRulesetStore rulesetStore { get; set; } = null!; + + private TestMetadataClient metadataClient = null!; + private OnlineUserListPanel panel = null!; + + [SetUp] + public void SetUp() => Schedule(() => + { + Child = new DependencyProvidingContainer + { + RelativeSizeAxes = Axes.Both, + CachedDependencies = + [ + (typeof(MetadataClient), metadataClient = new TestMetadataClient()) + ], + Children = new Drawable[] + { + metadataClient, + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Spacing = new Vector2(10f), + Children = new Drawable[] + { + new OnlineUserGridPanel(new APIUser + { + Username = @"flyte", + Id = 3103765, + CountryCode = CountryCode.JP, + CoverUrl = @"https://assets.ppy.sh/user-cover-presets/1/df28696b58541a9e67f6755918951d542d93bdf1da41720fcca2fd2c1ea8cf51.jpeg", + WasRecentlyOnline = true + }), + new OnlineUserGridPanel(new APIUser + { + Username = @"peppy", + Id = 2, + CountryCode = CountryCode.AU, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/8195163/4a8e2ad5a02a2642b631438cfa6c6bd7e2f9db289be881cb27df18331f64144c.jpeg", + IsSupporter = true, + SupportLevel = 3, + }), + new OnlineUserListPanel(new APIUser + { + Username = @"flyte", + Id = 3103765, + CountryCode = CountryCode.JP, + CoverUrl = @"https://assets.ppy.sh/user-cover-presets/1/df28696b58541a9e67f6755918951d542d93bdf1da41720fcca2fd2c1ea8cf51.jpeg", + WasRecentlyOnline = true + }), + panel = new OnlineUserListPanel(new APIUser + { + Username = @"peppy", + Id = 2, + CountryCode = CountryCode.AU, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/8195163/4a8e2ad5a02a2642b631438cfa6c6bd7e2f9db289be881cb27df18331f64144c.jpeg", + LastVisit = DateTimeOffset.Now + }), + } + } + } + }; + + metadataClient.BeginWatchingUserPresence(); + }); + + [Test] + public void TestUserActivity() + { + AddStep("idle", () => setPresence(UserStatus.Online, null)); + AddStep("in game", () => setPresence(UserStatus.Online, new UserActivity.InSoloGame(new BeatmapInfo(), rulesetStore.GetRuleset(0)!))); + } + + private void setPresence(UserStatus status, UserActivity? activity, int? userId = null) + { + if (status == UserStatus.Offline) + metadataClient.UserPresenceUpdated(userId ?? panel.User.OnlineID, null); + else + metadataClient.UserPresenceUpdated(userId ?? panel.User.OnlineID, new UserPresence { Status = status, Activity = activity }); + } + } +} diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs index a373fbbc51f0..a54844099dfa 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs @@ -22,7 +22,7 @@ public TestSceneUserListToolbar() OsuSpriteText sort; OsuSpriteText displayStyle; - Add(toolbar = new UserListToolbar + Add(toolbar = new UserListToolbar(true) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index cdccf7eb6107..97bc53388dae 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -15,6 +15,7 @@ using osu.Game.Input.Bindings; using osu.Game.Localisation; using osu.Game.Overlays; +using osu.Game.Overlays.Dashboard.Friends; using osu.Game.Overlays.Mods.Input; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Edit.Compose.Components; @@ -234,6 +235,9 @@ protected override void InitialiseDefaults() // intentionally uses `DateTime?` and not `DateTimeOffset?` because the latter fails due to `DateTimeOffset` not implementing `IConvertible` SetDefault(OsuSetting.LastOnlineTagsPopulation, (DateTime?)null); + + SetDefault(OsuSetting.DashboardSortMode, UserSortCriteria.LastVisit); + SetDefault(OsuSetting.DashboardDisplayStyle, OverlayPanelDisplayStyle.Card); } protected override bool CheckLookupContainsPrivateInformation(OsuSetting lookup) @@ -486,5 +490,8 @@ public enum OsuSetting LastOnlineTagsPopulation, AutomaticallyAdjustBeatmapOffset, + + DashboardSortMode, + DashboardDisplayStyle, } } diff --git a/osu.Game/Database/MemoryCachingComponent.cs b/osu.Game/Database/MemoryCachingComponent.cs index a91c60827933..eadfddbbc9d3 100644 --- a/osu.Game/Database/MemoryCachingComponent.cs +++ b/osu.Game/Database/MemoryCachingComponent.cs @@ -76,6 +76,15 @@ protected void Invalidate(Func matchKeyPredicate) statistics.Value.Usage = cache.Count; } + /// + /// Completely purge the cache. + /// + public virtual void Clear() + { + cache.Clear(); + statistics.Value.Usage = 0; + } + protected bool CheckExists(TLookup lookup, [MaybeNullWhen(false)] out TValue value) => cache.TryGetValue(lookup, out value); diff --git a/osu.Game/Overlays/Dashboard/CurrentlyOnline/CurrentlyOnlineDisplay.cs b/osu.Game/Overlays/Dashboard/CurrentlyOnline/CurrentlyOnlineDisplay.cs new file mode 100644 index 000000000000..4dbe775d9b6e --- /dev/null +++ b/osu.Game/Overlays/Dashboard/CurrentlyOnline/CurrentlyOnlineDisplay.cs @@ -0,0 +1,158 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using System.Threading; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Dashboard.Friends; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Overlays.Dashboard.CurrentlyOnline +{ + public partial class CurrentlyOnlineDisplay : CompositeDrawable + { + private Box background = null!; + private UserListToolbar userListToolbar = null!; + private Container listContainer = null!; + private LoadingLayer loading = null!; + private BasicSearchTextBox searchTextBox = null!; + + private CancellationTokenSource? listLoadCancellation; + + public CurrentlyOnlineDisplay() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + InternalChildren = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Margin = new MarginPadding { Bottom = 20 }, + Children = new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding + { + Horizontal = 40, + Vertical = 20 + }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.Absolute, 50), + new Dimension(GridSizeMode.AutoSize), + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new[] + { + searchTextBox = new BasicSearchTextBox + { + RelativeSizeAxes = Axes.X, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Height = 40, + ReleaseFocusOnCommit = false, + HoldFocus = true, + PlaceholderText = HomeStrings.SearchPlaceholder, + }, + Empty(), + userListToolbar = new UserListToolbar(false) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + }, + }, + }, + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + listContainer = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING } + }, + loading = new LoadingLayer(true) + } + } + } + } + }; + + background.Colour = colourProvider.Background4; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + userListToolbar.DisplayStyle.BindValueChanged(_ => reloadList(), true); + } + + private void reloadList() + { + listLoadCancellation?.Cancel(); + var cancellationSource = listLoadCancellation = new CancellationTokenSource(); + + RealtimeUserList? currentList = listContainer.SingleOrDefault(); + RealtimeUserList newList = new RealtimeUserList(userListToolbar.DisplayStyle.Value) + { + SortCriteria = { BindTarget = userListToolbar.SortCriteria }, + SearchText = { BindTarget = searchTextBox.Current } + }; + + loading.Show(); + LoadComponentAsync(newList, finishLoad, cancellationSource.Token); + + void finishLoad(RealtimeUserList list) + { + loading.Hide(); + + if (currentList != null) + { + currentList.FadeOut(250, Easing.OutQuint).Expire(); + currentList.Delay(25).Schedule(() => currentList.BypassAutoSizeAxes = Axes.Y); + } + + listContainer.Add(newList); + newList.FadeInFromZero(250, Easing.OutQuint); + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + listLoadCancellation?.Cancel(); + listLoadCancellation?.Dispose(); + } + } +} diff --git a/osu.Game/Overlays/Dashboard/CurrentlyOnline/OnlineUserGridPanel.cs b/osu.Game/Overlays/Dashboard/CurrentlyOnline/OnlineUserGridPanel.cs new file mode 100644 index 000000000000..3bc173990aba --- /dev/null +++ b/osu.Game/Overlays/Dashboard/CurrentlyOnline/OnlineUserGridPanel.cs @@ -0,0 +1,62 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Screens.OnlinePlay.Match.Components; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Overlays.Dashboard.CurrentlyOnline +{ + internal partial class OnlineUserGridPanel : OnlineUserPanel + { + public OnlineUserGridPanel(APIUser user) + : base(user) + { + Size = new Vector2(290, 162); + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new DelayedLoadUnloadWrapper(() => + { + var content = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(2), + Children = new Drawable[] + { + new UserGridPanel(User) + { + RelativeSizeAxes = Axes.X, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre + }, + new PurpleRoundedButton + { + RelativeSizeAxes = Axes.X, + Text = "Spectate", + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Action = BeginSpectating, + Enabled = { BindTarget = CanSpectate }, + } + } + }; + + content.OnLoadComplete += _ => content.FadeInFromZero(800, Easing.OutQuint); + + return content; + }, 40, 5000) + { + RelativeSizeAxes = Axes.Both, + }; + } + } +} diff --git a/osu.Game/Overlays/Dashboard/CurrentlyOnline/OnlineUserListPanel.cs b/osu.Game/Overlays/Dashboard/CurrentlyOnline/OnlineUserListPanel.cs new file mode 100644 index 000000000000..8c76f2fbc31d --- /dev/null +++ b/osu.Game/Overlays/Dashboard/CurrentlyOnline/OnlineUserListPanel.cs @@ -0,0 +1,67 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Screens.OnlinePlay.Match.Components; +using osu.Game.Users; + +namespace osu.Game.Overlays.Dashboard.CurrentlyOnline +{ + public partial class OnlineUserListPanel : OnlineUserPanel + { + public OnlineUserListPanel(APIUser user) + : base(user) + { + RelativeSizeAxes = Axes.X; + Height = 40; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new DelayedLoadUnloadWrapper(() => + { + var content = new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize) + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] + { + new UserListPanel(User), + new PurpleRoundedButton + { + Width = 100, + Text = "Spectate", + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Action = BeginSpectating, + Enabled = { BindTarget = CanSpectate }, + } + } + } + }; + + content.OnLoadComplete += _ => content.FadeInFromZero(800, Easing.OutQuint); + + return content; + }, 40, 5000) + { + RelativeSizeAxes = Axes.Both, + }; + } + } +} diff --git a/osu.Game/Overlays/Dashboard/CurrentlyOnline/OnlineUserPanel.cs b/osu.Game/Overlays/Dashboard/CurrentlyOnline/OnlineUserPanel.cs new file mode 100644 index 000000000000..50278fc60df0 --- /dev/null +++ b/osu.Game/Overlays/Dashboard/CurrentlyOnline/OnlineUserPanel.cs @@ -0,0 +1,51 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Framework.Screens; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Screens; +using osu.Game.Screens.Play; + +namespace osu.Game.Overlays.Dashboard.CurrentlyOnline +{ + public abstract partial class OnlineUserPanel : CompositeDrawable, IFilterable + { + public readonly APIUser User; + + public readonly Bindable CanSpectate = new Bindable(); + + [Resolved] + private IPerformFromScreenRunner? performer { get; set; } + + protected OnlineUserPanel(APIUser user) + { + User = user; + FilterTerms = new LocalisableString[] { User.Username }; + } + + protected void BeginSpectating() + { + performer?.PerformFromScreen(s => s.Push(new SoloSpectatorScreen(User))); + } + + public IEnumerable FilterTerms { get; } + + public bool FilteringActive { set; get; } + + public bool MatchingFilter + { + set + { + if (value) + Show(); + else + Hide(); + } + } + } +} diff --git a/osu.Game/Overlays/Dashboard/CurrentlyOnline/RealtimeUserList.cs b/osu.Game/Overlays/Dashboard/CurrentlyOnline/RealtimeUserList.cs new file mode 100644 index 000000000000..de1f3d2f137a --- /dev/null +++ b/osu.Game/Overlays/Dashboard/CurrentlyOnline/RealtimeUserList.cs @@ -0,0 +1,258 @@ +// 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.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Database; +using osu.Game.Extensions; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Metadata; +using osu.Game.Overlays.Dashboard.Friends; +using osu.Game.Rulesets; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Overlays.Dashboard.CurrentlyOnline +{ + internal partial class RealtimeUserList : CompositeDrawable + { + public readonly IBindable SortCriteria = new Bindable(); + public readonly IBindable SearchText = new Bindable(); + + private readonly IBindableDictionary onlineUserPresences = new BindableDictionary(); + private readonly Dictionary userPanels = new Dictionary(); + private readonly OverlayPanelDisplayStyle style; + + private OnlineUserSearchContainer searchContainer = null!; + + [Resolved] + private MetadataClient metadataClient { get; set; } = null!; + + [Cached(typeof(UserLookupCache))] // not used at the moment. + private UserWithRankLookupCache userCache { get; set; } = new UserWithRankLookupCache(); + + public RealtimeUserList(OverlayPanelDisplayStyle style) + { + this.style = style; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader] + private void load() + { + AddInternal(userCache); + + InternalChild = searchContainer = new OnlineUserSearchContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(style == OverlayPanelDisplayStyle.Card ? 10 : 3), + SortCriteria = { BindTarget = SortCriteria }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + onlineUserPresences.BindTo(metadataClient.UserPresences); + onlineUserPresences.BindCollectionChanged(onUserPresenceUpdated, true); + + SearchText.BindValueChanged(onSearchTextChanged, true); + + Scheduler.AddDelayed(updateUsers, 2000, true); + } + + private void onSearchTextChanged(ValueChangedEvent search) + { + searchContainer.SearchTerm = search.NewValue; + } + + private void onUserPresenceUpdated(object? sender, NotifyDictionaryChangedEventArgs e) + { + switch (e.Action) + { + case NotifyDictionaryChangedAction.Replace: + foreach ((int userId, var presence) in e.NewItems!) + { + if (userPanels.TryGetValue(userId, out var userPanel)) + updateUserSpectateState(presence, userPanel); + } + + break; + + case NotifyDictionaryChangedAction.Add: + pendingUsers.AddRange(e.NewItems!.Select(i => i.Key)); + + break; + + case NotifyDictionaryChangedAction.Remove: + foreach ((int userId, _) in e.OldItems!) + { + if (userPanels.Remove(userId, out var userPanel)) + userPanel.Expire(); + + pendingUsers.Remove(userId); + } + + break; + } + } + + private readonly HashSet pendingUsers = new HashSet(); + + protected override void Update() + { + base.Update(); + + // ReSharper disable once InconsistentlySynchronizedField + if (pendingUsers.Count > 100) + updateUsers(); + } + + private void updateUsers() + { + if (pendingUsers.Count == 0) + return; + + // partitioning here is just to break up the requests. + // without this, the intitial request will take seconds to minutes. + const int partition_size = 50; + + for (int i = 0; i <= pendingUsers.Count / partition_size; i++) + { + int[] partitionedUsers = pendingUsers.Skip(i * partition_size).Take(partition_size).ToArray(); + + userCache.GetUsersAsync(partitionedUsers).ContinueWith(task => Schedule(() => + { + var users = task.GetResultSafely(); + + foreach (APIUser? user in users) + { + if (user == null) + continue; + + var presence = metadataClient.GetPresence(user.Id); + + if (presence == null) + continue; + + if (userPanels.TryGetValue(user.Id, out _)) + return; + + // This is quite dodgy – it affects the global `UserLookupCache`. + // + // but it's the best we can do for now. + // this should probaly be returned by server-spectator not osu-web. + user.LastVisit = DateTimeOffset.Now; + + var panel = createUserPanel(user); + updateUserSpectateState(presence.Value, panel); + searchContainer.Add(userPanels[user.Id] = panel); + } + })); + } + + pendingUsers.Clear(); + } + + private static void updateUserSpectateState(UserPresence presence, OnlineUserPanel userPanel) + { + switch (presence.Activity) + { + default: + userPanel.CanSpectate.Value = false; + break; + + case UserActivity.InSoloGame: + case UserActivity.InMultiplayerGame: + case UserActivity.InPlaylistGame: + userPanel.CanSpectate.Value = true; + break; + } + } + + private OnlineUserPanel createUserPanel(APIUser user) + { + switch (style) + { + default: + case OverlayPanelDisplayStyle.Card: + return new OnlineUserGridPanel(user) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre + }; + + case OverlayPanelDisplayStyle.List: + return new OnlineUserListPanel(user); + } + } + + private partial class OnlineUserSearchContainer : SearchContainer + { + public readonly IBindable SortCriteria = new Bindable(); + + protected override void LoadComplete() + { + base.LoadComplete(); + SortCriteria.BindValueChanged(_ => InvalidateLayout(), true); + } + + public override IEnumerable FlowingChildren + { + get + { + IEnumerable panels = base.FlowingChildren.OfType(); + + switch (SortCriteria.Value) + { + default: + case UserSortCriteria.LastVisit: + // Todo: Last visit time is not currently updated according to realtime user presence. + return panels.OrderByDescending(panel => panel.User.LastVisit).ThenBy(panel => panel.User.Id); + + case UserSortCriteria.Rank: + // Todo: Rank is not currently displayed in the panels. Additionally the sort mode kind of breaks if you change ruleset with this overlay open. + return panels.OrderByDescending(panel => panel.User.Rank?.Rank != null).ThenBy(panel => panel.User.Rank?.Rank ?? 0); + + case UserSortCriteria.Username: + return panels.OrderBy(panel => panel.User.Username); + } + } + } + } + + /// + /// This is implemented local to avoid invalidating the full cache on ruleset change at a global `UserLookupCache` level. + /// We should probably do better than this (server-spectator sending the rank data instead? something else?). + /// + private partial class UserWithRankLookupCache : UserLookupCache + { + [Resolved] + private IBindable ruleset { get; set; } = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + ruleset.BindValueChanged(ruleset => + { + if (ruleset.OldValue?.OnlineID != ruleset.NewValue?.OnlineID) + Clear(); + }); + } + + protected override LookupUsersRequest CreateRequest(IEnumerable ids) => new LookupUsersRequest(ids.ToArray(), ruleset.Value?.OnlineID >= 0 ? ruleset.Value.OnlineID : null); + } + } +} diff --git a/osu.Game/Overlays/Dashboard/CurrentlyOnlineDisplay.cs b/osu.Game/Overlays/Dashboard/CurrentlyOnlineDisplay.cs deleted file mode 100644 index 02fe681492e4..000000000000 --- a/osu.Game/Overlays/Dashboard/CurrentlyOnlineDisplay.cs +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using System.Diagnostics; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Framework.Screens; -using osu.Game.Database; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Online.Metadata; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Screens; -using osu.Game.Screens.OnlinePlay.Match.Components; -using osu.Game.Screens.Play; -using osu.Game.Users; -using osuTK; - -namespace osu.Game.Overlays.Dashboard -{ - internal partial class CurrentlyOnlineDisplay : CompositeDrawable - { - private const float search_textbox_height = 40; - private const float padding = 10; - - private readonly IBindableDictionary onlineUserPresences = new BindableDictionary(); - private readonly Dictionary userPanels = new Dictionary(); - - private SearchContainer userFlow = null!; - private BasicSearchTextBox searchTextBox = null!; - - [Resolved] - private MetadataClient metadataClient { get; set; } = null!; - - [Resolved] - private UserLookupCache users { get; set; } = null!; - - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - - InternalChildren = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.X, - Height = padding * 2 + search_textbox_height, - Colour = colourProvider.Background4, - }, - new Container - { - RelativeSizeAxes = Axes.X, - Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING, Vertical = padding }, - Child = searchTextBox = new BasicSearchTextBox - { - RelativeSizeAxes = Axes.X, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Height = search_textbox_height, - ReleaseFocusOnCommit = false, - HoldFocus = true, - PlaceholderText = HomeStrings.SearchPlaceholder, - }, - }, - userFlow = new SearchContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(10), - Padding = new MarginPadding - { - Top = padding * 3 + search_textbox_height, - Bottom = padding, - Right = padding, - Left = padding, - }, - }, - }; - - searchTextBox.Current.ValueChanged += text => userFlow.SearchTerm = text.NewValue; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - onlineUserPresences.BindTo(metadataClient.UserPresences); - onlineUserPresences.BindCollectionChanged(onUserPresenceUpdated, true); - } - - protected override void OnFocus(FocusEvent e) - { - base.OnFocus(e); - - searchTextBox.TakeFocus(); - } - - private void onUserPresenceUpdated(object? sender, NotifyDictionaryChangedEventArgs e) => Schedule(() => - { - switch (e.Action) - { - case NotifyDictionaryChangedAction.Add: - Debug.Assert(e.NewItems != null); - - foreach (var kvp in e.NewItems) - { - int userId = kvp.Key; - - users.GetUserAsync(userId).ContinueWith(task => - { - if (task.GetResultSafely() is APIUser user) - Schedule(() => userFlow.Add(userPanels[userId] = createUserPanel(user))); - }); - } - - break; - - case NotifyDictionaryChangedAction.Remove: - Debug.Assert(e.OldItems != null); - - foreach (var kvp in e.OldItems) - { - int userId = kvp.Key; - if (userPanels.Remove(userId, out var userPanel)) - userPanel.Expire(); - } - - break; - } - }); - - private OnlineUserPanel createUserPanel(APIUser user) => - new OnlineUserPanel(user).With(panel => - { - panel.Anchor = Anchor.TopCentre; - panel.Origin = Anchor.TopCentre; - }); - - public partial class OnlineUserPanel : CompositeDrawable, IFilterable - { - public readonly APIUser User; - - private PurpleRoundedButton spectateButton = null!; - - public IEnumerable FilterTerms { get; } - - [Resolved] - private IPerformFromScreenRunner? performer { get; set; } - - [Resolved] - private MetadataClient? metadataClient { get; set; } - - public bool FilteringActive { set; get; } - - public bool MatchingFilter - { - set - { - if (value) - Show(); - else - Hide(); - } - } - - public OnlineUserPanel(APIUser user) - { - User = user; - - FilterTerms = new LocalisableString[] { User.Username }; - - AutoSizeAxes = Axes.Both; - } - - protected override void Update() - { - base.Update(); - - // TODO: we probably don't want to do this every frame. - var activity = metadataClient?.GetPresence(User.Id)?.Activity; - - switch (activity) - { - default: - spectateButton.Enabled.Value = false; - break; - - case UserActivity.InSoloGame: - case UserActivity.InMultiplayerGame: - case UserActivity.InPlaylistGame: - case UserActivity.PlayingDailyChallenge: - spectateButton.Enabled.Value = true; - break; - } - } - - [BackgroundDependencyLoader] - private void load() - { - InternalChildren = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(2), - Width = 290, - Children = new Drawable[] - { - new UserGridPanel(User) - { - RelativeSizeAxes = Axes.X, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre - }, - spectateButton = new PurpleRoundedButton - { - RelativeSizeAxes = Axes.X, - Text = "Spectate", - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Action = () => performer?.PerformFromScreen(s => s.Push(new SoloSpectatorScreen(User))), - } - } - }, - }; - } - } - } -} diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs index 56cf9fc6690e..0f5ae4d44f12 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs @@ -124,7 +124,7 @@ private void load(OverlayColourProvider colourProvider) PlaceholderText = HomeStrings.SearchPlaceholder, }, Empty(), - userListToolbar = new UserListToolbar + userListToolbar = new UserListToolbar(true) { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, diff --git a/osu.Game/Overlays/Dashboard/Friends/UserListToolbar.cs b/osu.Game/Overlays/Dashboard/Friends/UserListToolbar.cs index 3f31ceee1a4a..62ba89495c88 100644 --- a/osu.Game/Overlays/Dashboard/Friends/UserListToolbar.cs +++ b/osu.Game/Overlays/Dashboard/Friends/UserListToolbar.cs @@ -1,10 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osuTK; using osu.Framework.Bindables; +using osu.Game.Configuration; namespace osu.Game.Overlays.Dashboard.Friends { @@ -14,11 +16,16 @@ public partial class UserListToolbar : CompositeDrawable public Bindable DisplayStyle => styleControl.Current; + private readonly Bindable configDisplayStyle = new Bindable(); + + private readonly bool supportsBrickMode; private readonly UserSortTabControl sortControl; private readonly OverlayPanelDisplayStyleControl styleControl; - public UserListToolbar() + public UserListToolbar(bool supportsBrickMode) { + this.supportsBrickMode = supportsBrickMode; + AutoSizeAxes = Axes.Both; AddInternal(new FillFlowContainer @@ -33,7 +40,7 @@ public UserListToolbar() Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - styleControl = new OverlayPanelDisplayStyleControl + styleControl = new OverlayPanelDisplayStyleControl(supportsBrickMode) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -41,5 +48,30 @@ public UserListToolbar() } }); } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + config.BindWith(OsuSetting.DashboardSortMode, SortCriteria); + config.BindWith(OsuSetting.DashboardDisplayStyle, configDisplayStyle); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + configDisplayStyle.BindValueChanged(style => + { + if (style.NewValue == OverlayPanelDisplayStyle.Brick && !supportsBrickMode) + DisplayStyle.Value = OverlayPanelDisplayStyle.Card; + else + DisplayStyle.Value = style.NewValue; + }, true); + + DisplayStyle.BindValueChanged(style => + { + configDisplayStyle.Value = style.NewValue; + }, true); + } } } diff --git a/osu.Game/Overlays/DashboardOverlay.cs b/osu.Game/Overlays/DashboardOverlay.cs index 1912736135d7..941c5dc68564 100644 --- a/osu.Game/Overlays/DashboardOverlay.cs +++ b/osu.Game/Overlays/DashboardOverlay.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Online.Metadata; using osu.Game.Overlays.Dashboard; +using osu.Game.Overlays.Dashboard.CurrentlyOnline; using osu.Game.Overlays.Dashboard.Friends; namespace osu.Game.Overlays diff --git a/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs index c2bea0ed911d..1ddcb778f7ed 100644 --- a/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs +++ b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs @@ -29,7 +29,7 @@ public partial class OverlayPanelDisplayStyleControl : OsuTabControl false; - public OverlayPanelDisplayStyleControl() + public OverlayPanelDisplayStyleControl(bool supportsBrickMode) { AutoSizeAxes = Axes.Both; @@ -41,10 +41,14 @@ public OverlayPanelDisplayStyleControl() { Icon = FontAwesome.Solid.Bars }); - AddTabItem(new PanelDisplayTabItem(OverlayPanelDisplayStyle.Brick) + + if (supportsBrickMode) { - Icon = FontAwesome.Solid.Th - }); + AddTabItem(new PanelDisplayTabItem(OverlayPanelDisplayStyle.Brick) + { + Icon = FontAwesome.Solid.Th + }); + } } protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer diff --git a/osu.Game/Users/UserBrickPanel.cs b/osu.Game/Users/UserBrickPanel.cs index b92c9a9afdc7..fff1307e0a95 100644 --- a/osu.Game/Users/UserBrickPanel.cs +++ b/osu.Game/Users/UserBrickPanel.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -21,11 +20,8 @@ public UserBrickPanel(APIUser user) CornerRadius = 6; } - [BackgroundDependencyLoader] - private void load() - { - Background.FadeTo(0.2f); - } + // Matches osu!web styling. + protected override Drawable? CreateBackground() => Empty(); protected override Drawable CreateLayout() => new FillFlowContainer { From 8c180b00bebdfe7fca70c1e6c9165cba7e0ae080 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Thu, 5 Feb 2026 00:53:42 +0500 Subject: [PATCH 626/836] Change wide bonus distance reduction to be consistent with `SpeedAim.SINGLE_SPACING_THRESHOLD` (#36573) Slightly reducing aim/speedaim doubledipping, but mostly just done for consistency and ease of understanding of existing relation between both --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 4 ++-- .../Difficulty/Evaluators/SpeedAimEvaluator.cs | 6 +++--- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index c7e96d757262..8573d36c70a8 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -98,8 +98,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Penalize angle repetition. wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3)); - // Apply full wide angle bonus for distance more than one diameter - wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(currDistance, 0, diameter); + // Apply full wide angle bonus for distance more than SINGLE_SPACING_THRESHOLD + wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(currDistance, 0, SpeedAimEvaluator.SINGLE_SPACING_THRESHOLD); // Apply wiggle bonus for jumps that are [radius, 3*diameter] in distance, with < 110 angle // https://www.desmos.com/calculator/dp0v0nvowc diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs index c34fdb3236a3..d56ffbfe14bf 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { public static class SpeedAimEvaluator { - private const double single_spacing_threshold = OsuDifficultyHitObject.NORMALISED_DIAMETER * 1.25; // 1.25 circles distance between centers + public const double SINGLE_SPACING_THRESHOLD = OsuDifficultyHitObject.NORMALISED_DIAMETER * 1.25; // 1.25 circles distance between centers /// /// Evaluates the difficulty of aiming the current object, based on: @@ -30,10 +30,10 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) double distance = travelDistance + osuCurrObj.LazyJumpDistance; // Cap distance at single_spacing_threshold - distance = Math.Min(distance, single_spacing_threshold); + distance = Math.Min(distance, SINGLE_SPACING_THRESHOLD); // Max distance bonus is 1 * `distance_multiplier` at single_spacing_threshold - double distanceBonus = Math.Pow(distance / single_spacing_threshold, 3.95); + double distanceBonus = Math.Pow(distance / SINGLE_SPACING_THRESHOLD, 3.95); // Apply reduced small circle bonus because flow aim difficulty on small circles doesn't scale as hard as jumps distanceBonus *= Math.Sqrt(osuCurrObj.SmallCircleBonus); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index b84c85d38aed..715197b4b513 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Speed : HarmonicSkill { - private double skillMultiplier => 1.03; + private double skillMultiplier => 1.035; private readonly List sliderStrains = new List(); From 52be3111b44ddf1ba6c39ce0bf5840b073063d07 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Thu, 5 Feb 2026 01:19:42 +0500 Subject: [PATCH 627/836] Add a bunch of rhythm improvements (#36569) This does a couple of things: - Adds slider->circle effective ratio adjustment - Removes same polarity nerf for single delta count islands (which are pretty much THE most unpredictable) - Makes polarity nerf check actual deltas and not just the count - Excludes spinners from ratio calculation https://pp.huismetbenen.nl/rankings/players/minor-rhythm-improvements --------- Co-authored-by: James Wilson --- .../Difficulty/Evaluators/RhythmEvaluator.cs | 43 +++++++++++++------ .../Preprocessing/OsuDifficultyHitObject.cs | 3 +- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs index 1f379901969a..985898c6af44 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs @@ -15,7 +15,7 @@ public static class RhythmEvaluator { private const int history_time_max = 5 * 1000; // 5 seconds private const int history_objects_max = 32; - private const double rhythm_overall_multiplier = 1.0; + private const double rhythm_overall_multiplier = 0.9; private const double rhythm_ratio_multiplier = 30.0; /// @@ -55,6 +55,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) for (int i = rhythmStart; i > 0; i--) { OsuDifficultyHitObject currObj = (OsuDifficultyHitObject)current.Previous(i - 1); + if (currObj.BaseObject is Spinner) + continue; // scales note 0 to 1 from history to now double timeDecay = (history_time_max - (current.StartTime - currObj.StartTime)) / history_time_max; @@ -62,7 +64,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) double currHistoricalDecay = Math.Min(noteDecay, timeDecay); // either we're limited by time or limited by object count. - // Use custom cap value to ensure that that at this point delta time is actually zero + // Use custom cap value to ensure that at this point delta time is actually zero double currDelta = Math.Max(currObj.DeltaTime, 1e-7); double prevDelta = Math.Max(prevObj.DeltaTime, 1e-7); double lastDelta = Math.Max(lastObj.DeltaTime, 1e-7); @@ -71,17 +73,23 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) // this function is meant to reduce rhythm bonus for deltas that are multiples of each other (i.e 100 and 200) double deltaDifference = Math.Max(prevDelta, currDelta) / Math.Min(prevDelta, currDelta); - // Take only the fractional part of the value since we're only interested in punishing multiples - double deltaDifferenceFraction = deltaDifference - Math.Truncate(deltaDifference); - - double currRatio = 1.0 + rhythm_ratio_multiplier * Math.Min(0.5, DifficultyCalculationUtils.SmoothstepBellCurve(deltaDifferenceFraction)); - // reduce ratio bonus if delta difference is too big double differenceMultiplier = Math.Clamp(2.0 - deltaDifference / 8.0, 0.0, 1.0); double windowPenalty = Math.Min(1, Math.Max(0, Math.Abs(prevDelta - currDelta) - deltaDifferenceEpsilon) / deltaDifferenceEpsilon); - double effectiveRatio = windowPenalty * currRatio * differenceMultiplier; + double effectiveRatio = getEffectiveRatio(deltaDifference) * windowPenalty * differenceMultiplier; + + // if previous object is a slider it might be easier to tap since you don't have to do a whole tapping motion + // while a full deltatime might end up some weird ratio the "unpress->tap" motion might be simple + // for example a slider-circle-circle pattern should be evaluated as a regular triple and not as a single->double + if (prevObj.BaseObject is Slider) + { + double sliderEndDelta = currObj.MinimumJumpTime; + double sliderDeltaDifference = Math.Max(sliderEndDelta, currDelta) / Math.Min(sliderEndDelta, currDelta); + double sliderEffectiveRatio = getEffectiveRatio(sliderDeltaDifference); + effectiveRatio = Math.Min(sliderEffectiveRatio, effectiveRatio); + } if (firstDeltaSwitch) { @@ -99,7 +107,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) // bpm change was from a slider, this is easier typically than circle -> circle // unintentional side effect is that bursts with kicksliders at the ends might have lower difficulty than bursts without sliders if (prevObj.BaseObject is Slider) - effectiveRatio *= 0.3; + effectiveRatio *= 0.5; // repeated island polarity (2 -> 4, 3 -> 5) if (island.IsSimilarPolarity(previousIsland)) @@ -177,6 +185,14 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) return Math.Sqrt(4 + rhythmComplexitySum * rhythm_overall_multiplier) / 2.0; // produces multiplier that can be applied to strain. range [1, infinity) (not really though); } + private static double getEffectiveRatio(double deltaDifference) + { + // Take only the fractional part of the value since we're only interested in punishing multiples + double deltaDifferenceFraction = deltaDifference - Math.Truncate(deltaDifference); + + return 1.0 + rhythm_ratio_multiplier * Math.Min(0.5, DifficultyCalculationUtils.SmoothstepBellCurve(deltaDifferenceFraction)); + } + private class Island : IEquatable { private readonly double deltaDifferenceEpsilon; @@ -206,9 +222,12 @@ public void AddDelta(int delta) public bool IsSimilarPolarity(Island other) { - // TODO: consider islands to be of similar polarity only if they're having the same average delta (we don't want to consider 3 singletaps similar to a triple) - // naively adding delta check here breaks _a lot_ of maps because of the flawed ratio calculation - return DeltaCount % 2 == other.DeltaCount % 2; + // single delta islands shouldn't be compared + if (DeltaCount <= 1 || other.DeltaCount <= 1) + return false; + + return Math.Abs(Delta - other.Delta) < deltaDifferenceEpsilon && + DeltaCount % 2 == other.DeltaCount % 2; } public bool Equals(Island? other) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 935ee553ffd9..7c21895181c5 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -217,6 +217,8 @@ private void setDistances(double clockRate) TravelTime = Math.Max(LazyTravelTime / clockRate, MIN_DELTA_TIME); } + MinimumJumpTime = AdjustedDeltaTime; + // We don't need to calculate either angle or distance when one of the last->curr objects is a spinner if (BaseObject is Spinner || LastObject is Spinner) return; @@ -228,7 +230,6 @@ private void setDistances(double clockRate) JumpDistance = (LastObject.StackedPosition - BaseObject.StackedPosition).Length * scalingFactor; LazyJumpDistance = (BaseObject.StackedPosition - lastCursorPosition).Length * scalingFactor; - MinimumJumpTime = AdjustedDeltaTime; MinimumJumpDistance = LazyJumpDistance; if (LastObject is Slider lastSlider && lastDifficultyObject != null) From 5d4bb1bd37f0184ce9e76ff04daaa37a4e3eb6a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D1=82=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=9C?= =?UTF-8?q?=D0=B0=D0=BA=D1=81=D0=B8=D0=BC?= Date: Thu, 5 Feb 2026 19:22:25 +0500 Subject: [PATCH 628/836] Localise "running" in `DigitalClockDisplay` (#36589) --- osu.Game/Localisation/ToolbarStrings.cs | 5 +++++ osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/ToolbarStrings.cs b/osu.Game/Localisation/ToolbarStrings.cs index 5822f76e0272..acc5bc60305e 100644 --- a/osu.Game/Localisation/ToolbarStrings.cs +++ b/osu.Game/Localisation/ToolbarStrings.cs @@ -39,6 +39,11 @@ public static class ToolbarStrings /// public static LocalisableString PlaySomeRuleset(string arg0) => new TranslatableString(getKey(@"play_some_ruleset"), @"play some {0}", arg0); + /// + /// "running" + /// + public static LocalisableString TimeRunning => new TranslatableString(getKey(@"time_running"), @"running"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs b/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs index bd1c94484718..e1277f6e2991 100644 --- a/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs +++ b/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Localisation; using osuTK; namespace osu.Game.Overlays.Toolbar @@ -76,7 +77,7 @@ private void load(OsuColour colours) { new OsuSpriteText { - Text = "running", + Text = ToolbarStrings.TimeRunning, Font = OsuFont.Default.With(size: 10, weight: FontWeight.SemiBold), }, gameTime = new OsuSpriteText From 4eec06c1c35b9a021240e3df70113f27b08a1869 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Thu, 5 Feb 2026 22:38:59 +0500 Subject: [PATCH 629/836] Add real sliderend check in rhythm (#36593) Classic blunder. See https://discord.com/channels/546120878908506119/619291828054655016/1468738477297504489 --- .../Difficulty/Evaluators/RhythmEvaluator.cs | 15 +++++++-------- .../Preprocessing/OsuDifficultyHitObject.cs | 6 ++++++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs index 985898c6af44..eca4619e4aa9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs @@ -85,9 +85,13 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) // for example a slider-circle-circle pattern should be evaluated as a regular triple and not as a single->double if (prevObj.BaseObject is Slider) { - double sliderEndDelta = currObj.MinimumJumpTime; - double sliderDeltaDifference = Math.Max(sliderEndDelta, currDelta) / Math.Min(sliderEndDelta, currDelta); - double sliderEffectiveRatio = getEffectiveRatio(sliderDeltaDifference); + double sliderLazyEndDelta = currObj.MinimumJumpTime; + double sliderLazyDeltaDifference = Math.Max(sliderLazyEndDelta, currDelta) / Math.Min(sliderLazyEndDelta, currDelta); + + double sliderRealEndDelta = currObj.LastObjectEndDeltaTime; + double sliderRealDeltaDifference = Math.Max(sliderRealEndDelta, currDelta) / Math.Min(sliderRealEndDelta, currDelta); + + double sliderEffectiveRatio = Math.Min(getEffectiveRatio(sliderLazyDeltaDifference), getEffectiveRatio(sliderRealDeltaDifference)); effectiveRatio = Math.Min(sliderEffectiveRatio, effectiveRatio); } @@ -102,11 +106,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) { // bpm change is into slider, this is easy acc window if (currObj.BaseObject is Slider) - effectiveRatio *= 0.125; - - // bpm change was from a slider, this is easier typically than circle -> circle - // unintentional side effect is that bursts with kicksliders at the ends might have lower difficulty than bursts without sliders - if (prevObj.BaseObject is Slider) effectiveRatio *= 0.5; // repeated island polarity (2 -> 4, 3 -> 5) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 7c21895181c5..8b81788c73ad 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -35,6 +35,11 @@ public class OsuDifficultyHitObject : DifficultyHitObject /// /// Retrieve a instance for the provided From d5ef0d75fc52e8db8db5db120e14da3a3e1469d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Jan 2026 02:42:28 +0900 Subject: [PATCH 605/836] Reorder strings and enums too for consistency --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 6 +++--- osu.Game/Localisation/GlobalActionKeyBindingStrings.cs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 086b408f76ec..6da24e3571f4 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -523,11 +523,11 @@ public enum GlobalAction [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleCurrentGroup))] ToggleCurrentGroup, - [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.NextSkin))] - NextSkin, - [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.PreviousSkin))] PreviousSkin, + + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.NextSkin))] + NextSkin, } public enum GlobalActionCategory diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index 8f0e6f5b323b..1ba051994531 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -230,14 +230,14 @@ public static class GlobalActionKeyBindingStrings public static LocalisableString RandomSkin => new TranslatableString(getKey(@"random_skin"), @"Random skin"); /// - /// "Next skin" + /// "Previous skin" /// - public static LocalisableString NextSkin => new TranslatableString(getKey(@"next_skin"), @"Next skin"); + public static LocalisableString PreviousSkin => new TranslatableString(getKey(@"previous_skin"), @"Previous skin"); /// - /// "Previous skin" + /// "Next skin" /// - public static LocalisableString PreviousSkin => new TranslatableString(getKey(@"previous_skin"), @"Previous skin"); + public static LocalisableString NextSkin => new TranslatableString(getKey(@"next_skin"), @"Next skin"); /// /// "Pause / resume replay" From 64a29313a852d50095ae4b7ea8f22fde23aa634f Mon Sep 17 00:00:00 2001 From: YHSabc233 Date: Thu, 29 Jan 2026 02:04:12 +0800 Subject: [PATCH 606/836] Localise "Show storyboard" in `Editor` --- osu.Game/Localisation/EditorStrings.cs | 5 +++++ osu.Game/Screens/Edit/Editor.cs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs index a9e151d3e5a6..d06aa4012c5f 100644 --- a/osu.Game/Localisation/EditorStrings.cs +++ b/osu.Game/Localisation/EditorStrings.cs @@ -19,6 +19,11 @@ public static class EditorStrings /// public static LocalisableString WaveformOpacity => new TranslatableString(getKey(@"waveform_opacity"), @"Waveform opacity"); + /// + /// "Show storyboard" + /// + public static LocalisableString ShowStoryboard => new TranslatableString(getKey(@"show_storyboard"), @"Show storyboard"); + /// /// "Show hit markers" /// diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 991f10497d3d..2360febccb52 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -424,7 +424,7 @@ private void load(OsuConfigManager config) }, new OsuMenuItemSpacer(), new BackgroundDimMenuItem(editorBackgroundDim), - new ToggleMenuItem("Show storyboard") + new ToggleMenuItem(EditorStrings.ShowStoryboard) { State = { BindTarget = editorShowStoryboard }, }, From 9bf52034d7d259cab3f6edcdbd810dadff4fa99a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 29 Jan 2026 08:35:13 +0100 Subject: [PATCH 607/836] Make Hidden and Freeze Frame mods incompatible (#36515) Effectively closing https://github.com/ppy/osu/issues/21471 as a wontfix. The issue is demonstrated by the following test case:
    patch ```diff diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs index 31498295da..36b4fe5122 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs @@ -55,5 +55,49 @@ public void TestSkipToFirstSpinnerNotSuppressed() PassCondition = () => Player.GameplayClockContainer.GameplayStartTime > 0 }); } + + [Test] + public void TestFreezeFrameAppliedBeforeHidden() + { + CreateModTest(new ModTestData + { + Mods = + [ + new OsuModFreezeFrame(), + new OsuModHidden(), + ], + CreateBeatmap = () => new OsuBeatmap + { + HitObjects = + { + new HitCircle { StartTime = 3000, Position = OsuPlayfield.BASE_SIZE / 2, NewCombo = true }, + new HitCircle { StartTime = 5000, Position = OsuPlayfield.BASE_SIZE / 2 }, + } + }, + PassCondition = () => ((HitCircle)Player.GameplayState.Beatmap.HitObjects[1]).TimeFadeIn == 480 + }); + } + + [Test] + public void TestFreezeFrameAppliedAfterHidden() + { + CreateModTest(new ModTestData + { + Mods = + [ + new OsuModHidden(), + new OsuModFreezeFrame(), + ], + CreateBeatmap = () => new OsuBeatmap + { + HitObjects = + { + new HitCircle { StartTime = 3000, Position = OsuPlayfield.BASE_SIZE / 2, NewCombo = true }, + new HitCircle { StartTime = 5000, Position = OsuPlayfield.BASE_SIZE / 2 }, + } + }, + PassCondition = () => ((HitCircle)Player.GameplayState.Beatmap.HitObjects[1]).TimeFadeIn == 480 + }); + } } } ```
    The reason that this is happening is a data dependency. Freeze Frame modifies `TimePreempt` of hitobjects: https://github.com/ppy/osu/blob/54c0b2c20c3209f1f17be81b8883ef66ec8a83bb/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs#L53 while Hidden uses `TimePreempt` to set `TimeFadeIn`: https://github.com/ppy/osu/blob/54c0b2c20c3209f1f17be81b8883ef66ec8a83bb/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs#L45 Therefore the final value of `TimeFadeIn` with these two mods active depends on the order of application. The reason why I'm bothering to do this is that I was pinged from the PP development server about this again in the context of some ongoing 'rework' and I wish to get ahead of this before it becomes a bigger problem than it already is. The current order of application of these mods as done in `Player` is constant, but essentially undefined. I'm not even sure what even enforces the current order. It's currently Hidden, then Freeze Frame. If I were to guess, the thing "enforcing" (insert 400 tonne solid lead air quotes) it is probably the mod select overlay with its "I need to own all of the mod instances in the global bindable" substitution logic. I'm already getting pushback for this from the PP server crowd who are attempting to justify the current "behaviour" by saying that the player base wants this or by saying that it's already broken so it should remain that way forever. I am however not willing to accept [stable-taiko-tier stupidity again](https://github.com/ppy/osu/pull/27136#issuecomment-1957055402) and am not willing to accept the complexity this would invite everywhere else. I do not see any other easy way of fixing this problem at this point in time. I had hoped that I could inline the `TimePreempt` read in `OsuModHidden`, but it's not that easy because it's set in multiple places. Existing HDFF scores would probably need to be delisted from the leaderboards. I'm not even sure I can get myself to pretend to care. --- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs | 6 ++++-- osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 368d76d1ba40..fe45199ae450 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -27,8 +27,10 @@ public class OsuModFreezeFrame : Mod, IApplicableToDrawableHitObject, IApplicabl public override LocalisableString Description => "Burn the notes into your memory."; - //Alters the transforms of the approach circles, breaking the effects of these mods. - public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModApproachDifferent), typeof(OsuModTransform), typeof(OsuModDepth) }).ToArray(); + /// + /// Incompatible with all mods that directly modify or indirectly depend on , or alter the behaviour of approach circles. + /// + public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModApproachDifferent), typeof(OsuModTransform), typeof(OsuModDepth), typeof(OsuModHidden) }).ToArray(); public override ModType Type => ModType.Fun; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs index 6dc0d5d5229f..c9b5fb29f776 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs @@ -26,7 +26,7 @@ public class OsuModHidden : ModHidden, IHidesApproachCircles public override LocalisableString Description => @"Play with no approach circles and fading circles/sliders."; public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1; - public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles), typeof(OsuModSpinIn), typeof(OsuModDepth) }; + public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles), typeof(OsuModSpinIn), typeof(OsuModDepth), typeof(OsuModFreezeFrame) }; public const double FADE_IN_DURATION_MULTIPLIER = 0.4; public const double FADE_OUT_DURATION_MULTIPLIER = 0.3; From 586b2987a7ce6cb8c051bc99739fbe2d52a21581 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 29 Jan 2026 17:01:52 +0900 Subject: [PATCH 608/836] Fix multiplayer team display becoming inconsistent --- .../OnlinePlay/Multiplayer/Participants/TeamDisplay.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs index 282430d7445d..1550cbb8df18 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs @@ -106,14 +106,12 @@ private void updateUser() clickableContent.TooltipText = "Change team"; } - // reset to ensure samples don't play - DisplayedTeam = null; - updateState(); + updateState(false); } - private void onRoomUpdated() => Scheduler.AddOnce(updateState); + private void onRoomUpdated() => Scheduler.AddOnce(() => updateState(true)); - private void updateState() + private void updateState(bool playSamples) { // we don't have a way of knowing when an individual user's state has updated, so just handle on RoomUpdated for now. @@ -129,7 +127,7 @@ private void updateState() // only play the sample if an already valid team changes to another valid team. // this avoids playing a sound for each user if the match type is changed to/from a team mode. - if (newTeam != null && DisplayedTeam != null) + if (playSamples && newTeam != null && DisplayedTeam != null) sampleTeamSwap?.Play(); DisplayedTeam = newTeam; From 1885ab86f5a83b74e26463c96a56b2db64e8a07d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 29 Jan 2026 09:59:28 +0100 Subject: [PATCH 609/836] Make Difficulty Adjust and Target Practice mods incompatible (#36524) Closes https://github.com/ppy/osu/issues/36490. While I'm out here already taking heat for deleting mod combinations let me do more of that. The main problem with the mod combination here, again, is that the application of the mods does not commute. - The current behaviour is that TP is applied first, then DA. This is, again, "enforced" by the mod select overlay implicitly enforcing order of the mod instances in the global mod bindable to match the display order of mods inside it. Even this doesn't "work" correctly as is, because as the bug reporter points out, if they throw on DA with no changes expecting the map's default AR to be applied, it still gets halved. This is because DA works in a way wherein if you don't touch the AR slider, DA does not touch AR. Which means that the DA slider should *really* be at *half* of the map's base AR by default in this case because TP is active. How do you program this? - The *alternative* behaviour would be that DA is applied first, then TP. This in turn would mean that the effective range of AR adjustment offered by DA when TP is active would be halved to [0, 5] (or [-5, 5.5] with extended ranges). How do you program this? The above is just client-side concerns, while leaving out the other giant concern, which is "how do you get every single place in the game that may want to apply mods to a beatmap to apply them *in the same order*?". Then extend that to server-side components, then extend that to every external library that may want to re-implement SR/PP calculations, etc. etc. One additional remark: What the bug reporter *did not* say however, but I am saying, is that there's an elephant in the room, and that is the Easy mod, which *also* changes AR, but also *happens* to apply commutatively with Target Practice simply because both mods are implemented to halve the AR, which means that the order of application doesn't matter. If I were *really* bent on being a bad guy and just deleting mod combinations indiscriminately, I'd delete that one as well. But I'm not doing that. --- osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs | 4 ++++ osu.Game.Rulesets.Osu/Mods/OsuModTargetPractice.cs | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs index 0d6b02a7d14b..65ab6001c983 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs @@ -1,7 +1,9 @@ // 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.Collections.Generic; +using System.Linq; using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Game.Beatmaps; @@ -71,6 +73,8 @@ string format(string acronym, DifficultyBindable bindable) } } + public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModTargetPractice)).ToArray(); + protected override void ApplySettings(BeatmapDifficulty difficulty) { base.ApplySettings(difficulty); diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTargetPractice.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTargetPractice.cs index e82ec2fb104f..22dcd5079a08 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTargetPractice.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTargetPractice.cs @@ -48,7 +48,8 @@ public class OsuModTargetPractice : ModWithVisibilityAdjustment, IApplicableToDr typeof(OsuModSpunOut), typeof(OsuModStrictTracking), typeof(OsuModSuddenDeath), - typeof(OsuModDepth) + typeof(OsuModDepth), + typeof(OsuModDifficultyAdjust), }).ToArray(); [SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))] From de97660fa4724bbc15bf37ffde32f8fb28da88a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 29 Jan 2026 11:10:48 +0100 Subject: [PATCH 610/836] Fix hitsounds becoming loud in editor after entering setup section (#36512) Probably closes https://github.com/ppy/osu/issues/36492. This is dumb but it's in large part my stupidity. To begin with, the immediate direct offending call that causes the observed symptoms is https://github.com/ppy/osu/blob/a401c7d5e9d6d8b05b2ec293145ad308dfe9d6d0/osu.Game/Screens/Edit/Components/FormSampleSet.cs#L296 The reason why this "invalidation" affects sample volume is that in the framework implementation, the call [removes the relevant sample factory from the sample store which is an audio component](https://github.com/ppy/osu-framework/blob/5b716dcbef6f99e03188a7a7706361fa8445c754/osu.Framework/Audio/Sample/SampleStore.cs#L65-L72). In the process it also [unbinds audio adjustments](https://github.com/ppy/osu-framework/blob/5b716dcbef6f99e03188a7a7706361fa8445c754/osu.Framework/Audio/AudioCollectionManager.cs#L37-L38), which *would* have the effect of resetting the sample volume to 100%, effectively (and I've pretty much confirmed that that's what happens). Now for why this call sometimes does the right thing and sometimes doesn't: Sometimes the call is made in response to an *actual* change to the beatmap skin, which is correct and expected, if very indirect, but sometimes it is made *over-eagerly* when there is no reason to recycle anything yet. One such circumstance is entering the setup screen, which will still "invalidate" (read: remove) the samples, but the compose tab hasn't seen any change to the beatmap skin, so when it is returned to, it has no reason to retrieve the sample again, and as such it will try to play samples which are for better or worse in a completely undefined state because they're not supposed to be *in use* anymore. Therefore, the right thing here would seem to be to take the responsibility of invalidation from a random component, and move it to a place that's *actually* correlated to every other component needing to recycle samples, e.g. `EditorBeatmapSkin` responding to changes in the beatmap resources via raising `BeatmapSkinChanged`. Unfortunately, because of the structure of everything, this recycle needs to go from targeted to individual samples, to nuking the entire store. The reason for this is that `RealmBackedResourceStore` does not provide information as to *what* resources changed, it just says that *the set of them* did. For the recycle to be smarter, `EditorBeatmapSkin` would need to know not only which samples were added or replaced, but also which ones were *removed*, so that users don't hear phantom samples that no longer exist in the editor later. That would however be a lot of hassle for nothing, so I just recycle everything here and hope it won't matter. As to why I could only reproduce this on this one beatmap - I'm not super sure. The failure does not seem to be specific to beatmaps, but it may be exacerbated by certain patterns of accessing samples which means that beatmaps with high BPM like the one I managed to reproduce this on may just be more susceptible to this. As a final note, I do realise that this is not fundamentally improving the surrounding systems and it's still a pretty rickety thing to do. It's still on the consumers to know and respond to the sample store recycle and this is likely to fail if a consumer ever doesn't. That said, I have no brighter ideas at this point in time that won't involve me spending a week refactoring audio. --- .../Screens/Edit/Components/FormSampleSet.cs | 13 +------ osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 10 ++++- osu.Game/Skinning/Skin.cs | 39 ++++++++++++------- 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/FormSampleSet.cs b/osu.Game/Screens/Edit/Components/FormSampleSet.cs index a96b255b5c29..2d3404a513ba 100644 --- a/osu.Game/Screens/Edit/Components/FormSampleSet.cs +++ b/osu.Game/Screens/Edit/Components/FormSampleSet.cs @@ -289,18 +289,7 @@ private void recycleSamples() => Schedule(() => AddInternal(hoverSounds = (ActualFilename.Value == null ? new HoverClickSounds(HoverSampleSet.Button) : new HoverSounds(HoverSampleSet.Button))); - if (ActualFilename.Value != null) - { - // to cover all bases, invalidate the extensionless filename (which gameplay is most likely to use) - // as well as the filename with extension (which we are using here). - editorBeatmap?.BeatmapSkin?.Skin.Samples?.Invalidate(ExpectedFilename.Value); - editorBeatmap?.BeatmapSkin?.Skin.Samples?.Invalidate(ActualFilename.Value); - sample = editorBeatmap?.BeatmapSkin?.Skin.Samples?.Get(ActualFilename.Value); - } - else - { - sample = null; - } + sample = ActualFilename.Value != null ? editorBeatmap?.BeatmapSkin?.Skin.Samples?.Get(ActualFilename.Value) : null; }); protected override bool OnHover(HoverEvent e) diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index f47a6b020e2a..a88330f77294 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -61,7 +61,13 @@ public EditorBeatmapSkin(EditorBeatmap editorBeatmap, LegacyBeatmapSkin skin) ComboColours.BindCollectionChanged((_, _) => updateColours()); if (skin.BeatmapSetResources != null) - skin.BeatmapSetResources.CacheInvalidated += InvokeSkinChanged; + skin.BeatmapSetResources.CacheInvalidated += beatmapResourcesInvalidated; + } + + private void beatmapResourcesInvalidated() + { + Skin.RecycleSamples(); + InvokeSkinChanged(); } public void InvokeSkinChanged() => BeatmapSkinChanged?.Invoke(); @@ -149,7 +155,7 @@ public IEnumerable GetAvailableSampleSets() public void Dispose() { if (Skin.BeatmapSetResources != null) - Skin.BeatmapSetResources.CacheInvalidated -= InvokeSkinChanged; + Skin.BeatmapSetResources.CacheInvalidated -= beatmapResourcesInvalidated; Skin.Dispose(); } diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 3affd5afa675..d50fc2e3d075 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -38,7 +38,7 @@ public abstract class Skin : IDisposable, ISkin /// /// A sample store which can be used to perform user file lookups for this skin. /// - protected internal ISampleStore? Samples { get; } + protected internal ISampleStore? Samples { get; private set; } public readonly Live SkinInfo; @@ -84,18 +84,7 @@ protected Skin(SkinInfo skin, IStorageResourceProvider? resources, IResourceStor store.AddStore(new RealmBackedResourceStore(SkinInfo, resources.Files, resources.RealmAccess)); - var samples = resources.AudioManager?.GetSampleStore(store); - - if (samples != null) - { - samples.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY; - - // osu-stable performs audio lookups in order of wav -> mp3 -> ogg. - // The GetSampleStore() call above internally adds wav and mp3, so ogg is added at the end to ensure expected ordering. - samples.AddExtension(@"ogg"); - } - - Samples = samples; + RecycleSamples(); Textures = new TextureStore(resources.Renderer, CreateTextureLoaderStore(resources, store)); } else @@ -153,6 +142,30 @@ protected Skin(SkinInfo skin, IStorageResourceProvider? resources, IResourceStor } } + /// + /// Recreates . + /// All users of samples from the skin are expected to manually re-retrieve their samples from this skin after this is called. + /// Exposed as public for the purpose of e.g. editing flows where the skin's set of available samples changes. + /// In such a scenario a full recycle of the store is required to avoid accidentally retrieving stale samples that don't exist in the skin anymore. + /// + public void RecycleSamples() + { + Samples?.Dispose(); + + var samples = resources?.AudioManager?.GetSampleStore(store); + + if (samples != null) + { + samples.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY; + + // osu-stable performs audio lookups in order of wav -> mp3 -> ogg. + // The GetSampleStore() call above internally adds wav and mp3, so ogg is added at the end to ensure expected ordering. + samples.AddExtension(@"ogg"); + } + + Samples = samples; + } + protected virtual IResourceStore CreateTextureLoaderStore(IStorageResourceProvider resources, IResourceStore storage) => new MaxDimensionLimitedTextureLoaderStore(resources.CreateTextureLoaderStore(storage)); From 7d476b4b7c76413afc6c74188cefe9d3b09edce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 29 Jan 2026 11:11:10 +0100 Subject: [PATCH 611/836] Fix some text boxes no longer having borders (#36526) Regressed in d6bf4fd90d51b9978a20dacd3959a20f609c91fe. One very visible instance of this regression is the login form. https://github.com/user-attachments/assets/5ba10ac5-4cb1-49af-b55c-89cf58ca0b44 The `CommentEditor` usage was discovered with one of my favourite tricks which is doing ```diff diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index fefe776b01..c17cca726b 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -42,6 +42,12 @@ public partial class OsuTextBox : BasicTextBox Margin = new MarginPadding { Left = 2 }, }; + public new bool Masking + { + get => base.Masking; + set => base.Masking = value; + } + protected bool DrawBorder { get; init; } = true; private OsuCaret? caret; ``` and then looking for usages of the setter. That's all due diligence you're getting here, I'm not auditing every single text box in the game. And yes, the `CommentEditor` usage is OMEGA dodgy but the change applied here is the only one that preserves its visual appearance. I'm not putting in time to fix it. --- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 2 +- osu.Game/Overlays/Comments/CommentEditor.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index 4de7e0d7140c..fefe776b010c 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -42,7 +42,7 @@ public partial class OsuTextBox : BasicTextBox Margin = new MarginPadding { Left = 2 }, }; - protected bool DrawBorder { get; init; } + protected bool DrawBorder { get; init; } = true; private OsuCaret? caret; diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index c4565923837b..d679b8cf4f2f 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -234,7 +234,7 @@ private partial class EditorTextBox : OsuTextBox public EditorTextBox() { - Masking = false; + Masking = DrawBorder = false; TextContainer.Height = 0.4f; } From 14d8cf7275bbcc5b30e845d1d2c7ab4184cc8032 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Thu, 29 Jan 2026 13:13:02 +0300 Subject: [PATCH 612/836] Add localisation support for `DirectorySelector` (#36371) - depends on https://github.com/ppy/osu-framework/pull/6700 - closes https://github.com/ppy/osu/issues/36340 - supersedes and closes https://github.com/ppy/osu/pull/36352 image --------- Co-authored-by: Dean Herbert --- osu.Android.props | 2 +- .../FileSelection/HiddenFilesToggleCheckbox.cs | 3 ++- .../OsuDirectorySelectorBreadcrumbDisplay.cs | 14 ++++++++------ .../FileSelection/OsuDirectorySelectorDirectory.cs | 3 ++- .../UserInterfaceV2/OsuDirectorySelector.cs | 3 ++- .../Graphics/UserInterfaceV2/OsuFileSelector.cs | 3 ++- osu.Game/Localisation/UserInterfaceStrings.cs | 10 ++++++++++ osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 9 files changed, 29 insertions(+), 13 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 146becc7c993..083c83168f01 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index 3e2f63780e9f..ab61a6bfc43c 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From f57a271450b76825f936e506c8b36b5edfc302c1 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Thu, 29 Jan 2026 20:55:18 +0500 Subject: [PATCH 613/836] Undo slider high cs bonus hotfix (#36513) It existed for one map and now that that map is fine there's no need to do it anymore. --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 24db5ef525e4..664e0a636b96 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -160,13 +160,13 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Add in acute angle bonus or wide angle bonus, whichever is larger. aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier); - // Apply high circle size bonus - aimStrain *= osuCurrObj.SmallCircleBonus; - // Add in additional slider velocity bonus. if (withSliderTravelDistance) aimStrain += sliderBonus * slider_multiplier; + // Apply high circle size bonus + aimStrain *= osuCurrObj.SmallCircleBonus; + aimStrain *= highBpmBonus(osuCurrObj.AdjustedDeltaTime); return aimStrain; From 8be93174750368f90993043b6d6aff7bd057d1de Mon Sep 17 00:00:00 2001 From: Givy120 <89256026+Givikap120@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:31:41 +0200 Subject: [PATCH 614/836] Fix flashlight having near-zero bonus when reading difficulty is much higher (#36487) There was a recent PR (https://github.com/ppy/osu/pull/36464) that was aimed on accounting for the fact that getting your map partially memorized with FL makes reading easier, so those bonuses shouldn't reward full pp to each other. But in cases where FL pp is significantly lower than reading it have lead to cases where FL adds practically 0 additional pp. This PR is adjusting a formula to account for cases like this. FL reward on this map - https://osu.ppy.sh/beatmapsets/1487999#osu/3259719 with EZHDHT(FL): Full bonus: 408pp -> 486pp (+78pp) Current: 408pp -> 424pp (+16pp) This PR: 408pp -> 478pp (+70pp) Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com> --- .../Difficulty/OsuDifficultyCalculator.cs | 11 ++++++++++- .../Difficulty/OsuPerformanceCalculator.cs | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index ee6e0dba8514..fe430915f40d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -110,7 +110,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat double baseSpeedPerformance = HarmonicSkill.DifficultyToPerformance(speedRating); double baseReadingPerformance = HarmonicSkill.DifficultyToPerformance(readingRating); double baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating); - double baseCognitionPerformance = DifficultyCalculationUtils.Norm(2, baseReadingPerformance, baseFlashlightPerformance); + double baseCognitionPerformance = SumCognitionDifficulty(baseReadingPerformance, baseFlashlightPerformance); double basePerformance = DifficultyCalculationUtils.Norm(OsuPerformanceCalculator.PERFORMANCE_NORM_EXPONENT, baseAimPerformance, baseSpeedPerformance, baseCognitionPerformance); @@ -144,6 +144,15 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat return attributes; } + public static double SumCognitionDifficulty(double reading, double flashlight) + { + // Base LP summed value, accounting for map being partially memorized with FL + double cognition = DifficultyCalculationUtils.Norm(2, reading, flashlight); + + // Inrease FL bonus when it's lower than reading to avoid situations where high reading difficulty makes FL give practically 0 bonus + return flashlight >= reading ? cognition : double.Lerp(reading + flashlight, cognition, flashlight / reading); + } + private double calculateStarRating(double basePerformance) { return Math.Cbrt(basePerformance * OsuPerformanceCalculator.PERFORMANCE_BASE_MULTIPLIER); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 8ee76814c37d..c833defdd7b2 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -148,7 +148,7 @@ protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo s double readingValue = computeReadingValue(osuAttributes); double flashlightValue = computeFlashlightValue(score, osuAttributes); - double cognitionValue = DifficultyCalculationUtils.Norm(2, readingValue, flashlightValue); + double cognitionValue = OsuDifficultyCalculator.SumCognitionDifficulty(readingValue, flashlightValue); double totalValue = DifficultyCalculationUtils.Norm(PERFORMANCE_NORM_EXPONENT, aimValue, speedValue, accuracyValue, cognitionValue) * multiplier; From a774f19aef26fec1b31e284e57eb1e90c504200e Mon Sep 17 00:00:00 2001 From: Tim Oliver Date: Fri, 30 Jan 2026 13:40:25 +0800 Subject: [PATCH 615/836] Updated iOS 26 app icon assets with newer version (#36535) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After testing out the icon on device for a bit, we decided the osu! logo was a little too large. This PR replaces the app icons with a new version where the sizing of the logo itself is aligned to Apple's recommended boundary. Screenshot 2026-01-30 at 2 33 24 PM --- osu.iOS/AppIcon60x60@2x.png | Bin 23955 -> 21969 bytes osu.iOS/AppIcon76x76@2x~ipad.png | Bin 34568 -> 31224 bytes osu.iOS/Assets.car | Bin 5609864 -> 5063016 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/osu.iOS/AppIcon60x60@2x.png b/osu.iOS/AppIcon60x60@2x.png index ee8f3efcfbdf5da411c5b8e77d6cda8285aa7c68..1aba2b14aecace6423dae48479464bb4286f08b2 100644 GIT binary patch literal 21969 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 literal 34568 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 A^Z)<= diff --git a/osu.iOS/Assets.car b/osu.iOS/Assets.car index b87f48c6ea4ac0c73c110b21495befd3e35da146..9bd24cfa1c745277795b40ca396cd2b5004daa8a 100644 GIT binary patch delta 4715299 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

    218STvW%W4U?{=7 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¥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 z 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°46qOE895xV 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

    public readonly double AdjustedDeltaTime; + /// + /// Amount of time elapsed between lastDifficultyObject's and capped to a minimum of ms. + /// + public double LastObjectEndDeltaTime { get; private set; } + /// /// Time (in ms) between the object first appearing and the time it needs to be clicked. /// adjusted by clock rate. @@ -137,6 +142,7 @@ public OsuDifficultyHitObject(HitObject hitObject, HitObject lastObject, double // Capped to 25ms to prevent difficulty calculation breaking from simultaneous objects. AdjustedDeltaTime = Math.Max(DeltaTime, MIN_DELTA_TIME); + LastObjectEndDeltaTime = lastDifficultyObject != null ? Math.Max(StartTime - lastDifficultyObject.EndTime, MIN_DELTA_TIME) : AdjustedDeltaTime; SmallCircleBonus = Math.Max(1.0, 1.0 + (30 - BaseObject.Radius) / 40); From 5e01dda411ef386b4d07db829e71fae798e5371d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 6 Feb 2026 11:00:20 +0100 Subject: [PATCH 630/836] Fix star rating no longer updating from mod setting changes after re-entering song select (#36601) --- .../TestSceneBeatmapDifficultyCache.cs | 24 +++++++++++++++++++ osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 5 +++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs index b63c0a81960b..ca84d00bb333 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs @@ -114,6 +114,30 @@ public void TestStarDifficultyChangesOnModSettings() AddUntilStep($"star difficulty -> {BASE_STARS + 1.75}", () => starDifficultyBindable.Value.Stars == BASE_STARS + 1.75); } + [Test] + public void TestStarDifficultyChangesOnModSettingsCorrectlyTrackAcrossReferenceChanges() + { + OsuModDoubleTime dt = null; + + AddStep("set computation function", () => difficultyCache.ComputeDifficulty = lookup => + { + var modRateAdjust = (ModRateAdjust)lookup.OrderedMods.SingleOrDefault(mod => mod is ModRateAdjust); + return new StarDifficulty(BASE_STARS + modRateAdjust?.SpeedChange.Value ?? 0, 0); + }); + + AddStep("change selected mod to DT", () => SelectedMods.Value = new[] { dt = new OsuModDoubleTime { SpeedChange = { Value = 1.5 } } }); + AddUntilStep($"star difficulty -> {BASE_STARS + 1.5}", () => starDifficultyBindable.Value.Stars == BASE_STARS + 1.5); + + AddStep("change DT speed to 1.25", () => dt.SpeedChange.Value = 1.25); + AddUntilStep($"star difficulty -> {BASE_STARS + 1.25}", () => starDifficultyBindable.Value.Stars == BASE_STARS + 1.25); + + AddStep("reconstruct DT mod with same settings", () => SelectedMods.Value = new[] { dt = (OsuModDoubleTime)dt.DeepClone() }); + AddUntilStep($"star difficulty -> {BASE_STARS + 1.25}", () => starDifficultyBindable.Value.Stars == BASE_STARS + 1.25); + + AddStep("change DT speed to 1.25", () => dt.SpeedChange.Value = 2); + AddUntilStep($"star difficulty -> {BASE_STARS + 2}", () => starDifficultyBindable.Value.Stars == BASE_STARS + 2); + } + [Test] public void TestStarDifficultyAdjustHashCodeConflict() { diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index 291239e350e6..6ac8508036ec 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -76,7 +76,10 @@ protected override void LoadComplete() currentMods.BindValueChanged(mods => { // A change in bindable here doesn't guarantee that mods have actually changed. - if (mods.OldValue.SequenceEqual(mods.NewValue)) + // However, we *do* want to make sure that the mod *references* are the same; + // `SequenceEqual()` without a comparer would fall back to `IEquatable`. + // Failing to ensure reference equality can cause setting change tracking to fail later. + if (mods.OldValue.SequenceEqual(mods.NewValue, ReferenceEqualityComparer.Instance)) return; modSettingChangeTracker?.Dispose(); From 40b331654edb7d5b420138d620b5c3f8d559caf7 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Fri, 6 Feb 2026 13:12:07 +0300 Subject: [PATCH 631/836] Localise some strings on SSV2 (#36591) --- .../Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs | 2 +- .../Localisation/BeatmapLeaderboardWedgeStrings.cs | 10 ++++++++++ osu.Game/Localisation/SongSelectStrings.cs | 5 +++++ osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs | 4 ++-- osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs | 3 ++- 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs index 411c6acc82aa..d89d90ea84cd 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs @@ -295,7 +295,7 @@ private void checkDisplayedBPM(string target) AddUntilStep($"displayed bpm is {target}", () => { var label = titleWedge.ChildrenOfType().Single(l => l.TooltipText == BeatmapsetsStrings.ShowStatsBpm); - return label.Text == target; + return label.Text.ToString() == target; }); } diff --git a/osu.Game/Localisation/BeatmapLeaderboardWedgeStrings.cs b/osu.Game/Localisation/BeatmapLeaderboardWedgeStrings.cs index 68c1920a1b16..59d97f505d3d 100644 --- a/osu.Game/Localisation/BeatmapLeaderboardWedgeStrings.cs +++ b/osu.Game/Localisation/BeatmapLeaderboardWedgeStrings.cs @@ -69,6 +69,16 @@ public class BeatmapLeaderboardWedgeStrings /// public static LocalisableString Date => new TranslatableString(getKey(@"date"), @"Date"); + /// + /// "Personal Best" + /// + public static LocalisableString PersonalBest => new TranslatableString(getKey(@"personal_best"), @"Personal Best"); + + /// + /// "Personal Best (#{0:N0} of {1:N0})" + /// + public static LocalisableString PersonalBestWithPosition(int position, int totalCount) => new TranslatableString(getKey(@"personal_best_with_position"), @"Personal Best (#{0:N0} of {1:N0})", position, totalCount); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/SongSelectStrings.cs b/osu.Game/Localisation/SongSelectStrings.cs index e963b5a85ab5..169f4782a7b7 100644 --- a/osu.Game/Localisation/SongSelectStrings.cs +++ b/osu.Game/Localisation/SongSelectStrings.cs @@ -264,6 +264,11 @@ public static class SongSelectStrings /// public static LocalisableString TemporarilyShowingAllBeatmapsIn => new TranslatableString(getKey(@"temporarily_showing_all_beatmaps_in"), @"Temporarily showing all beatmaps in"); + /// + /// "mostly {0}" + /// + public static LocalisableString MostlyBPM(int mostCommonBPM) => new TranslatableString(getKey(@"mostly_bpm"), @"mostly {0}", mostCommonBPM); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs b/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs index af41a528b303..3c91185c2189 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs +++ b/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs @@ -368,9 +368,9 @@ protected void SetScores(IEnumerable scores, ScoreInfo? userScore = n scoresScroll.TransformTo(nameof(scoresScroll.Padding), new MarginPadding { Bottom = personal_best_height }, 300, Easing.OutQuint); if (totalCount != null && userScore.Position != null) - personalBestText.Text = $"Personal Best (#{userScore.Position:N0} of {totalCount.Value:N0})"; + personalBestText.Text = BeatmapLeaderboardWedgeStrings.PersonalBestWithPosition(userScore.Position.Value, totalCount.Value); else - personalBestText.Text = "Personal Best"; + personalBestText.Text = BeatmapLeaderboardWedgeStrings.PersonalBest; } } diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs index a74872eaa709..fdbed988850e 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs +++ b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs @@ -20,6 +20,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; @@ -278,7 +279,7 @@ private void updateLengthAndBpmStatistics() bpmStatistic.Text = bpmMin == bpmMax ? $"{bpmMin}" - : $"{bpmMin}-{bpmMax} (mostly {mostCommonBPM})"; + : LocalisableString.Interpolate($"{bpmMin}-{bpmMax} ({SongSelectStrings.MostlyBPM(mostCommonBPM)})"); }); }, token); } From 5231cfa1c71883a108e78c3e31e59ccd64e01b39 Mon Sep 17 00:00:00 2001 From: Michael Middlezong <119022671+mmiddlezong@users.noreply.github.com> Date: Fri, 6 Feb 2026 05:15:57 -0500 Subject: [PATCH 632/836] Change difficulty range slider colors to match star rating more closely (#36564) my attempt at #36452: changes difficulty range slider in song select V2 to use the new star difficulty text gradient colors from #36292. closes #36405 https://github.com/user-attachments/assets/134ace54-a8f8-4024-a32e-f1604c868232 to match star rating more closely for sr <= 7.5 (where i don't think the colors are so intense that they break harmony with the rest of the design), i removed the Lighten by 0.4f on color update also improved the transition from 7.9 to 8.0 which is quite abrupt in the current version https://github.com/ppy/osu/pull/33425#issuecomment-2951914385 is relevant here --- .../FilterControl.DifficultyRangeSlider.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/SelectV2/FilterControl.DifficultyRangeSlider.cs b/osu.Game/Screens/SelectV2/FilterControl.DifficultyRangeSlider.cs index f65c17bddf01..f15cfa4b4df5 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.DifficultyRangeSlider.cs +++ b/osu.Game/Screens/SelectV2/FilterControl.DifficultyRangeSlider.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Layout; using osu.Framework.Localisation; +using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; @@ -164,15 +165,20 @@ protected override void LoadComplete() protected override void UpdateDisplay(double value) { Colour4 nubColour = ColourUtils.SampleFromLinearGradient(spectrum, (float)Math.Round(value, 2, MidpointRounding.AwayFromZero)); - nubColour = nubColour.Lighten(0.4f); - if (value >= 8.0) + // Handle edge case colors for color harmony + if (value >= 7.5 && value < 8.0) + nubColour = Interpolation.ValueAt(value, nubColour, colours.Gray4, 7.5, 8.0); + else if (value >= 8.0) nubColour = colours.Gray4; Nub.AccentColour = nubColour; - Nub.GlowingAccentColour = nubColour.Lighten(0.2f); + Nub.GlowingAccentColour = nubColour.Lighten(0.1f); Nub.ShadowColour = Color4.Black.Opacity(0.2f); - NubText.Colour = OsuColour.ForegroundTextColourFor(nubColour); + NubText.Colour = colours.ForStarDifficultyText(value); + // Except for infinity, which should be white + if (Current.IsDefault && isUpper) + NubText.Colour = OsuColour.ForegroundTextColourFor(nubColour); base.UpdateDisplay(value); } From e77e08c0494e517558b30cd7a4ecd46dc8a4ce54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D1=82=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=9C?= =?UTF-8?q?=D0=B0=D0=BA=D1=81=D0=B8=D0=BC?= Date: Fri, 6 Feb 2026 15:22:06 +0500 Subject: [PATCH 633/836] Localize "Effect, Master, Music" in `VolumeOverlay` (#36594) --- osu.Game/Overlays/Volume/MasterVolumeMeter.cs | 3 ++- osu.Game/Overlays/Volume/VolumeMeter.cs | 5 +++-- osu.Game/Overlays/VolumeOverlay.cs | 8 +++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Volume/MasterVolumeMeter.cs b/osu.Game/Overlays/Volume/MasterVolumeMeter.cs index 951a6d53b187..fd3d410321f5 100644 --- a/osu.Game/Overlays/Volume/MasterVolumeMeter.cs +++ b/osu.Game/Overlays/Volume/MasterVolumeMeter.cs @@ -5,6 +5,7 @@ using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Localisation; using osuTK.Graphics; namespace osu.Game.Overlays.Volume @@ -20,7 +21,7 @@ public partial class MasterVolumeMeter : VolumeMeter [Resolved] private VolumeOverlay volumeOverlay { get; set; } = null!; - public MasterVolumeMeter(string name, float circleSize, Color4 meterColour) + public MasterVolumeMeter(LocalisableString name, float circleSize, Color4 meterColour) : base(name, circleSize, meterColour) { } diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index ed9c5c13efd2..ec3d897a635e 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -19,6 +19,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Framework.Threading; using osu.Framework.Utils; using osu.Game.Graphics; @@ -42,7 +43,7 @@ public partial class VolumeMeter : Container, IStateful protected readonly float CircleSize; private readonly Color4 meterColour; - private readonly string name; + private readonly LocalisableString name; private OsuSpriteText text; private BufferedContainer maxGlow; @@ -75,7 +76,7 @@ public SelectionState State private const float transition_length = 500; - public VolumeMeter(string name, float circleSize, Color4 meterColour) + public VolumeMeter(LocalisableString name, float circleSize, Color4 meterColour) { CircleSize = circleSize; this.meterColour = meterColour; diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index bb2ad6069522..8a656f4f2456 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -6,6 +6,7 @@ using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; @@ -15,6 +16,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Input.Bindings; +using osu.Game.Localisation; using osu.Game.Overlays.Volume; using osuTK; using osuTK.Graphics; @@ -67,9 +69,9 @@ private void load(AudioManager audio, OsuColour colours) Spacing = new Vector2(0, offset), Children = new[] { - volumeMeterEffect = new VolumeMeter("EFFECTS", 125, colours.BlueDarker), - volumeMeterMaster = new MasterVolumeMeter("MASTER", 150, colours.PinkDarker) { IsMuted = { BindTarget = IsMuted }, }, - volumeMeterMusic = new VolumeMeter("MUSIC", 125, colours.BlueDarker), + volumeMeterEffect = new VolumeMeter(AudioSettingsStrings.EffectVolume.ToUpper(), 125, colours.BlueDarker), + volumeMeterMaster = new MasterVolumeMeter(AudioSettingsStrings.MasterVolume.ToUpper(), 150, colours.PinkDarker) { IsMuted = { BindTarget = IsMuted }, }, + volumeMeterMusic = new VolumeMeter(AudioSettingsStrings.MusicVolume.ToUpper(), 125, colours.BlueDarker), } }, }, From a616fa61c97af4d74e252fecf8f9bd526f6835e9 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Fri, 6 Feb 2026 13:23:02 +0300 Subject: [PATCH 634/836] Localise some more strings in settings (#36590) --- osu.Game/Localisation/DialogStrings.cs | 20 +++++++++++++++++++ osu.Game/Localisation/SkinSettingsStrings.cs | 5 +++++ .../StableDirectoryLocationDialog.cs | 9 +++++---- .../StableDirectorySelectScreen.cs | 3 ++- .../Overlays/Settings/Sections/SkinSection.cs | 2 +- 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/osu.Game/Localisation/DialogStrings.cs b/osu.Game/Localisation/DialogStrings.cs index a7634575b878..f50268dd0347 100644 --- a/osu.Game/Localisation/DialogStrings.cs +++ b/osu.Game/Localisation/DialogStrings.cs @@ -29,6 +29,26 @@ public static class DialogStrings /// public static LocalisableString Cancel => new TranslatableString(getKey(@"cancel"), @"No! Abort mission"); + /// + /// "Failed to automatically locate an osu!stable installation." + /// + public static LocalisableString StableDirectoryLocationHeaderText => new TranslatableString(getKey(@"stable_directory_location_header_text"), @"Failed to automatically locate an osu!stable installation."); + + /// + /// "An existing install could not be located. If you know where it is, you can help locate it." + /// + public static LocalisableString StableDirectoryLocationBodyText => new TranslatableString(getKey(@"stable_directory_location_body_text"), @"An existing install could not be located. If you know where it is, you can help locate it."); + + /// + /// "Sure! I know where it is located!" + /// + public static LocalisableString StableDirectoryLocationOkButton => new TranslatableString(getKey(@"stable_directory_location_ok_button"), @"Sure! I know where it is located!"); + + /// + /// "Actually I don't have osu!stable installed." + /// + public static LocalisableString StableDirectoryLocationCancelButton => new TranslatableString(getKey(@"stable_directory_location_cancel_button"), @"Actually I don't have osu!stable installed."); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/SkinSettingsStrings.cs b/osu.Game/Localisation/SkinSettingsStrings.cs index 16dca7fd87c8..c453a09f07fc 100644 --- a/osu.Game/Localisation/SkinSettingsStrings.cs +++ b/osu.Game/Localisation/SkinSettingsStrings.cs @@ -19,6 +19,11 @@ public static class SkinSettingsStrings /// public static LocalisableString CurrentSkin => new TranslatableString(getKey(@"current_skin"), @"Current skin"); + /// + /// "Skin name" + /// + public static LocalisableString SkinName => new TranslatableString(getKey(@"skin_name"), @"Skin name"); + /// /// "Skin layout editor" /// diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs index fcbc603c8375..ff10a0a84e0e 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Framework.Screens; +using osu.Game.Localisation; using osu.Game.Overlays.Dialog; using osu.Game.Screens; @@ -17,20 +18,20 @@ public partial class StableDirectoryLocationDialog : PopupDialog public StableDirectoryLocationDialog(TaskCompletionSource taskCompletionSource) { - HeaderText = "Failed to automatically locate an osu!stable installation."; - BodyText = "An existing install could not be located. If you know where it is, you can help locate it."; + HeaderText = DialogStrings.StableDirectoryLocationHeaderText; + BodyText = DialogStrings.StableDirectoryLocationBodyText; Icon = FontAwesome.Solid.QuestionCircle; Buttons = new PopupDialogButton[] { new PopupDialogOkButton { - Text = "Sure! I know where it is located!", + Text = DialogStrings.StableDirectoryLocationOkButton, Action = () => Schedule(() => performer.PerformFromScreen(screen => screen.Push(new StableDirectorySelectScreen(taskCompletionSource)))) }, new PopupDialogCancelButton { - Text = "Actually I don't have osu!stable installed.", + Text = DialogStrings.StableDirectoryLocationCancelButton, Action = () => taskCompletionSource.TrySetCanceled() } }; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs index 3f12b9c0df78..6d95408ee654 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs @@ -8,6 +8,7 @@ using osu.Framework.Localisation; using osu.Framework.Screens; using osu.Game.Database; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Maintenance { @@ -22,7 +23,7 @@ public partial class StableDirectorySelectScreen : DirectorySelectScreen protected override bool IsValidDirectory(DirectoryInfo? info) => legacyImportManager.IsUsableForStableImport(info, out _); - public override LocalisableString HeaderText => "Please select your osu!stable install location"; + public override LocalisableString HeaderText => MaintenanceSettingsStrings.StableDirectorySelectHeader; public StableDirectorySelectScreen(TaskCompletionSource taskCompletionSource) { diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 84cfff6d1f57..e0bc193df654 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -261,7 +261,7 @@ public RenameSkinPopover() { textBox = new FocusedTextBox { - PlaceholderText = @"Skin name", + PlaceholderText = SkinSettingsStrings.SkinName, FontSize = OsuFont.DEFAULT_FONT_SIZE, RelativeSizeAxes = Axes.X, SelectAllOnFocus = true, From 2efe0c95e63817f312f5fb12cc60dd56bee0023b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 6 Feb 2026 12:22:53 +0100 Subject: [PATCH 635/836] Fix "copy labels from issues" workflow not having the appropriate permissions to do what it claims to do (#36602) --- .github/workflows/pull-request-copy-labels.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pull-request-copy-labels.yml b/.github/workflows/pull-request-copy-labels.yml index b1309b29c59a..895337644143 100644 --- a/.github/workflows/pull-request-copy-labels.yml +++ b/.github/workflows/pull-request-copy-labels.yml @@ -1,13 +1,19 @@ +name: Copy labels from linked issues + on: pull_request: types: [opened] +permissions: + issues: write # to read the labels of any linked issue(s), and to put the found labels if any on the PR + # not granting any `pull_requests` permissions because in github's modeling pull requests are a subset of issues. it's confusing. + jobs: copy-labels: runs-on: ubuntu-latest name: Copy labels from linked issues steps: - - name: copy-labels + - name: Copy labels uses: michalvankodev/copy-issue-labels@v1.3.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} From 48ffadc2df55a59dc1b6ccf96e465ea7b07fff2a Mon Sep 17 00:00:00 2001 From: Natelytle Date: Fri, 6 Feb 2026 18:38:34 -0500 Subject: [PATCH 636/836] fingies: i am goingst to touches you --- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 8f5f10680572..715197b4b513 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -9,6 +9,7 @@ using osu.Game.Rulesets.Osu.Objects; using System.Linq; using osu.Game.Rulesets.Difficulty.Skills; +using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; namespace osu.Game.Rulesets.Osu.Difficulty.Skills From b6cbaa63d4682e0723a0acef03f0fbd47a9af67e Mon Sep 17 00:00:00 2001 From: Natelytle Date: Fri, 6 Feb 2026 19:11:05 -0500 Subject: [PATCH 637/836] multage --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 47ec4298b9df..be3225dcaf1f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -34,7 +34,7 @@ public Aim(Mod[] mods, bool includeSliders) private double skillMultiplierAim => 130.0; private double skillMultiplierSpeed => 6.5; - private double skillMultiplierTotal => 1.01; + private double skillMultiplierTotal => 0.98; private double meanExponent => 1.2; private readonly List sliderStrains = new List(); From c9e44bcec1d6c1597445289db1b7a0bede029333 Mon Sep 17 00:00:00 2001 From: Natelytle Date: Fri, 6 Feb 2026 21:48:50 -0500 Subject: [PATCH 638/836] Move stuff to better spots, properly support databasing miss penalty coefficients, and fix minor bug with miss penalty --- .../Difficulty/OsuDifficultyAttributes.cs | 11 ++++++-- .../Difficulty/OsuDifficultyCalculator.cs | 9 +++--- .../Difficulty/OsuPerformanceCalculator.cs | 17 +++++++---- .../Difficulty/Skills/Aim.cs | 4 +-- .../{Aggregation => Skills}/OsuStrainSkill.cs | 2 +- .../Rulesets/Difficulty/Skills/TimeSkill.cs | 28 +++++++++---------- .../Rulesets}/Difficulty/Utils/Bin.cs | 0 .../Difficulty/Utils/PoissonBinomial.cs | 4 +-- .../Utils/PolynomialPenaltyUtils.cs | 28 +++++++++---------- .../Rulesets}/Difficulty/Utils/RootFinding.cs | 2 +- 10 files changed, 57 insertions(+), 48 deletions(-) rename osu.Game.Rulesets.Osu/Difficulty/{Aggregation => Skills}/OsuStrainSkill.cs (97%) rename osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuFcTimeSkill.cs => osu.Game/Rulesets/Difficulty/Skills/TimeSkill.cs (91%) rename {osu.Game.Rulesets.Osu => osu.Game/Rulesets}/Difficulty/Utils/Bin.cs (100%) rename {osu.Game.Rulesets.Osu => osu.Game/Rulesets}/Difficulty/Utils/PoissonBinomial.cs (98%) rename osu.Game.Rulesets.Osu/Difficulty/Utils/Polynomial.cs => osu.Game/Rulesets/Difficulty/Utils/PolynomialPenaltyUtils.cs (78%) rename {osu.Game.Rulesets.Osu => osu.Game/Rulesets}/Difficulty/Utils/RootFinding.cs (98%) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index c669643dfc5e..8ebd709072cd 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -8,7 +8,6 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Difficulty.Utils; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Difficulty @@ -76,8 +75,14 @@ public class OsuDifficultyAttributes : DifficultyAttributes [JsonProperty("speed_top_weighted_slider_factor")] public double SpeedTopWeightedSliderFactor { get; set; } - [JsonProperty("aim_penalty_curve")] - public Polynomial AimMissPenaltyCurve { get; set; } + [JsonProperty("aim_penalty_coefficient_a")] + public double AimMissPenaltyCoefficientA { get; set; } + + [JsonProperty("aim_penalty_coefficient_a")] + public double AimMissPenaltyCoefficientB { get; set; } + + [JsonProperty("aim_penalty_coefficient_a")] + public double AimMissPenaltyCoefficientC { get; set; } [JsonProperty("speed_difficult_strain_count")] public double SpeedDifficultStrainCount { get; set; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 351edffb7f70..fbaecfd2bd6a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -10,7 +10,6 @@ using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Difficulty.Aggregation; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Skills; using osu.Game.Rulesets.Osu.Difficulty.Utils; @@ -62,7 +61,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat double speedDifficultyValue = speed.DifficultyValue(); double readingDifficultyValue = reading.DifficultyValue(); - Polynomial aimMissPenaltyCurve = aim.GetMissPenaltyCurve(); + double[] aimMissPenaltyCoefficients = aim.GetMissPenaltyCoefficients(); double speedDifficultStrainCount = speed.CountTopWeightedObjectDifficulties(speedDifficultyValue); double readingDifficultNoteCount = reading.CountTopWeightedObjectDifficulties(readingDifficultyValue); @@ -107,7 +106,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat var simulator = new OsuLegacyScoreSimulator(); var scoreAttributes = simulator.Simulate(WorkingBeatmap, beatmap); - double baseAimPerformance = OsuStrainSkill.DifficultyToPerformance(aimRating); + double baseAimPerformance = TimeSkill.DifficultyToPerformance(aimRating); double baseSpeedPerformance = HarmonicSkill.DifficultyToPerformance(speedRating); double baseReadingPerformance = HarmonicSkill.DifficultyToPerformance(readingRating); double baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating); @@ -128,7 +127,9 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat FlashlightDifficulty = flashlightRating, ReadingDifficulty = readingRating, SliderFactor = sliderFactor, - AimMissPenaltyCurve = aimMissPenaltyCurve, + AimMissPenaltyCoefficientA = aimMissPenaltyCoefficients.ElementAtOrDefault(0), + AimMissPenaltyCoefficientB = aimMissPenaltyCoefficients.ElementAtOrDefault(1), + AimMissPenaltyCoefficientC = aimMissPenaltyCoefficients.ElementAtOrDefault(2), SpeedDifficultStrainCount = speedDifficultStrainCount, ReadingDifficultNoteCount = readingDifficultNoteCount, AimTopWeightedSliderFactor = aimTopWeightedSliderFactor, diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 30a0b12f810b..1cd1f1291124 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -10,9 +10,7 @@ using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty.Skills; -using osu.Game.Rulesets.Osu.Difficulty.Aggregation; using osu.Game.Rulesets.Osu.Difficulty.Skills; -using osu.Game.Rulesets.Osu.Difficulty.Utils; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; @@ -207,7 +205,17 @@ private double computeAimValue(ScoreInfo score, OsuDifficultyAttributes attribut double relevantMissCount = Math.Min(effectiveMissCount + aimEstimatedSliderBreaks, totalImperfectHits + countSliderTickMiss); - aimValue *= calculateCurveFittedMissPenalty(relevantMissCount, attributes.AimMissPenaltyCurve); + double[] coefficients = + [ + attributes.AimMissPenaltyCoefficientA, + attributes.AimMissPenaltyCoefficientB, + attributes.AimMissPenaltyCoefficientC, + // We can derive the 4th coefficient from the first third, since at x = 1 our polynomial is equal to the sum of the coefficients, + // and the relevant miss count there is log(totalHits - 1) since our polynomial uses log miss counts. + Math.Log(totalHits + 1) - attributes.AimMissPenaltyCoefficientA - attributes.AimMissPenaltyCoefficientB - attributes.AimMissPenaltyCoefficientC + ]; + + aimValue *= calculatePolynomialMissPenalty(relevantMissCount, coefficients); } // TC bonuses are excluded when blinds is present as the increased visual difficulty is unimportant when notes cannot be seen. @@ -529,8 +537,7 @@ private double calculateTraceableBonus(double sliderFactor = 1) // With the curve fitted miss penalty, we use a pre-computed curve of skill levels for each miss count, raised to the power of 1.5 as // the multiple of the exponents on star rating and PP. This power should be changed if either SR or PP begin to use a different exponent. - // As a result, this exponent is not subject to balance. - private double calculateCurveFittedMissPenalty(double missCount, Polynomial curve) => Math.Pow(1 - curve.GetPenaltyAt(Math.Log(missCount + 1)), 1.5); + private double calculatePolynomialMissPenalty(double missCount, double[] coefficients) => Math.Pow(1 - PolynomialPenaltyUtils.GetPenaltyAt(coefficients, Math.Log(missCount + 1)), 1.5); // With the strain count miss penalty, we use the amount of relatively difficult sections to adjust the miss penalty, // to make it more punishing on maps with lower amount of hard sections. This formula is subject to balance. diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index be3225dcaf1f..a6ab30563991 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -5,9 +5,9 @@ using System.Collections.Generic; using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Difficulty.Aggregation; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Utils; @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// /// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances. /// - public class Aim : OsuFcTimeSkill + public class Aim : TimeSkill { public readonly bool IncludeSliders; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuStrainSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuStrainSkill.cs rename to osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs index 7dd015735d7f..916b6e7b2d51 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuStrainSkill.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs @@ -8,7 +8,7 @@ using System.Linq; using osu.Framework.Utils; -namespace osu.Game.Rulesets.Osu.Difficulty.Aggregation +namespace osu.Game.Rulesets.Osu.Difficulty.Skills { public abstract class OsuStrainSkill : StrainSkill { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuFcTimeSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/TimeSkill.cs similarity index 91% rename from osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuFcTimeSkill.cs rename to osu.Game/Rulesets/Difficulty/Skills/TimeSkill.cs index 61469942a9e1..cf51e41cc252 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Aggregation/OsuFcTimeSkill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/TimeSkill.cs @@ -5,15 +5,15 @@ using System.Collections.Generic; using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; -using osu.Game.Rulesets.Difficulty.Skills; +using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Utils; -namespace osu.Game.Rulesets.Osu.Difficulty.Aggregation +namespace osu.Game.Rulesets.Difficulty.Skills { - public abstract class OsuFcTimeSkill : Skill + public abstract class TimeSkill : Skill { - protected OsuFcTimeSkill(Mod[] mods) + protected TimeSkill(Mod[] mods) : base(mods) { } @@ -105,24 +105,22 @@ private double timeSpentRetryingAtSkill(double skill, List? binList = null) /// /// The coefficients of a quartic fitted to the miss counts at each skill level. /// - /// The coefficients for ax^4+bx^3+cx^2. The 4th coefficient for dx^1 can be deduced from the first 3 in the performance calculator. - public Polynomial GetMissPenaltyCurve() + /// The coefficients for our penalty polynomial. + public double[] GetMissPenaltyCoefficients() { Dictionary missCounts = new Dictionary(); - Polynomial missPenaltyCurve = new Polynomial(); - - // If there are no notes, we just return the polynomial with all coefficients 0. + // If there are no notes, we just return a zero-polynomial. if (ObjectDifficulties.Count == 0 || ObjectDifficulties.Max() == 0) - return missPenaltyCurve; + return Array.Empty(); double fcSkill = DifficultyValue(); var bins = Bin.CreateBins(ObjectDifficulties, times, difficulty_bin_count, time_bin_count); - foreach (double skillProportion in Polynomial.SKILL_PROPORTIONS) + foreach (double skillProportion in PolynomialPenaltyUtils.SKILL_PROPORTIONS) { - if (skillProportion == 0) + if (skillProportion == 1) { missCounts[skillProportion] = 0; continue; @@ -134,9 +132,7 @@ public Polynomial GetMissPenaltyCurve() missCounts[skillProportion] = Math.Log(getMissCountAtSkill(penalizedSkill, bins) + 1); } - missPenaltyCurve.Fit(missCounts); - - return missPenaltyCurve; + return PolynomialPenaltyUtils.GetPenaltyCoefficients(missCounts); } /// @@ -218,5 +214,7 @@ public virtual double CountTopWeightedStrains(double difficultyValue) // Use a weighted sum of all strains. Constants are arbitrary and give nice values return ObjectDifficulties.Sum(s => 1.1 / (1 + Math.Exp(-10 * (s / consistentTopStrain - 0.88)))); } + + public static double DifficultyToPerformance(double difficulty) => 4.0 * Math.Pow(difficulty, 3.0); } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Utils/Bin.cs b/osu.Game/Rulesets/Difficulty/Utils/Bin.cs similarity index 100% rename from osu.Game.Rulesets.Osu/Difficulty/Utils/Bin.cs rename to osu.Game/Rulesets/Difficulty/Utils/Bin.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/Utils/PoissonBinomial.cs b/osu.Game/Rulesets/Difficulty/Utils/PoissonBinomial.cs similarity index 98% rename from osu.Game.Rulesets.Osu/Difficulty/Utils/PoissonBinomial.cs rename to osu.Game/Rulesets/Difficulty/Utils/PoissonBinomial.cs index 2bd4c58d638f..5c09180af4cd 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Utils/PoissonBinomial.cs +++ b/osu.Game/Rulesets/Difficulty/Utils/PoissonBinomial.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; -using osu.Game.Rulesets.Difficulty.Utils; +using osu.Game.Rulesets.Osu.Difficulty.Utils; -namespace osu.Game.Rulesets.Osu.Difficulty.Utils +namespace osu.Game.Rulesets.Difficulty.Utils { /// /// Approximation of the Poisson binomial distribution: diff --git a/osu.Game.Rulesets.Osu/Difficulty/Utils/Polynomial.cs b/osu.Game/Rulesets/Difficulty/Utils/PolynomialPenaltyUtils.cs similarity index 78% rename from osu.Game.Rulesets.Osu/Difficulty/Utils/Polynomial.cs rename to osu.Game/Rulesets/Difficulty/Utils/PolynomialPenaltyUtils.cs index b43a38873918..6c0d19924444 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Utils/Polynomial.cs +++ b/osu.Game/Rulesets/Difficulty/Utils/PolynomialPenaltyUtils.cs @@ -4,14 +4,13 @@ using System; using System.Collections.Generic; using System.Linq; -using osu.Game.Rulesets.Difficulty.Utils; -namespace osu.Game.Rulesets.Osu.Difficulty.Utils +namespace osu.Game.Rulesets.Difficulty.Utils { /// /// Represents a polynomial fitted to a given set of points. /// - public struct Polynomial + public static class PolynomialPenaltyUtils { /// /// The proportions of skill that this polynomial will fit a curve to the miss counts of. @@ -19,9 +18,6 @@ public struct Polynomial /// public static readonly double[] SKILL_PROPORTIONS = [1, 0.95, 0.9, 0.8, 0.6, 0.3, 0]; - // Stores the coefficients [a, b, c, d] of our polynomial ax^4 + bx^3 + cx^2 + dx - private double[]? coefficients; - // Pre-calculated matrix used for curve fitting. // It's derived using least-squares regression to find the best-fit polynomial through our data points. private static readonly double[][] matrix = @@ -39,13 +35,13 @@ public struct Polynomial /// A dictionary of miss counts, with keys representing skill proportions and values representing the miss count a player would achieve at that skill proportion. /// See comment on if you want to use custom skill proportions. /// - public void Fit(Dictionary missCounts) + public static double[] GetPenaltyCoefficients(Dictionary missCounts) { double endPoint = missCounts.Values.Max(); double[] sortedSkillProportions = missCounts.Keys.OrderByDescending(k => k).ToArray(); - coefficients = new double[4]; + double[] coefficients = new double[4]; coefficients[3] = endPoint; @@ -62,26 +58,28 @@ public void Fit(Dictionary missCounts) coefficients[3] -= coefficients[row]; } + + return coefficients; } /// /// Calculates what percentage penalty the player should receive. /// + /// The coefficients to achieve the penalty at /// The number of misses the player got /// A value between 0 and 1 representing the penalty percentage (0 = no penalty, 1 = full penalty) - public double GetPenaltyAt(double missCount) + public static double GetPenaltyAt(double[] coefficients, double missCount) { - if (coefficients is null) - return 1; - - List listCoefficients = coefficients.ToList(); - listCoefficients.Add(-missCount); + // Our first coefficients are the ones derived from the skill proportion miss counts, + // and subtracting missCount for the last one sets our root to the corresponding penalty. + List listCoefficients = [..coefficients, -missCount]; List xVals = DifficultyCalculationUtils.SolvePolynomialRoots(listCoefficients); const double max_error = 1e-7; - // We find the largest value of x (corresponding to the penalty) found as a root of the function, with a fallback of a 100% penalty if no roots were found. + // This will never happen (it is physically impossible for there to not be a root), + // but in the interest of sanity we fall back to a 100% penalty if no roots were found. double largestValue = xVals.Where(x => x >= 0 - max_error && x <= 1 + max_error).OrderDescending().FirstOrDefault() ?? 1; return Math.Clamp(largestValue, 0, 1); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Utils/RootFinding.cs b/osu.Game/Rulesets/Difficulty/Utils/RootFinding.cs similarity index 98% rename from osu.Game.Rulesets.Osu/Difficulty/Utils/RootFinding.cs rename to osu.Game/Rulesets/Difficulty/Utils/RootFinding.cs index bb01e8162c76..a1c9b5d49b6c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Utils/RootFinding.cs +++ b/osu.Game/Rulesets/Difficulty/Utils/RootFinding.cs @@ -3,7 +3,7 @@ using System; -namespace osu.Game.Rulesets.Osu.Difficulty.Utils +namespace osu.Game.Rulesets.Difficulty.Utils { public static class RootFinding { From 8fe76f25066930be745d4de9fa52fb7353585603 Mon Sep 17 00:00:00 2001 From: Natelytle Date: Sat, 7 Feb 2026 09:30:33 -0500 Subject: [PATCH 639/836] unfiretruck attribute json properties --- .../Difficulty/OsuDifficultyAttributes.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 8ebd709072cd..8384093e5035 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -60,9 +60,9 @@ public class OsuDifficultyAttributes : DifficultyAttributes public double SliderFactor { get; set; } /// - /// Describes how much of is contributed to by hitcircles or sliders - /// A value closer to 0.0 indicates most of is contributed by hitcircles - /// A value closer to Infinity indicates most of is contributed by sliders + /// Describes how much of the highest aim difficulties are hitcircles or sliders + /// A value closer to 0.0 indicates most of the highest aim difficulties are hitcircles + /// A value closer to Infinity indicates most of the highest aim difficulties are sliders /// [JsonProperty("aim_top_weighted_slider_factor")] public double AimTopWeightedSliderFactor { get; set; } @@ -78,10 +78,10 @@ public class OsuDifficultyAttributes : DifficultyAttributes [JsonProperty("aim_penalty_coefficient_a")] public double AimMissPenaltyCoefficientA { get; set; } - [JsonProperty("aim_penalty_coefficient_a")] + [JsonProperty("aim_penalty_coefficient_b")] public double AimMissPenaltyCoefficientB { get; set; } - [JsonProperty("aim_penalty_coefficient_a")] + [JsonProperty("aim_penalty_coefficient_c")] public double AimMissPenaltyCoefficientC { get; set; } [JsonProperty("speed_difficult_strain_count")] From 5cdf07c7e174e3c530878b1895fbf0b362407a15 Mon Sep 17 00:00:00 2001 From: SupDos <6813986+SupDos@users.noreply.github.com> Date: Sun, 8 Feb 2026 15:16:39 +0100 Subject: [PATCH 640/836] Make grouped friend notifications Transient and not important (#36620) Grouped notifications for more than 1 person were added in https://github.com/ppy/osu/pull/36180 but it looks like they forgot to add the Transient and IsImportant flags, which means the grouped notifications would still stay in the notification list/flash the taskbar. Before: https://github.com/user-attachments/assets/8a34bbc0-2b5c-4086-b2ee-1daa6d1e6e10 After: https://github.com/user-attachments/assets/03c25ba6-7c8e-464c-bbb1-688ab9da6bb6 --- osu.Game/Online/FriendPresenceNotifier.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Online/FriendPresenceNotifier.cs b/osu.Game/Online/FriendPresenceNotifier.cs index 0297aea556da..77d0421354f2 100644 --- a/osu.Game/Online/FriendPresenceNotifier.cs +++ b/osu.Game/Online/FriendPresenceNotifier.cs @@ -221,6 +221,8 @@ private partial class MultipleFriendsOnlineNotification : SimpleNotification { public MultipleFriendsOnlineNotification(ICollection users) { + Transient = true; + IsImportant = false; Text = NotificationsStrings.FriendOnline(string.Join(@", ", users.Select(u => u.Username))); } @@ -258,6 +260,8 @@ private partial class MultipleFriendsOfflineNotification : SimpleNotification { public MultipleFriendsOfflineNotification(ICollection users) { + Transient = true; + IsImportant = false; Text = NotificationsStrings.FriendOffline(string.Join(@", ", users.Select(u => u.Username))); } From 239951eda972fd3e59ba669b865eab1e6359382c Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 8 Feb 2026 06:57:22 -0800 Subject: [PATCH 641/836] Fix seeking to previous bookmark not working when song is playing (#36616) - Closes https://github.com/ppy/osu/issues/35389 Same as: https://github.com/ppy/osu/blob/2efe0c95e63817f312f5fb12cc60dd56bee0023b/osu.Game/Screens/Edit/Editor.cs#L1173-L1180 There's also seeking hit objects and sample points, but the seeks are relatively close to each other and probably useless when playing(?). If we want to make those cases not stuck at the same point in time, I believe the leniency should be lower than 1000 ms. With the above, that is why I just copy-pasted the code, as we may want to have different leniencies. Edit: forgot the automated label thing, will not label next time --- osu.Game/Screens/Edit/BookmarkController.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/BookmarkController.cs b/osu.Game/Screens/Edit/BookmarkController.cs index 80e77364e591..182e05a9284a 100644 --- a/osu.Game/Screens/Edit/BookmarkController.cs +++ b/osu.Game/Screens/Edit/BookmarkController.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Timing; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Localisation; @@ -106,8 +107,12 @@ private void removeClosestBookmark() private void seekBookmark(int direction) { + // In the case of a backwards seek while playing, it can be hard to jump before a bookmark. + // Adding some lenience here makes it more user-friendly. + double seekLenience = clock.IsRunning ? 1000 * ((IAdjustableClock)clock).Rate : 0; + int? targetBookmark = direction < 1 - ? bookmarks.Cast().LastOrDefault(b => b < clock.CurrentTimeAccurate) + ? bookmarks.Cast().LastOrDefault(b => b < clock.CurrentTimeAccurate - seekLenience) : bookmarks.Cast().FirstOrDefault(b => b > clock.CurrentTimeAccurate); if (targetBookmark != null) From 7263551aa868911a7d9148cf2cb16f9e0325f531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 8 Feb 2026 16:51:31 +0100 Subject: [PATCH 642/836] Improve handling of account registration errors (#36600) ## [Specify `Accept` header in registration request](https://github.com/ppy/osu/commit/28edb788f78723cda23281a8801acc2065592840) The lack of it meant that in specific scenarios web would respond with a chunk of HTML instead of JSON. ## [Allow showing registration error message even if no redirect is given](https://github.com/ppy/osu/commit/6ad49941ffd7cdf662ccd404836bb52fccec2142) There are scenarios where this can happen, and if it did, previously the strict requirement to have both would cause the specific message to be discarded and replaced with the generic "something happened" one. --- osu.Game/Online/API/APIAccess.cs | 4 ++-- osu.Game/Online/API/RegistrationRequest.cs | 8 +++++--- osu.Game/Overlays/AccountCreation/ScreenEntry.cs | 8 +++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 6fc897a8ffd1..6507665e9be8 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -428,10 +428,10 @@ public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, // attempt to parse a non-form error message var response = JObject.Parse(req.GetResponseString().AsNonNull()); - string redirect = (string)response.SelectToken(@"url", true); + string redirect = (string)response.SelectToken(@"url", false); string message = (string)response.SelectToken(@"error", false); - if (!string.IsNullOrEmpty(redirect)) + if (!string.IsNullOrEmpty(redirect) || !string.IsNullOrEmpty(message)) { return new RegistrationRequest.RegistrationRequestErrors { diff --git a/osu.Game/Online/API/RegistrationRequest.cs b/osu.Game/Online/API/RegistrationRequest.cs index 78633f70b7a5..4498bc541824 100644 --- a/osu.Game/Online/API/RegistrationRequest.cs +++ b/osu.Game/Online/API/RegistrationRequest.cs @@ -14,9 +14,11 @@ public class RegistrationRequest : OsuWebRequest protected override void PrePerform() { - AddParameter("user[username]", Username); - AddParameter("user[user_email]", Email); - AddParameter("user[password]", Password); + AddParameter(@"user[username]", Username); + AddParameter(@"user[user_email]", Email); + AddParameter(@"user[password]", Password); + + AddHeader(@"Accept", @"application/json"); base.PrePerform(); } diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs index b2b672342ed5..c801e9304f49 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs @@ -209,13 +209,11 @@ private void performRegistration() passwordDescription.AddErrors(errors.User.Password); } - if (!string.IsNullOrEmpty(errors.Redirect)) - { - if (!string.IsNullOrEmpty(errors.Message)) - passwordDescription.AddErrors(new[] { errors.Message }); + if (!string.IsNullOrEmpty(errors.Message)) + passwordDescription.AddErrors(new[] { errors.Message }); + if (!string.IsNullOrEmpty(errors.Redirect)) game?.OpenUrlExternally($"{errors.Redirect}?username={usernameTextBox.Text}&email={emailTextBox.Text}", LinkWarnMode.NeverWarn); - } } else { From bb04a180600b585fa6c964a118ddb92c2a063ff2 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Sun, 8 Feb 2026 19:52:43 +0300 Subject: [PATCH 643/836] Localise "lounge" & "quick play" in `ButtonSystem` (#36220) --- osu.Game/Localisation/ButtonSystemStrings.cs | 10 ++++++++++ osu.Game/Screens/Menu/ButtonSystem.cs | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/ButtonSystemStrings.cs b/osu.Game/Localisation/ButtonSystemStrings.cs index a9bc3068da83..c851119274a6 100644 --- a/osu.Game/Localisation/ButtonSystemStrings.cs +++ b/osu.Game/Localisation/ButtonSystemStrings.cs @@ -59,6 +59,16 @@ public static class ButtonSystemStrings /// public static LocalisableString DailyChallenge => new TranslatableString(getKey(@"daily_challenge"), @"daily challenge"); + /// + /// "lounge" + /// + public static LocalisableString Lounge => new TranslatableString(getKey(@"lounge"), @"lounge"); + + /// + /// "quick play" + /// + public static LocalisableString QuickPlay => new TranslatableString(getKey(@"quick_play"), @"quick play"); + /// /// "A few important words from your dev team!" /// diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index da78ea337105..362e442afc75 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -157,11 +157,11 @@ private void load(AudioManager audio, IdleTracker? idleTracker, GameHost host) buttonsPlay.Add(new DailyChallengeButton(@"button-daily-select", new Color4(94, 63, 186, 255), onDailyChallenge, Key.D)); buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play); - buttonsMulti.Add(new MainMenuButton("lounge", @"button-default-select", FontAwesome.Solid.Couch, new Color4(94, 63, 186, 255), onMultiplayer, Key.L, Key.M) + buttonsMulti.Add(new MainMenuButton(ButtonSystemStrings.Lounge, @"button-default-select", FontAwesome.Solid.Couch, new Color4(94, 63, 186, 255), onMultiplayer, Key.L, Key.M) { Padding = new MarginPadding { Left = WEDGE_WIDTH } }); - buttonsMulti.Add(new MainMenuButton("quick play", @"button-daily-select", FontAwesome.Solid.Bolt, new Color4(94, 63, 186, 255), onMatchmaking, Key.Q)); + buttonsMulti.Add(new MainMenuButton(ButtonSystemStrings.QuickPlay, @"button-daily-select", FontAwesome.Solid.Bolt, new Color4(94, 63, 186, 255), onMatchmaking, Key.Q)); buttonsMulti.ForEach(b => b.VisibleState = ButtonSystemState.Multi); buttonsEdit.Add(new MainMenuButton(EditorStrings.BeatmapEditor.ToLower(), @"button-default-select", OsuIcon.Beatmap, new Color4(238, 170, 0, 255), (_, _) => OnEditBeatmap?.Invoke(), Key.B, From 0f709035cdf6860048c4a5ad46b69e7f4e514cef Mon Sep 17 00:00:00 2001 From: molneya <62799417+molneya@users.noreply.github.com> Date: Mon, 9 Feb 2026 01:11:17 +0800 Subject: [PATCH 644/836] only nerf total cognition sum when reading > flashlight (#36599) Alternative to #36464 and #36487. Reading and flashlight should be treated much more separately, since the flashlight skill only accounts for object visibility and repetition, but reading accounts for overlaps, high/low AR, etc. However, for certain scores with very high reading (to the point of memorisation), the skill indeed overlaps with flashlight. This PR uses the normal strain sum exponent for reading and flashlight (for player expectations), with an extra factor on flashlight to account for the ease of adding flashlight to a partially memorised map when reading is the dominant skill. --- .../Difficulty/OsuDifficultyCalculator.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index fe430915f40d..d30f556c77f1 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -146,11 +146,8 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat public static double SumCognitionDifficulty(double reading, double flashlight) { - // Base LP summed value, accounting for map being partially memorized with FL - double cognition = DifficultyCalculationUtils.Norm(2, reading, flashlight); - - // Inrease FL bonus when it's lower than reading to avoid situations where high reading difficulty makes FL give practically 0 bonus - return flashlight >= reading ? cognition : double.Lerp(reading + flashlight, cognition, flashlight / reading); + // Nerf flashlight value in cognition sum when reading is greater than flashlight + return DifficultyCalculationUtils.Norm(OsuPerformanceCalculator.PERFORMANCE_NORM_EXPONENT, reading, flashlight * Math.Clamp(flashlight / reading, 0.25, 1.0)); } private double calculateStarRating(double basePerformance) From 0d42b77da7a854c994d32f0c383f9d71d5f412b4 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Mon, 9 Feb 2026 04:30:04 +0500 Subject: [PATCH 645/836] Return zero rhythm difficulty for `Swell` and `DrumRoll` (#36628) Found in the middle of hitwindow usage refactor --- .../Difficulty/Evaluators/RhythmEvaluator.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs index 3b3aea07f314..c0acd5935a62 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs @@ -8,6 +8,7 @@ using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data; +using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators { @@ -18,6 +19,9 @@ public class RhythmEvaluator /// public static double EvaluateDifficultyOf(DifficultyHitObject hitObject, double hitWindow) { + if (hitObject.BaseObject is not Hit) + return 0; + TaikoRhythmData rhythmData = ((TaikoDifficultyHitObject)hitObject).RhythmData; double difficulty = 0.0d; From 0a4497db3c83cd1577c2ffcce0666bc6f658d36f Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 8 Feb 2026 16:55:36 -0800 Subject: [PATCH 646/836] Fix local beatmap metadata not being cleared when previously selected beatmap is online (#36632) - Closes https://github.com/ppy/osu/issues/36584 The last two commits could be either fixes to the issue above, but in a code quality perspective, the scheduler in `setLink()` seems unnecessary as the other set methods don't have it (other than making it run last) and the other commit is self explanatory. --- .../TestSceneBeatmapMetadataWedge.cs | 38 ++++++++++++------- .../BeatmapMetadataWedge.MetadataDisplay.cs | 4 +- .../Screens/SelectV2/BeatmapMetadataWedge.cs | 4 +- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapMetadataWedge.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapMetadataWedge.cs index d4fab55c6296..02665843894a 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapMetadataWedge.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapMetadataWedge.cs @@ -7,8 +7,10 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Extensions; +using osu.Game.Graphics.Sprites; using osu.Game.Models; using osu.Game.Online.API.Requests.Responses; using osu.Game.Screens.SelectV2; @@ -53,8 +55,8 @@ public void TestVariousMetrics() working.Metadata.Source = string.Empty; - onlineLookupResult.Value = online; Beatmap.Value = working; + onlineLookupResult.Value = online; }); AddStep("no success rate", () => { @@ -63,8 +65,8 @@ public void TestVariousMetrics() online.Result!.Beatmaps.Single().PlayCount = 0; online.Result!.Beatmaps.Single().PassCount = 0; - onlineLookupResult.Value = online; Beatmap.Value = working; + onlineLookupResult.Value = online; }); AddStep("no user ratings", () => { @@ -72,8 +74,8 @@ public void TestVariousMetrics() online.Result!.Ratings = Array.Empty(); - onlineLookupResult.Value = online; Beatmap.Value = working; + onlineLookupResult.Value = online; }); AddStep("no fail times", () => { @@ -81,8 +83,8 @@ public void TestVariousMetrics() online.Result!.Beatmaps.Single().FailTimes = null; - onlineLookupResult.Value = online; Beatmap.Value = working; + onlineLookupResult.Value = online; }); AddStep("no metrics", () => { @@ -91,8 +93,8 @@ public void TestVariousMetrics() online.Result!.Ratings = Array.Empty(); online.Result!.Beatmaps.Single().FailTimes = null; - onlineLookupResult.Value = online; Beatmap.Value = working; + onlineLookupResult.Value = online; }); AddStep("local beatmap", () => { @@ -100,8 +102,8 @@ public void TestVariousMetrics() working.BeatmapInfo.OnlineID = 0; - onlineLookupResult.Value = null; Beatmap.Value = working; + onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(null); }); } @@ -119,8 +121,8 @@ public void TestTruncation() online.Result!.Language = new BeatmapSetOnlineLanguage { Id = 12, Name = "Verrrrryyyy llooonngggggg language" }; online.Result!.Beatmaps.Single().TopTags = Enumerable.Repeat(online.Result!.Beatmaps.Single().TopTags, 3).SelectMany(t => t!).ToArray(); - onlineLookupResult.Value = online; Beatmap.Value = working; + onlineLookupResult.Value = online; }); } @@ -137,20 +139,28 @@ public void TestOnlineAvailability() working.BeatmapInfo.ResetOnlineInfo(); - onlineLookupResult.Value = lookupResult; Beatmap.Value = working; + onlineLookupResult.Value = lookupResult; }); AddUntilStep("rating wedge hidden", () => !wedge.RatingsVisible); AddUntilStep("fail time wedge hidden", () => !wedge.FailRetryVisible); + + // just check for text everywhere on the wedge as the classes are private and generic + AddAssert("genre is still visible", () => wedge.ChildrenOfType().Any(t => t.Text == "Pop")); + AddAssert("language is still visible", () => wedge.ChildrenOfType().Any(t => t.Text == "English")); + AddStep("local beatmap", () => { var (working, _) = createTestBeatmap(); - onlineLookupResult.Value = null; Beatmap.Value = working; + onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(null); }); AddAssert("rating wedge still hidden", () => !wedge.RatingsVisible); AddAssert("fail time wedge still hidden", () => !wedge.FailRetryVisible); + + AddAssert("genre is cleared", () => wedge.ChildrenOfType().All(t => t.Text != "Pop")); + AddAssert("language is cleared", () => wedge.ChildrenOfType().All(t => t.Text != "English")); } [Test] @@ -166,8 +176,8 @@ public void TestUserTags() online.Result!.RelatedTags = null; working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear(); - onlineLookupResult.Value = online; Beatmap.Value = working; + onlineLookupResult.Value = online; }); } @@ -178,9 +188,9 @@ public void TestLoading() { var (working, online) = createTestBeatmap(); + Beatmap.Value = working; onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress(); Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500); - Beatmap.Value = working; }); AddWaitStep("wait", 5); @@ -192,9 +202,9 @@ public void TestLoading() online.Result!.RelatedTags[1].Name = "another/tag"; online.Result!.RelatedTags[2].Name = "some/tag"; + Beatmap.Value = working; onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress(); Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500); - Beatmap.Value = working; }); AddWaitStep("wait", 5); @@ -206,9 +216,9 @@ public void TestLoading() online.Result!.RelatedTags = null; working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear(); + Beatmap.Value = working; onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress(); Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500); - Beatmap.Value = working; }); AddWaitStep("wait", 5); @@ -220,9 +230,9 @@ public void TestLoading() online.Result!.RelatedTags = null; working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear(); + Beatmap.Value = working; onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress(); Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500); - Beatmap.Value = working; }); AddWaitStep("wait", 5); } diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.MetadataDisplay.cs b/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.MetadataDisplay.cs index 1c3cf8f8eb7a..84948678d0d9 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.MetadataDisplay.cs +++ b/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.MetadataDisplay.cs @@ -145,13 +145,13 @@ private void setText(LocalisableString text) contentText.Text = text; } - private void setLink(LocalisableString text, Action action) => Schedule(() => + private void setLink(LocalisableString text, Action action) { clear(); contentLinkText.Text = text; contentLink.Action = action; - }); + } private void setDate(DateTimeOffset date) { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.cs b/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.cs index d516f4b8466e..9c0ab105e24a 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.cs +++ b/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.cs @@ -250,8 +250,8 @@ private void load(AudioManager audio) protected override void LoadComplete() { base.LoadComplete(); - beatmap.BindValueChanged(_ => updateDisplay()); - onlineLookupResult.BindValueChanged(_ => updateDisplay()); + beatmap.BindValueChanged(_ => Scheduler.AddOnce(updateDisplay)); + onlineLookupResult.BindValueChanged(_ => Scheduler.AddOnce(updateDisplay)); apiState = api.State.GetBoundCopy(); apiState.BindValueChanged(_ => Scheduler.AddOnce(updateDisplay), true); From bb83f3dcf260b13f0fd9e44d9e2ddb23c8be3036 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Feb 2026 10:04:23 +0900 Subject: [PATCH 647/836] Fix unreliable async loading due to incorrect single-child assumption See https://github.com/ppy/osu/actions/runs/21807684945/job/62913744850. --- osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs index 0f5ae4d44f12..408823301324 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs @@ -173,7 +173,9 @@ private void reloadList() listLoadCancellation?.Cancel(); var cancellationSource = listLoadCancellation = new CancellationTokenSource(); - FriendsList? currentList = listContainer.SingleOrDefault(); + // There may be more than one active list in the container due to the delayed fade out. + FriendsList? currentList = listContainer.SingleOrDefault(d => d.LifetimeEnd == double.MaxValue); + FriendsList newList = new FriendsList(userListToolbar.DisplayStyle.Value, apiFriends.Select(f => f.TargetUser!).ToArray()) { OnlineStream = { BindTarget = streamControl.Current }, From 01982030ec17f5d837e1c28bab1383a652b681b4 Mon Sep 17 00:00:00 2001 From: failaip12 <86018517+failaip12@users.noreply.github.com> Date: Mon, 9 Feb 2026 02:15:34 +0100 Subject: [PATCH 648/836] Allow binding left/right modifier keys separately for gameplay bindings (#36585) Addresses #36583. --------- Co-authored-by: Dean Herbert --- .../Visual/Settings/TestSceneKeyBindingPanel.cs | 9 +++++++++ .../Sections/Input/KeyBindingRow.KeyButton.cs | 15 +++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index ac413fe306c5..d077294dd510 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -71,6 +71,15 @@ public void TestBindingSingleModifier() checkBinding("Increase volume", "Shift"); } + [Test] + public void TestRulesetBindingSingleModifier() + { + scrollToAndStartBinding("Left button"); + AddStep("press left shift", () => InputManager.Key(Key.ShiftLeft)); + AddStep("release left shift", () => InputManager.ReleaseKey(Key.ShiftLeft)); + checkBinding("Left button", "LShift"); + } + [Test] public void TestBindingSingleKeyWithModifier() { diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.KeyButton.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.KeyButton.cs index 2eb900207a11..5b986f65eefd 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.KeyButton.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.KeyButton.cs @@ -142,10 +142,17 @@ private void updateHoverState() /// The key which triggered this update, and should be used as the binding. public void UpdateKeyCombination(KeyCombination fullState, InputKey triggerKey) { - var combination = fullState.Keys.Where(KeyCombination.IsModifierKey) - .Append(triggerKey) - .Select(k => k.GetVirtualKey() ?? k) - .ToArray(); + var keys = fullState.Keys + .Where(KeyCombination.IsModifierKey) + .Append(triggerKey) + .ToArray(); + + // For gameplay bindings, users care about being able to use both left / right shift as different bindings. + // For global bindings, it's better to combine both of these into a virtual key which covers both side modifiers. + var combination = KeyBinding.Value.RulesetName == null + ? keys.Select(k => k.GetVirtualKey() ?? k).ToArray() + : keys; + UpdateKeyCombination(new KeyCombination(combination)); } From 60d98f0afd560ef2539e3952616b6195eb32ac99 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Mon, 9 Feb 2026 05:35:01 +0300 Subject: [PATCH 649/836] Improve adjusting mods settings values with keyboard (#36090) - closes https://github.com/ppy/osu/issues/36016 Co-authored-by: Dean Herbert --- osu.Game.Rulesets.Osu/Mods/OsuModBloom.cs | 10 +++++++++- osu.Game/Configuration/SettingSourceAttribute.cs | 7 ++++--- osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs | 10 +++++++++- osu.Game/Rulesets/Mods/ModMuted.cs | 5 +++++ osu.Game/Rulesets/Mods/ModNoScope.cs | 5 +++++ 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBloom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBloom.cs index 445fb8b37ad3..8947565992be 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBloom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBloom.cs @@ -39,7 +39,7 @@ public class OsuModBloom : Mod, IApplicableToScoreProcessor, IUpdatableByPlayfie [SettingSource( "Max size at combo", "The combo count at which the cursor reaches its maximum size", - SettingControlType = typeof(SettingsSlider>) + SettingControlType = typeof(SettingsSlider) )] public BindableInt MaxSizeComboCount { get; } = new BindableInt(50) { @@ -85,4 +85,12 @@ public void Update(Playfield playfield) cursor.ModScaleAdjust.Value = (float)Interpolation.Lerp(cursor.ModScaleAdjust.Value, currentSize, Math.Clamp(cursor.Time.Elapsed / TRANSITION_DURATION, 0, 1)); } } + + public partial class MaxSizeComboSlider : RoundedSliderBar + { + public MaxSizeComboSlider() + { + KeyboardStep = 1; + } + } } diff --git a/osu.Game/Configuration/SettingSourceAttribute.cs b/osu.Game/Configuration/SettingSourceAttribute.cs index 30cda4047ec8..87df5b3c927d 100644 --- a/osu.Game/Configuration/SettingSourceAttribute.cs +++ b/osu.Game/Configuration/SettingSourceAttribute.cs @@ -140,7 +140,7 @@ public static IEnumerable CreateSettingsControls(this object obj) LabelText = attr.Label, TooltipText = attr.Description, Current = bNumber, - KeyboardStep = 0.1f, + KeyboardStep = bNumber.Precision, }; break; @@ -151,7 +151,7 @@ public static IEnumerable CreateSettingsControls(this object obj) LabelText = attr.Label, TooltipText = attr.Description, Current = bNumber, - KeyboardStep = 0.1f, + KeyboardStep = (float)bNumber.Precision, }; break; @@ -161,7 +161,8 @@ public static IEnumerable CreateSettingsControls(this object obj) { LabelText = attr.Label, TooltipText = attr.Description, - Current = bNumber + Current = bNumber, + KeyboardStep = bNumber.Precision, }; break; diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index f26a1bd477de..404caa6b068a 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -53,7 +53,7 @@ public class ModAccuracyChallenge : ModFailCondition, IApplicableToScoreProcesso } } - [SettingSource("Minimum accuracy", "Trigger a failure if your accuracy goes below this value.", SettingControlType = typeof(SettingsPercentageSlider))] + [SettingSource("Minimum accuracy", "Trigger a failure if your accuracy goes below this value.", SettingControlType = typeof(MinimumAccuracySlider))] public BindableNumber MinimumAccuracy { get; } = new BindableDouble { MinValue = 0.60, @@ -103,4 +103,12 @@ public enum AccuracyMode Standard, } } + + public partial class MinimumAccuracySlider : SettingsPercentageSlider + { + public MinimumAccuracySlider() + { + KeyboardStep = 0.01f; + } + } } diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 094c476e871b..6d24854ac5c4 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -108,6 +108,11 @@ protected override LocalisableString GetSettingTooltipText(IBindable bindable) public partial class MuteComboSlider : RoundedSliderBar { + public MuteComboSlider() + { + KeyboardStep = 1; + } + public override LocalisableString TooltipText => FormatMuteComboValue(Current.Value); public static LocalisableString FormatMuteComboValue(int value) diff --git a/osu.Game/Rulesets/Mods/ModNoScope.cs b/osu.Game/Rulesets/Mods/ModNoScope.cs index bcbef8287c20..42dea82385a1 100644 --- a/osu.Game/Rulesets/Mods/ModNoScope.cs +++ b/osu.Game/Rulesets/Mods/ModNoScope.cs @@ -74,6 +74,11 @@ protected override LocalisableString GetSettingTooltipText(IBindable bindable) public partial class HiddenComboSlider : RoundedSliderBar { + public HiddenComboSlider() + { + KeyboardStep = 1; + } + public override LocalisableString TooltipText => FormatHiddenComboValue(Current.Value); public static LocalisableString FormatHiddenComboValue(int value) From efd4d12c217fc43c1a679892aa847d41e150229c Mon Sep 17 00:00:00 2001 From: maarvin Date: Mon, 9 Feb 2026 04:39:27 +0100 Subject: [PATCH 650/836] Add info about damage dealt to ranked play user state (#36627) Adds a `DamageInfo` property to `RankedPlayDamageInfo` to be used by the result screen. The issue this is trying to solve is that once the result screen initializes, the HP value of each player has already been updated in the room state so the previous values are no longer accessible. Doing this without the state exposing it would require some kinda setup to keep the previous MatchState's HP values around on the client which would introduce a lot of unnecessary weirdness. --- .../RankedPlay/RankedPlayDamageInfo.cs | 56 +++++++++++++++++++ .../RankedPlay/RankedPlayUserInfo.cs | 9 +++ 2 files changed, 65 insertions(+) create mode 100644 osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayDamageInfo.cs diff --git a/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayDamageInfo.cs b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayDamageInfo.cs new file mode 100644 index 000000000000..66ae9fc9a658 --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayDamageInfo.cs @@ -0,0 +1,56 @@ +// 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 MessagePack; + +namespace osu.Game.Online.Multiplayer.MatchTypes.RankedPlay +{ + [Serializable] + [MessagePackObject] + public class RankedPlayDamageInfo : IEquatable + { + /// + /// Total amount of damage dealt. + /// + [Key(0)] + public required int Damage { get; init; } + + /// + /// Damage dealt before multipliers are applied. + /// + [Key(1)] + public required int RawDamage { get; init; } + + /// + /// Life before damage was applied. + /// + [Key(2)] + public required int OldLife { get; init; } + + /// + /// Life after damage was applied. + /// + [Key(3)] + public required int NewLife { get; init; } + + public bool Equals(RankedPlayDamageInfo? other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + + return Damage == other.Damage && RawDamage == other.RawDamage && OldLife == other.OldLife && NewLife == other.NewLife; + } + + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + + return Equals((RankedPlayDamageInfo)obj); + } + + public override int GetHashCode() => HashCode.Combine(Damage, RawDamage, OldLife, NewLife); + } +} diff --git a/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayUserInfo.cs b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayUserInfo.cs index a5064676c675..a370ef194c8c 100644 --- a/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayUserInfo.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/RankedPlay/RankedPlayUserInfo.cs @@ -34,5 +34,14 @@ public class RankedPlayUserInfo /// [Key(3)] public int RatingAfter { get; set; } + + /// + /// Information about damage being applied in the current stage. + /// + /// + /// This value is only expected to be populated during the stage. + /// + [Key(4)] + public RankedPlayDamageInfo? DamageInfo; } } From f39b310eb514580a2a00b6737195409ef8f24195 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Feb 2026 12:50:40 +0900 Subject: [PATCH 651/836] Add missing wait step to fix flaky test in `TestSceneModPresetColumn` See https://github.com/ppy/osu/actions/runs/21799682256/job/62893024859?pr=36627 --- osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs index d904511267c6..cc2817cecf0f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs @@ -90,6 +90,8 @@ public void TestNumericHotkeys() Origin = Anchor.Centre, }); + AddUntilStep("3 panels visible", () => this.ChildrenOfType().Count() == 3); + AddStep("select first preset", () => InputManager.Key(Key.Number1)); AddAssert("first panel selected", () => this.ChildrenOfType().ElementAt(0).Active.Value); From cae8d3f4d45c740eba57af0146cb502845544d51 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Feb 2026 13:29:21 +0900 Subject: [PATCH 652/836] Update production endpoints in an attempt to fix Russian player connections --- osu.Game/Online/ProductionEndpointConfiguration.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/ProductionEndpointConfiguration.cs b/osu.Game/Online/ProductionEndpointConfiguration.cs index 20583c8c7ee1..37ce2b64e127 100644 --- a/osu.Game/Online/ProductionEndpointConfiguration.cs +++ b/osu.Game/Online/ProductionEndpointConfiguration.cs @@ -10,9 +10,9 @@ public ProductionEndpointConfiguration() WebsiteUrl = APIUrl = @"https://osu.ppy.sh"; APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; APIClientID = "5"; - SpectatorUrl = "https://spectator.ppy.sh/spectator"; - MultiplayerUrl = "https://spectator.ppy.sh/multiplayer"; - MetadataUrl = "https://spectator.ppy.sh/metadata"; + SpectatorUrl = "https://spectator.osu.ppy.sh/spectator"; + MultiplayerUrl = "https://spectator.osu.ppy.sh/multiplayer"; + MetadataUrl = "https://spectator.osu.ppy.sh/metadata"; BeatmapSubmissionServiceUrl = "https://bss.ppy.sh"; } } From a1136c3ceab72547e70455e30633700d159a58d6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Feb 2026 19:39:30 +0900 Subject: [PATCH 653/836] Update framework (#36637) --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 083c83168f01..468b97ce29e7 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index ab61a6bfc43c..5966a28d50a8 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From dbce8886f864eeee1568dd84ab08b07c124c392f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 9 Feb 2026 11:58:52 +0100 Subject: [PATCH 654/836] Rename `Ruleset.GetHitResults{ -> ForDisplay}()` --- .../Database/StandardisedScoreMigrationTools.cs | 2 +- osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs | 2 +- osu.Game/Rulesets/Ruleset.cs | 13 +++++++++---- osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs | 2 +- osu.Game/Scoring/ScoreInfo.cs | 2 +- .../JudgementCounter/JudgementCountController.cs | 2 +- 6 files changed, 14 insertions(+), 9 deletions(-) diff --git a/osu.Game/Database/StandardisedScoreMigrationTools.cs b/osu.Game/Database/StandardisedScoreMigrationTools.cs index 15e3da3c1929..204198a41044 100644 --- a/osu.Game/Database/StandardisedScoreMigrationTools.cs +++ b/osu.Game/Database/StandardisedScoreMigrationTools.cs @@ -51,7 +51,7 @@ public static long GetNewStandardised(ScoreInfo score) var beatmap = new Beatmap(); - HitResult maxRulesetJudgement = ruleset.GetHitResults().First().result; + HitResult maxRulesetJudgement = ruleset.GetHitResultsForDisplay().First().result; // This is a list of all results, ordered from best to worst. // We are constructing a "best possible" score from the statistics provided because it's the best we can do. diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index 0c8943ba7d7e..1e62b23780b7 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -106,7 +106,7 @@ private TableColumn[] createHeaders(IReadOnlyList scores) var ruleset = scores.First().Ruleset.CreateInstance(); - foreach (var resultGroup in ruleset.GetHitResults().GroupBy(r => r.displayName)) + foreach (var resultGroup in ruleset.GetHitResultsForDisplay().GroupBy(r => r.displayName)) { if (!resultGroup.Any(r => allScoreStatistics.Contains(r.result))) continue; diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 0dbe6e884560..9cbdee66b2c4 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -13,6 +13,7 @@ using osu.Framework.Input.Bindings; using osu.Framework.IO.Stores; using osu.Framework.Localisation; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Legacy; using osu.Game.Configuration; @@ -334,13 +335,17 @@ protected Ruleset() public virtual StatisticItem[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap) => Array.Empty(); /// - /// Get all valid s for this ruleset. - /// Generally used for results display purposes, where it can't be determined if zero-count means the user has not achieved any or the type is not used by this ruleset. + /// Get all s for this ruleset which are important enough to displayed to the end user. + /// Used for results display purposes, where it can't be determined if zero-count means the user has not achieved any or the type is not used by this ruleset. /// + /// + /// is implicitly included. Special types like are not returned by this method. + /// Values are returned as ordered by . + /// /// - /// All valid s along with a display-friendly name. + /// All relevant s along with a display-friendly name. /// - public IEnumerable<(HitResult result, LocalisableString displayName)> GetHitResults() + public IEnumerable<(HitResult result, LocalisableString displayName)> GetHitResultsForDisplay() { var validResults = GetValidHitResults(); diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs index 393df65cc8c4..05070d96ecf5 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs @@ -211,7 +211,7 @@ public static void PopulateMaximumStatistics(ScoreInfo score, WorkingBeatmap wor var scoreProcessor = rulesetInstance.CreateScoreProcessor(); // Populate the maximum statistics. - HitResult maxBasicResult = rulesetInstance.GetHitResults() + HitResult maxBasicResult = rulesetInstance.GetHitResultsForDisplay() .Select(h => h.result) .Where(h => h.IsBasic()).MaxBy(scoreProcessor.GetBaseScoreForResult); diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index 9e10b93168f6..5c524e9d36f7 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -361,7 +361,7 @@ private void updateModsJson() public IEnumerable GetStatisticsForDisplay() { - foreach (var r in Ruleset.CreateInstance().GetHitResults()) + foreach (var r in Ruleset.CreateInstance().GetHitResultsForDisplay()) { int value = Statistics.GetValueOrDefault(r.result); diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCountController.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCountController.cs index c00cb3487bb1..a979ed03fd63 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCountController.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCountController.cs @@ -32,7 +32,7 @@ private void load(IBindable ruleset) { // Due to weirdness in judgements, some results have the same name and should be aggregated for display purposes. // There's only one case of this right now ("slider end"). - foreach (var group in ruleset.Value.CreateInstance().GetHitResults().GroupBy(r => r.displayName)) + foreach (var group in ruleset.Value.CreateInstance().GetHitResultsForDisplay().GroupBy(r => r.displayName)) { var judgementCount = new JudgementCount { From 3678ea0d0f6f6b4a54baf63d608de610163c81bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 9 Feb 2026 12:00:30 +0100 Subject: [PATCH 655/836] Publicise `Ruleset.GetValidHitResults()` --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs | 2 +- osu.Game/Rulesets/Ruleset.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index dc163ed77e1f..f77c64407f4e 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -176,7 +176,7 @@ public override IEnumerable GetModsFor(ModType type) public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetCatch }; - protected override IEnumerable GetValidHitResults() + public override IEnumerable GetValidHitResults() { return new[] { diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index cc64ee0d6986..6762f534de21 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -383,7 +383,7 @@ private PlayfieldType getPlayfieldType(int variant) return (PlayfieldType)Enum.GetValues(typeof(PlayfieldType)).Cast().OrderDescending().First(v => variant >= v); } - protected override IEnumerable GetValidHitResults() + public override IEnumerable GetValidHitResults() { return new[] { diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index b2f924ca3bf9..56442620b9cb 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -277,7 +277,7 @@ public override IEnumerable GetModsFor(ModType type) public override IRulesetConfigManager CreateConfig(SettingsStore? settings) => new OsuRulesetConfigManager(settings, RulesetInfo); - protected override IEnumerable GetValidHitResults() + public override IEnumerable GetValidHitResults() { return new[] { diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index b25672f719bb..02cee1f5a6b9 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -222,7 +222,7 @@ public override IEnumerable CreateEditorSetupSections() => public override RulesetSettingsSubsection CreateSettings() => new TaikoSettingsSubsection(this); - protected override IEnumerable GetValidHitResults() + public override IEnumerable GetValidHitResults() { return new[] { diff --git a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs index f45422e0c467..9b87ce4bb477 100644 --- a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs +++ b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs @@ -526,7 +526,7 @@ protected override double ComputeTotalScore(double comboProgress, double accurac // ReSharper disable once MemberHidesStaticFromOuterClass private class TestRuleset : Ruleset { - protected override IEnumerable GetValidHitResults() => new[] { HitResult.Great }; + public override IEnumerable GetValidHitResults() => new[] { HitResult.Great }; public override IEnumerable GetModsFor(ModType type) => throw new NotImplementedException(); diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 9cbdee66b2c4..708b1f02adf7 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -376,7 +376,7 @@ protected Ruleset() /// /// is implicitly included. Special types like are ignored even when specified. /// - protected virtual IEnumerable GetValidHitResults() => EnumExtensions.GetValuesInOrder(); + public virtual IEnumerable GetValidHitResults() => EnumExtensions.GetValuesInOrder(); /// /// Get a display friendly name for the specified result type. From 15c49a729efc8d27b770272efdcf2cfc2b4dfee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 9 Feb 2026 12:31:54 +0100 Subject: [PATCH 656/836] Adjust contract of `Ruleset.GetValidHitResults()` to always enumerate all results used --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 5 +++++ osu.Game.Rulesets.Mania/ManiaRuleset.cs | 6 ++++-- osu.Game.Rulesets.Osu/OsuRuleset.cs | 5 +++++ osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 3 +++ osu.Game/Rulesets/Ruleset.cs | 7 +++---- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index f77c64407f4e..eb8cf137faf7 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -181,10 +181,15 @@ public override IEnumerable GetValidHitResults() return new[] { HitResult.Great, + HitResult.Miss, HitResult.LargeTickHit, + HitResult.LargeTickMiss, HitResult.SmallTickHit, + HitResult.SmallTickMiss, HitResult.LargeBonus, + HitResult.IgnoreHit, + HitResult.IgnoreMiss, }; } diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 6762f534de21..3fad9d1047b6 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -392,9 +392,11 @@ public override IEnumerable GetValidHitResults() HitResult.Good, HitResult.Ok, HitResult.Meh, + HitResult.Miss, - // HitResult.SmallBonus is used for awarding perfect bonus score but is not included here as - // it would be a bit redundant to show this to the user. + HitResult.IgnoreHit, + HitResult.ComboBreak, + HitResult.IgnoreMiss, }; } diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 56442620b9cb..f0c4e7441063 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -284,12 +284,17 @@ public override IEnumerable GetValidHitResults() HitResult.Great, HitResult.Ok, HitResult.Meh, + HitResult.Miss, HitResult.LargeTickHit, + HitResult.LargeTickMiss, HitResult.SmallTickHit, + HitResult.SmallTickMiss, HitResult.SliderTailHit, HitResult.SmallBonus, HitResult.LargeBonus, + HitResult.IgnoreHit, + HitResult.IgnoreMiss, }; } diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 02cee1f5a6b9..686d40ff37da 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -228,9 +228,12 @@ public override IEnumerable GetValidHitResults() { HitResult.Great, HitResult.Ok, + HitResult.Miss, HitResult.SmallBonus, HitResult.LargeBonus, + HitResult.IgnoreHit, + HitResult.IgnoreMiss, }; } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 708b1f02adf7..905c4011dc97 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -358,6 +358,7 @@ protected Ruleset() case HitResult.None: case HitResult.IgnoreHit: case HitResult.IgnoreMiss: + case HitResult.ComboBreak: // display is handled as a completion count with corresponding "hit" type. case HitResult.LargeTickMiss: case HitResult.SmallTickMiss: @@ -371,11 +372,9 @@ protected Ruleset() /// /// Get all valid s for this ruleset. - /// Generally used for results display purposes, where it can't be determined if zero-count means the user has not achieved any or the type is not used by this ruleset. + /// Used for strict validation purposes. The ruleset should return ALL applicable types here + /// (except and obsolete types). /// - /// - /// is implicitly included. Special types like are ignored even when specified. - /// public virtual IEnumerable GetValidHitResults() => EnumExtensions.GetValuesInOrder(); /// From 655d725f0c16620e66ee046510e1d8d137abd9a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 10 Feb 2026 05:34:43 +0100 Subject: [PATCH 657/836] Perform extra checks when loading rulesets (#36641) --- osu.Game.Tests/Database/RulesetStoreTests.cs | 71 ++++++++++++++++++++ osu.Game/Rulesets/RealmRulesetStore.cs | 6 ++ 2 files changed, 77 insertions(+) diff --git a/osu.Game.Tests/Database/RulesetStoreTests.cs b/osu.Game.Tests/Database/RulesetStoreTests.cs index 29aec737704e..7ef2429491c5 100644 --- a/osu.Game.Tests/Database/RulesetStoreTests.cs +++ b/osu.Game.Tests/Database/RulesetStoreTests.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.Rulesets; +using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; @@ -116,6 +117,69 @@ public void TestOutdatedRulesetNotAvailable() }); } + [Test] + public void TestFakedRulesetIdIsDetected() + { + RunTestWithRealm((realm, storage) => + { + LoadTestRuleset.HasImplementations = true; + LoadTestRuleset.Version = Ruleset.CURRENT_RULESET_API_VERSION; + + var ruleset = new LoadTestRuleset(); + string rulesetShortName = ruleset.RulesetInfo.ShortName; + + realm.Write(r => r.Add(new RulesetInfo(rulesetShortName, ruleset.RulesetInfo.Name, ruleset.RulesetInfo.InstantiationInfo, 0) + { + Available = true, + })); + + Assert.That(realm.Run(r => r.Find(rulesetShortName)!.Available), Is.True); + + // Availability is updated on construction of a RealmRulesetStore + using var _ = new RealmRulesetStore(realm, storage); + + Assert.That(realm.Run(r => r.Find(rulesetShortName)!.Available), Is.False); + }); + } + + [Test] + public void TestMultipleRulesetWithSameOnlineIdsAreDetected() + { + RunTestWithRealm((realm, storage) => + { + LoadTestRuleset.HasImplementations = true; + LoadTestRuleset.Version = Ruleset.CURRENT_RULESET_API_VERSION; + LoadTestRuleset.OnlineID = 2; + + var first = new LoadTestRuleset(); + var second = new CatchRuleset(); + + realm.Write(r => r.Add(new RulesetInfo(first.ShortName, first.RulesetInfo.Name, first.RulesetInfo.InstantiationInfo, first.RulesetInfo.OnlineID) + { + Available = true, + })); + realm.Write(r => r.Add(new RulesetInfo(second.ShortName, second.RulesetInfo.Name, second.RulesetInfo.InstantiationInfo, second.RulesetInfo.OnlineID) + { + Available = true, + })); + + Assert.That(realm.Run(r => r.Find(first.ShortName)!.Available), Is.True); + Assert.That(realm.Run(r => r.Find(second.ShortName)!.Available), Is.True); + + // Availability is updated on construction of a RealmRulesetStore + using var _ = new RealmRulesetStore(realm, storage); + + Assert.That(realm.Run(r => r.Find(first.ShortName)!.Available), Is.False); + Assert.That(realm.Run(r => r.Find(second.ShortName)!.Available), Is.False); + + realm.Write(r => r.Remove(r.Find(first.ShortName)!)); + + using var __ = new RealmRulesetStore(realm, storage); + + Assert.That(realm.Run(r => r.Find(second.ShortName)!.Available), Is.True); + }); + } + private class LoadTestRuleset : Ruleset { public override string RulesetAPIVersionSupported => Version; @@ -124,6 +188,13 @@ private class LoadTestRuleset : Ruleset public static string Version { get; set; } = CURRENT_RULESET_API_VERSION; + public static int OnlineID { get; set; } = -1; + + public LoadTestRuleset() + { + RulesetInfo.OnlineID = OnlineID; + } + public override IEnumerable GetModsFor(ModType type) { if (!HasImplementations) diff --git a/osu.Game/Rulesets/RealmRulesetStore.cs b/osu.Game/Rulesets/RealmRulesetStore.cs index b93110426b54..52ea5f7f4b74 100644 --- a/osu.Game/Rulesets/RealmRulesetStore.cs +++ b/osu.Game/Rulesets/RealmRulesetStore.cs @@ -93,6 +93,12 @@ private void prepareDetachedRulesets() $"Ruleset API version is too old (was {instance.RulesetAPIVersionSupported}, expected {Ruleset.CURRENT_RULESET_API_VERSION})"); } + if (r.OnlineID != instanceInfo.OnlineID) + throw new InvalidOperationException($@"Online ID mismatch for ruleset {r.ShortName}: database has {r.OnlineID}, constructed instance has {instanceInfo.OnlineID}"); + + if (r.OnlineID > 0 && rulesets.Any(otherRuleset => otherRuleset.ShortName != r.ShortName && otherRuleset.OnlineID == r.OnlineID)) + throw new InvalidOperationException($@"Ruleset {r.ShortName} shares online ID {r.OnlineID} with another ruleset"); + // If a ruleset isn't up-to-date with the API, it could cause a crash at an arbitrary point of execution. // To eagerly handle cases of missing implementations, enumerate all types here and mark as non-available on throw. resolvedType.Assembly.GetTypes(); From 25d2c04787d78db177178538f3e40ad4a335cc9a Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Tue, 10 Feb 2026 13:10:34 +0500 Subject: [PATCH 658/836] Add early returns in `HarmonicSkill` and `OsuDifficultyCalculator` (#36644) --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 6 ++++++ osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs | 3 --- osu.Game/Rulesets/Difficulty/Skills/HarmonicSkill.cs | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index d30f556c77f1..790580ea8e18 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -146,6 +146,12 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat public static double SumCognitionDifficulty(double reading, double flashlight) { + if (reading <= 0) + return flashlight; + + if (flashlight <= 0) + return reading; + // Nerf flashlight value in cognition sum when reading is greater than flashlight return DifficultyCalculationUtils.Norm(OsuPerformanceCalculator.PERFORMANCE_NORM_EXPONENT, reading, flashlight * Math.Clamp(flashlight / reading, 0.25, 1.0)); } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs index c475b2cfd817..07dc99e0f2c3 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs @@ -51,9 +51,6 @@ protected override void ApplyDifficultyTransformation(double[] difficulties) { const double reduced_difficulty_base_line = 0.0; // Assume the first seconds are completely memorised - if (difficulties.Length == 0) - return; - int reducedNoteCount = calculateReducedNoteCount(); for (int i = 0; i < Math.Min(difficulties.Length, reducedNoteCount); i++) diff --git a/osu.Game/Rulesets/Difficulty/Skills/HarmonicSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/HarmonicSkill.cs index b89b53d8cbac..cdd6048b8610 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/HarmonicSkill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/HarmonicSkill.cs @@ -59,6 +59,9 @@ public override double DifficultyValue() // These notes will not contribute to the difficulty. double[] difficulties = ObjectDifficulties.Where(p => p > 0).ToArray(); + if (difficulties.Length == 0) + return 0; + ApplyDifficultyTransformation(difficulties); double difficulty = 0; From 56bc80ffb96e9a4b52c70021ce8dc8266580830c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 10 Feb 2026 22:08:07 +0900 Subject: [PATCH 659/836] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 0bc4d1653e95..a2b108fc0a6f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From 3a4631954fc5e2005fd11449941f503667e7a600 Mon Sep 17 00:00:00 2001 From: Givy120 <89256026+Givikap120@users.noreply.github.com> Date: Tue, 10 Feb 2026 15:18:16 +0200 Subject: [PATCH 660/836] Nerf HD perfect stack reward (#36623) Safety measure to prevent potential major abuse maps. The alternative is reducing nerf on multiplier (for example 5000 instead of 2500), but increase nerf if rhythm is the same. Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com> --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs index 647278c520cc..326e98609c31 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs @@ -132,7 +132,7 @@ private static double calculateHiddenDifficulty(OsuDifficultyHitObject currObj, // Buff perfect stacks only if current note is completely invisible at the time you click the previous note. if (currObj.LazyJumpDistance == 0 && currObj.OpacityAt(previousObj.BaseObject.StartTime + previousObj.Preempt, true) == 0 && previousObj.StartTime + previousObj.Preempt > currObj.StartTime) - hiddenDifficulty += hidden_multiplier * 7500 / Math.Pow(currObj.AdjustedDeltaTime, 1.5); // Perfect stacks are harder the less time between notes + hiddenDifficulty += hidden_multiplier * 2500 / Math.Pow(currObj.AdjustedDeltaTime, 1.5); // Perfect stacks are harder the less time between notes return hiddenDifficulty; } From 50426eb3c8421d2aa2c31bdf937db9bb3a83a161 Mon Sep 17 00:00:00 2001 From: Krzysztof Gutkowski Date: Tue, 10 Feb 2026 15:18:36 +0100 Subject: [PATCH 661/836] Refactor UpdateableTeamFlag for use on team overlay (#36286) Part of #32584. Very much inspired by the respective component for displaying profile pictures on the user overlay * allow disabling interactivity/tooltips * add option to show placeholder on null team instead of hiding component entirely * move setting corner radius out to respective parent components to allow for easier overriding --- .../Online/TestSceneClickableTeamFlag.cs | 61 +++++++++ .../Online/TestSceneUpdateableTeamFlag.cs | 43 ++++++ .../Online/API/Requests/Responses/APITeam.cs | 2 +- .../Participants/ParticipantPanel.cs | 2 +- osu.Game/Users/Drawables/ClickableTeamFlag.cs | 52 ++++++++ osu.Game/Users/Drawables/DrawableTeamFlag.cs | 53 ++++++++ .../Users/Drawables/UpdateableTeamFlag.cs | 124 +++++++++--------- 7 files changed, 272 insertions(+), 65 deletions(-) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneClickableTeamFlag.cs create mode 100644 osu.Game.Tests/Visual/Online/TestSceneUpdateableTeamFlag.cs create mode 100644 osu.Game/Users/Drawables/ClickableTeamFlag.cs create mode 100644 osu.Game/Users/Drawables/DrawableTeamFlag.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneClickableTeamFlag.cs b/osu.Game.Tests/Visual/Online/TestSceneClickableTeamFlag.cs new file mode 100644 index 000000000000..525cc9758153 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneClickableTeamFlag.cs @@ -0,0 +1,61 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Graphics.Cursor; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Users.Drawables; +using osuTK; + +namespace osu.Game.Tests.Visual.Online +{ + public partial class TestSceneClickableTeamFlag : OsuManualInputManagerTestScene + { + [SetUpSteps] + public void SetUp() + { + AddStep("create flags", () => + { + Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Spacing = new Vector2(10f), + Children = new[] + { + new ClickableTeamFlag( + new APITeam + { + Id = 1, + Name = "Collective Wangs", + ShortName = "WANG", + }, showTooltipOnHover: false) { Width = 300, Height = 150 }, + new ClickableTeamFlag( + new APITeam + { + Id = 2, + Name = "mom?", + ShortName = "MOM", + FlagUrl = "https://assets.ppy.sh/teams/flag/1/b46fb10dbfd8a35dc50e6c00296c0dc6172dffc3ed3d3a4b379277ba498399fe.png", + }, showTooltipOnHover: true) { Width = 300, Height = 150 }, + }, + }; + }); + } + + [Test] + public void TestHover() + { + AddStep("hover flag with no tooltip", () => InputManager.MoveMouseTo(this.ChildrenOfType().ElementAt(0))); + AddWaitStep("wait", 3); + AddAssert("tooltip is not visible", () => this.ChildrenOfType().FirstOrDefault()?.State.Value, () => Is.EqualTo(Visibility.Hidden)); + AddStep("hover flag with tooltip", () => InputManager.MoveMouseTo(this.ChildrenOfType().ElementAt(1))); + AddUntilStep("wait for tooltip to show", () => this.ChildrenOfType().FirstOrDefault()?.State.Value, () => Is.EqualTo(Visibility.Visible)); + } + } +} diff --git a/osu.Game.Tests/Visual/Online/TestSceneUpdateableTeamFlag.cs b/osu.Game.Tests/Visual/Online/TestSceneUpdateableTeamFlag.cs new file mode 100644 index 000000000000..1813ede83085 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneUpdateableTeamFlag.cs @@ -0,0 +1,43 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Users.Drawables; + +namespace osu.Game.Tests.Visual.Online +{ + [TestFixture] + public partial class TestSceneUpdateableTeamFlag : OsuTestScene + { + [Test] + public void TestHideOnNull() + { + UpdateableTeamFlag flag = null!; + + AddStep("create flag with team", () => Child = flag = new UpdateableTeamFlag(createTeam(), hideOnNull: true) { Width = 300, Height = 150 }); + AddAssert("flag is present", () => flag.IsPresent, () => Is.True); + AddStep("set team to null", () => flag.Team = null); + AddAssert("flag is not present", () => flag.IsPresent, () => Is.False); + } + + [Test] + public void DontHideOnNull() + { + UpdateableTeamFlag flag = null!; + + AddStep("create flag with team", () => Child = flag = new UpdateableTeamFlag(createTeam(), hideOnNull: false) { Width = 300, Height = 150 }); + AddAssert("flag is present", () => flag.IsPresent, () => Is.True); + AddStep("set team to null", () => flag.Team = null); + AddAssert("flag is present", () => flag.IsPresent, () => Is.True); + } + + private static APITeam createTeam() => new APITeam + { + Id = 2, + Name = "mom?", + ShortName = "MOM", + FlagUrl = @"https://assets.ppy.sh/teams/flag/1/b46fb10dbfd8a35dc50e6c00296c0dc6172dffc3ed3d3a4b379277ba498399fe.png", + }; + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APITeam.cs b/osu.Game/Online/API/Requests/Responses/APITeam.cs index b4fcc2d26e0b..1d4aa17cda69 100644 --- a/osu.Game/Online/API/Requests/Responses/APITeam.cs +++ b/osu.Game/Online/API/Requests/Responses/APITeam.cs @@ -18,6 +18,6 @@ public class APITeam public string ShortName { get; set; } = string.Empty; [JsonProperty(@"flag_url")] - public string FlagUrl = string.Empty; + public string? FlagUrl = string.Empty; } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index 19868082fa0d..c9804a1bf8f0 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -245,7 +245,7 @@ private void updateUser() userFlag.CountryCode = user?.CountryCode ?? default; teamFlagContainer.Child = new UpdateableTeamFlag(user?.Team) { - Size = new Vector2(40, 20) + Size = new Vector2(40, 20), }; username.Text = user?.Username ?? string.Empty; diff --git a/osu.Game/Users/Drawables/ClickableTeamFlag.cs b/osu.Game/Users/Drawables/ClickableTeamFlag.cs new file mode 100644 index 000000000000..69d592054e5c --- /dev/null +++ b/osu.Game/Users/Drawables/ClickableTeamFlag.cs @@ -0,0 +1,52 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Users.Drawables +{ + public partial class ClickableTeamFlag : OsuClickableContainer + { + private readonly APITeam? team; + + [Resolved] + private OsuGame? game { get; set; } + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + /// + /// A clickable flag component for the specified team, with UI sounds and a tooltip. + /// + /// The team. A null value will show a placeholder background. + /// If set to true, the team's name is displayed in the tooltip. + public ClickableTeamFlag(APITeam? team, bool showTooltipOnHover = true) + { + this.team = team; + + if (team == null) + return; + + Action = openProfile; + + if (showTooltipOnHover) + TooltipText = team.Name; + } + + [BackgroundDependencyLoader] + private void load() + { + LoadComponentAsync(new DrawableTeamFlag(team) { RelativeSizeAxes = Axes.Both }, Add); + } + + private void openProfile() + { + if (team != null) + game?.OpenUrlExternally($@"{api.Endpoints.WebsiteUrl}/teams/{team.Id}"); + } + } +} diff --git a/osu.Game/Users/Drawables/DrawableTeamFlag.cs b/osu.Game/Users/Drawables/DrawableTeamFlag.cs new file mode 100644 index 000000000000..27b5f447a5ac --- /dev/null +++ b/osu.Game/Users/Drawables/DrawableTeamFlag.cs @@ -0,0 +1,53 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Users.Drawables +{ + [LongRunningLoad] + public partial class DrawableTeamFlag : CompositeDrawable + { + private readonly APITeam? team; + + private readonly Sprite sprite; + + /// + /// A simple, non-interactable flag sprite for the specified user. + /// + /// The team. A null value will show a placeholder background. + public DrawableTeamFlag(APITeam? team) + { + this.team = team; + + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Colour4.FromHex("333"), + }, + sprite = new Sprite + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + FillMode = FillMode.Fit, + } + }; + } + + [BackgroundDependencyLoader] + private void load(LargeTextureStore textures) + { + if (team != null) + sprite.Texture = textures.Get(team.FlagUrl); + } + } +} diff --git a/osu.Game/Users/Drawables/UpdateableTeamFlag.cs b/osu.Game/Users/Drawables/UpdateableTeamFlag.cs index 517eb589b9d6..adaa192451b6 100644 --- a/osu.Game/Users/Drawables/UpdateableTeamFlag.cs +++ b/osu.Game/Users/Drawables/UpdateableTeamFlag.cs @@ -1,17 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; +using osu.Framework.Graphics.Effects; using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Users.Drawables @@ -31,80 +23,86 @@ public APITeam? Team } } - protected override double LoadDelay => 200; - - public UpdateableTeamFlag(APITeam? team = null) + public new bool Masking { - Team = team; - - Masking = true; + get => base.Masking; + set => base.Masking = value; } - protected override Drawable? CreateDrawable(APITeam? team) - { - if (team == null) - return Empty(); + private bool useDefaultRadius = true; - return new TeamFlag(team) { RelativeSizeAxes = Axes.Both }; + public new float CornerRadius + { + get => base.CornerRadius; + set + { + useDefaultRadius = false; + base.CornerRadius = value; + } } - // Generally we just want team flags to disappear if the user doesn't have one. - // This also handles fill flow cases and avoids spacing being added for non-displaying flags. - public override bool IsPresent => base.IsPresent && Team != null; - - protected override void Update() + public new EdgeEffectParameters EdgeEffect { - base.Update(); - - CornerRadius = DrawHeight / 8; + get => base.EdgeEffect; + set => base.EdgeEffect = value; } - [LongRunningLoad] - public partial class TeamFlag : CompositeDrawable, IHasTooltip - { - private readonly APITeam team; + protected override double LoadDelay => 200; - public LocalisableString TooltipText { get; } + private readonly bool isInteractive; + private readonly bool hideOnNull; + private readonly bool showTooltipOnHover; + + /// + /// Construct a new UpdateableTeamFlag. + /// + /// The initial team to display. + /// If set to true, hover/click sounds will play and clicking the flag will open the team's profile. + /// + /// If set to true, the team's name is displayed in the tooltip. + /// Only has an effect if is true. + /// + /// Whether to hide the flag when the provided team is null. + public UpdateableTeamFlag(APITeam? team = null, bool isInteractive = true, bool hideOnNull = true, bool showTooltipOnHover = true) + { + this.isInteractive = isInteractive; + this.hideOnNull = hideOnNull; + this.showTooltipOnHover = showTooltipOnHover; - [Resolved] - private OsuGame? game { get; set; } + Team = team; - [Resolved] - private IAPIProvider api { get; set; } = null!; + Masking = true; + } - public TeamFlag(APITeam team) - { - this.team = team; - TooltipText = team.Name; - } + protected override Drawable? CreateDrawable(APITeam? team) + { + if (team == null && hideOnNull) + return Empty(); - [BackgroundDependencyLoader] - private void load(LargeTextureStore textures) + if (isInteractive) { - InternalChildren = new Drawable[] + return new ClickableTeamFlag(team, showTooltipOnHover) { - new HoverClickSounds(), - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Colour4.FromHex("333"), - }, - new Sprite - { - RelativeSizeAxes = Axes.Both, - Texture = textures.Get(team.FlagUrl), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fit, - } + RelativeSizeAxes = Axes.Both, }; } - protected override bool OnClick(ClickEvent e) + return new DrawableTeamFlag(team) { - game?.OpenUrlExternally($"{api.Endpoints.WebsiteUrl}/teams/{team.Id}"); - return true; - } + RelativeSizeAxes = Axes.Both, + }; } + + protected override void Update() + { + base.Update(); + + if (useDefaultRadius) + base.CornerRadius = DrawHeight / 8; + } + + // Generally we just want team flags to disappear if the user doesn't have one. + // This also handles fill flow cases and avoids spacing being added for non-displaying flags. + public override bool IsPresent => base.IsPresent && (Team != null || !hideOnNull); } } From c8318d6edda3c169927277272c23e3a2db672695 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Wed, 11 Feb 2026 01:01:51 +0500 Subject: [PATCH 662/836] Refactor `DifficultyHitObject` to include `ClockRate` and `HitWindows` (#36630) This changes difficulty calculations to use `ClockRate` and `HitWindows` from `DifficultyHitObjects` instead of providing them manually. It's main purpose is unifying all the calculations to use the same source of truth, and also allowing future work on supporting variable clockrates. --------- Co-authored-by: James Wilson --- .../Difficulty/CatchDifficultyCalculator.cs | 14 ++++------ .../Evaluators/MovementEvaluator.cs | 6 +++- .../Difficulty/Skills/Movement.cs | 18 ++---------- .../Difficulty/Evaluators/RhythmEvaluator.cs | 3 +- .../Difficulty/Evaluators/SpeedEvaluator.cs | 3 +- .../Difficulty/OsuDifficultyCalculator.cs | 2 +- .../Preprocessing/OsuDifficultyHitObject.cs | 22 +-------------- .../Difficulty/Skills/Reading.cs | 20 +++++-------- .../Difficulty/Evaluators/RhythmEvaluator.cs | 5 +++- .../Preprocessing/TaikoDifficultyHitObject.cs | 2 +- .../Difficulty/Skills/Rhythm.cs | 7 ++--- .../Difficulty/TaikoDifficultyCalculator.cs | 7 +---- .../Preprocessing/DifficultyHitObject.cs | 28 +++++++++++++++++++ 13 files changed, 62 insertions(+), 75 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 14a8ff31c56f..4e30be689cb9 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -22,8 +22,6 @@ public class CatchDifficultyCalculator : DifficultyCalculator { private const double difficulty_multiplier = 4.59; - private float halfCatcherWidth; - public override int Version => 20250306; public CatchDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) @@ -52,6 +50,11 @@ protected override IEnumerable CreateDifficultyHitObjects(I List objects = new List(); + float halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.Difficulty) * 0.5f; + + // For circle sizes above 5.5, reduce the catcher width further to simulate imperfect gameplay. + halfCatcherWidth *= 1 - (Math.Max(0, beatmap.Difficulty.CircleSize - 5.5f) * 0.0625f); + // In 2B beatmaps, it is possible that a normal Fruit is placed in the middle of a JuiceStream. foreach (var hitObject in CatchBeatmap.GetPalpableObjects(beatmap.HitObjects)) { @@ -70,14 +73,9 @@ protected override IEnumerable CreateDifficultyHitObjects(I protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) { - halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.Difficulty) * 0.5f; - - // For circle sizes above 5.5, reduce the catcher width further to simulate imperfect gameplay. - halfCatcherWidth *= 1 - (Math.Max(0, beatmap.Difficulty.CircleSize - 5.5f) * 0.0625f); - return new Skill[] { - new Movement(mods, halfCatcherWidth, clockRate), + new Movement(mods), }; } diff --git a/osu.Game.Rulesets.Catch/Difficulty/Evaluators/MovementEvaluator.cs b/osu.Game.Rulesets.Catch/Difficulty/Evaluators/MovementEvaluator.cs index 618b18394341..8c44cd35693c 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/Evaluators/MovementEvaluator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/Evaluators/MovementEvaluator.cs @@ -11,12 +11,16 @@ public static class MovementEvaluator { private const double direction_change_bonus = 21.0; - public static double EvaluateDifficultyOf(DifficultyHitObject current, double catcherSpeedMultiplier) + public static double EvaluateDifficultyOf(DifficultyHitObject current) { var catchCurrent = (CatchDifficultyHitObject)current; var catchLast = (CatchDifficultyHitObject)current.Previous(0); var catchLastLast = (CatchDifficultyHitObject)current.Previous(1); + // In catch, clockrate adjustments do not only affect the timings of hitobjects, + // but also the speed of the player's catcher, which has an impact on difficulty + double catcherSpeedMultiplier = current.ClockRate; + double weightedStrainTime = catchCurrent.StrainTime + 13 + (3 / catcherSpeedMultiplier); double distanceAddition = (Math.Pow(Math.Abs(catchCurrent.DistanceMoved), 1.3) / 510); diff --git a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs index 90055b9aa384..332ef7e17bf9 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs @@ -17,28 +17,14 @@ public class Movement : StrainDecaySkill protected override int SectionLength => 750; - protected readonly float HalfCatcherWidth; - - /// - /// The speed multiplier applied to the player's catcher. - /// - private readonly double catcherSpeedMultiplier; - - public Movement(Mod[] mods, float halfCatcherWidth, double clockRate) + public Movement(Mod[] mods) : base(mods) { - HalfCatcherWidth = halfCatcherWidth; - - // In catch, clockrate adjustments do not only affect the timings of hitobjects, - // but also the speed of the player's catcher, which has an impact on difficulty - // TODO: Support variable clockrates caused by mods such as ModTimeRamp - // (perhaps by using IApplicableToRate within the CatchDifficultyHitObject constructor to set a catcher speed for each object before processing) - catcherSpeedMultiplier = clockRate; } protected override double StrainValueOf(DifficultyHitObject current) { - return MovementEvaluator.EvaluateDifficultyOf(current, catcherSpeedMultiplier); + return MovementEvaluator.EvaluateDifficultyOf(current); } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs index eca4619e4aa9..f97bb85b562a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs @@ -8,6 +8,7 @@ using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { @@ -28,7 +29,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) double rhythmComplexitySum = 0; - double deltaDifferenceEpsilon = ((OsuDifficultyHitObject)current).HitWindowGreat * 0.3; + double deltaDifferenceEpsilon = ((OsuDifficultyHitObject)current).HitWindow(HitResult.Great) * 0.3; var island = new Island(deltaDifferenceEpsilon); var previousIsland = new Island(deltaDifferenceEpsilon); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs index 32bf36b0eb96..5b724af2a025 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs @@ -6,6 +6,7 @@ using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { @@ -33,7 +34,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) // Cap deltatime to the OD 300 hitwindow. // 0.93 is derived from making sure 260bpm OD8 streams aren't nerfed harshly, whilst 0.92 limits the effect of the cap. - strainTime /= Math.Clamp((strainTime / osuCurrObj.HitWindowGreat) / 0.93, 0.92, 1); + strainTime /= Math.Clamp((strainTime / osuCurrObj.HitWindow(HitResult.Great)) / 0.93, 0.92, 1); // speedBonus will be 0.0 for BPM < 200 double speedBonus = 0.0; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 790580ea8e18..3744a55a5292 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -182,7 +182,7 @@ protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clo new Aim(mods, true), new Aim(mods, false), new Speed(mods), - new Reading(beatmap, mods, clockRate) + new Reading(mods) }; if (mods.Any(h => h is OsuModFlashlight)) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 8b81788c73ad..b9b985fdc7c5 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -46,11 +46,6 @@ public class OsuDifficultyHitObject : DifficultyHitObject /// public readonly double Preempt; - /// - /// Beatmap playback rate. - /// - public readonly double ClockRate; - /// /// Normalised distance from the start position of the previous to the start position of this . /// @@ -121,11 +116,6 @@ public class OsuDifficultyHitObject : DifficultyHitObject /// public double? Angle { get; private set; } - /// - /// Retrieves the full hit window for a Great . - /// - public double HitWindowGreat { get; private set; } - /// /// Selective bonus for maps with higher circle size. /// @@ -146,18 +136,8 @@ public OsuDifficultyHitObject(HitObject hitObject, HitObject lastObject, double SmallCircleBonus = Math.Max(1.0, 1.0 + (30 - BaseObject.Radius) / 40); - ClockRate = clockRate; Preempt = BaseObject.TimePreempt / clockRate; - if (BaseObject is Slider sliderObject) - { - HitWindowGreat = 2 * sliderObject.HeadCircle.HitWindows.WindowFor(HitResult.Great) / clockRate; - } - else - { - HitWindowGreat = 2 * BaseObject.HitWindows.WindowFor(HitResult.Great) / clockRate; - } - computeSliderCursorPosition(); setDistances(clockRate); } @@ -206,7 +186,7 @@ public double GetDoubletapness(OsuDifficultyHitObject? osuNextObj) double deltaDifference = Math.Abs(nextDeltaTime - currDeltaTime); double speedRatio = currDeltaTime / Math.Max(currDeltaTime, deltaDifference); - double windowRatio = Math.Pow(Math.Min(1, currDeltaTime / HitWindowGreat), 5); + double windowRatio = Math.Pow(Math.Min(1, currDeltaTime / HitWindow(HitResult.Great)), 5); return 1.0 - Math.Pow(speedRatio, 1 - windowRatio); } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs index 07dc99e0f2c3..c548da5b8d76 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs @@ -5,12 +5,10 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Utils; -using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; using osu.Game.Rulesets.Osu.Mods; @@ -18,17 +16,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills { public class Reading : HarmonicSkill { - private readonly IReadOnlyList objectList; + private readonly List objectList = new List(); - private readonly double clockRate; private readonly bool hasHiddenMod; - public Reading(IBeatmap beatmap, Mod[] mods, double clockRate) + public Reading(Mod[] mods) : base(mods) { - this.clockRate = clockRate; hasHiddenMod = mods.OfType().Any(m => !m.OnlyFadeApproachCircles.Value); - objectList = beatmap.HitObjects; } private double currentDifficulty; @@ -40,6 +35,8 @@ public Reading(IBeatmap beatmap, Mod[] mods, double clockRate) protected override double ObjectDifficultyOf(DifficultyHitObject current) { + objectList.Add(current); + currentDifficulty *= strainDecay(current.DeltaTime); currentDifficulty += ReadingEvaluator.EvaluateDifficultyOf(current, hasHiddenMod) * skillMultiplier; @@ -64,19 +61,16 @@ private int calculateReducedNoteCount() { const double reduced_difficulty_duration = 60 * 1000; - if (objectList.Count < 2) + if (objectList.Count == 0) return 0; - // We take the 2nd note to match `CreateDifficultyHitObjects` - HitObject firstDifficultyObject = objectList[1]; - - double reducedDuration = (firstDifficultyObject.StartTime / clockRate) + reduced_difficulty_duration; + double reducedDuration = objectList.First().StartTime + reduced_difficulty_duration; int reducedNoteCount = 0; foreach (var hitObject in objectList) { - if (hitObject.StartTime / clockRate > reducedDuration) + if (hitObject.StartTime > reducedDuration) break; reducedNoteCount++; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs index c0acd5935a62..e7e216a08449 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Utils; +using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data; @@ -17,7 +18,7 @@ public class RhythmEvaluator /// /// Evaluate the difficulty of a hitobject considering its interval change. /// - public static double EvaluateDifficultyOf(DifficultyHitObject hitObject, double hitWindow) + public static double EvaluateDifficultyOf(DifficultyHitObject hitObject) { if (hitObject.BaseObject is not Hit) return 0; @@ -29,6 +30,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject hitObject, double double samePattern = 0; double intervalPenalty = 0; + double hitWindow = hitObject.HitWindow(HitResult.Great) / 2.0; // this is practically incorrect, but kept as is for balancing + if (rhythmData.SameRhythmGroupedHitObjects?.FirstHitObject == hitObject) // Difficulty for SameRhythmGroupedHitObjects { sameRhythm += 10.0 * evaluateDifficultyOf(rhythmData.SameRhythmGroupedHitObjects, hitWindow); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index f407e13ff1d6..f9bb38688d6f 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -7,10 +7,10 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; -using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm; using osu.Game.Rulesets.Taiko.Difficulty.Utils; +using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs index 45d0d0a5480f..e41f3ff5e975 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs @@ -17,17 +17,14 @@ public class Rhythm : StrainDecaySkill protected override double SkillMultiplier => 1.0; protected override double StrainDecayBase => 0.4; - private readonly double greatHitWindow; - - public Rhythm(Mod[] mods, double greatHitWindow) + public Rhythm(Mod[] mods) : base(mods) { - this.greatHitWindow = greatHitWindow; } protected override double StrainValueOf(DifficultyHitObject current) { - double difficulty = RhythmEvaluator.EvaluateDifficultyOf(current, greatHitWindow); + double difficulty = RhythmEvaluator.EvaluateDifficultyOf(current); // To prevent abuse of exceedingly long intervals between awkward rhythms, we penalise its difficulty. double staminaDifficulty = StaminaEvaluator.EvaluateDifficultyOf(current) - 0.5; // Remove base strain diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 42a5dad31520..e9163274ba6c 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -10,13 +10,11 @@ using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm; using osu.Game.Rulesets.Taiko.Difficulty.Skills; using osu.Game.Rulesets.Taiko.Mods; -using osu.Game.Rulesets.Taiko.Scoring; namespace osu.Game.Rulesets.Taiko.Difficulty { @@ -43,15 +41,12 @@ public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) { - HitWindows hitWindows = new TaikoHitWindows(); - hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); - isConvert = beatmap.BeatmapInfo.Ruleset.OnlineID == 0; isRelax = mods.Any(h => h is TaikoModRelax); return new Skill[] { - new Rhythm(mods, hitWindows.WindowFor(HitResult.Great) / clockRate), + new Rhythm(mods), new Reading(mods), new Colour(mods), new Stamina(mods, false, isConvert), diff --git a/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs b/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs index 9785865192bd..1db231945636 100644 --- a/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs +++ b/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Difficulty.Preprocessing { @@ -45,6 +46,11 @@ public class DifficultyHitObject /// public readonly double EndTime; + /// + /// Beatmap playback rate. + /// + public readonly double ClockRate; + /// /// Creates a new . /// @@ -62,6 +68,7 @@ public DifficultyHitObject(HitObject hitObject, HitObject lastObject, double clo DeltaTime = (hitObject.StartTime - lastObject.StartTime) / clockRate; StartTime = hitObject.StartTime / clockRate; EndTime = hitObject.GetEndTime() / clockRate; + ClockRate = clockRate; } public DifficultyHitObject Previous(int backwardsIndex) @@ -75,5 +82,26 @@ public DifficultyHitObject Next(int forwardsIndex) int index = Index + (forwardsIndex + 1); return index >= 0 && index < difficultyHitObjects.Count ? difficultyHitObjects[index] : default; } + + /// + /// Retrieves the full hit window for a . + /// + public virtual double HitWindow(HitResult hitResult) + { + // Try to get HitWindows from nested hit objects + // This is important for objects such as Slider in osu! where the object itself has HitWindows set to Empty, but the nested SliderHead has proper hit windows + if (BaseObject.HitWindows == HitWindows.Empty) + { + foreach (var nestedHitObject in BaseObject.NestedHitObjects) + { + if (nestedHitObject.HitWindows == HitWindows.Empty) + continue; + + return 2 * nestedHitObject.HitWindows.WindowFor(hitResult) / ClockRate; + } + } + + return 2 * BaseObject.HitWindows.WindowFor(hitResult) / ClockRate; + } } } From 5afd6c68352c1e82628b82164cfa5423c4590b55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 11 Feb 2026 16:57:03 +0100 Subject: [PATCH 663/836] Add user role to `MultiplayerRoomUser` (#36652) - Related to https://github.com/ppy/osu-server-spectator/issues/406 Adding this field to this model has several vague reasons that I can't fully formulate yet, but I can't really see myself going forward *without* this. - People were very excited about having referees displayed on the room participants' list, and so adding the referees as real `MultiplayerRoomUser`s helps this. Having the role could even be used client-side to show a special icon or other status on the participants list. (Which isn't done yet, could be as an aesthetic follow-up after the basics are in place.) - Server-side, having this field is convenient for things like permission checks or just plain logic, as with two hubs you just need to do different *stuff* on a `MultiplayerRoomUser`. --- osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs | 6 ++++++ .../Online/Multiplayer/MultiplayerRoomUserRole.cs | 11 +++++++++++ 2 files changed, 17 insertions(+) create mode 100644 osu.Game/Online/Multiplayer/MultiplayerRoomUserRole.cs diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs index d19386c98d71..3bf15a781fd5 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs @@ -55,6 +55,12 @@ public class MultiplayerRoomUser : IEquatable [Key(7)] public bool VotedToSkipIntro; + /// + /// The role of this user in the room. + /// + [Key(8)] + public MultiplayerRoomUserRole Role; + [IgnoreMember] public APIUser? User { get; set; } diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomUserRole.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomUserRole.cs new file mode 100644 index 000000000000..edef4f4c358f --- /dev/null +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomUserRole.cs @@ -0,0 +1,11 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Online.Multiplayer +{ + public enum MultiplayerRoomUserRole + { + Player, + Referee, + } +} From 860427e4aeded33642af1920116d60141b88914c Mon Sep 17 00:00:00 2001 From: Neti Date: Fri, 13 Feb 2026 00:48:07 -0500 Subject: [PATCH 664/836] Fix corner radius for user tag glow (#36659) Fixes incorrect glow corner radius around user tag buttons Before: image After: image --- osu.Game/Screens/Ranking/UserTagControl.DrawableUserTag.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/UserTagControl.DrawableUserTag.cs b/osu.Game/Screens/Ranking/UserTagControl.DrawableUserTag.cs index 0f88515f598b..09af68a4f71e 100644 --- a/osu.Game/Screens/Ranking/UserTagControl.DrawableUserTag.cs +++ b/osu.Game/Screens/Ranking/UserTagControl.DrawableUserTag.cs @@ -66,7 +66,7 @@ public DrawableUserTag(UserTag userTag, bool showVoteCount = true) [BackgroundDependencyLoader] private void load() { - CornerRadius = 5; + CornerRadius = 10; Masking = true; EdgeEffect = new EdgeEffectParameters From 94d9de955fffd1c7afc8544b56d01cd3b8ac3175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 13 Feb 2026 17:24:42 +0100 Subject: [PATCH 665/836] Add explanations for scoring mode used in ranked & total score tooltips (#36663) Because people get confused by how this works. Shows on results screen where the post-play statistics updates go. https://github.com/user-attachments/assets/ef3a91d1-86dd-4029-8f0f-bdf0b727ca6c --- osu.Game/Localisation/RankingStatisticsStrings.cs | 5 +++++ .../Screens/Ranking/Statistics/User/RankedScoreChangeRow.cs | 2 ++ osu.Game/Screens/Ranking/Statistics/User/RankingChangeRow.cs | 4 +++- .../Screens/Ranking/Statistics/User/TotalScoreChangeRow.cs | 2 ++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/RankingStatisticsStrings.cs b/osu.Game/Localisation/RankingStatisticsStrings.cs index b69d96d1a1bb..821c3db6f15f 100644 --- a/osu.Game/Localisation/RankingStatisticsStrings.cs +++ b/osu.Game/Localisation/RankingStatisticsStrings.cs @@ -34,6 +34,11 @@ public static class RankingStatisticsStrings /// public static LocalisableString NotAvailable => new TranslatableString(getKey(@"not_available"), @"(not available)"); + /// + /// "Classic scoring mode is always used for this statistic." + /// + public static LocalisableString ClassicScoringAlwaysUsed => new TranslatableString(getKey(@"classic_scoring_always_used"), @"Classic scoring mode is always used for this statistic."); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Screens/Ranking/Statistics/User/RankedScoreChangeRow.cs b/osu.Game/Screens/Ranking/Statistics/User/RankedScoreChangeRow.cs index 1cdf22bd75b3..08601ca912e4 100644 --- a/osu.Game/Screens/Ranking/Statistics/User/RankedScoreChangeRow.cs +++ b/osu.Game/Screens/Ranking/Statistics/User/RankedScoreChangeRow.cs @@ -3,6 +3,7 @@ using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Screens.Ranking.Statistics.User @@ -15,6 +16,7 @@ public RankedScoreChangeRow() } protected override LocalisableString Label => UsersStrings.ShowStatsRankedScore; + public override LocalisableString TooltipText => RankingStatisticsStrings.ClassicScoringAlwaysUsed; protected override LocalisableString FormatCurrentValue(long current) => current.ToLocalisableString(@"N0"); diff --git a/osu.Game/Screens/Ranking/Statistics/User/RankingChangeRow.cs b/osu.Game/Screens/Ranking/Statistics/User/RankingChangeRow.cs index e6a6530345f0..80f2fbc7a602 100644 --- a/osu.Game/Screens/Ranking/Statistics/User/RankingChangeRow.cs +++ b/osu.Game/Screens/Ranking/Statistics/User/RankingChangeRow.cs @@ -6,6 +6,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; @@ -17,7 +18,7 @@ namespace osu.Game.Screens.Ranking.Statistics.User { - public abstract partial class RankingChangeRow : CompositeDrawable + public abstract partial class RankingChangeRow : CompositeDrawable, IHasTooltip { public Bindable StatisticsUpdate { get; } = new Bindable(); @@ -153,6 +154,7 @@ private void onStatisticsUpdate(ValueChangedEvent default; protected abstract LocalisableString FormatCurrentValue(T current); protected abstract int CalculateDifference(T previous, T current, out LocalisableString formattedDifference); diff --git a/osu.Game/Screens/Ranking/Statistics/User/TotalScoreChangeRow.cs b/osu.Game/Screens/Ranking/Statistics/User/TotalScoreChangeRow.cs index 346de18e14c3..9b04f33be576 100644 --- a/osu.Game/Screens/Ranking/Statistics/User/TotalScoreChangeRow.cs +++ b/osu.Game/Screens/Ranking/Statistics/User/TotalScoreChangeRow.cs @@ -3,6 +3,7 @@ using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Screens.Ranking.Statistics.User @@ -15,6 +16,7 @@ public TotalScoreChangeRow() } protected override LocalisableString Label => UsersStrings.ShowStatsTotalScore; + public override LocalisableString TooltipText => RankingStatisticsStrings.ClassicScoringAlwaysUsed; protected override LocalisableString FormatCurrentValue(long current) => current.ToLocalisableString(@"N0"); From a166d0046d66a6d9841052f01b5f20c2e2779844 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Sun, 15 Feb 2026 04:59:15 +0500 Subject: [PATCH 666/836] Change accuracy pp to be uncapped (#36669) This also transfers some of the accuracy pp length bonus to aim which makes it at least somewhat difficulty-aware. Value changes are very mild (10pp at most for most players) image --- .../Difficulty/OsuPerformanceCalculator.cs | 6 ++++-- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 96281297d70c..5c78917184ae 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -199,7 +199,7 @@ private double computeAimValue(ScoreInfo score, OsuDifficultyAttributes attribut double aimValue = OsuStrainSkill.DifficultyToPerformance(aimDifficulty); - double lengthBonus = 0.95 + 0.3 * Math.Min(1.0, totalHits / 2000.0) + + double lengthBonus = 0.95 + 0.35 * Math.Min(1.0, totalHits / 2000.0) + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); aimValue *= lengthBonus; @@ -293,7 +293,9 @@ private double computeAccuracyValue(ScoreInfo score, OsuDifficultyAttributes att double accuracyValue = Math.Pow(1.52163, overallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83; // Bonus for many hitcircles - it's harder to keep good accuracy up for longer. - accuracyValue *= Math.Min(1.15, Math.Pow(amountHitObjectsWithAccuracy / 1000.0, 0.3)); + accuracyValue *= amountHitObjectsWithAccuracy < 1000 + ? Math.Pow(amountHitObjectsWithAccuracy / 1000.0, 0.3) + : Math.Pow(amountHitObjectsWithAccuracy / 1000.0, 0.1); // Increasing the accuracy value by object count for Blinds isn't ideal, so the minimum buff is given. if (score.Mods.Any(m => m is OsuModBlinds)) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 146ef8167dd9..d71794b9aa2b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -33,7 +33,7 @@ public Aim(Mod[] mods, bool includeSliders) private double skillMultiplierAim => 26.0; private double skillMultiplierSpeed => 1.3; - private double skillMultiplierTotal => 1.01; + private double skillMultiplierTotal => 1.0; private double meanExponent => 1.2; private readonly List sliderStrains = new List(); From 62fdd421ce7af46f9c6ebd4c60e42b3e989de0e2 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Sun, 15 Feb 2026 05:40:19 +0500 Subject: [PATCH 667/836] Adjust wide angle bonus to be closer to SpeedAim distance scaling (#36670) --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 4 ++-- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 8573d36c70a8..a75c0382cbf4 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -99,7 +99,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3)); // Apply full wide angle bonus for distance more than SINGLE_SPACING_THRESHOLD - wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(currDistance, 0, SpeedAimEvaluator.SINGLE_SPACING_THRESHOLD); + wideAngleBonus *= angleBonus * Math.Pow(DifficultyCalculationUtils.Smoothstep(currDistance, 0, SpeedAimEvaluator.SINGLE_SPACING_THRESHOLD), 3.0); // Apply wiggle bonus for jumps that are [radius, 3*diameter] in distance, with < 110 angle // https://www.desmos.com/calculator/dp0v0nvowc diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index d71794b9aa2b..edca971d8c3f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -31,8 +31,8 @@ public Aim(Mod[] mods, bool includeSliders) private double currentAimStrain; private double currentSpeedStrain; - private double skillMultiplierAim => 26.0; - private double skillMultiplierSpeed => 1.3; + private double skillMultiplierAim => 25.85; + private double skillMultiplierSpeed => 1.35; private double skillMultiplierTotal => 1.0; private double meanExponent => 1.2; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 715197b4b513..f6679f944340 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Speed : HarmonicSkill { - private double skillMultiplier => 1.035; + private double skillMultiplier => 1.04; private readonly List sliderStrains = new List(); From 29571d1de81d645af793b6c0ee4179224a23af0f Mon Sep 17 00:00:00 2001 From: Natelytle Date: Sat, 14 Feb 2026 23:03:19 -0500 Subject: [PATCH 668/836] Improve binning and fix the miss penalty being quite wrong --- .../Rulesets/Difficulty/Skills/TimeSkill.cs | 74 +++++++------- osu.Game/Rulesets/Difficulty/Utils/Bin.cs | 97 +++++++++++-------- .../Difficulty/Utils/PoissonBinomial.cs | 15 ++- 3 files changed, 106 insertions(+), 80 deletions(-) diff --git a/osu.Game/Rulesets/Difficulty/Skills/TimeSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/TimeSkill.cs index cf51e41cc252..96185ce5d1ee 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/TimeSkill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/TimeSkill.cs @@ -7,7 +7,6 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Difficulty.Utils; namespace osu.Game.Rulesets.Difficulty.Skills { @@ -25,7 +24,7 @@ protected TimeSkill(Mod[] mods) private const double max_delta_time = 5000; // Bin specific constants - private const double bin_threshold_note_count = 64; + private const double bin_threshold_note_count = difficulty_bin_count * time_bin_count; private const int difficulty_bin_count = 8; private const int time_bin_count = 16; @@ -74,18 +73,12 @@ private double timeSpentRetryingAtSkill(double skill, List? binList = null) // We use bins, falling back to exact difficulty calculation if not available. if (binList is not null) { - for (int timeIndex = time_bin_count - 1; timeIndex >= 0; timeIndex--) + for (int n = binList.Count - 1; n >= 0; n--) { - double deltaTime = times.LastOrDefault() / time_bin_count; + double deltaTime = n > 0 ? binList[n].Time - binList[n - 1].Time : binList[n].Time; - for (int difficultyIndex = 0; difficultyIndex < difficulty_bin_count; difficultyIndex++) - { - Bin bin = binList[difficulty_bin_count * timeIndex + difficultyIndex]; - - hitProbabilityProduct *= Math.Pow(HitProbability(skill, bin.Difficulty), bin.NoteCount); - } - - timeSpentRetrying += deltaTime / hitProbabilityProduct - deltaTime; + hitProbabilityProduct *= Math.Pow(HitProbability(skill, binList[n].Difficulty), binList[n].NoteCount); + timeSpentRetrying += hitProbabilityProduct > 0 ? deltaTime / hitProbabilityProduct - deltaTime : double.PositiveInfinity; } } else @@ -95,7 +88,7 @@ private double timeSpentRetryingAtSkill(double skill, List? binList = null) double deltaTime = n > 0 ? times[n] - times[n - 1] : times[n]; hitProbabilityProduct *= HitProbability(skill, ObjectDifficulties[n]); - timeSpentRetrying += deltaTime / hitProbabilityProduct - deltaTime; + timeSpentRetrying += hitProbabilityProduct > 0 ? deltaTime / hitProbabilityProduct - deltaTime : double.PositiveInfinity; } } @@ -116,7 +109,13 @@ public double[] GetMissPenaltyCoefficients() double fcSkill = DifficultyValue(); - var bins = Bin.CreateBins(ObjectDifficulties, times, difficulty_bin_count, time_bin_count); + // We only initialize bins if we have enough notes to use them. + List? binList = null; + + if (ObjectDifficulties.Count > bin_threshold_note_count) + { + binList = Bin.CreateBins(ObjectDifficulties, times, difficulty_bin_count, time_bin_count); + } foreach (double skillProportion in PolynomialPenaltyUtils.SKILL_PROPORTIONS) { @@ -129,7 +128,7 @@ public double[] GetMissPenaltyCoefficients() double penalizedSkill = fcSkill * skillProportion; // We take the log to squash miss counts, which have large absolute value differences, but low relative differences, into a straighter line for the polynomial. - missCounts[skillProportion] = Math.Log(getMissCountAtSkill(penalizedSkill, bins) + 1); + missCounts[skillProportion] = Math.Log(getMissCountAtSkill(penalizedSkill, binList) + 1); } return PolynomialPenaltyUtils.GetPenaltyCoefficients(missCounts); @@ -138,10 +137,9 @@ public double[] GetMissPenaltyCoefficients() /// /// Find the lowest misscount that a player with the provided would likely achieve within 12 minutes of retrying. /// - private double getMissCountAtSkill(double skill, List bins) + private double getMissCountAtSkill(double skill, List? binList = null) { double maxDiff = ObjectDifficulties.Max(); - double endTime = times.Max(); if (maxDiff == 0) return 0; @@ -155,43 +153,41 @@ private double getMissCountAtSkill(double skill, List bins) double retryTimeRequiredToObtainMissCount(double missCount) { poiBin.Reset(); - double timeSpentRetrying = 0; - if (ObjectDifficulties.Count > time_bin_count * difficulty_bin_count) + if (binList is not null) { - double binTimeSteps = endTime / time_bin_count; - - for (int timeIndex = 0; timeIndex < time_bin_count; timeIndex++) + for (int n = binList.Count - 1; n >= 0; n--) { - for (int difficultyIndex = 0; difficultyIndex < difficulty_bin_count; difficultyIndex++) - { - Bin bin = bins[timeIndex * difficulty_bin_count + difficultyIndex]; + double deltaTime = n > 0 ? binList[n].Time - binList[n - 1].Time : binList[n].Time; + double missProbability = 1 - HitProbability(skill, binList[n].Difficulty); + + // Add this bin's probabilities to track cumulative miss distribution from here to end + poiBin.AddBinnedProbabilities(missProbability, binList[n].NoteCount); - double missProb = 1 - HitProbability(skill, bin.Difficulty); - poiBin.AddBinnedProbabilities(missProb, bin.NoteCount); - } + // Probability of achieving less than this missCount from this point until map end + double missCountProb = poiBin.Cdf(missCount); - timeSpentRetrying += binTimeSteps * poiBin.Cdf(missCount); + // deltaTime divided by missCountProb = expected total plays of this segment + // Subtract deltaTime to get only the retry time (which excludes the success run) + timeSpentRetrying += missCountProb > 0 ? deltaTime / missCountProb - deltaTime : double.PositiveInfinity; } } else { - for (int i = 0; i < ObjectDifficulties.Count; i++) + // Same calculation but for individual notes. + for (int n = ObjectDifficulties.Count - 1; n >= 0; n--) { - double deltaTime = i > 0 ? times[i] - times[i - 1] : times[i]; + double deltaTime = n > 0 ? times[n] - times[n - 1] : times[n]; + double missProbability = 1 - HitProbability(skill, ObjectDifficulties[n]); + poiBin.AddProbability(missProbability); - double missProb = 1 - HitProbability(skill, ObjectDifficulties[i]); - poiBin.AddProbability(missProb); - - timeSpentRetrying += deltaTime * poiBin.Cdf(missCount); + double missCountProb = poiBin.Cdf(missCount); + timeSpentRetrying += missCountProb > 0 ? deltaTime / missCountProb - deltaTime : double.PositiveInfinity; } } - if (poiBin.Cdf(missCount) < 1e-10) - return double.PositiveInfinity; - - return (timeSpentRetrying / poiBin.Cdf(missCount) - endTime) * ms_to_minutes; + return timeSpentRetrying * ms_to_minutes; } } diff --git a/osu.Game/Rulesets/Difficulty/Utils/Bin.cs b/osu.Game/Rulesets/Difficulty/Utils/Bin.cs index b3465feb1941..7dd9d91a028a 100644 --- a/osu.Game/Rulesets/Difficulty/Utils/Bin.cs +++ b/osu.Game/Rulesets/Difficulty/Utils/Bin.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Linq; -namespace osu.Game.Rulesets.Osu.Difficulty.Utils +namespace osu.Game.Rulesets.Difficulty.Utils { public struct Bin { @@ -14,62 +14,79 @@ public struct Bin public double NoteCount; /// - /// Creates a 2D grid of bins using bilinear interpolation. - /// Notes are distributed across neighboring bins weighted by their fractional position. + /// Creates bins using 2D quantile-based binning. + /// First splits notes into time quantiles (equal note counts), then splits each time quantile into difficulty quantiles. /// public static List CreateBins(List difficulties, List times, int difficultyDimensionLength, int timeDimensionLength) { - double maxDifficulty = difficulties.Max(); - double endTime = times.Max(); + if (difficulties.Count == 0 || times.Count == 0 || difficultyDimensionLength <= 0 || timeDimensionLength <= 0) + return new List(); - var binsArray = new Bin[timeDimensionLength * difficultyDimensionLength]; + int n = difficulties.Count; + var bins = new List(); - for (int timeIndex = 0; timeIndex < timeDimensionLength; timeIndex++) + // Calculate how many notes per time quantile + int notesPerTimeQuantile = (int)Math.Ceiling((double)n / timeDimensionLength); + + // Split into time quantiles + for (int timeQuantile = 0; timeQuantile < timeDimensionLength; timeQuantile++) { - double time = endTime * timeIndex / (timeDimensionLength - 1); + int startIdx = timeQuantile * notesPerTimeQuantile; + int endIdx = Math.Min(startIdx + notesPerTimeQuantile, n); - for (int diffIndex = 0; diffIndex < difficultyDimensionLength; diffIndex++) - { - int binIndex = difficultyDimensionLength * timeIndex + diffIndex; + if (startIdx >= n) break; - binsArray[binIndex].Time = time; + int quantileSize = endIdx - startIdx; - // We don't create a 0 difficulty bin because 0 difficulty notes don't contribute to star rating. - binsArray[binIndex].Difficulty = maxDifficulty * (diffIndex + 1) / difficultyDimensionLength; - } - } + // Extract difficulties and times for this time quantile + var quantileDifficulties = new List(quantileSize); + var quantileTimes = new List(quantileSize); - for (int noteIndex = 0; noteIndex < difficulties.Count; noteIndex++) - { - double timeBinIndex = timeDimensionLength * (times[noteIndex] / endTime); - double difficultyBinIndex = difficultyDimensionLength * (difficulties[noteIndex] / maxDifficulty) - 1; + for (int i = startIdx; i < endIdx; i++) + { + quantileDifficulties.Add(difficulties[i]); + quantileTimes.Add(times[i]); + } - int timeLower = Math.Min((int)timeBinIndex, timeDimensionLength - 1); - int timeUpper = Math.Min(timeLower + 1, timeDimensionLength - 1); - double timeWeight = timeBinIndex - timeLower; + // Sort by difficulty for this quantile + int[] sortedIndices = Enumerable.Range(0, quantileSize) + .OrderBy(i => quantileDifficulties[i]) + .ToArray(); - int difficultyLower = fastFloor(difficultyBinIndex); - int difficultyUpper = Math.Min(difficultyLower + 1, difficultyDimensionLength - 1); - double difficultyWeight = difficultyBinIndex - difficultyLower; + // Calculate how many notes per difficulty quantile + int notesPerDiffQuantile = (int)Math.Ceiling((double)quantileSize / difficultyDimensionLength); - // The lower bound of difficulty can be -1, corresponding to buckets with 0 difficulty. - // We don't store those since they don't contribute to star rating. - if (difficultyLower >= 0) + // Split this time quantile into difficulty quantiles + for (int diffQuantile = 0; diffQuantile < difficultyDimensionLength; diffQuantile++) { - binsArray[difficultyDimensionLength * timeLower + difficultyLower].NoteCount += (1 - timeWeight) * (1 - difficultyWeight); - binsArray[difficultyDimensionLength * timeUpper + difficultyLower].NoteCount += timeWeight * (1 - difficultyWeight); + int diffStartIdx = diffQuantile * notesPerDiffQuantile; + int diffEndIdx = Math.Min(diffStartIdx + notesPerDiffQuantile, quantileSize); + + if (diffStartIdx >= quantileSize) + break; + + double diffSum = 0; + double timeSum = 0; + int count = diffEndIdx - diffStartIdx; + + for (int i = diffStartIdx; i < diffEndIdx; i++) + { + int originalIdx = sortedIndices[i]; + diffSum += quantileDifficulties[originalIdx]; + timeSum += quantileTimes[originalIdx]; + } + + bins.Add(new Bin + { + Difficulty = diffSum / count, + Time = timeSum / count, + NoteCount = count + }); } - - binsArray[difficultyDimensionLength * timeLower + difficultyUpper].NoteCount += (1 - timeWeight) * difficultyWeight; - binsArray[difficultyDimensionLength * timeUpper + difficultyUpper].NoteCount += timeWeight * difficultyWeight; } - var binsList = binsArray.ToList(); - - return binsList; + // Sort by time + return bins.OrderBy(b => b.Time).ToList(); } - - // Faster implementation of the floor function to speed up binning times. - private static int fastFloor(double x) => x >= 0 || x == -1 ? (int)x : (int)(x - 1); } } diff --git a/osu.Game/Rulesets/Difficulty/Utils/PoissonBinomial.cs b/osu.Game/Rulesets/Difficulty/Utils/PoissonBinomial.cs index 5c09180af4cd..db411397f1d7 100644 --- a/osu.Game/Rulesets/Difficulty/Utils/PoissonBinomial.cs +++ b/osu.Game/Rulesets/Difficulty/Utils/PoissonBinomial.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using osu.Game.Rulesets.Osu.Difficulty.Utils; namespace osu.Game.Rulesets.Difficulty.Utils { @@ -136,6 +135,13 @@ public void AddProbability(double p) gamma += p * (1 - p) * (1 - 2 * p); } + public void RemoveProbability(double p) + { + mu -= p; + var -= p * (1 - p); + gamma -= p * (1 - p) * (1 - 2 * p); + } + public void AddBinnedProbabilities(double p, double count) { mu += p * count; @@ -143,6 +149,13 @@ public void AddBinnedProbabilities(double p, double count) gamma += p * (1 - p) * (1 - 2 * p) * count; } + public void RemoveBinnedProbabilities(double p, double count) + { + mu -= p * count; + var -= p * (1 - p) * count; + gamma -= p * (1 - p) * (1 - 2 * p) * count; + } + public double Cdf(double count) { if (var == 0) From c494a3d900de24e77184b801fa0f8ae67684f566 Mon Sep 17 00:00:00 2001 From: Natelytle Date: Sat, 14 Feb 2026 23:20:45 -0500 Subject: [PATCH 669/836] unnerf zetsubou by adding a retry cooldown constant --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- osu.Game/Rulesets/Difficulty/Skills/TimeSkill.cs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index a6ab30563991..725e5128027a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -34,7 +34,7 @@ public Aim(Mod[] mods, bool includeSliders) private double skillMultiplierAim => 130.0; private double skillMultiplierSpeed => 6.5; - private double skillMultiplierTotal => 0.98; + private double skillMultiplierTotal => 0.94; private double meanExponent => 1.2; private readonly List sliderStrains = new List(); diff --git a/osu.Game/Rulesets/Difficulty/Skills/TimeSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/TimeSkill.cs index 96185ce5d1ee..310646a8baba 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/TimeSkill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/TimeSkill.cs @@ -22,6 +22,7 @@ protected TimeSkill(Mod[] mods) // FC time specific constants private const double time_threshold_minutes = 24; private const double max_delta_time = 5000; + private const double retry_cooldown_time = 60000; // Bin specific constants private const double bin_threshold_note_count = difficulty_bin_count * time_bin_count; @@ -39,7 +40,9 @@ protected TimeSkill(Mod[] mods) protected override double ProcessInternal(DifficultyHitObject current) { - times.Add(times.LastOrDefault() + Math.Min(current.DeltaTime, max_delta_time)); + times.Add(current.Index == 0 + ? retry_cooldown_time + Math.Min(current.DeltaTime, max_delta_time) + : times.Last() + Math.Min(current.DeltaTime, max_delta_time)); return StrainValueAt(current); } From 87f323a2e533ed4f132bcbce1a3c317964d7e450 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 Feb 2026 23:25:46 +0900 Subject: [PATCH 670/836] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a2b108fc0a6f..34373d0fbcaf 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@
    - + From 2f459dd94e8a15ae962e3c108841fbc5941f0587 Mon Sep 17 00:00:00 2001 From: Arthur Araujo <90941580+64ArthurAraujo@users.noreply.github.com> Date: Mon, 16 Feb 2026 00:50:04 -0300 Subject: [PATCH 671/836] Preserve bookmarks when creating a new difficulty from scratch (#36675) Closes #33395 Copies the bookmarks from `referenceWorkingBeatmap` while creating a new difficulty from scratch. I adapted the tests in `TestSceneEditorBeatmapCreation` to include the bookmark checks. --------- Co-authored-by: Dean Herbert --- .../Visual/Editing/TestSceneEditorBeatmapCreation.cs | 10 ++++++++++ osu.Game/Beatmaps/BeatmapManager.cs | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index 8d7eb41369f3..7440697ba08a 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -132,6 +132,7 @@ public void TestCreateNewDifficulty([Values] bool sameRuleset) AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = firstDifficultyName); AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 })); AddStep("add effect point", () => EditorBeatmap.ControlPointInfo.Add(500, new EffectControlPoint { KiaiMode = true })); + AddStep("add bookmarks", () => EditorBeatmap.Bookmarks.AddRange([500, 1000])); AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[] { new HitCircle @@ -185,6 +186,7 @@ public void TestCreateNewDifficulty([Values] bool sameRuleset) var effectPoint = EditorBeatmap.ControlPointInfo.EffectPoints.Single(); return effectPoint.Time == 500 && effectPoint.KiaiMode && effectPoint.ScrollSpeedBindable.IsDefault; }); + AddAssert("created difficulty has bookmarks", () => EditorBeatmap.Bookmarks.Count == 2); AddAssert("created difficulty has no objects", () => EditorBeatmap.HitObjects.Count == 0); AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified); @@ -223,6 +225,7 @@ public void TestCreateNewDifficultyWithScrollSpeed_SameRuleset() AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = previousDifficultyName = Guid.NewGuid().ToString()); AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 })); + AddStep("add bookmarks", () => EditorBeatmap.Bookmarks.AddRange([500, 1000])); AddStep("add effect points", () => { EditorBeatmap.ControlPointInfo.Add(250, new EffectControlPoint { KiaiMode = false, ScrollSpeed = 0.05 }); @@ -253,6 +256,8 @@ public void TestCreateNewDifficultyWithScrollSpeed_SameRuleset() return timingPoint.Time == 0 && timingPoint.BeatLength == 1000; }); + AddAssert("created difficulty has bookmarks", () => EditorBeatmap.Bookmarks.Count == 2); + AddAssert("created difficulty has effect points", () => { return EditorBeatmap.ControlPointInfo.EffectPoints.SequenceEqual(new[] @@ -284,6 +289,7 @@ public void TestCreateNewDifficultyWithScrollSpeed_DifferentRuleset() AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = firstDifficultyName); AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 })); + AddStep("add bookmarks", () => EditorBeatmap.Bookmarks.AddRange([500, 1000])); AddStep("add effect points", () => { EditorBeatmap.ControlPointInfo.Add(250, new EffectControlPoint { KiaiMode = false, ScrollSpeed = 0.05 }); @@ -311,6 +317,8 @@ public void TestCreateNewDifficultyWithScrollSpeed_DifferentRuleset() return timingPoint.Time == 0 && timingPoint.BeatLength == 1000; }); + AddAssert("created difficulty has bookmarks", () => EditorBeatmap.Bookmarks.Count == 2); + AddAssert("created difficulty has effect points", () => { // since this difficulty is on another ruleset, scroll speed specifications are completely reset, @@ -344,6 +352,7 @@ public void TestCopyDifficulty() StartTime = 1000 } })); + AddStep("add bookmarks", () => EditorBeatmap.Bookmarks.AddRange([500, 1000])); AddStep("set approach rate", () => EditorBeatmap.Difficulty.ApproachRate = 4); AddStep("set combo colours", () => { @@ -394,6 +403,7 @@ public void TestCopyDifficulty() return timingPoint.Time == 0 && timingPoint.BeatLength == 1000; }); AddAssert("created difficulty has objects", () => EditorBeatmap.HitObjects.Count == 2); + AddAssert("created difficulty has bookmarks", () => EditorBeatmap.Bookmarks.Count == 2); AddAssert("approach rate correctly copied", () => EditorBeatmap.Difficulty.ApproachRate == 4); AddAssert("combo colours correctly copied", () => EditorBeatmap.BeatmapSkin.AsNonNull().ComboColours.Count == 2); diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 8446f43c53e2..6d1dbaafba2f 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -154,7 +154,11 @@ public virtual WorkingBeatmap CreateNewDifficulty(BeatmapSetInfo targetBeatmapSe { DifficultyName = NamingUtils.GetNextBestName(targetBeatmapSet.Beatmaps.Select(b => b.DifficultyName), "New Difficulty") }; - var newBeatmap = new Beatmap { BeatmapInfo = newBeatmapInfo }; + var newBeatmap = new Beatmap + { + BeatmapInfo = newBeatmapInfo, + Bookmarks = referenceWorkingBeatmap.Beatmap.Bookmarks.ToArray() + }; foreach (var timingPoint in referenceWorkingBeatmap.Beatmap.ControlPointInfo.TimingPoints) newBeatmap.ControlPointInfo.Add(timingPoint.Time, timingPoint.DeepClone()); From 810edebe87d074e6ed4d0560ee94ae006956155d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 16 Feb 2026 11:02:59 +0100 Subject: [PATCH 672/836] Fix extra lives in Easy mod potentially getting reapplied during gameplay (#36678) Closes https://github.com/ppy/osu/issues/36676. --- .../Mods/TestSceneOsuModEasy.cs | 88 +++++++++++++++++++ .../Rulesets/Mods/ModEasyWithExtraLives.cs | 19 ++-- 2 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModEasy.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModEasy.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModEasy.cs new file mode 100644 index 000000000000..1b5d9da02bae --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModEasy.cs @@ -0,0 +1,88 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Tests.Beatmaps; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Osu.Tests.Mods +{ + public partial class TestSceneOsuModEasy : OsuModTestScene + { + protected override bool AllowFail => true; + + [Test] + public void TestMultipleApplication() + { + bool reapplied = false; + CreateModTest(new ModTestData + { + Mods = [new OsuModEasy { Retries = { Value = 1 } }], + Autoplay = false, + CreateBeatmap = () => + { + // do stuff to speed up fails + var b = new TestBeatmap(new OsuRuleset().RulesetInfo) + { + Difficulty = { DrainRate = 10 } + }; + + foreach (var ho in b.HitObjects) + ho.StartTime /= 4; + + return b; + }, + PassCondition = () => + { + if (((ModEasyTestPlayer)Player).FailuresSuppressed > 0 && !reapplied) + { + try + { + foreach (var mod in Player.GameplayState.Mods.OfType()) + mod.ApplyToDifficulty(new BeatmapDifficulty()); + + foreach (var mod in Player.GameplayState.Mods.OfType()) + mod.ApplyToPlayer(Player); + } + catch + { + // don't care if this fails. in fact a failure here is probably better than the alternative. + } + finally + { + reapplied = true; + } + } + + return Player.GameplayState.HasFailed && ((ModEasyTestPlayer)Player).FailuresSuppressed <= 1; + } + }); + } + + protected override TestPlayer CreateModPlayer(Ruleset ruleset) => new ModEasyTestPlayer(CurrentTestData, AllowFail); + + private partial class ModEasyTestPlayer : ModTestPlayer + { + public int FailuresSuppressed { get; private set; } + + public ModEasyTestPlayer(ModTestData data, bool allowFail) + : base(data, allowFail) + { + } + + protected override bool CheckModsAllowFailure() + { + bool failureAllowed = GameplayState.Mods.OfType().All(m => m.PerformFail()); + + if (!failureAllowed) + FailuresSuppressed++; + + return failureAllowed; + } + } + } +} diff --git a/osu.Game/Rulesets/Mods/ModEasyWithExtraLives.cs b/osu.Game/Rulesets/Mods/ModEasyWithExtraLives.cs index 1a2cb08a53f0..09086f4d862d 100644 --- a/osu.Game/Rulesets/Mods/ModEasyWithExtraLives.cs +++ b/osu.Game/Rulesets/Mods/ModEasyWithExtraLives.cs @@ -3,17 +3,18 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using Humanizer; using osu.Framework.Bindables; using osu.Framework.Localisation; -using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play; namespace osu.Game.Rulesets.Mods { - public abstract class ModEasyWithExtraLives : ModEasy, IApplicableFailOverride, IApplicableToHealthProcessor + public abstract class ModEasyWithExtraLives : ModEasy, IApplicableFailOverride, IApplicableToPlayer, IApplicableToHealthProcessor { [SettingSource("Extra Lives", "Number of extra lives")] public Bindable Retries { get; } = new BindableInt(2) @@ -33,18 +34,26 @@ public abstract class ModEasyWithExtraLives : ModEasy, IApplicableFailOverride, public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModAccuracyChallenge)).ToArray(); - private int retries; + private int? retries; private readonly BindableNumber health = new BindableDouble(); - public override void ApplyToDifficulty(BeatmapDifficulty difficulty) + public void ApplyToPlayer(Player player) { - base.ApplyToDifficulty(difficulty); + // this throw works for two reasons: + // - every time `Player` loads, it deep-clones mods into itself, and the deep clone copies *only* `[SettingsSource]` properties + // - `Player` is the only consumer of `IApplicableToPlayer` and it calls `ApplyToPlayer()` exactly once per mod instance + // if either of the above assumptions no longer holds true for any reason, this will need to be reconsidered + if (retries != null) + throw new InvalidOperationException(@"Cannot apply this mod instance to a player twice."); + retries = Retries.Value; } public bool PerformFail() { + Debug.Assert(retries != null); + if (retries == 0) return true; health.Value = health.MaxValue; From 8e26cf4e1b8f2bd09e0e69f9f290cef906598480 Mon Sep 17 00:00:00 2001 From: Krzysztof Gutkowski Date: Mon, 16 Feb 2026 16:40:29 +0100 Subject: [PATCH 673/836] Restore previous beatmap when leaving scoped mode (#36582) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves #36288. If the current selection is still available after leaving scoped mode, it's left as is. If it's not, the selection from before entering scoped mode is restored. https://github.com/user-attachments/assets/b1ac3de1-7c7f-4949-82a9-1dd0459f3f61 --------- Co-authored-by: Bartłomiej Dach --- .../TestSceneSongSelectFiltering.cs | 192 ++++++++++++++++-- .../FilterControl.ScopedBeatmapSetDisplay.cs | 19 +- osu.Game/Screens/SelectV2/FilterControl.cs | 31 +-- osu.Game/Screens/SelectV2/ISongSelect.cs | 17 +- .../SelectV2/PanelBeatmapSet.SpreadDisplay.cs | 9 +- .../PanelBeatmapStandalone.SpreadDisplay.cs | 9 +- osu.Game/Screens/SelectV2/SongSelect.cs | 25 ++- 7 files changed, 248 insertions(+), 54 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs index 0e195b4742b5..2e7e08b33191 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs @@ -12,6 +12,7 @@ using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Chat; +using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; @@ -266,6 +267,8 @@ public void TestSelectionRetainedWhenFilteringAllPanelsAway() AddUntilStep("wait for placeholder visible", () => getPlaceholder()?.State.Value == Visibility.Visible); AddAssert("still has selection", () => Beatmap.IsDefault, () => Is.False); + + AddStep("reset star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMinimum, 0.0)); } [Test] @@ -365,13 +368,7 @@ public void TestScopeToBeatmapWhenDifficultiesSplitApart() SortBy(SortMode.Difficulty); checkMatchedBeatmaps(6); - AddUntilStep("wait for spread indicator", () => this.ChildrenOfType().Any(d => d.Enabled.Value)); - AddStep("click spread indicator", () => - { - InputManager.MoveMouseTo(this.ChildrenOfType().Single(d => d.Enabled.Value)); - InputManager.Click(MouseButton.Left); - }); - WaitForFiltering(); + scopeBeatmap(false); checkMatchedBeatmaps(3); AddStep("press Escape", () => InputManager.Key(Key.Escape)); @@ -389,9 +386,7 @@ public void TestScopeToBeatmapWhenDifficultiesGroupedBySet() SortBy(SortMode.Artist); checkMatchedBeatmaps(6); - AddUntilStep("wait for spread indicator", () => this.ChildrenOfType().Any(d => d.Enabled.Value)); - AddStep("click spread indicator", () => this.ChildrenOfType().Single(d => d.Enabled.Value).TriggerClick()); - WaitForFiltering(); + scopeBeatmap(true); checkMatchedBeatmaps(3); AddStep("press Escape", () => InputManager.Key(Key.Escape)); @@ -413,9 +408,7 @@ public void TestDismissingScopeDoesNotClearSearchTextBox() WaitForFiltering(); checkMatchedBeatmaps(3); - AddUntilStep("wait for spread indicator", () => this.ChildrenOfType().Any(d => d.Enabled.Value)); - AddStep("click spread indicator", () => this.ChildrenOfType().Single(d => d.Enabled.Value).TriggerClick()); - WaitForFiltering(); + scopeBeatmap(true); checkMatchedBeatmaps(3); AddStep("press Escape", () => InputManager.Key(Key.Escape)); @@ -424,6 +417,179 @@ public void TestDismissingScopeDoesNotClearSearchTextBox() AddAssert("text filter not emptied", () => filterTextBox.Current.Value, () => Is.Not.Empty); } + [TestCase(false)] + [TestCase(true)] + public void TestUnscopeRevertsToOriginalSelection(bool grouped) + { + ImportBeatmapForRuleset(0); + ImportBeatmapForRuleset(0); + + LoadSongSelect(); + SortBy(grouped ? SortMode.Title : SortMode.Difficulty); + checkMatchedBeatmaps(6); + + AddStep("select normal difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Normal"))); + AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Normal"))); + + scopeBeatmap(grouped); + checkMatchedBeatmaps(3); + + AddStep("select insane difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Insane"))); + AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Insane"))); + + AddStep("exit scoped view", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().First()); + InputManager.Click(MouseButton.Left); + }); + WaitForFiltering(); + + checkMatchedBeatmaps(6); + AddAssert("normal difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Normal"))); + + AddStep("reset star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, 10.1)); + } + + [TestCase(false)] + [TestCase(true)] + public void TestUnscopeWhenSelectedBeatmapHiddenByFilters(bool grouped) + { + ImportBeatmapForRuleset(0); + ImportBeatmapForRuleset(0); + + LoadSongSelect(); + SortBy(grouped ? SortMode.Title : SortMode.Difficulty); + checkMatchedBeatmaps(6); + + AddStep("set star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, findBeatmap("Hard").StarRating + 0.1)); + WaitForFiltering(); + + AddStep("select hard difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Hard"))); + AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard"))); + + scopeBeatmap(grouped); + checkMatchedBeatmaps(3); + + AddStep("select insane difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Insane"))); + AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Insane"))); + + AddStep("exit scoped view", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().First()); + InputManager.Click(MouseButton.Left); + }); + WaitForFiltering(); + + AddAssert("hard difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard"))); + + AddStep("reset star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, 10.1)); + } + + [TestCase(false)] + [TestCase(true)] + public void TestUnscopeByChangingRuleset(bool grouped) + { + bool showConverts = Config.Get(OsuSetting.ShowConvertedBeatmaps); + + AddStep("hide converts", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, false)); + + ImportBeatmapForRuleset(0, 2); + + LoadSongSelect(); + SortBy(grouped ? SortMode.Title : SortMode.Difficulty); + checkMatchedBeatmaps(2); + + scopeBeatmap(grouped); + checkMatchedBeatmaps(2); + + AddStep("select insane difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Insane"))); + AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Insane"))); + + AddStep("change ruleset", () => Ruleset.Value = new CatchRuleset().RulesetInfo); + WaitForFiltering(); + + AddAssert("hard catch difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard"))); + + AddStep("revert convert setting", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, showConverts)); + } + + [TestCase(false)] + [TestCase(true)] + public void TestUnscopeByShowingConverts(bool grouped) + { + bool showConverts = Config.Get(OsuSetting.ShowConvertedBeatmaps); + + AddStep("hide converts", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, false)); + + ImportBeatmapForRuleset(0); + ImportBeatmapForRuleset(0); + + LoadSongSelect(); + SortBy(grouped ? SortMode.Title : SortMode.Difficulty); + checkMatchedBeatmaps(6); + + AddStep("set star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, Beatmap.Value.BeatmapSetInfo.Beatmaps.ElementAt(1).StarRating + 0.1)); + WaitForFiltering(); + + AddStep("select hard difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Hard"))); + AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard"))); + + scopeBeatmap(grouped); + checkMatchedBeatmaps(3); + + AddStep("select insane difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Insane"))); + AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Insane"))); + + AddStep("show converts", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, true)); + WaitForFiltering(); + + AddAssert("hard difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard"))); + + AddStep("revert convert setting", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, showConverts)); + AddStep("reset star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, 10.1)); + } + + [TestCase(false)] + [TestCase(true)] + public void TestUnscopeByChangingFilterText(bool grouped) + { + ImportBeatmapForRuleset(0); + ImportBeatmapForRuleset(0); + + LoadSongSelect(); + SortBy(grouped ? SortMode.Title : SortMode.Difficulty); + checkMatchedBeatmaps(6); + + AddStep("select hard difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Hard"))); + AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard"))); + + scopeBeatmap(grouped); + checkMatchedBeatmaps(3); + + AddStep("set filter text", () => filterTextBox.Current.Value = findBeatmap("Normal").DifficultyName); + WaitForFiltering(); + + AddAssert("normal difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Normal"))); + } + + private void scopeBeatmap(bool grouped) + { + if (grouped) + { + AddUntilStep("wait for spread indicator", () => this.ChildrenOfType().Any(d => d.Enabled.Value)); + AddStep("click spread indicator", () => this.ChildrenOfType().Single(d => d.Enabled.Value).TriggerClick()); + } + else + { + AddUntilStep("wait for spread indicator", () => this.ChildrenOfType().Any(d => d.Enabled.Value)); + AddStep("click spread indicator", () => this.ChildrenOfType().Single(d => d.Enabled.Value).TriggerClick()); + } + + WaitForFiltering(); + } + + private BeatmapInfo findBeatmap(string difficultySubstring) => Beatmap.Value.BeatmapSetInfo.Beatmaps.First(b => b.DifficultyName.Contains(difficultySubstring)); + private NoResultsPlaceholder? getPlaceholder() => SongSelect.ChildrenOfType().FirstOrDefault(); private void checkMatchedBeatmaps(int expected) => AddUntilStep($"{expected} matching shown", () => Carousel.MatchedBeatmapsCount, () => Is.EqualTo(expected)); diff --git a/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs b/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs index 650ef4a1a99b..378db5cb2d94 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs +++ b/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs @@ -22,13 +22,8 @@ public partial class FilterControl { public partial class ScopedBeatmapSetDisplay : OsuClickableContainer, IKeyBindingHandler { - public Bindable ScopedBeatmapSet - { - get => scopedBeatmapSet.Current; - set => scopedBeatmapSet.Current = value; - } + public IBindable ScopedBeatmapSet { get; } = new Bindable(); - private readonly BindableWithCurrent scopedBeatmapSet = new BindableWithCurrent(); private Box flashLayer = null!; private Container content = null!; private OsuTextFlowContainer text = null!; @@ -44,7 +39,7 @@ public ScopedBeatmapSetDisplay() } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load(ISongSelect? songSelect, OverlayColourProvider colourProvider) { Content.AutoSizeEasing = Easing.OutQuint; Content.AutoSizeDuration = transition_duration; @@ -97,25 +92,25 @@ private void load(OverlayColourProvider colourProvider) Alpha = 0, }, }); - Action = () => scopedBeatmapSet.Value = null; + Action = () => songSelect?.UnscopeBeatmapSet(); } protected override void LoadComplete() { base.LoadComplete(); - scopedBeatmapSet.BindValueChanged(_ => updateState(), true); + ScopedBeatmapSet.BindValueChanged(_ => updateState(), true); } private void updateState() { - if (scopedBeatmapSet.Value != null) + if (ScopedBeatmapSet.Value != null) { content.BypassAutoSizeAxes = Axes.None; text.Clear(); text.AddText(SongSelectStrings.TemporarilyShowingAllBeatmapsIn); text.AddText(@" "); - text.AddText(scopedBeatmapSet.Value.Metadata.GetDisplayTitleRomanisable(), t => t.Font = OsuFont.Style.Body.With(weight: FontWeight.Bold)); + text.AddText(ScopedBeatmapSet.Value.Metadata.GetDisplayTitleRomanisable(), t => t.Font = OsuFont.Style.Body.With(weight: FontWeight.Bold)); } else { @@ -126,7 +121,7 @@ private void updateState() public bool OnPressed(KeyBindingPressEvent e) { - if (scopedBeatmapSet.Value != null && e.Action == GlobalAction.Back && !e.Repeat) + if (ScopedBeatmapSet.Value != null && e.Action == GlobalAction.Back && !e.Repeat) { TriggerClick(); return true; diff --git a/osu.Game/Screens/SelectV2/FilterControl.cs b/osu.Game/Screens/SelectV2/FilterControl.cs index 268e9371678f..be2d472e6b98 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.cs +++ b/osu.Game/Screens/SelectV2/FilterControl.cs @@ -39,7 +39,7 @@ public partial class FilterControl : OverlayContainer private const float corner_radius = 10; - public Bindable ScopedBeatmapSet { get; } = new Bindable(); + public IBindable ScopedBeatmapSet { get; } = new Bindable(); private SongSelectSearchTextBox searchTextBox = null!; private ShearedToggleButton showConvertedBeatmapsButton = null!; @@ -48,6 +48,9 @@ public partial class FilterControl : OverlayContainer private ShearedDropdown groupDropdown = null!; private CollectionDropdown collectionDropdown = null!; + [Resolved] + private ISongSelect? songSelect { get; set; } + [Resolved] private IBindable ruleset { get; set; } = null!; @@ -115,7 +118,7 @@ private void load(IAPIProvider api) { RelativeSizeAxes = Axes.X, HoldFocus = true, - ScopedBeatmapSet = ScopedBeatmapSet, + ScopedBeatmapSet = { BindTarget = ScopedBeatmapSet }, }, }, new GridContainer @@ -190,7 +193,7 @@ private void load(IAPIProvider api) }, new ScopedBeatmapSetDisplay { - ScopedBeatmapSet = ScopedBeatmapSet, + ScopedBeatmapSet = { BindTarget = ScopedBeatmapSet }, } }, } @@ -298,7 +301,7 @@ private void updateCriteria(bool clearScopedSet = true) { if (clearScopedSet && ScopedBeatmapSet.Value != null) { - ScopedBeatmapSet.Value = null; + songSelect?.UnscopeBeatmapSet(); // because `ScopedBeatmapSet` has a value change callback bound to it that calls `updateCriteria()` again, // we can just do nothing other than clear it to avoid extra work and duplicated `CriteriaChanged` invocations return; @@ -331,34 +334,22 @@ protected override void PopOut() internal partial class SongSelectSearchTextBox : ShearedFilterTextBox { - public Bindable ScopedBeatmapSet - { - get => scopedBeatmapSet.Current; - set => scopedBeatmapSet.Current = value; - } - - private readonly BindableWithCurrent scopedBeatmapSet = new BindableWithCurrent(); + public IBindable ScopedBeatmapSet { get; } = new Bindable(); protected override InnerSearchTextBox CreateInnerTextBox() => new InnerTextBox { - ScopedBeatmapSet = ScopedBeatmapSet, + ScopedBeatmapSet = { BindTarget = ScopedBeatmapSet }, }; private partial class InnerTextBox : InnerFilterTextBox { - public Bindable ScopedBeatmapSet - { - get => scopedBeatmapSet.Current; - set => scopedBeatmapSet.Current = value; - } - - private readonly BindableWithCurrent scopedBeatmapSet = new BindableWithCurrent(); + public IBindable ScopedBeatmapSet { get; } = new Bindable(); public override bool HandleLeftRightArrows => false; public override bool OnPressed(KeyBindingPressEvent e) { - if (e.Action == GlobalAction.Back && scopedBeatmapSet.Value != null) + if (e.Action == GlobalAction.Back && ScopedBeatmapSet.Value != null) return false; return base.OnPressed(e); diff --git a/osu.Game/Screens/SelectV2/ISongSelect.cs b/osu.Game/Screens/SelectV2/ISongSelect.cs index 6280e4048ae4..5de1d4e75eea 100644 --- a/osu.Game/Screens/SelectV2/ISongSelect.cs +++ b/osu.Game/Screens/SelectV2/ISongSelect.cs @@ -48,8 +48,21 @@ public interface ISongSelect IEnumerable GetForwardActions(BeatmapInfo beatmap); /// - /// Set this to a non- value in order to temporarily bypass filter and show all difficulties of the given beatmap set. + /// Temporarily bypasses filters and shows all difficulties of the given beatmapset. /// - Bindable ScopedBeatmapSet { get; } + /// The beatmapset. + void ScopeToBeatmapSet(BeatmapSetInfo beatmapSet); + + /// + /// Removes the beatmapset scope and reverts the previously selected filters. + /// + void UnscopeBeatmapSet(); + + /// + /// Contains the currently scoped beatmapset. Used by external consumers for displaying its state. + /// Cannot be used to change the value, any changes must be done through + /// or . + /// + IBindable ScopedBeatmapSet { get; } } } diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs index db34630c4855..08ea270e1fde 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs @@ -34,11 +34,14 @@ public partial class SpreadDisplay : OsuAnimatedButton protected override Colour4 DimColour => Colour4.White; - private readonly Bindable scopedBeatmapSet = new Bindable(); + private readonly IBindable scopedBeatmapSet = new Bindable(); private readonly Bindable showConvertedBeatmaps = new Bindable(); private const double transition_duration = 200; + [Resolved] + private ISongSelect? songSelect { get; set; } + [Resolved] private Bindable ruleset { get; set; } = null!; @@ -59,7 +62,7 @@ public SpreadDisplay() } [BackgroundDependencyLoader] - private void load(ISongSelect? songSelect, OsuConfigManager configManager) + private void load(OsuConfigManager configManager) { Add(new FillFlowContainer { @@ -201,7 +204,7 @@ private void updateBeatmapSet() } } - Action = () => scopedBeatmapSet.Value = BeatmapSet.Value; + Action = () => songSelect?.ScopeToBeatmapSet(BeatmapSet.Value); updateEnabled(); } diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs index b6b0bac07720..f8f5883c9964 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs @@ -29,11 +29,14 @@ public partial class SpreadDisplay : OsuAnimatedButton protected override Colour4 DimColour => Colour4.White; - private readonly Bindable scopedBeatmapSet = new Bindable(); + private readonly IBindable scopedBeatmapSet = new Bindable(); private readonly Bindable showConvertedBeatmaps = new Bindable(); private const double transition_duration = 200; + [Resolved] + private ISongSelect? songSelect { get; set; } + [Resolved] private Bindable ruleset { get; set; } = null!; @@ -56,12 +59,12 @@ public SpreadDisplay() Action = () => { if (Beatmap.Value != null) - scopedBeatmapSet.Value = Beatmap.Value.BeatmapSet!; + songSelect?.ScopeToBeatmapSet(Beatmap.Value.BeatmapSet!); }; } [BackgroundDependencyLoader] - private void load(ISongSelect? songSelect, OsuConfigManager configManager) + private void load(OsuConfigManager configManager) { Add(new FillFlowContainer { diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index ecf8b3301bc9..00590336ceb4 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -284,6 +284,7 @@ private void load(AudioManager audio, OsuConfigManager config) Anchor = Anchor.TopRight, Origin = Anchor.TopRight, RelativeSizeAxes = Axes.X, + ScopedBeatmapSet = { BindTarget = ScopedBeatmapSet }, }, } }, @@ -1242,7 +1243,29 @@ public void RestoreAllHidden(BeatmapSetInfo beatmapSet) beatmaps.Restore(b); } - public Bindable ScopedBeatmapSet => filterControl.ScopedBeatmapSet; + private GroupedBeatmap? beforeScopedSelection; + + private readonly Bindable scopedBeatmapSet = new Bindable(); + public IBindable ScopedBeatmapSet => scopedBeatmapSet; + + public void ScopeToBeatmapSet(BeatmapSetInfo beatmapSet) + { + beforeScopedSelection = carousel.CurrentGroupedBeatmap; + + scopedBeatmapSet.Value = beatmapSet; + } + + public void UnscopeBeatmapSet() + { + if (scopedBeatmapSet.Value == null) + return; + + if (beforeScopedSelection != null) + queueBeatmapSelection(beforeScopedSelection); + + scopedBeatmapSet.Value = null; + beforeScopedSelection = null; + } #endregion From fc4e29793d86b969f6b3e57e68ff550f3856cc31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 16 Feb 2026 16:46:30 +0100 Subject: [PATCH 674/836] Use directory of last-selected sample as initial directory in sample set add controls (#36680) Closes https://github.com/ppy/osu/issues/36470. Applied directly to relevant control for now. --- osu.Game/Screens/Edit/Components/FormSampleSet.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Components/FormSampleSet.cs b/osu.Game/Screens/Edit/Components/FormSampleSet.cs index 2d3404a513ba..370d36dd8cd9 100644 --- a/osu.Game/Screens/Edit/Components/FormSampleSet.cs +++ b/osu.Game/Screens/Edit/Components/FormSampleSet.cs @@ -46,6 +46,7 @@ public Bindable Current private readonly BindableWithCurrent current = new BindableWithCurrent(); private readonly Dictionary<(string name, string bank), SampleButton> buttons = new Dictionary<(string, string), SampleButton>(); + private readonly Bindable lastSelectedFileDirectory = new Bindable(); private FormControlBackground background = null!; private FormFieldCaption caption = null!; @@ -125,6 +126,7 @@ private IEnumerable createTableContent() Margin = new MarginPadding(5), SampleAddRequested = SampleAddRequested, SampleRemoveRequested = SampleRemoveRequested, + LastSelectedFileDirectory = { BindTarget = lastSelectedFileDirectory }, }; protected override void LoadComplete() @@ -197,6 +199,7 @@ public partial class SampleButton : OsuButton, IHasPopover, IHasContextMenu public Action? SampleRemoveRequested { get; init; } private Bindable selectedFile { get; } = new Bindable(); + public Bindable LastSelectedFileDirectory { get; } = new Bindable(); private TrianglesV2? triangles { get; set; } @@ -313,6 +316,7 @@ private void addSample() this.HidePopover(); ActualFilename.Value = SampleAddRequested?.Invoke(selectedFile.Value, ExpectedFilename.Value) ?? selectedFile.Value.ToString(); + LastSelectedFileDirectory.Value = selectedFile.Value.Directory; } private void deleteSample() @@ -324,7 +328,9 @@ private void deleteSample() ActualFilename.Value = null; } - public Popover? GetPopover() => ActualFilename.Value == null ? new FormFileSelector.FileChooserPopover(SupportedExtensions.AUDIO_EXTENSIONS, selectedFile, null) : null; + public Popover? GetPopover() => ActualFilename.Value == null + ? new FormFileSelector.FileChooserPopover(SupportedExtensions.AUDIO_EXTENSIONS, selectedFile, LastSelectedFileDirectory.Value?.FullName) + : null; public MenuItem[]? ContextMenuItems => ActualFilename.Value != null From 42bf25442b9f2440eef9e6e6f58efdefdccd49bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 16 Feb 2026 16:50:16 +0100 Subject: [PATCH 675/836] Fix osu! editor composer scale handles not updating correctly when selected object is changed (#36681) Before: https://github.com/user-attachments/assets/d0a0373d-2d46-48a9-9ea5-bac82a612f32 After: https://github.com/user-attachments/assets/f5785b54-d7fc-4ce0-86b0-60c96ff22bc3 --- Closes https://github.com/ppy/osu/issues/36677. Kinda shocking this went by unnoticed for this long. --- .../Edit/OsuSelectionScaleHandler.cs | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionScaleHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionScaleHandler.cs index d5f313776989..17f32ea67d5d 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionScaleHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionScaleHandler.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Framework.Utils; @@ -37,13 +38,16 @@ public partial class OsuSelectionScaleHandler : SelectionScaleHandler [Resolved] private IEditorChangeHandler? changeHandler { get; set; } + [Resolved] + private EditorBeatmap editorBeatmap { get; set; } = null!; + [Resolved(CanBeNull = true)] private IDistanceSnapProvider? snapProvider { get; set; } private BindableList selectedItems { get; } = new BindableList(); [BackgroundDependencyLoader] - private void load(EditorBeatmap editorBeatmap) + private void load() { selectedItems.BindTo(editorBeatmap.SelectedHitObjects); } @@ -53,15 +57,22 @@ protected override void LoadComplete() base.LoadComplete(); selectedItems.CollectionChanged += (_, __) => updateState(); + editorBeatmap.HitObjectUpdated += hitObjectUpdated; updateState(); } + private void hitObjectUpdated(HitObject hitObject) + { + if (selectedMovableObjects.Contains(hitObject)) + updateState(); + } + private void updateState() { var quad = GeometryUtils.GetSurroundingQuad(selectedMovableObjects); - CanScaleX.Value = quad.Width > 0; - CanScaleY.Value = quad.Height > 0; + CanScaleX.Value = Precision.DefinitelyBigger(quad.Width, 0); + CanScaleY.Value = Precision.DefinitelyBigger(quad.Height, 0); CanScaleDiagonally.Value = CanScaleX.Value && CanScaleY.Value; CanScaleFromPlayfieldOrigin.Value = selectedMovableObjects.Any(); IsScalingSlider.Value = selectedMovableObjects.Count() == 1 && selectedMovableObjects.First() is Slider; @@ -339,5 +350,13 @@ public OriginalHitObjectState(OsuHitObject hitObject) PathControlPointTypes = (hitObject as IHasPath)?.Path.ControlPoints.Select(p => p.Type).ToArray(); } } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (editorBeatmap.IsNotNull()) + editorBeatmap.HitObjectUpdated -= hitObjectUpdated; + } } } From 94cec71502cc1a3f91cabaf89551d00cc360f823 Mon Sep 17 00:00:00 2001 From: Vanni <103026931+imvanni@users.noreply.github.com> Date: Tue, 17 Feb 2026 06:49:59 +0100 Subject: [PATCH 676/836] Prevent tagging beatmaps when played with conversion mods (#36684) Closes #36553. Supersedes #36614. As discussed in #36614, the only exception to this is `ModClassic`. --- osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index 5c5c814c5b98..55e029f0410f 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -21,6 +21,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.Placeholders; +using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Ranking.Statistics.User; using osuTK; @@ -258,6 +259,8 @@ protected virtual IEnumerable CreateStatisticItems(ScoreInfo newS preventTaggingReason = "Play the beatmap in its original ruleset to contribute to beatmap tags!"; else if (localUserScore.Rank < ScoreRank.C) preventTaggingReason = "Set a better score to contribute to beatmap tags!"; + else if (localUserScore.Mods.Any(m => (m.Type == ModType.Conversion) && !(m is ModClassic))) + preventTaggingReason = "Play this beatmap without conversion mods to contribute to beatmap tags!"; if (preventTaggingReason == null) { From 71583bc06f8d3388deebf886cd89e09f24fb17c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Feb 2026 15:54:31 +0900 Subject: [PATCH 677/836] Add basic support for `scoreentry-` skinnable text --- osu.Game/Skinning/LegacyFont.cs | 1 + osu.Game/Skinning/LegacyKeyCounter.cs | 7 ++----- osu.Game/Skinning/LegacySkinExtensions.cs | 9 ++++++++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/osu.Game/Skinning/LegacyFont.cs b/osu.Game/Skinning/LegacyFont.cs index d1971cb84ce6..bd4971faa4de 100644 --- a/osu.Game/Skinning/LegacyFont.cs +++ b/osu.Game/Skinning/LegacyFont.cs @@ -11,5 +11,6 @@ public enum LegacyFont Score, Combo, HitCircle, + ScoreEntry, } } diff --git a/osu.Game/Skinning/LegacyKeyCounter.cs b/osu.Game/Skinning/LegacyKeyCounter.cs index 609e21b9ffb3..74c7caf0a09e 100644 --- a/osu.Game/Skinning/LegacyKeyCounter.cs +++ b/osu.Game/Skinning/LegacyKeyCounter.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics.Textures; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; using osu.Game.Screens.Play.HUD; namespace osu.Game.Skinning @@ -32,7 +31,7 @@ public Colour4 TextColour } private readonly Container keyContainer; - private readonly OsuSpriteText overlayKeyText; + private readonly LegacySpriteText overlayKeyText; private readonly Sprite keySprite; public LegacyKeyCounter(InputTrigger trigger) @@ -57,13 +56,12 @@ public LegacyKeyCounter(InputTrigger trigger) AutoSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Child = overlayKeyText = new OsuSpriteText + Child = overlayKeyText = new LegacySpriteText(LegacyFont.ScoreEntry) { Anchor = Anchor.Centre, Origin = Anchor.Centre, Text = trigger.Name, Colour = textColour, - Font = OsuFont.GetFont(weight: FontWeight.SemiBold), }, }, } @@ -88,7 +86,6 @@ protected override void Activate(bool forwardPlayback = true) keyContainer.ScaleTo(0.75f, transition_duration, Easing.Out); keySprite.Colour = ActiveColour; overlayKeyText.Text = CountPresses.Value.ToString(); - overlayKeyText.Font = overlayKeyText.Font.With(weight: FontWeight.SemiBold); } protected override void Deactivate(bool forwardPlayback = true) diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs index a8ec67d98b57..e4da89fc91be 100644 --- a/osu.Game/Skinning/LegacySkinExtensions.cs +++ b/osu.Game/Skinning/LegacySkinExtensions.cs @@ -55,7 +55,8 @@ public static partial class LegacySkinExtensions } } - public static Texture[] GetTextures(this ISkin? source, string componentName, WrapMode wrapModeS, WrapMode wrapModeT, bool animatable, string animationSeparator, Vector2? maxSize, out ISkin? retrievalSource) + public static Texture[] GetTextures(this ISkin? source, string componentName, WrapMode wrapModeS, WrapMode wrapModeT, bool animatable, string animationSeparator, Vector2? maxSize, + out ISkin? retrievalSource) { retrievalSource = null; @@ -140,6 +141,9 @@ public static string GetFontPrefix(this ISkin source, LegacyFont font) { switch (font) { + case LegacyFont.ScoreEntry: + return "scoreentry"; + case LegacyFont.Score: return source.GetConfig(LegacySetting.ScorePrefix)?.Value ?? "score"; @@ -163,6 +167,9 @@ public static float GetFontOverlap(this ISkin source, LegacyFont font) { switch (font) { + case LegacyFont.ScoreEntry: + return 0; + case LegacyFont.Score: return source.GetConfig(LegacySetting.ScoreOverlap)?.Value ?? 0f; From 6e03d5b00ed9788228949af7af07c3d5b1bf6c12 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Feb 2026 16:02:13 +0900 Subject: [PATCH 678/836] Show initial key placeholder / trigger name using non-skinned font In stable, there was support for mixed fonts (some coming from the user's skin, with fallback missing characters generated from TTF backend). We don't really have support for this so this is a simple in-between for the time being. --- osu.Game/Skinning/LegacyKeyCounter.cs | 40 +++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/osu.Game/Skinning/LegacyKeyCounter.cs b/osu.Game/Skinning/LegacyKeyCounter.cs index 74c7caf0a09e..84ecfb79baf2 100644 --- a/osu.Game/Skinning/LegacyKeyCounter.cs +++ b/osu.Game/Skinning/LegacyKeyCounter.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Textures; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; using osu.Game.Screens.Play.HUD; namespace osu.Game.Skinning @@ -26,14 +27,19 @@ public Colour4 TextColour set { textColour = value; + initialNameText.Colour = value; overlayKeyText.Colour = value; } } private readonly Container keyContainer; private readonly LegacySpriteText overlayKeyText; + private readonly OsuSpriteText initialNameText; + private readonly Sprite keySprite; + private bool activatedOnce; + public LegacyKeyCounter(InputTrigger trigger) : base(trigger) { @@ -56,13 +62,26 @@ public LegacyKeyCounter(InputTrigger trigger) AutoSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Child = overlayKeyText = new LegacySpriteText(LegacyFont.ScoreEntry) + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = trigger.Name, - Colour = textColour, - }, + // The legacy font doesn't contain all the characters necessary to display placeholders. + // Keep things simple by using a normal font for this case. + initialNameText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = trigger.Name, + Font = OsuFont.GetFont(weight: FontWeight.SemiBold), + Colour = textColour, + }, + overlayKeyText = new LegacySpriteText(LegacyFont.ScoreEntry) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + Colour = textColour, + } + } }, } }; @@ -83,9 +102,18 @@ private void load(ISkinSource source) protected override void Activate(bool forwardPlayback = true) { base.Activate(forwardPlayback); + keyContainer.ScaleTo(0.75f, transition_duration, Easing.Out); keySprite.Colour = ActiveColour; + overlayKeyText.Text = CountPresses.Value.ToString(); + + if (!activatedOnce) + { + activatedOnce = true; + initialNameText.FadeOut(transition_duration, Easing.Out); + overlayKeyText.FadeIn(transition_duration, Easing.Out); + } } protected override void Deactivate(bool forwardPlayback = true) From cc9a5ede29083a1613fab47ba2223b26b2f97a3c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Feb 2026 16:44:26 +0900 Subject: [PATCH 679/836] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 34373d0fbcaf..7210afb0c6c5 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From 86ab507e2e40280a341ff2185013672d16a3d16f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Feb 2026 02:21:56 +0900 Subject: [PATCH 680/836] Use default overlap of 1 Matches closer to stable spec. --- osu.Game/Skinning/LegacySkinExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs index e4da89fc91be..0339194c9e4e 100644 --- a/osu.Game/Skinning/LegacySkinExtensions.cs +++ b/osu.Game/Skinning/LegacySkinExtensions.cs @@ -168,7 +168,7 @@ public static float GetFontOverlap(this ISkin source, LegacyFont font) switch (font) { case LegacyFont.ScoreEntry: - return 0; + return 1; case LegacyFont.Score: return source.GetConfig(LegacySetting.ScoreOverlap)?.Value ?? 0f; From 7445efaecd1005ab6b3dc644f9202a4ba6d7ba49 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Feb 2026 02:25:09 +0900 Subject: [PATCH 681/836] Ensure state resets back to initial display on rewind --- osu.Game/Skinning/LegacyKeyCounter.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacyKeyCounter.cs b/osu.Game/Skinning/LegacyKeyCounter.cs index 84ecfb79baf2..1879c999641a 100644 --- a/osu.Game/Skinning/LegacyKeyCounter.cs +++ b/osu.Game/Skinning/LegacyKeyCounter.cs @@ -108,7 +108,7 @@ protected override void Activate(bool forwardPlayback = true) overlayKeyText.Text = CountPresses.Value.ToString(); - if (!activatedOnce) + if (forwardPlayback && !activatedOnce) { activatedOnce = true; initialNameText.FadeOut(transition_duration, Easing.Out); @@ -121,6 +121,13 @@ protected override void Deactivate(bool forwardPlayback = true) base.Deactivate(forwardPlayback); keyContainer.ScaleTo(1f, transition_duration, Easing.Out); keySprite.Colour = Colour4.White; + + if (!forwardPlayback && activatedOnce && CountPresses.Value == 0) + { + activatedOnce = false; + initialNameText.FadeIn(transition_duration, Easing.Out); + overlayKeyText.FadeOut(transition_duration, Easing.Out); + } } } } From f15e086bb0f2cc95d314ec19a96706043832a8c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Feb 2026 17:21:03 +0900 Subject: [PATCH 682/836] Add "spin" keyword for menu cursor rotation --- .../Settings/Sections/UserInterface/GeneralSettings.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs index 9a894e89fed7..62ecfbc0598c 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs @@ -24,7 +24,10 @@ private void load(OsuConfigManager config) { Caption = UserInterfaceStrings.CursorRotation, Current = config.GetBindable(OsuSetting.CursorRotation) - }), + }) + { + Keywords = [@"spin"], + }, new SettingsItemV2(new FormSliderBar { Caption = UserInterfaceStrings.MenuCursorSize, @@ -45,7 +48,7 @@ private void load(OsuConfigManager config) LabelFormat = v => $"{v:N0} ms", }) { - Keywords = new[] { @"delay" }, + Keywords = [@"delay"], ApplyClassicDefault = c => ((IHasCurrentValue)c).Current.Value = 0, }, }; From 83587e22657541f0d0e64e7295baa0e00b527ffd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Feb 2026 19:43:17 +0900 Subject: [PATCH 683/836] Add ability for `LoadingLayer` to block all keyboard input --- .../UserInterface/TestSceneLoadingLayer.cs | 93 ++++++++++++++++++- .../Graphics/UserInterface/LoadingLayer.cs | 30 ++++-- .../Overlays/Toolbar/ToolbarUserButton.cs | 3 +- .../Screens/Play/BeatmapMetadataDisplay.cs | 5 +- 4 files changed, 117 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs index 66bf870f90b2..2fb8d11cd32b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs @@ -7,21 +7,27 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Input.Bindings; using osuTK; using osuTK.Graphics; +using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public partial class TestSceneLoadingLayer : OsuTestScene + public partial class TestSceneLoadingLayer : OsuManualInputManagerTestScene { private TestLoadingLayer overlay; private Container content; + private PressableButton pressableButton; + [SetUp] public void SetUp() => Schedule(() => { @@ -51,10 +57,9 @@ public void SetUp() => Schedule(() => { new OsuSpriteText { Text = "Sample content" }, new RoundedButton { Text = "can't puush me", Width = 200, }, - new RoundedButton { Text = "puush me", Width = 200, Action = () => { } }, + pressableButton = new PressableButton { Text = "puush me", Width = 200 }, } }, - overlay = new TestLoadingLayer(true), } }, }; @@ -63,20 +68,62 @@ public void SetUp() => Schedule(() => [Test] public void TestShowHide() { + AddStep("create loading layer", () => content.Add(overlay = new TestLoadingLayer(true))); + AddAssert("not visible", () => !overlay.IsPresent); AddStep("show", () => overlay.Show()); - AddUntilStep("wait for content dim", () => overlay.Alpha > 0); AddStep("hide", () => overlay.Hide()); - AddUntilStep("wait for content restore", () => Precision.AlmostEquals(overlay.Alpha, 0)); } + [TestCase(true)] + [TestCase(false)] + public void TestBlockPositional(bool blockInput) + { + AddStep("create loading layer", () => content.Add(overlay = new TestLoadingLayer(true) { BlockPositionalInput = blockInput })); + AddStep("show", () => overlay.Show()); + + AddStep("click button", () => + { + InputManager.MoveMouseTo(pressableButton); + InputManager.Click(MouseButton.Left); + }); + + AddAssert("check pressed", () => pressableButton.Pressed, () => Is.EqualTo(!blockInput)); + } + + [TestCase(true)] + [TestCase(false)] + public void TestBlockNonPositional(bool blockKeyboardInput) + { + AddStep("create loading layer", () => content.Add(overlay = new TestLoadingLayer(true) { BlockNonPositionalInput = blockKeyboardInput })); + AddStep("show", () => overlay.Show()); + + AddStep("press enter", () => InputManager.Key(Key.Enter)); + + AddAssert("check pressed", () => pressableButton.Pressed, () => Is.EqualTo(!blockKeyboardInput)); + } + + [TestCase(true)] + [TestCase(false)] + public void TestBlockNonPositionalGlobalAction(bool blockKeyboardInput) + { + AddStep("create loading layer", () => content.Add(overlay = new TestLoadingLayer(true) { BlockNonPositionalInput = blockKeyboardInput })); + AddStep("show", () => overlay.Show()); + + AddStep("press enter", () => InputManager.Key(Key.F8)); + + AddAssert("check pressed", () => pressableButton.Pressed, () => Is.EqualTo(!blockKeyboardInput)); + } + [Test] public void TestLargeArea() { + AddStep("create loading layer", () => content.Add(overlay = new TestLoadingLayer(true))); + AddStep("show", () => { content.RelativeSizeAxes = Axes.Both; @@ -88,6 +135,42 @@ public void TestLargeArea() AddStep("hide", () => overlay.Hide()); } + public partial class PressableButton : RoundedButton, IKeyBindingHandler + { + public PressableButton() + { + Action = () => Pressed = true; + } + + public bool Pressed { get; private set; } + + protected override bool OnKeyDown(KeyDownEvent e) + { + if (e.Key == Key.Enter) + { + Pressed = true; + return true; + } + + return base.OnKeyDown(e); + } + + public bool OnPressed(KeyBindingPressEvent e) + { + if (e.Action == GlobalAction.ToggleChat) + { + Pressed = true; + return true; + } + + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + } + } + private partial class TestLoadingLayer : LoadingLayer { public TestLoadingLayer(bool dimBackground = false, bool withBox = true) diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index 916b041696ca..0a5801475e63 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -6,7 +6,9 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Game.Input.Bindings; using osuTK; using osuTK.Graphics; @@ -17,20 +19,28 @@ namespace osu.Game.Graphics.UserInterface /// Also optionally dims target elements. /// Useful for disabling all elements in a form and showing we are waiting on a response, for instance. /// - public partial class LoadingLayer : LoadingSpinner + public partial class LoadingLayer : LoadingSpinner, IKeyBindingHandler { - private readonly bool blockInput; + /// + /// Whether to block positional input of components behind the loading layer. + /// Defaults to true. + /// + public bool BlockPositionalInput { get; init; } = true; + + /// + /// Whether to block all keyboard input. Includes global actions. + /// Defaults to false. + /// + public bool BlockNonPositionalInput { get; init; } /// /// Construct a new loading spinner. /// /// Whether the full background area should be dimmed while loading. /// Whether the spinner should have a surrounding black box for visibility. - /// Whether to block input of components behind the loading layer. - public LoadingLayer(bool dimBackground = false, bool withBox = true, bool blockInput = true) + public LoadingLayer(bool dimBackground = false, bool withBox = true) : base(withBox) { - this.blockInput = blockInput; RelativeSizeAxes = Axes.Both; Size = new Vector2(1); @@ -48,11 +58,11 @@ public LoadingLayer(bool dimBackground = false, bool withBox = true, bool blockI } } - public override bool HandleNonPositionalInput => false; + public override bool HandleNonPositionalInput => BlockNonPositionalInput; protected override bool Handle(UIEvent e) { - if (!blockInput) + if (!BlockPositionalInput) return false; switch (e) @@ -76,5 +86,11 @@ protected override void Update() MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 20, 80)); } + + public bool OnPressed(KeyBindingPressEvent e) => BlockNonPositionalInput; + + public void OnReleased(KeyBindingReleaseEvent e) + { + } } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index 787c525566bb..2ade335ef710 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -59,8 +59,9 @@ private void load(OsuColour colours, IAPIProvider api, LoginOverlay? login) { RelativeSizeAxes = Axes.Both, }, - spinner = new LoadingLayer(dimBackground: true, withBox: false, blockInput: false) + spinner = new LoadingLayer(dimBackground: true, withBox: false) { + BlockPositionalInput = false, Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index 23264c4518c9..f1df01b7434d 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -114,7 +114,10 @@ private void load(BeatmapDifficultyCache difficultyCache) Anchor = Anchor.Centre, FillMode = FillMode.Fill, }, - loading = new LoadingLayer(dimBackground: true, blockInput: false) + loading = new LoadingLayer(dimBackground: true) + { + BlockPositionalInput = false, + } } }, versionFlow = new FillFlowContainer From 93d1a61dc206c237324a804acf8d4366520da0de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Feb 2026 19:29:56 +0900 Subject: [PATCH 684/836] Migrate playlist freestyle select screen to use `SongSelectV2` --- .../OnlinePlay/OnlinePlayFreestyleSelectV2.cs | 113 ++++++++++++++++++ .../Playlists/PlaylistsRoomSubScreen.cs | 2 +- ...t.cs => PlaylistsRoomFreestyleSelectV2.cs} | 14 +-- osu.Game/Screens/SelectV2/FilterControl.cs | 10 +- osu.Game/Screens/SelectV2/SongSelect.cs | 17 +-- 5 files changed, 137 insertions(+), 19 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs rename osu.Game/Screens/OnlinePlay/{Playlists/PlaylistsRoomFreestyleSelect.cs => PlaylistsRoomFreestyleSelectV2.cs} (64%) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs new file mode 100644 index 000000000000..e68ffffc1095 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs @@ -0,0 +1,113 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using Humanizer; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Logging; +using osu.Game.Beatmaps; +using osu.Game.Database; +using osu.Game.Online.Rooms; +using osu.Game.Rulesets; +using osu.Game.Screens.Select; +using SongSelect = osu.Game.Screens.SelectV2.SongSelect; + +namespace osu.Game.Screens.OnlinePlay +{ + public abstract partial class OnlinePlayFreestyleSelectV2 : SongSelect, IHandlePresentBeatmap, IOnlinePlaySubScreen + { + private readonly PlaylistItem item; + + public string ShortTitle => "style selection"; + public override string Title => ShortTitle.Humanize(); + + protected abstract void StartAction(); + + [Resolved] + private RealmAccess realm { get; set; } = null!; + + protected OnlinePlayFreestyleSelectV2(PlaylistItem item) + { + this.item = item; + + Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; + } + + [BackgroundDependencyLoader] + private void load() + { + FilterControl.ApplyRequiredCriteria = applyRestrictions; + } + + protected override void OnStart() + { + if (isValidForSelection()) + StartAction(); + } + + private void applyRestrictions(FilterCriteria criteria) + { + double itemLength = 0; + int beatmapSetId = 0; + + realm.Run(r => + { + int beatmapId = item.Beatmap.OnlineID; + BeatmapInfo? beatmap = r.All().FirstOrDefault(b => b.OnlineID == beatmapId); + + itemLength = beatmap?.Length ?? 0; + beatmapSetId = beatmap?.BeatmapSet?.OnlineID ?? 0; + }); + + // Must be from the same set as the playlist item. + criteria.BeatmapSetId = beatmapSetId; + criteria.HasOnlineID = true; + + // Must be within 30s of the playlist item. + criteria.Length.Min = itemLength - 30000; + criteria.Length.Max = itemLength + 30000; + criteria.Length.IsLowerInclusive = true; + criteria.Length.IsUpperInclusive = true; + } + + private bool isValidForSelection() + { + FilterCriteria criteria = FilterControl.CreateCriteria(); + + // Beatmaps with too different of a duration are filtered away; this is just a final safety. + if (!criteria.Length.IsInRange(Beatmap.Value.BeatmapInfo.Length)) + { + Logger.Log("The selected beatmap's duration differs too much from the host's selection.", level: LogLevel.Error); + return false; + } + + // Beatmaps without a valid online ID are filtered away; this is just a final safety. + if (Beatmap.Value.BeatmapInfo.OnlineID < 0) + { + Logger.Log("The selected beatmap is not available online.", level: LogLevel.Error); + return false; + } + + // Beatmaps from different sets are filtered away; this is just a final safety. + if (Beatmap.Value.BeatmapSetInfo.OnlineID != criteria.BeatmapSetId) + { + Logger.Log("The selected beatmap is from a different beatmap set.", level: LogLevel.Error); + return false; + } + + if (Ruleset.Value.OnlineID < 0) + { + Logger.Log("The selected ruleset is not available online.", level: LogLevel.Error); + return false; + } + + return true; + } + + void IHandlePresentBeatmap.PresentBeatmap(WorkingBeatmap workingBeatmap, RulesetInfo ruleset) + { + // This screen cannot present beatmaps. + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index bc99ab16bb60..bab4d691bb94 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -696,7 +696,7 @@ private void showUserStyleSelect() if (!this.IsCurrentScreen() || SelectedItem.Value == null) return; - this.Push(new PlaylistsRoomFreestyleSelect(room, SelectedItem.Value) + this.Push(new PlaylistsRoomFreestyleSelectV2(SelectedItem.Value) { Beatmap = { BindTarget = UserBeatmap }, Ruleset = { BindTarget = UserRuleset } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomFreestyleSelect.cs b/osu.Game/Screens/OnlinePlay/PlaylistsRoomFreestyleSelectV2.cs similarity index 64% rename from osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomFreestyleSelect.cs rename to osu.Game/Screens/OnlinePlay/PlaylistsRoomFreestyleSelectV2.cs index 1f0f92aea289..ead76dac8d81 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomFreestyleSelect.cs +++ b/osu.Game/Screens/OnlinePlay/PlaylistsRoomFreestyleSelectV2.cs @@ -7,28 +7,24 @@ using osu.Game.Online.Rooms; using osu.Game.Rulesets; -namespace osu.Game.Screens.OnlinePlay.Playlists +namespace osu.Game.Screens.OnlinePlay { - public partial class PlaylistsRoomFreestyleSelect : OnlinePlayFreestyleSelect + public partial class PlaylistsRoomFreestyleSelectV2 : OnlinePlayFreestyleSelectV2 { public new readonly Bindable Beatmap = new Bindable(); public new readonly Bindable Ruleset = new Bindable(); - public PlaylistsRoomFreestyleSelect(Room room, PlaylistItem item) - : base(room, item) + public PlaylistsRoomFreestyleSelectV2(PlaylistItem item) + : base(item) { } - protected override bool OnStart() + protected override void StartAction() { - if (!base.OnStart()) - return false; - Beatmap.Value = base.Beatmap.Value.BeatmapInfo; Ruleset.Value = base.Ruleset.Value; this.Exit(); - return true; } } } diff --git a/osu.Game/Screens/SelectV2/FilterControl.cs b/osu.Game/Screens/SelectV2/FilterControl.cs index be2d472e6b98..20a55e3e09e3 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.cs +++ b/osu.Game/Screens/SelectV2/FilterControl.cs @@ -32,7 +32,7 @@ namespace osu.Game.Screens.SelectV2 { - public partial class FilterControl : OverlayContainer + public sealed partial class FilterControl : OverlayContainer { // taken from draw visualiser. used for carousel alignment purposes. public const float HEIGHT_FROM_SCREEN_TOP = 141 - corner_radius; @@ -48,6 +48,11 @@ public partial class FilterControl : OverlayContainer private ShearedDropdown groupDropdown = null!; private CollectionDropdown collectionDropdown = null!; + /// + /// An optional method which can force certain criteria adjustments. + /// + public Action? ApplyRequiredCriteria { get; set; } + [Resolved] private ISongSelect? songSelect { get; set; } @@ -294,6 +299,9 @@ public FilterCriteria CreateCriteria() criteria.RulesetCriteria = ruleset.Value.CreateInstance().CreateRulesetFilterCriteria(); FilterQueryParser.ApplyQueries(criteria, query); + + ApplyRequiredCriteria?.Invoke(criteria); + return criteria; } diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index 00590336ceb4..96e292152ad0 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -111,7 +111,8 @@ public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBind private BeatmapCarousel carousel = null!; - private FilterControl filterControl = null!; + protected FilterControl FilterControl = null!; + private BeatmapTitleWedge titleWedge = null!; private BeatmapDetailsArea detailsArea = null!; private FillFlowContainer wedgesContainer = null!; @@ -275,11 +276,11 @@ private void load(AudioManager audio, OsuConfigManager config) }, noResultsPlaceholder = new NoResultsPlaceholder { - RequestClearFilterText = () => filterControl.Search(string.Empty) + RequestClearFilterText = () => FilterControl.Search(string.Empty) } } }, - filterControl = new FilterControl + FilterControl = new FilterControl { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, @@ -379,7 +380,7 @@ protected override void LoadComplete() inputManager = GetContainingInputManager()!; - filterControl.CriteriaChanged += criteriaChanged; + FilterControl.CriteriaChanged += criteriaChanged; modSelectOverlay.State.BindValueChanged(v => { @@ -821,13 +822,13 @@ private void updateWedgeVisibility() { titleWedge.Hide(); detailsArea.Hide(); - filterControl.Hide(); + FilterControl.Hide(); } else { titleWedge.Show(); detailsArea.Show(); - filterControl.Show(); + FilterControl.Show(); } } @@ -890,7 +891,7 @@ private void newItemsPresented(IEnumerable carouselItems) // Intentionally not localised until we have proper support for this (see https://github.com/ppy/osu-framework/pull/4918 // but also in this case we want support for formatting a number within a string). - filterControl.StatusText = count != 1 ? $"{count:#,0} matches" : $"{count:#,0} match"; + FilterControl.StatusText = count != 1 ? $"{count:#,0} matches" : $"{count:#,0} match"; // If there's already a selection update in progress, let's not interrupt it. // Interrupting could cause the debounce interval to be reduced. @@ -1148,7 +1149,7 @@ private void fetchOnlineInfo(bool force = false) #region Implementation of ISongSelect - void ISongSelect.Search(string query) => filterControl.Search(query); + void ISongSelect.Search(string query) => FilterControl.Search(query); void ISongSelect.PresentScore(ScoreInfo score) { From fb8c228d32699080965e8de6b58c5c98efbaf86c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Feb 2026 18:09:22 +0900 Subject: [PATCH 685/836] Add test coverage of actual user flows involving freestyle select screen Of note, this test scene still doesn't use the new footer properly. Should these even be here? Maybe it's better to leave these real world flows to a `Navigation` style test so we're not dealing with weird test setups that kinda do something but don't... or maybe do it in three different ways (two footers present, three back buttons etc.) Dunno. But this kind of covers what I want (except it doesn't cover the new footer usage). --- .../TestScenePlaylistsRoomSubScreen.cs | 115 +++++++++++++++--- 1 file changed, 96 insertions(+), 19 deletions(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs index 87f65111b004..346625b50ca4 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs @@ -13,11 +13,11 @@ using osu.Framework.Extensions; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Platform; +using osu.Framework.Screens; +using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; -using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Rulesets; @@ -30,10 +30,12 @@ using osu.Game.Rulesets.Taiko; using osu.Game.Rulesets.Taiko.Mods; using osu.Game.Screens; +using osu.Game.Screens.Footer; using osu.Game.Screens.OnlinePlay; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual.OnlinePlay; +using osuTK.Input; namespace osu.Game.Tests.Visual.Playlists { @@ -215,6 +217,85 @@ public void TestBeatmapStyle_Reset_OnSelection() AddUntilStep("second beatmap selected", () => Beatmap.Value.BeatmapInfo.Equals(importedSet.Beatmaps[0])); } + [Test] + public void TestFreestyleSelectAbort() + { + Room room = null!; + + AddStep("add room", () => + { + room = new Room + { + RoomID = 1, + Playlist = + [ + new PlaylistItem(importedSet.Beatmaps[0]) + { + RulesetID = new OsuRuleset().RulesetInfo.OnlineID, + Freestyle = true + }, + ] + }; + + API.Perform(new CreateRoomRequest(room)); + }); + + TestPlaylistsScreen playlistsScreen = null!; + + AddStep("load screen", () => LoadScreen(playlistsScreen = new TestPlaylistsScreen(new TestPlaylistsRoomSubScreen(room)))); + AddUntilStep("wait for playlist room screen", () => playlistsScreen.Stack.CurrentScreen is PlaylistsRoomSubScreen roomSubScreen && roomSubScreen.IsLoaded); + + AddUntilStep("original beatmap", () => Beatmap.Value.BeatmapInfo.Equals(importedSet.Beatmaps[0])); + + AddStep("enter freestyle select", () => playlistsScreen.Stack.ChildrenOfType().Single(b => b.IsPresent).TriggerClick()); + AddUntilStep("wait for select screen", () => playlistsScreen.Stack.CurrentScreen is PlaylistsRoomFreestyleSelectV2 selectScreen && selectScreen.CarouselItemsPresented); + + AddStep("select next beatmap", () => InputManager.Key(Key.Down)); + AddStep("abort", () => playlistsScreen.Stack.CurrentScreen.Exit()); + + AddUntilStep("beatmap not changed", () => Beatmap.Value.BeatmapInfo.Equals(importedSet.Beatmaps[0])); + } + + [Test] + public void TestFreestyleSelect() + { + Room room = null!; + + AddStep("add room", () => + { + room = new Room + { + RoomID = 1, + Playlist = + [ + new PlaylistItem(importedSet.Beatmaps[0]) + { + RulesetID = new OsuRuleset().RulesetInfo.OnlineID, + Freestyle = true + }, + ] + }; + + API.Perform(new CreateRoomRequest(room)); + }); + + TestPlaylistsScreen playlistsScreen = null!; + + AddStep("load screen", () => LoadScreen(playlistsScreen = new TestPlaylistsScreen(new TestPlaylistsRoomSubScreen(room)))); + AddUntilStep("wait for playlist room screen", () => playlistsScreen.Stack.CurrentScreen is PlaylistsRoomSubScreen roomSubScreen && roomSubScreen.IsLoaded); + + AddUntilStep("original beatmap", () => Beatmap.Value.BeatmapInfo.Equals(importedSet.Beatmaps[0])); + + AddStep("enter freestyle select", () => playlistsScreen.Stack.ChildrenOfType().Single(b => b.IsPresent).TriggerClick()); + AddUntilStep("wait for select screen", () => playlistsScreen.Stack.CurrentScreen is PlaylistsRoomFreestyleSelectV2 selectScreen && selectScreen.CarouselItemsPresented); + + AddStep("select next beatmap", () => InputManager.Key(Key.Down)); + AddStep("select (beatmap)", () => InputManager.Key(Key.Enter)); + AddStep("select (exit screen)", () => InputManager.Key(Key.Enter)); + + AddUntilStep("beatmap changed", () => Beatmap.Value.BeatmapInfo.Equals(importedSet.Beatmaps[1])); + } + /// /// Tests that the ruleset style is reset when the selected item is changed and it's no longer valid. /// @@ -591,30 +672,26 @@ protected override void Dispose(bool isDisposing) private partial class TestPlaylistsScreen : OsuScreen { + public readonly OnlinePlaySubScreenStack Stack; + public TestPlaylistsScreen(PlaylistsRoomSubScreen screen) { - OnlinePlaySubScreenStack stack; - - InternalChildren = new Drawable[] + ScreenFooter footer; + InternalChild = new DependencyProvidingContainer { - stack = new OnlinePlaySubScreenStack - { - RelativeSizeAxes = Axes.Both - }, - new BackButton + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - State = { Value = Visibility.Visible }, - Action = () => + Stack = new OnlinePlaySubScreenStack { - if (stack.CurrentScreen is not PlaylistsRoomSubScreen) - stack.Exit(); - } - } + RelativeSizeAxes = Axes.Both + }, + footer = new ScreenFooter(), + }, + CachedDependencies = new (Type, object)[] { (typeof(ScreenFooter), footer) }, }; - stack.Push(screen); + Stack.Push(screen); } } From 110f11fa5e0eaabf1a35dcc7d6b38827e4823de6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Feb 2026 19:18:13 +0900 Subject: [PATCH 686/836] Fade out header line for now to avoid visual overlap --- osu.Game/Screens/OnlinePlay/Header.cs | 13 ++++++++++++- osu.Game/Screens/OnlinePlay/IOnlinePlaySubScreen.cs | 2 ++ .../OnlinePlay/OnlinePlayFreestyleSelectV2.cs | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Header.cs b/osu.Game/Screens/OnlinePlay/Header.cs index 825f80939758..a646dc73c9f4 100644 --- a/osu.Game/Screens/OnlinePlay/Header.cs +++ b/osu.Game/Screens/OnlinePlay/Header.cs @@ -43,7 +43,18 @@ public Header(LocalisableString mainTitle, ScreenStack? stack) } } - private void updateSubScreenTitle() => title.Screen = stack?.CurrentScreen as IOnlinePlaySubScreen; + private void updateSubScreenTitle() + { + IOnlinePlaySubScreen? screen = stack?.CurrentScreen as IOnlinePlaySubScreen; + + if (screen?.ShowHeaderLine == true) + { + title.FadeIn(200, Easing.OutQuint); + title.Screen = screen; + } + else + title.FadeOut(200, Easing.OutQuint); + } private partial class MultiHeaderTitle : CompositeDrawable { diff --git a/osu.Game/Screens/OnlinePlay/IOnlinePlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/IOnlinePlaySubScreen.cs index c528e3952ea6..265a2e18e4bd 100644 --- a/osu.Game/Screens/OnlinePlay/IOnlinePlaySubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/IOnlinePlaySubScreen.cs @@ -8,5 +8,7 @@ public interface IOnlinePlaySubScreen : IOsuScreen string Title { get; } string ShortTitle { get; } + + bool ShowHeaderLine => true; } } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs index e68ffffc1095..751c23d526a9 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs @@ -21,6 +21,7 @@ public abstract partial class OnlinePlayFreestyleSelectV2 : SongSelect, IHandleP public string ShortTitle => "style selection"; public override string Title => ShortTitle.Humanize(); + public bool ShowHeaderLine => false; protected abstract void StartAction(); From d33a6d551285efa4ef040fcae111df6b841b1c42 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Feb 2026 19:43:17 +0900 Subject: [PATCH 687/836] Add ability for `LoadingLayer` to block all keyboard input --- .../UserInterface/TestSceneLoadingLayer.cs | 93 ++++++++++++++++++- .../Graphics/UserInterface/LoadingLayer.cs | 30 ++++-- .../Overlays/Toolbar/ToolbarUserButton.cs | 3 +- .../Screens/Play/BeatmapMetadataDisplay.cs | 5 +- 4 files changed, 117 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs index 66bf870f90b2..2fb8d11cd32b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs @@ -7,21 +7,27 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Input.Bindings; using osuTK; using osuTK.Graphics; +using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public partial class TestSceneLoadingLayer : OsuTestScene + public partial class TestSceneLoadingLayer : OsuManualInputManagerTestScene { private TestLoadingLayer overlay; private Container content; + private PressableButton pressableButton; + [SetUp] public void SetUp() => Schedule(() => { @@ -51,10 +57,9 @@ public void SetUp() => Schedule(() => { new OsuSpriteText { Text = "Sample content" }, new RoundedButton { Text = "can't puush me", Width = 200, }, - new RoundedButton { Text = "puush me", Width = 200, Action = () => { } }, + pressableButton = new PressableButton { Text = "puush me", Width = 200 }, } }, - overlay = new TestLoadingLayer(true), } }, }; @@ -63,20 +68,62 @@ public void SetUp() => Schedule(() => [Test] public void TestShowHide() { + AddStep("create loading layer", () => content.Add(overlay = new TestLoadingLayer(true))); + AddAssert("not visible", () => !overlay.IsPresent); AddStep("show", () => overlay.Show()); - AddUntilStep("wait for content dim", () => overlay.Alpha > 0); AddStep("hide", () => overlay.Hide()); - AddUntilStep("wait for content restore", () => Precision.AlmostEquals(overlay.Alpha, 0)); } + [TestCase(true)] + [TestCase(false)] + public void TestBlockPositional(bool blockInput) + { + AddStep("create loading layer", () => content.Add(overlay = new TestLoadingLayer(true) { BlockPositionalInput = blockInput })); + AddStep("show", () => overlay.Show()); + + AddStep("click button", () => + { + InputManager.MoveMouseTo(pressableButton); + InputManager.Click(MouseButton.Left); + }); + + AddAssert("check pressed", () => pressableButton.Pressed, () => Is.EqualTo(!blockInput)); + } + + [TestCase(true)] + [TestCase(false)] + public void TestBlockNonPositional(bool blockKeyboardInput) + { + AddStep("create loading layer", () => content.Add(overlay = new TestLoadingLayer(true) { BlockNonPositionalInput = blockKeyboardInput })); + AddStep("show", () => overlay.Show()); + + AddStep("press enter", () => InputManager.Key(Key.Enter)); + + AddAssert("check pressed", () => pressableButton.Pressed, () => Is.EqualTo(!blockKeyboardInput)); + } + + [TestCase(true)] + [TestCase(false)] + public void TestBlockNonPositionalGlobalAction(bool blockKeyboardInput) + { + AddStep("create loading layer", () => content.Add(overlay = new TestLoadingLayer(true) { BlockNonPositionalInput = blockKeyboardInput })); + AddStep("show", () => overlay.Show()); + + AddStep("press enter", () => InputManager.Key(Key.F8)); + + AddAssert("check pressed", () => pressableButton.Pressed, () => Is.EqualTo(!blockKeyboardInput)); + } + [Test] public void TestLargeArea() { + AddStep("create loading layer", () => content.Add(overlay = new TestLoadingLayer(true))); + AddStep("show", () => { content.RelativeSizeAxes = Axes.Both; @@ -88,6 +135,42 @@ public void TestLargeArea() AddStep("hide", () => overlay.Hide()); } + public partial class PressableButton : RoundedButton, IKeyBindingHandler + { + public PressableButton() + { + Action = () => Pressed = true; + } + + public bool Pressed { get; private set; } + + protected override bool OnKeyDown(KeyDownEvent e) + { + if (e.Key == Key.Enter) + { + Pressed = true; + return true; + } + + return base.OnKeyDown(e); + } + + public bool OnPressed(KeyBindingPressEvent e) + { + if (e.Action == GlobalAction.ToggleChat) + { + Pressed = true; + return true; + } + + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + } + } + private partial class TestLoadingLayer : LoadingLayer { public TestLoadingLayer(bool dimBackground = false, bool withBox = true) diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index 916b041696ca..0a5801475e63 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -6,7 +6,9 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Game.Input.Bindings; using osuTK; using osuTK.Graphics; @@ -17,20 +19,28 @@ namespace osu.Game.Graphics.UserInterface /// Also optionally dims target elements. /// Useful for disabling all elements in a form and showing we are waiting on a response, for instance. /// - public partial class LoadingLayer : LoadingSpinner + public partial class LoadingLayer : LoadingSpinner, IKeyBindingHandler { - private readonly bool blockInput; + /// + /// Whether to block positional input of components behind the loading layer. + /// Defaults to true. + /// + public bool BlockPositionalInput { get; init; } = true; + + /// + /// Whether to block all keyboard input. Includes global actions. + /// Defaults to false. + /// + public bool BlockNonPositionalInput { get; init; } /// /// Construct a new loading spinner. /// /// Whether the full background area should be dimmed while loading. /// Whether the spinner should have a surrounding black box for visibility. - /// Whether to block input of components behind the loading layer. - public LoadingLayer(bool dimBackground = false, bool withBox = true, bool blockInput = true) + public LoadingLayer(bool dimBackground = false, bool withBox = true) : base(withBox) { - this.blockInput = blockInput; RelativeSizeAxes = Axes.Both; Size = new Vector2(1); @@ -48,11 +58,11 @@ public LoadingLayer(bool dimBackground = false, bool withBox = true, bool blockI } } - public override bool HandleNonPositionalInput => false; + public override bool HandleNonPositionalInput => BlockNonPositionalInput; protected override bool Handle(UIEvent e) { - if (!blockInput) + if (!BlockPositionalInput) return false; switch (e) @@ -76,5 +86,11 @@ protected override void Update() MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 20, 80)); } + + public bool OnPressed(KeyBindingPressEvent e) => BlockNonPositionalInput; + + public void OnReleased(KeyBindingReleaseEvent e) + { + } } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index 787c525566bb..2ade335ef710 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -59,8 +59,9 @@ private void load(OsuColour colours, IAPIProvider api, LoginOverlay? login) { RelativeSizeAxes = Axes.Both, }, - spinner = new LoadingLayer(dimBackground: true, withBox: false, blockInput: false) + spinner = new LoadingLayer(dimBackground: true, withBox: false) { + BlockPositionalInput = false, Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index 23264c4518c9..f1df01b7434d 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -114,7 +114,10 @@ private void load(BeatmapDifficultyCache difficultyCache) Anchor = Anchor.Centre, FillMode = FillMode.Fill, }, - loading = new LoadingLayer(dimBackground: true, blockInput: false) + loading = new LoadingLayer(dimBackground: true) + { + BlockPositionalInput = false, + } } }, versionFlow = new FillFlowContainer From 48544733c3bdb10c5fed7da7622cc12e4c6c3b9c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Feb 2026 19:44:05 +0900 Subject: [PATCH 688/836] Migrate multiplayer freestyle select screen to use `SongSelectV2` --- .../Multiplayer/TestSceneMultiplayer.cs | 8 +++---- ...s => MultiplayerMatchFreestyleSelectV2.cs} | 22 +++++-------------- .../Multiplayer/MultiplayerMatchSubScreen.cs | 4 ++-- 3 files changed, 12 insertions(+), 22 deletions(-) rename osu.Game/Screens/OnlinePlay/Multiplayer/{MultiplayerMatchFreestyleSelect.cs => MultiplayerMatchFreestyleSelectV2.cs} (80%) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 4c487c82886b..0330c5fbfa5b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -1153,7 +1153,7 @@ public void TestUserStyleSelectionDoesNotExitWhenBeatmapSetNotChanged() }); AddStep("open user style selection", () => this.ChildrenOfType().Single().ShowUserStyleSelect()); - AddUntilStep("style selection screen opened", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() == true); + AddUntilStep("style selection screen opened", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() == true); AddStep("change beatmap", () => { @@ -1166,7 +1166,7 @@ public void TestUserStyleSelectionDoesNotExitWhenBeatmapSetNotChanged() }); AddWaitStep("wait for potential beatmap change", 2); - AddAssert("style selection screen still open", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() == true); + AddAssert("style selection screen still open", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() == true); } /// @@ -1190,7 +1190,7 @@ public void TestUserStyleSelectionExitedWhenBeatmapSetChanged() }); AddStep("open user style selection", () => this.ChildrenOfType().Single().ShowUserStyleSelect()); - AddUntilStep("style selection screen opened", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() == true); + AddUntilStep("style selection screen opened", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() == true); AddStep("change beatmap set", () => { @@ -1203,7 +1203,7 @@ public void TestUserStyleSelectionExitedWhenBeatmapSetChanged() }); AddUntilStep("selected beatmap changed", () => Beatmap.Value.BeatmapInfo.Equals(importedSet2.Beatmaps.First())); - AddUntilStep("style selection screen closed", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() != true); + AddUntilStep("style selection screen closed", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() != true); } private void enterGameplay() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchFreestyleSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchFreestyleSelectV2.cs similarity index 80% rename from osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchFreestyleSelect.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchFreestyleSelectV2.cs index 846f781cdc11..d32ab89777c7 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchFreestyleSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchFreestyleSelectV2.cs @@ -12,7 +12,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public partial class MultiplayerMatchFreestyleSelect : OnlinePlayFreestyleSelect + public partial class MultiplayerMatchFreestyleSelectV2 : OnlinePlayFreestyleSelectV2 { [Resolved] private MultiplayerClient client { get; set; } = null!; @@ -25,15 +25,15 @@ public partial class MultiplayerMatchFreestyleSelect : OnlinePlayFreestyleSelect private LoadingLayer loadingLayer = null!; private IDisposable? selectionOperation; - public MultiplayerMatchFreestyleSelect(Room room, PlaylistItem item) - : base(room, item) + public MultiplayerMatchFreestyleSelectV2(PlaylistItem item) + : base(item) { } [BackgroundDependencyLoader] private void load() { - AddInternal(loadingLayer = new LoadingLayer(true)); + AddInternal(loadingLayer = new LoadingLayer(dimBackground: true) { BlockNonPositionalInput = true }); } protected override void LoadComplete() @@ -52,17 +52,14 @@ private void updateLoadingLayer() loadingLayer.Hide(); } - protected override bool OnStart() + protected override void StartAction() { if (operationInProgress.Value) { Logger.Log($"{nameof(OnStart)} aborted due to {nameof(operationInProgress)}"); - return false; + return; } - if (!base.OnStart()) - return false; - selectionOperation = operationTracker.BeginOperation(); client.ChangeUserStyle(Beatmap.Value.BeatmapInfo.OnlineID, Ruleset.Value.OnlineID) @@ -79,14 +76,7 @@ protected override bool OnStart() }, onError: _ => { selectionOperation.Dispose(); - - Schedule(() => - { - Carousel.AllowSelection = true; - }); }); - - return true; } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 05fd5b8c6961..fcbb38c8ed2b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -506,7 +506,7 @@ private void onActivePlaylistItemChanged() return; // Check if we need to make this the current screen as a result of the beatmap set changing while the user's selecting a style. - if (this.GetChildScreen() is MultiplayerMatchFreestyleSelect) + if (this.GetChildScreen() is MultiplayerMatchFreestyleSelectV2) { MultiplayerPlaylistItem item = client.Room.CurrentPlaylistItem; @@ -722,7 +722,7 @@ public void ShowUserStyleSelect() return; MultiplayerPlaylistItem item = client.Room.CurrentPlaylistItem; - this.Push(new MultiplayerMatchFreestyleSelect(room, new PlaylistItem(item))); + this.Push(new MultiplayerMatchFreestyleSelectV2(new PlaylistItem(item))); } /// From e15cb08b4425f4f042ea95712dd894d972218df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 18 Feb 2026 14:42:04 +0100 Subject: [PATCH 689/836] Privatise setter --- osu.Game/Screens/SelectV2/SongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index 96e292152ad0..d144daad7bb1 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -111,7 +111,7 @@ public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBind private BeatmapCarousel carousel = null!; - protected FilterControl FilterControl = null!; + protected FilterControl FilterControl { get; private set; } = null!; private BeatmapTitleWedge titleWedge = null!; private BeatmapDetailsArea detailsArea = null!; From 1153d17153ef92602f73d7adba917c97c81bdda8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Feb 2026 01:47:03 +0900 Subject: [PATCH 690/836] Disallow use of scoping button when at freestyle song select --- osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs | 2 ++ osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs | 3 ++- osu.Game/Screens/SelectV2/SongSelect.cs | 6 ++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs index 751c23d526a9..b5b53e51afd4 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs @@ -33,6 +33,8 @@ protected OnlinePlayFreestyleSelectV2(PlaylistItem item) this.item = item; Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; + + SupportScoping = false; } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs index 08ea270e1fde..89916b13d870 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs @@ -108,6 +108,7 @@ protected override void LoadComplete() showConvertedBeatmaps.BindValueChanged(_ => updateBeatmapSet(), true); Expanded.BindValueChanged(_ => updateEnabled()); scopedBeatmapSet.BindValueChanged(_ => updateEnabled(), true); + scopedBeatmapSet.BindDisabledChanged(_ => updateEnabled(), true); Enabled.BindValueChanged(_ => updateAppearance(), true); FinishTransforms(true); } @@ -210,7 +211,7 @@ private void updateBeatmapSet() private void updateEnabled() { - Enabled.Value = Expanded.Value && scopedBeatmapSet.Value == null; + Enabled.Value = Expanded.Value && !scopedBeatmapSet.Disabled && scopedBeatmapSet.Value == null; } protected override bool OnMouseDown(MouseDownEvent e) diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index d144daad7bb1..a535d827d6b4 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -93,6 +93,12 @@ public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBind /// protected bool ControlGlobalMusic { get; init; } = true; + /// + /// Whether this song select instance should allow scoping down to a specific beatmap set, + /// exposing other difficulties that are otherwise hidden by filter criteria. + /// + protected bool SupportScoping { init => scopedBeatmapSet.Disabled = !value; } + /// /// Whether the osu! logo should be shown at the bottom-right of the screen. /// From de507899e2a79b544755bc1584bcf1313927f402 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Wed, 18 Feb 2026 23:12:12 +0500 Subject: [PATCH 691/836] Adjust RX-related multipliers (#36697) Mostly just keeping RX sane. I don't think we want to go too deep into the balancing here --- osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs | 4 ++-- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs index 43107c8dce1f..768a1f3e73e3 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs @@ -76,9 +76,9 @@ public double ComputeReadingRating(double readingDifficultyValue) readingRating = Math.Pow(readingRating, 0.8); if (mods.Any(m => m is OsuModRelax)) - readingRating *= 0.7; + readingRating *= 0.6; else if (mods.Any(m => m is OsuModAutopilot)) - readingRating *= 0.4; + readingRating *= 0.3; if (mods.Any(m => m is OsuModMagnetised)) { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index edca971d8c3f..8371f0f28b05 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -60,6 +60,11 @@ protected override double StrainValueAt(DifficultyHitObject current) speedDifficulty = Math.Pow(speedDifficulty, 0.95); } + if (Mods.Any(m => m is OsuModRelax)) + { + speedDifficulty *= 0.0; + } + currentAimStrain *= decayAim; currentAimStrain += aimDifficulty * (1 - decayAim) * skillMultiplierAim; From 716cd8d9ab7b9362552370669d0b9cad4dd3c84e Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Wed, 18 Feb 2026 23:37:36 +0500 Subject: [PATCH 692/836] Fix Aim's `skillMultiplierTotal` being applied incorrectly (#36699) Fortunately its 1.0 so it didn't break anything Co-authored-by: James Wilson --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 8371f0f28b05..6de1e5e9c459 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -44,7 +44,7 @@ public Aim(Mod[] mods, bool includeSliders) protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => DifficultyCalculationUtils.Norm(meanExponent, currentAimStrain * strainDecayAim(time - current.Previous(0).StartTime), - currentSpeedStrain * strainDecaySpeed(time - current.Previous(0).StartTime)); + currentSpeedStrain * strainDecaySpeed(time - current.Previous(0).StartTime)) * skillMultiplierTotal; protected override double StrainValueAt(DifficultyHitObject current) { @@ -71,12 +71,12 @@ protected override double StrainValueAt(DifficultyHitObject current) currentSpeedStrain *= decaySpeed; currentSpeedStrain += speedDifficulty * (1 - decaySpeed) * skillMultiplierSpeed; - double totalStrain = DifficultyCalculationUtils.Norm(meanExponent, currentAimStrain, currentSpeedStrain); + double totalStrain = DifficultyCalculationUtils.Norm(meanExponent, currentAimStrain, currentSpeedStrain) * skillMultiplierTotal; if (current.BaseObject is Slider) sliderStrains.Add(totalStrain); - return totalStrain * skillMultiplierTotal; + return totalStrain; } public double GetDifficultSliders() From f9f927fa45488c7a5527c3f89ed5a207cf4b983b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 19 Feb 2026 10:07:51 +0100 Subject: [PATCH 693/836] Disable footer buttons on freestyle song select - The mods button should not be visible because it is not hooked up properly to actually work with selecting user mods. As written it would show (and feign the ability to modify) required mods on the playlist item. You could probably adjust the logic to make user mods controllable via this button but this is simpler for now. - The random and options buttons could perhaps remain, but they are of very limited use on this screen anyway. The previous iteration disabled all footer buttons altogether, so I'm just following precedent here mostly. --- osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs index b5b53e51afd4..73fd651a0101 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.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.Collections.Generic; using System.Linq; using Humanizer; using osu.Framework.Allocation; @@ -10,6 +11,7 @@ using osu.Game.Database; using osu.Game.Online.Rooms; using osu.Game.Rulesets; +using osu.Game.Screens.Footer; using osu.Game.Screens.Select; using SongSelect = osu.Game.Screens.SelectV2.SongSelect; @@ -108,6 +110,8 @@ private bool isValidForSelection() return true; } + public override IReadOnlyList CreateFooterButtons() => []; + void IHandlePresentBeatmap.PresentBeatmap(WorkingBeatmap workingBeatmap, RulesetInfo ruleset) { // This screen cannot present beatmaps. From 1e8b9a7639c5a1f17dee06e8ce025ddd30ab65a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 20 Feb 2026 04:53:12 +0100 Subject: [PATCH 694/836] Adjust nightcore sample playback to not stop randomly and be closer to stable (#36702) - Closes https://github.com/ppy/osu/issues/30293 - Fixes https://osu.ppy.sh/community/forums/topics/2179339?n=1 Aside from fixing the off-by-one error that I mentioned in https://github.com/ppy/osu/issues/30293#issuecomment-2413801663, this also: - Brings back the behaviour wherein if timing points are arranged very weird and nightcore would play e.g. two first beats in a timing point back-to-back, the second timing point is silent. - Brings back the behaviour wherein the finish sample only plays if `OmitFirstBarLine` on the timing point is disabled. However: - This does not bring back the behaviour wherein hat samples only play if the slider tick rate is even because that only kind of makes sense in common time, and if common time is mixed with waltz time or other time signatures, it just gets weird. - Also stable has zero attempt for compensating for waltz time anyway, lazer's behaviour is bespoke, so that is not going to match any way you cut it. My testing procedure essentially consisted of getting stable to log when it was playing nightcore samples and cross-checking the first 30sec or so of https://osu.ppy.sh/beatmapsets/534385#osu/1131956 (check out the timing of that beatmap, for something ranked it is DEEPLY messed up). I guess I can add test cases if deemed required but I already wasted much more time than I would have liked here... --- osu.Game/Rulesets/Mods/ModNightcore.cs | 37 +++++++++++++++++++------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModNightcore.cs b/osu.Game/Rulesets/Mods/ModNightcore.cs index bb18940f8cd9..75adc1e4bfad 100644 --- a/osu.Game/Rulesets/Mods/ModNightcore.cs +++ b/osu.Game/Rulesets/Mods/ModNightcore.cs @@ -10,7 +10,6 @@ using osu.Framework.Localisation; using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Beatmaps.Timing; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -81,6 +80,7 @@ public partial class NightcoreBeatContainer : BeatSyncedContainer private PausableSkinnableSound? finishSample; private int? firstBeat; + private int lastBeat = -1; public NightcoreBeatContainer() { @@ -116,21 +116,35 @@ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, if (!firstBeat.HasValue || beatIndex < firstBeat) // decide on a good starting beat index if once has not yet been decided. - firstBeat = beatIndex < 0 ? 0 : (beatIndex / segmentLength + 1) * segmentLength; + firstBeat = beatIndex < 0 ? 0 : (beatIndex / segmentLength) * segmentLength; if (beatIndex >= firstBeat) - playBeatFor(beatIndex % segmentLength, timingPoint.TimeSignature); + playBeatFor(beatIndex, segmentLength, timingPoint); } - private void playBeatFor(int beatIndex, TimeSignature signature) + private void playBeatFor(int beatIndex, int segmentLength, TimingControlPoint timingPoint) { - if (beatIndex == 0) - finishSample?.Play(); + // https://github.com/peppy/osu-stable-reference/blob/6ab0cf1f9f7b3449f5c0d8defcd458aae72cdb88/osu!/Audio/NightcoreBeat.cs#L41 + if (lastBeat == beatIndex) + return; + + lastBeat = beatIndex; + + int beatInSegment = beatIndex % segmentLength; + + if (beatInSegment == 0) + { + // https://github.com/peppy/osu-stable-reference/blob/6ab0cf1f9f7b3449f5c0d8defcd458aae72cdb88/osu!/Audio/NightcoreBeat.cs#L53 + bool playFinish = beatIndex > 0 || !timingPoint.OmitFirstBarLine; + + if (playFinish) + finishSample?.Play(); + } - switch (signature.Numerator) + switch (timingPoint.TimeSignature.Numerator) { case 3: - switch (beatIndex % 6) + switch (beatInSegment % 6) { case 0: kickSample?.Play(); @@ -148,7 +162,7 @@ private void playBeatFor(int beatIndex, TimeSignature signature) break; case 4: - switch (beatIndex % 4) + switch (beatInSegment % 4) { case 0: kickSample?.Play(); @@ -159,6 +173,11 @@ private void playBeatFor(int beatIndex, TimeSignature signature) break; default: + // note that in stable hat samples would only play if the beatmap tick rate was even + // (https://github.com/peppy/osu-stable-reference/blob/6ab0cf1f9f7b3449f5c0d8defcd458aae72cdb88/osu!/Audio/NightcoreBeat.cs#L30-L32) + // that kind of presumes that only music timed in 4/4 exists, and does not really work well + // if the beatmap e.g. mixes 4/4 and 3/4 signature timing control points. + // therefore this conditional behaviour is not reimplemented. hatSample?.Play(); break; } From c144cf188a37ebc965b25818938527c02013efc4 Mon Sep 17 00:00:00 2001 From: Arthur Araujo <90941580+64ArthurAraujo@users.noreply.github.com> Date: Fri, 20 Feb 2026 12:57:42 -0300 Subject: [PATCH 695/836] Fix reversing straight perfect curve sliders positioning them weirdly (#36698) --- .../Editor/TestSceneSliderReversal.cs | 232 +++++++++++++++++- .../Rulesets/Objects/SliderPathExtensions.cs | 11 +- 2 files changed, 234 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderReversal.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderReversal.cs index a44c16a2e03d..058776c527b7 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderReversal.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderReversal.cs @@ -3,10 +3,13 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; using osu.Game.Tests.Beatmaps; @@ -30,6 +33,16 @@ public partial class TestSceneSliderReversal : TestSceneOsuEditor PathType.LINEAR, new Vector2(100, 0), new Vector2(100, 100) + ), + createPathSegment( + PathType.PERFECT_CURVE, + new Vector2(100.009f, -50.0009f), + new Vector2(200.0089f, -100) + ), + createPathSegment( + PathType.PERFECT_CURVE, + new Vector2(25, -50), + new Vector2(100, 75) ) }; @@ -48,9 +61,13 @@ private static PathControlPoint[] createPathSegment(PathType type, params Vector [TestCase(0, 250)] [TestCase(0, 200)] - [TestCase(1, 120)] - [TestCase(1, 80)] - public void TestSliderReversal(int pathIndex, double length) + [TestCase(1, 120, false, false)] + [TestCase(1, 80, false, false)] + [TestCase(2, 250)] + [TestCase(2, 190)] + [TestCase(3, 250)] + [TestCase(3, 190)] + public void TestSliderReversal(int pathIndex, double length, bool assertEqualDistances = true, bool assertSliderReduction = true) { var controlPoints = paths[pathIndex]; @@ -90,6 +107,215 @@ public void TestSliderReversal(int pathIndex, double length) InputManager.ReleaseKey(Key.LControl); }); + if (pathIndex == 2) + { + AddRepeatStep("Reverse slider again", () => + { + InputManager.PressKey(Key.LControl); + InputManager.Key(Key.G); + InputManager.ReleaseKey(Key.LControl); + }, 2); + } + + if (assertEqualDistances) + { + AddAssert("Middle control point has the same distance from start to end", () => + { + var pathControlPoints = selectedSlider.Path.ControlPoints; + float middleToStart = Vector2.Distance(pathControlPoints[^2].Position, pathControlPoints[0].Position); + float middleToEnd = Vector2.Distance(pathControlPoints[^2].Position, pathControlPoints[^1].Position); + + return Precision.AlmostEquals(middleToStart, middleToEnd, 1f); + }); + } + + AddAssert("Middle control point is not at start or end", () => + Vector2.Distance(selectedSlider.Path.ControlPoints[^2].Position, oldStartPos) > 1 && + Vector2.Distance(selectedSlider.Path.ControlPoints[^2].Position, oldEndPos) > 1 + ); + + AddAssert("Slider has correct length", () => + Precision.AlmostEquals(selectedSlider.Path.Distance, oldDistance)); + + AddAssert("Slider has correct start position", () => + Vector2.Distance(selectedSlider.Position, oldEndPos) < 1); + + AddAssert("Slider has correct end position", () => + Vector2.Distance(selectedSlider.EndPosition, oldStartPos) < 1); + + AddAssert("Control points have correct types", () => + { + var newControlPointTypes = selectedSlider.Path.ControlPoints.Select(p => p.Type).ToArray(); + + return oldControlPointTypes.Take(newControlPointTypes.Length).SequenceEqual(newControlPointTypes); + }); + + if (assertSliderReduction) + { + AddStep("Move to marker", () => + { + var marker = this.ChildrenOfType().Single(); + var markerPos = (marker.ScreenSpaceDrawQuad.TopRight + marker.ScreenSpaceDrawQuad.BottomRight) / 2; + // sometimes the cursor may miss the marker's hitbox so we + // add a little offset here to be sure it lands in a clickable position. + var position = new Vector2(markerPos.X + 2f, markerPos.Y); + InputManager.MoveMouseTo(position); + }); + AddStep("Click", () => InputManager.PressButton(MouseButton.Left)); + AddStep("Reduce slider", () => + { + var middleControlPoint = this.ChildrenOfType>().ToArray()[^2]; + InputManager.MoveMouseTo(middleControlPoint); + }); + AddStep("Release click", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddStep("Save half slider info", () => + { + oldStartPos = selectedSlider.Position; + oldEndPos = selectedSlider.EndPosition; + oldDistance = selectedSlider.Path.Distance; + }); + + AddStep("Reverse slider", () => + { + InputManager.PressKey(Key.LControl); + InputManager.Key(Key.G); + InputManager.ReleaseKey(Key.LControl); + }); + + AddAssert("Middle control point has the same distance from start to end", () => + { + var pathControlPoints = selectedSlider.Path.ControlPoints; + float middleToStart = Vector2.Distance(pathControlPoints[^2].Position, pathControlPoints[0].Position); + float middleToEnd = Vector2.Distance(pathControlPoints[^2].Position, pathControlPoints[^1].Position); + + return Precision.AlmostEquals(middleToStart, middleToEnd, 1f); + }); + + AddAssert("Middle control point is not at start or end", () => + Vector2.Distance(selectedSlider.Path.ControlPoints[^2].Position, oldStartPos) > 1 && + Vector2.Distance(selectedSlider.Path.ControlPoints[^2].Position, oldEndPos) > 1 + ); + + AddAssert("Slider has correct length", () => + Precision.AlmostEquals(selectedSlider.Path.Distance, oldDistance)); + + AddAssert("Slider has correct start position", () => + Vector2.Distance(selectedSlider.Position, oldEndPos) < 1); + + AddAssert("Slider has correct end position", () => + Vector2.Distance(selectedSlider.EndPosition, oldStartPos) < 1); + + AddAssert("Control points have correct types", () => + { + var newControlPointTypes = selectedSlider.Path.ControlPoints.Select(p => p.Type).ToArray(); + + return oldControlPointTypes.Take(newControlPointTypes.Length).SequenceEqual(newControlPointTypes); + }); + } + } + + [Test] + public void TestSegmentedSliderReversal() + { + PathControlPoint[] segmentedSliderPath = + [ + new PathControlPoint + { + Position = new Vector2(0, 0), + Type = PathType.PERFECT_CURVE + }, + new PathControlPoint + { + Position = new Vector2(100, 150), + }, + new PathControlPoint + { + Position = new Vector2(75, -50), + Type = PathType.PERFECT_CURVE + }, + new PathControlPoint + { + Position = new Vector2(225, -75), + }, + new PathControlPoint + { + Position = new Vector2(350, 50), + Type = PathType.PERFECT_CURVE + }, + new PathControlPoint + { + Position = new Vector2(500, -75), + }, + new PathControlPoint + { + Position = new Vector2(350, -120), + }, + ]; + + Vector2 oldStartPos = default; + Vector2 oldEndPos = default; + double oldDistance = default; + + var oldControlPointTypes = segmentedSliderPath.Select(p => p.Type); + + AddStep("Add slider", () => + { + var slider = new Slider + { + Position = new Vector2(0, 200), + Path = new SliderPath(segmentedSliderPath) + { + ExpectedDistance = { Value = 1314 } + } + }; + + EditorBeatmap.Add(slider); + + oldStartPos = slider.Position; + oldEndPos = slider.EndPosition; + oldDistance = slider.Path.Distance; + }); + + AddStep("Select slider", () => + { + var slider = (Slider)EditorBeatmap.HitObjects[0]; + EditorBeatmap.SelectedHitObjects.Add(slider); + }); + + AddRepeatStep("Reverse slider", () => + { + InputManager.PressKey(Key.LControl); + InputManager.Key(Key.G); + InputManager.ReleaseKey(Key.LControl); + }, 3); + + AddAssert("First arc's control is not at the slider's middle", () => + Vector2.Distance(selectedSlider.Path.ControlPoints[^2].Position, selectedSlider.Path.PositionAt(0.5)) > 1 + ); + + AddAssert("Last arc's control is not at the slider's middle", () => + Vector2.Distance(selectedSlider.Path.ControlPoints[1].Position, selectedSlider.Path.PositionAt(0.5)) > 1 + ); + + AddAssert("First arc centered middle control point", () => + { + var pathControlPoints = selectedSlider.Path.ControlPoints; + float middleToStart = Vector2.Distance(pathControlPoints[1].Position, pathControlPoints[0].Position); + float middleToEnd = Vector2.Distance(pathControlPoints[1].Position, pathControlPoints[2].Position); + + return Precision.AlmostEquals(middleToStart, middleToEnd, 1f); + }); + + AddAssert("Last arc centered middle control point", () => + { + var pathControlPoints = selectedSlider.Path.ControlPoints; + float middleToStart = Vector2.Distance(pathControlPoints[^2].Position, pathControlPoints[^3].Position); + float middleToEnd = Vector2.Distance(pathControlPoints[^2].Position, pathControlPoints[^1].Position); + + return Precision.AlmostEquals(middleToStart, middleToEnd, 1f); + }); + AddAssert("Slider has correct length", () => Precision.AlmostEquals(selectedSlider.Path.Distance, oldDistance)); diff --git a/osu.Game/Rulesets/Objects/SliderPathExtensions.cs b/osu.Game/Rulesets/Objects/SliderPathExtensions.cs index 4ce8166421e7..b28225d81bae 100644 --- a/osu.Game/Rulesets/Objects/SliderPathExtensions.cs +++ b/osu.Game/Rulesets/Objects/SliderPathExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; using System.Linq; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects.Types; @@ -56,12 +55,12 @@ public static void Reverse(this SliderPath sliderPath, out Vector2 positionalOff if (controlPoints.Count >= 3 && controlPoints[^3].Type == PathType.PERFECT_CURVE && controlPoints[^2].Type == null && segmentEnds.Any()) { double lastSegmentStart = segmentEnds.Length > 1 ? segmentEnds[^2] : 0; - double lastSegmentEnd = segmentEnds[^1]; - var circleArcPath = new List(); - sliderPath.GetPathToProgress(circleArcPath, lastSegmentStart / lastSegmentEnd, 1); - - controlPoints[^2].Position = circleArcPath[circleArcPath.Count / 2]; + // we want to shorten the last perfect segment, preserving its shape, so that its end is consistent with the slider path's end. + // therefore we also reposition the middle point of the segment to be ideally halfway through its arc. + // the end of the segment is assumed to be at path position 1 at all times, + // but the start of the segment cannot be assumed to be at 0 because multi-segment sliders exist. + controlPoints[^2].Position = sliderPath.PositionAt((lastSegmentStart + 1) / 2); } sliderPath.reverseControlPoints(out positionalOffset); From 29a39cbfb77ab05ce2676d4b81a8a4def3fb0980 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 21 Feb 2026 06:19:32 -0800 Subject: [PATCH 696/836] Fix spectator player cells not having initial shadow edge effect set (#36729) - Fixes https://github.com/ppy/osu/issues/36727 Copies/sets the non-maximised edge effect initially: https://github.com/ppy/osu/blob/c144cf188a37ebc965b25818938527c02013efc4/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid.Cell.cs#L83-L88 --- .../OnlinePlay/Multiplayer/Spectate/PlayerGrid.Cell.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid.Cell.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid.Cell.cs index d1ba21411723..edb9b5465504 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid.Cell.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid.Cell.cs @@ -47,6 +47,13 @@ public Cell(int facadeIndex, Drawable content, Facade facade) Masking = true; CornerRadius = 5; + + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 10, + Colour = Colour4.Black.Opacity(0.2f), + }; } protected override void Update() From a14e87fdd90d43d5e6e562504e1a9debb1cfb80c Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Sun, 22 Feb 2026 20:48:58 +0500 Subject: [PATCH 697/836] Q1 2026 osu! Balancing pass (#36734) Nerf mid-level snap aim, buff raw tapping, buff flow slightly, buff highbpm aim slightly https://pp.huismetbenen.nl/rankings/players/q1-2026-balancing --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 4 ++-- .../Difficulty/Evaluators/RhythmEvaluator.cs | 4 ++-- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 4 ++-- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index a75c0382cbf4..b9436b448b96 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -12,9 +12,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators public static class AimEvaluator { private const double wide_angle_multiplier = 1.5; - private const double acute_angle_multiplier = 2.3; + private const double acute_angle_multiplier = 2.6; private const double slider_multiplier = 1.5; - private const double velocity_change_multiplier = 0.75; + private const double velocity_change_multiplier = 0.9; private const double wiggle_multiplier = 1.02; // WARNING: Increasing this multiplier beyond 1.02 reduces difficulty as distance increases. Refer to the desmos link above the wiggle bonus calculation /// diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs index f97bb85b562a..bd7dcfd59262 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs @@ -16,8 +16,8 @@ public static class RhythmEvaluator { private const int history_time_max = 5 * 1000; // 5 seconds private const int history_objects_max = 32; - private const double rhythm_overall_multiplier = 0.9; - private const double rhythm_ratio_multiplier = 30.0; + private const double rhythm_overall_multiplier = 0.8; + private const double rhythm_ratio_multiplier = 32.0; /// /// Calculates a rhythm multiplier for the difficulty of the tap associated with historic data of the current . diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 6de1e5e9c459..2e3cb96458ed 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -31,8 +31,8 @@ public Aim(Mod[] mods, bool includeSliders) private double currentAimStrain; private double currentSpeedStrain; - private double skillMultiplierAim => 25.85; - private double skillMultiplierSpeed => 1.35; + private double skillMultiplierAim => 25.0; + private double skillMultiplierSpeed => 1.4; private double skillMultiplierTotal => 1.0; private double meanExponent => 1.2; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index f6679f944340..211d9d57b9ac 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Speed : HarmonicSkill { - private double skillMultiplier => 1.04; + private double skillMultiplier => 1.07; private readonly List sliderStrains = new List(); From d139f5997c4e282bd4f2f9f246e1854b36f93a83 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Feb 2026 03:37:40 +0900 Subject: [PATCH 698/836] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 7210afb0c6c5..d86eefe75627 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From a09489d4c050533c4fb8ee7d8625a487b61bd847 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Feb 2026 15:46:05 +0900 Subject: [PATCH 699/836] Move transformation logic local to transient drawable --- .../Overlays/Toolbar/ToolbarUserButton.cs | 75 +++++++++---------- .../TransientUserStatisticsUpdateDisplay.cs | 24 ++++-- 2 files changed, 55 insertions(+), 44 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index 2ade335ef710..e39a66cec51d 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -40,51 +40,48 @@ public ToolbarUserButton() [BackgroundDependencyLoader] private void load(OsuColour colours, IAPIProvider api, LoginOverlay? login) { - Flow.Add(new Container + Flow.AddRange(new Drawable[] { - Masking = true, - CornerRadius = 4, - Size = new Vector2(32), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - EdgeEffect = new EdgeEffectParameters + new Container { - Type = EdgeEffectType.Shadow, - Radius = 4, - Colour = Color4.Black.Opacity(0.1f), - }, - Children = new Drawable[] - { - avatar = new UpdateableAvatar(isInteractive: false) + Masking = true, + CornerRadius = 4, + Size = new Vector2(32), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + EdgeEffect = new EdgeEffectParameters { - RelativeSizeAxes = Axes.Both, + Type = EdgeEffectType.Shadow, + Radius = 4, + Colour = Color4.Black.Opacity(0.1f), }, - spinner = new LoadingLayer(dimBackground: true, withBox: false) + Children = new Drawable[] { - BlockPositionalInput = false, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - }, - failingIcon = new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Alpha = 0, - Size = new Vector2(0.3f), - Icon = FontAwesome.Solid.ExclamationTriangle, - RelativeSizeAxes = Axes.Both, - Colour = colours.YellowLight, - }, - } - }); - - Flow.Add(new TransientUserStatisticsUpdateDisplay - { - Alpha = 0 + avatar = new UpdateableAvatar(isInteractive: false) + { + RelativeSizeAxes = Axes.Both, + }, + spinner = new LoadingLayer(dimBackground: true, withBox: false) + { + BlockPositionalInput = false, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + }, + failingIcon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + Size = new Vector2(0.3f), + Icon = FontAwesome.Solid.ExclamationTriangle, + RelativeSizeAxes = Axes.Both, + Colour = colours.YellowLight, + }, + } + }, + new TransientUserStatisticsUpdateDisplay(), }); - Flow.AutoSizeEasing = Easing.OutQuint; - Flow.AutoSizeDuration = 250; apiState = api.State.GetBoundCopy(); apiState.BindValueChanged(onlineStateChanged, true); diff --git a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs index 85b7358d2d28..3a91fc47f6a5 100644 --- a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs +++ b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs @@ -26,11 +26,12 @@ public partial class TransientUserStatisticsUpdateDisplay : CompositeDrawable private Statistic globalRank = null!; private Statistic pp = null!; + private ScheduledDelegate? shrinkDelegate; + [BackgroundDependencyLoader] private void load(UserStatisticsWatcher? userStatisticsWatcher) { RelativeSizeAxes = Axes.Y; - AutoSizeAxes = Axes.X; Alpha = 0; InternalChild = new FillFlowContainer @@ -40,7 +41,7 @@ private void load(UserStatisticsWatcher? userStatisticsWatcher) Padding = new MarginPadding { Horizontal = 10 }, Spacing = new Vector2(10), Direction = FillDirection.Horizontal, - Children = new Drawable[] + Children = new[] { globalRank = new Statistic(UsersStrings.ShowRankGlobalSimple, @"#", Comparer.Create((before, after) => before - after)), pp = new Statistic(RankingsStrings.StatPerformance, string.Empty, Comparer.Create((before, after) => Math.Sign(after - before))), @@ -71,8 +72,7 @@ protected override void LoadComplete() return; FinishTransforms(true); - - this.FadeIn(500, Easing.OutQuint); + shrinkDelegate?.Cancel(); if (update.After.GlobalRank != null) { @@ -90,7 +90,21 @@ protected override void LoadComplete() pp.Display(before, delta, after); } - this.Delay(5000).FadeOut(500, Easing.OutQuint); + this.FadeIn(500, Easing.OutQuint); + + AutoSizeAxes = Axes.X; + AutoSizeDuration = 500; + AutoSizeEasing = Easing.OutQuint; + + using (BeginDelayedSequence(5000)) + { + this.FadeOut(500, Easing.OutQuint); + shrinkDelegate = Schedule(() => + { + AutoSizeAxes = Axes.None; + this.ResizeWidthTo(0, 500, Easing.OutQuint); + }); + } }); } From 4916c87f14d4d6f14c000a423a497cfc8c481260 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Feb 2026 15:47:19 +0900 Subject: [PATCH 700/836] Move toolbar button text local to single usage in `ToolbarUserButton` --- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 12 ------------ osu.Game/Overlays/Toolbar/ToolbarUserButton.cs | 13 +++++++++++-- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index 5b75b8419c8d..c535137c745a 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -45,12 +45,6 @@ public void SetIcon(IconUsage icon) => Icon = icon, }); - public LocalisableString Text - { - get => DrawableText.Text; - set => DrawableText.Text = value; - } - public LocalisableString TooltipMain { get => tooltip1.Text; @@ -67,7 +61,6 @@ public LocalisableString TooltipSub protected readonly Container ButtonContent; protected ConstrainedIconContainer IconContainer; - protected SpriteText DrawableText; protected Box HoverBackground; private readonly Box flashBackground; private readonly FillFlowContainer tooltipContainer; @@ -139,11 +132,6 @@ protected ToolbarButton() Size = new Vector2(20), Alpha = 0, }, - DrawableText = new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, }, }, }, diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index e39a66cec51d..f2ff08b526cc 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Online.API; @@ -32,6 +33,8 @@ public partial class ToolbarUserButton : ToolbarOverlayToggleButton private IBindable apiState = null!; + private OsuSpriteText usernameText = null!; + public ToolbarUserButton() { ButtonContent.AutoSizeAxes = Axes.X; @@ -42,6 +45,12 @@ private void load(OsuColour colours, IAPIProvider api, LoginOverlay? login) { Flow.AddRange(new Drawable[] { + usernameText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Right = 5 }, + }, new Container { Masking = true, @@ -80,7 +89,7 @@ private void load(OsuColour colours, IAPIProvider api, LoginOverlay? login) }, } }, - new TransientUserStatisticsUpdateDisplay(), + new TransientUserStatisticsUpdateDisplay() }); apiState = api.State.GetBoundCopy(); @@ -94,7 +103,7 @@ private void load(OsuColour colours, IAPIProvider api, LoginOverlay? login) private void userChanged(ValueChangedEvent user) => Schedule(() => { - Text = user.NewValue.Username; + usernameText.Text = user.NewValue.Username; avatar.User = user.NewValue; }); From f39615a374afce4c880e02c645a888b8ceffd60e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Feb 2026 15:59:09 +0900 Subject: [PATCH 701/836] Move spacing local to usages --- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 1 - osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarUserButton.cs | 5 ++++- .../Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs | 1 - 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index c535137c745a..b0a6841a2f81 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -117,7 +117,6 @@ protected ToolbarButton() Flow = new FillFlowContainer { Direction = FillDirection.Horizontal, - Spacing = new Vector2(5), Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Padding = new MarginPadding { Left = Toolbar.HEIGHT / 2, Right = Toolbar.HEIGHT / 2 }, diff --git a/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs b/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs index 51b95b7d3287..e6ffc1ad5ef7 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs @@ -43,7 +43,7 @@ private void load(NowPlayingOverlay music) Origin = Anchor.CentreLeft, Width = 3f, Height = IconContainer.Height, - Margin = new MarginPadding { Horizontal = 2.5f }, + Margin = new MarginPadding { Left = 7.5f, Right = 2.5f }, Masking = true, Children = new[] { diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index f2ff08b526cc..d8350ce4519d 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -89,7 +89,10 @@ private void load(OsuColour colours, IAPIProvider api, LoginOverlay? login) }, } }, - new TransientUserStatisticsUpdateDisplay() + new TransientUserStatisticsUpdateDisplay + { + Alpha = 0, + } }); apiState = api.State.GetBoundCopy(); diff --git a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs index 3a91fc47f6a5..e5df7a65dc0a 100644 --- a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs +++ b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs @@ -32,7 +32,6 @@ public partial class TransientUserStatisticsUpdateDisplay : CompositeDrawable private void load(UserStatisticsWatcher? userStatisticsWatcher) { RelativeSizeAxes = Axes.Y; - Alpha = 0; InternalChild = new FillFlowContainer { From efc9a27d2defeb8953875d2a35e8f984a31552e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Feb 2026 01:29:24 +0900 Subject: [PATCH 702/836] Remove no longer used class --- .../OnlinePlay/OnlinePlayFreestyleSelect.cs | 138 ------------------ 1 file changed, 138 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs deleted file mode 100644 index 13ac40639688..000000000000 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using System.Linq; -using Humanizer; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Logging; -using osu.Game.Beatmaps; -using osu.Game.Database; -using osu.Game.Online.Rooms; -using osu.Game.Rulesets; -using osu.Game.Screens.Select; -using osu.Game.Users; - -namespace osu.Game.Screens.OnlinePlay -{ - public abstract partial class OnlinePlayFreestyleSelect : SongSelect, IOnlinePlaySubScreen, IHandlePresentBeatmap - { - public string ShortTitle => "style selection"; - - public override string Title => ShortTitle.Humanize(); - - public override bool AllowEditing => false; - - protected override UserActivity InitialActivity => new UserActivity.InLobby(room); - - private readonly Room room; - private readonly PlaylistItem item; - - protected OnlinePlayFreestyleSelect(Room room, PlaylistItem item) - { - this.room = room; - this.item = item; - - Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; - } - - [BackgroundDependencyLoader] - private void load() - { - LeftArea.Padding = new MarginPadding { Top = Header.HEIGHT }; - } - - protected override bool OnStart() - { - FilterCriteria criteria = FilterControl.CreateCriteria(); - - // Beatmaps with too different of a duration are filtered away; this is just a final safety. - if (!criteria.Length.IsInRange(Beatmap.Value.BeatmapInfo.Length)) - { - Logger.Log("The selected beatmap's duration differs too much from the host's selection.", level: LogLevel.Error); - return false; - } - - // Beatmaps without a valid online ID are filtered away; this is just a final safety. - if (Beatmap.Value.BeatmapInfo.OnlineID < 0) - { - Logger.Log("The selected beatmap is not available online.", level: LogLevel.Error); - return false; - } - - // Beatmaps from different sets are filtered away; this is just a final safety. - if (Beatmap.Value.BeatmapSetInfo.OnlineID != criteria.BeatmapSetId) - { - Logger.Log("The selected beatmap is from a different beatmap set.", level: LogLevel.Error); - return false; - } - - if (Ruleset.Value.OnlineID < 0) - { - Logger.Log("The selected ruleset is not available online.", level: LogLevel.Error); - return false; - } - - return true; - } - - protected override FilterControl CreateFilterControl() => new DifficultySelectFilterControl(item); - - protected override IEnumerable<(FooterButton button, OverlayContainer? overlay)> CreateSongSelectFooterButtons() - { - // Required to create the drawable components. - base.CreateSongSelectFooterButtons(); - return Enumerable.Empty<(FooterButton, OverlayContainer?)>(); - } - - protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); - - public void PresentBeatmap(WorkingBeatmap beatmap, RulesetInfo ruleset) - { - // This screen cannot present beatmaps. - } - - private partial class DifficultySelectFilterControl : FilterControl - { - private readonly PlaylistItem item; - - [Resolved] - private RealmAccess realm { get; set; } = null!; - - public DifficultySelectFilterControl(PlaylistItem item) - { - this.item = item; - } - - public override FilterCriteria CreateCriteria() - { - var criteria = base.CreateCriteria(); - - double itemLength = 0; - int beatmapSetId = 0; - - realm.Run(r => - { - int beatmapId = item.Beatmap.OnlineID; - BeatmapInfo? beatmap = r.All().FirstOrDefault(b => b.OnlineID == beatmapId); - - itemLength = beatmap?.Length ?? 0; - beatmapSetId = beatmap?.BeatmapSet?.OnlineID ?? 0; - }); - - // Must be from the same set as the playlist item. - criteria.BeatmapSetId = beatmapSetId; - criteria.HasOnlineID = true; - - // Must be within 30s of the playlist item. - criteria.Length.Min = itemLength - 30000; - criteria.Length.Max = itemLength + 30000; - criteria.Length.IsLowerInclusive = true; - criteria.Length.IsUpperInclusive = true; - return criteria; - } - } - } -} From cb12d35d8f71efaa1ef1719d3de8362dadd8c530 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Feb 2026 01:49:24 +0900 Subject: [PATCH 703/836] Combine old classes to provide better starting point for migration --- .../Multiplayer/MultiplayerMatchSongSelect.cs | 243 +++++++++++++++- .../OnlinePlay/OnlinePlaySongSelect.cs | 274 ------------------ 2 files changed, 233 insertions(+), 284 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 7328e01026b4..41239cd7a8dc 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -2,21 +2,41 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; +using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Framework.Screens; +using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; +using osu.Game.Online.API; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; +using osu.Game.Overlays; +using osu.Game.Overlays.Mods; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select; +using osu.Game.Users; +using osu.Game.Utils; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public partial class MultiplayerMatchSongSelect : OnlinePlaySongSelect + public partial class MultiplayerMatchSongSelect : SongSelect, IOnlinePlaySubScreen { + public string ShortTitle => "song selection"; + + public override string Title => ShortTitle.Humanize(); + + public override bool AllowEditing => false; + [Resolved] private MultiplayerClient client { get; set; } = null!; @@ -30,21 +50,50 @@ public partial class MultiplayerMatchSongSelect : OnlinePlaySongSelect private LoadingLayer loadingLayer = null!; private IDisposable? selectionOperation; + [Resolved] + private RulesetStore rulesets { get; set; } = null!; + + [Resolved] + private BeatmapManager beatmapManager { get; set; } = null!; + + protected override UserActivity InitialActivity => new UserActivity.InLobby(room); + + protected readonly Bindable> FreeMods = new Bindable>(Array.Empty()); + + private readonly Bindable freestyle = new Bindable(true); + + private readonly PlaylistItem? initialItem; + private readonly FreeModSelectOverlay freeModSelect; + private FooterButton freeModsFooterButton = null!; + + private IDisposable? freeModSelectOverlayRegistration; + /// /// Construct a new instance of multiplayer song select. /// /// The room. /// The item to be edited. May be null, in which case a new item will be added to the playlist. public MultiplayerMatchSongSelect(Room room, PlaylistItem? itemToEdit = null) - : base(room, itemToEdit) { this.room = room; this.itemToEdit = itemToEdit; + initialItem = itemToEdit ?? room.Playlist.LastOrDefault(); + + Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; + + freeModSelect = new FreeModSelectOverlay + { + SelectedMods = { BindTarget = FreeMods }, + IsValidMod = isValidAllowedMod, + }; } [BackgroundDependencyLoader] private void load() { + LeftArea.Padding = new MarginPadding { Top = Header.HEIGHT }; + + LoadComponent(freeModSelect); AddInternal(loadingLayer = new LoadingLayer(true)); } @@ -52,23 +101,133 @@ protected override void LoadComplete() { base.LoadComplete(); + if (initialItem != null) + { + // Prefer using a local databased beatmap lookup since OnlineId may be -1 for an invalid beatmap selection. + BeatmapInfo? beatmapInfo = initialItem.Beatmap as BeatmapInfo; + + // And in the case that this isn't a local databased beatmap, query by online ID. + if (beatmapInfo == null) + { + int onlineId = initialItem.Beatmap.OnlineID; + beatmapInfo = beatmapManager.QueryBeatmap(b => b.OnlineID == onlineId); + } + + if (beatmapInfo != null) + Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapInfo); + + RulesetInfo? ruleset = rulesets.GetRuleset(initialItem.RulesetID); + + if (ruleset != null) + { + Ruleset.Value = ruleset; + + var rulesetInstance = ruleset.CreateInstance(); + Debug.Assert(rulesetInstance != null); + + // At this point, Mods contains both the required and allowed mods. For selection purposes, it should only contain the required mods. + // Similarly, freeMods is currently empty but should only contain the allowed mods. + Mods.Value = initialItem.RequiredMods.Select(m => m.ToMod(rulesetInstance)).ToArray(); + FreeMods.Value = initialItem.AllowedMods.Select(m => m.ToMod(rulesetInstance)).ToArray(); + } + + freestyle.Value = initialItem.Freestyle; + } + + Mods.BindValueChanged(_ => updateValidMods()); + Ruleset.BindValueChanged(onRulesetChanged); + freestyle.BindValueChanged(onFreestyleChanged); + + freeModSelectOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(freeModSelect); + + updateFooterButtons(); + updateValidMods(); + operationInProgress.BindTo(operationTracker.InProgress); - operationInProgress.BindValueChanged(_ => updateLoadingLayer(), true); + operationInProgress.BindValueChanged(operation => + { + if (operation.NewValue) + loadingLayer.Show(); + else + loadingLayer.Hide(); + }, true); + } + + protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); + + private void onFreestyleChanged(ValueChangedEvent enabled) + { + updateFooterButtons(); + updateValidMods(); + + if (enabled.NewValue) + { + // Freestyle allows all mods to be selected as freemods. This does not play nicely for some components: + // - We probably don't want to store a gigantic list of acronyms to the database. + // - The mod select overlay isn't built to handle duplicate mods/mods from all rulesets being shoved into it. + // Instead, freestyle inherently assumes this list is empty, and must be empty for server-side validation to pass. + FreeMods.Value = []; + } + else + { + // When disabling freestyle, enable freemods by default. + FreeMods.Value = freeModSelect.AllAvailableMods.Where(state => state.ValidForSelection.Value).Select(state => state.Mod).ToArray(); + } } - private void updateLoadingLayer() + private void onRulesetChanged(ValueChangedEvent ruleset) { - if (operationInProgress.Value) - loadingLayer.Show(); + // Todo: We can probably attempt to preserve across rulesets like the global mods do. + FreeMods.Value = []; + } + + private void updateFooterButtons() + { + if (freestyle.Value) + { + freeModsFooterButton.Enabled.Value = false; + freeModSelect.Hide(); + } else - loadingLayer.Hide(); + freeModsFooterButton.Enabled.Value = true; + } + + /// + /// Removes invalid mods from and , + /// and updates mod selection overlays to display the new mods valid for selection. + /// + private void updateValidMods() + { + Mod[] validMods = Mods.Value.Where(isValidRequiredMod).ToArray(); + if (!validMods.SequenceEqual(Mods.Value)) + Mods.Value = validMods; + + Mod[] validFreeMods = FreeMods.Value.Where(isValidAllowedMod).ToArray(); + if (!validFreeMods.SequenceEqual(FreeMods.Value)) + FreeMods.Value = validFreeMods; + + ModSelect.IsValidMod = isValidRequiredMod; + freeModSelect.IsValidMod = isValidAllowedMod; } - protected override bool SelectItem(PlaylistItem item) + protected sealed override bool OnStart() + { + var item = new PlaylistItem(Beatmap.Value.BeatmapInfo) + { + RulesetID = Ruleset.Value.OnlineID, + RequiredMods = Mods.Value.Select(m => new APIMod(m)).ToArray(), + AllowedMods = FreeMods.Value.Select(m => new APIMod(m)).ToArray(), + Freestyle = freestyle.Value + }; + + return selectItem(item); + } + + private bool selectItem(PlaylistItem item) { if (operationInProgress.Value) { - Logger.Log($"{nameof(SelectItem)} aborted due to {nameof(operationInProgress)}"); + Logger.Log($"{nameof(selectItem)} aborted due to {nameof(operationInProgress)}"); return false; } @@ -120,6 +279,70 @@ protected override bool SelectItem(PlaylistItem item) return true; } - protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); + public override bool OnBackButton() + { + if (freeModSelect.State.Value == Visibility.Visible) + { + freeModSelect.Hide(); + return true; + } + + return base.OnBackButton(); + } + + public override bool OnExiting(ScreenExitEvent e) + { + freeModSelect.Hide(); + return base.OnExiting(e); + } + + protected override ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay(OverlayColourScheme.Plum) + { + IsValidMod = isValidRequiredMod + }; + + protected override IEnumerable<(FooterButton button, OverlayContainer? overlay)> CreateSongSelectFooterButtons() + { + var baseButtons = base.CreateSongSelectFooterButtons().ToList(); + + baseButtons.Single(i => i.button is FooterButtonMods).button.TooltipText = MultiplayerMatchStrings.RequiredModsButtonTooltip; + + baseButtons.InsertRange(baseButtons.FindIndex(b => b.button is FooterButtonMods) + 1, new (FooterButton, OverlayContainer?)[] + { + (freeModsFooterButton = new FooterButtonFreeMods(freeModSelect) + { + FreeMods = { BindTarget = FreeMods }, + Freestyle = { BindTarget = freestyle } + }, null), + (new FooterButtonFreestyle + { + Freestyle = { BindTarget = freestyle } + }, null) + }); + + return baseButtons; + } + + /// + /// Checks whether a given is valid to be selected as a required mod. + /// + /// The to check. + private bool isValidRequiredMod(Mod mod) => ModUtils.IsValidModForMatch(mod, true, room.Type, freestyle.Value); + + /// + /// Checks whether a given is valid to be selected as an allowed mod. + /// + /// The to check. + private bool isValidAllowedMod(Mod mod) => ModUtils.IsValidModForMatch(mod, false, room.Type, freestyle.Value) + // Mod must not be contained in the required mods. + && Mods.Value.All(m => m.Acronym != mod.Acronym) + // Mod must be compatible with all the required mods. + && ModUtils.CheckCompatibleSet(Mods.Value.Append(mod).ToArray()); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + freeModSelectOverlayRegistration?.Dispose(); + } } } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs deleted file mode 100644 index bb6d75fa3bd5..000000000000 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ /dev/null @@ -1,274 +0,0 @@ -// 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.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Humanizer; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Screens; -using osu.Game.Beatmaps; -using osu.Game.Online.API; -using osu.Game.Online.Rooms; -using osu.Game.Overlays; -using osu.Game.Overlays.Mods; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Select; -using osu.Game.Users; -using osu.Game.Utils; -using osu.Game.Localisation; - -namespace osu.Game.Screens.OnlinePlay -{ - public abstract partial class OnlinePlaySongSelect : SongSelect, IOnlinePlaySubScreen - { - public string ShortTitle => "song selection"; - - public override string Title => ShortTitle.Humanize(); - - public override bool AllowEditing => false; - - [Resolved] - private RulesetStore rulesets { get; set; } = null!; - - [Resolved] - private BeatmapManager beatmapManager { get; set; } = null!; - - protected override UserActivity InitialActivity => new UserActivity.InLobby(room); - - protected readonly Bindable> FreeMods = new Bindable>(Array.Empty()); - protected readonly Bindable Freestyle = new Bindable(true); - - private readonly Room room; - private readonly PlaylistItem? initialItem; - private readonly FreeModSelectOverlay freeModSelect; - private FooterButton freeModsFooterButton = null!; - - private IDisposable? freeModSelectOverlayRegistration; - - /// - /// Creates a new . - /// - /// The room. - /// An optional initial to use for the initial beatmap/ruleset/mods. - /// If null, the last in the room will be used. - protected OnlinePlaySongSelect(Room room, PlaylistItem? initialItem = null) - { - this.room = room; - this.initialItem = initialItem ?? room.Playlist.LastOrDefault(); - - Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; - - freeModSelect = new FreeModSelectOverlay - { - SelectedMods = { BindTarget = FreeMods }, - IsValidMod = isValidAllowedMod, - }; - } - - [BackgroundDependencyLoader] - private void load() - { - LeftArea.Padding = new MarginPadding { Top = Header.HEIGHT }; - LoadComponent(freeModSelect); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - if (initialItem != null) - { - // Prefer using a local databased beatmap lookup since OnlineId may be -1 for an invalid beatmap selection. - BeatmapInfo? beatmapInfo = initialItem.Beatmap as BeatmapInfo; - - // And in the case that this isn't a local databased beatmap, query by online ID. - if (beatmapInfo == null) - { - int onlineId = initialItem.Beatmap.OnlineID; - beatmapInfo = beatmapManager.QueryBeatmap(b => b.OnlineID == onlineId); - } - - if (beatmapInfo != null) - Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapInfo); - - RulesetInfo? ruleset = rulesets.GetRuleset(initialItem.RulesetID); - - if (ruleset != null) - { - Ruleset.Value = ruleset; - - var rulesetInstance = ruleset.CreateInstance(); - Debug.Assert(rulesetInstance != null); - - // At this point, Mods contains both the required and allowed mods. For selection purposes, it should only contain the required mods. - // Similarly, freeMods is currently empty but should only contain the allowed mods. - Mods.Value = initialItem.RequiredMods.Select(m => m.ToMod(rulesetInstance)).ToArray(); - FreeMods.Value = initialItem.AllowedMods.Select(m => m.ToMod(rulesetInstance)).ToArray(); - } - - Freestyle.Value = initialItem.Freestyle; - } - - Mods.BindValueChanged(onGlobalModsChanged); - Ruleset.BindValueChanged(onRulesetChanged); - Freestyle.BindValueChanged(onFreestyleChanged); - - freeModSelectOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(freeModSelect); - - updateFooterButtons(); - updateValidMods(); - } - - private void onFreestyleChanged(ValueChangedEvent enabled) - { - updateFooterButtons(); - updateValidMods(); - - if (enabled.NewValue) - { - // Freestyle allows all mods to be selected as freemods. This does not play nicely for some components: - // - We probably don't want to store a gigantic list of acronyms to the database. - // - The mod select overlay isn't built to handle duplicate mods/mods from all rulesets being shoved into it. - // Instead, freestyle inherently assumes this list is empty, and must be empty for server-side validation to pass. - FreeMods.Value = []; - } - else - { - // When disabling freestyle, enable freemods by default. - FreeMods.Value = freeModSelect.AllAvailableMods.Where(state => state.ValidForSelection.Value).Select(state => state.Mod).ToArray(); - } - } - - private void onGlobalModsChanged(ValueChangedEvent> mods) - { - updateValidMods(); - } - - private void onRulesetChanged(ValueChangedEvent ruleset) - { - // Todo: We can probably attempt to preserve across rulesets like the global mods do. - FreeMods.Value = []; - } - - private void updateFooterButtons() - { - if (Freestyle.Value) - { - freeModsFooterButton.Enabled.Value = false; - freeModSelect.Hide(); - } - else - freeModsFooterButton.Enabled.Value = true; - } - - /// - /// Removes invalid mods from and , - /// and updates mod selection overlays to display the new mods valid for selection. - /// - private void updateValidMods() - { - Mod[] validMods = Mods.Value.Where(isValidRequiredMod).ToArray(); - if (!validMods.SequenceEqual(Mods.Value)) - Mods.Value = validMods; - - Mod[] validFreeMods = FreeMods.Value.Where(isValidAllowedMod).ToArray(); - if (!validFreeMods.SequenceEqual(FreeMods.Value)) - FreeMods.Value = validFreeMods; - - ModSelect.IsValidMod = isValidRequiredMod; - freeModSelect.IsValidMod = isValidAllowedMod; - } - - protected sealed override bool OnStart() - { - var item = new PlaylistItem(Beatmap.Value.BeatmapInfo) - { - RulesetID = Ruleset.Value.OnlineID, - RequiredMods = Mods.Value.Select(m => new APIMod(m)).ToArray(), - AllowedMods = FreeMods.Value.Select(m => new APIMod(m)).ToArray(), - Freestyle = Freestyle.Value - }; - - return SelectItem(item); - } - - /// - /// Invoked when the user has requested a selection of a beatmap. - /// - /// The resultant . This item has not yet been added to the 's. - /// true if a selection occurred. - protected abstract bool SelectItem(PlaylistItem item); - - public override bool OnBackButton() - { - if (freeModSelect.State.Value == Visibility.Visible) - { - freeModSelect.Hide(); - return true; - } - - return base.OnBackButton(); - } - - public override bool OnExiting(ScreenExitEvent e) - { - freeModSelect.Hide(); - return base.OnExiting(e); - } - - protected override ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay(OverlayColourScheme.Plum) - { - IsValidMod = isValidRequiredMod - }; - - protected override IEnumerable<(FooterButton button, OverlayContainer? overlay)> CreateSongSelectFooterButtons() - { - var baseButtons = base.CreateSongSelectFooterButtons().ToList(); - - baseButtons.Single(i => i.button is FooterButtonMods).button.TooltipText = MultiplayerMatchStrings.RequiredModsButtonTooltip; - - baseButtons.InsertRange(baseButtons.FindIndex(b => b.button is FooterButtonMods) + 1, new (FooterButton, OverlayContainer?)[] - { - (freeModsFooterButton = new FooterButtonFreeMods(freeModSelect) - { - FreeMods = { BindTarget = FreeMods }, - Freestyle = { BindTarget = Freestyle } - }, null), - (new FooterButtonFreestyle - { - Freestyle = { BindTarget = Freestyle } - }, null) - }); - - return baseButtons; - } - - /// - /// Checks whether a given is valid to be selected as a required mod. - /// - /// The to check. - private bool isValidRequiredMod(Mod mod) => ModUtils.IsValidModForMatch(mod, true, room.Type, Freestyle.Value); - - /// - /// Checks whether a given is valid to be selected as an allowed mod. - /// - /// The to check. - private bool isValidAllowedMod(Mod mod) => ModUtils.IsValidModForMatch(mod, false, room.Type, Freestyle.Value) - // Mod must not be contained in the required mods. - && Mods.Value.All(m => m.Acronym != mod.Acronym) - // Mod must be compatible with all the required mods. - && ModUtils.CheckCompatibleSet(Mods.Value.Append(mod).ToArray()); - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - freeModSelectOverlayRegistration?.Dispose(); - } - } -} From fabce18552a63745b6ae2839c0ebfa136e5af0ce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Feb 2026 16:58:16 +0900 Subject: [PATCH 704/836] Remove `V2` suffix from migrated classes --- osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs | 8 ++++---- .../Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs | 4 ++-- ...tyleSelectV2.cs => MultiplayerMatchFreestyleSelect.cs} | 4 ++-- .../OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs | 4 ++-- ...yFreestyleSelectV2.cs => OnlinePlayFreestyleSelect.cs} | 4 ++-- .../OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs | 2 +- ...eestyleSelectV2.cs => PlaylistsRoomFreestyleSelect.cs} | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) rename osu.Game/Screens/OnlinePlay/Multiplayer/{MultiplayerMatchFreestyleSelectV2.cs => MultiplayerMatchFreestyleSelect.cs} (94%) rename osu.Game/Screens/OnlinePlay/{OnlinePlayFreestyleSelectV2.cs => OnlinePlayFreestyleSelect.cs} (95%) rename osu.Game/Screens/OnlinePlay/{PlaylistsRoomFreestyleSelectV2.cs => PlaylistsRoomFreestyleSelect.cs} (83%) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 0330c5fbfa5b..4c487c82886b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -1153,7 +1153,7 @@ public void TestUserStyleSelectionDoesNotExitWhenBeatmapSetNotChanged() }); AddStep("open user style selection", () => this.ChildrenOfType().Single().ShowUserStyleSelect()); - AddUntilStep("style selection screen opened", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() == true); + AddUntilStep("style selection screen opened", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() == true); AddStep("change beatmap", () => { @@ -1166,7 +1166,7 @@ public void TestUserStyleSelectionDoesNotExitWhenBeatmapSetNotChanged() }); AddWaitStep("wait for potential beatmap change", 2); - AddAssert("style selection screen still open", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() == true); + AddAssert("style selection screen still open", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() == true); } /// @@ -1190,7 +1190,7 @@ public void TestUserStyleSelectionExitedWhenBeatmapSetChanged() }); AddStep("open user style selection", () => this.ChildrenOfType().Single().ShowUserStyleSelect()); - AddUntilStep("style selection screen opened", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() == true); + AddUntilStep("style selection screen opened", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() == true); AddStep("change beatmap set", () => { @@ -1203,7 +1203,7 @@ public void TestUserStyleSelectionExitedWhenBeatmapSetChanged() }); AddUntilStep("selected beatmap changed", () => Beatmap.Value.BeatmapInfo.Equals(importedSet2.Beatmaps.First())); - AddUntilStep("style selection screen closed", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() != true); + AddUntilStep("style selection screen closed", () => this.ChildrenOfType().SingleOrDefault()?.IsCurrentScreen() != true); } private void enterGameplay() diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs index 346625b50ca4..3f9a7270779f 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs @@ -248,7 +248,7 @@ public void TestFreestyleSelectAbort() AddUntilStep("original beatmap", () => Beatmap.Value.BeatmapInfo.Equals(importedSet.Beatmaps[0])); AddStep("enter freestyle select", () => playlistsScreen.Stack.ChildrenOfType().Single(b => b.IsPresent).TriggerClick()); - AddUntilStep("wait for select screen", () => playlistsScreen.Stack.CurrentScreen is PlaylistsRoomFreestyleSelectV2 selectScreen && selectScreen.CarouselItemsPresented); + AddUntilStep("wait for select screen", () => playlistsScreen.Stack.CurrentScreen is PlaylistsRoomFreestyleSelect selectScreen && selectScreen.CarouselItemsPresented); AddStep("select next beatmap", () => InputManager.Key(Key.Down)); AddStep("abort", () => playlistsScreen.Stack.CurrentScreen.Exit()); @@ -287,7 +287,7 @@ public void TestFreestyleSelect() AddUntilStep("original beatmap", () => Beatmap.Value.BeatmapInfo.Equals(importedSet.Beatmaps[0])); AddStep("enter freestyle select", () => playlistsScreen.Stack.ChildrenOfType().Single(b => b.IsPresent).TriggerClick()); - AddUntilStep("wait for select screen", () => playlistsScreen.Stack.CurrentScreen is PlaylistsRoomFreestyleSelectV2 selectScreen && selectScreen.CarouselItemsPresented); + AddUntilStep("wait for select screen", () => playlistsScreen.Stack.CurrentScreen is PlaylistsRoomFreestyleSelect selectScreen && selectScreen.CarouselItemsPresented); AddStep("select next beatmap", () => InputManager.Key(Key.Down)); AddStep("select (beatmap)", () => InputManager.Key(Key.Enter)); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchFreestyleSelectV2.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchFreestyleSelect.cs similarity index 94% rename from osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchFreestyleSelectV2.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchFreestyleSelect.cs index d32ab89777c7..8b0fc786900e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchFreestyleSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchFreestyleSelect.cs @@ -12,7 +12,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public partial class MultiplayerMatchFreestyleSelectV2 : OnlinePlayFreestyleSelectV2 + public partial class MultiplayerMatchFreestyleSelect : OnlinePlayFreestyleSelect { [Resolved] private MultiplayerClient client { get; set; } = null!; @@ -25,7 +25,7 @@ public partial class MultiplayerMatchFreestyleSelectV2 : OnlinePlayFreestyleSele private LoadingLayer loadingLayer = null!; private IDisposable? selectionOperation; - public MultiplayerMatchFreestyleSelectV2(PlaylistItem item) + public MultiplayerMatchFreestyleSelect(PlaylistItem item) : base(item) { } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index fcbb38c8ed2b..ed4f431d4ea7 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -506,7 +506,7 @@ private void onActivePlaylistItemChanged() return; // Check if we need to make this the current screen as a result of the beatmap set changing while the user's selecting a style. - if (this.GetChildScreen() is MultiplayerMatchFreestyleSelectV2) + if (this.GetChildScreen() is MultiplayerMatchFreestyleSelect) { MultiplayerPlaylistItem item = client.Room.CurrentPlaylistItem; @@ -722,7 +722,7 @@ public void ShowUserStyleSelect() return; MultiplayerPlaylistItem item = client.Room.CurrentPlaylistItem; - this.Push(new MultiplayerMatchFreestyleSelectV2(new PlaylistItem(item))); + this.Push(new MultiplayerMatchFreestyleSelect(new PlaylistItem(item))); } /// diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs similarity index 95% rename from osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs rename to osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs index 73fd651a0101..0ff3ade809b3 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.OnlinePlay { - public abstract partial class OnlinePlayFreestyleSelectV2 : SongSelect, IHandlePresentBeatmap, IOnlinePlaySubScreen + public abstract partial class OnlinePlayFreestyleSelect : SongSelect, IHandlePresentBeatmap, IOnlinePlaySubScreen { private readonly PlaylistItem item; @@ -30,7 +30,7 @@ public abstract partial class OnlinePlayFreestyleSelectV2 : SongSelect, IHandleP [Resolved] private RealmAccess realm { get; set; } = null!; - protected OnlinePlayFreestyleSelectV2(PlaylistItem item) + protected OnlinePlayFreestyleSelect(PlaylistItem item) { this.item = item; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index bab4d691bb94..16570e68e916 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -696,7 +696,7 @@ private void showUserStyleSelect() if (!this.IsCurrentScreen() || SelectedItem.Value == null) return; - this.Push(new PlaylistsRoomFreestyleSelectV2(SelectedItem.Value) + this.Push(new PlaylistsRoomFreestyleSelect(SelectedItem.Value) { Beatmap = { BindTarget = UserBeatmap }, Ruleset = { BindTarget = UserRuleset } diff --git a/osu.Game/Screens/OnlinePlay/PlaylistsRoomFreestyleSelectV2.cs b/osu.Game/Screens/OnlinePlay/PlaylistsRoomFreestyleSelect.cs similarity index 83% rename from osu.Game/Screens/OnlinePlay/PlaylistsRoomFreestyleSelectV2.cs rename to osu.Game/Screens/OnlinePlay/PlaylistsRoomFreestyleSelect.cs index ead76dac8d81..6c16d917fa3c 100644 --- a/osu.Game/Screens/OnlinePlay/PlaylistsRoomFreestyleSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/PlaylistsRoomFreestyleSelect.cs @@ -9,12 +9,12 @@ namespace osu.Game.Screens.OnlinePlay { - public partial class PlaylistsRoomFreestyleSelectV2 : OnlinePlayFreestyleSelectV2 + public partial class PlaylistsRoomFreestyleSelect : OnlinePlayFreestyleSelect { public new readonly Bindable Beatmap = new Bindable(); public new readonly Bindable Ruleset = new Bindable(); - public PlaylistsRoomFreestyleSelectV2(PlaylistItem item) + public PlaylistsRoomFreestyleSelect(PlaylistItem item) : base(item) { } From ccb0224a1beb74bcbcb301aab4b5f3959b0da7d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 24 Feb 2026 13:30:27 +0100 Subject: [PATCH 705/836] Attempt to fix "copy labels from issues" workflow permissions again It's still broken: https://github.com/ppy/osu/actions/runs/22310482792/job/64540909415 and I'm not sure what else it could be other than this, so I'm giving it one more honest try before I throw up hands. For better or worse, https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#permissions explicitly lists that the `pull-requests` permission allows tagging PRs, so I'm holding out hope that this is it. Still terrible marks for documentation here, both to the github action, as well as everything to do with `GITHUB_TOKEN`. --- .github/workflows/pull-request-copy-labels.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull-request-copy-labels.yml b/.github/workflows/pull-request-copy-labels.yml index 895337644143..b8b8c35d9b0e 100644 --- a/.github/workflows/pull-request-copy-labels.yml +++ b/.github/workflows/pull-request-copy-labels.yml @@ -5,8 +5,8 @@ on: types: [opened] permissions: - issues: write # to read the labels of any linked issue(s), and to put the found labels if any on the PR - # not granting any `pull_requests` permissions because in github's modeling pull requests are a subset of issues. it's confusing. + issues: read # to read the labels of any linked issue(s) + pull-requests: write # to put the found labels if any on the PR jobs: copy-labels: From ee8d99034c3cc1faef1b0928339596f85c5f7b60 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 02:18:18 +0900 Subject: [PATCH 706/836] Rename one more missed song select v2 class --- ...aylistsSongSelectV2.cs => TestScenePlaylistsSongSelect.cs} | 4 ++-- osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs | 4 ++-- osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs | 2 +- .../Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs | 2 +- ...V2.PlaylistTray.cs => PlaylistsSongSelect.PlaylistTray.cs} | 2 +- .../{PlaylistsSongSelectV2.cs => PlaylistsSongSelect.cs} | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) rename osu.Game.Tests/Visual/Multiplayer/{TestScenePlaylistsSongSelectV2.cs => TestScenePlaylistsSongSelect.cs} (98%) rename osu.Game/Screens/OnlinePlay/Playlists/{PlaylistsSongSelectV2.PlaylistTray.cs => PlaylistsSongSelect.PlaylistTray.cs} (99%) rename osu.Game/Screens/OnlinePlay/Playlists/{PlaylistsSongSelectV2.cs => PlaylistsSongSelect.cs} (98%) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs similarity index 98% rename from osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs rename to osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs index 6d2d507bf1a6..fa0092eedb3a 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelectV2.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs @@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { - public partial class TestScenePlaylistsSongSelectV2 : OnlinePlayTestScene + public partial class TestScenePlaylistsSongSelect : OnlinePlayTestScene { private RulesetStore rulesets = null!; private BeatmapManager manager = null!; @@ -191,7 +191,7 @@ protected override void Dispose(bool isDisposing) rulesets.Dispose(); } - private partial class TestPlaylistsSongSelect : PlaylistsSongSelectV2 + private partial class TestPlaylistsSongSelect : PlaylistsSongSelect { public new IBindable Freestyle => base.Freestyle; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index e46d8f74a553..b720772cac25 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -94,7 +94,7 @@ public void TestConfirmationRequiredToDiscardPlaylist(bool withPlaylistItemAdded AddStep("edit playlist", () => InputManager.Key(Key.Enter)); - AddUntilStep("wait for song select", () => playlistScreen.CurrentSubScreen is PlaylistsSongSelectV2 songSelect && songSelect.IsLoaded && !songSelect.IsFiltering); + AddUntilStep("wait for song select", () => playlistScreen.CurrentSubScreen is PlaylistsSongSelect songSelect && songSelect.IsLoaded && !songSelect.IsFiltering); AddUntilStep("wait for selection", () => !Game.Beatmap.IsDefault); @@ -109,7 +109,7 @@ public void TestConfirmationRequiredToDiscardPlaylist(bool withPlaylistItemAdded InputManager.Click(MouseButton.Left); }); - AddUntilStep("wait for song select", () => playlistScreen.CurrentSubScreen is PlaylistsSongSelectV2 songSelect && songSelect.IsLoaded && !songSelect.IsFiltering); + AddUntilStep("wait for song select", () => playlistScreen.CurrentSubScreen is PlaylistsSongSelect songSelect && songSelect.IsLoaded && !songSelect.IsFiltering); AddStep("press home button", () => { diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs index e64d74ecba42..f936bdaaf9df 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistTray.cs @@ -18,7 +18,7 @@ public override void SetUpSteps() { base.SetUpSteps(); - AddStep("add tray", () => Child = new PlaylistsSongSelectV2.PlaylistTray(room = new Room()) + AddStep("add tray", () => Child = new PlaylistsSongSelect.PlaylistTray(room = new Room()) { Anchor = Anchor.Centre, Origin = Anchor.Centre diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 16570e68e916..646da4e96779 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -404,7 +404,7 @@ private void load() EditPlaylist = () => { if (this.IsCurrentScreen()) - this.Push(new PlaylistsSongSelectV2(room)); + this.Push(new PlaylistsSongSelect(room)); } } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.PlaylistTray.cs similarity index 99% rename from osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs rename to osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.PlaylistTray.cs index 10c6ee6ef95f..b46759915315 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.PlaylistTray.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.PlaylistTray.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { - public partial class PlaylistsSongSelectV2 + public partial class PlaylistsSongSelect { public partial class PlaylistTray : CompositeDrawable { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs similarity index 98% rename from osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs rename to osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs index 0431885d1fba..60a3133758da 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelectV2.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { - public partial class PlaylistsSongSelectV2 : SongSelect, IOnlinePlaySubScreen + public partial class PlaylistsSongSelect : SongSelect, IOnlinePlaySubScreen { public string ShortTitle => "song selection"; @@ -43,7 +43,7 @@ public partial class PlaylistsSongSelectV2 : SongSelect, IOnlinePlaySubScreen private IDisposable? modSelectOverlayRegistration; - public PlaylistsSongSelectV2(Room room) + public PlaylistsSongSelect(Room room) { this.room = room; From 99ab245cf0686e2fa24fd33553eef4b2015ca2fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 14:34:00 +0900 Subject: [PATCH 707/836] Tidy up how `SettingsSubsection` headings are created Previously we were always making header content in the base class then overwriting it, which felt ick. --- .../Settings/Sections/InputSubsection.cs | 21 ++++++------ .../Overlays/Settings/SettingsSubsection.cs | 33 +++++++++---------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs index 71d844e8efde..740102765a46 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs @@ -30,6 +30,8 @@ public partial class InputSubsection : SettingsSubsection private readonly BindableBool handlerEnabled = new BindableBool(); + private ToggleableHeader header = null!; + public InputSubsection(InputHandler handler) { this.handler = handler; @@ -37,14 +39,10 @@ public InputSubsection(InputHandler handler) FlowContent.AlwaysPresent = true; } - [BackgroundDependencyLoader] - private void load() + protected override Drawable CreateHeader() => header = new ToggleableHeader(Header, IsToggleable) { - HeaderContainer.Child = new ToggleableHeader(Header, IsToggleable) - { - Current = { BindTarget = handlerEnabled }, - }; - } + Current = { BindTarget = handlerEnabled }, + }; protected override void LoadComplete() { @@ -58,7 +56,7 @@ private void updateEnabledState() { // set negative bottom margin to not have too much vertical gap between disabled input subsections. bool negativeBottomMargin = !handlerEnabled.Value || FlowContent.Count == 0; - HeaderContainer.TransformTo(nameof(Margin), new MarginPadding { Bottom = negativeBottomMargin ? -15 : 0 }, 300, Easing.OutQuint); + header.TransformTo(nameof(Margin), new MarginPadding { Bottom = negativeBottomMargin ? -VERTICAL_PADDING : 0 }, 300, Easing.OutQuint); FlowContent.ClearTransforms(); @@ -92,6 +90,11 @@ private partial class ToggleableHeader : CompositeDrawable public ToggleableHeader(LocalisableString text, bool toggleable) { + Padding = SettingsPanel.CONTENT_PADDING; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + this.text = text; this.toggleable = toggleable; } @@ -105,8 +108,6 @@ public ToggleableHeader(LocalisableString text, bool toggleable) [BackgroundDependencyLoader] private void load() { - AutoSizeAxes = Axes.Both; - InternalChildren = new Drawable[] { switchButton = new SwitchButton diff --git a/osu.Game/Overlays/Settings/SettingsSubsection.cs b/osu.Game/Overlays/Settings/SettingsSubsection.cs index 669425b667fc..8d7d9844a883 100644 --- a/osu.Game/Overlays/Settings/SettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/SettingsSubsection.cs @@ -14,12 +14,12 @@ namespace osu.Game.Overlays.Settings { public abstract partial class SettingsSubsection : FillFlowContainer, IFilterable { + public const float VERTICAL_PADDING = (header_height - header_font_size) * 0.5f; + protected override Container Content => FlowContent; protected readonly FillFlowContainer FlowContent; - protected Container HeaderContainer { get; private set; } = null!; - protected abstract LocalisableString Header { get; } public virtual IEnumerable FilterTerms => new[] { Header }; @@ -53,25 +53,22 @@ protected SettingsSubsection() [BackgroundDependencyLoader] private void load() { - AddRangeInternal(new Drawable[] + AddRangeInternal(new[] { - HeaderContainer = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = SettingsPanel.CONTENT_PADDING, - Children = new[] - { - new OsuSpriteText - { - Text = Header, - Font = OsuFont.GetFont(size: header_font_size), - Margin = new MarginPadding { Vertical = (header_height - header_font_size) * 0.5f }, - }, - }, - }, + CreateHeader(), FlowContent }); } + + protected virtual Drawable CreateHeader() + { + return new OsuSpriteText + { + Text = Header, + Font = OsuFont.GetFont(size: header_font_size), + Margin = new MarginPadding { Vertical = VERTICAL_PADDING }, + Padding = SettingsPanel.CONTENT_PADDING, + }; + } } } From cb597c4120058db452870f7d0c832826dfda189f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 14:34:30 +0900 Subject: [PATCH 708/836] Fix flow animating its display initially when it shouldn't --- osu.Game/Overlays/Settings/Sections/InputSubsection.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs index 740102765a46..f6bac302171f 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs @@ -49,15 +49,17 @@ protected override void LoadComplete() base.LoadComplete(); handlerEnabled.BindTo(handler.Enabled); - handlerEnabled.BindValueChanged(v => updateEnabledState(), true); + handlerEnabled.BindValueChanged(updateEnabledState, true); } - private void updateEnabledState() + private void updateEnabledState(ValueChangedEvent state) { // set negative bottom margin to not have too much vertical gap between disabled input subsections. bool negativeBottomMargin = !handlerEnabled.Value || FlowContent.Count == 0; header.TransformTo(nameof(Margin), new MarginPadding { Bottom = negativeBottomMargin ? -VERTICAL_PADDING : 0 }, 300, Easing.OutQuint); + // Avoid crashes from toggling `AutoSizeAxes` while active `AutoSizeDuration` transforms are still running. + // This is probably a framework bug. FlowContent.ClearTransforms(); if (!handlerEnabled.Value) @@ -72,7 +74,7 @@ private void updateEnabledState() // enable auto size transform momentarily for smooth pop in animation, and disable it right after the transform is added. // we don't want this specification to apply when a dropdown in the input settings is being open, it causes too slow animation. // (try removing the schedule below then watch a settings dropdown menu opening animation). - FlowContent.AutoSizeDuration = 300; + FlowContent.AutoSizeDuration = state.NewValue == state.OldValue ? 0 : 300; FlowContent.AutoSizeEasing = Easing.OutQuint; FlowContent.AutoSizeAxes = Axes.Y; ScheduleAfterChildren(() => FlowContent.AutoSizeDuration = 0); From 047ea7c09d2cf44e7a0ceffb4e13e7aa9261ea83 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 14:35:21 +0900 Subject: [PATCH 709/836] Fix hidden settings flow content still being interactive `AlwaysPresent` is a code smell here. Rather than doing this, let's just using masking as we usually do. Closes https://github.com/ppy/osu/issues/36748. --- osu.Game/Overlays/Settings/Sections/InputSubsection.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs index f6bac302171f..68a19bd7a3d1 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSubsection.cs @@ -35,8 +35,6 @@ public partial class InputSubsection : SettingsSubsection public InputSubsection(InputHandler handler) { this.handler = handler; - - FlowContent.AlwaysPresent = true; } protected override Drawable CreateHeader() => header = new ToggleableHeader(Header, IsToggleable) @@ -50,6 +48,9 @@ protected override void LoadComplete() handlerEnabled.BindTo(handler.Enabled); handlerEnabled.BindValueChanged(updateEnabledState, true); + + // We use masking to hide the content of these sections. + FlowContent.Masking = true; } private void updateEnabledState(ValueChangedEvent state) @@ -66,8 +67,6 @@ private void updateEnabledState(ValueChangedEvent state) { FlowContent.AutoSizeAxes = Axes.None; FlowContent.ResizeHeightTo(0, 300, Easing.OutQuint); - - FlowContent.FadeOut(200, Easing.OutQuint); } else { @@ -77,9 +76,8 @@ private void updateEnabledState(ValueChangedEvent state) FlowContent.AutoSizeDuration = state.NewValue == state.OldValue ? 0 : 300; FlowContent.AutoSizeEasing = Easing.OutQuint; FlowContent.AutoSizeAxes = Axes.Y; - ScheduleAfterChildren(() => FlowContent.AutoSizeDuration = 0); - FlowContent.FadeIn(300, Easing.OutQuint); + ScheduleAfterChildren(() => FlowContent.AutoSizeDuration = 0); } } From 0dfb362b2d9cc82a25517e794c26f2cdc4192c0a Mon Sep 17 00:00:00 2001 From: Neti Date: Wed, 25 Feb 2026 02:31:36 -0500 Subject: [PATCH 710/836] Use `HotkeyDisplay` for toolbar buttons (#36750) Uses `HotkeyDisplay` for toolbar button tooltips rather than `SpriteText` image --------- Co-authored-by: Dean Herbert --- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 58 ++++++---------------- 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index b0a6841a2f81..f40f00523e12 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -1,23 +1,20 @@ // 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.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; -using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Localisation; -using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osuTK; using osuTK.Graphics; @@ -36,14 +33,7 @@ public void SetIcon(Drawable icon) IconContainer.Show(); } - [Resolved] - private ReadableKeyCombinationProvider keyCombinationProvider { get; set; } = null!; - - public void SetIcon(IconUsage icon) => - SetIcon(new SpriteIcon - { - Icon = icon, - }); + public void SetIcon(IconUsage icon) => SetIcon(new SpriteIcon { Icon = icon }); public LocalisableString TooltipMain { @@ -66,15 +56,11 @@ public LocalisableString TooltipSub private readonly FillFlowContainer tooltipContainer; private readonly SpriteText tooltip1; private readonly SpriteText tooltip2; - private readonly SpriteText keyBindingTooltip; protected FillFlowContainer Flow; protected readonly Container BackgroundContent; - private IDisposable? realmSubscription; - - [Resolved] - private RealmAccess realm { get; set; } = null!; + private readonly FillFlowContainer subTooltipFlow; protected ToolbarButton() { @@ -152,16 +138,15 @@ protected ToolbarButton() Shadow = true, Font = OsuFont.GetFont(size: 22, weight: FontWeight.Bold), }, - new FillFlowContainer + subTooltipFlow = new FillFlowContainer { AutoSizeAxes = Axes.Both, Anchor = TooltipAnchor, Origin = TooltipAnchor, Direction = FillDirection.Horizontal, - Children = new[] + Children = new Drawable[] { tooltip2 = new OsuSpriteText { Shadow = true }, - keyBindingTooltip = new OsuSpriteText { Shadow = true } } } } @@ -174,8 +159,13 @@ private void load() { if (Hotkey != null) { - realmSubscription = realm.SubscribeToPropertyChanged(r => r.All().FirstOrDefault(rkb => rkb.RulesetName == null && rkb.ActionInt == (int)Hotkey.Value), - kb => kb.KeyCombinationString, updateKeyBindingTooltip); + subTooltipFlow.Add(new HotkeyDisplay + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Hotkey = new Hotkey(Hotkey.Value), + Margin = new MarginPadding { Left = 3 }, + }); } } @@ -190,16 +180,16 @@ protected override bool OnClick(ClickEvent e) protected override bool OnHover(HoverEvent e) { - HoverBackground.FadeIn(200); - tooltipContainer.FadeIn(100); + HoverBackground.FadeIn(300, Easing.OutQuint); + tooltipContainer.FadeIn(200, Easing.OutQuint); return true; } protected override void OnHoverLost(HoverLostEvent e) { - HoverBackground.FadeOut(200); - tooltipContainer.FadeOut(100); + HoverBackground.FadeOut(200, Easing.Out); + tooltipContainer.FadeOut(100, Easing.Out); } public bool OnPressed(KeyBindingPressEvent e) @@ -216,22 +206,6 @@ public bool OnPressed(KeyBindingPressEvent e) public void OnReleased(KeyBindingReleaseEvent e) { } - - private void updateKeyBindingTooltip(string keyCombination) - { - string keyBindingString = keyCombinationProvider.GetReadableString(keyCombination); - - keyBindingTooltip.Text = !string.IsNullOrEmpty(keyBindingString) - ? $" ({keyBindingString})" - : string.Empty; - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - realmSubscription?.Dispose(); - } } public partial class OpaqueBackground : Container From 5174d8b9186769a6abcbe76fc143e4ed3af598d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 25 Feb 2026 18:47:45 +0100 Subject: [PATCH 711/836] Fix changing normal sample bank via keyboard hotkeys not updating addition bank if set to auto (#36741) Closes https://github.com/ppy/osu/issues/36703. It was only broken via keyboard hotkeys and not via the sample popover because the sample popover has a separate copy of the logic that didn't have the bug. Compare: https://github.com/ppy/osu/blob/13aeed15f95fa6585ff01eedaccc43b28ff656cb/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs#L473-L475 I considered splitting a helper to have one copy of the logic but it's not very simple to do compared to a two-liner fix so I gave up. --- .../TestSceneHitObjectSampleAdjustments.cs | 86 +++++++++++++++++-- .../Components/EditorSelectionHandler.cs | 14 ++- .../Components/Timeline/SamplePointPiece.cs | 9 ++ 3 files changed, 100 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs index 082064d19866..8ebc09bf25f9 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs @@ -19,6 +19,7 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; using osu.Game.Screens.Edit.Components.TernaryButtons; +using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Screens.Edit.Compose.Components.Timeline; using osu.Game.Screens.Edit.Timing; using osu.Game.Tests.Beatmaps; @@ -112,6 +113,77 @@ public void TestSingleSelection() hitObjectHasSampleBank(1, HitSampleInfo.BANK_DRUM); } + [Test] + public void TestAutoAdditionsBankMatchesNormalBankWhenChangedViaPopover() + { + clickSamplePiece(0); + setBankViaPopover(HitSampleInfo.BANK_SOFT); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_SOFT); + + toggleAdditionViaPopover(1); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_SOFT); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_SOFT); + + setBankViaPopover(HitSampleInfo.BANK_DRUM); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM); + + setAdditionBankViaPopover(HitSampleInfo.BANK_NORMAL); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_NORMAL); + + setAdditionBankViaPopover(EditorSelectionHandler.HIT_BANK_AUTO); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM); + } + + [Test] + public void TestAutoAdditionsBankMatchesNormalBankWhenChangedViaHotkeys() + { + AddStep("select first object", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects[0])); + AddStep("set soft normal bank", () => + { + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.E); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_SOFT); + + AddStep("toggle finish", () => InputManager.Key(Key.E)); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_SOFT); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_SOFT); + + AddStep("set drum normal bank", () => + { + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.R); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM); + + AddStep("set normal addition bank", () => + { + InputManager.PressKey(Key.AltLeft); + InputManager.Key(Key.W); + InputManager.ReleaseKey(Key.AltLeft); + }); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_NORMAL); + + AddStep("set auto addition bank", () => + { + InputManager.PressKey(Key.AltLeft); + InputManager.Key(Key.Q); + InputManager.ReleaseKey(Key.AltLeft); + }); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM); + } + [Test] public void TestUndo() { @@ -346,7 +418,7 @@ public void TestHotkeysMultipleSelectionWithSameSampleBank() { for (int i = 0; i < h.Samples.Count; i++) { - h.Samples[i] = h.Samples[i].With(newBank: HitSampleInfo.BANK_SOFT); + h.Samples[i] = h.Samples[i].With(newBank: HitSampleInfo.BANK_SOFT, newEditorAutoBank: false); } } }); @@ -354,7 +426,7 @@ public void TestHotkeysMultipleSelectionWithSameSampleBank() AddStep("add whistle addition", () => { foreach (var h in EditorBeatmap.HitObjects) - h.Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_WHISTLE, HitSampleInfo.BANK_SOFT)); + h.Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_WHISTLE, HitSampleInfo.BANK_SOFT, editorAutoBank: false)); }); AddStep("select both objects", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects)); @@ -599,19 +671,19 @@ public void TestHotkeysAffectNodeSamples() Path = new SliderPath(new[] { new PathControlPoint(Vector2.Zero), new PathControlPoint(new Vector2(250, 0)) }), Samples = { - new HitSampleInfo(HitSampleInfo.HIT_NORMAL) + new HitSampleInfo(HitSampleInfo.HIT_NORMAL, editorAutoBank: false) }, NodeSamples = new List> { new List { - new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_DRUM), - new HitSampleInfo(HitSampleInfo.HIT_CLAP, bank: HitSampleInfo.BANK_DRUM), + new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_DRUM, editorAutoBank: false), + new HitSampleInfo(HitSampleInfo.HIT_CLAP, bank: HitSampleInfo.BANK_DRUM, editorAutoBank: false), }, new List { - new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_SOFT), - new HitSampleInfo(HitSampleInfo.HIT_WHISTLE, bank: HitSampleInfo.BANK_SOFT), + new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_SOFT, editorAutoBank: false), + new HitSampleInfo(HitSampleInfo.HIT_WHISTLE, bank: HitSampleInfo.BANK_SOFT, editorAutoBank: false), }, } }); diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs index a258016da5a8..374ceaccc610 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs @@ -16,6 +16,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Screens.Edit.Compose.Components.Timeline; using osuTK.Input; namespace osu.Game.Screens.Edit.Compose.Components @@ -342,6 +343,9 @@ private IEnumerable> enumerateAllSamples(HitObject hitObjec /// /// Sets the sample bank for all selected s. /// + /// + /// Should be kept in sync with . + /// /// The name of the sample bank. public void SetSampleBank(string bankName) { @@ -366,12 +370,12 @@ bool hasRelevantBank(HitObject hitObject) if (hasRelevantBank(h)) return; - h.Samples = h.Samples.Select(s => s.Name == HitSampleInfo.HIT_NORMAL ? s.With(newBank: bankName) : s).ToList(); + h.Samples = h.Samples.Select(s => s.Name == HitSampleInfo.HIT_NORMAL || s.EditorAutoBank ? s.With(newBank: bankName) : s).ToList(); if (h is IHasRepeats hasRepeats) { for (int i = 0; i < hasRepeats.NodeSamples.Count; ++i) - hasRepeats.NodeSamples[i] = hasRepeats.NodeSamples[i].Select(s => s.Name == HitSampleInfo.HIT_NORMAL ? s.With(newBank: bankName) : s).ToList(); + hasRepeats.NodeSamples[i] = hasRepeats.NodeSamples[i].Select(s => s.Name == HitSampleInfo.HIT_NORMAL || s.EditorAutoBank ? s.With(newBank: bankName) : s).ToList(); } }); } @@ -379,6 +383,9 @@ bool hasRelevantBank(HitObject hitObject) /// /// Sets the sample addition bank for all selected s. /// + /// + /// Should be kept in sync with . + /// /// The name of the sample bank. public void SetSampleAdditionBank(string bankName) { @@ -432,6 +439,9 @@ private bool hasRelevantSample(HitObject hitObject, string sampleName) /// /// Adds a hit sample to all selected s. /// + /// + /// Should be kept in sync with . + /// /// The name of the hit sample. public void AddHitSample(string sampleName) { diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs index 7f7f749c44f4..c2def9506893 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -464,6 +464,9 @@ private void updateAllRelevantSamples(Action> up beatmap.EndChange(); } + /// + /// Should be kept in sync with . + /// private void setBank(string newBank) { updateAllRelevantSamples((_, relevantSamples) => @@ -477,6 +480,9 @@ private void setBank(string newBank) }); } + /// + /// Should be kept in sync with . + /// private void setAdditionBank(string newBank) { updateAllRelevantSamples((_, relevantSamples) => @@ -583,6 +589,9 @@ private IEnumerable createTernaryButtons() } } + /// + /// Should be kept in sync with . + /// private void addHitSample(string sampleName) { if (string.IsNullOrEmpty(sampleName)) From 7e2771c3f0a0eb40ab8cfa807e5ca662bde9a17b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 26 Feb 2026 07:18:29 +0100 Subject: [PATCH 712/836] Improve usability of sample bank toggles (#36753) - [x] Depends on https://github.com/ppy/osu/pull/36741 for merge conflict avoidance RFC, cc @OliBomby ## [Adjust behaviour of automatic bank assignment during placement](https://github.com/ppy/osu/commit/547f55e9b3ded668fe6e1c8865a2d625e64a2f45) Diatribe time! This is fallout of the discussion about auto bank in https://github.com/ppy/osu/issues/36705. Auto bank in lazer as written before this commit is confused. On stable, auto bank is closer to "no bank", as in "go look up the current sample timing point, get the bank of that, and use that". lazer has no timing points anymore, but people still want auto bank. So what do? Auto bank for normal samples is somewhat sane still. It only works during placement, and will just copy the normal bank of the previous object - if one exists. That said, one *might not* exist, but the resulting object will still have its normal sample created with `editorAutoBank: true`. That is largely cosmetic and without consequences, but this commit fixes that. Auto bank for *addition* samples, however... Hoo boy. - For placed objects, auto bank means "take the normal sample, read its bank, and use that". Simple enough, right? - Hoooooowever. During placement, auto bank before this commit used to mean "look at the *previous object*, check if it has an addition sound and then use its bank, if not use *the previous object's* normal sample and then use its bank" which is a completely different thing with its own implications. Like, say, what happens if the previous object uses the auto addition bank too? What should be copied over? Should it be the notion of "auto bank" in that the addition bank should match the normal bank, or should it be the literal bank that the previous object is using? This change attempts to define this unambiguously. "Auto additions bank" means "the same bank as the normal bank of this object", full stop. ## [Do not touch sample toggle state if there are no selected objects](https://github.com/ppy/osu/commit/052cde5987e48800ec68ab2528c7e0ce3140e6e0) Fixes issue described in https://github.com/ppy/osu/issues/36705#issuecomment-3953917163 wherein opening a sample popover will disable addition bank toggles and toggle off all addition samples. --------- Co-authored-by: Dean Herbert --- .../TestSceneHitObjectSampleAdjustments.cs | 186 ++++++++++++++++++ .../Editing/TestScenePlacementBlueprint.cs | 4 +- .../Edit/HitObjectPlacementBlueprint.cs | 26 +-- .../Components/EditorSelectionHandler.cs | 27 +-- 4 files changed, 216 insertions(+), 27 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs index 8ebc09bf25f9..515fa4c0b571 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs @@ -595,6 +595,172 @@ void checkPlacementSampleAdditionBank(string expected) => AddAssert($"Placement () => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name != HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(expected)); } + [Test] + public void TestNonAutoBankHotkeysDuringPlacementPersistAfterPlacement() + { + AddStep("Clear all objects", () => EditorBeatmap.Clear()); + AddStep("Enter placement mode", () => InputManager.Key(Key.Number2)); + AddStep("Move mouse to centre", () => InputManager.MoveMouseTo(Editor.ChildrenOfType().First().ScreenSpaceDrawQuad.Centre)); + + AddStep("Move to 3000", () => EditorClock.Seek(3000)); + + AddStep("Press drum bank shortcut", () => + { + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.R); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + + AddAssert($"Placement sample is {HitSampleInfo.BANK_DRUM}", + () => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name == HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(HitSampleInfo.BANK_DRUM)); + + AddStep("Press normal addition bank shortcut", () => + { + InputManager.PressKey(Key.AltLeft); + InputManager.Key(Key.W); + InputManager.ReleaseKey(Key.AltLeft); + }); + + AddStep("Press finish sample shortcut", () => + { + InputManager.Key(Key.E); + }); + + AddAssert($"Placement sample addition is {HitSampleInfo.BANK_NORMAL}", + () => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name != HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(HitSampleInfo.BANK_NORMAL)); + + AddStep("Finish placement", () => InputManager.Click(MouseButton.Left)); + + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasAutoNormalBankFlag(0, false); + hitObjectHasAutoAdditionBankFlag(0, false); + + clickSamplePiece(0); + samplePopoverIsOpen(); + samplePopoverHasSingleAdditionBank(HitSampleInfo.BANK_NORMAL); + } + + [Test] + public void TestAutoAdditionBankHotkeyDuringPlacementPersistsAfterPlacement() + { + AddStep("Clear all objects", () => EditorBeatmap.Clear()); + AddStep("Enter placement mode", () => InputManager.Key(Key.Number2)); + AddStep("Move mouse to centre", () => InputManager.MoveMouseTo(Editor.ChildrenOfType().First().ScreenSpaceDrawQuad.Centre)); + + AddStep("Move to 3000", () => EditorClock.Seek(3000)); + + AddStep("Press drum bank shortcut", () => + { + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.R); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + + AddAssert($"Placement sample is {HitSampleInfo.BANK_DRUM}", + () => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name == HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(HitSampleInfo.BANK_DRUM)); + + AddStep("Press normal addition bank shortcut", () => + { + InputManager.PressKey(Key.AltLeft); + InputManager.Key(Key.W); + InputManager.ReleaseKey(Key.AltLeft); + }); + + AddStep("Press finish sample shortcut", () => + { + InputManager.Key(Key.E); + }); + + AddStep("Press auto addition bank shortcut", () => + { + InputManager.PressKey(Key.AltLeft); + InputManager.Key(Key.Q); + InputManager.ReleaseKey(Key.AltLeft); + }); + + AddAssert($"Placement sample addition is {HitSampleInfo.BANK_DRUM}", + () => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name != HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(HitSampleInfo.BANK_DRUM)); + + AddStep("Finish placement", () => InputManager.Click(MouseButton.Left)); + + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasAutoNormalBankFlag(0, false); + hitObjectHasAutoAdditionBankFlag(0, true); + + clickSamplePiece(0); + samplePopoverIsOpen(); + samplePopoverHasSingleAdditionBank(EditorSelectionHandler.HIT_BANK_AUTO); + } + + [Test] + public void TestFullAutoBankHotkeyDuringPlacementPersistsAfterPlacement() + { + AddStep("Clear all objects", () => EditorBeatmap.Clear()); + AddStep("Enter placement mode", () => InputManager.Key(Key.Number2)); + AddStep("Move mouse to centre", () => InputManager.MoveMouseTo(Editor.ChildrenOfType().First().ScreenSpaceDrawQuad.Centre)); + + AddStep("Move to 3000", () => EditorClock.Seek(3000)); + + AddStep("Press auto normal bank shortcut", () => + { + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.Q); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + + AddAssert($"Placement sample is {HitSampleInfo.BANK_NORMAL}", + () => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name == HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(HitSampleInfo.BANK_NORMAL)); + + AddStep("Press finish sample shortcut", () => + { + InputManager.Key(Key.E); + }); + + AddStep("Press auto addition bank shortcut", () => + { + InputManager.PressKey(Key.AltLeft); + InputManager.Key(Key.Q); + InputManager.ReleaseKey(Key.AltLeft); + }); + + AddAssert($"Placement sample addition is {HitSampleInfo.BANK_NORMAL}", + () => EditorBeatmap.PlacementObject.Value.Samples.First(s => s.Name != HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(HitSampleInfo.BANK_NORMAL)); + + AddStep("Finish placement", () => InputManager.Click(MouseButton.Left)); + + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasAutoNormalBankFlag(0, false); // it's the first object - nothing to inherit bank from + hitObjectHasAutoAdditionBankFlag(0, true); + + clickSamplePiece(0); + samplePopoverIsOpen(); + samplePopoverHasSingleBank(HitSampleInfo.BANK_NORMAL); + samplePopoverHasSingleAdditionBank(EditorSelectionHandler.HIT_BANK_AUTO); + dismissPopover(); + + AddStep("Move to 5000", () => EditorClock.Seek(5000)); + AddStep("Enter placement mode", () => InputManager.Key(Key.Number2)); + AddStep("Move mouse to centre", () => InputManager.MoveMouseTo(Editor.ChildrenOfType().First().ScreenSpaceDrawQuad.Centre)); + AddStep("Finish placement", () => InputManager.Click(MouseButton.Left)); + + hitObjectHasSamples(1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); // finish is still implied, continuing from first placement + hitObjectHasSampleNormalBank(1, HitSampleInfo.BANK_NORMAL); + hitObjectHasSampleAdditionBank(1, HitSampleInfo.BANK_NORMAL); + hitObjectHasAutoNormalBankFlag(1, true); + hitObjectHasAutoAdditionBankFlag(1, true); + + clickSamplePiece(1); + samplePopoverIsOpen(); + samplePopoverHasSingleBank(HitSampleInfo.BANK_NORMAL); + samplePopoverHasSingleAdditionBank(EditorSelectionHandler.HIT_BANK_AUTO); + } + [Test] public void PopoverForMultipleSelectionChangesAllSamples() { @@ -952,6 +1118,14 @@ private void samplePopoverHasIndeterminateBank() => AddUntilStep("sample popover return dropdown?.Current.Value == "(multiple)"; }); + private void samplePopoverHasSingleAdditionBank(string bank) => AddUntilStep($"sample popover has bank {bank}", () => + { + var popover = this.ChildrenOfType().SingleOrDefault(); + var dropdown = popover?.ChildrenOfType>().ElementAt(1); + + return dropdown?.Current.Value == bank; + }); + private void dismissPopover() { AddStep("dismiss popover", () => InputManager.Key(Key.Escape)); @@ -1025,6 +1199,18 @@ private void hitObjectHasSampleAdditionBank(int objectIndex, string bank) => Add return h.Samples.Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(o => o.Bank == bank); }); + private void hitObjectHasAutoNormalBankFlag(int objectIndex, bool autoBank) => AddAssert($"{objectIndex.ToOrdinalWords()} has auto normal bank {(autoBank ? "on" : "off")}", () => + { + var h = EditorBeatmap.HitObjects.ElementAt(objectIndex); + return h.Samples.Where(o => o.Name == HitSampleInfo.HIT_NORMAL).All(o => o.EditorAutoBank == autoBank); + }); + + private void hitObjectHasAutoAdditionBankFlag(int objectIndex, bool autoBank) => AddAssert($"{objectIndex.ToOrdinalWords()} has auto addition bank {(autoBank ? "on" : "off")}", () => + { + var h = EditorBeatmap.HitObjects.ElementAt(objectIndex); + return h.Samples.Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(o => o.EditorAutoBank == autoBank); + }); + private void hitObjectNodeHasSamples(int objectIndex, int nodeIndex, params string[] samples) => AddAssert( $"{objectIndex.ToOrdinalWords()} object {nodeIndex.ToOrdinalWords()} node has samples {string.Join(',', samples)}", () => { diff --git a/osu.Game.Tests/Visual/Editing/TestScenePlacementBlueprint.cs b/osu.Game.Tests/Visual/Editing/TestScenePlacementBlueprint.cs index 675de2f57a86..31e2e5b30280 100644 --- a/osu.Game.Tests/Visual/Editing/TestScenePlacementBlueprint.cs +++ b/osu.Game.Tests/Visual/Editing/TestScenePlacementBlueprint.cs @@ -272,8 +272,8 @@ public void TestAutomaticBankAssignment() AddAssert("circle has 2 samples", () => EditorBeatmap.HitObjects[1].Samples, () => Has.Count.EqualTo(2)); AddAssert("normal sample has soft bank", () => EditorBeatmap.HitObjects[1].Samples.Single(s => s.Name == HitSampleInfo.HIT_NORMAL).Bank, () => Is.EqualTo(HitSampleInfo.BANK_SOFT)); - AddAssert("clap sample has drum bank", () => EditorBeatmap.HitObjects[1].Samples.Single(s => s.Name == HitSampleInfo.HIT_CLAP).Bank, - () => Is.EqualTo(HitSampleInfo.BANK_DRUM)); + AddAssert("clap sample has soft bank", () => EditorBeatmap.HitObjects[1].Samples.Single(s => s.Name == HitSampleInfo.HIT_CLAP).Bank, + () => Is.EqualTo(HitSampleInfo.BANK_SOFT)); AddAssert("circle inherited volume", () => EditorBeatmap.HitObjects[1].Samples.All(s => s.Volume == 70)); AddStep("seek to 1000", () => EditorClock.Seek(1000)); // previous object is the one at time 500, which has no additions diff --git a/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs b/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs index 7b378edda6b4..a24249d42c7f 100644 --- a/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/HitObjectPlacementBlueprint.cs @@ -113,22 +113,14 @@ public override SnapResult UpdateTimeAndPosition(Vector2 screenSpacePosition, do var lastHitObject = getPreviousHitObject(); var lastHitNormal = lastHitObject?.Samples?.FirstOrDefault(o => o.Name == HitSampleInfo.HIT_NORMAL); - if (AutomaticAdditionBankAssignment) - { - // Inherit the addition bank from the previous hit object - // If there is no previous addition, inherit from the normal sample - var lastAddition = lastHitObject?.Samples?.FirstOrDefault(o => o.Name != HitSampleInfo.HIT_NORMAL) ?? lastHitNormal; - - if (lastAddition != null) - HitObject.Samples = HitObject.Samples.Select(s => s.Name != HitSampleInfo.HIT_NORMAL ? s.With(newBank: lastAddition.Bank) : s).ToList(); - } + if (lastHitNormal != null && AutomaticBankAssignment) + // Inherit the bank from the previous hit object + HitObject.Samples = HitObject.Samples.Select(s => s.Name == HitSampleInfo.HIT_NORMAL ? s.With(newBank: lastHitNormal.Bank, newEditorAutoBank: true) : s).ToList(); + else + HitObject.Samples = HitObject.Samples.Select(s => s.Name == HitSampleInfo.HIT_NORMAL ? s.With(newEditorAutoBank: false) : s).ToList(); if (lastHitNormal != null) { - if (AutomaticBankAssignment) - // Inherit the bank from the previous hit object - HitObject.Samples = HitObject.Samples.Select(s => s.Name == HitSampleInfo.HIT_NORMAL ? s.With(newBank: lastHitNormal.Bank) : s).ToList(); - // Inherit the volume and sample set info from the previous hit object HitObject.Samples = HitObject.Samples.Select(s => s.With( newVolume: lastHitNormal.Volume, @@ -136,6 +128,14 @@ public override SnapResult UpdateTimeAndPosition(Vector2 screenSpacePosition, do newUseBeatmapSamples: lastHitNormal.UseBeatmapSamples)).ToList(); } + if (AutomaticAdditionBankAssignment) + { + string bank = HitObject.Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL)?.Bank ?? HitSampleInfo.BANK_SOFT; + HitObject.Samples = HitObject.Samples.Select(s => s.Name != HitSampleInfo.HIT_NORMAL ? s.With(newBank: bank, newEditorAutoBank: true) : s).ToList(); + } + else + HitObject.Samples = HitObject.Samples.Select(s => s.Name != HitSampleInfo.HIT_NORMAL ? s.With(newEditorAutoBank: false) : s).ToList(); + if (HitObject is IHasRepeats hasRepeats) { // Make sure all the node samples are identical to the hit object's samples diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs index 374ceaccc610..074d94eb2670 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs @@ -297,22 +297,25 @@ protected virtual void UpdateTernaryStates() var samplesInSelection = SelectedItems.SelectMany(enumerateAllSamples).ToArray(); - foreach ((string sampleName, var bindable) in SelectionSampleStates) + if (samplesInSelection.Length > 0) { - bindable.Value = GetStateFromSelection(samplesInSelection, h => h.Any(s => s.Name == sampleName)); - } + foreach ((string sampleName, var bindable) in SelectionSampleStates) + { + bindable.Value = GetStateFromSelection(samplesInSelection, h => h.Any(s => s.Name == sampleName)); + } - foreach ((string bankName, var bindable) in SelectionBankStates) - { - bindable.Value = GetStateFromSelection(samplesInSelection.SelectMany(s => s).Where(o => o.Name == HitSampleInfo.HIT_NORMAL), h => h.Bank == bankName); - } + foreach ((string bankName, var bindable) in SelectionBankStates) + { + bindable.Value = GetStateFromSelection(samplesInSelection.SelectMany(s => s).Where(o => o.Name == HitSampleInfo.HIT_NORMAL), h => h.Bank == bankName); + } - SelectionAdditionBanksEnabled.Value = samplesInSelection.SelectMany(s => s).Any(o => o.Name != HitSampleInfo.HIT_NORMAL); + SelectionAdditionBanksEnabled.Value = samplesInSelection.SelectMany(s => s).Any(o => o.Name != HitSampleInfo.HIT_NORMAL); - foreach ((string bankName, var bindable) in SelectionAdditionBankStates) - { - bindable.Value = GetStateFromSelection(samplesInSelection.SelectMany(s => s).Where(o => o.Name != HitSampleInfo.HIT_NORMAL), - h => (bankName != HIT_BANK_AUTO && h.Bank == bankName && !h.EditorAutoBank) || (bankName == HIT_BANK_AUTO && h.EditorAutoBank)); + foreach ((string bankName, var bindable) in SelectionAdditionBankStates) + { + bindable.Value = GetStateFromSelection(samplesInSelection.SelectMany(s => s).Where(o => o.Name != HitSampleInfo.HIT_NORMAL), + h => (bankName != HIT_BANK_AUTO && h.Bank == bankName && !h.EditorAutoBank) || (bankName == HIT_BANK_AUTO && h.EditorAutoBank)); + } } } From 2d6fa65262517ea5d5d765386ca1b9b5d6035821 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Fri, 27 Feb 2026 00:13:21 +0500 Subject: [PATCH 713/836] Use full hitwindow in taiko Rhythm skill (#36671) --- .../Difficulty/Evaluators/RhythmEvaluator.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs index e7e216a08449..9cbc5bf2de77 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs @@ -30,7 +30,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject hitObject) double samePattern = 0; double intervalPenalty = 0; - double hitWindow = hitObject.HitWindow(HitResult.Great) / 2.0; // this is practically incorrect, but kept as is for balancing + double hitWindow = hitObject.HitWindow(HitResult.Great); if (rhythmData.SameRhythmGroupedHitObjects?.FirstHitObject == hitObject) // Difficulty for SameRhythmGroupedHitObjects { @@ -63,8 +63,8 @@ private static double evaluateDifficultyOf(SameRhythmHitObjectGrouping sameRhyth { intervalDifficulty *= DifficultyCalculationUtils.Logistic( durationDifference / hitWindow, - midpointOffset: 0.7, - multiplier: 1.0, + midpointOffset: 0.35, + multiplier: 2, maxValue: 1); } } @@ -72,8 +72,8 @@ private static double evaluateDifficultyOf(SameRhythmHitObjectGrouping sameRhyth // Penalise patterns that can be hit within a single hit window. intervalDifficulty *= DifficultyCalculationUtils.Logistic( sameRhythmGroupedHitObjects.Duration / hitWindow, - midpointOffset: 0.6, - multiplier: 1, + midpointOffset: 0.3, + multiplier: 2, maxValue: 1); return Math.Pow(intervalDifficulty, 0.75); From 5131b188d1ada7b541601e72cb5d1322415c52da Mon Sep 17 00:00:00 2001 From: Krzysztof Gutkowski Date: Fri, 27 Feb 2026 11:12:30 +0100 Subject: [PATCH 714/836] Remove redundant footer from `TestScenePlaylistsRoomSubscreen` `ScreenTestScene` already provides one. --- .../Playlists/TestScenePlaylistsRoomSubScreen.cs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs index 3f9a7270779f..01156ad4a1a4 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs @@ -30,7 +30,6 @@ using osu.Game.Rulesets.Taiko; using osu.Game.Rulesets.Taiko.Mods; using osu.Game.Screens; -using osu.Game.Screens.Footer; using osu.Game.Screens.OnlinePlay; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Tests.Resources; @@ -676,19 +675,9 @@ private partial class TestPlaylistsScreen : OsuScreen public TestPlaylistsScreen(PlaylistsRoomSubScreen screen) { - ScreenFooter footer; - InternalChild = new DependencyProvidingContainer + InternalChild = Stack = new OnlinePlaySubScreenStack { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - Stack = new OnlinePlaySubScreenStack - { - RelativeSizeAxes = Axes.Both - }, - footer = new ScreenFooter(), - }, - CachedDependencies = new (Type, object)[] { (typeof(ScreenFooter), footer) }, + RelativeSizeAxes = Axes.Both }; Stack.Push(screen); From c72b6412eaca8e595635aa3e37266f15ec70ffd7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 28 Feb 2026 00:42:44 +0900 Subject: [PATCH 715/836] Add pool type to matchmaking room invited event (#36765) Rebase of https://github.com/smoogipoo/osu/pull/193 Going forward, the client will have to know the type of pool being invited to so that it can enter the appropriate screen when clicking the notification. Unfortunately, SignalR does not support overloading methods, or even adding parameters to them, so this PR deprecates the `MatchmakingRoomInvited` event and adds its replacement `MatchmakingRoomInvitedWithParams` with a complex `invitation` parameter that we _can_ extend in the future if required (such as potentially adding the name of the pool). This also prepares the notification by extracting some code to a `Complete` method receiving said `invitation` parameter. This part of code will be further modified to enter the correct screen: https://github.com/smoogipoo/osu/blob/0a4018045b9d908f66c63dee65d0059d05b26e43/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs#L200 In particular, I have tested that new clients continue to work with the old server (dev.ppy.sh) in quick play | | Old Server | New Server | | ------------- |:-------------:| :-----:| | Old Client | :green_circle: | :green_circle: | | New Client | :green_circle: | :green_circle: | --- .../Online/Matchmaking/IMatchmakingClient.cs | 11 +++++++ .../MatchmakingRoomInvitationParams.cs | 16 ++++++++++ .../Online/Multiplayer/MultiplayerClient.cs | 10 +++++-- .../Multiplayer/OnlineMultiplayerClient.cs | 1 + .../Matchmaking/Queue/QueueController.cs | 29 ++++++++++--------- 5 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 osu.Game/Online/Matchmaking/MatchmakingRoomInvitationParams.cs diff --git a/osu.Game/Online/Matchmaking/IMatchmakingClient.cs b/osu.Game/Online/Matchmaking/IMatchmakingClient.cs index be05e3ca0ddc..e44eafb3903f 100644 --- a/osu.Game/Online/Matchmaking/IMatchmakingClient.cs +++ b/osu.Game/Online/Matchmaking/IMatchmakingClient.cs @@ -23,8 +23,19 @@ public interface IMatchmakingClient : IStatefulUserHubClient /// declined, /// or ignored - in which case it will automatically be declined after a short timeout period. /// + /// + /// Provided for compatibility with older clients - can be removed 20260825. + /// Task MatchmakingRoomInvited(); + /// + /// Signals that a match has been found and the local user is invited to it. + /// The invitation may be accepted, + /// declined, + /// or ignored - in which case it will automatically be declined after a short timeout period. + /// + Task MatchmakingRoomInvitedWithParams(MatchmakingRoomInvitationParams invitation); + /// /// Signals that the matchmaking room is ready to be opened. /// diff --git a/osu.Game/Online/Matchmaking/MatchmakingRoomInvitationParams.cs b/osu.Game/Online/Matchmaking/MatchmakingRoomInvitationParams.cs new file mode 100644 index 000000000000..38b4d8573453 --- /dev/null +++ b/osu.Game/Online/Matchmaking/MatchmakingRoomInvitationParams.cs @@ -0,0 +1,16 @@ +// 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 MessagePack; + +namespace osu.Game.Online.Matchmaking +{ + [MessagePackObject] + [Serializable] + public class MatchmakingRoomInvitationParams + { + [Key(0)] + public MatchmakingPoolType Type { get; set; } + } +} diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 62228e60bd29..b9b4419cbb7c 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -123,7 +123,7 @@ public abstract partial class MultiplayerClient : Component, IMultiplayerClient, public event Action? MatchmakingQueueJoined; public event Action? MatchmakingQueueLeft; - public event Action? MatchmakingRoomInvited; + public event Action? MatchmakingRoomInvited; public event Action? MatchmakingRoomReady; public event Action? MatchmakingLobbyStatusChanged; public event Action? MatchmakingQueueStatusChanged; @@ -1085,7 +1085,13 @@ Task IMatchmakingClient.MatchmakingQueueLeft() Task IMatchmakingClient.MatchmakingRoomInvited() { - Scheduler.Add(() => MatchmakingRoomInvited?.Invoke()); + // Compatibility with older servers. + return ((IMatchmakingClient)this).MatchmakingRoomInvitedWithParams(new MatchmakingRoomInvitationParams { Type = MatchmakingPoolType.QuickPlay }); + } + + Task IMatchmakingClient.MatchmakingRoomInvitedWithParams(MatchmakingRoomInvitationParams invitation) + { + Scheduler.Add(() => MatchmakingRoomInvited?.Invoke(invitation)); return Task.CompletedTask; } diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index b36e2cf17766..b23a0b3db212 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -76,6 +76,7 @@ private void load(IAPIProvider api) connection.On(nameof(IMatchmakingClient.MatchmakingQueueJoined), ((IMatchmakingClient)this).MatchmakingQueueJoined); connection.On(nameof(IMatchmakingClient.MatchmakingQueueLeft), ((IMatchmakingClient)this).MatchmakingQueueLeft); connection.On(nameof(IMatchmakingClient.MatchmakingRoomInvited), ((IMatchmakingClient)this).MatchmakingRoomInvited); + connection.On(nameof(IMatchmakingClient.MatchmakingRoomInvitedWithParams), ((IMatchmakingClient)this).MatchmakingRoomInvitedWithParams); connection.On(nameof(IMatchmakingClient.MatchmakingRoomReady), ((IMatchmakingClient)this).MatchmakingRoomReady); connection.On(nameof(IMatchmakingClient.MatchmakingLobbyStatusChanged), ((IMatchmakingClient)this).MatchmakingLobbyStatusChanged); connection.On(nameof(IMatchmakingClient.MatchmakingQueueStatusChanged), ((IMatchmakingClient)this).MatchmakingQueueStatusChanged); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs index 6d23dd4eb114..9456e56bf978 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Screens; using osu.Game.Graphics; +using osu.Game.Online.Matchmaking; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Overlays; @@ -94,15 +95,12 @@ private void onMatchmakingQueueLeft() => Scheduler.Add(() => closeNotifications(); }); - private void onMatchmakingRoomInvited() => Scheduler.Add(() => + private void onMatchmakingRoomInvited(MatchmakingRoomInvitationParams invitation) => Scheduler.Add(() => { CurrentState.Value = ScreenQueue.MatchmakingScreenState.PendingAccept; - if (backgroundNotification != null) - { - backgroundNotification.State = ProgressNotificationState.Completed; - backgroundNotification = null; - } + backgroundNotification?.Complete(invitation); + backgroundNotification = null; }); private void onMatchmakingRoomReady(long roomId, string password) => Scheduler.Add(() => @@ -183,6 +181,17 @@ private void load(AudioManager audio) return false; }; + CancelRequested = () => + { + client.MatchmakingLeaveQueue().FireAndForget(); + return true; + }; + + matchFoundSample = audio.Samples.Get(@"Multiplayer/Matchmaking/match-found"); + } + + public void Complete(MatchmakingRoomInvitationParams invitation) + { CompletionClickAction = () => { client.MatchmakingAcceptInvitation().FireAndForget(); @@ -194,13 +203,7 @@ private void load(AudioManager audio) return true; }; - CancelRequested = () => - { - client.MatchmakingLeaveQueue().FireAndForget(); - return true; - }; - - matchFoundSample = audio.Samples.Get(@"Multiplayer/Matchmaking/match-found"); + State = ProgressNotificationState.Completed; } protected override Notification CreateCompletionNotification() From 105342e5bfd32f462c4dc06201db244f1f6fc0d1 Mon Sep 17 00:00:00 2001 From: Krzysztof Gutkowski Date: Fri, 27 Feb 2026 20:22:58 +0100 Subject: [PATCH 716/836] Migrate sheared overlay tests to `ScreenTestScene` (#36736) Part of the screen footer refactor. Once footer content is being managed by `OsuScreen`, the current tests which simply create the tested overlay and `ScreenFooter` in a container will no longer work. This PR refactors them to use `ScreenTestScene` with the setup being creating a dedicated testing `OsuScreen` which does the bare minimum to create the tested overlay and necessary components (eg. `FooterButtonFreeModsV2` for `TestSceneFreeModsOverlay`). Most of the changes here can be described as `%s/<...>Overlay/screen.Overlay/g`, with some minor touchups as necessary, given that we're now testing a more complete flow which checks more things that were previously not handled by the tests. ## [Move footer to front in ScreenTestScene](https://github.com/ppy/osu/commit/f8740e0403b3c0badd60d394c737f2aa912a9ed6) Self-explanatory. Without it the footer would show below the actual overlay, breaking tests depending on manual input. For the sake of tests not breaking in CI, both #36718 and this have this included - would prefer the former to be merged first since it was already reviewed there. ## `TestSceneModSelectOverlay` There were a few tests (`TestColumnHidingOnIsValidChange`, `TestColumnHidingOnTextFilterChange`, and `TestHidingOverlayClearsTextSearch`) that would create a custom overlay instance instead of the globally provided one. I've tested both and the tests run fine with the default overlay, so they're now using that instead. ## `TestSceneFreeModSelectOverlay` Updated to use footer v2. --------- Co-authored-by: Dean Herbert --- .../TestSceneBeatmapSubmissionOverlay.cs | 77 +++++--- .../TestSceneFreeModSelectOverlay.cs | 132 +++++++++---- .../TestSceneFirstRunSetupOverlay.cs | 77 +++++--- .../TestSceneModSelectOverlay.cs | 181 +++++++++++------- osu.Game/Tests/Visual/ScreenTestScene.cs | 21 +- 5 files changed, 306 insertions(+), 182 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneBeatmapSubmissionOverlay.cs b/osu.Game.Tests/Visual/Editing/TestSceneBeatmapSubmissionOverlay.cs index f83d424d566f..a47fb50c3cbd 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneBeatmapSubmissionOverlay.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneBeatmapSubmissionOverlay.cs @@ -1,45 +1,64 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; +using System; +using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Testing; +using osu.Game.Overlays; +using osu.Game.Screens; using osu.Game.Screens.Edit.Submission; -using osu.Game.Screens.Footer; namespace osu.Game.Tests.Visual.Editing { - public partial class TestSceneBeatmapSubmissionOverlay : OsuTestScene + public partial class TestSceneBeatmapSubmissionOverlay : ScreenTestScene { - private ScreenFooter footer = null!; + private TestBeatmapSubmissionOverlayScreen screen = null!; + + [Cached] + private readonly BeatmapSubmissionSettings beatmapSubmissionSettings = new BeatmapSubmissionSettings(); [SetUpSteps] - public void SetUpSteps() + public override void SetUpSteps() { - AddStep("add overlay", () => + base.SetUpSteps(); + + AddStep("push screen", () => LoadScreen(screen = new TestBeatmapSubmissionOverlayScreen())); + AddUntilStep("wait until screen is loaded", () => screen.IsLoaded, () => Is.True); + AddStep("show overlay", () => screen.Overlay.Show()); + } + + private partial class TestBeatmapSubmissionOverlayScreen : OsuScreen + { + public override bool ShowFooter => true; + + public BeatmapSubmissionOverlay Overlay = null!; + + private IDisposable? overlayRegistration; + + [Resolved] + private IOverlayManager? overlayManager { get; set; } + + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + [BackgroundDependencyLoader] + private void load() + { + LoadComponent(Overlay = new BeatmapSubmissionOverlay()); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + overlayRegistration = overlayManager?.RegisterBlockingOverlay(Overlay); + } + + protected override void Dispose(bool isDisposing) { - var receptor = new ScreenFooter.BackReceptor(); - footer = new ScreenFooter(receptor); - - Child = new DependencyProvidingContainer - { - RelativeSizeAxes = Axes.Both, - CachedDependencies = new[] - { - (typeof(ScreenFooter), (object)footer), - (typeof(BeatmapSubmissionSettings), new BeatmapSubmissionSettings()), - }, - Children = new Drawable[] - { - receptor, - new BeatmapSubmissionOverlay - { - State = { Value = Visibility.Visible, }, - }, - footer, - } - }; - }); + base.Dispose(isDisposing); + overlayRegistration?.Dispose(); + } } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs index fd589e928ad1..b749c34db3d8 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs @@ -7,27 +7,30 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Framework.Testing; +using osu.Game.Graphics; +using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Mods; +using osu.Game.Screens; using osu.Game.Screens.Footer; using osu.Game.Screens.OnlinePlay; +using osu.Game.Screens.SelectV2; using osu.Game.Utils; using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public partial class TestSceneFreeModSelectOverlay : MultiplayerTestScene + public partial class TestSceneFreeModSelectOverlay : ScreenTestScene { - private FreeModSelectOverlay freeModSelectOverlay = null!; - private FooterButtonFreeMods footerButtonFreeMods = null!; - private ScreenFooter footer = null!; + private TestFreeModSelectOverlayScreen screen = null!; private readonly Bindable>> availableMods = new Bindable>>(); + private readonly Bindable> freeMods = new Bindable>([]); + + private FreeModSelectOverlay freeModSelectOverlay => screen.Overlay; [BackgroundDependencyLoader] private void load(OsuGameBase osuGameBase) @@ -35,6 +38,14 @@ private void load(OsuGameBase osuGameBase) availableMods.BindTo(osuGameBase.AvailableMods); } + [SetUpSteps] + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("reset selected mods", () => freeMods.Value = []); + } + [Test] public void TestFreeModSelect() { @@ -44,11 +55,6 @@ public void TestFreeModSelect() () => this.ChildrenOfType() .Where(panel => panel.IsPresent) .All(panel => panel.Mod.HasImplementation && panel.Mod.UserPlayable)); - - AddToggleStep("toggle visibility", visible => - { - freeModSelectOverlay.State.Value = visible ? Visibility.Visible : Visibility.Hidden; - }); } [Test] @@ -72,18 +78,16 @@ public void TestSelectAllButtonUpdatesStateWhenSearchTermChanged() AddAssert("select all button enabled", () => this.ChildrenOfType().Single().Enabled.Value); - AddStep("click select all button", navigateAndClick); + AddStep("click select all button", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); AddAssert("select all button disabled", () => !this.ChildrenOfType().Single().Enabled.Value); AddStep("change search term", () => freeModSelectOverlay.SearchTerm = "e"); AddAssert("select all button enabled", () => this.ChildrenOfType().Single().Enabled.Value); - - void navigateAndClick() where T : Drawable - { - InputManager.MoveMouseTo(this.ChildrenOfType().Single()); - InputManager.Click(MouseButton.Left); - } } [Test] @@ -130,16 +134,24 @@ public void TestSelectAllViaFooterButtonThenDeselectFromOverlay() createFreeModSelect(); AddAssert("overlay select all button enabled", () => this.ChildrenOfType().Single().Enabled.Value); - AddAssert("footer button displays off", () => footerButtonFreeMods.ChildrenOfType().Any(t => t.Text == "off")); + AddUntilStep( + "footer button displays no mods", + () => screen.Button.ChildrenOfType().Single().IsPresent, + () => Is.False + ); AddStep("click footer select all button", () => { - InputManager.MoveMouseTo(footerButtonFreeMods); + InputManager.MoveMouseTo(ScreenFooter.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); AddUntilStep("all mods selected", assertAllAvailableModsSelected); - AddAssert("footer button displays all", () => footerButtonFreeMods.ChildrenOfType().Any(t => t.Text == "all")); + AddUntilStep( + "footer button displays correct mod count", + () => screen.Button.ChildrenOfType().Single().ChildrenOfType().Single().Text.ToString(), + () => Is.EqualTo($"{freeMods.Value.Count} MODS") + ); AddStep("click deselect all button", () => { @@ -147,32 +159,21 @@ public void TestSelectAllViaFooterButtonThenDeselectFromOverlay() InputManager.Click(MouseButton.Left); }); AddUntilStep("all mods deselected", () => !freeModSelectOverlay.SelectedMods.Value.Any()); - AddAssert("footer button displays off", () => footerButtonFreeMods.ChildrenOfType().Any(t => t.Text == "off")); + AddUntilStep( + "footer button displays no mods", + () => screen.Button.ChildrenOfType().Single().IsPresent, + () => Is.False + ); } private void createFreeModSelect() { - AddStep("create free mod select screen", () => Child = new DependencyProvidingContainer + AddStep("create free mod select screen", () => LoadScreen(screen = new TestFreeModSelectOverlayScreen { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - freeModSelectOverlay = new FreeModSelectOverlay - { - State = { Value = Visibility.Visible } - }, - footerButtonFreeMods = new FooterButtonFreeMods(freeModSelectOverlay) - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Y = -ScreenFooter.HEIGHT, - FreeMods = { BindTarget = freeModSelectOverlay.SelectedMods }, - }, - footer = new ScreenFooter(), - }, - CachedDependencies = new (Type, object)[] { (typeof(ScreenFooter), footer) }, - }); - + FreeMods = { BindTarget = freeMods }, + })); + AddUntilStep("wait until screen is loaded", () => screen.IsLoaded, () => Is.True); + AddStep("show overlay", () => freeModSelectOverlay.Show()); AddUntilStep("all column content loaded", () => freeModSelectOverlay.ChildrenOfType().Any() && freeModSelectOverlay.ChildrenOfType().All(column => column.IsLoaded && column.ItemsLoaded)); @@ -197,5 +198,52 @@ private bool assertAllAvailableModsSelected() return true; } + + private partial class TestFreeModSelectOverlayScreen : OsuScreen + { + public override bool ShowFooter => true; + + public FreeModSelectOverlay Overlay = null!; + private IDisposable? overlayRegistration; + + public FooterButtonFreeModsV2 Button = null!; + + public readonly Bindable> FreeMods = new Bindable>([]); + + [Resolved] + private IOverlayManager? overlayManager { get; set; } + + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + [BackgroundDependencyLoader] + private void load() + { + LoadComponent(Overlay = new FreeModSelectOverlay + { + SelectedMods = { BindTarget = FreeMods } + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + overlayRegistration = overlayManager?.RegisterBlockingOverlay(Overlay); + } + + public override IReadOnlyList CreateFooterButtons() => + [ + Button = new FooterButtonFreeModsV2(Overlay) + { + FreeMods = { BindTarget = FreeMods }, + }, + ]; + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + overlayRegistration?.Dispose(); + } + } } } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs index dc51e5516ae2..c0e7a1761dfa 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs @@ -12,7 +12,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Framework.Testing; @@ -23,17 +22,16 @@ using osu.Game.Overlays.FirstRunSetup; using osu.Game.Overlays.Notifications; using osu.Game.Screens; -using osu.Game.Screens.Footer; using osu.Game.Tests.Beatmaps; using osuTK; using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public partial class TestSceneFirstRunSetupOverlay : OsuManualInputManagerTestScene + public partial class TestSceneFirstRunSetupOverlay : ScreenTestScene { - private FirstRunSetupOverlay overlay; - private ScreenFooter footer; + private TestFirstRunSetupOverlayScreen screen = null!; + private FirstRunSetupOverlay overlay => screen.Overlay; private readonly Mock performer = new Mock(); @@ -53,8 +51,10 @@ private void load() } [SetUpSteps] - public void SetUpSteps() + public override void SetUpSteps() { + base.SetUpSteps(); + AddStep("setup dependencies", () => { performer.Reset(); @@ -67,16 +67,16 @@ public void SetUpSteps() .Callback((Notification n) => lastNotification = n); }); - createOverlay(); + AddStep("reset first run", () => LocalConfig.SetValue(OsuSetting.ShowFirstRunSetup, true)); - AddStep("show overlay", () => overlay.Show()); + createScreen(); } [Test] public void TestBasic() { AddAssert("overlay visible", () => overlay.State.Value == Visibility.Visible); - AddAssert("footer visible", () => footer.State.Value == Visibility.Visible); + AddAssert("footer visible", () => ScreenFooter.State.Value == Visibility.Visible); } [Test] @@ -92,7 +92,8 @@ public void TestDoesntOpenOnSecondRun() AddAssert("first run false", () => !LocalConfig.Get(OsuSetting.ShowFirstRunSetup)); - createOverlay(); + AddStep("exit screen", () => Stack.Exit()); + createScreen(); AddWaitStep("wait some", 5); @@ -146,7 +147,7 @@ public void TestBackButton(bool keyboard) if (keyboard) InputManager.Key(Key.Escape); else - footer.BackButton.TriggerClick(); + ScreenFooter.BackButton.TriggerClick(); } return overlay.CurrentScreen is ScreenWelcome; @@ -161,7 +162,7 @@ public void TestBackButton(bool keyboard) } else { - AddStep("press back button", () => footer.BackButton.TriggerClick()); + AddStep("press back button", () => ScreenFooter.BackButton.TriggerClick()); AddAssert("overlay dismissed", () => overlay.State.Value == Visibility.Hidden); } } @@ -204,25 +205,45 @@ public void TestResumeViaNotification() AddAssert("is resumed", () => overlay.CurrentScreen is ScreenUIScale); } - private void createOverlay() + private void createScreen() { - AddStep("add overlay", () => + AddStep("push screen", () => LoadScreen(screen = new TestFirstRunSetupOverlayScreen())); + AddUntilStep("wait until screen is loaded", () => screen.IsLoaded, () => Is.True); + } + + private partial class TestFirstRunSetupOverlayScreen : OsuScreen + { + public override bool ShowFooter => true; + + public FirstRunSetupOverlay Overlay = null!; + + [CanBeNull] + private IDisposable overlayRegistration; + + [CanBeNull] + [Resolved] + private IOverlayManager overlayManager { get; set; } + + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + [BackgroundDependencyLoader] + private void load() { - var receptor = new ScreenFooter.BackReceptor(); - footer = new ScreenFooter(receptor); + LoadComponent(Overlay = new FirstRunSetupOverlay()); + } - Child = new DependencyProvidingContainer - { - RelativeSizeAxes = Axes.Both, - CachedDependencies = new[] { (typeof(ScreenFooter), (object)footer) }, - Children = new Drawable[] - { - receptor, - overlay = new FirstRunSetupOverlay(), - footer, - } - }; - }); + protected override void LoadComplete() + { + base.LoadComplete(); + overlayRegistration = overlayManager?.RegisterBlockingOverlay(Overlay); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + overlayRegistration?.Dispose(); + } } // interface mocks break hot reload, mocking this stub implementation instead works around it. diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 6127be481c1f..d0778172d933 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Localisation; +using osu.Framework.Screens; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Configuration; @@ -25,6 +26,7 @@ using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Taiko.Mods; +using osu.Game.Screens; using osu.Game.Screens.Footer; using osu.Game.Tests.Mods; using osuTK; @@ -33,17 +35,19 @@ namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public partial class TestSceneModSelectOverlay : OsuManualInputManagerTestScene + public partial class TestSceneModSelectOverlay : ScreenTestScene { protected override bool UseFreshStoragePerRun => true; private RulesetStore rulesetStore = null!; - private TestModSelectOverlay modSelectOverlay = null!; + private TestModSelectOverlayScreen screen = null!; [Resolved] private OsuConfigManager configManager { get; set; } = null!; + private ModSelectOverlay modSelectOverlay => screen.Overlay; + [BackgroundDependencyLoader] private void load() { @@ -52,9 +56,10 @@ private void load() } [SetUpSteps] - public void SetUpSteps() + public override void SetUpSteps() { - AddStep("clear contents", Clear); + base.SetUpSteps(); + AddStep("reset ruleset", () => Ruleset.Value = rulesetStore.GetRuleset(0)); AddStep("reset mods", () => SelectedMods.SetDefault()); AddStep("reset config", () => configManager.SetValue(OsuSetting.ModSelectTextSearchStartsActive, true)); @@ -97,29 +102,8 @@ public void SetUpSteps() private void createScreen() { - AddStep("create screen", () => - { - var receptor = new ScreenFooter.BackReceptor(); - var footer = new ScreenFooter(receptor); - - Child = new DependencyProvidingContainer - { - RelativeSizeAxes = Axes.Both, - CachedDependencies = new[] { (typeof(ScreenFooter), (object)footer) }, - Children = new Drawable[] - { - receptor, - modSelectOverlay = new TestModSelectOverlay - { - RelativeSizeAxes = Axes.Both, - State = { Value = Visibility.Visible }, - Beatmap = { Value = Beatmap.Value }, - SelectedMods = { BindTarget = SelectedMods }, - }, - footer, - } - }; - }); + AddStep("create screen", () => LoadScreen(screen = new TestModSelectOverlayScreen { SelectedMods = { BindTarget = SelectedMods } })); + AddUntilStep("wait until screen is loaded", () => screen.IsLoaded, () => Is.True); waitForColumnLoad(); } @@ -306,29 +290,30 @@ public void TestDismissCustomisationWhenHidingOverlay() [Test] public void TestSettingsNotCrossPolluting() { + TestScreenWithTwoOverlays screenWithTwoOverlays = null!; Bindable> selectedMods2 = null!; - ModSelectOverlay modSelectOverlay2 = null!; - createScreen(); - AddStep("select difficulty adjust via panel", () => getPanelForMod(typeof(OsuModDifficultyAdjust)).TriggerClick()); + AddStep("push screen", () => + { + selectedMods2 = new Bindable>(new Mod[] { new OsuModDifficultyAdjust() }); - AddStep("set setting", () => modSelectOverlay.ChildrenOfType>().First().Current.Value = 8); + LoadScreen(screen = screenWithTwoOverlays = new TestScreenWithTwoOverlays + { + SelectedMods = { BindTarget = SelectedMods }, + SelectedMods2 = { BindTarget = selectedMods2 }, + }); + }); + AddStep("wait until screen is loaded", () => screenWithTwoOverlays.IsCurrentScreen()); + waitForColumnLoad(); - AddAssert("ensure setting is propagated", () => SelectedMods.Value.OfType().Single().CircleSize.Value == 8); + AddStep("select difficulty adjust via panel", () => getPanelForMod(typeof(OsuModDifficultyAdjust)).TriggerClick()); - AddStep("create second bindable", () => selectedMods2 = new Bindable>(new Mod[] { new OsuModDifficultyAdjust() })); + AddStep("set setting", () => screenWithTwoOverlays.Overlay.ChildrenOfType>().First().Current.Value = 8); - AddStep("create second overlay", () => - { - Add(modSelectOverlay2 = new UserModSelectOverlay().With(d => - { - d.Origin = Anchor.TopCentre; - d.Anchor = Anchor.TopCentre; - d.SelectedMods.BindTarget = selectedMods2; - })); - }); + AddAssert("ensure setting is propagated", () => SelectedMods.Value.OfType().Single().CircleSize.Value == 8); - AddStep("show", () => modSelectOverlay2.Show()); + AddStep("hide first overlay", () => screenWithTwoOverlays.Overlay.Hide()); + AddStep("show second overlay", () => screenWithTwoOverlays.SecondOverlay.Show()); AddAssert("ensure first is unchanged", () => SelectedMods.Value.OfType().Single().CircleSize.Value == 8); AddAssert("ensure second is default", () => selectedMods2.Value.OfType().Single().CircleSize.Value == null); @@ -481,6 +466,7 @@ public void TestSettingsAreRetainedOnReload() AddStep("set customized mod externally", () => SelectedMods.Value = new[] { new OsuModDoubleTime { SpeedChange = { Value = 1.01 } } }); AddAssert("setting remains", () => (SelectedMods.Value.SingleOrDefault() as OsuModDoubleTime)?.SpeedChange.Value == 1.01); + AddStep("exit screen", () => Stack.Exit()); createScreen(); AddAssert("setting remains", () => (SelectedMods.Value.SingleOrDefault() as OsuModDoubleTime)?.SpeedChange.Value == 1.01); } @@ -797,16 +783,11 @@ public void TestCloseViaToggleModSelectionBinding() [Test] public void TestColumnHidingOnIsValidChange() { - AddStep("create screen", () => Child = modSelectOverlay = new TestModSelectOverlay - { - RelativeSizeAxes = Axes.Both, - State = { Value = Visibility.Visible }, - SelectedMods = { BindTarget = SelectedMods }, - IsValidMod = mod => mod.Type == ModType.DifficultyIncrease || mod.Type == ModType.Conversion - }); - waitForColumnLoad(); + createScreen(); changeRuleset(0); + AddStep("set filter for 2 columns", () => modSelectOverlay.IsValidMod = mod => mod.Type is ModType.DifficultyIncrease or ModType.Conversion); + AddAssert("two columns visible", () => this.ChildrenOfType().Count(col => col.IsPresent) == 2); AddStep("unset filter", () => modSelectOverlay.IsValidMod = _ => true); @@ -816,9 +797,7 @@ public void TestColumnHidingOnIsValidChange() AddAssert("no columns visible", () => this.ChildrenOfType().All(col => !col.IsPresent)); AddStep("hide", () => modSelectOverlay.Hide()); - AddStep("set filter for 3 columns", () => modSelectOverlay.IsValidMod = mod => mod.Type == ModType.DifficultyReduction - || mod.Type == ModType.Automation - || mod.Type == ModType.Conversion); + AddStep("set filter for 3 columns", () => modSelectOverlay.IsValidMod = mod => mod.Type is ModType.DifficultyReduction or ModType.Automation or ModType.Conversion); AddStep("show", () => modSelectOverlay.Show()); AddUntilStep("3 columns visible", () => this.ChildrenOfType().Count(col => col.IsPresent) == 3); @@ -830,13 +809,7 @@ public void TestColumnHidingOnIsValidChange() [Test] public void TestColumnHidingOnTextFilterChange() { - AddStep("create screen", () => Child = modSelectOverlay = new TestModSelectOverlay - { - RelativeSizeAxes = Axes.Both, - State = { Value = Visibility.Visible }, - SelectedMods = { BindTarget = SelectedMods } - }); - waitForColumnLoad(); + createScreen(); changeRuleset(0); AddAssert("all columns visible", () => this.ChildrenOfType().All(col => col.IsPresent)); @@ -854,13 +827,7 @@ public void TestColumnHidingOnTextFilterChange() [Test] public void TestHidingOverlayClearsTextSearch() { - AddStep("create screen", () => Child = modSelectOverlay = new TestModSelectOverlay - { - RelativeSizeAxes = Axes.Both, - State = { Value = Visibility.Visible }, - SelectedMods = { BindTarget = SelectedMods } - }); - waitForColumnLoad(); + createScreen(); changeRuleset(0); AddAssert("all columns visible", () => this.ChildrenOfType().All(col => col.IsPresent)); @@ -1019,8 +986,8 @@ public void TestActiveStatesRefreshedOnPanelsCreated() { selectedMods = new Bindable>([]); - modSelectOverlay.SelectedMods.UnbindFrom(SelectedMods); - modSelectOverlay.SelectedMods.BindTo(selectedMods); + screen.SelectedMods.UnbindFrom(SelectedMods); + screen.SelectedMods.BindTo(selectedMods); }); AddStep("activate PF", () => selectedMods.Value = [new OsuModPerfect()]); @@ -1066,11 +1033,79 @@ protected override void Dispose(bool isDisposing) rulesetStore.Dispose(); } - private partial class TestModSelectOverlay : UserModSelectOverlay + private partial class TestModSelectOverlayScreen : OsuScreen + { + public readonly Bindable> SelectedMods = new Bindable>(); + + public override bool ShowFooter => true; + + public ModSelectOverlay Overlay = null!; + + private IDisposable? firstOverlayRegistration; + + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + [Resolved] + protected IOverlayManager? OverlayManager { get; private set; } + + [BackgroundDependencyLoader] + private void load() + { + LoadComponent(Overlay = new UserModSelectOverlay + { + RelativeSizeAxes = Axes.Both, + State = { Value = Visibility.Visible }, + Beatmap = { Value = Beatmap.Value }, + SelectedMods = { BindTarget = SelectedMods }, + ShowPresets = true, + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + firstOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(Overlay); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + firstOverlayRegistration?.Dispose(); + } + } + + private partial class TestScreenWithTwoOverlays : TestModSelectOverlayScreen { - public TestModSelectOverlay() + public readonly Bindable> SelectedMods2 = new Bindable>([]); + + public ModSelectOverlay SecondOverlay = null!; + + private IDisposable? secondOverlayRegistration; + + [BackgroundDependencyLoader] + private void load() + { + LoadComponent(SecondOverlay = new UserModSelectOverlay + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + SelectedMods = { BindTarget = SelectedMods2 }, + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + secondOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(SecondOverlay); + } + + protected override void Dispose(bool isDisposing) { - ShowPresets = true; + base.Dispose(isDisposing); + secondOverlayRegistration?.Dispose(); } } diff --git a/osu.Game/Tests/Visual/ScreenTestScene.cs b/osu.Game/Tests/Visual/ScreenTestScene.cs index 7d28ee1d1d55..e1775cf5a1df 100644 --- a/osu.Game/Tests/Visual/ScreenTestScene.cs +++ b/osu.Game/Tests/Visual/ScreenTestScene.cs @@ -43,28 +43,29 @@ protected ScreenTestScene() base.Content.AddRange(new Drawable[] { backReceptor = new ScreenFooter.BackReceptor(), - Stack = new OsuScreenStack - { - Name = nameof(ScreenTestScene), - RelativeSizeAxes = Axes.Both - }, new PopoverContainer { RelativeSizeAxes = Axes.Both, Children = new Drawable[] { + Stack = new OsuScreenStack + { + Name = nameof(ScreenTestScene), + RelativeSizeAxes = Axes.Both + }, + // TODO: is this ever used? it probably shouldn't be. content = new Container { RelativeSizeAxes = Axes.Both }, + overlayContent = new Container + { + RelativeSizeAxes = Axes.Both, + Child = DialogOverlay = new DialogOverlay() + }, screenStackFooter = new ScreenStackFooter(Stack, backReceptor) { BackButtonPressed = () => Stack.Exit() } } }, - overlayContent = new Container - { - RelativeSizeAxes = Axes.Both, - Child = DialogOverlay = new DialogOverlay() - }, }); ScreenFooter = screenStackFooter.Footer; From 9c489aacf8a7227e5d18b40b01289ae78967b96e Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Sat, 28 Feb 2026 16:58:07 +0300 Subject: [PATCH 717/836] Use better text structure for `ScreenshotSaved` notification (#36701) reads a bit better when filename isn't in main text also added "click to view" text by analogy with `LogsExportFinished` | master | pr | |-|-| | image | image | --- osu.Game/Localisation/NotificationsStrings.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 835dfef08e14..a8dac2d25c94 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -236,9 +236,11 @@ public static class NotificationsStrings public static LocalisableString ElevatedPrivileges(LocalisableString user) => new TranslatableString(getKey(@"elevated_privileges"), @"Running osu! as {0} does not improve performance, may break integrations and poses a security risk. Please run the game as a normal user.", user); /// - /// "Screenshot {0} saved!" + /// "Screenshot saved! Click to view. + /// {0}" /// - public static LocalisableString ScreenshotSaved(string filename) => new TranslatableString(getKey(@"screenshot_saved"), @"Screenshot {0} saved!", filename); + public static LocalisableString ScreenshotSaved(string filename) => new TranslatableString(getKey(@"screenshot_saved"), @"Screenshot saved! Click to view. +{0}", filename); /// /// "The multiplayer server will be right back..." From b88cba082978dff3766cd7a4bf20ed5cdff92806 Mon Sep 17 00:00:00 2001 From: Krzysztof Gutkowski Date: Sun, 1 Mar 2026 14:36:07 +0100 Subject: [PATCH 718/836] Refactor `TestSceneScreenFooter` to test entire `OsuScreen`s (#36718) Part of the `ScreenFooter` refactor, which intends to move the footer content handling to `OsuScreen`. This commit updates the `ScreenFooter` test to operate on entire `OsuScreen`s, in order to better test the entire flow of pushing a screen, and having it create and add its own content to the footer. This should be 80-90% identical to the original test case structure wise, just that instead of manually manipulating the footer with `SetButtons()`, various screens with the appropriate buttons are being moved around the screen stack. Additionally this adds some more tests handling common use cases, as well as removes `TestLoadOverlayAfterFooterIsDisplayed()`, since as far as I understand the behaviour described in it doesn't actually happen in production code. From what I can see, Screens instantiate their overlays in `load()`, and then register them in `LoadComplete()`. There seems to be no case where a `ShearedOverlayContainer` is created in the middle of a screen's lifecycle. --- .../TestSceneScreenFooterNavigation.cs | 234 +++++++++-- .../SongSelectV2/TestSceneScreenFooter.cs | 301 --------------- .../UserInterface/TestSceneScreenFooter.cs | 365 ++++++++++++++++++ osu.Game/OsuGame.cs | 1 + osu.Game/Tests/Visual/ScreenTestScene.cs | 4 +- 5 files changed, 572 insertions(+), 333 deletions(-) delete mode 100644 osu.Game.Tests/Visual/SongSelectV2/TestSceneScreenFooter.cs create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenFooterNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenFooterNavigation.cs index 0b17b66dec8f..27c7528efa2a 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenFooterNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenFooterNavigation.cs @@ -8,9 +8,13 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; using osu.Framework.Screens; using osu.Framework.Testing; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; +using osu.Game.Overlays.Mods; using osu.Game.Screens; using osu.Game.Screens.Footer; @@ -23,10 +27,13 @@ public partial class TestSceneScreenFooterNavigation : OsuGameTestScene [Test] public void TestFooterButtonsOnScreenTransitions() { - PushAndConfirm(() => new TestScreenOne()); + PushAndConfirm(() => new TestScreen + { + CreateButtons = () => [new ScreenFooterButton { Text = "Button One" }] + }); AddUntilStep("button one shown", () => screenFooter.ChildrenOfType().First().Text.ToString(), () => Is.EqualTo("Button One")); - PushAndConfirm(() => new TestScreenTwo()); + PushAndConfirm(() => new TestScreen { CreateButtons = () => [new ScreenFooterButton { Text = "Button Two" }] }); AddUntilStep("button two shown", () => screenFooter.ChildrenOfType().First().Text.ToString(), () => Is.EqualTo("Button Two")); AddStep("exit screen", () => Game.ScreenStack.Exit()); @@ -40,7 +47,7 @@ public void TestFooterHidesOldBackButton() AddAssert("footer hidden", () => screenFooter.State.Value, () => Is.EqualTo(Visibility.Hidden)); AddAssert("old back button shown", () => Game.BackButton.State.Value, () => Is.EqualTo(Visibility.Visible)); - PushAndConfirm(() => new TestScreen(true)); + PushAndConfirm(() => new TestScreen()); AddAssert("footer shown", () => screenFooter.State.Value, () => Is.EqualTo(Visibility.Visible)); AddAssert("old back button hidden", () => Game.BackButton.State.Value, () => Is.EqualTo(Visibility.Hidden)); @@ -69,10 +76,16 @@ public void TestPushAndExitSubScreens() AddAssert("footer hidden", () => screenFooter.State.Value, () => Is.EqualTo(Visibility.Hidden)); AddAssert("old back button shown", () => Game.BackButton.State.Value, () => Is.EqualTo(Visibility.Visible)); - pushSubScreenAndConfirm(() => screen, () => new TestScreenOne()); + pushSubScreenAndConfirm(() => screen, () => new TestScreen + { + CreateButtons = () => [new ScreenFooterButton { Text = "Button One" }] + }); AddUntilStep("button one shown", () => screenFooter.ChildrenOfType().First().Text.ToString(), () => Is.EqualTo("Button One")); - pushSubScreenAndConfirm(() => screen, () => new TestScreenTwo()); + pushSubScreenAndConfirm(() => screen, () => new TestScreen + { + CreateButtons = () => [new ScreenFooterButton { Text = "Button Two" }] + }); AddUntilStep("button two shown", () => screenFooter.ChildrenOfType().First().Text.ToString(), () => Is.EqualTo("Button Two")); AddStep("exit sub screen", () => screen.ExitSubScreen()); @@ -92,10 +105,16 @@ public void TestPushParentScreenDuringSubScreen() TestScreenWithSubScreen screen = null!; PushAndConfirm(() => screen = new TestScreenWithSubScreen()); - pushSubScreenAndConfirm(() => screen, () => new TestScreenOne()); + pushSubScreenAndConfirm(() => screen, () => new TestScreen + { + CreateButtons = () => [new ScreenFooterButton { Text = "Button One" }] + }); AddUntilStep("button one shown", () => screenFooter.ChildrenOfType().First().Text.ToString(), () => Is.EqualTo("Button One")); - PushAndConfirm(() => new TestScreenTwo()); + PushAndConfirm(() => new TestScreen + { + CreateButtons = () => [new ScreenFooterButton { Text = "Button Two" }] + }); AddUntilStep("button two shown", () => screenFooter.ChildrenOfType().First().Text.ToString(), () => Is.EqualTo("Button Two")); AddStep("exit parent screen", () => Game.ScreenStack.Exit()); @@ -111,14 +130,23 @@ public void TestPushSubScreenWhileNotCurrent() TestScreenWithSubScreen screen = null!; PushAndConfirm(() => screen = new TestScreenWithSubScreen()); - pushSubScreenAndConfirm(() => screen, () => new TestScreenOne()); + pushSubScreenAndConfirm(() => screen, () => new TestScreen + { + CreateButtons = () => [new ScreenFooterButton { Text = "Button One" }] + }); AddUntilStep("button one shown", () => screenFooter.ChildrenOfType().First().Text.ToString(), () => Is.EqualTo("Button One")); - PushAndConfirm(() => new TestScreenOne()); + PushAndConfirm(() => new TestScreen + { + CreateButtons = () => [new ScreenFooterButton { Text = "Button One" }] + }); AddUntilStep("button one shown", () => screenFooter.ChildrenOfType().First().Text.ToString(), () => Is.EqualTo("Button One")); // Can't use the helper method because the screen never loads - AddStep("Push new sub screen", () => screen.PushSubScreen(new TestScreenTwo())); + AddStep("Push new sub screen", () => screen.PushSubScreen(new TestScreen + { + CreateButtons = () => [new ScreenFooterButton { Text = "Button Two" }] + })); AddWaitStep("wait for potential screen load", 5); AddUntilStep("button one still shown", () => screenFooter.ChildrenOfType().First().Text.ToString(), () => Is.EqualTo("Button One")); @@ -126,6 +154,83 @@ public void TestPushSubScreenWhileNotCurrent() AddUntilStep("button two shown", () => screenFooter.ChildrenOfType().First().Text.ToString(), () => Is.EqualTo("Button Two")); } + /// + /// Tests clicking the back button while an overlay is open. + /// + [Test] + public void TestBackButtonWhenOverlayOpen() + { + TestScreen screen = null!; + + PushAndConfirm(() => + { + ShearedOverlayContainer overlay = new TestShearedOverlayContainer(); + + return screen = new TestScreen + { + Overlay = overlay, + CreateButtons = () => + [ + new ScreenFooterButton(overlay) + { + AccentColour = Dependencies.Get().Orange1, + Icon = FontAwesome.Solid.Toolbox, + Text = "One", + }, + new ScreenFooterButton { Text = "Two", Action = () => { } }, + new ScreenFooterButton { Text = "Three", Action = () => { } }, + ], + }; + }); + + AddStep("show overlay", () => screen.Overlay.Show()); + AddAssert("overlay shown", () => screen.Overlay.State.Value, () => Is.EqualTo(Visibility.Visible)); + + AddStep("press back", () => screenFooter.ChildrenOfType().Single().TriggerClick()); + AddAssert("overlay hidden", () => screen.Overlay.State.Value, () => Is.EqualTo(Visibility.Hidden)); + AddAssert("screen still shown", () => screen.IsCurrentScreen(), () => Is.True); + } + + /// + /// Tests clicking the back button on an overlay with `BackButtonPressed` being overridden. + /// + [Test] + public void TestBackButtonWithCustomBackButtonPressed() + { + TestScreen screen = null!; + TestShearedOverlayContainer overlay = null!; + + PushAndConfirm(() => + { + return screen = new TestScreen + { + Overlay = overlay = new TestShearedOverlayContainer(), + CreateButtons = () => + [ + new ScreenFooterButton(overlay) + { + AccentColour = Dependencies.Get().Orange1, + Icon = FontAwesome.Solid.Toolbox, + Text = "One", + }, + new ScreenFooterButton { Text = "Two", Action = () => { } }, + new ScreenFooterButton { Text = "Three", Action = () => { } }, + ], + }; + }); + + AddStep("show overlay", () => screen.Overlay.Show()); + AddAssert("overlay shown", () => screen.Overlay.State.Value, () => Is.EqualTo(Visibility.Visible)); + AddStep("set block count", () => overlay.BackButtonCount = 1); + + AddStep("press back", () => screenFooter.ChildrenOfType().Single().TriggerClick()); + AddAssert("overlay still shown", () => screen.Overlay.State.Value, () => Is.EqualTo(Visibility.Visible)); + + AddStep("press back again", () => screenFooter.ChildrenOfType().Single().TriggerClick()); + AddAssert("overlay hidden", () => screen.Overlay.State.Value, () => Is.EqualTo(Visibility.Hidden)); + AddAssert("screen still shown", () => screen.IsCurrentScreen(), () => Is.True); + } + private void pushSubScreenAndConfirm(Func target, Func newScreen) { Screen screen = null!; @@ -142,39 +247,45 @@ private void pushSubScreenAndConfirm(Func target, Func< && (previousScreen == null || previousScreen.GetChildScreen() == screen)); } - private partial class TestScreenOne : OsuScreen + private partial class TestScreen : OsuScreen { - public override bool ShowFooter => true; + public override bool ShowFooter { get; } - [Cached] - private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + public Func> CreateButtons = Array.Empty; - public override IReadOnlyList CreateFooterButtons() => new[] - { - new ScreenFooterButton { Text = "Button One" }, - }; - } + public ShearedOverlayContainer Overlay = new TestShearedOverlayContainer(); - private partial class TestScreenTwo : OsuScreen - { - public override bool ShowFooter => true; + private IDisposable? overlayRegistration; [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); - public override IReadOnlyList CreateFooterButtons() => new[] + [Resolved] + private IOverlayManager? overlayManager { get; set; } + + public TestScreen(bool showFooter = true) { - new ScreenFooterButton { Text = "Button Two" }, - }; - } + ShowFooter = showFooter; + } - private partial class TestScreen : OsuScreen - { - public override bool ShowFooter { get; } + [BackgroundDependencyLoader] + private void load() + { + LoadComponent(Overlay); + } - public TestScreen(bool footer) + protected override void LoadComplete() { - ShowFooter = footer; + base.LoadComplete(); + overlayRegistration = overlayManager?.RegisterBlockingOverlay(Overlay); + } + + public override IReadOnlyList CreateFooterButtons() => CreateButtons.Invoke(); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + overlayRegistration?.Dispose(); } } @@ -196,5 +307,66 @@ public TestScreenWithSubScreen() public void ExitSubScreen() => SubScreenStack.Exit(); } + + private partial class TestShearedOverlayContainer : ShearedOverlayContainer + { + public TestShearedOverlayContainer() + : base(OverlayColourScheme.Orange) + { + } + + [BackgroundDependencyLoader] + private void load() + { + Header.Title = "Test overlay"; + Header.Description = "An overlay that is made purely for testing purposes."; + } + + public int BackButtonCount; + + public override bool OnBackButton() + { + if (BackButtonCount > 0) + { + BackButtonCount--; + return true; + } + + return false; + } + + public override VisibilityContainer CreateFooterContent() => new TestFooterContent(); + + public partial class TestFooterContent : VisibilityContainer + { + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Children = new[] + { + new ShearedButton(200) { Text = "Action #1", Action = () => { } }, + new ShearedButton(140) { Text = "Action #2", Action = () => { } }, + } + }; + } + + protected override void PopIn() + { + this.MoveToY(0, 400, Easing.OutQuint) + .FadeIn(400, Easing.OutQuint); + } + + protected override void PopOut() + { + this.MoveToY(-20f, 200, Easing.OutQuint) + .FadeOut(200, Easing.OutQuint); + } + } + } } } diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneScreenFooter.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneScreenFooter.cs deleted file mode 100644 index e247b92f528a..000000000000 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneScreenFooter.cs +++ /dev/null @@ -1,301 +0,0 @@ -// 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.Linq; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Testing; -using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; -using osu.Game.Overlays; -using osu.Game.Overlays.Mods; -using osu.Game.Screens.Footer; -using osu.Game.Screens.SelectV2; - -namespace osu.Game.Tests.Visual.SongSelectV2 -{ - public partial class TestSceneScreenFooter : OsuManualInputManagerTestScene - { - private DependencyProvidingContainer contentContainer = null!; - private ScreenFooter screenFooter = null!; - private UserModSelectOverlay modOverlay = null!; - - [SetUp] - public void SetUp() => Schedule(() => - { - screenFooter = new ScreenFooter(); - - Child = contentContainer = new DependencyProvidingContainer - { - RelativeSizeAxes = Axes.Both, - CachedDependencies = new (Type, object)[] - { - (typeof(ScreenFooter), screenFooter) - }, - Children = new Drawable[] - { - modOverlay = new UserModSelectOverlay { ShowPresets = true }, - new PopoverContainer - { - RelativeSizeAxes = Axes.Both, - Depth = float.MinValue, - Child = screenFooter, - }, - }, - }; - - screenFooter.SetButtons(new ScreenFooterButton[] - { - new FooterButtonMods(modOverlay) { Current = SelectedMods }, - new FooterButtonRandom(), - new FooterButtonOptions(), - }); - }); - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("show footer", () => screenFooter.Show()); - } - - /// - /// Transition when moving from a screen with no buttons to a screen with buttons. - /// - [Test] - public void TestButtonsIn() - { - } - - /// - /// Transition when moving from a screen with buttons to a screen with no buttons. - /// - [Test] - public void TestButtonsOut() - { - AddStep("clear buttons", () => screenFooter.SetButtons(Array.Empty())); - } - - /// - /// Transition when moving from a screen with buttons to a screen with buttons. - /// - [Test] - public void TestReplaceButtons() - { - AddStep("replace buttons", () => screenFooter.SetButtons(new[] - { - new ScreenFooterButton { Text = "One", Action = () => { } }, - new ScreenFooterButton { Text = "Two", Action = () => { } }, - new ScreenFooterButton { Text = "Three", Action = () => { } }, - })); - } - - [Test] - public void TestExternalOverlayContent() - { - TestShearedOverlayContainer externalOverlay = null!; - - AddStep("add overlay", () => contentContainer.Add(externalOverlay = new TestShearedOverlayContainer())); - AddStep("set buttons", () => screenFooter.SetButtons(new[] - { - new ScreenFooterButton(externalOverlay) - { - AccentColour = Dependencies.Get().Orange1, - Icon = FontAwesome.Solid.Toolbox, - Text = "One", - }, - new ScreenFooterButton { Text = "Two", Action = () => { } }, - new ScreenFooterButton { Text = "Three", Action = () => { } }, - })); - AddWaitStep("wait for transition", 3); - - AddStep("show overlay", () => externalOverlay.Show()); - contentDisplayed(); - AddUntilStep("other buttons hidden", () => screenFooter.ChildrenOfType().Skip(1).All(b => b.Child.Parent!.Y > 0)); - - AddStep("hide overlay", () => externalOverlay.Hide()); - contentHidden(); - AddUntilStep("other buttons returned", () => screenFooter.ChildrenOfType().Skip(1).All(b => b.ChildrenOfType().First().Y == 0)); - } - - [Test] - public void TestTemporarilyShowFooter() - { - TestShearedOverlayContainer externalOverlay = null!; - - AddStep("hide footer", () => screenFooter.Hide()); - AddStep("remove buttons", () => screenFooter.SetButtons(Array.Empty())); - - AddStep("add external overlay", () => contentContainer.Add(externalOverlay = new TestShearedOverlayContainer())); - AddStep("show external overlay", () => externalOverlay.Show()); - AddAssert("footer shown", () => screenFooter.State.Value == Visibility.Visible); - contentDisplayed(); - - AddStep("hide external overlay", () => externalOverlay.Hide()); - AddAssert("footer hidden", () => screenFooter.State.Value == Visibility.Hidden); - contentHidden(); - - AddStep("show footer", () => screenFooter.Show()); - AddAssert("content still hidden from footer", () => screenFooter.ChildrenOfType().SingleOrDefault()?.IsPresent != true); - - AddStep("show external overlay", () => externalOverlay.Show()); - AddAssert("footer still visible", () => screenFooter.State.Value == Visibility.Visible); - - AddStep("hide external overlay", () => externalOverlay.Hide()); - AddAssert("footer still visible", () => screenFooter.State.Value == Visibility.Visible); - - AddStep("hide footer", () => screenFooter.Hide()); - AddStep("show external overlay", () => externalOverlay.Show()); - } - - [Test] - public void TestBackButton() - { - TestShearedOverlayContainer externalOverlay = null!; - - AddStep("hide footer", () => screenFooter.Hide()); - AddStep("remove buttons", () => screenFooter.SetButtons(Array.Empty())); - - AddStep("add external overlay", () => contentContainer.Add(externalOverlay = new TestShearedOverlayContainer())); - AddStep("show external overlay", () => externalOverlay.Show()); - AddAssert("footer shown", () => screenFooter.State.Value == Visibility.Visible); - - AddStep("press back", () => this.ChildrenOfType().Single().TriggerClick()); - AddAssert("overlay hidden", () => externalOverlay.State.Value == Visibility.Hidden); - AddAssert("footer hidden", () => screenFooter.State.Value == Visibility.Hidden); - - AddStep("show external overlay", () => externalOverlay.Show()); - AddStep("set block count", () => externalOverlay.BackButtonCount = 1); - AddStep("press back", () => this.ChildrenOfType().Single().TriggerClick()); - AddAssert("overlay still visible", () => externalOverlay.State.Value == Visibility.Visible); - AddAssert("footer still shown", () => screenFooter.State.Value == Visibility.Visible); - AddStep("press back again", () => this.ChildrenOfType().Single().TriggerClick()); - AddAssert("overlay hidden", () => externalOverlay.State.Value == Visibility.Hidden); - AddAssert("footer hidden", () => screenFooter.State.Value == Visibility.Hidden); - } - - [Test] - public void TestLoadOverlayAfterFooterIsDisplayed() - { - TestShearedOverlayContainer externalOverlay = null!; - - AddStep("show mod overlay", () => modOverlay.Show()); - AddUntilStep("mod footer content shown", () => this.ChildrenOfType().SingleOrDefault()?.IsPresent, () => Is.True); - - AddStep("add external overlay", () => contentContainer.Add(externalOverlay = new TestShearedOverlayContainer())); - AddUntilStep("wait for load", () => externalOverlay.IsLoaded); - AddAssert("mod footer content still shown", () => this.ChildrenOfType().SingleOrDefault()?.IsPresent, () => Is.True); - AddAssert("external overlay content not shown", () => this.ChildrenOfType().SingleOrDefault()?.IsPresent, () => Is.Not.True); - - AddStep("hide mod overlay", () => modOverlay.Hide()); - AddUntilStep("mod footer content hidden", () => this.ChildrenOfType().SingleOrDefault()?.IsPresent, () => Is.Not.True); - AddAssert("external overlay content still not shown", () => this.ChildrenOfType().SingleOrDefault()?.IsPresent, () => Is.Not.True); - } - - [Test] - public void TestButtonResizedAfterFooterIsDisplayed() - { - TestShearedOverlayContainer externalOverlay = null!; - - AddStep("add overlay", () => contentContainer.Add(externalOverlay = new TestShearedOverlayContainer())); - AddStep("set buttons", () => screenFooter.SetButtons(new[] - { - new ScreenFooterButton(externalOverlay) - { - AccentColour = Dependencies.Get().Orange1, - Icon = FontAwesome.Solid.Toolbox, - Text = "One", - }, - new ScreenFooterButton { Text = "Two", Action = () => { } }, - new ScreenFooterButton { Text = "Three", Action = () => { } }, - })); - AddWaitStep("wait for transition", 3); - - AddStep("show overlay", () => externalOverlay.Show()); - contentDisplayed(); - AddUntilStep("other buttons hidden", () => screenFooter.ChildrenOfType().Skip(1).All(b => b.Child.Parent!.Y > 0)); - - AddStep("resize active button", () => this.ChildrenOfType().First().ResizeWidthTo(240, 300, Easing.OutQuint)); - AddStep("resize active button back", () => this.ChildrenOfType().First().ResizeWidthTo(116, 300, Easing.OutQuint)); - - AddStep("hide overlay", () => externalOverlay.Hide()); - contentHidden(); - AddUntilStep("other buttons returned", () => screenFooter.ChildrenOfType().Skip(1).All(b => b.ChildrenOfType().First().Y == 0)); - } - - private void contentHidden() - { - AddUntilStep("content hidden from footer", () => screenFooter.ChildrenOfType().SingleOrDefault()?.IsPresent != true); - } - - private void contentDisplayed() - { - AddUntilStep("content displayed in footer", () => screenFooter.ChildrenOfType().Single().IsPresent); - } - - private partial class TestShearedOverlayContainer : ShearedOverlayContainer - { - public TestShearedOverlayContainer() - : base(OverlayColourScheme.Orange) - { - } - - [BackgroundDependencyLoader] - private void load() - { - Header.Title = "Test overlay"; - Header.Description = "An overlay that is made purely for testing purposes."; - } - - public int BackButtonCount; - - public override bool OnBackButton() - { - if (BackButtonCount > 0) - { - BackButtonCount--; - return true; - } - - return false; - } - - public override VisibilityContainer CreateFooterContent() => new TestFooterContent(); - - public partial class TestFooterContent : VisibilityContainer - { - [BackgroundDependencyLoader] - private void load() - { - AutoSizeAxes = Axes.Both; - - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Children = new[] - { - new ShearedButton(200) { Text = "Action #1", Action = () => { } }, - new ShearedButton(140) { Text = "Action #2", Action = () => { } }, - } - }; - } - - protected override void PopIn() - { - this.MoveToY(0, 400, Easing.OutQuint) - .FadeIn(400, Easing.OutQuint); - } - - protected override void PopOut() - { - this.MoveToY(-20f, 200, Easing.OutQuint) - .FadeOut(200, Easing.OutQuint); - } - } - } - } -} diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs new file mode 100644 index 000000000000..0da7c3eb958d --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs @@ -0,0 +1,365 @@ +// 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.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Screens; +using osu.Framework.Testing; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays; +using osu.Game.Overlays.Mods; +using osu.Game.Screens; +using osu.Game.Screens.Footer; +using osu.Game.Screens.SelectV2; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public partial class TestSceneScreenFooter : ScreenTestScene + { + [Test] + public void TestButtonsIn() + { + AddStep("push empty screen", () => LoadScreen(new TestScreen())); + AddStep("push screen", () => LoadScreen(new TestScreen + { + CreateButtons = () => new[] + { + new ScreenFooterButton { Text = "Button 1", Action = () => { } }, + new ScreenFooterButton { Text = "Button 2", Action = () => { } }, + new ScreenFooterButton { Text = "Button 3", Action = () => { } }, + }, + })); + } + + [Test] + public void TestButtonsOut() + { + AddStep("push empty screen", () => LoadScreen(new TestScreen())); + AddStep("push screen", () => LoadScreen(new TestScreen + { + CreateButtons = () => new[] + { + new ScreenFooterButton { Text = "Button 1", Action = () => { } }, + new ScreenFooterButton { Text = "Button 2", Action = () => { } }, + new ScreenFooterButton { Text = "Button 3", Action = () => { } }, + }, + })); + AddStep("exit screen", () => Stack.Exit()); + } + + [Test] + public void TestReplaceButtons() + { + AddStep("push first screen", () => LoadScreen(new TestScreen + { + CreateButtons = () => new[] + { + new ScreenFooterButton { Text = "Button 1", Action = () => { } }, + new ScreenFooterButton { Text = "Button 2", Action = () => { } }, + new ScreenFooterButton { Text = "Button 3", Action = () => { } }, + }, + })); + AddStep("push second screen", () => LoadScreen(new TestScreen + { + CreateButtons = () => new[] + { + new ScreenFooterButton { Text = "Button 4", Action = () => { } }, + new ScreenFooterButton { Text = "Button 5", Action = () => { } }, + new ScreenFooterButton { Text = "Button 6", Action = () => { } }, + }, + })); + } + + [Test] + public void TestFooterVisibility() + { + TestScreen screen = null!; + TestScreen screenWithoutFooter = null!; + + AddAssert("footer hidden", () => ScreenFooter.State.Value, () => Is.EqualTo(Visibility.Hidden)); + + AddStep("push screen", () => LoadScreen(screen = new TestScreen + { + CreateButtons = () => new[] + { + new ScreenFooterButton { Text = "Button 1", Action = () => { } }, + new ScreenFooterButton { Text = "Button 2", Action = () => { } }, + new ScreenFooterButton { Text = "Button 3", Action = () => { } }, + }, + })); + AddUntilStep("wait until screen is loaded", () => screen.IsCurrentScreen(), () => Is.True); + AddAssert("footer shown", () => ScreenFooter.State.Value, () => Is.EqualTo(Visibility.Visible)); + + AddStep("push screen with no footer", () => LoadScreen(screenWithoutFooter = new TestScreen(showFooter: false))); + AddUntilStep("wait until screen is loaded", () => screenWithoutFooter.IsCurrentScreen(), () => Is.True); + AddAssert("footer hidden", () => ScreenFooter.State.Value, () => Is.EqualTo(Visibility.Hidden)); + + AddStep("exit screen", () => Stack.Exit()); + AddUntilStep("wait until screen is loaded", () => screen.IsCurrentScreen(), () => Is.True); + AddAssert("footer shown", () => ScreenFooter.State.Value, () => Is.EqualTo(Visibility.Visible)); + } + + [Test] + public void TestExternalOverlayContent() + { + TestScreen screen = null!; + + AddStep("push screen", () => + { + ShearedOverlayContainer overlay = new TestShearedOverlayContainer(); + + LoadScreen(screen = new TestScreen + { + Overlay = overlay, + CreateButtons = () => new[] + { + new ScreenFooterButton(overlay) + { + AccentColour = Dependencies.Get().Orange1, + Icon = FontAwesome.Solid.Toolbox, + Text = "One", + }, + new ScreenFooterButton { Text = "Two", Action = () => { } }, + new ScreenFooterButton { Text = "Three", Action = () => { } }, + }, + }); + }); + AddUntilStep("wait until screen is loaded", () => screen.IsCurrentScreen(), () => Is.True); + + AddStep("show overlay", () => screen.Overlay.Show()); + contentDisplayed(); + AddAssert("other buttons hidden", () => ScreenFooter.ChildrenOfType().Skip(1).All(b => b.Child.Parent!.Y > 0)); + + AddStep("hide overlay", () => screen.Overlay.Hide()); + contentHidden(); + AddAssert("other buttons returned", () => ScreenFooter.ChildrenOfType().Skip(1).All(b => b.ChildrenOfType().First().Y == 0)); + } + + [Test] + public void TestTemporarilyShowFooter() + { + TestScreen screen = null!; + + AddStep("push screen", () => LoadScreen(screen = new TestScreen(showFooter: false))); + AddUntilStep("wait until screen is loaded", () => screen.IsCurrentScreen(), () => Is.True); + AddAssert("footer hidden", () => ScreenFooter.State.Value, () => Is.EqualTo(Visibility.Hidden)); + + AddStep("show overlay", () => screen.Overlay.Show()); + AddAssert("footer shown", () => ScreenFooter.State.Value, () => Is.EqualTo(Visibility.Visible)); + contentDisplayed(); + + AddStep("hide overlay", () => screen.Overlay.Hide()); + AddAssert("footer hidden", () => ScreenFooter.State.Value, () => Is.EqualTo(Visibility.Hidden)); + contentHidden(); + } + + [Test] + public void TestShowOverlayHidesOtherOverlays() + { + TestScreen screen = null!; + + AddStep("push screen", () => + { + ShearedOverlayContainer overlay = new TestShearedOverlayContainer(); + ModSelectOverlay secondOverlay = new ModSelectOverlay(); + + LoadScreen(screen = new TestScreen + { + Overlay = overlay, + SecondOverlay = secondOverlay, + CreateButtons = () => new[] + { + new ScreenFooterButton(overlay) + { + AccentColour = Dependencies.Get().Orange1, + Icon = FontAwesome.Solid.Toolbox, + Text = "One", + }, + new FooterButtonMods(secondOverlay), + new ScreenFooterButton { Text = "Two", Action = () => { } }, + new ScreenFooterButton { Text = "Three", Action = () => { } }, + }, + }); + }); + AddUntilStep("wait until screen is loaded", () => screen.IsCurrentScreen(), () => Is.True); + + AddStep("show mods overlay", () => ScreenFooter.ChildrenOfType().First().TriggerClick()); + AddUntilStep("wait until overlay is shown", () => screen.SecondOverlay.State.Value, () => Is.EqualTo(Visibility.Visible)); + AddAssert("first button still visible", () => ScreenFooter.ChildrenOfType().First(b => b.Text == "One").Y, () => Is.EqualTo(0)); + + AddStep("show test overlay", () => ScreenFooter.ChildrenOfType().First(b => b.Text == "One").TriggerClick()); + AddUntilStep("wait until overlay is shown", () => screen.Overlay.State.Value, () => Is.EqualTo(Visibility.Visible)); + AddAssert("mod overlay is hidden", () => screen.SecondOverlay.State.Value, () => Is.EqualTo(Visibility.Hidden)); + + AddStep("hide test overlay", () => screen.Overlay.Hide()); + contentHidden(); + AddAssert("other buttons returned", () => ScreenFooter.ChildrenOfType().Skip(1).All(b => b.ChildrenOfType().First().Y == 0)); + } + + [Test] + public void TestButtonResizedAfterFooterIsDisplayed() + { + TestScreen screen = null!; + + const float initial_width = 116; + const float width_increase = 124; + + float secondButtonX = 0; + float overlayContentX = 0; + + AddStep("push screen", () => + { + ShearedOverlayContainer overlay = new TestShearedOverlayContainer(); + + LoadScreen(screen = new TestScreen + { + Overlay = overlay, + CreateButtons = () => new[] + { + new ScreenFooterButton(overlay) + { + AccentColour = Dependencies.Get().Orange1, + Icon = FontAwesome.Solid.Toolbox, + Text = "One", + }, + new ScreenFooterButton { Text = "Two", Action = () => { } }, + new ScreenFooterButton { Text = "Three", Action = () => { } }, + }, + }); + }); + AddUntilStep("wait until screen is loaded", () => screen.IsCurrentScreen(), () => Is.True); + AddStep("save second button position", () => secondButtonX = ScreenFooter.ChildrenOfType().ElementAt(1).X); + + AddStep("resize active button", () => ScreenFooter.ChildrenOfType().First().ResizeWidthTo(initial_width + width_increase, 300, Easing.OutQuint)); + AddUntilStep("second button moved", () => ScreenFooter.ChildrenOfType().ElementAt(1).X, () => Is.EqualTo(secondButtonX + width_increase).Within(0.001)); + AddStep("resize active button back", () => this.ChildrenOfType().First().ResizeWidthTo(initial_width, 300, Easing.OutQuint)); + AddUntilStep("second button moved back", () => ScreenFooter.ChildrenOfType().ElementAt(1).X, () => Is.EqualTo(secondButtonX).Within(0.001)); + + AddStep("show overlay", () => screen.Overlay.Show()); + contentDisplayed(); + AddAssert("other buttons hidden", () => ScreenFooter.ChildrenOfType().Skip(1).All(b => b.Child.Parent!.Y > 0)); + AddStep("save overlay content position", () => overlayContentX = ScreenFooter.ChildrenOfType().First().Parent!.Parent!.X); + + AddStep("resize active button", () => ScreenFooter.ChildrenOfType().First().ResizeWidthTo(initial_width + width_increase, 300, Easing.OutQuint)); + AddUntilStep("overlay content moved", () => ScreenFooter.ChildrenOfType().First().Parent!.Parent!.X, () => Is.EqualTo(overlayContentX + width_increase).Within(0.001)); + AddStep("resize active button back", () => this.ChildrenOfType().First().ResizeWidthTo(initial_width, 300, Easing.OutQuint)); + AddUntilStep("overlay content moved back", () => ScreenFooter.ChildrenOfType().First().Parent!.Parent!.X, () => Is.EqualTo(overlayContentX).Within(0.001)); + + AddStep("hide overlay", () => screen.Overlay.Hide()); + contentHidden(); + AddUntilStep("other buttons returned", () => ScreenFooter.ChildrenOfType().Skip(1).All(b => b.ChildrenOfType().First().Y == 0)); + } + + private void contentHidden() + { + AddUntilStep("content hidden from footer", () => ScreenFooter.ChildrenOfType().SingleOrDefault()?.IsPresent != true); + } + + private void contentDisplayed() + { + AddUntilStep("content displayed in footer", () => ScreenFooter.ChildrenOfType().Single().IsPresent); + } + + private partial class TestScreen : OsuScreen + { + public override bool ShowFooter { get; } + + public Func> CreateButtons = Array.Empty; + + public ShearedOverlayContainer Overlay = new TestShearedOverlayContainer(); + public ShearedOverlayContainer SecondOverlay = new TestShearedOverlayContainer(); + + private IDisposable? overlayRegistration; + private IDisposable? secondOverlayRegistration; + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + [Resolved] + private IOverlayManager? overlayManager { get; set; } + + public TestScreen(bool showFooter = true) + { + ShowFooter = showFooter; + } + + [BackgroundDependencyLoader] + private void load() + { + LoadComponent(Overlay); + LoadComponent(SecondOverlay); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + overlayRegistration = overlayManager?.RegisterBlockingOverlay(Overlay); + secondOverlayRegistration = overlayManager?.RegisterBlockingOverlay(SecondOverlay); + } + + public override IReadOnlyList CreateFooterButtons() => CreateButtons.Invoke(); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + overlayRegistration?.Dispose(); + secondOverlayRegistration?.Dispose(); + } + } + + private partial class TestShearedOverlayContainer : ShearedOverlayContainer + { + public TestShearedOverlayContainer() + : base(OverlayColourScheme.Orange) + { + } + + [BackgroundDependencyLoader] + private void load() + { + Header.Title = "Test overlay"; + Header.Description = "An overlay that is made purely for testing purposes."; + } + + public override VisibilityContainer CreateFooterContent() => new TestFooterContent(); + + public partial class TestFooterContent : VisibilityContainer + { + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Children = new[] + { + new ShearedButton(200) { Text = "Action #1", Action = () => { } }, + new ShearedButton(140) { Text = "Action #2", Action = () => { } }, + } + }; + } + + protected override void PopIn() + { + this.MoveToY(0, 400, Easing.OutQuint) + .FadeIn(400, Easing.OutQuint); + } + + protected override void PopOut() + { + this.MoveToY(-20f, 200, Easing.OutQuint) + .FadeOut(200, Easing.OutQuint); + } + } + } + } +} diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e112c1424d63..563922f31d21 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1139,6 +1139,7 @@ protected override void LoadComplete() }, new PopoverContainer { + // Ensure the footer is displayed above any content and/or overlays. Depth = -1, RelativeSizeAxes = Axes.Both, Child = screenStackFooter = new ScreenStackFooter(ScreenStack, backReceptor) diff --git a/osu.Game/Tests/Visual/ScreenTestScene.cs b/osu.Game/Tests/Visual/ScreenTestScene.cs index e1775cf5a1df..3d106bc5b7a6 100644 --- a/osu.Game/Tests/Visual/ScreenTestScene.cs +++ b/osu.Game/Tests/Visual/ScreenTestScene.cs @@ -62,7 +62,7 @@ protected ScreenTestScene() }, screenStackFooter = new ScreenStackFooter(Stack, backReceptor) { - BackButtonPressed = () => Stack.Exit() + BackButtonPressed = BackButtonPressed, } } }, @@ -74,6 +74,8 @@ protected ScreenTestScene() Stack.ScreenExited += (_, newScreen) => Logger.Log($"{nameof(ScreenTestScene)} screen changed ← {newScreen}"); } + protected virtual void BackButtonPressed() => Stack.Exit(); + protected void LoadScreen(OsuScreen screen) => Stack.Push(screen); [SetUpSteps] From 033e13cb3b79e6195ddcd9f659b04095aa52fd2f Mon Sep 17 00:00:00 2001 From: Linus Genz Date: Sun, 1 Mar 2026 18:08:19 +0100 Subject: [PATCH 719/836] Fix song select navigation with page up/down (#36293) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves #36099 This PR fixes keyboard navigation in the beatmap select carousel for lazer by implementing page-wise traversal with the Page Up and Page Down keys and changing it from only scrolling to actually selecting items. **Changes:** - Added handling for `TraversalType.Page` in the keyboard traversal switch. - Implemented `traverseKeyboardPage(int direction)` method to move the selection by approximately one "page" of visible items, accounting for partially obscured items like the search bar. Also it does not wrap around (like the current PageUp/Down functionality). - Added new key bindings: - `PageUp` → SelectPreviousPage - `PageDown` → SelectNextPage The code may be very explicit for the scroll logic with the page keys, so I would appreciate some feedback when the PR is reviewed. The naming of the keybinds may need to be adjusted. `Next page` and `previous page` may be somewhat misleading. **Behavior after the change:** - Pressing Page Up/Down now moves the selection by a page of items. - After navigating, pressing Left/Right selects the navigated song instead of moving relative to the previous position. **See:** https://www.youtube.com/watch?v=JXmKAhhKiCc --------- Signed-off-by: Linus Genz Co-authored-by: Dean Herbert --- .../Carousel/Carousel.ScrollContainer.cs | 19 ++++ osu.Game/Graphics/Carousel/Carousel.cs | 90 +++++++++++++++---- 2 files changed, 94 insertions(+), 15 deletions(-) diff --git a/osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs b/osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs index accd74aa4ba8..835a83998ad3 100644 --- a/osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs +++ b/osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs @@ -33,6 +33,9 @@ public abstract partial class Carousel where T : notnull /// protected partial class ScrollContainer : UserTrackingScrollContainer, IKeyBindingHandler { + public Action? OnPageUp { get; init; } + public Action? OnPageDown { get; init; } + public readonly Container Panels; public void SetLayoutHeight(float height) => Panels.Height = height; @@ -127,6 +130,22 @@ protected override float FromScrollbarPosition(float scrollbarPosition) protected override bool IsDragging => base.IsDragging || AbsoluteScrolling; + protected override bool OnKeyDown(KeyDownEvent e) + { + switch (e.Key) + { + case Key.PageUp: + OnPageUp?.Invoke(); + return true; + + case Key.PageDown: + OnPageDown?.Invoke(); + return true; + } + + return base.OnKeyDown(e); + } + public bool OnPressed(KeyBindingPressEvent e) { switch (e.Action) diff --git a/osu.Game/Graphics/Carousel/Carousel.cs b/osu.Game/Graphics/Carousel/Carousel.cs index 3b7e31b2ea12..13d3c22c1900 100644 --- a/osu.Game/Graphics/Carousel/Carousel.cs +++ b/osu.Game/Graphics/Carousel/Carousel.cs @@ -317,6 +317,8 @@ protected Carousel() { Masking = false, RelativeSizeAxes = Axes.Both, + OnPageUp = () => Scheduler.AddOnce(traverseFromKey, new TraversalOperation(TraversalType.Page, -1)), + OnPageDown = () => Scheduler.AddOnce(traverseFromKey, new TraversalOperation(TraversalType.Page, 1)), }; Items.BindCollectionChanged((_, args) => @@ -538,26 +540,30 @@ public bool OnPressed(KeyBindingPressEvent e) } return false; + } - void traverseFromKey(TraversalOperation traversal) + private void traverseFromKey(TraversalOperation traversal) + { + switch (traversal.Type) { - switch (traversal.Type) - { - case TraversalType.Keyboard: - traverseKeyboardSelection(traversal.Direction); - break; + case TraversalType.Keyboard: + traverseKeyboardSelection(traversal.Direction); + break; + + case TraversalType.Page: + traverseKeyboardPage(traversal.Direction); + break; - case TraversalType.Set: - traverseSetSelection(traversal.Direction); - break; + case TraversalType.Set: + traverseSetSelection(traversal.Direction); + break; - case TraversalType.Group: - traverseGroupSelection(traversal.Direction); - break; + case TraversalType.Group: + traverseGroupSelection(traversal.Direction); + break; - default: - throw new ArgumentOutOfRangeException(); - } + default: + throw new ArgumentOutOfRangeException(); } } @@ -565,6 +571,7 @@ private enum TraversalType { Keyboard, Set, + Page, Group } @@ -622,6 +629,59 @@ private void traverseKeyboardSelection(int direction) } while (newIndex != originalIndex); } + /// + /// Performs a page-wise keyboard traversal in the carousel, moving the selection by approximately one "page" of items. + /// + /// Positive for downwards, negative for upwards. + private void traverseKeyboardPage(int direction) + { + if (carouselItems == null || carouselItems.Count == 0) + return; + + int startIndex = currentKeyboardSelection.Index ?? (direction > 0 ? carouselItems.Count - 1 : 0); + + // Compute the number of visible panels to treat as one page. + // Reduced by 50% to account for the search bar covering the top items. + int visiblePanelsCount = Math.Max(1, Scroll.Panels.Count / 2); + int visibleCount = 0; + int i = startIndex; + + while (i >= 0 && i < carouselItems.Count) + { + i += direction; + + if (i < 0 || i >= carouselItems.Count) + break; + + var item = carouselItems[i]; + + if (!item.IsVisible) + continue; + + visibleCount++; + + if (visibleCount >= visiblePanelsCount) + { + setKeyboardSelection(item.Model); + ScrollToSelection(); + playTraversalSound(); + return; + } + } + + // If we are at the beginning or end and there are not enough items left to scroll through a complete page, then we go to the last or first item. + var fallback = direction > 0 + ? carouselItems.LastOrDefault(x => x.IsVisible) + : carouselItems.FirstOrDefault(x => x.IsVisible); + + if (fallback != null && !CheckModelEquality(fallback.Model, currentKeyboardSelection.Model)) + { + setKeyboardSelection(fallback.Model); + ScrollToSelection(); + playTraversalSound(); + } + } + /// /// Select the next valid group selection relative to a current selection. /// This is generally for keyboard based traversal. From 9c8dfaf38693aff48a6acb2793c1eff5f7b32550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 2 Mar 2026 12:07:11 +0100 Subject: [PATCH 720/836] Apply more sanity checks when handling files from archives --- osu.Game/Database/ModelManager.cs | 5 +++ .../Database/RealmArchiveModelImporter.cs | 14 ++++++- .../Utils/FilesystemSanityCheckHelpers.cs | 37 +++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Utils/FilesystemSanityCheckHelpers.cs diff --git a/osu.Game/Database/ModelManager.cs b/osu.Game/Database/ModelManager.cs index e96a8cc1b16a..2eaba596d654 100644 --- a/osu.Game/Database/ModelManager.cs +++ b/osu.Game/Database/ModelManager.cs @@ -12,6 +12,7 @@ using osu.Game.Extensions; using osu.Game.Models; using osu.Game.Overlays.Notifications; +using osu.Game.Utils; using Realms; namespace osu.Game.Database @@ -87,6 +88,10 @@ public void ReplaceFile(RealmNamedFileUsage file, Stream contents, Realm realm) public void AddFile(TModel item, Stream contents, string filename, Realm realm) { filename = filename.ToStandardisedPath(); + + if (FilesystemSanityCheckHelpers.IncursPathTraversalRisk(filename)) + throw new InvalidOperationException($@"Filename ""{filename}"" is not allowed."); + var existing = item.GetFile(filename); if (existing != null) diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index af57d5ec5b3c..1836e4ba80ef 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -17,6 +17,7 @@ using osu.Game.IO.Archives; using osu.Game.Models; using osu.Game.Overlays.Notifications; +using osu.Game.Utils; using Realms; namespace osu.Game.Database @@ -221,7 +222,15 @@ public async Task> BeginExternalEditing(TModel mod foreach (string piece in realmFile.Filename.Split('/').Select(f => f.GetValidFilename())) destinationPath = Path.Combine(destinationPath, piece); - Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)!); + string destinationDirectory = Path.GetDirectoryName(destinationPath)!; + + if (!FilesystemSanityCheckHelpers.IsSubDirectory(parent: mountedPath, child: destinationDirectory)) + { + Logger.Log($@"Skipping attempt to mount {realmFile.Filename} due to detected escape out of mounted path.", LoggingTarget.Database); + continue; + } + + Directory.CreateDirectory(destinationDirectory); // Consider using hard links here to make this instant. using (var inStream = Files.Storage.GetStream(sourcePath)) @@ -361,6 +370,9 @@ public async Task> BeginExternalEditing(TModel mod // We intentionally delay adding to realm to avoid blocking on a write during disk operations. foreach (var filenames in getShortenedFilenames(archive)) { + if (FilesystemSanityCheckHelpers.IncursPathTraversalRisk(filenames.shortened)) + throw new InvalidOperationException($@"Filename ""{filenames.original}"" is not allowed."); + using (Stream s = archive.GetStream(filenames.original)) files.Add(new RealmNamedFileUsage(Files.Add(s, realm, false, parameters.PreferHardLinks), filenames.shortened)); } diff --git a/osu.Game/Utils/FilesystemSanityCheckHelpers.cs b/osu.Game/Utils/FilesystemSanityCheckHelpers.cs new file mode 100644 index 000000000000..d73475081052 --- /dev/null +++ b/osu.Game/Utils/FilesystemSanityCheckHelpers.cs @@ -0,0 +1,37 @@ +// 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.IO; + +namespace osu.Game.Utils +{ + public static class FilesystemSanityCheckHelpers + { + /// + /// Returns whether is potentially susceptible to path traversal style attacks. + /// + public static bool IncursPathTraversalRisk(string path) + => path.Contains("../", StringComparison.Ordinal) || path.Contains("..\\", StringComparison.Ordinal) || Path.IsPathRooted(path); + + /// + /// Returns whether is a subdirectory (direct or nested) of . + /// + public static bool IsSubDirectory(string parent, string child) + { + // `Path.GetFullPath()` invocations are required to fully resolve the paths to unambiguous downwards-traversal-only paths. + var parentInfo = new DirectoryInfo(Path.GetFullPath(parent)); + var childInfo = new DirectoryInfo(Path.GetFullPath(child)); + + while (childInfo != null) + { + if (parentInfo.FullName == childInfo.FullName) + return true; + + childInfo = childInfo.Parent; + } + + return false; + } + } +} From f241d9c84e8dbaa23bd5d29284d59087eb0bbd28 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Tue, 3 Mar 2026 04:14:31 +0500 Subject: [PATCH 721/836] Fix combined slider velocity calculation (#36773) This changes how the current/previous velocity is being calculated in Aim. Currently it's being calculated as an addition of 2 velocities together which isn't really correct, instead here velocity is being calculated as a (combined distances) / (combined times). On practice this buffs underweighted slider maps while overweighted ones stay about the same https://pp.huismetbenen.nl/rankings/players/use-proper-slider-velocity --- .../Difficulty/Evaluators/AimEvaluator.cs | 14 +++++--------- .../Preprocessing/OsuDifficultyHitObject.cs | 2 +- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index b9436b448b96..4e28b28b88dd 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -13,7 +13,7 @@ public static class AimEvaluator { private const double wide_angle_multiplier = 1.5; private const double acute_angle_multiplier = 2.6; - private const double slider_multiplier = 1.5; + private const double slider_multiplier = 2.9; private const double velocity_change_multiplier = 0.9; private const double wiggle_multiplier = 1.02; // WARNING: Increasing this multiplier beyond 1.02 reduces difficulty as distance increases. Refer to the desmos link above the wiggle bonus calculation @@ -46,10 +46,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // But if the last object is a slider, then we extend the travel velocity through the slider into the current object. if (osuLastObj.BaseObject is Slider && withSliderTravelDistance) { - double travelVelocity = osuLastObj.TravelDistance / osuLastObj.TravelTime; // calculate the slider velocity from slider head to slider end. - double movementVelocity = osuCurrObj.MinimumJumpDistance / osuCurrObj.MinimumJumpTime; // calculate the movement velocity from slider end to current object - - currVelocity = Math.Max(currVelocity, movementVelocity + travelVelocity); // take the larger total combined velocity. + double sliderDistance = osuLastObj.LazyTravelDistance + osuCurrObj.LazyJumpDistance; + currVelocity = Math.Max(currVelocity, sliderDistance / osuCurrObj.AdjustedDeltaTime); } // As above, do the same for the previous hitobject. @@ -58,10 +56,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with if (osuLastLastObj.BaseObject is Slider && withSliderTravelDistance) { - double travelVelocity = osuLastLastObj.TravelDistance / osuLastLastObj.TravelTime; - double movementVelocity = osuLastObj.MinimumJumpDistance / osuLastObj.MinimumJumpTime; - - prevVelocity = Math.Max(prevVelocity, movementVelocity + travelVelocity); + double sliderDistance = osuLastLastObj.LazyTravelDistance + osuLastObj.LazyJumpDistance; + prevVelocity = Math.Max(prevVelocity, sliderDistance / osuLastObj.AdjustedDeltaTime); } double wideAngleBonus = 0; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index b9b985fdc7c5..cee768b06f3b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -199,7 +199,7 @@ private void setDistances(double clockRate) if (BaseObject is Slider currentSlider) { // Bonus for repeat sliders until a better per nested object strain system can be achieved. - TravelDistance = LazyTravelDistance * Math.Pow(1 + currentSlider.RepeatCount / 2.5, 1.0 / 2.5); + TravelDistance = LazyTravelDistance * Math.Max(1, Math.Pow(currentSlider.RepeatCount, 0.2)); TravelTime = Math.Max(LazyTravelTime / clockRate, MIN_DELTA_TIME); } From b1227e1f128034eaf6825ed0c1ea0d93422e5aec Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Tue, 3 Mar 2026 04:38:32 +0500 Subject: [PATCH 722/836] Aim strain influence reduction (#36792) Currently, live aim evaluation prioritizes high bpms with lower distances over low bpms with higher distances, something you may have heard colloquially called "d/t^2" in here. This creates an inherent DT advantage / NM & HR disadvantage in the average aim case. This change makes it so the evaluation is nudged closer to the ideal distance/time aim evaluation. In practice, higher spacing (distance) and/or slower jumps should generally see a buff, lower spacing (distance) and/or faster jumps should generally see a nerf. This includes some 3-mod scores as HR spacing is underweighted regardless of bpm. It also affects streams the same way, where faster high bpm low spacing streams (speedflow) are nerfed and high spacing low bpm streams are buffed. As a disclaimer: this isn't a complete fix, it is moreso a step in the right direction (hence, a Nudge, per se) towards the ideal d/t world. This also doesn't change anything angle-related so high-spacing farm maps will gain pp - this will be addressed separately after this change. https://pp.huismetbenen.nl/rankings/players/reduce-strain-influence --------- Co-authored-by: James Wilson --- .../Difficulty/Evaluators/AimEvaluator.cs | 10 +++++----- .../Difficulty/Evaluators/SpeedAimEvaluator.cs | 4 ++-- .../Difficulty/OsuRatingCalculator.cs | 2 +- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 4 ++-- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 4e28b28b88dd..5f1a5a379c2d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -11,10 +11,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { public static class AimEvaluator { - private const double wide_angle_multiplier = 1.5; + private const double wide_angle_multiplier = 1.4; private const double acute_angle_multiplier = 2.6; - private const double slider_multiplier = 2.9; - private const double velocity_change_multiplier = 0.9; + private const double slider_multiplier = 2.0; + private const double velocity_change_multiplier = 1.1; private const double wiggle_multiplier = 1.02; // WARNING: Increasing this multiplier beyond 1.02 reduces difficulty as distance increases. Refer to the desmos link above the wiggle bonus calculation /// @@ -158,7 +158,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Add in additional slider velocity bonus. if (withSliderTravelDistance) - aimStrain += sliderBonus * slider_multiplier; + aimStrain += (sliderBonus < 1 ? sliderBonus : Math.Pow(sliderBonus, 0.75)) * slider_multiplier; // Apply high circle size bonus aimStrain *= osuCurrObj.SmallCircleBonus; @@ -171,7 +171,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // We decrease strain for distances 1 / (1 - Math.Pow(0.15, ms / 1000)) + private static double highBpmBonus(double ms, double distance) => 1 / (1 - Math.Pow(0.03, Math.Pow(ms / 1000, 0.75))) * DifficultyCalculationUtils.Smootherstep(distance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS); private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs index d56ffbfe14bf..9211ec39cf88 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs @@ -33,10 +33,10 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) distance = Math.Min(distance, SINGLE_SPACING_THRESHOLD); // Max distance bonus is 1 * `distance_multiplier` at single_spacing_threshold - double distanceBonus = Math.Pow(distance / SINGLE_SPACING_THRESHOLD, 3.95); + double distanceBonus = Math.Pow(distance / SINGLE_SPACING_THRESHOLD, 2.9); // Apply reduced small circle bonus because flow aim difficulty on small circles doesn't scale as hard as jumps - distanceBonus *= Math.Sqrt(osuCurrObj.SmallCircleBonus); + distanceBonus *= Math.Pow(osuCurrObj.SmallCircleBonus, 0.7); double strain = distanceBonus * 1000 / osuCurrObj.AdjustedDeltaTime; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs index 768a1f3e73e3..bc9de3494fa2 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs @@ -29,7 +29,7 @@ public double ComputeAimRating(double aimDifficultyValue) if (mods.Any(m => m is OsuModAutopilot)) return 0; - double aimRating = CalculateDifficultyRating(aimDifficultyValue); + double aimRating = Math.Pow(aimDifficultyValue, 0.58) * 0.0346; if (mods.Any(m => m is OsuModRelax)) aimRating *= 0.9; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index cee768b06f3b..b0b1c5132fa0 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -134,7 +134,7 @@ public OsuDifficultyHitObject(HitObject hitObject, HitObject lastObject, double AdjustedDeltaTime = Math.Max(DeltaTime, MIN_DELTA_TIME); LastObjectEndDeltaTime = lastDifficultyObject != null ? Math.Max(StartTime - lastDifficultyObject.EndTime, MIN_DELTA_TIME) : AdjustedDeltaTime; - SmallCircleBonus = Math.Max(1.0, 1.0 + (30 - BaseObject.Radius) / 40); + SmallCircleBonus = Math.Max(1.0, 1.0 + (30 - BaseObject.Radius) / 60); Preempt = BaseObject.TimePreempt / clockRate; @@ -199,7 +199,7 @@ private void setDistances(double clockRate) if (BaseObject is Slider currentSlider) { // Bonus for repeat sliders until a better per nested object strain system can be achieved. - TravelDistance = LazyTravelDistance * Math.Max(1, Math.Pow(currentSlider.RepeatCount, 0.2)); + TravelDistance = LazyTravelDistance * Math.Max(1, Math.Pow(currentSlider.RepeatCount, 0.3)); TravelTime = Math.Max(LazyTravelTime / clockRate, MIN_DELTA_TIME); } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 2e3cb96458ed..50fc9333a798 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -31,8 +31,8 @@ public Aim(Mod[] mods, bool includeSliders) private double currentAimStrain; private double currentSpeedStrain; - private double skillMultiplierAim => 25.0; - private double skillMultiplierSpeed => 1.4; + private double skillMultiplierAim => 58.5; + private double skillMultiplierSpeed => 2.0; private double skillMultiplierTotal => 1.0; private double meanExponent => 1.2; From ee9f8d5e9252c2311685806a4d77574437c9a980 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Mar 2026 12:59:18 +0900 Subject: [PATCH 723/836] Fix custom tooltip formats no longer displaying in settings Closes #36793. --- osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 6f51b947502d..7adf6913090b 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -157,7 +157,7 @@ public FormSliderBar() { Current = currentNumberInstantaneous, OnCommit = () => current.Value = currentNumberInstantaneous.Value, - TooltipFormat = TooltipFormat, + TooltipFormat = s => TooltipFormat(s), DisplayAsPercentage = DisplayAsPercentage, PlaySamplesOnAdjust = PlaySamplesOnAdjust, ResetToDefault = () => From d27d0f40c11cbbf70de492052b611da77f850230 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Mar 2026 13:41:48 +0900 Subject: [PATCH 724/836] Switch multiplayer to use song select v2 (#36747) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests pass and seems to work. Need to do a bit more self-testing for higher confidence, but in theory.. Closes https://github.com/ppy/osu/issues/34035. --------- Co-authored-by: Bartłomiej Dach --- .../Visual/Multiplayer/QueueModeTestScene.cs | 37 +++- .../TestSceneAllPlayersQueueMode.cs | 49 +---- .../TestSceneFreeModSelectOverlay.cs | 47 +---- .../Multiplayer/TestSceneHostOnlyQueueMode.cs | 43 ++-- .../Multiplayer/TestSceneMultiplayer.cs | 19 +- .../TestSceneMultiplayerMatchSongSelect.cs | 72 +++++-- .../TestScenePlaylistsSongSelect.cs | 6 +- .../TestSceneFooterButtonFreeModsV2.cs | 4 +- .../TestSceneFooterButtonFreestyleV2.cs | 2 +- .../Online/Leaderboards/LeaderboardScore.cs | 1 + osu.Game/OsuGame.cs | 6 +- .../SkinEditor/SkinEditorSceneLibrary.cs | 1 - .../Submission/BeatmapSubmissionScreen.cs | 2 +- .../OnlinePlay/FooterButtonFreeMods.cs | 187 +++++++++--------- .../OnlinePlay/FooterButtonFreeModsV2.cs | 151 -------------- .../OnlinePlay/FooterButtonFreestyle.cs | 68 +------ .../OnlinePlay/FooterButtonFreestyleV2.cs | 51 ----- .../Multiplayer/MultiplayerMatchSongSelect.cs | 62 +++--- .../Playlists/PlaylistsSongSelect.cs | 4 +- osu.Game/Screens/SelectV2/SongSelect.cs | 30 ++- 20 files changed, 295 insertions(+), 547 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs delete mode 100644 osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs index 184bb33c2ff4..f0b7d643b2c3 100644 --- a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs @@ -1,6 +1,8 @@ // 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.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; @@ -15,6 +17,7 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Screens.OnlinePlay; using osu.Game.Screens.OnlinePlay.Lounge; @@ -22,6 +25,7 @@ using osu.Game.Screens.OnlinePlay.Multiplayer.Match; using osu.Game.Screens.Play; using osu.Game.Tests.Resources; +using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { @@ -35,7 +39,8 @@ public abstract partial class QueueModeTestScene : ScreenTestScene protected IScreen CurrentScreen => multiplayerComponents.CurrentScreen; protected IScreen CurrentSubScreen => multiplayerComponents.MultiplayerScreen.CurrentSubScreen; - private BeatmapManager beatmaps = null!; + protected BeatmapManager Beatmaps { get; private set; } = null!; + private BeatmapSetInfo importedSet = null!; private RulesetStore rulesets = null!; @@ -49,7 +54,7 @@ private void load(GameHost host, AudioManager audio) BeatmapStore beatmapStore; Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); - Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default)); + Dependencies.Cache(Beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default)); Dependencies.CacheAs(beatmapStore = new RealmDetachedBeatmapStore()); Dependencies.Cache(Realm); @@ -62,13 +67,13 @@ public override void SetUpSteps() AddStep("import beatmap", () => { - beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely(); + Beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely(); Realm.Write(r => { foreach (var beatmapInfo in r.All()) beatmapInfo.OnlineMD5Hash = beatmapInfo.MD5Hash; }); - importedSet = beatmaps.GetAllUsableBeatmapSets().First(); + importedSet = Beatmaps.GetAllUsableBeatmapSets().First(); InitialBeatmap = importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0); OtherBeatmap = importedSet.Beatmaps.Last(b => b.Ruleset.OnlineID == 0); }); @@ -118,6 +123,30 @@ protected void RunGameplay() AddStep("exit player", () => multiplayerComponents.MultiplayerScreen.MakeCurrent()); } + protected void AddBeatmapFromSongSelect(Func beatmap, RulesetInfo? ruleset = null, IReadOnlyList? mods = null) + { + Screens.SelectV2.SongSelect? songSelect = null; + + AddStep("click add button", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.SelectV2.SongSelect) != null); + AddUntilStep("wait for loaded", () => songSelect.IsCurrentScreen() && !songSelect.AsNonNull().IsFiltering); + + if (ruleset != null) + AddStep($"set {ruleset.Name} ruleset", () => songSelect.AsNonNull().Ruleset.Value = ruleset); + + if (mods != null) + AddStep($"set mods to {string.Join(",", mods.Select(m => m.Acronym))}", () => songSelect.AsNonNull().Mods.Value = mods); + + AddStep("select other beatmap", () => songSelect.AsNonNull().Beatmap.Value = Beatmaps.GetWorkingBeatmap(beatmap())); + AddStep("confirm selection", () => InputManager.Key(Key.Enter)); + AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen); + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs index 869b8bb32874..be089224153f 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs @@ -1,24 +1,16 @@ // 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.Collections.Generic; using System.Linq; using NUnit.Framework; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Screens; -using osu.Framework.Testing; -using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; -using osu.Game.Rulesets; using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; using osu.Game.Screens.Play; -using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { @@ -45,10 +37,10 @@ public void TestSingleItemExpiredAfterGameplay() [Test] public void TestItemAddedToTheEndOfQueue() { - addItem(() => OtherBeatmap); + AddBeatmapFromSongSelect(() => OtherBeatmap); AddUntilStep("playlist has 2 items", () => MultiplayerClient.ClientAPIRoom?.Playlist.Count == 2); - addItem(() => InitialBeatmap); + AddBeatmapFromSongSelect(() => InitialBeatmap); AddUntilStep("playlist has 3 items", () => MultiplayerClient.ClientAPIRoom?.Playlist.Count == 3); AddUntilStep("first item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); @@ -57,8 +49,8 @@ public void TestItemAddedToTheEndOfQueue() [Test] public void TestNextItemSelectedAfterGameplayFinish() { - addItem(() => OtherBeatmap); - addItem(() => InitialBeatmap); + AddBeatmapFromSongSelect(() => OtherBeatmap); + AddBeatmapFromSongSelect(() => InitialBeatmap); RunGameplay(); @@ -74,8 +66,8 @@ public void TestNextItemSelectedAfterGameplayFinish() [Test] public void TestItemsNotClearedWhenSwitchToHostOnlyMode() { - addItem(() => OtherBeatmap); - addItem(() => InitialBeatmap); + AddBeatmapFromSongSelect(() => OtherBeatmap); + AddBeatmapFromSongSelect(() => InitialBeatmap); // Move to the "other" beatmap. RunGameplay(); @@ -89,14 +81,14 @@ public void TestItemsNotClearedWhenSwitchToHostOnlyMode() [Test] public void TestCorrectItemSelectedAfterNewItemAdded() { - addItem(() => OtherBeatmap); + AddBeatmapFromSongSelect(() => OtherBeatmap); AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID); } [Test] public void TestCorrectRulesetSelectedAfterNewItemAdded() { - addItem(() => OtherBeatmap, new CatchRuleset().RulesetInfo); + AddBeatmapFromSongSelect(() => OtherBeatmap, new CatchRuleset().RulesetInfo); AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID); AddUntilStep("wait for idle", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Idle); @@ -113,7 +105,7 @@ public void TestCorrectRulesetSelectedAfterNewItemAdded() [Test] public void TestCorrectModsSelectedAfterNewItemAdded() { - addItem(() => OtherBeatmap, mods: new Mod[] { new OsuModDoubleTime() }); + AddBeatmapFromSongSelect(() => OtherBeatmap, mods: new Mod[] { new OsuModDoubleTime() }); AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID); AddUntilStep("wait for idle", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Idle); @@ -126,28 +118,5 @@ public void TestCorrectModsSelectedAfterNewItemAdded() AddAssert("mods are correct", () => !((Player)CurrentScreen).Mods.Value.Any()); AddStep("exit player", () => CurrentScreen.Exit()); } - - private void addItem(Func beatmap, RulesetInfo? ruleset = null, IReadOnlyList? mods = null) - { - Screens.Select.SongSelect? songSelect = null; - - AddStep("click add button", () => - { - InputManager.MoveMouseTo(this.ChildrenOfType().Single()); - InputManager.Click(MouseButton.Left); - }); - - AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.Select.SongSelect) != null); - AddUntilStep("wait for loaded", () => songSelect.AsNonNull().BeatmapSetsLoaded); - - if (ruleset != null) - AddStep($"set {ruleset.Name} ruleset", () => songSelect.AsNonNull().Ruleset.Value = ruleset); - - if (mods != null) - AddStep($"set mods to {string.Join(",", mods.Select(m => m.Acronym))}", () => songSelect.AsNonNull().Mods.Value = mods); - - AddStep("select other beatmap", () => songSelect.AsNonNull().FinaliseSelection(beatmap())); - AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen); - } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs index b749c34db3d8..65b3af50f336 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs @@ -7,18 +7,15 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Framework.Testing; -using osu.Game.Graphics; using osu.Game.Overlays; using osu.Game.Overlays.Mods; -using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens; using osu.Game.Screens.Footer; using osu.Game.Screens.OnlinePlay; -using osu.Game.Screens.SelectV2; using osu.Game.Utils; using osuTK.Input; @@ -128,44 +125,6 @@ public void TestSelectDeselectAll() AddAssert("select all button enabled", () => this.ChildrenOfType().Single().Enabled.Value); } - [Test] - public void TestSelectAllViaFooterButtonThenDeselectFromOverlay() - { - createFreeModSelect(); - - AddAssert("overlay select all button enabled", () => this.ChildrenOfType().Single().Enabled.Value); - AddUntilStep( - "footer button displays no mods", - () => screen.Button.ChildrenOfType().Single().IsPresent, - () => Is.False - ); - - AddStep("click footer select all button", () => - { - InputManager.MoveMouseTo(ScreenFooter.ChildrenOfType().Single()); - InputManager.Click(MouseButton.Left); - }); - - AddUntilStep("all mods selected", assertAllAvailableModsSelected); - AddUntilStep( - "footer button displays correct mod count", - () => screen.Button.ChildrenOfType().Single().ChildrenOfType().Single().Text.ToString(), - () => Is.EqualTo($"{freeMods.Value.Count} MODS") - ); - - AddStep("click deselect all button", () => - { - InputManager.MoveMouseTo(this.ChildrenOfType().Single()); - InputManager.Click(MouseButton.Left); - }); - AddUntilStep("all mods deselected", () => !freeModSelectOverlay.SelectedMods.Value.Any()); - AddUntilStep( - "footer button displays no mods", - () => screen.Button.ChildrenOfType().Single().IsPresent, - () => Is.False - ); - } - private void createFreeModSelect() { AddStep("create free mod select screen", () => LoadScreen(screen = new TestFreeModSelectOverlayScreen @@ -206,8 +165,6 @@ private partial class TestFreeModSelectOverlayScreen : OsuScreen public FreeModSelectOverlay Overlay = null!; private IDisposable? overlayRegistration; - public FooterButtonFreeModsV2 Button = null!; - public readonly Bindable> FreeMods = new Bindable>([]); [Resolved] @@ -233,7 +190,7 @@ protected override void LoadComplete() public override IReadOnlyList CreateFooterButtons() => [ - Button = new FooterButtonFreeModsV2(Overlay) + new FooterButtonFreeMods(Overlay) { FreeMods = { BindTarget = FreeMods }, }, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs index 7d3d30b9f98b..89980b4257af 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs @@ -5,6 +5,8 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; @@ -36,6 +38,14 @@ public void TestNewItemCreatedAfterGameplayFinished() AddUntilStep("second playlist item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[1].ID); } + [Test] + public void TestItemStillSelectedAfterChangeToSameBeatmap() + { + selectNewItem(() => InitialBeatmap); + + AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); + } + [Test] public void TestSettingsUpdatedWhenChangingQueueMode() { @@ -47,14 +57,6 @@ public void TestSettingsUpdatedWhenChangingQueueMode() AddUntilStep("api room updated", () => MultiplayerClient.ClientAPIRoom?.QueueMode == QueueMode.AllPlayers); } - [Test] - public void TestItemStillSelectedAfterChangeToSameBeatmap() - { - selectNewItem(() => InitialBeatmap); - - AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); - } - [Test] public void TestItemStillSelectedAfterChangeToOtherBeatmap() { @@ -80,13 +82,15 @@ public void TestOnlyLastItemChangedAfterGameplayFinished() [Test] public void TestAddItemsAsHost() { - addItem(() => OtherBeatmap); + AddBeatmapFromSongSelect(() => OtherBeatmap); AddUntilStep("playlist contains two items", () => MultiplayerClient.ClientAPIRoom?.Playlist.Count == 2); } private void selectNewItem(Func beatmap) { + Screens.SelectV2.SongSelect? songSelect = null; + AddUntilStep("wait for playlist panels to load", () => { var queueList = this.ChildrenOfType().Single(); @@ -99,26 +103,15 @@ private void selectNewItem(Func beatmap) InputManager.Click(MouseButton.Left); }); - AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.BeatmapSetsLoaded); + AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.SelectV2.SongSelect) != null); + AddUntilStep("wait for loaded", () => songSelect.IsCurrentScreen() && !songSelect.AsNonNull().IsFiltering); BeatmapInfo otherBeatmap = null!; - AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(otherBeatmap = beatmap())); - + AddStep("select other beatmap", () => songSelect.AsNonNull().Beatmap.Value = Beatmaps.GetWorkingBeatmap(otherBeatmap = beatmap())); + AddStep("confirm selection", () => InputManager.Key(Key.Enter)); AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen); - AddUntilStep("selected item is new beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == otherBeatmap.OnlineID); - } - private void addItem(Func beatmap) - { - AddStep("click add button", () => - { - InputManager.MoveMouseTo(this.ChildrenOfType().Single()); - InputManager.Click(MouseButton.Left); - }); - - AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.BeatmapSetsLoaded); - AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(beatmap())); - AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen); + AddUntilStep("selected item is new beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == otherBeatmap.OnlineID); } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 4c487c82886b..b424621dcb76 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -228,7 +228,7 @@ public void TestCreateRoomViaKeyboard() // edit playlist item AddStep("Press select", () => InputManager.Key(Key.Enter)); - AddUntilStep("wait for song select", () => InputManager.ChildrenOfType().FirstOrDefault()?.BeatmapSetsLoaded == true); + waitForSongSelect(); // select beatmap AddStep("Press select", () => InputManager.Key(Key.Enter)); @@ -451,7 +451,7 @@ public void TestPlayStartsWithCorrectBeatmapWhileAtSongSelect() ((MultiplayerMatchSubScreen)currentSubScreen).ShowSongSelect(item); }); - AddUntilStep("wait for song select", () => this.ChildrenOfType().FirstOrDefault()?.BeatmapSetsLoaded == true); + waitForSongSelect(); AddUntilStep("Beatmap matches current item", () => Beatmap.Value.BeatmapInfo.OnlineID == multiplayerClient.ClientRoom?.Playlist.First().BeatmapID); @@ -492,7 +492,7 @@ public void TestPlayStartsWithCorrectRulesetWhileAtSongSelect() ((MultiplayerMatchSubScreen)currentSubScreen).ShowSongSelect(item); }); - AddUntilStep("wait for song select", () => this.ChildrenOfType().FirstOrDefault()?.BeatmapSetsLoaded == true); + waitForSongSelect(); AddUntilStep("Ruleset matches current item", () => Ruleset.Value.OnlineID == multiplayerClient.ClientRoom?.Playlist.First().RulesetID); @@ -533,7 +533,7 @@ public void TestPlayStartsWithCorrectModsWhileAtSongSelect() ((MultiplayerMatchSubScreen)currentSubScreen).ShowSongSelect(item); }); - AddUntilStep("wait for song select", () => this.ChildrenOfType().FirstOrDefault()?.BeatmapSetsLoaded == true); + waitForSongSelect(); AddUntilStep("Mods match current item", () => SelectedMods.Value.Select(m => m.Acronym).SequenceEqual(multiplayerClient.ClientRoom.AsNonNull().Playlist.First().RequiredMods.Select(m => m.Acronym))); @@ -1051,7 +1051,7 @@ public void TestGameplayStartsWhileInSongSelectWithDifferentRuleset() AddStep("press edit on second item", () => this.ChildrenOfType().Single(i => i.Item.RulesetID == 1) .ChildrenOfType().Single().TriggerClick()); - AddUntilStep("wait for song select", () => InputManager.ChildrenOfType().FirstOrDefault()?.BeatmapSetsLoaded == true); + waitForSongSelect(); AddAssert("ruleset is taiko", () => Ruleset.Value.OnlineID == 1); AddStep("start match", () => multiplayerClient.StartMatch().WaitSafely()); @@ -1249,6 +1249,15 @@ private void createRoom(Func room) AddUntilStep("wait for join", () => multiplayerClient.RoomJoined); } + private void waitForSongSelect() + { + AddUntilStep("wait for song select", () => + { + var songSelect = InputManager.ChildrenOfType().FirstOrDefault(); + return songSelect != null && songSelect.IsCurrentScreen() && !songSelect.IsFiltering; + }); + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs index e6f3d7e5ac18..b9f2d32cf391 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs @@ -16,6 +16,7 @@ using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Database; +using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Overlays.Mods; using osu.Game.Rulesets; @@ -26,8 +27,8 @@ using osu.Game.Rulesets.Taiko.Mods; using osu.Game.Screens.OnlinePlay; using osu.Game.Screens.OnlinePlay.Multiplayer; -using osu.Game.Screens.Select; using osu.Game.Tests.Resources; +using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { @@ -64,7 +65,11 @@ public override void SetUpSteps() { base.SetUpSteps(); - AddStep("create room", () => room = CreateDefaultRoom()); + AddStep("create room", () => + { + Ruleset.Value = new OsuRuleset().RulesetInfo; + room = CreateDefaultRoom(); + }); AddStep("join room", () => JoinRoom(room)); WaitForJoined(); } @@ -80,7 +85,7 @@ private void setUp() LoadScreen(songSelect = new TestMultiplayerMatchSongSelect(room)); }); - AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && songSelect.BeatmapSetsLoaded); + AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && !songSelect.IsFiltering); } [Test] @@ -101,19 +106,21 @@ public void TestBeatmapConfirmed() setUp(); AddStep("change ruleset", () => Ruleset.Value = new TaikoRuleset().RulesetInfo); + + AddUntilStep("wait for filtering", () => !songSelect.IsFiltering); AddStep("select beatmap", - () => songSelect.Carousel.SelectBeatmap(selectedBeatmap = beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == new TaikoRuleset().LegacyID))); + () => songSelect.SelectBeatmap(selectedBeatmap = beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == new TaikoRuleset().LegacyID))); AddUntilStep("wait for selection", () => Beatmap.Value.BeatmapInfo.Equals(selectedBeatmap)); AddUntilStep("wait for ongoing operation to complete", () => !OnlinePlayDependencies.OngoingOperationTracker.InProgress.Value); AddStep("set mods", () => SelectedMods.Value = new[] { new TaikoModDoubleTime() }); - AddStep("confirm selection", () => songSelect.FinaliseSelection()); + AddStep("confirm selection", () => InputManager.Key(Key.Enter)); AddUntilStep("song select exited", () => !songSelect.IsCurrentScreen()); - AddAssert("beatmap not changed", () => Beatmap.Value.BeatmapInfo.Equals(selectedBeatmap)); + AddAssert("beatmap not changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo((selectedBeatmap))); AddAssert("ruleset not changed", () => Ruleset.Value.Equals(new TaikoRuleset().RulesetInfo)); AddAssert("mods not changed", () => SelectedMods.Value.Single() is TaikoModDoubleTime); } @@ -133,10 +140,42 @@ public void TestAllowedModDeselectedWhenRequired(Type allowedMod, Type requiredM // A previous test's mod overlay could still be fading out. AddUntilStep("wait for only one freemod overlay", () => this.ChildrenOfType().Count() == 1); + AddStep("open free mod overlay", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + assertFreeModNotShown(allowedMod); assertFreeModNotShown(requiredMod); } + [Test] + public void TestFreeModsDisplayedOnEnter() + { + AddStep("set room freemods", () => + { + var editedItem = MultiplayerClient.ClientRoom!.CurrentPlaylistItem.Clone(); + + editedItem.AllowedMods = + [ + new APIMod(new OsuModHardRock()), + ]; + + MultiplayerClient.EditPlaylistItem(editedItem); + }); + + setUp(); + + AddStep("open free mod overlay", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + + assertFreeModShown(typeof(OsuModHardRock)); + } + [Test] public void TestChangeRulesetImmediatelyAfterLoadComplete() { @@ -154,16 +193,27 @@ public void TestChangeRulesetImmediatelyAfterLoadComplete() songSelect.OnLoadComplete += _ => Ruleset.Value = new TaikoRuleset().RulesetInfo; LoadScreen(songSelect); }); - AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && songSelect.BeatmapSetsLoaded); - AddStep("confirm selection", () => songSelect.FinaliseSelection()); + AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && !songSelect.IsFiltering); + + AddStep("confirm selection", () => InputManager.Key(Key.Enter)); AddAssert("beatmap is taiko", () => Beatmap.Value.BeatmapInfo.Ruleset.OnlineID, () => Is.EqualTo(1)); AddAssert("ruleset is taiko", () => Ruleset.Value.OnlineID, () => Is.EqualTo(1)); } + private void assertFreeModShown(Type type) + { + AddUntilStep($"{type.ReadableName()} displayed in freemod overlay", + () => this.ChildrenOfType() + .Single() + .ChildrenOfType() + .Where(panel => panel.Visible) + .Any(b => b.Mod.GetType() == type)); + } + private void assertFreeModNotShown(Type type) { - AddAssert($"{type.ReadableName()} not displayed in freemod overlay", + AddUntilStep($"{type.ReadableName()} not displayed in freemod overlay", () => this.ChildrenOfType() .Single() .ChildrenOfType() @@ -185,12 +235,12 @@ private partial class TestMultiplayerMatchSongSelect : MultiplayerMatchSongSelec public new Bindable> FreeMods => base.FreeMods; - public new BeatmapCarousel Carousel => base.Carousel; - public TestMultiplayerMatchSongSelect(Room room, PlaylistItem? itemToEdit = null) : base(room, itemToEdit) { } + + public void SelectBeatmap(BeatmapInfo beatmap) => SelectAndRun(beatmap, () => { }); } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs index fa0092eedb3a..87c1b67ba7d7 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs @@ -164,20 +164,20 @@ public void TestFreeModSelectionDisable() AddAssert("freestyle enabled", () => songSelect.Freestyle.Value, () => Is.True); AddStep("click icon in free mods button", () => { - InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); AddAssert("mod select not visible", () => this.ChildrenOfType().Single().State.Value, () => Is.EqualTo(Visibility.Hidden)); AddStep("toggle freestyle off", () => { - InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); AddAssert("freestyle disabled", () => songSelect.Freestyle.Value, () => Is.False); AddStep("click icon in free mods button", () => { - InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); AddAssert("mod select visible", () => this.ChildrenOfType().Single().State.Value, () => Is.EqualTo(Visibility.Visible)); diff --git a/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreeModsV2.cs b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreeModsV2.cs index 222b9a80f83d..52a24ae9f470 100644 --- a/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreeModsV2.cs +++ b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreeModsV2.cs @@ -17,13 +17,13 @@ public partial class TestSceneFooterButtonFreeModsV2 : OsuTestScene [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); - private readonly FooterButtonFreeModsV2 button; + private readonly FooterButtonFreeMods button; public TestSceneFooterButtonFreeModsV2() { ModSelectOverlay modSelectOverlay; Add(modSelectOverlay = new TestModSelectOverlay()); - Add(button = new FooterButtonFreeModsV2(modSelectOverlay) + Add(button = new FooterButtonFreeMods(modSelectOverlay) { Anchor = Anchor.Centre, Origin = Anchor.CentreLeft, diff --git a/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreestyleV2.cs b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreestyleV2.cs index 32c2c33db108..3eda3bd21da8 100644 --- a/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreestyleV2.cs +++ b/osu.Game.Tests/Visual/Playlists/TestSceneFooterButtonFreestyleV2.cs @@ -15,7 +15,7 @@ public partial class TestSceneFooterButtonFreestyleV2 : OsuTestScene public TestSceneFooterButtonFreestyleV2() { - Add(new FooterButtonFreestyleV2 + Add(new FooterButtonFreestyle { Anchor = Anchor.Centre, Origin = Anchor.CentreLeft, diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index e5aac279fba4..1e4d3484b7ea 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -34,6 +34,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Utils; using CommonStrings = osu.Game.Localisation.CommonStrings; +using SongSelect = osu.Game.Screens.SelectV2.SongSelect; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; namespace osu.Game.Online.Leaderboards diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 563922f31d21..b671360d7727 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -70,8 +70,8 @@ using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select; using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.SelectV2; using osu.Game.Seasonal; using osu.Game.Skinning; using osu.Game.Updater; @@ -762,7 +762,7 @@ public void PresentBeatmap(IBeatmapSetInfo beatmap, Predicate diffi } }, validScreens: new[] { - typeof(SongSelect), typeof(Screens.SelectV2.SongSelect), typeof(IHandlePresentBeatmap) + typeof(SongSelect), typeof(IHandlePresentBeatmap) }); } @@ -865,7 +865,7 @@ public void PresentScore(IScoreInfo score, ScorePresentType presentType = ScoreP // which may not match the score, and thus crash. IEnumerable validScreens = Beatmap.Value.BeatmapInfo.Equals(databasedBeatmap) && Ruleset.Value.Equals(databasedScore.ScoreInfo.Ruleset) - ? new[] { typeof(SongSelect), typeof(Screens.SelectV2.SongSelect), typeof(DailyChallenge) } + ? new[] { typeof(SongSelect), typeof(DailyChallenge) } : Array.Empty(); PerformFromScreen(screen => diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs b/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs index f8d5213622f0..efc305b4921e 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs @@ -14,7 +14,6 @@ using osu.Game.Screens; using osu.Game.Screens.SelectV2; using osuTK; -using SongSelect = osu.Game.Screens.Select.SongSelect; namespace osu.Game.Overlays.SkinEditor { diff --git a/osu.Game/Screens/Edit/Submission/BeatmapSubmissionScreen.cs b/osu.Game/Screens/Edit/Submission/BeatmapSubmissionScreen.cs index 78066edc7e07..8d78d76428e0 100644 --- a/osu.Game/Screens/Edit/Submission/BeatmapSubmissionScreen.cs +++ b/osu.Game/Screens/Edit/Submission/BeatmapSubmissionScreen.cs @@ -30,7 +30,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; -using osu.Game.Screens.Select; +using osu.Game.Screens.SelectV2; using osuTK; namespace osu.Game.Screens.Edit.Submission diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs index 7c632d16194e..aff9b803c653 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs @@ -1,146 +1,151 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// 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.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Framework.Utils; using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; +using osu.Game.Overlays; +using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Select; +using osu.Game.Screens.Footer; +using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.SelectV2; using osuTK; namespace osu.Game.Screens.OnlinePlay { - public partial class FooterButtonFreeMods : FooterButton + public partial class FooterButtonFreeMods : ScreenFooterButton { - public readonly Bindable> FreeMods = new Bindable>(); - public readonly IBindable Freestyle = new Bindable(); - - protected override bool IsActive => FreeMods.Value.Count > 0; + public readonly Bindable> FreeMods = new Bindable>([]); + public readonly Bindable Freestyle = new Bindable(); public new Action Action { set => throw new NotSupportedException("The click action is handled by the button itself."); } - private OsuSpriteText count = null!; - private Circle circle = null!; + [Resolved] + private OsuColour colours { get; set; } = null!; - private readonly FreeModSelectOverlay freeModSelectOverlay; + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; - public FooterButtonFreeMods(FreeModSelectOverlay freeModSelectOverlay) - { - this.freeModSelectOverlay = freeModSelectOverlay; + private Container modsWedge = null!; + private ModDisplay modDisplay = null!; + private Container modContainer = null!; + private FooterButtonMods.ModCountText overflowModCountDisplay = null!; - // Overwrite any external behaviour as we delegate the main toggle action to a sub-button. - base.Action = toggleAllFreeMods; + public FooterButtonFreeMods(ModSelectOverlay overlay) + : base(overlay) + { } - [Resolved] - private OsuColour colours { get; set; } = null!; - [BackgroundDependencyLoader] private void load() { - ButtonContentContainer.AddRange(new[] + Text = OnlinePlayStrings.FooterButtonFreemods; + Icon = FontAwesome.Solid.ExchangeAlt; + AccentColour = colours.Lime1; + + Add(modsWedge = new InputBlockingContainer { - new Container + Y = -5f, + Depth = float.MaxValue, + Origin = Anchor.BottomLeft, + Shear = OsuGame.SHEAR, + CornerRadius = CORNER_RADIUS, + Size = new Vector2(BUTTON_WIDTH, FooterButtonMods.BAR_HEIGHT), + Masking = true, + EdgeEffect = new EdgeEffectParameters { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] + Type = EdgeEffectType.Shadow, + Radius = 4, + // Figma says 50% opacity, but it does not match up visually if taken at face value, and looks bad. + Colour = Colour4.Black.Opacity(0.25f), + Offset = new Vector2(0, 2), + }, + Alpha = 0, + Children = new Drawable[] + { + new Box { - circle = new Circle - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.YellowDark, - RelativeSizeAxes = Axes.Both, - }, - count = new OsuSpriteText + Colour = colourProvider.Background4, + RelativeSizeAxes = Axes.Both, + }, + modContainer = new Container + { + CornerRadius = CORNER_RADIUS, + RelativeSizeAxes = Axes.Both, + Masking = true, + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Padding = new MarginPadding(5), - UseFullGlyphHeight = false, + modDisplay = new ModDisplay(showExtendedInformation: true) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Shear = -OsuGame.SHEAR, + Scale = new Vector2(0.5f), + Current = { BindTarget = FreeMods }, + ExpansionMode = ExpansionMode.AlwaysContracted, + }, + overflowModCountDisplay = new FooterButtonMods.ModCountText + { + Mods = { BindTarget = FreeMods }, + }, } - } - }, - new IconButton - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(0.8f), - Icon = FontAwesome.Solid.Bars, - Enabled = { BindTarget = Enabled }, - Action = () => freeModSelectOverlay.ToggleVisibility() + }, } }); - - SelectedColour = colours.Yellow; - DeselectedColour = SelectedColour.Opacity(0.5f); - Text = @"freemods"; - - TooltipText = MultiplayerMatchStrings.FreeModsButtonTooltip; } protected override void LoadComplete() { base.LoadComplete(); - Freestyle.BindValueChanged(_ => updateModDisplay()); - FreeMods.BindValueChanged(_ => updateModDisplay(), true); + Freestyle.BindValueChanged(f => + { + Enabled.Value = !f.NewValue; + overflowModCountDisplay.CustomText = f.NewValue ? ModSelectOverlayStrings.AllMods.ToUpper() : (LocalisableString?)null; + }, true); + FreeMods.BindValueChanged(m => + { + if (m.NewValue.Count == 0 && !Freestyle.Value) + modsWedge.FadeOut(300, Easing.OutExpo); + else + modsWedge.FadeIn(300, Easing.OutExpo); + }, true); } - /// - /// Immediately toggle all free mods on/off. - /// - private void toggleAllFreeMods() + protected override void Update() { - var availableMods = allAvailableAndValidMods.ToArray(); + base.Update(); - FreeMods.Value = FreeMods.Value.Count == availableMods.Length - ? Array.Empty() - : availableMods; - } + // If there are freemods selected but the display has no width, it's still loading. + // Don't update visibility in this state or we will cause an awkward flash. + if (FreeMods.Value.Count > 0 && Precision.AlmostEquals(modDisplay.DrawWidth, 0)) + return; - private void updateModDisplay() - { - int currentCount = FreeMods.Value.Count; + bool showCountText = + // When freestyle is enabled this text shows "ALL MODS" + Freestyle.Value + // Standard flow where mods are overflowing so we show count text. + || modDisplay.DrawWidth * modDisplay.Scale.X > modContainer.DrawWidth; - if (currentCount == allAvailableAndValidMods.Count() || Freestyle.Value) - { - count.Text = "all"; - count.FadeColour(colours.Gray2, 200, Easing.OutQuint); - circle.FadeColour(colours.Yellow, 200, Easing.OutQuint); - } - else if (currentCount > 0) - { - count.Text = $"{currentCount} mods"; - count.FadeColour(colours.Gray2, 200, Easing.OutQuint); - circle.FadeColour(colours.YellowDark, 200, Easing.OutQuint); - } + if (showCountText) + overflowModCountDisplay.Show(); else - { - count.Text = "off"; - count.FadeColour(colours.GrayF, 200, Easing.OutQuint); - circle.FadeColour(colours.Gray4, 200, Easing.OutQuint); - } + overflowModCountDisplay.Hide(); } - - private IEnumerable allAvailableAndValidMods => freeModSelectOverlay.AllAvailableMods - .Where(state => state.ValidForSelection.Value) - .Select(state => state.Mod); } } diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs deleted file mode 100644 index 612eca9474cd..000000000000 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeModsV2.cs +++ /dev/null @@ -1,151 +0,0 @@ -// 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.Collections.Generic; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.LocalisationExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Localisation; -using osu.Framework.Utils; -using osu.Game.Graphics; -using osu.Game.Localisation; -using osu.Game.Overlays; -using osu.Game.Overlays.Mods; -using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Footer; -using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.SelectV2; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay -{ - public partial class FooterButtonFreeModsV2 : ScreenFooterButton - { - public readonly Bindable> FreeMods = new Bindable>([]); - public readonly Bindable Freestyle = new Bindable(); - - public new Action Action - { - set => throw new NotSupportedException("The click action is handled by the button itself."); - } - - [Resolved] - private OsuColour colours { get; set; } = null!; - - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; - - private Container modsWedge = null!; - private ModDisplay modDisplay = null!; - private Container modContainer = null!; - private FooterButtonMods.ModCountText overflowModCountDisplay = null!; - - public FooterButtonFreeModsV2(ModSelectOverlay overlay) - : base(overlay) - { - } - - [BackgroundDependencyLoader] - private void load() - { - Text = OnlinePlayStrings.FooterButtonFreemods; - Icon = FontAwesome.Solid.ExchangeAlt; - AccentColour = colours.Lime1; - - Add(modsWedge = new InputBlockingContainer - { - Y = -5f, - Depth = float.MaxValue, - Origin = Anchor.BottomLeft, - Shear = OsuGame.SHEAR, - CornerRadius = CORNER_RADIUS, - Size = new Vector2(BUTTON_WIDTH, FooterButtonMods.BAR_HEIGHT), - Masking = true, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Radius = 4, - // Figma says 50% opacity, but it does not match up visually if taken at face value, and looks bad. - Colour = Colour4.Black.Opacity(0.25f), - Offset = new Vector2(0, 2), - }, - Alpha = 0, - Children = new Drawable[] - { - new Box - { - Colour = colourProvider.Background4, - RelativeSizeAxes = Axes.Both, - }, - modContainer = new Container - { - CornerRadius = CORNER_RADIUS, - RelativeSizeAxes = Axes.Both, - Masking = true, - Children = new Drawable[] - { - modDisplay = new ModDisplay(showExtendedInformation: true) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Shear = -OsuGame.SHEAR, - Scale = new Vector2(0.5f), - Current = { BindTarget = FreeMods }, - ExpansionMode = ExpansionMode.AlwaysContracted, - }, - overflowModCountDisplay = new FooterButtonMods.ModCountText - { - Mods = { BindTarget = FreeMods }, - }, - } - }, - } - }); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - Freestyle.BindValueChanged(f => - { - Enabled.Value = !f.NewValue; - overflowModCountDisplay.CustomText = f.NewValue ? ModSelectOverlayStrings.AllMods.ToUpper() : (LocalisableString?)null; - }, true); - FreeMods.BindValueChanged(m => - { - if (m.NewValue.Count == 0 && !Freestyle.Value) - modsWedge.FadeOut(300, Easing.OutExpo); - else - modsWedge.FadeIn(300, Easing.OutExpo); - }, true); - } - - protected override void Update() - { - base.Update(); - - // If there are freemods selected but the display has no width, it's still loading. - // Don't update visibility in this state or we will cause an awkward flash. - if (FreeMods.Value.Count > 0 && Precision.AlmostEquals(modDisplay.DrawWidth, 0)) - return; - - bool showCountText = - // When freestyle is enabled this text shows "ALL MODS" - Freestyle.Value - // Standard flow where mods are overflowing so we show count text. - || modDisplay.DrawWidth * modDisplay.Scale.X > modContainer.DrawWidth; - - if (showCountText) - overflowModCountDisplay.Show(); - else - overflowModCountDisplay.Hide(); - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyle.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyle.cs index c4edcec97697..51b5020c94b9 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyle.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyle.cs @@ -4,31 +4,23 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; using osu.Game.Localisation; -using osu.Game.Screens.Select; +using osu.Game.Screens.Footer; namespace osu.Game.Screens.OnlinePlay { - public partial class FooterButtonFreestyle : FooterButton + public partial class FooterButtonFreestyle : ScreenFooterButton { public readonly Bindable Freestyle = new Bindable(); - protected override bool IsActive => Freestyle.Value; - public new Action Action { set => throw new NotSupportedException("The click action is handled by the button itself."); } - private OsuSpriteText text = null!; - private Circle circle = null!; - [Resolved] private OsuColour colours { get; set; } = null!; @@ -41,61 +33,19 @@ public FooterButtonFreestyle() [BackgroundDependencyLoader] private void load() { - ButtonContentContainer.AddRange(new[] - { - new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - circle = new Circle - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.YellowDark, - RelativeSizeAxes = Axes.Both, - }, - text = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Padding = new MarginPadding(5), - UseFullGlyphHeight = false, - } - } - } - }); - - SelectedColour = colours.Yellow; - DeselectedColour = SelectedColour.Opacity(0.5f); - Text = @"freestyle"; - - TooltipText = MultiplayerMatchStrings.FreestyleButtonTooltip; + Text = OnlinePlayStrings.FooterButtonFreestyle; + Icon = FontAwesome.Solid.ExchangeAlt; + AccentColour = colours.Lime1; } protected override void LoadComplete() { base.LoadComplete(); - Freestyle.BindValueChanged(_ => updateDisplay(), true); - } - - private void updateDisplay() - { - if (Freestyle.Value) - { - text.Text = "on"; - text.FadeColour(colours.Gray2, 200, Easing.OutQuint); - circle.FadeColour(colours.Yellow, 200, Easing.OutQuint); - } - else + Freestyle.BindValueChanged(active => { - text.Text = "off"; - text.FadeColour(colours.GrayF, 200, Easing.OutQuint); - circle.FadeColour(colours.Gray4, 200, Easing.OutQuint); - } + OverlayState.Value = active.NewValue ? Visibility.Visible : Visibility.Hidden; + }, true); } } } diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs deleted file mode 100644 index e7e33855ac09..000000000000 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyleV2.cs +++ /dev/null @@ -1,51 +0,0 @@ -// 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 osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; -using osu.Game.Localisation; -using osu.Game.Screens.Footer; - -namespace osu.Game.Screens.OnlinePlay -{ - public partial class FooterButtonFreestyleV2 : ScreenFooterButton - { - public readonly Bindable Freestyle = new Bindable(); - - public new Action Action - { - set => throw new NotSupportedException("The click action is handled by the button itself."); - } - - [Resolved] - private OsuColour colours { get; set; } = null!; - - public FooterButtonFreestyleV2() - { - // Overwrite any external behaviour as we delegate the main toggle action to a sub-button. - base.Action = () => Freestyle.Value = !Freestyle.Value; - } - - [BackgroundDependencyLoader] - private void load() - { - Text = OnlinePlayStrings.FooterButtonFreestyle; - Icon = FontAwesome.Solid.ExchangeAlt; - AccentColour = colours.Lime1; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - Freestyle.BindValueChanged(active => - { - OverlayState.Value = active.NewValue ? Visibility.Visible : Visibility.Hidden; - }, true); - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 41239cd7a8dc..f234bed697b3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -23,9 +23,10 @@ using osu.Game.Overlays.Mods; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Select; +using osu.Game.Screens.Footer; using osu.Game.Users; using osu.Game.Utils; +using osu.Game.Screens.SelectV2; namespace osu.Game.Screens.OnlinePlay.Multiplayer { @@ -35,18 +36,20 @@ public partial class MultiplayerMatchSongSelect : SongSelect, IOnlinePlaySubScre public override string Title => ShortTitle.Humanize(); - public override bool AllowEditing => false; - [Resolved] private MultiplayerClient client { get; set; } = null!; [Resolved] private OngoingOperationTracker operationTracker { get; set; } = null!; + [Resolved] + private IOverlayManager? overlayManager { get; set; } + private readonly Room room; private readonly IBindable operationInProgress = new Bindable(); private readonly PlaylistItem? itemToEdit; + private ModSelectOverlay modSelect = null!; private LoadingLayer loadingLayer = null!; private IDisposable? selectionOperation; @@ -64,7 +67,6 @@ public partial class MultiplayerMatchSongSelect : SongSelect, IOnlinePlaySubScre private readonly PlaylistItem? initialItem; private readonly FreeModSelectOverlay freeModSelect; - private FooterButton freeModsFooterButton = null!; private IDisposable? freeModSelectOverlayRegistration; @@ -80,6 +82,7 @@ public MultiplayerMatchSongSelect(Room room, PlaylistItem? itemToEdit = null) initialItem = itemToEdit ?? room.Playlist.LastOrDefault(); Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; + LeftPadding = new MarginPadding { Top = CORNER_RADIUS_HIDE_OFFSET + Header.HEIGHT }; freeModSelect = new FreeModSelectOverlay { @@ -91,10 +94,11 @@ public MultiplayerMatchSongSelect(Room room, PlaylistItem? itemToEdit = null) [BackgroundDependencyLoader] private void load() { - LeftArea.Padding = new MarginPadding { Top = Header.HEIGHT }; - LoadComponent(freeModSelect); - AddInternal(loadingLayer = new LoadingLayer(true)); + AddInternal(loadingLayer = new LoadingLayer(true) + { + BlockNonPositionalInput = true, + }); } protected override void LoadComplete() @@ -138,7 +142,7 @@ protected override void LoadComplete() Ruleset.BindValueChanged(onRulesetChanged); freestyle.BindValueChanged(onFreestyleChanged); - freeModSelectOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(freeModSelect); + freeModSelectOverlayRegistration = overlayManager?.RegisterBlockingOverlay(freeModSelect); updateFooterButtons(); updateValidMods(); @@ -153,8 +157,6 @@ protected override void LoadComplete() }, true); } - protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); - private void onFreestyleChanged(ValueChangedEvent enabled) { updateFooterButtons(); @@ -184,12 +186,7 @@ private void onRulesetChanged(ValueChangedEvent ruleset) private void updateFooterButtons() { if (freestyle.Value) - { - freeModsFooterButton.Enabled.Value = false; freeModSelect.Hide(); - } - else - freeModsFooterButton.Enabled.Value = true; } /// @@ -206,11 +203,11 @@ private void updateValidMods() if (!validFreeMods.SequenceEqual(FreeMods.Value)) FreeMods.Value = validFreeMods; - ModSelect.IsValidMod = isValidRequiredMod; + modSelect.IsValidMod = isValidRequiredMod; freeModSelect.IsValidMod = isValidAllowedMod; } - protected sealed override bool OnStart() + protected sealed override void OnStart() { var item = new PlaylistItem(Beatmap.Value.BeatmapInfo) { @@ -220,7 +217,7 @@ protected sealed override bool OnStart() Freestyle = freestyle.Value }; - return selectItem(item); + selectItem(item); } private bool selectItem(PlaylistItem item) @@ -263,11 +260,6 @@ private bool selectItem(PlaylistItem item) }, onError: _ => { selectionOperation.Dispose(); - - Schedule(() => - { - Carousel.AllowSelection = true; - }); }); } else @@ -296,31 +288,31 @@ public override bool OnExiting(ScreenExitEvent e) return base.OnExiting(e); } - protected override ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay(OverlayColourScheme.Plum) + protected override ModSelectOverlay CreateModSelectOverlay() => modSelect = new UserModSelectOverlay(OverlayColourScheme.Plum) { IsValidMod = isValidRequiredMod }; - protected override IEnumerable<(FooterButton button, OverlayContainer? overlay)> CreateSongSelectFooterButtons() + public override IReadOnlyList CreateFooterButtons() { - var baseButtons = base.CreateSongSelectFooterButtons().ToList(); + var buttons = base.CreateFooterButtons().ToList(); - baseButtons.Single(i => i.button is FooterButtonMods).button.TooltipText = MultiplayerMatchStrings.RequiredModsButtonTooltip; + buttons.Single(i => i is FooterButtonMods).TooltipText = MultiplayerMatchStrings.RequiredModsButtonTooltip; - baseButtons.InsertRange(baseButtons.FindIndex(b => b.button is FooterButtonMods) + 1, new (FooterButton, OverlayContainer?)[] - { - (freeModsFooterButton = new FooterButtonFreeMods(freeModSelect) + buttons.InsertRange(buttons.FindIndex(b => b is FooterButtonMods) + 1, + [ + new FooterButtonFreeMods(freeModSelect) { FreeMods = { BindTarget = FreeMods }, Freestyle = { BindTarget = freestyle } - }, null), - (new FooterButtonFreestyle + }, + new FooterButtonFreestyle { Freestyle = { BindTarget = freestyle } - }, null) - }); + } + ]); - return baseButtons; + return buttons; } /// diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs index 60a3133758da..fb921f219a06 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs @@ -211,12 +211,12 @@ public override IReadOnlyList CreateFooterButtons() buttons.InsertRange(buttons.FindIndex(b => b is FooterButtonMods) + 1, [ - new FooterButtonFreeModsV2(freeModSelect) + new FooterButtonFreeMods(freeModSelect) { FreeMods = { BindTarget = freeMods }, Freestyle = { BindTarget = Freestyle } }, - new FooterButtonFreestyleV2 + new FooterButtonFreestyle { Freestyle = { BindTarget = Freestyle } } diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index a535d827d6b4..b12d6d1018f1 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -396,19 +396,6 @@ protected override void LoadComplete() if (ShowOsuLogo) logo?.FadeTo(v.NewValue == Visibility.Visible ? 0f : 1f, 200, Easing.OutQuint); }); - - Beatmap.BindValueChanged(_ => - { - if (!this.IsCurrentScreen()) - return; - - ensureGlobalBeatmapValid(); - - ensurePlayingSelected(); - updateBackgroundDim(); - updateWedgeVisibility(); - fetchOnlineInfo(); - }); } protected override void Update() @@ -554,7 +541,7 @@ private void ensureTrackLooping(IWorkingBeatmap beatmap, TrackChangeDirection ch /// /// The beatmap which should be selected. If not provided, the current globally selected beatmap will be used. /// The action to perform if conditions are met to be able to proceed. May not be invoked if in an invalid state. - public void SelectAndRun(BeatmapInfo beatmap, Action startAction) + protected void SelectAndRun(BeatmapInfo beatmap, Action startAction) { if (!this.IsCurrentScreen()) return; @@ -726,8 +713,6 @@ private void onArrivingAtScreen() carousel.VisuallyFocusSelected = false; - updateWedgeVisibility(); - if (ControlGlobalMusic) { // Avoid abruptly starting playback at preview point. @@ -746,17 +731,28 @@ private void onArrivingAtScreen() beginLooping(); } + Beatmap.BindValueChanged(updateVariousState, true); + } + + private void updateVariousState(ValueChangedEvent e) + { + if (!this.IsCurrentScreen()) + return; + ensureGlobalBeatmapValid(); ensurePlayingSelected(); updateBackgroundDim(); - fetchOnlineInfo(force: true); + updateWedgeVisibility(); + fetchOnlineInfo(force: ReferenceEquals(e.OldValue, e.NewValue)); } private void onLeavingScreen() { restoreBackground(); + Beatmap.ValueChanged -= updateVariousState; + modSelectOverlay.SelectedMods.UnbindFrom(Mods); modSelectOverlay.Beatmap.UnbindFrom(Beatmap); From d60a12a3517af15e082ea85a3fd37ff793787e76 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Mar 2026 14:03:55 +0900 Subject: [PATCH 725/836] Fix ordering of skins not working as expected (#36772) As mentioned [here](https://github.com/ppy/osu/pull/11536#issuecomment-3977314909). Realm ordering is weird/broken so let's just do it at our end. --- osu.Game/Skinning/SkinManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index dfb549754285..e62b2a150c83 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -158,11 +158,11 @@ public IList> GetAllUsableSkins() var userSkins = realm.All() .Where(s => !s.DeletePending && !s.Protected) - .OrderBy(s => s.Name, StringComparer.OrdinalIgnoreCase) .AsEnumerable() + .OrderBy(s => s.Name, StringComparer.OrdinalIgnoreCase) .Select(s => s.ToLive(Realm)); - foreach (var s in userSkins.Where(s => !s.Value.Protected)) + foreach (var s in userSkins) skins.Add(s); }); From b0759ff34dbdcec73eba118a1d2f35e7f2e1167d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Mar 2026 15:36:46 +0900 Subject: [PATCH 726/836] Fix song select carousel state capture Closes #36776. --- osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs b/osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs index 835a83998ad3..5f1488513aa6 100644 --- a/osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs +++ b/osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs @@ -220,6 +220,8 @@ private partial class ScrollBar : ScrollbarContainer private readonly Drawable box; + private bool capturingMouseDown; + protected override float MinimumDimSize => SCROLL_BAR_WIDTH * 3; private const float expanded_size_ratio = 2; @@ -280,6 +282,7 @@ protected override bool OnMouseDown(MouseDownEvent e) { if (!base.OnMouseDown(e)) return false; + capturingMouseDown = true; updateVisuals(e); return true; } @@ -294,13 +297,14 @@ protected override void OnMouseUp(MouseUpEvent e) { if (e.Button != MouseButton.Left) return; + capturingMouseDown = false; updateVisuals(e); base.OnMouseUp(e); } private void updateVisuals(MouseEvent e) { - if (IsDragged || e.PressedButtons.Contains(MouseButton.Left)) + if (capturingMouseDown) box.FadeColour(highlightColour, 100); else if (IsHovered) box.FadeColour(hoverColour, 100); From c372f9b8f538cec50a085003b4d2758224fa79fc Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 2 Mar 2026 22:37:19 -0800 Subject: [PATCH 727/836] Standardise display order of playcount / favourites --- .../Drawables/Cards/BeatmapCardExtra.cs | 18 +++++++++--------- .../Drawables/Cards/BeatmapCardNormal.cs | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs index 222acbc03989..4c4a0637084f 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs @@ -296,20 +296,20 @@ BeatmapCardStatistic withMargin(BeatmapCardStatistic original) return original; } - statisticsContainer.Content[0][0] = withMargin(new FavouritesStatistic(BeatmapSet) - { - Current = FavouriteState, - }); - - statisticsContainer.Content[1][0] = withMargin(new PlayCountStatistic(BeatmapSet)); - var hypesStatistic = HypesStatistic.CreateFor(BeatmapSet); if (hypesStatistic != null) - statisticsContainer.Content[0][1] = withMargin(hypesStatistic); + statisticsContainer.Content[0][0] = withMargin(hypesStatistic); var nominationsStatistic = NominationsStatistic.CreateFor(BeatmapSet); if (nominationsStatistic != null) - statisticsContainer.Content[1][1] = withMargin(nominationsStatistic); + statisticsContainer.Content[1][0] = withMargin(nominationsStatistic); + + statisticsContainer.Content[0][1] = withMargin(new PlayCountStatistic(BeatmapSet)); + + statisticsContainer.Content[1][1] = withMargin(new FavouritesStatistic(BeatmapSet) + { + Current = FavouriteState, + }); var dateStatistic = BeatmapCardDateStatistic.CreateFor(BeatmapSet); if (dateStatistic != null) diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs index ac9ee94f5611..6974cf81ea92 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs @@ -278,8 +278,8 @@ private IEnumerable createStatistics() if (nominationsStatistic != null) yield return nominationsStatistic; - yield return new FavouritesStatistic(BeatmapSet) { Current = FavouriteState }; yield return new PlayCountStatistic(BeatmapSet); + yield return new FavouritesStatistic(BeatmapSet) { Current = FavouriteState }; var dateStatistic = BeatmapCardDateStatistic.CreateFor(BeatmapSet); if (dateStatistic != null) From b831bcbcd469459323a3400a17f0aa32c590e8d4 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 2 Mar 2026 22:40:16 -0800 Subject: [PATCH 728/836] Change beatmap card play count and date icon to solid to match web --- .../Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs | 2 +- .../Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs index 861ec9f0274a..cb4c548556a3 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs @@ -17,7 +17,7 @@ private BeatmapCardDateStatistic(DateTimeOffset dateTime) { this.dateTime = dateTime; - Icon = FontAwesome.Regular.CheckCircle; + Icon = FontAwesome.Solid.CheckCircle; Text = dateTime.ToLocalisedMediumDate(); } diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs index 4ce37b865948..8b6e23862584 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs @@ -15,7 +15,7 @@ public partial class PlayCountStatistic : BeatmapCardStatistic { public PlayCountStatistic(IBeatmapSetOnlineInfo onlineInfo) { - Icon = FontAwesome.Regular.PlayCircle; + Icon = FontAwesome.Solid.PlayCircle; Text = onlineInfo.PlayCount.ToMetric(decimals: 1); TooltipText = BeatmapsStrings.PanelPlaycount(onlineInfo.PlayCount.ToLocalisableString(@"N0")); } From 7dfbab212eab1a48bcaf0ba17f2c664e24041815 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 2 Mar 2026 22:42:41 -0800 Subject: [PATCH 729/836] Add nominations statistic to beatmap info overlay See https://github.com/ppy/osu-web/blob/2198adfa68bf24709c3b0cc2e6d838e86be5b1d1/resources/js/beatmapsets-show/header.tsx#L116-L123. --- .../Visual/Online/TestSceneBeatmapSetOverlay.cs | 4 ++++ osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index b164c530cb26..227e15ccf705 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -72,6 +72,10 @@ public void TestLocalBeatmaps() Preview = @"https://b.ppy.sh/preview/12345.mp3", PlayCount = 123, FavouriteCount = 456, + NominationStatus = new BeatmapSetNominationStatus + { + Current = 2, + }, Submitted = DateTime.Now, Ranked = DateTime.Now, BPM = 111, diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index f2630caa831e..94aa63927484 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Extensions; using osu.Game.Graphics; @@ -32,7 +33,7 @@ public partial class BeatmapPicker : Container private const float tile_spacing = 2; private readonly LinkFlowContainer infoContainer; - private readonly Statistic plays, favourites; + private readonly Statistic nominations, plays, favourites; public readonly DifficultiesContainer Difficulties; @@ -107,6 +108,7 @@ public BeatmapPicker() Margin = new MarginPadding { Top = 5 }, Children = new[] { + nominations = new Statistic(FontAwesome.Solid.ThumbsUp), plays = new Statistic(FontAwesome.Solid.PlayCircle), favourites = new Statistic(FontAwesome.Solid.Heart), }, @@ -176,6 +178,14 @@ private void updateDisplay() // Else just choose the first available difficulty for now. Beatmap.Value ??= Difficulties.FirstOrDefault()?.Beatmap; + if (beatmapSet?.Status == BeatmapOnlineStatus.Pending && beatmapSet.NominationStatus != null) + { + nominations.Show(); + nominations.Value = beatmapSet.NominationStatus.Current; + } + else + nominations.Hide(); + plays.Value = BeatmapSet?.PlayCount ?? 0; favourites.Value = BeatmapSet?.FavouriteCount ?? 0; From 564b6ebd0c5bf35e830f13dd20dfd65f1e68882f Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 2 Mar 2026 22:53:09 -0800 Subject: [PATCH 730/836] Add tooltips to beatmap info overlay statistics --- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 94aa63927484..59b0547d4ee8 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -9,6 +9,7 @@ using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; @@ -108,8 +109,14 @@ public BeatmapPicker() Margin = new MarginPadding { Top = 5 }, Children = new[] { - nominations = new Statistic(FontAwesome.Solid.ThumbsUp), - plays = new Statistic(FontAwesome.Solid.PlayCircle), + nominations = new Statistic(FontAwesome.Solid.ThumbsUp) + { + TooltipText = BeatmapsetsStrings.ShowStatsNominations, + }, + plays = new Statistic(FontAwesome.Solid.PlayCircle) + { + TooltipText = BeatmapsetsStrings.ShowStatsPlaycount, + }, favourites = new Statistic(FontAwesome.Solid.Heart), }, }, @@ -188,6 +195,7 @@ private void updateDisplay() plays.Value = BeatmapSet?.PlayCount ?? 0; favourites.Value = BeatmapSet?.FavouriteCount ?? 0; + favourites.TooltipText = BeatmapSet?.FavouriteCount > 0 ? BeatmapsetsStrings.ShowStatsFavourites : BeatmapsetsStrings.ShowStatsNoFavourites; updateDifficultyButtons(); } @@ -377,7 +385,7 @@ private void load(OverlayColourProvider colourProvider) } } - private partial class Statistic : FillFlowContainer + private partial class Statistic : FillFlowContainer, IHasTooltip { private readonly OsuSpriteText text; @@ -417,6 +425,8 @@ public Statistic(IconUsage icon) }, }; } + + public LocalisableString TooltipText { get; set; } } public enum DifficultySelectorState From 521a40d86025d71b927c16913dd26e035419b278 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 02:19:52 +0900 Subject: [PATCH 731/836] Remove now unused footer buttons From a7e62863969d382836fd1ae9a48d25a4cce10ae4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 16:44:48 +0900 Subject: [PATCH 732/836] Fix a few remaining references to old song select From f20d1827758973c9709610ca95cbe8c2b7fe8da5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 18:52:58 +0900 Subject: [PATCH 733/836] Update filter matching tests to be independent of old song select classes --- .../BenchmarkCarouselFilter.cs | 6 +++--- .../NonVisual/Filtering/FilterMatchingTest.cs | 20 +++++++++++++++++++ .../Filtering/FilterQueryParserTest.cs | 3 +-- .../SelectV2/BeatmapCarouselFilterMatching.cs | 4 ++-- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/osu.Game.Benchmarks/BenchmarkCarouselFilter.cs b/osu.Game.Benchmarks/BenchmarkCarouselFilter.cs index 8f7027da1772..ecd76872d184 100644 --- a/osu.Game.Benchmarks/BenchmarkCarouselFilter.cs +++ b/osu.Game.Benchmarks/BenchmarkCarouselFilter.cs @@ -5,7 +5,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Carousel; +using osu.Game.Tests.NonVisual.Filtering; namespace osu.Game.Benchmarks { @@ -42,7 +42,7 @@ public class BenchmarkCarouselFilter : BenchmarkTest Status = BeatmapOnlineStatus.Loved }; - private CarouselBeatmap carouselBeatmap = null!; + private FilterMatchingTest.CarouselBeatmap carouselBeatmap = null!; private FilterCriteria criteria1 = null!; private FilterCriteria criteria2 = null!; private FilterCriteria criteria3 = null!; @@ -55,7 +55,7 @@ public override void SetUp() var beatmap = getExampleBeatmap(); beatmap.OnlineID = 20201010; beatmap.BeatmapSet = new BeatmapSetInfo { OnlineID = 1535 }; - carouselBeatmap = new CarouselBeatmap(beatmap); + carouselBeatmap = new FilterMatchingTest.CarouselBeatmap(beatmap); criteria1 = new FilterCriteria(); criteria2 = new FilterCriteria { diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs index 12aab055adf2..7dcb8621bfde 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs @@ -588,6 +588,26 @@ public void TestNotEqualSearchForDateFilter(string query, int[] expectedBeatmapI Assert.That(visibleBeatmaps, Is.EqualTo(expectedBeatmapIndexes)); } + // This is a temporary class that emulates what these tests originally used from song select v1. + // If anyone ever ends up tidying up these test, here's a starting point: + // https://gist.github.com/peppy/67fda38f6483fd1dd01ef845ed5bf932 + public class CarouselBeatmap + { + public readonly BeatmapInfo BeatmapInfo; + + public BindableBool Filtered = new BindableBool(); + + public CarouselBeatmap(BeatmapInfo beatmapInfo) + { + BeatmapInfo = beatmapInfo; + } + + public void Filter(FilterCriteria criteria) + { + Filtered.Value = !BeatmapCarouselFilterMatching.CheckCriteriaMatch(BeatmapInfo, criteria); + } + } + private class CustomCriteria : IRulesetFilterCriteria { private readonly bool match; diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 87e439534bbd..6a87cc1207e8 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -10,7 +10,6 @@ using osu.Game.Rulesets.Filter; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Carousel; using osu.Game.Screens.Select.Filter; namespace osu.Game.Tests.NonVisual.Filtering @@ -509,7 +508,7 @@ public void TestDifficultySearch(string query, int[] expectedBeatmapIndexes) ("Another One", "diff ]with [[ brackets]]]"), ("Diff in title", "a"), ("a", "Diff in diff"), - }).Select(info => new CarouselBeatmap(new BeatmapInfo + }).Select(info => new FilterMatchingTest.CarouselBeatmap(new BeatmapInfo { Metadata = new BeatmapMetadata { diff --git a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs b/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs index 31e6c790f2e7..80f7f058f789 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs @@ -42,7 +42,7 @@ private IEnumerable matchItems(IEnumerable items, Fi if (beatmap.Hidden) continue; - if (!checkCriteriaMatch(beatmap, criteria)) + if (!CheckCriteriaMatch(beatmap, criteria)) continue; countMatching++; @@ -52,7 +52,7 @@ private IEnumerable matchItems(IEnumerable items, Fi BeatmapItemsCount = countMatching; } - private static bool checkCriteriaMatch(BeatmapInfo beatmap, FilterCriteria criteria) + public static bool CheckCriteriaMatch(BeatmapInfo beatmap, FilterCriteria criteria) { bool match = criteria.Ruleset == null || beatmap.AllowGameplayWithRuleset(criteria.Ruleset!, criteria.AllowConvertedBeatmaps); From ce542b03db2dade2aa153ba545f52c8b56b6f685 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 17:58:46 +0900 Subject: [PATCH 734/836] Move components only used by beatmap set overlay local to namespace --- .../TestSceneAdvancedStats.cs | 4 +-- .../Online/TestSceneBeatmapSetOverlay.cs | 1 - .../TestSceneBeatmapSetOverlayDetails.cs | 1 - .../TestSceneBeatmapSetOverlaySuccessRate.cs | 1 - .../BeatmapSet}/AdvancedStats.cs | 28 +++++++++---------- osu.Game/Overlays/BeatmapSet/Details.cs | 1 - .../BeatmapSet}/FailRetryGraph.cs | 6 ++-- osu.Game/Overlays/BeatmapSet/SuccessRate.cs | 1 - .../BeatmapSet}/UserRatings.cs | 2 +- 9 files changed, 20 insertions(+), 25 deletions(-) rename osu.Game.Tests/Visual/{SongSelect => Online}/TestSceneAdvancedStats.cs (99%) rename osu.Game/{Screens/Select/Details => Overlays/BeatmapSet}/AdvancedStats.cs (99%) rename osu.Game/{Screens/Select/Details => Overlays/BeatmapSet}/FailRetryGraph.cs (98%) rename osu.Game/{Screens/Select/Details => Overlays/BeatmapSet}/UserRatings.cs (99%) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs b/osu.Game.Tests/Visual/Online/TestSceneAdvancedStats.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs rename to osu.Game.Tests/Visual/Online/TestSceneAdvancedStats.cs index 3afc8cd1a4a7..2ceb8ff0be55 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneAdvancedStats.cs @@ -12,15 +12,15 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Localisation; +using osu.Game.Overlays.BeatmapSet; using osu.Game.Rulesets; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Select.Details; using osuTK.Graphics; -namespace osu.Game.Tests.Visual.SongSelect +namespace osu.Game.Tests.Visual.Online { [System.ComponentModel.Description("Advanced beatmap statistics display")] public partial class TestSceneAdvancedStats : OsuTestScene diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index b164c530cb26..13d668e58c69 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -22,7 +22,6 @@ using osu.Game.Overlays.BeatmapSet.Scores; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Select.Details; using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Online diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs index 69c9faa9d365..89be688cf2fa 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs @@ -12,7 +12,6 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; -using osu.Game.Screens.Select.Details; namespace osu.Game.Tests.Visual.Online { diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs index 59c96ec7195d..7f88f1ebd1c3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs @@ -16,7 +16,6 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; -using osu.Game.Screens.Select.Details; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Overlays/BeatmapSet/AdvancedStats.cs similarity index 99% rename from osu.Game/Screens/Select/Details/AdvancedStats.cs rename to osu.Game/Overlays/BeatmapSet/AdvancedStats.cs index 2d105ae382a4..ae2b421edce4 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Overlays/BeatmapSet/AdvancedStats.cs @@ -4,36 +4,36 @@ #nullable disable using System; -using osuTK.Graphics; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Beatmaps; -using osu.Framework.Bindables; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using osu.Game.Rulesets.Mods; using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; using osu.Framework.Threading; using osu.Framework.Utils; +using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Mods; using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; -using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; using osu.Game.Utils; +using osuTK.Graphics; -namespace osu.Game.Screens.Select.Details +namespace osu.Game.Overlays.BeatmapSet { public partial class AdvancedStats : Container { diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs index 7d69cb73293e..50c5d5e4c515 100644 --- a/osu.Game/Overlays/BeatmapSet/Details.cs +++ b/osu.Game/Overlays/BeatmapSet/Details.cs @@ -11,7 +11,6 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.BeatmapSet.Buttons; using osu.Game.Rulesets; -using osu.Game.Screens.Select.Details; using osuTK; namespace osu.Game.Overlays.BeatmapSet diff --git a/osu.Game/Screens/Select/Details/FailRetryGraph.cs b/osu.Game/Overlays/BeatmapSet/FailRetryGraph.cs similarity index 98% rename from osu.Game/Screens/Select/Details/FailRetryGraph.cs rename to osu.Game/Overlays/BeatmapSet/FailRetryGraph.cs index 9891ef6463dc..697c879a35f5 100644 --- a/osu.Game/Screens/Select/Details/FailRetryGraph.cs +++ b/osu.Game/Overlays/BeatmapSet/FailRetryGraph.cs @@ -4,15 +4,15 @@ #nullable disable using System; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -using System.Linq; -using osu.Game.Beatmaps; -namespace osu.Game.Screens.Select.Details +namespace osu.Game.Overlays.BeatmapSet { public partial class FailRetryGraph : Container { diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index 48732ac586a1..28190580da76 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -14,7 +14,6 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; -using osu.Game.Screens.Select.Details; namespace osu.Game.Overlays.BeatmapSet { diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Overlays/BeatmapSet/UserRatings.cs similarity index 99% rename from osu.Game/Screens/Select/Details/UserRatings.cs rename to osu.Game/Overlays/BeatmapSet/UserRatings.cs index 3664a893942e..3f65c055f8ef 100644 --- a/osu.Game/Screens/Select/Details/UserRatings.cs +++ b/osu.Game/Overlays/BeatmapSet/UserRatings.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Resources.Localisation.Web; -namespace osu.Game.Screens.Select.Details +namespace osu.Game.Overlays.BeatmapSet { public partial class UserRatings : Container { From 54a1417dd87732301b4c8355705950a8950c0134 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 18:15:51 +0900 Subject: [PATCH 735/836] Move leaderboards classes to gameplay namespace for now --- ...stSceneDrawableGameplayLeaderboardScore.cs | 2 +- .../Gameplay/TestSceneGameplayLeaderboard.cs | 2 +- .../TestSceneHUDOverlayRulesetLayouts.cs | 2 +- .../TestSceneSkinEditorMultipleSkins.cs | 2 +- .../Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +- ...estSceneSoloGameplayLeaderboardProvider.cs | 2 +- ...MultiplayerGameplayLeaderboardTestScene.cs | 2 +- .../TestSceneMultiSpectatorLeaderboard.cs | 2 +- ...TestSceneMultiplayerGameplayLeaderboard.cs | 2 +- ...ceneMultiplayerGameplayLeaderboardTeams.cs | 2 +- .../TestSceneMultiplayerPositionDisplay.cs | 2 +- .../Navigation/TestSceneScreenNavigation.cs | 2 +- .../TestSceneLeaderboardScopeSelector.cs | 2 +- .../Ranking/TestSceneSoloResultsScreen.cs | 2 +- .../TestSceneBeatmapLeaderboardWedge.cs | 2 +- .../SongSelectV2/TestSceneSongSelect.cs | 2 +- osu.Game/Configuration/OsuConfigManager.cs | 2 +- osu.Game/Extensions/ModelExtensions.cs | 2 +- .../Online/API/Requests/GetScoresRequest.cs | 2 +- .../Online/Leaderboards/LeaderboardManager.cs | 2 +- .../Leaderboards/LeaderboardSortMode.cs | 2 +- osu.Game/OsuGame.cs | 2 +- .../BeatmapSet/LeaderboardScopeSelector.cs | 2 +- .../BeatmapSet/Scores/NoScoresPlaceholder.cs | 2 +- .../BeatmapSet/Scores/ScoresContainer.cs | 2 +- osu.Game/Scoring/ScoreInfoExtensions.cs | 2 +- .../Screens/Edit/GameplayTest/EditorPlayer.cs | 2 +- .../Multiplayer/MultiplayerPlayer.cs | 2 +- .../Multiplayer/MultiplayerPositionDisplay.cs | 2 +- .../Spectate/MultiSpectatorPlayer.cs | 2 +- .../Spectate/MultiSpectatorScreen.cs | 2 +- .../OnlinePlay/Playlists/PlaylistsPlayer.cs | 2 +- .../Play/HUD/DrawableGameplayLeaderboard.cs | 2 +- .../HUD/DrawableGameplayLeaderboardScore.cs | 2 +- .../Leaderboards/BeatmapLeaderboardScope.cs | 2 +- .../Leaderboards/GameplayLeaderboardScore.cs | 3 +- .../IGameplayLeaderboardProvider.cs | 2 +- .../MultiSpectatorLeaderboardProvider.cs | 2 +- .../MultiplayerLeaderboardProvider.cs | 2 +- .../PlaylistsGameplayLeaderboardProvider.cs | 3 +- .../SoloGameplayLeaderboardProvider.cs | 3 +- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- osu.Game/Screens/Play/ReplayPlayer.cs | 2 +- osu.Game/Screens/Play/SoloPlayer.cs | 2 +- osu.Game/Screens/Play/SoloSpectatorPlayer.cs | 2 +- osu.Game/Screens/Ranking/SoloResultsScreen.cs | 2 +- .../Select/Leaderboards/BeatmapLeaderboard.cs | 138 ------------------ .../SelectV2/BeatmapDetailsArea.Header.cs | 3 +- .../SelectV2/BeatmapLeaderboardWedge.cs | 2 +- 49 files changed, 49 insertions(+), 189 deletions(-) rename osu.Game/{Screens/Select => Online}/Leaderboards/LeaderboardSortMode.cs (95%) rename osu.Game/Screens/{Select => Play}/Leaderboards/BeatmapLeaderboardScope.cs (95%) rename osu.Game/Screens/{Select => Play}/Leaderboards/GameplayLeaderboardScore.cs (98%) rename osu.Game/Screens/{Select => Play}/Leaderboards/IGameplayLeaderboardProvider.cs (94%) rename osu.Game/Screens/{Select => Play}/Leaderboards/MultiSpectatorLeaderboardProvider.cs (95%) rename osu.Game/Screens/{Select => Play}/Leaderboards/MultiplayerLeaderboardProvider.cs (99%) rename osu.Game/Screens/{Select => Play}/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs (98%) rename osu.Game/Screens/{Select => Play}/Leaderboards/SoloGameplayLeaderboardProvider.cs (98%) delete mode 100644 osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableGameplayLeaderboardScore.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableGameplayLeaderboardScore.cs index 1363ef12a9f1..e17f1349b316 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableGameplayLeaderboardScore.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableGameplayLeaderboardScore.cs @@ -8,7 +8,7 @@ using osu.Game.Graphics; using osu.Game.Online.API.Requests.Responses; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osuTK.Graphics; namespace osu.Game.Tests.Visual.Gameplay diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 45e14053e0e0..764a8569e6d0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -21,7 +21,7 @@ using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Tests.Gameplay; using osuTK.Graphics; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlayRulesetLayouts.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlayRulesetLayouts.cs index e67c2d9f090c..131b901d6f21 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlayRulesetLayouts.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlayRulesetLayouts.cs @@ -25,7 +25,7 @@ using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Scoring; using osu.Game.Screens.Play; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Skinning; using osu.Game.Tests.Gameplay; using osu.Game.Tests.Visual.Spectator; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs index 76daffbbadba..824e4f6a1cb2 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs @@ -15,7 +15,7 @@ using osu.Game.Screens.Edit; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Tests.Gameplay; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs index 6e4f3af70a25..e42e8f994e15 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs @@ -21,7 +21,7 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Skinning; using osu.Game.Tests.Gameplay; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboardProvider.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboardProvider.cs index 7e728a84ca7c..e45c4607f940 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboardProvider.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboardProvider.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu; using osu.Game.Scoring; using osu.Game.Screens.Play; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Tests.Gameplay; namespace osu.Game.Tests.Visual.Gameplay diff --git a/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs index 955737578aac..801a748105d6 100644 --- a/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs @@ -21,7 +21,7 @@ using osu.Game.Replays.Legacy; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs index c39708352ed2..68a2fec0ea6d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs @@ -10,7 +10,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs index 53e265decb78..3cf95b3304a2 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs @@ -9,7 +9,7 @@ using osu.Game.Online.Multiplayer; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs index 6141820cb75a..6e5add006ae4 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs @@ -7,7 +7,7 @@ using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPositionDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPositionDisplay.cs index 9123f63f561f..05430cae3357 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPositionDisplay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPositionDisplay.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Osu; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.Play; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Tests.Gameplay; namespace osu.Game.Tests.Visual.Multiplayer diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index b720772cac25..1062f32efb25 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -48,9 +48,9 @@ using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.SelectV2; using osu.Game.Tests.Beatmaps.IO; using osu.Game.Tests.Resources; diff --git a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs index 4c67f778a2a4..e4e79e645969 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs @@ -4,9 +4,9 @@ using osu.Game.Overlays.BeatmapSet; using osu.Framework.Graphics; using osu.Framework.Bindables; -using osu.Game.Screens.Select.Leaderboards; using osu.Framework.Allocation; using osu.Game.Overlays; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Tests.Visual.Online { diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs b/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs index e75c831a7fd1..266adf1ee855 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs @@ -19,8 +19,8 @@ using osu.Game.Online.Leaderboards; using osu.Game.Rulesets; using osu.Game.Scoring; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Ranking diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs index 1c3a5e4babcf..4609bd8936bb 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs @@ -25,7 +25,7 @@ using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; using osu.Game.Users; diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs index f47eafc93737..243492439355 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs @@ -20,9 +20,9 @@ using osu.Game.Scoring; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; using osuTK.Input; diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 97bc53388dae..ab6a687cb686 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -14,6 +14,7 @@ using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.Localisation; +using osu.Game.Online.Leaderboards; using osu.Game.Overlays; using osu.Game.Overlays.Dashboard.Friends; using osu.Game.Overlays.Mods.Input; @@ -22,7 +23,6 @@ using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Skinning; using osu.Game.Users; diff --git a/osu.Game/Extensions/ModelExtensions.cs b/osu.Game/Extensions/ModelExtensions.cs index 7c9d92999918..3b17ee104f42 100644 --- a/osu.Game/Extensions/ModelExtensions.cs +++ b/osu.Game/Extensions/ModelExtensions.cs @@ -8,7 +8,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Users; namespace osu.Game.Extensions diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index 87fb54a5a95a..eb0c82e7903a 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -4,7 +4,6 @@ using System; using osu.Game.Beatmaps; using osu.Game.Rulesets; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mods; using System.Collections.Generic; @@ -12,6 +11,7 @@ using System.Linq; using osu.Framework.IO.Network; using osu.Game.Extensions; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Online.API.Requests { diff --git a/osu.Game/Online/Leaderboards/LeaderboardManager.cs b/osu.Game/Online/Leaderboards/LeaderboardManager.cs index de53acc3f617..d4a258a3079e 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardManager.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardManager.cs @@ -18,7 +18,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using Realms; namespace osu.Game.Online.Leaderboards diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardSortMode.cs b/osu.Game/Online/Leaderboards/LeaderboardSortMode.cs similarity index 95% rename from osu.Game/Screens/Select/Leaderboards/LeaderboardSortMode.cs rename to osu.Game/Online/Leaderboards/LeaderboardSortMode.cs index d5fb2f3c5474..2f2418763d5c 100644 --- a/osu.Game/Screens/Select/Leaderboards/LeaderboardSortMode.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardSortMode.cs @@ -4,7 +4,7 @@ using osu.Framework.Localisation; using osu.Game.Localisation; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Online.Leaderboards { public enum LeaderboardSortMode { diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b671360d7727..0785ecaeaf6a 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -69,8 +69,8 @@ using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.SelectV2; using osu.Game.Seasonal; using osu.Game.Skinning; diff --git a/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs b/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs index 12fbc4c790c9..ed00f4b0e28d 100644 --- a/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs @@ -1,13 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Graphics.UserInterface; using osu.Framework.Allocation; using osuTK.Graphics; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Graphics; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Overlays.BeatmapSet { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs b/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs index b161ee49c63b..a3e406ac8d43 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs @@ -3,10 +3,10 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Screens.Select.Leaderboards; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Overlays.BeatmapSet.Scores { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index cc0638327409..63729319dba1 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -19,7 +19,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osuTK; using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; diff --git a/osu.Game/Scoring/ScoreInfoExtensions.cs b/osu.Game/Scoring/ScoreInfoExtensions.cs index 2eec0399d617..fc367554e7de 100644 --- a/osu.Game/Scoring/ScoreInfoExtensions.cs +++ b/osu.Game/Scoring/ScoreInfoExtensions.cs @@ -7,8 +7,8 @@ using osu.Game.Beatmaps; using osu.Game.Models; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Leaderboards; using osu.Game.Rulesets.Scoring; -using osu.Game.Screens.Select.Leaderboards; using Realms; namespace osu.Game.Scoring diff --git a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs index 2c9b97114d35..32762135e535 100644 --- a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs +++ b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs @@ -18,8 +18,8 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Scoring; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Users; namespace osu.Game.Screens.Edit.GameplayTest diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 4cc6f3469d3a..d7cbd02918d0 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -17,8 +17,8 @@ using osu.Game.Online.Rooms; using osu.Game.Scoring; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Users; using osuTK; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPositionDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPositionDisplay.cs index a2b9db5a0691..f2cbc41d16a9 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPositionDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPositionDisplay.cs @@ -18,7 +18,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Screens.Play; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index e557c6821b86..070cda327ac2 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -8,8 +8,8 @@ using osu.Game.Beatmaps; using osu.Game.Scoring; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index f0b0709ab2aa..ad7966587e5b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -17,7 +17,7 @@ using osu.Game.Online.Spectator; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Spectate; using osu.Game.Users; using osuTK; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs index 69a1e3b76389..ecd45370fc37 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs @@ -12,8 +12,8 @@ using osu.Game.Rulesets; using osu.Game.Scoring; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Users; namespace osu.Game.Screens.OnlinePlay.Playlists diff --git a/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboard.cs index ddb926ebf1cd..cd3ee730187e 100644 --- a/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboard.cs @@ -12,7 +12,7 @@ using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Localisation.SkinComponents; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Skinning; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs index ef27d027c201..f7220e98ac8c 100644 --- a/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs @@ -16,7 +16,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Online.API; using osu.Game.Rulesets.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Users; using osu.Game.Users.Drawables; using osu.Game.Utils; diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs b/osu.Game/Screens/Play/Leaderboards/BeatmapLeaderboardScope.cs similarity index 95% rename from osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs rename to osu.Game/Screens/Play/Leaderboards/BeatmapLeaderboardScope.cs index 497e4568810e..555a2a72c5e6 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs +++ b/osu.Game/Screens/Play/Leaderboards/BeatmapLeaderboardScope.cs @@ -4,7 +4,7 @@ using osu.Framework.Localisation; using osu.Game.Localisation; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { public enum BeatmapLeaderboardScope { diff --git a/osu.Game/Screens/Select/Leaderboards/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/Leaderboards/GameplayLeaderboardScore.cs similarity index 98% rename from osu.Game/Screens/Select/Leaderboards/GameplayLeaderboardScore.cs rename to osu.Game/Screens/Play/Leaderboards/GameplayLeaderboardScore.cs index dfe95b8ccdd3..eb65306ae445 100644 --- a/osu.Game/Screens/Select/Leaderboards/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/Leaderboards/GameplayLeaderboardScore.cs @@ -9,10 +9,9 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Scoring.Legacy; -using osu.Game.Screens.Play; using osu.Game.Users; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { /// /// Represents a score shown on a gameplay leaderboard. diff --git a/osu.Game/Screens/Select/Leaderboards/IGameplayLeaderboardProvider.cs b/osu.Game/Screens/Play/Leaderboards/IGameplayLeaderboardProvider.cs similarity index 94% rename from osu.Game/Screens/Select/Leaderboards/IGameplayLeaderboardProvider.cs rename to osu.Game/Screens/Play/Leaderboards/IGameplayLeaderboardProvider.cs index 9c4875477c15..350569f46f33 100644 --- a/osu.Game/Screens/Select/Leaderboards/IGameplayLeaderboardProvider.cs +++ b/osu.Game/Screens/Play/Leaderboards/IGameplayLeaderboardProvider.cs @@ -3,7 +3,7 @@ using osu.Framework.Bindables; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { /// /// Provides a leaderboard to show during gameplay. diff --git a/osu.Game/Screens/Select/Leaderboards/MultiSpectatorLeaderboardProvider.cs b/osu.Game/Screens/Play/Leaderboards/MultiSpectatorLeaderboardProvider.cs similarity index 95% rename from osu.Game/Screens/Select/Leaderboards/MultiSpectatorLeaderboardProvider.cs rename to osu.Game/Screens/Play/Leaderboards/MultiSpectatorLeaderboardProvider.cs index 19ae12a6caf1..a6f75e6ca14d 100644 --- a/osu.Game/Screens/Select/Leaderboards/MultiSpectatorLeaderboardProvider.cs +++ b/osu.Game/Screens/Play/Leaderboards/MultiSpectatorLeaderboardProvider.cs @@ -5,7 +5,7 @@ using osu.Framework.Timing; using osu.Game.Online.Multiplayer; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { public partial class MultiSpectatorLeaderboardProvider : MultiplayerLeaderboardProvider { diff --git a/osu.Game/Screens/Select/Leaderboards/MultiplayerLeaderboardProvider.cs b/osu.Game/Screens/Play/Leaderboards/MultiplayerLeaderboardProvider.cs similarity index 99% rename from osu.Game/Screens/Select/Leaderboards/MultiplayerLeaderboardProvider.cs rename to osu.Game/Screens/Play/Leaderboards/MultiplayerLeaderboardProvider.cs index 08af8926df17..01bc56c1b57c 100644 --- a/osu.Game/Screens/Select/Leaderboards/MultiplayerLeaderboardProvider.cs +++ b/osu.Game/Screens/Play/Leaderboards/MultiplayerLeaderboardProvider.cs @@ -24,7 +24,7 @@ using osu.Game.Rulesets.Scoring; using osuTK.Graphics; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { [LongRunningLoad] public partial class MultiplayerLeaderboardProvider : CompositeComponent, IGameplayLeaderboardProvider diff --git a/osu.Game/Screens/Select/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs b/osu.Game/Screens/Play/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs similarity index 98% rename from osu.Game/Screens/Select/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs rename to osu.Game/Screens/Play/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs index ea0a2b68dcca..7efbfe23a822 100644 --- a/osu.Game/Screens/Select/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs +++ b/osu.Game/Screens/Play/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs @@ -9,9 +9,8 @@ using osu.Framework.Graphics; using osu.Game.Online.API; using osu.Game.Online.Rooms; -using osu.Game.Screens.Play; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { [LongRunningLoad] public partial class PlaylistsGameplayLeaderboardProvider : Component, IGameplayLeaderboardProvider diff --git a/osu.Game/Screens/Select/Leaderboards/SoloGameplayLeaderboardProvider.cs b/osu.Game/Screens/Play/Leaderboards/SoloGameplayLeaderboardProvider.cs similarity index 98% rename from osu.Game/Screens/Select/Leaderboards/SoloGameplayLeaderboardProvider.cs rename to osu.Game/Screens/Play/Leaderboards/SoloGameplayLeaderboardProvider.cs index fd4ad142a44e..62d1220c5022 100644 --- a/osu.Game/Screens/Select/Leaderboards/SoloGameplayLeaderboardProvider.cs +++ b/osu.Game/Screens/Play/Leaderboards/SoloGameplayLeaderboardProvider.cs @@ -9,9 +9,8 @@ using osu.Framework.Graphics; using osu.Game.Online.Leaderboards; using osu.Game.Scoring; -using osu.Game.Screens.Play; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { public partial class SoloGameplayLeaderboardProvider : Component, IGameplayLeaderboardProvider { diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index df535169b3b1..d082ce6a5738 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -34,8 +34,8 @@ using osu.Game.Screens.Footer; using osu.Game.Screens.Menu; using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Play.PlayerSettings; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Skinning; using osu.Game.Users; using osu.Game.Utils; diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index b9a6de54b4ae..cd769d761596 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -15,9 +15,9 @@ using osu.Game.Input.Bindings; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Skinning; using osu.Game.Users; diff --git a/osu.Game/Screens/Play/SoloPlayer.cs b/osu.Game/Screens/Play/SoloPlayer.cs index 1e9222e40aa8..ee891dd816a3 100644 --- a/osu.Game/Screens/Play/SoloPlayer.cs +++ b/osu.Game/Screens/Play/SoloPlayer.cs @@ -13,7 +13,7 @@ using osu.Game.Online.Rooms; using osu.Game.Online.Solo; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Screens.Play { diff --git a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs index d635fa9fe989..c0950929ba9e 100644 --- a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs @@ -6,7 +6,7 @@ using osu.Framework.Screens; using osu.Game.Online.Spectator; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Users; namespace osu.Game.Screens.Play diff --git a/osu.Game/Screens/Ranking/SoloResultsScreen.cs b/osu.Game/Screens/Ranking/SoloResultsScreen.cs index 5e0095611c7f..1ed6f70f23ad 100644 --- a/osu.Game/Screens/Ranking/SoloResultsScreen.cs +++ b/osu.Game/Screens/Ranking/SoloResultsScreen.cs @@ -12,7 +12,7 @@ using osu.Game.Online.API; using osu.Game.Online.Leaderboards; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Screens.Ranking { diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs deleted file mode 100644 index ddb7814d1293..000000000000 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ /dev/null @@ -1,138 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Threading; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Game.Beatmaps; -using osu.Game.Online.API; -using osu.Game.Online.Leaderboards; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Scoring; - -namespace osu.Game.Screens.Select.Leaderboards -{ - public partial class BeatmapLeaderboard : Leaderboard - { - public Action? ScoreSelected; - - private BeatmapInfo? beatmapInfo; - - public BeatmapInfo? BeatmapInfo - { - get => beatmapInfo; - set - { - if (beatmapInfo == null && value == null) - return; - - if (beatmapInfo?.Equals(value) == true) - return; - - beatmapInfo = value; - - // Refetch is scheduled, which can cause scores to be outdated if the leaderboard is not currently updating. - // As scores are potentially used by other components, clear them eagerly to ensure a more correct state. - SetScores(null); - - RefetchScores(); - } - } - - private bool filterMods; - - /// - /// Whether to apply the game's currently selected mods as a filter when retrieving scores. - /// - public bool FilterMods - { - get => filterMods; - set - { - if (value == filterMods) - return; - - filterMods = value; - - RefetchScores(); - } - } - - private readonly IBindable fetchedScores = new Bindable(); - - [Resolved] - private IBindable ruleset { get; set; } = null!; - - [Resolved] - private IBindable> mods { get; set; } = null!; - - [Resolved] - private LeaderboardManager leaderboardManager { get; set; } = null!; - - [BackgroundDependencyLoader] - private void load() - { - ruleset.ValueChanged += _ => RefetchScores(); - mods.ValueChanged += _ => - { - if (filterMods) - RefetchScores(); - }; - } - - private bool initialFetchComplete; - - protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local; - - protected override APIRequest? FetchScores(CancellationToken cancellationToken) - { - var fetchBeatmapInfo = BeatmapInfo; - var fetchRuleset = ruleset.Value ?? fetchBeatmapInfo?.Ruleset; - - // Without this check, an initial fetch will be performed and clear global cache. - if (fetchBeatmapInfo == null) - return null; - - // For now, we forcefully refresh to keep things simple. - // In the future, removing this requirement may be deemed useful, but will need ample testing of edge case scenarios - // (like returning from gameplay after setting a new score, returning to song select after main menu). - leaderboardManager.FetchWithCriteria(new LeaderboardCriteria(fetchBeatmapInfo, fetchRuleset, Scope, filterMods ? mods.Value.Where(m => m.UserPlayable).ToArray() : null), forceRefresh: true); - - if (!initialFetchComplete) - { - // only bind this after the first fetch to avoid reading stale scores. - fetchedScores.BindTo(leaderboardManager.Scores); - fetchedScores.BindValueChanged(_ => updateScores(), true); - initialFetchComplete = true; - } - - return null; - } - - private void updateScores() - { - var scores = fetchedScores.Value; - - if (scores == null) return; - - if (scores.FailState == null) - Schedule(() => SetScores(scores.TopScores, scores.UserScore)); - else - Schedule(() => SetErrorState((LeaderboardState)scores.FailState)); - } - - protected override LeaderboardScore CreateDrawableScore(ScoreInfo model, int index) => new LeaderboardScore(model, index, IsOnlineScope, Scope != BeatmapLeaderboardScope.Friend) - { - Action = () => ScoreSelected?.Invoke(model) - }; - - protected override LeaderboardScore CreateDrawableTopScore(ScoreInfo model) => new LeaderboardScore(model, model.Position, false, Scope != BeatmapLeaderboardScope.Friend) - { - Action = () => ScoreSelected?.Invoke(model) - }; - } -} diff --git a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs b/osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs index f4a223985d45..5b3f27ce6462 100644 --- a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs +++ b/osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs @@ -12,8 +12,9 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; +using osu.Game.Online.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Leaderboards; using osuTK; namespace osu.Game.Screens.SelectV2 diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs b/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs index 3c91185c2189..18b1bc2e2766 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs +++ b/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs @@ -33,7 +33,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osuTK; using osuTK.Graphics; From 1a8d2855d4add4f8d86660d7fe890e1be94fcd6b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 19:08:44 +0900 Subject: [PATCH 736/836] Remove all song select v1 files This contains no code changes (that would need review), only file deletion and extraction where required in a few odd cases. --- .../TestSceneBeatmapMetadataDisplay.cs | 2 +- .../TestSceneUserTopScoreContainer.cs | 6 +- .../TestSceneMatchBeatmapDetailArea.cs | 52 - .../SongSelect/TestSceneBeatmapCarousel.cs | 1467 ----------------- .../SongSelect/TestSceneBeatmapDetails.cs | 162 -- .../SongSelect/TestSceneBeatmapInfoWedge.cs | 305 ---- .../TestSceneBeatmapOptionsOverlay.cs | 31 - .../SongSelect/TestSceneFilterControl.cs | 24 - .../SongSelect/TestSceneSongSelectFooter.cs | 109 -- .../SongSelect/TestSceneTopLocalRank.cs | 224 --- .../TestSceneUpdateBeatmapSetButton.cs | 262 --- .../TestSceneCollectionDropdown.cs | 2 +- .../TestSceneFooterButtonMods.cs | 99 -- .../Graphics/UserInterface/TwoLayerButton.cs | 23 +- .../Overlays/Settings/Sections/SkinSection.cs | 23 +- .../BeatmapDetailAreaPlaylistTabItem.cs | 12 - .../Components/MatchBeatmapDetailArea.cs | 110 -- osu.Game/Screens/Select/BeatmapCarousel.cs | 1280 -------------- osu.Game/Screens/Select/BeatmapDetailArea.cs | 108 -- .../Select/BeatmapDetailAreaDetailTabItem.cs | 10 - .../BeatmapDetailAreaLeaderboardTabItem.cs | 22 - .../Select/BeatmapDetailAreaTabControl.cs | 108 -- .../Select/BeatmapDetailAreaTabItem.cs | 37 - osu.Game/Screens/Select/BeatmapDetails.cs | 278 ---- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 517 ------ .../Select/BeatmapInfoWedgeBackground.cs | 65 - .../Select/Carousel/CarouselBeatmap.cs | 161 -- .../Select/Carousel/CarouselBeatmapSet.cs | 184 --- .../Screens/Select/Carousel/CarouselGroup.cs | 140 -- .../Carousel/CarouselGroupEagerSelect.cs | 159 -- .../Screens/Select/Carousel/CarouselHeader.cs | 168 -- .../Screens/Select/Carousel/CarouselItem.cs | 66 - .../Carousel/DrawableCarouselBeatmap.cs | 321 ---- .../Carousel/DrawableCarouselBeatmapSet.cs | 356 ---- .../Select/Carousel/DrawableCarouselItem.cs | 177 -- .../Carousel/FilterableDifficultyIcon.cs | 35 - .../Select/Carousel/GroupedDifficultyIcon.cs | 60 - .../Select/Carousel/SetPanelBackground.cs | 92 -- .../Select/Carousel/SetPanelContent.cs | 117 -- .../Screens/Select/Carousel/TopLocalRank.cs | 86 - .../Select/Carousel/UpdateBeatmapSetButton.cs | 178 -- osu.Game/Screens/Select/FilterControl.cs | 309 ---- osu.Game/Screens/Select/Footer.cs | 124 -- osu.Game/Screens/Select/FooterButton.cs | 234 --- osu.Game/Screens/Select/FooterButtonMods.cs | 143 -- .../Screens/Select/FooterButtonOptions.cs | 22 - osu.Game/Screens/Select/FooterButtonRandom.cs | 169 -- .../Screens/Select/NoResultsPlaceholder.cs | 155 -- .../Select/Options/BeatmapOptionsButton.cs | 159 -- .../Select/Options/BeatmapOptionsOverlay.cs | 137 -- .../Screens/Select/PlayBeatmapDetailArea.cs | 150 -- osu.Game/Screens/Select/SkinDeleteDialog.cs | 30 - osu.Game/Screens/Select/SongSelect.cs | 1184 ------------- osu.Game/Screens/Select/WedgeBackground.cs | 39 - .../SelectV2/LeftSideInteractionContainer.cs | 60 + osu.Game/Screens/SelectV2/SongSelect.cs | 4 +- 56 files changed, 101 insertions(+), 10456 deletions(-) rename osu.Game.Tests/Visual/{SongSelect => Gameplay}/TestSceneBeatmapMetadataDisplay.cs (99%) rename osu.Game.Tests/Visual/{SongSelect => Gameplay}/TestSceneUserTopScoreContainer.cs (98%) delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs rename osu.Game.Tests/Visual/{SongSelect => UserInterface}/TestSceneCollectionDropdown.cs (99%) delete mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs delete mode 100644 osu.Game/Screens/Select/BeatmapCarousel.cs delete mode 100644 osu.Game/Screens/Select/BeatmapDetailArea.cs delete mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs delete mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs delete mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs delete mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs delete mode 100644 osu.Game/Screens/Select/BeatmapDetails.cs delete mode 100644 osu.Game/Screens/Select/BeatmapInfoWedge.cs delete mode 100644 osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs delete mode 100644 osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs delete mode 100644 osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs delete mode 100644 osu.Game/Screens/Select/Carousel/CarouselGroup.cs delete mode 100644 osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs delete mode 100644 osu.Game/Screens/Select/Carousel/CarouselHeader.cs delete mode 100644 osu.Game/Screens/Select/Carousel/CarouselItem.cs delete mode 100644 osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs delete mode 100644 osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs delete mode 100644 osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs delete mode 100644 osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs delete mode 100644 osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs delete mode 100644 osu.Game/Screens/Select/Carousel/SetPanelBackground.cs delete mode 100644 osu.Game/Screens/Select/Carousel/SetPanelContent.cs delete mode 100644 osu.Game/Screens/Select/Carousel/TopLocalRank.cs delete mode 100644 osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs delete mode 100644 osu.Game/Screens/Select/FilterControl.cs delete mode 100644 osu.Game/Screens/Select/Footer.cs delete mode 100644 osu.Game/Screens/Select/FooterButton.cs delete mode 100644 osu.Game/Screens/Select/FooterButtonMods.cs delete mode 100644 osu.Game/Screens/Select/FooterButtonOptions.cs delete mode 100644 osu.Game/Screens/Select/FooterButtonRandom.cs delete mode 100644 osu.Game/Screens/Select/NoResultsPlaceholder.cs delete mode 100644 osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs delete mode 100644 osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs delete mode 100644 osu.Game/Screens/Select/PlayBeatmapDetailArea.cs delete mode 100644 osu.Game/Screens/Select/SkinDeleteDialog.cs delete mode 100644 osu.Game/Screens/Select/SongSelect.cs delete mode 100644 osu.Game/Screens/Select/WedgeBackground.cs create mode 100644 osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapMetadataDisplay.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs rename to osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapMetadataDisplay.cs index a9829fbf0c25..63a0198ef5ba 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapMetadataDisplay.cs @@ -19,7 +19,7 @@ using osu.Game.Screens.Play; using osuTK; -namespace osu.Game.Tests.Visual.SongSelect +namespace osu.Game.Tests.Visual.Gameplay { public partial class TestSceneBeatmapMetadataDisplay : OsuTestScene { diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneUserTopScoreContainer.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs rename to osu.Game.Tests/Visual/Gameplay/TestSceneUserTopScoreContainer.cs index 30f1803795b9..8edf83631a87 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneUserTopScoreContainer.cs @@ -6,16 +6,16 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Online.API.Requests.Responses; -using osuTK.Graphics; using osu.Game.Online.Leaderboards; using osu.Game.Overlays; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; -using osu.Game.Scoring; using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Scoring; using osu.Game.Users; +using osuTK.Graphics; -namespace osu.Game.Tests.Visual.SongSelect +namespace osu.Game.Tests.Visual.Gameplay { public partial class TestSceneUserTopScoreContainer : OsuTestScene { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs deleted file mode 100644 index e372d63fde40..000000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Linq; -using osu.Framework.Graphics; -using osu.Game.Online.API; -using osu.Game.Online.Rooms; -using osu.Game.Rulesets.Osu; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.OnlinePlay.Components; -using osu.Game.Tests.Beatmaps; -using osu.Game.Tests.Visual.OnlinePlay; -using osuTK; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - public partial class TestSceneMatchBeatmapDetailArea : OnlinePlayTestScene - { - private Room room = null!; - - public override void SetUpSteps() - { - base.SetUpSteps(); - - AddStep("create area", () => - { - Child = new MatchBeatmapDetailArea(room = new Room()) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(500), - CreateNewItem = createNewItem - }; - }); - } - - private void createNewItem() - { - room.Playlist = room.Playlist.Append(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo) - { - ID = room.Playlist.Count, - RulesetID = new OsuRuleset().RulesetInfo.OnlineID, - RequiredMods = new[] - { - new APIMod(new OsuModHardRock()), - new APIMod(new OsuModDoubleTime()), - new APIMod(new OsuModAutoplay()) - } - }).ToArray(); - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs deleted file mode 100644 index 11e754c8689f..000000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ /dev/null @@ -1,1467 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; -using System.Linq; -using JetBrains.Annotations; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Testing; -using osu.Framework.Utils; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Database; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Catch; -using osu.Game.Rulesets.Osu; -using osu.Game.Rulesets.Taiko; -using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Carousel; -using osu.Game.Screens.Select.Filter; -using osu.Game.Tests.Beatmaps; -using osu.Game.Tests.Resources; -using osuTK.Input; - -namespace osu.Game.Tests.Visual.SongSelect -{ - [TestFixture] - public partial class TestSceneBeatmapCarousel : OsuManualInputManagerTestScene - { - private TestBeatmapCarousel carousel; - private RulesetStore rulesets; - - private readonly Stack selectedSets = new Stack(); - private readonly HashSet eagerSelectedIDs = new HashSet(); - - private BeatmapInfo currentSelection => carousel.SelectedBeatmapInfo; - - private const int set_count = 5; - private const int diff_count = 3; - - [Cached(typeof(BeatmapStore))] - private TestBeatmapStore beatmaps = new TestBeatmapStore(); - - [BackgroundDependencyLoader] - private void load(RulesetStore rulesets) - { - this.rulesets = rulesets; - } - - [Test] - public void TestExternalRulesetChange() - { - createCarousel(new List()); - - AddStep("filter to ruleset 0", () => carousel.FilterImmediately(new FilterCriteria - { - Ruleset = rulesets.AvailableRulesets.ElementAt(0), - AllowConvertedBeatmaps = true, - })); - - AddStep("add mixed ruleset beatmapset", () => - { - var testMixed = TestResources.CreateTestBeatmapSetInfo(3); - - for (int i = 0; i <= 2; i++) - { - testMixed.Beatmaps[i].Ruleset = rulesets.AvailableRulesets.ElementAt(i); - } - - carousel.UpdateBeatmapSet(testMixed); - }); - - AddUntilStep("wait for filtered difficulties", () => - { - var visibleBeatmapPanels = carousel.Items.OfType().Where(p => p.IsPresent).ToArray(); - - return visibleBeatmapPanels.Length == 1 - && visibleBeatmapPanels.Count(p => ((CarouselBeatmap)p.Item)!.BeatmapInfo.Ruleset.OnlineID == 0) == 1; - }); - - AddStep("filter to ruleset 1", () => carousel.FilterImmediately(new FilterCriteria - { - Ruleset = rulesets.AvailableRulesets.ElementAt(1), - AllowConvertedBeatmaps = true, - })); - - AddUntilStep("wait for filtered difficulties", () => - { - var visibleBeatmapPanels = carousel.Items.OfType().Where(p => p.IsPresent).ToArray(); - - return visibleBeatmapPanels.Length == 2 - && visibleBeatmapPanels.Count(p => ((CarouselBeatmap)p.Item)!.BeatmapInfo.Ruleset.OnlineID == 0) == 1 - && visibleBeatmapPanels.Count(p => ((CarouselBeatmap)p.Item)!.BeatmapInfo.Ruleset.OnlineID == 1) == 1; - }); - - AddStep("filter to ruleset 2", () => carousel.FilterImmediately(new FilterCriteria - { - Ruleset = rulesets.AvailableRulesets.ElementAt(2), - AllowConvertedBeatmaps = true, - })); - - AddUntilStep("wait for filtered difficulties", () => - { - var visibleBeatmapPanels = carousel.Items.OfType().Where(p => p.IsPresent).ToArray(); - - return visibleBeatmapPanels.Length == 2 - && visibleBeatmapPanels.Count(p => ((CarouselBeatmap)p.Item!).BeatmapInfo.Ruleset.OnlineID == 0) == 1 - && visibleBeatmapPanels.Count(p => ((CarouselBeatmap)p.Item!).BeatmapInfo.Ruleset.OnlineID == 2) == 1; - }); - } - - [Test] - public void TestScrollPositionMaintainedOnAdd() - { - loadBeatmaps(setCount: 1); - - for (int i = 0; i < 10; i++) - { - AddRepeatStep("Add some sets", () => carousel.UpdateBeatmapSet(TestResources.CreateTestBeatmapSetInfo()), 4); - - checkSelectionIsCentered(); - } - } - - [Test] - public void TestDeletion() - { - loadBeatmaps(setCount: 5, randomDifficulties: true); - - AddStep("remove first set", () => carousel.RemoveBeatmapSet(carousel.Items.Select(item => item.Item).OfType().First().BeatmapSet)); - AddUntilStep("4 beatmap sets visible", () => this.ChildrenOfType().Count(set => set.Alpha > 0) == 4); - } - - [Test] - public void TestScrollPositionMaintainedOnDelete() - { - loadBeatmaps(setCount: 50); - - for (int i = 0; i < 10; i++) - { - AddRepeatStep("Remove some sets", () => - carousel.RemoveBeatmapSet(carousel.Items.Select(item => item.Item) - .OfType() - .OrderBy(item => item.GetHashCode()) - .First(item => item.State.Value != CarouselItemState.Selected && item.Visible).BeatmapSet), 4); - - checkSelectionIsCentered(); - } - } - - [Test] - public void TestManyPanels() - { - loadBeatmaps(setCount: 5000, randomDifficulties: true); - } - - [Test] - public void TestKeyRepeat() - { - loadBeatmaps(); - advanceSelection(false); - - AddStep("press down arrow", () => InputManager.PressKey(Key.Down)); - - BeatmapInfo selection = null; - - checkSelectionIterating(true); - - AddStep("press up arrow", () => InputManager.PressKey(Key.Up)); - - checkSelectionIterating(true); - - AddStep("release down arrow", () => InputManager.ReleaseKey(Key.Down)); - - checkSelectionIterating(true); - - AddStep("release up arrow", () => InputManager.ReleaseKey(Key.Up)); - - checkSelectionIterating(false); - - void checkSelectionIterating(bool isIterating) - { - for (int i = 0; i < 3; i++) - { - AddStep("store selection", () => selection = carousel.SelectedBeatmapInfo); - if (isIterating) - AddUntilStep("selection changed", () => !carousel.SelectedBeatmapInfo?.Equals(selection) == true); - else - AddUntilStep("selection not changed", () => carousel.SelectedBeatmapInfo?.Equals(selection) == true); - } - } - } - - [Test] - public void TestRecommendedSelection() - { - loadBeatmaps(carouselAdjust: carousel => carousel.GetRecommendedBeatmap = beatmaps => beatmaps.LastOrDefault()); - - AddStep("select last", () => carousel.SelectBeatmap(carousel.BeatmapSets.Last().Beatmaps.Last())); - - // check recommended was selected - advanceSelection(direction: 1, diff: false); - waitForSelection(1, 3); - - // change away from recommended - advanceSelection(direction: -1, diff: true); - waitForSelection(1, 2); - - // next set, check recommended - advanceSelection(direction: 1, diff: false); - waitForSelection(2, 3); - - // next set, check recommended - advanceSelection(direction: 1, diff: false); - waitForSelection(3, 3); - - // go back to first set and ensure user selection was retained - advanceSelection(direction: -1, diff: false); - advanceSelection(direction: -1, diff: false); - waitForSelection(1, 2); - } - - /// - /// Test keyboard traversal - /// - [Test] - public void TestTraversal() - { - loadBeatmaps(); - - AddStep("select first", () => carousel.SelectBeatmap(carousel.BeatmapSets.First().Beatmaps.First())); - waitForSelection(1, 1); - - advanceSelection(direction: 1, diff: true); - waitForSelection(1, 2); - - advanceSelection(direction: -1, diff: false); - waitForSelection(set_count, 1); - - advanceSelection(direction: -1, diff: true); - waitForSelection(set_count - 1, 3); - - advanceSelection(diff: false); - advanceSelection(diff: false); - waitForSelection(1, 2); - - advanceSelection(direction: -1, diff: true); - advanceSelection(direction: -1, diff: true); - waitForSelection(set_count, 3); - } - - [TestCase(true)] - [TestCase(false)] - public void TestTraversalBeyondVisible(bool forwards) - { - var sets = new List(); - - const int total_set_count = 200; - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - for (int i = 0; i < total_set_count; i++) - sets.Add(TestResources.CreateTestBeatmapSetInfo()); - }); - - loadBeatmaps(sets); - - for (int i = 1; i < total_set_count; i += i) - selectNextAndAssert(i); - - void selectNextAndAssert(int amount) - { - setSelected(forwards ? 1 : total_set_count, 1); - - AddStep($"{(forwards ? "Next" : "Previous")} beatmap {amount} times", () => - { - for (int i = 0; i < amount; i++) - { - carousel.SelectNext(forwards ? 1 : -1); - } - }); - - waitForSelection(forwards ? amount + 1 : total_set_count - amount); - } - } - - [Test] - public void TestTraversalBeyondVisibleDifficulties() - { - var sets = new List(); - - const int total_set_count = 20; - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - for (int i = 0; i < total_set_count; i++) - sets.Add(TestResources.CreateTestBeatmapSetInfo(3)); - }); - - loadBeatmaps(sets); - - // Selects next set once, difficulty index doesn't change - selectNextAndAssert(3, true, 2, 1); - - // Selects next set 16 times (50 \ 3 == 16), difficulty index changes twice (50 % 3 == 2) - selectNextAndAssert(50, true, 17, 3); - - // Travels around the carousel thrice (200 \ 60 == 3) - // continues to select 20 times (200 \ 60 == 20) - // selects next set 6 times (20 \ 3 == 6) - // difficulty index changes twice (20 % 3 == 2) - selectNextAndAssert(200, true, 7, 3); - - // All same but in reverse - selectNextAndAssert(3, false, 19, 3); - selectNextAndAssert(50, false, 4, 1); - selectNextAndAssert(200, false, 14, 1); - - void selectNextAndAssert(int amount, bool forwards, int expectedSet, int expectedDiff) - { - // Select very first or very last difficulty - setSelected(forwards ? 1 : 20, forwards ? 1 : 3); - - AddStep($"{(forwards ? "Next" : "Previous")} difficulty {amount} times", () => - { - for (int i = 0; i < amount; i++) - carousel.SelectNext(forwards ? 1 : -1, false); - }); - - waitForSelection(expectedSet, expectedDiff); - } - } - - /// - /// Test filtering - /// - [Test] - public void TestFiltering() - { - loadBeatmaps(); - - // basic filtering - setSelected(1, 1); - - AddStep("Filter", () => carousel.FilterImmediately(new FilterCriteria { SearchText = carousel.BeatmapSets.ElementAt(2).Metadata.Title })); - checkVisibleItemCount(diff: false, count: 1); - checkVisibleItemCount(diff: true, count: 3); - waitForSelection(3, 1); - - advanceSelection(diff: true, count: 4); - waitForSelection(3, 2); - - AddStep("Un-filter (debounce)", () => carousel.Filter(new FilterCriteria())); - AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); - checkVisibleItemCount(diff: false, count: set_count); - checkVisibleItemCount(diff: true, count: 3); - - // test filtering some difficulties (and keeping current beatmap set selected). - - setSelected(1, 2); - AddStep("Filter some difficulties", () => carousel.FilterImmediately(new FilterCriteria { SearchText = "Normal" })); - waitForSelection(1, 1); - - AddStep("Un-filter", () => carousel.FilterImmediately(new FilterCriteria())); - waitForSelection(1, 1); - - AddStep("Filter all", () => carousel.FilterImmediately(new FilterCriteria { SearchText = "Dingo" })); - - checkVisibleItemCount(false, 0); - checkVisibleItemCount(true, 0); - AddAssert("Selection is null", () => currentSelection == null); - - advanceSelection(true); - AddAssert("Selection is null", () => currentSelection == null); - - advanceSelection(false); - AddAssert("Selection is null", () => currentSelection == null); - - AddStep("Un-filter", () => carousel.FilterImmediately(new FilterCriteria())); - - AddAssert("Selection is non-null", () => currentSelection != null); - - setSelected(1, 3); - } - - [Test] - public void TestFilterRange() - { - string searchText = null; - - loadBeatmaps(); - - // buffer the selection - setSelected(3, 2); - - AddStep("get search text", () => searchText = carousel.SelectedBeatmapSet!.Metadata.Title); - - setSelected(1, 3); - - AddStep("Apply a range filter", () => carousel.FilterImmediately(new FilterCriteria - { - SearchText = searchText, - StarDifficulty = new FilterCriteria.OptionalRange - { - Min = 2, - Max = 5.5, - IsLowerInclusive = true - } - })); - - // should reselect the buffered selection. - waitForSelection(3, 2); - } - - /// - /// Test random non-repeating algorithm - /// - [Test] - public void TestRandom() - { - loadBeatmaps(); - - setSelected(1, 1); - - nextRandom(); - ensureRandomDidntRepeat(); - nextRandom(); - ensureRandomDidntRepeat(); - nextRandom(); - ensureRandomDidntRepeat(); - - prevRandom(); - ensureRandomFetchSuccess(); - prevRandom(); - ensureRandomFetchSuccess(); - - nextRandom(); - ensureRandomDidntRepeat(); - nextRandom(); - ensureRandomDidntRepeat(); - - nextRandom(); - AddAssert("ensure repeat", () => selectedSets.Contains(carousel.SelectedBeatmapSet)); - - AddStep("Add set with 100 difficulties", () => carousel.UpdateBeatmapSet(TestResources.CreateTestBeatmapSetInfo(100, rulesets.AvailableRulesets.ToArray()))); - AddStep("Filter Extra", () => carousel.FilterImmediately(new FilterCriteria { SearchText = "Extra 10" })); - checkInvisibleDifficultiesUnselectable(); - checkInvisibleDifficultiesUnselectable(); - checkInvisibleDifficultiesUnselectable(); - checkInvisibleDifficultiesUnselectable(); - checkInvisibleDifficultiesUnselectable(); - AddStep("Un-filter", () => carousel.FilterImmediately(new FilterCriteria())); - } - - [Test] - public void TestRewind() - { - const int local_set_count = 3; - const int random_select_count = local_set_count * 3; - loadBeatmaps(setCount: local_set_count); - - for (int i = 0; i < random_select_count; i++) - nextRandom(); - - for (int i = 0; i < random_select_count; i++) - { - prevRandom(); - AddAssert("correct random last selected", () => selectedSets.Peek(), () => Is.EqualTo(carousel.SelectedBeatmapSet)); - } - } - - [Test] - public void TestRewindToDeletedBeatmap() - { - loadBeatmaps(); - - var firstAdded = TestResources.CreateTestBeatmapSetInfo(); - - AddStep("add new set", () => carousel.UpdateBeatmapSet(firstAdded)); - AddStep("select set", () => carousel.SelectBeatmap(firstAdded.Beatmaps.First())); - - nextRandom(); - - AddStep("delete set", () => carousel.RemoveBeatmapSet(firstAdded)); - - prevRandom(); - - AddAssert("deleted set not selected", () => carousel.SelectedBeatmapSet?.Equals(firstAdded) == false); - } - - /// - /// Test adding and removing beatmap sets - /// - [Test] - public void TestAddRemove() - { - loadBeatmaps(); - - var firstAdded = TestResources.CreateTestBeatmapSetInfo(); - var secondAdded = TestResources.CreateTestBeatmapSetInfo(); - - AddStep("Add new set", () => carousel.UpdateBeatmapSet(firstAdded)); - AddStep("Add new set", () => carousel.UpdateBeatmapSet(secondAdded)); - - checkVisibleItemCount(false, set_count + 2); - - AddStep("Remove set", () => carousel.RemoveBeatmapSet(firstAdded)); - - checkVisibleItemCount(false, set_count + 1); - - setSelected(set_count + 1, 1); - - AddStep("Remove set", () => carousel.RemoveBeatmapSet(secondAdded)); - - checkVisibleItemCount(false, set_count); - - waitForSelection(set_count); - } - - [Test] - public void TestDifficultiesSplitOutOnLoad() - { - loadBeatmaps(new List { TestResources.CreateTestBeatmapSetInfo(diff_count) }, () => new FilterCriteria - { - Sort = SortMode.Difficulty, - }); - - checkVisibleItemCount(false, 3); - } - - [Test] - public void TestAddRemoveDifficultySort() - { - const int local_set_count = 2; - const int local_diff_count = 2; - - loadBeatmaps(setCount: local_set_count, diffCount: local_diff_count); - - AddStep("Sort by difficulty", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Difficulty })); - - checkVisibleItemCount(false, local_set_count * local_diff_count); - - var firstAdded = TestResources.CreateTestBeatmapSetInfo(local_diff_count); - firstAdded.Status = BeatmapOnlineStatus.Loved; - - AddStep("Add new set", () => carousel.UpdateBeatmapSet(firstAdded)); - - checkVisibleItemCount(false, (local_set_count + 1) * local_diff_count); - - AddStep("Remove set", () => carousel.RemoveBeatmapSet(firstAdded)); - - checkVisibleItemCount(false, (local_set_count) * local_diff_count); - - setSelected(local_set_count, 1); - - waitForSelection(local_set_count); - } - - [Test] - public void TestSelectionEnteringFromEmptyRuleset() - { - var sets = new List(); - - AddStep("Create beatmaps for taiko only", () => - { - sets.Clear(); - - var rulesetBeatmapSet = TestResources.CreateTestBeatmapSetInfo(1); - var taikoRuleset = rulesets.AvailableRulesets.ElementAt(1); - rulesetBeatmapSet.Beatmaps.ForEach(b => b.Ruleset = taikoRuleset); - - sets.Add(rulesetBeatmapSet); - }); - - loadBeatmaps(sets, () => new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) }); - - AddStep("Set non-empty mode filter", () => - carousel.FilterImmediately(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(1) })); - - AddAssert("Something is selected", () => carousel.SelectedBeatmapInfo != null); - } - - [Test] - public void TestSortingDateSubmitted() - { - var sets = new List(); - const string zzz_string = "zzzzz"; - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < 10; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(5); - - // A total of 6 sets have date submitted (4 don't) - // A total of 5 sets have artist string (3 of which also have date submitted) - - if (i >= 2 && i < 8) // i = 2, 3, 4, 5, 6, 7 have submitted date - set.DateSubmitted = DateTimeOffset.Now.AddMinutes(i); - if (i < 5) // i = 0, 1, 2, 3, 4 have matching string - set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_string); - - set.Beatmaps.ForEach(b => b.Metadata.Title = $"submitted: {set.DateSubmitted}"); - - sets.Add(set); - } - }); - - loadBeatmaps(sets); - - AddStep("Sort by date submitted", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.DateSubmitted })); - checkVisibleItemCount(diff: false, count: 10); - checkVisibleItemCount(diff: true, count: 5); - - AddAssert("missing date are at end", - () => carousel.Items.OfType().Reverse().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted == null).Count(), () => Is.EqualTo(4)); - AddAssert("rest are at start", () => carousel.Items.OfType().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted != null).Count(), - () => Is.EqualTo(6)); - - AddStep("Sort by date submitted and string", () => carousel.FilterImmediately(new FilterCriteria - { - Sort = SortMode.DateSubmitted, - SearchText = zzz_string - })); - checkVisibleItemCount(diff: false, count: 5); - checkVisibleItemCount(diff: true, count: 5); - - AddAssert("missing date are at end", - () => carousel.Items.OfType().Reverse().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted == null).Count(), () => Is.EqualTo(2)); - AddAssert("rest are at start", () => carousel.Items.OfType().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted != null).Count(), - () => Is.EqualTo(3)); - } - - [Test] - public void TestSorting() - { - var sets = new List(); - - const string zzz_lowercase = "zzzzz"; - const string zzz_uppercase = "ZZZZZ"; - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < 20; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(); - - if (i == 4) - set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_uppercase); - - if (i == 8) - set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_lowercase); - - if (i == 12) - set.Beatmaps.ForEach(b => b.Metadata.Author.Username = zzz_uppercase); - - if (i == 16) - set.Beatmaps.ForEach(b => b.Metadata.Author.Username = zzz_lowercase); - - sets.Add(set); - } - }); - - loadBeatmaps(sets); - - AddStep("Sort by author", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Author })); - AddAssert($"Check {zzz_uppercase} is last", () => carousel.BeatmapSets.Last().Metadata.Author.Username == zzz_uppercase); - AddAssert($"Check {zzz_lowercase} is second last", () => carousel.BeatmapSets.SkipLast(1).Last().Metadata.Author.Username == zzz_lowercase); - AddStep("Sort by artist", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Artist })); - AddAssert($"Check {zzz_uppercase} is last", () => carousel.BeatmapSets.Last().Metadata.Artist == zzz_uppercase); - AddAssert($"Check {zzz_lowercase} is second last", () => carousel.BeatmapSets.SkipLast(1).Last().Metadata.Artist == zzz_lowercase); - } - - [Test] - public void TestSortByArtistUsesTitleAsTiebreaker() - { - var sets = new List(); - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < 20; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(); - - if (i == 4) - { - set.Beatmaps.ForEach(b => - { - b.Metadata.Artist = "ZZZ"; - b.Metadata.Title = "AAA"; - }); - } - - if (i == 8) - { - set.Beatmaps.ForEach(b => - { - b.Metadata.Artist = "ZZZ"; - b.Metadata.Title = "ZZZ"; - }); - } - - sets.Add(set); - } - }); - - loadBeatmaps(sets); - - AddStep("Sort by artist", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Artist })); - AddAssert("Check last item", () => - { - var lastItem = carousel.BeatmapSets.Last(); - return lastItem.Metadata.Artist == "ZZZ" && lastItem.Metadata.Title == "ZZZ"; - }); - AddAssert("Check second last item", () => - { - var secondLastItem = carousel.BeatmapSets.SkipLast(1).Last(); - return secondLastItem.Metadata.Artist == "ZZZ" && secondLastItem.Metadata.Title == "AAA"; - }); - } - - /// - /// Ensures stability is maintained on different sort modes for items with equal properties. - /// - [Test] - public void TestSortingStabilityDateAdded() - { - var sets = new List(); - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < 10; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(); - - set.DateAdded = DateTimeOffset.FromUnixTimeSeconds(i); - - // only need to set the first as they are a shared reference. - var beatmap = set.Beatmaps.First(); - - beatmap.Metadata.Artist = "a"; - beatmap.Metadata.Title = "b"; - - sets.Add(set); - } - }); - - loadBeatmaps(sets); - - AddStep("Sort by title", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Title })); - AddAssert("Items remain in descending added order", () => carousel.BeatmapSets.Select(s => s.DateAdded), () => Is.Ordered.Descending); - - AddStep("Sort by artist", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Artist })); - AddAssert("Items remain in descending added order", () => carousel.BeatmapSets.Select(s => s.DateAdded), () => Is.Ordered.Descending); - } - - /// - /// Ensures stability is maintained on different sort modes while a new item is added to the carousel. - /// - [Test] - public void TestSortingStabilityWithRemovedAndReaddedItem() - { - List sets = new List(); - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < 3; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(diff_count); - - // only need to set the first as they are a shared reference. - var beatmap = set.Beatmaps.First(); - - beatmap.Metadata.Artist = "same artist"; - beatmap.Metadata.Title = "same title"; - - // testing the case where DateAdded happens to equal (quite rare). - set.DateAdded = DateTimeOffset.UnixEpoch; - - sets.Add(set); - } - }); - - Guid[] originalOrder = null!; - - loadBeatmaps(sets); - - AddStep("Sort by artist", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Artist })); - - AddAssert("Items in descending added order", () => carousel.BeatmapSets.Select(s => s.DateAdded), () => Is.Ordered.Descending); - AddStep("Save order", () => originalOrder = carousel.BeatmapSets.Select(s => s.ID).ToArray()); - - AddStep("Remove item", () => carousel.RemoveBeatmapSet(sets[1])); - AddStep("Re-add item", () => carousel.UpdateBeatmapSet(sets[1])); - - AddAssert("Order didn't change", () => carousel.BeatmapSets.Select(s => s.ID), () => Is.EqualTo(originalOrder)); - - AddStep("Sort by title", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Title })); - AddAssert("Order didn't change", () => carousel.BeatmapSets.Select(s => s.ID), () => Is.EqualTo(originalOrder)); - } - - /// - /// Ensures stability is maintained on different sort modes while a new item is added to the carousel. - /// - [Test] - public void TestSortingStabilityWithNewItems() - { - List sets = new List(); - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < 3; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(diff_count); - - // only need to set the first as they are a shared reference. - var beatmap = set.Beatmaps.First(); - - beatmap.Metadata.Artist = "same artist"; - beatmap.Metadata.Title = "same title"; - - // testing the case where DateAdded happens to equal (quite rare). - set.DateAdded = DateTimeOffset.UnixEpoch; - - sets.Add(set); - } - }); - - Guid[] originalOrder = null!; - - loadBeatmaps(sets); - - AddStep("Sort by artist", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Artist })); - - AddAssert("Items in descending added order", () => carousel.BeatmapSets.Select(s => s.DateAdded), () => Is.Ordered.Descending); - AddStep("Save order", () => originalOrder = carousel.BeatmapSets.Select(s => s.ID).ToArray()); - - AddStep("Add new item", () => - { - var set = TestResources.CreateTestBeatmapSetInfo(); - - // only need to set the first as they are a shared reference. - var beatmap = set.Beatmaps.First(); - - beatmap.Metadata.Artist = "same artist"; - beatmap.Metadata.Title = "same title"; - - set.DateAdded = DateTimeOffset.FromUnixTimeSeconds(1); - - carousel.UpdateBeatmapSet(set); - - // add set to expected ordering - originalOrder = originalOrder.Prepend(set.ID).ToArray(); - }); - - AddAssert("Order didn't change", () => carousel.BeatmapSets.Select(s => s.ID), () => Is.EqualTo(originalOrder)); - - AddStep("Sort by title", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Title })); - AddAssert("Order didn't change", () => carousel.BeatmapSets.Select(s => s.ID), () => Is.EqualTo(originalOrder)); - } - - [Test] - public void TestSortingWithDifficultyFiltered() - { - const int local_diff_count = 3; - const int local_set_count = 2; - - List sets = new List(); - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < local_set_count; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(local_diff_count); - set.Beatmaps[0].StarRating = 3 - i; - set.Beatmaps[1].StarRating = 6 + i; - sets.Add(set); - } - }); - - loadBeatmaps(sets); - - AddStep("Sort by difficulty", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Difficulty })); - - checkVisibleItemCount(false, local_set_count * local_diff_count); - checkVisibleItemCount(true, 1); - - AddStep("Filter to normal", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Difficulty, SearchText = "Normal" })); - checkVisibleItemCount(false, local_set_count); - checkVisibleItemCount(true, 1); - - AddUntilStep("Check all visible sets have one normal", () => - { - return carousel.Items.OfType() - .Where(p => p.IsPresent) - .Count(p => ((CarouselBeatmapSet)p.Item)!.Beatmaps.Single().BeatmapInfo.DifficultyName.StartsWith("Normal", StringComparison.Ordinal)) == local_set_count; - }); - - AddStep("Filter to insane", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Difficulty, SearchText = "Insane" })); - checkVisibleItemCount(false, local_set_count); - checkVisibleItemCount(true, 1); - - AddUntilStep("Check all visible sets have one insane", () => - { - return carousel.Items.OfType() - .Where(p => p.IsPresent) - .Count(p => ((CarouselBeatmapSet)p.Item)!.Beatmaps.Single().BeatmapInfo.DifficultyName.StartsWith("Insane", StringComparison.Ordinal)) == local_set_count; - }); - } - - [Test] - public void TestRemoveAll() - { - loadBeatmaps(); - - setSelected(2, 1); - AddAssert("Selection is non-null", () => currentSelection != null); - - AddStep("Remove selected", () => carousel.RemoveBeatmapSet(carousel.SelectedBeatmapSet!)); - waitForSelection(2); - - AddStep("Remove first", () => carousel.RemoveBeatmapSet(carousel.BeatmapSets.First())); - AddStep("Remove first", () => carousel.RemoveBeatmapSet(carousel.BeatmapSets.First())); - waitForSelection(1); - - AddUntilStep("Remove all", () => - { - if (!carousel.BeatmapSets.Any()) return true; - - carousel.RemoveBeatmapSet(carousel.BeatmapSets.Last()); - return false; - }); - - checkNoSelection(); - } - - [Test] - public void TestEmptyTraversal() - { - loadBeatmaps(new List()); - - advanceSelection(direction: 1, diff: false); - checkNoSelection(); - - advanceSelection(direction: 1, diff: true); - checkNoSelection(); - - advanceSelection(direction: -1, diff: false); - checkNoSelection(); - - advanceSelection(direction: -1, diff: true); - checkNoSelection(); - } - - [Test] - public void TestHiding() - { - BeatmapSetInfo hidingSet = null; - List hiddenList = new List(); - - AddStep("create hidden set", () => - { - hidingSet = TestResources.CreateTestBeatmapSetInfo(diff_count); - hidingSet.Beatmaps[1].Hidden = true; - - hiddenList.Clear(); - hiddenList.Add(hidingSet); - }); - - loadBeatmaps(hiddenList); - - setSelected(1, 1); - - checkVisibleItemCount(true, 2); - advanceSelection(true); - waitForSelection(1, 3); - - setHidden(3); - waitForSelection(1, 1); - - setHidden(2, false); - advanceSelection(true); - waitForSelection(1, 2); - - setHidden(1); - waitForSelection(1, 2); - - setHidden(2); - checkNoSelection(); - - void setHidden(int diff, bool hidden = true) - { - AddStep((hidden ? "" : "un") + $"hide diff {diff}", () => - { - hidingSet.Beatmaps[diff - 1].Hidden = hidden; - carousel.UpdateBeatmapSet(hidingSet); - }); - } - } - - [Test] - public void TestSelectingFilteredRuleset() - { - BeatmapSetInfo testMixed = null; - - createCarousel(new List()); - - AddStep("add mixed ruleset beatmapset", () => - { - testMixed = TestResources.CreateTestBeatmapSetInfo(diff_count); - - for (int i = 0; i <= 2; i++) - { - testMixed.Beatmaps[i].Ruleset = rulesets.AvailableRulesets.ElementAt(i); - } - - carousel.UpdateBeatmapSet(testMixed); - }); - AddStep("filter to ruleset 0", () => - carousel.FilterImmediately(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) })); - AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testMixed.Beatmaps[1], false)); - AddAssert("unfiltered beatmap not selected", () => carousel.SelectedBeatmapInfo?.Ruleset.OnlineID == 0); - - AddStep("remove mixed set", () => - { - carousel.RemoveBeatmapSet(testMixed); - testMixed = null; - }); - BeatmapSetInfo testSingle = null; - AddStep("add single ruleset beatmapset", () => - { - testSingle = TestResources.CreateTestBeatmapSetInfo(diff_count); - testSingle.Beatmaps.ForEach(b => - { - b.Ruleset = rulesets.AvailableRulesets.ElementAt(1); - }); - - carousel.UpdateBeatmapSet(testSingle); - }); - AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testSingle.Beatmaps[0], false)); - checkNoSelection(); - AddStep("remove single ruleset set", () => carousel.RemoveBeatmapSet(testSingle)); - } - - [Test] - public void TestCarouselRemembersSelection() - { - List manySets = new List(); - - AddStep("Populuate beatmap sets", () => - { - manySets.Clear(); - - for (int i = 1; i <= 50; i++) - manySets.Add(TestResources.CreateTestBeatmapSetInfo(diff_count)); - }); - - loadBeatmaps(manySets); - - advanceSelection(direction: 1, diff: false); - - for (int i = 0; i < 5; i++) - { - AddStep("Toggle non-matching filter", () => - { - carousel.FilterImmediately(new FilterCriteria { SearchText = Guid.NewGuid().ToString() }); - }); - - AddStep("Restore no filter", () => - { - carousel.FilterImmediately(new FilterCriteria()); - eagerSelectedIDs.Add(carousel.SelectedBeatmapSet!.ID); - }); - } - - // always returns to same selection as long as it's available. - AddAssert("Selection was remembered", () => eagerSelectedIDs.Count == 1); - } - - [Test] - public void TestCarouselRemembersSelectionDifficultySort() - { - List manySets = new List(); - - AddStep("Populate beatmap sets", () => - { - manySets.Clear(); - - for (int i = 1; i <= 50; i++) - manySets.Add(TestResources.CreateTestBeatmapSetInfo(diff_count)); - }); - - loadBeatmaps(manySets); - - AddStep("Sort by difficulty", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Difficulty })); - - advanceSelection(direction: 1, diff: false); - - for (int i = 0; i < 5; i++) - { - AddStep("Toggle non-matching filter", () => - { - carousel.FilterImmediately(new FilterCriteria { SearchText = Guid.NewGuid().ToString() }); - }); - - AddStep("Restore no filter", () => - { - carousel.FilterImmediately(new FilterCriteria()); - eagerSelectedIDs.Add(carousel.SelectedBeatmapSet!.ID); - }); - } - - // always returns to same selection as long as it's available. - AddAssert("Selection was remembered", () => eagerSelectedIDs.Count == 1); - } - - [Test] - public void TestCarouselRetainsSelectionFromDifficultySort() - { - List manySets = new List(); - - AddStep("Populate beatmap sets", () => - { - manySets.Clear(); - - for (int i = 1; i <= 50; i++) - manySets.Add(TestResources.CreateTestBeatmapSetInfo(diff_count)); - }); - - loadBeatmaps(manySets); - - BeatmapInfo chosenBeatmap = null!; - AddStep("select given beatmap", () => carousel.SelectBeatmap(chosenBeatmap = manySets[20].Beatmaps[0])); - AddUntilStep("selection changed", () => carousel.SelectedBeatmapInfo, () => Is.EqualTo(chosenBeatmap)); - - AddStep("sort by difficulty", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Difficulty })); - AddAssert("selection retained", () => carousel.SelectedBeatmapInfo, () => Is.EqualTo(chosenBeatmap)); - - AddStep("sort by title", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Title })); - AddAssert("selection retained", () => carousel.SelectedBeatmapInfo, () => Is.EqualTo(chosenBeatmap)); - } - - [Test] - public void TestFilteringByUserStarDifficulty() - { - BeatmapSetInfo set = null; - - loadBeatmaps(new List()); - - AddStep("add mixed difficulty set", () => - { - set = TestResources.CreateTestBeatmapSetInfo(1); - set.Beatmaps.Clear(); - - for (int i = 1; i <= 15; i++) - { - set.Beatmaps.Add(new BeatmapInfo(new OsuRuleset().RulesetInfo, new BeatmapDifficulty(), new BeatmapMetadata()) - { - DifficultyName = $"Stars: {i}", - StarRating = i, - }); - } - - carousel.UpdateBeatmapSet(set); - }); - - AddStep("select added set", () => carousel.SelectBeatmap(set.Beatmaps[0], false)); - - AddStep("filter [5..]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Min = 5 } })); - AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); - checkVisibleItemCount(true, 11); - - AddStep("filter to [0..7]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Max = 7 } })); - AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); - checkVisibleItemCount(true, 7); - - AddStep("filter to [5..7]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Min = 5, Max = 7 } })); - AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); - checkVisibleItemCount(true, 3); - - AddStep("filter [2..2]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Min = 2, Max = 2 } })); - AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); - checkVisibleItemCount(true, 1); - - AddStep("filter to [0..]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Min = 0 } })); - AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); - checkVisibleItemCount(true, 15); - } - - [Test] - public void TestCarouselSelectsNextWhenPreviousIsFiltered() - { - List sets = new List(); - - // 10 sets that go osu! -> taiko -> catch -> osu! -> ... - for (int i = 0; i < 10; i++) - sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { getRuleset(i) })); - - // Sort mode is important to keep the ruleset order - loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title }); - setSelected(1, 1); - - for (int i = 1; i < 10; i++) - { - var rulesetInfo = getRuleset(i % 3); - - AddStep($"Set ruleset to {rulesetInfo.ShortName}", () => - { - carousel.FilterImmediately(new FilterCriteria { Ruleset = rulesetInfo, Sort = SortMode.Title }); - }); - waitForSelection(i + 1, 1); - } - - static RulesetInfo getRuleset(int index) - { - switch (index % 3) - { - default: - return new OsuRuleset().RulesetInfo; - - case 1: - return new TaikoRuleset().RulesetInfo; - - case 2: - return new CatchRuleset().RulesetInfo; - } - } - } - - [Test] - public void TestCarouselSelectsBackwardsWhenDistanceIsShorter() - { - List sets = new List(); - - // 10 sets that go taiko, osu!, osu!, osu!, taiko, osu!, osu!, osu!, ... - for (int i = 0; i < 10; i++) - sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { getRuleset(i) })); - - // Sort mode is important to keep the ruleset order - loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title }); - - for (int i = 2; i < 10; i += 4) - { - setSelected(i, 1); - AddStep("Set ruleset to taiko", () => - { - carousel.FilterImmediately(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(1), Sort = SortMode.Title }); - }); - waitForSelection(i - 1, 1); - AddStep("Remove ruleset filter", () => - { - carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Title }); - }); - } - - static RulesetInfo getRuleset(int index) - { - switch (index % 4) - { - case 0: - return new TaikoRuleset().RulesetInfo; - - default: - return new OsuRuleset().RulesetInfo; - } - } - } - - private void loadBeatmaps(List beatmapSets = null, Func initialCriteria = null, Action carouselAdjust = null, - int? setCount = null, int? diffCount = null, bool randomDifficulties = false) - { - bool changed = false; - - if (beatmapSets == null) - { - beatmapSets = new List(); - var statuses = Enum.GetValues() - .Except(new[] { BeatmapOnlineStatus.None }) // make sure a badge is always shown. - .ToArray(); - - for (int i = 1; i <= (setCount ?? set_count); i++) - { - var set = randomDifficulties - ? TestResources.CreateTestBeatmapSetInfo() - : TestResources.CreateTestBeatmapSetInfo(diffCount ?? diff_count); - set.Status = statuses[RNG.Next(statuses.Length)]; - - beatmapSets.Add(set); - } - } - - createCarousel(beatmapSets, initialCriteria, c => - { - carousel.BeatmapSetsChanged = () => changed = true; - carouselAdjust?.Invoke(c); - }); - - AddUntilStep("Wait for load", () => changed); - } - - private void createCarousel(List beatmapSets, [CanBeNull] Func initialCriteria = null, Action carouselAdjust = null, Container target = null) - { - AddStep("Create carousel", () => - { - selectedSets.Clear(); - eagerSelectedIDs.Clear(); - - carousel = new TestBeatmapCarousel(initialCriteria?.Invoke() ?? new FilterCriteria()) - { - RelativeSizeAxes = Axes.Both, - }; - - carouselAdjust?.Invoke(carousel); - - beatmaps.BeatmapSets.Clear(); - beatmaps.BeatmapSets.AddRange(beatmapSets); - - (target ?? this).Child = carousel; - }); - } - - private void ensureRandomFetchSuccess() => - AddAssert("ensure prev random fetch worked", () => selectedSets.Peek().Equals(carousel.SelectedBeatmapSet)); - - private void waitForSelection(int set, int? diff = null) => - AddUntilStep($"selected is set{set}{(diff.HasValue ? $" diff{diff.Value}" : "")}", () => - { - if (diff != null) - return carousel.SelectedBeatmapInfo?.Equals(carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Skip(diff.Value - 1).First()) == true; - - return carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Contains(carousel.SelectedBeatmapInfo); - }); - - private void setSelected(int set, int diff) => - AddStep($"select set{set} diff{diff}", () => - carousel.SelectBeatmap(carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Skip(diff - 1).First())); - - private void advanceSelection(bool diff, int direction = 1, int count = 1) - { - if (count == 1) - { - AddStep($"select {(direction > 0 ? "next" : "prev")} {(diff ? "diff" : "set")}", () => - carousel.SelectNext(direction, !diff)); - } - else - { - AddRepeatStep($"select {(direction > 0 ? "next" : "prev")} {(diff ? "diff" : "set")}", () => - carousel.SelectNext(direction, !diff), count); - } - } - - private void checkVisibleItemCount(bool diff, int count) - { - // until step required as we are querying against alive items, which are loaded asynchronously inside DrawableCarouselBeatmapSet. - AddUntilStep($"{count} {(diff ? "diffs" : "sets")} visible", () => - carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible), () => Is.EqualTo(count)); - } - - private void checkSelectionIsCentered() - { - AddAssert("Selected panel is centered", () => - { - return Precision.AlmostEquals( - carousel.ScreenSpaceDrawQuad.Centre, - carousel.Items - .First(i => i.Item?.State.Value == CarouselItemState.Selected) - .ScreenSpaceDrawQuad.Centre, 100); - }); - } - - private void checkNoSelection() => AddAssert("Selection is null", () => currentSelection == null); - - private void nextRandom() => - AddStep("select random next", () => - { - carousel.RandomAlgorithm.Value = RandomSelectAlgorithm.RandomPermutation; - - if (!selectedSets.Any() && carousel.SelectedBeatmapInfo != null) - selectedSets.Push(carousel.SelectedBeatmapSet); - - carousel.SelectNextRandom(); - selectedSets.Push(carousel.SelectedBeatmapSet); - }); - - private void ensureRandomDidntRepeat() => - AddAssert("ensure no repeats", () => selectedSets.Distinct().Count() == selectedSets.Count); - - private void prevRandom() => AddStep("select random last", () => - { - carousel.SelectPreviousRandom(); - selectedSets.Pop(); - }); - - private bool selectedBeatmapVisible() - { - var currentlySelected = carousel.Items.FirstOrDefault(s => s.Item is CarouselBeatmap && s.Item.State.Value == CarouselItemState.Selected); - if (currentlySelected == null) - return true; - - return currentlySelected.Item!.Visible; - } - - private void checkInvisibleDifficultiesUnselectable() - { - nextRandom(); - AddAssert("Selection is visible", selectedBeatmapVisible); - } - - private partial class TestBeatmapCarousel : BeatmapCarousel - { - public TestBeatmapCarousel(FilterCriteria criteria) - : base(criteria) - { - } - - public bool PendingFilterTask => PendingFilter != null; - - public IEnumerable Items - { - get - { - foreach (var item in Scroll.Children.OrderBy(c => c.Y)) - { - if (item.Item?.Visible != true) - continue; - - yield return item; - - if (item is DrawableCarouselBeatmapSet set) - { - foreach (var difficulty in set.DrawableBeatmaps) - yield return difficulty; - } - } - } - } - - public void FilterImmediately(FilterCriteria newCriteria) - { - Filter(newCriteria); - FlushPendingFilterOperations(); - } - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs deleted file mode 100644 index 20cc1e544ecf..000000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.Linq; -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Game.Beatmaps; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Screens.Select; - -namespace osu.Game.Tests.Visual.SongSelect -{ - [System.ComponentModel.Description("PlaySongSelect beatmap details")] - public partial class TestSceneBeatmapDetails : OsuTestScene - { - private BeatmapDetails details; - - private DummyAPIAccess api => (DummyAPIAccess)API; - - [SetUp] - public void Setup() => Schedule(() => - { - Child = details = new BeatmapDetails - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(150), - }; - }); - - [Test] - public void TestAllMetrics() - { - AddStep("all metrics", () => details.BeatmapInfo = new APIBeatmap - { - BeatmapSet = new APIBeatmapSet - { - Source = "osu!", - Tags = "this beatmap has all the metrics", - Ratings = Enumerable.Range(0, 11).ToArray(), - }, - DifficultyName = "All Metrics", - CircleSize = 7, - DrainRate = 1, - OverallDifficulty = 5.7f, - ApproachRate = 3.5f, - StarRating = 5.3f, - FailTimes = new APIFailTimes - { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), - }, - }); - } - - [Test] - public void TestAllMetricsExceptSource() - { - AddStep("all except source", () => details.BeatmapInfo = new APIBeatmap - { - BeatmapSet = new APIBeatmapSet - { - Tags = "this beatmap has all the metrics", - Ratings = Enumerable.Range(0, 11).ToArray(), - }, - DifficultyName = "All Metrics", - CircleSize = 7, - DrainRate = 1, - OverallDifficulty = 5.7f, - ApproachRate = 3.5f, - StarRating = 5.3f, - FailTimes = new APIFailTimes - { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), - }, - }); - } - - [Test] - public void TestOnlyRatings() - { - AddStep("ratings", () => details.BeatmapInfo = new APIBeatmap - { - BeatmapSet = new APIBeatmapSet - { - Ratings = Enumerable.Range(0, 11).ToArray(), - Source = "osu!", - Tags = "this beatmap has ratings metrics but not retries or fails", - }, - DifficultyName = "Only Ratings", - CircleSize = 6, - DrainRate = 9, - OverallDifficulty = 6, - ApproachRate = 6, - StarRating = 4.8f, - }); - } - - [Test] - public void TestOnlyFailsAndRetries() - { - AddStep("fails retries", () => details.BeatmapInfo = new APIBeatmap - { - DifficultyName = "Only Retries and Fails", - BeatmapSet = new APIBeatmapSet - { - Source = "osu!", - Tags = "this beatmap has retries and fails but no ratings", - }, - CircleSize = 3.7f, - DrainRate = 6, - OverallDifficulty = 6, - ApproachRate = 7, - StarRating = 2.91f, - FailTimes = new APIFailTimes - { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), - }, - }); - } - - [Test] - public void TestNoMetrics() - { - AddStep("no metrics", () => details.BeatmapInfo = new APIBeatmap - { - DifficultyName = "No Metrics", - BeatmapSet = new APIBeatmapSet - { - Source = "osu!", - Tags = "this beatmap has no metrics", - }, - CircleSize = 5, - DrainRate = 5, - OverallDifficulty = 5.5f, - ApproachRate = 6.5f, - StarRating = 1.97f, - }); - } - - [Test] - public void TestNullBeatmap() - { - AddStep("null beatmap", () => details.BeatmapInfo = null); - } - - [Test] - public void TestOnlineMetrics() - { - AddStep("online ratings/retries/fails", () => details.BeatmapInfo = new APIBeatmap - { - OnlineID = 162, - }); - AddStep("set online", () => api.SetState(APIState.Online)); - AddStep("set offline", () => api.SetState(APIState.Offline)); - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs deleted file mode 100644 index 0e0f3c554aa3..000000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs +++ /dev/null @@ -1,305 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Testing; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Extensions; -using osu.Game.Graphics.Sprites; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Catch; -using osu.Game.Rulesets.Mania; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Legacy; -using osu.Game.Rulesets.Osu; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Rulesets.Taiko; -using osu.Game.Screens.Select; -using osuTK; - -namespace osu.Game.Tests.Visual.SongSelect -{ - [TestFixture] - public partial class TestSceneBeatmapInfoWedge : OsuTestScene - { - [Resolved] - private RulesetStore rulesets { get; set; } = null!; - - private TestBeatmapInfoWedge infoWedge = null!; - private readonly List beatmaps = new List(); - - protected override void LoadComplete() - { - base.LoadComplete(); - - Add(infoWedge = new TestBeatmapInfoWedge - { - Size = new Vector2(0.5f, 245), - RelativeSizeAxes = Axes.X, - Margin = new MarginPadding { Top = 20 } - }); - - AddStep("show", () => infoWedge.Show()); - - selectBeatmap(Beatmap.Value.Beatmap); - - AddWaitStep("wait for select", 3); - - AddStep("hide", () => { infoWedge.Hide(); }); - - AddWaitStep("wait for hide", 3); - - AddStep("show", () => { infoWedge.Show(); }); - - AddSliderStep("change star difficulty", 0, 11.9, 5.55, v => - { - foreach (var hasCurrentValue in infoWedge.Info.ChildrenOfType>()) - hasCurrentValue.Current.Value = new StarDifficulty(v, 0); - }); - - foreach (var rulesetInfo in rulesets.AvailableRulesets) - { - var instance = rulesetInfo.CreateInstance(); - var testBeatmap = CreateTestBeatmap(rulesetInfo); - - beatmaps.Add(testBeatmap); - - setRuleset(rulesetInfo); - - selectBeatmap(testBeatmap); - - testBeatmapLabels(instance); - - switch (instance) - { - case OsuRuleset: - testInfoLabels(5); - break; - - case TaikoRuleset: - testInfoLabels(5); - break; - - case CatchRuleset: - testInfoLabels(5); - break; - - case ManiaRuleset: - testInfoLabels(4); - break; - - default: - testInfoLabels(2); - break; - } - } - } - - private void testBeatmapLabels(Ruleset ruleset) - { - AddAssert("check version", () => infoWedge.Info.VersionLabel.Current.Value == $"{ruleset.ShortName}Version"); - AddAssert("check title", () => infoWedge.Info.TitleLabel.Current.Value == $"{ruleset.ShortName}Title"); - AddAssert("check artist", () => infoWedge.Info.ArtistLabel.Current.Value == $"{ruleset.ShortName}Artist"); - AddAssert("check author", () => infoWedge.Info.MapperContainer.ChildrenOfType().Any(s => s.Current.Value == $"{ruleset.ShortName}Author")); - } - - private void testInfoLabels(int expectedCount) - { - AddAssert("check info labels exists", () => infoWedge.Info.ChildrenOfType().Any()); - AddAssert("check info labels count", () => infoWedge.Info.ChildrenOfType().Count() == expectedCount); - } - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("reset mods", () => SelectedMods.SetDefault()); - } - - [Test] - public void TestTruncation() - { - selectBeatmap(CreateLongMetadata()); - } - - [Test] - public void TestNullBeatmap() - { - selectBeatmap(null); - AddAssert("check empty version", () => string.IsNullOrEmpty(infoWedge.Info.VersionLabel.Current.Value)); - AddAssert("check default title", () => infoWedge.Info.TitleLabel.Current.Value == Beatmap.Default.BeatmapInfo.Metadata.Title); - AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Current.Value == Beatmap.Default.BeatmapInfo.Metadata.Artist); - AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.ChildrenOfType().Any()); - AddAssert("check no info labels", () => !infoWedge.Info.ChildrenOfType().Any()); - } - - [Test] - public void TestBPMUpdates() - { - const double bpm = 120; - IBeatmap beatmap = CreateTestBeatmap(new OsuRuleset().RulesetInfo); - beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / bpm }); - - OsuModDoubleTime doubleTime = null!; - - selectBeatmap(beatmap); - checkDisplayedBPM($"{bpm}"); - - AddStep("select DT", () => SelectedMods.Value = new[] { doubleTime = new OsuModDoubleTime() }); - checkDisplayedBPM($"{bpm * 1.5f}"); - - AddStep("change DT rate", () => doubleTime.SpeedChange.Value = 2); - checkDisplayedBPM($"{bpm * 2}"); - } - - [TestCase(120, 125, null, "120-125 (mostly 120)")] - [TestCase(120, 120.6, null, "120-121 (mostly 120)")] - [TestCase(120, 120.4, null, "120")] - [TestCase(120, 120.6, "DT", "180-181 (mostly 180)")] - [TestCase(120, 120.4, "DT", "180-181 (mostly 180)")] - public void TestVaryingBPM(double commonBpm, double otherBpm, string? mod, string expectedDisplay) - { - IBeatmap beatmap = CreateTestBeatmap(new OsuRuleset().RulesetInfo); - beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / commonBpm }); - beatmap.ControlPointInfo.Add(100, new TimingControlPoint { BeatLength = 60 * 1000 / otherBpm }); - beatmap.ControlPointInfo.Add(200, new TimingControlPoint { BeatLength = 60 * 1000 / commonBpm }); - - if (mod != null) - AddStep($"select {mod}", () => SelectedMods.Value = new[] { Ruleset.Value.CreateInstance().CreateModFromAcronym(mod) }); - - selectBeatmap(beatmap); - checkDisplayedBPM(expectedDisplay); - } - - private void checkDisplayedBPM(string target) - { - AddUntilStep($"displayed bpm is {target}", () => - { - var label = infoWedge.DisplayedContent.ChildrenOfType().Single(l => l.Statistic.Name == BeatmapsetsStrings.ShowStatsBpm); - return label.Statistic.Content == target; - }); - } - - [TestCase] - public void TestLengthUpdates() - { - IBeatmap beatmap = CreateTestBeatmap(new OsuRuleset().RulesetInfo); - double drain = beatmap.CalculateDrainLength(); - beatmap.BeatmapInfo.Length = drain; - - OsuModDoubleTime doubleTime = null!; - - selectBeatmap(beatmap); - checkDisplayedLength(drain); - - AddStep("select DT", () => SelectedMods.Value = new[] { doubleTime = new OsuModDoubleTime() }); - checkDisplayedLength(Math.Round(drain / 1.5f)); - - AddStep("change DT rate", () => doubleTime.SpeedChange.Value = 2); - checkDisplayedLength(Math.Round(drain / 2)); - } - - private void checkDisplayedLength(double drain) - { - var displayedLength = drain.ToFormattedDuration(); - - AddUntilStep($"check map drain ({displayedLength})", () => - { - var label = infoWedge.DisplayedContent.ChildrenOfType() - .Single(l => l.Statistic.Name == BeatmapsetsStrings.ShowStatsTotalLength(displayedLength)); - return label.Statistic.Content == displayedLength.ToString(); - }); - } - - private void setRuleset(RulesetInfo rulesetInfo) - { - Container? containerBefore = null; - - AddStep("set ruleset", () => - { - // wedge content is only refreshed if the ruleset changes, so only wait for load in that case. - if (!rulesetInfo.Equals(Ruleset.Value)) - containerBefore = infoWedge.DisplayedContent; - - Ruleset.Value = rulesetInfo; - }); - - AddUntilStep("wait for async load", () => infoWedge.DisplayedContent != containerBefore); - } - - private void selectBeatmap(IBeatmap? b) - { - Container? containerBefore = null; - - AddStep($"select {b?.Metadata.Title ?? "null"} beatmap", () => - { - containerBefore = infoWedge.DisplayedContent; - infoWedge.Beatmap = Beatmap.Value = b == null ? Beatmap.Default : CreateWorkingBeatmap(b); - }); - - AddUntilStep("wait for async load", () => infoWedge.DisplayedContent != containerBefore); - } - - public static IBeatmap CreateTestBeatmap(RulesetInfo ruleset) - { - List objects = new List(); - for (double i = 0; i < 50000; i += 1000) - objects.Add(new TestHitObject { StartTime = i }); - - return new Beatmap - { - BeatmapInfo = new BeatmapInfo - { - Metadata = new BeatmapMetadata - { - Author = { Username = $"{ruleset.ShortName}Author" }, - Artist = $"{ruleset.ShortName}Artist", - Source = $"{ruleset.ShortName}Source", - Title = $"{ruleset.ShortName}Title" - }, - Ruleset = ruleset, - StarRating = 6, - DifficultyName = $"{ruleset.ShortName}Version", - Difficulty = new BeatmapDifficulty() - }, - HitObjects = objects - }; - } - - public static IBeatmap CreateLongMetadata() - { - return new Beatmap - { - BeatmapInfo = new BeatmapInfo - { - Metadata = new BeatmapMetadata - { - Author = { Username = "WWWWWWWWWWWWWWW" }, - Artist = "Verrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Artist", - Source = "Verrrrry long Source", - Title = "Verrrrry long Title" - }, - DifficultyName = "Verrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Version", - Status = BeatmapOnlineStatus.Graveyard, - }, - }; - } - - private partial class TestBeatmapInfoWedge : BeatmapInfoWedge - { - public new Container DisplayedContent => base.DisplayedContent; - - public new WedgeInfoText Info => base.Info; - } - - private class TestHitObject : ConvertHitObject; - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs deleted file mode 100644 index fa4981c137c4..000000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.ComponentModel; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; -using osu.Game.Screens.Select.Options; - -namespace osu.Game.Tests.Visual.SongSelect -{ - [Description("bottom beatmap details")] - public partial class TestSceneBeatmapOptionsOverlay : OsuTestScene - { - public TestSceneBeatmapOptionsOverlay() - { - var overlay = new BeatmapOptionsOverlay(); - - var colours = new OsuColour(); - - overlay.AddButton(@"Manage", @"collections", FontAwesome.Solid.Book, colours.Green, null); - overlay.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, null); - overlay.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null); - overlay.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, null); - overlay.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, null); - - Add(overlay); - - AddStep(@"Toggle", overlay.ToggleVisibility); - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs deleted file mode 100644 index 41e44357d70d..000000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Game.Screens.Select; - -namespace osu.Game.Tests.Visual.SongSelect -{ - public partial class TestSceneFilterControl : OsuManualInputManagerTestScene - { - [SetUp] - public void SetUp() => Schedule(() => - { - Child = new FilterControl - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.X, - Height = FilterControl.HEIGHT, - }; - }); - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs deleted file mode 100644 index 646dedc2be78..000000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.Linq; -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Framework.Testing; -using osu.Game.Screens.Select; -using osuTK; -using osuTK.Input; - -namespace osu.Game.Tests.Visual.SongSelect -{ - public partial class TestSceneSongSelectFooter : OsuManualInputManagerTestScene - { - private FooterButtonRandom randomButton; - - private bool nextRandomCalled; - private bool previousRandomCalled; - - [SetUp] - public void SetUp() => Schedule(() => - { - nextRandomCalled = false; - previousRandomCalled = false; - - Footer footer; - - Child = footer = new Footer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }; - - footer.AddButton(new FooterButtonMods(), null); - footer.AddButton(randomButton = new FooterButtonRandom - { - NextRandom = () => nextRandomCalled = true, - PreviousRandom = () => previousRandomCalled = true, - }, null); - footer.AddButton(new FooterButtonOptions(), null); - - InputManager.MoveMouseTo(Vector2.Zero); - }); - - [Test] - public void TestState() - { - AddRepeatStep("toggle options state", () => this.ChildrenOfType().Last().Enabled.Toggle(), 20); - } - - [Test] - public void TestFooterRandom() - { - AddStep("press F2", () => InputManager.Key(Key.F2)); - AddAssert("next random invoked", () => nextRandomCalled && !previousRandomCalled); - } - - [Test] - public void TestFooterRandomViaMouse() - { - AddStep("click button", () => - { - InputManager.MoveMouseTo(randomButton); - InputManager.Click(MouseButton.Left); - }); - AddAssert("next random invoked", () => nextRandomCalled && !previousRandomCalled); - } - - [Test] - public void TestFooterRewind() - { - AddStep("press Shift+F2", () => - { - InputManager.PressKey(Key.LShift); - InputManager.PressKey(Key.F2); - InputManager.ReleaseKey(Key.F2); - InputManager.ReleaseKey(Key.LShift); - }); - AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled); - } - - [Test] - public void TestFooterRewindViaShiftMouseLeft() - { - AddStep("shift + click button", () => - { - InputManager.PressKey(Key.LShift); - InputManager.MoveMouseTo(randomButton); - InputManager.Click(MouseButton.Left); - InputManager.ReleaseKey(Key.LShift); - }); - AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled); - } - - [Test] - public void TestFooterRewindViaMouseRight() - { - AddStep("right click button", () => - { - InputManager.MoveMouseTo(randomButton); - InputManager.Click(MouseButton.Right); - }); - AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled); - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs deleted file mode 100644 index cb0845ede877..000000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Linq; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Extensions; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Graphics; -using osu.Framework.Platform; -using osu.Framework.Testing; -using osu.Game.Beatmaps; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Rulesets; -using osu.Game.Scoring; -using osu.Game.Screens.Select.Carousel; -using osu.Game.Tests.Resources; -using osuTK; - -namespace osu.Game.Tests.Visual.SongSelect -{ - public partial class TestSceneTopLocalRank : OsuTestScene - { - private RulesetStore rulesets = null!; - private BeatmapManager beatmapManager = null!; - private ScoreManager scoreManager = null!; - private TopLocalRank topLocalRank = null!; - - [BackgroundDependencyLoader] - private void load(GameHost host, AudioManager audio) - { - Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); - Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default)); - Dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmapManager, LocalStorage, Realm, API)); - Dependencies.Cache(Realm); - - beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely(); - } - - private BeatmapInfo importedBeatmap => beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First(b => b.Ruleset.ShortName == "osu"); - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("Delete all scores", () => scoreManager.Delete()); - - AddStep("Create local rank", () => - { - Child = topLocalRank = new TopLocalRank(importedBeatmap) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(10), - }; - }); - - AddAssert("No rank displayed initially", () => topLocalRank.DisplayedRank == null); - } - - [Test] - public void TestBasicImportDelete() - { - ScoreInfo testScoreInfo = null!; - - AddStep("Add score for current user", () => - { - testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = API.LocalUser.Value; - testScoreInfo.Rank = ScoreRank.B; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B); - - AddStep("Delete score", () => scoreManager.Delete(testScoreInfo)); - - AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank == null); - } - - [Test] - public void TestRulesetChange() - { - AddStep("Add score for current user", () => - { - var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = API.LocalUser.Value; - testScoreInfo.Rank = ScoreRank.B; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("Wait for initial display", () => topLocalRank.DisplayedRank == ScoreRank.B); - - AddStep("Change ruleset", () => Ruleset.Value = rulesets.GetRuleset("fruits")); - AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank == null); - - AddStep("Change ruleset back", () => Ruleset.Value = rulesets.GetRuleset("osu")); - AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B); - } - - [Test] - public void TestHigherScoreSet() - { - AddStep("Add score for current user", () => - { - var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = API.LocalUser.Value; - testScoreInfo.Rank = ScoreRank.B; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B); - - AddStep("Add higher score for current user", () => - { - var testScoreInfo2 = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo2.User = API.LocalUser.Value; - testScoreInfo2.Rank = ScoreRank.X; - testScoreInfo2.TotalScore = 1000000; - testScoreInfo2.Statistics = testScoreInfo2.MaximumStatistics; - - scoreManager.Import(testScoreInfo2); - }); - - AddUntilStep("SS rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.X); - } - - [Test] - public void TestLegacyScore() - { - ScoreInfo testScoreInfo = null!; - - AddStep("Add legacy score for current user", () => - { - testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = API.LocalUser.Value; - testScoreInfo.Rank = ScoreRank.B; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B); - - AddStep("Add higher-graded score for current user", () => - { - var testScoreInfo2 = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo2.User = API.LocalUser.Value; - testScoreInfo2.Rank = ScoreRank.X; - testScoreInfo2.Statistics = testScoreInfo2.MaximumStatistics; - testScoreInfo2.TotalScore = testScoreInfo.TotalScore + 1; - - scoreManager.Import(testScoreInfo2); - }); - - AddUntilStep("SS rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.X); - } - - [Test] - public void TestGuestScore() - { - AddStep("Add score for guest user", () => - { - var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = new GuestUser(); - testScoreInfo.Rank = ScoreRank.B; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank, () => Is.EqualTo(ScoreRank.B)); - } - - [Test] - public void TestUnknownUserScore() - { - AddStep("Add score for unknown user", () => - { - var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = new APIUser { Username = "AAA", }; - testScoreInfo.Rank = ScoreRank.S; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("S rank displayed", () => topLocalRank.DisplayedRank, () => Is.EqualTo(ScoreRank.S)); - } - - [Test] - public void TestAnotherUserScore() - { - AddStep("Add score for not-current user", () => - { - var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = new APIUser { Username = "notme", Id = 43, }; - testScoreInfo.Rank = ScoreRank.S; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank, () => Is.Null); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - if (rulesets.IsNotNull()) - rulesets.Dispose(); - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs deleted file mode 100644 index 2311c360ffc7..000000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs +++ /dev/null @@ -1,262 +0,0 @@ -// 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.Linq; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Graphics; -using osu.Framework.Testing; -using osu.Game.Beatmaps; -using osu.Game.Database; -using osu.Game.Online.API; -using osu.Game.Overlays; -using osu.Game.Overlays.Dialog; -using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Carousel; -using osu.Game.Screens.Select.Filter; -using osu.Game.Tests.Beatmaps; -using osu.Game.Tests.Online; -using osu.Game.Tests.Resources; -using osuTK.Input; - -namespace osu.Game.Tests.Visual.SongSelect -{ - [TestFixture] - public partial class TestSceneUpdateBeatmapSetButton : OsuManualInputManagerTestScene - { - private BeatmapCarousel carousel = null!; - - private TestScenePlaylistsBeatmapAvailabilityTracker.TestBeatmapModelDownloader beatmapDownloader = null!; - - private BeatmapSetInfo testBeatmapSetInfo = null!; - - [Cached(typeof(BeatmapStore))] - private TestBeatmapStore beatmaps = new TestBeatmapStore(); - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - var importer = parent.Get(); - - dependencies.CacheAs(beatmapDownloader = new TestScenePlaylistsBeatmapAvailabilityTracker.TestBeatmapModelDownloader(importer, API)); - return dependencies; - } - - private UpdateBeatmapSetButton? getUpdateButton() => carousel.ChildrenOfType().SingleOrDefault(); - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("create carousel", () => Child = createCarousel()); - - AddUntilStep("wait for load", () => carousel.BeatmapSetsLoaded); - - AddAssert("update button not visible", () => getUpdateButton() == null); - } - - [Test] - public void TestDownloadToCompletion() - { - ArchiveDownloadRequest? downloadRequest = null; - - AddStep("update online hash", () => - { - testBeatmapSetInfo.Beatmaps.First().OnlineMD5Hash = "different hash"; - testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now; - - carousel.UpdateBeatmapSet(testBeatmapSetInfo); - }); - - AddUntilStep("only one set visible", () => carousel.ChildrenOfType().Count() == 1); - AddUntilStep("update button visible", () => getUpdateButton() != null); - - AddStep("click button", () => getUpdateButton()?.TriggerClick()); - - AddUntilStep("wait for download started", () => - { - downloadRequest = beatmapDownloader.GetExistingDownload(testBeatmapSetInfo); - return downloadRequest != null; - }); - - AddUntilStep("wait for button disabled", () => getUpdateButton()?.Enabled.Value == false); - - AddUntilStep("progress download to completion", () => - { - if (downloadRequest is TestScenePlaylistsBeatmapAvailabilityTracker.TestDownloadRequest testRequest) - { - testRequest.SetProgress(testRequest.Progress + 0.1f); - - if (testRequest.Progress >= 1) - { - testRequest.TriggerSuccess(); - - // usually this would be done by the import process. - testBeatmapSetInfo.Beatmaps.First().MD5Hash = "different hash"; - testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now; - - // usually this would be done by a realm subscription. - carousel.UpdateBeatmapSet(testBeatmapSetInfo); - return true; - } - } - - return false; - }); - } - - [Test] - public void TestDownloadFailed() - { - ArchiveDownloadRequest? downloadRequest = null; - - AddStep("update online hash", () => - { - testBeatmapSetInfo.Beatmaps.First().OnlineMD5Hash = "different hash"; - testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now; - - carousel.UpdateBeatmapSet(testBeatmapSetInfo); - }); - - AddUntilStep("only one set visible", () => carousel.ChildrenOfType().Count() == 1); - AddUntilStep("update button visible", () => getUpdateButton() != null); - - AddStep("click button", () => getUpdateButton()?.TriggerClick()); - - AddUntilStep("wait for download started", () => - { - downloadRequest = beatmapDownloader.GetExistingDownload(testBeatmapSetInfo); - return downloadRequest != null; - }); - - AddUntilStep("wait for button disabled", () => getUpdateButton()?.Enabled.Value == false); - - AddUntilStep("progress download to failure", () => - { - if (downloadRequest is TestScenePlaylistsBeatmapAvailabilityTracker.TestDownloadRequest testRequest) - { - testRequest.SetProgress(testRequest.Progress + 0.1f); - - if (testRequest.Progress >= 0.5f) - { - testRequest.TriggerFailure(new InvalidOperationException()); - return true; - } - } - - return false; - }); - - AddUntilStep("wait for button enabled", () => getUpdateButton()?.Enabled.Value == true); - } - - [Test] - public void TestUpdateLocalBeatmap() - { - DialogOverlay dialogOverlay = null!; - UpdateBeatmapSetButton? updateButton = null; - - AddStep("create carousel with dialog overlay", () => - { - dialogOverlay = new DialogOverlay(); - - Child = new DependencyProvidingContainer - { - RelativeSizeAxes = Axes.Both, - CachedDependencies = new (Type, object)[] { (typeof(IDialogOverlay), dialogOverlay), }, - Children = new Drawable[] - { - createCarousel(), - dialogOverlay, - }, - }; - }); - - AddStep("setup beatmap state", () => - { - testBeatmapSetInfo.Beatmaps.First().OnlineMD5Hash = "different hash"; - testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now; - testBeatmapSetInfo.Status = BeatmapOnlineStatus.LocallyModified; - - carousel.UpdateBeatmapSet(testBeatmapSetInfo); - }); - - AddUntilStep("wait for update button", () => (updateButton = getUpdateButton()) != null); - AddStep("click button", () => updateButton.AsNonNull().TriggerClick()); - - AddAssert("dialog displayed", () => dialogOverlay.CurrentDialog is UpdateLocalConfirmationDialog); - AddStep("click confirmation", () => - { - InputManager.MoveMouseTo(dialogOverlay.CurrentDialog.ChildrenOfType().First()); - InputManager.PressButton(MouseButton.Left); - }); - - AddUntilStep("update started", () => beatmapDownloader.GetExistingDownload(testBeatmapSetInfo) != null); - AddStep("release mouse button", () => InputManager.ReleaseButton(MouseButton.Left)); - } - - [Test] - public void TestSplitDisplay() - { - ArchiveDownloadRequest? downloadRequest = null; - - AddStep("set difficulty sort mode", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Difficulty })); - AddStep("update online hash", () => - { - testBeatmapSetInfo.Beatmaps.First().OnlineMD5Hash = "different hash"; - testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now; - - carousel.UpdateBeatmapSet(testBeatmapSetInfo); - }); - - AddUntilStep("multiple \"sets\" visible", () => carousel.ChildrenOfType().Count(), () => Is.GreaterThan(1)); - AddUntilStep("update button visible", getUpdateButton, () => Is.Not.Null); - - AddStep("click button", () => getUpdateButton()?.TriggerClick()); - - AddUntilStep("wait for download started", () => - { - downloadRequest = beatmapDownloader.GetExistingDownload(testBeatmapSetInfo); - return downloadRequest != null; - }); - - AddUntilStep("wait for button disabled", () => getUpdateButton()?.Enabled.Value == false); - - AddUntilStep("progress download to completion", () => - { - if (downloadRequest is TestScenePlaylistsBeatmapAvailabilityTracker.TestDownloadRequest testRequest) - { - testRequest.SetProgress(testRequest.Progress + 0.1f); - - if (testRequest.Progress >= 1) - { - testRequest.TriggerSuccess(); - - // usually this would be done by the import process. - testBeatmapSetInfo.Beatmaps.First().MD5Hash = "different hash"; - testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now; - - // usually this would be done by a realm subscription. - carousel.UpdateBeatmapSet(testBeatmapSetInfo); - return true; - } - } - - return false; - }); - } - - private BeatmapCarousel createCarousel() - { - beatmaps.BeatmapSets.Clear(); - beatmaps.BeatmapSets.Add(testBeatmapSetInfo = TestResources.CreateTestBeatmapSetInfo(5)); - - return carousel = new BeatmapCarousel(new FilterCriteria()) - { - RelativeSizeAxes = Axes.Both, - }; - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCollectionDropdown.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs rename to osu.Game.Tests/Visual/UserInterface/TestSceneCollectionDropdown.cs index 8525e33a337a..c5a0d7eab8a8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCollectionDropdown.cs @@ -25,7 +25,7 @@ using osuTK.Input; using Realms; -namespace osu.Game.Tests.Visual.SongSelect +namespace osu.Game.Tests.Visual.UserInterface { public partial class TestSceneCollectionDropdown : OsuManualInputManagerTestScene { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs deleted file mode 100644 index b79ce6c75fe3..000000000000 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs +++ /dev/null @@ -1,99 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Select; -using osu.Game.Utils; - -namespace osu.Game.Tests.Visual.UserInterface -{ - public partial class TestSceneFooterButtonMods : OsuTestScene - { - private readonly TestFooterButtonMods footerButtonMods; - - public TestSceneFooterButtonMods() - { - Add(footerButtonMods = new TestFooterButtonMods()); - } - - [Test] - public void TestIncrementMultiplier() - { - var hiddenMod = new Mod[] { new OsuModHidden() }; - AddStep(@"Add Hidden", () => changeMods(hiddenMod)); - AddAssert(@"Check Hidden multiplier", () => assertModsMultiplier(hiddenMod)); - - var hardRockMod = new Mod[] { new OsuModHardRock() }; - AddStep(@"Add HardRock", () => changeMods(hardRockMod)); - AddAssert(@"Check HardRock multiplier", () => assertModsMultiplier(hardRockMod)); - - var doubleTimeMod = new Mod[] { new OsuModDoubleTime() }; - AddStep(@"Add DoubleTime", () => changeMods(doubleTimeMod)); - AddAssert(@"Check DoubleTime multiplier", () => assertModsMultiplier(doubleTimeMod)); - - var multipleIncrementMods = new Mod[] { new OsuModDoubleTime(), new OsuModHidden(), new OsuModHardRock() }; - AddStep(@"Add multiple Mods", () => changeMods(multipleIncrementMods)); - AddAssert(@"Check multiple mod multiplier", () => assertModsMultiplier(multipleIncrementMods)); - } - - [Test] - public void TestDecrementMultiplier() - { - var easyMod = new Mod[] { new OsuModEasy() }; - AddStep(@"Add Easy", () => changeMods(easyMod)); - AddAssert(@"Check Easy multiplier", () => assertModsMultiplier(easyMod)); - - var noFailMod = new Mod[] { new OsuModNoFail() }; - AddStep(@"Add NoFail", () => changeMods(noFailMod)); - AddAssert(@"Check NoFail multiplier", () => assertModsMultiplier(noFailMod)); - - var multipleDecrementMods = new Mod[] { new OsuModEasy(), new OsuModNoFail() }; - AddStep(@"Add Multiple Mods", () => changeMods(multipleDecrementMods)); - AddAssert(@"Check multiple mod multiplier", () => assertModsMultiplier(multipleDecrementMods)); - } - - [Test] - public void TestClearMultiplier() - { - var multipleMods = new Mod[] { new OsuModDoubleTime(), new OsuModFlashlight() }; - AddStep(@"Add mods", () => changeMods(multipleMods)); - AddStep(@"Clear selected mod", () => changeMods(Array.Empty())); - AddAssert(@"Check empty multiplier", () => assertModsMultiplier(Array.Empty())); - } - - [Test] - public void TestUnrankedBadge() - { - AddStep(@"Add unranked mod", () => changeMods(new[] { new OsuModDeflate() })); - AddAssert("Unranked badge shown", () => footerButtonMods.UnrankedBadge.Alpha == 1); - AddStep(@"Clear selected mod", () => changeMods(Array.Empty())); - AddAssert("Unranked badge not shown", () => footerButtonMods.UnrankedBadge.Alpha == 0); - } - - private void changeMods(IReadOnlyList mods) - { - footerButtonMods.Current.Value = mods; - } - - private bool assertModsMultiplier(IEnumerable mods) - { - double multiplier = mods.Aggregate(1.0, (current, mod) => current * mod.ScoreMultiplier); - string expectedValue = multiplier == 1 ? string.Empty : ModUtils.FormatScoreMultiplier(multiplier).ToString(); - - return expectedValue == footerButtonMods.MultiplierText.Current.Value; - } - - private partial class TestFooterButtonMods : FooterButtonMods - { - public new OsuSpriteText MultiplierText => base.MultiplierText; - public new Drawable UnrankedBadge => base.UnrankedBadge; - } - } -} diff --git a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs index 6f61a14b7568..3083abc39391 100644 --- a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs +++ b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs @@ -1,21 +1,20 @@ // 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 osu.Framework.Audio.Track; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osuTK; -using osuTK.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Framework.Extensions.Color4Extensions; -using osu.Game.Graphics.Containers; -using osu.Game.Beatmaps.ControlPoints; -using osu.Framework.Audio.Track; -using System; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; -using osu.Game.Screens.Select; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { @@ -31,7 +30,9 @@ public partial class TwoLayerButton : OsuClickableContainer private const float shear_width = 5f; - private static readonly Vector2 shear = new Vector2(shear_width / Footer.HEIGHT, 0); + public const float HEIGHT = 50; + + private static readonly Vector2 shear = new Vector2(shear_width / HEIGHT, 0); public static readonly Vector2 SIZE_EXTENDED = new Vector2(140, 50); public static readonly Vector2 SIZE_RETRACTED = new Vector2(100, 50); diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index e0bc193df654..8d8c73b14e1a 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -22,8 +22,8 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; +using osu.Game.Overlays.Dialog; using osu.Game.Overlays.SkinEditor; -using osu.Game.Screens.Select; using osu.Game.Skinning; using osuTK; using Realms; @@ -237,6 +237,27 @@ private void delete() } } + public partial class SkinDeleteDialog : DeletionDialog + { + private readonly Skin skin; + + public SkinDeleteDialog(Skin skin) + { + this.skin = skin; + BodyText = skin.SkinInfo.Value.Name; + } + + [BackgroundDependencyLoader] + private void load(SkinManager manager) + { + DangerousAction = () => + { + manager.Delete(skin.SkinInfo.Value); + manager.CurrentSkinInfo.SetDefault(); + }; + } + } + public partial class RenameSkinPopover : OsuPopover { [Resolved] diff --git a/osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs deleted file mode 100644 index 41b994ea32ad..000000000000 --- a/osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Screens.Select; - -namespace osu.Game.Screens.OnlinePlay.Components -{ - public class BeatmapDetailAreaPlaylistTabItem : BeatmapDetailAreaTabItem - { - public override string Name => "Playlist"; - } -} diff --git a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs b/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs deleted file mode 100644 index 1f2b2e3fc2c7..000000000000 --- a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs +++ /dev/null @@ -1,110 +0,0 @@ -// 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.ComponentModel; -using System.Linq; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics.UserInterfaceV2; -using osu.Game.Online.Rooms; -using osu.Game.Screens.OnlinePlay.Playlists; -using osu.Game.Screens.Select; -using osuTK; -using Container = osu.Framework.Graphics.Containers.Container; - -namespace osu.Game.Screens.OnlinePlay.Components -{ - public partial class MatchBeatmapDetailArea : BeatmapDetailArea - { - public Action? CreateNewItem; - - private readonly Room room; - private readonly GridContainer playlistArea; - private readonly DrawableRoomPlaylist playlist; - - public MatchBeatmapDetailArea(Room room) - { - this.room = room; - - Add(playlistArea = new GridContainer - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Vertical = 10 }, - Content = new[] - { - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Bottom = 10 }, - Child = playlist = new PlaylistsRoomSettingsPlaylist - { - RelativeSizeAxes = Axes.Both - } - } - }, - new Drawable[] - { - new RoundedButton - { - Text = "Add new playlist entry", - RelativeSizeAxes = Axes.Both, - Size = Vector2.One, - Action = () => CreateNewItem?.Invoke() - } - }, - }, - RowDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.Absolute, 50), - } - }); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - playlist.Items.BindCollectionChanged((_, __) => room.Playlist = playlist.Items.ToArray()); - - room.PropertyChanged += onRoomPropertyChanged; - updateRoomPlaylist(); - } - - private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == nameof(Room.Playlist)) - updateRoomPlaylist(); - } - - private void updateRoomPlaylist() - => playlist.Items.ReplaceRange(0, playlist.Items.Count, room.Playlist); - - protected override void OnTabChanged(BeatmapDetailAreaTabItem tab, bool selectedMods) - { - base.OnTabChanged(tab, selectedMods); - - switch (tab) - { - case BeatmapDetailAreaPlaylistTabItem: - playlistArea.Show(); - break; - - default: - playlistArea.Hide(); - break; - } - } - - protected override BeatmapDetailAreaTabItem[] CreateTabItems() => base.CreateTabItems().Prepend(new BeatmapDetailAreaPlaylistTabItem()).ToArray(); - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - room.PropertyChanged -= onRoomPropertyChanged; - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs deleted file mode 100644 index dda62e8ba80f..000000000000 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ /dev/null @@ -1,1280 +0,0 @@ -// 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.Collections.Generic; -using System.Collections.Specialized; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; -using osu.Framework.Caching; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Pooling; -using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Framework.Layout; -using osu.Framework.Threading; -using osu.Framework.Utils; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Database; -using osu.Game.Extensions; -using osu.Game.Graphics.Containers; -using osu.Game.Input.Bindings; -using osu.Game.Screens.Select.Carousel; -using osu.Game.Screens.Select.Filter; -using osuTK; -using osuTK.Input; - -namespace osu.Game.Screens.Select -{ - public partial class BeatmapCarousel : CompositeDrawable, IKeyBindingHandler - { - /// - /// Height of the area above the carousel that should be treated as visible due to transparency of elements in front of it. - /// - public float BleedTop { get; set; } - - /// - /// Height of the area below the carousel that should be treated as visible due to transparency of elements in front of it. - /// - public float BleedBottom { get; set; } - - /// - /// Triggered when finish loading, or are subsequently changed. - /// - public Action? BeatmapSetsChanged; - - /// - /// Triggered after filter conditions have finished being applied to the model hierarchy. - /// - public Action? FilterApplied; - - /// - /// The currently selected beatmap. - /// - public BeatmapInfo? SelectedBeatmapInfo => selectedBeatmap?.BeatmapInfo; - - private CarouselBeatmap? selectedBeatmap => selectedBeatmapSet?.Beatmaps.FirstOrDefault(s => s.State.Value == CarouselItemState.Selected); - - /// - /// The total count of non-filtered beatmaps displayed. - /// - public int CountDisplayed => beatmapSets.Where(s => !s.Filtered.Value).Sum(s => s.TotalItemsNotFiltered); - - /// - /// The currently selected beatmap set. - /// - public BeatmapSetInfo? SelectedBeatmapSet => selectedBeatmapSet?.BeatmapSet; - - /// - /// A function to optionally decide on a recommended difficulty from a beatmap set. - /// - public Func, BeatmapInfo?>? GetRecommendedBeatmap; - - private CarouselBeatmapSet? selectedBeatmapSet; - - /// - /// Raised when the is changed. - /// - public Action? SelectionChanged; - - public override bool HandleNonPositionalInput => AllowSelection; - public override bool HandlePositionalInput => AllowSelection; - - public override bool PropagatePositionalInputSubTree => AllowSelection; - public override bool PropagateNonPositionalInputSubTree => AllowSelection; - - private (int first, int last) displayedRange; - - /// - /// Extend the range to retain already loaded pooled drawables. - /// - private const float distance_offscreen_before_unload = 2048; - - /// - /// Extend the range to update positions / retrieve pooled drawables outside of visible range. - /// - private const float distance_offscreen_to_preload = 768; - - /// - /// Whether carousel items have completed asynchronously loaded. - /// - public bool BeatmapSetsLoaded { get; private set; } - - [Cached] - protected readonly CarouselScrollContainer Scroll; - - [Resolved] - private RealmAccess realm { get; set; } = null!; - - private IBindableList? detachedBeatmapSets; - - private readonly NoResultsPlaceholder noResultsPlaceholder; - - private IEnumerable beatmapSets => root.Items.OfType(); - - internal IEnumerable BeatmapSets => beatmapSets.Select(g => g.BeatmapSet); - - private void loadNewRoot() - { - beatmapsSplitOut = activeCriteria.Sort == SortMode.Difficulty; - - // Ensure no changes are made to the list while we are initialising items. - // We'll catch up on changes via subscriptions anyway. - BeatmapSetInfo[] loadableSets = detachedBeatmapSets!.ToArray(); - - if (selectedBeatmapSet != null && !loadableSets.Contains(selectedBeatmapSet.BeatmapSet, EqualityComparer.Default)) - selectedBeatmapSet = null; - - var selectedBeatmapBefore = selectedBeatmap?.BeatmapInfo; - - CarouselRoot newRoot = new CarouselRoot(this); - - if (beatmapsSplitOut) - { - var carouselBeatmapSets = loadableSets.SelectMany(s => s.Beatmaps).Select(b => - { - return createCarouselSet(new BeatmapSetInfo(new[] { b }) - { - ID = b.BeatmapSet!.ID, - OnlineID = b.BeatmapSet!.OnlineID, - Status = b.BeatmapSet!.Status, - }); - }).OfType(); - - newRoot.AddItems(carouselBeatmapSets); - } - else - { - var carouselBeatmapSets = loadableSets.Select(createCarouselSet).OfType(); - - newRoot.AddItems(carouselBeatmapSets); - } - - root = newRoot; - root.Filter(activeCriteria); - - Scroll.Clear(false); - itemsCache.Invalidate(); - ScrollToSelected(); - - // Restore selection - if (selectedBeatmapBefore != null && newRoot.BeatmapSetsByID.TryGetValue(selectedBeatmapBefore.BeatmapSet!.ID, out var newSelectionCandidates)) - { - CarouselBeatmap? found = newSelectionCandidates.SelectMany(s => s.Beatmaps).SingleOrDefault(b => b.BeatmapInfo.ID == selectedBeatmapBefore.ID); - - if (found != null) - found.State.Value = CarouselItemState.Selected; - } - - Schedule(() => - { - invalidateAfterChange(); - BeatmapSetsLoaded = true; - }); - } - - private readonly List visibleItems = new List(); - - private readonly Cached itemsCache = new Cached(); - private PendingScrollOperation pendingScrollOperation = PendingScrollOperation.None; - - public Bindable RandomAlgorithm = new Bindable(); - private readonly List previouslyVisitedRandomSets = new List(); - private readonly List randomSelectedBeatmaps = new List(); - - private CarouselRoot root; - - private readonly DrawablePool setPool = new DrawablePool(100); - - private Sample? spinSample; - private Sample? randomSelectSample; - - private int visibleSetsCount; - - public BeatmapCarousel(FilterCriteria initialCriteria) - { - root = new CarouselRoot(this); - InternalChild = new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - setPool, - Scroll = new CarouselScrollContainer - { - RelativeSizeAxes = Axes.Both, - }, - noResultsPlaceholder = new NoResultsPlaceholder() - } - }; - - activeCriteria = initialCriteria; - } - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config, AudioManager audio, BeatmapStore beatmaps, CancellationToken? cancellationToken) - { - spinSample = audio.Samples.Get("SongSelect/random-spin"); - randomSelectSample = audio.Samples.Get(@"SongSelect/select-random"); - - config.BindWith(OsuSetting.RandomSelectAlgorithm, RandomAlgorithm); - - detachedBeatmapSets = beatmaps.GetBeatmapSets(cancellationToken); - detachedBeatmapSets.BindCollectionChanged(beatmapSetsChanged); - loadNewRoot(); - } - - private readonly HashSet setsRequiringUpdate = new HashSet(); - private readonly HashSet setsRequiringRemoval = new HashSet(); - - private void beatmapSetsChanged(object? beatmaps, NotifyCollectionChangedEventArgs changed) - { - IEnumerable? oldBeatmapSets = changed.OldItems?.Cast(); - HashSet oldBeatmapSetIDs = oldBeatmapSets?.Select(s => s.ID).ToHashSet() ?? []; - - IEnumerable? newBeatmapSets = changed.NewItems?.Cast(); - HashSet newBeatmapSetIDs = newBeatmapSets?.Select(s => s.ID).ToHashSet() ?? []; - - switch (changed.Action) - { - case NotifyCollectionChangedAction.Add: - setsRequiringRemoval.RemoveWhere(s => newBeatmapSetIDs.Contains(s.ID)); - setsRequiringUpdate.AddRange(newBeatmapSets!); - break; - - case NotifyCollectionChangedAction.Remove: - setsRequiringUpdate.RemoveWhere(s => oldBeatmapSetIDs.Contains(s.ID)); - setsRequiringRemoval.AddRange(oldBeatmapSets!); - break; - - case NotifyCollectionChangedAction.Replace: - setsRequiringUpdate.RemoveWhere(s => oldBeatmapSetIDs.Contains(s.ID)); - setsRequiringRemoval.AddRange(oldBeatmapSets!); - - setsRequiringRemoval.RemoveWhere(s => newBeatmapSetIDs.Contains(s.ID)); - setsRequiringUpdate.AddRange(newBeatmapSets!); - break; - - case NotifyCollectionChangedAction.Move: - setsRequiringUpdate.AddRange(newBeatmapSets!); - break; - - case NotifyCollectionChangedAction.Reset: - setsRequiringRemoval.Clear(); - setsRequiringUpdate.Clear(); - loadNewRoot(); - break; - } - - Scheduler.AddOnce(processBeatmapChanges); - } - - // All local operations must be scheduled. - // - // If we don't schedule, beatmaps getting changed while song select is suspended (ie. last played being updated) - // will cause unexpected sounds and operations to occur in the background. - private void processBeatmapChanges() - { - try - { - // To handle the beatmap update flow, attempt to track selection changes across delete-insert transactions. - // When an update occurs, the previous beatmap set is either soft or hard deleted. - // Check if the current selection was potentially deleted by re-querying its validity. - bool selectedSetMarkedDeleted = SelectedBeatmapSet != null && fetchFromID(SelectedBeatmapSet.ID)?.DeletePending != false; - - foreach (var set in setsRequiringRemoval) removeBeatmapSet(set.ID); - - foreach (var set in setsRequiringUpdate) updateBeatmapSet(set); - - if (setsRequiringRemoval.Count > 0 && SelectedBeatmapInfo != null) - { - // If SelectedBeatmapInfo is non-null, the set should also be non-null. - Debug.Assert(SelectedBeatmapSet != null); - - if (selectedSetMarkedDeleted && setsRequiringUpdate.Any()) - { - // If it is no longer valid, make the bold assumption that an updated version will be available in the modified/inserted indices. - // This relies on the full update operation being in a single transaction, so please don't change that. - foreach (var set in setsRequiringUpdate) - { - foreach (var beatmapInfo in set.Beatmaps) - { - if (!((IBeatmapMetadataInfo)beatmapInfo.Metadata).Equals(SelectedBeatmapInfo.Metadata)) continue; - - // Best effort matching. We can't use ID because in the update flow a new version will get its own GUID. - if (beatmapInfo.DifficultyName == SelectedBeatmapInfo.DifficultyName) - { - SelectBeatmap(beatmapInfo); - return; - } - } - } - - // If a direct selection couldn't be made, it's feasible that the difficulty name (or beatmap metadata) changed. - // Let's attempt to follow set-level selection anyway. - SelectBeatmap(setsRequiringUpdate.First().Beatmaps.First()); - } - } - } - finally - { - BeatmapSetsLoaded = true; - invalidateAfterChange(); - } - - setsRequiringRemoval.Clear(); - setsRequiringUpdate.Clear(); - - BeatmapSetInfo? fetchFromID(Guid id) => realm.Realm.Find(id); - } - - public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() => - { - removeBeatmapSet(beatmapSet.ID); - invalidateAfterChange(); - }); - - private void removeBeatmapSet(Guid beatmapSetID) - { - if (!root.BeatmapSetsByID.TryGetValue(beatmapSetID, out var existingSets)) - return; - - foreach (var set in existingSets) - { - foreach (var beatmap in set.Beatmaps) - randomSelectedBeatmaps.Remove(beatmap); - previouslyVisitedRandomSets.Remove(set); - - root.RemoveItem(set); - } - } - - public void UpdateBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() => - { - updateBeatmapSet(beatmapSet); - invalidateAfterChange(); - }); - - private void updateBeatmapSet(BeatmapSetInfo beatmapSet) - { - var newSets = new List(); - - if (beatmapsSplitOut) - { - foreach (var beatmap in beatmapSet.Beatmaps) - { - var newSet = createCarouselSet(new BeatmapSetInfo(new[] { beatmap }) - { - ID = beatmapSet.ID, - OnlineID = beatmapSet.OnlineID, - Status = beatmapSet.Status, - }); - - if (newSet != null) - newSets.Add(newSet); - } - } - else - { - var newSet = createCarouselSet(beatmapSet); - - if (newSet != null) - newSets.Add(newSet); - } - - var removedSets = root.ReplaceItem(beatmapSet, newSets); - - // If we don't remove these here, it may remain in a hidden state until scrolled off screen. - // Doesn't really affect anything during actual user interaction, but makes testing annoying. - foreach (var removedSet in removedSets) - { - var removedDrawable = Scroll.FirstOrDefault(c => c.Item == removedSet); - if (removedDrawable != null) - expirePanelImmediately(removedDrawable); - } - } - - /// - /// Selects a given beatmap on the carousel. - /// - /// The beatmap to select. - /// Whether to select the beatmap even if it is filtered (i.e., not visible on carousel). - /// True if a selection was made, False if it wasn't. - public bool SelectBeatmap(BeatmapInfo? beatmapInfo, bool bypassFilters = true) - { - // ensure that any pending events from BeatmapManager have been run before attempting a selection. - Scheduler.Update(); - - if (beatmapInfo?.Hidden != false) - return false; - - foreach (CarouselBeatmapSet set in beatmapSets) - { - if (!bypassFilters && set.Filtered.Value) - continue; - - var item = set.Beatmaps.FirstOrDefault(p => p.BeatmapInfo.Equals(beatmapInfo)); - - if (item == null) - // The beatmap that needs to be selected doesn't exist in this set - continue; - - if (!bypassFilters && item.Filtered.Value) - return false; - - select(item); - - // if we got here and the set is filtered, it means we were bypassing filters. - // in this case, reapplying the filter is necessary to ensure the panel is in the correct place - // (since it is forcefully being included in the carousel). - if (set.Filtered.Value) - { - Debug.Assert(bypassFilters); - - applyActiveCriteria(false); - } - - return true; - } - - return false; - } - - /// - /// Increment selection in the carousel in a chosen direction. - /// - /// The direction to increment. Negative is backwards. - /// Whether to skip individual difficulties and only increment over full groups. - public void SelectNext(int direction = 1, bool skipDifficulties = true) - { - if (beatmapSets.All(s => s.Filtered.Value)) - return; - - if (skipDifficulties) - selectNextSet(direction, true); - else - selectNextDifficulty(direction); - } - - private void selectNextSet(int direction, bool skipDifficulties) - { - if (selectedBeatmap == null || selectedBeatmapSet == null) - return; - - var unfilteredSets = beatmapSets.Where(s => !s.Filtered.Value).ToList(); - - var nextSet = unfilteredSets[(unfilteredSets.IndexOf(selectedBeatmapSet) + direction + unfilteredSets.Count) % unfilteredSets.Count]; - - if (skipDifficulties) - select(nextSet); - else - select(direction > 0 ? nextSet.Beatmaps.First(b => !b.Filtered.Value) : nextSet.Beatmaps.Last(b => !b.Filtered.Value)); - } - - private void selectNextDifficulty(int direction) - { - if (selectedBeatmap == null || selectedBeatmapSet == null) - return; - - var unfilteredDifficulties = selectedBeatmapSet.Items.Where(s => !s.Filtered.Value).ToList(); - - int index = unfilteredDifficulties.IndexOf(selectedBeatmap); - - if (index + direction < 0 || index + direction >= unfilteredDifficulties.Count) - selectNextSet(direction, false); - else - select(unfilteredDifficulties[index + direction]); - } - - /// - /// Select the next beatmap in the random sequence. - /// - /// True if a selection could be made, else False. - public bool SelectNextRandom() - { - if (!AllowSelection) - return false; - - var visibleSets = beatmapSets.Where(s => !s.Filtered.Value).ToList(); - - visibleSetsCount = visibleSets.Count; - - if (!visibleSets.Any()) - return false; - - if (selectedBeatmap != null && selectedBeatmapSet != null) - { - randomSelectedBeatmaps.Add(selectedBeatmap); - - // when performing a random, we want to add the current set to the previously visited list - // else the user may be "randomised" to the existing selection. - if (previouslyVisitedRandomSets.LastOrDefault() != selectedBeatmapSet) - previouslyVisitedRandomSets.Add(selectedBeatmapSet); - } - - CarouselBeatmapSet set; - - if (RandomAlgorithm.Value == RandomSelectAlgorithm.RandomPermutation) - { - var notYetVisitedSets = visibleSets.Except(previouslyVisitedRandomSets).ToList(); - - if (!notYetVisitedSets.Any()) - { - previouslyVisitedRandomSets.RemoveAll(visibleSets.Contains); - notYetVisitedSets = visibleSets; - } - - set = notYetVisitedSets.ElementAt(RNG.Next(notYetVisitedSets.Count)); - previouslyVisitedRandomSets.Add(set); - } - else - set = visibleSets.ElementAt(RNG.Next(visibleSets.Count)); - - if (selectedBeatmapSet != null) - playSpinSample(distanceBetween(set, selectedBeatmapSet)); - - select(set); - return true; - } - - public void SelectPreviousRandom() - { - while (randomSelectedBeatmaps.Any()) - { - var beatmap = randomSelectedBeatmaps[^1]; - randomSelectedBeatmaps.RemoveAt(randomSelectedBeatmaps.Count - 1); - - if (!beatmap.Filtered.Value && beatmap.BeatmapInfo.BeatmapSet?.DeletePending != true) - { - if (selectedBeatmapSet != null) - { - if (RandomAlgorithm.Value == RandomSelectAlgorithm.RandomPermutation) - previouslyVisitedRandomSets.Remove(selectedBeatmapSet); - - playSpinSample(distanceBetween(beatmap, selectedBeatmapSet)); - } - - select(beatmap); - break; - } - } - } - - private double distanceBetween(CarouselItem item1, CarouselItem item2) => Math.Ceiling(Math.Abs(item1.CarouselYPosition - item2.CarouselYPosition) / DrawableCarouselItem.MAX_HEIGHT); - - private void playSpinSample(double distance) - { - var chan = spinSample?.GetChannel(); - - if (chan != null) - { - chan.Frequency.Value = 1f + Math.Min(1f, distance / visibleSetsCount); - chan.Play(); - } - - randomSelectSample?.Play(); - } - - private void select(CarouselItem? item) - { - if (!AllowSelection) - return; - - if (item == null) return; - - item.State.Value = CarouselItemState.Selected; - } - - private FilterCriteria activeCriteria; - - protected ScheduledDelegate? PendingFilter; - - public bool AllowSelection = true; - - /// - /// Half the height of the visible content. - /// - /// This is different from the height of .displayableContent, since - /// the beatmap carousel bleeds into the and the - /// - /// - private float visibleHalfHeight => (DrawHeight + BleedBottom + BleedTop) / 2; - - /// - /// The position of the lower visible bound with respect to the current scroll position. - /// - private float visibleBottomBound => (float)(Scroll.Current + DrawHeight + BleedBottom); - - /// - /// The position of the upper visible bound with respect to the current scroll position. - /// - private float visibleUpperBound => (float)(Scroll.Current - BleedTop); - - public void FlushPendingFilterOperations() - { - if (!IsLoaded) - return; - - if (PendingFilter?.Completed == false) - { - applyActiveCriteria(false); - Update(); - } - } - - public void Filter(FilterCriteria? newCriteria) - { - if (newCriteria != null) - activeCriteria = newCriteria; - - applyActiveCriteria(true); - } - - private bool beatmapsSplitOut; - - private void applyActiveCriteria(bool debounce) - { - PendingFilter?.Cancel(); - PendingFilter = null; - - if (debounce) - PendingFilter = Scheduler.AddDelayed(perform, 250); - else - { - // if initial load is not yet finished, this will be run inline in loadBeatmapSets to ensure correct order of operation. - if (!BeatmapSetsLoaded) - PendingFilter = Schedule(perform); - else - perform(); - } - - void perform() - { - PendingFilter = null; - - if ((activeCriteria.Sort == SortMode.Difficulty) != beatmapsSplitOut) - { - loadNewRoot(); - return; - } - - root.Filter(activeCriteria); - itemsCache.Invalidate(); - - ScrollToSelected(true); - - FilterApplied?.Invoke(); - } - } - - private void invalidateAfterChange() - { - itemsCache.Invalidate(); - - if (!Scroll.UserScrolling) - ScrollToSelected(true); - - BeatmapSetsChanged?.Invoke(); - } - - private float? scrollTarget; - - /// - /// Scroll to the current . - /// - /// - /// Whether the scroll position should immediately be shifted to the target, delegating animation to visible panels. - /// This should be true for operations like filtering - where panels are changing visibility state - to avoid large jumps in animation. - /// - public void ScrollToSelected(bool immediate = false) => - pendingScrollOperation = immediate ? PendingScrollOperation.Immediate : PendingScrollOperation.Standard; - - #region Button selection logic - - public bool OnPressed(KeyBindingPressEvent e) - { - switch (e.Action) - { - case GlobalAction.SelectNext: - case GlobalAction.ActivateNextSet: - SelectNext(1, e.Action == GlobalAction.ActivateNextSet); - return true; - - case GlobalAction.SelectPrevious: - case GlobalAction.ActivatePreviousSet: - SelectNext(-1, e.Action == GlobalAction.ActivatePreviousSet); - return true; - } - - return false; - } - - public void OnReleased(KeyBindingReleaseEvent e) - { - } - - #endregion - - protected override bool OnInvalidate(Invalidation invalidation, InvalidationSource source) - { - // handles the vertical size of the carousel changing (ie. on window resize when aspect ratio has changed). - if (invalidation.HasFlag(Invalidation.DrawSize)) - itemsCache.Invalidate(); - - return base.OnInvalidate(invalidation, source); - } - - protected override void Update() - { - base.Update(); - - bool revalidateItems = !itemsCache.IsValid; - - // First we iterate over all non-filtered carousel items and populate their - // vertical position data. - if (revalidateItems) - { - updateYPositions(); - - if (visibleItems.Count == 0) - { - noResultsPlaceholder.Filter = activeCriteria; - noResultsPlaceholder.Show(); - } - else - noResultsPlaceholder.Hide(); - } - - // if there is a pending scroll action we apply it without animation and transfer the difference in position to the panels. - // this is intentionally applied before updating the visible range below, to avoid animating new items (sourced from pool) from locations off-screen, as it looks bad. - if (pendingScrollOperation != PendingScrollOperation.None) - updateScrollPosition(); - - // This data is consumed to find the currently displayable range. - // This is the range we want to keep drawables for, and should exceed the visible range slightly to avoid drawable churn. - var newDisplayRange = getDisplayRange(); - - // If the filtered items or visible range has changed, pooling requirements need to be checked. - // This involves fetching new items from the pool, returning no-longer required items. - if (revalidateItems || newDisplayRange != displayedRange) - { - displayedRange = newDisplayRange; - - if (visibleItems.Count > 0) - { - var toDisplay = visibleItems.GetRange(displayedRange.first, displayedRange.last - displayedRange.first + 1); - - foreach (var panel in Scroll) - { - Debug.Assert(panel.Item != null); - - if (toDisplay.Remove(panel.Item)) - { - // panel already displayed. - continue; - } - - // panel loaded as drawable but not required by visible range. - // remove but only if too far off-screen - if (panel.Y + panel.DrawHeight < visibleUpperBound - distance_offscreen_before_unload || panel.Y > visibleBottomBound + distance_offscreen_before_unload) - expirePanelImmediately(panel); - } - - // Add those items within the previously found index range that should be displayed. - foreach (var item in toDisplay) - { - var panel = setPool.Get(); - - panel.Item = item; - panel.Y = item.CarouselYPosition; - - Scroll.Add(panel); - } - } - } - - // Update externally controlled state of currently visible items (e.g. x-offset and opacity). - // This is a per-frame update on all drawable panels. - foreach (DrawableCarouselItem item in Scroll) - { - updateItem(item); - - Debug.Assert(item.Item != null); - - if (item.Item.Visible) - { - bool isSelected = item.Item.State.Value == CarouselItemState.Selected; - - bool hasPassedSelection = item.Item.CarouselYPosition < selectedBeatmapSet?.CarouselYPosition; - - // Cheap way of doing animations when entering / exiting song select. - const double half_time = 50; - const float panel_x_offset_when_inactive = 200; - - if (isSelected || AllowSelection) - { - item.Alpha = (float)Interpolation.DampContinuously(item.Alpha, 1, half_time, Clock.ElapsedFrameTime); - item.X = (float)Interpolation.DampContinuously(item.X, 0, half_time, Clock.ElapsedFrameTime); - } - else - { - item.Alpha = (float)Interpolation.DampContinuously(item.Alpha, 0, half_time, Clock.ElapsedFrameTime); - item.X = (float)Interpolation.DampContinuously(item.X, panel_x_offset_when_inactive, half_time, Clock.ElapsedFrameTime); - } - - Scroll.ChangeChildDepth(item, hasPassedSelection ? -item.Item.CarouselYPosition : item.Item.CarouselYPosition); - } - - if (item is DrawableCarouselBeatmapSet set) - { - for (int i = 0; i < set.DrawableBeatmaps.Count; i++) - updateItem(set.DrawableBeatmaps[i], item); - } - } - } - - private static void expirePanelImmediately(DrawableCarouselItem panel) - { - // may want a fade effect here (could be seen if a huge change happens, like a set with 20 difficulties becomes selected). - panel.ClearTransforms(); - panel.Expire(); - } - - private readonly CarouselBoundsItem carouselBoundsItem = new CarouselBoundsItem(); - - private (int firstIndex, int lastIndex) getDisplayRange() - { - // Find index range of all items that should be on-screen - carouselBoundsItem.CarouselYPosition = visibleUpperBound - distance_offscreen_to_preload; - int firstIndex = visibleItems.BinarySearch(carouselBoundsItem); - if (firstIndex < 0) firstIndex = ~firstIndex; - - carouselBoundsItem.CarouselYPosition = visibleBottomBound + distance_offscreen_to_preload; - int lastIndex = visibleItems.BinarySearch(carouselBoundsItem); - if (lastIndex < 0) lastIndex = ~lastIndex; - - // as we can't be 100% sure on the size of individual carousel drawables, - // always play it safe and extend bounds by one. - firstIndex = Math.Max(0, firstIndex - 1); - lastIndex = Math.Clamp(lastIndex + 1, firstIndex, Math.Max(0, visibleItems.Count - 1)); - - return (firstIndex, lastIndex); - } - - private CarouselBeatmapSet? createCarouselSet(BeatmapSetInfo beatmapSet) - { - // This can be moved to the realm query if required using: - // .Filter("DeletePending == false && Protected == false && ANY Beatmaps.Hidden == false") - // - // As long as we are detaching though, it makes more sense to do it here as adding to the realm query has an overhead - // as seen at https://github.com/realm/realm-dotnet/discussions/2773#discussioncomment-2004275. - if (beatmapSet.Beatmaps.All(b => b.Hidden)) - return null; - - var set = new CarouselBeatmapSet(beatmapSet) - { - GetRecommendedBeatmap = beatmaps => GetRecommendedBeatmap?.Invoke(beatmaps) - }; - - foreach (var c in set.Beatmaps) - { - c.State.ValueChanged += state => - { - if (state.NewValue == CarouselItemState.Selected) - { - selectedBeatmapSet = set; - SelectionChanged?.Invoke(c.BeatmapInfo); - - itemsCache.Invalidate(); - ScrollToSelected(); - } - }; - } - - return set; - } - - /// - /// Computes the target Y positions for every item in the carousel. - /// - /// The Y position of the currently selected item. - private void updateYPositions() - { - visibleItems.Clear(); - - float currentY = visibleHalfHeight; - - scrollTarget = null; - - foreach (CarouselItem item in root.Items) - { - if (item.Filtered.Value) - continue; - - switch (item) - { - case CarouselBeatmapSet set: - { - bool isSelected = item.State.Value == CarouselItemState.Selected; - - float padding = isSelected ? 5 : -5; - - if (isSelected) - // double padding because we want to cancel the negative padding from the last item. - currentY += padding * 2; - - visibleItems.Add(set); - set.CarouselYPosition = currentY; - - if (isSelected) - { - // scroll position at currentY makes the set panel appear at the very top of the carousel's screen space - // move down by half of visible height (height of the carousel's visible extent, including semi-transparent areas) - // then reapply the top semi-transparent area (because carousel's screen space starts below it) - scrollTarget = currentY + DrawableCarouselBeatmapSet.HEIGHT - visibleHalfHeight + BleedTop; - - foreach (var b in set.Beatmaps) - { - if (!b.Visible) - continue; - - if (b.State.Value == CarouselItemState.Selected) - { - scrollTarget += b.TotalHeight / 2; - break; - } - - scrollTarget += b.TotalHeight; - } - } - - currentY += set.TotalHeight + padding; - break; - } - } - } - - currentY += visibleHalfHeight; - - Scroll.ScrollContent.Height = currentY; - - itemsCache.Validate(); - - // update and let external consumers know about selection loss. - if (BeatmapSetsLoaded && AllowSelection) - { - bool selectionLost = selectedBeatmapSet != null && selectedBeatmapSet.State.Value != CarouselItemState.Selected; - - if (selectionLost) - { - selectedBeatmapSet = null; - SelectionChanged?.Invoke(null); - } - } - } - - private bool firstScroll = true; - - private void updateScrollPosition() - { - if (scrollTarget != null) - { - if (firstScroll) - { - // reduce movement when first displaying the carousel. - Scroll.ScrollTo(scrollTarget.Value - 200, false); - firstScroll = false; - } - - switch (pendingScrollOperation) - { - case PendingScrollOperation.Standard: - Scroll.ScrollTo(scrollTarget.Value); - break; - - case PendingScrollOperation.Immediate: - - // in order to simplify animation logic, rather than using the animated version of ScrollTo, - // we take the difference in scroll height and apply to all visible panels. - // this avoids edge cases like when the visible panels is reduced suddenly, causing ScrollContainer - // to enter clamp-special-case mode where it animates completely differently to normal. - float scrollChange = (float)(scrollTarget.Value - Scroll.Current); - Scroll.ScrollTo(scrollTarget.Value, false); - foreach (var i in Scroll) - i.Y += scrollChange; - break; - } - - pendingScrollOperation = PendingScrollOperation.None; - } - } - - /// - /// Computes the x-offset of currently visible items. Makes the carousel appear round. - /// - /// - /// Vertical distance from the center of the carousel container - /// ranging from -1 to 1. - /// - /// Half the height of the carousel container. - private static float offsetX(float dist, float halfHeight) - { - // The radius of the circle the carousel moves on. - const float circle_radius = 3; - float discriminant = MathF.Max(0, circle_radius * circle_radius - dist * dist); - float x = (circle_radius - MathF.Sqrt(discriminant)) * halfHeight; - - return 125 + x; - } - - /// - /// Update an item's x position and multiplicative alpha based on its y position and - /// the current scroll position. - /// - /// The item to be updated. - /// For nested items, the parent of the item to be updated. - private void updateItem(DrawableCarouselItem item, DrawableCarouselItem? parent = null) - { - Vector2 posInScroll = Scroll.ScrollContent.ToLocalSpace(item.Header.ScreenSpaceDrawQuad.Centre); - float itemDrawY = posInScroll.Y - visibleUpperBound; - float dist = Math.Abs(1f - itemDrawY / visibleHalfHeight); - - // adjusting the item's overall X position can cause it to become masked away when - // child items (difficulties) are still visible. - item.Header.X = offsetX(dist, visibleHalfHeight) - (parent?.X ?? 0); - } - - private enum PendingScrollOperation - { - None, - Standard, - Immediate, - } - - /// - /// A carousel item strictly used for binary search purposes. - /// - private class CarouselBoundsItem : CarouselItem - { - public override DrawableCarouselItem CreateDrawableRepresentation() => throw new NotImplementedException(); - } - - private class CarouselRoot : CarouselGroupEagerSelect - { - // May only be null during construction (State.Value set causes PerformSelection to be triggered). - private readonly BeatmapCarousel? carousel; - - public readonly Dictionary> BeatmapSetsByID = new Dictionary>(); - - public CarouselRoot(BeatmapCarousel carousel) - { - // root should always remain selected. if not, PerformSelection will not be called. - State.Value = CarouselItemState.Selected; - State.ValueChanged += _ => State.Value = CarouselItemState.Selected; - - this.carousel = carousel; - } - - public override void AddItem(CarouselItem i) - { - CarouselBeatmapSet set = (CarouselBeatmapSet)i; - if (BeatmapSetsByID.TryGetValue(set.BeatmapSet.ID, out var sets)) - sets.Add(set); - else - BeatmapSetsByID.Add(set.BeatmapSet.ID, new List { set }); - - base.AddItem(i); - } - - /// - /// A special method to handle replace operations (general for updating a beatmap). - /// Avoids event-driven selection flip-flopping during the remove/add process. - /// - /// The beatmap set to be replaced. - /// All new items to replace the removed beatmap set. - /// All removed items, for any further processing. - public IEnumerable ReplaceItem(BeatmapSetInfo oldItem, List newItems) - { - var previousSelection = (LastSelected as CarouselBeatmapSet)?.Beatmaps - .FirstOrDefault(s => s.State.Value == CarouselItemState.Selected) - ?.BeatmapInfo; - - bool wasSelected = previousSelection?.BeatmapSet?.ID == oldItem.ID; - - // Without doing this, the removal of the old beatmap will cause carousel's eager selection - // logic to invoke, causing one unnecessary selection. - DisableSelection = true; - var removedSets = RemoveItemsByID(oldItem.ID); - DisableSelection = false; - - foreach (var set in newItems) - AddItem(set); - - // Check if we can/need to maintain our current selection. - if (wasSelected) - { - CarouselBeatmap? matchingBeatmap = newItems.SelectMany(s => s.Beatmaps) - .FirstOrDefault(b => b.BeatmapInfo.ID == previousSelection?.ID); - - if (matchingBeatmap != null) - matchingBeatmap.State.Value = CarouselItemState.Selected; - } - - return removedSets; - } - - public IEnumerable RemoveItemsByID(Guid beatmapSetID) - { - if (BeatmapSetsByID.TryGetValue(beatmapSetID, out var carouselBeatmapSets)) - { - foreach (var set in carouselBeatmapSets) - RemoveItem(set); - - return carouselBeatmapSets; - } - - return Enumerable.Empty(); - } - - public override void RemoveItem(CarouselItem i) - { - CarouselBeatmapSet set = (CarouselBeatmapSet)i; - BeatmapSetsByID.Remove(set.BeatmapSet.ID); - - base.RemoveItem(i); - } - - protected override void PerformSelection() - { - if (LastSelected == null) - carousel?.SelectNextRandom(); - else - base.PerformSelection(); - } - } - - public partial class CarouselScrollContainer : UserTrackingScrollContainer, IKeyBindingHandler - { - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; - - public CarouselScrollContainer() - { - // size is determined by the carousel itself, due to not all content necessarily being loaded. - ScrollContent.AutoSizeAxes = Axes.None; - - // the scroll container may get pushed off-screen by global screen changes, but we still want panels to display outside of the bounds. - Masking = false; - } - - #region Absolute scrolling - - private bool absoluteScrolling; - - protected override bool IsDragging => base.IsDragging || absoluteScrolling; - - public bool OnPressed(KeyBindingPressEvent e) - { - switch (e.Action) - { - case GlobalAction.AbsoluteScrollSongList: - beginAbsoluteScrolling(e); - return true; - } - - return false; - } - - public void OnReleased(KeyBindingReleaseEvent e) - { - switch (e.Action) - { - case GlobalAction.AbsoluteScrollSongList: - endAbsoluteScrolling(); - break; - } - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - if (e.Button == MouseButton.Right) - { - // To avoid conflicts with context menus, disallow absolute scroll if it looks like things will fall over. - if (GetContainingInputManager()!.HoveredDrawables.OfType().Any()) - return false; - - beginAbsoluteScrolling(e); - } - - return base.OnMouseDown(e); - } - - protected override void OnMouseUp(MouseUpEvent e) - { - if (e.Button == MouseButton.Right) - endAbsoluteScrolling(); - base.OnMouseUp(e); - } - - protected override bool OnMouseMove(MouseMoveEvent e) - { - if (absoluteScrolling) - { - ScrollToAbsolutePosition(e.CurrentState.Mouse.Position); - return true; - } - - return base.OnMouseMove(e); - } - - private void beginAbsoluteScrolling(UIEvent e) - { - ScrollToAbsolutePosition(e.CurrentState.Mouse.Position); - absoluteScrolling = true; - } - - private void endAbsoluteScrolling() => absoluteScrolling = false; - - #endregion - - protected override ScrollbarContainer CreateScrollbar(Direction direction) - { - return new PaddedScrollbar(); - } - - protected partial class PaddedScrollbar : OsuScrollbar - { - public PaddedScrollbar() - : base(Direction.Vertical) - { - } - } - - private const float top_padding = 10; - private const float bottom_padding = 70; - - protected override float ToScrollbarPosition(double scrollPosition) - { - if (Precision.AlmostEquals(0, ScrollableExtent)) - return 0; - - return (float)(top_padding + (ScrollbarMovementExtent - (top_padding + bottom_padding)) * (scrollPosition / ScrollableExtent)); - } - - protected override float FromScrollbarPosition(float scrollbarPosition) - { - if (Precision.AlmostEquals(0, ScrollbarMovementExtent)) - return 0; - - return (float)(ScrollableExtent * ((scrollbarPosition - top_padding) / (ScrollbarMovementExtent - (top_padding + bottom_padding)))); - } - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs deleted file mode 100644 index 595b86924b29..000000000000 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; - -namespace osu.Game.Screens.Select -{ - public abstract partial class BeatmapDetailArea : Container - { - private const float details_padding = 10; - - private WorkingBeatmap beatmap; - - public virtual WorkingBeatmap Beatmap - { - get => beatmap; - set - { - beatmap = value; - - Details.BeatmapInfo = value?.BeatmapInfo; - } - } - - public readonly BeatmapDetails Details; - - protected Bindable CurrentTab => tabControl.Current; - - protected Bindable CurrentModsFilter => tabControl.CurrentModsFilter; - - private readonly Container content; - protected override Container Content => content; - - private readonly BeatmapDetailAreaTabControl tabControl; - - protected BeatmapDetailArea() - { - AddRangeInternal(new Drawable[] - { - content = new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = BeatmapDetailAreaTabControl.HEIGHT }, - Child = Details = new BeatmapDetails - { - RelativeSizeAxes = Axes.X, - Alpha = 0, - Margin = new MarginPadding { Top = details_padding }, - } - }, - tabControl = new BeatmapDetailAreaTabControl - { - RelativeSizeAxes = Axes.X, - TabItems = CreateTabItems(), - OnFilter = OnTabChanged, - }, - }); - } - - /// - /// Refreshes the currently-displayed details. - /// - public virtual void Refresh() - { - } - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - Details.Height = Math.Min(DrawHeight - details_padding * 3 - BeatmapDetailAreaTabControl.HEIGHT, 450); - } - - /// - /// Invoked when a new tab is selected. - /// - /// The tab that was selected. - /// Whether the currently-selected mods should be considered. - protected virtual void OnTabChanged(BeatmapDetailAreaTabItem tab, bool selectedMods) - { - switch (tab) - { - case BeatmapDetailAreaDetailTabItem: - Details.Show(); - break; - - default: - Details.Hide(); - break; - } - } - - /// - /// Creates the tabs to be displayed. - /// - /// The tabs. - protected virtual BeatmapDetailAreaTabItem[] CreateTabItems() => new BeatmapDetailAreaTabItem[] - { - new BeatmapDetailAreaDetailTabItem(), - }; - } -} diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs b/osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs deleted file mode 100644 index 4ff2600a7263..000000000000 --- a/osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -namespace osu.Game.Screens.Select -{ - public class BeatmapDetailAreaDetailTabItem : BeatmapDetailAreaTabItem - { - public override string Name => "Details"; - } -} diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs b/osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs deleted file mode 100644 index 8dbe5b8bea65..000000000000 --- a/osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; - -namespace osu.Game.Screens.Select -{ - public class BeatmapDetailAreaLeaderboardTabItem : BeatmapDetailAreaTabItem - where TScope : Enum - { - public override string Name => Scope.ToString(); - - public override bool FilterableByMods => true; - - public readonly TScope Scope; - - public BeatmapDetailAreaLeaderboardTabItem(TScope scope) - { - Scope = scope; - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs deleted file mode 100644 index f9dab2bb1d74..000000000000 --- a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; -using osuTK.Graphics; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; -using osu.Framework.Graphics.Shapes; - -namespace osu.Game.Screens.Select -{ - public partial class BeatmapDetailAreaTabControl : Container - { - public const float HEIGHT = 24; - - public Bindable Current - { - get => tabs.Current; - set => tabs.Current = value; - } - - public Bindable CurrentModsFilter - { - get => modsCheckbox.Current; - set => modsCheckbox.Current = value; - } - - public Action OnFilter; // passed the selected tab and if mods is checked - - public IReadOnlyList TabItems - { - get => tabs.Items; - set => tabs.Items = value; - } - - private readonly OsuTabControlCheckbox modsCheckbox; - private readonly OsuTabControl tabs; - private readonly Container tabsContainer; - - public BeatmapDetailAreaTabControl() - { - Height = HEIGHT; - - Children = new Drawable[] - { - new Box - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - Height = 1, - Colour = Color4.White.Opacity(0.2f), - }, - tabsContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Child = tabs = new OsuTabControl - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Both, - IsSwitchable = true, - }, - }, - modsCheckbox = new OsuTabControlCheckbox - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Text = @"Selected Mods", - Alpha = 0, - }, - }; - - tabs.Current.ValueChanged += _ => invokeOnFilter(); - modsCheckbox.Current.ValueChanged += _ => invokeOnFilter(); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colour) - { - modsCheckbox.AccentColour = tabs.AccentColour = colour.YellowLight; - } - - private void invokeOnFilter() - { - OnFilter?.Invoke(tabs.Current.Value, modsCheckbox.Current.Value); - - if (tabs.Current.Value.FilterableByMods) - { - modsCheckbox.FadeTo(1, 200, Easing.OutQuint); - tabsContainer.Padding = new MarginPadding { Right = 100 }; - } - else - { - modsCheckbox.FadeTo(0, 200, Easing.OutQuint); - tabsContainer.Padding = new MarginPadding(); - } - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs deleted file mode 100644 index 7b7a93d6ee5b..000000000000 --- a/osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; - -namespace osu.Game.Screens.Select -{ - public abstract class BeatmapDetailAreaTabItem : IEquatable - { - /// - /// The name of this tab, to be displayed in the tab control. - /// - public abstract string Name { get; } - - /// - /// Whether the contents of this tab can be filtered by the user's currently-selected mods. - /// - public virtual bool FilterableByMods => false; - - public override string ToString() => Name; - - public bool Equals(BeatmapDetailAreaTabItem other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - - return Name == other.Name; - } - - public override int GetHashCode() - { - return Name != null ? Name.GetHashCode() : 0; - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs deleted file mode 100644 index 6a6a4cddf3e5..000000000000 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; -using osu.Game.Overlays.BeatmapSet; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Screens.Select.Details; -using osuTK; - -namespace osu.Game.Screens.Select -{ - public partial class BeatmapDetails : Container - { - private const float spacing = 10; - private const float transition_duration = 250; - - private readonly UserRatings ratingsDisplay; - private readonly MetadataSection description, source, tags; - private readonly Container failRetryContainer; - private readonly FailRetryGraph failRetryGraph; - private readonly LoadingLayer loading; - - [Resolved] - private IAPIProvider api { get; set; } = null!; - - [Resolved] - private SongSelect? songSelect { get; set; } - - private IBeatmapInfo? beatmapInfo; - - private APIFailTimes? failTimes; - - private int[]? ratings; - - public IBeatmapInfo? BeatmapInfo - { - get => beatmapInfo; - set - { - if (value == beatmapInfo) return; - - beatmapInfo = value; - - var onlineInfo = beatmapInfo as IBeatmapOnlineInfo; - var onlineSetInfo = beatmapInfo?.BeatmapSet as IBeatmapSetOnlineInfo; - - failTimes = onlineInfo?.FailTimes; - ratings = onlineSetInfo?.Ratings; - - Scheduler.AddOnce(updateStatistics); - } - } - - public BeatmapDetails() - { - CornerRadius = 10; - Masking = true; - - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Colour4.Black.Opacity(0.3f), - }, - new GridContainer - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = spacing }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension() - }, - Content = new[] - { - new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Width = 0.5f, - Spacing = new Vector2(spacing), - Padding = new MarginPadding { Right = spacing / 2 }, - Children = new[] - { - new DetailBox().WithChild(new OnlineViewContainer(string.Empty) - { - RelativeSizeAxes = Axes.X, - Height = 134, - Padding = new MarginPadding { Horizontal = spacing, Top = spacing }, - Child = ratingsDisplay = new UserRatings - { - RelativeSizeAxes = Axes.Both, - }, - }), - }, - }, - new OsuScrollContainer - { - RelativeSizeAxes = Axes.X, - Height = 250, - Width = 0.5f, - ScrollbarVisible = false, - Padding = new MarginPadding { Left = spacing / 2 }, - Child = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - LayoutDuration = transition_duration, - LayoutEasing = Easing.OutQuad, - Children = new[] - { - description = new MetadataSectionDescription(query => songSelect?.Search(query)), - source = new MetadataSectionSource(query => songSelect?.Search(query)), - tags = new MetadataSectionMapperTags(query => songSelect?.Search(query)), - }, - }, - }, - }, - }, - }, - new Drawable[] - { - failRetryContainer = new OnlineViewContainer("Sign in to view more details") - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = BeatmapsetsStrings.ShowInfoPointsOfFailure, - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14), - }, - failRetryGraph = new FailRetryGraph - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 14 + spacing / 2 }, - }, - }, - }, - } - } - }, - loading = new LoadingLayer(true) - }; - } - - private void updateStatistics() - { - description.Metadata = BeatmapInfo?.DifficultyName ?? string.Empty; - source.Metadata = BeatmapInfo?.Metadata.Source ?? string.Empty; - tags.Metadata = BeatmapInfo?.Metadata.Tags ?? string.Empty; - - // failTimes may have been previously fetched - if (ratings != null && failTimes != null) - { - updateMetrics(); - return; - } - - // for now, let's early abort if an OnlineID is not present (should have been populated at import time). - if (BeatmapInfo == null || BeatmapInfo.OnlineID <= 0 || api.State.Value == APIState.Offline) - { - updateMetrics(); - return; - } - - var requestedBeatmap = BeatmapInfo; - - var lookup = new GetBeatmapRequest(requestedBeatmap); - - lookup.Success += res => - { - Schedule(() => - { - if (beatmapInfo != requestedBeatmap) - // the beatmap has been changed since we started the lookup. - return; - - ratings = res.BeatmapSet?.Ratings; - failTimes = res.FailTimes; - - updateMetrics(); - }); - }; - - lookup.Failure += _ => - { - Schedule(() => - { - if (beatmapInfo != requestedBeatmap) - // the beatmap has been changed since we started the lookup. - return; - - updateMetrics(); - }); - }; - - api.Queue(lookup); - loading.Show(); - } - - private void updateMetrics() - { - bool hasMetrics = (failTimes?.Retries?.Any() ?? false) || (failTimes?.Fails?.Any() ?? false); - - if (ratings?.Any() ?? false) - { - ratingsDisplay.Ratings = ratings; - ratingsDisplay.FadeIn(transition_duration); - } - else - { - // loading or just has no data server-side. - ratingsDisplay.Ratings = new int[10]; - ratingsDisplay.FadeTo(0.25f, transition_duration); - } - - if (hasMetrics) - { - failRetryGraph.FailTimes = failTimes; - failRetryContainer.FadeIn(transition_duration); - } - else - { - failRetryGraph.FailTimes = new APIFailTimes - { - Fails = new int[100], - Retries = new int[100], - }; - } - - loading.Hide(); - } - - private partial class DetailBox : Container - { - private readonly Container content; - protected override Container Content => content; - - public DetailBox() - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - - InternalChildren = new Drawable[] - { - content = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }, - }; - } - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs deleted file mode 100644 index 79564167f42c..000000000000 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ /dev/null @@ -1,517 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using osuTK; -using osuTK.Graphics; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Localisation; -using osu.Framework.Logging; -using osu.Game.Configuration; -using osu.Game.Extensions; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.UI; -using osu.Game.Graphics.Containers; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Utils; - -namespace osu.Game.Screens.Select -{ - public partial class BeatmapInfoWedge : VisibilityContainer - { - public const float BORDER_THICKNESS = 2.5f; - private const float shear_width = 36.75f; - - private const float transition_duration = 250; - - private static readonly Vector2 wedged_container_shear = new Vector2(shear_width / SongSelect.WEDGE_HEIGHT, 0); - - [Resolved] - private IBindable ruleset { get; set; } - - protected Container DisplayedContent { get; private set; } - - protected WedgeInfoText Info { get; private set; } - - public BeatmapInfoWedge() - { - Shear = wedged_container_shear; - Masking = true; - BorderColour = new Color4(221, 255, 255, 255); - BorderThickness = BORDER_THICKNESS; - Alpha = 0; - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = new Color4(130, 204, 255, 150), - Radius = 15, - Roundness = 15, - }; - } - - [BackgroundDependencyLoader] - private void load() - { - ruleset.BindValueChanged(_ => updateDisplay()); - } - - private const double animation_duration = 800; - - protected override void PopIn() - { - this.MoveToX(0, animation_duration, Easing.OutQuint); - this.FadeIn(transition_duration); - } - - protected override void PopOut() - { - this.MoveToX(-100, animation_duration, Easing.In); - this.FadeOut(transition_duration * 2, Easing.In); - } - - private WorkingBeatmap beatmap; - - public WorkingBeatmap Beatmap - { - get => beatmap; - set - { - if (beatmap == value) return; - - beatmap = value; - - updateDisplay(); - } - } - - public override bool IsPresent => base.IsPresent || DisplayedContent == null; // Visibility is updated in the LoadComponentAsync callback - - private Container loadingInfo; - - private void updateDisplay() - { - Scheduler.AddOnce(perform); - - void perform() - { - void removeOldInfo() - { - State.Value = beatmap == null ? Visibility.Hidden : Visibility.Visible; - - DisplayedContent?.FadeOut(transition_duration); - DisplayedContent?.Expire(); - DisplayedContent = null; - } - - if (beatmap == null) - { - removeOldInfo(); - return; - } - - LoadComponentAsync(loadingInfo = new Container - { - RelativeSizeAxes = Axes.Both, - Shear = -Shear, - Depth = DisplayedContent?.Depth + 1 ?? 0, - Children = new Drawable[] - { - new BeatmapInfoWedgeBackground(beatmap), - Info = new WedgeInfoText(beatmap, ruleset.Value), - } - }, loaded => - { - // ensure we are the most recent loaded wedge. - if (loaded != loadingInfo) return; - - removeOldInfo(); - Add(DisplayedContent = loaded); - }); - } - } - - public partial class WedgeInfoText : Container - { - public OsuSpriteText VersionLabel { get; private set; } - public OsuSpriteText TitleLabel { get; private set; } - public OsuSpriteText ArtistLabel { get; private set; } - public FillFlowContainer MapperContainer { get; private set; } - - private Container difficultyColourBar; - private StarRatingDisplay starRatingDisplay; - - private ILocalisedBindableString titleBinding; - private ILocalisedBindableString artistBinding; - private FillFlowContainer infoLabelContainer; - private Container bpmLabelContainer; - private Container lengthLabelContainer; - - private readonly WorkingBeatmap working; - private readonly RulesetInfo ruleset; - - [Resolved] - private IBindable> mods { get; set; } - - [Resolved] - private BeatmapDifficultyCache difficultyCache { get; set; } - - [Resolved] - private OsuColour colours { get; set; } - - private ModSettingChangeTracker settingChangeTracker; - - public WedgeInfoText(WorkingBeatmap working, RulesetInfo userRuleset) - { - this.working = working; - ruleset = userRuleset ?? working.BeatmapInfo.Ruleset; - } - - private CancellationTokenSource cancellationSource; - private IBindable starDifficulty; - - [BackgroundDependencyLoader] - private void load(LocalisationManager localisation) - { - var beatmapInfo = working.BeatmapInfo; - var metadata = beatmapInfo.Metadata; - - RelativeSizeAxes = Axes.Both; - - titleBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.TitleUnicode, metadata.Title)); - artistBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist)); - - const float top_height = 0.7f; - - Children = new Drawable[] - { - difficultyColourBar = new Container - { - RelativeSizeAxes = Axes.Y, - Width = 20f, - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Width = top_height, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Both, - Alpha = 0.5f, - X = top_height, - Width = 1 - top_height, - } - } - }, - new FillFlowContainer - { - Name = "Topleft-aligned metadata", - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Direction = FillDirection.Vertical, - Padding = new MarginPadding { Top = 10, Left = 25, Right = shear_width * 2.5f }, - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Children = new Drawable[] - { - VersionLabel = new TruncatingSpriteText - { - Text = beatmapInfo.DifficultyName, - Font = OsuFont.GetFont(size: 24, italics: true), - RelativeSizeAxes = Axes.X, - }, - } - }, - new FillFlowContainer - { - Name = "Topright-aligned metadata", - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Direction = FillDirection.Vertical, - Padding = new MarginPadding { Top = 14, Right = shear_width / 2 }, - AutoSizeAxes = Axes.Both, - Shear = wedged_container_shear, - Spacing = new Vector2(0f, 5f), - Children = new Drawable[] - { - starRatingDisplay = new StarRatingDisplay(default, animated: true) - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Shear = -wedged_container_shear, - Alpha = 0f, - }, - new BeatmapSetOnlineStatusPill - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Shear = -wedged_container_shear, - TextSize = 11, - TextPadding = new MarginPadding { Horizontal = 8, Vertical = 2 }, - Status = beatmapInfo.Status, - Alpha = string.IsNullOrEmpty(beatmapInfo.DifficultyName) ? 0 : 1 - } - } - }, - new FillFlowContainer - { - Name = "Centre-aligned metadata", - Anchor = Anchor.CentreLeft, - Origin = Anchor.TopLeft, - Y = -7, - Direction = FillDirection.Vertical, - Padding = new MarginPadding { Left = 25, Right = shear_width }, - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Children = new Drawable[] - { - TitleLabel = new TruncatingSpriteText - { - Current = { BindTarget = titleBinding }, - Font = OsuFont.GetFont(size: 28, italics: true), - RelativeSizeAxes = Axes.X, - }, - ArtistLabel = new TruncatingSpriteText - { - Current = { BindTarget = artistBinding }, - Font = OsuFont.GetFont(size: 17, italics: true), - RelativeSizeAxes = Axes.X, - }, - MapperContainer = new FillFlowContainer - { - Margin = new MarginPadding { Top = 10 }, - Direction = FillDirection.Horizontal, - AutoSizeAxes = Axes.Both, - Child = getMapper(metadata), - }, - infoLabelContainer = new FillFlowContainer - { - Margin = new MarginPadding { Top = 8 }, - Spacing = new Vector2(20, 0), - AutoSizeAxes = Axes.Both, - } - } - } - }; - - addInfoLabels(); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - starRatingDisplay.DisplayedStars.BindValueChanged(s => - { - difficultyColourBar.Colour = colours.ForStarDifficulty(s.NewValue); - }, true); - - starDifficulty = difficultyCache.GetBindableDifficulty(working.BeatmapInfo, (cancellationSource = new CancellationTokenSource()).Token); - starDifficulty.BindValueChanged(s => - { - starRatingDisplay.Current.Value = s.NewValue; - - // Don't roll the counter on initial display (but still allow it to roll on applying mods etc.) - if (!starRatingDisplay.IsPresent) - starRatingDisplay.FinishTransforms(true); - - starRatingDisplay.FadeIn(transition_duration); - }); - - mods.BindValueChanged(m => - { - settingChangeTracker?.Dispose(); - - refreshBPMAndLengthLabel(); - - settingChangeTracker = new ModSettingChangeTracker(m.NewValue); - settingChangeTracker.SettingChanged += _ => refreshBPMAndLengthLabel(); - }, true); - } - - private void addInfoLabels() - { - if (working.Beatmap?.HitObjects.Any() != true) - return; - - try - { - IBeatmap playableBeatmap; - - try - { - // Try to get the beatmap with the user's ruleset - playableBeatmap = working.GetPlayableBeatmap(ruleset, Array.Empty()); - } - catch (BeatmapInvalidForRulesetException) - { - // Can't be converted to the user's ruleset, so use the beatmap's own ruleset - playableBeatmap = working.GetPlayableBeatmap(working.BeatmapInfo.Ruleset, Array.Empty()); - } - - infoLabelContainer.Children = new Drawable[] - { - lengthLabelContainer = new Container - { - AutoSizeAxes = Axes.Both, - }, - bpmLabelContainer = new Container - { - AutoSizeAxes = Axes.Both, - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Spacing = new Vector2(20, 0), - Children = playableBeatmap.GetStatistics().Select(s => new InfoLabel(s)).ToArray() - } - }; - } - catch (Exception e) - { - Logger.Error(e, "Could not load beatmap successfully!"); - } - } - - private void refreshBPMAndLengthLabel() - { - var beatmap = working.Beatmap; - - if (beatmap == null || bpmLabelContainer == null) - return; - - double rate = ModUtils.CalculateRateWithMods(mods.Value); - - int bpmMax = FormatUtils.RoundBPM(beatmap.ControlPointInfo.BPMMaximum, rate); - int bpmMin = FormatUtils.RoundBPM(beatmap.ControlPointInfo.BPMMinimum, rate); - int mostCommonBPM = FormatUtils.RoundBPM(60000 / beatmap.GetMostCommonBeatLength(), rate); - - string labelText = bpmMin == bpmMax - ? $"{bpmMin}" - : $"{bpmMin}-{bpmMax} (mostly {mostCommonBPM})"; - - bpmLabelContainer.Child = new InfoLabel(new BeatmapStatistic - { - Name = BeatmapsetsStrings.ShowStatsBpm, - CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Bpm), - Content = labelText - }); - - double drainLength = Math.Round(beatmap.CalculateDrainLength() / rate); - double hitLength = Math.Round(beatmap.BeatmapInfo.Length / rate); - - lengthLabelContainer.Child = new InfoLabel(new BeatmapStatistic - { - Name = BeatmapsetsStrings.ShowStatsTotalLength(drainLength.ToFormattedDuration()), - CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Length), - Content = hitLength.ToFormattedDuration().ToString(), - }); - } - - private Drawable getMapper(BeatmapMetadata metadata) - { - if (string.IsNullOrEmpty(metadata.Author.Username)) - return Empty(); - - return new LinkFlowContainer(s => - { - s.Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 15); - }).With(d => - { - d.AutoSizeAxes = Axes.Both; - d.AddText("mapped by "); - d.AddUserLink(metadata.Author); - }); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - settingChangeTracker?.Dispose(); - cancellationSource?.Cancel(); - } - - public partial class InfoLabel : Container, IHasTooltip - { - public LocalisableString TooltipText { get; } - - internal BeatmapStatistic Statistic { get; } - - public InfoLabel(BeatmapStatistic statistic) - { - Statistic = statistic; - TooltipText = statistic.Name; - AutoSizeAxes = Axes.Both; - - Children = new Drawable[] - { - new Container - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Size = new Vector2(20), - Children = new[] - { - new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"441288"), - Icon = FontAwesome.Solid.Square, - Rotation = 45, - }, - new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"f7dd55"), - Icon = FontAwesome.Regular.Circle, - Size = new Vector2(0.7f) - }, - statistic.CreateIcon().With(i => - { - i.Anchor = Anchor.Centre; - i.Origin = Anchor.Centre; - i.RelativeSizeAxes = Axes.Both; - i.Colour = Color4Extensions.FromHex(@"f7dd55"); - i.Size = new Vector2(0.6f); - }), - } - }, - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Colour = new Color4(255, 221, 85, 255), - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 17), - Margin = new MarginPadding { Left = 30 }, - Text = statistic.Content, - } - }; - } - } - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs b/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs deleted file mode 100644 index 50ec446c4fea..000000000000 --- a/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osuTK.Graphics; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Drawables; -using osu.Framework.Graphics.Shapes; - -namespace osu.Game.Screens.Select -{ - internal partial class BeatmapInfoWedgeBackground : CompositeDrawable - { - private readonly IWorkingBeatmap beatmap; - - public BeatmapInfoWedgeBackground(IWorkingBeatmap beatmap) - { - this.beatmap = beatmap; - } - - [BackgroundDependencyLoader] - private void load() - { - RelativeSizeAxes = Axes.Both; - - InternalChild = new BufferedContainer(cachedFrameBuffer: true) - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - // We will create the white-to-black gradient by modulating transparency and having - // a black backdrop. This results in an sRGB-space gradient and not linear space, - // transitioning from white to black more perceptually uniformly. - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - // We use a container, such that we can set the colour gradient to go across the - // vertices of the masked container instead of the vertices of the (larger) sprite. - new Container - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(Color4.White, Color4.White.Opacity(0.3f)), - Children = new[] - { - // Zoomed-in and cropped beatmap background - new BeatmapBackgroundSprite(beatmap) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill, - }, - }, - }, - } - }; - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs deleted file mode 100644 index 39bf4e134baf..000000000000 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ /dev/null @@ -1,161 +0,0 @@ -// 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.Linq; -using osu.Game.Beatmaps; -using osu.Game.Screens.Select.Filter; -using osu.Game.Utils; - -namespace osu.Game.Screens.Select.Carousel -{ - public class CarouselBeatmap : CarouselItem - { - public override float TotalHeight => DrawableCarouselBeatmap.HEIGHT; - - public readonly BeatmapInfo BeatmapInfo; - - public CarouselBeatmap(BeatmapInfo beatmapInfo) - { - BeatmapInfo = beatmapInfo; - State.Value = CarouselItemState.Collapsed; - } - - public override DrawableCarouselItem CreateDrawableRepresentation() => new DrawableCarouselBeatmap(this); - - public override void Filter(FilterCriteria criteria) - { - base.Filter(criteria); - - Filtered.Value = !checkMatch(criteria); - } - - private bool checkMatch(FilterCriteria criteria) - { - bool match = - criteria.Ruleset == null || - BeatmapInfo.Ruleset.ShortName == criteria.Ruleset.ShortName || - (BeatmapInfo.Ruleset.OnlineID == 0 && criteria.Ruleset.OnlineID != 0 && criteria.AllowConvertedBeatmaps); - - if (BeatmapInfo.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true) - { - // only check ruleset equality or convertability for selected beatmap - return match; - } - - if (!match) return false; - - if (criteria.SearchTerms.Length > 0) - { - match = BeatmapInfo.Match(criteria.SearchTerms); - - // if a match wasn't found via text matching of terms, do a second catch-all check matching against online IDs. - // this should be done after text matching so we can prioritise matching numbers in metadata. - if (!match && criteria.SearchNumber.HasValue) - { - match = (BeatmapInfo.OnlineID == criteria.SearchNumber.Value) || - (BeatmapInfo.BeatmapSet?.OnlineID == criteria.SearchNumber.Value); - } - } - - if (!match) return false; - - match &= !criteria.StarDifficulty.HasFilter || criteria.StarDifficulty.IsInRange(BeatmapInfo.StarRating.FloorToDecimalDigits(2)); - match &= !criteria.ApproachRate.HasFilter || criteria.ApproachRate.IsInRange(BeatmapInfo.Difficulty.ApproachRate); - match &= !criteria.DrainRate.HasFilter || criteria.DrainRate.IsInRange(BeatmapInfo.Difficulty.DrainRate); - match &= !criteria.CircleSize.HasFilter || criteria.CircleSize.IsInRange(BeatmapInfo.Difficulty.CircleSize); - match &= !criteria.OverallDifficulty.HasFilter || criteria.OverallDifficulty.IsInRange(BeatmapInfo.Difficulty.OverallDifficulty); - match &= !criteria.Length.HasFilter || criteria.Length.IsInRange(BeatmapInfo.Length); - match &= !criteria.LastPlayed.HasFilter || criteria.LastPlayed.IsInRange(BeatmapInfo.LastPlayed ?? DateTimeOffset.MinValue); - match &= !criteria.DateRanked.HasFilter || (BeatmapInfo.BeatmapSet?.DateRanked != null && criteria.DateRanked.IsInRange(BeatmapInfo.BeatmapSet.DateRanked.Value)); - match &= !criteria.DateSubmitted.HasFilter || (BeatmapInfo.BeatmapSet?.DateSubmitted != null && criteria.DateSubmitted.IsInRange(BeatmapInfo.BeatmapSet.DateSubmitted.Value)); - match &= !criteria.BPM.HasFilter || criteria.BPM.IsInRange(BeatmapInfo.BPM); - - match &= !criteria.BeatDivisor.HasFilter || criteria.BeatDivisor.IsInRange(BeatmapInfo.BeatDivisor); - match &= !criteria.OnlineStatus.HasFilter || criteria.OnlineStatus.IsInRange(BeatmapInfo.Status); - - if (!match) return false; - - match &= !criteria.Creator.HasFilter || criteria.Creator.Matches(BeatmapInfo.Metadata.Author.Username); - - if (criteria.Artist.HasFilter) - { - if (criteria.Artist.ExcludeTerm) - match &= criteria.Artist.Matches(BeatmapInfo.Metadata.Artist) && criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode); - else - match &= criteria.Artist.Matches(BeatmapInfo.Metadata.Artist) || criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode); - } - - if (criteria.Title.HasFilter) - { - if (criteria.Title.ExcludeTerm) - match &= criteria.Title.Matches(BeatmapInfo.Metadata.Title) && criteria.Title.Matches(BeatmapInfo.Metadata.TitleUnicode); - else - match &= criteria.Title.Matches(BeatmapInfo.Metadata.Title) || criteria.Title.Matches(BeatmapInfo.Metadata.TitleUnicode); - } - - match &= !criteria.DifficultyName.HasFilter || criteria.DifficultyName.Matches(BeatmapInfo.DifficultyName); - match &= !criteria.Source.HasFilter || criteria.Source.Matches(BeatmapInfo.Metadata.Source); - - if (criteria.UserTags.Any()) - { - foreach (var tagFilter in criteria.UserTags) - { - if (tagFilter.ExcludeTerm) - { - // if `ExcludeTerm` is true, `Matches()` will return true if a user tag *doesn't match* the excluded term. - // thus, every user tag must pass this filter. - foreach (string tag in BeatmapInfo.Metadata.UserTags) - match &= tagFilter.Matches(tag); - } - else - { - // if `ExcludeTerm` is false, `Matches()` will return true if a user tag *matches* the expected term. - // the expected behaviour is that a beatmap should be displayed if at least one of the user tags passes the filter. - bool anyTagMatched = false; - - foreach (string tag in BeatmapInfo.Metadata.UserTags) - anyTagMatched |= tagFilter.Matches(tag); - - match &= anyTagMatched; - } - } - } - - match &= !criteria.UserStarDifficulty.HasFilter || criteria.UserStarDifficulty.IsInRange(BeatmapInfo.StarRating); - - if (!match) return false; - - match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true; - if (match && criteria.RulesetCriteria != null) - match &= criteria.RulesetCriteria.Matches(BeatmapInfo, criteria); - - if (match && criteria.HasOnlineID == true) - match &= BeatmapInfo.OnlineID >= 0; - - if (match && criteria.BeatmapSetId != null) - match &= criteria.BeatmapSetId == BeatmapInfo.BeatmapSet?.OnlineID; - - return match; - } - - public override int CompareTo(FilterCriteria criteria, CarouselItem other) - { - if (!(other is CarouselBeatmap otherBeatmap)) - return base.CompareTo(criteria, other); - - switch (criteria.Sort) - { - default: - case SortMode.Difficulty: - int ruleset = BeatmapInfo.Ruleset.CompareTo(otherBeatmap.BeatmapInfo.Ruleset); - - if (ruleset != 0) return ruleset; - - return BeatmapInfo.StarRating.CompareTo(otherBeatmap.BeatmapInfo.StarRating); - } - } - - public override string ToString() => BeatmapInfo.ToString(); - } -} diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs deleted file mode 100644 index 7e1569980438..000000000000 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ /dev/null @@ -1,184 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Game.Beatmaps; -using osu.Game.Screens.Select.Filter; -using osu.Game.Utils; - -namespace osu.Game.Screens.Select.Carousel -{ - public class CarouselBeatmapSet : CarouselGroupEagerSelect - { - public override float TotalHeight - { - get - { - switch (State.Value) - { - case CarouselItemState.Selected: - return DrawableCarouselBeatmapSet.HEIGHT + Items.Count(c => c.Visible) * DrawableCarouselBeatmap.HEIGHT; - - default: - return DrawableCarouselBeatmapSet.HEIGHT; - } - } - } - - public IEnumerable Beatmaps => Items.OfType(); - - public BeatmapSetInfo BeatmapSet; - - public Func, BeatmapInfo?>? GetRecommendedBeatmap; - - public CarouselBeatmapSet(BeatmapSetInfo beatmapSet) - { - BeatmapSet = beatmapSet ?? throw new ArgumentNullException(nameof(beatmapSet)); - - beatmapSet.Beatmaps - .Where(b => !b.Hidden) - .OrderBy(b => b.Ruleset) - .ThenBy(b => b.StarRating) - .Select(b => new CarouselBeatmap(b)) - .ForEach(AddItem); - } - - public override CarouselItem? GetNextToSelect() - { - if (LastSelected == null || LastSelected.Filtered.Value) - { - if (GetRecommendedBeatmap?.Invoke(Items.OfType().Where(b => !b.Filtered.Value).Select(b => b.BeatmapInfo)) is BeatmapInfo recommended) - return Items.OfType().First(b => b.BeatmapInfo.Equals(recommended)); - } - - return base.GetNextToSelect(); - } - - public override int CompareTo(FilterCriteria criteria, CarouselItem other) - { - if (!(other is CarouselBeatmapSet otherSet)) - return base.CompareTo(criteria, other); - - int comparison; - - switch (criteria.Sort) - { - default: - case SortMode.Artist: - comparison = OrdinalSortByCaseStringComparer.DEFAULT.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist); - if (comparison == 0) - goto case SortMode.Title; - break; - - case SortMode.Title: - comparison = OrdinalSortByCaseStringComparer.DEFAULT.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title); - break; - - case SortMode.Author: - comparison = OrdinalSortByCaseStringComparer.DEFAULT.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username); - break; - - case SortMode.Source: - comparison = OrdinalSortByCaseStringComparer.DEFAULT.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source); - break; - - case SortMode.DateAdded: - comparison = otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded); - break; - - case SortMode.DateRanked: - comparison = Nullable.Compare(otherSet.BeatmapSet.DateRanked, BeatmapSet.DateRanked); - break; - - case SortMode.LastPlayed: - comparison = -compareUsingAggregateMax(otherSet, static b => (b.LastPlayed ?? DateTimeOffset.MinValue).ToUnixTimeSeconds()); - break; - - case SortMode.BPM: - comparison = compareUsingAggregateMax(otherSet, static b => b.BPM); - break; - - case SortMode.Length: - comparison = compareUsingAggregateMax(otherSet, static b => b.Length); - break; - - case SortMode.Difficulty: - comparison = compareUsingAggregateMax(otherSet, static b => b.StarRating); - break; - - case SortMode.DateSubmitted: - comparison = Nullable.Compare(otherSet.BeatmapSet.DateSubmitted, BeatmapSet.DateSubmitted); - break; - } - - if (comparison != 0) return comparison; - - // If the initial sort could not differentiate, attempt to use DateAdded to order sets in a stable fashion. - // The directionality of this matches the current SortMode.DateAdded, but we may want to reconsider if that becomes a user decision (ie. asc / desc). - comparison = otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded); - - if (comparison != 0) return comparison; - - // If DateAdded fails to break the tie, fallback to our internal GUID for stability. - // This basically means it's a stable random sort. - return otherSet.BeatmapSet.ID.CompareTo(BeatmapSet.ID); - } - - /// - /// All beatmaps which are not filtered and valid for display. - /// - protected IEnumerable ValidBeatmaps - { - get - { - foreach (var item in Items) // iterating over Items directly to not allocate 2 enumerators - { - if (item is CarouselBeatmap b && (!b.Filtered.Value || b.State.Value == CarouselItemState.Selected)) - yield return b.BeatmapInfo; - } - } - } - - /// - /// Whether there are available beatmaps which are not filtered and valid for display. - /// Cheaper alternative to .Any() - /// - public bool HasValidBeatmaps - { - get - { - foreach (var item in Items) // iterating over Items directly to not allocate 2 enumerators - { - if (item is CarouselBeatmap b && (!b.Filtered.Value || b.State.Value == CarouselItemState.Selected)) - return true; - } - - return false; - } - } - - private int compareUsingAggregateMax(CarouselBeatmapSet other, Func func) - { - bool ourBeatmaps = HasValidBeatmaps; - bool otherBeatmaps = other.HasValidBeatmaps; - - if (!ourBeatmaps && !otherBeatmaps) return 0; - if (!ourBeatmaps) return -1; - if (!otherBeatmaps) return 1; - - return ValidBeatmaps.Max(func).CompareTo(other.ValidBeatmaps.Max(func)); - } - - public override void Filter(FilterCriteria criteria) - { - base.Filter(criteria); - - Filtered.Value = Items.All(i => i.Filtered.Value); - } - - public override string ToString() => BeatmapSet.ToString(); - } -} diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs deleted file mode 100644 index c0fb5fa3977d..000000000000 --- a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using osu.Framework.Extensions.ListExtensions; -using osu.Framework.Lists; - -namespace osu.Game.Screens.Select.Carousel -{ - /// - /// A group which ensures only one item is selected. - /// - public abstract class CarouselGroup : CarouselItem - { - protected CarouselGroup(List? items = null) - { - if (items != null) this.items = items; - - State.ValueChanged += state => - { - switch (state.NewValue) - { - case CarouselItemState.Collapsed: - case CarouselItemState.NotSelected: - this.items.ForEach(c => c.State.Value = CarouselItemState.Collapsed); - break; - - case CarouselItemState.Selected: - this.items.ForEach(c => - { - if (c.State.Value == CarouselItemState.Collapsed) c.State.Value = CarouselItemState.NotSelected; - }); - break; - } - }; - } - - public override DrawableCarouselItem? CreateDrawableRepresentation() => null; - - public SlimReadOnlyListWrapper Items => items.AsSlimReadOnly(); - - public int TotalItemsNotFiltered { get; private set; } - - private readonly List items = new List(); - - /// - /// Used to assign a monotonically increasing ID to items as they are added. This member is - /// incremented whenever an item is added. - /// - private ulong currentItemID; - - private Comparer? criteriaComparer; - private FilterCriteria? lastCriteria; - - protected int GetIndexOfItem(CarouselItem lastSelected) => items.IndexOf(lastSelected); - - public virtual void RemoveItem(CarouselItem i) - { - items.Remove(i); - - if (!i.Filtered.Value) - TotalItemsNotFiltered--; - - // it's important we do the deselection after removing, so any further actions based on - // State.ValueChanged make decisions post-removal. - i.State.Value = CarouselItemState.Collapsed; - } - - public virtual void AddItem(CarouselItem i) - { - i.State.ValueChanged += state => ChildItemStateChanged(i, state.NewValue); - i.ItemID = ++currentItemID; - - if (lastCriteria != null) - { - i.Filter(lastCriteria); - - int index = items.BinarySearch(i, criteriaComparer); - if (index < 0) index = ~index; // BinarySearch hacks multiple return values with 2's complement. - - items.Insert(index, i); - } - else - { - // criteria may be null for initial population. the filtering will be applied post-add. - items.Add(i); - } - - if (!i.Filtered.Value) - TotalItemsNotFiltered++; - } - - public override void Filter(FilterCriteria criteria) - { - base.Filter(criteria); - - TotalItemsNotFiltered = 0; - - foreach (var c in items) - { - c.Filter(criteria); - if (!c.Filtered.Value) - TotalItemsNotFiltered++; - } - - // Sorting is expensive, so only perform if it's actually changed. - if (lastCriteria?.RequiresSorting(criteria) != false) - { - criteriaComparer = Comparer.Create((x, y) => - { - int comparison = x.CompareTo(criteria, y); - if (comparison != 0) - return comparison; - - return x.ItemID.CompareTo(y.ItemID); - }); - - items.Sort(criteriaComparer); - } - - lastCriteria = criteria; - } - - protected virtual void ChildItemStateChanged(CarouselItem item, CarouselItemState value) - { - // ensure we are the only item selected - if (value == CarouselItemState.Selected) - { - foreach (var b in items) - { - if (item == b) continue; - - b.State.Value = CarouselItemState.NotSelected; - } - - State.Value = CarouselItemState.Selected; - } - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs deleted file mode 100644 index 8cc1ea258a71..000000000000 --- a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs +++ /dev/null @@ -1,159 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; - -namespace osu.Game.Screens.Select.Carousel -{ - /// - /// A group which ensures at least one item is selected (if the group itself is selected). - /// - public abstract class CarouselGroupEagerSelect : CarouselGroup - { - protected CarouselGroupEagerSelect() - { - State.ValueChanged += state => - { - if (state.NewValue == CarouselItemState.Selected) - attemptSelection(); - }; - } - - /// - /// The last selected item. - /// - protected CarouselItem? LastSelected { get; private set; } - - /// - /// We need to keep track of the index for cases where the selection is removed but we want to select a new item based on its old location. - /// - private int lastSelectedIndex; - - /// - /// To avoid overhead during filter operations, we don't attempt any selections until after all - /// items have been filtered. This bool will be true during the base - /// operation. - /// - protected bool DisableSelection; - - public override void Filter(FilterCriteria criteria) - { - DisableSelection = true; - base.Filter(criteria); - DisableSelection = false; - - attemptSelection(); - } - - public override void RemoveItem(CarouselItem i) - { - base.RemoveItem(i); - - if (i != LastSelected) - updateSelectedIndex(); - } - - private bool addingItems; - - public void AddItems(IEnumerable items) - { - addingItems = true; - - foreach (var i in items) - AddItem(i); - - addingItems = false; - - attemptSelection(); - } - - public override void AddItem(CarouselItem i) - { - base.AddItem(i); - if (!addingItems) - attemptSelection(); - } - - protected override void ChildItemStateChanged(CarouselItem item, CarouselItemState value) - { - base.ChildItemStateChanged(item, value); - - switch (value) - { - case CarouselItemState.Selected: - updateSelected(item); - break; - - case CarouselItemState.NotSelected: - case CarouselItemState.Collapsed: - attemptSelection(); - break; - } - } - - private void attemptSelection() - { - if (DisableSelection) return; - - // we only perform eager selection if we are a currently selected group. - if (State.Value != CarouselItemState.Selected) return; - - // we only perform eager selection if none of our items are in a selected state already. - if (Items.Any(i => i.State.Value == CarouselItemState.Selected)) return; - - PerformSelection(); - } - - /// - /// Finds the item this group would select next if it attempted selection - /// - /// An unfiltered item nearest to the last selected one or null if all items are filtered - public virtual CarouselItem? GetNextToSelect() - { - if (Items.Count == 0) - return null; - - int forwardsIndex = lastSelectedIndex; - int backwardsIndex = Math.Min(lastSelectedIndex, Items.Count - 1); - - while (true) - { - bool hasBackwards = backwardsIndex >= 0 && backwardsIndex < Items.Count; - bool hasForwards = forwardsIndex < Items.Count; - - if (!hasBackwards && !hasForwards) - return null; - - if (hasForwards && !Items[forwardsIndex].Filtered.Value) - return Items[forwardsIndex]; - - if (hasBackwards && !Items[backwardsIndex].Filtered.Value) - return Items[backwardsIndex]; - - forwardsIndex++; - backwardsIndex--; - } - } - - protected virtual void PerformSelection() - { - CarouselItem? nextToSelect = GetNextToSelect(); - - if (nextToSelect != null) - nextToSelect.State.Value = CarouselItemState.Selected; - else - updateSelected(null); - } - - private void updateSelected(CarouselItem? newSelection) - { - if (newSelection != null) - LastSelected = newSelection; - updateSelectedIndex(); - } - - private void updateSelectedIndex() => lastSelectedIndex = LastSelected == null ? 0 : Math.Max(0, GetIndexOfItem(LastSelected)); - } -} diff --git a/osu.Game/Screens/Select/Carousel/CarouselHeader.cs b/osu.Game/Screens/Select/Carousel/CarouselHeader.cs deleted file mode 100644 index 7e668fcd879b..000000000000 --- a/osu.Game/Screens/Select/Carousel/CarouselHeader.cs +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Events; -using osu.Framework.Utils; -using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class CarouselHeader : Container - { - public Container BorderContainer; - - public readonly Bindable State = new Bindable(CarouselItemState.NotSelected); - - private readonly HoverLayer hoverLayer; - - protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; - - private const float corner_radius = 10; - private const float border_thickness = 2.5f; - - public CarouselHeader() - { - RelativeSizeAxes = Axes.X; - Height = DrawableCarouselItem.MAX_HEIGHT; - - InternalChild = BorderContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = corner_radius, - BorderColour = new Color4(221, 255, 255, 255), - Children = new Drawable[] - { - Content, - hoverLayer = new HoverLayer(), - new HeaderSounds(), - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - State.BindValueChanged(updateState, true); - } - - private void updateState(ValueChangedEvent state) - { - switch (state.NewValue) - { - case CarouselItemState.Collapsed: - case CarouselItemState.NotSelected: - hoverLayer.InsetForBorder = false; - - BorderContainer.BorderThickness = 0; - BorderContainer.EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(1), - Radius = 10, - Colour = Color4.Black.Opacity(100), - }; - break; - - case CarouselItemState.Selected: - hoverLayer.InsetForBorder = true; - - BorderContainer.BorderThickness = border_thickness; - BorderContainer.EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = new Color4(130, 204, 255, 150), - Radius = 20, - Roundness = 10, - }; - break; - } - } - - public partial class HoverLayer : CompositeDrawable - { - private Box box = null!; - - public HoverLayer() - { - RelativeSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - InternalChild = box = new Box - { - Colour = colours.Blue.Opacity(0.1f), - Alpha = 0, - Blending = BlendingParameters.Additive, - RelativeSizeAxes = Axes.Both, - }; - } - - public bool InsetForBorder - { - set - { - if (value) - { - // apply same border as above to avoid applying additive overlay to it (and blowing out the colour). - Masking = true; - CornerRadius = corner_radius; - BorderThickness = border_thickness; - } - else - { - BorderThickness = 0; - CornerRadius = 0; - Masking = false; - } - } - } - - protected override bool OnHover(HoverEvent e) - { - box.FadeIn(100, Easing.OutQuint); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - box.FadeOut(1000, Easing.OutQuint); - base.OnHoverLost(e); - } - } - - private partial class HeaderSounds : HoverSampleDebounceComponent - { - private Sample? sampleHover; - - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - sampleHover = audio.Samples.Get("UI/default-hover"); - } - - public override void PlayHoverSample() - { - if (sampleHover == null) return; - - sampleHover.Frequency.Value = 0.99 + RNG.NextDouble(0.02); - sampleHover.Play(); - } - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/CarouselItem.cs b/osu.Game/Screens/Select/Carousel/CarouselItem.cs deleted file mode 100644 index 5e425a4a1c0b..000000000000 --- a/osu.Game/Screens/Select/Carousel/CarouselItem.cs +++ /dev/null @@ -1,66 +0,0 @@ -// 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 osu.Framework.Bindables; - -namespace osu.Game.Screens.Select.Carousel -{ - public abstract class CarouselItem : IComparable - { - public virtual float TotalHeight => 0; - - /// - /// An externally defined value used to determine this item's vertical display offset relative to the carousel. - /// - public float CarouselYPosition; - - public readonly BindableBool Filtered = new BindableBool(); - - public readonly Bindable State = new Bindable(CarouselItemState.NotSelected); - - /// - /// This item is not in a hidden state. - /// - public bool Visible => State.Value != CarouselItemState.Collapsed && !Filtered.Value; - - protected CarouselItem() - { - Filtered.ValueChanged += filtered => - { - if (filtered.NewValue && State.Value == CarouselItemState.Selected) - State.Value = CarouselItemState.NotSelected; - }; - } - - /// - /// Used as a default sort method for s of differing types. - /// - internal ulong ItemID; - - /// - /// Create a fresh drawable version of this item. - /// - public abstract DrawableCarouselItem? CreateDrawableRepresentation(); - - public virtual void Filter(FilterCriteria criteria) - { - } - - public virtual int CompareTo(FilterCriteria criteria, CarouselItem other) => ItemID.CompareTo(other.ItemID); - - public int CompareTo(CarouselItem? other) - { - if (other == null) return 1; - - return CarouselYPosition.CompareTo(other.CarouselYPosition); - } - } - - public enum CarouselItemState - { - Collapsed, - NotSelected, - Selected, - } -} diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs deleted file mode 100644 index a8f5b6dd24b8..000000000000 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ /dev/null @@ -1,321 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Threading; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Extensions.LocalisationExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Collections; -using osu.Game.Database; -using osu.Game.Graphics; -using osu.Game.Graphics.Backgrounds; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; -using osu.Game.Overlays; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osuTK; -using osuTK.Graphics; -using CommonStrings = osu.Game.Localisation.CommonStrings; -using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class DrawableCarouselBeatmap : DrawableCarouselItem, IHasContextMenu - { - public const float CAROUSEL_BEATMAP_SPACING = 5; - - /// - /// The height of a carousel beatmap, including vertical spacing. - /// - public const float HEIGHT = height + CAROUSEL_BEATMAP_SPACING; - - private const float height = MAX_HEIGHT * 0.6f; - - private readonly BeatmapInfo beatmapInfo; - - private Sprite background = null!; - - private MenuItem[]? mainMenuItems; - - private Action? selectRequested; - private Action? hideRequested; - - private Triangles triangles = null!; - - private StarCounter starCounter = null!; - private DifficultyIcon difficultyIcon = null!; - - private OsuSpriteText keyCountText = null!; - - [Resolved] - private BeatmapSetOverlay? beatmapOverlay { get; set; } - - [Resolved] - private BeatmapDifficultyCache difficultyCache { get; set; } = null!; - - [Resolved] - private ManageCollectionsDialog? manageCollectionsDialog { get; set; } - - [Resolved] - private RealmAccess realm { get; set; } = null!; - - [Resolved] - private IBindable ruleset { get; set; } = null!; - - [Resolved] - private IBindable> mods { get; set; } = null!; - - [Resolved] - private IAPIProvider api { get; set; } = null!; - - [Resolved] - private OsuGame? game { get; set; } - - [Resolved] - private BeatmapManager? manager { get; set; } - - private IBindable starDifficultyBindable = null!; - private CancellationTokenSource? starDifficultyCancellationSource; - - public DrawableCarouselBeatmap(CarouselBeatmap panel) - { - beatmapInfo = panel.BeatmapInfo; - Item = panel; - } - - [BackgroundDependencyLoader] - private void load(SongSelect? songSelect) - { - Header.Height = height; - - if (songSelect != null) - { - mainMenuItems = songSelect.CreateForwardNavigationMenuItemsForBeatmap(() => beatmapInfo); - selectRequested = b => songSelect.FinaliseSelection(b); - } - - if (manager != null) - hideRequested = b => manager.Hide(b); - - Header.Children = new Drawable[] - { - background = new Box - { - RelativeSizeAxes = Axes.Both, - }, - triangles = new Triangles - { - TriangleScale = 2, - RelativeSizeAxes = Axes.Both, - ColourLight = Color4Extensions.FromHex(@"3a7285"), - ColourDark = Color4Extensions.FromHex(@"123744") - }, - new FillFlowContainer - { - Padding = new MarginPadding(5), - Direction = FillDirection.Horizontal, - AutoSizeAxes = Axes.Both, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Children = new Drawable[] - { - difficultyIcon = new DifficultyIcon(beatmapInfo) - { - TooltipType = DifficultyIconTooltipType.None, - Scale = new Vector2(1.8f), - }, - new FillFlowContainer - { - Padding = new MarginPadding { Left = 5 }, - Direction = FillDirection.Vertical, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new FillFlowContainer - { - Direction = FillDirection.Horizontal, - Spacing = new Vector2(4, 0), - AutoSizeAxes = Axes.Both, - Children = new[] - { - keyCountText = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 20), - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Alpha = 0, - }, - new OsuSpriteText - { - Text = beatmapInfo.DifficultyName, - Font = OsuFont.GetFont(size: 20), - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft - }, - new OsuSpriteText - { - Text = BeatmapsetsStrings.ShowDetailsMappedBy(beatmapInfo.Metadata.Author.Username), - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft - }, - } - }, - new FillFlowContainer - { - Direction = FillDirection.Horizontal, - Spacing = new Vector2(4, 0), - Scale = new Vector2(0.8f), - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new TopLocalRank(beatmapInfo), - starCounter = new StarCounter() - } - } - } - } - } - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - ruleset.BindValueChanged(_ => updateKeyCount()); - mods.BindValueChanged(_ => updateKeyCount()); - } - - protected override void Selected() - { - base.Selected(); - - MovementContainer.MoveToX(-50, 500, Easing.OutExpo); - - background.Colour = ColourInfo.GradientVertical( - new Color4(20, 43, 51, 255), - new Color4(40, 86, 102, 255)); - - triangles.Colour = Color4.White; - } - - protected override void Deselected() - { - base.Deselected(); - - MovementContainer.MoveToX(0, 500, Easing.OutExpo); - - background.Colour = new Color4(20, 43, 51, 255); - triangles.Colour = OsuColour.Gray(0.5f); - } - - protected override bool OnClick(ClickEvent e) - { - if (Item?.State.Value == CarouselItemState.Selected) - selectRequested?.Invoke(beatmapInfo); - - return base.OnClick(e); - } - - protected override void ApplyState() - { - if (Item?.State.Value != CarouselItemState.Collapsed && Alpha == 0) - starCounter.ReplayAnimation(); - - starDifficultyCancellationSource?.Cancel(); - - // Only compute difficulty when the item is visible. - if (Item?.State.Value != CarouselItemState.Collapsed) - { - // We've potentially cancelled the computation above so a new bindable is required. - starDifficultyBindable = difficultyCache.GetBindableDifficulty(beatmapInfo, (starDifficultyCancellationSource = new CancellationTokenSource()).Token, 200); - starDifficultyBindable.BindValueChanged(d => - { - starCounter.Current = (float)(d.NewValue.Stars); - difficultyIcon.Current.Value = d.NewValue; - }, true); - - updateKeyCount(); - } - - base.ApplyState(); - } - - private void updateKeyCount() - { - if (Item?.State.Value == CarouselItemState.Collapsed) - return; - - if (ruleset.Value.OnlineID == 3) - { - // Account for mania differences locally for now. - // Eventually this should be handled in a more modular way, allowing rulesets to add more information to the panel. - ILegacyRuleset legacyRuleset = (ILegacyRuleset)ruleset.Value.CreateInstance(); - - keyCountText.Alpha = 1; - keyCountText.Text = $"[{legacyRuleset.GetKeyCount(beatmapInfo, mods.Value)}K]"; - } - else - keyCountText.Alpha = 0; - } - - public MenuItem[] ContextMenuItems - { - get - { - List items = new List(); - - if (mainMenuItems != null) - items.AddRange(mainMenuItems); - - if (beatmapInfo.OnlineID > 0 && beatmapOverlay != null) - items.Add(new OsuMenuItem("Details...", MenuItemType.Standard, () => beatmapOverlay.FetchAndShowBeatmap(beatmapInfo.OnlineID))); - - var collectionItems = realm.Realm.All() - .OrderBy(c => c.Name) - .AsEnumerable() - .Select(c => new CollectionToggleMenuItem(c.ToLive(realm), beatmapInfo)).Cast().ToList(); - - if (manageCollectionsDialog != null) - collectionItems.Add(new OsuMenuItem("Manage...", MenuItemType.Standard, manageCollectionsDialog.Show)); - - items.Add(new OsuMenuItem("Collections") { Items = collectionItems }); - - if (beatmapInfo.GetOnlineURL(api, ruleset.Value) is string url) - items.Add(new OsuMenuItem(CommonStrings.CopyLink, MenuItemType.Standard, () => game?.CopyToClipboard(url))); - - if (manager != null) - items.Add(new OsuMenuItem("Mark as played", MenuItemType.Standard, () => manager.MarkPlayed(beatmapInfo))); - - if (hideRequested != null) - items.Add(new OsuMenuItem(WebCommonStrings.ButtonsHide.ToSentence(), MenuItemType.Destructive, () => hideRequested(beatmapInfo))); - - return items.ToArray(); - } - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - starDifficultyCancellationSource?.Cancel(); - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs deleted file mode 100644 index f0e024663d2f..000000000000 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ /dev/null @@ -1,356 +0,0 @@ -// 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.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Primitives; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Utils; -using osu.Game.Beatmaps; -using osu.Game.Collections; -using osu.Game.Database; -using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; -using osu.Game.Online.API; -using osu.Game.Overlays; -using osu.Game.Rulesets; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class DrawableCarouselBeatmapSet : DrawableCarouselItem, IHasContextMenu - { - public const float HEIGHT = MAX_HEIGHT; - - private Action restoreHiddenRequested = null!; - private Action? viewDetails; - - [Resolved] - private IDialogOverlay? dialogOverlay { get; set; } - - [Resolved] - private ManageCollectionsDialog? manageCollectionsDialog { get; set; } - - [Resolved] - private RealmAccess realm { get; set; } = null!; - - [Resolved] - private IAPIProvider api { get; set; } = null!; - - [Resolved] - private OsuGame? game { get; set; } - - [Resolved] - private IBindable ruleset { get; set; } = null!; - - public IReadOnlyList DrawableBeatmaps => beatmapContainer?.IsLoaded != true ? Array.Empty() : beatmapContainer; - - private Container? beatmapContainer; - - private BeatmapSetInfo beatmapSet = null!; - - private Task? beatmapsLoadTask; - - private MenuItem[]? mainMenuItems; - - private double timeSinceUnpool; - - [Resolved] - private BeatmapManager manager { get; set; } = null!; - - protected override void FreeAfterUse() - { - base.FreeAfterUse(); - - Item = null; - timeSinceUnpool = 0; - - ClearTransforms(); - } - - [BackgroundDependencyLoader] - private void load(BeatmapSetOverlay? beatmapOverlay, SongSelect? songSelect) - { - if (songSelect != null) - mainMenuItems = songSelect.CreateForwardNavigationMenuItemsForBeatmap(() => (((CarouselBeatmapSet)Item!).GetNextToSelect() as CarouselBeatmap)!.BeatmapInfo); - - restoreHiddenRequested = s => - { - foreach (var b in s.Beatmaps) - manager.Restore(b); - }; - - if (beatmapOverlay != null) - viewDetails = beatmapOverlay.FetchAndShowBeatmapSet; - } - - protected override void Update() - { - base.Update(); - - Debug.Assert(Item != null); - - // position updates should not occur if the item is filtered away. - // this avoids panels flying across the screen only to be eventually off-screen or faded out. - if (!Item.Visible) return; - - float targetY = Item.CarouselYPosition; - - if (Precision.AlmostEquals(targetY, Y)) - Y = targetY; - else - // algorithm for this is taken from ScrollContainer. - // while it doesn't necessarily need to match 1:1, as we are emulating scroll in some cases this feels most correct. - Y = (float)Interpolation.Lerp(targetY, Y, Math.Exp(-0.01 * Time.Elapsed)); - - loadContentIfRequired(); - } - - private CancellationTokenSource? loadCancellation; - - protected override void UpdateItem() - { - loadCancellation?.Cancel(); - loadCancellation = null; - - base.UpdateItem(); - - Content.Clear(); - Header.Clear(); - - beatmapContainer = null; - beatmapsLoadTask = null; - - if (Item == null) - return; - - beatmapSet = ((CarouselBeatmapSet)Item).BeatmapSet; - } - - protected override void Deselected() - { - base.Deselected(); - - MovementContainer.MoveToX(0, 500, Easing.OutExpo); - - updateBeatmapYPositions(); - } - - protected override void Selected() - { - base.Selected(); - - MovementContainer.MoveToX(-100, 500, Easing.OutExpo); - - updateBeatmapDifficulties(); - } - - private void updateBeatmapDifficulties() - { - Debug.Assert(Item != null); - - var carouselBeatmapSet = (CarouselBeatmapSet)Item; - - var visibleBeatmaps = carouselBeatmapSet.Items.Where(c => c.Visible).ToArray(); - - // if we are already displaying all the correct beatmaps, only run animation updates. - // note that the displayed beatmaps may change due to the applied filter. - // a future optimisation could add/remove only changed difficulties rather than reinitialise. - if (beatmapContainer != null && visibleBeatmaps.Length == beatmapContainer.Count && visibleBeatmaps.All(b => beatmapContainer.Any(c => c.Item == b))) - { - updateBeatmapYPositions(); - } - else - { - // on selection we show our child beatmaps. - // for now this is a simple drawable construction each selection. - // can be improved in the future. - beatmapContainer = new Container - { - X = 100, - RelativeSizeAxes = Axes.Both, - ChildrenEnumerable = visibleBeatmaps.Select(c => c.CreateDrawableRepresentation()!) - }; - - beatmapsLoadTask = LoadComponentAsync(beatmapContainer, loaded => - { - // make sure the pooled target hasn't changed. - if (beatmapContainer != loaded) - return; - - Content.Child = loaded; - updateBeatmapYPositions(); - }); - } - } - - [Resolved] - private BeatmapCarousel.CarouselScrollContainer scrollContainer { get; set; } = null!; - - private void loadContentIfRequired() - { - Quad containingSsdq = scrollContainer.ScreenSpaceDrawQuad; - - // Using DelayedLoadWrappers would only allow us to load content when on screen, but we want to preload while off-screen - // to provide a better user experience. - - // This is tracking time that this drawable is updating since the last pool. - // This is intended to provide a debounce so very fast scrolls (from one end to the other of the carousel) - // don't cause huge overheads. - // - // We increase the delay based on distance from centre, so the beatmaps the user is currently looking at load first. - float timeUpdatingBeforeLoad = 50 + Math.Abs(containingSsdq.Centre.Y - ScreenSpaceDrawQuad.Centre.Y) / containingSsdq.Height * 100; - - Debug.Assert(Item != null); - - // A load is already in progress if the cancellation token is non-null. - if (loadCancellation != null) - return; - - timeSinceUnpool += Time.Elapsed; - - // We only trigger a load after this set has been in an updating state for a set amount of time. - if (timeSinceUnpool <= timeUpdatingBeforeLoad) - return; - - loadCancellation = new CancellationTokenSource(); - - LoadComponentsAsync(new CompositeDrawable[] - { - // Choice of background image matches BSS implementation (always uses the lowest `beatmap_id` from the set). - new SetPanelBackground(manager.GetWorkingBeatmap(beatmapSet.Beatmaps.MinBy(b => b.OnlineID))) - { - RelativeSizeAxes = Axes.Both, - }, - new SetPanelContent((CarouselBeatmapSet)Item) - { - Depth = float.MinValue, - RelativeSizeAxes = Axes.Both, - } - }, drawables => - { - Header.AddRange(drawables); - drawables.ForEach(d => d.FadeInFromZero(150)); - }, loadCancellation.Token); - } - - private void updateBeatmapYPositions() - { - if (beatmapContainer == null) - return; - - if (beatmapsLoadTask == null || !beatmapsLoadTask.IsCompleted) - return; - - float yPos = DrawableCarouselBeatmap.CAROUSEL_BEATMAP_SPACING; - - bool isSelected = Item?.State.Value == CarouselItemState.Selected; - - foreach (var panel in beatmapContainer) - { - Debug.Assert(panel.Item != null); - - if (isSelected) - { - panel.MoveToY(yPos, 800, Easing.OutQuint); - yPos += panel.Item.TotalHeight; - } - else - panel.MoveToY(0, 800, Easing.OutQuint); - } - } - - public MenuItem[] ContextMenuItems - { - get - { - Debug.Assert(beatmapSet != null); - - List items = new List(); - - if (Item?.State.Value == CarouselItemState.NotSelected) - items.Add(new OsuMenuItem("Expand", MenuItemType.Highlighted, () => Item.State.Value = CarouselItemState.Selected)); - - if (mainMenuItems != null) - items.AddRange(mainMenuItems); - - if (beatmapSet.OnlineID > 0 && viewDetails != null) - items.Add(new OsuMenuItem("Details...", MenuItemType.Standard, () => viewDetails(beatmapSet.OnlineID))); - - var collectionItems = realm.Realm.All() - .OrderBy(c => c.Name) - .AsEnumerable() - .Select(createCollectionMenuItem) - .ToList(); - - if (manageCollectionsDialog != null) - collectionItems.Add(new OsuMenuItem("Manage...", MenuItemType.Standard, manageCollectionsDialog.Show)); - - items.Add(new OsuMenuItem("Collections") { Items = collectionItems }); - - if (beatmapSet.Beatmaps.Any(b => b.Hidden)) - items.Add(new OsuMenuItem("Restore all hidden", MenuItemType.Standard, () => restoreHiddenRequested(beatmapSet))); - - if (beatmapSet.GetOnlineURL(api, ruleset.Value) is string url) - items.Add(new OsuMenuItem(CommonStrings.CopyLink, MenuItemType.Standard, () => game?.CopyToClipboard(url))); - - if (dialogOverlay != null) - items.Add(new OsuMenuItem("Delete...", MenuItemType.Destructive, () => dialogOverlay.Push(new BeatmapDeleteDialog(beatmapSet)))); - return items.ToArray(); - } - } - - private MenuItem createCollectionMenuItem(BeatmapCollection collection) - { - Debug.Assert(beatmapSet != null); - - TernaryState state; - - int countExisting = beatmapSet.Beatmaps.Count(b => collection.BeatmapMD5Hashes.Contains(b.MD5Hash)); - - if (countExisting == beatmapSet.Beatmaps.Count) - state = TernaryState.True; - else if (countExisting > 0) - state = TernaryState.Indeterminate; - else - state = TernaryState.False; - - var liveCollection = collection.ToLive(realm); - - return new TernaryStateToggleMenuItem(collection.Name, MenuItemType.Standard, s => - { - Task.Run(() => liveCollection.PerformWrite(c => - { - foreach (var b in beatmapSet.Beatmaps) - { - switch (s) - { - case TernaryState.True: - if (c.BeatmapMD5Hashes.Contains(b.MD5Hash)) - continue; - - c.BeatmapMD5Hashes.Add(b.MD5Hash); - break; - - case TernaryState.False: - c.BeatmapMD5Hashes.Remove(b.MD5Hash); - break; - } - } - })); - }) - { - State = { Value = state } - }; - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs deleted file mode 100644 index 10921c331eff..000000000000 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Diagnostics; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Pooling; -using osu.Framework.Input.Events; -using osuTK; - -namespace osu.Game.Screens.Select.Carousel -{ - public abstract partial class DrawableCarouselItem : PoolableDrawable - { - public const float MAX_HEIGHT = 80; - - public override bool IsPresent => base.IsPresent || Item?.Visible == true; - - public override bool HandlePositionalInput => Item?.Visible == true; - public override bool PropagatePositionalInputSubTree => Item?.Visible == true; - - public readonly CarouselHeader Header; - - /// - /// Optional content which sits below the header. - /// - protected readonly Container Content; - - protected readonly Container MovementContainer; - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => - Header.ReceivePositionalInputAt(screenSpacePos); - - private CarouselItem? item; - - public CarouselItem? Item - { - get => item; - set - { - if (item == value) - return; - - if (item != null) - { - item.Filtered.ValueChanged -= onStateChange; - item.State.ValueChanged -= onStateChange; - - Header.State.UnbindFrom(item.State); - - if (item is CarouselGroup group) - { - foreach (var c in group.Items) - c.Filtered.ValueChanged -= onStateChange; - } - } - - item = value; - - if (IsLoaded && !IsDisposed) - UpdateItem(); - } - } - - protected DrawableCarouselItem() - { - RelativeSizeAxes = Axes.X; - - Alpha = 0; - - InternalChildren = new Drawable[] - { - MovementContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - Header = new CarouselHeader(), - Content = new Container - { - RelativeSizeAxes = Axes.Both, - } - } - }, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - UpdateItem(); - } - - protected override void Update() - { - base.Update(); - Content.Y = Header.Height; - } - - protected virtual void UpdateItem() - { - if (Item == null) - return; - - Scheduler.AddOnce(ApplyState); - - Item.Filtered.ValueChanged += onStateChange; - Item.State.ValueChanged += onStateChange; - - Header.State.BindTo(Item.State); - - if (Item is CarouselGroup group) - { - foreach (var c in group.Items) - c.Filtered.ValueChanged += onStateChange; - } - } - - private void onStateChange(ValueChangedEvent obj) => Scheduler.AddOnce(ApplyState); - - private void onStateChange(ValueChangedEvent _) => Scheduler.AddOnce(ApplyState); - - protected virtual void ApplyState() - { - Debug.Assert(Item != null); - - // Use the fact that we know the precise height of the item from the model to avoid the need for AutoSize overhead. - // Additionally, AutoSize doesn't work well due to content starting off-screen and being masked away. - Height = Item.TotalHeight; - - switch (Item.State.Value) - { - case CarouselItemState.NotSelected: - Deselected(); - break; - - case CarouselItemState.Selected: - Selected(); - break; - } - - if (!Item.Visible) - this.FadeOut(100, Easing.OutQuint); - else - this.FadeIn(400, Easing.OutQuint); - } - - protected virtual void Selected() - { - Debug.Assert(Item != null); - } - - protected virtual void Deselected() - { - } - - protected override bool OnClick(ClickEvent e) - { - Debug.Assert(Item != null); - - Item.State.Value = CarouselItemState.Selected; - return true; - } - - protected override bool OnHover(HoverEvent e) => true; - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - // This is important to clean up event subscriptions. - Item = null; - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs b/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs deleted file mode 100644 index cd8e20ad392e..000000000000 --- a/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Input.Events; -using osu.Game.Beatmaps.Drawables; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class FilterableDifficultyIcon : DifficultyIcon - { - private readonly BindableBool filtered = new BindableBool(); - - public bool IsFiltered => filtered.Value; - - public readonly CarouselBeatmap Item; - - public FilterableDifficultyIcon(CarouselBeatmap item) - : base(item.BeatmapInfo) - { - filtered.BindTo(item.Filtered); - filtered.ValueChanged += isFiltered => Schedule(() => this.FadeTo(isFiltered.NewValue ? 0.1f : 1, 100)); - filtered.TriggerChange(); - - Item = item; - } - - protected override bool OnClick(ClickEvent e) - { - Item.State.Value = CarouselItemState.Selected; - return true; - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs b/osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs deleted file mode 100644 index 3de44fa0326a..000000000000 --- a/osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Graphics; -using osu.Framework.Input.Events; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets; -using osuTK.Graphics; - -namespace osu.Game.Screens.Select.Carousel -{ - /// - /// A difficulty icon that contains a counter on the right-side of it. - /// - /// - /// Used in cases when there are too many difficulty icons to show. - /// - public partial class GroupedDifficultyIcon : DifficultyIcon - { - public readonly List Items; - - public GroupedDifficultyIcon(List items, RulesetInfo ruleset) - : base(items.OrderBy(b => b.BeatmapInfo.StarRating).Last().BeatmapInfo, ruleset) - { - Items = items; - - foreach (var item in items) - item.Filtered.BindValueChanged(_ => Scheduler.AddOnce(updateFilteredDisplay)); - - AddInternal(new OsuSpriteText - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Padding = new MarginPadding { Left = Size.X }, - Margin = new MarginPadding { Left = 2, Right = 5 }, - Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold), - Text = items.Count.ToString(), - Colour = Color4.White, - }); - - updateFilteredDisplay(); - } - - protected override bool OnClick(ClickEvent e) - { - Items.First().State.Value = CarouselItemState.Selected; - return true; - } - - private void updateFilteredDisplay() - { - // for now, fade the whole group based on the ratio of hidden items. - this.FadeTo(1 - 0.9f * ((float)Items.Count(i => i.Filtered.Value) / Items.Count), 100); - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs b/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs deleted file mode 100644 index b8729b7174d2..000000000000 --- a/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs +++ /dev/null @@ -1,92 +0,0 @@ -// 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 osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Game.Beatmaps; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class SetPanelBackground : BufferedContainer - { - public SetPanelBackground(IWorkingBeatmap working) - : base(cachedFrameBuffer: true) - { - RedrawOnScale = false; - - Children = new Drawable[] - { - new PanelBeatmapBackground(working) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill, - }, - new FillFlowContainer - { - Depth = -1, - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - // This makes the gradient not be perfectly horizontal, but diagonal at a ~40° angle - Shear = new Vector2(0.8f, 0), - Alpha = 0.5f, - Children = new[] - { - // The left half with no gradient applied - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Width = 0.4f, - }, - // Piecewise-linear gradient with 3 segments to make it appear smoother - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(Color4.Black, new Color4(0f, 0f, 0f, 0.9f)), - Width = 0.05f, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(new Color4(0f, 0f, 0f, 0.9f), new Color4(0f, 0f, 0f, 0.1f)), - Width = 0.2f, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(new Color4(0f, 0f, 0f, 0.1f), new Color4(0, 0, 0, 0)), - Width = 0.05f, - }, - } - }, - }; - } - - public partial class PanelBeatmapBackground : Sprite - { - private readonly IWorkingBeatmap working; - - public PanelBeatmapBackground(IWorkingBeatmap working) - { - ArgumentNullException.ThrowIfNull(working); - - this.working = working; - } - - [BackgroundDependencyLoader] - private void load() - { - Texture = working.GetPanelBackground(); - } - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/SetPanelContent.cs b/osu.Game/Screens/Select/Carousel/SetPanelContent.cs deleted file mode 100644 index c3ded16bd244..000000000000 --- a/osu.Game/Screens/Select/Carousel/SetPanelContent.cs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Localisation; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osuTK; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class SetPanelContent : CompositeDrawable - { - // Disallow interacting with difficulty icons on a panel until the panel has been selected. - public override bool PropagatePositionalInputSubTree => carouselSet.State.Value == CarouselItemState.Selected; - - private readonly CarouselBeatmapSet carouselSet; - - private FillFlowContainer iconFlow = null!; - - public SetPanelContent(CarouselBeatmapSet carouselSet) - { - this.carouselSet = carouselSet; - - // required to ensure we load as soon as any part of the panel comes on screen - RelativeSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader] - private void load() - { - var beatmapSet = carouselSet.BeatmapSet; - - InternalChild = new FillFlowContainer - { - // required to ensure we load as soon as any part of the panel comes on screen - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Padding = new MarginPadding { Top = 5, Left = 18, Right = 10, Bottom = 10 }, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = new RomanisableString(beatmapSet.Metadata.TitleUnicode, beatmapSet.Metadata.Title), - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 22, italics: true), - Shadow = true, - }, - new OsuSpriteText - { - Text = new RomanisableString(beatmapSet.Metadata.ArtistUnicode, beatmapSet.Metadata.Artist), - Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 17, italics: true), - Shadow = true, - }, - new FillFlowContainer - { - Direction = FillDirection.Horizontal, - AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Top = 5 }, - Spacing = new Vector2(5), - Children = new[] - { - beatmapSet.AllBeatmapsUpToDate - ? Empty() - : new Container - { - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Children = new Drawable[] - { - new UpdateBeatmapSetButton(beatmapSet), - } - }, - new BeatmapSetOnlineStatusPill - { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - TextSize = 11, - TextPadding = new MarginPadding { Horizontal = 8, Vertical = 2 }, - Status = beatmapSet.Status - }, - iconFlow = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Spacing = new Vector2(3), - }, - } - } - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - iconFlow.ChildrenEnumerable = getDifficultyIcons(); - } - - private const int maximum_difficulty_icons = 18; - - private IEnumerable getDifficultyIcons() - { - var beatmaps = carouselSet.Beatmaps.ToList(); - - return beatmaps.Count > maximum_difficulty_icons - ? beatmaps.GroupBy(b => b.BeatmapInfo.Ruleset) - .Select(group => new GroupedDifficultyIcon(group.ToList(), group.Last().BeatmapInfo.Ruleset)) - : beatmaps.Select(b => new FilterableDifficultyIcon(b)); - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs deleted file mode 100644 index 6f1f2e83704d..000000000000 --- a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs +++ /dev/null @@ -1,86 +0,0 @@ -// 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.Linq; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; -using osu.Game.Database; -using osu.Game.Online.API; -using osu.Game.Online.Leaderboards; -using osu.Game.Rulesets; -using osu.Game.Scoring; -using osuTK; -using Realms; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class TopLocalRank : CompositeDrawable - { - private readonly BeatmapInfo beatmapInfo; - - [Resolved] - private IBindable ruleset { get; set; } = null!; - - [Resolved] - private RealmAccess realm { get; set; } = null!; - - [Resolved] - private IAPIProvider api { get; set; } = null!; - - private IDisposable? scoreSubscription; - - private readonly UpdateableRank updateable; - - public ScoreRank? DisplayedRank => updateable.Rank; - - public TopLocalRank(BeatmapInfo beatmapInfo) - { - this.beatmapInfo = beatmapInfo; - - AutoSizeAxes = Axes.Both; - - InternalChild = updateable = new UpdateableRank - { - Size = new Vector2(40, 20), - Alpha = 0, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - ruleset.BindValueChanged(_ => - { - scoreSubscription?.Dispose(); - scoreSubscription = realm.RegisterForNotifications(r => - r.GetAllLocalScoresForUser(api.LocalUser.Value.Id) - .Filter($@"{nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $0" - + $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $1", beatmapInfo.ID, ruleset.Value.ShortName), - localScoresChanged); - }, true); - - void localScoresChanged(IRealmCollection sender, ChangeSet? changes) - { - // This subscription may fire from changes to linked beatmaps, which we don't care about. - // It's currently not possible for a score to be modified after insertion, so we can safely ignore callbacks with only modifications. - if (changes?.HasCollectionChanges() == false) - return; - - ScoreInfo? topScore = sender.MaxBy(info => (info.TotalScore, -info.Date.UtcDateTime.Ticks)); - updateable.Rank = topScore?.Rank; - updateable.Alpha = topScore != null ? 1 : 0; - } - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - scoreSubscription?.Dispose(); - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs b/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs deleted file mode 100644 index d41870f1d2ef..000000000000 --- a/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Input.Events; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; -using osu.Game.Overlays; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class UpdateBeatmapSetButton : OsuAnimatedButton - { - private readonly BeatmapSetInfo beatmapSetInfo; - private SpriteIcon icon = null!; - private Box progressFill = null!; - - [Resolved] - private BeatmapModelDownloader beatmapDownloader { get; set; } = null!; - - [Resolved] - private IAPIProvider api { get; set; } = null!; - - [Resolved] - private LoginOverlay? loginOverlay { get; set; } - - [Resolved] - private IDialogOverlay? dialogOverlay { get; set; } - - public UpdateBeatmapSetButton(BeatmapSetInfo beatmapSetInfo) - { - this.beatmapSetInfo = beatmapSetInfo; - - AutoSizeAxes = Axes.Both; - - Anchor = Anchor.CentreLeft; - Origin = Anchor.CentreLeft; - } - - private Bindable preferNoVideo = null!; - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - const float icon_size = 14; - - preferNoVideo = config.GetBindable(OsuSetting.PreferNoVideo); - - Content.Anchor = Anchor.CentreLeft; - Content.Origin = Anchor.CentreLeft; - - Content.AddRange(new Drawable[] - { - progressFill = new Box - { - Colour = Color4.White, - Alpha = 0.2f, - Blending = BlendingParameters.Additive, - RelativeSizeAxes = Axes.Both, - Width = 0, - }, - new FillFlowContainer - { - Padding = new MarginPadding { Horizontal = 5, Vertical = 3 }, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(4), - Children = new Drawable[] - { - new Container - { - Size = new Vector2(icon_size), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Children = new Drawable[] - { - icon = new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Icon = FontAwesome.Solid.SyncAlt, - Size = new Vector2(icon_size), - }, - } - }, - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.Default.With(weight: FontWeight.Bold), - Text = "Update", - } - } - }, - }); - - Action = updateBeatmap; - } - - private bool updateConfirmed; - - private void updateBeatmap() - { - if (!api.IsLoggedIn) - { - loginOverlay?.Show(); - return; - } - - if (dialogOverlay != null && beatmapSetInfo.Status == BeatmapOnlineStatus.LocallyModified && !updateConfirmed) - { - dialogOverlay.Push(new UpdateLocalConfirmationDialog(() => - { - updateConfirmed = true; - updateBeatmap(); - })); - - return; - } - - updateConfirmed = false; - - beatmapDownloader.DownloadAsUpdate(beatmapSetInfo, preferNoVideo.Value); - attachExistingDownload(); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - icon.Spin(4000, RotationDirection.Clockwise); - } - - private void attachExistingDownload() - { - var download = beatmapDownloader.GetExistingDownload(beatmapSetInfo); - - if (download != null) - { - Enabled.Value = false; - TooltipText = string.Empty; - - download.DownloadProgressed += progress => progressFill.ResizeWidthTo(progress, 100, Easing.OutQuint); - download.Failure += _ => attachExistingDownload(); - } - else - { - Enabled.Value = true; - TooltipText = "Update beatmap with online changes"; - - progressFill.ResizeWidthTo(0, 100, Easing.OutQuint); - } - } - - protected override bool OnHover(HoverEvent e) - { - icon.Spin(400, RotationDirection.Clockwise, icon.Rotation); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - icon.Spin(4000, RotationDirection.Clockwise, icon.Rotation); - base.OnHoverLost(e); - } - } -} diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs deleted file mode 100644 index 4781a3dee71d..000000000000 --- a/osu.Game/Screens/Select/FilterControl.cs +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using JetBrains.Annotations; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Game.Collections; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Select.Filter; -using osuTK; -using osuTK.Input; - -namespace osu.Game.Screens.Select -{ - public partial class FilterControl : Container - { - public const float HEIGHT = 2 * side_margin + 120; - - private const float side_margin = 10; - - public Action FilterChanged; - - public Bindable CurrentTextSearch => searchTextBox.Current; - - public LocalisableString InformationalText - { - get => searchTextBox.FilterText.Text; - set => searchTextBox.FilterText.Text = value; - } - - private OsuTabControl sortTabs; - private Bindable sortMode; - private Bindable groupMode; - private FilterControlTextBox searchTextBox; - private CollectionDropdown collectionDropdown; - - [CanBeNull] - private FilterCriteria currentCriteria; - - public virtual FilterCriteria CreateCriteria() - { - string query = searchTextBox.Text; - - var criteria = new FilterCriteria - { - Group = groupMode.Value, - Sort = sortMode.Value, - AllowConvertedBeatmaps = showConverted.Value, - Ruleset = ruleset.Value, - Mods = mods.Value, - CollectionBeatmapMD5Hashes = collectionDropdown.Current.Value?.Collection?.PerformRead(c => c.BeatmapMD5Hashes).ToImmutableHashSet() - }; - - if (!minimumStars.IsDefault) - criteria.UserStarDifficulty.Min = minimumStars.Value; - - if (!maximumStars.IsDefault) - criteria.UserStarDifficulty.Max = maximumStars.Value; - - criteria.RulesetCriteria = ruleset.Value.CreateInstance().CreateRulesetFilterCriteria(); - - FilterQueryParser.ApplyQueries(criteria, query); - return criteria; - } - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => - base.ReceivePositionalInputAt(screenSpacePos) || sortTabs.ReceivePositionalInputAt(screenSpacePos); - - [BackgroundDependencyLoader(permitNulls: true)] - private void load(OsuColour colours, OsuConfigManager config) - { - sortMode = config.GetBindable(OsuSetting.SongSelectSortingMode); - groupMode = config.GetBindable(OsuSetting.SongSelectGroupMode); - - Children = new Drawable[] - { - new Box - { - Colour = OsuColour.Gray(0.05f), - Alpha = 0.96f, - Width = 2, - RelativeSizeAxes = Axes.Both, - }, - new Container - { - Padding = new MarginPadding(side_margin), - RelativeSizeAxes = Axes.Both, - Width = 0.5f, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - // Reverse ChildID so that dropdowns in the top section appear on top of the bottom section. - Child = new ReverseChildIDFillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Spacing = new Vector2(0, 5), - Children = new Drawable[] - { - searchTextBox = new FilterControlTextBox - { - RelativeSizeAxes = Axes.X, - }, - new Box - { - RelativeSizeAxes = Axes.X, - Height = 1, - Colour = OsuColour.Gray(80), - }, - new GridContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Absolute, OsuTabControl.HORIZONTAL_SPACING), - new Dimension(), - new Dimension(GridSizeMode.Absolute, OsuTabControl.HORIZONTAL_SPACING), - new Dimension(GridSizeMode.AutoSize), - }, - RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, - Content = new[] - { - new[] - { - new OsuSpriteText - { - Text = SortStrings.Default, - Font = OsuFont.GetFont(size: 14), - Margin = new MarginPadding(5), - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - }, - Empty(), - sortTabs = new OsuTabControl - { - RelativeSizeAxes = Axes.X, - Height = 24, - AutoSort = true, - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - AccentColour = colours.GreenLight, - Current = { BindTarget = sortMode } - }, - Empty(), - new OsuTabControlCheckbox - { - Text = "Show converted", - Current = config.GetBindable(OsuSetting.ShowConvertedBeatmaps), - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - }, - } - } - }, - new Container - { - RelativeSizeAxes = Axes.X, - Height = 40, - Children = new Drawable[] - { - new RangeSlider - { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Label = "Difficulty range", - LowerBound = config.GetBindable(OsuSetting.DisplayStarsMinimum), - UpperBound = config.GetBindable(OsuSetting.DisplayStarsMaximum), - RelativeSizeAxes = Axes.Both, - Width = 0.48f, - DefaultStringLowerBound = "0", - DefaultStringUpperBound = "∞", - DefaultTooltipUpperBound = UserInterfaceStrings.NoLimit, - TooltipSuffix = "stars" - }, - collectionDropdown = new CollectionDropdown - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - RequestFilter = updateCriteria, - RelativeSizeAxes = Axes.X, - Y = 4, - Width = 0.5f, - } - } - }, - } - } - } - }; - - config.BindWith(OsuSetting.ShowConvertedBeatmaps, showConverted); - showConverted.ValueChanged += _ => updateCriteria(); - - config.BindWith(OsuSetting.DisplayStarsMinimum, minimumStars); - minimumStars.ValueChanged += _ => updateCriteria(); - - config.BindWith(OsuSetting.DisplayStarsMaximum, maximumStars); - maximumStars.ValueChanged += _ => updateCriteria(); - - ruleset.BindValueChanged(_ => updateCriteria()); - mods.BindValueChanged(m => - { - // Mods are updated once by the mod select overlay when song select is entered, - // regardless of if there are any mods or any changes have taken place. - // Updating the criteria here so early triggers a re-ordering of panels on song select, via... some mechanism. - // Todo: Investigate/fix and potentially remove this. - if (m.NewValue.SequenceEqual(m.OldValue)) - return; - - if (currentCriteria?.RulesetCriteria?.FilterMayChangeFromMods(m) == true) - updateCriteria(); - }); - - groupMode.BindValueChanged(_ => updateCriteria()); - sortMode.BindValueChanged(_ => updateCriteria()); - - searchTextBox.Current.ValueChanged += _ => updateCriteria(); - - updateCriteria(); - } - - public void Deactivate() - { - searchTextBox.ReadOnly = true; - searchTextBox.HoldFocus = false; - if (searchTextBox.HasFocus) - GetContainingFocusManager()!.ChangeFocus(searchTextBox); - } - - public void Activate() - { - searchTextBox.ReadOnly = false; - searchTextBox.HoldFocus = true; - } - - [Resolved] - private IBindable ruleset { get; set; } = null!; - - [Resolved] - private IBindable> mods { get; set; } = null!; - - private readonly Bindable showConverted = new Bindable(); - private readonly Bindable minimumStars = new BindableDouble(); - private readonly Bindable maximumStars = new BindableDouble(); - - private void updateCriteria() => FilterChanged?.Invoke(currentCriteria = CreateCriteria()); - - protected override bool OnClick(ClickEvent e) => true; - - protected override bool OnHover(HoverEvent e) => true; - - internal partial class FilterControlTextBox : SeekLimitedSearchTextBox - { - private const float filter_text_size = 12; - - public OsuSpriteText FilterText { get; private set; } - - public FilterControlTextBox() - { - Height += filter_text_size; - TextContainer.Height *= (Height - filter_text_size) / Height; - TextContainer.Margin = new MarginPadding { Bottom = filter_text_size }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - TextContainer.Add(FilterText = new OsuSpriteText - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.TopLeft, - Depth = float.MinValue, - Font = OsuFont.Default.With(size: filter_text_size, weight: FontWeight.SemiBold), - Margin = new MarginPadding { Top = 2, Left = 2 }, - Colour = colours.Yellow - }); - } - - public override bool OnPressed(KeyBindingPressEvent e) - { - // the "cut" platform key binding (shift-delete) conflicts with the beatmap deletion action. - if (e.Action == PlatformAction.Cut && e.ShiftPressed && e.CurrentState.Keyboard.Keys.IsPressed(Key.Delete)) - return false; - - return base.OnPressed(e); - } - } - } -} diff --git a/osu.Game/Screens/Select/Footer.cs b/osu.Game/Screens/Select/Footer.cs deleted file mode 100644 index 1d05f644b791..000000000000 --- a/osu.Game/Screens/Select/Footer.cs +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.Collections.Generic; -using System.Linq; -using osuTK; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Events; -using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; - -namespace osu.Game.Screens.Select -{ - public partial class Footer : Container - { - private readonly Box modeLight; - - public const float HEIGHT = 50; - - public const int TRANSITION_LENGTH = 300; - - private const float padding = 80; - - private readonly FillFlowContainer buttons; - - private readonly List overlays = new List(); - - /// The button to be added. - /// The to be toggled by this button. - public void AddButton(FooterButton button, OverlayContainer overlay) - { - if (overlay != null) - { - overlays.Add(overlay); - button.Action = () => showOverlay(overlay); - } - - button.Hovered = updateModeLight; - button.HoverLost = updateModeLight; - - buttons.Add(button); - } - - private void showOverlay(OverlayContainer overlay) - { - foreach (var o in overlays) - { - if (o == overlay) - o.ToggleVisibility(); - else - o.Hide(); - } - } - - private void updateModeLight() - { - var selectedButton = buttons.FirstOrDefault(b => b.Enabled.Value && b.IsHovered); - - if (selectedButton != null) - { - modeLight.FadeIn(TRANSITION_LENGTH, Easing.OutQuint); - modeLight.FadeColour(selectedButton.SelectedColour, TRANSITION_LENGTH, Easing.OutQuint); - } - else - modeLight.FadeOut(TRANSITION_LENGTH, Easing.OutQuint); - } - - public Footer() - { - RelativeSizeAxes = Axes.X; - Height = HEIGHT; - Anchor = Anchor.BottomCentre; - Origin = Anchor.BottomCentre; - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Size = Vector2.One, - Colour = OsuColour.Gray(0.1f), - Alpha = 0.96f, - }, - modeLight = new Box - { - RelativeSizeAxes = Axes.X, - Height = 3, - Position = new Vector2(0, -3), - Colour = OsuColour.Gray(0.1f), - }, - new FillFlowContainer - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Position = new Vector2(TwoLayerButton.SIZE_EXTENDED.X + padding, 0), - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(padding, 0), - Children = new Drawable[] - { - buttons = new FillFlowContainer - { - Direction = FillDirection.Horizontal, - Spacing = new Vector2(-FooterButton.SHEAR_WIDTH, 0), - AutoSizeAxes = Axes.Both, - } - } - } - }; - - updateModeLight(); - } - - protected override bool OnMouseDown(MouseDownEvent e) => true; - - protected override bool OnClick(ClickEvent e) => true; - - protected override bool OnHover(HoverEvent e) => true; - } -} diff --git a/osu.Game/Screens/Select/FooterButton.cs b/osu.Game/Screens/Select/FooterButton.cs deleted file mode 100644 index dafa0b0c1c5c..000000000000 --- a/osu.Game/Screens/Select/FooterButton.cs +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Input.Bindings; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Select -{ - public partial class FooterButton : OsuClickableContainer, IKeyBindingHandler - { - public const float SHEAR_WIDTH = 7.5f; - - protected static readonly Vector2 SHEAR = new Vector2(SHEAR_WIDTH / Footer.HEIGHT, 0); - - /// - /// Used to show an initial animation hinting at the enabled state. - /// - protected virtual bool IsActive => false; - - public LocalisableString Text - { - get => SpriteText?.Text ?? default; - set - { - if (SpriteText != null) - SpriteText.Text = value; - } - } - - private Color4 deselectedColour; - - public Color4 DeselectedColour - { - get => deselectedColour; - set - { - deselectedColour = value; - if (light.Colour != SelectedColour) - light.Colour = value; - } - } - - private Color4 selectedColour; - - public Color4 SelectedColour - { - get => selectedColour; - set - { - selectedColour = value; - box.Colour = selectedColour; - } - } - - protected FillFlowContainer ButtonContentContainer; - protected readonly Container TextContainer; - protected readonly SpriteText SpriteText; - private readonly Box box; - private readonly Box light; - - public FooterButton() - { - AutoSizeAxes = Axes.Both; - Shear = SHEAR; - Children = new Drawable[] - { - box = new Box - { - RelativeSizeAxes = Axes.Both, - EdgeSmoothness = new Vector2(2, 0), - Colour = Color4.White, - Alpha = 0, - }, - light = new Box - { - Height = 4, - EdgeSmoothness = new Vector2(2, 0), - RelativeSizeAxes = Axes.X, - }, - new Container - { - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - ButtonContentContainer = new FillFlowContainer - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Direction = FillDirection.Horizontal, - Shear = -SHEAR, - AutoSizeAxes = Axes.X, - Height = 50, - Spacing = new Vector2(15, 0), - Children = new Drawable[] - { - TextContainer = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Child = SpriteText = new OsuSpriteText - { - AlwaysPresent = true, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - }, - }, - }, - }, - }, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - Enabled.BindValueChanged(_ => updateDisplay(), true); - - if (IsActive) - { - box.ClearTransforms(); - - using (box.BeginDelayedSequence(200)) - { - box.FadeIn(200) - .Then() - .FadeOut(1500, Easing.OutQuint); - } - } - } - - public Action Hovered; - public Action HoverLost; - public GlobalAction? Hotkey; - - private bool mouseDown; - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - float horizontalMargin = (100 - TextContainer.Width) / 2; - ButtonContentContainer.Padding = new MarginPadding - { - Left = horizontalMargin, - // right side margin offset to compensate for shear - Right = horizontalMargin - SHEAR_WIDTH / 2 - }; - } - - protected override bool OnHover(HoverEvent e) - { - Hovered?.Invoke(); - updateDisplay(); - return true; - } - - protected override void OnHoverLost(HoverLostEvent e) - { - HoverLost?.Invoke(); - updateDisplay(); - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - if (!Enabled.Value) - return true; - - mouseDown = true; - updateDisplay(); - return base.OnMouseDown(e); - } - - protected override void OnMouseUp(MouseUpEvent e) - { - mouseDown = false; - updateDisplay(); - base.OnMouseUp(e); - } - - protected override bool OnClick(ClickEvent e) - { - if (!Enabled.Value) - return true; - - box.ClearTransforms(); - box.Alpha = 1; - box.FadeOut(Footer.TRANSITION_LENGTH * 3, Easing.OutQuint); - return base.OnClick(e); - } - - public virtual bool OnPressed(KeyBindingPressEvent e) - { - if (e.Action == Hotkey && !e.Repeat) - { - TriggerClick(); - return true; - } - - return false; - } - - public virtual void OnReleased(KeyBindingReleaseEvent e) { } - - private void updateDisplay() - { - this.FadeTo(Enabled.Value ? 1 : 0.25f, Footer.TRANSITION_LENGTH, Easing.OutQuint); - - light.ScaleTo(Enabled.Value && IsHovered ? new Vector2(1, 2) : new Vector2(1), Footer.TRANSITION_LENGTH, Easing.OutQuint); - light.FadeColour(Enabled.Value && IsHovered ? SelectedColour : DeselectedColour, Footer.TRANSITION_LENGTH, Easing.OutQuint); - - box.FadeTo(Enabled.Value & mouseDown ? 0.3f : 0f, Footer.TRANSITION_LENGTH * 2, Easing.OutQuint); - - if (Enabled.Value && IsHovered) - Hovered?.Invoke(); - else - HoverLost?.Invoke(); - } - } -} diff --git a/osu.Game/Screens/Select/FooterButtonMods.cs b/osu.Game/Screens/Select/FooterButtonMods.cs deleted file mode 100644 index a15d315f1b5c..000000000000 --- a/osu.Game/Screens/Select/FooterButtonMods.cs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Game.Screens.Play.HUD; -using osu.Game.Rulesets.Mods; -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Extensions.LocalisationExtensions; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osuTK; -using osuTK.Graphics; -using osu.Game.Input.Bindings; -using osu.Game.Localisation; -using osu.Game.Utils; - -namespace osu.Game.Screens.Select -{ - public partial class FooterButtonMods : FooterButton, IHasCurrentValue> - { - public Bindable> Current - { - get => modDisplay.Current; - set => modDisplay.Current = value; - } - - protected OsuSpriteText MultiplierText { get; private set; } = null!; - protected Container UnrankedBadge { get; private set; } = null!; - - private readonly ModDisplay modDisplay; - - private ModSettingChangeTracker? modSettingChangeTracker; - - private Color4 lowMultiplierColour; - private Color4 highMultiplierColour; - - public FooterButtonMods() - { - // must be created in ctor for correct operation of `Current`. - modDisplay = new ModDisplay - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(0.8f), - ExpansionMode = ExpansionMode.AlwaysContracted, - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - SelectedColour = colours.Yellow; - DeselectedColour = SelectedColour.Opacity(0.5f); - lowMultiplierColour = colours.Green; - highMultiplierColour = colours.Red; - Text = @"mods"; - Hotkey = GlobalAction.ToggleModSelection; - - ButtonContentContainer.AddRange(new Drawable[] - { - modDisplay, - MultiplierText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(weight: FontWeight.Bold), - }, - UnrankedBadge = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Circle - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.Yellow, - RelativeSizeAxes = Axes.Both, - }, - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.Gray2, - Padding = new MarginPadding(5), - UseFullGlyphHeight = false, - Text = ModSelectOverlayStrings.Unranked.ToLower() - } - } - }, - }); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - Current.BindValueChanged(mods => - { - modSettingChangeTracker?.Dispose(); - - updateMultiplierText(); - - if (mods.NewValue != null) - { - modSettingChangeTracker = new ModSettingChangeTracker(mods.NewValue); - modSettingChangeTracker.SettingChanged += _ => updateMultiplierText(); - } - }, true); - } - - private void updateMultiplierText() => Schedule(() => - { - double multiplier = Current.Value?.Aggregate(1.0, (current, mod) => current * mod.ScoreMultiplier) ?? 1; - MultiplierText.Text = multiplier == 1 ? string.Empty : ModUtils.FormatScoreMultiplier(multiplier); - - if (multiplier > 1) - MultiplierText.FadeColour(highMultiplierColour, 200); - else if (multiplier < 1) - MultiplierText.FadeColour(lowMultiplierColour, 200); - else - MultiplierText.FadeColour(Color4.White, 200); - - if (Current.Value?.Count > 0) - modDisplay.FadeIn(); - else - modDisplay.FadeOut(); - - bool anyUnrankedMods = Current.Value?.Any(m => !m.Ranked) == true; - UnrankedBadge.FadeTo(anyUnrankedMods ? 1 : 0); - }); - } -} diff --git a/osu.Game/Screens/Select/FooterButtonOptions.cs b/osu.Game/Screens/Select/FooterButtonOptions.cs deleted file mode 100644 index 532051369b97..000000000000 --- a/osu.Game/Screens/Select/FooterButtonOptions.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Game.Graphics; -using osu.Game.Input.Bindings; - -namespace osu.Game.Screens.Select -{ - public partial class FooterButtonOptions : FooterButton - { - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - SelectedColour = colours.Blue; - DeselectedColour = SelectedColour.Opacity(0.5f); - Text = @"options"; - Hotkey = GlobalAction.ToggleBeatmapOptions; - } - } -} diff --git a/osu.Game/Screens/Select/FooterButtonRandom.cs b/osu.Game/Screens/Select/FooterButtonRandom.cs deleted file mode 100644 index 2d5d04913337..000000000000 --- a/osu.Game/Screens/Select/FooterButtonRandom.cs +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Events; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Input.Bindings; -using osuTK; -using osuTK.Input; - -namespace osu.Game.Screens.Select -{ - public partial class FooterButtonRandom : FooterButton - { - public Action NextRandom { get; set; } - public Action PreviousRandom { get; set; } - - private Container persistentText; - private OsuSpriteText randomSpriteText; - private OsuSpriteText rewindSpriteText; - private bool rewindSearch; - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - SelectedColour = colours.Green; - DeselectedColour = SelectedColour.Opacity(0.5f); - - TextContainer.Add(persistentText = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AlwaysPresent = true, - AutoSizeAxes = Axes.Both, - Children = new[] - { - randomSpriteText = new OsuSpriteText - { - AlwaysPresent = true, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "random", - }, - rewindSpriteText = new OsuSpriteText - { - AlwaysPresent = true, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "rewind", - Alpha = 0f, - } - } - }); - - Action = () => - { - if (rewindSearch) - { - const double fade_time = 500; - - OsuSpriteText fallingRewind; - - TextContainer.Add(fallingRewind = new OsuSpriteText - { - Alpha = 0, - Text = rewindSpriteText.Text, - AlwaysPresent = true, // make sure the button is sized large enough to always show this - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }); - - fallingRewind.FadeOutFromOne(fade_time, Easing.In); - fallingRewind.MoveTo(Vector2.Zero).MoveTo(new Vector2(0, 10), fade_time, Easing.In); - fallingRewind.Expire(); - - persistentText.FadeInFromZero(fade_time, Easing.In); - - PreviousRandom.Invoke(); - } - else - { - NextRandom.Invoke(); - } - }; - } - - protected override bool OnKeyDown(KeyDownEvent e) - { - updateText(e); - return base.OnKeyDown(e); - } - - protected override void OnKeyUp(KeyUpEvent e) - { - updateText(e); - base.OnKeyUp(e); - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - updateText(e); - return base.OnMouseDown(e); - } - - protected override bool OnClick(ClickEvent e) - { - try - { - // this uses OR to handle rewinding when clicks are triggered by other sources (i.e. right button in OnMouseUp). - rewindSearch |= e.ShiftPressed; - return base.OnClick(e); - } - finally - { - rewindSearch = false; - } - } - - protected override void OnMouseUp(MouseUpEvent e) - { - base.OnMouseUp(e); - - if (e.Button == MouseButton.Right && IsHovered) - { - rewindSearch = true; - TriggerClick(); - } - - updateText(e); - } - - public override bool OnPressed(KeyBindingPressEvent e) - { - rewindSearch = e.Action == GlobalAction.SelectPreviousRandom; - - if (e.Action != GlobalAction.SelectNextRandom && e.Action != GlobalAction.SelectPreviousRandom) - { - return false; - } - - if (!e.Repeat) - TriggerClick(); - return true; - } - - public override void OnReleased(KeyBindingReleaseEvent e) - { - if (e.Action == GlobalAction.SelectPreviousRandom) - { - rewindSearch = false; - } - } - - private void updateText(UIEvent e) - { - bool aboutToRewind = e.ShiftPressed || e.CurrentState.Mouse.IsPressed(MouseButton.Right); - - randomSpriteText.Alpha = aboutToRewind ? 0 : 1; - rewindSpriteText.Alpha = aboutToRewind ? 1 : 0; - } - } -} diff --git a/osu.Game/Screens/Select/NoResultsPlaceholder.cs b/osu.Game/Screens/Select/NoResultsPlaceholder.cs deleted file mode 100644 index 50577d5feace..000000000000 --- a/osu.Game/Screens/Select/NoResultsPlaceholder.cs +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Localisation; -using osu.Game.Online.Chat; -using osu.Game.Overlays; -using osuTK; - -namespace osu.Game.Screens.Select -{ - public partial class NoResultsPlaceholder : VisibilityContainer - { - private FilterCriteria? filter; - - private LinkFlowContainer textFlow = null!; - - [Resolved] - private BeatmapManager beatmaps { get; set; } = null!; - - [Resolved] - private FirstRunSetupOverlay? firstRunSetupOverlay { get; set; } - - [Resolved] - private OsuConfigManager config { get; set; } = null!; - - public FilterCriteria Filter - { - set - { - if (filter == value) - return; - - filter = value; - Scheduler.AddOnce(updateText); - } - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Masking = true; - CornerRadius = 10; - - Width = 400; - AutoSizeAxes = Axes.Y; - - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - - InternalChildren = new Drawable[] - { - new Box - { - Colour = colours.Gray2, - RelativeSizeAxes = Axes.Both, - }, - new SpriteIcon - { - Icon = FontAwesome.Regular.SadTear, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Margin = new MarginPadding(10), - Size = new Vector2(50), - }, - textFlow = new LinkFlowContainer - { - Y = 60, - Padding = new MarginPadding(10), - TextAnchor = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - } - }; - } - - protected override void PopIn() - { - this.FadeIn(600, Easing.OutQuint); - - Scheduler.AddOnce(updateText); - } - - protected override void PopOut() - { - this.FadeOut(200, Easing.OutQuint); - } - - private void updateText() - { - // TODO: Refresh this text when new beatmaps are imported. Right now it won't get up-to-date suggestions. - - // Bounce should play every time the filter criteria is updated. - this.ScaleTo(0.9f) - .ScaleTo(1f, 1000, Easing.OutElastic); - - textFlow.Clear(); - - if (beatmaps.QueryBeatmapSet(s => !s.Protected && !s.DeletePending) == null) - { - textFlow.AddParagraph("No beatmaps found!"); - textFlow.AddParagraph(string.Empty); - - textFlow.AddParagraph("- Consider running the \""); - textFlow.AddLink(FirstRunSetupOverlayStrings.FirstRunSetupTitle, () => firstRunSetupOverlay?.Show()); - textFlow.AddText("\" to download or import some beatmaps!"); - } - else - { - textFlow.AddParagraph("No beatmaps match your filter criteria!"); - textFlow.AddParagraph(string.Empty); - - if (filter?.UserStarDifficulty.HasFilter == true) - { - textFlow.AddParagraph("- Try "); - textFlow.AddLink("removing", () => - { - config.SetValue(OsuSetting.DisplayStarsMinimum, 0.0); - config.SetValue(OsuSetting.DisplayStarsMaximum, 10.1); - }); - - string lowerStar = $"{filter.UserStarDifficulty.Min ?? 0:N1}"; - string upperStar = filter.UserStarDifficulty.Max == null ? "∞" : $"{filter.UserStarDifficulty.Max:N1}"; - - textFlow.AddText($" the {lowerStar} - {upperStar} star difficulty filter."); - } - - // TODO: Add realm queries to hint at which ruleset results are available in (and allow clicking to switch). - // TODO: Make this message more certain by ensuring the osu! beatmaps exist before suggesting. - if (filter?.Ruleset?.OnlineID != 0 && filter?.AllowConvertedBeatmaps == false) - { - textFlow.AddParagraph("- Try "); - textFlow.AddLink("enabling ", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, true)); - textFlow.AddText("automatic conversion!"); - } - } - - if (!string.IsNullOrEmpty(filter?.SearchText)) - { - textFlow.AddParagraph("- Try "); - textFlow.AddLink("searching online", LinkAction.SearchBeatmapSet, filter.SearchText); - textFlow.AddText($" for \"{filter.SearchText}\"."); - } - // TODO: add clickable link to reset criteria. - } - } -} diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs deleted file mode 100644 index 572b2427b178..000000000000 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osuTK; -using osuTK.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; - -namespace osu.Game.Screens.Select.Options -{ - public partial class BeatmapOptionsButton : OsuClickableContainer - { - private const float width = 130; - - private readonly Box background; - private readonly Box flash; - private readonly SpriteIcon iconText; - private readonly OsuSpriteText firstLine; - private readonly OsuSpriteText secondLine; - private readonly Container box; - - public Color4 ButtonColour - { - get => background.Colour; - set => background.Colour = value; - } - - public IconUsage Icon - { - get => iconText.Icon; - set => iconText.Icon = value; - } - - public LocalisableString FirstLineText - { - get => firstLine.Text; - set => firstLine.Text = value; - } - - public LocalisableString SecondLineText - { - get => secondLine.Text; - set => secondLine.Text = value; - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - flash.FadeTo(0.1f, 1000, Easing.OutQuint); - return base.OnMouseDown(e); - } - - protected override void OnMouseUp(MouseUpEvent e) - { - flash.FadeTo(0, 1000, Easing.OutQuint); - base.OnMouseUp(e); - } - - protected override bool OnClick(ClickEvent e) - { - flash.ClearTransforms(); - flash.Alpha = 0.9f; - flash.FadeOut(800, Easing.OutExpo); - - return base.OnClick(e); - } - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => box.ReceivePositionalInputAt(screenSpacePos); - - public BeatmapOptionsButton() - : base(HoverSampleSet.Button) - { - Width = width; - RelativeSizeAxes = Axes.Y; - - Children = new Drawable[] - { - box = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Shear = OsuGame.SHEAR, - Masking = true, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(0.2f), - Roundness = 5, - Radius = 8, - }, - Children = new Drawable[] - { - background = new Box - { - RelativeSizeAxes = Axes.Both, - EdgeSmoothness = new Vector2(1.5f, 0), - Colour = Color4.Black, - }, - flash = new Box - { - RelativeSizeAxes = Axes.Both, - EdgeSmoothness = new Vector2(1.5f, 0), - Blending = BlendingParameters.Additive, - Colour = Color4.White, - Alpha = 0, - }, - }, - }, - new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - iconText = new SpriteIcon - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Size = new Vector2(30), - Shadow = true, - Icon = FontAwesome.Solid.TimesCircle, - Margin = new MarginPadding - { - Bottom = 5, - }, - }, - firstLine = new OsuSpriteText - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Font = OsuFont.GetFont(weight: FontWeight.Bold), - Text = @"", - }, - secondLine = new OsuSpriteText - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Font = OsuFont.GetFont(weight: FontWeight.Bold), - Text = @"", - }, - }, - }, - }; - } - } -} diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs deleted file mode 100644 index 7b631ebfea8c..000000000000 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osuTK; -using osuTK.Graphics; -using osuTK.Input; -using osu.Game.Graphics.Containers; -using osu.Framework.Input.Events; -using System.Linq; -using osu.Framework.Localisation; - -namespace osu.Game.Screens.Select.Options -{ - public partial class BeatmapOptionsOverlay : OsuFocusedOverlayContainer - { - private const float transition_duration = 500; - private const float x_position = 0.2f; - private const float x_movement = 0.8f; - - private const float height = 100; - - private readonly Box holder; - private readonly FillFlowContainer buttonsContainer; - - public override bool BlockScreenWideMouse => false; - - protected override string PopInSampleName => "SongSelect/options-pop-in"; - protected override string PopOutSampleName => "SongSelect/options-pop-out"; - - public BeatmapOptionsOverlay() - { - AutoSizeAxes = Axes.Y; - RelativeSizeAxes = Axes.X; - Anchor = Anchor.BottomLeft; - Origin = Anchor.BottomLeft; - - Children = new Drawable[] - { - holder = new Box - { - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Both, - Height = 0.5f, - Scale = new Vector2(1, 0), - Colour = Color4.Black.Opacity(0.5f), - }, - buttonsContainer = new ReverseChildIDFillFlowContainer - { - Height = height, - RelativePositionAxes = Axes.X, - AutoSizeAxes = Axes.X, - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - }, - }; - } - - /// Text in the first line. - /// Text in the second line. - /// Colour of the button. - /// Icon of the button. - /// Binding the button does. - public void AddButton(LocalisableString firstLine, string secondLine, IconUsage icon, Color4 colour, Action action) - { - var button = new BeatmapOptionsButton - { - FirstLineText = firstLine, - SecondLineText = secondLine, - Icon = icon, - ButtonColour = colour, - Action = () => - { - Hide(); - action?.Invoke(); - }, - }; - - buttonsContainer.Add(button); - } - - protected override void PopIn() - { - this.FadeIn(transition_duration, Easing.OutQuint); - - if (buttonsContainer.Position.X == 1 || Alpha == 0) - buttonsContainer.MoveToX(x_position - x_movement); - - holder.ScaleTo(new Vector2(1, 1), transition_duration / 2, Easing.OutQuint); - - buttonsContainer.MoveToX(x_position, transition_duration, Easing.OutQuint); - buttonsContainer.TransformSpacingTo(Vector2.Zero, transition_duration, Easing.OutQuint); - } - - protected override void PopOut() - { - base.PopOut(); - - holder.ScaleTo(new Vector2(1, 0), transition_duration / 2, Easing.InSine); - - buttonsContainer.MoveToX(x_position + x_movement, transition_duration, Easing.InSine); - buttonsContainer.TransformSpacingTo(new Vector2(200f, 0f), transition_duration, Easing.InSine); - - this.FadeOut(transition_duration, Easing.InQuint); - } - - protected override bool OnKeyDown(KeyDownEvent e) - { - // don't absorb control as ToolbarRulesetSelector uses control + number to navigate - if (e.ControlPressed) return false; - - if (!e.Repeat && e.Key >= Key.Number1 && e.Key <= Key.Number9) - { - int requested = e.Key - Key.Number1; - - // go reverse as buttonsContainer is a ReverseChildIDFillFlowContainer - BeatmapOptionsButton found = buttonsContainer.Children.ElementAtOrDefault((buttonsContainer.Children.Count - 1) - requested); - - if (found != null) - { - found.TriggerClick(); - return true; - } - } - - return base.OnKeyDown(e); - } - } -} diff --git a/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs b/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs deleted file mode 100644 index ae318de754de..000000000000 --- a/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Screens.Select.Leaderboards; - -namespace osu.Game.Screens.Select -{ - public partial class PlayBeatmapDetailArea : BeatmapDetailArea - { - public readonly BeatmapLeaderboard Leaderboard; - - public override WorkingBeatmap Beatmap - { - get => base.Beatmap; - set - { - base.Beatmap = value; - - Leaderboard.BeatmapInfo = value is DummyWorkingBeatmap ? null : value?.BeatmapInfo; - } - } - - private Bindable selectedTab; - - private Bindable selectedModsFilter; - - public PlayBeatmapDetailArea() - { - Add(Leaderboard = new BeatmapLeaderboard { RelativeSizeAxes = Axes.Both }); - } - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - selectedTab = config.GetBindable(OsuSetting.BeatmapDetailTab); - selectedModsFilter = config.GetBindable(OsuSetting.BeatmapDetailModsFilter); - - selectedTab.BindValueChanged(tab => CurrentTab.Value = getTabItemFromTabType(tab.NewValue), true); - CurrentTab.BindValueChanged(tab => selectedTab.Value = getTabTypeFromTabItem(tab.NewValue)); - - selectedModsFilter.BindValueChanged(checkbox => CurrentModsFilter.Value = checkbox.NewValue, true); - CurrentModsFilter.BindValueChanged(checkbox => selectedModsFilter.Value = checkbox.NewValue); - } - - public override void Refresh() - { - base.Refresh(); - - Leaderboard.RefetchScores(); - } - - protected override void OnTabChanged(BeatmapDetailAreaTabItem tab, bool selectedMods) - { - base.OnTabChanged(tab, selectedMods); - - Leaderboard.FilterMods = selectedMods; - - switch (tab) - { - case BeatmapDetailAreaLeaderboardTabItem leaderboard: - Leaderboard.Scope = leaderboard.Scope; - Leaderboard.Show(); - break; - - default: - Leaderboard.Hide(); - break; - } - } - - protected override BeatmapDetailAreaTabItem[] CreateTabItems() => base.CreateTabItems().Concat(new BeatmapDetailAreaTabItem[] - { - new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local), - new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Global), - new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Country), - new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Friend), - new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Team), - }).ToArray(); - - private BeatmapDetailAreaTabItem getTabItemFromTabType(BeatmapDetailTab type) - { - switch (type) - { - case BeatmapDetailTab.Details: - return new BeatmapDetailAreaDetailTabItem(); - - case BeatmapDetailTab.Local: - return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local); - - case BeatmapDetailTab.Global: - return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Global); - - case BeatmapDetailTab.Country: - return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Country); - - case BeatmapDetailTab.Friends: - return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Friend); - - case BeatmapDetailTab.Team: - return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Team); - - default: - throw new ArgumentOutOfRangeException(nameof(type)); - } - } - - private BeatmapDetailTab getTabTypeFromTabItem(BeatmapDetailAreaTabItem item) - { - switch (item) - { - case BeatmapDetailAreaDetailTabItem: - return BeatmapDetailTab.Details; - - case BeatmapDetailAreaLeaderboardTabItem leaderboardTab: - switch (leaderboardTab.Scope) - { - case BeatmapLeaderboardScope.Local: - return BeatmapDetailTab.Local; - - case BeatmapLeaderboardScope.Country: - return BeatmapDetailTab.Country; - - case BeatmapLeaderboardScope.Global: - return BeatmapDetailTab.Global; - - case BeatmapLeaderboardScope.Friend: - return BeatmapDetailTab.Friends; - - case BeatmapLeaderboardScope.Team: - return BeatmapDetailTab.Team; - - default: - throw new ArgumentOutOfRangeException(nameof(item)); - } - - default: - throw new ArgumentOutOfRangeException(nameof(item)); - } - } - } -} diff --git a/osu.Game/Screens/Select/SkinDeleteDialog.cs b/osu.Game/Screens/Select/SkinDeleteDialog.cs deleted file mode 100644 index cd14b5b6d274..000000000000 --- a/osu.Game/Screens/Select/SkinDeleteDialog.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Game.Skinning; -using osu.Game.Overlays.Dialog; - -namespace osu.Game.Screens.Select -{ - public partial class SkinDeleteDialog : DeletionDialog - { - private readonly Skin skin; - - public SkinDeleteDialog(Skin skin) - { - this.skin = skin; - BodyText = skin.SkinInfo.Value.Name; - } - - [BackgroundDependencyLoader] - private void load(SkinManager manager) - { - DangerousAction = () => - { - manager.Delete(skin.SkinInfo.Value); - manager.CurrentSkinInfo.SetDefault(); - }; - } - } -} diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs deleted file mode 100644 index 606d53d884f2..000000000000 --- a/osu.Game/Screens/Select/SongSelect.cs +++ /dev/null @@ -1,1184 +0,0 @@ -// 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.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Audio.Track; -using osu.Framework.Bindables; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input; -using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Framework.Logging; -using osu.Framework.Screens; -using osu.Framework.Threading; -using osu.Game.Beatmaps; -using osu.Game.Collections; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Cursor; -using osu.Game.Graphics.UserInterface; -using osu.Game.Input.Bindings; -using osu.Game.Overlays; -using osu.Game.Overlays.Mods; -using osu.Game.Overlays.Volume; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Backgrounds; -using osu.Game.Screens.Edit; -using osu.Game.Screens.Menu; -using osu.Game.Screens.Play; -using osu.Game.Screens.Select.Details; -using osu.Game.Screens.Select.Options; -using osu.Game.Skinning; -using osu.Game.Utils; -using osuTK; -using osuTK.Graphics; -using osuTK.Input; - -namespace osu.Game.Screens.Select -{ - public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler - { - public static readonly float WEDGE_HEIGHT = 200; - - protected const float BACKGROUND_BLUR = 20; - private const float left_area_padding = 20; - - public FilterControl FilterControl { get; private set; } = null!; - - /// - /// Whether this song select instance should take control of the global track, - /// applying looping and preview offsets. - /// - protected virtual bool ControlGlobalMusic => true; - - protected virtual bool ShowSongSelectFooter => true; - - public override bool? ApplyModTrackAdjustments => true; - - /// - /// Can be null if is false. - /// - protected BeatmapOptionsOverlay BeatmapOptions { get; private set; } = null!; - - /// - /// Can be null if is false. - /// - protected Footer? SongSelectFooter { get; private set; } - - /// - /// Contains any panel which is triggered by a footer button. - /// Helps keep them located beneath the footer itself. - /// - protected Container FooterPanels { get; private set; } = null!; - - /// - /// The that opens the mod select dialog. - /// - protected FooterButton ModsFooterButton { get; private set; } = null!; - - /// - /// Whether entering editor mode should be allowed. - /// - public virtual bool AllowEditing => true; - - public bool BeatmapSetsLoaded => IsLoaded && Carousel.BeatmapSetsLoaded; - - /// - /// Creates any "action" menu items for the provided beatmap (ie. "Select", "Play", "Edit"). - /// These will always be placed at the top of the context menu, with common items added below them. - /// - /// The beatmap to create items for. - /// The menu items. - public virtual MenuItem[] CreateForwardNavigationMenuItemsForBeatmap(Func getBeatmap) => new MenuItem[] - { - new OsuMenuItem(@"Select", MenuItemType.Highlighted, () => FinaliseSelection(getBeatmap())) - }; - - [Resolved] - private OsuGameBase game { get; set; } = null!; - - [Resolved] - private Bindable> selectedMods { get; set; } = null!; - - protected BeatmapCarousel Carousel { get; private set; } = null!; - - private ParallaxContainer wedgeBackground = null!; - - protected Container LeftArea { get; private set; } = null!; - - private BeatmapInfoWedge beatmapInfoWedge = null!; - - [Resolved] - private IDialogOverlay? dialogOverlay { get; set; } - - [Resolved] - private BeatmapManager beatmaps { get; set; } = null!; - - protected ModSelectOverlay ModSelect { get; private set; } = null!; - - protected Sample? SampleConfirm { get; private set; } - - private Sample sampleChangeDifficulty = null!; - private Sample sampleChangeBeatmap = null!; - - private bool pendingFilterApplication; - - private Container carouselContainer = null!; - - protected BeatmapDetailArea BeatmapDetails { get; private set; } = null!; - - private FooterButtonOptions beatmapOptionsButton = null!; - - private readonly Bindable decoupledRuleset = new Bindable(); - - private double audioFeedbackLastPlaybackTime; - - private IDisposable? modSelectOverlayRegistration; - private ModSpeedHotkeyHandler modSpeedHotkeyHandler = null!; - - private AdvancedStats advancedStats = null!; - - [Resolved] - private MusicController music { get; set; } = null!; - - [Resolved] - internal IOverlayManager? OverlayManager { get; private set; } - - private Bindable configBackgroundBlur = null!; - - [BackgroundDependencyLoader(true)] - private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender, OsuConfigManager config) - { - configBackgroundBlur = config.GetBindable(OsuSetting.SongSelectBackgroundBlur); - configBackgroundBlur.BindValueChanged(e => - { - if (!this.IsCurrentScreen()) - return; - - ApplyToBackground(applyBlurToBackground); - }); - - // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). - transferRulesetValue(); - - AddRangeInternal(new Drawable[] - { - new GlobalScrollAdjustsVolume(), - new VerticalMaskingContainer - { - Children = new Drawable[] - { - new GlobalScrollAdjustsVolume(), - new GridContainer // used for max width implementation - { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.Relative, 0.5f, maxSize: 850), - }, - Content = new[] - { - new Drawable[] - { - wedgeBackground = new ParallaxContainer - { - ParallaxAmount = 0.005f, - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Child = new WedgeBackground - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Right = -150 }, - }, - }, - carouselContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding - { - Top = FilterControl.HEIGHT, - Bottom = Select.Footer.HEIGHT - }, - Child = new LoadingSpinner(true) { State = { Value = Visibility.Visible } } - } - }, - } - }, - FilterControl = CreateFilterControl().With(d => - { - d.RelativeSizeAxes = Axes.X; - d.Height = FilterControl.HEIGHT; - }), - new GridContainer // used for max width implementation - { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.Relative, 0.5f, maxSize: 650), - }, - Content = new[] - { - new Drawable[] - { - LeftArea = new Container - { - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 5 }, - Children = new Drawable[] - { - new LeftSideInteractionContainer(() => Carousel.ScrollToSelected()) - { - RelativeSizeAxes = Axes.Both, - }, - beatmapInfoWedge = new BeatmapInfoWedge - { - Height = WEDGE_HEIGHT, - RelativeSizeAxes = Axes.X, - Margin = new MarginPadding - { - Right = left_area_padding, - Left = -BeatmapInfoWedge.BORDER_THICKNESS, // Hide the left border - }, - }, - new Container - { - RelativeSizeAxes = Axes.X, - Height = 90, - Padding = new MarginPadding(10) - { - Left = left_area_padding, - Right = left_area_padding * 2 + 5, - }, - Y = WEDGE_HEIGHT, - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 10, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Colour4.Black.Opacity(0.3f), - }, - advancedStats = new AdvancedStats(2) - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Padding = new MarginPadding(10), - }, - } - }, - } - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding - { - Bottom = Select.Footer.HEIGHT, - Top = WEDGE_HEIGHT + 70, - Left = left_area_padding, - Right = left_area_padding * 2, - }, - Child = BeatmapDetails = CreateBeatmapDetailArea().With(d => - { - d.RelativeSizeAxes = Axes.Both; - d.Padding = new MarginPadding { Top = 10, Right = 5 }; - }) - }, - } - }, - }, - } - } - } - }, - new SkinnableContainer(new GlobalSkinnableContainerLookup(GlobalSkinnableContainers.SongSelect)) - { - RelativeSizeAxes = Axes.Both, - }, - modSpeedHotkeyHandler = new ModSpeedHotkeyHandler(), - }); - - // Important to load this after the filter control is loaded (so we have initial filter criteria prepared). - LoadComponentAsync(Carousel = new BeatmapCarousel(FilterControl.CreateCriteria()) - { - AllowSelection = false, // delay any selection until our bindables are ready to make a good choice. - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Both, - BleedTop = FilterControl.HEIGHT, - BleedBottom = Select.Footer.HEIGHT, - SelectionChanged = updateSelectedBeatmap, - BeatmapSetsChanged = carouselBeatmapsLoaded, - FilterApplied = () => Scheduler.AddOnce(updateVisibleBeatmapCount), - GetRecommendedBeatmap = s => recommender?.GetRecommendedBeatmap(s), - }, c => carouselContainer.Child = c); - - FilterControl.FilterChanged = criteria => - { - // If a filter operation is applied when we're in a state that doesn't allow selection, - // we might end up in an unexpected state. This is because currently carousel panels are in charge - // of updating the global selection (which is very hard to deal with). - // - // For now let's just avoid filtering when selection isn't allowed locally. - // This should be nuked from existence when we get around to fixing the complexity of song select <-> beatmap carousel. - // The debounce part of BeatmapCarousel's filtering should probably also be removed and handled locally. - if (Carousel.AllowSelection) - Carousel.Filter(criteria); - else - pendingFilterApplication = true; - }; - - if (ShowSongSelectFooter) - { - AddRangeInternal(new Drawable[] - { - FooterPanels = new Container - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Bottom = Select.Footer.HEIGHT }, - Children = new Drawable[] - { - BeatmapOptions = new BeatmapOptionsOverlay(), - } - }, - SongSelectFooter = new Footer() - }); - } - - // preload the mod select overlay for later use in `LoadComplete()`. - // therein it will be registered at the `OsuGame` level to properly function as a blocking overlay. - LoadComponent(ModSelect = CreateModSelectOverlay()); - - if (SongSelectFooter != null) - { - foreach (var (button, overlay) in CreateSongSelectFooterButtons()) - SongSelectFooter.AddButton(button, overlay); - - BeatmapOptions.AddButton(@"Manage", @"collections", FontAwesome.Solid.Book, colours.Green, () => manageCollectionsDialog?.Show()); - BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => DeleteBeatmap(Beatmap.Value.BeatmapSetInfo)); - BeatmapOptions.AddButton(@"Mark", @"as played", FontAwesome.Regular.TimesCircle, colours.Purple, () => beatmaps.MarkPlayed(Beatmap.Value.BeatmapInfo)); - BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, () => ClearScores(Beatmap.Value.BeatmapInfo)); - } - - sampleChangeDifficulty = audio.Samples.Get(@"SongSelect/select-difficulty"); - sampleChangeBeatmap = audio.Samples.Get(@"SongSelect/select-expand"); - SampleConfirm = audio.Samples.Get(@"SongSelect/confirm-selection"); - } - - protected virtual FilterControl CreateFilterControl() => new FilterControl(); - - protected override void LoadComplete() - { - base.LoadComplete(); - - modSelectOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(ModSelect); - } - - protected override bool OnScroll(ScrollEvent e) - { - // Match stable behaviour of only alt-scroll adjusting volume. - // Supporting scroll adjust without a modifier key just feels bad, since there are so many scrollable elements on the screen. - if (!e.CurrentState.Keyboard.AltPressed) - return true; - - return base.OnScroll(e); - } - - /// - /// Creates the buttons to be displayed in the footer. - /// - /// A set of and an optional which the button opens when pressed. - protected virtual IEnumerable<(FooterButton button, OverlayContainer? overlay)> CreateSongSelectFooterButtons() => new (FooterButton, OverlayContainer?)[] - { - (ModsFooterButton = new FooterButtonMods { Current = Mods }, ModSelect), - (new FooterButtonRandom - { - NextRandom = () => Carousel.SelectNextRandom(), - PreviousRandom = Carousel.SelectPreviousRandom - }, null), - (beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions) - }; - - protected virtual ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay - { - ShowPresets = true, - }; - - private DependencyContainer dependencies = null!; - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - dependencies.CacheAs(this); - dependencies.CacheAs(decoupledRuleset); - dependencies.CacheAs>(decoupledRuleset); - - return dependencies; - } - - /// - /// Creates the beatmap details to be displayed underneath the wedge. - /// - protected abstract BeatmapDetailArea CreateBeatmapDetailArea(); - - public void Edit(BeatmapInfo? beatmapInfo = null) - { - if (!AllowEditing) - throw new InvalidOperationException($"Attempted to edit when {nameof(AllowEditing)} is disabled"); - - // Forced refetch is important here to guarantee correct invalidation across all difficulties. - Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo ?? beatmapInfoNoDebounce, true); - - FinaliseSelection(customStartAction: () => this.Push(new EditorLoader())); - } - - /// - /// Set the query to the search text box. - /// - /// The string to search. - public void Search(string query) - { - FilterControl.CurrentTextSearch.Value = query; - } - - /// - /// Call to make a selection and perform the default action for this SongSelect. - /// - /// An optional beatmap to override the current carousel selection. - /// An optional ruleset to override the current carousel selection. - /// An optional custom action to perform instead of . - public void FinaliseSelection(BeatmapInfo? beatmapInfo = null, RulesetInfo? ruleset = null, Action? customStartAction = null) - { - // This is very important as we have not yet bound to screen-level bindables before the carousel load is completed. - if (!Carousel.BeatmapSetsLoaded) - { - Logger.Log($"{nameof(FinaliseSelection)} aborted as carousel beatmaps are not yet loaded"); - return; - } - - if (ruleset != null) - Ruleset.Value = ruleset; - - transferRulesetValue(); - - // while transferRulesetValue will flush, it only does so if the ruleset changes. - // the user could have changed a filter, and we want to ensure we are 100% up-to-date and consistent here. - Carousel.FlushPendingFilterOperations(); - - // avoid attempting to continue before a selection has been obtained. - // this could happen via a user interaction while the carousel is still in a loading state. - if (Carousel.SelectedBeatmapInfo == null) return; - - if (beatmapInfo != null) - Carousel.SelectBeatmap(beatmapInfo); - - if (selectionChangedDebounce?.Completed == false) - { - selectionChangedDebounce.RunTask(); - selectionChangedDebounce?.Cancel(); // cancel the already scheduled task. - selectionChangedDebounce = null; - } - - if (customStartAction != null) - { - customStartAction(); - Carousel.AllowSelection = false; - } - else if (OnStart()) - Carousel.AllowSelection = false; - } - - /// - /// Called when a selection is made. - /// - /// If a resultant action occurred that takes the user away from SongSelect. - protected abstract bool OnStart(); - - private ScheduledDelegate? selectionChangedDebounce; - - private void updateCarouselSelection(ValueChangedEvent e = default) - { - var beatmap = e.NewValue ?? Beatmap.Value; - if (beatmap is DummyWorkingBeatmap || !this.IsCurrentScreen()) return; - - if (beatmap.BeatmapSetInfo.Protected) - { - Logger.Log($"Denying working beatmap switch to protected beatmap {beatmap}"); - Beatmap.Value = e.OldValue; - return; - } - - Logger.Log($"Song select working beatmap updated to {beatmap}"); - - if (!Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) - { - // A selection may not have been possible with filters applied. - - // There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match. - if (!beatmap.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) - { - Ruleset.Value = beatmap.BeatmapInfo.Ruleset; - transferRulesetValue(); - } - - // Even if a ruleset mismatch was not the cause (ie. a text filter is applied), - // we still want to temporarily show the new beatmap, bypassing filters. - // This will be undone the next time the user changes the filter. - var criteria = FilterControl.CreateCriteria(); - criteria.SelectedBeatmapSet = beatmap.BeatmapInfo.BeatmapSet; - Carousel.Filter(criteria); - - Carousel.SelectBeatmap(beatmap.BeatmapInfo); - } - } - - // We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds. - private BeatmapInfo? beatmapInfoPrevious; - private BeatmapInfo? beatmapInfoNoDebounce; - private RulesetInfo? rulesetNoDebounce; - - private void updateSelectedBeatmap(BeatmapInfo? beatmapInfo) - { - if (beatmapInfo == null && beatmapInfoNoDebounce == null) - return; - - if (beatmapInfo?.Equals(beatmapInfoNoDebounce) == true) - return; - - beatmapInfoNoDebounce = beatmapInfo; - performUpdateSelected(); - } - - private void updateSelectedRuleset(RulesetInfo? ruleset) - { - if (ruleset == null && rulesetNoDebounce == null) - return; - - if (ruleset?.Equals(rulesetNoDebounce) == true) - return; - - rulesetNoDebounce = ruleset; - performUpdateSelected(); - } - - /// - /// Selection has been changed as the result of a user interaction. - /// - private void performUpdateSelected() - { - var beatmap = beatmapInfoNoDebounce; - RulesetInfo? ruleset = rulesetNoDebounce; - - selectionChangedDebounce?.Cancel(); - - if (beatmapInfoNoDebounce == null) - run(); - else - { - // Intentionally slightly higher than repeat_tick_rate to avoid loading songs when holding left / right arrows. - // See https://github.com/ppy/osu-framework/blob/master/osu.Framework/Input/InputManager.cs#L44 - selectionChangedDebounce = Scheduler.AddDelayed(run, 80); - } - - if (beatmap?.Equals(beatmapInfoPrevious) != true) - { - if (beatmap != null && beatmapInfoPrevious != null && Time.Current - audioFeedbackLastPlaybackTime >= 50) - { - if (beatmap.BeatmapSet?.ID == beatmapInfoPrevious.BeatmapSet?.ID) - sampleChangeDifficulty.Play(); - else - sampleChangeBeatmap.Play(); - - audioFeedbackLastPlaybackTime = Time.Current; - } - - beatmapInfoPrevious = beatmap; - } - - void run() - { - // clear pending task immediately to track any potential nested debounce operation. - selectionChangedDebounce = null; - - Logger.Log($"Song select updating selection with beatmap: {beatmap} {beatmap?.ID.ToString() ?? "null"} ruleset:{ruleset?.ShortName ?? "null"}"); - - if (transferRulesetValue()) - { - // transferRulesetValue() may trigger a re-filter. If the current selection does not match the new ruleset, we want to switch away from it. - // The default logic on WorkingBeatmap change is to switch to a matching ruleset (see workingBeatmapChanged()), but we don't want that here. - // We perform an early selection attempt and clear out the beatmap selection to avoid a second ruleset change (revert). - if (beatmap != null && !Carousel.SelectBeatmap(beatmap, false)) - beatmap = null; - } - - if (selectionChangedDebounce != null) - { - // a new nested operation was started; switch to it for further selection. - // this avoids having two separate debounces trigger from the same source. - selectionChangedDebounce.RunTask(); - return; - } - - // We may be arriving here due to another component changing the bindable Beatmap. - // In these cases, the other component has already loaded the beatmap, so we don't need to do so again. - if (!EqualityComparer.Default.Equals(beatmap, Beatmap.Value.BeatmapInfo)) - { - Logger.Log($"Song select changing beatmap from \"{Beatmap.Value.BeatmapInfo}\" to \"{beatmap?.ToString() ?? "null"}\""); - Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); - } - - if (this.IsCurrentScreen()) - ensurePlayingSelected(); - - updateComponentFromBeatmap(Beatmap.Value); - } - } - - public override void OnEntering(ScreenTransitionEvent e) - { - base.OnEntering(e); - - this.FadeInFromZero(250); - FilterControl.Activate(); - - ModSelect.SelectedMods.BindTo(selectedMods); - - beginLooping(); - } - - private const double logo_transition = 250; - - protected override void LogoArriving(OsuLogo logo, bool resuming) - { - base.LogoArriving(logo, resuming); - - logo.RelativePositionAxes = Axes.None; - logo.ChangeAnchor(Anchor.BottomRight); - - Vector2 position = new Vector2(-76, -36); - - if (logo.Alpha > 0.8f) - { - logo.MoveTo(position, 500, Easing.OutQuint); - } - else - { - logo.Hide(); - logo.ScaleTo(0.2f); - logo.MoveTo(position); - } - - logo.FadeIn(logo_transition, Easing.OutQuint); - logo.ScaleTo(0.4f, logo_transition, Easing.OutQuint); - - logo.Action = () => - { - if (this.IsCurrentScreen()) - FinaliseSelection(); - return false; - }; - } - - protected override void LogoExiting(OsuLogo logo) - { - base.LogoExiting(logo); - logo.ScaleTo(0.2f, logo_transition / 2, Easing.Out); - logo.FadeOut(logo_transition / 2, Easing.Out); - } - - public override void OnResuming(ScreenTransitionEvent e) - { - base.OnResuming(e); - - // required due to https://github.com/ppy/osu-framework/issues/3218 - ModSelect.SelectedMods.Disabled = false; - ModSelect.SelectedMods.BindTo(selectedMods); - - Carousel.AllowSelection = true; - - BeatmapDetails.Refresh(); - - beginLooping(); - - if (!Beatmap.Value.BeatmapSetInfo.DeletePending) - { - updateCarouselSelection(); - - updateComponentFromBeatmap(Beatmap.Value); - - if (ControlGlobalMusic) - { - // restart playback on returning to song select, regardless. - // not sure this should be a permanent thing (we may want to leave a user pause paused even on returning) - music.ResetTrackAdjustments(); - music.Play(requestedByUser: true); - } - } - - LeftArea.MoveToX(0, 400, Easing.OutQuint); - LeftArea.FadeIn(100, Easing.OutQuint); - - FilterControl.MoveToY(0, 400, Easing.OutQuint); - FilterControl.FadeIn(100, Easing.OutQuint); - - this.FadeIn(250, Easing.OutQuint); - - wedgeBackground.ScaleTo(1, 500, Easing.OutQuint); - - FilterControl.Activate(); - } - - protected override void Update() - { - base.Update(); - - if (Carousel.AllowSelection && pendingFilterApplication) - { - Carousel.Filter(FilterControl.CreateCriteria()); - pendingFilterApplication = false; - } - } - - public override void OnSuspending(ScreenTransitionEvent e) - { - // Handle the case where FinaliseSelection is never called (ie. when a screen is pushed externally). - // Without this, it's possible for a transfer to happen while we are not the current screen. - transferRulesetValue(); - - ModSelect.SelectedMods.UnbindFrom(selectedMods); - - playExitingTransition(); - base.OnSuspending(e); - } - - public override bool OnExiting(ScreenExitEvent e) - { - if (base.OnExiting(e)) - return true; - - playExitingTransition(); - return false; - } - - private void playExitingTransition() - { - ModSelect.Hide(); - - BeatmapOptions.Hide(); - - Carousel.AllowSelection = false; - - endLooping(); - - FilterControl.MoveToY(-120, 500, Easing.OutQuint); - FilterControl.FadeOut(200, Easing.OutQuint); - - LeftArea.MoveToX(-150, 1800, Easing.OutQuint); - LeftArea.FadeOut(200, Easing.OutQuint); - - wedgeBackground.ScaleTo(2.4f, 400, Easing.OutQuint); - - this.FadeOut(400, Easing.OutQuint); - - FilterControl.Deactivate(); - } - - private bool isHandlingLooping; - - private void beginLooping() - { - if (!ControlGlobalMusic) - return; - - Debug.Assert(!isHandlingLooping); - - isHandlingLooping = true; - - ensureTrackLooping(Beatmap.Value, TrackChangeDirection.None); - - music.TrackChanged += ensureTrackLooping; - } - - private void endLooping() - { - // may be called multiple times during screen exit process. - if (!isHandlingLooping) - return; - - music.CurrentTrack.Looping = isHandlingLooping = false; - - music.TrackChanged -= ensureTrackLooping; - } - - private void ensureTrackLooping(IWorkingBeatmap beatmap, TrackChangeDirection changeDirection) - => beatmap.PrepareTrackForPreview(true); - - public override bool OnBackButton() - { - if (ModSelect.State.Value == Visibility.Visible) - { - ModSelect.Hide(); - return true; - } - - return false; - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - decoupledRuleset.UnbindAll(); - - if (music.IsNotNull()) - music.TrackChanged -= ensureTrackLooping; - - modSelectOverlayRegistration?.Dispose(); - } - - /// - /// Allow components in SongSelect to update their loaded beatmap details. - /// This is a debounced call (unlike directly binding to WorkingBeatmap.ValueChanged). - /// - /// The working beatmap. - private void updateComponentFromBeatmap(WorkingBeatmap beatmap) - { - // If not the current screen, this will be applied in OnResuming. - if (this.IsCurrentScreen()) - { - ApplyToBackground(backgroundModeBeatmap => - { - backgroundModeBeatmap.Beatmap = beatmap; - backgroundModeBeatmap.IgnoreUserSettings.Value = true; - backgroundModeBeatmap.FadeColour(Color4.White, 250); - - applyBlurToBackground(backgroundModeBeatmap); - }); - } - - beatmapInfoWedge.Beatmap = beatmap; - - BeatmapDetails.Beatmap = beatmap; - - ModSelect.Beatmap.Value = beatmap; - - advancedStats.BeatmapInfo = beatmap.BeatmapInfo; - advancedStats.Mods.Value = selectedMods.Value; - advancedStats.Ruleset.Value = Ruleset.Value; - - bool beatmapSelected = beatmap is not DummyWorkingBeatmap; - - if (beatmapSelected) - beatmapOptionsButton.Enabled.Value = true; - else - { - beatmapOptionsButton.Enabled.Value = false; - BeatmapOptions.Hide(); - } - } - - private void applyBlurToBackground(BackgroundScreenBeatmap backgroundModeBeatmap) - { - backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value ? BACKGROUND_BLUR : 0f; - backgroundModeBeatmap.DimWhenUserSettingsIgnored.Value = configBackgroundBlur.Value ? 0 : 0.4f; - - wedgeBackground.FadeTo(configBackgroundBlur.Value ? 0.5f : 0.2f, UserDimContainer.BACKGROUND_FADE_DURATION, Easing.OutQuint); - } - - private readonly WeakReference lastTrack = new WeakReference(null); - - /// - /// Ensures some music is playing for the current track. - /// Will resume playback from a manual user pause if the track has changed. - /// - private void ensurePlayingSelected() - { - if (!ControlGlobalMusic) - return; - - ITrack track = music.CurrentTrack; - - bool isNewTrack = !lastTrack.TryGetTarget(out var last) || last != track; - - if (!track.IsRunning && (music.UserPauseRequested != true || isNewTrack)) - { - Logger.Log($"Song select decided to {nameof(ensurePlayingSelected)}"); - music.Play(true); - } - - lastTrack.SetTarget(track); - } - - private void carouselBeatmapsLoaded() - { - bindBindables(); - Scheduler.AddOnce(updateVisibleBeatmapCount); - - Carousel.AllowSelection = true; - - // If a selection was already obtained, do not attempt to update the selected beatmap. - if (Carousel.SelectedBeatmapSet != null) - return; - - // Attempt to select the current beatmap on the carousel, if it is valid to be selected. - if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false) - { - if (Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false)) - return; - - // prefer not changing ruleset at this point, so look for another difficulty in the currently playing beatmap - var found = Beatmap.Value.BeatmapSetInfo.Beatmaps.FirstOrDefault(b => b.Ruleset.Equals(decoupledRuleset.Value)); - - if (found != null && Carousel.SelectBeatmap(found, false)) - return; - } - - // If the current active beatmap could not be selected, select a new random beatmap. - if (!Carousel.SelectNextRandom()) - { - // in the case random selection failed, we want to trigger selectionChanged - // to show the dummy beatmap (we have nothing else to display). - performUpdateSelected(); - } - } - - private void updateVisibleBeatmapCount() - { - // Intentionally not localised until we have proper support for this (see https://github.com/ppy/osu-framework/pull/4918 - // but also in this case we want support for formatting a number within a string). - int carouselCountDisplayed = Carousel.CountDisplayed; - FilterControl.InformationalText = carouselCountDisplayed != 1 ? $"{carouselCountDisplayed:#,0} matches" : $"{carouselCountDisplayed:#,0} match"; - } - - private bool boundLocalBindables; - - private void bindBindables() - { - if (boundLocalBindables) - return; - - // manual binding to parent ruleset to allow for delayed load in the incoming direction. - transferRulesetValue(); - - Ruleset.ValueChanged += r => updateSelectedRuleset(r.NewValue); - - decoupledRuleset.ValueChanged += r => - { - bool wasDisabled = Ruleset.Disabled; - - // a sub-screen may have taken a lease on this decoupled ruleset bindable, - // which would indirectly propagate to the game-global bindable via the `DisabledChanged` callback below. - // to make sure changes sync without crashes, lift the disable for a short while to sync, and then restore the old value. - Ruleset.Disabled = false; - Ruleset.Value = r.NewValue; - Ruleset.Disabled = wasDisabled; - }; - decoupledRuleset.DisabledChanged += r => Ruleset.Disabled = r; - - Beatmap.BindValueChanged(updateCarouselSelection); - - selectedMods.BindValueChanged(_ => - { - if (decoupledRuleset.Value.Equals(rulesetNoDebounce)) - advancedStats.Mods.Value = selectedMods.Value; - }, true); - - boundLocalBindables = true; - } - - /// - /// Transfer the game-wide ruleset to the local decoupled ruleset. - /// Will immediately run filter operations if required. - /// - /// Whether a transfer occurred. - private bool transferRulesetValue() - { - if (decoupledRuleset.Value?.Equals(Ruleset.Value) == true) - return false; - - Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); - rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; - - // if we have a pending filter operation, we want to run it now. - // it could change selection (ie. if the ruleset has been changed). - if (IsLoaded) - Carousel.FlushPendingFilterOperations(); - - return true; - } - - /// - /// Request to delete a specific beatmap. - /// - public void DeleteBeatmap(BeatmapSetInfo? beatmap) - { - if (beatmap == null) return; - - dialogOverlay?.Push(new BeatmapDeleteDialog(beatmap)); - } - - /// - /// Request to clear the scores of a specific beatmap. - /// - public void ClearScores(BeatmapInfo? beatmapInfo) - { - if (beatmapInfo == null) return; - - dialogOverlay?.Push(new BeatmapClearScoresDialog(beatmapInfo, () => - // schedule done here rather than inside the dialog as the dialog may fade out and never callback. - Schedule(() => BeatmapDetails.Refresh()))); - } - - public virtual bool OnPressed(KeyBindingPressEvent e) - { - if (!this.IsCurrentScreen()) return false; - - switch (e.Action) - { - case GlobalAction.IncreaseModSpeed: - return modSpeedHotkeyHandler.ChangeSpeed(0.05, ModUtils.FlattenMods(game.AvailableMods.Value.SelectMany(kv => kv.Value))); - - case GlobalAction.DecreaseModSpeed: - return modSpeedHotkeyHandler.ChangeSpeed(-0.05, ModUtils.FlattenMods(game.AvailableMods.Value.SelectMany(kv => kv.Value))); - } - - if (e.Repeat) - return false; - - switch (e.Action) - { - case GlobalAction.Select: - FinaliseSelection(); - return true; - } - - return false; - } - - public void OnReleased(KeyBindingReleaseEvent e) - { - } - - protected override bool OnKeyDown(KeyDownEvent e) - { - if (e.Repeat) return false; - - switch (e.Key) - { - case Key.Delete: - if (e.ShiftPressed) - { - if (!Beatmap.IsDefault) - DeleteBeatmap(Beatmap.Value.BeatmapSetInfo); - return true; - } - - break; - } - - return base.OnKeyDown(e); - } - - private partial class VerticalMaskingContainer : Container - { - private const float panel_overflow = 1.2f; - - protected override Container Content { get; } - - public VerticalMaskingContainer() - { - RelativeSizeAxes = Axes.Both; - Masking = true; - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - Width = panel_overflow; // avoid horizontal masking so the panels don't clip when screen stack is pushed. - InternalChild = Content = new OsuContextMenuContainer - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Width = 1 / panel_overflow, - }; - } - } - - /// - /// Handles mouse interactions required when moving away from the carousel. - /// - internal partial class LeftSideInteractionContainer : Container - { - private readonly Action? resetCarouselPosition; - - private bool mouseContained; - - private InputManager inputManager = null!; - - public LeftSideInteractionContainer(Action resetCarouselPosition) - { - this.resetCarouselPosition = resetCarouselPosition; - } - - // we want to block plain scrolls on the left side so that they don't scroll the carousel, - // but also we *don't* want to handle scrolls when they're combined with keyboard modifiers - // as those will usually correspond to other interactions like adjusting volume. - protected override bool OnScroll(ScrollEvent e) => !e.ControlPressed && !e.AltPressed && !e.ShiftPressed && !e.SuperPressed; - - protected override bool OnMouseDown(MouseDownEvent e) => true; - - protected override void LoadComplete() - { - inputManager = GetContainingInputManager()!; - base.LoadComplete(); - } - - protected override void Update() - { - base.Update(); - - // We want to trigger an action whenever the cursor is in the left area of song select. - // Other elements in song select handle input, so rather than using `OnHover` let's check the true mouse position. - if (Contains(inputManager.CurrentState.Mouse.Position)) - { - if (!mouseContained) - { - mouseContained = true; - resetCarouselPosition?.Invoke(); - } - } - else - { - mouseContained = false; - } - } - } - } -} diff --git a/osu.Game/Screens/Select/WedgeBackground.cs b/osu.Game/Screens/Select/WedgeBackground.cs deleted file mode 100644 index 2e2b43cd70da..000000000000 --- a/osu.Game/Screens/Select/WedgeBackground.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Select -{ - public partial class WedgeBackground : Container - { - public WedgeBackground() - { - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Size = new Vector2(1, 0.5f), - Colour = Color4.Black, - Shear = new Vector2(0.15f, 0), - EdgeSmoothness = new Vector2(2, 0), - }, - new Box - { - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Y, - Size = new Vector2(1, -0.5f), - Position = new Vector2(0, 1), - Colour = Color4.Black, - Shear = new Vector2(-0.15f, 0), - EdgeSmoothness = new Vector2(2, 0), - }, - }; - } - } -} diff --git a/osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs b/osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs new file mode 100644 index 000000000000..212bb233f487 --- /dev/null +++ b/osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs @@ -0,0 +1,60 @@ +// 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 osu.Framework.Graphics.Containers; +using osu.Framework.Input; +using osu.Framework.Input.Events; + +namespace osu.Game.Screens.SelectV2 +{ + /// + /// Handles mouse interactions required when moving away from the carousel. + /// + internal partial class LeftSideInteractionContainer : Container + { + private readonly Action? resetCarouselPosition; + + private bool mouseContained; + + private InputManager inputManager = null!; + + public LeftSideInteractionContainer(Action resetCarouselPosition) + { + this.resetCarouselPosition = resetCarouselPosition; + } + + // we want to block plain scrolls on the left side so that they don't scroll the carousel, + // but also we *don't* want to handle scrolls when they're combined with keyboard modifiers + // as those will usually correspond to other interactions like adjusting volume. + protected override bool OnScroll(ScrollEvent e) => !e.ControlPressed && !e.AltPressed && !e.ShiftPressed && !e.SuperPressed; + + protected override bool OnMouseDown(MouseDownEvent e) => true; + + protected override void LoadComplete() + { + inputManager = GetContainingInputManager()!; + base.LoadComplete(); + } + + protected override void Update() + { + base.Update(); + + // We want to trigger an action whenever the cursor is in the left area of song select. + // Other elements in song select handle input, so rather than using `OnHover` let's check the true mouse position. + if (Contains(inputManager.CurrentState.Mouse.Position)) + { + if (!mouseContained) + { + mouseContained = true; + resetCarouselPosition?.Invoke(); + } + } + else + { + mouseContained = false; + } + } + } +} diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index b12d6d1018f1..d47155ee6b16 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -61,7 +61,7 @@ namespace osu.Game.Screens.SelectV2 { /// /// This screen is intended to house all components introduced in the new song select design to add transitions and examine the overall look. - /// This will be gradually built upon and ultimately replace once everything is in place. + /// This will be gradually built upon and ultimately replace once everything is in place. /// public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler, ISongSelect, IHandlePresentBeatmap, IProvideCursor { @@ -228,7 +228,7 @@ private void load(AudioManager audio, OsuConfigManager config) // Pad enough to only reset scroll when well into the left wedge areas. Padding = new MarginPadding { Right = 40 }, RelativeSizeAxes = Axes.Both, - Child = new Select.SongSelect.LeftSideInteractionContainer(() => carousel.ScrollToSelection()) + Child = new LeftSideInteractionContainer(() => carousel.ScrollToSelection()) { RelativeSizeAxes = Axes.Both, }, From 7e7421e1ea741427378715cea7a155ec5104b261 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 19:29:45 +0900 Subject: [PATCH 737/836] Update `TestSceneDeleteLocalScore` to use newer leaderboard --- .../TestSceneDeleteLocalScore.cs | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index c2277f2c7ce6..5eec60e9ec40 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -26,7 +26,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osuTK; using osuTK.Input; @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.UserInterface public partial class TestSceneDeleteLocalScore : OsuManualInputManagerTestScene { private readonly ContextMenuContainer contextMenuContainer; - private readonly BeatmapLeaderboard leaderboard; + private readonly BeatmapLeaderboardWedge leaderboard; private RulesetStore rulesets = null!; private BeatmapManager beatmapManager; @@ -46,9 +46,16 @@ public partial class TestSceneDeleteLocalScore : OsuManualInputManagerTestScene private BeatmapInfo beatmapInfo; + private LeaderboardManager leaderboardManager { get; set; } + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + [Cached(typeof(IDialogOverlay))] private readonly DialogOverlay dialogOverlay; + private IEnumerable scores => leaderboardManager.Scores.Value?.AllScores ?? Enumerable.Empty(); + public TestSceneDeleteLocalScore() { Children = new Drawable[] @@ -56,13 +63,11 @@ public TestSceneDeleteLocalScore() contextMenuContainer = new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, - Child = leaderboard = new BeatmapLeaderboard + Child = leaderboard = new BeatmapLeaderboardWedge { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Size = new Vector2(550f, 450f), - Scope = BeatmapLeaderboardScope.Local, - BeatmapInfo = TestResources.CreateTestBeatmapSetInfo().Beatmaps.First() + Size = new Vector2(0.6f), } }, dialogOverlay = new DialogOverlay() @@ -76,8 +81,11 @@ protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnl dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default)); dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get(), () => beatmapManager, LocalStorage, Realm, API)); + dependencies.Cache(leaderboardManager = new LeaderboardManager()); Dependencies.Cache(Realm); + Add(leaderboardManager); + return dependencies; } @@ -125,13 +133,13 @@ public void SetupSteps() }); AddStep("set up leaderboard", () => { - leaderboard.BeatmapInfo = beatmapInfo; - leaderboard.RefetchScores(); // Required in the case that the beatmap hasn't changed + Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapInfo); + leaderboard.Show(); }); // Ensure the leaderboard items have finished showing up AddStep("finish transforms", () => leaderboard.FinishTransforms(true)); - AddUntilStep("wait for drawables", () => leaderboard.ChildrenOfType().Any()); + AddUntilStep("wait for drawables", () => leaderboard.ChildrenOfType().Any()); } [Test] @@ -140,7 +148,7 @@ public void TestDeleteViaRightClick() ScoreInfo scoreBeingDeleted = null; AddStep("open menu for top score", () => { - var leaderboardScore = leaderboard.ChildrenOfType().First(); + var leaderboardScore = leaderboard.ChildrenOfType().First(); scoreBeingDeleted = leaderboardScore.Score; @@ -167,8 +175,8 @@ public void TestDeleteViaRightClick() InputManager.PressButton(MouseButton.Left); }); - AddUntilStep("wait for fetch", () => leaderboard.Scores.Any()); - AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != scoreBeingDeleted.OnlineID)); + AddUntilStep("wait for fetch", () => scores.Any()); + AddUntilStep("score removed from leaderboard", () => scores.All(s => s.OnlineID != scoreBeingDeleted.OnlineID)); // "Clean up" AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left)); @@ -178,8 +186,8 @@ public void TestDeleteViaRightClick() public void TestDeleteViaDatabase() { AddStep("delete top score", () => scoreManager.Delete(importedScores[0])); - AddUntilStep("wait for fetch", () => leaderboard.Scores.Any()); - AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != importedScores[0].OnlineID)); + AddUntilStep("wait for fetch", () => scores.Any()); + AddUntilStep("score removed from leaderboard", () => scores.All(s => s.OnlineID != importedScores[0].OnlineID)); } protected override void Dispose(bool isDisposing) From b4f40639a1ab5e2eb1120f7c6f43448f0977ee27 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 19:37:19 +0900 Subject: [PATCH 738/836] Add special not regarding collection dropdown --- .../TestSceneCollectionDropdown.cs | 7 +- osu.Game/Collections/CollectionDropdown.cs | 1 + osu.Game/Screens/Select/CollectionDropdown.cs | 257 ++++++++++++++++++ 3 files changed, 263 insertions(+), 2 deletions(-) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneCollectionDropdown.cs (97%) create mode 100644 osu.Game/Screens/Select/CollectionDropdown.cs diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneCollectionDropdown.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs similarity index 97% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneCollectionDropdown.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs index 8cee78e0b8d2..e1c39ce4f24d 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneCollectionDropdown.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs @@ -24,10 +24,13 @@ using osu.Game.Tests.Resources; using osuTK.Input; using Realms; -using CollectionDropdown = osu.Game.Screens.SelectV2.CollectionDropdown; +using CollectionDropdown = osu.Game.Screens.Select.CollectionDropdown; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { + /// + /// WARNING: TODO: we have TWO `CollectionDropdowns` with diverging functionality. This is not good. + /// public partial class TestSceneCollectionDropdown : OsuManualInputManagerTestScene { private RulesetStore rulesets = null!; diff --git a/osu.Game/Collections/CollectionDropdown.cs b/osu.Game/Collections/CollectionDropdown.cs index 2f9e94fef7b4..e9fec32e1213 100644 --- a/osu.Game/Collections/CollectionDropdown.cs +++ b/osu.Game/Collections/CollectionDropdown.cs @@ -24,6 +24,7 @@ namespace osu.Game.Collections { /// /// A dropdown to select the collection to be used to filter results. + /// WARNING: TODO: we have TWO `CollectionDropdowns` with diverging functionality. This is not good. /// public partial class CollectionDropdown : OsuDropdown { diff --git a/osu.Game/Screens/Select/CollectionDropdown.cs b/osu.Game/Screens/Select/CollectionDropdown.cs new file mode 100644 index 000000000000..ee2263754104 --- /dev/null +++ b/osu.Game/Screens/Select/CollectionDropdown.cs @@ -0,0 +1,257 @@ +// 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.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; +using osu.Game.Collections; +using osu.Game.Database; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Localisation; +using osuTK; +using Realms; + +namespace osu.Game.Screens.Select +{ + /// + /// A dropdown to select the collection to be used to filter results. + /// WARNING: TODO: we have TWO `CollectionDropdowns` with diverging functionality. This is not good. + /// + public partial class CollectionDropdown : ShearedDropdown // TODO: partial class under FilterControl? + { + /// + /// Whether to show the "manage collections..." menu item in the dropdown. + /// + protected virtual bool ShowManageCollectionsItem => true; + + private readonly BindableList filters = new BindableList(); + + [Resolved] + private ManageCollectionsDialog? manageCollectionsDialog { get; set; } + + [Resolved] + private RealmAccess realm { get; set; } = null!; + + private IDisposable? realmSubscription; + + private readonly CollectionFilterMenuItem allBeatmapsItem = new AllBeatmapsCollectionFilterMenuItem(); + + public CollectionDropdown() + : base(CollectionsStrings.Collection) + { + ItemSource = filters; + + Current.Value = allBeatmapsItem; + AlwaysShowSearchBar = true; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + realmSubscription = realm.RegisterForNotifications(r => r.All().OrderBy(c => c.Name), collectionsChanged); + + Current.BindValueChanged(selectionChanged); + } + + private void collectionsChanged(IRealmCollection collections, ChangeSet? changes) + { + if (changes == null) + { + filters.Clear(); + filters.Add(allBeatmapsItem); + filters.AddRange(collections.Select(c => new CollectionFilterMenuItem(c.ToLive(realm)))); + if (ShowManageCollectionsItem) + filters.Add(new ManageCollectionsFilterMenuItem()); + } + else + { + foreach (int i in changes.DeletedIndices.OrderDescending()) + filters.RemoveAt(i + 1); + + foreach (int i in changes.InsertedIndices) + filters.Insert(i + 1, new CollectionFilterMenuItem(collections[i].ToLive(realm))); + + var selectedItem = SelectedItem?.Value; + + foreach (int i in changes.NewModifiedIndices) + { + var updatedItem = collections[i]; + + // This is responsible for updating the state of the +/- button and the collection's name. + // TODO: we can probably make the menu items update with changes to avoid this. + filters.RemoveAt(i + 1); + filters.Insert(i + 1, new CollectionFilterMenuItem(updatedItem.ToLive(realm))); + + if (updatedItem.ID == selectedItem?.Collection?.ID) + { + // This current update and schedule is required to work around dropdown headers not updating text even when the selected item + // changes. It's not great but honestly the whole dropdown menu structure isn't great. This needs to be fixed, but I'll issue + // a warning that it's going to be a frustrating journey. + Current.Value = allBeatmapsItem; + Schedule(() => + { + // current may have changed before the scheduled call is run. + if (Current.Value != allBeatmapsItem) + return; + + Current.Value = filters.SingleOrDefault(f => f.Collection?.ID == selectedItem.Collection?.ID) ?? filters[0]; + }); + + break; + } + } + } + } + + private void selectionChanged(ValueChangedEvent filter) + { + // May be null during .Clear(). + if (filter.NewValue.IsNull()) + return; + + // Never select the manage collection filter - rollback to the previous filter. + // This is done after the above since it is important that bindable is unbound from OldValue, which is lost after forcing it back to the old value. + if (filter.NewValue is ManageCollectionsFilterMenuItem) + { + Current.Value = filter.OldValue; + manageCollectionsDialog?.Show(); + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + realmSubscription?.Dispose(); + } + + protected override LocalisableString GenerateItemText(CollectionFilterMenuItem item) => item.CollectionName; + + protected sealed override DropdownMenu CreateMenu() => CreateCollectionMenu(); + + protected virtual ShearedCollectionDropdownMenu CreateCollectionMenu() => new ShearedCollectionDropdownMenu(); + + protected partial class ShearedCollectionDropdownMenu : ShearedDropdownMenu + { + public ShearedCollectionDropdownMenu() + { + MaxHeight = 200; + } + + protected override DrawableDropdownMenuItem CreateDrawableDropdownMenuItem(MenuItem item) => new DrawableCollectionMenuItem(item) + { + BackgroundColourHover = HoverColour, + BackgroundColourSelected = SelectionColour + }; + } + + protected partial class DrawableCollectionMenuItem : ShearedDropdownMenu.ShearedMenuItem + { + private IconButton addOrRemoveButton = null!; + + private bool beatmapInCollection; + + private readonly Live? collection; + + [Resolved] + private IBindable beatmap { get; set; } = null!; + + public DrawableCollectionMenuItem(MenuItem item) + : base(item) + { + collection = ((DropdownMenuItem)item).Value.Collection; + } + + [BackgroundDependencyLoader] + private void load() + { + AddInternal(addOrRemoveButton = new NoFocusChangeIconButton + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Shear = -OsuGame.SHEAR, + X = -OsuScrollContainer.SCROLL_BAR_WIDTH, + Scale = new Vector2(0.65f), + Action = addOrRemove, + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + if (collection != null) + { + beatmap.BindValueChanged(_ => + { + beatmapInCollection = collection.PerformRead(c => c.BeatmapMD5Hashes.Contains(beatmap.Value.BeatmapInfo.MD5Hash)); + + addOrRemoveButton.Enabled.Value = !beatmap.IsDefault; + addOrRemoveButton.Icon = beatmapInCollection ? FontAwesome.Solid.MinusSquare : FontAwesome.Solid.PlusSquare; + addOrRemoveButton.TooltipText = beatmapInCollection ? CollectionsStrings.RemoveSelectedBeatmap : CollectionsStrings.AddSelectedBeatmap; + + updateButtonVisibility(); + }, true); + } + + updateButtonVisibility(); + } + + protected override bool OnHover(HoverEvent e) + { + updateButtonVisibility(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateButtonVisibility(); + base.OnHoverLost(e); + } + + protected override void OnSelectChange() + { + base.OnSelectChange(); + updateButtonVisibility(); + } + + private void updateButtonVisibility() + { + if (collection == null) + addOrRemoveButton.Alpha = 0; + else + addOrRemoveButton.Alpha = IsHovered || IsPreSelected || beatmapInCollection ? 1 : 0; + } + + private void addOrRemove() + { + Debug.Assert(collection != null); + + Task.Run(() => collection.PerformWrite(c => + { + if (!c.BeatmapMD5Hashes.Remove(beatmap.Value.BeatmapInfo.MD5Hash)) + c.BeatmapMD5Hashes.Add(beatmap.Value.BeatmapInfo.MD5Hash); + })); + } + + protected override Drawable CreateContent() => (Content)base.CreateContent(); + + private partial class NoFocusChangeIconButton : IconButton + { + public override bool ChangeFocusOnClick => false; + } + } + } +} From c28c64940aeb21bff5429c8f32f664b8e5931394 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 19:39:45 +0900 Subject: [PATCH 739/836] Move v2 files to final location This contains only renames and namespace updates. --- .../NonVisual/Filtering/FilterMatchingTest.cs | 1 - .../Background/TestSceneUserDimBackgrounds.cs | 2 +- .../DailyChallenge/TestSceneDailyChallenge.cs | 2 +- .../Visual/Editing/TestSceneEditorSaving.cs | 2 +- .../Editing/TestSceneOpenEditorTimestamp.cs | 2 +- .../Visual/Multiplayer/QueueModeTestScene.cs | 4 +- .../Multiplayer/TestSceneHostOnlyQueueMode.cs | 4 +- .../TestSceneBeatmapEditorNavigation.cs | 2 +- .../TestSceneButtonSystemNavigation.cs | 2 +- .../TestSceneChangeAndUseGameplayBindings.cs | 2 +- .../TestSceneMouseWheelVolumeAdjust.cs | 2 +- .../Navigation/TestScenePerformFromScreen.cs | 2 +- .../Navigation/TestScenePresentBeatmap.cs | 2 +- .../Navigation/TestScenePresentScore.cs | 4 +- .../Navigation/TestSceneScreenNavigation.cs | 29 +- .../TestSceneSkinEditorNavigation.cs | 2 +- .../TestSceneSongSelectNavigation.cs | 8 +- .../BeatmapCarouselFilterGroupingTest.cs | 3 +- .../BeatmapCarouselFilterSortingTest.cs | 3 +- .../BeatmapCarouselTestScene.cs | 4 +- .../SongSelectComponentsTestScene.cs | 2 +- .../SongSelectTestScene.cs | 6 +- .../TestSceneBeatmapCarousel.cs | 4 +- .../TestSceneBeatmapCarouselArtistGrouping.cs | 4 +- ...tSceneBeatmapCarouselCollectionGrouping.cs | 2 +- ...tSceneBeatmapCarouselDifficultyGrouping.cs | 4 +- .../TestSceneBeatmapCarouselFiltering.cs | 4 +- .../TestSceneBeatmapCarouselNoGrouping.cs | 4 +- .../TestSceneBeatmapCarouselRandom.cs | 4 +- .../TestSceneBeatmapCarouselScrolling.cs | 4 +- .../TestSceneBeatmapCarouselSetsSplitApart.cs | 4 +- .../TestSceneBeatmapCarouselUpdateHandling.cs | 4 +- .../TestSceneBeatmapFilterControl.cs | 4 +- .../TestSceneBeatmapLeaderboardScore.cs | 4 +- .../TestSceneBeatmapLeaderboardSorting.cs | 6 +- .../TestSceneBeatmapLeaderboardWedge.cs | 4 +- .../TestSceneBeatmapMetadataWedge.cs | 24 +- .../TestSceneBeatmapRecommendations.cs | 2 +- .../TestSceneBeatmapTitleWedge.cs | 47 +++- .../TestSceneBeatmapTitleWedgeStatistic.cs | 4 +- .../TestSceneDifficultyRangeSlider.cs | 4 +- .../TestSceneDifficultyStatisticsDisplay.cs | 4 +- .../TestSceneFooterButtonMods.cs | 4 +- .../TestScenePanelBeatmap.cs | 4 +- .../TestScenePanelBeatmapStandalone.cs | 4 +- .../TestScenePanelGroup.cs | 6 +- .../TestScenePanelSet.cs | 4 +- .../TestScenePanelUpdateBeatmapButton.cs | 4 +- .../TestSceneSongSelect.cs | 13 +- ...neSongSelectCurrentSelectionInvalidated.cs | 6 +- .../TestSceneSongSelectFiltering.cs | 8 +- .../TestSceneSongSelectGrouping.cs | 4 +- .../UserInterface/TestSceneScreenFooter.cs | 2 +- osu.Game/Beatmaps/BeatmapMetadata.cs | 2 +- .../Online/Leaderboards/LeaderboardScore.cs | 2 +- osu.Game/OsuGame.cs | 2 +- .../Overlays/FirstRunSetup/ScreenUIScale.cs | 2 +- .../Overlays/SkinEditor/SkinEditorOverlay.cs | 2 +- .../SkinEditor/SkinEditorSceneLibrary.cs | 2 +- .../Submission/BeatmapSubmissionScreen.cs | 2 +- osu.Game/Screens/Menu/MainMenu.cs | 2 +- .../DailyChallengeLeaderboard.cs | 2 +- .../OnlinePlay/FooterButtonFreeMods.cs | 2 +- .../Multiplayer/MultiplayerMatchSongSelect.cs | 2 +- .../OnlinePlay/OnlinePlayFreestyleSelect.cs | 1 - .../Playlists/PlaylistsSongSelect.cs | 2 +- .../{SelectV2 => Select}/BeatmapCarousel.cs | 5 +- .../BeatmapCarouselFilterGrouping.cs | 3 +- .../BeatmapCarouselFilterMatching.cs | 3 +- .../BeatmapCarouselFilterSorting.cs | 3 +- .../BeatmapDetailsArea.Header.cs | 3 +- .../BeatmapDetailsArea.WedgeSelector.cs | 2 +- .../BeatmapDetailsArea.cs | 2 +- .../BeatmapLeaderboardScore.Tooltip.cs | 2 +- .../BeatmapLeaderboardScore.cs | 3 +- .../BeatmapLeaderboardWedge.cs | 2 +- .../BeatmapMetadataWedge.FailRetryDisplay.cs | 2 +- .../BeatmapMetadataWedge.MetadataDisplay.cs | 2 +- ...eatmapMetadataWedge.RatingSpreadDisplay.cs | 2 +- ...BeatmapMetadataWedge.SuccessRateDisplay.cs | 2 +- .../BeatmapMetadataWedge.TagsLine.cs | 2 +- .../BeatmapMetadataWedge.UserRatingDisplay.cs | 2 +- .../BeatmapMetadataWedge.cs | 2 +- .../BeatmapTitleWedge.DifficultyDisplay.cs | 2 +- ...pTitleWedge.DifficultyStatisticsDisplay.cs | 2 +- .../BeatmapTitleWedge.FavouriteButton.cs | 2 +- .../BeatmapTitleWedge.Statistic.cs | 2 +- .../BeatmapTitleWedge.StatisticDifficulty.cs | 2 +- .../BeatmapTitleWedge.StatisticPlayCount.cs | 2 +- .../{SelectV2 => Select}/BeatmapTitleWedge.cs | 2 +- .../FilterControl.DifficultyRangeSlider.cs | 2 +- .../FilterControl.ScopedBeatmapSetDisplay.cs | 2 +- .../{SelectV2 => Select}/FilterControl.cs | 3 +- .../{SelectV2 => Select}/FooterButtonMods.cs | 2 +- .../FooterButtonOptions.Popover.cs | 2 +- .../FooterButtonOptions.cs | 2 +- .../FooterButtonRandom.cs | 2 +- .../{SelectV2 => Select}/ISongSelect.cs | 2 +- .../LeftSideInteractionContainer.cs | 2 +- .../NoResultsPlaceholder.cs | 3 +- .../Screens/{SelectV2 => Select}/Panel.cs | 2 +- .../{SelectV2 => Select}/PanelBeatmap.cs | 2 +- .../PanelBeatmapSet.SpreadDisplay.cs | 2 +- .../{SelectV2 => Select}/PanelBeatmapSet.cs | 2 +- .../PanelBeatmapStandalone.SpreadDisplay.cs | 2 +- .../PanelBeatmapStandalone.cs | 2 +- .../{SelectV2 => Select}/PanelGroup.cs | 2 +- .../PanelGroupRankDisplay.cs | 2 +- .../PanelGroupRankedStatus.cs | 2 +- .../PanelGroupStarDifficulty.cs | 2 +- .../PanelLocalRankDisplay.cs | 2 +- .../PanelSetBackground.cs | 2 +- .../PanelUpdateBeatmapButton.cs | 3 +- .../RealmPopulatingOnlineLookupSource.cs | 2 +- .../{SelectV2 => Select}/SoloSongSelect.cs | 3 +- .../{SelectV2 => Select}/SongSelect.cs | 3 +- .../UpdateLocalConfirmationDialog.cs | 4 +- .../{SelectV2 => Select}/WedgeBackground.cs | 2 +- .../Screens/SelectV2/CollectionDropdown.cs | 256 ------------------ .../Tests/Visual/EditorSavingTestScene.cs | 2 +- 120 files changed, 220 insertions(+), 472 deletions(-) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/BeatmapCarouselFilterGroupingTest.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/BeatmapCarouselFilterSortingTest.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/BeatmapCarouselTestScene.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/SongSelectComponentsTestScene.cs (97%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/SongSelectTestScene.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarousel.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselArtistGrouping.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselCollectionGrouping.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselDifficultyGrouping.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselFiltering.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselNoGrouping.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselRandom.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselScrolling.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselSetsSplitApart.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselUpdateHandling.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapFilterControl.cs (93%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapLeaderboardScore.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapLeaderboardSorting.cs (95%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapLeaderboardWedge.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapMetadataWedge.cs (90%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapTitleWedge.cs (88%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapTitleWedgeStatistic.cs (97%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneDifficultyRangeSlider.cs (96%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneDifficultyStatisticsDisplay.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneFooterButtonMods.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestScenePanelBeatmap.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestScenePanelBeatmapStandalone.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestScenePanelGroup.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestScenePanelSet.cs (97%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestScenePanelUpdateBeatmapButton.cs (95%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneSongSelect.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneSongSelectCurrentSelectionInvalidated.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneSongSelectFiltering.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneSongSelectGrouping.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapCarousel.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapCarouselFilterGrouping.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapCarouselFilterMatching.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapCarouselFilterSorting.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapDetailsArea.Header.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapDetailsArea.WedgeSelector.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapDetailsArea.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapLeaderboardScore.Tooltip.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapLeaderboardScore.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapLeaderboardWedge.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.FailRetryDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.MetadataDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.RatingSpreadDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.SuccessRateDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.TagsLine.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.UserRatingDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.DifficultyDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.FavouriteButton.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.Statistic.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.StatisticDifficulty.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.StatisticPlayCount.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/FilterControl.DifficultyRangeSlider.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/FilterControl.ScopedBeatmapSetDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/FilterControl.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/FooterButtonMods.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/FooterButtonOptions.Popover.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/FooterButtonOptions.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/FooterButtonRandom.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/ISongSelect.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/LeftSideInteractionContainer.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/NoResultsPlaceholder.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/Panel.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelBeatmap.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelBeatmapSet.SpreadDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelBeatmapSet.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelBeatmapStandalone.SpreadDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelBeatmapStandalone.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelGroup.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelGroupRankDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelGroupRankedStatus.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelGroupStarDifficulty.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelLocalRankDisplay.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/PanelSetBackground.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelUpdateBeatmapButton.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/RealmPopulatingOnlineLookupSource.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/SoloSongSelect.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/SongSelect.cs (99%) rename osu.Game/Screens/Select/{Carousel => }/UpdateLocalConfirmationDialog.cs (94%) rename osu.Game/Screens/{SelectV2 => Select}/WedgeBackground.cs (98%) delete mode 100644 osu.Game/Screens/SelectV2/CollectionDropdown.cs diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs index 7dcb8621bfde..5455963ff8f2 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs @@ -11,7 +11,6 @@ using osu.Game.Rulesets.Filter; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Carousel; using osu.Game.Screens.Select.Filter; namespace osu.Game.Tests.NonVisual.Filtering diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs index 1365d95a55bd..3b531e203610 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs @@ -32,7 +32,7 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Screens.Ranking; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Storyboards.Drawables; using osu.Game.Tests.Resources; using osuTK; diff --git a/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallenge.cs b/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallenge.cs index f1422b46548e..bf88cee11bae 100644 --- a/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallenge.cs +++ b/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallenge.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual.Metadata; using osu.Game.Tests.Visual.OnlinePlay; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs index 66a039f36e87..4ab757163695 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components.Timeline; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK.Input; namespace osu.Game.Tests.Visual.Editing diff --git a/osu.Game.Tests/Visual/Editing/TestSceneOpenEditorTimestamp.cs b/osu.Game.Tests/Visual/Editing/TestSceneOpenEditorTimestamp.cs index e3b79d40533b..46f47f6a928d 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneOpenEditorTimestamp.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneOpenEditorTimestamp.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets.Osu; using osu.Game.Screens.Edit; using osu.Game.Screens.Menu; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Editing diff --git a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs index f0b7d643b2c3..b10be77fb654 100644 --- a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs @@ -125,7 +125,7 @@ protected void RunGameplay() protected void AddBeatmapFromSongSelect(Func beatmap, RulesetInfo? ruleset = null, IReadOnlyList? mods = null) { - Screens.SelectV2.SongSelect? songSelect = null; + Screens.Select.SongSelect? songSelect = null; AddStep("click add button", () => { @@ -133,7 +133,7 @@ protected void AddBeatmapFromSongSelect(Func beatmap, RulesetInfo? InputManager.Click(MouseButton.Left); }); - AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.SelectV2.SongSelect) != null); + AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.Select.SongSelect) != null); AddUntilStep("wait for loaded", () => songSelect.IsCurrentScreen() && !songSelect.AsNonNull().IsFiltering); if (ruleset != null) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs index 89980b4257af..a1ced5698e15 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs @@ -89,7 +89,7 @@ public void TestAddItemsAsHost() private void selectNewItem(Func beatmap) { - Screens.SelectV2.SongSelect? songSelect = null; + Screens.Select.SongSelect? songSelect = null; AddUntilStep("wait for playlist panels to load", () => { @@ -103,7 +103,7 @@ private void selectNewItem(Func beatmap) InputManager.Click(MouseButton.Left); }); - AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.SelectV2.SongSelect) != null); + AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.Select.SongSelect) != null); AddUntilStep("wait for loaded", () => songSelect.IsCurrentScreen() && !songSelect.AsNonNull().IsFiltering); BeatmapInfo otherBeatmap = null!; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneBeatmapEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneBeatmapEditorNavigation.cs index c7499c98b589..09e8253080be 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneBeatmapEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneBeatmapEditorNavigation.cs @@ -26,8 +26,8 @@ using osu.Game.Screens.Edit.GameplayTest; using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Menu; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneButtonSystemNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneButtonSystemNavigation.cs index 0ccfb5a4e36a..a908c9cf1bf6 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneButtonSystemNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneButtonSystemNavigation.cs @@ -5,7 +5,7 @@ using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Screens.Menu; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK.Input; namespace osu.Game.Tests.Visual.Navigation diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs index 4f27d9b3230a..6ddd78432910 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays.Settings.Sections.Input; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Beatmaps.IO; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs b/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs index 0a4349d73f4e..d3321753c1ab 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs @@ -5,7 +5,7 @@ using osu.Framework.Extensions; using osu.Game.Configuration; using osu.Game.Screens.Play; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Beatmaps.IO; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs index 04d7b15295cf..f86727ab10ee 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs @@ -17,7 +17,7 @@ using osu.Game.Screens; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Beatmaps.IO; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs index 1dd39e5bf9f4..4acc174f72f2 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs @@ -16,7 +16,7 @@ using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Menu; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.Navigation { diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs index fa337a3ec2b0..06ea5c7da2e8 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs @@ -18,8 +18,8 @@ using osu.Game.Screens.Menu; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; -using osu.Game.Screens.SelectV2; -using FilterControl = osu.Game.Screens.SelectV2.FilterControl; +using osu.Game.Screens.Select; +using FilterControl = osu.Game.Screens.Select.FilterControl; namespace osu.Game.Tests.Visual.Navigation { diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 1062f32efb25..68aaba6c68f0 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -51,12 +51,13 @@ using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Screens.Ranking; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Beatmaps.IO; using osu.Game.Tests.Resources; using osu.Game.Utils; using osuTK; using osuTK.Input; +using CollectionDropdown = osu.Game.Screens.Select.CollectionDropdown; namespace osu.Game.Tests.Visual.Navigation { @@ -197,14 +198,14 @@ public void TestSongSelectBackActionHandling() AddStep("set filter again", () => filterControlTextBox().Current.Value = "test"); AddStep("open collections dropdown", () => { - InputManager.MoveMouseTo(songSelect.ChildrenOfType().Single()); + InputManager.MoveMouseTo(songSelect.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); AddStep("press back once", () => InputManager.Click(MouseButton.Button1)); AddAssert("still at song select", () => Game.ScreenStack.CurrentScreen == songSelect); AddAssert("collections dropdown closed", () => songSelect - .ChildrenOfType().Single() + .ChildrenOfType().Single() .ChildrenOfType.DropdownMenu>().Single().State == MenuState.Closed); AddStep("press back a second time", () => InputManager.Click(MouseButton.Button1)); @@ -317,7 +318,7 @@ public void TestOpenModSelectOverlayUsingAction() [Test] public void TestAttemptPlayBeatmapWrongHashFails() { - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).GetResultSafely()); PushAndConfirm(() => songSelect = new SoloSongSelect()); @@ -352,7 +353,7 @@ public void TestAttemptPlayBeatmapWrongHashFails() [Test] public void TestAttemptPlayBeatmapMissingFails() { - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).GetResultSafely()); PushAndConfirm(() => songSelect = new SoloSongSelect()); @@ -386,7 +387,7 @@ public void TestOffsetAdjustDuringPause() { Player player = null; - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); @@ -429,7 +430,7 @@ public void TestScrollSpeedAdjustDuringGameplay() { Player player = null; - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); @@ -483,7 +484,7 @@ public void TestOffsetAdjustDuringGameplay() { Player player = null; - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); @@ -526,7 +527,7 @@ public void TestRetryCountIncrements() { Player player = null; - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); @@ -1194,9 +1195,9 @@ public void TestTouchScreenDetectionAtSongSelect() AddStep("close settings sidebar", () => InputManager.Key(Key.Escape)); - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; AddRepeatStep("go to solo", () => InputManager.Key(Key.P), 3); - AddUntilStep("wait for song select", () => (songSelect = Game.ScreenStack.CurrentScreen as Screens.SelectV2.SongSelect) != null); + AddUntilStep("wait for song select", () => (songSelect = Game.ScreenStack.CurrentScreen as Screens.Select.SongSelect) != null); AddUntilStep("wait for beatmap sets loaded", () => songSelect.CarouselItemsPresented); AddStep("switch to osu! ruleset", () => @@ -1281,7 +1282,7 @@ public void TestTouchScreenDetectionInGame() [Test] public void TestExitSongSelectAndImmediatelyClickLogo() { - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); @@ -1312,7 +1313,7 @@ public void TestPresentBeatmapAfterDeletion() { BeatmapSetInfo beatmap = null; - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); @@ -1371,7 +1372,7 @@ private Func playToCompletion() IWorkingBeatmap beatmap() => Game.Beatmap.Value; - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index 9ddeb7870ba2..97dfcd75b584 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -27,7 +27,7 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD.HitErrorMeters; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Skinning; using osu.Game.Tests.Beatmaps.IO; using osuTK; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs index 4295e9e88e80..298461380776 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs @@ -24,17 +24,13 @@ using osu.Game.Screens.Menu; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Beatmaps.IO; using osu.Game.Tests.Resources; using osuTK.Input; namespace osu.Game.Tests.Visual.Navigation { - /// - /// Tests copied out of `TestSceneScreenNavigation` which are specific to song select. - /// These are for SongSelectV2. Eventually, the tests in the above class should be deleted along with old song select. - /// public partial class TestSceneSongSelectNavigation : OsuGameTestScene { [Test] @@ -277,7 +273,7 @@ public void TestSelectionNotLostWithConvertedBeatmapsShown() /// /// Note: This test was written to demonstrate the failure described at https://github.com/ppy/osu/issues/35023, /// but because the failure scenario there entailed a race condition, it was possible for the test to pass regardless - /// unless was increased. + /// unless was increased. /// [Test] public void TestPresentFromResults() diff --git a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselFilterGroupingTest.cs b/osu.Game.Tests/Visual/SongSelect/BeatmapCarouselFilterGroupingTest.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselFilterGroupingTest.cs rename to osu.Game.Tests/Visual/SongSelect/BeatmapCarouselFilterGroupingTest.cs index 3e935ac5d75c..814e93014b80 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselFilterGroupingTest.cs +++ b/osu.Game.Tests/Visual/SongSelect/BeatmapCarouselFilterGroupingTest.cs @@ -14,10 +14,9 @@ using osu.Game.Scoring; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class BeatmapCarouselFilterGroupingTest diff --git a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselFilterSortingTest.cs b/osu.Game.Tests/Visual/SongSelect/BeatmapCarouselFilterSortingTest.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselFilterSortingTest.cs rename to osu.Game.Tests/Visual/SongSelect/BeatmapCarouselFilterSortingTest.cs index 868abf958333..d6729d214111 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselFilterSortingTest.cs +++ b/osu.Game.Tests/Visual/SongSelect/BeatmapCarouselFilterSortingTest.cs @@ -12,10 +12,9 @@ using osu.Game.Graphics.Carousel; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class BeatmapCarouselFilterSortingTest diff --git a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs b/osu.Game.Tests/Visual/SongSelect/BeatmapCarouselTestScene.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs rename to osu.Game.Tests/Visual/SongSelect/BeatmapCarouselTestScene.cs index dc3a49c068e9..ae31606abb7c 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs +++ b/osu.Game.Tests/Visual/SongSelect/BeatmapCarouselTestScene.cs @@ -25,15 +25,13 @@ using osu.Game.Scoring; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Beatmaps; using osu.Game.Tests.Resources; using osuTK; using osuTK.Graphics; using osuTK.Input; -using BeatmapCarousel = osu.Game.Screens.SelectV2.BeatmapCarousel; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public abstract partial class BeatmapCarouselTestScene : OsuManualInputManagerTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/SongSelectComponentsTestScene.cs b/osu.Game.Tests/Visual/SongSelect/SongSelectComponentsTestScene.cs similarity index 97% rename from osu.Game.Tests/Visual/SongSelectV2/SongSelectComponentsTestScene.cs rename to osu.Game.Tests/Visual/SongSelect/SongSelectComponentsTestScene.cs index 843d65b7f8e9..94ca56897ec4 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/SongSelectComponentsTestScene.cs +++ b/osu.Game.Tests/Visual/SongSelect/SongSelectComponentsTestScene.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.Cursor; using osu.Game.Overlays; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public abstract partial class SongSelectComponentsTestScene : OsuManualInputManagerTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/SongSelectTestScene.cs b/osu.Game.Tests/Visual/SongSelect/SongSelectTestScene.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/SongSelectTestScene.cs rename to osu.Game.Tests/Visual/SongSelect/SongSelectTestScene.cs index ac8591699a05..e5fce2981230 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/SongSelectTestScene.cs +++ b/osu.Game.Tests/Visual/SongSelect/SongSelectTestScene.cs @@ -23,11 +23,11 @@ using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Menu; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public abstract partial class SongSelectTestScene : ScreenTestScene { @@ -38,7 +38,7 @@ public abstract partial class SongSelectTestScene : ScreenTestScene private RealmDetachedBeatmapStore beatmapStore = null!; - protected Screens.SelectV2.SongSelect SongSelect { get; private set; } = null!; + protected Screens.Select.SongSelect SongSelect { get; private set; } = null!; protected BeatmapCarousel Carousel => SongSelect.ChildrenOfType().Single(); [Cached] diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarousel.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index ce671c7e7fb6..b7c113cffb9d 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -10,11 +10,11 @@ using osu.Framework.Threading; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { /// /// Covers common steps which can be used for manual testing. diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselArtistGrouping.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselArtistGrouping.cs index 28cdca34e1dd..a591dff01060 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselArtistGrouping.cs @@ -7,12 +7,12 @@ using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Graphics.Carousel; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; using osuTK; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselArtistGrouping : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselCollectionGrouping.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselCollectionGrouping.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselCollectionGrouping.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselCollectionGrouping.cs index e410d66ce851..0d7b9c29919a 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselCollectionGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselCollectionGrouping.cs @@ -8,7 +8,7 @@ using osu.Game.Collections; using osu.Game.Screens.Select.Filter; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselCollectionGrouping : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselDifficultyGrouping.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselDifficultyGrouping.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselDifficultyGrouping.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselDifficultyGrouping.cs index 2cffe60ec1aa..4a41612c3037 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselDifficultyGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselDifficultyGrouping.cs @@ -5,11 +5,11 @@ using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Graphics.Carousel; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osuTK; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselDifficultyGrouping : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselFiltering.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselFiltering.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselFiltering.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselFiltering.cs index b1bd9fd3ed50..73596a768d89 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselFiltering.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselFiltering.cs @@ -9,11 +9,11 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselFiltering : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselNoGrouping.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselNoGrouping.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselNoGrouping.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselNoGrouping.cs index c839a2805569..1ff87712de5d 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselNoGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselNoGrouping.cs @@ -4,12 +4,12 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Testing; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osuTK; using osuTK.Input; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselNoGrouping : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselRandom.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselRandom.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselRandom.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselRandom.cs index ce68d587c8ee..66328de8dd5b 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselRandom.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselRandom.cs @@ -5,10 +5,10 @@ using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselRandom : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselScrolling.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselScrolling.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselScrolling.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselScrolling.cs index c1cee4e398b3..319803ef5f44 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselScrolling.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselScrolling.cs @@ -5,9 +5,9 @@ using NUnit.Framework; using osu.Framework.Graphics.Primitives; using osu.Framework.Testing; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselScrolling : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselSetsSplitApart.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselSetsSplitApart.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselSetsSplitApart.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselSetsSplitApart.cs index 31488e399a58..12d70702d5cf 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselSetsSplitApart.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselSetsSplitApart.cs @@ -6,10 +6,10 @@ using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselSetsSplitApart : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselUpdateHandling.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselUpdateHandling.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselUpdateHandling.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselUpdateHandling.cs index 17f328b54912..1033a17e05cf 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselUpdateHandling.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselUpdateHandling.cs @@ -12,11 +12,11 @@ using osu.Game.Extensions; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselUpdateHandling : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapFilterControl.cs similarity index 93% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapFilterControl.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapFilterControl.cs index 284484d2df42..81f6cbc70d9e 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapFilterControl.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapFilterControl.cs @@ -4,9 +4,9 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapFilterControl : SongSelectComponentsTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardScore.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardScore.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardScore.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardScore.cs index 0aca2d6a1ce5..856a4be67dcc 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardScore.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardScore.cs @@ -21,13 +21,13 @@ using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Users; using osuTK; using osuTK.Input; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapLeaderboardScore : SongSelectComponentsTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardSorting.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardSorting.cs similarity index 95% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardSorting.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardSorting.cs index a37700f6bee9..9c50bccd6e7a 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardSorting.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardSorting.cs @@ -24,11 +24,11 @@ using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Users; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapLeaderboardSorting : SongSelectComponentsTestScene { @@ -44,7 +44,7 @@ public partial class TestSceneBeatmapLeaderboardSorting : SongSelectComponentsTe private LeaderboardManager leaderboardManager = null!; - private readonly IBindable onlineLookupResult = new Bindable(); + private readonly IBindable onlineLookupResult = new Bindable(); protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardWedge.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardWedge.cs index 4609bd8936bb..c6d6339c98c9 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardWedge.cs @@ -26,12 +26,12 @@ using osu.Game.Rulesets.Osu.Mods; using osu.Game.Scoring; using osu.Game.Screens.Play.Leaderboards; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Users; using osuTK.Input; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapLeaderboardWedge : SongSelectComponentsTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapMetadataWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataWedge.cs similarity index 90% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapMetadataWedge.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataWedge.cs index 02665843894a..769d6bb8f864 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapMetadataWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataWedge.cs @@ -13,16 +13,16 @@ using osu.Game.Graphics.Sprites; using osu.Game.Models; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapMetadataWedge : SongSelectComponentsTestScene { private BeatmapMetadataWedge wedge = null!; - [Cached(typeof(IBindable))] - private Bindable onlineLookupResult = new Bindable(); + [Cached(typeof(IBindable))] + private Bindable onlineLookupResult = new Bindable(); protected override void LoadComplete() { @@ -103,7 +103,7 @@ public void TestVariousMetrics() working.BeatmapInfo.OnlineID = 0; Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(null); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(null); }); } @@ -154,7 +154,7 @@ public void TestOnlineAvailability() var (working, _) = createTestBeatmap(); Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(null); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(null); }); AddAssert("rating wedge still hidden", () => !wedge.RatingsVisible); AddAssert("fail time wedge still hidden", () => !wedge.FailRetryVisible); @@ -189,7 +189,7 @@ public void TestLoading() var (working, online) = createTestBeatmap(); Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress(); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.InProgress(); Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500); }); AddWaitStep("wait", 5); @@ -203,7 +203,7 @@ public void TestLoading() online.Result!.RelatedTags[2].Name = "some/tag"; Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress(); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.InProgress(); Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500); }); AddWaitStep("wait", 5); @@ -217,7 +217,7 @@ public void TestLoading() working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear(); Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress(); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.InProgress(); Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500); }); AddWaitStep("wait", 5); @@ -231,13 +231,13 @@ public void TestLoading() working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear(); Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress(); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.InProgress(); Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500); }); AddWaitStep("wait", 5); } - private (WorkingBeatmap, Screens.SelectV2.SongSelect.BeatmapSetLookupResult) createTestBeatmap() + private (WorkingBeatmap, Screens.Select.SongSelect.BeatmapSetLookupResult) createTestBeatmap() { var working = CreateWorkingBeatmap(Ruleset.Value); var onlineSet = new APIBeatmapSet @@ -292,7 +292,7 @@ public void TestLoading() working.BeatmapSetInfo.DateSubmitted = DateTimeOffset.Now; working.BeatmapSetInfo.DateRanked = DateTimeOffset.Now; working.Metadata.UserTags.AddRange(onlineSet.RelatedTags.Select(t => t.Name)); - return (working, Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(onlineSet)); + return (working, Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(onlineSet)); } } } diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index 832e8fc90fb5..f2b4e414700b 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -23,7 +23,7 @@ using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Taiko; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Users; using osu.Game.Utils; diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedge.cs similarity index 88% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedge.cs index d89d90ea84cd..0d14de8b9e48 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedge.cs @@ -29,11 +29,10 @@ using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Skinning; -using osu.Game.Tests.Visual.SongSelect; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapTitleWedge : SongSelectComponentsTestScene { @@ -42,8 +41,8 @@ public partial class TestSceneBeatmapTitleWedge : SongSelectComponentsTestScene private BeatmapTitleWedge titleWedge = null!; private BeatmapTitleWedge.DifficultyDisplay difficultyDisplay => titleWedge.ChildrenOfType().Single(); - [Cached(typeof(IBindable))] - private Bindable onlineLookupResult = new Bindable(); + [Cached(typeof(IBindable))] + private Bindable onlineLookupResult = new Bindable(); [BackgroundDependencyLoader] private void load(RulesetStore rulesets) @@ -86,7 +85,7 @@ public void TestRulesetChange() foreach (var rulesetInfo in rulesets.AvailableRulesets) { - var testBeatmap = TestSceneBeatmapInfoWedge.CreateTestBeatmap(rulesetInfo); + var testBeatmap = createTestBeatmapFromRuleset(rulesetInfo); setRuleset(rulesetInfo); selectBeatmap(testBeatmap); @@ -108,7 +107,7 @@ public void TestNullBeatmap() public void TestBPMUpdates() { const double bpm = 120; - IBeatmap beatmap = TestSceneBeatmapInfoWedge.CreateTestBeatmap(new OsuRuleset().RulesetInfo); + IBeatmap beatmap = createTestBeatmapFromRuleset(new OsuRuleset().RulesetInfo); beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / bpm }); OsuModDoubleTime doubleTime = null!; @@ -160,7 +159,7 @@ public void TestOnlineAvailability() var (working, _) = createTestBeatmap(); Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(null); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(null); }); AddUntilStep("play count is -", () => this.ChildrenOfType().ElementAt(0).Text.ToString(), () => Is.EqualTo("-")); AddUntilStep("favourites count is -", () => this.ChildrenOfType().Single().Text.ToString(), () => Is.EqualTo("-")); @@ -255,7 +254,7 @@ public void TestFavouriting() [TestCase(120, 120.4, "DT", "180-181 (mostly 180)")] public void TestVaryingBPM(double commonBpm, double otherBpm, string? mod, string expectedDisplay) { - IBeatmap beatmap = TestSceneBeatmapInfoWedge.CreateTestBeatmap(new OsuRuleset().RulesetInfo); + IBeatmap beatmap = createTestBeatmapFromRuleset(new OsuRuleset().RulesetInfo); beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / commonBpm }); beatmap.ControlPointInfo.Add(100, new TimingControlPoint { BeatLength = 60 * 1000 / otherBpm }); beatmap.ControlPointInfo.Add(200, new TimingControlPoint { BeatLength = 60 * 1000 / commonBpm }); @@ -299,7 +298,7 @@ private void checkDisplayedBPM(string target) }); } - private (WorkingBeatmap, Screens.SelectV2.SongSelect.BeatmapSetLookupResult) createTestBeatmap() + private (WorkingBeatmap, Screens.Select.SongSelect.BeatmapSetLookupResult) createTestBeatmap() { var working = CreateWorkingBeatmap(Ruleset.Value); var onlineSet = new APIBeatmapSet @@ -320,7 +319,33 @@ private void checkDisplayedBPM(string target) working.BeatmapSetInfo.DateSubmitted = DateTimeOffset.Now; working.BeatmapSetInfo.DateRanked = DateTimeOffset.Now; - return (working, Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(onlineSet)); + return (working, Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(onlineSet)); + } + + private static IBeatmap createTestBeatmapFromRuleset(RulesetInfo ruleset) + { + List objects = new List(); + for (double i = 0; i < 50000; i += 1000) + objects.Add(new TestHitObject { StartTime = i }); + + return new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + Metadata = new BeatmapMetadata + { + Author = { Username = $"{ruleset.ShortName}Author" }, + Artist = $"{ruleset.ShortName}Artist", + Source = $"{ruleset.ShortName}Source", + Title = $"{ruleset.ShortName}Title" + }, + Ruleset = ruleset, + StarRating = 6, + DifficultyName = $"{ruleset.ShortName}Version", + Difficulty = new BeatmapDifficulty() + }, + HitObjects = objects + }; } private class TestHitObject : ConvertHitObject; diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedgeStatistic.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedgeStatistic.cs similarity index 97% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedgeStatistic.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedgeStatistic.cs index 6bf946902154..f0691f05a185 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedgeStatistic.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedgeStatistic.cs @@ -8,10 +8,10 @@ using osu.Framework.Testing; using osu.Game.Graphics; using osu.Game.Overlays; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Visual.UserInterface; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapTitleWedgeStatistic : ThemeComparisonTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneDifficultyRangeSlider.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeSlider.cs similarity index 96% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneDifficultyRangeSlider.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeSlider.cs index f97af65fd99d..ed7ade491474 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneDifficultyRangeSlider.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeSlider.cs @@ -7,12 +7,12 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Overlays; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Visual.UserInterface; using osuTK; using osuTK.Graphics; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneDifficultyRangeSlider : ThemeComparisonTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneDifficultyStatisticsDisplay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyStatisticsDisplay.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneDifficultyStatisticsDisplay.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyStatisticsDisplay.cs index 0ee742a09d58..5b15add2ad08 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneDifficultyStatisticsDisplay.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyStatisticsDisplay.cs @@ -11,10 +11,10 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Testing; using osu.Game.Overlays; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK.Graphics; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneDifficultyStatisticsDisplay : OsuTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneFooterButtonMods.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneFooterButtonMods.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneFooterButtonMods.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneFooterButtonMods.cs index c339f16bb48a..08d02015a29d 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneFooterButtonMods.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneFooterButtonMods.cs @@ -13,10 +13,10 @@ using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Utils; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneFooterButtonMods : OsuTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelBeatmap.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePanelBeatmap.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestScenePanelBeatmap.cs rename to osu.Game.Tests/Visual/SongSelect/TestScenePanelBeatmap.cs index 618b9e0d482a..ca71f5a212e6 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelBeatmap.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePanelBeatmap.cs @@ -19,12 +19,12 @@ using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual.UserInterface; using osuTK; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestScenePanelBeatmap : ThemeComparisonTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelBeatmapStandalone.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePanelBeatmapStandalone.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestScenePanelBeatmapStandalone.cs rename to osu.Game.Tests/Visual/SongSelect/TestScenePanelBeatmapStandalone.cs index 67a9f54f1a93..48c0fef48afd 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelBeatmapStandalone.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePanelBeatmapStandalone.cs @@ -19,12 +19,12 @@ using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual.UserInterface; using osuTK; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestScenePanelBeatmapStandalone : ThemeComparisonTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelGroup.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePanelGroup.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestScenePanelGroup.cs rename to osu.Game.Tests/Visual/SongSelect/TestScenePanelGroup.cs index 12557a80f460..62c8a9c8c554 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelGroup.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePanelGroup.cs @@ -7,15 +7,15 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; -using osu.Game.Overlays; using osu.Game.Graphics.Carousel; using osu.Game.Graphics.Cursor; +using osu.Game.Overlays; using osu.Game.Scoring; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Visual.UserInterface; using osuTK; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestScenePanelGroup : ThemeComparisonTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelSet.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePanelSet.cs similarity index 97% rename from osu.Game.Tests/Visual/SongSelectV2/TestScenePanelSet.cs rename to osu.Game.Tests/Visual/SongSelect/TestScenePanelSet.cs index b574262d55fc..a903f8c83f73 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelSet.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePanelSet.cs @@ -11,12 +11,12 @@ using osu.Game.Graphics.Carousel; using osu.Game.Graphics.Cursor; using osu.Game.Overlays; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual.UserInterface; using osuTK; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestScenePanelSet : ThemeComparisonTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelUpdateBeatmapButton.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePanelUpdateBeatmapButton.cs similarity index 95% rename from osu.Game.Tests/Visual/SongSelectV2/TestScenePanelUpdateBeatmapButton.cs rename to osu.Game.Tests/Visual/SongSelect/TestScenePanelUpdateBeatmapButton.cs index 8156842eb982..02715ade3a0a 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelUpdateBeatmapButton.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePanelUpdateBeatmapButton.cs @@ -5,9 +5,9 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Game.Beatmaps; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestScenePanelUpdateBeatmapButton : OsuTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelect.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneSongSelect.cs index 243492439355..6eddc8e1d858 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelect.cs @@ -23,15 +23,14 @@ using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; using osuTK.Input; -using BeatmapCarousel = osu.Game.Screens.SelectV2.BeatmapCarousel; -using FooterButtonMods = osu.Game.Screens.SelectV2.FooterButtonMods; -using FooterButtonOptions = osu.Game.Screens.SelectV2.FooterButtonOptions; -using FooterButtonRandom = osu.Game.Screens.SelectV2.FooterButtonRandom; +using BeatmapCarousel = osu.Game.Screens.Select.BeatmapCarousel; +using FooterButtonMods = osu.Game.Screens.Select.FooterButtonMods; +using FooterButtonOptions = osu.Game.Screens.Select.FooterButtonOptions; +using FooterButtonRandom = osu.Game.Screens.Select.FooterButtonRandom; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneSongSelect : SongSelectTestScene { @@ -324,7 +323,7 @@ public void TestFilteringRunsAfterReturningFromGameplay() AddStep("exit gameplay", () => Stack.CurrentScreen.Exit()); - AddUntilStep("wait for song select", () => Stack.CurrentScreen is Screens.SelectV2.SongSelect); + AddUntilStep("wait for song select", () => Stack.CurrentScreen is Screens.Select.SongSelect); AddUntilStep("wait for filtered", () => SongSelect.ChildrenOfType().Single().FilterCount, () => Is.EqualTo(2)); } diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectCurrentSelectionInvalidated.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectCurrentSelectionInvalidated.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectCurrentSelectionInvalidated.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectCurrentSelectionInvalidated.cs index 0ec61f59dae7..59c9074ddb44 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectCurrentSelectionInvalidated.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectCurrentSelectionInvalidated.cs @@ -8,11 +8,11 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osuTK.Input; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { /// /// The fallback behaviour guaranteed by SongSelect is that a random selection will happen in worst case scenario. @@ -226,7 +226,7 @@ public void TestDebounceNotBypassedOnUpdate() Beatmaps.Delete(Beatmaps.GetAllUsableBeatmapSets().Last()); // check selection during debounce - Scheduler.AddDelayed(() => selectedBeatmapDuringDebounce = Beatmap.Value.BeatmapInfo, Screens.SelectV2.SongSelect.SELECTION_DEBOUNCE / 2f); + Scheduler.AddDelayed(() => selectedBeatmapDuringDebounce = Beatmap.Value.BeatmapInfo, Screens.Select.SongSelect.SELECTION_DEBOUNCE / 2f); }); WaitForFiltering(); diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFiltering.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFiltering.cs index 2e7e08b33191..a479a286573c 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFiltering.cs @@ -16,13 +16,13 @@ using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osuTK.Input; -using FilterControl = osu.Game.Screens.SelectV2.FilterControl; -using NoResultsPlaceholder = osu.Game.Screens.SelectV2.NoResultsPlaceholder; +using FilterControl = osu.Game.Screens.Select.FilterControl; +using NoResultsPlaceholder = osu.Game.Screens.Select.NoResultsPlaceholder; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneSongSelectFiltering : SongSelectTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectGrouping.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectGrouping.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectGrouping.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectGrouping.cs index e65c9553c246..eb282d3d3c9b 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectGrouping.cs @@ -16,11 +16,11 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Scoring; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { /// /// Test suite for grouping modes which require the presence of API / realm. diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs index 0da7c3eb958d..a958c5f43e9a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs @@ -17,7 +17,7 @@ using osu.Game.Overlays.Mods; using osu.Game.Screens; using osu.Game.Screens.Footer; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.UserInterface { diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 1603a9848c3e..d8bf2c752bc7 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -6,7 +6,7 @@ using JetBrains.Annotations; using Newtonsoft.Json; using osu.Game.Models; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Users; using osu.Game.Utils; using Realms; diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index 1e4d3484b7ea..57682513d4bb 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -34,7 +34,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Utils; using CommonStrings = osu.Game.Localisation.CommonStrings; -using SongSelect = osu.Game.Screens.SelectV2.SongSelect; +using SongSelect = osu.Game.Screens.Select.SongSelect; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; namespace osu.Game.Online.Leaderboards diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 0785ecaeaf6a..77ccf7edfc10 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -71,7 +71,7 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Seasonal; using osu.Game.Skinning; using osu.Game.Updater; diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs index edadc333c8bf..09bdb8b843b7 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs @@ -25,7 +25,7 @@ using osu.Game.Screens; using osu.Game.Screens.Footer; using osu.Game.Screens.Menu; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Visual; using osuTK; diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs index 19b2757e4c48..134bed22afb3 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs @@ -28,7 +28,7 @@ using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Users; using osu.Game.Utils; diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs b/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs index efc305b4921e..52dcadd977dd 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Screens; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK; namespace osu.Game.Overlays.SkinEditor diff --git a/osu.Game/Screens/Edit/Submission/BeatmapSubmissionScreen.cs b/osu.Game/Screens/Edit/Submission/BeatmapSubmissionScreen.cs index 8d78d76428e0..78066edc7e07 100644 --- a/osu.Game/Screens/Edit/Submission/BeatmapSubmissionScreen.cs +++ b/osu.Game/Screens/Edit/Submission/BeatmapSubmissionScreen.cs @@ -30,7 +30,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK; namespace osu.Game.Screens.Edit.Submission diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 2296213dd657..ee734acb6015 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -39,7 +39,7 @@ using osu.Game.Screens.OnlinePlay.DailyChallenge; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Playlists; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Seasonal; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallengeLeaderboard.cs b/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallengeLeaderboard.cs index 65805a970db8..62c5c0c8dfb5 100644 --- a/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallengeLeaderboard.cs +++ b/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallengeLeaderboard.cs @@ -17,7 +17,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK; namespace osu.Game.Screens.OnlinePlay.DailyChallenge diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs index aff9b803c653..28154180e66a 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs @@ -20,7 +20,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Screens.Footer; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK; namespace osu.Game.Screens.OnlinePlay diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index f234bed697b3..ce5d68b004be 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -24,9 +24,9 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Footer; +using osu.Game.Screens.Select; using osu.Game.Users; using osu.Game.Utils; -using osu.Game.Screens.SelectV2; namespace osu.Game.Screens.OnlinePlay.Multiplayer { diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs index 0ff3ade809b3..150cdb859dd6 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs @@ -13,7 +13,6 @@ using osu.Game.Rulesets; using osu.Game.Screens.Footer; using osu.Game.Screens.Select; -using SongSelect = osu.Game.Screens.SelectV2.SongSelect; namespace osu.Game.Screens.OnlinePlay { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs index fb921f219a06..7c1b3cd620e5 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs @@ -18,7 +18,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Footer; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Utils; namespace osu.Game.Screens.OnlinePlay.Playlists diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapCarousel.cs rename to osu.Game/Screens/Select/BeatmapCarousel.cs index adf65887270b..2cf8c7d2d041 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -13,8 +13,8 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; @@ -31,10 +31,9 @@ using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Scoring; -using osu.Game.Screens.Select; using Realms; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { [Cached] public partial class BeatmapCarousel : Carousel diff --git a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs b/osu.Game/Screens/Select/BeatmapCarouselFilterGrouping.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs rename to osu.Game/Screens/Select/BeatmapCarouselFilterGrouping.cs index 280db188efa5..8db8ed5cb09b 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs +++ b/osu.Game/Screens/Select/BeatmapCarouselFilterGrouping.cs @@ -11,11 +11,10 @@ using osu.Game.Collections; using osu.Game.Graphics.Carousel; using osu.Game.Scoring; -using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; using osu.Game.Utils; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public class BeatmapCarouselFilterGrouping : ICarouselFilter { diff --git a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs b/osu.Game/Screens/Select/BeatmapCarouselFilterMatching.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs rename to osu.Game/Screens/Select/BeatmapCarouselFilterMatching.cs index 80f7f058f789..5011166bb149 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs +++ b/osu.Game/Screens/Select/BeatmapCarouselFilterMatching.cs @@ -8,10 +8,9 @@ using System.Threading.Tasks; using osu.Game.Beatmaps; using osu.Game.Graphics.Carousel; -using osu.Game.Screens.Select; using osu.Game.Utils; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public class BeatmapCarouselFilterMatching : ICarouselFilter { diff --git a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterSorting.cs b/osu.Game/Screens/Select/BeatmapCarouselFilterSorting.cs similarity index 98% rename from osu.Game/Screens/SelectV2/BeatmapCarouselFilterSorting.cs rename to osu.Game/Screens/Select/BeatmapCarouselFilterSorting.cs index e9d65f710802..60e94299b26a 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterSorting.cs +++ b/osu.Game/Screens/Select/BeatmapCarouselFilterSorting.cs @@ -8,11 +8,10 @@ using System.Threading.Tasks; using osu.Game.Beatmaps; using osu.Game.Graphics.Carousel; -using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; using osu.Game.Utils; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public class BeatmapCarouselFilterSorting : ICarouselFilter { diff --git a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs b/osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs rename to osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs index 5b3f27ce6462..fd6437d1a967 100644 --- a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs +++ b/osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs @@ -14,10 +14,9 @@ using osu.Game.Localisation; using osu.Game.Online.Leaderboards; using osu.Game.Screens.Play.Leaderboards; -using osu.Game.Screens.Select; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapDetailsArea { diff --git a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.WedgeSelector.cs b/osu.Game/Screens/Select/BeatmapDetailsArea.WedgeSelector.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapDetailsArea.WedgeSelector.cs rename to osu.Game/Screens/Select/BeatmapDetailsArea.WedgeSelector.cs index 95f60fb423c8..9a5db9b818ed 100644 --- a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.WedgeSelector.cs +++ b/osu.Game/Screens/Select/BeatmapDetailsArea.WedgeSelector.cs @@ -18,7 +18,7 @@ using osu.Game.Overlays; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapDetailsArea { diff --git a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.cs b/osu.Game/Screens/Select/BeatmapDetailsArea.cs similarity index 98% rename from osu.Game/Screens/SelectV2/BeatmapDetailsArea.cs rename to osu.Game/Screens/Select/BeatmapDetailsArea.cs index 7a2068b0cfb2..f83fd1539de5 100644 --- a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailsArea.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { /// /// The left portion of the song select screen which houses the metadata or leaderboards wedge, along with controls diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.Tooltip.cs b/osu.Game/Screens/Select/BeatmapLeaderboardScore.Tooltip.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.Tooltip.cs rename to osu.Game/Screens/Select/BeatmapLeaderboardScore.Tooltip.cs index 1f92699887d3..bd3b6f16b371 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.Tooltip.cs +++ b/osu.Game/Screens/Select/BeatmapLeaderboardScore.Tooltip.cs @@ -34,7 +34,7 @@ using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapLeaderboardScore { diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs b/osu.Game/Screens/Select/BeatmapLeaderboardScore.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs rename to osu.Game/Screens/Select/BeatmapLeaderboardScore.cs index 079f4192e04f..c6d52a7ace03 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs +++ b/osu.Game/Screens/Select/BeatmapLeaderboardScore.cs @@ -32,7 +32,6 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; -using osu.Game.Screens.Select; using osu.Game.Users; using osu.Game.Users.Drawables; using osu.Game.Utils; @@ -40,7 +39,7 @@ using osuTK.Graphics; using CommonStrings = osu.Game.Localisation.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public sealed partial class BeatmapLeaderboardScore : OsuClickableContainer, IHasContextMenu, IHasCustomTooltip { diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs b/osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs rename to osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs index 18b1bc2e2766..25eac3e18232 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs +++ b/osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs @@ -37,7 +37,7 @@ using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapLeaderboardWedge : VisibilityContainer { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.FailRetryDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.FailRetryDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.FailRetryDisplay.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.FailRetryDisplay.cs index 9ee61b7c5ced..1bbce94f4fc9 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.FailRetryDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.FailRetryDisplay.cs @@ -17,7 +17,7 @@ using osu.Game.Resources.Localisation.Web; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.MetadataDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.MetadataDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.MetadataDisplay.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.MetadataDisplay.cs index 84948678d0d9..3b9d31380a63 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.MetadataDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.MetadataDisplay.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.RatingSpreadDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.RatingSpreadDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.RatingSpreadDisplay.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.RatingSpreadDisplay.cs index ee938ecdd9d9..3a6017f4ec7b 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.RatingSpreadDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.RatingSpreadDisplay.cs @@ -13,7 +13,7 @@ using osu.Game.Resources.Localisation.Web; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.SuccessRateDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.SuccessRateDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.SuccessRateDisplay.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.SuccessRateDisplay.cs index 611854727466..48680b5b2902 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.SuccessRateDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.SuccessRateDisplay.cs @@ -15,7 +15,7 @@ using osu.Game.Resources.Localisation.Web; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.TagsLine.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.TagsLine.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.TagsLine.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.TagsLine.cs index e48b4f20da9e..975dfd621254 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.TagsLine.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.TagsLine.cs @@ -22,7 +22,7 @@ using osu.Game.Overlays; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.UserRatingDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.UserRatingDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.UserRatingDisplay.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.UserRatingDisplay.cs index 2f38079577d1..2d8d039d990f 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.UserRatingDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.UserRatingDisplay.cs @@ -13,7 +13,7 @@ using osu.Game.Resources.Localisation.Web; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.cs index 9c0ab105e24a..128dde88c934 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.cs @@ -22,7 +22,7 @@ using osu.Game.Resources.Localisation.Web; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge : VisibilityContainer { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.DifficultyDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.DifficultyDisplay.cs index fc6ce0ac2069..432ba22c31ef 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.DifficultyDisplay.cs @@ -26,7 +26,7 @@ using osu.Game.Rulesets.Mods; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs index 595959cfce7d..e07eea1491d3 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs @@ -17,7 +17,7 @@ using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.FavouriteButton.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.FavouriteButton.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.FavouriteButton.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.FavouriteButton.cs index 62ac8a07b4dd..bd3aaaa2396b 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.FavouriteButton.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.FavouriteButton.cs @@ -26,7 +26,7 @@ using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.Statistic.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.Statistic.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.Statistic.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.Statistic.cs index 85a0382360a6..1ed08ce124ce 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.Statistic.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.Statistic.cs @@ -15,7 +15,7 @@ using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticDifficulty.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.StatisticDifficulty.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticDifficulty.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.StatisticDifficulty.cs index bcce78246d96..3133f8a67bcb 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticDifficulty.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.StatisticDifficulty.cs @@ -19,7 +19,7 @@ using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticPlayCount.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.StatisticPlayCount.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticPlayCount.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.StatisticPlayCount.cs index d193cbe286eb..f8f5fe378231 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticPlayCount.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.StatisticPlayCount.cs @@ -18,7 +18,7 @@ using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.cs index fdbed988850e..657e3ba15b35 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.cs @@ -28,7 +28,7 @@ using osu.Game.Utils; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge : VisibilityContainer { diff --git a/osu.Game/Screens/SelectV2/FilterControl.DifficultyRangeSlider.cs b/osu.Game/Screens/Select/FilterControl.DifficultyRangeSlider.cs similarity index 99% rename from osu.Game/Screens/SelectV2/FilterControl.DifficultyRangeSlider.cs rename to osu.Game/Screens/Select/FilterControl.DifficultyRangeSlider.cs index f15cfa4b4df5..902b335c621c 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.DifficultyRangeSlider.cs +++ b/osu.Game/Screens/Select/FilterControl.DifficultyRangeSlider.cs @@ -21,7 +21,7 @@ using osu.Game.Utils; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class FilterControl { diff --git a/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs b/osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs rename to osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs index 378db5cb2d94..78dfb163ade5 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs +++ b/osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs @@ -16,7 +16,7 @@ using osu.Game.Localisation; using osu.Game.Overlays; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class FilterControl { diff --git a/osu.Game/Screens/SelectV2/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs similarity index 99% rename from osu.Game/Screens/SelectV2/FilterControl.cs rename to osu.Game/Screens/Select/FilterControl.cs index 20a55e3e09e3..7473a2153160 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -25,12 +25,11 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; using osuTK; using osuTK.Input; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public sealed partial class FilterControl : OverlayContainer { diff --git a/osu.Game/Screens/SelectV2/FooterButtonMods.cs b/osu.Game/Screens/Select/FooterButtonMods.cs similarity index 99% rename from osu.Game/Screens/SelectV2/FooterButtonMods.cs rename to osu.Game/Screens/Select/FooterButtonMods.cs index 27e0ac68f91a..81668cc414d3 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonMods.cs +++ b/osu.Game/Screens/Select/FooterButtonMods.cs @@ -30,7 +30,7 @@ using osuTK.Graphics; using osuTK.Input; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class FooterButtonMods : ScreenFooterButton, IHasCurrentValue> { diff --git a/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs b/osu.Game/Screens/Select/FooterButtonOptions.Popover.cs similarity index 99% rename from osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs rename to osu.Game/Screens/Select/FooterButtonOptions.Popover.cs index 2f0f36c99c64..d4b7a13d9c20 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs +++ b/osu.Game/Screens/Select/FooterButtonOptions.Popover.cs @@ -23,7 +23,7 @@ using osuTK.Graphics; using osuTK.Input; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class FooterButtonOptions { diff --git a/osu.Game/Screens/SelectV2/FooterButtonOptions.cs b/osu.Game/Screens/Select/FooterButtonOptions.cs similarity index 98% rename from osu.Game/Screens/SelectV2/FooterButtonOptions.cs rename to osu.Game/Screens/Select/FooterButtonOptions.cs index 4da40559e98a..819b51aea5f9 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonOptions.cs +++ b/osu.Game/Screens/Select/FooterButtonOptions.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays; using osu.Game.Screens.Footer; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class FooterButtonOptions : ScreenFooterButton, IHasPopover { diff --git a/osu.Game/Screens/SelectV2/FooterButtonRandom.cs b/osu.Game/Screens/Select/FooterButtonRandom.cs similarity index 99% rename from osu.Game/Screens/SelectV2/FooterButtonRandom.cs rename to osu.Game/Screens/Select/FooterButtonRandom.cs index 4bd42497ebf1..bf001b7b8f11 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonRandom.cs +++ b/osu.Game/Screens/Select/FooterButtonRandom.cs @@ -15,7 +15,7 @@ using osuTK; using osuTK.Input; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class FooterButtonRandom : ScreenFooterButton { diff --git a/osu.Game/Screens/SelectV2/ISongSelect.cs b/osu.Game/Screens/Select/ISongSelect.cs similarity index 98% rename from osu.Game/Screens/SelectV2/ISongSelect.cs rename to osu.Game/Screens/Select/ISongSelect.cs index 5de1d4e75eea..b1c32435bf7f 100644 --- a/osu.Game/Screens/SelectV2/ISongSelect.cs +++ b/osu.Game/Screens/Select/ISongSelect.cs @@ -8,7 +8,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Scoring; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { /// /// Actions exposed by song select which are used by subcomponents to perform top-level operations. diff --git a/osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs b/osu.Game/Screens/Select/LeftSideInteractionContainer.cs similarity index 98% rename from osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs rename to osu.Game/Screens/Select/LeftSideInteractionContainer.cs index 212bb233f487..4b28213f4ecb 100644 --- a/osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs +++ b/osu.Game/Screens/Select/LeftSideInteractionContainer.cs @@ -6,7 +6,7 @@ using osu.Framework.Input; using osu.Framework.Input.Events; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { /// /// Handles mouse interactions required when moving away from the carousel. diff --git a/osu.Game/Screens/SelectV2/NoResultsPlaceholder.cs b/osu.Game/Screens/Select/NoResultsPlaceholder.cs similarity index 99% rename from osu.Game/Screens/SelectV2/NoResultsPlaceholder.cs rename to osu.Game/Screens/Select/NoResultsPlaceholder.cs index 597b6de8512f..cd38ce2f6c86 100644 --- a/osu.Game/Screens/SelectV2/NoResultsPlaceholder.cs +++ b/osu.Game/Screens/Select/NoResultsPlaceholder.cs @@ -14,10 +14,9 @@ using osu.Game.Localisation; using osu.Game.Online.Chat; using osu.Game.Overlays; -using osu.Game.Screens.Select; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class NoResultsPlaceholder : VisibilityContainer { diff --git a/osu.Game/Screens/SelectV2/Panel.cs b/osu.Game/Screens/Select/Panel.cs similarity index 99% rename from osu.Game/Screens/SelectV2/Panel.cs rename to osu.Game/Screens/Select/Panel.cs index 241002fa76a8..60175d0a0d30 100644 --- a/osu.Game/Screens/SelectV2/Panel.cs +++ b/osu.Game/Screens/Select/Panel.cs @@ -24,7 +24,7 @@ using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public abstract partial class Panel : PoolableDrawable, ICarouselPanel, IHasContextMenu { diff --git a/osu.Game/Screens/SelectV2/PanelBeatmap.cs b/osu.Game/Screens/Select/PanelBeatmap.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelBeatmap.cs rename to osu.Game/Screens/Select/PanelBeatmap.cs index 6dc2286f44b0..4c259a63550a 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmap.cs +++ b/osu.Game/Screens/Select/PanelBeatmap.cs @@ -27,7 +27,7 @@ using osu.Game.Rulesets.Mods; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelBeatmap : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs b/osu.Game/Screens/Select/PanelBeatmapSet.SpreadDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs rename to osu.Game/Screens/Select/PanelBeatmapSet.SpreadDisplay.cs index 89916b13d870..338b4036bd24 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs +++ b/osu.Game/Screens/Select/PanelBeatmapSet.SpreadDisplay.cs @@ -20,7 +20,7 @@ using osu.Game.Rulesets; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelBeatmapSet { diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs b/osu.Game/Screens/Select/PanelBeatmapSet.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelBeatmapSet.cs rename to osu.Game/Screens/Select/PanelBeatmapSet.cs index f6a33e5ce00a..5a9508a82383 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs +++ b/osu.Game/Screens/Select/PanelBeatmapSet.cs @@ -32,7 +32,7 @@ using osuTK.Graphics; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelBeatmapSet : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs b/osu.Game/Screens/Select/PanelBeatmapStandalone.SpreadDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs rename to osu.Game/Screens/Select/PanelBeatmapStandalone.SpreadDisplay.cs index f8f5883c9964..1e4efe495c97 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs +++ b/osu.Game/Screens/Select/PanelBeatmapStandalone.SpreadDisplay.cs @@ -18,7 +18,7 @@ using osu.Game.Rulesets; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelBeatmapStandalone { diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs b/osu.Game/Screens/Select/PanelBeatmapStandalone.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs rename to osu.Game/Screens/Select/PanelBeatmapStandalone.cs index 5fc6be3d6225..77cdbc356c0b 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs +++ b/osu.Game/Screens/Select/PanelBeatmapStandalone.cs @@ -24,7 +24,7 @@ using osu.Game.Rulesets.Mods; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelBeatmapStandalone : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelGroup.cs b/osu.Game/Screens/Select/PanelGroup.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelGroup.cs rename to osu.Game/Screens/Select/PanelGroup.cs index d2ae495610a8..0b3fed927803 100644 --- a/osu.Game/Screens/SelectV2/PanelGroup.cs +++ b/osu.Game/Screens/Select/PanelGroup.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelGroup : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelGroupRankDisplay.cs b/osu.Game/Screens/Select/PanelGroupRankDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelGroupRankDisplay.cs rename to osu.Game/Screens/Select/PanelGroupRankDisplay.cs index 6895c30fee33..0697e992f45f 100644 --- a/osu.Game/Screens/SelectV2/PanelGroupRankDisplay.cs +++ b/osu.Game/Screens/Select/PanelGroupRankDisplay.cs @@ -23,7 +23,7 @@ using osuTK.Graphics; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelGroupRankDisplay : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelGroupRankedStatus.cs b/osu.Game/Screens/Select/PanelGroupRankedStatus.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelGroupRankedStatus.cs rename to osu.Game/Screens/Select/PanelGroupRankedStatus.cs index ce175efcf662..fdd48a0a1061 100644 --- a/osu.Game/Screens/SelectV2/PanelGroupRankedStatus.cs +++ b/osu.Game/Screens/Select/PanelGroupRankedStatus.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelGroupRankedStatus : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelGroupStarDifficulty.cs b/osu.Game/Screens/Select/PanelGroupStarDifficulty.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelGroupStarDifficulty.cs rename to osu.Game/Screens/Select/PanelGroupStarDifficulty.cs index e6b59334cd5b..1abbd44d9f14 100644 --- a/osu.Game/Screens/SelectV2/PanelGroupStarDifficulty.cs +++ b/osu.Game/Screens/Select/PanelGroupStarDifficulty.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelGroupStarDifficulty : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelLocalRankDisplay.cs b/osu.Game/Screens/Select/PanelLocalRankDisplay.cs similarity index 98% rename from osu.Game/Screens/SelectV2/PanelLocalRankDisplay.cs rename to osu.Game/Screens/Select/PanelLocalRankDisplay.cs index c72835144fa9..a0fdb82a4341 100644 --- a/osu.Game/Screens/SelectV2/PanelLocalRankDisplay.cs +++ b/osu.Game/Screens/Select/PanelLocalRankDisplay.cs @@ -16,7 +16,7 @@ using osuTK; using Realms; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelLocalRankDisplay : CompositeDrawable { diff --git a/osu.Game/Screens/SelectV2/PanelSetBackground.cs b/osu.Game/Screens/Select/PanelSetBackground.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelSetBackground.cs rename to osu.Game/Screens/Select/PanelSetBackground.cs index 7f15a23b9acc..b6c4be7fd68d 100644 --- a/osu.Game/Screens/SelectV2/PanelSetBackground.cs +++ b/osu.Game/Screens/Select/PanelSetBackground.cs @@ -17,7 +17,7 @@ using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelSetBackground : Container { diff --git a/osu.Game/Screens/SelectV2/PanelUpdateBeatmapButton.cs b/osu.Game/Screens/Select/PanelUpdateBeatmapButton.cs similarity index 98% rename from osu.Game/Screens/SelectV2/PanelUpdateBeatmapButton.cs rename to osu.Game/Screens/Select/PanelUpdateBeatmapButton.cs index e7204eefafbe..fc83fa77ef6d 100644 --- a/osu.Game/Screens/SelectV2/PanelUpdateBeatmapButton.cs +++ b/osu.Game/Screens/Select/PanelUpdateBeatmapButton.cs @@ -18,12 +18,11 @@ using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Overlays; -using osu.Game.Screens.Select.Carousel; using osuTK; using osuTK.Graphics; using CommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelUpdateBeatmapButton : OsuAnimatedButton { diff --git a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs b/osu.Game/Screens/Select/RealmPopulatingOnlineLookupSource.cs similarity index 99% rename from osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs rename to osu.Game/Screens/Select/RealmPopulatingOnlineLookupSource.cs index 2b75820587d0..132a160106f9 100644 --- a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs +++ b/osu.Game/Screens/Select/RealmPopulatingOnlineLookupSource.cs @@ -15,7 +15,7 @@ using osu.Game.Online.API.Requests.Responses; using Realms; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { /// /// This component is designed to perform lookups of online data diff --git a/osu.Game/Screens/SelectV2/SoloSongSelect.cs b/osu.Game/Screens/Select/SoloSongSelect.cs similarity index 98% rename from osu.Game/Screens/SelectV2/SoloSongSelect.cs rename to osu.Game/Screens/Select/SoloSongSelect.cs index cf87a3466f60..270d8f326a40 100644 --- a/osu.Game/Screens/SelectV2/SoloSongSelect.cs +++ b/osu.Game/Screens/Select/SoloSongSelect.cs @@ -19,12 +19,11 @@ using osu.Game.Rulesets.Mods; using osu.Game.Screens.Edit; using osu.Game.Screens.Play; -using osu.Game.Screens.Select; using osu.Game.Users; using osu.Game.Utils; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class SoloSongSelect : SongSelect { diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs similarity index 99% rename from osu.Game/Screens/SelectV2/SongSelect.cs rename to osu.Game/Screens/Select/SongSelect.cs index d47155ee6b16..3b29c100b29d 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -50,14 +50,13 @@ using osu.Game.Screens.Menu; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select; using osu.Game.Skinning; using osu.Game.Utils; using osuTK; using osuTK.Graphics; using osuTK.Input; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { /// /// This screen is intended to house all components introduced in the new song select design to add transitions and examine the overall look. diff --git a/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs b/osu.Game/Screens/Select/UpdateLocalConfirmationDialog.cs similarity index 94% rename from osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs rename to osu.Game/Screens/Select/UpdateLocalConfirmationDialog.cs index 6157e8f6a540..3f847c6816fa 100644 --- a/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs +++ b/osu.Game/Screens/Select/UpdateLocalConfirmationDialog.cs @@ -3,10 +3,10 @@ using System; using osu.Framework.Graphics.Sprites; -using osu.Game.Overlays.Dialog; using osu.Game.Localisation; +using osu.Game.Overlays.Dialog; -namespace osu.Game.Screens.Select.Carousel +namespace osu.Game.Screens.Select { public partial class UpdateLocalConfirmationDialog : DangerousActionDialog { diff --git a/osu.Game/Screens/SelectV2/WedgeBackground.cs b/osu.Game/Screens/Select/WedgeBackground.cs similarity index 98% rename from osu.Game/Screens/SelectV2/WedgeBackground.cs rename to osu.Game/Screens/Select/WedgeBackground.cs index 3fa21beee237..aa1ce025bda0 100644 --- a/osu.Game/Screens/SelectV2/WedgeBackground.cs +++ b/osu.Game/Screens/Select/WedgeBackground.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics; using osu.Game.Overlays; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { internal sealed partial class WedgeBackground : InputBlockingContainer { diff --git a/osu.Game/Screens/SelectV2/CollectionDropdown.cs b/osu.Game/Screens/SelectV2/CollectionDropdown.cs deleted file mode 100644 index 9f1950ac5f42..000000000000 --- a/osu.Game/Screens/SelectV2/CollectionDropdown.cs +++ /dev/null @@ -1,256 +0,0 @@ -// 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.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Game.Beatmaps; -using osu.Game.Collections; -using osu.Game.Database; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; -using osu.Game.Graphics.UserInterfaceV2; -using osu.Game.Localisation; -using osuTK; -using Realms; - -namespace osu.Game.Screens.SelectV2 -{ - /// - /// A dropdown to select the collection to be used to filter results. - /// - public partial class CollectionDropdown : ShearedDropdown // TODO: partial class under FilterControl? - { - /// - /// Whether to show the "manage collections..." menu item in the dropdown. - /// - protected virtual bool ShowManageCollectionsItem => true; - - private readonly BindableList filters = new BindableList(); - - [Resolved] - private ManageCollectionsDialog? manageCollectionsDialog { get; set; } - - [Resolved] - private RealmAccess realm { get; set; } = null!; - - private IDisposable? realmSubscription; - - private readonly CollectionFilterMenuItem allBeatmapsItem = new AllBeatmapsCollectionFilterMenuItem(); - - public CollectionDropdown() - : base(CollectionsStrings.Collection) - { - ItemSource = filters; - - Current.Value = allBeatmapsItem; - AlwaysShowSearchBar = true; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - realmSubscription = realm.RegisterForNotifications(r => r.All().OrderBy(c => c.Name), collectionsChanged); - - Current.BindValueChanged(selectionChanged); - } - - private void collectionsChanged(IRealmCollection collections, ChangeSet? changes) - { - if (changes == null) - { - filters.Clear(); - filters.Add(allBeatmapsItem); - filters.AddRange(collections.Select(c => new CollectionFilterMenuItem(c.ToLive(realm)))); - if (ShowManageCollectionsItem) - filters.Add(new ManageCollectionsFilterMenuItem()); - } - else - { - foreach (int i in changes.DeletedIndices.OrderDescending()) - filters.RemoveAt(i + 1); - - foreach (int i in changes.InsertedIndices) - filters.Insert(i + 1, new CollectionFilterMenuItem(collections[i].ToLive(realm))); - - var selectedItem = SelectedItem?.Value; - - foreach (int i in changes.NewModifiedIndices) - { - var updatedItem = collections[i]; - - // This is responsible for updating the state of the +/- button and the collection's name. - // TODO: we can probably make the menu items update with changes to avoid this. - filters.RemoveAt(i + 1); - filters.Insert(i + 1, new CollectionFilterMenuItem(updatedItem.ToLive(realm))); - - if (updatedItem.ID == selectedItem?.Collection?.ID) - { - // This current update and schedule is required to work around dropdown headers not updating text even when the selected item - // changes. It's not great but honestly the whole dropdown menu structure isn't great. This needs to be fixed, but I'll issue - // a warning that it's going to be a frustrating journey. - Current.Value = allBeatmapsItem; - Schedule(() => - { - // current may have changed before the scheduled call is run. - if (Current.Value != allBeatmapsItem) - return; - - Current.Value = filters.SingleOrDefault(f => f.Collection?.ID == selectedItem.Collection?.ID) ?? filters[0]; - }); - - break; - } - } - } - } - - private void selectionChanged(ValueChangedEvent filter) - { - // May be null during .Clear(). - if (filter.NewValue.IsNull()) - return; - - // Never select the manage collection filter - rollback to the previous filter. - // This is done after the above since it is important that bindable is unbound from OldValue, which is lost after forcing it back to the old value. - if (filter.NewValue is ManageCollectionsFilterMenuItem) - { - Current.Value = filter.OldValue; - manageCollectionsDialog?.Show(); - } - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - realmSubscription?.Dispose(); - } - - protected override LocalisableString GenerateItemText(CollectionFilterMenuItem item) => item.CollectionName; - - protected sealed override DropdownMenu CreateMenu() => CreateCollectionMenu(); - - protected virtual ShearedCollectionDropdownMenu CreateCollectionMenu() => new ShearedCollectionDropdownMenu(); - - protected partial class ShearedCollectionDropdownMenu : ShearedDropdownMenu - { - public ShearedCollectionDropdownMenu() - { - MaxHeight = 200; - } - - protected override DrawableDropdownMenuItem CreateDrawableDropdownMenuItem(MenuItem item) => new DrawableCollectionMenuItem(item) - { - BackgroundColourHover = HoverColour, - BackgroundColourSelected = SelectionColour - }; - } - - protected partial class DrawableCollectionMenuItem : ShearedDropdownMenu.ShearedMenuItem - { - private IconButton addOrRemoveButton = null!; - - private bool beatmapInCollection; - - private readonly Live? collection; - - [Resolved] - private IBindable beatmap { get; set; } = null!; - - public DrawableCollectionMenuItem(MenuItem item) - : base(item) - { - collection = ((DropdownMenuItem)item).Value.Collection; - } - - [BackgroundDependencyLoader] - private void load() - { - AddInternal(addOrRemoveButton = new NoFocusChangeIconButton - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Shear = -OsuGame.SHEAR, - X = -OsuScrollContainer.SCROLL_BAR_WIDTH, - Scale = new Vector2(0.65f), - Action = addOrRemove, - }); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - if (collection != null) - { - beatmap.BindValueChanged(_ => - { - beatmapInCollection = collection.PerformRead(c => c.BeatmapMD5Hashes.Contains(beatmap.Value.BeatmapInfo.MD5Hash)); - - addOrRemoveButton.Enabled.Value = !beatmap.IsDefault; - addOrRemoveButton.Icon = beatmapInCollection ? FontAwesome.Solid.MinusSquare : FontAwesome.Solid.PlusSquare; - addOrRemoveButton.TooltipText = beatmapInCollection ? CollectionsStrings.RemoveSelectedBeatmap : CollectionsStrings.AddSelectedBeatmap; - - updateButtonVisibility(); - }, true); - } - - updateButtonVisibility(); - } - - protected override bool OnHover(HoverEvent e) - { - updateButtonVisibility(); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - updateButtonVisibility(); - base.OnHoverLost(e); - } - - protected override void OnSelectChange() - { - base.OnSelectChange(); - updateButtonVisibility(); - } - - private void updateButtonVisibility() - { - if (collection == null) - addOrRemoveButton.Alpha = 0; - else - addOrRemoveButton.Alpha = IsHovered || IsPreSelected || beatmapInCollection ? 1 : 0; - } - - private void addOrRemove() - { - Debug.Assert(collection != null); - - Task.Run(() => collection.PerformWrite(c => - { - if (!c.BeatmapMD5Hashes.Remove(beatmap.Value.BeatmapInfo.MD5Hash)) - c.BeatmapMD5Hashes.Add(beatmap.Value.BeatmapInfo.MD5Hash); - })); - } - - protected override Drawable CreateContent() => (Content)base.CreateContent(); - - private partial class NoFocusChangeIconButton : IconButton - { - public override bool ChangeFocusOnClick => false; - } - } - } -} diff --git a/osu.Game/Tests/Visual/EditorSavingTestScene.cs b/osu.Game/Tests/Visual/EditorSavingTestScene.cs index 8d27618c00a0..5a3f5c432e59 100644 --- a/osu.Game/Tests/Visual/EditorSavingTestScene.cs +++ b/osu.Game/Tests/Visual/EditorSavingTestScene.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Menu; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK.Input; namespace osu.Game.Tests.Visual From b1044b6b2d4e4186807d413d9dccc196b2e31929 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Mar 2026 17:20:14 +0900 Subject: [PATCH 740/836] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 468b97ce29e7..e8daf491307b 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index 5966a28d50a8..0f4e8bb3a358 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From 317be21569335e7a624e0aba688c7b7678701af6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Mar 2026 17:24:29 +0900 Subject: [PATCH 741/836] Final attempt to make copy labels work --- .github/workflows/pull-request-copy-labels.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull-request-copy-labels.yml b/.github/workflows/pull-request-copy-labels.yml index b8b8c35d9b0e..a48a1ef974e4 100644 --- a/.github/workflows/pull-request-copy-labels.yml +++ b/.github/workflows/pull-request-copy-labels.yml @@ -5,8 +5,9 @@ on: types: [opened] permissions: - issues: read # to read the labels of any linked issue(s) - pull-requests: write # to put the found labels if any on the PR + issues: write + pull-requests: write + contents: read jobs: copy-labels: From e64e0f0ca9c1de81ecef8effb92781d4bd8f7df9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 3 Mar 2026 12:41:40 +0100 Subject: [PATCH 742/836] Fix beatmap set overlay not showing user tags at all Regressed in 60d9c358b8ec6a4be778078956c907a4d47c0360. In general an `APIBeatmap`'s `BeatmapSet` need not be present. In the usage site of `osu.Game.Overlays.BeatmapSet.Info`, `Beatmap` and `BeatmapSet` were actually two separate bindables. Moving the logic to a helper, and therefore implicitly moving `BeatmapSet` from tracking said separate bindable to instead refer to `Beatmap.BeatmapSet` broke this. --- .../BeatmapSet/BeatmapSetHeaderContent.cs | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs index f75e7b1d3c95..3c5f15addeed 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs @@ -242,12 +242,14 @@ private void load(OverlayColourProvider colourProvider) BeatmapSet.BindValueChanged(setInfo => { - Picker.BeatmapSet = rulesetSelector.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue; - cover.OnlineInfo = setInfo.NewValue; + var newBeatmapSet = setInfo.NewValue; + + Picker.BeatmapSet = rulesetSelector.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = newBeatmapSet; + cover.OnlineInfo = newBeatmapSet; downloadTracker?.RemoveAndDisposeImmediately(); - if (setInfo.NewValue == null) + if (newBeatmapSet == null) { onlineStatusPill.FadeTo(0.5f, 500, Easing.OutQuint); videoIconPill.Hide(); @@ -261,7 +263,10 @@ private void load(OverlayColourProvider colourProvider) } else { - downloadTracker = new BeatmapDownloadTracker(setInfo.NewValue); + foreach (var beatmap in newBeatmapSet.Beatmaps) + beatmap.BeatmapSet = newBeatmapSet; + + downloadTracker = new BeatmapDownloadTracker(newBeatmapSet); downloadTracker.State.BindValueChanged(_ => updateDownloadButtons()); AddInternal(downloadTracker); @@ -269,18 +274,18 @@ private void load(OverlayColourProvider colourProvider) loading.Hide(); - if (setInfo.NewValue.HasVideo) + if (newBeatmapSet.HasVideo) videoIconPill.Show(); else videoIconPill.Hide(); - if (setInfo.NewValue.HasStoryboard) + if (newBeatmapSet.HasStoryboard) storyboardIconPill.Show(); else storyboardIconPill.Hide(); - var titleText = new RomanisableString(setInfo.NewValue.TitleUnicode, setInfo.NewValue.Title); - var artistText = new RomanisableString(setInfo.NewValue.ArtistUnicode, setInfo.NewValue.Artist); + var titleText = new RomanisableString(newBeatmapSet.TitleUnicode, newBeatmapSet.Title); + var artistText = new RomanisableString(newBeatmapSet.ArtistUnicode, newBeatmapSet.Artist); title.Clear(); artist.Clear(); @@ -290,13 +295,13 @@ private void load(OverlayColourProvider colourProvider) title.AddArbitraryDrawable(Empty().With(d => d.Width = 5)); title.AddArbitraryDrawable(externalLink = new ExternalLinkButton()); - if (setInfo.NewValue.HasExplicitContent) + if (newBeatmapSet.HasExplicitContent) { title.AddArbitraryDrawable(Empty().With(d => d.Width = 10)); title.AddArbitraryDrawable(new ExplicitContentBeatmapBadge()); } - if (setInfo.NewValue.FeaturedInSpotlight) + if (newBeatmapSet.FeaturedInSpotlight) { title.AddArbitraryDrawable(Empty().With(d => d.Width = 10)); title.AddArbitraryDrawable(new SpotlightBeatmapBadge()); @@ -304,7 +309,7 @@ private void load(OverlayColourProvider colourProvider) artist.AddLink(artistText, LinkAction.SearchBeatmapSet, LocalisableString.Interpolate($@"artist=""""{artistText}""""")); - if (setInfo.NewValue.TrackId != null) + if (newBeatmapSet.TrackId != null) { artist.AddArbitraryDrawable(Empty().With(d => d.Width = 10)); artist.AddArbitraryDrawable(new FeaturedArtistBeatmapBadge()); From 2f96e96576e12115a3ea43b9ac62b1c2000f16a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 3 Mar 2026 12:48:00 +0100 Subject: [PATCH 743/836] Migrate realm populating online lookup source to use helper method for retrieving tags To reduce logic duplication. --- .../Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs b/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs index 2b75820587d0..821e791140ff 100644 --- a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs +++ b/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs @@ -101,10 +101,9 @@ private static void updateRealmBeatmapSet(Realm r, APIBeatmapSet onlineBeatmapSe if (dbBeatmap.MatchesOnlineVersion && dbBeatmap.Status != onlineBeatmap.Status) dbBeatmap.Status = onlineBeatmap.Status; - HashSet userTags = onlineBeatmap.TopTags? - .Select(t => (topTag: t, relatedTag: tagsById.GetValueOrDefault(t.TagId))) - .Where(t => t.relatedTag != null) - .Select(t => t.relatedTag!.Name) + onlineBeatmap.BeatmapSet = onlineBeatmapSet; + HashSet userTags = onlineBeatmap.GetTopUserTags()? + .Select(t => t.Tag.Name) .ToHashSet() ?? []; if (!userTags.SetEquals(dbBeatmap.Metadata.UserTags)) From 65b49137ee8ee9f233e6b9cc4bde589bd28bf235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 3 Mar 2026 12:49:41 +0100 Subject: [PATCH 744/836] Move constant closer to helper --- osu.Game/Online/API/Requests/Responses/APIBeatmap.cs | 6 ++++++ .../Screens/Ranking/UserTagControl.DrawableUserTag.cs | 9 ++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index 3a0afcd0abe2..ed2a395fc92c 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -117,6 +117,12 @@ private double hitLengthInSeconds [JsonProperty(@"owners")] public BeatmapOwner[] BeatmapOwners { get; set; } = Array.Empty(); + /// + /// Minimum count of votes required to display a tag on the beatmap's page. + /// Should match value specified web-side as https://github.com/ppy/osu-web/blob/cae2fdf03cfb8c30c8e332cfb142e03188ceffef/config/osu.php#L59. + /// + public const int MINIMUM_USER_TAG_VOTES_FOR_DISPLAY = 5; + public (APITag Tag, int VoteCount)[] GetTopUserTags() { if (TopTags == null || TopTags.Length == 0 || BeatmapSet?.RelatedTags == null) diff --git a/osu.Game/Screens/Ranking/UserTagControl.DrawableUserTag.cs b/osu.Game/Screens/Ranking/UserTagControl.DrawableUserTag.cs index 09af68a4f71e..2a26ebc3c688 100644 --- a/osu.Game/Screens/Ranking/UserTagControl.DrawableUserTag.cs +++ b/osu.Game/Screens/Ranking/UserTagControl.DrawableUserTag.cs @@ -13,6 +13,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Screens.Ranking { @@ -20,12 +21,6 @@ public partial class UserTagControl { public partial class DrawableUserTag : OsuAnimatedButton { - /// - /// Minimum count of votes required to display a tag on the beatmap's page. - /// Should match value specified web-side as https://github.com/ppy/osu-web/blob/cae2fdf03cfb8c30c8e332cfb142e03188ceffef/config/osu.php#L59. - /// - public const int MIN_VOTES_DISPLAY = 5; - public readonly UserTag UserTag; public Action? OnSelected { get; set; } @@ -160,7 +155,7 @@ protected override void LoadComplete() { voteCount.BindValueChanged(_ => { - confirmed.Value = voteCount.Value >= MIN_VOTES_DISPLAY; + confirmed.Value = voteCount.Value >= APIBeatmap.MINIMUM_USER_TAG_VOTES_FOR_DISPLAY; }, true); voted.BindValueChanged(v => { From d9e182230d085984e4650cfd3298d7812f664a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 3 Mar 2026 12:55:14 +0100 Subject: [PATCH 745/836] Add bool flag for checking tag vote threshold & utilise as required Closes https://github.com/ppy/osu/issues/36453. My omission was in assuming that web was going to start filtering out the tags below the threshold from API responses, which is not the case. Whether or not the consumers want or not to display tags below threshold is subjective. I figured that the matchmaking card tooltip might want to display below threshold but I dunno. --- osu.Game/Online/API/Requests/Responses/APIBeatmap.cs | 12 ++++++++++-- osu.Game/Overlays/BeatmapSet/Info.cs | 2 +- .../MatchmakingSelectPanel.CardContentBeatmap.cs | 4 ++-- .../SelectV2/RealmPopulatingOnlineLookupSource.cs | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index ed2a395fc92c..0d3724a76970 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -123,7 +123,15 @@ private double hitLengthInSeconds /// public const int MINIMUM_USER_TAG_VOTES_FOR_DISPLAY = 5; - public (APITag Tag, int VoteCount)[] GetTopUserTags() + /// + /// Retrieves top user tags for the beatmap, ordered in a way matching osu!web. + /// Requires to be populated. + /// + /// + /// If , only tags above will be shown. + /// If , all tags regardless of vote count will be shown. + /// + public (APITag Tag, int VoteCount)[] GetTopUserTags(bool confirmedOnly) { if (TopTags == null || TopTags.Length == 0 || BeatmapSet?.RelatedTags == null) return []; @@ -132,7 +140,7 @@ private double hitLengthInSeconds return TopTags .Select(t => (topTag: t, relatedTag: tagsById.GetValueOrDefault(t.TagId))) - .Where(t => t.relatedTag != null) + .Where(t => t.relatedTag != null && (!confirmedOnly || t.topTag.VoteCount >= MINIMUM_USER_TAG_VOTES_FOR_DISPLAY)) // see https://github.com/ppy/osu-web/blob/bb3bd2e7c6f84f26066df5ea20a81c77ec9bb60a/resources/js/beatmapsets-show/controller.ts#L103-L106 for sort criteria .OrderByDescending(t => t.topTag.VoteCount) .ThenBy(t => t.relatedTag!.Name) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index e25c1370c548..ca29724e8319 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -129,7 +129,7 @@ public Info() private void updateUserTags() { - userTags.Metadata = Beatmap.Value?.GetTopUserTags().Select(t => t.Tag.Name).ToArray(); + userTags.Metadata = Beatmap.Value?.GetTopUserTags(confirmedOnly: true).Select(t => t.Tag.Name).ToArray(); } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs index e2d5fa7890bf..de27e8fc6288 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs @@ -458,7 +458,7 @@ private void load(OverlayColourProvider colourProvider) new OsuSpriteText { Padding = new MarginPadding { Vertical = 3, Horizontal = 8 }, - Text = beatmap.GetTopUserTags().FirstOrDefault().Tag?.Name ?? string.Empty, + Text = beatmap.GetTopUserTags(confirmedOnly: true).FirstOrDefault().Tag?.Name ?? string.Empty, AlwaysPresent = true, Colour = colourProvider.Content2, Font = OsuFont.Style.Caption2, @@ -468,7 +468,7 @@ private void load(OverlayColourProvider colourProvider) }; } - public LocalisableString TooltipText => string.Join('\n', beatmap.GetTopUserTags().Select(t => $"{t.Tag.Name} ({t.VoteCount})")); + public LocalisableString TooltipText => string.Join('\n', beatmap.GetTopUserTags(confirmedOnly: false).Select(t => $"{t.Tag.Name} ({t.VoteCount})")); } } } diff --git a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs b/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs index 821e791140ff..46f97345c14f 100644 --- a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs +++ b/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs @@ -102,7 +102,7 @@ private static void updateRealmBeatmapSet(Realm r, APIBeatmapSet onlineBeatmapSe dbBeatmap.Status = onlineBeatmap.Status; onlineBeatmap.BeatmapSet = onlineBeatmapSet; - HashSet userTags = onlineBeatmap.GetTopUserTags()? + HashSet userTags = onlineBeatmap.GetTopUserTags(confirmedOnly: true) .Select(t => t.Tag.Name) .ToHashSet() ?? []; From 1aa42a73b102e7d5d452c2953bf367ba4530696b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 3 Mar 2026 13:38:23 +0100 Subject: [PATCH 746/836] Fix code quality --- osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs b/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs index 46f97345c14f..1850e6f6ac53 100644 --- a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs +++ b/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs @@ -70,7 +70,6 @@ public partial class RealmPopulatingOnlineLookupSource : Component private static void updateRealmBeatmapSet(Realm r, APIBeatmapSet onlineBeatmapSet) { - var tagsById = (onlineBeatmapSet.RelatedTags ?? []).ToDictionary(t => t.Id); var onlineBeatmaps = onlineBeatmapSet.Beatmaps.ToDictionary(b => b.OnlineID); var dbBeatmapSets = r.All().Where(b => b.OnlineID == onlineBeatmapSet.OnlineID); @@ -104,7 +103,7 @@ private static void updateRealmBeatmapSet(Realm r, APIBeatmapSet onlineBeatmapSe onlineBeatmap.BeatmapSet = onlineBeatmapSet; HashSet userTags = onlineBeatmap.GetTopUserTags(confirmedOnly: true) .Select(t => t.Tag.Name) - .ToHashSet() ?? []; + .ToHashSet(); if (!userTags.SetEquals(dbBeatmap.Metadata.UserTags)) { From a028f0ba4ae070771ae4b5d66ec7ee71222c7a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 3 Mar 2026 15:40:08 +0100 Subject: [PATCH 747/836] Fix loose spacers at top of leaderboard score context menu (#36799) Closes https://github.com/ppy/osu/issues/36777. --- osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs b/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs index 079f4192e04f..1f290ca12f6b 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs +++ b/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs @@ -628,7 +628,9 @@ MenuItem[] IHasContextMenu.ContextMenuItems if (Score.Files.Count <= 0) return items.ToArray(); - items.Add(new OsuMenuItemSpacer()); + if (items.Count > 0) + items.Add(new OsuMenuItemSpacer()); + items.Add(new OsuMenuItem(SongSelectStrings.WatchReplay, MenuItemType.Standard, () => game?.PresentScore(Score, ScorePresentType.Gameplay))); items.Add(new OsuMenuItem(CommonStrings.Export, MenuItemType.Standard, () => scoreManager.Export(Score))); items.Add(new OsuMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score)))); From 43af89f75c16b29655dcfc1c86fd6e4b68c36f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 4 Mar 2026 08:44:31 +0100 Subject: [PATCH 748/836] Remove outdated xmldoc --- osu.Game/Screens/Select/SongSelect.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 3b29c100b29d..56a1476c38ab 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -58,10 +58,6 @@ namespace osu.Game.Screens.Select { - /// - /// This screen is intended to house all components introduced in the new song select design to add transitions and examine the overall look. - /// This will be gradually built upon and ultimately replace once everything is in place. - /// public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler, ISongSelect, IHandlePresentBeatmap, IProvideCursor { /// From 9b55e1dfdb5836d4be1b93f8947919a4ff610baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 4 Mar 2026 10:34:35 +0100 Subject: [PATCH 749/836] Only show user tags above threshold by default --- osu.Game/Online/API/Requests/Responses/APIBeatmap.cs | 2 +- osu.Game/Overlays/BeatmapSet/Info.cs | 2 +- .../MatchmakingSelectPanel.CardContentBeatmap.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index 0d3724a76970..9c7992736329 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -131,7 +131,7 @@ private double hitLengthInSeconds /// If , only tags above will be shown. /// If , all tags regardless of vote count will be shown. /// - public (APITag Tag, int VoteCount)[] GetTopUserTags(bool confirmedOnly) + public (APITag Tag, int VoteCount)[] GetTopUserTags(bool confirmedOnly = true) { if (TopTags == null || TopTags.Length == 0 || BeatmapSet?.RelatedTags == null) return []; diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index ca29724e8319..e25c1370c548 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -129,7 +129,7 @@ public Info() private void updateUserTags() { - userTags.Metadata = Beatmap.Value?.GetTopUserTags(confirmedOnly: true).Select(t => t.Tag.Name).ToArray(); + userTags.Metadata = Beatmap.Value?.GetTopUserTags().Select(t => t.Tag.Name).ToArray(); } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs index de27e8fc6288..e2d5fa7890bf 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/MatchmakingSelectPanel.CardContentBeatmap.cs @@ -458,7 +458,7 @@ private void load(OverlayColourProvider colourProvider) new OsuSpriteText { Padding = new MarginPadding { Vertical = 3, Horizontal = 8 }, - Text = beatmap.GetTopUserTags(confirmedOnly: true).FirstOrDefault().Tag?.Name ?? string.Empty, + Text = beatmap.GetTopUserTags().FirstOrDefault().Tag?.Name ?? string.Empty, AlwaysPresent = true, Colour = colourProvider.Content2, Font = OsuFont.Style.Caption2, @@ -468,7 +468,7 @@ private void load(OverlayColourProvider colourProvider) }; } - public LocalisableString TooltipText => string.Join('\n', beatmap.GetTopUserTags(confirmedOnly: false).Select(t => $"{t.Tag.Name} ({t.VoteCount})")); + public LocalisableString TooltipText => string.Join('\n', beatmap.GetTopUserTags().Select(t => $"{t.Tag.Name} ({t.VoteCount})")); } } } From ae032622aca39420886cb8d3c9becadd9958d212 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 5 Mar 2026 00:31:43 +0900 Subject: [PATCH 750/836] Unimplement legacy compatibility method (#36812) The spectator server invokes both legacy and non-legacy methods to keep compatibility with older clients: https://github.com/ppy/osu-server-spectator/blob/fe0dad324587c8a12a2f203fd8289ce64182c2d9/osu.Server.Spectator/Hubs/Multiplayer/Matchmaking/Queue/MatchmakingQueueBackgroundService.cs#L292-L299 I thought that it'd be a good idea to implement the legacy method here, but it turns out to not be such a good idea because it means ranked-play clients will assume they're receiving a quick play invitation. --- osu.Game/Online/Matchmaking/IMatchmakingClient.cs | 2 ++ osu.Game/Online/Multiplayer/MultiplayerClient.cs | 4 ++-- osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Matchmaking/IMatchmakingClient.cs b/osu.Game/Online/Matchmaking/IMatchmakingClient.cs index e44eafb3903f..f4263e21bee8 100644 --- a/osu.Game/Online/Matchmaking/IMatchmakingClient.cs +++ b/osu.Game/Online/Matchmaking/IMatchmakingClient.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; namespace osu.Game.Online.Matchmaking @@ -26,6 +27,7 @@ public interface IMatchmakingClient : IStatefulUserHubClient /// /// Provided for compatibility with older clients - can be removed 20260825. /// + [Obsolete] Task MatchmakingRoomInvited(); /// diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index b9b4419cbb7c..04d7d287d18d 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -1085,8 +1085,8 @@ Task IMatchmakingClient.MatchmakingQueueLeft() Task IMatchmakingClient.MatchmakingRoomInvited() { - // Compatibility with older servers. - return ((IMatchmakingClient)this).MatchmakingRoomInvitedWithParams(new MatchmakingRoomInvitationParams { Type = MatchmakingPoolType.QuickPlay }); + // Not implemented (used by older clients). + return Task.CompletedTask; } Task IMatchmakingClient.MatchmakingRoomInvitedWithParams(MatchmakingRoomInvitationParams invitation) diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index b23a0b3db212..53e3edbe6b75 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -75,7 +75,6 @@ private void load(IAPIProvider api) connection.On(nameof(IMatchmakingClient.MatchmakingQueueJoined), ((IMatchmakingClient)this).MatchmakingQueueJoined); connection.On(nameof(IMatchmakingClient.MatchmakingQueueLeft), ((IMatchmakingClient)this).MatchmakingQueueLeft); - connection.On(nameof(IMatchmakingClient.MatchmakingRoomInvited), ((IMatchmakingClient)this).MatchmakingRoomInvited); connection.On(nameof(IMatchmakingClient.MatchmakingRoomInvitedWithParams), ((IMatchmakingClient)this).MatchmakingRoomInvitedWithParams); connection.On(nameof(IMatchmakingClient.MatchmakingRoomReady), ((IMatchmakingClient)this).MatchmakingRoomReady); connection.On(nameof(IMatchmakingClient.MatchmakingLobbyStatusChanged), ((IMatchmakingClient)this).MatchmakingLobbyStatusChanged); From cab50e94c8a14aed1835f25246d9bb3dbf9d11bc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 5 Mar 2026 00:44:03 +0900 Subject: [PATCH 751/836] Reduce online user list panel churn on initial display (#36811) Yes this is a funny way of doing it, but it works and is better than what we have for the initial release. Don't expect this to stay around forever. --- .../Dashboard/CurrentlyOnline/RealtimeUserList.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Dashboard/CurrentlyOnline/RealtimeUserList.cs b/osu.Game/Overlays/Dashboard/CurrentlyOnline/RealtimeUserList.cs index de1f3d2f137a..32f89dde4bc2 100644 --- a/osu.Game/Overlays/Dashboard/CurrentlyOnline/RealtimeUserList.cs +++ b/osu.Game/Overlays/Dashboard/CurrentlyOnline/RealtimeUserList.cs @@ -152,8 +152,12 @@ private void updateUsers() // This is quite dodgy – it affects the global `UserLookupCache`. // // but it's the best we can do for now. - // this should probaly be returned by server-spectator not osu-web. - user.LastVisit = DateTimeOffset.Now; + // this should probably be returned by server-spectator not osu-web. + var now = DateTimeOffset.Now; + + // Drop the seconds to avoid every new user appearing at the top of the list and causing + // the list to visually churn in an unusable way (especially on first display). + user.LastVisit = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, now.Offset); var panel = createUserPanel(user); updateUserSpectateState(presence.Value, panel); @@ -219,7 +223,9 @@ public override IEnumerable FlowingChildren default: case UserSortCriteria.LastVisit: // Todo: Last visit time is not currently updated according to realtime user presence. - return panels.OrderByDescending(panel => panel.User.LastVisit).ThenBy(panel => panel.User.Id); + return panels.OrderByDescending(panel => panel.User.LastVisit) + .ThenBy(panel => panel.User.Rank?.Rank != null) + .ThenBy(panel => panel.User.Rank?.Rank ?? 0); case UserSortCriteria.Rank: // Todo: Rank is not currently displayed in the panels. Additionally the sort mode kind of breaks if you change ruleset with this overlay open. From 020e6fa1b20eec4f12a00a0e466a84dda7029c92 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Wed, 4 Mar 2026 22:50:49 +0500 Subject: [PATCH 752/836] Reduce strain influence a bit more (#36813) Changes snap aim scaling to d/t^1.65 and speedflow scaling to d/t^1.9 (roughly). This is as much as we can nudge scaling towards d/t without breaking everything --- .../Difficulty/Evaluators/AimEvaluator.cs | 8 ++++---- .../Difficulty/Evaluators/SpeedAimEvaluator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs | 2 +- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 5f1a5a379c2d..d0fc0637035f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -11,9 +11,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { public static class AimEvaluator { - private const double wide_angle_multiplier = 1.4; - private const double acute_angle_multiplier = 2.6; - private const double slider_multiplier = 2.0; + private const double wide_angle_multiplier = 1.35; + private const double acute_angle_multiplier = 2.5; + private const double slider_multiplier = 1.9; private const double velocity_change_multiplier = 1.1; private const double wiggle_multiplier = 1.02; // WARNING: Increasing this multiplier beyond 1.02 reduces difficulty as distance increases. Refer to the desmos link above the wiggle bonus calculation @@ -171,7 +171,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // We decrease strain for distances 1 / (1 - Math.Pow(0.03, Math.Pow(ms / 1000, 0.75))) + private static double highBpmBonus(double ms, double distance) => 1 / (1 - Math.Pow(0.03, Math.Pow(ms / 1000, 0.65))) * DifficultyCalculationUtils.Smootherstep(distance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS); private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs index 9211ec39cf88..afa1245820cf 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs @@ -45,6 +45,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) return strain; } - private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.3, ms / 1000)); + private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.3, Math.Pow(ms / 1000, 0.9))); } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs index bc9de3494fa2..5826f497d623 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs @@ -29,7 +29,7 @@ public double ComputeAimRating(double aimDifficultyValue) if (mods.Any(m => m is OsuModAutopilot)) return 0; - double aimRating = Math.Pow(aimDifficultyValue, 0.58) * 0.0346; + double aimRating = Math.Pow(aimDifficultyValue, 0.62) * 0.0248; if (mods.Any(m => m is OsuModRelax)) aimRating *= 0.9; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index b0b1c5132fa0..33bb6b29c8b5 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -134,7 +134,7 @@ public OsuDifficultyHitObject(HitObject hitObject, HitObject lastObject, double AdjustedDeltaTime = Math.Max(DeltaTime, MIN_DELTA_TIME); LastObjectEndDeltaTime = lastDifficultyObject != null ? Math.Max(StartTime - lastDifficultyObject.EndTime, MIN_DELTA_TIME) : AdjustedDeltaTime; - SmallCircleBonus = Math.Max(1.0, 1.0 + (30 - BaseObject.Radius) / 60); + SmallCircleBonus = Math.Max(1.0, 1.0 + (30 - BaseObject.Radius) / 70); Preempt = BaseObject.TimePreempt / clockRate; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 50fc9333a798..3c8491a6dcd1 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -31,8 +31,8 @@ public Aim(Mod[] mods, bool includeSliders) private double currentAimStrain; private double currentSpeedStrain; - private double skillMultiplierAim => 58.5; - private double skillMultiplierSpeed => 2.0; + private double skillMultiplierAim => 65.2; + private double skillMultiplierSpeed => 2.8; private double skillMultiplierTotal => 1.0; private double meanExponent => 1.2; From 45945e3bb192a60bcb6efb7ea860b0c2d7ae4193 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Thu, 5 Mar 2026 07:01:33 +0300 Subject: [PATCH 753/836] Return tooltips to footer buttons on `MultiplayerMatchSongSelect` (#36817) - reported by @Loreos7 in https://discord.com/channels/188630481301012481/188630652340404224/1478809956076491006 - probably regressed in https://github.com/ppy/osu/pull/36752 --- osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs | 2 ++ osu.Game/Screens/OnlinePlay/FooterButtonFreestyle.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs index 28154180e66a..85299427ebc2 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs @@ -107,6 +107,8 @@ private void load() }, } }); + + TooltipText = MultiplayerMatchStrings.FreeModsButtonTooltip; } protected override void LoadComplete() diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyle.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyle.cs index 51b5020c94b9..e3ad226b18d2 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreestyle.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreestyle.cs @@ -36,6 +36,8 @@ private void load() Text = OnlinePlayStrings.FooterButtonFreestyle; Icon = FontAwesome.Solid.ExchangeAlt; AccentColour = colours.Lime1; + + TooltipText = MultiplayerMatchStrings.FreestyleButtonTooltip; } protected override void LoadComplete() From 28a18f768c16fe8a94d2581975b98ed3382a9006 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Thu, 5 Mar 2026 07:40:31 +0300 Subject: [PATCH 754/836] Use web localisation on `LeaderboardScopeSelector` to match `osu-web` (#36814) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - regressed in https://github.com/ppy/osu/commit/1f052bb195bfc5a2681b1b324bf34764641a1c40 - also see https://github.com/ppy/osu/pull/34074#discussion_r2211853662 did it by analogy with https://github.com/ppy/osu/blob/a0ecbd7c8704d6beee3e5c54c2ccb5f735872fb0/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs#L27-L49 | master | pr | `osu-web` | |-|-|-| | osu_2026-03-04_18-26-44 | ![osu_2026-03-04_18-36-12](https://github.com/user-attachments/assets/1498c4a9-7188-4e97-a6bd-3553b9befa5e) | Снимок экрана 2026-03-04 182558 | --------- Co-authored-by: Dean Herbert --- .../BeatmapSet/LeaderboardScopeSelector.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs b/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs index ed00f4b0e28d..55dfa52143a9 100644 --- a/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs @@ -1,12 +1,15 @@ // 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 osu.Game.Graphics.UserInterface; using osu.Framework.Allocation; using osuTK.Graphics; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Graphics; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Overlays.BeatmapSet @@ -39,6 +42,27 @@ public ScopeSelectorTabItem(BeatmapLeaderboardScope value) { } + protected override LocalisableString CreateText() + { + switch (Value) + { + case BeatmapLeaderboardScope.Global: + return BeatmapsetsStrings.ShowScoreboardGlobal; + + case BeatmapLeaderboardScope.Country: + return BeatmapsetsStrings.ShowScoreboardCountry; + + case BeatmapLeaderboardScope.Friend: + return BeatmapsetsStrings.ShowScoreboardFriend; + + case BeatmapLeaderboardScope.Team: + return BeatmapsetsStrings.ShowScoreboardTeam; + + default: + throw new ArgumentOutOfRangeException(); + } + } + protected override bool OnHover(HoverEvent e) { Text.FadeColour(AccentColour); From bb289363a2b8e6bf62be355f8570def018f0d7be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 5 Mar 2026 14:58:12 +0900 Subject: [PATCH 755/836] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 39e9a38179fd..89cf30c3ebbd 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From 43897457fb7b0617125aa05a084e4078633ad4ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 5 Mar 2026 14:37:50 +0100 Subject: [PATCH 756/836] Fix subscription leak from composer reloads (#36828) The reproduction scenario for the subscription leak is as follows: 1. Switch to a scrolling ruleset (anything but osu! from the standard ones). 2. Select a beatmap to edit. 3. Load the composer. 4. Go to timing tab. 5. Change a timing point. 6. Go back to the composer. At this point, `EditorChangeHandler.OnStateChange` will have multiple of the same delegate in the invocation list. Screenshot 2026-03-05 at 11 15 55 That in turn is caused by the fact that changing a timing point *does* incur a full reload of the composer via the following flow: https://github.com/ppy/osu/blob/15b6e28ebe888b1a87574891be1a0db3b04093b7/osu.Game/Rulesets/Edit/ScrollingHitObjectComposer.cs#L145 https://github.com/ppy/osu/blob/64a29313a852d50095ae4b7ea8f22fde23aa634f/osu.Game/Screens/Edit/Editor.cs#L1137-L1145 This flow is my "fault"; see https://github.com/ppy/osu/pull/28444. The reason why a full composer reload is used is not clear to my recollection at this time, but it is likely because it's just the least likely to fail. A smarter solution that wouldn't require a full reload would also entail checking that there exists a safe insertion point that allows replacing timing points in a way that will reflect everywhere it must. Including all of the `IScrollingAlgorithm` machinery and such. In general it is not uncommon in the codebase to not bother to clean up some event callbacks if it is implicitly or explicitly guaranteed that both objects bound by the callback will always get disposed in tandem at the same time. This *was* true with this particular flow to a point, which was until that full composer reload was implemented.
    To address the elephant in the room Someone will inevitably notice https://github.com/ppy/osu/pull/36824 which was a clanked pull request pointing out this leak. And then someone will inevitably call this "AI discrimination"! *Gasp!* So first of all, let me stop you right there. Yes, as far as I am _personally_ concerned, it is "AI discrimination". I invoke the full force of the Butlerian Jihad. The clank army's goal is to eradicate my job and make me work in an Amazon warehouse instead. Or, if not that, at least my job is to be rid of all remnants of fun I still get from it and for me to be reduced to that one guy from the meme "i guess we're doin circles now". You know the one. I resent this. You attack me directly. I do not perceive the need to meet you halfway or be civil. That said, I have too much respect for the users of this software to leave reports of potentially real issues unchecked. So I did check, and it was real. And you know what? Good job to the clanker. It did what it was designed to do: it parsed a code file, recognised a hole in a pattern it was designed to recognise, and invoked forms of language given to it to communicate this to the meatbag that opened that PR. And here's the thing: my primary issue is with that meatbag that opened that PR. That meatbag served no functional purpose in any of this. The meatbag took a hose that spews 90% water and 10% raw sewage at random intervals and pointed it at my house directly, claiming that they just want to clean it. At no point did the meatbag appear to have the common decency to pull out a container, pour some magic liquid out, check if there's sewage in it, and filter it out if there is any. But no, that would take *effort* and *thought*, would it not? The *effort* and *thought* that is required of *me* to *review* the clanker's work? The PR had no reproduction scenario, and had testing checkboxes that were presumably meant for *me* to check off. Why is it *my* job to figure all of this out rather than the submitter meatbag's? I do *not* have obligations towards spew-hose-pointing meatbags. Point that hose at your own backyard at your peril. If you *actually manage* to get the clanker to filter out *all* of the spew without fail itself, my only win condition is gone. But it is not yet that time. So at least have the decency to check for the spew yourself, rather than telling the clanker to put checkboxes in the PR descriptions telling *me* to check for it.
    --- .../Edit/DrawableEditorRulesetWrapper.cs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/osu.Game/Rulesets/Edit/DrawableEditorRulesetWrapper.cs b/osu.Game/Rulesets/Edit/DrawableEditorRulesetWrapper.cs index 174b278d8991..19ab9657dc30 100644 --- a/osu.Game/Rulesets/Edit/DrawableEditorRulesetWrapper.cs +++ b/osu.Game/Rulesets/Edit/DrawableEditorRulesetWrapper.cs @@ -49,17 +49,17 @@ protected override void LoadComplete() { base.LoadComplete(); - beatmap.HitObjectAdded += addHitObject; - beatmap.HitObjectRemoved += removeHitObject; + beatmap.HitObjectAdded += hitObjectAdded; + beatmap.HitObjectRemoved += hitObjectRemoved; if (changeHandler != null) { // for now only regenerate replay on a finalised state change, not HitObjectUpdated. - changeHandler.OnStateChange += () => Scheduler.AddOnce(regenerateAutoplay); + changeHandler.OnStateChange += stateChanged; } else { - beatmap.HitObjectUpdated += _ => Scheduler.AddOnce(regenerateAutoplay); + beatmap.HitObjectUpdated += hitObjectUpdated; } Scheduler.AddOnce(regenerateAutoplay); @@ -71,18 +71,22 @@ private void regenerateAutoplay() drawableRuleset.SetReplayScore(autoplayMod.CreateScoreFromReplayData(drawableRuleset.Beatmap, drawableRuleset.Mods)); } - private void addHitObject(HitObject hitObject) + private void hitObjectAdded(HitObject hitObject) { drawableRuleset.AddHitObject((TObject)hitObject); drawableRuleset.Playfield.PostProcess(); } - private void removeHitObject(HitObject hitObject) + private void hitObjectRemoved(HitObject hitObject) { drawableRuleset.RemoveHitObject((TObject)hitObject); drawableRuleset.Playfield.PostProcess(); } + private void hitObjectUpdated(HitObject _) => Scheduler.AddOnce(regenerateAutoplay); + + private void stateChanged() => Scheduler.AddOnce(regenerateAutoplay); + public override bool PropagatePositionalInputSubTree => false; public override bool PropagateNonPositionalInputSubTree => false; @@ -95,9 +99,13 @@ protected override void Dispose(bool isDisposing) if (beatmap.IsNotNull()) { - beatmap.HitObjectAdded -= addHitObject; - beatmap.HitObjectRemoved -= removeHitObject; + beatmap.HitObjectAdded -= hitObjectAdded; + beatmap.HitObjectRemoved -= hitObjectRemoved; + beatmap.HitObjectUpdated -= hitObjectUpdated; } + + if (changeHandler != null) + changeHandler.OnStateChange -= stateChanged; } } } From 6b10ef8709709f5581fa820699808e4b808eb44b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 5 Mar 2026 16:19:10 +0100 Subject: [PATCH 757/836] Disable presenting scores in online song selects (#36826) RFC. Closes https://github.com/ppy/osu/issues/36815 I guess. Song select V1 completely disabled the ability to view a score outside of solo play in ways that are very easy to let fly under the radar: https://github.com/ppy/osu/blob/5fc836d1f09cebf983313c9b91a5c252890c607a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs#L26 https://github.com/ppy/osu/blob/46db3ad96d0e1cd6ba4176b9b474cb79a338965d/osu.Game/Screens/Select/PlaySongSelect.cs#L47-L53 therefore the issue this is trying to close would never even manifest there. The direct cause of the issue is that the results screen is pushed to the relevant online screen's *substack* of screens rather than the game-global parent stack. That means that when the back button is pressed, the following logic fires: https://github.com/ppy/osu/blob/6fa4a7152f144ed2524f20ecf7cfd26492bbe61d/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs#L174-L189 This logic fires *on the parent screen* even though *the child screen* is the one the user is attempting to back out of. And none of the exemptions for the screen substack inside of the above method fire because the subscreen is not an `IOnlinePlaySubScreen` (it's `SoloResultsScreen` in this case). Now the direct cause here is probably fixable, although possibly not without some significant pulling of footer-shaped teeth. *However*, I kind of question as to why viewing scores should be permitted on online song selects in the first place - it kind of distracts from the primary purpose of the screens which is to *just pick a map already*. --- .../Multiplayer/MultiplayerMatchSongSelect.cs | 7 ++++++- .../OnlinePlay/OnlinePlayFreestyleSelect.cs | 7 ++++++- .../Playlists/PlaylistsSongSelect.cs | 7 ++++++- .../Screens/Select/BeatmapLeaderboardScore.cs | 4 +++- .../Screens/Select/BeatmapLeaderboardWedge.cs | 7 ++++++- osu.Game/Screens/Select/ISongSelect.cs | 8 +++++++- osu.Game/Screens/Select/SongSelect.cs | 19 +++++++++++++++---- 7 files changed, 49 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index ce5d68b004be..706f86a6eb4f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -23,6 +23,7 @@ using osu.Game.Overlays.Mods; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Scoring; using osu.Game.Screens.Footer; using osu.Game.Screens.Select; using osu.Game.Users; @@ -30,7 +31,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public partial class MultiplayerMatchSongSelect : SongSelect, IOnlinePlaySubScreen + public partial class MultiplayerMatchSongSelect : SongSelect, IOnlinePlaySubScreen, ISongSelect { public string ShortTitle => "song selection"; @@ -336,5 +337,9 @@ protected override void Dispose(bool isDisposing) base.Dispose(isDisposing); freeModSelectOverlayRegistration?.Dispose(); } + + bool ISongSelect.CanPresentScore => false; + + void ISongSelect.PresentScore(ScoreInfo score, ScorePresentType presentType) { } } } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs index 150cdb859dd6..58b92e9f8ab8 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs @@ -11,12 +11,13 @@ using osu.Game.Database; using osu.Game.Online.Rooms; using osu.Game.Rulesets; +using osu.Game.Scoring; using osu.Game.Screens.Footer; using osu.Game.Screens.Select; namespace osu.Game.Screens.OnlinePlay { - public abstract partial class OnlinePlayFreestyleSelect : SongSelect, IHandlePresentBeatmap, IOnlinePlaySubScreen + public abstract partial class OnlinePlayFreestyleSelect : SongSelect, IHandlePresentBeatmap, IOnlinePlaySubScreen, ISongSelect { private readonly PlaylistItem item; @@ -115,5 +116,9 @@ void IHandlePresentBeatmap.PresentBeatmap(WorkingBeatmap workingBeatmap, Ruleset { // This screen cannot present beatmaps. } + + bool ISongSelect.CanPresentScore => false; + + void ISongSelect.PresentScore(ScoreInfo score, ScorePresentType presentType) { } } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs index 7c1b3cd620e5..0fa0266cc952 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs @@ -17,13 +17,14 @@ using osu.Game.Overlays.Mods; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Scoring; using osu.Game.Screens.Footer; using osu.Game.Screens.Select; using osu.Game.Utils; namespace osu.Game.Screens.OnlinePlay.Playlists { - public partial class PlaylistsSongSelect : SongSelect, IOnlinePlaySubScreen + public partial class PlaylistsSongSelect : SongSelect, IOnlinePlaySubScreen, ISongSelect { public string ShortTitle => "song selection"; @@ -260,5 +261,9 @@ protected override void Dispose(bool isDisposing) base.Dispose(isDisposing); modSelectOverlayRegistration?.Dispose(); } + + bool ISongSelect.CanPresentScore => false; + + void ISongSelect.PresentScore(ScoreInfo score, ScorePresentType presentType) { } } } diff --git a/osu.Game/Screens/Select/BeatmapLeaderboardScore.cs b/osu.Game/Screens/Select/BeatmapLeaderboardScore.cs index dded40d6a215..bb96c97d520a 100644 --- a/osu.Game/Screens/Select/BeatmapLeaderboardScore.cs +++ b/osu.Game/Screens/Select/BeatmapLeaderboardScore.cs @@ -58,6 +58,7 @@ public sealed partial class BeatmapLeaderboardScore : OsuClickableContainer, IHa public int? Rank { get; init; } public HighlightType? Highlight { get; init; } + public Action? ShowReplay { get; init; } [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -630,7 +631,8 @@ MenuItem[] IHasContextMenu.ContextMenuItems if (items.Count > 0) items.Add(new OsuMenuItemSpacer()); - items.Add(new OsuMenuItem(SongSelectStrings.WatchReplay, MenuItemType.Standard, () => game?.PresentScore(Score, ScorePresentType.Gameplay))); + if (ShowReplay != null) + items.Add(new OsuMenuItem(SongSelectStrings.WatchReplay, MenuItemType.Standard, () => ShowReplay.Invoke(Score))); items.Add(new OsuMenuItem(CommonStrings.Export, MenuItemType.Standard, () => scoreManager.Export(Score))); items.Add(new OsuMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score)))); diff --git a/osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs b/osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs index 25eac3e18232..660b5110113b 100644 --- a/osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs +++ b/osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs @@ -308,7 +308,12 @@ protected void SetScores(IEnumerable scores, ScoreInfo? userScore = n Rank = i + 1, Highlight = highlightType, SelectedMods = { BindTarget = mods }, - Action = () => onLeaderboardScoreClicked(s), + Action = songSelect?.CanPresentScore == true + ? () => songSelect.PresentScore(s) + : null, + ShowReplay = songSelect?.CanPresentScore == true + ? info => songSelect.PresentScore(info, ScorePresentType.Gameplay) + : null }; }), loadedScores => { diff --git a/osu.Game/Screens/Select/ISongSelect.cs b/osu.Game/Screens/Select/ISongSelect.cs index b1c32435bf7f..d63f241c80ce 100644 --- a/osu.Game/Screens/Select/ISongSelect.cs +++ b/osu.Game/Screens/Select/ISongSelect.cs @@ -31,11 +31,17 @@ public interface ISongSelect ///
    void ManageCollections(); + /// + /// Whether can be performed by this screen. + /// If , will have no effect. + /// + bool CanPresentScore { get; } + /// /// Opens results screen with the given score. /// This assumes active beatmap and ruleset selection matches the score. /// - void PresentScore(ScoreInfo score); + void PresentScore(ScoreInfo score, ScorePresentType presentType = ScorePresentType.Results); /// /// Set the current filter text query to the provided string. diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 56a1476c38ab..51e814b1a177 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -1148,12 +1148,23 @@ private void fetchOnlineInfo(bool force = false) void ISongSelect.Search(string query) => FilterControl.Search(query); - void ISongSelect.PresentScore(ScoreInfo score) + bool ISongSelect.CanPresentScore => true; + + void ISongSelect.PresentScore(ScoreInfo score, ScorePresentType presentType) { - Debug.Assert(Beatmap.Value.BeatmapInfo.Equals(score.BeatmapInfo)); - Debug.Assert(Ruleset.Value.Equals(score.Ruleset)); + switch (presentType) + { + case ScorePresentType.Results: + Debug.Assert(Beatmap.Value.BeatmapInfo.Equals(score.BeatmapInfo)); + Debug.Assert(Ruleset.Value.Equals(score.Ruleset)); + + this.Push(new SoloResultsScreen(score)); + break; - this.Push(new SoloResultsScreen(score)); + case ScorePresentType.Gameplay: + (game as OsuGame)?.PresentScore(score, presentType); + break; + } } #endregion From b76a7e1bb64f0747ef06d832eb2e87d052ca030d Mon Sep 17 00:00:00 2001 From: Krzysztof Gutkowski Date: Thu, 5 Mar 2026 18:09:05 +0100 Subject: [PATCH 758/836] Refactor `ShearedButton` to allow easier relative sizing (#36802) This commit rearranges the contents of `ShearedButtons` to be more independent of each other in regards to sizing. Thanks to that, the custom logic related to enabling autosizing is no longer necessary. Witdh and height are no longer set via the constructor, and can be freely configured using the initializer syntax. Additionally, this allows the button to use relative sizing without having to resort to any hackery with `Size` (this will come in handy for me when implementing the new footer on multiplayer screens). Given that most of the `ShearedButton`s currently in use set their width explicitly, I did not set `AutoSizeAxes = Axes.X` like it would be by default previously. Instead it is set on the only two such buttons (show converts/selected mods on ssv2). I suppose it might be a good idea to have it set that by default if no `Width` is specified, as right now it'll just not show anything. Also I've set the margin on the text field by default in all cases instead of only when autosizing like how it was previously, since otherwise it would be a pain to set that on each button instance when needed. I've checked all affected components and could not find any text overflowing issues that this could cause. --------- Co-authored-by: Dean Herbert --- .../TestSceneScreenFooterNavigation.cs | 4 +- .../UserInterface/TestSceneButtonsInput.cs | 3 +- .../UserInterface/TestSceneScreenFooter.cs | 4 +- .../UserInterface/TestSceneShearedButtons.cs | 21 +++++-- .../Graphics/UserInterface/ShearedButton.cs | 62 +++++++------------ .../UserInterface/ShearedToggleButton.cs | 15 ----- osu.Game/Overlays/Mods/AddPresetButton.cs | 1 - osu.Game/Overlays/Mods/AddPresetPopover.cs | 3 +- .../Overlays/Mods/DeselectAllModsButton.cs | 3 +- osu.Game/Overlays/Mods/EditPresetPopover.cs | 6 +- osu.Game/Overlays/Mods/SelectAllModsButton.cs | 3 +- osu.Game/Overlays/WizardOverlay.cs | 3 +- osu.Game/Screens/Footer/ScreenBackButton.cs | 7 +-- .../Matchmaking/Queue/ScreenQueue.cs | 16 ++--- .../Playlists/AddToPlaylistFooterButton.cs | 7 +-- .../Select/BeatmapDetailsArea.Header.cs | 1 + .../FilterControl.ScopedBeatmapSetDisplay.cs | 3 +- osu.Game/Screens/Select/FilterControl.cs | 1 + 18 files changed, 67 insertions(+), 96 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenFooterNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenFooterNavigation.cs index 27c7528efa2a..7c8ff56a57f5 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenFooterNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenFooterNavigation.cs @@ -349,8 +349,8 @@ private void load() AutoSizeAxes = Axes.Both, Children = new[] { - new ShearedButton(200) { Text = "Action #1", Action = () => { } }, - new ShearedButton(140) { Text = "Action #2", Action = () => { } }, + new ShearedButton { Width = 200, Text = "Action #1", Action = () => { } }, + new ShearedButton { Width = 140, Text = "Action #2", Action = () => { } }, } }; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs index f30b82d618b7..5c98f27d8618 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs @@ -72,12 +72,13 @@ public TestSceneButtonsInput() Enabled = { Value = true }, Text = "Rounded button" }, - shearedButton = new ShearedButton(width) + shearedButton = new ShearedButton { Text = "Sheared button", LighterColour = Colour4.FromHex("#FFFFFF"), DarkerColour = Colour4.FromHex("#FFCC22"), TextColour = Colour4.Black, + Width = width, Height = 40, Enabled = { Value = true }, Padding = new MarginPadding(0) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs index a958c5f43e9a..97b72924971f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs @@ -342,8 +342,8 @@ private void load() AutoSizeAxes = Axes.Both, Children = new[] { - new ShearedButton(200) { Text = "Action #1", Action = () => { } }, - new ShearedButton(140) { Text = "Action #2", Action = () => { } }, + new ShearedButton { Width = 200, Text = "Action #1", Action = () => { } }, + new ShearedButton { Width = 140, Text = "Action #2", Action = () => { } }, } }; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs index bdec96f44681..f226920cb633 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs @@ -36,8 +36,10 @@ public void TestShearedButton(bool bigButton) if (bigButton) { - Child = button = new ShearedButton(400, 80) + Child = button = new ShearedButton { + Width = 400, + Height = 80, LighterColour = Colour4.FromHex("#FFFFFF"), DarkerColour = Colour4.FromHex("#FFCC22"), TextColour = Colour4.Black, @@ -50,8 +52,10 @@ public void TestShearedButton(bool bigButton) } else { - Child = button = new ShearedButton(200, 80) + Child = button = new ShearedButton { + Width = 200, + Height = 80, LighterColour = Colour4.FromHex("#FF86DD"), DarkerColour = Colour4.FromHex("#DE31AE"), TextColour = Colour4.White, @@ -79,8 +83,9 @@ public void TestShearedToggleButton() AddStep("create button", () => { - Child = button = new ShearedToggleButton(200) + Child = button = new ShearedToggleButton { + Width = 200, Anchor = Anchor.Centre, Origin = Anchor.Centre, Text = "Toggle me", @@ -96,8 +101,9 @@ public void TestSizing() { ShearedToggleButton toggleButton = null; - AddStep("create fixed width button", () => Child = toggleButton = new ShearedToggleButton(200) + AddStep("create fixed width button", () => Child = toggleButton = new ShearedToggleButton { + Width = 200, Anchor = Anchor.Centre, Origin = Anchor.Centre, Text = "Fixed width" @@ -109,6 +115,7 @@ public void TestSizing() AddStep("create auto-sizing button", () => Child = toggleButton = new ShearedToggleButton { + AutoSizeAxes = Axes.X, Anchor = Anchor.Centre, Origin = Anchor.Centre, Text = "This button autosizes to its text!" @@ -130,8 +137,9 @@ public void TestDisabledState() AddStep("create button", () => { - Child = button = new ShearedToggleButton(200) + Child = button = new ShearedToggleButton { + Width = 200, Anchor = Anchor.Centre, Origin = Anchor.Centre, Text = "Toggle me", @@ -186,6 +194,7 @@ public void TestButtons() { new ShearedButton { + AutoSizeAxes = Axes.X, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Text = "Button", @@ -194,6 +203,7 @@ public void TestButtons() }, new ShearedButton { + AutoSizeAxes = Axes.X, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Text = "Button", @@ -202,6 +212,7 @@ public void TestButtons() }, new ShearedButton { + AutoSizeAxes = Axes.X, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Text = "Button", diff --git a/osu.Game/Graphics/UserInterface/ShearedButton.cs b/osu.Game/Graphics/UserInterface/ShearedButton.cs index 2047fc74f40e..e6737d6a5750 100644 --- a/osu.Game/Graphics/UserInterface/ShearedButton.cs +++ b/osu.Game/Graphics/UserInterface/ShearedButton.cs @@ -75,19 +75,15 @@ public Colour4 TextColour protected readonly Container ButtonContent; /// - /// Creates a new + /// Creates a new /// - /// - /// The width of the button. - /// - /// If a non- value is provided, this button will have a fixed width equal to the provided value. - /// If a value is provided (or the argument is omitted entirely), the button will autosize in width to fit the text. - /// - /// - /// The height of the button. - public ShearedButton(float? width = null, float height = DEFAULT_HEIGHT) + /// + /// By default, the button will have a height of . + /// Width should be set for each usage. + /// + public ShearedButton() { - Height = height; + Height = DEFAULT_HEIGHT; Shear = OsuGame.SHEAR; @@ -99,27 +95,25 @@ public ShearedButton(float? width = null, float height = DEFAULT_HEIGHT) { backgroundLayer = new Container { - RelativeSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.Both, CornerRadius = CORNER_RADIUS, Masking = true, BorderThickness = BORDER_THICKNESS, - Children = new Drawable[] + Child = background = new Box { - background = new Box - { - RelativeSizeAxes = Axes.Both - }, - ButtonContent = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Shear = -OsuGame.SHEAR, - Child = text = new OsuSpriteText - { - Font = OsuFont.TorusAlternate.With(size: 17), - } - }, + RelativeSizeAxes = Axes.Both, + }, + }, + ButtonContent = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Shear = -OsuGame.SHEAR, + Child = text = new OsuSpriteText + { + Font = OsuFont.TorusAlternate.With(size: 17), + Margin = new MarginPadding { Horizontal = 15 }, } }, flashLayer = new Box @@ -130,18 +124,6 @@ public ShearedButton(float? width = null, float height = DEFAULT_HEIGHT) Alpha = 0, }, }; - - if (width != null) - { - Width = width.Value; - backgroundLayer.RelativeSizeAxes = Axes.Both; - } - else - { - AutoSizeAxes = Axes.X; - backgroundLayer.AutoSizeAxes = Axes.X; - text.Margin = new MarginPadding { Horizontal = 15 }; - } } protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet) { Enabled = { BindTarget = Enabled } }; diff --git a/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs b/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs index c2f547ba1933..7731425635ca 100644 --- a/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs +++ b/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs @@ -24,21 +24,6 @@ public partial class ShearedToggleButton : ShearedButton /// public BindableBool Active { get; } = new BindableBool(); - /// - /// Creates a new - /// - /// - /// The width of the button. - /// - /// If a non- value is provided, this button will have a fixed width equal to the provided value. - /// If a value is provided (or the argument is omitted entirely), the button will autosize in width to fit the text. - /// - /// - public ShearedToggleButton(float? width = null) - : base(width) - { - } - [BackgroundDependencyLoader] private void load(AudioManager audio) { diff --git a/osu.Game/Overlays/Mods/AddPresetButton.cs b/osu.Game/Overlays/Mods/AddPresetButton.cs index e4f7f83c1102..0844291f91df 100644 --- a/osu.Game/Overlays/Mods/AddPresetButton.cs +++ b/osu.Game/Overlays/Mods/AddPresetButton.cs @@ -27,7 +27,6 @@ public partial class AddPresetButton : ShearedToggleButton, IHasPopover private Bindable> selectedMods { get; set; } = null!; public AddPresetButton() - : base(1) { RelativeSizeAxes = Axes.X; Height = ModSelectPanel.HEIGHT; diff --git a/osu.Game/Overlays/Mods/AddPresetPopover.cs b/osu.Game/Overlays/Mods/AddPresetPopover.cs index 817a61f7ac60..831f03f78c57 100644 --- a/osu.Game/Overlays/Mods/AddPresetPopover.cs +++ b/osu.Game/Overlays/Mods/AddPresetPopover.cs @@ -74,11 +74,12 @@ public AddPresetPopover(AddPresetButton addPresetButton) Direction = FillDirection.Vertical, Children = new Drawable[] { - createButton = new ShearedButton(content_width) + createButton = new ShearedButton { // todo: for some very odd reason, this needs to be anchored to topright for the fill flow to be correctly sized to the AABB of the sheared button Anchor = Anchor.TopRight, Origin = Anchor.TopRight, + Width = content_width, Text = ModSelectOverlayStrings.AddPreset, Action = createPreset } diff --git a/osu.Game/Overlays/Mods/DeselectAllModsButton.cs b/osu.Game/Overlays/Mods/DeselectAllModsButton.cs index 0e60fc34147e..9b8ae1e3b6b0 100644 --- a/osu.Game/Overlays/Mods/DeselectAllModsButton.cs +++ b/osu.Game/Overlays/Mods/DeselectAllModsButton.cs @@ -15,8 +15,9 @@ public partial class DeselectAllModsButton : ShearedButton private readonly Bindable> selectedMods = new Bindable>(); public DeselectAllModsButton(ModSelectOverlay modSelectOverlay) - : base(ModSelectOverlay.BUTTON_WIDTH) { + Width = ModSelectOverlay.BUTTON_WIDTH; + Text = CommonStrings.DeselectAll; Action = modSelectOverlay.DeselectAll; diff --git a/osu.Game/Overlays/Mods/EditPresetPopover.cs b/osu.Game/Overlays/Mods/EditPresetPopover.cs index eb128c77921a..820ffad26551 100644 --- a/osu.Game/Overlays/Mods/EditPresetPopover.cs +++ b/osu.Game/Overlays/Mods/EditPresetPopover.cs @@ -114,22 +114,24 @@ private void load() Direction = FillDirection.Vertical, Children = new Drawable[] { - useCurrentModsButton = new ShearedButton(content_width) + useCurrentModsButton = new ShearedButton { // todo: for some very odd reason, this needs to be anchored to topright for the fill flow to be correctly sized to the AABB of the sheared button Anchor = Anchor.TopRight, Origin = Anchor.TopRight, + Width = content_width, Text = ModSelectOverlayStrings.UseCurrentMods, DarkerColour = colours.Blue1, LighterColour = colours.Blue0, TextColour = colourProvider.Background6, Action = useCurrentMods, }, - saveButton = new ShearedButton(content_width) + saveButton = new ShearedButton { // todo: for some very odd reason, this needs to be anchored to topright for the fill flow to be correctly sized to the AABB of the sheared button Anchor = Anchor.TopRight, Origin = Anchor.TopRight, + Width = content_width, Text = Resources.Localisation.Web.CommonStrings.ButtonsSave, DarkerColour = colours.Orange1, LighterColour = colours.Orange0, diff --git a/osu.Game/Overlays/Mods/SelectAllModsButton.cs b/osu.Game/Overlays/Mods/SelectAllModsButton.cs index 1da762d164f6..2fb72ef2c423 100644 --- a/osu.Game/Overlays/Mods/SelectAllModsButton.cs +++ b/osu.Game/Overlays/Mods/SelectAllModsButton.cs @@ -18,8 +18,9 @@ public partial class SelectAllModsButton : ShearedButton private readonly Bindable searchTerm = new Bindable(); public SelectAllModsButton(FreeModSelectOverlay modSelectOverlay) - : base(ModSelectOverlay.BUTTON_WIDTH) { + Width = ModSelectOverlay.BUTTON_WIDTH; + Text = CommonStrings.SelectAll; Action = modSelectOverlay.SelectAll; diff --git a/osu.Game/Overlays/WizardOverlay.cs b/osu.Game/Overlays/WizardOverlay.cs index 3cc403dbffef..a75f1aff3c2d 100644 --- a/osu.Game/Overlays/WizardOverlay.cs +++ b/osu.Game/Overlays/WizardOverlay.cs @@ -245,10 +245,9 @@ private void load(OverlayColourProvider colourProvider) Padding = new MarginPadding { Right = OsuGame.SCREEN_EDGE_MARGIN }; - InternalChild = NextButton = new ShearedButton(0) + InternalChild = NextButton = new ShearedButton { RelativeSizeAxes = Axes.X, - Width = 1, Text = FirstRunSetupOverlayStrings.GetStarted, DarkerColour = colourProvider.Colour3, LighterColour = colourProvider.Colour2, diff --git a/osu.Game/Screens/Footer/ScreenBackButton.cs b/osu.Game/Screens/Footer/ScreenBackButton.cs index 481192088c36..37d4260d1825 100644 --- a/osu.Game/Screens/Footer/ScreenBackButton.cs +++ b/osu.Game/Screens/Footer/ScreenBackButton.cs @@ -32,14 +32,11 @@ public sealed override bool ReceivePositionalInputAt(Vector2 screenSpacePos) return inputRectangle.Contains(ToLocalSpace(screenSpacePos)); } - public ScreenBackButton() - : base(BUTTON_WIDTH) - { - } - [BackgroundDependencyLoader] private void load() { + Width = BUTTON_WIDTH; + ButtonContent.Child = new FillFlowContainer { X = -10f, diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs index da4b3e96023a..87d50213ee8c 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs @@ -269,12 +269,13 @@ public void SetState(MatchmakingScreenState newState) AvailablePools = { BindTarget = availablePools }, SelectedPool = { BindTarget = selectedPool } }, - new BeginQueueingButton(200) + new BeginQueueingButton { DarkerColour = colours.Blue2, LighterColour = colours.Blue1, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, + Width = 200, SelectedPool = { BindTarget = selectedPool }, Action = () => { @@ -308,12 +309,13 @@ public void SetState(MatchmakingScreenState newState) { State = { Value = Visibility.Visible }, }, - new ShearedButton(200) + new ShearedButton { DarkerColour = colours.Red3, LighterColour = colours.Red4, Anchor = Anchor.Centre, Origin = Anchor.Centre, + Width = 200, Text = "Stop queueing", Action = () => client.MatchmakingLeaveQueue().FireAndForget() } @@ -430,11 +432,6 @@ private partial class BeginQueueingButton : SelectionButton { public readonly IBindable SelectedPool = new Bindable(); - public BeginQueueingButton(float? width = null) - : base(width) - { - } - protected override void LoadComplete() { base.LoadComplete(); @@ -445,11 +442,6 @@ protected override void LoadComplete() private partial class SelectionButton : ShearedButton, IKeyBindingHandler { - protected SelectionButton(float? width = null, float height = DEFAULT_HEIGHT) - : base(width, height) - { - } - public bool OnPressed(KeyBindingPressEvent e) { if (e.Action == GlobalAction.Select && !e.Repeat) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs index 1d8dcf37ab74..622b87503fda 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs @@ -13,14 +13,11 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { public partial class AddToPlaylistFooterButton : ShearedButton { - public AddToPlaylistFooterButton() - : base(width: 220) - { - } - [BackgroundDependencyLoader] private void load(OsuColour colours) { + Width = 220; + DarkerColour = colours.Blue3; LighterColour = colours.Blue1; diff --git a/osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs b/osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs index fd6437d1a967..b20254a35c9c 100644 --- a/osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs +++ b/osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs @@ -76,6 +76,7 @@ private void load(OsuConfigManager config) { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, + AutoSizeAxes = Axes.X, Text = UserInterfaceStrings.SelectedMods, Height = 30f, // Eyeballed to make spacing match. Because shear is silly and implemented in different ways between dropdown and button. diff --git a/osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs b/osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs index 78dfb163ade5..040081605f89 100644 --- a/osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs +++ b/osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs @@ -73,10 +73,11 @@ private void load(ISongSelect? songSelect, OverlayColourProvider colourProvider) Colour = colourProvider.Background6, Padding = new MarginPadding { Right = 80, Vertical = 5 } }, - new ShearedButton(80) + new ShearedButton { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, + Width = 80, Text = CommonStrings.Back, RelativeSizeAxes = Axes.Y, Height = 1, diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 7473a2153160..4867e7de8c62 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -151,6 +151,7 @@ private void load(IAPIProvider api) { Anchor = Anchor.Centre, Origin = Anchor.Centre, + AutoSizeAxes = Axes.X, Text = UserInterfaceStrings.ShowConverts, Height = 30f, }, From b945e2e27776bc23961168e5a98a2ab70132b730 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Thu, 5 Mar 2026 23:11:04 +0500 Subject: [PATCH 759/836] Adjust wide aim bonus cutoff after SpeedAim changes (#36835) Removing exponent since after d/t rescaling it's just making low spaced streams way too nerfed --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index d0fc0637035f..9f9bbb7eb32b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -95,7 +95,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3)); // Apply full wide angle bonus for distance more than SINGLE_SPACING_THRESHOLD - wideAngleBonus *= angleBonus * Math.Pow(DifficultyCalculationUtils.Smoothstep(currDistance, 0, SpeedAimEvaluator.SINGLE_SPACING_THRESHOLD), 3.0); + wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smoothstep(currDistance, 0, SpeedAimEvaluator.SINGLE_SPACING_THRESHOLD); // Apply wiggle bonus for jumps that are [radius, 3*diameter] in distance, with < 110 angle // https://www.desmos.com/calculator/dp0v0nvowc From ba2ae3218e4dd377505eadbb0007b6a20b63a2d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 6 Mar 2026 07:29:47 +0100 Subject: [PATCH 760/836] Show first two slider repeats with the rest of the combo in Freeze Frame mod (#36427) Before: https://github.com/user-attachments/assets/95b19bdb-12c5-4ee7-b7e2-f9098aecd2fa After: https://github.com/user-attachments/assets/937081c5-92cb-4bea-a774-e53afbdbb1fb --- This is a subjective diff and can be closed on the spot with no discussion if deemed incorrect. I mostly just want to get it off my list of unresolved forum threads. The catalyst for this change is [this thread](https://osu.ppy.sh/community/forums/topics/2171493?n=1), wherein the complaint is that you can get jumpscared by a slider repeat in a combo because the slider repeats do not fade in with the rest of the combo. Which means that you don't immediately know whether a slider will need to be repeated or not and you have to watch out for potential slider repeats fading in, which could happen at an *arbitrary* time because it's still dependent on the map's original AR. This seems pretty anti-user so I made it fade in with the rest of the combo. The original comment cited "broken layering" which I guess refers to the fact that sliders can repeat *more* than once and the second repeat will show *under the slider head*. It's pretty broken, sure, but I don't think it's *that* bad, and I *do* think that it's better than the current behaviour. The reason it shows only the first two repeats is that there's no point in showing more for reasons that are hopefully obvious. --- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index fe45199ae450..b89280212746 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -62,14 +62,22 @@ void applyFadeInAdjustment(OsuHitObject osuObject) if (osuObject is not Spinner) osuObject.TimePreempt += osuObject.StartTime - lastNewComboTime; + int repeatCount = 0; + foreach (var nested in osuObject.NestedHitObjects.OfType()) { switch (nested) { - //Freezing the SliderTicks doesnt play well with snaking sliders + // Freezing the SliderTicks doesnt play well with snaking sliders case SliderTick: - //SliderRepeat wont layer correctly if preempt is changed. + break; + case SliderRepeat: + if (repeatCount > 2) + break; + + applyFadeInAdjustment(nested); + repeatCount++; break; default: From e9112179803af6c4781823ee40f4539854a56f7b Mon Sep 17 00:00:00 2001 From: Eeli Ogata Date: Fri, 6 Mar 2026 08:36:39 +0000 Subject: [PATCH 761/836] Fix crash when clicking panels during recycling (#36457) Closes #36246 This PR overrides `HandlePositionalInput` to reject all positional input when `Item` is null. --------- Co-authored-by: Dean Herbert --- .../SongSelect/TestSceneBeatmapCarousel.cs | 17 +++++++++++++++++ osu.Game/Screens/Select/Panel.cs | 10 ++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index b7c113cffb9d..85a5201b96e5 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -95,6 +95,23 @@ public void TestRandomStatus() }); } + [Test] + public void TestClickExpiredPanel() + { + CreateCarousel(); + + AddStep("set eager loading very low", () => + { + Carousel.DistanceOffscreenToPreload = -100; + }); + + AddBeatmaps(50, 10); + + AddUntilStep("wait for panels", () => Carousel.ChildrenOfType().Any()); + + AddRepeatStep("click last panel", () => Carousel.ChildrenOfType().FirstOrDefault()?.TriggerClick(), 20); + } + [Test] public void TestHighChurnUpdatesStillShowsPanels() { diff --git a/osu.Game/Screens/Select/Panel.cs b/osu.Game/Screens/Select/Panel.cs index 60175d0a0d30..a02710b0a6ef 100644 --- a/osu.Game/Screens/Select/Panel.cs +++ b/osu.Game/Screens/Select/Panel.cs @@ -265,7 +265,12 @@ protected override void FreeAfterUse() protected override bool OnClick(ClickEvent e) { - carousel?.Activate(Item!); + // Item may be set to null before actual `FreeAfterUse`. + // This is because Carousel knows to do this ahead of time and let the drawable fade/animate away. + // See https://github.com/ppy/osu/blob/033e13cb3b79e6195ddcd9f659b04095aa52fd2f/osu.Game/Graphics/Carousel/Carousel.cs#L1132-L1135. + if (item != null) + carousel?.Activate(item); + return true; } @@ -362,7 +367,8 @@ public CarouselItem? Item if (ReferenceEquals(item, value)) return; - // If a new item is set and we already have an item, this is a case of reuse. + // If a new item is set and we already have an item, this is a special case of reuse. + // See https://github.com/ppy/osu/blob/033e13cb3b79e6195ddcd9f659b04095aa52fd2f/osu.Game/Graphics/Carousel/Carousel.cs#L1071 // To keep things simple, assume that we need to do a full refresh. // // In the future, this could be more contextual and check whether the associated model has actually changed. From c1555af620e6c60c429e0a38bd9116a1a4ca2f01 Mon Sep 17 00:00:00 2001 From: Eeli Ogata Date: Fri, 6 Mar 2026 08:56:14 +0000 Subject: [PATCH 762/836] Only play nightcore hat sounds when tick rate is a multiple of 2 (#36459) Closes #13513 Matches stable behavior where hat only plays when the slider tick rate is a multiple of 2. --------- Co-authored-by: Dean Herbert --- osu.Game/Rulesets/Mods/ModNightcore.cs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModNightcore.cs b/osu.Game/Rulesets/Mods/ModNightcore.cs index 75adc1e4bfad..a6196dcad4d3 100644 --- a/osu.Game/Rulesets/Mods/ModNightcore.cs +++ b/osu.Game/Rulesets/Mods/ModNightcore.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Framework.Utils; using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Configuration; @@ -69,7 +70,11 @@ public abstract partial class ModNightcore : ModNightcore, IApplicableT { public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - drawableRuleset.Overlays.Add(new NightcoreBeatContainer()); + // from stable: + // > (in a perfect world) tick rates other than 2 imply there isn't a regular offbeat, so offbeat hats would stand out. + // > only enable them if tick rate is a multiple of 2. + bool playHats = Precision.AlmostEquals(drawableRuleset.Beatmap.Difficulty.SliderTickRate % 2, 0); + drawableRuleset.Overlays.Add(new NightcoreBeatContainer(playHats)); } public partial class NightcoreBeatContainer : BeatSyncedContainer @@ -82,8 +87,11 @@ public partial class NightcoreBeatContainer : BeatSyncedContainer private int? firstBeat; private int lastBeat = -1; - public NightcoreBeatContainer() + private readonly bool playHats; + + public NightcoreBeatContainer(bool playHats = true) { + this.playHats = playHats; Divisor = 2; } @@ -155,7 +163,8 @@ private void playBeatFor(int beatIndex, int segmentLength, TimingControlPoint ti break; default: - hatSample?.Play(); + if (playHats) + hatSample?.Play(); break; } @@ -173,12 +182,8 @@ private void playBeatFor(int beatIndex, int segmentLength, TimingControlPoint ti break; default: - // note that in stable hat samples would only play if the beatmap tick rate was even - // (https://github.com/peppy/osu-stable-reference/blob/6ab0cf1f9f7b3449f5c0d8defcd458aae72cdb88/osu!/Audio/NightcoreBeat.cs#L30-L32) - // that kind of presumes that only music timed in 4/4 exists, and does not really work well - // if the beatmap e.g. mixes 4/4 and 3/4 signature timing control points. - // therefore this conditional behaviour is not reimplemented. - hatSample?.Play(); + if (playHats) + hatSample?.Play(); break; } From 8fe63ade3161013a99c91103c53ff70789d506f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 Mar 2026 19:32:19 +0900 Subject: [PATCH 763/836] Adjust padding and text size in editor inspector (#36843) It was taking up way too much vertical space previously. I'm using the same font specs that are in the new dropdown header, which seem to work quite well. Negative padding because without it everything is way too vertically sparse. Why? I was looking at [this discussion](https://github.com/ppy/osu/discussions/36708) and like "we need to have SV visible here" but there's really not much room with all this text in the way. --- osu.Game/Screens/Edit/Compose/Components/EditorInspector.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorInspector.cs b/osu.Game/Screens/Edit/Compose/Components/EditorInspector.cs index 5837dd794627..7aaa2e7f65f3 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorInspector.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorInspector.cs @@ -35,14 +35,14 @@ private void load() protected void AddHeader(string header) => InspectorText.AddParagraph($"{header}: ", s => { - s.Padding = new MarginPadding { Top = 2 }; - s.Font = s.Font.With(size: 12); + s.Font = OsuFont.Style.Caption1; s.Colour = colourProvider.Content2; }); protected void AddValue(string value) => InspectorText.AddParagraph(value, s => { - s.Font = s.Font.With(weight: FontWeight.SemiBold); + s.Padding = new MarginPadding { Top = -5 }; + s.Font = OsuFont.Style.Body; s.Colour = colourProvider.Content1; }); } From 04767f44bb9c201e943607577827d432948e6c8e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 Mar 2026 19:32:34 +0900 Subject: [PATCH 764/836] Allow editor 100% background dim (#36847) Whatever at this point. https://github.com/ppy/osu/discussions/30421 --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- osu.Game/Screens/Edit/BackgroundDimMenuItem.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index ab6a687cb686..7037d8c50a28 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -198,7 +198,7 @@ protected override void InitialiseDefaults() SetDefault(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full); - SetDefault(OsuSetting.EditorDim, 0.25f, 0f, 0.75f, 0.25f); + SetDefault(OsuSetting.EditorDim, 0.25f, 0f, 1f, 0.25f); SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f, 0f, 1f, 0.25f); SetDefault(OsuSetting.EditorShowHitMarkers, true); SetDefault(OsuSetting.EditorAutoSeekOnPlacement, true); diff --git a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs index 2a1159eb2782..26f2f145e9ba 100644 --- a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs +++ b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs @@ -24,6 +24,7 @@ public BackgroundDimMenuItem(Bindable backgroundDim) createMenuItem(0.25f), createMenuItem(0.5f), createMenuItem(0.75f), + createMenuItem(1), }; this.backgroundDim = backgroundDim; From f9e863af013a4e2b091eb906113e8eec85ce8d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 6 Mar 2026 11:54:44 +0100 Subject: [PATCH 765/836] Remove "copy labels from linked issues" github workflow (#36854) [It still doesn't work.](https://github.com/ppy/osu/actions/runs/22759488243/job/66012293202) Looking at the [job output](https://github.com/ppy/osu/actions/runs/22759488243/job/66012293202#step:1:21) it appears that the permissions of the `GITHUB_TOKEN` are *automatically* constrained to `read` even if you request more scopes. Would be nice if that was *actually documented* somewhere! Also given supply-chain attacks that people are running on github [via *issue titles* these days](https://grith.ai/blog/clinejection-when-your-ai-tool-installs-another) I'm not sure we want any automation near where it can reach code. Sure, much of the fault in the aforementioned attack was the fault of meatbags trusting clankers *WAY* too much, which is a mistake we *would not* do, but given everpresent software degradation *from unknown sources and for unknown reasons* let's not ~~COPILOT~~ *ahem* tempt fate... --- .../workflows/pull-request-copy-labels.yml | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 .github/workflows/pull-request-copy-labels.yml diff --git a/.github/workflows/pull-request-copy-labels.yml b/.github/workflows/pull-request-copy-labels.yml deleted file mode 100644 index a48a1ef974e4..000000000000 --- a/.github/workflows/pull-request-copy-labels.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Copy labels from linked issues - -on: - pull_request: - types: [opened] - -permissions: - issues: write - pull-requests: write - contents: read - -jobs: - copy-labels: - runs-on: ubuntu-latest - name: Copy labels from linked issues - steps: - - name: Copy labels - uses: michalvankodev/copy-issue-labels@v1.3.0 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} From 482d31d59805b8513c274e8efc664f5ca51705ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 Mar 2026 20:11:04 +0900 Subject: [PATCH 766/836] Fix "no tablet" settings display not updating after language change (#36848) Closes https://github.com/ppy/osu/issues/36833. Schedule is unfortunate but I'm not really wanting to go down a rabbit hole right now. --- .../Settings/Sections/Input/TabletSettings.cs | 152 ++++++++++-------- 1 file changed, 89 insertions(+), 63 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index b5e9e2ee4e93..c6116ddc7b53 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -77,7 +77,7 @@ public partial class TabletSettings : InputSubsection private FillFlowContainer mainSettings; - private Container noTabletMessage; + private Drawable noTabletMessage; protected override LocalisableString Header => TabletSettingsStrings.Tablet; @@ -94,69 +94,9 @@ private void load(OsuColour colours, LocalisationManager localisation, OsuConfig scalingSizeX = osuConfig.GetBindable(OsuSetting.ScalingSizeX); scalingSizeY = osuConfig.GetBindable(OsuSetting.ScalingSizeY); - AddRange(new Drawable[] + AddRange(new[] { - noTabletMessage = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = SettingsPanel.CONTENT_PADDING, - Child = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Masking = true, - CornerRadius = 5, - CornerExponent = 2.5f, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Dark2, - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(5f), - Padding = new MarginPadding { Horizontal = 8, Vertical = 10 }, - Children = new Drawable[] - { - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = TabletSettingsStrings.NoTabletDetected, - Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold), - Colour = colourProvider.Content2, - }, - new LinkFlowContainer(cp => - { - cp.Colour = colours.Orange1; - cp.Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold); - }) - { - TextAnchor = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }.With(t => - { - t.NewLine(); - - const string url = @"https://opentabletdriver.net/Wiki/FAQ/General"; - var formattedSource = MessageFormatter.FormatText(localisation.GetLocalisedString(TabletSettingsStrings.NoTabletDetectedDescription(url))); - - t.AddLinks(formattedSource.Text, formattedSource.Links); - }), - } - }, - }, - }, - }, + noTabletMessage = new NoTabletMessage(), mainSettings = new FillFlowContainer { Alpha = 0, @@ -402,5 +342,91 @@ private void forceAspectRatio(float aspectRatio) private static float getHeight(float width, float aspectRatio) => width / aspectRatio; private static float getWidth(float height, float aspectRatio) => height * aspectRatio; + + private partial class NoTabletMessage : CompositeDrawable + { + private readonly Bindable currentLanguage = new Bindable(); + private LinkFlowContainer linkContainer; + + [Resolved] + private LocalisationManager localisation { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuGameBase game, OsuColour colours, OverlayColourProvider colourProvider) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = SettingsPanel.CONTENT_PADDING; + + InternalChild = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Masking = true, + CornerRadius = 5, + CornerExponent = 2.5f, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Dark2, + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5f), + Padding = new MarginPadding { Horizontal = 8, Vertical = 10 }, + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = TabletSettingsStrings.NoTabletDetected, + Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold), + Colour = colourProvider.Content2, + }, + linkContainer = new LinkFlowContainer(cp => + { + cp.Colour = colours.Orange1; + cp.Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold); + }) + { + TextAnchor = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }, + } + }, + }, + }; + + if (game != null) + currentLanguage.BindTo(game.CurrentLanguage); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + currentLanguage.BindValueChanged(_ => + // schedule required because `LocalisationManager` won't have new language set correctly yet. + Schedule(() => + { + linkContainer.Clear(); + linkContainer.NewLine(); + + const string url = @"https://opentabletdriver.net/Wiki/FAQ/General"; + var formattedSource = MessageFormatter.FormatText(localisation.GetLocalisedString(TabletSettingsStrings.NoTabletDetectedDescription(url))); + + linkContainer.AddLinks(formattedSource.Text, formattedSource.Links); + }), true); + } + } } } From b46656e7d36532f8b4f92cbbe3189cb75c6157fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 Mar 2026 20:11:16 +0900 Subject: [PATCH 767/836] Fix loading spinner not being centered correctly (#36849) One of those things you can't un-see. Closes https://github.com/ppy/osu/issues/36832. --- osu.Game/Graphics/UserInterface/LoadingSpinner.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs index b4bc6fb8c3f5..24bf86c8ad9a 100644 --- a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs +++ b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs @@ -49,6 +49,9 @@ public LoadingSpinner(bool withBox = false, bool inverted = false) Anchor = Anchor.Centre; Origin = Anchor.Centre; + // Font awesome icon isn't centered perfectly. + Vector2 spinnerActualCentre = new Vector2(29.78f, 29.78f); + if (withBox) { Child = MainContents = new Container @@ -80,7 +83,8 @@ public LoadingSpinner(bool withBox = false, bool inverted = false) spinner = new SpriteIcon { Anchor = Anchor.Centre, - Origin = Anchor.Centre, + Origin = Anchor.Custom, + OriginPosition = spinnerActualCentre, Colour = inverted ? Color4.Black : Color4.White, Scale = new Vector2(0.6f), RelativeSizeAxes = Axes.Both, @@ -103,7 +107,8 @@ public LoadingSpinner(bool withBox = false, bool inverted = false) spinner = new SpriteIcon { Anchor = Anchor.Centre, - Origin = Anchor.Centre, + Origin = Anchor.Custom, + OriginPosition = spinnerActualCentre, Colour = inverted ? Color4.Black : Color4.White, RelativeSizeAxes = Axes.Both, Icon = FontAwesome.Solid.CircleNotch From 0d749835517da4b782ab6403ac9d2431715ffb85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 6 Mar 2026 16:20:10 +0100 Subject: [PATCH 768/836] Fix rotation of certain objects breaking change states (#36852) Closes https://github.com/ppy/osu/issues/36830. This is a regression from https://github.com/ppy/osu/pull/36681. Due to the aforementioned pull request's changes, rotating an object that could not scale on the X or Y axis (due to having that dimension zero) would trigger `CanScale{X,Y}` to change as said rotated object's width or height became not zero. This in turn would cause `SelectionBox` to *fully recreate* all of its handles and buttons, *including* the rotation handle that initiated the rotation operation, therefore dropping the ongoing rotation operation completely and leaving the editor in a half-broken state. The suggested solution here is to recreate handles more granularly to prevent this from happening. (I've probably not improved it as much as I could have, but this is as far as I'm willing to go for now unless review finds it unpalatable.) --- .../Edit/Compose/Components/SelectionBox.cs | 265 ++++++++++-------- .../SelectionBoxDragHandleContainer.cs | 23 ++ 2 files changed, 165 insertions(+), 123 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs index 2171ba696fc8..03838182a617 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs @@ -53,7 +53,7 @@ public bool CanReverse if (canReverse == value) return; canReverse = value; - recreate(); + recreateButtons(); } } @@ -78,7 +78,7 @@ public bool CanFlipX if (canFlipX == value) return; canFlipX = value; - recreate(); + recreateButtons(); } } @@ -95,7 +95,7 @@ public bool CanFlipY if (canFlipY == value) return; canFlipY = value; - recreate(); + recreateButtons(); } } @@ -116,7 +116,7 @@ public string Text } private SelectionBoxDragHandleContainer dragHandles = null!; - private FillFlowContainer buttons = null!; + private FillFlowContainer buttons = null!; private OsuSpriteText? selectionDetailsText; @@ -126,6 +126,60 @@ public string Text [BackgroundDependencyLoader] private void load() { + InternalChildren = new Drawable[] + { + new Container + { + Name = "info text", + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + Colour = colours.YellowDark, + RelativeSizeAxes = Axes.Both, + }, + selectionDetailsText = new OsuSpriteText + { + Padding = new MarginPadding(2), + Colour = colours.Gray0, + Font = OsuFont.Default.With(size: 11), + Text = text, + } + } + }, + new Container + { + Masking = true, + BorderThickness = BORDER_RADIUS, + BorderColour = colours.YellowDark, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + + AlwaysPresent = true, + Alpha = 0 + }, + } + }, + dragHandles = new SelectionBoxDragHandleContainer + { + RelativeSizeAxes = Axes.Both, + // ensures that the centres of all drag handles line up with the middle of the selection box border. + Padding = new MarginPadding(BORDER_RADIUS / 2) + }, + buttons = new FillFlowContainer + { + AutoSizeAxes = Axes.X, + Height = 30, + Direction = FillDirection.Horizontal, + Margin = new MarginPadding(button_padding), + } + }; + if (rotationHandler != null) canRotate.BindTo(rotationHandler.CanRotateAroundSelectionOrigin); @@ -136,10 +190,14 @@ private void load() canScaleDiagonally.BindTo(scaleHandler.CanScaleDiagonally); } - canRotate.BindValueChanged(_ => recreate()); - canScaleX.BindValueChanged(_ => recreate()); - canScaleY.BindValueChanged(_ => recreate()); - canScaleDiagonally.BindValueChanged(_ => recreate(), true); + canScaleX.BindValueChanged(_ => recreateScaleHandles()); + canScaleY.BindValueChanged(_ => recreateScaleHandles()); + canScaleDiagonally.BindValueChanged(_ => recreateScaleHandles(), true); + canRotate.BindValueChanged(_ => + { + recreateRotationHandles(); + recreateButtons(); + }, true); } protected override bool OnKeyDown(KeyDownEvent e) @@ -181,78 +239,52 @@ protected override void Update() ensureButtonsOnScreen(); } - private void recreate() + private void recreateScaleHandles() { if (LoadState < LoadState.Loading) return; - InternalChildren = new Drawable[] + dragHandles.ClearScaleHandles(); + + if (canScaleY.Value) { - new Container - { - Name = "info text", - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - Colour = colours.YellowDark, - RelativeSizeAxes = Axes.Both, - }, - selectionDetailsText = new OsuSpriteText - { - Padding = new MarginPadding(2), - Colour = colours.Gray0, - Font = OsuFont.Default.With(size: 11), - Text = text, - } - } - }, - new Container - { - Masking = true, - BorderThickness = BORDER_RADIUS, - BorderColour = colours.YellowDark, - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, + addScaleHandle(Anchor.TopCentre); + addScaleHandle(Anchor.BottomCentre); + } - AlwaysPresent = true, - Alpha = 0 - }, - } - }, - dragHandles = new SelectionBoxDragHandleContainer - { - RelativeSizeAxes = Axes.Both, - // ensures that the centres of all drag handles line up with the middle of the selection box border. - Padding = new MarginPadding(BORDER_RADIUS / 2) - }, - buttons = new FillFlowContainer - { - AutoSizeAxes = Axes.X, - Height = 30, - Direction = FillDirection.Horizontal, - Margin = new MarginPadding(button_padding), - } + if (canScaleDiagonally.Value) + { + addScaleHandle(Anchor.TopLeft); + addScaleHandle(Anchor.TopRight); + addScaleHandle(Anchor.BottomLeft); + addScaleHandle(Anchor.BottomRight); + } + + if (canScaleX.Value) + { + addScaleHandle(Anchor.CentreLeft); + addScaleHandle(Anchor.CentreRight); + } + } + + private void addScaleHandle(Anchor anchor) + { + var handle = new SelectionBoxScaleHandle + { + Anchor = anchor, }; - if (canScaleX.Value) addXScaleComponents(); - if (canScaleDiagonally.Value) addFullScaleComponents(); - if (canScaleY.Value) addYScaleComponents(); - if (CanFlipX) addXFlipComponents(); - if (CanFlipY) addYFlipComponents(); - if (canRotate.Value) addRotationComponents(); - if (CanReverse) reverseButton = addButton(FontAwesome.Solid.Backward, "Reverse pattern (Ctrl-G)", () => OnReverse?.Invoke()); + handle.OperationStarted += operationStarted; + handle.OperationEnded += operationEnded; + dragHandles.AddScaleHandle(handle); } - private void addRotationComponents() + private void recreateRotationHandles() { - rotateCounterClockwiseButton = addButton(FontAwesome.Solid.Undo, "Rotate 90 degrees counter-clockwise (Ctrl-<)", () => rotationHandler?.Rotate(-90)); - rotateClockwiseButton = addButton(FontAwesome.Solid.Redo, "Rotate 90 degrees clockwise (Ctrl->)", () => rotationHandler?.Rotate(90)); + if (LoadState < LoadState.Loading) + return; + + dragHandles.ClearRotationHandles(); addRotateHandle(Anchor.TopLeft); addRotateHandle(Anchor.TopRight); @@ -260,34 +292,39 @@ private void addRotationComponents() addRotateHandle(Anchor.BottomRight); } - private void addYScaleComponents() + private void addRotateHandle(Anchor anchor) { - addScaleHandle(Anchor.TopCentre); - addScaleHandle(Anchor.BottomCentre); - } + var handle = new SelectionBoxRotationHandle + { + Anchor = anchor, + }; - private void addFullScaleComponents() - { - addScaleHandle(Anchor.TopLeft); - addScaleHandle(Anchor.TopRight); - addScaleHandle(Anchor.BottomLeft); - addScaleHandle(Anchor.BottomRight); + handle.OperationStarted += operationStarted; + handle.OperationEnded += operationEnded; + dragHandles.AddRotationHandle(handle); } - private void addXScaleComponents() + private void recreateButtons() { - addScaleHandle(Anchor.CentreLeft); - addScaleHandle(Anchor.CentreRight); - } + if (LoadState < LoadState.Loading) + return; - private void addXFlipComponents() - { - addButton(FontAwesome.Solid.ArrowsAltH, "Flip horizontally", () => OnFlip?.Invoke(Direction.Horizontal, false)); - } + clearButtons(); - private void addYFlipComponents() - { - addButton(FontAwesome.Solid.ArrowsAltV, "Flip vertically", () => OnFlip?.Invoke(Direction.Vertical, false)); + if (canRotate.Value) + { + rotateCounterClockwiseButton = addButton(FontAwesome.Solid.Undo, "Rotate 90 degrees counter-clockwise (Ctrl-<)", () => rotationHandler?.Rotate(-90)); + rotateClockwiseButton = addButton(FontAwesome.Solid.Redo, "Rotate 90 degrees clockwise (Ctrl->)", () => rotationHandler?.Rotate(90)); + } + + if (CanFlipX) + addButton(FontAwesome.Solid.ArrowsAltH, "Flip horizontally", () => OnFlip?.Invoke(Direction.Horizontal, false)); + + if (CanFlipY) + addButton(FontAwesome.Solid.ArrowsAltV, "Flip vertically", () => OnFlip?.Invoke(Direction.Vertical, false)); + + if (CanReverse) + reverseButton = addButton(FontAwesome.Solid.Backward, "Reverse pattern (Ctrl-G)", () => OnReverse?.Invoke()); } private SelectionBoxButton addButton(IconUsage icon, string tooltip, Action action) @@ -308,6 +345,21 @@ private SelectionBoxButton addButton(IconUsage icon, string tooltip, Action acti return button; } + private void clearButtons() + { + foreach (var button in buttons) + { + button.Clicked -= freezeButtonPosition; + button.HoverLost -= unfreezeButtonPosition; + + button.OperationStarted -= operationStarted; + button.OperationEnded -= operationEnded; + } + + unfreezeButtonPosition(); + buttons.Clear(); + } + /// /// This method should be called when a selection needs to be flipped /// because of an ongoing scale handle drag that would otherwise cause width or height to go negative. @@ -327,41 +379,8 @@ public void PerformFlipFromScaleHandles(Axes axes) } } - private void addScaleHandle(Anchor anchor) - { - var handle = new SelectionBoxScaleHandle - { - Anchor = anchor, - }; - - handle.OperationStarted += operationStarted; - handle.OperationEnded += operationEnded; - dragHandles.AddScaleHandle(handle); - } - - private void addRotateHandle(Anchor anchor) - { - var handle = new SelectionBoxRotationHandle - { - Anchor = anchor, - }; - - handle.OperationStarted += operationStarted; - handle.OperationEnded += operationEnded; - dragHandles.AddRotationHandle(handle); - } - private int activeOperations; - private float convertDragEventToAngleOfRotation(DragEvent e) - { - // Adjust coordinate system to the center of SelectionBox - float startAngle = MathF.Atan2(e.LastMousePosition.Y - DrawHeight / 2, e.LastMousePosition.X - DrawWidth / 2); - float endAngle = MathF.Atan2(e.MousePosition.Y - DrawHeight / 2, e.MousePosition.X - DrawWidth / 2); - - return (endAngle - startAngle) * 180 / MathF.PI; - } - private void operationEnded() { if (--activeOperations == 0) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandleContainer.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandleContainer.cs index e5ac05ca6a37..d927efef83ee 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandleContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandleContainer.cs @@ -51,6 +51,13 @@ public void AddScaleHandle(SelectionBoxScaleHandle handle) scaleHandles.Add(handle); } + public void ClearScaleHandles() + { + foreach (var scaleHandle in scaleHandles) + unbindDragHandle(scaleHandle); + scaleHandles.Clear(); + } + public void AddRotationHandle(SelectionBoxRotationHandle handle) { handle.Alpha = 0; @@ -60,6 +67,13 @@ public void AddRotationHandle(SelectionBoxRotationHandle handle) rotationHandles.Add(handle); } + public void ClearRotationHandles() + { + foreach (var rotationHandle in rotationHandles) + unbindDragHandle(rotationHandle); + rotationHandles.Clear(); + } + private void bindDragHandle(SelectionBoxDragHandle handle) { handle.HoverGained += updateRotationHandlesVisibility; @@ -69,6 +83,15 @@ private void bindDragHandle(SelectionBoxDragHandle handle) allDragHandles.Add(handle); } + private void unbindDragHandle(SelectionBoxDragHandle handle) + { + handle.HoverGained -= updateRotationHandlesVisibility; + handle.HoverLost -= updateRotationHandlesVisibility; + handle.MouseDown -= updateRotationHandlesVisibility; + handle.MouseUp -= updateRotationHandlesVisibility; + allDragHandles.Remove(handle); + } + public void FlipScaleHandles(Direction direction) { foreach (var handle in scaleHandles) From 16bc1de9fd4bd6225823e7916b7f055b44d5cc02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 6 Mar 2026 16:47:35 +0100 Subject: [PATCH 769/836] Allow changing addition bank button state when objects are selected even if the selection has no addition sounds (#36808) Before: https://github.com/user-attachments/assets/d87bd7e3-37f8-4634-9e6a-5859d5bade57 After: https://github.com/user-attachments/assets/4de940af-1e30-4266-9aac-5ccd12f38742 --- The title is convoluted but basically I'm angling to close https://github.com/ppy/osu/issues/36705 with this. The point is that on current `master`, the keyboard-hotkey-based toggles on the left of the screen get disabled if you select a range of objects which contains no addition samples. The report linked above finds this annoying because it means you basically always need to add an addition sound *first* and *then* pick a bank. This is not necessary, and this commit changes the behaviour such that the bank selection toggles are no longer blocked when you select a range of objects without additions. Choosing an addition bank when there are no additions still does nothing to the selected object, *but* adding a sound *after* that bank preselection will use the preselected bank rather than auto. --- .../TestSceneHitObjectSampleAdjustments.cs | 168 ++++++++++++++++++ .../Components/ComposeBlueprintContainer.cs | 12 -- .../Components/EditorSelectionHandler.cs | 68 +++---- 3 files changed, 205 insertions(+), 43 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs index 515fa4c0b571..6b18aac478d5 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs @@ -1046,6 +1046,174 @@ void assertNoChanges() } } + [Test] + public void TestAddSoundBeforeSettingNonAutoAdditionBankOnSelectedObject() + { + AddStep("select first object", () => + { + EditorBeatmap.SelectedHitObjects.Clear(); + EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects[0]); + }); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + + AddStep("add finish sound", () => InputManager.Key(Key.E)); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasAutoAdditionBankFlag(0, true); + + AddStep("set drum addition bank", () => + { + InputManager.PressKey(Key.AltLeft); + InputManager.Key(Key.R); + InputManager.ReleaseKey(Key.AltLeft); + }); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasAutoAdditionBankFlag(0, false); + } + + [Test] + public void TestAddSoundAfterSettingNonAutoAdditionBankOnSelectedObject() + { + AddStep("select first object", () => + { + EditorBeatmap.SelectedHitObjects.Clear(); + EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects[0]); + }); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + + AddStep("set drum addition bank", () => + { + InputManager.PressKey(Key.AltLeft); + InputManager.Key(Key.R); + InputManager.ReleaseKey(Key.AltLeft); + }); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + + AddStep("add finish sound", () => InputManager.Key(Key.E)); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasAutoAdditionBankFlag(0, false); + } + + [Test] + public void TestSwitchSoundAfterSettingNonAutoAdditionBankOnSelectedObject() + { + AddStep("select first object", () => + { + EditorBeatmap.SelectedHitObjects.Clear(); + EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects[0]); + }); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + + AddStep("set drum addition bank", () => + { + InputManager.PressKey(Key.AltLeft); + InputManager.Key(Key.R); + InputManager.ReleaseKey(Key.AltLeft); + }); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + + AddStep("add finish sound", () => InputManager.Key(Key.E)); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasAutoAdditionBankFlag(0, false); + + AddStep("remove finish sound", () => InputManager.Key(Key.E)); + AddStep("add whistle sound", () => InputManager.Key(Key.W)); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasAutoAdditionBankFlag(0, false); + } + + [Test] + public void TestAddSoundBeforeSettingAutoAdditionBankOnSelectedObject() + { + AddStep("select first object", () => + { + EditorBeatmap.SelectedHitObjects.Clear(); + EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects[0]); + }); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + + AddStep("add finish sound", () => InputManager.Key(Key.E)); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasAutoAdditionBankFlag(0, true); + + AddStep("set auto addition bank", () => + { + InputManager.PressKey(Key.AltLeft); + InputManager.Key(Key.Q); + InputManager.ReleaseKey(Key.AltLeft); + }); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasAutoAdditionBankFlag(0, true); + + AddStep("set drum normal bank", () => + { + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.R); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasAutoAdditionBankFlag(0, true); + } + + [Test] + public void TestAddSoundAfterSettingAutoAdditionBankOnSelectedObject() + { + AddStep("select first object", () => + { + EditorBeatmap.SelectedHitObjects.Clear(); + EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects[0]); + }); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + + AddStep("set auto addition bank", () => + { + InputManager.PressKey(Key.AltLeft); + InputManager.Key(Key.Q); + InputManager.ReleaseKey(Key.AltLeft); + }); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + + AddStep("add finish sound", () => InputManager.Key(Key.E)); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_NORMAL); + hitObjectHasAutoAdditionBankFlag(0, true); + + AddStep("set drum normal bank", () => + { + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.R); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_FINISH); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasAutoAdditionBankFlag(0, true); + } + private void clickSamplePiece(int objectIndex) => AddStep($"click {objectIndex.ToOrdinalWords()} sample piece", () => { var samplePiece = this.ChildrenOfType().Single(piece => piece is not NodeSamplePointPiece && piece.HitObject == EditorBeatmap.HitObjects.ElementAt(objectIndex)); diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index 4414e963bf2a..11ae0ef56d3f 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -100,7 +100,6 @@ protected override void LoadComplete() kvp.Value.BindValueChanged(_ => updatePlacementSamples()); SelectionHandler.AutoSelectionBankEnabled.BindValueChanged(_ => updateAutoBankTernaryButtonTooltip(), true); - SelectionHandler.SelectionAdditionBanksEnabled.BindValueChanged(_ => updateAdditionBankTernaryButtonTooltips(), true); } protected override void TransferBlueprintFor(HitObject hitObject, DrawableHitObject drawableObject) @@ -252,17 +251,6 @@ private void updateAutoBankTernaryButtonTooltip() autoBankButton.NormalButton.TooltipText = !enabled ? "Auto normal bank can only be used during hit object placement" : string.Empty; } - private void updateAdditionBankTernaryButtonTooltips() - { - bool enabled = SelectionHandler.SelectionAdditionBanksEnabled.Value; - - foreach (var ternaryButton in SampleBankTernaryStates) - { - ternaryButton.AdditionsButton.Enabled.Value = enabled; - ternaryButton.AdditionsButton.TooltipText = !enabled ? "Add an addition sample first to be able to set a bank" : string.Empty; - } - } - #region Placement /// diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs index 074d94eb2670..9bee0a4fffd5 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs @@ -85,11 +85,6 @@ protected override bool ShouldQuickDelete(MouseButtonEvent e) /// public readonly Bindable AutoSelectionBankEnabled = new Bindable(); - /// - /// Whether the selection contains any addition samples and the can be used. - /// - public readonly Bindable SelectionAdditionBanksEnabled = new Bindable(); - /// /// Set up ternary state bindables and bind them to selection/hitobject changes (in both directions) /// @@ -201,26 +196,18 @@ private void createStateBindables() break; case TernaryState.True: - if (SelectedItems.Count == 0) - { - // Ensure the user can't stack multiple bank selections when there's no hitobject selection. - // Note that in normal scenarios this is sorted out by the feedback from applying the bank to the selected objects. - foreach (var other in SelectionAdditionBankStates.Values) - { - if (other != bindable) - other.Value = TernaryState.False; - } - } - else - { - // If none of the selected objects have any addition samples, we should not apply the addition bank. - if (SelectedItems.SelectMany(enumerateAllSamples).All(h => h.All(o => o.Name == HitSampleInfo.HIT_NORMAL))) - { - bindable.Value = TernaryState.False; - break; - } - + // If any of the selected objects have any addition samples, we should apply the addition bank. + if (SelectedItems.SelectMany(enumerateAllSamples).Any(h => h.Any(o => o.Name != HitSampleInfo.HIT_NORMAL))) SetSampleAdditionBank(bankName); + + // There are either no selected items, or none of the selected items have addition sounds. + // This state is basically the user pre-selecting an addition bank before actually adding an addition. + // Ensure the user can't stack multiple bank selections in this state. + // Note that in normal scenarios this is sorted out by the feedback from applying the bank to the selected objects. + foreach (var other in SelectionAdditionBankStates.Values) + { + if (other != bindable) + other.Value = TernaryState.False; } break; @@ -279,7 +266,6 @@ private void resetTernaryStates() SelectionNewComboState.Value = TernaryState.False; AutoSelectionBankEnabled.Value = true; - SelectionAdditionBanksEnabled.Value = true; SelectionBankStates[HIT_BANK_AUTO].Value = TernaryState.True; SelectionAdditionBankStates[HIT_BANK_AUTO].Value = TernaryState.True; foreach (var (_, sampleState) in SelectionSampleStates) @@ -309,12 +295,17 @@ protected virtual void UpdateTernaryStates() bindable.Value = GetStateFromSelection(samplesInSelection.SelectMany(s => s).Where(o => o.Name == HitSampleInfo.HIT_NORMAL), h => h.Bank == bankName); } - SelectionAdditionBanksEnabled.Value = samplesInSelection.SelectMany(s => s).Any(o => o.Name != HitSampleInfo.HIT_NORMAL); - - foreach ((string bankName, var bindable) in SelectionAdditionBankStates) + // if there are no addition samples in the selection, do not touch the state of addition bank bindables. + // this is to reduce annoyance from the bank resetting if the user wants to e.g. remove the only addition sound on an object, but then add another addition sound + // while keeping the bank the same. + // note that deselecting all objects will still reset the addition bank selection to auto via `ResetTernaryStates()`. this may need to be reconsidered later. + if (samplesInSelection.SelectMany(s => s).Any(o => o.Name != HitSampleInfo.HIT_NORMAL)) { - bindable.Value = GetStateFromSelection(samplesInSelection.SelectMany(s => s).Where(o => o.Name != HitSampleInfo.HIT_NORMAL), - h => (bankName != HIT_BANK_AUTO && h.Bank == bankName && !h.EditorAutoBank) || (bankName == HIT_BANK_AUTO && h.EditorAutoBank)); + foreach ((string bankName, var bindable) in SelectionAdditionBankStates) + { + bindable.Value = GetStateFromSelection(samplesInSelection.SelectMany(s => s).Where(o => o.Name != HitSampleInfo.HIT_NORMAL), + h => (bankName != HIT_BANK_AUTO && h.Bank == bankName && !h.EditorAutoBank) || (bankName == HIT_BANK_AUTO && h.EditorAutoBank)); + } } } } @@ -453,9 +444,24 @@ public void AddHitSample(string sampleName) EditorBeatmap.PerformOnSelection(h => { + string? forcedBank = null; + // if the selected object(s) only have normal samples, check whether the user has preselected a singular non-auto bank using `SelectionAdditionBankStates`. + // other scenarios are already handled by `CreateHitSampleInfo()`: + // - if the selected object(s) already have addition samples, `CreateHitSampleInfo()` will copy the bank from said addition samples. + // - if the selected object(s) do not have addition samples but the user has preselected auto bank, `CreateHitSampleInfo()` will use the auto bank anyway. + if (h.Samples.All(s => s.Name == HitSampleInfo.HIT_NORMAL)) + forcedBank = SelectionAdditionBankStates.SingleOrDefault(kv => kv.Value.Value == TernaryState.True).Key; + // Make sure there isn't already an existing sample if (h.Samples.All(s => s.Name != sampleName)) - h.Samples.Add(h.CreateHitSampleInfo(sampleName)); + { + var hitSample = h.CreateHitSampleInfo(sampleName); + + if (forcedBank != null && forcedBank != HIT_BANK_AUTO) + hitSample = hitSample.With(newBank: forcedBank, newEditorAutoBank: false); + + h.Samples.Add(hitSample); + } if (h is IHasRepeats hasRepeats) { From 0fd0bd3580d2236f1b3871250580c701c43f8868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=8D=E4=BA=88?= Date: Sat, 7 Mar 2026 00:41:59 +0800 Subject: [PATCH 770/836] Consider comments in wiki's front matter YAML (#36758) This PR makes front matter items with comments able to be parsed correctly by the client, for example: ```markdown --- tags: - keyboard - tap - hybrid - play style needs_cleanup: true # https://github.com/ppy/osu-wiki/issues/9919 --- # Hybrid ... ``` The front matter YAML used by osu!wiki not complicated, so simply splitting with `#` is possible. --------- Co-authored-by: Dean Herbert --- .../Online/TestSceneWikiMarkdownContainer.cs | 27 +++++++++++++++++++ .../Wiki/Markdown/WikiNoticeContainer.cs | 13 +++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index e453a32652a2..243a22243ea4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -116,6 +116,33 @@ public void TestOnlyShowOutdatedNoticeBox() }); } + [Test] + public void TestOutdatedNoticeBoxWithSuffixComments() + { + AddStep("Add outdated yaml with comments", () => + { + markdownContainer.Text = @"--- +outdated: true # not sure about the format for ""list of mods"". +---"; + }); + + AddAssert("Outdated notice box visible", () => markdownContainer.ChildrenOfType().Any()); + } + + [Test] + public void TestCommentedOutFrontMatter() + { + AddStep("Add commented out front matter", () => + { + markdownContainer.Text = @"--- +#outdated: true +# outdated: true +---"; + }); + + AddAssert("No notice box visible", () => !markdownContainer.ChildrenOfType().Any()); + } + [Test] public void TestAbsoluteImage() { diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs index 1ab35b197250..ee00843317b3 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs @@ -1,7 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using Markdig.Extensions.Yaml; +using Markdig.Helpers; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -27,9 +29,16 @@ public WikiNoticeContainer(YamlFrontMatterBlock yamlFrontMatterBlock) Direction = FillDirection.Vertical; Spacing = new Vector2(10); - foreach (object line in yamlFrontMatterBlock.Lines) + foreach (StringLine line in yamlFrontMatterBlock.Lines) { - switch (line.ToString()) + // Commonly, comments are added to the end of lines. + // There are cases of '#' used inside frontmatter, ie for url content, so matching with the prefix space is important. + string cleaned = line.ToString().Split(" #").First().Trim(); + + // Exact text matching should hopefully be enough as a certain degree of linting is applied at + // the wiki side. Note that this will ensure cases of the whole line being commented out are not actioned + // on, covering cases not caught by the above check. + switch (cleaned) { case @"outdated: true": isOutdated = true; From 098855256751dfb1b62d995c680e746fb0675c32 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 7 Mar 2026 02:30:50 +0900 Subject: [PATCH 771/836] Implement ranked play (#36819) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I don't really have much to say here. Instead, I'll give a brief history rundown that lists many pages of documentation you can read, if interested. - Started off as BTMC + Happy24 (Vivi)'s ["The Vision"](https://docs.google.com/document/d/1p1IpPmd2RICp8G4OqkCSs7u8Ug8FbFv8qqP0mfSrHf0/edit?tab=t.0#heading=h.fol093d9f9xi) - Initial [designs](https://www.figma.com/design/f5qqC57t9jFlgpzhRqUNVX/The-Vision?node-id=0-1&p=f) were led by Vivi. - Designs [morphed](https://www.figma.com/design/vtFmLrXKvWNyYiRjTezFTM/Untitled--Copy-?node-id=0-1&p=f) during development into what's currently present, led by @minetoblend. - There is some more ongoing work creating a [game design document](https://docs.google.com/document/d/1iffJFCsIBfYF0D4ogItSBEj6YBmbp-rdCpItAeaJiTA/edit?tab=t.0). **tl;dr:** Create something with the mechanics of a trading card game within osu!. The name of this is "ranked play". --- To be frank, a lot of stuff is missing here. Some of it I don't want to mention, because the point of this exercise is to get the system into the hands of players, gather feedback especially around mechanics, and discuss any further direction with the team. I am expecting a blanket approval on all of the new code, with particular attention to changes in existing components that I'll point out in a self review. There is also some [ongoing work](https://github.com/smoogipoo/osu/pulls) that may arrive in this branch prior to being merged. --------- Co-authored-by: maarvin Co-authored-by: Marvin Co-authored-by: Jamie Taylor Co-authored-by: ArijanJ Co-authored-by: Dean Herbert Co-authored-by: Tim Oliver Co-authored-by: Joseph Madamba Co-authored-by: Bartłomiej Dach Co-authored-by: nil <25884226+voidstar0@users.noreply.github.com> Co-authored-by: Ботников Максим Co-authored-by: Denis Titovets Co-authored-by: Michael Middlezong <119022671+mmiddlezong@users.noreply.github.com> Co-authored-by: SupDos <6813986+SupDos@users.noreply.github.com> Co-authored-by: failaip12 <86018517+failaip12@users.noreply.github.com> --- .../Requests/api-beatmaps-rankedplay.json | 1590 +++++++++++++++++ .../TestSceneMatchmakingQueueScreen.cs | 3 +- .../Online/TestSceneBeatmapSetOverlay.cs | 4 +- .../Visual/RankedPlay/RankedPlayTestScene.cs | 78 + .../RankedPlay/TestSceneDiscardScreen.cs | 32 + .../Visual/RankedPlay/TestSceneEndedScreen.cs | 63 + .../TestSceneGameplayWarmupScreen.cs | 49 + .../Visual/RankedPlay/TestSceneHandReplay.cs | 140 ++ .../Visual/RankedPlay/TestSceneIntroScreen.cs | 37 + .../RankedPlay/TestSceneOpponentPickScreen.cs | 32 + .../Visual/RankedPlay/TestScenePickScreen.cs | 32 + .../RankedPlay/TestScenePlayerCardHand.cs | 161 ++ .../TestSceneRankedPlayBackground.cs | 62 + .../RankedPlay/TestSceneRankedPlayCard.cs | 222 +++ .../TestSceneRankedPlayCornerPiece.cs | 61 + .../RankedPlay/TestSceneRankedPlayScreen.cs | 176 ++ .../TestSceneRankedPlayUserDisplay.cs | 58 + .../RankedPlay/TestSceneResultsScreen.cs | 231 +++ .../Visual/RankedPlay/TestSceneSongPreview.cs | 80 + osu.Game/Audio/PreviewTrack.cs | 21 + osu.Game/Audio/SamplePlaybackHelper.cs | 38 + osu.Game/Localisation/ButtonSystemStrings.cs | 5 + osu.Game/Online/Leaderboards/DrawableRank.cs | 31 + .../Matchmaking/MatchmakingStage.cs | 2 +- .../Online/Multiplayer/MultiplayerClient.cs | 71 +- .../Multiplayer/OnlineMultiplayerClient.cs | 27 + osu.Game/Screens/Menu/ButtonSystem.cs | 24 +- osu.Game/Screens/Menu/MainMenu.cs | 8 +- .../Matchmaking/Intro/ScreenIntro.cs | 27 +- .../Matchmaking/Queue/PoolSelector.cs | 2 +- .../Matchmaking/Queue/QueueController.cs | 46 +- .../Matchmaking/Queue/ScreenQueue.cs | 37 +- .../CardDetailsOverlayContainer.UserTags.cs | 123 ++ .../Card/CardDetailsOverlayContainer.cs | 146 ++ .../Card/RankedPlayCard.SongPreview.cs | 306 ++++ .../RankedPlay/Card/RankedPlayCard.cs | 241 +++ .../RankedPlay/Card/RankedPlayCardBackSide.cs | 32 + .../RankedPlayCardContent.AttributeListing.cs | 173 ++ .../Card/RankedPlayCardContent.Colours.cs | 77 + .../Card/RankedPlayCardContent.Cover.cs | 55 + .../Card/RankedPlayCardContent.Metadata.cs | 203 +++ .../RankedPlay/Card/RankedPlayCardContent.cs | 147 ++ .../Card/RankedPlayCardExtensions.cs | 43 + .../Card/SongPreviewParticleContainer.cs | 129 ++ .../RankedPlay/Components/CardFlow.cs | 79 + .../Components/RankedPlayCornerPiece.cs | 160 ++ .../Components/RankedPlayScoreCounter.cs | 234 +++ .../Components/RankedPlayStageDisplay.cs | 240 +++ .../Components/RankedPlayUserDisplay.cs | 398 +++++ .../Matchmaking/RankedPlay/DiscardScreen.cs | 352 ++++ .../Matchmaking/RankedPlay/EndedScreen.cs | 207 +++ .../Matchmaking/RankedPlay/GameplayScreen.cs | 42 + .../GameplayWarmupScreen.DifficultyDisplay.cs | 234 +++ .../GameplayWarmupScreen.MetadataWedge.cs | 260 +++ .../GameplayWarmupScreen.TitleWedge.cs | 167 ++ .../RankedPlay/GameplayWarmupScreen.cs | 182 ++ .../Matchmaking/RankedPlay/HamburgerMenu.cs | 116 ++ .../RankedPlay/Hand/HandOfCards.HandCard.cs | 113 ++ .../RankedPlay/Hand/HandOfCards.cs | 255 +++ .../RankedPlay/Hand/HandReplayPlayer.cs | 72 + .../RankedPlay/Hand/HandReplayRecorder.cs | 124 ++ .../RankedPlay/Hand/HandSelectionMode.cs | 12 + .../RankedPlay/Hand/OpponentHandOfCards.cs | 28 + .../Hand/PlayerHandOfCards.PlayerHandCard.cs | 170 ++ .../RankedPlay/Hand/PlayerHandOfCards.cs | 219 +++ .../RankedPlay/Intro/CoverReveal.cs | 119 ++ .../RankedPlay/Intro/IntroScreen.cs | 123 ++ .../RankedPlay/Intro/StarRatingSequence.cs | 341 ++++ .../RankedPlay/Intro/UserWithRating.cs | 9 + .../RankedPlay/Intro/VsSequence.cs | 325 ++++ .../RankedPlay/OpponentPickScreen.cs | 160 ++ .../Matchmaking/RankedPlay/PickScreen.cs | 267 +++ .../RankedPlay/RankedPlayBackground.cs | 213 +++ .../RankedPlay/RankedPlayBackgroundScreen.cs | 110 ++ .../RankedPlayCardWithPlaylistItem.cs | 30 + .../RankedPlay/RankedPlayColourScheme.cs | 35 + .../RankedPlay/RankedPlayMatchInfo.cs | 176 ++ .../RankedPlay/RankedPlayScreen.cs | 535 ++++++ .../RankedPlay/RankedPlaySubScreen.cs | 89 + .../RankedPlay/ResultsScreen.PanelScaffold.cs | 118 ++ .../RankedPlay/ResultsScreen.ScoreBar.cs | 67 + .../RankedPlay/ResultsScreen.ScoreDetails.cs | 109 ++ .../ResultsScreen.ScoreRankDisplay.cs | 39 + .../ResultsScreen.ScoreStatisticsDisplay.cs | 70 + .../Matchmaking/RankedPlay/ResultsScreen.cs | 606 +++++++ .../BeatmapMetadataWedge.FailRetryDisplay.cs | 2 +- .../BeatmapMetadataWedge.MetadataDisplay.cs | 2 +- ...eatmapMetadataWedge.RatingSpreadDisplay.cs | 2 +- ...BeatmapMetadataWedge.SuccessRateDisplay.cs | 2 +- .../BeatmapMetadataWedge.UserRatingDisplay.cs | 2 +- osu.Game/Tests/Beatmaps/TestBeatmap.cs | 2 + .../Multiplayer/TestMultiplayerClient.cs | 156 ++ osu.Game/Tests/Visual/OsuTestScene.cs | 56 +- osu.Game/Users/UserActivity.cs | 23 +- 94 files changed, 12526 insertions(+), 51 deletions(-) create mode 100644 osu.Game.Tests/Resources/Requests/api-beatmaps-rankedplay.json create mode 100644 osu.Game.Tests/Visual/RankedPlay/RankedPlayTestScene.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestSceneDiscardScreen.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestSceneEndedScreen.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestSceneGameplayWarmupScreen.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestSceneHandReplay.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestSceneIntroScreen.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestSceneOpponentPickScreen.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestScenePickScreen.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestScenePlayerCardHand.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayBackground.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayCard.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayCornerPiece.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayScreen.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayUserDisplay.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestSceneResultsScreen.cs create mode 100644 osu.Game.Tests/Visual/RankedPlay/TestSceneSongPreview.cs create mode 100644 osu.Game/Audio/SamplePlaybackHelper.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/CardDetailsOverlayContainer.UserTags.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/CardDetailsOverlayContainer.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCard.SongPreview.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCard.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardBackSide.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.AttributeListing.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.Colours.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.Cover.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.Metadata.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardExtensions.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/SongPreviewParticleContainer.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/CardFlow.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayCornerPiece.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayScoreCounter.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayStageDisplay.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayUserDisplay.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/EndedScreen.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayScreen.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.DifficultyDisplay.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.MetadataWedge.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.TitleWedge.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/HamburgerMenu.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandOfCards.HandCard.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandOfCards.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandReplayPlayer.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandReplayRecorder.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandSelectionMode.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/OpponentHandOfCards.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/PlayerHandOfCards.PlayerHandCard.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/PlayerHandOfCards.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/CoverReveal.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/IntroScreen.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/StarRatingSequence.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/UserWithRating.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/VsSequence.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/OpponentPickScreen.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayBackground.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayBackgroundScreen.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayCardWithPlaylistItem.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayColourScheme.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayMatchInfo.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayScreen.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlaySubScreen.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.PanelScaffold.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreBar.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreDetails.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreRankDisplay.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreStatisticsDisplay.cs create mode 100644 osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.cs diff --git a/osu.Game.Tests/Resources/Requests/api-beatmaps-rankedplay.json b/osu.Game.Tests/Resources/Requests/api-beatmaps-rankedplay.json new file mode 100644 index 000000000000..416aff1ed690 --- /dev/null +++ b/osu.Game.Tests/Resources/Requests/api-beatmaps-rankedplay.json @@ -0,0 +1,1590 @@ +[ + { + "beatmapset_id": 989460, + "difficulty_rating": 8.77437, + "id": 2069833, + "mode": "osu", + "status": "ranked", + "total_length": 306, + "user_id": 11, + "version": "Endless Days", + "accuracy": 9.4, + "ar": 9.8, + "bpm": 260, + "convert": false, + "count_circles": 2075, + "count_sliders": 452, + "count_spinners": 3, + "cs": 4.2, + "deleted_at": null, + "drain": 5, + "hit_length": 306, + "is_scoreable": true, + "last_updated": "2019-10-04T20:59:44Z", + "mode_int": 0, + "passcount": 5346, + "playcount": 77382, + "ranked": 1, + "url": "https:\/\/dev.ppy.sh\/beatmaps\/2069833", + "checksum": "d6b18fbcba356cfe9c6edcb21e78dfec", + "beatmapset": { + "anime_cover": false, + "artist": "Rivers of Nihil", + "artist_unicode": "Rivers of Nihil", + "covers": { + "cover": "https:\/\/assets.ppy.sh\/beatmaps\/989460\/covers\/cover.jpg?1631512608", + "cover@2x": "https:\/\/assets.ppy.sh\/beatmaps\/989460\/covers\/cover@2x.jpg?1631512608", + "card": "https:\/\/assets.ppy.sh\/beatmaps\/989460\/covers\/card.jpg?1631512608", + "card@2x": "https:\/\/assets.ppy.sh\/beatmaps\/989460\/covers\/card@2x.jpg?1631512608", + "list": "https:\/\/assets.ppy.sh\/beatmaps\/989460\/covers\/list.jpg?1631512608", + "list@2x": "https:\/\/assets.ppy.sh\/beatmaps\/989460\/covers\/list@2x.jpg?1631512608", + "slimcover": "https:\/\/assets.ppy.sh\/beatmaps\/989460\/covers\/slimcover.jpg?1631512608", + "slimcover@2x": "https:\/\/assets.ppy.sh\/beatmaps\/989460\/covers\/slimcover@2x.jpg?1631512608" + }, + "creator": "vrnl", + "favourite_count": 142, + "genre_id": 11, + "hype": null, + "id": 989460, + "language_id": 2, + "nsfw": false, + "offset": 0, + "play_count": 77382, + "preview_url": "\/\/b.ppy.sh\/preview\/989460.mp3", + "source": "", + "spotlight": false, + "status": "ranked", + "title": "Hollow", + "title_unicode": "Hollow", + "track_id": 1762, + "user_id": 11, + "video": false, + "bpm": 260, + "can_be_hyped": false, + "deleted_at": null, + "discussion_enabled": true, + "discussion_locked": false, + "is_scoreable": true, + "last_updated": "2019-10-04T20:59:43Z", + "legacy_thread_url": null, + "nominations_summary": { + "current": 2, + "eligible_main_rulesets": null, + "required_meta": { + "main_ruleset": 2, + "non_main_ruleset": 1 + } + }, + "ranked": 1, + "ranked_date": "2019-10-15T22:45:04Z", + "rating": 9.40909, + "storyboard": false, + "submitted_date": "2019-06-18T16:00:11Z", + "tags": "where owls know my name english progressive technical death metal featured artist", + "availability": { + "download_disabled": false, + "more_information": null + }, + "has_favourited": false, + "ratings": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "current_user_playcount": 0, + "failtimes": { + "fail": [ + 0, + 4, + 41, + 64, + 149, + 210, + 547, + 5901, + 2455, + 595, + 1318, + 9767, + 993, + 687, + 4161, + 673, + 48, + 5, + 14, + 32, + 9, + 2, + 5, + 14, + 70, + 37, + 56, + 126, + 60, + 43, + 55, + 59, + 72, + 161, + 310, + 71, + 112, + 22, + 286, + 1038, + 5569, + 3662, + 16, + 15, + 85, + 72, + 12, + 15, + 18, + 2, + 47, + 114, + 34, + 96, + 82, + 34, + 56, + 46, + 81, + 98, + 66, + 12, + 172, + 52, + 3, + 0, + 3, + 0, + 10, + 0, + 0, + 28, + 2, + 0, + 0, + 0, + 0, + 2, + 5, + 118, + 745, + 415, + 102, + 2, + 1, + 29, + 3, + 1, + 0, + 0, + 109, + 79, + 8, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "exit": [ + 0, + 0, + 1976, + 1345, + 1068, + 877, + 261, + 1636, + 1133, + 713, + 1050, + 2397, + 1079, + 1191, + 1394, + 779, + 269, + 257, + 252, + 297, + 221, + 94, + 69, + 133, + 223, + 227, + 212, + 199, + 141, + 168, + 110, + 102, + 61, + 112, + 162, + 93, + 110, + 89, + 103, + 160, + 625, + 694, + 162, + 228, + 433, + 347, + 263, + 181, + 172, + 79, + 229, + 311, + 173, + 231, + 268, + 207, + 176, + 87, + 95, + 168, + 64, + 46, + 55, + 71, + 50, + 33, + 40, + 10, + 14, + 8, + 5, + 41, + 16, + 2, + 15, + 7, + 18, + 16, + 10, + 71, + 99, + 70, + 104, + 57, + 44, + 104, + 60, + 19, + 22, + 48, + 114, + 86, + 66, + 58, + 30, + 55, + 28, + 16, + 19, + 42 + ] + }, + "max_combo": 3275, + "owners": [ + { + "id": 11, + "username": "ThePooN" + } + ] + }, + { + "beatmapset_id": 1681275, + "difficulty_rating": 3.72672, + "id": 3631491, + "mode": "osu", + "status": "ranked", + "total_length": 212, + "user_id": 11, + "version": "Wanpachi's Hard", + "accuracy": 6, + "ar": 8, + "bpm": 240, + "convert": false, + "count_circles": 218, + "count_sliders": 359, + "count_spinners": 2, + "cs": 3, + "deleted_at": null, + "drain": 5, + "hit_length": 180, + "is_scoreable": true, + "last_updated": "2022-07-21T06:02:13Z", + "mode_int": 0, + "passcount": 1, + "playcount": 9, + "ranked": 1, + "url": "https:\/\/dev.ppy.sh\/beatmaps\/3631491", + "checksum": "5111a3da1c545d05ff4136802ad76590", + "beatmapset": { + "anime_cover": false, + "artist": "BUTAOTOME", + "artist_unicode": "\u8c5a\u4e59\u5973", + "covers": { + "cover": "https:\/\/assets.ppy.sh\/beatmaps\/1681275\/covers\/cover.jpg?1658383350", + "cover@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1681275\/covers\/cover@2x.jpg?1658383350", + "card": "https:\/\/assets.ppy.sh\/beatmaps\/1681275\/covers\/card.jpg?1658383350", + "card@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1681275\/covers\/card@2x.jpg?1658383350", + "list": "https:\/\/assets.ppy.sh\/beatmaps\/1681275\/covers\/list.jpg?1658383350", + "list@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1681275\/covers\/list@2x.jpg?1658383350", + "slimcover": "https:\/\/assets.ppy.sh\/beatmaps\/1681275\/covers\/slimcover.jpg?1658383350", + "slimcover@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1681275\/covers\/slimcover@2x.jpg?1658383350" + }, + "creator": "Deca", + "favourite_count": 8, + "genre_id": 4, + "hype": null, + "id": 1681275, + "language_id": 3, + "nsfw": false, + "offset": 0, + "play_count": 28, + "preview_url": "\/\/b.ppy.sh\/preview\/1681275.mp3", + "source": "", + "spotlight": false, + "status": "ranked", + "title": "Shinsan Game", + "title_unicode": "\u8f9b\u9178\u30b2\u30fc\u30e0", + "track_id": null, + "user_id": 11, + "video": false, + "bpm": 240, + "can_be_hyped": false, + "deleted_at": null, + "discussion_enabled": true, + "discussion_locked": false, + "is_scoreable": true, + "last_updated": "2022-07-21T06:02:11Z", + "legacy_thread_url": null, + "nominations_summary": { + "current": 2, + "eligible_main_rulesets": [ + "osu" + ], + "required_meta": { + "main_ruleset": 2, + "non_main_ruleset": 1 + } + }, + "ranked": 1, + "ranked_date": "2023-09-13T20:04:46Z", + "rating": 0, + "storyboard": false, + "submitted_date": "2022-01-23T05:51:07Z", + "tags": "evilelvis buta-otome hardships game comp ranko doubt \u30e9\u30f3\u30b3 jounzan natteke desu aragon lasse amb1d3x hishiro chizuru wanpachi some hero heroine bongo \u30c0\u30a6\u30c8 japanese rock", + "availability": { + "download_disabled": false, + "more_information": null + }, + "has_favourited": false, + "ratings": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "current_user_playcount": 0, + "failtimes": { + "exit": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "fail": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "max_combo": 968, + "owners": [ + { + "id": 11, + "username": "ThePooN" + } + ] + }, + { + "beatmapset_id": 1703042, + "difficulty_rating": 2.36513, + "id": 3658033, + "mode": "osu", + "status": "ranked", + "total_length": 199, + "user_id": 11, + "version": "Jon's Normal", + "accuracy": 4, + "ar": 5, + "bpm": 184, + "convert": false, + "count_circles": 125, + "count_sliders": 237, + "count_spinners": 1, + "cs": 4, + "deleted_at": null, + "drain": 4, + "hit_length": 184, + "is_scoreable": true, + "last_updated": "2022-07-24T19:26:15Z", + "mode_int": 0, + "passcount": 0, + "playcount": 0, + "ranked": 1, + "url": "https:\/\/dev.ppy.sh\/beatmaps\/3658033", + "checksum": "e37bb04f424cfdd58481d05a61f7f642", + "beatmapset": { + "anime_cover": false, + "artist": "yuchaP", + "artist_unicode": "\u3086\u3061\u3083P", + "covers": { + "cover": "https:\/\/assets.ppy.sh\/beatmaps\/1703042\/covers\/cover.jpg?1658690797", + "cover@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1703042\/covers\/cover@2x.jpg?1658690797", + "card": "https:\/\/assets.ppy.sh\/beatmaps\/1703042\/covers\/card.jpg?1658690797", + "card@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1703042\/covers\/card@2x.jpg?1658690797", + "list": "https:\/\/assets.ppy.sh\/beatmaps\/1703042\/covers\/list.jpg?1658690797", + "list@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1703042\/covers\/list@2x.jpg?1658690797", + "slimcover": "https:\/\/assets.ppy.sh\/beatmaps\/1703042\/covers\/slimcover.jpg?1658690797", + "slimcover@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1703042\/covers\/slimcover@2x.jpg?1658690797" + }, + "creator": "Nevo", + "favourite_count": 3, + "genre_id": 4, + "hype": null, + "id": 1703042, + "language_id": 3, + "nsfw": false, + "offset": 0, + "play_count": 7, + "preview_url": "\/\/b.ppy.sh\/preview\/1703042.mp3", + "source": "", + "spotlight": false, + "status": "ranked", + "title": "Pokerface", + "title_unicode": "\u30dd\u30fc\u30ab\u30fc\u30d5\u30a7\u30a4\u30b9", + "track_id": null, + "user_id": 11, + "video": true, + "bpm": 184, + "can_be_hyped": false, + "deleted_at": null, + "discussion_enabled": true, + "discussion_locked": false, + "is_scoreable": true, + "last_updated": "2022-07-24T19:26:14Z", + "legacy_thread_url": null, + "nominations_summary": { + "current": 2, + "eligible_main_rulesets": [ + "osu" + ], + "required_meta": { + "main_ruleset": 2, + "non_main_ruleset": 1 + } + }, + "ranked": 1, + "ranked_date": "2023-09-13T19:22:20Z", + "rating": 0, + "storyboard": false, + "submitted_date": "2022-02-19T21:39:17Z", + "tags": "vocaloid japanese cover utaite gumi len fast rvmathew jonarwhal rock jrock j-rock kaichi hnd", + "availability": { + "download_disabled": false, + "more_information": null + }, + "has_favourited": false, + "ratings": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "current_user_playcount": 0, + "failtimes": { + "fail": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 9, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 9, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "exit": [ + 0, + 0, + 0, + 0, + 0, + 9, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "max_combo": 619, + "owners": [ + { + "id": 11, + "username": "ThePooN" + } + ] + }, + { + "beatmapset_id": 1789487, + "difficulty_rating": 1.98075, + "id": 3666654, + "mode": "osu", + "status": "ranked", + "total_length": 88, + "user_id": 11, + "version": "ckharv's Easy", + "accuracy": 2, + "ar": 3, + "bpm": 180, + "convert": false, + "count_circles": 77, + "count_sliders": 59, + "count_spinners": 0, + "cs": 3, + "deleted_at": null, + "drain": 2, + "hit_length": 87, + "is_scoreable": true, + "last_updated": "2022-07-25T00:02:22Z", + "mode_int": 0, + "passcount": 9, + "playcount": 22, + "ranked": 1, + "url": "https:\/\/dev.ppy.sh\/beatmaps\/3666654", + "checksum": "da748165d116b6dcbb2ff6e064cbf5bf", + "beatmapset": { + "anime_cover": false, + "artist": "Satono Diamond (CV: Tachibana Hina), Kitasan Black (CV: Yano Hinaki)", + "artist_unicode": "\u30b5\u30c8\u30ce\u30c0\u30a4\u30e4\u30e2\u30f3\u30c9 (CV\uff1a\u7acb\u82b1\u65e5\u83dc), \u30ad\u30bf\u30b5\u30f3\u30d6\u30e9\u30c3\u30af (CV\uff1a\u77e2\u91ce\u5983\u83dc\u559c)", + "covers": { + "cover": "https:\/\/assets.ppy.sh\/beatmaps\/1789487\/covers\/cover.jpg?1658707359", + "cover@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1789487\/covers\/cover@2x.jpg?1658707359", + "card": "https:\/\/assets.ppy.sh\/beatmaps\/1789487\/covers\/card.jpg?1658707359", + "card@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1789487\/covers\/card@2x.jpg?1658707359", + "list": "https:\/\/assets.ppy.sh\/beatmaps\/1789487\/covers\/list.jpg?1658707359", + "list@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1789487\/covers\/list@2x.jpg?1658707359", + "slimcover": "https:\/\/assets.ppy.sh\/beatmaps\/1789487\/covers\/slimcover.jpg?1658707359", + "slimcover@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1789487\/covers\/slimcover@2x.jpg?1658707359" + }, + "creator": "Zekk", + "favourite_count": 9, + "genre_id": 5, + "hype": null, + "id": 1789487, + "language_id": 3, + "nsfw": false, + "offset": 0, + "play_count": 114, + "preview_url": "\/\/b.ppy.sh\/preview\/1789487.mp3", + "source": "\u30a6\u30de\u5a18 \u30d7\u30ea\u30c6\u30a3\u30fc\u30c0\u30fc\u30d3\u30fc", + "spotlight": false, + "status": "ranked", + "title": "Ambitious World (PV Size)", + "title_unicode": "Ambitious World (PV Size)", + "track_id": null, + "user_id": 11, + "video": false, + "bpm": 180, + "can_be_hyped": false, + "deleted_at": null, + "discussion_enabled": true, + "discussion_locked": false, + "is_scoreable": true, + "last_updated": "2022-07-25T00:02:21Z", + "legacy_thread_url": null, + "nominations_summary": { + "current": 2, + "eligible_main_rulesets": [ + "osu" + ], + "required_meta": { + "main_ruleset": 2, + "non_main_ruleset": 1 + } + }, + "ranked": 1, + "ranked_date": "2023-09-13T19:24:15Z", + "rating": 10, + "storyboard": false, + "submitted_date": "2022-06-19T22:22:08Z", + "tags": "horse girls uma musume pretty derby japanese pop video game anime kowari ckharv satonodiamond nanoya koldnoodl", + "availability": { + "download_disabled": false, + "more_information": null + }, + "has_favourited": false, + "ratings": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "current_user_playcount": 0, + "failtimes": { + "exit": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 9, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "fail": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "max_combo": 239, + "owners": [ + { + "id": 11, + "username": "ThePooN" + } + ] + }, + { + "beatmapset_id": 1811717, + "difficulty_rating": 2.29139, + "id": 3716286, + "mode": "osu", + "status": "ranked", + "total_length": 125, + "user_id": 11, + "version": "Xahlt's Bot Diff", + "accuracy": 4.5, + "ar": 5.5, + "bpm": 180.55, + "convert": false, + "count_circles": 113, + "count_sliders": 130, + "count_spinners": 0, + "cs": 3.3, + "deleted_at": null, + "drain": 3, + "hit_length": 116, + "is_scoreable": true, + "last_updated": "2022-07-24T18:59:31Z", + "mode_int": 0, + "passcount": 0, + "playcount": 1, + "ranked": 1, + "url": "https:\/\/dev.ppy.sh\/beatmaps\/3716286", + "checksum": "fe662e406ce708e33dd6264f59c6f9cd", + "beatmapset": { + "anime_cover": false, + "artist": "Porter Robinson", + "artist_unicode": "Porter Robinson", + "covers": { + "cover": "https:\/\/assets.ppy.sh\/beatmaps\/1811717\/covers\/cover.jpg?1658689187", + "cover@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1811717\/covers\/cover@2x.jpg?1658689187", + "card": "https:\/\/assets.ppy.sh\/beatmaps\/1811717\/covers\/card.jpg?1658689187", + "card@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1811717\/covers\/card@2x.jpg?1658689187", + "list": "https:\/\/assets.ppy.sh\/beatmaps\/1811717\/covers\/list.jpg?1658689187", + "list@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1811717\/covers\/list@2x.jpg?1658689187", + "slimcover": "https:\/\/assets.ppy.sh\/beatmaps\/1811717\/covers\/slimcover.jpg?1658689187", + "slimcover@2x": "https:\/\/assets.ppy.sh\/beatmaps\/1811717\/covers\/slimcover@2x.jpg?1658689187" + }, + "creator": "Sotarks", + "favourite_count": 29, + "genre_id": 5, + "hype": null, + "id": 1811717, + "language_id": 2, + "nsfw": false, + "offset": 0, + "play_count": 12, + "preview_url": "\/\/b.ppy.sh\/preview\/1811717.mp3", + "source": "League of Legends", + "spotlight": false, + "status": "ranked", + "title": "Everything Goes On (Star Guardian Version) (Sped Up Ver.)", + "title_unicode": "Everything Goes On (Star Guardian Version) (Sped Up Ver.)", + "track_id": null, + "user_id": 11, + "video": true, + "bpm": 180.55, + "can_be_hyped": false, + "deleted_at": null, + "discussion_enabled": true, + "discussion_locked": false, + "is_scoreable": true, + "last_updated": "2022-07-24T18:59:29Z", + "legacy_thread_url": null, + "nominations_summary": { + "current": 2, + "eligible_main_rulesets": [ + "osu" + ], + "required_meta": { + "main_ruleset": 2, + "non_main_ruleset": 1 + } + }, + "ranked": 1, + "ranked_date": "2023-09-12T20:24:15Z", + "rating": 9.88889, + "storyboard": false, + "submitted_date": "2022-07-21T19:32:53Z", + "tags": "speed 2022 official music video red dog culture house riot games english electronic pop male vocals vocalist edit banter pepekcz xahlt kuon- gweon sua", + "availability": { + "download_disabled": false, + "more_information": null + }, + "has_favourited": false, + "ratings": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "current_user_playcount": 0, + "failtimes": { + "exit": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 18, + 9, + 9, + 0, + 0, + 9, + 0, + 9, + 0, + 0, + 9, + 0, + 0, + 0, + 9, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 9, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 9, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "fail": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "max_combo": 406, + "owners": [ + { + "id": 11, + "username": "ThePooN" + } + ] + } +] \ No newline at end of file diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingQueueScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingQueueScreen.cs index 07d0fe6ed9f3..4787b195b170 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingQueueScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingQueueScreen.cs @@ -7,6 +7,7 @@ using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Matchmaking; using osu.Game.Screens.OnlinePlay.Matchmaking.Intro; using osu.Game.Screens.OnlinePlay.Matchmaking.Queue; using osu.Game.Tests.Visual.Multiplayer; @@ -26,7 +27,7 @@ public override void SetUpSteps() { base.SetUpSteps(); - AddStep("load screen", () => LoadScreen(new ScreenIntro())); + AddStep("load screen", () => LoadScreen(new ScreenIntro(MatchmakingPoolType.QuickPlay))); } [Test] diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index 84e0e499fa9e..9f7930d09ae3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -277,7 +277,7 @@ public void TestBeatmapSetHasVideoOrStoryboard() public void TestSelectedModsDontAffectStatistics() { AddStep("show map", () => overlay.ShowBeatmapSet(getBeatmapSet())); - AddAssert("AR displayed as 0", () => overlay.ChildrenOfType().Single(s => s.Title == SongSelectStrings.ApproachRate).Value, () => Is.EqualTo((0, 0))); + AddAssert("AR displayed as 7", () => overlay.ChildrenOfType().Single(s => s.Title == SongSelectStrings.ApproachRate).Value, () => Is.EqualTo((7.0f, 7.0f))); AddStep("set AR10 diff adjust", () => SelectedMods.Value = new[] { new OsuModDifficultyAdjust @@ -285,7 +285,7 @@ public void TestSelectedModsDontAffectStatistics() ApproachRate = { Value = 10 } } }); - AddAssert("AR still displayed as 0", () => overlay.ChildrenOfType().Single(s => s.Title == SongSelectStrings.ApproachRate).Value, () => Is.EqualTo((0, 0))); + AddAssert("AR still displayed as 7", () => overlay.ChildrenOfType().Single(s => s.Title == SongSelectStrings.ApproachRate).Value, () => Is.EqualTo((7.0f, 7.0f))); } [Test] diff --git a/osu.Game.Tests/Visual/RankedPlay/RankedPlayTestScene.cs b/osu.Game.Tests/Visual/RankedPlay/RankedPlayTestScene.cs new file mode 100644 index 000000000000..f56b7a7725c3 --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/RankedPlayTestScene.cs @@ -0,0 +1,78 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.IO; +using System.Linq; +using Newtonsoft.Json; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osu.Game.Tests.Resources; +using osu.Game.Tests.Visual.Multiplayer; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public abstract partial class RankedPlayTestScene : MultiplayerTestScene + { + /// + /// Returns 5 sample s. + /// + protected static APIBeatmap[] GetSampleBeatmaps() + { + using var resourceStream = TestResources.OpenResource("Requests/api-beatmaps-rankedplay.json"); + using var reader = new StreamReader(resourceStream); + + return JsonConvert.DeserializeObject(reader.ReadToEnd())!; + } + + /// + /// A request handler that will resolve api requests to any beatmaps provided by . + /// + public class BeatmapRequestHandler + { + public readonly APIBeatmap[] Beatmaps = GetSampleBeatmaps(); + + public bool HandleRequest(APIRequest request) + { + switch (request) + { + case GetBeatmapRequest beatmapRequest: + var beatmap = Beatmaps.FirstOrDefault(it => it.OnlineID == beatmapRequest.OnlineID); + + if (beatmap != null) + { + beatmapRequest.TriggerSuccess(beatmap); + return true; + } + + break; + + case GetBeatmapsRequest beatmapsRequest: + beatmapsRequest.TriggerSuccess(new GetBeatmapsResponse + { + Beatmaps = beatmapsRequest + .BeatmapIds + .Select(id => Beatmaps.FirstOrDefault(it => it.OnlineID == id)) + .ToList() + }); + + return true; + } + + return false; + } + } + + public class RevealedRankedPlayCardWithPlaylistItem : RankedPlayCardWithPlaylistItem + { + public RevealedRankedPlayCardWithPlaylistItem(APIBeatmap beatmap, RankedPlayCardItem? card = null) + : base(card ?? new RankedPlayCardItem()) + { + PlaylistItem.Value = new MultiplayerPlaylistItem(new PlaylistItem(beatmap)); + } + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneDiscardScreen.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneDiscardScreen.cs new file mode 100644 index 000000000000..f3e39796ac19 --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneDiscardScreen.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Extensions; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osu.Game.Tests.Visual.Multiplayer; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestSceneDiscardScreen : MultiplayerTestScene + { + private RankedPlayScreen screen = null!; + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("join room", () => JoinRoom(CreateDefaultRoom(MatchType.RankedPlay))); + WaitForJoined(); + + AddStep("add other user", () => MultiplayerClient.AddUser(new MultiplayerRoomUser(2))); + + AddStep("load screen", () => LoadScreen(screen = new RankedPlayScreen(MultiplayerClient.ClientRoom!))); + AddUntilStep("screen loaded", () => screen.IsLoaded); + + AddStep("set pick state", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.CardDiscard).WaitSafely()); + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneEndedScreen.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneEndedScreen.cs new file mode 100644 index 000000000000..8a7f22c8229e --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneEndedScreen.cs @@ -0,0 +1,63 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Extensions; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osu.Game.Tests.Visual.Multiplayer; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestSceneEndedScreen : MultiplayerTestScene + { + private RankedPlayScreen screen = null!; + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("join room", () => JoinRoom(CreateDefaultRoom(MatchType.RankedPlay))); + WaitForJoined(); + + AddStep("add other user", () => MultiplayerClient.AddUser(new MultiplayerRoomUser(2))); + + AddStep("load screen", () => LoadScreen(screen = new RankedPlayScreen(MultiplayerClient.ClientRoom!))); + AddUntilStep("screen loaded", () => screen.IsLoaded); + } + + [Test] + public void TestVictory() + { + AddStep("set results state", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.Ended, s => + { + s.WinningUserId = API.LocalUser.Value.OnlineID; + s.Users[API.LocalUser.Value.OnlineID].RatingAfter = 1520; + s.Users[2].RatingAfter = 1480; + }).WaitSafely()); + } + + [Test] + public void TestDefeat() + { + AddStep("set results state", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.Ended, s => + { + s.WinningUserId = 2; + s.Users[API.LocalUser.Value.OnlineID].RatingAfter = 1480; + s.Users[2].RatingAfter = 1520; + }).WaitSafely()); + } + + [Test] + public void TestDraw() + { + AddStep("set results state", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.Ended, s => + { + s.Users[API.LocalUser.Value.OnlineID].RatingAfter = 1480; + s.Users[2].RatingAfter = 1520; + }).WaitSafely()); + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneGameplayWarmupScreen.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneGameplayWarmupScreen.cs new file mode 100644 index 000000000000..125cfd97811a --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneGameplayWarmupScreen.cs @@ -0,0 +1,49 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Extensions; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osu.Game.Tests.Beatmaps; +using osu.Game.Tests.Visual.Multiplayer; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestSceneGameplayWarmupScreen : MultiplayerTestScene + { + private RankedPlayScreen screen = null!; + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("join room", () => + { + var beatmap = new TestBeatmap(Ruleset.Value).BeatmapInfo; + beatmap.StarRating = 2; + + var room = CreateDefaultRoom(MatchType.RankedPlay); + room.Playlist = + [ + new PlaylistItem(beatmap) + { + RulesetID = Ruleset.Value.OnlineID + } + ]; + + JoinRoom(room); + }); + + WaitForJoined(); + AddStep("add other user", () => MultiplayerClient.AddUser(new MultiplayerRoomUser(2))); + + AddStep("load screen", () => LoadScreen(screen = new RankedPlayScreen(MultiplayerClient.ClientRoom!))); + AddUntilStep("screen loaded", () => screen.IsLoaded); + AddStep("play card", () => MultiplayerClient.PlayCard(new RankedPlayCardItem())); + + AddStep("set warmup state", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.GameplayWarmup).WaitSafely()); + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneHandReplay.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneHandReplay.cs new file mode 100644 index 000000000000..304b6c223825 --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneHandReplay.cs @@ -0,0 +1,140 @@ +// 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.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; +using osu.Framework.Utils; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.RankedPlay; +using osu.Game.Online.Rooms; +using osu.Game.Overlays; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand; +using osu.Game.Tests.Visual.Multiplayer; +using osuTK; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestSceneHandReplay : MultiplayerTestScene + { + private PlayerHandOfCards playerHand = null!; + private OpponentHandOfCards opponentHand = null!; + private TestHandReplayRecorder recorder = null!; + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("join room", () => JoinRoom(CreateDefaultRoom(MatchType.RankedPlay))); + WaitForJoined(); + + AddStep("setup", () => + { + var cards = Enumerable.Range(0, 5) + .Select(_ => new RankedPlayCardWithPlaylistItem(new RankedPlayCardItem())) + .ToArray(); + + Children = + [ + playerHand = new PlayerHandOfCards + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.5f), + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + SelectionMode = HandSelectionMode.Multiple + }, + opponentHand = new OpponentHandOfCards + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.5f), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + new HandReplayPlayer(API.LocalUser.Value.OnlineID, opponentHand), + recorder = new TestHandReplayRecorder(playerHand) + { + FlushInterval = flushInterval, + RecordInterval = recordInterval, + } + ]; + + foreach (var card in cards) + { + playerHand.AddCard(card); + opponentHand.AddCard(card); + } + }); + } + + private double flushInterval = 1000; + private double recordInterval = 25; + private double fixedLatency; + private double maxLatency; + + [Test] + public void TestCardHandReplay() + { + AddSliderStep("record interval", 0.0, 1000.0, 25.0, value => + { + recordInterval = value; + recreateRecorder(); + }); + AddSliderStep("flush interval", 0.0, 5000.0, 1000.0, value => + { + flushInterval = value; + recreateRecorder(); + }); + AddSliderStep("latency", 0.0, 5000.0, 0.0, value => + { + fixedLatency = value; + recreateRecorder(); + }); + AddSliderStep("randomize latency", 0.0, 5000.0, 0.0, value => + { + maxLatency = value; + recreateRecorder(); + }); + } + + private void recreateRecorder() + { + if (recorder.IsNotNull()) + { + Remove(recorder, true); + Add(recorder = new TestHandReplayRecorder(playerHand) + { + FlushInterval = flushInterval, + RecordInterval = recordInterval, + FixedLatency = fixedLatency, + RandomLatency = maxLatency, + }); + } + } + + private partial class TestHandReplayRecorder(PlayerHandOfCards handOfCards) : HandReplayRecorder(handOfCards) + { + private double lastSendTime; + + public double FixedLatency; + + public double RandomLatency; + + protected override void Flush(RankedPlayCardHandReplayFrame[] frames) + { + double sendTime = Math.Max(lastSendTime, Time.Current + FixedLatency + RNG.NextDouble(RandomLatency)); + + lastSendTime = sendTime; + + Scheduler.AddDelayed(() => base.Flush(frames), sendTime - Time.Current); + } + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneIntroScreen.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneIntroScreen.cs new file mode 100644 index 000000000000..05ca5673ffbd --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneIntroScreen.cs @@ -0,0 +1,37 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro; +using osu.Game.Tests.Visual.Matchmaking; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestSceneIntroScreen : MatchmakingTestScene + { + public override void SetUpSteps() + { + base.SetUpSteps(); + + IntroScreen introScreen = null!; + + AddStep("Add screen", () => Child = introScreen = new IntroScreen()); + + AddStep("play animation", () => introScreen.PlayIntroSequence( + new UserWithRating(new APIUser + { + Id = 2, + Username = "User 1", + CoverUrl = "https://assets.ppy.sh/user-profile-covers/13845312/53e4eda7ad3ce41f0990c041179d8ab5d553fef988835f346a8d8da0482506ec.png" + }, 1234), + new UserWithRating(new APIUser + { + Id = 3, + Username = "User 2", + CoverUrl = "https://assets.ppy.sh/user-profile-covers/14102976/10144df2f1c6fb2101726e0f89087a6061bc75755d88e59a9faf2c84034f2c71.jpeg" + }, 1234), + 6.3f + )); + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneOpponentPickScreen.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneOpponentPickScreen.cs new file mode 100644 index 000000000000..838a49d2558f --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneOpponentPickScreen.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Extensions; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osu.Game.Tests.Visual.Multiplayer; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestSceneOpponentPickScreen : MultiplayerTestScene + { + private RankedPlayScreen screen = null!; + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("join room", () => JoinRoom(CreateDefaultRoom(MatchType.RankedPlay))); + WaitForJoined(); + + AddStep("add other user", () => MultiplayerClient.AddUser(new MultiplayerRoomUser(2))); + + AddStep("load screen", () => LoadScreen(screen = new RankedPlayScreen(MultiplayerClient.ClientRoom!))); + AddUntilStep("screen loaded", () => screen.IsLoaded); + + AddStep("set pick state", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.CardPlay, state => state.ActiveUserId = 2).WaitSafely()); + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestScenePickScreen.cs b/osu.Game.Tests/Visual/RankedPlay/TestScenePickScreen.cs new file mode 100644 index 000000000000..042a56adf8b5 --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestScenePickScreen.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Extensions; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osu.Game.Tests.Visual.Multiplayer; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestScenePickScreen : MultiplayerTestScene + { + private RankedPlayScreen screen = null!; + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("join room", () => JoinRoom(CreateDefaultRoom(MatchType.RankedPlay))); + WaitForJoined(); + + AddStep("add other user", () => MultiplayerClient.AddUser(new MultiplayerRoomUser(2))); + + AddStep("load screen", () => LoadScreen(screen = new RankedPlayScreen(MultiplayerClient.ClientRoom!))); + AddUntilStep("screen loaded", () => screen.IsLoaded); + + AddStep("set pick state", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.CardPlay, state => state.ActiveUserId = API.LocalUser.Value.OnlineID).WaitSafely()); + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestScenePlayerCardHand.cs b/osu.Game.Tests/Visual/RankedPlay/TestScenePlayerCardHand.cs new file mode 100644 index 000000000000..a567079e20d1 --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestScenePlayerCardHand.cs @@ -0,0 +1,161 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using Humanizer; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Overlays; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestScenePlayerCardHand : OsuManualInputManagerTestScene + { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + + private PlayerHandOfCards handOfCards = null!; + + [BackgroundDependencyLoader] + private void load() + { + Child = handOfCards = new PlayerHandOfCards + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + }; + } + + [Test] + public void TestSingleSelectionMode() + { + AddStep("add cards", () => + { + handOfCards.Clear(); + for (int i = 0; i < 5; i++) + handOfCards.AddCard(new RankedPlayCardWithPlaylistItem(new RankedPlayCardItem())); + }); + AddStep("single selection mode", () => handOfCards.SelectionMode = HandSelectionMode.Single); + + AddStep("click first card", () => handOfCards.Cards.First().TriggerClick()); + AddAssert("first card selected", () => handOfCards.Selection.SequenceEqual([handOfCards.Cards.First().Item])); + + AddStep("click second card", () => handOfCards.Cards.ElementAt(1).TriggerClick()); + AddAssert("second card selected", () => handOfCards.Selection.SequenceEqual([handOfCards.Cards.ElementAt(1).Item])); + + AddStep("click second card again", () => handOfCards.Cards.ElementAt(1).TriggerClick()); + AddAssert("second card selected", () => handOfCards.Selection.SequenceEqual([handOfCards.Cards.ElementAt(1).Item])); + } + + [Test] + public void TestMultiSelectionMode() + { + AddStep("add cards", () => + { + handOfCards.Clear(); + for (int i = 0; i < 5; i++) + handOfCards.AddCard(new RankedPlayCardWithPlaylistItem(new RankedPlayCardItem())); + }); + AddStep("multi selection mode", () => handOfCards.SelectionMode = HandSelectionMode.Multiple); + + AddStep("click first card", () => handOfCards.Cards.First().TriggerClick()); + AddAssert("first card selected", () => handOfCards.Selection.SequenceEqual([handOfCards.Cards.First().Item])); + + AddStep("click second card", () => handOfCards.Cards.ElementAt(1).TriggerClick()); + AddAssert("both cards selected", () => handOfCards.Selection.SequenceEqual([handOfCards.Cards.ElementAt(0).Item, handOfCards.Cards.ElementAt(1).Item])); + + AddStep("click second card again", () => handOfCards.Cards.ElementAt(1).TriggerClick()); + AddAssert("first card selected", () => handOfCards.Selection.SequenceEqual([handOfCards.Cards.ElementAt(0).Item])); + } + + [Test] + public void TestCardCount() + { + for (int i = 1; i <= 8; i++) + { + int numCards = i; + + AddStep($"{i} {"cards".Pluralize(i == 1)}", () => + { + handOfCards.Clear(); + + for (int j = 0; j < numCards; j++) + handOfCards.AddCard(new RankedPlayCardWithPlaylistItem(new RankedPlayCardItem())); + }); + } + } + + [Test] + public void TestKeyboardSelectionSingleSelection() + { + bool playActionTriggered = false; + + AddStep("add cards", () => + { + playActionTriggered = false; + handOfCards.PlayCardAction = () => playActionTriggered = true; + + handOfCards.Clear(); + for (int i = 0; i < 5; i++) + handOfCards.AddCard(new RankedPlayCardWithPlaylistItem(new RankedPlayCardItem())); + }); + AddStep("single selection mode", () => handOfCards.SelectionMode = HandSelectionMode.Single); + + for (int i = 0; i < 5; i++) + { + int i1 = i; + Key key = Key.Number1 + i; + + AddStep($"key {i + 1}", () => InputManager.Key(key)); + AddAssert("first card selected", () => handOfCards.Selection.SequenceEqual([handOfCards.Cards.ElementAt(i1).Item])); + } + + AddStep("right arrow", () => InputManager.Key(Key.Right)); + AddAssert("first card selected", () => handOfCards.Selection.SequenceEqual([handOfCards.Cards.ElementAt(0).Item])); + + AddStep("right arrow", () => InputManager.Key(Key.Right)); + AddAssert("second card selected", () => handOfCards.Selection.SequenceEqual([handOfCards.Cards.ElementAt(1).Item])); + + AddStep("left arrow", () => InputManager.Key(Key.Left)); + AddAssert("first card selected", () => handOfCards.Selection.SequenceEqual([handOfCards.Cards.ElementAt(0).Item])); + + AddStep("left arrow", () => InputManager.Key(Key.Left)); + AddAssert("last card selected", () => handOfCards.Selection.SequenceEqual([handOfCards.Cards.ElementAt(^1).Item])); + + AddStep("space", () => InputManager.Key(Key.Space)); + AddAssert("play action triggered", () => playActionTriggered); + } + + [Test] + public void TestKeyboardSelectionMultiSelection() + { + AddStep("add cards", () => + { + handOfCards.Clear(); + for (int i = 0; i < 5; i++) + handOfCards.AddCard(new RankedPlayCardWithPlaylistItem(new RankedPlayCardItem())); + }); + AddStep("multi selection mode", () => handOfCards.SelectionMode = HandSelectionMode.Multiple); + + for (int i = 0; i < 5; i++) + { + int i1 = i; + Key key = Key.Number1 + i; + + AddStep($"key {i + 1}", () => InputManager.Key(key)); + AddAssert("card hovered", () => handOfCards.Cards.ElementAt(i1).CardHovered); + + AddAssert("card not selected", () => !handOfCards.Selection.Contains(handOfCards.Cards.ElementAt(i1).Card.Item)); + AddStep("space", () => InputManager.Key(Key.Space)); + AddAssert("card selected", () => handOfCards.Selection.Contains(handOfCards.Cards.ElementAt(i1).Card.Item)); + } + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayBackground.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayBackground.cs new file mode 100644 index 000000000000..a181abc1c656 --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayBackground.cs @@ -0,0 +1,62 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osuTK; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestSceneRankedPlayBackground : OsuTestScene + { + private readonly RankedPlayBackground background; + + private readonly Bindable gradientOuter = new Bindable(Color4Extensions.FromHex("AC6D97")); + private readonly Bindable gradientInner = new Bindable(Color4Extensions.FromHex("544483")); + private readonly Bindable dots = new Bindable(Color4Extensions.FromHex("D56CF6")); + + public TestSceneRankedPlayBackground() + { + Children = + [ + background = new RankedPlayBackground { RelativeSizeAxes = Axes.Both }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = + [ + new BasicColourPicker + { + Scale = new Vector2(0.4f), + Current = gradientOuter, + }, + new BasicColourPicker + { + Scale = new Vector2(0.4f), + Current = gradientInner, + }, + new BasicColourPicker + { + Scale = new Vector2(0.4f), + Current = dots, + } + ] + } + ]; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + gradientOuter.BindValueChanged(e => background.GradientOutside = e.NewValue, true); + gradientInner.BindValueChanged(e => background.GradientInside = e.NewValue, true); + dots.BindValueChanged(e => background.DotsColour = e.NewValue, true); + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayCard.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayCard.cs new file mode 100644 index 000000000000..54fc56a4f9a5 --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayCard.cs @@ -0,0 +1,222 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Cursor; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; +using osu.Game.Rulesets; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand; +using osuTK; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestSceneRankedPlayCard : RankedPlayTestScene + { + protected override Container Content { get; } + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + + [Cached] + private readonly CardDetailsOverlayContainer overlayContainer; + + [Cached] + private readonly SongPreviewParticleContainer particleContainer; + + private readonly BeatmapRequestHandler requestHandler = new BeatmapRequestHandler(); + + public TestSceneRankedPlayCard() + { + base.Content.AddRange(new Drawable[] + { + new OsuContextMenuContainer + { + RelativeSizeAxes = Axes.Both, + Child = Content = new Container + { + RelativeSizeAxes = Axes.Both, + } + }, + overlayContainer = new CardDetailsOverlayContainer(), + particleContainer = new SongPreviewParticleContainer(), + }); + } + + [Test] + public void TestCards() + { + AddStep("add cards", () => + { + FillFlowContainer flow; + + Child = flow = new FillFlowContainer + { + RelativeSizeAxes = Axes.Y, + Width = 800f, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Spacing = new Vector2(10), + }; + + for (int i = 0; i < 10; i++) + { + var beatmap = CreateAPIBeatmap(); + + beatmap.BeatmapSet!.Ratings = Enumerable.Range(0, 11).ToArray(); + beatmap.BeatmapSet!.RelatedTags = + [ + new APITag + { + Id = 2, + Name = "song representation/simple", + Description = "Accessible and straightforward map design." + }, + new APITag + { + Id = 4, + Name = "style/clean", + Description = "Visually uncluttered and organised patterns, often involving few overlaps and equal visual spacing between objects." + }, + new APITag + { + Id = 23, + Name = "aim/aim control", + Description = "Patterns with velocity or direction changes which strongly go against a player's natural movement pattern." + } + ]; + + beatmap.TopTags = + [ + new APIBeatmapTag { TagId = 4, VoteCount = 1 }, + new APIBeatmapTag { TagId = 2, VoteCount = 1 }, + new APIBeatmapTag { TagId = 23, VoteCount = 5 }, + ]; + + beatmap.FailTimes = new APIFailTimes + { + Fails = Enumerable.Range(1, 100).Select(x => x % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(x => x % 12 - 6).ToArray(), + }; + + beatmap.StarRating = i + 1; + + flow.Add(new RankedPlayCardContent(beatmap) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(1.2f), + }); + } + }); + } + + [Test] + public void TestCardHand() + { + AddStep("setup request handler", () => ((DummyAPIAccess)API).HandleRequest = requestHandler.HandleRequest); + + AddStep("add cards", () => + { + PlayerHandOfCards handOfCards; + + Child = handOfCards = new PlayerHandOfCards + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.5f), + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + SelectionMode = HandSelectionMode.Single + }; + + foreach (var beatmap in requestHandler.Beatmaps) + { + handOfCards.AddCard(new RevealedRankedPlayCardWithPlaylistItem(beatmap)); + } + }); + } + + [Resolved] + private RulesetStore rulesetStore { get; set; } = null!; + + [Test] + public void TestRulesets() + { + var rulesets = rulesetStore.AvailableRulesets.Where(it => it.OnlineID >= 0); + + foreach (var ruleset in rulesets) + { + AddStep(ruleset.ShortName, () => + { + FillFlowContainer flow; + + Child = flow = new FillFlowContainer + { + RelativeSizeAxes = Axes.Y, + Width = 800f, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Spacing = new Vector2(10), + }; + + for (int i = 0; i < 10; i++) + { + var beatmap = CreateAPIBeatmap(ruleset); + + beatmap.BeatmapSet!.Ratings = Enumerable.Range(0, 11).ToArray(); + beatmap.BeatmapSet!.RelatedTags = + [ + new APITag + { + Id = 2, + Name = "song representation/simple", + Description = "Accessible and straightforward map design." + }, + new APITag + { + Id = 4, + Name = "style/clean", + Description = "Visually uncluttered and organised patterns, often involving few overlaps and equal visual spacing between objects." + }, + new APITag + { + Id = 23, + Name = "aim/aim control", + Description = "Patterns with velocity or direction changes which strongly go against a player's natural movement pattern." + } + ]; + + beatmap.TopTags = + [ + new APIBeatmapTag { TagId = 4, VoteCount = 1 }, + new APIBeatmapTag { TagId = 2, VoteCount = 1 }, + new APIBeatmapTag { TagId = 23, VoteCount = 5 }, + ]; + + beatmap.FailTimes = new APIFailTimes + { + Fails = Enumerable.Range(1, 100).Select(x => x % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(x => x % 12 - 6).ToArray(), + }; + + beatmap.StarRating = i + 1; + + flow.Add(new RankedPlayCardContent(beatmap) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(1.2f), + }); + } + }); + } + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayCornerPiece.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayCornerPiece.cs new file mode 100644 index 000000000000..f467540cb8e8 --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayCornerPiece.cs @@ -0,0 +1,61 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components; +using osu.Game.Tests.Visual.Multiplayer; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestSceneRankedPlayCornerPiece : MultiplayerTestScene + { + private readonly Bindable visibility = new Bindable(Visibility.Visible); + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("add children", () => + { + Children = + [ + new RankedPlayCornerPiece(RankedPlayColourScheme.Blue, Anchor.BottomLeft) + { + State = { BindTarget = visibility }, + Child = new RankedPlayUserDisplay(2, Anchor.BottomLeft, RankedPlayColourScheme.Blue) + { + RelativeSizeAxes = Axes.Both, + } + }, + new RankedPlayCornerPiece(RankedPlayColourScheme.Red, Anchor.TopRight) + { + State = { BindTarget = visibility }, + Child = new RankedPlayUserDisplay(2, Anchor.TopRight, RankedPlayColourScheme.Red) + { + RelativeSizeAxes = Axes.Both, + } + }, + ]; + }); + } + + [Test] + public void TestCornerPieces() + { + AddStep("show", () => visibility.Value = Visibility.Visible); + AddStep("hide", () => visibility.Value = Visibility.Hidden); + AddSliderStep("health", 0, 1_000_000, 1_000_000, value => + { + foreach (var d in this.ChildrenOfType()) + { + d.Health.Value = value; + } + }); + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayScreen.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayScreen.cs new file mode 100644 index 000000000000..6446ec8f081c --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayScreen.cs @@ -0,0 +1,176 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Extensions; +using osu.Framework.Testing; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestSceneRankedPlayScreen : RankedPlayTestScene + { + private RankedPlayScreen screen = null!; + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("join room", () => JoinRoom(CreateDefaultRoom(MatchType.RankedPlay))); + WaitForJoined(); + + AddStep("join other user", () => MultiplayerClient.AddUser(new APIUser { Id = 2 })); + + AddStep("load screen", () => LoadScreen(screen = new RankedPlayScreen(MultiplayerClient.ClientRoom!))); + } + + [Test] + public void TestIntroStage() + { + AddStep("set round warmup phase", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.RoundWarmup, s => s.StarRating = 6.3f).WaitSafely()); + } + + [Test] + public void TestDiscardCardsStage() + { + AddStep("set discard phase", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.CardDiscard).WaitSafely()); + + AddWaitStep("wait", 3); + + for (int i = 0; i < 3; i++) + { + int i2 = i; + AddStep($"click card {i2}", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().ElementAt(i2)); + InputManager.Click(MouseButton.Left); + }); + } + + AddWaitStep("wait", 3); + + AddStep("click discard button", () => + { + var button = screen.ChildrenOfType().Single(it => it.Name == "Discard Button"); + + InputManager.MoveMouseTo(button); + InputManager.Click(MouseButton.Left); + }); + + AddWaitStep("wait", 13); + AddStep("set finish discard phase", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.FinishCardDiscard).WaitSafely()); + } + + [Test] + public void TestAddRemoveCards() + { + AddStep("set discard phase", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.CardDiscard).WaitSafely()); + + for (int i = 0; i < 3; i++) + AddStep("add card", () => MultiplayerClient.RankedPlayAddCards([new RankedPlayCardItem()]).WaitSafely()); + + for (int i = 0; i < 3; i++) + AddStep("remove card", () => MultiplayerClient.RankedPlayRemoveCards(hand => [hand[0]]).WaitSafely()); + } + + [Test] + public void TestRevealCards() + { + var requestHandler = new BeatmapRequestHandler(); + + AddStep("setup request handler", () => ((DummyAPIAccess)API).HandleRequest = requestHandler.HandleRequest); + + AddStep("set discard phase", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.CardDiscard).WaitSafely()); + + for (int i = 0; i < 3; i++) + { + int i2 = i; + AddStep("reveal card", () => MultiplayerClient.RankedPlayRevealCard(hand => hand[i2], new MultiplayerPlaylistItem + { + ID = i2, + BeatmapID = requestHandler.Beatmaps[i2].OnlineID + }).WaitSafely()); + } + } + + [Test] + public void TestPlayCardDirect() + { + AddStep("set play phase", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.CardPlay, state => state.ActiveUserId = API.LocalUser.Value.OnlineID).WaitSafely()); + AddWaitStep("wait", 3); + AddStep("play card", () => MultiplayerClient.PlayCard(hand => hand[0]).WaitSafely()); + } + + [Test] + public void TestDiscardCardsDirect() + { + AddStep("set discard phase", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.CardDiscard).WaitSafely()); + AddWaitStep("wait", 3); + AddStep("discard cards", () => MultiplayerClient.DiscardCards(hand => hand.Take(3)).WaitSafely()); + AddWaitStep("wait", 13); + AddStep("set finish discard phase", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.FinishCardDiscard).WaitSafely()); + } + + [Test] + public void TestPlayStage() + { + AddStep("set play phase", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.CardPlay, state => state.ActiveUserId = API.LocalUser.Value.OnlineID).WaitSafely()); + AddUntilStep("wait until cards are present", () => this.ChildrenOfType().Count() == 5); + + for (int i = 0; i < 3; i++) + { + int i2 = i; + AddStep($"click card {i2}", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().ElementAt(i2)); + InputManager.Click(MouseButton.Left); + }); + } + + AddWaitStep("wait", 3); + + AddStep("click play button", () => + { + var button = screen + .ChildrenOfType() + .First(it => it.Selected) + .ChildrenOfType() + .First(); + + InputManager.MoveMouseTo(button); + InputManager.Click(MouseButton.Left); + }); + } + + [Test] + public void TestOtherPlaysCard() + { + AddStep("set play phase", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.CardPlay, state => state.ActiveUserId = 2).WaitSafely()); + AddWaitStep("wait", 5); + AddStep("play beatmap", () => MultiplayerClient.PlayUserCard(2, hand => hand[0]).WaitSafely()); + AddStep("reveal card", () => MultiplayerClient.RankedPlayRevealUserCard(2, hand => hand[0], new MultiplayerPlaylistItem + { + ID = 0, + BeatmapID = 0 + }).WaitSafely()); + } + + [Test] + public void TestHealthChange() + { + AddStep("set play phase", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.CardPlay, state => state.ActiveUserId = 2).WaitSafely()); + AddWaitStep("wait", 5); + AddStep("change player 1 health", () => MultiplayerClient.RankedPlayChangeUserState(MultiplayerClient.LocalUser!.UserID, state => state.Life = 250_000).WaitSafely()); + AddWaitStep("wait", 5); + AddStep("change player 2 health", () => MultiplayerClient.RankedPlayChangeUserState(2, state => state.Life = 250_000).WaitSafely()); + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayUserDisplay.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayUserDisplay.cs new file mode 100644 index 000000000000..f7cc9885c79a --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayUserDisplay.cs @@ -0,0 +1,58 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components; +using osu.Game.Tests.Visual.Multiplayer; +using osuTK; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestSceneRankedPlayUserDisplay : MultiplayerTestScene + { + private readonly BindableInt health = new BindableInt + { + MaxValue = 1_000_000, + MinValue = 0, + Value = 1_000_000, + }; + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("add display", () => Child = new RankedPlayUserDisplay(2, Anchor.BottomLeft, RankedPlayColourScheme.Blue) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(256, 72), + Health = { BindTarget = health } + }); + } + + [Test] + public void TesUserDisplay() + { + AddStep("blue color scheme", () => Child = new RankedPlayUserDisplay(2, Anchor.BottomLeft, RankedPlayColourScheme.Blue) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(256, 72), + Health = { BindTarget = health } + }); + + AddStep("red color scheme", () => Child = new RankedPlayUserDisplay(2, Anchor.BottomLeft, RankedPlayColourScheme.Red) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(256, 72), + Health = { BindTarget = health } + }); + + AddSliderStep("health", 0, 1_000_000, 1_000_000, value => health.Value = value); + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneResultsScreen.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneResultsScreen.cs new file mode 100644 index 000000000000..00eb63751205 --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneResultsScreen.cs @@ -0,0 +1,231 @@ +// 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.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Extensions; +using osu.Framework.Utils; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.Rooms; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; +using osu.Game.Tests.Visual.Multiplayer; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestSceneResultsScreen : MultiplayerTestScene + { + private RankedPlayScreen screen = null!; + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("join room", () => JoinRoom(CreateDefaultRoom(MatchType.RankedPlay))); + WaitForJoined(); + + AddStep("add other user", () => MultiplayerClient.AddUser(new MultiplayerRoomUser(2))); + + AddStep("load screen", () => LoadScreen(screen = new RankedPlayScreen(MultiplayerClient.ClientRoom!))); + AddUntilStep("screen loaded", () => screen.IsLoaded); + + setupRequestHandler(); + } + + [Test] + public void TestBasic() + { + AddStep("set results state", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.Results, state => + { + int losingPlayer = state.Users.Keys.First(); + + foreach (var (id, userInfo) in state.Users) + { + if (id == losingPlayer) + { + userInfo.DamageInfo = new RankedPlayDamageInfo + { + RawDamage = 123_456, + Damage = 123_456, + OldLife = 500_000, + NewLife = 500_000 - 123_456, + }; + + userInfo.Life = 500_000 - 123_456; + } + else + { + userInfo.DamageInfo = new RankedPlayDamageInfo + { + RawDamage = 0, + Damage = 0, + OldLife = 1_000_000, + NewLife = 1_000_000, + }; + } + } + }).WaitSafely()); + } + + [Test] + public void TestMultiplier() + { + AddStep("set results state", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.Results, state => + { + int losingPlayer = state.Users.Keys.First(); + + state.DamageMultiplier = 2; + + foreach (var (id, userInfo) in state.Users) + { + if (id == losingPlayer) + { + userInfo.DamageInfo = new RankedPlayDamageInfo + { + RawDamage = 123_456, + Damage = 123_456 * 2, + OldLife = 1_000_000, + NewLife = 1_000_000 - 123_456 * 2, + }; + + userInfo.Life = 1_000_000 - 123_456 * 2; + } + else + { + userInfo.DamageInfo = new RankedPlayDamageInfo + { + RawDamage = 0, + Damage = 0, + OldLife = 1_000_000, + NewLife = 1_000_000, + }; + } + } + }).WaitSafely()); + } + + [Test] + public void TestMissingScores() + { + AddStep("setup request handler", () => + { + Func? defaultRequestHandler = ((DummyAPIAccess)API).HandleRequest; + + ((DummyAPIAccess)API).HandleRequest = request => + { + switch (request) + { + case IndexPlaylistScoresRequest index: + index.TriggerSuccess(new IndexedMultiplayerScores()); + return true; + + default: + return defaultRequestHandler?.Invoke(request) ?? false; + } + }; + }); + + AddStep("set results state", () => MultiplayerClient.RankedPlayChangeStage(RankedPlayStage.Results, state => + { + int losingPlayer = state.Users.Keys.First(); + + state.DamageMultiplier = 2; + + foreach (var (id, userInfo) in state.Users) + { + if (id == losingPlayer) + { + userInfo.DamageInfo = new RankedPlayDamageInfo + { + RawDamage = 123_456, + Damage = 123_456 * 2, + OldLife = 1_000_000, + NewLife = 1_000_000 - 123_456 * 2, + }; + } + else + { + userInfo.DamageInfo = new RankedPlayDamageInfo + { + RawDamage = 0, + Damage = 0, + OldLife = 1_000_000, + NewLife = 1_000_000, + }; + } + } + }).WaitSafely()); + } + + private void setupRequestHandler() + { + AddStep("setup request handler", () => + { + Func? defaultRequestHandler = ((DummyAPIAccess)API).HandleRequest; + + ((DummyAPIAccess)API).HandleRequest = request => + { + switch (request) + { + case IndexPlaylistScoresRequest index: + var result = new IndexedMultiplayerScores(); + + foreach (int userId in new[] { 2, API.LocalUser.Value.OnlineID }) + { + result.Scores.Add(new MultiplayerScore + { + ID = userId, + Accuracy = RNG.NextSingle(), + EndedAt = DateTimeOffset.Now, + Passed = true, + Rank = (ScoreRank)RNG.Next((int)ScoreRank.D, (int)ScoreRank.XH), + MaxCombo = RNG.Next(1000), + TotalScore = userId == 2 ? 750_000 : 750_000 - 123_456, + Statistics = new Dictionary + { + [HitResult.Miss] = 1, + [HitResult.Meh] = 50, + [HitResult.Ok] = 100, + [HitResult.Good] = 200, + [HitResult.Great] = 300, + [HitResult.Perfect] = 320, + [HitResult.SmallTickHit] = 50, + [HitResult.SmallTickMiss] = 25, + [HitResult.LargeTickHit] = 100, + [HitResult.LargeTickMiss] = 50, + [HitResult.SmallBonus] = 10, + [HitResult.LargeBonus] = 50 + }, + MaximumStatistics = new Dictionary + { + [HitResult.Perfect] = 971, + [HitResult.SmallTickHit] = 75, + [HitResult.LargeTickHit] = 150, + [HitResult.SmallBonus] = 10, + [HitResult.LargeBonus] = 50, + }, + User = new APIUser + { + Id = userId, + Username = $"user {userId}", + } + }); + } + + index.TriggerSuccess(result); + return true; + + default: + return defaultRequestHandler?.Invoke(request) ?? false; + } + }; + }); + } + } +} diff --git a/osu.Game.Tests/Visual/RankedPlay/TestSceneSongPreview.cs b/osu.Game.Tests/Visual/RankedPlay/TestSceneSongPreview.cs new file mode 100644 index 000000000000..363082f668cc --- /dev/null +++ b/osu.Game.Tests/Visual/RankedPlay/TestSceneSongPreview.cs @@ -0,0 +1,80 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Game.Online.API; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand; +using osuTK; + +namespace osu.Game.Tests.Visual.RankedPlay +{ + public partial class TestSceneSongPreview : RankedPlayTestScene + { + private readonly Bindable previewEnabled = new BindableBool(true); + + private readonly BeatmapRequestHandler requestHandler = new BeatmapRequestHandler(); + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("setup request handler", () => ((DummyAPIAccess)API).HandleRequest = requestHandler.HandleRequest); + + AddStep("add cards", () => + { + PlayerHandOfCards handOfCards; + + Child = handOfCards = new PlayerHandOfCards + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = new Vector2(0.5f), + }; + + foreach (var beatmap in requestHandler.Beatmaps.Take(3)) + { + handOfCards.AddCard(new RevealedRankedPlayCardWithPlaylistItem(beatmap), handCard => + { + handCard.Card.SongPreviewEnabled.BindTarget = previewEnabled; + }); + } + }); + + AddUntilStep("load tracks", () => this.ChildrenOfType().All(card => card.PreviewTrackLoaded)); + } + + [Test] + public void TestSongPreview() + { + AddStep("move mouse to first card", () => InputManager.MoveMouseTo(getCard(0))); + + AddAssert("first track running", () => getCard(0).PreviewTrackRunning); + AddAssert("only one track running", () => this.ChildrenOfType().Count(c => c.PreviewTrackRunning) == 1); + + AddStep("move mouse to second card", () => InputManager.MoveMouseTo(getCard(1))); + + AddAssert("second track running", () => getCard(1).PreviewTrackRunning); + AddAssert("only one track running", () => this.ChildrenOfType().Count(c => c.PreviewTrackRunning) == 1); + + AddStep("disable preview", () => previewEnabled.Value = false); + + AddAssert("no tracks running", () => !this.ChildrenOfType().Any(c => c.PreviewTrackRunning)); + + AddStep("move mouse to third card", () => InputManager.MoveMouseTo(getCard(2))); + + AddAssert("no tracks running", () => !this.ChildrenOfType().Any(c => c.PreviewTrackRunning)); + + AddStep("enable preview", () => previewEnabled.Value = true); + + AddAssert("third track running", () => getCard(2).PreviewTrackRunning); + } + + private RankedPlayCard getCard(int index) => this.ChildrenOfType().ElementAt(index); + } +} diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 961990a1bd70..c22f4fcdf0b0 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -32,8 +32,12 @@ public abstract partial class PreviewTrack : Component private void load() { Track = GetTrack(); + if (Track != null) + { Track.Completed += Stop; + Track.Looping = looping; + } } /// @@ -56,6 +60,23 @@ private void load() /// public bool IsRunning => Track?.IsRunning ?? false; + private bool looping; + + /// + /// Whether the track should loop. + /// + public bool Looping + { + get => looping; + set + { + looping = value; + + if (Track != null) + Track.Looping = looping; + } + } + private ScheduledDelegate? startDelegate; /// diff --git a/osu.Game/Audio/SamplePlaybackHelper.cs b/osu.Game/Audio/SamplePlaybackHelper.cs new file mode 100644 index 000000000000..8c7168e7edd1 --- /dev/null +++ b/osu.Game/Audio/SamplePlaybackHelper.cs @@ -0,0 +1,38 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Audio.Sample; +using osu.Framework.Utils; + +namespace osu.Game.Audio +{ + public static class SamplePlaybackHelper + { + /// + /// Plays the provided with a randomised pitch. + /// + /// The to be played. + /// The amount of pitch variation to allow. + /// The that was used for playback. + public static SampleChannel? PlayWithRandomPitch(Sample? sample, double pitchVariation = 0.2f) + { + var chan = sample?.GetChannel(); + if (chan == null) + return null; + + chan.Frequency.Value = RNG.NextDouble(1 - pitchVariation, 1 + pitchVariation); + chan.Play(); + + return chan; + } + + /// + /// Plays a random sample from the given array, with a randomised pitch. + /// + /// An array of to play. + /// The amount of pitch variation to allow. + /// The that was used for playback. + public static SampleChannel? PlayWithRandomPitch(Sample?[]? samples, double pitchVariation = 0.2f) => + PlayWithRandomPitch(samples?[RNG.Next(0, samples.Length)], pitchVariation); + } +} diff --git a/osu.Game/Localisation/ButtonSystemStrings.cs b/osu.Game/Localisation/ButtonSystemStrings.cs index c851119274a6..2bce75c01013 100644 --- a/osu.Game/Localisation/ButtonSystemStrings.cs +++ b/osu.Game/Localisation/ButtonSystemStrings.cs @@ -69,6 +69,11 @@ public static class ButtonSystemStrings /// public static LocalisableString QuickPlay => new TranslatableString(getKey(@"quick_play"), @"quick play"); + /// + /// "ranked play" + /// + public static LocalisableString RankedPlay => new TranslatableString(getKey(@"ranked_play"), @"ranked play"); + /// /// "A few important words from your dev team!" /// diff --git a/osu.Game/Online/Leaderboards/DrawableRank.cs b/osu.Game/Online/Leaderboards/DrawableRank.cs index f4f4165c7fb3..efcc14a5c184 100644 --- a/osu.Game/Online/Leaderboards/DrawableRank.cs +++ b/osu.Game/Online/Leaderboards/DrawableRank.cs @@ -115,5 +115,36 @@ public static ColourInfo GetRankLetterColour(ScoreRank rank) return Color4Extensions.FromHex(@"CC3333"); } } + + public static string GetLegacyRankTextureName(ScoreRank rank) + { + switch (rank) + { + case ScoreRank.XH: + return "ranking-XH"; + + case ScoreRank.SH: + return "ranking-SH"; + + case ScoreRank.X: + return "ranking-X"; + + case ScoreRank.S: + return "ranking-S"; + + case ScoreRank.A: + return "ranking-A"; + + case ScoreRank.B: + return "ranking-B"; + + case ScoreRank.C: + return "ranking-C"; + + default: + case ScoreRank.D: + return "ranking-D"; + } + } } } diff --git a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingStage.cs b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingStage.cs index edffa4ec2353..de5344709724 100644 --- a/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingStage.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/Matchmaking/MatchmakingStage.cs @@ -54,6 +54,6 @@ public enum MatchmakingStage /// /// All rounds have completed. Users may still be chatting. /// - Ended + Ended, } } diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 04d7d287d18d..ff974e2e6dd5 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -19,15 +19,22 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Matchmaking; using osu.Game.Online.Multiplayer.Countdown; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.RankedPlay; using osu.Game.Online.Rooms; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; using osu.Game.Utils; namespace osu.Game.Online.Multiplayer { - public abstract partial class MultiplayerClient : Component, IMultiplayerClient, IMultiplayerRoomServer, IMatchmakingServer, IMatchmakingClient + public abstract partial class MultiplayerClient : + Component, + IMultiplayerClient, IMultiplayerRoomServer, + IMatchmakingServer, IMatchmakingClient, + IRankedPlayClient, IRankedPlayServer { public Action? PostNotification { protected get; set; } @@ -131,6 +138,10 @@ public abstract partial class MultiplayerClient : Component, IMultiplayerClient, public event Action? MatchmakingItemDeselected; public event Action? MatchRoomStateChanged; + public event Action? RankedPlayCardAdded; + public event Action? RankedPlayCardRemoved; + public event Action? RankedPlayCardPlayed; + public event Action? UserVotedToSkipIntro; public event Action? VoteToSkipIntroPassed; @@ -197,6 +208,7 @@ public virtual bool IsHost protected Room? APIRoom { get; private set; } private readonly Queue pendingRequests = new Queue(); + private readonly Dictionary cardsWithPlaylistItems = []; [BackgroundDependencyLoader] private void load() @@ -331,6 +343,7 @@ public Task LeaveRoom() APIRoom = null; Room = null; PlayingUserIds.Clear(); + cardsWithPlaylistItems.Clear(); RoomUpdated?.Invoke(); }); @@ -1135,6 +1148,62 @@ Task IMatchmakingClient.MatchmakingItemDeselected(int userId, long playlistItemI return Task.CompletedTask; } + public abstract Task DiscardCards(RankedPlayCardItem[] cards); + + public abstract Task PlayCard(RankedPlayCardItem card); + + Task IRankedPlayClient.RankedPlayCardAdded(int userId, RankedPlayCardItem card) + { + handleRoomRequest(() => + { + RankedPlayCardAdded?.Invoke(userId, GetCardWithPlaylistItem(card)); + RoomUpdated?.Invoke(); + }); + + return Task.CompletedTask; + } + + Task IRankedPlayClient.RankedPlayCardRemoved(int userId, RankedPlayCardItem card) + { + handleRoomRequest(() => + { + RankedPlayCardRemoved?.Invoke(userId, GetCardWithPlaylistItem(card)); + RoomUpdated?.Invoke(); + }); + + return Task.CompletedTask; + } + + Task IRankedPlayClient.RankedPlayCardRevealed(RankedPlayCardItem card, MultiplayerPlaylistItem item) + { + handleRoomRequest(() => + { + GetCardWithPlaylistItem(card).PlaylistItem.Value = item; + RoomUpdated?.Invoke(); + }); + + return Task.CompletedTask; + } + + Task IRankedPlayClient.RankedPlayCardPlayed(RankedPlayCardItem card) + { + handleRoomRequest(() => + { + RankedPlayCardPlayed?.Invoke(GetCardWithPlaylistItem(card)); + RoomUpdated?.Invoke(); + }); + + return Task.CompletedTask; + } + + public RankedPlayCardWithPlaylistItem GetCardWithPlaylistItem(RankedPlayCardItem card) + { + if (cardsWithPlaylistItems.TryGetValue(card, out var existing)) + return existing; + + return cardsWithPlaylistItems[card] = new RankedPlayCardWithPlaylistItem(card); + } + public abstract Task GetMatchmakingPoolsOfType(MatchmakingPoolType type); public abstract Task MatchmakingJoinLobby(); diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 53e3edbe6b75..6d722807aa41 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -15,6 +15,8 @@ using osu.Game.Overlays.Notifications; using osu.Game.Localisation; using osu.Game.Online.Matchmaking; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.RankedPlay; namespace osu.Game.Online.Multiplayer { @@ -82,6 +84,11 @@ private void load(IAPIProvider api) connection.On(nameof(IMatchmakingClient.MatchmakingItemSelected), ((IMatchmakingClient)this).MatchmakingItemSelected); connection.On(nameof(IMatchmakingClient.MatchmakingItemDeselected), ((IMatchmakingClient)this).MatchmakingItemDeselected); + connection.On(nameof(IRankedPlayClient.RankedPlayCardAdded), ((IRankedPlayClient)this).RankedPlayCardAdded); + connection.On(nameof(IRankedPlayClient.RankedPlayCardRemoved), ((IRankedPlayClient)this).RankedPlayCardRemoved); + connection.On(nameof(IRankedPlayClient.RankedPlayCardRevealed), ((IRankedPlayClient)this).RankedPlayCardRevealed); + connection.On(nameof(IRankedPlayClient.RankedPlayCardPlayed), ((IRankedPlayClient)this).RankedPlayCardPlayed); + connection.On(nameof(IStatefulUserHubClient.DisconnectRequested), ((IMultiplayerClient)this).DisconnectRequested); }; @@ -333,6 +340,26 @@ public override Task DisconnectInternal() return connector.Disconnect(); } + public override Task DiscardCards(RankedPlayCardItem[] cards) + { + if (!IsConnected.Value) + return Task.CompletedTask; + + Debug.Assert(connection != null); + + return connection.InvokeAsync(nameof(IRankedPlayServer.DiscardCards), cards); + } + + public override Task PlayCard(RankedPlayCardItem card) + { + if (!IsConnected.Value) + return Task.CompletedTask; + + Debug.Assert(connection != null); + + return connection.InvokeAsync(nameof(IRankedPlayServer.PlayCard), card); + } + public override Task GetMatchmakingPoolsOfType(MatchmakingPoolType type) { if (!IsConnected.Value) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 362e442afc75..926e824d7f9d 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -47,7 +47,8 @@ public partial class ButtonSystem : Container, IStateful, IKe public Action? OnSolo; public Action? OnSettings; public Action? OnMultiplayer; - public Action? OnMatchmaking; + public Action? OnQuickPlay; + public Action? OnRankedPlay; public Action? OnPlaylists; public Action? OnDailyChallenge; @@ -161,7 +162,11 @@ private void load(AudioManager audio, IdleTracker? idleTracker, GameHost host) { Padding = new MarginPadding { Left = WEDGE_WIDTH } }); - buttonsMulti.Add(new MainMenuButton(ButtonSystemStrings.QuickPlay, @"button-daily-select", FontAwesome.Solid.Bolt, new Color4(94, 63, 186, 255), onMatchmaking, Key.Q)); +#if DEBUG + buttonsMulti.Add(new MainMenuButton(ButtonSystemStrings.RankedPlay, @"button-daily-select", FontAwesome.Solid.Crown, new Color4(94, 63, 186, 255), onRankedPlay, Key.R)); +#else + buttonsMulti.Add(new MainMenuButton(ButtonSystemStrings.QuickPlay, @"button-daily-select", FontAwesome.Solid.Bolt, new Color4(94, 63, 186, 255), onQuickPlay, Key.Q)); +#endif buttonsMulti.ForEach(b => b.VisibleState = ButtonSystemState.Multi); buttonsEdit.Add(new MainMenuButton(EditorStrings.BeatmapEditor.ToLower(), @"button-default-select", OsuIcon.Beatmap, new Color4(238, 170, 0, 255), (_, _) => OnEditBeatmap?.Invoke(), Key.B, @@ -217,7 +222,7 @@ private void onMultiplayer(MainMenuButton mainMenuButton, UIEvent uiEvent) OnMultiplayer?.Invoke(); } - private void onMatchmaking(MainMenuButton mainMenuButton, UIEvent uiEvent) + private void onQuickPlay(MainMenuButton mainMenuButton, UIEvent uiEvent) { if (api.State.Value != APIState.Online) { @@ -225,7 +230,18 @@ private void onMatchmaking(MainMenuButton mainMenuButton, UIEvent uiEvent) return; } - OnMatchmaking?.Invoke(); + OnQuickPlay?.Invoke(); + } + + private void onRankedPlay(MainMenuButton mainMenuButton, UIEvent uiEvent) + { + if (api.State.Value != APIState.Online) + { + loginOverlay?.Show(); + return; + } + + OnRankedPlay?.Invoke(); } private void onPlaylists(MainMenuButton mainMenuButton, UIEvent uiEvent) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index ee734acb6015..0820d336225f 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -29,6 +29,7 @@ using osu.Game.IO; using osu.Game.Localisation; using osu.Game.Online.API; +using osu.Game.Online.Matchmaking; using osu.Game.Overlays; using osu.Game.Overlays.Dialog; using osu.Game.Overlays.SkinEditor; @@ -159,7 +160,8 @@ private void load(BeatmapListingOverlay beatmapListing, SettingsOverlay settings }, OnSolo = loadSongSelect, OnMultiplayer = () => this.Push(new Multiplayer()), - OnMatchmaking = joinOrLeaveMatchmakingQueue, + OnQuickPlay = loadQuickPlay, + OnRankedPlay = loadRankedPlay, OnPlaylists = () => this.Push(new Playlists()), OnDailyChallenge = room => { @@ -482,7 +484,9 @@ public void OnReleased(KeyBindingReleaseEvent e) private void loadSongSelect() => this.Push(new SoloSongSelect()); - private void joinOrLeaveMatchmakingQueue() => this.Push(new OnlinePlay.Matchmaking.Intro.ScreenIntro()); + private void loadQuickPlay() => this.Push(new OnlinePlay.Matchmaking.Intro.ScreenIntro(MatchmakingPoolType.QuickPlay)); + + private void loadRankedPlay() => this.Push(new OnlinePlay.Matchmaking.Intro.ScreenIntro(MatchmakingPoolType.RankedPlay)); private partial class MobileDisclaimerDialog : PopupDialog { diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Intro/ScreenIntro.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Intro/ScreenIntro.cs index 7d630ff986ef..0f20ec9a54f6 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Intro/ScreenIntro.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Intro/ScreenIntro.cs @@ -11,6 +11,7 @@ using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Online.Matchmaking; using osu.Game.Overlays; using osu.Game.Screens.OnlinePlay.Matchmaking.Match; using osu.Game.Screens.OnlinePlay.Matchmaking.Queue; @@ -40,28 +41,36 @@ public partial class ScreenIntro : OsuScreen [Resolved] private MusicController musicController { get; set; } = null!; + private readonly MatchmakingPoolType poolType; + private Sample? dateWindupSample; private Sample? dateImpactSample; private Sample? beatmapWindupSample; - private Sample? beatmapImpactSample; private SampleChannel? dateWindupChannel; private SampleChannel? dateImpactChannel; private SampleChannel? beatmapWindupChannel; - private SampleChannel? beatmapImpactChannel; private IDisposable? duckOperation; protected override BackgroundScreen CreateBackground() => new MatchmakingBackgroundScreen(colourProvider); - public ScreenIntro() + public ScreenIntro(MatchmakingPoolType poolType) { + this.poolType = poolType; ValidForResume = false; } [BackgroundDependencyLoader] private void load(AudioManager audio) { + string poolTypeName = poolType switch + { + MatchmakingPoolType.QuickPlay => "Quick Play", + MatchmakingPoolType.RankedPlay => "Ranked Play", + _ => throw new ArgumentOutOfRangeException() + }; + InternalChildren = new Drawable[] { introContent = new Container @@ -99,7 +108,7 @@ private void load(AudioManager audio) { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = "Quick Play", + Text = poolTypeName, Margin = new MarginPadding { Horizontal = 10f, Vertical = 5f }, Shear = -OsuGame.SHEAR, Font = OsuFont.GetFont(size: 32, weight: FontWeight.Light, typeface: Typeface.TorusAlternate), @@ -115,7 +124,6 @@ private void load(AudioManager audio) dateWindupSample = audio.Samples.Get(@"DailyChallenge/date-windup"); dateImpactSample = audio.Samples.Get(@"DailyChallenge/date-impact"); beatmapWindupSample = audio.Samples.Get(@"DailyChallenge/beatmap-windup"); - beatmapImpactSample = audio.Samples.Get(@"DailyChallenge/beatmap-impact"); } public override void OnEntering(ScreenTransitionEvent e) @@ -194,7 +202,7 @@ private void beginAnimation() Schedule(() => { if (this.IsCurrentScreen()) - this.Push(new ScreenQueue()); + this.Push(new ScreenQueue(poolType)); }); } } @@ -219,12 +227,6 @@ private void playBeatmapWindupSample() beatmapWindupChannel?.Play(); } - private void playBeatmapImpactSample() - { - beatmapImpactChannel = beatmapImpactSample?.GetChannel(); - beatmapImpactChannel?.Play(); - } - protected override void Dispose(bool isDisposing) { resetAudio(); @@ -236,7 +238,6 @@ private void resetAudio() dateWindupChannel?.Stop(); dateImpactChannel?.Stop(); beatmapWindupChannel?.Stop(); - beatmapImpactChannel?.Stop(); duckOperation?.Dispose(); } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/PoolSelector.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/PoolSelector.cs index a89700ffe320..7995f72f1af6 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/PoolSelector.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/PoolSelector.cs @@ -24,7 +24,7 @@ public partial class PoolSelector : CompositeDrawable { private const float icon_size = 34; - public readonly Bindable AvailablePools = new Bindable(); + public readonly Bindable AvailablePools = new Bindable([]); public readonly Bindable SelectedPool = new Bindable(); private FillFlowContainer poolFlow = null!; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs index 9456e56bf978..02e944df9f93 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.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.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -40,6 +41,7 @@ public partial class QueueController : Component private BackgroundQueueNotification? backgroundNotification; private bool isBackgrounded; + private MatchmakingPool? lastJoinedPool; protected override void LoadComplete() { @@ -52,6 +54,36 @@ protected override void LoadComplete() client.MatchmakingRoomReady += onMatchmakingRoomReady; } + /// + /// Joins the matchmaking queue. + /// + /// The pool to join. + public void JoinQueue(MatchmakingPool pool) + { + client.MatchmakingJoinQueue(pool.Id).FireAndForget(); + lastJoinedPool = pool; + } + + /// + /// Leaves the matchmaking queue. + /// + public void LeaveQueue() + { + client.MatchmakingLeaveQueue().FireAndForget(); + } + + /// + /// Rejoins the last joined matchmaking queue. + /// + public void RejoinQueue() + { + if (lastJoinedPool != null) + JoinQueue(lastJoinedPool); + } + + /// + /// Moves the matchmaking queue search to the background. + /// public void SearchInBackground() { if (isBackgrounded) @@ -61,6 +93,9 @@ public void SearchInBackground() postNotification(); } + /// + /// Moves the matchmaking queue search to the foreground. + /// public void SearchInForeground() { if (!isBackgrounded) @@ -117,7 +152,8 @@ private void postNotification() if (backgroundNotification != null) return; - notifications?.Post(backgroundNotification = new BackgroundQueueNotification(this)); + Debug.Assert(lastJoinedPool != null); + notifications?.Post(backgroundNotification = new BackgroundQueueNotification(this, lastJoinedPool.Type)); } private void closeNotifications() @@ -153,13 +189,15 @@ private partial class BackgroundQueueNotification : ProgressNotification private MultiplayerClient client { get; set; } = null!; private readonly QueueController controller; + private readonly MatchmakingPoolType poolType; private Notification? foundNotification; private Sample? matchFoundSample; - public BackgroundQueueNotification(QueueController controller) + public BackgroundQueueNotification(QueueController controller, MatchmakingPoolType poolType) { this.controller = controller; + this.poolType = poolType; } [BackgroundDependencyLoader] @@ -174,7 +212,7 @@ private void load(AudioManager audio) if (s is ScreenIntro || s is ScreenQueue) return; - s.Push(new ScreenIntro()); + s.Push(new ScreenIntro(poolType)); }, [typeof(ScreenIntro), typeof(ScreenQueue)]); // Closed when appropriate by SearchInForeground(). @@ -197,7 +235,7 @@ public void Complete(MatchmakingRoomInvitationParams invitation) client.MatchmakingAcceptInvitation().FireAndForget(); controller.CurrentState.Value = ScreenQueue.MatchmakingScreenState.AcceptedWaitingForRoom; - performer?.PerformFromScreen(s => s.Push(new ScreenIntro())); + performer?.PerformFromScreen(s => s.Push(new ScreenIntro(invitation.Type))); Close(false); return true; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs index 87d50213ee8c..2d28cafaab5c 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs @@ -29,8 +29,10 @@ using osu.Game.Online.Matchmaking; using osu.Game.Online.Multiplayer; using osu.Game.Overlays; +using osu.Game.Overlays.Volume; using osu.Game.Rulesets; using osu.Game.Screens.OnlinePlay.Matchmaking.Match; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay; using osuTK; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue @@ -74,9 +76,11 @@ public partial class ScreenQueue : OsuScreen private readonly IBindable currentState = new Bindable(); - private readonly Bindable availablePools = new Bindable(); + private readonly Bindable availablePools = new Bindable([]); private readonly Bindable selectedPool = new Bindable(); + private readonly MatchmakingPoolType poolType; + private CancellationTokenSource userLookupCancellation = new CancellationTokenSource(); private Sample? enqueueSample; @@ -86,6 +90,11 @@ public partial class ScreenQueue : OsuScreen private SampleChannel? waitingLoopChannel; private ScheduledDelegate? startLoopPlaybackDelegate; + public ScreenQueue(MatchmakingPoolType poolType) + { + this.poolType = poolType; + } + protected override void LoadComplete() { base.LoadComplete(); @@ -95,6 +104,7 @@ protected override void LoadComplete() RelativeSizeAxes = Axes.Both, Children = new Drawable[] { + new GlobalScrollAdjustsVolume(), cloud = new CloudVisualisation { Y = -100, @@ -151,7 +161,7 @@ protected override void LoadComplete() private async Task populateAvailablePools() { - MatchmakingPool[] pools = await client.GetMatchmakingPoolsOfType(MatchmakingPoolType.QuickPlay).ConfigureAwait(false); + MatchmakingPool[] pools = await client.GetMatchmakingPoolsOfType(poolType).ConfigureAwait(false); Schedule(() => { @@ -228,7 +238,7 @@ public override bool OnExiting(ScreenExitEvent e) case MatchmakingScreenState.PendingAccept: case MatchmakingScreenState.AcceptedWaitingForRoom: - client.MatchmakingLeaveQueue().FireAndForget(); + controller.LeaveQueue(); return true; case MatchmakingScreenState.InRoom: @@ -280,7 +290,7 @@ public void SetState(MatchmakingScreenState newState) Action = () => { Debug.Assert(selectedPool.Value != null); - client.MatchmakingJoinQueue(selectedPool.Value.Id).FireAndForget(); + controller.JoinQueue(selectedPool.Value); }, Text = "Begin queueing", } @@ -317,7 +327,7 @@ public void SetState(MatchmakingScreenState newState) Origin = Anchor.Centre, Width = 200, Text = "Stop queueing", - Action = () => client.MatchmakingLeaveQueue().FireAndForget() + Action = () => controller.LeaveQueue() } } }; @@ -383,7 +393,22 @@ public void SetState(MatchmakingScreenState newState) }; using (BeginDelayedSequence(2000)) - Schedule(() => this.Push(new ScreenMatchmaking(client.Room!))); + { + Schedule(() => + { + switch (poolType) + { + case MatchmakingPoolType.QuickPlay: + this.Push(new ScreenMatchmaking(client.Room!)); + break; + + case MatchmakingPoolType.RankedPlay: + this.Push(new RankedPlayScreen(client.Room!)); + break; + } + }); + } + break; default: diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/CardDetailsOverlayContainer.UserTags.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/CardDetailsOverlayContainer.UserTags.cs new file mode 100644 index 000000000000..decbccc6bf51 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/CardDetailsOverlayContainer.UserTags.cs @@ -0,0 +1,123 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Screens.Ranking; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card +{ + public partial class CardDetailsOverlayContainer + { + private partial class UserTagSection : CompositeDrawable + { + public IEnumerable Tags + { + set + { + Debug.Assert(LoadState >= LoadState.Ready); + + tagFlow.ChildrenEnumerable = value.Select(tag => new DrawableUserTag(tag)); + this.FadeTo(tagFlow.Children.Count > 0 ? 1 : 0); + } + } + + private FillFlowContainer tagFlow = null!; + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding(10); + + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + Children = + [ + new OsuSpriteText + { + Text = "User Tags", + Font = OsuFont.GetFont(size: 18, weight: FontWeight.SemiBold), + }, + tagFlow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(4) + } + ] + }; + } + } + + private partial class DrawableUserTag(UserTag tag) : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + AutoSizeAxes = Axes.Both; + Masking = true; + CornerRadius = 3; + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = + [ + new Container + { + AutoSizeAxes = Axes.Both, + Alpha = tag.GroupName != null ? 1 : 0, + Children = + [ + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colour.Gray6, + }, + new OsuSpriteText + { + Text = tag.GroupName ?? "", + Padding = new MarginPadding { Left = 5, Right = 3 }, + Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold), + } + ] + }, + new Container + { + AutoSizeAxes = Axes.Both, + Children = + [ + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colour.Gray2, + }, + new OsuSpriteText + { + Text = tag.DisplayName, + Padding = new MarginPadding { Left = 5, Right = 3 }, + Font = OsuFont.GetFont(size: 12), + } + ] + }, + ] + }; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/CardDetailsOverlayContainer.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/CardDetailsOverlayContainer.cs new file mode 100644 index 000000000000..21b42b981ee3 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/CardDetailsOverlayContainer.cs @@ -0,0 +1,146 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Transforms; +using osu.Framework.Threading; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; +using osu.Game.Screens.Ranking; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card +{ + [Cached] + public partial class CardDetailsOverlayContainer : Container + { + public double HideDelay { get; set; } = 1000; + + protected override Container Content { get; } + + private readonly CardDetailsOverlay overlay; + + public CardDetailsOverlayContainer() + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = + [ + Content = new Container + { + RelativeSizeAxes = Axes.Both, + }, + overlay = new CardDetailsOverlay + { + Alpha = 0, + } + ]; + } + + private ScheduledDelegate? hideDelegate; + + public void ShowCardDetails(Drawable targetDrawable, APIBeatmap beatmap) + { + // TODO: remove this once there's more than just tags in the overlay + if (beatmap.GetTopUserTags().Length == 0) + return; + + hideDelegate?.Cancel(); + hideDelegate = Scheduler.AddDelayed(overlay.Hide, HideDelay); + + overlay.TargetDrawable = targetDrawable; + overlay.Beatmap.Value = beatmap; + overlay.Show(); + } + + private partial class CardDetailsOverlay : VisibilityContainer + { + public readonly Bindable Beatmap = new Bindable(); + + public Drawable? TargetDrawable; + + private Container content = null!; + private UserTagSection tagSection = null!; + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Width = 200; + Origin = Anchor.CentreRight; + + InternalChild = content = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Masking = true, + CornerRadius = 6, + Children = + [ + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background4, + Alpha = 0.85f, + }, + tagSection = new UserTagSection() + ] + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Beatmap.BindValueChanged(e => + { + if (e.NewValue != null) + populateContent(e.NewValue); + }, true); + } + + private void populateContent(APIBeatmap beatmap) + { + tagSection.Tags = beatmap.GetTopUserTags().Select(it => new UserTag(it.Tag) { VoteCount = { Value = it.VoteCount } }); + } + + private Vector2 targetPosition => TargetDrawable is { } drawable + ? Parent!.ToLocalSpace(drawable.ScreenSpaceDrawQuad.TopLeft) + new Vector2(-20, 0) + // this results essentially a no-op when there's no valid target + : Position; + + private readonly Vector2Spring position = new Vector2Spring + { + NaturalFrequency = 2f, + Response = 0.25f, + Damping = 0.85f + }; + + protected override void Update() + { + base.Update(); + + // Workaround for AutoSizeAxes not working due to content being able to move + Height = content.Height; + + Position = position.Update(Time.Elapsed, targetPosition); + } + + protected override void PopIn() + { + this.FadeIn(300); + + content.MoveToX(-50) + .MoveToX(0, 400, Easing.OutExpo); + + position.Current = position.PreviousTarget = targetPosition; + } + + protected override void PopOut() => this.FadeOut(300); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCard.SongPreview.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCard.SongPreview.cs new file mode 100644 index 000000000000..6559fd586003 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCard.SongPreview.cs @@ -0,0 +1,306 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Track; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Transforms; +using osu.Framework.Input.Events; +using osu.Framework.Timing; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card +{ + public partial class RankedPlayCard + { + public partial class SongPreviewContainer : Container, IBeatSyncProvider + { + private const double minimum_beat_length = 800; + + public readonly Bindable Enabled = new BindableBool(true); + + public bool TrackLoaded => previewTrack?.TrackLoaded ?? false; + + public bool IsRunning => previewTrack?.IsRunning ?? false; + + protected override Container Content { get; } + + private readonly Bindable trackRunning = new BindableBool(); + private readonly Container overlayLayer; + + private bool shouldBePlaying => Enabled.Value && IsHovered; + + [Resolved] + private PreviewTrackManager previewTrackManager { get; set; } = null!; + + [Resolved] + private OsuColour osuColour { get; set; } = null!; + + public SongPreviewContainer() + { + InternalChildren = + [ + new PulseContainer + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = + [ + Content = new Container + { + RelativeSizeAxes = Axes.Both, + }, + overlayLayer = new Container + { + RelativeSizeAxes = Axes.Both, + } + ] + }, + ]; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Enabled.BindValueChanged(enabled => + { + if (!enabled.NewValue) + { + previewTrack?.Stop(); + return; + } + + if (shouldBePlaying) + { + startPreviewIfAvailable(); + } + }); + } + + private PreviewTrack? previewTrack; + + public void LoadPreview(APIBeatmap beatmap) + { + Debug.Assert(previewTrack == null); + + LoadComponentAsync(previewTrack = previewTrackManager.Get(beatmap.BeatmapSet!), track => + { + AddInternal(track); + + track.Looping = true; + track.Started += onTrackStarted; + track.Stopped += onTrackStopped; + + setupBeatSyncProvider(track, beatmap); + + var cardColours = new RankedPlayCardContent.CardColours(beatmap, osuColour); + + overlayLayer.Add(new RippleVisualization(cardColours.Border) + { + TrackRunning = trackRunning.GetBoundCopy(), + }); + + if (IsHovered) + startPreviewIfAvailable(); + }); + } + + protected override bool OnHover(HoverEvent e) + { + if (shouldBePlaying) + startPreviewIfAvailable(); + + return base.OnHover(e); + } + + private void onTrackStarted() => Schedule(() => trackRunning.Value = true); + + private void onTrackStopped() => Schedule(() => trackRunning.Value = false); + + private void startPreviewIfAvailable() => previewTrack?.Start(); + + #region IBeatSyncProvider implementation + + private readonly PreviewTrackClock beatSyncClock = new PreviewTrackClock(); + private readonly ControlPointInfo controlPoints = new ControlPointInfo(); + + ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => ChannelAmplitudes.Empty; + ControlPointInfo IBeatSyncProvider.ControlPoints => controlPoints; + IClock IBeatSyncProvider.Clock => beatSyncClock; + + private void setupBeatSyncProvider(PreviewTrack track, APIBeatmap beatmap) + { + beatSyncClock.Track = track; + + controlPoints.Add(0, new TimingControlPoint + { + BeatLength = beatmap.BPM > 0 ? 60_000 / beatmap.BPM : TimingControlPoint.DEFAULT_BEAT_LENGTH + }); + } + + private class PreviewTrackClock : IClock + { + public PreviewTrack? Track { get; set; } + + public double CurrentTime => Track?.CurrentTime ?? 0; + public double Rate => 1; + public bool IsRunning => Track?.IsRunning ?? false; + } + + #endregion + + private partial class PulseContainer : BeatSyncedContainer + { + public const double EXPAND_DURATION = 200; + + public PulseContainer() + { + MinimumBeatLength = minimum_beat_length; + } + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + { + if (!IsBeatSyncedWithTrack) + return; + + double beatLength = TimeUntilNextBeat; + + this.ScaleTo(1.02f, EXPAND_DURATION, Easing.In) + .Then() + .ScaleTo(1f, beatLength - EXPAND_DURATION, new CubicBezierEasingFunction(easeIn: 0.1f, easeOut: 1f)); + } + } + + private partial class RippleVisualization : BeatSyncedContainer + { + [Resolved] + private SongPreviewParticleContainer? particleContainer { get; set; } + + public required IBindable TrackRunning { get; init; } + + private readonly Color4 accentColour; + private readonly Container rippleContainer; + + public RippleVisualization(Color4 accentColour) + { + this.accentColour = accentColour; + + MinimumBeatLength = minimum_beat_length; + + RelativeSizeAxes = Axes.Both; + + InternalChildren = + [ + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = CORNER_RADIUS + 1.5f, + Blending = BlendingParameters.Additive, + BorderThickness = 2f, + BorderColour = this.accentColour.Opacity(0.5f), + EdgeEffect = new EdgeEffectParameters + { + Colour = this.accentColour.Opacity(0.1f), + Type = EdgeEffectType.Glow, + Radius = 25f, + Hollow = true, + }, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + EdgeSmoothness = new Vector2(3), + }, + }, + rippleContainer = new Container + { + RelativeSizeAxes = Axes.Both, + } + ]; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + TrackRunning.BindValueChanged(e => + { + if (e.NewValue) + { + rippleContainer.Clear(); + this.FadeIn(100); + } + else + { + this.FadeOut(200); + } + }, true); + } + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + { + if (!IsBeatSyncedWithTrack) + return; + + var ripple = new Container + { + Size = DrawSize, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Masking = true, + CornerRadius = CORNER_RADIUS, + BorderThickness = 2, + BorderColour = accentColour, + Blending = BlendingParameters.Additive, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + }, + Alpha = 0, + }; + + rippleContainer.Add(ripple); + + const float expansion = 20; + + // The animation here is delayed to be in sync with the pulse-container's expansion animation. + // Since the pulse container expands with ease-out, the animation starts a tiny bit + // earlier, so it looks like it's maintaining the momentum of the pulse container's expansion + using (BeginDelayedSequence(PulseContainer.EXPAND_DURATION - 50)) + { + ripple.FadeIn(200) + .Then() + .FadeOut(1000); + + ripple.ResizeTo(DrawSize + new Vector2(expansion), 1000, Easing.OutQuart) + .TransformTo(nameof(CornerRadius), CORNER_RADIUS + expansion / 2, 1000, Easing.OutQuart) + .TransformTo(nameof(BorderThickness), 0.5f, 1000, Easing.In) + .Expire(); + + Schedule(() => particleContainer?.AddParticles(this, accentColour)); + } + } + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCard.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCard.cs new file mode 100644 index 000000000000..8ece23e4d33b --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCard.cs @@ -0,0 +1,241 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Logging; +using osu.Game.Audio; +using osu.Game.Database; +using osu.Game.Online.Rooms; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card +{ + [Cached] + public partial class RankedPlayCard : CompositeDrawable + { + public static readonly Vector2 SIZE = new Vector2(120, 200); + + public static readonly float CORNER_RADIUS = 6; + + public readonly RankedPlayCardWithPlaylistItem Item; + + private readonly IBindable playlistItem; + + public readonly Bindable SongPreviewEnabled = new BindableBool(true); + + private readonly Container content; + private readonly Container cardContent; + private readonly Container shadow; + private readonly SelectionOutline selectionOutline; + private readonly SongPreviewContainer songPreviewContainer; + + public bool ShowSelectionOutline + { + set => selectionOutline.FadeTo(value ? 1 : 0, 50); + } + + public float Elevation; + + public bool PreviewTrackLoaded => songPreviewContainer.TrackLoaded; + public bool PreviewTrackRunning => songPreviewContainer.IsRunning; + + private Sample? cardFlipSample; + + [Resolved] + private BeatmapLookupCache beatmapLookupCache { get; set; } = null!; + + public RankedPlayCard(RankedPlayCardWithPlaylistItem item) + { + Item = item; + + Size = SIZE; + + playlistItem = item.PlaylistItem.GetBoundCopy(); + + InternalChild = songPreviewContainer = new SongPreviewContainer + { + Enabled = { BindTarget = SongPreviewEnabled }, + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = + [ + shadow = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = CORNER_RADIUS, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 5, + Colour = Color4.Black.Opacity(0.1f), + }, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + } + }, + content = new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = + [ + cardContent = new Container + { + RelativeSizeAxes = Axes.Both, + Child = new RankedPlayCardBackSide() + }, + selectionOutline = new SelectionOutline + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + } + ] + } + ] + }; + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + cardFlipSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/card-flip-1"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + playlistItem.BindValueChanged(e => onPlaylistItemChanged(e.NewValue)); + if (playlistItem.Value != null) + loadCardContent(playlistItem.Value, false); + } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + shadow.Scale = content.Scale; + shadow.Size = new Vector2(1 - Elevation * 0.25f); + shadow.Position = new Vector2(-25, 20) * Elevation; + } + + #region beatmap fetching logic & card flip + + private readonly TaskCompletionSource cardRevealed = new TaskCompletionSource(); + + public Task CardRevealed => cardRevealed.Task; + + private void onPlaylistItemChanged(MultiplayerPlaylistItem? playlistItem) + { + if (playlistItem == null) + { + SetContent(new RankedPlayCardBackSide(), true); + return; + } + + loadCardContent(playlistItem, true); + } + + private void loadCardContent(MultiplayerPlaylistItem playlistItem, bool flip) => Task.Run(async () => + { + var beatmap = await beatmapLookupCache.GetBeatmapAsync(playlistItem.BeatmapID).ConfigureAwait(false); + + cardRevealed.TrySetResult(); + + if (beatmap == null) + { + Logger.Log($"Failed to load beatmap {playlistItem.BeatmapID} for playlistItem {playlistItem.ID}.", level: LogLevel.Error); + return; + } + + Schedule(() => + { + SetContent(new RankedPlayCardContent(beatmap), flip); + songPreviewContainer.LoadPreview(beatmap); + }); + }); + + public void SetContent(Drawable newContent, bool flip) + { + if (!flip) + { + cardContent.Child = newContent; + return; + } + + content.ScaleTo(new Vector2(0, 1), 100, Easing.In) + .Then() + .Schedule(() => cardContent.Child = newContent) + .ScaleTo(new Vector2(1), 300, Easing.OutElasticQuarter); + + SamplePlaybackHelper.PlayWithRandomPitch(cardFlipSample); + } + + #endregion + + public void PopOutAndExpire() + { + content.ScaleTo(0, 500, Easing.In); + + this.FadeOut(500) + .Expire(); + } + + private partial class SelectionOutline : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load() + { + const float border_width = 4; + + InternalChild = new Container + { + RelativeSizeAxes = Axes.Both, + // anti-aliasing would create a gap between the border & card here if we used border_width directly + Padding = new MarginPadding(-(border_width - 1)), + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = CORNER_RADIUS + border_width, + BorderThickness = border_width, + BorderColour = Color4Extensions.FromHex("72D5FF"), + Blending = BlendingParameters.Additive, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Radius = 30, + Colour = Color4Extensions.FromHex("72D5FF").Opacity(0.2f), + Hollow = true, + Roundness = 10 + }, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + } + } + }; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardBackSide.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardBackSide.cs new file mode 100644 index 000000000000..be8ab9ab526b --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardBackSide.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Overlays; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card +{ + public partial class RankedPlayCardBackSide : CompositeDrawable + { + public RankedPlayCardBackSide() + { + Size = RankedPlayCard.SIZE; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Masking = true; + CornerRadius = RankedPlayCard.CORNER_RADIUS; + + InternalChild = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background1, + }; + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.AttributeListing.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.AttributeListing.cs new file mode 100644 index 000000000000..70f8d312fd8e --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.AttributeListing.cs @@ -0,0 +1,173 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Extensions; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Difficulty; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card +{ + public partial class RankedPlayCardContent + { + private partial class AttributeListing(APIBeatmap beatmap) : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load(RulesetStore rulesets) + { + var rulesetInfo = rulesets.GetRuleset(beatmap.RulesetID); + Debug.Assert(rulesetInfo != null); + var ruleset = rulesetInfo.CreateInstance(); + + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + Padding = new MarginPadding(7), + Children = + [ + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = + [ + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Spacing = new Vector2(4), + Children = + [ + new OsuSpriteText + { + Text = "Length", + Font = OsuFont.GetFont(size: 9, weight: FontWeight.Medium), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + UseFullGlyphHeight = false, + }, + new OsuSpriteText + { + Text = beatmap.HitLength.ToFormattedDuration(), + Font = OsuFont.GetFont(size: 9, weight: FontWeight.SemiBold), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + UseFullGlyphHeight = false, + }, + ] + }, + + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Spacing = new Vector2(4), + Children = + [ + new OsuSpriteText + { + Text = "BPM", + Font = OsuFont.GetFont(size: 9, weight: FontWeight.Medium), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + UseFullGlyphHeight = false, + }, + new OsuSpriteText + { + Text = ((int)beatmap.BPM).ToString(), + Font = OsuFont.GetFont(size: 9, weight: FontWeight.SemiBold), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + UseFullGlyphHeight = false, + }, + ] + }, + ] + }, + ..ruleset.GetBeatmapAttributesForDisplay(beatmap, []) + .Select(attribute => new AttributeRow(attribute)) + ] + }; + } + } + + private partial class AttributeRow(RulesetBeatmapAttribute attribute) : CompositeDrawable + { + private float normalizedValue => float.Clamp(attribute.AdjustedValue / attribute.MaxValue, 0, 1); + + [BackgroundDependencyLoader] + private void load(CardColours colours) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + InternalChildren = + [ + new OsuSpriteText + { + Text = attribute.Label, + Font = OsuFont.GetFont(size: 9, weight: FontWeight.Medium), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + UseFullGlyphHeight = false, + }, + new OsuSpriteText + { + RelativePositionAxes = Axes.X, + Text = attribute.AdjustedValue.ToStandardFormattedString(maxDecimalDigits: 1), + Font = OsuFont.GetFont(size: 9, weight: FontWeight.SemiBold), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreRight, + UseFullGlyphHeight = false, + X = 0.65f, + Padding = new MarginPadding { Right = 2 }, + Colour = colours.OnBackground, + }, + new CircularContainer + { + RelativeSizeAxes = Axes.X, + Width = 0.35f, + Height = 2, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Masking = true, + Children = + [ + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.BackgroundLightest, + }, + new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Width = normalizedValue, + Masking = true, + Children = + [ + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.PrimaryWithContrastToBackground, + }, + ] + } + ] + } + ]; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.Colours.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.Colours.cs new file mode 100644 index 000000000000..f25e5a00b6ff --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.Colours.cs @@ -0,0 +1,77 @@ +// 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 osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Online.API.Requests.Responses; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card +{ + public partial class RankedPlayCardContent + { + public class CardColours(APIBeatmap beatmap, OsuColour colour) + { + private static readonly Color4 base_background = Color4Extensions.FromHex("#222228"); + + public readonly Color4 Primary = colour.ForStarDifficulty(beatmap.StarRating); + + public Color4 OnPrimary => + beatmap.StarRating >= OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF + ? colour.Orange1 + : getColour(1f, 0.15f); + + public Colour4 Background => mix(base_background, getColour(0.05f, 0.15f), 0.5f); + + public Colour4 BackgroundLighter => mix(base_background, getColour(0.1f, 0.2f), 0.5f); + + public Colour4 BackgroundLightest => mix(base_background, getColour(0.2f, 0.23f), 0.5f); + + public Color4 OnBackground => getColour(1f, 0.9f, isAccent: true); + + public Color4 Border => beatmap.StarRating > 8.0 ? Color4Extensions.FromHex("34044f") : Primary; + + public Colour4 PrimaryWithContrastToBackground => + beatmap.StarRating >= OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF ? OnPrimary : Primary; + + private Color4 getColour(float saturation, float lightness, bool isAccent = false) + { + float hue = Primary.ToHSV().h / 360f; + + // at higher star ratings primary colour can become pure black. in that case we want to just use a very desaturated purple as base + if (beatmap.StarRating >= OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF) + { + hue = isAccent ? 0.15f : 0.77f; + saturation *= 0.5f; + } + + // colours should generally shift slightly towards blue as they get darker + float shadowHue = 0.66f; + float colourShift = (1 - lightness) * 0.5f; + + // except yellow. yellow just *has* to look bad when you do that with it. it gets to fade to red + if (Math.Abs(hue - 0.16f) < 0.1f) + { + shadowHue = 0; + colourShift = float.Pow(colourShift, 0.25f); + } + + return mix( + Color4.FromHsl(new Vector4(hue, saturation, lightness, 1)), + Color4.FromHsl(new Vector4(shadowHue, saturation, lightness, 1)), + colourShift + ); + } + } + + private static Color4 mix(Color4 lhs, Color4 rhs, float alpha) => new Color4( + r: float.Lerp(lhs.R, rhs.R, alpha), + g: float.Lerp(lhs.G, rhs.G, alpha), + b: float.Lerp(lhs.B, rhs.B, alpha), + a: float.Lerp(lhs.A, rhs.A, alpha) + ); + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.Cover.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.Cover.cs new file mode 100644 index 000000000000..c3e0d364122f --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.Cover.cs @@ -0,0 +1,55 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Online.API.Requests.Responses; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card +{ + public partial class RankedPlayCardContent + { + private partial class CardCover(APIBeatmap beatmap) : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load(CardColours colours) + { + BufferedContainer coverContainer; + + InternalChildren = + [ + coverContainer = new BufferedContainer + { + RelativeSizeAxes = Axes.Both, + GrayscaleStrength = 0.25f, + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(colours.Background.Opacity(0.2f), colours.Background.Opacity(0.65f)) + } + ]; + + var cover = new OnlineBeatmapSetCover(beatmap.BeatmapSet) + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + FillMode = FillMode.Fill, + EdgeSmoothness = new Vector2(2), + }; + + LoadComponentAsync(cover, _ => + { + coverContainer.Add(cover); + cover.FadeInFromZero(200); + }); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.Metadata.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.Metadata.cs new file mode 100644 index 000000000000..2b935acca6a2 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.Metadata.cs @@ -0,0 +1,203 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card +{ + public partial class RankedPlayCardContent + { + private partial class CardMetadata(APIBeatmap beatmap) : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load(CardColours colours) + { + InternalChildren = + [ + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = + [ + new StarRatingBadge(beatmap) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Margin = new MarginPadding { Top = 4 }, + }, + ] + }, + new LinkFlowContainer(static s => s.ShadowOffset = new Vector2(0, 0.15f)) + { + Name = "Beatmap Metadata", + RelativeSizeAxes = Axes.Both, + TextAnchor = Anchor.BottomLeft, + Padding = new MarginPadding(5) { Bottom = 10 }, + ParagraphSpacing = 0.2f, + }.With(d => + { + d.AddText(new RomanisableString(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title), static s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold)); + + d.NewLine(); + d.AddText(new RomanisableString(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist), static s => s.Font = OsuFont.GetFont(size: 9, weight: FontWeight.SemiBold)); + + d.NewParagraph(); + d.AddText("mapped by ", static s => s.Font = OsuFont.GetFont(size: 9, weight: FontWeight.SemiBold)); + d.AddText(beatmap.Metadata.Author.Username, s => + { + s.Font = OsuFont.GetFont(size: 9, weight: FontWeight.SemiBold); + s.Colour = colours.OnBackground; + }); + }), + ]; + } + } + + private partial class StarRatingBadge(APIBeatmap beatmap) : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load(CardColours colours) + { + AutoSizeAxes = Axes.Y; + Width = RankedPlayCard.SIZE.X - 20; + + Masking = true; + CornerRadius = 3; + + InternalChildren = + [ + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Primary, + }, + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = 3, Vertical = 1 }, + ColumnDimensions = + [ + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + ], + RowDimensions = [new Dimension(GridSizeMode.AutoSize)], + Content = new Drawable[][] + { + [ + new StarsDisplay(beatmap.StarRating) + { + StarSize = 6, + Colour = colours.OnPrimary, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + new TruncatingSpriteText + { + Text = FormattableString.Invariant($"{beatmap.StarRating:F2}"), + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Font = OsuFont.GetFont(size: 9, weight: FontWeight.Bold), + Colour = colours.OnPrimary, + }, + ] + } + } + ]; + } + } + + private partial class StarsDisplay(double starRating) : CompositeDrawable + { + public required float StarSize { get; init; } + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + FillFlowContainer flow; + + InternalChild = flow = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(1), + }; + + int numStars = (int)starRating - 1; + + for (int i = 0; i <= numStars; i++) + { + flow.Add(new SpriteIcon + { + Size = new Vector2(StarSize), + Icon = FontAwesome.Solid.Star, + }); + } + + float lastStarWidth = (int)((starRating % 1) * 4) / 4f; + + if (lastStarWidth > 0) + { + flow.Add(new Container + { + Size = new Vector2(StarSize * lastStarWidth, StarSize), + Masking = true, + Child = new SpriteIcon + { + Icon = FontAwesome.Solid.Star, + Size = new Vector2(StarSize), + } + }); + } + } + } + + private partial class DifficultyNameBadge(APIBeatmap beatmap) : CompositeDrawable + { + public new Axes AutoSizeAxes + { + get => base.AutoSizeAxes; + set => base.AutoSizeAxes = value; + } + + [BackgroundDependencyLoader] + private void load(CardColours colours) + { + Masking = true; + CornerRadius = 3; + InternalChildren = + [ + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.BackgroundLighter, + }, + new TruncatingSpriteText + { + MaxWidth = 100f, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = beatmap.DifficultyName, + Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), + Colour = colours.OnBackground, + Padding = new MarginPadding { Vertical = 1 }, + } + ]; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.cs new file mode 100644 index 000000000000..e75af5029cdd --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardContent.cs @@ -0,0 +1,147 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card +{ + public partial class RankedPlayCardContent : CompositeDrawable, IHasContextMenu + { + public readonly APIBeatmap Beatmap; + + private CardColours colours = null!; + + [Resolved] + private CardDetailsOverlayContainer? cardDetailsOverlay { get; set; } + + public RankedPlayCardContent(APIBeatmap beatmap) + { + Size = RankedPlayCard.SIZE; + + Beatmap = beatmap; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = + [ + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = RankedPlayCard.CORNER_RADIUS, + Children = + [ + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Background, + }, + new Container + { + Name = "Top Area", + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + Children = + [ + new CardCover(Beatmap) + { + RelativeSizeAxes = Axes.Both, + }, + new CardMetadata(Beatmap) + { + RelativeSizeAxes = Axes.Both, + }, + new DifficultyNameBadge(Beatmap) + { + Width = 100, + AutoSizeAxes = Axes.Y, + + // this container partially overlaps with the bottom area + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + } + ], + }, + new Container + { + Name = "Bottom Area", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = RankedPlayCard.SIZE.X + 6 }, + Children = + [ + new AttributeListing(Beatmap) + { + RelativeSizeAxes = Axes.Both, + } + ] + }, + ] + }, + new CardBorder() + ]; + } + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + + dependencies.CacheAs(colours = new CardColours(Beatmap, dependencies.Get())); + + return dependencies; + } + + public override bool HandlePositionalInput => true; + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + if (IsHovered) + cardDetailsOverlay?.ShowCardDetails(this, Beatmap); + } + + private partial class CardBorder : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load(CardColours colours) + { + RelativeSizeAxes = Axes.Both; + Masking = true; + CornerRadius = RankedPlayCard.CORNER_RADIUS; + BorderThickness = 1.5f; + BorderColour = ColourInfo.GradientVertical(colours.Border.Opacity(0.5f), colours.Border.Opacity(0)); + + InternalChild = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + EdgeSmoothness = new Vector2(3), + }; + } + } + + [Resolved] + private BeatmapSetOverlay? beatmapSetOverlay { get; set; } + + public MenuItem[] ContextMenuItems => + [ + new OsuMenuItem(ContextMenuStrings.ViewBeatmap, MenuItemType.Highlighted, () => beatmapSetOverlay?.ShowBeatmapSet(Beatmap.BeatmapSet)) + ]; + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardExtensions.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardExtensions.cs new file mode 100644 index 000000000000..bb7526f8b8b5 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCardExtensions.cs @@ -0,0 +1,43 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card +{ + public static class RankedPlayCardExtensions + { + /// + /// Adjusts the transforms of a drawable relative to a parent drawable to match the given drawQuad. + /// + /// the target drawable. + /// screen space drawQuad to fit the drawable to. + /// drawable to calculate the transforms in relation to. + public static T MatchScreenSpaceDrawQuad(this T target, Quad drawQuad, CompositeDrawable parent) where T : Drawable + { + drawQuad = parent.ToLocalSpace(drawQuad); + + var originPosition = target.RelativeOriginPosition; + + // child may not have been made alive yet by the parent so anchor is calculated manually + var anchorPosition = parent.ChildSize * target.RelativeAnchorPosition; + + var positionWithOrigin = Vector2.Lerp( + Vector2.Lerp(drawQuad.TopLeft, drawQuad.TopRight, originPosition.X), + Vector2.Lerp(drawQuad.BottomLeft, drawQuad.BottomRight, originPosition.X), + originPosition.Y + ); + + target.Position = positionWithOrigin - anchorPosition; + + target.Rotation = MathHelper.RadiansToDegrees(new Line(drawQuad.TopLeft, drawQuad.TopRight).Theta); + + target.Scale = new Vector2(Vector2.Distance(drawQuad.TopLeft, drawQuad.TopRight) / target.DrawWidth); + + return target; + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/SongPreviewParticleContainer.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/SongPreviewParticleContainer.cs new file mode 100644 index 000000000000..89319d9fd008 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/SongPreviewParticleContainer.cs @@ -0,0 +1,129 @@ +// 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.Diagnostics; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Utils; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card +{ + public partial class SongPreviewParticleContainer : CompositeDrawable + { + public SongPreviewParticleContainer() + { + RelativeSizeAxes = Axes.Both; + } + + private Vector2 lastPosition; + + private Texture[] particleTextures = null!; + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + const int texture_count = 3; + + particleTextures = new Texture[texture_count]; + + for (int i = 0; i < texture_count; i++) + { + particleTextures[i] = textures.Get($"Online/RankedPlay/note-particle-{i}"); + Debug.Assert(particleTextures[i] != null); + } + } + + public void AddParticles(Drawable source, Color4 seedColour) + { + var drawQuad = ToLocalSpace(source.ScreenSpaceDrawQuad); + + var position = sampleRandomPosition(drawQuad); + + for (int i = 0; i < 10; i++) + { + if (Vector2.Distance(position, lastPosition) > 100) + break; + + position = sampleRandomPosition(drawQuad); + } + + lastPosition = position; + + var texture = particleTextures[RNG.Next(particleTextures.Length)]; + + var particle = new Particle(texture) + { + Position = position, + Rotation = RNG.NextSingle(-3, 3), + Colour = seedColour, + Blending = BlendingParameters.Additive, + }; + + AddInternal(particle); + + particle.ScaleTo(0) + .ScaleTo(RNG.NextSingle(0.75f, 1f), 1000, Easing.OutElasticHalf) + .Then() + .FadeOut(1800, Easing.OutCubic) + .Expire(); + } + + private static Vector2 sampleRandomPosition(Quad quad) + { + static float remap(float value, float fromLower, float fromHigher, float toLower, float toHigher) => + (value - fromLower) / (fromHigher - fromLower) * (toHigher - toLower) + toLower; + + static float randomValue() + { + float x = RNG.NextSingle(); + // using quadratic rational smoothstep to increase the likelihood that particles spawn at the edge of the card + float smoothStep = x * x / (2f * x * x - 2f * x + 1f); + + if (smoothStep < 0.5f) + return remap(smoothStep, 0, 0.5f, -0.05f, 0.15f); + else + return remap(smoothStep, 0.5f, 1f, 0.85f, 1.05f); + } + + var top = Vector2.Lerp(quad.TopLeft, quad.TopRight, randomValue()); + var bottom = Vector2.Lerp(quad.BottomLeft, quad.BottomRight, randomValue()); + + return Vector2.Lerp(top, bottom, randomValue()); + } + + private partial class Particle : Sprite + { + public Particle(Texture texture) + { + Size = new Vector2(40); + Texture = texture; + Origin = Anchor.Centre; + } + + private float initialX; + private readonly float seed = RNG.NextSingle() * MathF.PI * 2; + + protected override void LoadComplete() + { + base.LoadComplete(); + + initialX = X; + } + + protected override void Update() + { + base.Update(); + + X = initialX + (float)Math.Cos(Time.Current * 0.002 + seed) * 5; + Y -= (float)(Time.Elapsed * 0.04f); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/CardFlow.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/CardFlow.cs new file mode 100644 index 000000000000..af9985ac27b6 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/CardFlow.cs @@ -0,0 +1,79 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components +{ + /// + /// Container that arranges a collection of s horizontally. + /// Layout is not automatic and has to be triggered by calling + /// + /// + /// Drawables are expected to be added to this container with an Anchor/Origin of . + /// + public partial class CardFlow : Container + { + public float Spacing = 20; + + /// + /// Moves all cards into a horizontal arrangement centered within the container's bounds. + /// + /// delay to be added to the movement of each subsequent card + /// duration of the movement + /// easing of the movement + public void LayoutCards(double stagger = 0, double duration = 400, Easing easing = Easing.OutExpo) + { + // makes sure that all facades had a chance to initialize their transforms based on the provided drawQuad + CheckChildrenLife(); + + float totalWidth = Children.Sum(c => c.LayoutSize.X + Spacing) - Spacing; + + float x = -totalWidth / 2; + + double delay = 0; + + foreach (var card in Children) + { + card.Delay(delay) + .MoveTo(new Vector2(x + card.LayoutSize.X * 0.5f, 0), duration, easing) + .RotateTo(0, duration, easing) + .ScaleTo(1, duration, easing); + + x += card.LayoutSize.X + Spacing; + + delay += stagger; + } + } + + /// + /// + /// + /// + /// + /// + /// + public bool RemoveCard(RankedPlayCardWithPlaylistItem item, [MaybeNullWhen(false)] out RankedPlayCard card, out Quad screenSpaceDrawQuad) + { + card = Children.FirstOrDefault(it => it.Item.Equals(item)); + + if (card == null) + { + screenSpaceDrawQuad = default; + return false; + } + + screenSpaceDrawQuad = card.ScreenSpaceDrawQuad; + + Remove(card, false); + + return true; + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayCornerPiece.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayCornerPiece.cs new file mode 100644 index 000000000000..c2a4825de491 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayCornerPiece.cs @@ -0,0 +1,160 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Transforms; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components +{ + [Cached] + public partial class RankedPlayCornerPiece : VisibilityContainer + { + private readonly BufferedContainer background; + private readonly Container bottomLayer; + private readonly Container topLayer; + + protected override Container Content { get; } + + public RankedPlayCornerPiece(RankedPlayColourScheme colourScheme, Anchor anchor) + { + Size = new Vector2(345, 100); + + Anchor = Origin = anchor; + + InternalChildren = + [ + background = new BufferedContainer + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2( + (anchor & Anchor.x0) != 0 ? 1 : -1, + (anchor & Anchor.y0) != 0 ? -1 : 1 + ), + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Rotation = -2, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Shear = new Vector2(-0.5f, 0), + Padding = new MarginPadding + { + Left = -60, + Bottom = -30, + Top = 20, + Right = 15, + }, + Children = + [ + bottomLayer = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 20, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourScheme.PrimaryDarkest, + Alpha = 0.2f, + // This is a hack to work around alpha-blending issues when drawing on top of a transparent background without premultiplied alpha + // This method requires that this Drawable is not drawn on top of anything else + Blending = BlendingParameters.Mixture with + { + Destination = BlendingType.Zero, + DestinationAlpha = BlendingType.Zero, + Source = BlendingType.One, + SourceAlpha = BlendingType.One, + } + }, + }, + topLayer = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(10), + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 15, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal(colourScheme.Primary, colourScheme.PrimaryDarker.Opacity(0.35f)), + Alpha = 0.75f + }, + }, + } + ] + }, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = anchor, + Origin = anchor, + Margin = new MarginPadding(18), + Child = Content = new Container + { + Anchor = (anchor & Anchor.x0) != 0 ? Anchor.CentreLeft : Anchor.CentreRight, + Origin = (anchor & Anchor.x0) != 0 ? Anchor.CentreLeft : Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + } + } + ]; + } + + public void OnHealthChanged(int health) + { + background.GrayscaleTo(health <= 0f ? 0.75f : 0, 300); + } + + protected override void Update() + { + base.Update(); + + Width = WidthFor(Parent!.ChildSize.X); + } + + public static float WidthFor(float parentWidth) => float.Clamp(parentWidth * 0.25f, 250, 335); + + protected override void PopIn() + { + this.FadeIn(300); + + Content.Delay(150) + .MoveToX(0, 400, Easing.OutExpo) + .ScaleTo(1f, 400, Easing.OutExpo) + .FadeIn(); + + background.MoveToY(0, 400, Easing.OutExpo); + + bottomLayer.RotateTo(0, 400, Easing.OutQuart); + topLayer.RotateTo(0, 400, Easing.OutQuart); + } + + protected override void PopOut() + { + this.FadeOut(300); + + background.MoveToY((Anchor & Anchor.y0) != 0 ? -60 : 60, 500, new CubicBezierEasingFunction(easeIn: 0.2, easeOut: 0.75)); + Content.MoveToX((Anchor & Anchor.x0) != 0 ? -200 : 200, 500, new CubicBezierEasingFunction(easeIn: 0.2, easeOut: 0.5)) + .ScaleTo(0.5f, 400, Easing.OutCubic) + .FadeOut(200); + + bottomLayer.RotateTo(-25, 500, new CubicBezierEasingFunction(easeIn: 0.2, easeOut: 0.75)); + topLayer.RotateTo(25, 500, new CubicBezierEasingFunction(easeIn: 0.2, easeOut: 0.75)); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayScoreCounter.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayScoreCounter.cs new file mode 100644 index 000000000000..d84df287afc6 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayScoreCounter.cs @@ -0,0 +1,234 @@ +// 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.Diagnostics; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transforms; +using osu.Game.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components +{ + public partial class RankedPlayScoreCounter : CompositeDrawable + { + private readonly FillFlowContainer digitFlow; + private readonly CounterDigit[] digits; + + public required FontUsage Font { get; init; } + + private long value; + + public long Value + { + get => value; + set + { + this.value = value; + if (!IsLoaded) + return; + + updateDigits(); + } + } + + public TransformSequence TransformValueTo(long value, double duration = 0, Easing easing = Easing.None) => this.TransformTo(nameof(Value), value, duration, easing); + + public RankedPlayScoreCounter(int numDigits = 6) + { + digits = new CounterDigit[numDigits]; + + AutoSizeAxes = Axes.Both; + + InternalChildren = + [ + digitFlow = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + } + ]; + } + + public Vector2 Spacing + { + get => digitFlow.Spacing; + set => digitFlow.Spacing = value; + } + + [BackgroundDependencyLoader] + private void load() + { + string templateString = Math.Pow(10, digits.Length - 1).ToString("N0"); + + for (int i = 0, digitIndex = 0; i < templateString.Length; i++) + { + if (char.IsDigit(templateString[i])) + { + digitFlow.Add(digits[digitIndex++] = new CounterDigit + { + Font = Font.With(fixedWidth: true), + }); + } + else + { + digitFlow.Add(new OsuSpriteText + { + Text = templateString[i].ToString(), + Font = Font, + Shadow = false, + }); + } + } + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + updateDigits(false); + } + + public void SetValueInstantly(long value) + { + ClearTransforms(true); + this.value = value; + updateDigits(false); + } + + private void updateDigits(bool animated = true) + { + long current = value; + + for (int i = digits.Length - 1; i >= 0; i--) + { + digits[i].Offset = current; + + if (!animated) + digits[i].CompleteAnimations(); + + current /= 10; + } + } + + private partial class CounterDigit : CompositeDrawable + { + private readonly DoubleSpring spring = new DoubleSpring + { + NaturalFrequency = 2.5f, + Damping = 0.8f, + Response = 1f + }; + + public double Offset { get; set; } + + private OsuSpriteText upperDigit = null!; + private OsuSpriteText lowerDigit = null!; + + private BufferedContainer blurContainer = null!; + + public required FontUsage Font { get; init; } + + [BackgroundDependencyLoader] + private void load() + { + Debug.Assert(Font.FixedWidth); + + InternalChild = blurContainer = new BufferedContainer + { + RelativeSizeAxes = Axes.Both, + Height = 3f, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + BackgroundColour = Colour4.White.Opacity(0), + Children = + [ + new Container + { + RelativeSizeAxes = Axes.Both, + Height = 1f / 3f, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = + [ + upperDigit = new OsuSpriteText + { + Text = "9", + Font = Font, + RelativePositionAxes = Axes.Y, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Shadow = false, + }, + lowerDigit = new OsuSpriteText + { + Text = "0", + Font = Font, + RelativePositionAxes = Axes.Y, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Shadow = false, + } + ] + } + ] + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Size = lowerDigit.DrawSize; + } + + protected override void Update() + { + base.Update(); + + spring.Damping = spring.Velocity > 30 ? 1f : 0.8f; + + spring.Update(Time.Elapsed, Offset); + + updateState(); + } + + private void updateState() + { + int digit = (int)spring.Current % 10; + if (digit < 0) digit += 10; + + lowerDigit.Text = digit.ToString(); + upperDigit.Text = ((digit + 1) % 10).ToString(); + + float y = (float)(spring.Current % 1); + + if (y < 0) + y = 0; + + upperDigit.Y = (y - 1) * 0.65f; + lowerDigit.Y = y * 0.65f; + + lowerDigit.Alpha = MathF.Pow(1 - y, 2); + upperDigit.Alpha = MathF.Pow(y, 2); + + upperDigit.Scale = new Vector2(float.Lerp(0.5f, 1f, MathF.Sqrt(0.5f + y * 0.5f))); + lowerDigit.Scale = new Vector2(float.Lerp(0.5f, 1f, MathF.Sqrt(1 - y * 0.5f))); + + blurContainer.BlurSigma = new Vector2(0, float.Clamp((float)Math.Abs(spring.Velocity * 0.1f) - 5, 0, 10)); + } + + public void CompleteAnimations() + { + spring.Current = Offset; + spring.PreviousTarget = Offset; + spring.Velocity = 0; + + updateState(); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayStageDisplay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayStageDisplay.cs new file mode 100644 index 000000000000..d0fb4f9332a2 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayStageDisplay.cs @@ -0,0 +1,240 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.RankedPlay; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components +{ + public partial class RankedPlayStageDisplay : CompositeDrawable + { + public required LocalisableString Heading { get; init; } + + public required LocalisableString Caption { get; init; } + + public Color4? CaptionColour { get; init; } + + [Resolved] + private MultiplayerClient client { get; set; } = null!; + + private readonly RankedPlayColourScheme colourScheme; + + private Drawable headingTextBackground = null!; + private OsuSpriteText headingText = null!; + private Drawable progressBar = null!; + private OsuSpriteText progressText = null!; + + private DateTimeOffset countdownStartTime; + private DateTimeOffset countdownEndTime; + + public RankedPlayStageDisplay(RankedPlayColourScheme colourScheme) + { + this.colourScheme = colourScheme; + + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + const float phase_text_background_height = 55; + Vector2 progressBarSize = new Vector2(300, 25); + MarginPadding progressBarMargin = new MarginPadding + { + Left = 40, + Top = phase_text_background_height - progressBarSize.Y / 2 + }; + + InternalChildren = new Drawable[] + { + new BufferedContainer + { + AutoSizeAxes = Axes.Both, + BackgroundColour = colourScheme.Surface.Opacity(0), + Alpha = 0.7f, + Children = new[] + { + headingTextBackground = new Container + { + Height = phase_text_background_height, + Shear = OsuGame.SHEAR, + Masking = true, + CornerRadius = 3, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourScheme.Surface.Darken(0.1f), + Alpha = 0.8f + } + }, + new Container + { + Size = progressBarSize, + Margin = progressBarMargin, + Shear = OsuGame.SHEAR, + Masking = true, + CornerRadius = 3, + BorderThickness = 1f, + BorderColour = ColourInfo.GradientVertical(colourScheme.Surface, colourScheme.SurfaceBorder), + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourScheme.Surface, + } + }, + } + }, + headingText = new OsuSpriteText + { + Margin = new MarginPadding + { + Top = 5, + Left = 20, + }, + Text = Heading, + Font = OsuFont.TorusAlternate.With(size: 34), + Shadow = false, + }, + new Container + { + Size = progressBarSize, + Shear = OsuGame.SHEAR, + Padding = new MarginPadding { Horizontal = 2.2f, Vertical = 2 }, + Margin = progressBarMargin, + Children = + [ + progressBar = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 2, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Children = + [ + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.8f, + Colour = ColourInfo.GradientHorizontal(colourScheme.PrimaryDarker, colourScheme.Primary) + }, + new TrianglesV2 + { + Width = progressBarSize.X, + RelativeSizeAxes = Axes.Y, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + SpawnRatio = 0.5f, + ScaleAdjust = 0.75f, + Alpha = 0.1f, + Blending = BlendingParameters.Additive, + Colour = ColourInfo.GradientHorizontal(Color4.Transparent, Color4.White) + }, + ], + }, + progressText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Shear = -OsuGame.SHEAR, + Margin = new MarginPadding + { + Left = 10 + }, + UseFullGlyphHeight = false, + Text = "00:27:123", + Font = OsuFont.TorusAlternate.With(size: 16, fixedWidth: true, weight: FontWeight.SemiBold) + } + ] + }, + new OsuSpriteText + { + Margin = new MarginPadding + { + Top = 80, + Left = 20 + }, + Colour = CaptionColour ?? colourScheme.Primary, + Text = Caption, + Font = OsuFont.TorusAlternate.With(size: 24, weight: FontWeight.SemiBold) + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + client.CountdownStarted += onCountdownStarted; + client.CountdownStopped += onCountdownStopped; + + if (client.Room != null) + { + foreach (var countdown in client.Room.ActiveCountdowns) + onCountdownStarted(countdown); + } + } + + protected override void Update() + { + base.Update(); + + headingTextBackground.Width = headingText.DrawWidth + 80; + + TimeSpan duration = countdownEndTime - countdownStartTime; + TimeSpan remaining = countdownEndTime - DateTimeOffset.Now; + + if (duration > TimeSpan.Zero) + progressBar.Width = (float)Math.Clamp(remaining / duration, 0, 1); + + int minutes = (int)Math.Max(0, remaining.TotalMinutes); + int seconds = Math.Max(0, remaining.Seconds); + int ms = Math.Max(0, remaining.Milliseconds); + + progressText.Text = $"{minutes:00}:{seconds:00}.{ms:000}"; + } + + private void onCountdownStarted(MultiplayerCountdown countdown) => Scheduler.Add(() => + { + if (countdown is not RankedPlayStageCountdown) + return; + + countdownStartTime = DateTimeOffset.Now; + countdownEndTime = DateTimeOffset.Now + countdown.TimeRemaining; + }); + + private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add(() => + { + if (countdown is not RankedPlayStageCountdown) + return; + + countdownEndTime = DateTimeOffset.Now; + }); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (client.IsNotNull()) + { + client.CountdownStarted -= onCountdownStarted; + client.CountdownStopped -= onCountdownStopped; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayUserDisplay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayUserDisplay.cs new file mode 100644 index 000000000000..0195c47945f4 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayUserDisplay.cs @@ -0,0 +1,398 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Utils; +using osu.Game.Database; +using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Users.Drawables; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components +{ + public partial class RankedPlayUserDisplay : CompositeDrawable + { + public readonly BindableInt Health = new BindableInt + { + MaxValue = 1_000_000, + MinValue = 0, + Value = 1_000_000, + }; + + [Resolved] + private UserLookupCache users { get; set; } = null!; + + private readonly int userId; + private readonly Anchor contentAnchor; + private readonly RankedPlayColourScheme colourScheme; + + private BufferedContainer grayScaleContainer = null!; + + [Resolved] + private RankedPlayCornerPiece? cornerPiece { get; set; } + + public RankedPlayUserDisplay(int userId, Anchor contentAnchor, RankedPlayColourScheme colourScheme) + { + this.userId = userId; + this.contentAnchor = contentAnchor; + this.colourScheme = colourScheme; + } + + [BackgroundDependencyLoader] + private void load() + { + APIUser user = users.GetUserAsync(userId).GetResultSafely()!; + + var shear = contentAnchor == Anchor.TopLeft || contentAnchor == Anchor.BottomRight + ? -OsuGame.SHEAR + : OsuGame.SHEAR; + + InternalChildren = + [ + new CircularContainer + { + Name = "Avatar", + Size = new Vector2(72), + Masking = true, + Anchor = contentAnchor, + Origin = contentAnchor, + Children = + [ + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourScheme.Surface, + Alpha = 0.5f, + }, + grayScaleContainer = new BufferedContainer(cachedFrameBuffer: false, pixelSnapping: true) + { + RelativeSizeAxes = Axes.Both, + Child = new UpdateableAvatar(user) + { + RelativeSizeAxes = Axes.Both, + } + } + ] + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Padding = (contentAnchor & Anchor.x0) != 0 ? new MarginPadding { Left = 72 } : new MarginPadding { Right = 72 }, + Direction = FillDirection.Vertical, + Children = + [ + HealthDisplay = new HealthBar(colourScheme, (contentAnchor & Anchor.x0) != 0, shear) + { + Health = { BindTarget = Health }, + RelativeSizeAxes = Axes.X, + Height = 22, + Anchor = contentAnchor, + Origin = contentAnchor, + }, + new OsuSpriteText + { + Name = "Username", + Text = user.Username, + Anchor = contentAnchor, + Origin = contentAnchor, + Padding = new MarginPadding { Horizontal = 4, Vertical = 6 }, + Font = OsuFont.GetFont(size: 24, weight: FontWeight.SemiBold), + UseFullGlyphHeight = false, + }, + ] + } + ]; + } + + public HealthBar HealthDisplay { get; private set; } = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + Health.BindValueChanged(e => + { + grayScaleContainer.GrayscaleTo(e.NewValue <= 0 ? 1 : 0, 300); + cornerPiece?.OnHealthChanged(e.NewValue); + }); + } + + public partial class HealthBar : CompositeDrawable + { + private readonly bool leftToRight; + + public readonly BindableInt Health = new BindableInt + { + MaxValue = 1_000_000, + MinValue = 0, + Value = 1_000_000, + }; + + private readonly BindableInt healthTextValue = new BindableInt(); + + /// + /// relative health threshold below which the health bar starts flashing red + /// + public float HealthFlashThreshold { get; set; } = 0.3f; + + private readonly ColourInfo healthBarColour; + + private readonly Container healthBar; + private readonly Box healthBarBackground; + private readonly Container damageIndicator; + private readonly TrianglesV2 triangles; + private readonly SpriteIcon heartIcon; + private readonly OsuSpriteText healthText; + + /// + /// Impact position for damage animation + /// + public Vector2 ScreenSpaceImpactPosition + { + get + { + var rect = healthBar.ScreenSpaceDrawQuad.AABBFloat; + + return leftToRight ? new Vector2(rect.Right, rect.Centre.Y) : new Vector2(rect.Left, rect.Centre.Y); + } + } + + public HealthBar(RankedPlayColourScheme colourScheme, bool leftToRight, Vector2 shear) + { + this.leftToRight = leftToRight; + + Shear = shear; + + Anchor contentAnchor = leftToRight ? Anchor.CentreLeft : Anchor.CentreRight; + + BufferedContainer content; + + InternalChildren = + [ + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 3, + BorderThickness = 1f, + BorderColour = ColourInfo.GradientVertical(colourScheme.Surface, colourScheme.SurfaceBorder), + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourScheme.Surface, + Alpha = 0.8f, + } + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = 2.2f, Vertical = 2 }, // slightly different ratio to account for shear + Children = + [ + healthBar = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 2, + Anchor = contentAnchor, + Origin = contentAnchor, + Children = + [ + healthBarBackground = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.8f, + Colour = healthBarColour = leftToRight + ? ColourInfo.GradientHorizontal(colourScheme.PrimaryDarker, colourScheme.Primary) + : ColourInfo.GradientHorizontal(colourScheme.Primary, colourScheme.PrimaryDarker), + }, + triangles = new TrianglesV2 + { + RelativeSizeAxes = Axes.Y, + Anchor = contentAnchor, + Origin = contentAnchor, + SpawnRatio = 0.5f, + ScaleAdjust = 0.75f, + Alpha = 0.1f, + Blending = BlendingParameters.Additive, + Colour = leftToRight + ? ColourInfo.GradientHorizontal(Color4.Transparent, Color4.White) + : ColourInfo.GradientHorizontal(Color4.White, Color4.Transparent), + }, + ], + }, + ] + }, + content = new BufferedContainer(pixelSnapping: true) + { + RelativeSizeAxes = Axes.Both, + Shear = -shear, + BackgroundColour = Color4.White.Opacity(0), // workaround for non-premultiplied alpha blending of white content on transparent background + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Spacing = new Vector2(3), + Padding = new MarginPadding { Horizontal = 10 }, + Children = + [ + new Container + { + Size = new Vector2(10), + Anchor = contentAnchor, + Origin = contentAnchor, + Child = heartIcon = new SpriteIcon + { + Icon = FontAwesome.Solid.Heart, + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }, + healthText = new OsuSpriteText + { + Text = "1,000,000", + Anchor = contentAnchor, + Origin = contentAnchor, + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Medium, fixedWidth: true), + Spacing = new Vector2(-1, 0), + UseFullGlyphHeight = false, + Padding = new MarginPadding { Top = 1 }, + Shadow = false, + } + ] + } + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = 2.2f, Vertical = 2 }, // slightly different ratio to account for shear + Children = + [ + damageIndicator = new Container + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.X, + Anchor = contentAnchor, + Origin = contentAnchor, + Masking = true, + CornerRadius = 2, + Alpha = 0, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Radius = 25, + Colour = Color4Extensions.FromHex("FF171B").Opacity(0.5f), + Roundness = 10, + Hollow = true, + }, + Children = + [ + new Box + { + RelativeSizeAxes = Axes.Both, + }, + content.CreateView().With(d => + { + d.SynchronisedDrawQuad = true; + d.Colour = Color4.Red; + }) + ], + }, + ] + }, + ]; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Health.BindValueChanged(onHealthChanged, true); + + healthTextValue.BindValueChanged(e => healthText.Text = FormattableString.Invariant($"{e.NewValue:N0}"), true); + + FinishTransforms(true); + + Scheduler.AddDelayed(flashHealth, 1000, true); + } + +#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value + private float normalizedHealth; + private float normalizedHealthWithDamage; +#pragma warning restore CS0649 // Field is never assigned to, and will always have its default value + + private void onHealthChanged(ValueChangedEvent e) + { + this.TransformBindableTo(healthTextValue, e.NewValue, 500, Easing.OutExpo); + + bool isHealthDecrease = e.NewValue < e.OldValue; + + if (isHealthDecrease) + { + damageIndicator.FadeIn(50) + .Then(delay: 1100) + .FadeOut(200); + + healthBarBackground.FadeColour(Color4.Red, 100) + .Then() + .FadeColour(healthBarColour, 1000); + + this.TransformTo(nameof(normalizedHealthWithDamage), Health.NormalizedValue, 400, Easing.OutExpo) + .Then(500) + .TransformTo(nameof(normalizedHealth), Health.NormalizedValue, 800, Easing.OutExpo); + } + + else + { + this.TransformTo(nameof(normalizedHealthWithDamage), Health.NormalizedValue, 800, Easing.OutExpo) + .TransformTo(nameof(normalizedHealth), Health.NormalizedValue, 800, Easing.OutExpo); + } + } + + protected override void Update() + { + base.Update(); + + triangles.Width = DrawWidth; + healthBar.Width = normalizedHealth; + + damageIndicator.X = leftToRight ? normalizedHealthWithDamage : -normalizedHealthWithDamage; + damageIndicator.Width = float.Clamp(normalizedHealth - normalizedHealthWithDamage, 0, 1); + } + + private void flashHealth() + { + if (Health.NormalizedValue > HealthFlashThreshold) + return; + + var almostRed = Interpolation.ValueAt(0.75, healthBarColour, ColourInfo.SingleColour(Color4.Red), 0.0, 1.0); + + healthBarBackground.FadeColour(almostRed, 150) + .Then() + .FadeColour(healthBarColour, 800); + + heartIcon + .ScaleTo(0.8f, 150, Easing.Out) + .Then() + .ScaleTo(1f, 400, Easing.OutElasticHalf); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs new file mode 100644 index 000000000000..fbc86e5c9777 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs @@ -0,0 +1,352 @@ +// 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.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Humanizer; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Primitives; +using osu.Game.Audio; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.RankedPlay; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class DiscardScreen : RankedPlaySubScreen + { + // When the 'time running out' warning sample starts to play (in remaining seconds) + private const int warning_time_threshold = 10; + + public CardFlow CenterRow { get; private set; } = null!; + + private PlayerHandOfCards playerHand = null!; + private ShearedButton discardButton = null!; + private OsuTextFlowContainer explainer = null!; + + [Resolved] + private RankedPlayMatchInfo matchInfo { get; set; } = null!; + + private Sample? cardAddSample; + private Sample? cardDiscardSample; + + private const int card_play_samples = 2; + private Sample?[]? cardPlaySamples; + + private bool timeRunningOutWarningActive; + private Sample? timeRunningOutSample; + private SampleChannel? timeRunningOutSampleChannel; + + private DateTimeOffset stageEndTime; + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + var matchState = Client.Room?.MatchState as RankedPlayRoomState; + + Debug.Assert(matchState != null); + + Children = + [ + CenterRow = new CardFlow + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new RankedPlayStageDisplay(RankedPlayColourScheme.Blue) + { + Heading = "Discard Phase", + Caption = "Replace cards from your hand", + CaptionColour = Color4.White, + Margin = new MarginPadding { Top = 60 }, + }, + discardButton = new ShearedButton + { + Name = "Discard Button", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 150, + Action = onDiscardButtonClicked, + Enabled = { Value = true }, + } + ]; + + CenterColumn.Children = + [ + playerHand = new PlayerHandOfCards + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + SelectionMode = HandSelectionMode.Multiple, + }, + explainer = new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(size: 24)) + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + TextAnchor = Anchor.TopCentre, + Y = 250, + ParagraphSpacing = 1, + Alpha = 0, + }.With(d => + { + d.AddParagraph("These are your cards for this match!"); + d.AddParagraph("When it’s your turn, you can play a card to go head-to-head against your opponent!"); + }) + ]; + + cardAddSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/card-add-1"); + cardDiscardSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/card-discard-1"); + + cardPlaySamples = new Sample?[card_play_samples]; + for (int i = 0; i < card_play_samples; i++) + cardPlaySamples[i] = audio.Samples.Get($@"Multiplayer/Matchmaking/Ranked/card-play-{1 + i}"); + + timeRunningOutSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/time-running-out"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + matchInfo.PlayerCardAdded += cardAdded; + matchInfo.PlayerCardRemoved += cardRemoved; + + playerHand.SelectionChanged += onSelectionChanged; + + Client.CountdownStarted += onCountdownStarted; + Client.CountdownStopped += onCountdownStopped; + + if (Client.Room != null) + { + foreach (var countdown in Client.Room.ActiveCountdowns) + onCountdownStarted(countdown); + } + + onSelectionChanged(); + } + + protected override void Update() + { + base.Update(); + + TimeSpan remainingTime = stageEndTime - DateTimeOffset.Now; + + if (timeRunningOutWarningActive && remainingTime.TotalSeconds < warning_time_threshold) + { + timeRunningOutSampleChannel ??= timeRunningOutSample?.GetChannel(); + + if (timeRunningOutSampleChannel == null || timeRunningOutSampleChannel.Playing) + return; + + timeRunningOutSampleChannel.ManualFree = true; + timeRunningOutSampleChannel.Looping = true; + timeRunningOutSampleChannel.Play(); + } + } + + public override void OnEntering(RankedPlaySubScreen? previous) + { + base.OnEntering(previous); + + var screenBottomCenter = new Vector2(DrawWidth / 2, DrawHeight); + int cardCount = 0; + + foreach (var card in matchInfo.PlayerCards) + { + playerHand.AddCard(card, c => + { + c.Position = ToSpaceOfOtherDrawable(screenBottomCenter, playerHand); + }); + Scheduler.AddDelayed(() => + { + SamplePlaybackHelper.PlayWithRandomPitch(cardAddSample); + }, 50 * cardCount); + cardCount++; + } + + playerHand.UpdateLayout(stagger: 50); + } + + private void onCountdownStarted(MultiplayerCountdown countdown) => Scheduler.Add(() => + { + if (countdown is not RankedPlayStageCountdown stageCountdown) + return; + + stageEndTime = DateTimeOffset.Now + countdown.TimeRemaining; + timeRunningOutWarningActive = stageCountdown.Stage == RankedPlayStage.CardDiscard; + }); + + private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add(() => + { + if (countdown is not RankedPlayStageCountdown) + return; + + timeRunningOutSampleChannel?.Stop(); + + stageEndTime = DateTimeOffset.Now; + timeRunningOutWarningActive = false; + }); + + private void onSelectionChanged() + { + if (playerHand.Selection.Any()) + discardButton.Text = $"Replace {"card".ToQuantity(playerHand.Selection.Count())}"; + else + discardButton.Text = "Keep cards"; + } + + private void onDiscardButtonClicked() + { + discardButton.Hide(); + + Client.DiscardCards(playerHand.Selection.Select(it => it.Card).ToArray()).FireAndForget(); + playerHand.SelectionMode = HandSelectionMode.Disabled; + } + + private readonly List discardedCards = new List(); + + private void cardRemoved(RankedPlayCardWithPlaylistItem item) => discardedCards.Add(item); + + private void playDiscardAnimation() + { + const double stagger = 100; + double delay = 0; + + foreach (var item in discardedCards) + { + if (!playerHand.RemoveCard(item, out var card, out Quad drawQuad)) + return; + + card.Anchor = Anchor.Centre; + card.Origin = Anchor.Centre; + + card.MatchScreenSpaceDrawQuad(drawQuad, CenterRow); + + CenterRow.Add(card); + + using (BeginDelayedSequence(1000 + delay)) + { + card.PopOutAndExpire(); + } + + Scheduler.AddDelayed(() => + { + SamplePlaybackHelper.PlayWithRandomPitch(cardPlaySamples); + }, delay); + + delay += stagger; + } + + Scheduler.AddDelayed(() => + { + cardDiscardSample?.Play(); + }, 1000); + + discardedCards.Clear(); + CenterRow.LayoutCards(stagger: stagger); + } + + private double nextCardDrawTime; + private double earliestPresentationTime; + + private void cardAdded(RankedPlayCardWithPlaylistItem card) + { + if (discardedCards.Count > 0) + { + playDiscardAnimation(); + nextCardDrawTime = Math.Max(nextCardDrawTime, Time.Current + 2000); + } + + double delay = Math.Max(0, nextCardDrawTime - Time.Current); + nextCardDrawTime = Time.Current + delay + 100; + + earliestPresentationTime = Time.Current + 3500; + + Scheduler.AddDelayed(() => + { + playerHand.AddCard(card, d => + { + d.Position = ToSpaceOfOtherDrawable(new Vector2(DrawWidth, DrawHeight * 0.5f), playerHand); + d.Rotation = -30; + }); + + SamplePlaybackHelper.PlayWithRandomPitch(cardAddSample); + }, delay); + } + + public void PresentRemainingCards() + { + discardButton.Hide(); + + double presentationTime = Math.Max(earliestPresentationTime, Time.Current); + Scheduler.AddDelayed(presentRemainingCards, presentationTime - Time.Current); + } + + private void presentRemainingCards() + { + int delay = 0; + + foreach (var item in matchInfo.PlayerCards) + { + if (playerHand.RemoveCard(item, out var card, out Quad drawQuad)) + { + card.MatchScreenSpaceDrawQuad(drawQuad, CenterRow); + + CenterRow.Add(card); + + Scheduler.AddDelayed(() => + { + SamplePlaybackHelper.PlayWithRandomPitch(cardPlaySamples); + }, delay); + + delay += 50; + } + else + { + CenterRow.Add(new RankedPlayCard(item) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + } + } + + CenterRow.LayoutCards(stagger: 50, duration: 600); + + explainer + .Delay(100) + .MoveToOffset(new Vector2(0, 50)) + .MoveToOffset(new Vector2(0, -50), 600, Easing.OutExpo) + .FadeIn(250); + } + + protected override void Dispose(bool isDisposing) + { + timeRunningOutSampleChannel?.Stop(); + timeRunningOutSampleChannel?.Dispose(); + + matchInfo.PlayerCardAdded -= cardAdded; + matchInfo.PlayerCardRemoved -= cardRemoved; + + base.Dispose(isDisposing); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/EndedScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/EndedScreen.cs new file mode 100644 index 000000000000..ba0549e5fa20 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/EndedScreen.cs @@ -0,0 +1,207 @@ +// 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.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class EndedScreen : RankedPlaySubScreen + { + /// + /// Invoked when the user requests to exit this screen. + /// + public Action? ExitRequested { get; init; } + + [Resolved] + private RankedPlayMatchInfo matchInfo { get; set; } = null!; + + private OsuSpriteText titleText = null!; + private Drawable titleSeparator = null!; + private OsuTextFlowContainer localRatingText = null!; + private OsuTextFlowContainer opponentRatingText = null!; + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + CenterColumn.Child = new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(20), + Children = new[] + { + titleText = new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "VICTORY", + Font = OsuFont.Torus.With(size: 100, weight: FontWeight.SemiBold), + UseFullGlyphHeight = false, + Colour = colours.Green1, + }, + titleSeparator = new Box + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + Height = 2, + Colour = colours.Green1 + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(2), + Children = new Drawable[] + { + new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Shear = OsuGame.SHEAR, + Masking = true, + CornerRadius = 8, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.5f + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding(10), + Shear = -OsuGame.SHEAR, + Children = new Drawable[] + { + localRatingText = new OsuTextFlowContainer(s => s.Font = OsuFont.Style.Heading1) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + } + } + } + } + }, + new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Shear = OsuGame.SHEAR, + Masking = true, + CornerRadius = 8, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.5f + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding(10), + Shear = -OsuGame.SHEAR, + Children = new Drawable[] + { + opponentRatingText = new OsuTextFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } + } + } + } + } + } + }, + new FillFlowContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new ShearedButton + { + Width = 100, + Text = "Quit", + Action = () => ExitRequested?.Invoke(false), + DarkerColour = colours.Red3, + LighterColour = colours.Red4, + }, + new ShearedButton + { + Width = 200, + Text = "Play Again", + Action = () => ExitRequested?.Invoke(true), + DarkerColour = colours.Green3, + LighterColour = colours.Green4, + }, + } + } + } + }; + + RankedPlayUserInfo localUser = matchInfo.RoomState.Users[Client.LocalUser!.UserID]; + RankedPlayUserInfo otherUser = matchInfo.RoomState.Users.Values.Single(u => u != localUser); + + if (matchInfo.RoomState.WinningUserId == null) + { + titleText.Text = "DRAW"; + titleText.Colour = titleSeparator.Colour = colours.Orange1; + } + else if (matchInfo.RoomState.WinningUserId == Client.LocalUser!.UserID) + { + titleText.Text = "VICTORY"; + titleText.Colour = titleSeparator.Colour = colours.Green1; + } + else + { + titleText.Text = "DEFEAT"; + titleText.Colour = titleSeparator.Colour = colours.Red1; + } + + localRatingText.AddText("Your Rating: ", s => s.Font = OsuFont.Style.Heading1.With(weight: FontWeight.Regular)); + localRatingText.AddText(localUser.RatingAfter.ToString("N0"), s => s.Font = OsuFont.Style.Heading1); + localRatingText.AddText($" ({localUser.RatingAfter - localUser.Rating:+0;-0;+0})", s => + { + s.Font = OsuFont.Style.Caption1; + s.Colour = localUser.RatingAfter >= localUser.Rating ? colours.GreenDark : colours.RedDark; + }); + + opponentRatingText.AddText("Opponent Rating: ", s => s.Font = OsuFont.Style.Heading1.With(weight: FontWeight.Regular)); + opponentRatingText.AddText(otherUser.RatingAfter.ToString("N0"), s => s.Font = OsuFont.Style.Heading1); + opponentRatingText.AddText($" ({otherUser.RatingAfter - otherUser.Rating:+0;-0;+0})", s => + { + s.Font = OsuFont.Style.Caption1; + s.Colour = otherUser.RatingAfter >= otherUser.Rating ? colours.GreenDark : colours.RedDark; + }); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayScreen.cs new file mode 100644 index 000000000000..8a558b24e3d8 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayScreen.cs @@ -0,0 +1,42 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class GameplayScreen : RankedPlaySubScreen + { + [BackgroundDependencyLoader] + private void load() + { + CenterColumn.Children = + [ + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Spacing = new Vector2(20), + Children = + [ + new OsuSpriteText + { + Text = "Gameplay is in progress...", + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Font = OsuFont.GetFont(typeface: Typeface.TorusAlternate, size: 42, weight: FontWeight.Regular), + }, + ] + }, + ]; + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.DifficultyDisplay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.DifficultyDisplay.cs new file mode 100644 index 000000000000..65af9c57a3b3 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.DifficultyDisplay.cs @@ -0,0 +1,234 @@ +// 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.Linq; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; +using osu.Game.Overlays; +using osu.Game.Rulesets; +using osu.Game.Screens.Select; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class GameplayWarmupScreen + { + private partial class DifficultyDisplay : CompositeDrawable + { + private const float border_weight = 2; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + [Resolved] + private MultiplayerClient client { get; set; } = null!; + + [Resolved] + private BeatmapManager beatmapManager { get; set; } = null!; + + [Resolved] + private RulesetStore rulesets { get; set; } = null!; + + private readonly APIBeatmap beatmap; + + private StarRatingDisplay starRatingDisplay = null!; + private FillFlowContainer nameLine = null!; + private OsuSpriteText difficultyText = null!; + private OsuSpriteText mappedByText = null!; + private OsuSpriteText mapperText = null!; + + private BeatmapTitleWedge.DifficultyStatisticsDisplay countStatisticsDisplay = null!; + private BeatmapTitleWedge.DifficultyStatisticsDisplay difficultyStatisticsDisplay = null!; + + public DifficultyDisplay(APIBeatmap beatmap) + { + this.beatmap = beatmap; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Masking = true; + CornerRadius = 10; + Shear = OsuGame.SHEAR; + + InternalChildren = new Drawable[] + { + new WedgeBackground(), + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new ShearAligningWrapper(new GridContainer + { + Shear = -OsuGame.SHEAR, + AlwaysPresent = true, + RelativeSizeAxes = Axes.X, + Height = 20, + Margin = new MarginPadding { Vertical = 5f }, + Padding = new MarginPadding { Left = SongSelect.WEDGE_CONTENT_MARGIN }, + RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, 6), + new Dimension(), + }, + Content = new[] + { + new[] + { + starRatingDisplay = new StarRatingDisplay(default, animated: true) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + Empty(), + nameLine = new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Margin = new MarginPadding { Bottom = 2f }, + Children = new Drawable[] + { + difficultyText = new TruncatingSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Font = OsuFont.Style.Body.With(weight: FontWeight.SemiBold), + }, + mappedByText = new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Text = " mapped by ", + Font = OsuFont.Style.Body, + }, + mapperText = new TruncatingSpriteText + { + Shadow = true, + Font = OsuFont.Style.Body.With(weight: FontWeight.SemiBold), + }, + }, + }, + } + }, + }), + new ShearAligningWrapper(new Container + { + Shear = -OsuGame.SHEAR, + RelativeSizeAxes = Axes.X, + Height = 53, + Padding = new MarginPadding { Bottom = border_weight, Right = border_weight }, + Child = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Masking = true, + CornerRadius = 10 - border_weight, + Shear = OsuGame.SHEAR, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background5.Opacity(0.8f), + }, + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Left = SongSelect.WEDGE_CONTENT_MARGIN, Right = 20f, Vertical = 7.5f }, + Shear = -OsuGame.SHEAR, + RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.Absolute, 30), + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new[] + { + countStatisticsDisplay = new BeatmapTitleWedge.DifficultyStatisticsDisplay + { + RelativeSizeAxes = Axes.X, + }, + Empty(), + difficultyStatisticsDisplay = new BeatmapTitleWedge.DifficultyStatisticsDisplay(autoSize: true), + } + }, + } + }, + } + }), + } + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + MultiplayerPlaylistItem item = client.Room!.CurrentPlaylistItem; + + RulesetInfo ruleset = rulesets.GetRuleset(item.RulesetID)!; + Ruleset rulesetInstance = ruleset.CreateInstance(); + BeatmapInfo? localBeatmap = + beatmapManager.QueryBeatmap($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", item.BeatmapID); + WorkingBeatmap workingBeatmap = beatmapManager.GetWorkingBeatmap(localBeatmap); + IBeatmap playableBeatmap = workingBeatmap.GetPlayableBeatmap(ruleset); + + difficultyText.Text = beatmap.DifficultyName; + mapperText.Text = beatmap.Metadata.Author.Username; + starRatingDisplay.Current.Value = new StarDifficulty(beatmap.StarRating, beatmap.MaxCombo ?? 0); + + countStatisticsDisplay.Statistics = playableBeatmap.GetStatistics() + .Select(s => new BeatmapTitleWedge.StatisticDifficulty.Data(s.Name, s.BarDisplayLength ?? 0, s.BarDisplayLength ?? 0, 1, s.Content)) + .ToList(); + + difficultyStatisticsDisplay.Statistics = rulesetInstance.GetBeatmapAttributesForDisplay(beatmap, []) + .Select(a => new BeatmapTitleWedge.StatisticDifficulty.Data(a)) + .ToList(); + } + + protected override void Update() + { + base.Update(); + + difficultyText.MaxWidth = Math.Max(nameLine.DrawWidth - mappedByText.DrawWidth - mapperText.DrawWidth - 20, 0); + + // Use difficulty colour until it gets too dark to be visible against dark backgrounds. + Color4 col = starRatingDisplay.DisplayedStars.Value >= OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF ? colours.Orange1 : starRatingDisplay.DisplayedDifficultyColour; + + difficultyText.Colour = col; + mappedByText.Colour = col; + countStatisticsDisplay.AccentColour = col; + difficultyStatisticsDisplay.AccentColour = col; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.MetadataWedge.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.MetadataWedge.cs new file mode 100644 index 000000000000..7ffb1fba6a96 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.MetadataWedge.cs @@ -0,0 +1,260 @@ +// 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.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Containers; +using osu.Game.Localisation; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; +using osu.Game.Screens.Select; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class GameplayWarmupScreen + { + private partial class MetadataWedge : CompositeDrawable + { + private readonly APIBeatmap beatmap; + + private BeatmapMetadataWedge.MetadataDisplay creator = null!; + private BeatmapMetadataWedge.MetadataDisplay source = null!; + private BeatmapMetadataWedge.MetadataDisplay genre = null!; + private BeatmapMetadataWedge.MetadataDisplay language = null!; + private BeatmapMetadataWedge.MetadataDisplay userTags = null!; + private BeatmapMetadataWedge.MetadataDisplay mapperTags = null!; + private BeatmapMetadataWedge.MetadataDisplay submitted = null!; + private BeatmapMetadataWedge.MetadataDisplay ranked = null!; + + private BeatmapMetadataWedge.SuccessRateDisplay successRateDisplay = null!; + private BeatmapMetadataWedge.UserRatingDisplay userRatingDisplay = null!; + private BeatmapMetadataWedge.RatingSpreadDisplay ratingSpreadDisplay = null!; + private BeatmapMetadataWedge.FailRetryDisplay failRetryDisplay = null!; + + public MetadataWedge(APIBeatmap beatmap) + { + this.beatmap = beatmap; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + Width = 0.9f; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0f, 4f), + Shear = OsuGame.SHEAR, + Children = new[] + { + new ShearAligningWrapper(new Container + { + CornerRadius = 10, + Masking = true, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new WedgeBackground(), + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Shear = -OsuGame.SHEAR, + Padding = new MarginPadding { Left = SongSelect.WEDGE_CONTENT_MARGIN, Right = 35, Vertical = 16 }, + Children = new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0f, 10f), + Children = new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(), + new Dimension(), + }, + Content = new[] + { + new[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0f, 10f), + Children = new[] + { + creator = new BeatmapMetadataWedge.MetadataDisplay(EditorSetupStrings.Creator), + genre = new BeatmapMetadataWedge.MetadataDisplay(BeatmapsetsStrings.ShowInfoGenre), + }, + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0f, 10f), + Children = new[] + { + source = new BeatmapMetadataWedge.MetadataDisplay(BeatmapsetsStrings.ShowInfoSource), + language = new BeatmapMetadataWedge.MetadataDisplay(BeatmapsetsStrings.ShowInfoLanguage), + }, + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0f, 10f), + Children = new[] + { + submitted = new BeatmapMetadataWedge.MetadataDisplay(SongSelectStrings.Submitted), + ranked = new BeatmapMetadataWedge.MetadataDisplay(SongSelectStrings.Ranked), + }, + }, + }, + }, + }, + userTags = new BeatmapMetadataWedge.MetadataDisplay(BeatmapsetsStrings.ShowInfoUserTags) + { + Alpha = 0, + }, + mapperTags = new BeatmapMetadataWedge.MetadataDisplay(BeatmapsetsStrings.ShowInfoMapperTags), + }, + }, + }, + }, + }, + }), + new ShearAligningWrapper(new Container + { + CornerRadius = 10, + Masking = true, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new WedgeBackground(), + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Shear = -OsuGame.SHEAR, + RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.Absolute, 10), + new Dimension(), + new Dimension(GridSizeMode.Absolute, 10), + new Dimension(), + }, + Padding = new MarginPadding { Left = SongSelect.WEDGE_CONTENT_MARGIN, Right = 40f, Vertical = 16 }, + Content = new[] + { + new[] + { + successRateDisplay = new BeatmapMetadataWedge.SuccessRateDisplay(), + Empty(), + userRatingDisplay = new BeatmapMetadataWedge.UserRatingDisplay(), + Empty(), + ratingSpreadDisplay = new BeatmapMetadataWedge.RatingSpreadDisplay(), + }, + }, + }, + } + }), + new ShearAligningWrapper(new Container + { + CornerRadius = 10, + Masking = true, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new WedgeBackground(), + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Shear = -OsuGame.SHEAR, + Padding = new MarginPadding { Left = SongSelect.WEDGE_CONTENT_MARGIN, Right = 40f, Vertical = 16 }, + Child = failRetryDisplay = new BeatmapMetadataWedge.FailRetryDisplay(), + }, + }, + }), + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + var metadata = beatmap.Metadata; + var beatmapSet = beatmap.BeatmapSet!; + + creator.Data = (metadata.Author.Username, null); + + if (!string.IsNullOrEmpty(metadata.Source)) + source.Data = (metadata.Source, null); + else + source.Data = ("-", null); + + if (!string.IsNullOrEmpty(metadata.Tags)) + mapperTags.Tags = (metadata.Tags.Split(' '), _ => { }); + else + mapperTags.Tags = (Array.Empty(), _ => { }); + + submitted.Date = beatmapSet.Submitted; + ranked.Date = beatmapSet.Ranked; + + genre.Data = (beatmapSet.Genre.Name, null); + language.Data = (beatmapSet.Language.Name, null); + + userRatingDisplay.Data = beatmapSet.Ratings; + ratingSpreadDisplay.Data = beatmapSet.Ratings; + successRateDisplay.Data = (beatmap.PassCount, beatmap.PlayCount); + failRetryDisplay.Data = beatmap.FailTimes ?? new APIFailTimes(); + + var tagsById = beatmapSet.RelatedTags?.ToDictionary(t => t.Id) ?? new Dictionary(); + string[] topUserTags = beatmap.TopTags? + .Select(t => (topTag: t, relatedTag: tagsById.GetValueOrDefault(t.TagId))) + .Where(t => t.relatedTag != null) + // see https://github.com/ppy/osu-web/blob/bb3bd2e7c6f84f26066df5ea20a81c77ec9bb60a/resources/js/beatmapsets-show/controller.ts#L103-L106 for sort criteria + .OrderByDescending(t => t.topTag.VoteCount) + .ThenBy(t => t.relatedTag!.Name) + .Select(t => t.relatedTag!.Name) + .ToArray() ?? []; + + userTags.Tags = (topUserTags, _ => { }); + + if (topUserTags.Length > 0) + userTags.Show(); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.TitleWedge.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.TitleWedge.cs new file mode 100644 index 000000000000..381b12bbf8f0 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.TitleWedge.cs @@ -0,0 +1,167 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Extensions; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; +using osu.Game.Resources.Localisation.Web; +using osu.Game.Screens.Select; +using osu.Game.Utils; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class GameplayWarmupScreen + { + private partial class TitleWedge : CompositeDrawable + { + private const float corner_radius = 10; + + private readonly APIBeatmap beatmap; + + private BeatmapSetOnlineStatusPill statusPill = null!; + private MarqueeContainer titleLabel = null!; + private MarqueeContainer artistLabel = null!; + + private BeatmapTitleWedge.StatisticPlayCount playCount = null!; + private BeatmapTitleWedge.FavouriteButton favouriteButton = null!; + private BeatmapTitleWedge.Statistic lengthStatistic = null!; + private BeatmapTitleWedge.Statistic bpmStatistic = null!; + + public TitleWedge(APIBeatmap beatmap) + { + this.beatmap = beatmap; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader] + private void load() + { + Masking = true; + Shear = OsuGame.SHEAR; + CornerRadius = corner_radius; + + InternalChildren = new Drawable[] + { + new WedgeBackground(), + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Padding = new MarginPadding + { + Top = SongSelect.WEDGE_CONTENT_MARGIN, + Left = SongSelect.WEDGE_CONTENT_MARGIN + }, + Spacing = new Vector2(0f, 4f), + Children = new Drawable[] + { + new ShearAligningWrapper(statusPill = new BeatmapSetOnlineStatusPill + { + Shear = -OsuGame.SHEAR, + ShowUnknownStatus = true, + TextSize = OsuFont.Style.Caption1.Size, + TextPadding = new MarginPadding { Horizontal = 6, Vertical = 1 }, + }), + new ShearAligningWrapper(new Container + { + Shear = -OsuGame.SHEAR, + RelativeSizeAxes = Axes.X, + Height = OsuFont.Style.Title.Size, + Margin = new MarginPadding { Bottom = -4f }, + Child = titleLabel = new MarqueeContainer + { + OverflowSpacing = 50, + } + }), + new ShearAligningWrapper(new Container + { + Shear = -OsuGame.SHEAR, + RelativeSizeAxes = Axes.X, + Height = OsuFont.Style.Heading2.Size, + Margin = new MarginPadding { Left = 1f }, + Child = artistLabel = new MarqueeContainer + { + OverflowSpacing = 50, + } + }), + new ShearAligningWrapper(new FillFlowContainer + { + Shear = -OsuGame.SHEAR, + AutoSizeAxes = Axes.X, + Height = 30, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(2f, 0f), + Children = new Drawable[] + { + playCount = new BeatmapTitleWedge.StatisticPlayCount(background: true, leftPadding: SongSelect.WEDGE_CONTENT_MARGIN, minSize: 50f) + { + Margin = new MarginPadding { Left = -SongSelect.WEDGE_CONTENT_MARGIN }, + }, + favouriteButton = new BeatmapTitleWedge.FavouriteButton(), + lengthStatistic = new BeatmapTitleWedge.Statistic(OsuIcon.Clock), + bpmStatistic = new BeatmapTitleWedge.Statistic(OsuIcon.Metronome) + { + TooltipText = BeatmapsetsStrings.ShowStatsBpm, + Margin = new MarginPadding { Left = 5f }, + }, + }, + }), + new ShearAligningWrapper(new Container + { + Shear = -OsuGame.SHEAR, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding { Left = -SongSelect.WEDGE_CONTENT_MARGIN }, + Padding = new MarginPadding { Right = -SongSelect.WEDGE_CONTENT_MARGIN }, + Child = new DifficultyDisplay(beatmap), + }), + }, + } + }; + + statusPill.Status = beatmap.Status; + + var titleText = new RomanisableString(beatmap.BeatmapSet!.TitleUnicode, beatmap.BeatmapSet.Title); + titleLabel.CreateContent = () => new OsuSpriteText + { + Text = titleText, + Shadow = true, + Font = OsuFont.Style.Title, + }; + + var artistText = new RomanisableString(beatmap.BeatmapSet.ArtistUnicode, beatmap.BeatmapSet.Artist); + artistLabel.CreateContent = () => new OsuSpriteText + { + Text = artistText, + Shadow = true, + Font = OsuFont.Style.Heading2, + }; + + double rate = ModUtils.CalculateRateWithMods([]); // Todo: mods + double drainLength = Math.Round(beatmap.Length / rate); + double hitLength = Math.Round(beatmap.HitLength / rate); + + lengthStatistic.Text = hitLength.ToFormattedDuration(); + lengthStatistic.TooltipText = BeatmapsetsStrings.ShowStatsTotalLength(drainLength.ToFormattedDuration()); + bpmStatistic.Text = beatmap.BPM.ToLocalisableString(); + + playCount.Value = new BeatmapTitleWedge.StatisticPlayCount.Data(beatmap.PlayCount, beatmap.UserPlayCount); + favouriteButton.SetBeatmapSet(beatmap.BeatmapSet); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.cs new file mode 100644 index 000000000000..80f4bb4ad54c --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.cs @@ -0,0 +1,182 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Logging; +using osu.Game.Database; +using osu.Game.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Overlays; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card; +using osu.Game.Screens.Select; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class GameplayWarmupScreen : RankedPlaySubScreen + { + public override bool ShowBeatmapBackground => true; + + [Cached(typeof(IBindable))] + private readonly Bindable lastLookupResult = new Bindable(); + + [Resolved] + private BeatmapLookupCache beatmapLookupCache { get; set; } = null!; + + [Resolved] + private RankedPlayMatchInfo matchInfo { get; set; } = null!; + + [Resolved] + private OverlayColourProvider overlayColours { get; set; } = null!; + + private Container cardColumn = null!; + private Drawable separator = null!; + private Drawable detailsColumn = null!; + private Drawable wedgesContainer = null!; + + [BackgroundDependencyLoader] + private void load() + { + APIBeatmap beatmap = beatmapLookupCache.GetBeatmapAsync(Client.Room!.CurrentPlaylistItem.BeatmapID).GetResultSafely()!; + lastLookupResult.Value = SongSelect.BeatmapSetLookupResult.Completed(beatmap.BeatmapSet); + + var matchState = Client.Room?.MatchState as RankedPlayRoomState; + Debug.Assert(matchState != null); + + Children = + [ + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Direction = FillDirection.Horizontal, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Width = 0.5f, + Spacing = new Vector2(20), + LayoutDuration = 500, + LayoutEasing = Easing.OutPow10, + Children = new[] + { + cardColumn = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + }, + separator = new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(2, 50), + Scale = new Vector2(1, 0), + Alpha = 0, + Colour = overlayColours.Colour0 + }, + detailsColumn = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Masking = true, + Scale = new Vector2(0.8f), + Alpha = 0, + Child = wedgesContainer = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Shear = OsuGame.SHEAR, + X = -20, + Padding = new MarginPadding + { + Left = -SongSelect.CORNER_RADIUS_HIDE_OFFSET, + }, + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(0f, 4f), + Direction = FillDirection.Vertical, + Children = + [ + new ShearAligningWrapper(new TitleWedge(beatmap)) + { + Shear = -OsuGame.SHEAR, + }, + new ShearAligningWrapper(new MetadataWedge(beatmap)) + { + Shear = -OsuGame.SHEAR, + }, + ] + } + } + } + } + } + ]; + } + + public override void OnEntering(RankedPlaySubScreen? previous) + { + base.OnEntering(previous); + + if (matchInfo.LastPlayedCard == null) + return; + + RankedPlayCard? card = null; + + switch (previous) + { + case PickScreen pick: + { + if (pick.CenterRow.RemoveCard(matchInfo.LastPlayedCard, out card, out var screenSpaceDrawQuad)) + card.MatchScreenSpaceDrawQuad(screenSpaceDrawQuad, cardColumn); + break; + } + + case OpponentPickScreen opponentPick: + { + if (opponentPick.CenterRow.RemoveCard(matchInfo.LastPlayedCard, out card, out var screenSpaceDrawQuad)) + card.MatchScreenSpaceDrawQuad(screenSpaceDrawQuad, cardColumn); + break; + } + } + + if (card == null) + { + Logger.Log($"Played card {matchInfo.LastPlayedCard.Card.ID} was not on the screen.", level: LogLevel.Error); + + card = new RankedPlayCard(matchInfo.LastPlayedCard) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + + cardColumn.Add(card); + + separator.AlwaysPresent = true; + detailsColumn.AlwaysPresent = true; + + using (BeginDelayedSequence(500)) + { + separator.FadeIn(); + separator.ScaleTo(Vector2.One, 1000, Easing.OutPow10); + + using (BeginDelayedSequence(200)) + { + detailsColumn.FadeIn(800, Easing.OutPow10); + wedgesContainer.MoveToX(0, 1000, Easing.OutPow10); + } + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/HamburgerMenu.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/HamburgerMenu.cs new file mode 100644 index 000000000000..2d422b525212 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/HamburgerMenu.cs @@ -0,0 +1,116 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Framework.Screens; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Overlays; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class HamburgerMenu : IconButton, IHasPopover + { + public HamburgerMenu() + { + Icon = FontAwesome.Solid.Bars; + Action = this.ShowPopover; + } + + public Framework.Graphics.UserInterface.Popover GetPopover() => new Popover(); + + private partial class Popover : OsuPopover + { + [Resolved] + private RankedPlayScreen? rankedPlayScreen { get; set; } + + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); + private FillFlowContainer buttonFlow = null!; + + [BackgroundDependencyLoader] + private void load() + { + Content.Padding = new MarginPadding(5); + + Child = buttonFlow = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(3), + }; + + addButton(rankedPlayScreen?.ActiveSubScreen is not EndedScreen ? "Give up" : "Exit", FontAwesome.Solid.SignOutAlt, () => rankedPlayScreen?.Exit()); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + ScheduleAfterChildren(() => GetContainingFocusManager()!.ChangeFocus(this)); + } + + private void addButton(LocalisableString text, IconUsage? icon, Action? action, Color4? colour = null) + { + var button = new OptionButton + { + Text = text, + Icon = icon ?? new IconUsage(), + BackgroundColour = colourProvider.Background3, + TextColour = colour, + Action = () => + { + Scheduler.AddDelayed(Hide, 50); + action?.Invoke(); + }, + }; + + buttonFlow.Add(button); + } + + private partial class OptionButton : OsuButton + { + public IconUsage Icon { get; init; } + public Color4? TextColour { get; init; } + + public OptionButton() + { + Size = new Vector2(265, 50); + } + + [BackgroundDependencyLoader] + private void load() + { + SpriteText.Colour = TextColour ?? Color4.White; + Content.CornerRadius = 10; + + Add(new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(17), + X = 15, + Icon = Icon, + Colour = TextColour ?? Color4.White, + }); + } + + protected override SpriteText CreateText() => new OsuSpriteText + { + Depth = -1, + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + X = 40 + }; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandOfCards.HandCard.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandOfCards.HandCard.cs new file mode 100644 index 000000000000..43e8cbf270e2 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandOfCards.HandCard.cs @@ -0,0 +1,113 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.RankedPlay; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand +{ + public abstract partial class HandOfCards + { + public partial class HandCard : CompositeDrawable + { + public float LayoutWidth => DrawWidth * (State.Hovered ? hover_scale : 1); + + private readonly Bindable state = new Bindable(); + + public RankedPlayCardState State + { + get => state.Value; + set => state.Value = value; + } + + public bool Selected + { + get => State.Selected; + set => State = State with { Selected = value }; + } + + public bool CardHovered + { + get => State.Hovered; + set => State = State with { Hovered = value }; + } + + public bool CardPressed + { + get => State.Pressed; + set => State = State with { Pressed = value }; + } + + [Resolved] + private HandOfCards handOfCards { get; set; } = null!; + + public readonly RankedPlayCard Card; + + public RankedPlayCardWithPlaylistItem Item => Card.Item; + + public HandCard(RankedPlayCard card) + { + Size = card.DrawSize; + + card.Anchor = Anchor.Centre; + card.Origin = Anchor.Centre; + card.Position = Vector2.Zero; + card.Rotation = 0; + card.Scale = Vector2.One; + + AddInternal(Card = card); + + Anchor = Anchor.BottomCentre; + Origin = Anchor.BottomCentre; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + state.BindValueChanged(OnStateChanged, true); + } + + protected virtual void OnStateChanged(ValueChangedEvent state) + { + handOfCards.OnCardStateChanged(this, state.NewValue); + + Card.ShowSelectionOutline = state.NewValue.Selected; + + switch (state.NewValue.Pressed, state.OldValue.Pressed) + { + case (true, false): + Card.ScaleTo(0.95f, 300, Easing.OutExpo); + break; + + case (false, true): + Card.ScaleTo(1f, 400, Easing.OutElasticHalf); + break; + } + } + + public RankedPlayCard Detach() + { + Card.ShowSelectionOutline = false; + Card.Elevation = 0; + + RemoveInternal(Card, false); + + return Card; + } + + protected override void Update() + { + base.Update(); + + Card.Elevation = float.Lerp(CardHovered ? 1 : 0, Card.Elevation, (float)Math.Exp(-0.03f * Time.Elapsed)); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandOfCards.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandOfCards.cs new file mode 100644 index 000000000000..935d8fb3b8a9 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandOfCards.cs @@ -0,0 +1,255 @@ +// 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.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Caching; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.RankedPlay; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand +{ + /// + /// Drawable that layouts cards as if held in a player's hands. + /// + [Cached] + public abstract partial class HandOfCards : CompositeDrawable + { + private const float hover_scale = 1.2f; + + public IEnumerable Cards => cardContainer.Children; + + /// + /// How far a card slides upwards when hovered. + /// Used for making sure a card moves entirely into frame when the hand is partially off-screen. + /// + public float HoverYOffset = 15; + + /// + /// If true, card layout will be flipped on both axes for a card hand placed at the top edge of the screen, while keeping the cards upright. + /// Used for . + /// + protected virtual bool Flipped => false; + + private readonly Container cardContainer; + + private readonly Dictionary cardLookup = new Dictionary(); + + protected HandOfCards() + { + AddInternal(cardContainer = new Container + { + RelativeSizeAxes = Axes.Both, + }); + } + + protected override void Update() + { + base.Update(); + + if (!layoutBacking.IsValid) + { + updateLayout(); + layoutBacking.Validate(); + } + } + + protected bool Contracted { get; private set; } + + /// + /// Contracts all cards towards the bottom (or top when ). + /// Cards will no longer get layouted after this method is called. + /// + public void Contract() + { + Contracted = true; + + double delay = 0; + + foreach (var card in cardContainer) + { + card.Delay(delay) + .MoveTo(new Vector2(0, Flipped ? -220 : 220), 400, Easing.OutExpo) + .RotateTo(0, 400, Easing.OutExpo) + .ScaleTo(1, 400, Easing.OutExpo); + + delay += 50; + } + } + + private Anchor cardAnchor => Flipped ? Anchor.TopCentre : Anchor.BottomCentre; + + public void AddCard(RankedPlayCardWithPlaylistItem item, Action? setupAction = null) => AddCard(new RankedPlayCard(item), setupAction); + + public void AddCard(RankedPlayCard card, Action? setupAction = null) + { + if (cardLookup.ContainsKey(card.Item.Card)) + return; + + var drawable = CreateHandCard(card); + drawable.Anchor = drawable.Origin = cardAnchor; + + cardLookup[card.Item.Card] = drawable; + + cardContainer.Add(drawable); + layoutBacking.Invalidate(); + + setupAction?.Invoke(drawable); + } + + public void Clear() => cardContainer.Clear(); + + public bool RemoveCard(RankedPlayCardWithPlaylistItem item) + { + if (!cardLookup.Remove(item.Card, out var drawable)) + return false; + + cardContainer.Remove(drawable, true); + layoutBacking.Invalidate(); + return false; + } + + /// + /// Removes a card and detaches it's contained card so it can be attached to a new card facade. + /// + /// Item to remove the card for + /// Contained + /// of the removed card + /// Whether a card was found for the provided item + public bool RemoveCard(RankedPlayCardWithPlaylistItem item, [MaybeNullWhen(false)] out RankedPlayCard card, out Quad screenSpaceDrawQuad) + { + if (!cardLookup.Remove(item.Card, out var drawable)) + { + card = null; + screenSpaceDrawQuad = default; + return false; + } + + screenSpaceDrawQuad = drawable.ScreenSpaceDrawQuad; + card = drawable.Detach(); + + cardContainer.Remove(drawable, true); + layoutBacking.Invalidate(); + + return true; + } + + protected virtual HandCard CreateHandCard(RankedPlayCard card) => new HandCard(card); + + protected virtual void OnCardStateChanged(HandCard card, RankedPlayCardState state) + { + InvalidateLayout(); + + // hovered state can be caused by keyboard focus, in which case we have to clean up after the other cards manually + if (state.Hovered) + { + foreach (var c in cardContainer) + { + if (c != card) + c.CardHovered = false; + } + } + } + + #region Layout + + private readonly Cached layoutBacking = new Cached(); + + protected void InvalidateLayout() => layoutBacking.Invalidate(); + + public void UpdateLayout(double stagger = 0) + { + updateLayout(stagger); + layoutBacking.Validate(); + } + + private void updateLayout(double stagger = 0) + { + if (Contracted) + return; + + const float spacing = -20; + + float totalWidth = cardContainer.Sum(it => it.LayoutWidth + spacing) - spacing; + + float x = -totalWidth / 2; + + const int no_card_hovered = -1; + int hoverIndex = no_card_hovered; + + for (int i = 0; i < cardContainer.Count; i++) + { + if (cardContainer[i].CardHovered) + { + hoverIndex = i; + break; + } + } + + double delay = 0; + + for (int i = 0; i < cardContainer.Count; i++) + { + var child = cardContainer[i]; + + x += child.LayoutWidth / 2; + + float yOffset = 0; + + var position = new Vector2(x, MathF.Pow(MathF.Abs(x / 250), 2) * 20 - 10); + + if (hoverIndex != no_card_hovered && cardContainer.Children.Count > 1) + { + int distance = Math.Abs(i - hoverIndex); + int direction = Math.Sign(i - hoverIndex); + + position.X += direction switch + { + 0 => 0, + + // special case for the left card when there's only 2 cards + // too much offset looks kinda odd here so it's reduced + < 0 when cardContainer.Count == 2 => -3, + + < 0 => -10 / MathF.Pow(distance, 3), + + // cards right to the hovered card have a higher offset because they are partially + // covering the cards to their left + > 0 => 20 / MathF.Pow(distance, 2), + }; + } + + if (child.CardHovered) + yOffset = -HoverYOffset; + + float rotation = x * 0.03f; + + float angle = MathHelper.DegreesToRadians(rotation + 90); + + position += new Vector2(MathF.Cos(angle), MathF.Sin(angle)) * yOffset; + + position *= Flipped ? -1 : 1; + + child + .Delay(delay) + .MoveTo(position, 300, Easing.OutExpo) + .RotateTo(rotation, 300, Easing.OutExpo) + .ScaleTo(child.CardHovered ? hover_scale : 1f, 400, Easing.OutElasticQuarter); + + x += child.LayoutWidth / 2 + spacing; + + delay += stagger; + } + } + + #endregion + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandReplayPlayer.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandReplayPlayer.cs new file mode 100644 index 000000000000..e7c6fe0ec8ad --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandReplayPlayer.cs @@ -0,0 +1,72 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.RankedPlay; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand +{ + public partial class HandReplayPlayer : Component + { + /// + /// Maximum amount of frames that can get queued up at the same time + /// + public int MaxQueuedFrames { get; set; } = 20; + + private readonly int userId; + private readonly OpponentHandOfCards handOfCards; + + private int queuedFrames; + private double? lastPlayback; + + public HandReplayPlayer(int userId, OpponentHandOfCards handOfCards) + { + this.userId = userId; + this.handOfCards = handOfCards; + } + + [Resolved] + private MultiplayerClient client { get; set; } = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + client.MatchEvent += onMatchEvent; + } + + private void onMatchEvent(MatchServerEvent e) + { + if (e is not RankedPlayCardHandReplayEvent replayEvent || replayEvent.UserId != userId) + return; + + foreach (var frame in replayEvent.Frames) + { + if (queuedFrames >= MaxQueuedFrames) + return; + + queuedFrames++; + + double delay = Math.Max(lastPlayback != null ? lastPlayback.Value + frame.Delay - Time.Current : 0, 0); + lastPlayback = Time.Current + delay; + + Scheduler.AddDelayed(() => + { + queuedFrames--; + + handOfCards.SetState(frame.Cards); + }, delay); + } + } + + protected override void Dispose(bool isDisposing) + { + client.MatchEvent -= onMatchEvent; + + base.Dispose(isDisposing); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandReplayRecorder.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandReplayRecorder.cs new file mode 100644 index 000000000000..9c4bf1d1cbc2 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandReplayRecorder.cs @@ -0,0 +1,124 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.RankedPlay; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand +{ + public partial class HandReplayRecorder : Component + { + /// + /// Interval at which buffered frames get collected and emitted + /// + public double FlushInterval { get; init; } = 1000; + + /// + /// Minimum interval between individual replay frames + /// + public double RecordInterval { get; init; } = 25; + + /// + /// Max amount of frames to collect per + /// + public int MaxBufferSize = 20; + + [Resolved] + private MultiplayerClient client { get; set; } = null!; + + private readonly PlayerHandOfCards handOfCards; + + private readonly List buffer = new List(); + private bool hasChanges; + private double? lastFrameTime; + + public HandReplayRecorder(PlayerHandOfCards handOfCards) + { + this.handOfCards = handOfCards; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Scheduler.AddDelayed(recordFrame, RecordInterval, true); + Scheduler.AddDelayed(tryFlush, FlushInterval, true); + + handOfCards.StateChanged += onHandOfCardsStateChanged; + } + + private void onHandOfCardsStateChanged() => hasChanges = true; + + private void recordFrame() + { + if (!hasChanges || buffer.Count >= MaxBufferSize) + return; + + double delay = lastFrameTime != null ? Time.Current - lastFrameTime.Value : 0; + + buffer.Add(new RankedPlayCardHandReplayFrame + { + Delay = delay, + Cards = handOfCards.State, + }); + + lastFrameTime = Time.Current; + hasChanges = false; + } + + private void tryFlush() + { + if (buffer.Count == 0) + return; + + var frames = compress(buffer).ToArray(); + buffer.Clear(); + + if (frames.Length > 0) + Flush(frames); + } + + /// + /// Compresses a list of s by only keeping values that have changed between each frame + /// + private IEnumerable compress(IReadOnlyList frames) + { + if (frames.Count == 0) + yield break; + + // The first frame always contains the full state since the replay player may drop frames starting from the end for each message. + yield return frames[0]; + + var lastFrame = frames[0]; + + foreach (var frame in frames.Skip(1)) + { + yield return frame.RelativeTo(lastFrame); + + lastFrame = frame; + } + } + + protected virtual void Flush(RankedPlayCardHandReplayFrame[] frames) + { + if (frames.Length == 0) + return; + + client.SendMatchRequest(new RankedPlayCardHandReplayRequest + { + Frames = frames, + }); + } + + protected override void Dispose(bool isDisposing) + { + handOfCards.StateChanged -= onHandOfCardsStateChanged; + + base.Dispose(isDisposing); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandSelectionMode.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandSelectionMode.cs new file mode 100644 index 000000000000..4a8091331489 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/HandSelectionMode.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand +{ + public enum HandSelectionMode + { + Disabled, + Single, + Multiple, + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/OpponentHandOfCards.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/OpponentHandOfCards.cs new file mode 100644 index 000000000000..e2e27d820d2a --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/OpponentHandOfCards.cs @@ -0,0 +1,28 @@ +// 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.Collections.Generic; +using osu.Game.Online.RankedPlay; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand +{ + /// + /// Card hand representing the opponent's current hand, intended to be placed at the top edge of the screen. + /// + public partial class OpponentHandOfCards : HandOfCards + { + protected override bool Flipped => true; + + public void SetState(Dictionary state) + { + foreach (var card in Cards) + { + if (!state.TryGetValue(card.Item.Card.ID, out var cardState)) + continue; + + card.State = cardState; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/PlayerHandOfCards.PlayerHandCard.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/PlayerHandOfCards.PlayerHandCard.cs new file mode 100644 index 000000000000..c4021d7df9d4 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/PlayerHandOfCards.PlayerHandCard.cs @@ -0,0 +1,170 @@ +// 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 osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Events; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.RankedPlay; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand +{ + public partial class PlayerHandOfCards + { + public partial class PlayerHandCard : HandCard + { + private Action? playAction; + + public Action? PlayAction + { + get => playAction; + set + { + playAction = value; + PlayButton.Action = value; + updatePlayButtonVisibility(); + } + } + + public required Action Clicked; + + public required IBindable AllowSelection; + + private readonly Drawable cardInputArea; + private readonly Drawable fullInputArea; + + public readonly ShearedButton PlayButton; + + public PlayerHandCard(RankedPlayCard card) + : base(card) + { + AddRangeInternal(new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(-10) + { + // card moves upwards on hover which can produce jitter if the hitbox doesn't extend all the way to the bottom of the screen + Bottom = -50 + }, + Child = cardInputArea = new Container + { + RelativeSizeAxes = Axes.Both, + }, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = -40 }, + Child = fullInputArea = new Container + { + RelativeSizeAxes = Axes.Both, + Child = PlayButton = new ShearedButton + { + Name = "Play Button", + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Size = new Vector2(90, 30), + Text = "Play", + TextSize = 14, + LighterColour = Colour4.FromHex("87D8FA"), + DarkerColour = Colour4.FromHex("72D5FF") + } + } + } + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + AddInternal(new HoverSounds()); + } + + protected override void OnStateChanged(ValueChangedEvent state) + { + base.OnStateChanged(state); + updatePlayButtonVisibility(); + } + + private void updatePlayButtonVisibility() + { + PlayButton.Alpha = PlayButton.Action != null && Selected ? 1 : 0; + } + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) + { + if (PlayButton.Alpha > 0) + return fullInputArea.ReceivePositionalInputAt(screenSpacePos); + + // input events are handled for an area that's slightly larger than the actual card so the cursor always hovers a card when moving over a gap between two cards + return cardInputArea.ReceivePositionalInputAt(screenSpacePos); + } + + protected override bool OnHover(HoverEvent e) + { + CardHovered = true; + + return true; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + CardHovered = false; + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (e.Button == MouseButton.Left && AllowSelection.Value) + { + CardPressed = true; + + return true; + } + + return false; + } + + protected override void OnMouseUp(MouseUpEvent e) + { + if (e.Button == MouseButton.Left) + CardPressed = false; + } + + protected override bool OnClick(ClickEvent e) + { + if (!AllowSelection.Value) + return false; + + Clicked(this); + + return true; + } + + public override bool AcceptsFocus => true; + + public override bool ChangeFocusOnClick => false; + + protected override void OnFocus(FocusEvent e) + { + base.OnFocus(e); + + CardHovered = true; + } + + protected override void OnFocusLost(FocusLostEvent e) + { + base.OnFocusLost(e); + + CardHovered = false; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/PlayerHandOfCards.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/PlayerHandOfCards.cs new file mode 100644 index 000000000000..7ec73b76627c --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Hand/PlayerHandOfCards.cs @@ -0,0 +1,219 @@ +// 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.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Input.Events; +using osu.Game.Audio; +using osu.Game.Online.RankedPlay; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card; +using osuTK.Input; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand +{ + /// + /// Card hand representing the player's current hand, intended to be placed at the bottom edge of the screen. + /// This version of the card hand reacts to player inputs like hovering a card. + /// + public partial class PlayerHandOfCards : HandOfCards + { + /// + /// Fired if any card is selected or deselected + /// + public event Action? SelectionChanged; + + /// + /// Fired if a card's has changed + /// + public event Action? StateChanged; + + private HandSelectionMode selectionMode; + + /// + /// Current selection mode. + /// + /// + /// will disable some of the card's mouse interactions. + /// + public HandSelectionMode SelectionMode + { + get => selectionMode; + set + { + selectionMode = value; + allowSelection.Value = value != HandSelectionMode.Disabled; + + if (value == HandSelectionMode.Disabled) + { + foreach (var card in Cards) + card.Selected = false; + } + } + } + + private Action? playCardAction; + + /// + /// When set to non-null, displays a "Play" button on the selected card that invokes this action. + /// + public Action? PlayCardAction + { + get => playCardAction; + set + { + playCardAction = value; + + foreach (var card in Cards.OfType()) + card.PlayAction = value; + } + } + + private IEnumerable selection => Cards.OfType().Where(it => it.Selected); + + /// + /// Currently selected cards. + /// + public IEnumerable Selection => selection.Select(it => it.Card.Item); + + private readonly BindableBool allowSelection = new BindableBool(); + + private const int select_samples = 1; + private const int deselect_samples = 2; + + private Sample?[]? cardSelectSamples; + private Sample?[]? cardDeselectSamples; + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + cardSelectSamples = new Sample?[select_samples]; + for (int i = 0; i < select_samples; i++) + cardSelectSamples[i] = audio.Samples.Get(@$"Multiplayer/Matchmaking/Ranked/card-select-{i + 1}"); + + cardDeselectSamples = new Sample?[deselect_samples]; + for (int i = 0; i < deselect_samples; i++) + cardDeselectSamples[i] = audio.Samples.Get(@$"Multiplayer/Matchmaking/Ranked/card-deselect-{i + 1}"); + } + + protected override HandCard CreateHandCard(RankedPlayCard card) => new PlayerHandCard(card) + { + Clicked = cardClicked, + AllowSelection = allowSelection.GetBoundCopy(), + PlayAction = PlayCardAction, + }; + + private void cardClicked(PlayerHandCard card) + { + if (selectionMode == HandSelectionMode.Disabled) + return; + + try + { + if (selectionMode == HandSelectionMode.Single) + { + // only play feedback SFX if the selected card has changed + if (!card.Selected) + SamplePlaybackHelper.PlayWithRandomPitch(cardSelectSamples); + + foreach (var c in Cards) + { + ((PlayerHandCard)c).Selected = c == card; + } + + return; + } + + card.Selected = !card.Selected; + + SamplePlaybackHelper.PlayWithRandomPitch(card.Selected ? cardSelectSamples : cardDeselectSamples); + } + finally + { + SelectionChanged?.Invoke(); + } + } + + protected override void OnCardStateChanged(HandCard card, RankedPlayCardState state) + { + StateChanged?.Invoke(); + + base.OnCardStateChanged(card, state); + } + + public Dictionary State => Cards.Select(static card => new KeyValuePair(card.Item.Card.ID, card.State)).ToDictionary(); + + protected override bool OnKeyDown(KeyDownEvent e) + { + if (e.Repeat || Contracted) + return false; + + switch (e.Key) + { + case >= Key.Number1 and <= Key.Number9: + focusCard(e.Key - Key.Number1); + return true; + + case Key.Space: + if (selectionMode == HandSelectionMode.Disabled) + return false; + + if (Cards.FirstOrDefault(it => it.HasFocus) is not PlayerHandCard card) + return false; + + if (card.Selected) + card.PlayButton.TriggerClick(); + else + card.TriggerClick(); + + return true; + + case Key.Left: + moveCardFocus(-1); + return true; + + case Key.Right: + moveCardFocus(1); + return true; + } + + return base.OnKeyDown(e); + } + + private void moveCardFocus(int direction) + { + int currentIndex = Cards.ToList().FindIndex(c => c.HasFocus); + + // default behaviour is to start from either end of the cards if no card is focused currently + // in single-selection mode we can however use the current selection as a fallback index if there's no focus + if (selectionMode == HandSelectionMode.Single && currentIndex == -1) + currentIndex = Cards.ToList().FindIndex(c => c.Selected); + + int newIndex = currentIndex + direction; + + if (newIndex < 0) + newIndex = Cards.Count() - 1; + else if (newIndex >= Cards.Count()) + newIndex = 0; + + focusCard(newIndex); + } + + private void focusCard(int index) + { + var card = Cards.ElementAtOrDefault(index); + + if (card == null) + return; + + GetContainingFocusManager()?.ChangeFocus(card); + + if (SelectionMode == HandSelectionMode.Single && !card.Selected) + card.TriggerClick(); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/CoverReveal.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/CoverReveal.cs new file mode 100644 index 000000000000..fe25ab85016b --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/CoverReveal.cs @@ -0,0 +1,119 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Transforms; +using osu.Game.Graphics.Backgrounds; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro +{ + public partial class CoverReveal : CompositeDrawable + { + private readonly Container content; + private readonly Box bottomLayer; + private readonly Box middleLayer; + private readonly Box topLayer; + private readonly TrianglesV2 triangles; + + public CoverReveal(RankedPlayColourScheme colourScheme) + { + Padding = new MarginPadding { Horizontal = 100 }; + Masking = true; + + InternalChild = content = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = -50 }, + Children = + [ + new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = + [ + triangles = new TrianglesV2 + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.X, + ClampAxes = Axes.None, + Colour = ColourInfo.GradientHorizontal(Color4.White, Color4.White.Opacity(0)), + }, + bottomLayer = new Box + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Shear = new Vector2(-0.1f, 0), + Colour = ColourInfo.GradientVertical(colourScheme.PrimaryDarkest, colourScheme.PrimaryDarkest.Opacity(0)), + Alpha = 0.5f, + }, + middleLayer = new Box + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Shear = new Vector2(0.1f, 0), + Colour = ColourInfo.GradientVertical(colourScheme.PrimaryDarker, colourScheme.Primary.Opacity(0.5f)), + Alpha = 0.75f, + }, + topLayer = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourScheme.Primary, + Shear = new Vector2(-0.1f, 0) + }, + ] + }, + ] + }; + } + + protected override void Update() + { + base.Update(); + + Padding = new MarginPadding + { + Horizontal = -DrawHeight * 0.25f / 2 + }; + } + + public void Play() + { + content.MoveToX(50) + .MoveToX(-50, 4000); + + triangles.MoveToX(-0.75f, 3500, new CubicBezierEasingFunction(0.05, 1, 0, 1)) + .FadeOut(2000); + + topLayer.ResizeWidthTo(0.0f, 2800, new CubicBezierEasingFunction(0.05, 1, 0, 1)) + .TransformTo(nameof(Shear), new Vector2(0.1f, 0), 2800, Easing.OutPow10) + .Then() + .ResizeWidthTo(0, 500, Easing.InQuart); + + middleLayer + .Delay(50) + .ResizeWidthTo(0.15f, 2900, new CubicBezierEasingFunction(0.05, 1, 0, 1)) + .TransformTo(nameof(Shear), new Vector2(-0.15f, 0), 2900, Easing.OutPow10) + .Then() + .ResizeWidthTo(0, 500, Easing.InQuart) + .TransformTo(nameof(Shear), new Vector2(-0.25f, 0), 500, Easing.InCubic); + + bottomLayer + .Delay(100) + .ResizeWidthTo(0.2f, 3000, new CubicBezierEasingFunction(0.05, 1, 0, 1)) + .TransformTo(nameof(Shear), new Vector2(0.3f, 0), 3000, Easing.OutPow10) + .Then() + .ResizeWidthTo(0, 500, Easing.InQuart) + .TransformTo(nameof(Shear), new Vector2(0.5f, 0), 500, Easing.InCubic); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/IntroScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/IntroScreen.cs new file mode 100644 index 000000000000..87fac18026bb --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/IntroScreen.cs @@ -0,0 +1,123 @@ +// 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.Linq; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Database; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Overlays; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro +{ + public partial class IntroScreen : RankedPlaySubScreen + { + public IntroScreen() + { + CornerPieceVisibility.Value = Visibility.Hidden; + } + + [Resolved] + private UserLookupCache userLookupCache { get; set; } = null!; + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + [Resolved] + private MusicController? musicController { get; set; } + + private Sample? windupSample; + private Sample? impactSample; + private Sample? swooshSample; + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + windupSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/vs-windup"); + impactSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/vs-impact"); + swooshSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/vs-swoosh"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + loadUsers().FireAndForget(); + } + + private async Task loadUsers() + { + var roomState = ((RankedPlayRoomState)Client.Room!.MatchState!); + + int[] userIds = roomState.Users.Keys.ToArray(); + + var users = await userLookupCache.GetUsersAsync(userIds).ConfigureAwait(false); + + var player = users.OfType().First(it => it.Id == api.LocalUser.Value.Id); + var opponent = users.OfType().First(it => it.Id != api.LocalUser.Value.Id); + + int playerRating = roomState.Users[player.Id].Rating; + int opponentRating = roomState.Users[opponent.Id].Rating; + + Schedule(() => PlayIntroSequence( + new UserWithRating(player, playerRating), + new UserWithRating(opponent, opponentRating), + roomState.StarRating + )); + } + + private StarRatingSequence? starRatingAnimation; + + private IDisposable? duckOperation; + + public void PlayIntroSequence(UserWithRating player, UserWithRating opponent, double starRating) + { + double delay = 0; + + var vsScreen = new VsSequence(player, opponent); + + starRatingAnimation = new StarRatingSequence(); + + AddRangeInternal([vsScreen, starRatingAnimation]); + + vsScreen.Play(ref delay, out double impactDelay); + + duckOperation = musicController?.Duck(); + + if (windupSample != null) + { + Scheduler.AddDelayed(() => windupSample?.Play(), impactDelay - windupSample.Length); + Scheduler.AddDelayed(() => impactSample?.Play(), impactDelay); + Scheduler.AddDelayed(() => swooshSample?.Play(), impactDelay + 3200); + } + + Scheduler.AddDelayed(() => CornerPieceVisibility.Value = Visibility.Visible, delay); + + starRatingAnimation.Play(ref delay, (float)starRating); + } + + public override void OnExiting(RankedPlaySubScreen? next) + { + starRatingAnimation?.PopOut(); + + duckOperation?.Dispose(); + + this.Delay(500).FadeOut(); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + duckOperation?.Dispose(); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/StarRatingSequence.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/StarRatingSequence.cs new file mode 100644 index 000000000000..d4f64bdfc727 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/StarRatingSequence.cs @@ -0,0 +1,341 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transforms; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro +{ + public partial class StarRatingSequence : CompositeDrawable + { + private Container bars = null!; + private Container starContainer = null!; + private Container centerContainer = null!; + private OsuSpriteText title = null!; + private OsuSpriteText creatingMapPool = null!; + private OsuSpriteText explainer = null!; + + private Sample? tickSample; + private Sample? tickFinalSample; + private Sample? ratingFoundSample; + private Sample? noticeSample; + + private float lastTickStdDev; + + [BackgroundDependencyLoader] + private void load(OsuColour colour, AudioManager audio) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + Alpha = 0; + + Padding = new MarginPadding { Horizontal = 100 }; + + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = + [ + title = new OsuSpriteText + { + Text = "Finding Match Rating...", + Font = OsuFont.Style.Title, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + creatingMapPool = new OsuSpriteText + { + Text = "Creating a mappool...", + Font = OsuFont.Style.Heading1, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Margin = new MarginPadding { Bottom = 30 }, + Alpha = 0, + AlwaysPresent = true, + }, + centerContainer = new Container + { + RelativeSizeAxes = Axes.X, + Height = 90, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Children = + [ + bars = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 30 }, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + }, + ] + }, + starContainer = new Container + { + RelativeSizeAxes = Axes.X, + Height = 20, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + explainer = new OsuSpriteText + { + Text = "There’s still a chance that you get maps outside of the selected match rating!", + Font = OsuFont.Style.Heading2, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Margin = new MarginPadding { Top = 20 }, + Alpha = 0, + AlwaysPresent = true, + } + ], + }; + + for (int i = 0; i < 100; i++) + { + float difficulty = i / 10f; + + bars.Add(new Bar + { + StarRating = difficulty, + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.X, + X = difficulty / 10f, + Width = 0.0075f, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Colour = colour.ForStarDifficulty(Math.Max(difficulty, 0.1)), + Height = 0 + }); + + if (i > 0 && i % 10 == 0) + { + var starRatingDisplay = new StarRatingDisplay(new StarDifficulty(difficulty, 0), StarRatingDisplaySize.Small) + { + RelativePositionAxes = Axes.X, + X = difficulty / 10f, + Anchor = Anchor.CentreLeft, + Origin = Anchor.Centre, + Scale = new Vector2(0) + }; + + starContainer.Add(starRatingDisplay); + } + } + + tickSample = audio.Samples.Get("Multiplayer/Matchmaking/Ranked/star-rating-tick"); + tickFinalSample = audio.Samples.Get("Multiplayer/Matchmaking/Ranked/star-rating-tick-final"); + ratingFoundSample = audio.Samples.Get("Multiplayer/Matchmaking/Ranked/star-rating-found"); + noticeSample = audio.Samples.Get("Multiplayer/Matchmaking/Ranked/star-rating-notice"); + } + + private float starRating { get; set; } = 5; + + private float amplitude { get; set; } = 0; + + private float stdDev { get; set; } = 6; + + private bool animateGaussianCurve; + + public void Play(ref double delay, float starRating) + { + using (BeginDelayedSequence(delay)) + { + popIn(); + } + + delay += 500; + + using (BeginDelayedSequence(delay)) + { + Schedule(() => animateGaussianCurve = true); + + this.TransformTo(nameof(starRating), starRating < 5 ? starRating + 4 : starRating - 4); + this.TransformTo(nameof(starRating), starRating, 4000, new CubicBezierEasingFunction(easeIn: 0.3, easeOut: 0.5)); + this.TransformTo(nameof(amplitude), 1f, 4000, new CubicBezierEasingFunction(easeIn: 0.1, easeOut: 0.8)); + this.TransformTo(nameof(stdDev), 0.3f, 4500, new CubicBezierEasingFunction(easeIn: 0.2, easeOut: 0.7)); + } + + delay += 5000; + + using (BeginDelayedSequence(delay)) + { + Schedule(() => + { + animateGaussianCurve = false; + + ratingFoundSample?.Play(); + + var container = new FillFlowContainer + { + Direction = FillDirection.Horizontal, + Anchor = Anchor.TopLeft, + Origin = Anchor.BottomCentre, + AutoSizeAxes = Axes.Both, + RelativePositionAxes = Axes.X, + X = starRating * 0.1f, + Y = 24, + Colour = Color4Extensions.FromHex("#FFE280"), + Spacing = new Vector2(4, 0), + Children = + [ + new OsuSpriteText + { + Text = FormattableString.Invariant($"~{starRating:F2}"), + Font = OsuFont.GetFont(size: 24, weight: FontWeight.Bold), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new SpriteIcon + { + Icon = FontAwesome.Solid.Star, + Size = new Vector2(19), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + ] + }; + + centerContainer.Add(container); + + container.FadeInFromZero(200) + .ScaleTo(0) + .ScaleTo(1, 400, Easing.OutElasticQuarter); + + title.Text = "Match rating found!"; + + creatingMapPool.FadeIn(100); + explainer.Delay(1050).FadeIn(100); + Scheduler.AddDelayed(() => + { + noticeSample?.Play(); + }, 1050); + }); + } + } + + private void popIn() + { + this.FadeIn(200); + + foreach (var bar in bars) + { + double delay = Math.Abs(bar.StarRating - 5) * 50; + + bar.Delay(delay) + .ResizeHeightTo(0.1f, 300, Easing.OutExpo); + } + + foreach (var drawable in starContainer) + { + double delay = Math.Abs((drawable.X * 10) - 5) * 50 + 100; + + drawable.Delay(delay) + .ScaleTo(0.8f, 400, Easing.OutElasticQuarter); + } + } + + public void PopOut() + { + foreach (var bar in bars) + { + double delay = Math.Abs(bar.StarRating - 5) * 50; + + bar.Delay(delay) + .ResizeHeightTo(0f, 300, Easing.OutExpo); + } + + foreach (var drawable in starContainer) + { + double delay = Math.Abs((drawable.X * 10) - 5) * 50 + 100; + + drawable.Delay(delay) + .ScaleTo(0f, 400, Easing.OutElasticQuarter); + } + + this.FadeOut(150); + } + + protected override void Update() + { + base.Update(); + + if (!animateGaussianCurve) + return; + + foreach (var bar in bars) + { + float value = gaussianCurve(bar.StarRating, 1f, starRating, stdDev); + + bar.Height = float.Lerp(0.1f, 1f, value * amplitude); + + float targetAlpha = float.Clamp(0.35f + value * 20f, 0.35f, 1); + + bar.Alpha = float.Lerp(targetAlpha, bar.Alpha, (float)Math.Exp(-0.01f * Time.Elapsed)); + } + + foreach (var child in starContainer) + { + float value = gaussianCurve(child.X * 10f, 1f, starRating, stdDev); + + float targetAlpha = float.Clamp(0.35f + value * 20f, 0.35f, 1); + + child.Alpha = float.Lerp(targetAlpha, child.Alpha, (float)Math.Exp(-0.01f * Time.Elapsed)); + } + + static float gaussianCurve(float x, float amplitude, float center, float stdev) + { + float v1 = x - center; + float v2 = (v1 * v1) / (2 * (stdev * stdev)); + return amplitude * MathF.Exp(-v2); + } + + if (Math.Abs(lastTickStdDev - stdDev) <= 0.075) return; + + var tickChannel = tickSample!.GetChannel(); + tickChannel.Frequency.Value = 1 + amplitude * 0.3f; + tickChannel.Volume.Value = 0.5 + amplitude * 0.5; + tickChannel.Play(); + + if (stdDev < 1) + { + var tickFinalChannel = tickFinalSample!.GetChannel(); + tickFinalChannel.Frequency.Value = 1 + amplitude * 0.3f; + tickFinalChannel.Volume.Value = 0.1f + amplitude * 0.4f; + tickFinalChannel.Play(); + } + + lastTickStdDev = stdDev; + } + + private partial class Bar : CircularContainer + { + public required float StarRating; + + public Bar() + { + Masking = true; + InternalChild = new Box + { + RelativeSizeAxes = Axes.Both, + }; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/UserWithRating.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/UserWithRating.cs new file mode 100644 index 000000000000..584dea0a6ba4 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/UserWithRating.cs @@ -0,0 +1,9 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro +{ + public record UserWithRating(APIUser User, int Rating); +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/VsSequence.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/VsSequence.cs new file mode 100644 index 000000000000..b845c0031050 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/VsSequence.cs @@ -0,0 +1,325 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Graphics.Transforms; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Users.Drawables; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro +{ + public partial class VsSequence(UserWithRating player, UserWithRating opponent) : CompositeDrawable + { + private Drawable playerBackground = null!; + private Drawable opponentBackground = null!; + private Box flash = null!; + private Drawable playerDisplay = null!; + private Drawable opponentDisplay = null!; + private CoverReveal opponentCoverReveal = null!; + private CoverReveal playerCoverReveal = null!; + private VsText vsText = null!; + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + InternalChildren = + [ + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = -100 }, + Children = + [ + playerBackground = new DelayedLoadWrapper(() => new PlayerCover(player.User) + { + RelativeSizeAxes = Axes.Both, + }, timeBeforeLoad: 0) + { + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(0.5f), Color4.White.Opacity(0.85f)), + Alpha = 0, + AlwaysPresent = true, + }, + opponentBackground = new DelayedLoadWrapper(() => new PlayerCover(opponent.User) + { + RelativeSizeAxes = Axes.Both, + }, timeBeforeLoad: 0) + { + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(0.85f), Color4.White.Opacity(0.5f)), + Alpha = 0, + AlwaysPresent = true, + }, + ], + }, + playerDisplay = new UserDisplay(player, Anchor.BottomLeft) + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Margin = new MarginPadding(70), + Alpha = 0, + AlwaysPresent = true, + }, + opponentDisplay = new UserDisplay(opponent, Anchor.BottomRight) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.BottomLeft, + Margin = new MarginPadding(70), + Alpha = 0, + AlwaysPresent = true, + }, + opponentCoverReveal = new CoverReveal(RankedPlayColourScheme.Red) + { + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Scale = new Vector2(-1, 1), + Alpha = 0, + }, + playerCoverReveal = new CoverReveal(RankedPlayColourScheme.Blue) + { + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Alpha = 0, + }, + flash = new Box + { + RelativeSizeAxes = Axes.Both, + Blending = BlendingParameters.Additive, + Alpha = 0, + }, + vsText = new VsText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + ]; + } + + public void Play(ref double delay, out double impactDelay) + { + using (BeginDelayedSequence(delay)) + { + this.FadeInFromZero(500); + + vsText.AnimateEntry(1000, Easing.OutExpo); + vsText.ScaleTo(0.4f, 1300, Easing.OutExpo); + } + + delay += 850; + + impactDelay = delay; + + using (BeginDelayedSequence(delay)) + { + flash.FadeOutFromOne(500, Easing.Out); + + vsText.RevealText(); + + playerCoverReveal.FadeIn(); + opponentCoverReveal.FadeIn(); + + playerCoverReveal.Play(); + opponentCoverReveal.Play(); + + playerBackground + .FadeIn() + .MoveToX(-40) + .MoveToX(40, 3000, new CubicBezierEasingFunction(0, 0.3, 0, 0.65)) + .Then() + .MoveToX(100, 500, new CubicBezierEasingFunction(0.8, 0.05, 0.8, 0.8)); + + opponentBackground + .FadeIn() + .MoveToX(40) + .MoveToX(-40, 3000, new CubicBezierEasingFunction(0, 0.3, 0, 0.65)) + .Then() + .MoveToX(-100, 500, new CubicBezierEasingFunction(0.8, 0.05, 0.8, 0.8)); + + playerDisplay + .FadeIn() + .MoveToX(-400) + .MoveToX(-100, 3000, new CubicBezierEasingFunction(0, 0.3, 0, 0.75)) + .Then() + .MoveToX(800, 500, new CubicBezierEasingFunction(0.8, 0.05, 0.8, 0.8)); + + opponentDisplay + .FadeIn() + .MoveToX(400) + .MoveToX(100, 3000, new CubicBezierEasingFunction(0, 0.6, 0, 0.75)) + .Then() + .MoveToX(-800, 500, new CubicBezierEasingFunction(0.8, 0.05, 0.8, 0.8)); + + vsText.Delay(3200) + .ScaleTo(0.25f, 400, Easing.InCubic); + + this.Delay(3200).FadeOut(300).Expire(); + } + + delay += 3350; + } + + private partial class UserDisplay : CompositeDrawable + { + public UserDisplay(UserWithRating user, Anchor contentAnchor) + { + AutoSizeAxes = Axes.Both; + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10), + Children = + [ + new CircularContainer + { + Size = new Vector2(96), + Masking = true, + Anchor = contentAnchor, + Origin = contentAnchor, + Child = new DelayedLoadWrapper(() => new DrawableAvatar(user.User) + { + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fill, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, timeBeforeLoad: 0) + { + RelativeSizeAxes = Axes.Both, + } + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Anchor = contentAnchor, + Origin = contentAnchor, + Padding = new MarginPadding { Vertical = 10 }, + Children = + [ + new OsuSpriteText + { + Text = FormattableString.Invariant($"Rating: {user.Rating:N0}"), + Alpha = 0.8f, + Font = OsuFont.Style.Title.With(size: 26), + Anchor = contentAnchor, + Origin = contentAnchor, + }, + new OsuSpriteText + { + Text = user.User.Username, + Font = OsuFont.Style.Title.With(size: 40, weight: FontWeight.SemiBold), + Anchor = contentAnchor, + Origin = contentAnchor, + }, + ] + } + ] + }; + } + } + + [LongRunningLoad] + public partial class PlayerCover : CompositeDrawable + { + private readonly APIUser user; + + public PlayerCover(APIUser user) + { + this.user = user; + } + + [BackgroundDependencyLoader] + private void load(LargeTextureStore textures) + { + Masking = true; + + AddInternal(new Sprite + { + RelativeSizeAxes = Axes.Both, + Texture = textures.Get(user.CoverUrl), + FillMode = FillMode.Fill, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + this.FadeInFromZero(250); + } + } + + private partial class VsText : CompositeDrawable + { + private Sprite vsText = null!; + private LogoAnimation logoAnimation = null!; + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + AutoSizeAxes = Axes.Both; + + InternalChildren = + [ + vsText = new Sprite + { + Texture = textures.Get("Online/RankedPlay/vs"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + }, + logoAnimation = new LogoAnimation + { + Texture = textures.Get("Online/RankedPlay/vs-animation"), + }, + ]; + } + + public void AnimateEntry(double duration, Easing easing) + { + logoAnimation.TransformTo(nameof(logoAnimation.AnimationProgress), 1f, duration, easing); + } + + public void RevealText() + { + vsText.FadeIn(); + logoAnimation.FadeOut(); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/OpponentPickScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/OpponentPickScreen.cs new file mode 100644 index 000000000000..122b3ff8dd9a --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/OpponentPickScreen.cs @@ -0,0 +1,160 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Graphics; +using osu.Framework.Logging; +using osu.Game.Audio; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class OpponentPickScreen : RankedPlaySubScreen + { + public CardFlow CenterRow { get; private set; } = null!; + + private PlayerHandOfCards playerHand = null!; + private OpponentHandOfCards opponentHand = null!; + + [Resolved] + private RankedPlayMatchInfo matchInfo { get; set; } = null!; + + private const int card_play_samples = 2; + private Sample?[]? cardPlaySamples; + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + var matchState = Client.Room?.MatchState as RankedPlayRoomState; + + Debug.Assert(matchState != null); + + Children = + [ + CenterRow = new CardFlow + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new RankedPlayStageDisplay(RankedPlayColourScheme.Red) + { + Heading = "Pick Phase", + Caption = "Waiting for your opponent...", + Margin = new MarginPadding { Top = 60 }, + }, + ]; + + CenterColumn.Children = + [ + playerHand = new PlayerHandOfCards + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Y = 100, + HoverYOffset = 90 + }, + opponentHand = new OpponentHandOfCards + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + }, + new HandReplayRecorder(playerHand), + new HandReplayPlayer(matchInfo.OpponentId, opponentHand), + ]; + + cardPlaySamples = new Sample?[card_play_samples]; + for (int i = 0; i < card_play_samples; i++) + cardPlaySamples[i] = audio.Samples.Get($@"Multiplayer/Matchmaking/Ranked/card-play-{1 + i}"); + } + + public override void OnEntering(RankedPlaySubScreen? previous) + { + base.OnEntering(previous); + + foreach (var card in matchInfo.PlayerCards) + { + playerHand.AddCard(card, c => + { + c.Position = ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, DrawHeight), playerHand); + }); + } + + foreach (var card in matchInfo.OpponentCards) + { + opponentHand.AddCard(card, c => + { + c.Position = ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), playerHand); + }); + } + + playerHand.UpdateLayout(stagger: 50); + opponentHand.UpdateLayout(stagger: 50); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + matchInfo.CardPlayed += cardPlayed; + } + + private void cardPlayed(RankedPlayCardWithPlaylistItem item) => Task.Run(async () => + { + if (opponentHand.Cards.FirstOrDefault(it => it.Card.Item.Equals(item)) is { } c) + await c.Card.CardRevealed.ConfigureAwait(false); + + Schedule(() => + { + RankedPlayCard? card; + + if (opponentHand.RemoveCard(item, out card, out var drawQuad)) + { + card.MatchScreenSpaceDrawQuad(drawQuad, CenterRow); + } + else + { + Logger.Log($"Played card {item.Card.ID} was not present in hand.", level: LogLevel.Error); + + card = new RankedPlayCard(item) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + + CenterRow.Add(card); + + SamplePlaybackHelper.PlayWithRandomPitch(cardPlaySamples); + + card + .MoveTo(new Vector2(0), 600, Easing.OutExpo) + .ScaleTo(CENTERED_CARD_SCALE, 600, Easing.OutExpo) + .RotateTo(0, 400, Easing.OutExpo); + + opponentHand.Contract(); + playerHand.Contract(); + }); + }); + + protected override void Dispose(bool isDisposing) + { + matchInfo.CardPlayed -= cardPlayed; + + base.Dispose(isDisposing); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs new file mode 100644 index 000000000000..2f59e22b0f37 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs @@ -0,0 +1,267 @@ +// 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.Diagnostics; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Graphics; +using osu.Framework.Logging; +using osu.Game.Audio; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.RankedPlay; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class PickScreen : RankedPlaySubScreen + { + // When the 'time running out' warning sample starts to play (in remaining seconds) + private const int warning_time_threshold = 10; + + public CardFlow CenterRow { get; private set; } = null!; + + private PlayerHandOfCards playerHand = null!; + private OpponentHandOfCards opponentHand = null!; + + [Resolved] + private RankedPlayMatchInfo matchInfo { get; set; } = null!; + + private Sample? cardAddSample; + + private const int card_play_samples = 2; + private Sample?[]? cardPlaySamples; + + private bool timeRunningOutWarningActive; + private Sample? timeRunningOutSample; + private SampleChannel? timeRunningOutSampleChannel; + private Sample? timeUpBuzzerSample; + + private DateTimeOffset stageEndTime; + + /// + /// Whether the local user has played a card themselves. + /// + private bool hasPlayedCard; + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + var matchState = Client.Room?.MatchState as RankedPlayRoomState; + + Debug.Assert(matchState != null); + + Children = + [ + CenterRow = new CardFlow + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new RankedPlayStageDisplay(RankedPlayColourScheme.Blue) + { + Heading = "Pick Phase", + Caption = "It's your turn to play a card!", + Margin = new MarginPadding { Top = 60 }, + }, + ]; + + CenterColumn.Children = + [ + playerHand = new PlayerHandOfCards + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + SelectionMode = HandSelectionMode.Single, + PlayCardAction = onPlayButtonClicked + }, + opponentHand = new OpponentHandOfCards + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Y = -100, + }, + new HandReplayRecorder(playerHand), + new HandReplayPlayer(matchInfo.OpponentId, opponentHand), + ]; + + cardAddSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/card-add-1"); + + cardPlaySamples = new Sample?[card_play_samples]; + for (int i = 0; i < card_play_samples; i++) + cardPlaySamples[i] = audio.Samples.Get($@"Multiplayer/Matchmaking/Ranked/card-play-{1 + i}"); + + timeRunningOutSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/time-running-out"); + timeUpBuzzerSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/time-up"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + matchInfo.CardPlayed += cardPlayed; + + Client.CountdownStarted += onCountdownStarted; + Client.CountdownStopped += onCountdownStopped; + + if (Client.Room != null) + { + foreach (var countdown in Client.Room.ActiveCountdowns) + onCountdownStarted(countdown); + } + } + + protected override void Update() + { + base.Update(); + + TimeSpan remainingTime = stageEndTime - DateTimeOffset.Now; + + if (timeRunningOutWarningActive && remainingTime.TotalSeconds < warning_time_threshold) + { + timeRunningOutSampleChannel ??= timeRunningOutSample?.GetChannel(); + + if (timeRunningOutSampleChannel == null || timeRunningOutSampleChannel.Playing) + return; + + timeRunningOutSampleChannel.ManualFree = true; + timeRunningOutSampleChannel.Looping = true; + timeRunningOutSampleChannel.Play(); + } + } + + public override void OnEntering(RankedPlaySubScreen? previous) + { + base.OnEntering(previous); + + int delay = 0; + + foreach (var item in matchInfo.PlayerCards) + { + if ((previous as DiscardScreen)?.CenterRow.RemoveCard(item, out var card, out var drawQuad) == true) + { + playerHand.AddCard(card, c => + { + c.MatchScreenSpaceDrawQuad(drawQuad, playerHand); + }); + } + else + { + playerHand.AddCard(item, c => + { + c.Position = ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, DrawHeight), playerHand); + }); + Scheduler.AddDelayed(() => + { + SamplePlaybackHelper.PlayWithRandomPitch(cardAddSample); + }, 50 * delay); + delay++; + } + } + + foreach (var item in matchInfo.OpponentCards) + { + opponentHand.AddCard(item, c => + { + c.Position = ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), playerHand); + }); + } + + playerHand.UpdateLayout(stagger: 50); + opponentHand.UpdateLayout(stagger: 50); + } + + private void onCountdownStarted(MultiplayerCountdown countdown) => Scheduler.Add(() => + { + if (countdown is not RankedPlayStageCountdown stageCountdown) + return; + + stageEndTime = DateTimeOffset.Now + countdown.TimeRemaining; + timeRunningOutWarningActive = stageCountdown.Stage == RankedPlayStage.CardPlay; + }); + + private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add(() => + { + if (countdown is not RankedPlayStageCountdown stageCountdown) + return; + + timeRunningOutSampleChannel?.Stop(); + + stageEndTime = DateTimeOffset.Now; + timeRunningOutWarningActive = false; + + if (stageCountdown.Stage == RankedPlayStage.CardPlay && !hasPlayedCard) + timeUpBuzzerSample?.Play(); + }); + + private void onPlayButtonClicked() + { + var selection = playerHand.Selection.SingleOrDefault(); + + if (selection != null) + { + hasPlayedCard = true; + playerHand.SelectionMode = HandSelectionMode.Disabled; + + Client.PlayCard(selection.Card).FireAndForget(); + } + + playerHand.PlayCardAction = null; + } + + private void cardPlayed(RankedPlayCardWithPlaylistItem item) + { + RankedPlayCard? card; + + if (playerHand.RemoveCard(item, out card, out var drawQuad)) + { + card.MatchScreenSpaceDrawQuad(drawQuad, CenterRow); + } + else + { + Logger.Log($"Played card {item.Card.ID} was not present in hand.", level: LogLevel.Error); + + card = new RankedPlayCard(item) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + + CenterRow.Add(card); + + card + .MoveTo(new Vector2(0), 600, Easing.OutExpo) + .ScaleTo(CENTERED_CARD_SCALE, 600, Easing.OutExpo) + .RotateTo(0, 400, Easing.OutExpo); + + SamplePlaybackHelper.PlayWithRandomPitch(cardPlaySamples); + + opponentHand.Contract(); + playerHand.Contract(); + + playerHand.SelectionMode = HandSelectionMode.Disabled; + } + + protected override void Dispose(bool isDisposing) + { + timeRunningOutSampleChannel?.Stop(); + timeRunningOutSampleChannel?.Dispose(); + + matchInfo.CardPlayed -= cardPlayed; + + base.Dispose(isDisposing); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayBackground.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayBackground.cs new file mode 100644 index 000000000000..c6316e1fb101 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayBackground.cs @@ -0,0 +1,213 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Runtime.InteropServices; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Shaders; +using osu.Framework.Graphics.Shaders.Types; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Utils; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class RankedPlayBackground : CompositeDrawable, IBufferedDrawable + { + public float GridSize = 10; + + public IShader? TextureShader { get; private set; } + public Color4 BackgroundColour => Color4.Black; + public DrawColourInfo? FrameBufferDrawColour => null; + public Vector2 FrameBufferScale => new Vector2(0.1f); + + public Color4 GradientOutside = Color4Extensions.FromHex("AC6D97"); + public Color4 GradientInside = Color4Extensions.FromHex("544483"); + public Color4 DotsColour = Color4Extensions.FromHex("6b2980"); + + public RankedPlayBackground() + { + InternalChildren = + [ + new Triangles + { + RelativeSizeAxes = Axes.Both, + }, + ]; + } + + [BackgroundDependencyLoader] + private void load(ShaderManager shaders) + { + TextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, @"RankedPlayBackground"); + } + + private readonly BufferedDrawNodeSharedData sharedData = new BufferedDrawNodeSharedData(); + + protected override void Update() + { + base.Update(); + + Invalidate(Invalidation.DrawNode); + } + + protected override DrawNode CreateDrawNode() => new RankedPlayBackgroundDrawNode(this, sharedData); + + protected override void Dispose(bool isDisposing) + { + sharedData.Dispose(); + + base.Dispose(isDisposing); + } + + private class RankedPlayBackgroundDrawNode : BufferedDrawNode, ICompositeDrawNode + { + protected new RankedPlayBackground Source => (RankedPlayBackground)base.Source; + + protected new CompositeDrawableDrawNode Child => (CompositeDrawableDrawNode)base.Child; + + public RankedPlayBackgroundDrawNode(RankedPlayBackground source, BufferedDrawNodeSharedData sharedData) + : base(source, new CompositeDrawableDrawNode(source), sharedData) + { + } + + private Vector2 drawSize; + private float time; + private float gridSize; + private Color4 gradientOutside; + private Color4 gradientInside; + private Color4 dotsColour; + + private IUniformBuffer? shaderParameterBuffer; + + public override void ApplyState() + { + base.ApplyState(); + + time = (float)(Source.Time.Current / 1000); + drawSize = Source.DrawSize; + gridSize = Source.GridSize; + gradientOutside = Source.GradientOutside; + gradientInside = Source.GradientInside; + dotsColour = Source.DotsColour; + } + + protected override void BindUniformResources(IShader shader, IRenderer renderer) + { + shaderParameterBuffer ??= renderer.CreateUniformBuffer(); + + shaderParameterBuffer.Data = new RankedPlayBackgroundParameters + { + DrawSize = drawSize, + Time = time, + GridSize = gridSize, + GradientOutside = new Vector4(gradientOutside.R, gradientOutside.G, gradientOutside.B, gradientOutside.A), + GradientInside = new Vector4(gradientInside.R, gradientInside.G, gradientInside.B, gradientInside.A), + DotsColour = new Vector4(dotsColour.R, dotsColour.G, dotsColour.B, dotsColour.A), + }; + + shader.BindUniformBlock("m_RankedPlayBackgroundParameters", shaderParameterBuffer); + } + + public List? Children + { + get => Child.Children; + set => Child.Children = value; + } + + public bool AddChildDrawNodes => RequiresRedraw; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private record struct RankedPlayBackgroundParameters + { + public UniformVector2 DrawSize; + public UniformFloat Time; + public UniformFloat GridSize; + public UniformVector4 GradientOutside; + public UniformVector4 GradientInside; + public UniformVector4 DotsColour; + } + } + + public partial class Triangles : CompositeDrawable + { + private Texture triangleTexture = null!; + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + triangleTexture = textures.Get("Online/RankedPlay/triangle"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + for (int i = 0; i < 20; i++) + { + AddInternal(new Triangle + { + Texture = triangleTexture, + RelativePositionAxes = Axes.Both, + X = RNG.NextSingle(), + Y = -0.2f + RNG.NextSingle() * 1.4f, + Origin = Anchor.Centre, + Rotation = RNG.NextSingle() * 360, + AngularVelocity = RNG.NextSingle() - 0.75f, + Size = new Vector2(100 + RNG.NextSingle() * 1000), + MovementSpeed = 0.25f + RNG.NextSingle() * 0.75f, + Alpha = 0.5f + RNG.NextSingle() * 0.5f, + }); + } + } + + public float ParticleVelocity = 1; + + protected override void Update() + { + base.Update(); + + if (DrawHeight <= 0) + return; + + float baseVelocity = 0.03f * ParticleVelocity / DrawHeight; + float elapsed = (float)Time.Elapsed; + + foreach (var c in InternalChildren) + { + var triangle = (Triangle)c; + + triangle.Y -= baseVelocity * elapsed * triangle.MovementSpeed; + + triangle.Rotation += triangle.AngularVelocity * elapsed * 0.02f; + + // wrap vertically + if (triangle.Y < -0.2f) + { + triangle.X = RNG.NextSingle(); + triangle.Y = 1.2f; + triangle.Alpha = 0.5f + RNG.NextSingle() * 0.5f; + } + else if (triangle.Y > 1.2f) + { + triangle.X = RNG.NextSingle(); + triangle.Y = -0.2f; + triangle.Alpha = 0.5f + RNG.NextSingle() * 0.5f; + } + } + } + + private partial class Triangle : Sprite + { + public float MovementSpeed = 1; + public float AngularVelocity; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayBackgroundScreen.cs new file mode 100644 index 000000000000..72224b876ed2 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayBackgroundScreen.cs @@ -0,0 +1,110 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transforms; +using osu.Game.Beatmaps; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class RankedPlayBackgroundScreen : BackgroundScreen + { + public RankedPlayBackground Background { get; } + + [Resolved] + private Bindable beatmap { get; set; } = null!; + + public Bindable ShowBeatmapBackground { get; } = new BindableBool(); + + public RankedPlayBackgroundScreen() + { + InternalChild = Background = new RankedPlayBackground + { + RelativeSizeAxes = Axes.Both, + GradientOutside = Color4Extensions.FromHex("716BE0"), + GradientInside = Color4Extensions.FromHex("#71308F"), + DotsColour = Color4Extensions.FromHex("#CC46F6").Opacity(0.5f), + }; + } + + private CancellationTokenSource? pendingBackgroundLoad; + private BeatmapBackground? currentBackground; + + protected override void LoadComplete() + { + base.LoadComplete(); + + beatmap.BindValueChanged(_ => updateBackground()); + ShowBeatmapBackground.BindValueChanged(_ => updateBackground()); + updateBackground(); + } + + private void updateBackground() + { + pendingBackgroundLoad?.Cancel(); + + if (beatmap.Value == null || !ShowBeatmapBackground.Value) + { + currentBackground?.PopOut().Expire(); + currentBackground = null; + return; + } + + pendingBackgroundLoad = new CancellationTokenSource(); + + LoadComponentAsync(new BeatmapBackground(beatmap.Value), background => + { + currentBackground?.PopOut().Expire(); + + AddInternal(background); + currentBackground = background; + + background.PopIn(); + }, pendingBackgroundLoad.Token); + } + + [LongRunningLoad] + private partial class BeatmapBackground(WorkingBeatmap beatmap) : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + InternalChild = new BufferedContainer(cachedFrameBuffer: true) + { + RelativeSizeAxes = Axes.Both, + FrameBufferScale = new Vector2(0.15f), + GrayscaleStrength = 0.3f, + BlurSigma = new Vector2(5), + Colour = Color4Extensions.FromHex("#cccccc"), + Child = new Sprite + { + RelativeSizeAxes = Axes.Both, + Texture = beatmap.GetBackground(), + FillMode = FillMode.Fill, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + } + + public void PopIn() => this.FadeOut() + .FadeTo(0.4f, 300) + .ScaleTo(1.2f) + .ScaleTo(1f, 600, Easing.OutExpo); + + public TransformSequence PopOut() => + this.FadeOut(300).ScaleTo(1.1f, 600, Easing.OutExpo); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayCardWithPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayCardWithPlaylistItem.cs new file mode 100644 index 000000000000..71ef9ee9db38 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayCardWithPlaylistItem.cs @@ -0,0 +1,30 @@ +// 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 osu.Framework.Bindables; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.Rooms; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public class RankedPlayCardWithPlaylistItem : IEquatable + { + public readonly Bindable PlaylistItem = new Bindable(); + public readonly RankedPlayCardItem Card; + + public RankedPlayCardWithPlaylistItem(RankedPlayCardItem card) + { + Card = card; + } + + public bool Equals(RankedPlayCardWithPlaylistItem? other) + => other != null && Card.Equals(other.Card); + + public override bool Equals(object? obj) + => obj is RankedPlayCardWithPlaylistItem other && Equals(other); + + public override int GetHashCode() + => Card.GetHashCode(); + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayColourScheme.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayColourScheme.cs new file mode 100644 index 000000000000..89b95d061186 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayColourScheme.cs @@ -0,0 +1,35 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Extensions.Color4Extensions; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public class RankedPlayColourScheme + { + public required Color4 Primary; + public required Color4 PrimaryDarker; + public required Color4 PrimaryDarkest; + public required Color4 Surface; + public required Color4 SurfaceBorder; + + public static RankedPlayColourScheme Blue => new RankedPlayColourScheme + { + Primary = Color4Extensions.FromHex("5EBFFF"), + PrimaryDarker = Color4Extensions.FromHex("4382FF"), + PrimaryDarkest = Color4Extensions.FromHex("5C55FF"), + Surface = Color4Extensions.FromHex("33303D"), + SurfaceBorder = Color4Extensions.FromHex("514c5e"), + }; + + public static RankedPlayColourScheme Red => new RankedPlayColourScheme + { + Primary = Color4Extensions.FromHex("FF8198"), + PrimaryDarker = Color4Extensions.FromHex("F94D92"), + PrimaryDarkest = Color4Extensions.FromHex("B6104D"), + Surface = Color4Extensions.FromHex("242023"), + SurfaceBorder = Color4Extensions.FromHex("403b3f"), + }; + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayMatchInfo.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayMatchInfo.cs new file mode 100644 index 000000000000..657fbb13808d --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayMatchInfo.cs @@ -0,0 +1,176 @@ +// 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.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class RankedPlayMatchInfo : Component + { + /// + /// Cards belonging to the player. + /// + public IReadOnlyList PlayerCards => playerCards; + + /// + /// Cards belonging to the opponent. + /// + public IReadOnlyList OpponentCards => opponentCards; + + /// + /// The last card that was played. + /// + public RankedPlayCardWithPlaylistItem? LastPlayedCard { get; private set; } + + /// + /// The current room stage. + /// + public IBindable Stage => stage; + + /// + /// Fired when a card gets added to the player's hand. + /// + public event Action? PlayerCardAdded; + + /// + /// Fired when a card gets removed from the player's hand, i.e. by being discarded. + /// + public event Action? PlayerCardRemoved; + + /// + /// Fired when a card gets added to the opponent's hand. + /// + public event Action? OpponentCardAdded; + + /// + /// Fired when a card gets removed from the player's hand, i.e. by being discarded. + /// + public event Action? OpponentCardRemoved; + + /// + /// Fired when the active player plays a card. + /// + public event Action? CardPlayed; + + /// + /// The player's health + /// + public readonly BindableInt PlayerHealth = new BindableInt { MinValue = 0, MaxValue = 1_000_000, Value = 1_000_000 }; + + /// + /// The opponent's health + /// + public readonly BindableInt OpponentHealth = new BindableInt { MinValue = 0, MaxValue = 1_000_000, Value = 1_000_000 }; + + public RankedPlayRoomState RoomState { get; private set; } = null!; + + public bool IsOwnTurn => RoomState.ActiveUserId == client.LocalUser?.UserID; + + public int CurrentRound => RoomState.CurrentRound; + + public int OpponentId => RoomState.Users.Keys.Single(u => u != client.LocalUser?.UserID); + + private readonly List playerCards = new List(); + private readonly List opponentCards = new List(); + private readonly Bindable stage = new Bindable(); + + [Resolved] + private MultiplayerClient client { get; set; } = null!; + + private APIUser player = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + player = client.LocalUser!.User!; + + client.MatchRoomStateChanged += onMatchRoomStateChanged; + client.RankedPlayCardAdded += onCardAdded; + client.RankedPlayCardRemoved += onCardRemoved; + client.RankedPlayCardPlayed += onCardPlayed; + + var roomState = (RankedPlayRoomState)client.Room!.MatchState!; + + onMatchRoomStateChanged(roomState); + + foreach (var (userId, user) in roomState.Users) + { + foreach (var card in user.Hand) + { + onCardAdded(userId, client.GetCardWithPlaylistItem(card)); + } + } + } + + private void onMatchRoomStateChanged(MatchRoomState state) + { + if (state is not RankedPlayRoomState roomState) + return; + + RoomState = roomState; + + stage.Value = roomState.Stage; + + foreach (var (userId, userInfo) in roomState.Users) + { + if (userId == player.Id) + PlayerHealth.Value = userInfo.Life; + else + OpponentHealth.Value = userInfo.Life; + } + } + + private void onCardAdded(int userId, RankedPlayCardWithPlaylistItem item) + { + if (userId == player.Id) + { + playerCards.Add(item); + PlayerCardAdded?.Invoke(item); + } + else + { + opponentCards.Add(item); + OpponentCardAdded?.Invoke(item); + } + } + + private void onCardRemoved(int userId, RankedPlayCardWithPlaylistItem item) + { + if (userId == player.Id) + { + playerCards.Remove(item); + PlayerCardRemoved?.Invoke(item); + } + else + { + opponentCards.Remove(item); + OpponentCardRemoved?.Invoke(item); + } + } + + private void onCardPlayed(RankedPlayCardWithPlaylistItem item) + { + LastPlayedCard = item; + CardPlayed?.Invoke(item); + } + + protected override void Dispose(bool isDisposing) + { + client.MatchRoomStateChanged -= onMatchRoomStateChanged; + client.RankedPlayCardAdded -= onCardAdded; + client.RankedPlayCardRemoved -= onCardRemoved; + client.RankedPlayCardPlayed -= onCardPlayed; + + base.Dispose(isDisposing); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayScreen.cs new file mode 100644 index 000000000000..c61a8e1fc57c --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayScreen.cs @@ -0,0 +1,535 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics; +using System.Linq; +using System.Threading; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Logging; +using osu.Framework.Screens; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Database; +using osu.Game.Graphics.Cursor; +using osu.Game.Online; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.Rooms; +using osu.Game.Overlays; +using osu.Game.Overlays.Dialog; +using osu.Game.Overlays.Volume; +using osu.Game.Rulesets; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match.Gameplay; +using osu.Game.Screens.OnlinePlay.Matchmaking.Queue; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro; +using osu.Game.Screens.OnlinePlay.Multiplayer; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + [Cached] + public partial class RankedPlayScreen : OsuScreen, IPreviewTrackOwner, IHandlePresentBeatmap + { + protected override bool InitialBackButtonVisibility => false; + + public override bool HideOverlaysOnEnter => true; + + public RankedPlaySubScreen? ActiveSubScreen { get; private set; } + + protected override BackgroundScreen CreateBackground() => new RankedPlayBackgroundScreen + { + ShowBeatmapBackground = { BindTarget = showBeatmapBackground } + }; + + public override float BackgroundParallaxAmount => 0; + + [Cached(typeof(OnlinePlayBeatmapAvailabilityTracker))] + private readonly OnlinePlayBeatmapAvailabilityTracker beatmapAvailabilityTracker = new MultiplayerBeatmapAvailabilityTracker(); + + [Resolved] + private MultiplayerClient client { get; set; } = null!; + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + [Resolved] + private BeatmapManager beatmapManager { get; set; } = null!; + + [Resolved] + private RulesetStore rulesets { get; set; } = null!; + + [Resolved] + private BeatmapLookupCache beatmapLookupCache { get; set; } = null!; + + [Resolved] + private BeatmapModelDownloader beatmapDownloader { get; set; } = null!; + + [Resolved] + private IDialogOverlay dialogOverlay { get; set; } = null!; + + [Resolved] + private AudioManager audio { get; set; } = null!; + + [Resolved] + private OsuConfigManager config { get; set; } = null!; + + [Resolved] + private PreviewTrackManager previewTrackManager { get; set; } = null!; + + [Resolved] + private MusicController music { get; set; } = null!; + + [Resolved] + private QueueController? controller { get; set; } + + private readonly MultiplayerRoom room; + private readonly Container screenContainer; + private readonly MatchmakingChatDisplay chat; + + private IBindable stage = null!; + + private Sample? sampleStart; + private CancellationTokenSource? downloadCheckCancellation; + private int? lastDownloadCheckedBeatmapId; + + private readonly Bindable cornerPieceVisibility = new Bindable(); + private readonly Bindable showBeatmapBackground = new Bindable(); + + [Cached] + private readonly RankedPlayMatchInfo matchInfo; + + [Cached] + private readonly CardDetailsOverlayContainer overlayContainer; + + [Cached] + private readonly SongPreviewParticleContainer particleContainer; + + public RankedPlayScreen(MultiplayerRoom room) + { + this.room = room; + + InternalChildren = new Drawable[] + { + matchInfo = new RankedPlayMatchInfo(), + beatmapAvailabilityTracker, + new GlobalScrollAdjustsVolume(), + new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + Child = new OsuContextMenuContainer + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + screenContainer = new Container + { + RelativeSizeAxes = Axes.Both, + }, + chat = new MatchmakingChatDisplay(new Room(room)) + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Size = new Vector2(320, 160), + Margin = new MarginPadding + { + Bottom = 10, + Right = 10 + }, + Alpha = 0, + }, + new HamburgerMenu + { + Size = new Vector2(56), + } + } + } + }, + overlayContainer = new CardDetailsOverlayContainer(), + particleContainer = new SongPreviewParticleContainer(), + }; + } + + [BackgroundDependencyLoader] + private void load() + { + stage = matchInfo.Stage.GetBoundCopy(); + sampleStart = audio.Samples.Get(@"SongSelect/confirm-selection"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + client.RoomUpdated += onRoomUpdated; + client.UserStateChanged += onUserStateChanged; + client.SettingsChanged += onSettingsChanged; + client.LoadRequested += onLoadRequested; + + beatmapAvailabilityTracker.Availability.BindValueChanged(onBeatmapAvailabilityChanged, true); + + int localUserId = api.LocalUser.Value.OnlineID; + int opponentUserId = ((RankedPlayRoomState)client.Room!.MatchState!).Users.Keys.Single(it => it != localUserId); + + AddRangeInternal([ + new RankedPlayCornerPiece(RankedPlayColourScheme.Blue, Anchor.BottomLeft) + { + State = { BindTarget = cornerPieceVisibility }, + Child = new RankedPlayUserDisplay(localUserId, Anchor.BottomLeft, RankedPlayColourScheme.Blue) + { + RelativeSizeAxes = Axes.Both, + Health = { BindTarget = matchInfo.PlayerHealth } + } + }, + new RankedPlayCornerPiece(RankedPlayColourScheme.Red, Anchor.TopRight) + { + State = { BindTarget = cornerPieceVisibility }, + Child = new RankedPlayUserDisplay(opponentUserId, Anchor.TopRight, RankedPlayColourScheme.Red) + { + RelativeSizeAxes = Axes.Both, + Health = { BindTarget = matchInfo.OpponentHealth } + } + }, + ]); + + cornerPieceVisibility.BindValueChanged(e => + { + if (e.NewValue == Visibility.Visible) + chat.Appear(); + else + chat.Disappear(); + }); + + stage.BindValueChanged(e => onStageChanged(e.NewValue)); + } + + public void ShowScreen(RankedPlaySubScreen screen) + { + if (screen == ActiveSubScreen) + return; + + LoadComponent(screen); + + var previousScreen = ActiveSubScreen; + + screenContainer.Add(ActiveSubScreen = screen); + screen.OnLoadComplete += _ => + { + previousScreen?.OnExiting(screen); + screen.OnEntering(previousScreen); + previousScreen?.Expire(); + + if (previousScreen != null) + cornerPieceVisibility.UnbindFrom(previousScreen.CornerPieceVisibility); + + cornerPieceVisibility.BindTo(screen.CornerPieceVisibility); + showBeatmapBackground.Value = screen.ShowBeatmapBackground; + }; + } + + private void onRoomUpdated() + { + if (this.IsCurrentScreen() && client.Room == null) + { + Logger.Log($"{this} exiting due to loss of room or connection"); + exitConfirmed = true; + this.Exit(); + } + } + + private void onUserStateChanged(MultiplayerRoomUser user, MultiplayerUserState state) + { + if (user.Equals(client.LocalUser) && state == MultiplayerUserState.Idle) + this.MakeCurrent(); + } + + private void onSettingsChanged(MultiplayerRoomSettings _) => Scheduler.Add(() => + { + checkForAutomaticDownload(); + updateGameplayState(); + }); + + private void onLoadRequested() => Scheduler.Add(() => + { + updateGameplayState(); + + if (Beatmap.IsDefault) + { + Logger.Log("Aborting gameplay start - beatmap not downloaded."); + return; + } + + sampleStart?.Play(); + + this.Push(new MultiplayerPlayerLoader(() => new ScreenGameplay(new Room(room), new PlaylistItem(client.Room!.CurrentPlaylistItem), room.Users.ToArray()))); + }); + + private void onStageChanged(RankedPlayStage stage) + { + switch (stage) + { + case RankedPlayStage.RoundWarmup when matchInfo.CurrentRound == 1: + ShowScreen(new IntroScreen()); + break; + + case RankedPlayStage.CardDiscard: + ShowScreen(new DiscardScreen()); + break; + + case RankedPlayStage.FinishCardDiscard: + (ActiveSubScreen as DiscardScreen)?.PresentRemainingCards(); + break; + + case RankedPlayStage.CardPlay: + ShowScreen(matchInfo.IsOwnTurn ? new PickScreen() : new OpponentPickScreen()); + break; + + case RankedPlayStage.FinishCardPlay: + Debug.Assert(ActiveSubScreen is PickScreen || ActiveSubScreen is OpponentPickScreen); + break; + + case RankedPlayStage.GameplayWarmup: + ShowScreen(new GameplayWarmupScreen()); + break; + + case RankedPlayStage.Gameplay: + ShowScreen(new GameplayScreen()); + break; + + case RankedPlayStage.Results: + ShowScreen(new ResultsScreen()); + break; + + case RankedPlayStage.Ended: + ShowScreen(new EndedScreen + { + ExitRequested = retry => + { + retryRequested = retry; + exitConfirmed = true; + + if (this.IsCurrentScreen()) + this.Exit(); + } + }); + break; + } + } + + private void onBeatmapAvailabilityChanged(ValueChangedEvent e) => Scheduler.Add(() => + { + if (client.Room == null || client.LocalUser == null) + return; + + client.ChangeBeatmapAvailability(e.NewValue).FireAndForget(); + + switch (e.NewValue.State) + { + case DownloadState.NotDownloaded: + case DownloadState.LocallyAvailable: + updateGameplayState(); + break; + } + }); + + private void updateGameplayState() + { + MultiplayerPlaylistItem item = client.Room!.CurrentPlaylistItem; + + if (item.Expired) + return; + + RulesetInfo ruleset = rulesets.GetRuleset(item.RulesetID)!; + Ruleset rulesetInstance = ruleset.CreateInstance(); + + // Update global gameplay state to correspond to the new selection. + // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info + var localBeatmap = beatmapManager.QueryBeatmap($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", item.BeatmapID); + + if (localBeatmap != null) + { + Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); + Ruleset.Value = ruleset; + Mods.Value = item.RequiredMods.Select(m => m.ToMod(rulesetInstance)).ToArray(); + + // Notify the server that the beatmap has been set and that we are ready to start gameplay. + if (client.LocalUser!.State == MultiplayerUserState.Idle) + client.ChangeState(MultiplayerUserState.Ready).FireAndForget(); + } + else + { + // Notify the server that we don't have the beatmap. + if (client.LocalUser!.State == MultiplayerUserState.Ready) + client.ChangeState(MultiplayerUserState.Idle).FireAndForget(); + } + + client.ChangeBeatmapAvailability(beatmapAvailabilityTracker.Availability.Value).FireAndForget(); + } + + private void checkForAutomaticDownload() + { + if (client.Room == null) + return; + + MultiplayerPlaylistItem item = client.Room.CurrentPlaylistItem; + + // This method is called every time anything changes in the room. + // This could result in download requests firing far too often, when we only expect them to fire once per beatmap. + // + // Without this check, we would see especially egregious behaviour when a user has hit the download rate limit. + if (lastDownloadCheckedBeatmapId == item.BeatmapID) + return; + + lastDownloadCheckedBeatmapId = item.BeatmapID; + + downloadCheckCancellation?.Cancel(); + + if (beatmapManager.IsAvailableLocally(new APIBeatmap { OnlineID = item.BeatmapID })) + return; + + // In a perfect world we'd use BeatmapAvailability, but there's no event-driven flow for when a selection changes. + // ie. if selection changes from "not downloaded" to another "not downloaded" we wouldn't get a value changed raised. + beatmapLookupCache + .GetBeatmapAsync(item.BeatmapID, (downloadCheckCancellation = new CancellationTokenSource()).Token) + .ContinueWith(resolved => Schedule(() => + { + APIBeatmapSet? beatmapSet = resolved.GetResultSafely()?.BeatmapSet; + + if (beatmapSet == null) + return; + + beatmapDownloader.Download(beatmapSet, config.Get(OsuSetting.PreferNoVideo)); + })); + } + + public override void OnEntering(ScreenTransitionEvent e) + { + base.OnEntering(e); + + beginHandlingTrack(); + } + + public override void OnSuspending(ScreenTransitionEvent e) + { + endHandlingTrack(); + + base.OnSuspending(e); + } + + private bool exitConfirmed; + private bool retryRequested; + + public override bool OnExiting(ScreenExitEvent e) + { + if (exitConfirmed || ActiveSubScreen is EndedScreen) + { + if (base.OnExiting(e)) + { + exitConfirmed = false; + return true; + } + + endHandlingTrack(); + + client.LeaveRoom().FireAndForget(); + + if (retryRequested) + controller?.RejoinQueue(); + + return false; + } + + if (dialogOverlay.CurrentDialog is ConfirmDialog confirmDialog) + confirmDialog.PerformOkAction(); + else + { + dialogOverlay.Push(new ConfirmDialog("Are you sure you want to leave this multiplayer match?", () => + { + exitConfirmed = true; + if (this.IsCurrentScreen()) + this.Exit(); + })); + } + + return true; + } + + public override void OnResuming(ScreenTransitionEvent e) + { + base.OnResuming(e); + + beginHandlingTrack(); + + if (e.Last is not MultiplayerPlayerLoader playerLoader) + return; + + if (!playerLoader.GameplayPassed) + { + client.AbortGameplay().FireAndForget(); + return; + } + + client.ChangeState(MultiplayerUserState.Idle).FireAndForget(); + } + + /// + /// Handles changes in the track to keep it looping while active. + /// + private void beginHandlingTrack() + { + Beatmap.BindValueChanged(applyLoopingToTrack, true); + } + + /// + /// Stops looping the current track and stops handling further changes to the track. + /// + private void endHandlingTrack() + { + Beatmap.ValueChanged -= applyLoopingToTrack; + Beatmap.Value.Track.Looping = false; + + previewTrackManager.StopAnyPlaying(this); + } + + /// + /// Invoked on changes to the beatmap to loop the track. See: . + /// + /// The beatmap change event. + private void applyLoopingToTrack(ValueChangedEvent beatmap) + { + if (!this.IsCurrentScreen()) + return; + + beatmap.NewValue.PrepareTrackForPreview(true); + music.EnsurePlayingSomething(); + } + + public void PresentBeatmap(WorkingBeatmap beatmap, RulesetInfo ruleset) + { + // Do nothing to prevent the user from potentially being kicked out + // of gameplay due to the screen performer's internal processes. + } + + protected override void Dispose(bool isDisposing) + { + client.RoomUpdated -= onRoomUpdated; + client.UserStateChanged -= onUserStateChanged; + client.SettingsChanged -= onSettingsChanged; + client.LoadRequested -= onLoadRequested; + + base.Dispose(isDisposing); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlaySubScreen.cs new file mode 100644 index 000000000000..b19340107f02 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlaySubScreen.cs @@ -0,0 +1,89 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Globalization; +using Humanizer; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.Multiplayer; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public abstract partial class RankedPlaySubScreen : Container + { + public const float CENTERED_CARD_SCALE = 1.2f; + + public readonly Bindable CornerPieceVisibility = new Bindable(Visibility.Visible); + + public virtual bool ShowBeatmapBackground => false; + + [Resolved] + private MultiplayerClient client { get; set; } = null!; + + protected MultiplayerClient Client => client; + + protected override Container Content { get; } + + protected readonly Container CenterColumn; + + protected readonly FillFlowContainer ButtonsContainer; + + protected RankedPlaySubScreen() + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = + [ + CenterColumn = new Container + { + Name = "Center Column", + RelativeSizeAxes = Axes.Y, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Padding = new MarginPadding(20), + }, + Content = new Container + { + Name = "Content", + RelativeSizeAxes = Axes.Both, + }, + ButtonsContainer = new FillFlowContainer + { + Name = "Buttons", + AutoSizeAxes = Axes.Both, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + X = 30, + Y = -110, + Direction = FillDirection.Vertical, + Spacing = new Vector2(8) + }, + ]; + } + + protected override void Update() + { + base.Update(); + + CenterColumn.Width = DrawWidth - RankedPlayCornerPiece.WidthFor(DrawWidth) * 2; + } + + public virtual void OnEntering(RankedPlaySubScreen? previous) + { + } + + public virtual void OnExiting(RankedPlaySubScreen? next) + { + Hide(); + } + + protected static string FormatRoundIndex(int roundNumber) + { + return roundNumber >= 10 ? roundNumber.Ordinalize(CultureInfo.InvariantCulture) : roundNumber.ToOrdinalWords(CultureInfo.InvariantCulture); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.PanelScaffold.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.PanelScaffold.cs new file mode 100644 index 000000000000..e4c69f9ee70c --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.PanelScaffold.cs @@ -0,0 +1,118 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class ResultsScreen + { + public partial class PanelScaffold : Container + { + private const float corner_radius = 6; + private const float border_thickness = 2; + + protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; + + public readonly ScreenBottomOrnament BottomOrnament = new ScreenBottomOrnament(); + + private BufferedContainer background = null!; + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = + [ + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Bottom = -30 }, + Child = background = new BufferedContainer(cachedFrameBuffer: false) + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Bottom = 30 }, + BackgroundColour = Color4Extensions.FromHex("222228").Opacity(0), + Alpha = 0.7f, + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = corner_radius, + BorderThickness = border_thickness, + BorderColour = new ColourInfo + { + TopLeft = RankedPlayColourScheme.Blue.PrimaryDarkest.Opacity(0.5f), + BottomLeft = RankedPlayColourScheme.Blue.Primary.Opacity(0.75f), + TopRight = RankedPlayColourScheme.Red.PrimaryDarkest.Opacity(0.5f), + BottomRight = RankedPlayColourScheme.Red.Primary.Opacity(0.75f), + }, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex("222228"), + }, + }, + } + }, + Content.With(static d => + { + d.Masking = true; + d.CornerRadius = corner_radius; + }), + BottomOrnament.With(static d => + { + d.Anchor = Anchor.BottomCentre; + d.Origin = Anchor.Centre; + d.Y -= border_thickness / 2; + }), + ]; + + background.Add(BottomOrnament.Background.CreateProxy()); + } + } + + public partial class ScreenBottomOrnament : Container + { + protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both, }; + + public Drawable Background => background; + + private readonly Container background = new Container { RelativeSizeAxes = Axes.Both }; + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + InternalChildren = + [ + background.WithChildren([ + new NineSliceSprite + { + RelativeSizeAxes = Axes.Both, + Texture = textures.Get("Online/RankedPlay/damage-display-background"), + TextureInsetRelativeAxes = Axes.None, + TextureInset = new MarginPadding { Horizontal = 30 }, + Colour = Color4Extensions.FromHex("222228"), + }, + new NineSliceSprite + { + RelativeSizeAxes = Axes.Both, + Texture = textures.Get("Online/RankedPlay/damage-display-border"), + TextureInsetRelativeAxes = Axes.None, + TextureInset = new MarginPadding { Horizontal = 30 }, + Alpha = 0.25f, + Colour = Color4Extensions.FromHex("ddddff") + }, + ]), + Content, + ]; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreBar.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreBar.cs new file mode 100644 index 000000000000..7aee36358faf --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreBar.cs @@ -0,0 +1,67 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class ResultsScreen + { + public partial class ScoreBar(RankedPlayColourScheme colours) : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load() + { + Masking = true; + CornerRadius = 6; + BorderThickness = 2; + BorderColour = colours.PrimaryDarkest.Darken(0.35f); + + InternalChildren = + [ + new Box + { + RelativeSizeAxes = Axes.Both, + Height = 1 / 3f, + Colour = ColourInfo.GradientVertical(colours.Primary, colours.PrimaryDarker) + }, + new Box + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Y, + Height = 2f / 3f, + Y = 1f / 3f, + Colour = ColourInfo.GradientVertical(colours.PrimaryDarker, colours.PrimaryDarkest) + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(3), + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 3, + Colour = ColourInfo.GradientHorizontal(Colour4.White, Colour4.White.Opacity(0)), + BorderThickness = 3, + BorderColour = ColourInfo.GradientVertical(Colour4.White, Colour4.White.Opacity(0)), + Alpha = 0.25f, + Blending = BlendingParameters.Additive, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + } + } + }, + ]; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreDetails.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreDetails.cs new file mode 100644 index 000000000000..f8a55e8778d9 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreDetails.cs @@ -0,0 +1,109 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Scoring; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class ResultsScreen + { + public partial class ScoreDetails(ScoreInfo score, RankedPlayColourScheme colours) : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(30), + Children = + [ + new ScoreStatisticsDisplay(score, colours) + { + RelativeSizeAxes = Axes.X, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + }, + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + ColumnDimensions = + [ + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + ], + RowDimensions = [new Dimension(GridSizeMode.AutoSize)], + Content = new Drawable[][] + { + [ + new ScoreRankDisplay(score) + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Spacing = new Vector2(20), + Children = + [ + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = + [ + new OsuSpriteText + { + Text = "Accuracy", + UseFullGlyphHeight = false, + }, + new OsuSpriteText + { + Text = score.DisplayAccuracy, + Font = OsuFont.GetFont(size: 36, weight: FontWeight.SemiBold) + }, + ] + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = + [ + new OsuSpriteText + { + Text = "Combo", + UseFullGlyphHeight = false, + }, + new OsuSpriteText + { + Text = $"{score.MaxCombo}x", + Font = OsuFont.GetFont(size: 36, weight: FontWeight.SemiBold) + }, + ] + } + ] + } + ] + } + } + ] + }; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreRankDisplay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreRankDisplay.cs new file mode 100644 index 000000000000..b3981f05812f --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreRankDisplay.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Online.Leaderboards; +using osu.Game.Scoring; +using osu.Game.Skinning; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class ResultsScreen + { + private partial class ScoreRankDisplay : CompositeDrawable + { + private readonly ScoreInfo score; + + public ScoreRankDisplay(ScoreInfo score) + { + this.score = score; + + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(SkinManager skinManager) + { + InternalChild = new Sprite + { + Scale = new Vector2(0.5f), + Texture = skinManager.DefaultClassicSkin.GetTexture(DrawableRank.GetLegacyRankTextureName(score.Rank)) + }; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreStatisticsDisplay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreStatisticsDisplay.cs new file mode 100644 index 000000000000..217984beff4c --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreStatisticsDisplay.cs @@ -0,0 +1,70 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Scoring; +using osu.Game.Screens.Select; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class ResultsScreen + { + private partial class ScoreStatisticsDisplay : CompositeDrawable + { + private readonly ScoreInfo score; + private readonly RankedPlayColourScheme colours; + + private FillFlowContainer statisticsFlow = null!; + + public ScoreStatisticsDisplay(ScoreInfo score, RankedPlayColourScheme colours) + { + this.score = score; + this.colours = colours; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(20), + Children = new Drawable[] + { + statisticsFlow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(10, 20), + Children = score.GetStatisticsForDisplay().Select(it => new BeatmapTitleWedge.StatisticDifficulty + { + Width = 80, + Value = new BeatmapTitleWedge.StatisticDifficulty.Data(it.DisplayName, it.Count, it.Count, it.MaxCount ?? it.Count), + AccentColour = colours.PrimaryDarker, + }).ToArray(), + } + } + }; + } + + protected override void Update() + { + base.Update(); + + int statisticsPerRow = (statisticsFlow.Count + 1) / 2; + float statisticWidth = (DrawWidth - (statisticsPerRow - 1) * statisticsFlow.Spacing.X) / statisticsPerRow; + foreach (var statistic in statisticsFlow) + statistic.Width = statisticWidth; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.cs new file mode 100644 index 000000000000..872920272a2a --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.cs @@ -0,0 +1,606 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Transforms; +using osu.Framework.Logging; +using osu.Framework.Utils; +using osu.Game.Beatmaps; +using osu.Game.Database; +using osu.Game.Extensions; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Models; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; +using osu.Game.Online.Rooms; +using osu.Game.Rulesets; +using osu.Game.Scoring; +using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay +{ + public partial class ResultsScreen : RankedPlaySubScreen + { + public override bool ShowBeatmapBackground => true; + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + [Resolved] + private MultiplayerClient client { get; set; } = null!; + + [Resolved] + private BeatmapLookupCache beatmapLookupCache { get; set; } = null!; + + [Resolved] + private ScoreManager scoreManager { get; set; } = null!; + + [Resolved] + private RulesetStore rulesets { get; set; } = null!; + + [Resolved] + private IBindable globalRuleset { get; set; } = null!; + + private LoadingSpinner loadingSpinner = null!; + + [BackgroundDependencyLoader] + private void load() + { + CornerPieceVisibility.Value = Visibility.Hidden; + + InternalChildren = new Drawable[] + { + loadingSpinner = new LoadingSpinner + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + loadingSpinner.Show(); + + queryScores().FireAndForget(); + } + + private async Task queryScores() + { + try + { + if (client.Room == null) + return; + + Task beatmapTask = beatmapLookupCache.GetBeatmapAsync(client.Room.CurrentPlaylistItem.BeatmapID); + TaskCompletionSource> scoreTask = new TaskCompletionSource>(); + + var request = new IndexPlaylistScoresRequest(client.Room.RoomID, client.Room.Settings.PlaylistItemId); + request.Success += req => scoreTask.SetResult(req.Scores); + request.Failure += scoreTask.SetException; + api.Queue(request); + + await Task.WhenAll(beatmapTask, scoreTask.Task).ConfigureAwait(false); + + APIBeatmap? apiBeatmap = beatmapTask.GetResultSafely(); + List apiScores = scoreTask.Task.GetResultSafely(); + + if (apiBeatmap == null) + return; + + // Reference: PlaylistItemResultsScreen + setScores(apiScores.Select(s => s.CreateScoreInfo(scoreManager, rulesets, new BeatmapInfo + { + Difficulty = new BeatmapDifficulty(apiBeatmap.Difficulty), + Metadata = + { + Artist = apiBeatmap.Metadata.Artist, + Title = apiBeatmap.Metadata.Title, + Author = new RealmUser + { + Username = apiBeatmap.Metadata.Author.Username, + OnlineID = apiBeatmap.Metadata.Author.OnlineID, + } + }, + DifficultyName = apiBeatmap.DifficultyName, + StarRating = apiBeatmap.StarRating, + Length = apiBeatmap.Length, + BPM = apiBeatmap.BPM + })).ToArray()); + } + catch (Exception e) + { + Logger.Error(e, "Failed to load scores for playlist item."); + throw; + } + finally + { + Scheduler.Add(() => loadingSpinner.Hide()); + } + } + + [Resolved] + private RankedPlayMatchInfo matchInfo { get; set; } = null!; + + private void setScores(ScoreInfo[] scores) => Scheduler.Add(() => + { + int playerId = api.LocalUser.Value.OnlineID; + int opponentId = matchInfo.RoomState.Users.Keys.Single(it => it != playerId); + + ScoreInfo playerScore = scores.SingleOrDefault(s => s.UserID == playerId) ?? new ScoreInfo + { + Rank = ScoreRank.F, + Ruleset = globalRuleset.Value, + User = new APIUser { Id = playerId } + }; + + ScoreInfo opponentScore = scores.SingleOrDefault(s => s.UserID == opponentId) ?? new ScoreInfo + { + Rank = ScoreRank.F, + Ruleset = globalRuleset.Value, + User = new APIUser { Id = opponentId } + }; + + AddInternal(new ResultScreenContent + { + PlayerScore = playerScore, + OpponentScore = opponentScore, + PlayerDamageInfo = matchInfo.RoomState.Users[playerId].DamageInfo!, + OpponentDamageInfo = matchInfo.RoomState.Users[opponentId].DamageInfo!, + }); + }); + + private partial class ResultScreenContent : CompositeDrawable + { + public required ScoreInfo PlayerScore { get; init; } + public required ScoreInfo OpponentScore { get; init; } + public required RankedPlayDamageInfo PlayerDamageInfo { get; init; } + public required RankedPlayDamageInfo OpponentDamageInfo { get; init; } + + [Resolved] + private RankedPlayMatchInfo matchInfo { get; set; } = null!; + + [Resolved] + private OsuColour colour { get; set; } = null!; + + private static Vector2 cardSize => new Vector2(950, 550); + + private readonly Bindable cornerPieceVisibility = new Bindable(); + private readonly Bindable scoreBarProgress = new Bindable(); + + private PanelScaffold panelScaffold = null!; + private Box flash = null!; + private ScoreDetails playerScoreDetails = null!; + private ScoreDetails opponentScoreDetails = null!; + private RankedPlayScoreCounter playerScoreCounter = null!; + private RankedPlayScoreCounter opponentScoreCounter = null!; + private RankedPlayScoreCounter damageCounter = null!; + private OsuSpriteText flyingDamageText = null!; + private ScoreBar playerScoreBar = null!; + private ScoreBar opponentScoreBar = null!; + private OsuSpriteText roundNumber = null!; + private RankedPlayUserDisplay playerUserDisplay = null!; + private RankedPlayUserDisplay opponentUserDisplay = null!; + + private RankedPlayDamageInfo losingDamageInfo = null!; + + [BackgroundDependencyLoader] + private void load() + { + // this works under the assumption that only one player can receive damage each round + losingDamageInfo = matchInfo.RoomState.Users + .Select(it => it.Value.DamageInfo) + .OfType() + .MaxBy(it => it.Damage)!; + + RelativeSizeAxes = Axes.Both; + + AddInternal(panelScaffold = new PanelScaffold + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = + [ + new RankedPlayCornerPiece(RankedPlayColourScheme.Blue, Anchor.BottomLeft) + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + State = { BindTarget = cornerPieceVisibility }, + Child = playerUserDisplay = new RankedPlayUserDisplay(PlayerScore.UserID, Anchor.BottomLeft, RankedPlayColourScheme.Blue) + { + RelativeSizeAxes = Axes.Both, + Health = { Value = PlayerDamageInfo.OldLife } + } + }, + new RankedPlayCornerPiece(RankedPlayColourScheme.Red, Anchor.BottomRight) + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + State = { BindTarget = cornerPieceVisibility }, + Child = opponentUserDisplay = new RankedPlayUserDisplay(OpponentScore.UserID, Anchor.BottomRight, RankedPlayColourScheme.Red) + { + RelativeSizeAxes = Axes.Both, + Health = { Value = OpponentDamageInfo.OldLife } + } + }, + new Container + { + RelativeSizeAxes = Axes.X, + Height = 110, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Padding = new MarginPadding { Bottom = 30 }, + Child = roundNumber = new OsuSpriteText + { + Text = $"Round {matchInfo.CurrentRound}", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 36, weight: FontWeight.Bold, typeface: Typeface.TorusAlternate), + Alpha = 0, + }, + }, + new GridContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = cardSize, + Padding = new MarginPadding { Bottom = 110, Top = 60, Horizontal = 60 }, + ColumnDimensions = + [ + new Dimension(), + new Dimension(GridSizeMode.Absolute, 40), + new Dimension(GridSizeMode.Absolute, 60), + new Dimension(GridSizeMode.Absolute, 10), + new Dimension(GridSizeMode.Absolute, 60), + new Dimension(GridSizeMode.Absolute, 40), + new Dimension(), + ], + Content = new Drawable?[][] + { + [ + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = + [ + new Dimension(), + new Dimension(GridSizeMode.AutoSize) + ], + Content = new Drawable[][] + { + [ + playerScoreDetails = new ScoreDetails(PlayerScore, RankedPlayColourScheme.Blue) + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + }, + ], + [ + playerScoreCounter = new RankedPlayScoreCounter(numDigits(PlayerScore.TotalScore)) + { + Font = OsuFont.GetFont(size: 60, fixedWidth: true), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Spacing = new Vector2(-4), + Alpha = 0, + AlwaysPresent = true, + } + ] + } + }, + null, + playerScoreBar = new ScoreBar(RankedPlayColourScheme.Blue) + { + RelativeSizeAxes = Axes.Both, + Height = 0.05f, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Alpha = 0, + }, + null, + opponentScoreBar = new ScoreBar(RankedPlayColourScheme.Red) + { + RelativeSizeAxes = Axes.Both, + Height = 0.05f, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Alpha = 0, + }, + null, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = + [ + new Dimension(), + new Dimension(GridSizeMode.AutoSize) + ], + Content = new Drawable[][] + { + [ + opponentScoreDetails = new ScoreDetails(OpponentScore, RankedPlayColourScheme.Red) + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + }, + ], + [ + opponentScoreCounter = new RankedPlayScoreCounter(numDigits(OpponentScore.TotalScore)) + { + Font = OsuFont.GetFont(size: 60, fixedWidth: true), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Spacing = new Vector2(-4), + Alpha = 0, + AlwaysPresent = true, + } + ] + } + }, + ] + } + }, + flash = new Box + { + RelativeSizeAxes = Axes.Both, + }, + ], + BottomOrnament = + { + Size = new Vector2(200, 60), + Alpha = 0, + Children = + [ + new Container + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = + [ + damageCounter = new RankedPlayScoreCounter(numDigits(losingDamageInfo.Damage)) + { + Font = OsuFont.GetFont(size: 36, weight: FontWeight.SemiBold, fixedWidth: true), + Spacing = new Vector2(-2), + }, + flyingDamageText = new OsuSpriteText + { + Text = FormattableString.Invariant($"{losingDamageInfo.Damage:N0}"), + Font = OsuFont.GetFont(size: 36, weight: FontWeight.SemiBold, fixedWidth: true), + Spacing = new Vector2(-2), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + BypassAutoSizeAxes = Axes.Both, + Alpha = 0, + }, + new OsuSpriteText + { + BypassAutoSizeAxes = Axes.Both, + Text = $"{matchInfo.RoomState.DamageMultiplier.ToStandardFormattedString(maxDecimalDigits: 1)}x", + Anchor = Anchor.CentreRight, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 42), + Rotation = 30, + Alpha = 0, + Colour = colour.RedLight + }, + ] + }, + new OsuSpriteText + { + Text = Precision.AlmostEquals(matchInfo.RoomState.DamageMultiplier, 1) + ? "Damage" + : $"Damage {matchInfo.RoomState.DamageMultiplier.ToStandardFormattedString(maxDecimalDigits: 1)}x", + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 22), + }, + ] + } + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + double delay = 0; + + appear(ref delay); + + animateCountersAndScoreBars(ref delay); + + showScoreInfo(ref delay); + + updateHealthBars(ref delay); + } + + private void appear(ref double delay) + { + panelScaffold.FadeIn(100) + .ResizeTo(0) + .ResizeTo(cardSize with { Y = 30 }, 600, Easing.OutExpo) + // deliberately cutting this delay 300ms short so the vertical resize interrupts the horizontal one + .Delay(300) + .ResizeHeightTo(cardSize.Y, 800, Easing.OutExpo); + + flash.Delay(150).FadeOut(600, Easing.Out); + + using (BeginDelayedSequence(700)) + { + roundNumber.FadeIn(600); + playerScoreCounter.FadeIn(600); + opponentScoreCounter.FadeIn(600); + + Schedule(() => cornerPieceVisibility.Value = Visibility.Visible); + } + + using (BeginDelayedSequence(900)) + { + panelScaffold.BottomOrnament + .FadeIn(300) + .ResizeWidthTo(cardSize.X - 550, 600, Easing.OutExpo); + } + + delay += 1000; + } + + private void animateCountersAndScoreBars(ref double delay) + { + using (BeginDelayedSequence(delay)) + { + const double score_text_duration = 2000; + + playerScoreCounter.TransformValueTo(PlayerScore.TotalScore, score_text_duration - 500); + opponentScoreCounter.TransformValueTo(OpponentScore.TotalScore, score_text_duration - 500); + + damageCounter.TransformValueTo(losingDamageInfo.Damage, score_text_duration - 500); + + long maxAchievableScore = Math.Max( + Math.Max(PlayerScore.TotalScore, OpponentScore.TotalScore), + 1_000_000 + ); + + float playerScorePercent = (float)PlayerScore.TotalScore / maxAchievableScore; + float opponentScorePercent = (float)OpponentScore.TotalScore / maxAchievableScore; + float maxScorePercent = Math.Max(playerScorePercent, opponentScorePercent); + + playerScoreBar.FadeIn(100); + opponentScoreBar.FadeIn(100); + + this.TransformBindableTo(scoreBarProgress, maxScorePercent, score_text_duration, new CubicBezierEasingFunction(easeIn: 0.4, easeOut: 1)); + + scoreBarProgress.BindValueChanged(e => + { + playerScoreBar.Height = float.Lerp(0.05f, 1f, Math.Min(e.NewValue, playerScorePercent)); + opponentScoreBar.Height = float.Lerp(0.05f, 1f, Math.Min(e.NewValue, opponentScorePercent)); + }); + } + + delay += 2200; + } + + private void updateHealthBars(ref double delay) + { + const double text_movement_duration = 400; + + using (BeginDelayedSequence(delay)) + { + Schedule(() => + { + RankedPlayUserDisplay userDisplay = + PlayerScore.TotalScore > OpponentScore.TotalScore + ? opponentUserDisplay + : playerUserDisplay; + + Vector2 screenSpacePosition = userDisplay.HealthDisplay.ScreenSpaceImpactPosition; + + var position = flyingDamageText.Parent!.ToLocalSpace(screenSpacePosition) - flyingDamageText.AnchorPosition; + + damageCounter.FadeOut() + .Delay(200) + .FadeIn(300) + .ScaleTo(0.9f) + .ScaleTo(1f, 300, Easing.OutElasticHalf); + + flyingDamageText.FadeIn() + .MoveTo(position, text_movement_duration, Easing.InCubic) + .ScaleTo(0.75f, text_movement_duration, new CubicBezierEasingFunction(easeIn: 0.35, easeOut: 0.5)) + .RotateTo(12 * Math.Sign(position.X), text_movement_duration, new CubicBezierEasingFunction(easeIn: 0.35, easeOut: 0.5)) + .Then() + .FadeOut(); + + Scheduler.AddDelayed(() => + { + userDisplay.Shake(shakeDuration: 60, shakeMagnitude: 2, maximumLength: 120); + + for (int i = 0; i < 10; i++) + { + var particle = new DamageParticle + { + Size = new Vector2(RNG.NextSingle(5, 15)), + Origin = Anchor.Centre, + Position = ToLocalSpace(screenSpacePosition), + Rotation = RNG.NextSingle(0, 360), + Blending = BlendingParameters.Additive, + }; + + AddInternal(particle); + + particle.FadeOut(600) + .ScaleTo(0, 600) + .RotateTo(particle.Rotation + RNG.NextSingle(-20, 20), 600) + .FadeColour(Color4.Red, 600) + .Expire(); + } + }, text_movement_duration); + }); + } + + delay += text_movement_duration; + + using (BeginDelayedSequence(delay)) + { + Schedule(() => + { + playerUserDisplay.Health.Value = PlayerDamageInfo.NewLife; + opponentUserDisplay.Health.Value = OpponentDamageInfo.NewLife; + }); + } + + delay += 400; + } + + private void showScoreInfo(ref double delay) + { + using (BeginDelayedSequence(delay)) + { + playerScoreDetails.FadeIn(300); + opponentScoreDetails.FadeIn(300); + } + + delay += 800; + } + + private static int numDigits(long value) + { + if (value <= 0) + return 1; + + return (int)Math.Floor(Math.Log10(value)) + 1; + } + + private partial class DamageParticle : Triangle + { + private Vector2 velocity = new Vector2(RNG.NextSingle(-0.3f, 0.3f), RNG.NextSingle(-0.3f, 0.3f)); + + private Vector2 gravity => new Vector2(0, 0.0002f); + + protected override void Update() + { + base.Update(); + + velocity += gravity * (float)Time.Elapsed; + Position += velocity * (float)Time.Elapsed; + } + } + } + } +} diff --git a/osu.Game/Screens/Select/BeatmapMetadataWedge.FailRetryDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.FailRetryDisplay.cs index 1bbce94f4fc9..e47c35c3cef1 100644 --- a/osu.Game/Screens/Select/BeatmapMetadataWedge.FailRetryDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.FailRetryDisplay.cs @@ -21,7 +21,7 @@ namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { - private partial class FailRetryDisplay : CompositeDrawable + public partial class FailRetryDisplay : CompositeDrawable { private readonly GraphDrawable retriesGraph; private readonly GraphDrawable failsGraph; diff --git a/osu.Game/Screens/Select/BeatmapMetadataWedge.MetadataDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.MetadataDisplay.cs index 3b9d31380a63..5aa8279f66a3 100644 --- a/osu.Game/Screens/Select/BeatmapMetadataWedge.MetadataDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.MetadataDisplay.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { - private partial class MetadataDisplay : FillFlowContainer + public partial class MetadataDisplay : FillFlowContainer { private readonly OsuSpriteText labelText; private readonly OsuSpriteText contentText; diff --git a/osu.Game/Screens/Select/BeatmapMetadataWedge.RatingSpreadDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.RatingSpreadDisplay.cs index 3a6017f4ec7b..a74ab3d8b6b7 100644 --- a/osu.Game/Screens/Select/BeatmapMetadataWedge.RatingSpreadDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.RatingSpreadDisplay.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { - private partial class RatingSpreadDisplay : CompositeDrawable + public partial class RatingSpreadDisplay : CompositeDrawable { private const float min_height = 4f; private const float max_height = 32f; diff --git a/osu.Game/Screens/Select/BeatmapMetadataWedge.SuccessRateDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.SuccessRateDisplay.cs index 48680b5b2902..a7038ef9cbb4 100644 --- a/osu.Game/Screens/Select/BeatmapMetadataWedge.SuccessRateDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.SuccessRateDisplay.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { - private partial class SuccessRateDisplay : CompositeDrawable, IHasTooltip + public partial class SuccessRateDisplay : CompositeDrawable, IHasTooltip { private readonly OsuSpriteText valueText; private readonly Circle backgroundBar; diff --git a/osu.Game/Screens/Select/BeatmapMetadataWedge.UserRatingDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.UserRatingDisplay.cs index 2d8d039d990f..8c55e5320c5b 100644 --- a/osu.Game/Screens/Select/BeatmapMetadataWedge.UserRatingDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.UserRatingDisplay.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { - private partial class UserRatingDisplay : CompositeDrawable + public partial class UserRatingDisplay : CompositeDrawable { private readonly OsuSpriteText negativeText; private readonly OsuSpriteText positiveText; diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs index caf99a4cf6a9..dfb6a4fff5bc 100644 --- a/osu.Game/Tests/Beatmaps/TestBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs @@ -47,6 +47,8 @@ public TestBeatmap(RulesetInfo ruleset, bool withHitObjects = true) BeatmapInfo.Ruleset = ruleset; BeatmapInfo.Length = 75000; + BeatmapInfo.BPM = 123; + BeatmapInfo.StarRating = 4.32; BeatmapInfo.OnlineInfo = new APIBeatmap(); BeatmapInfo.OnlineID = Interlocked.Increment(ref onlineBeatmapID); BeatmapInfo.Status = BeatmapOnlineStatus.Ranked; diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 21fffba1f3cb..c6e39016f073 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -19,7 +19,9 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.Countdown; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; +using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; +using osu.Game.Online.RankedPlay; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Mods; using osu.Game.Tests.Visual.OnlinePlay; @@ -123,6 +125,16 @@ private void addUser(MultiplayerRoomUser user) user.MatchState = new TeamVersusUserState { TeamID = bestTeam }; ((IMultiplayerClient)this).MatchUserStateChanged(clone(user.UserID), clone(user.MatchState)).WaitSafely(); break; + + case RankedPlayRoomState: + ((RankedPlayRoomState)ServerRoom!.MatchState!).Users[user.UserID] = new RankedPlayUserInfo + { + Rating = 1500, + Hand = Enumerable.Range(0, 5).Select(_ => new RankedPlayCardItem()).ToList() + }; + + ((IMultiplayerClient)this).MatchRoomStateChanged(clone(ServerRoom.MatchState)).WaitSafely(); + break; } } @@ -428,6 +440,14 @@ public async Task SendUserMatchRequest(int userId, MatchUserRequest request) Action = avatarAction.Action }).ConfigureAwait(false); break; + + case RankedPlayCardHandReplayRequest cardHandState: + await ((IMultiplayerClient)this).MatchEvent(new RankedPlayCardHandReplayEvent + { + UserId = userId, + Frames = cardHandState.Frames, + }).ConfigureAwait(false); + break; } } @@ -624,6 +644,28 @@ private async Task changeMatchType(MatchType type) await ((IMultiplayerClient)this).MatchUserStateChanged(clone(user.UserID), clone(user.MatchState)).ConfigureAwait(false); } + break; + + case MatchType.RankedPlay: + ServerRoom.MatchState = new RankedPlayRoomState(); + + foreach (var user in ServerRoom.Users) + { + ((RankedPlayRoomState)ServerRoom.MatchState).Users[user.UserID] = new RankedPlayUserInfo + { + Rating = 1500, + Hand = Enumerable.Range(0, 5).Select(_ => new RankedPlayCardItem()).ToList() + }; + } + + await ((IMultiplayerClient)this).MatchRoomStateChanged(clone(ServerRoom.MatchState)).ConfigureAwait(false); + + foreach (var user in ServerRoom.Users) + { + user.MatchState = null; + await ((IMultiplayerClient)this).MatchUserStateChanged(clone(user.UserID), clone(user.MatchState)).ConfigureAwait(false); + } + break; } } @@ -782,6 +824,33 @@ public async Task ChangeMatchRoomState(MatchRoomState state) await ((IMultiplayerClient)this).MatchRoomStateChanged(clone(ServerRoom.MatchState)).ConfigureAwait(false); } + public override Task DiscardCards(RankedPlayCardItem[] cards) + => DiscardCards(_ => cards); + + public Task DiscardCards(Func> selector) + => DiscardUserCards(api.LocalUser.Value.OnlineID, selector); + + public async Task DiscardUserCards(int userId, Func> selector) + { + RankedPlayUserInfo info = ((RankedPlayRoomState)ServerRoom!.MatchState!).Users[userId]; + RankedPlayCardItem[] cards = selector(info.Hand.ToArray()).ToArray(); + + await RankedPlayRemoveUserCards(userId, _ => cards).ConfigureAwait(false); + await RankedPlayAddUserCards(userId, Enumerable.Range(0, cards.Length).Select(_ => new RankedPlayCardItem()).ToArray()).ConfigureAwait(false); + } + + public override Task PlayCard(RankedPlayCardItem card) + => PlayCard(_ => card); + + public Task PlayCard(Func selector) + => PlayUserCard(api.LocalUser.Value.OnlineID, selector); + + public async Task PlayUserCard(int userId, Func selector) + { + RankedPlayCardItem card = selector(((RankedPlayRoomState)ServerRoom!.MatchState!).Users[userId].Hand.ToArray()); + await ((IRankedPlayClient)this).RankedPlayCardPlayed(clone(card)).ConfigureAwait(false); + } + public override Task GetMatchmakingPoolsOfType(MatchmakingPoolType type) { return Task.FromResult( @@ -865,6 +934,93 @@ await StartCountdown(new MatchmakingStageCountdown }).ConfigureAwait(false); } + /// + /// Adds a card to the local user's hand. + /// + public Task RankedPlayAddCards(RankedPlayCardItem[] cards) + => RankedPlayAddUserCards(api.LocalUser.Value.OnlineID, cards); + + /// + /// Adds a card to the given user's hand. + /// + public async Task RankedPlayAddUserCards(int userId, RankedPlayCardItem[] cards) + { + foreach (var card in cards) + { + ((RankedPlayRoomState)ServerRoom!.MatchState!).Users[userId].Hand.Add(card); + await ((IRankedPlayClient)this).RankedPlayCardAdded(userId, clone(card)).ConfigureAwait(false); + } + + await ((IMultiplayerClient)this).MatchRoomStateChanged(clone(ServerRoom!.MatchState)).ConfigureAwait(false); + } + + /// + /// Removes a card from the local user's hand. + /// + public Task RankedPlayRemoveCards(Func selector) + => RankedPlayRemoveUserCards(api.LocalUser.Value.OnlineID, selector); + + /// + /// Removes a card from the given user's hand. + /// + public async Task RankedPlayRemoveUserCards(int userId, Func selector) + { + RankedPlayCardItem[] cards = selector(((RankedPlayRoomState)ServerRoom!.MatchState!).Users[userId].Hand.ToArray()); + + foreach (var card in cards) + { + ((RankedPlayRoomState)ServerRoom!.MatchState!).Users[userId].Hand.Remove(card); + await ((IRankedPlayClient)this).RankedPlayCardRemoved(userId, clone(card)).ConfigureAwait(false); + } + + await ((IMultiplayerClient)this).MatchRoomStateChanged(clone(ServerRoom!.MatchState)).ConfigureAwait(false); + } + + /// + /// Reveals a card in the local user's hand. + /// + public Task RankedPlayRevealCard(Func selector, MultiplayerPlaylistItem item) + => RankedPlayRevealUserCard(api.LocalUser.Value.OnlineID, selector, item); + + /// + /// Reveals a card in the given user's hand. + /// + public async Task RankedPlayRevealUserCard(int userId, Func selector, MultiplayerPlaylistItem item) + { + RankedPlayCardItem card = selector(((RankedPlayRoomState)ServerRoom!.MatchState!).Users[userId].Hand.ToArray()); + await ((IRankedPlayClient)this).RankedPlayCardRevealed(clone(card), clone(item)).ConfigureAwait(false); + } + + public async Task RankedPlayChangeStage(RankedPlayStage stage, Action? prepare = null) + { + RankedPlayRoomState state = clone((RankedPlayRoomState)ServerRoom!.MatchState!); + + state.Stage = stage; + + if (stage == RankedPlayStage.RoundWarmup) + state.CurrentRound++; + + prepare?.Invoke(state); + + await ChangeMatchRoomState(state).ConfigureAwait(false); + await StartCountdown(new RankedPlayStageCountdown + { + Stage = stage, + TimeRemaining = TimeSpan.FromSeconds(stage == RankedPlayStage.CardPlay ? 30 : 10) + }).ConfigureAwait(false); + } + + public async Task RankedPlayChangeUserState(int userId, Action prepare) + { + Debug.Assert(ServerRoom != null); + + var userInfo = clone(((RankedPlayRoomState)ServerRoom!.MatchState!).Users[userId]); + prepare(userInfo); + + ((RankedPlayRoomState)ServerRoom!.MatchState!).Users[userId] = userInfo; + await ((IMultiplayerClient)this).MatchRoomStateChanged(clone(ServerRoom!.MatchState)).ConfigureAwait(false); + } + #region API Room Handling public IReadOnlyList ServerSideRooms diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 9b0b66a18ca6..8c2ba938833b 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -274,6 +274,8 @@ public static APIBeatmapSet CreateAPIBeatmapSet(IBeatmapInfo original) var result = new APIBeatmapSet { + Genre = new BeatmapSetOnlineGenre { Id = 15, Name = "Future genre" }, + Language = new BeatmapSetOnlineLanguage { Id = 15, Name = "Future language" }, OnlineID = original.BeatmapSet.OnlineID, Status = BeatmapOnlineStatus.Ranked, Covers = new BeatmapSetOnlineCovers @@ -293,6 +295,34 @@ public static APIBeatmapSet CreateAPIBeatmapSet(IBeatmapInfo original) }, Source = original.Metadata.Source, Tags = original.Metadata.Tags, + BPM = original.BPM, + HasFavourited = false, + PlayCount = 123, + FavouriteCount = 456, + Submitted = DateTime.Now, + Ranked = DateTime.Now, + Ratings = Enumerable.Range(0, 11).ToArray(), + RelatedTags = + [ + new APITag + { + Id = 2, + Name = "song representation/simple", + Description = "Accessible and straightforward map design." + }, + new APITag + { + Id = 4, + Name = "style/clean", + Description = "Visually uncluttered and organised patterns, often involving few overlaps and equal visual spacing between objects." + }, + new APITag + { + Id = 23, + Name = "aim/aim control", + Description = "Patterns with velocity or direction changes which strongly go against a player's natural movement pattern." + } + ], Beatmaps = new[] { new APIBeatmap @@ -305,10 +335,30 @@ public static APIBeatmapSet CreateAPIBeatmapSet(IBeatmapInfo original) RulesetID = original.Ruleset.OnlineID, StarRating = original.StarRating, DifficultyName = original.DifficultyName, + CircleSize = original.Difficulty.CircleSize, + DrainRate = original.Difficulty.DrainRate, + OverallDifficulty = original.Difficulty.OverallDifficulty, + ApproachRate = original.Difficulty.ApproachRate, + Length = original.Length, + HitLength = original.Length, + CircleCount = 111, + SliderCount = 12, + PlayCount = 222, + BPM = original.BPM, + PassCount = 21, + FailTimes = new APIFailTimes + { + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), + }, + TopTags = + [ + new APIBeatmapTag { TagId = 4, VoteCount = 1 }, + new APIBeatmapTag { TagId = 2, VoteCount = 1 }, + new APIBeatmapTag { TagId = 23, VoteCount = 5 }, + ], } - }, - HasFavourited = false, - FavouriteCount = 0, + } }; foreach (var beatmap in result.Beatmaps) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 86c84c0bb2eb..d9aa772f661f 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -274,15 +274,22 @@ public InLobby(Room room) public InLobby(MultiplayerRoom room) { - if (room.Settings.MatchType == MatchType.Matchmaking) + switch (room.Settings.MatchType) { - RoomID = -1; - RoomName = "Quick Play"; - } - else - { - RoomID = room.RoomID; - RoomName = room.Settings.Name; + case MatchType.Matchmaking: + RoomID = -1; + RoomName = "Quick Play"; + break; + + case MatchType.RankedPlay: + RoomID = -1; + RoomName = "Ranked Play"; + break; + + default: + RoomID = room.RoomID; + RoomName = room.Settings.Name; + break; } } From de9cf751d2f5e17011426a7d93e1c5701b64c676 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 7 Mar 2026 02:51:50 +0900 Subject: [PATCH 772/836] Fix `LoadingLayer` centering oops. --- osu.Game/Graphics/UserInterface/LoadingSpinner.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs index 24bf86c8ad9a..a2247006d73f 100644 --- a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs +++ b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs @@ -49,9 +49,6 @@ public LoadingSpinner(bool withBox = false, bool inverted = false) Anchor = Anchor.Centre; Origin = Anchor.Centre; - // Font awesome icon isn't centered perfectly. - Vector2 spinnerActualCentre = new Vector2(29.78f, 29.78f); - if (withBox) { Child = MainContents = new Container @@ -84,7 +81,6 @@ public LoadingSpinner(bool withBox = false, bool inverted = false) { Anchor = Anchor.Centre, Origin = Anchor.Custom, - OriginPosition = spinnerActualCentre, Colour = inverted ? Color4.Black : Color4.White, Scale = new Vector2(0.6f), RelativeSizeAxes = Axes.Both, @@ -108,7 +104,6 @@ public LoadingSpinner(bool withBox = false, bool inverted = false) { Anchor = Anchor.Centre, Origin = Anchor.Custom, - OriginPosition = spinnerActualCentre, Colour = inverted ? Color4.Black : Color4.White, RelativeSizeAxes = Axes.Both, Icon = FontAwesome.Solid.CircleNotch @@ -154,6 +149,9 @@ protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); + // Font awesome icon isn't centered perfectly. + spinner.OriginPosition = spinner.DrawSize * 0.4963333333f; + if (withBox) { MainContents.CornerRadius = MainContents.DrawWidth / 4; From ab2c91e10c0ce829ac2198632a764b839c101d33 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Sat, 7 Mar 2026 00:19:15 +0500 Subject: [PATCH 773/836] Slightly increase TD penalty (#36855) --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 3c8491a6dcd1..9865d40b77fa 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -56,7 +56,7 @@ protected override double StrainValueAt(DifficultyHitObject current) if (Mods.Any(m => m is OsuModTouchDevice)) { - aimDifficulty = Math.Pow(aimDifficulty, 0.8); + aimDifficulty = Math.Pow(aimDifficulty, 0.76); speedDifficulty = Math.Pow(speedDifficulty, 0.95); } From c4402e9ce511d81889e115159ff7f6c388471b42 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 7 Mar 2026 04:40:25 +0900 Subject: [PATCH 774/836] Fix potential crash due to handling scores in leaderboard post-disposal (#36860) Closes https://github.com/ppy/osu/issues/36858. Classic. --- osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs b/osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs index 660b5110113b..4373b7b0736c 100644 --- a/osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs +++ b/osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs @@ -256,7 +256,9 @@ public void RefetchScores() { // only bind this after the first fetch to avoid reading stale scores. fetchedScores.BindTo(leaderboardManager.Scores); - fetchedScores.BindValueChanged(_ => updateScores(), true); + + // Schedule is important here to avoid handling changes after this drawable is disposed. + fetchedScores.BindValueChanged(_ => Schedule(updateScores), true); initialFetchComplete = true; } }, initialFetchComplete && fetchScope != BeatmapLeaderboardScope.Local ? 300 : 0); From 8efb10dd2e908d1add2fb9c0902461df15092e09 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Sat, 7 Mar 2026 00:43:52 +0500 Subject: [PATCH 775/836] Increase high cs bonus in SpeedAim (#36856) --- .../Difficulty/Evaluators/SpeedAimEvaluator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs index afa1245820cf..246aa151f581 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs @@ -35,8 +35,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) // Max distance bonus is 1 * `distance_multiplier` at single_spacing_threshold double distanceBonus = Math.Pow(distance / SINGLE_SPACING_THRESHOLD, 2.9); - // Apply reduced small circle bonus because flow aim difficulty on small circles doesn't scale as hard as jumps - distanceBonus *= Math.Pow(osuCurrObj.SmallCircleBonus, 0.7); + // Apply increased high circle size bonus + distanceBonus *= Math.Pow(osuCurrObj.SmallCircleBonus, 1.5); double strain = distanceBonus * 1000 / osuCurrObj.AdjustedDeltaTime; From 14ae2312ffbdb06128b283f68866c39aedf2a38e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 7 Mar 2026 23:19:13 +0900 Subject: [PATCH 776/836] Fix a few flaky tests See failures on https://github.com/ppy/osu/runs/66073876886#r3s1. --- .../TestSceneDrawableStoryboardSprite.cs | 16 ++++++++++++++-- .../Navigation/TestSceneSongSelectNavigation.cs | 2 ++ .../SongSelect/TestSceneBeatmapTitleWedge.cs | 8 ++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs index 494365a2053b..afbd9da73cba 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs @@ -14,6 +14,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.IO.Stores; using osu.Framework.Testing; +using osu.Framework.Timing; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; @@ -53,12 +54,20 @@ public void TestSkinSpriteDisallowedByDefault() [Test] public void TestSpriteFadeOverflowBehaviour() { + ManualClock manualClock = new ManualClock(); + + AddStep("allow storyboard lookup", () => + { + storyboard.UseSkinSprites = false; + storyboard.ProvideResources = true; + }); + AddStep("create sprite", () => SetContents(_ => { var layer = storyboard.GetLayer("Background"); var sprite = new StoryboardSprite(lookup_name, Anchor.TopLeft, new Vector2(256, 192)); - sprite.Commands.AddAlpha(Easing.None, Time.Current, Time.Current + 2000, 0, 2); + sprite.Commands.AddAlpha(Easing.None, 0, 2000, 0, 2); layer.Elements.Clear(); layer.Add(sprite); @@ -68,13 +77,16 @@ public void TestSpriteFadeOverflowBehaviour() RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - storyboard.CreateDrawable() + storyboard.CreateDrawable().With(d => d.Clock = new FramedClock(manualClock)) } }; })); + AddStep("seek to 1000 ms", () => manualClock.CurrentTime = 900); AddUntilStep("sprite reached high opacity once", () => sprites.All(sprite => sprite.ChildrenOfType().All(s => s.Alpha > 0.8f))); + AddStep("seek to 2000 ms", () => manualClock.CurrentTime = 1100); AddUntilStep("sprite reset to low opacity", () => sprites.All(sprite => sprite.ChildrenOfType().All(s => s.Alpha < 0.2f))); + AddStep("seek to 2000 ms", () => manualClock.CurrentTime = 1900); AddUntilStep("sprite reached high opacity twice", () => sprites.All(sprite => sprite.ChildrenOfType().All(s => s.Alpha > 0.8f))); } diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs index 298461380776..461061c56846 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs @@ -82,6 +82,8 @@ public void TestEditBeatmap() AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault); AddStep("open menu", () => InputManager.Key(Key.F3)); + AddUntilStep("wait for footer focus", () => InputManager.FocusedDrawable is FooterButtonOptions.Popover); + AddStep("trigger edit", () => { // TODO: should be 5, not 4. diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedge.cs index 0d14de8b9e48..2421cf7bc316 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedge.cs @@ -240,11 +240,11 @@ public void TestFavouriting() }); AddStep("reset event", resetEvent.Reset); AddStep("click favourite button", () => this.ChildrenOfType().Single().TriggerClick()); - AddAssert("spinner visible", () => this.ChildrenOfType().Single() - .ChildrenOfType().Single().State.Value, () => Is.EqualTo(Visibility.Visible)); + AddUntilStep("spinner visible", () => this.ChildrenOfType().Single() + .ChildrenOfType().Single().State.Value, () => Is.EqualTo(Visibility.Visible)); AddStep("allow request to complete", resetEvent.Set); - AddAssert("spinner hidden", () => this.ChildrenOfType().Single() - .ChildrenOfType().Single().State.Value, () => Is.EqualTo(Visibility.Hidden)); + AddUntilStep("spinner hidden", () => this.ChildrenOfType().Single() + .ChildrenOfType().Single().State.Value, () => Is.EqualTo(Visibility.Hidden)); } [TestCase(120, 125, null, "120-125 (mostly 120)")] From e3a0464e90ab8f5bdcef1b4716fc9cfdff0a00c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 7 Mar 2026 23:39:17 +0900 Subject: [PATCH 777/836] Update a few sample playback usages to use new helper method --- .../Containers/OsuRearrangeableListContainer.cs | 8 ++------ osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 13 +++---------- osu.Game/Graphics/UserInterface/HoverSounds.cs | 5 ++--- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 10 ++-------- 4 files changed, 9 insertions(+), 27 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs b/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs index fcc48d80ea2b..ab0bd6007e08 100644 --- a/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs +++ b/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs @@ -10,7 +10,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Utils; +using osu.Game.Audio; namespace osu.Game.Graphics.Containers { @@ -52,12 +52,8 @@ private void playSwapSample() if (Time.Current - sampleLastPlaybackTime <= 35) return; - var channel = sampleSwap?.GetChannel(); - if (channel == null) - return; + SamplePlaybackHelper.PlayWithRandomPitch(sampleSwap, pitchVariation: 0.04); - channel.Frequency.Value = 0.96 + RNG.NextDouble(0.08); - channel.Play(); sampleLastPlaybackTime = Time.Current; } diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index b8f97cab5ea4..ef95288be795 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -8,6 +8,7 @@ using osu.Framework.Extensions; using osu.Framework.Input.Events; using osu.Framework.Utils; +using osu.Game.Audio; using osuTK.Input; namespace osu.Game.Graphics.UserInterface @@ -55,15 +56,7 @@ protected override bool OnClick(ClickEvent e) return base.OnClick(e); } - public void PlayClickSample() - { - var channel = Enabled.Value ? sampleClick?.GetChannel() : sampleClickDisabled?.GetChannel(); - - if (channel != null) - { - channel.Frequency.Value = 0.99 + RNG.NextDouble(0.02); - channel.Play(); - } - } + public void PlayClickSample() => + SamplePlaybackHelper.PlayWithRandomPitch(Enabled.Value ? sampleClick : sampleClickDisabled, pitchVariation: 0.01); } } diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index cd67a0f93504..b305104eeeda 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -9,7 +9,7 @@ using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; -using osu.Framework.Utils; +using osu.Game.Audio; namespace osu.Game.Graphics.UserInterface { @@ -43,8 +43,7 @@ public override void PlayHoverSample() if (!Enabled.Value) return; - sampleHover.Frequency.Value = 0.98 + RNG.NextDouble(0.04); - sampleHover.Play(); + SamplePlaybackHelper.PlayWithRandomPitch(sampleHover, pitchVariation: 0.02); } } } diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index f91a67a7e36c..50787726fb27 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -15,6 +15,7 @@ using osu.Framework.Threading; using osu.Framework.Timing; using osu.Framework.Utils; +using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -414,14 +415,7 @@ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, if (!IsBeatSyncedWithTrack || !EnableClicking) return; - var channel = beatIndex % timingPoint.TimeSignature.Numerator == 0 ? sampleTickDownbeat?.GetChannel() : sampleTick?.GetChannel(); - - if (channel == null) - return; - - channel.Frequency.Value = RNG.NextDouble(0.98f, 1.02f); - channel.Play(); - + SamplePlaybackHelper.PlayWithRandomPitch(beatIndex % timingPoint.TimeSignature.Numerator == 0 ? sampleTickDownbeat : sampleTick, 0.02f); Ticked?.Invoke(); } } From 7227afebbb7c4a752a4746a4a2864b6d328fa7bb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Mar 2026 08:22:16 +0900 Subject: [PATCH 778/836] Fix missed using statement --- osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index ef95288be795..f1c14eb6b530 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -7,7 +7,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Extensions; using osu.Framework.Input.Events; -using osu.Framework.Utils; using osu.Game.Audio; using osuTK.Input; From e4f7bd5443733d7a3306801e8ec49f68ecccf41b Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 8 Mar 2026 22:50:50 -0700 Subject: [PATCH 779/836] Fix score delete dialog not using user-facing rank terminology (#36861) - Resolves https://github.com/ppy/osu/issues/36859 | Before | After | | --- | --- | | image | image | While we're here, should there be more statistics shown? At least score, and maybe max combo too. Not doing for now. Proposed order: User (Score, Max Combo, Accuracy, Rank) Order is derived from the leaderboard score left to right, but prioritizes score first as I believe that is the most important in differentiating what score is which. --- osu.Game/Screens/Select/LocalScoreDeleteDialog.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs b/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs index ec2b8437e1aa..4127e474f884 100644 --- a/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs +++ b/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Extensions; using osu.Game.Overlays.Dialog; using osu.Game.Scoring; @@ -19,7 +20,7 @@ public LocalScoreDeleteDialog(ScoreInfo score) [BackgroundDependencyLoader] private void load(ScoreManager scoreManager) { - BodyText = $"{score.User} ({score.DisplayAccuracy}, {score.Rank})"; + BodyText = $"{score.User} ({score.DisplayAccuracy}, {score.Rank.GetLocalisableDescription()})"; DangerousAction = () => scoreManager.Delete(score); } } From a34440888ec98665b8db7ffb91c23aeab2010a81 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 9 Mar 2026 15:49:07 +0900 Subject: [PATCH 780/836] Fix possible exception (#36895) Randomly encountered this one. Not sure how it behaves in practice/whether this is the correct fix, but it should be quite rare? ``` System.ArgumentOutOfRangeException: duration ('-199.99999999999955') must be a non-negative value. (Parameter 'duration') Actual value was -199.99999999999955. at System.ArgumentOutOfRangeException.ThrowNegative[T](T value, String paramName) at System.ArgumentOutOfRangeException.ThrowIfNegative[T](T value, String paramName) at osu.Framework.Graphics.TransformableExtensions.PopulateTransform[TValue,TEasing,TThis](TThis t, Transform`3 transform, TValue newValue, Double duration, TEasing& easing) at osu.Framework.Graphics.TransformableExtensions.MakeTransform[TThis,TEasing,TValue](TThis t, String propertyOrFieldName, TValue newValue, Double duration, TEasing& easing, String grouping) at osu.Framework.Graphics.TransformableExtensions.TransformTo[TThis,TValue,TEasing](TThis t, String propertyOrFieldName, TValue newValue, Double duration, TEasing& easing, String grouping) at osu.Framework.Graphics.TransformableExtensions.ScaleTo[T,TEasing](T drawable, Vector2 newScale, Double duration, TEasing& easing) at osu.Framework.Graphics.TransformableExtensions.ScaleTo[T,TEasing](T drawable, Single newScale, Double duration, TEasing& easing) at osu.Framework.Graphics.TransformSequenceExtensions.<>c__DisplayClass42_0`2.b__0(T o) at osu.Framework.Graphics.Transforms.TransformSequence`1.Append(Generator childGenerator) at osu.Framework.Graphics.TransformSequenceExtensions.ScaleTo[T,TEasing](TransformSequence`1 t, Single newScale, Double duration, TEasing easing) at osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card.RankedPlayCard.SongPreviewContainer.PulseContainer.OnNewBeat(Int32 beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) ``` --- .../Matchmaking/RankedPlay/Card/RankedPlayCard.SongPreview.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCard.SongPreview.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCard.SongPreview.cs index 6559fd586003..b1350a95715f 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCard.SongPreview.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Card/RankedPlayCard.SongPreview.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.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Audio; @@ -183,7 +184,7 @@ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, this.ScaleTo(1.02f, EXPAND_DURATION, Easing.In) .Then() - .ScaleTo(1f, beatLength - EXPAND_DURATION, new CubicBezierEasingFunction(easeIn: 0.1f, easeOut: 1f)); + .ScaleTo(1f, Math.Max(0, beatLength - EXPAND_DURATION), new CubicBezierEasingFunction(easeIn: 0.1f, easeOut: 1f)); } } From 3b86d15572ef1efbd61fd71515a2c21d140ffc0b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 9 Mar 2026 16:14:31 +0900 Subject: [PATCH 781/836] Mute warning samples during stage fast forwards (#36894) In particular, the discard stage fast forwards using a 3s timer: https://github.com/ppy/osu-server-spectator/blob/9cb1dd35c677f216a7cf93b04fd490c68a76f632/osu.Server.Spectator/Hubs/Multiplayer/Matchmaking/RankedPlay/Stages/CardDiscardStage.cs#L46-L48 Play stage changes are only to conform to this new implementation. --- .../Matchmaking/RankedPlay/DiscardScreen.cs | 29 +++++++++++++------ .../Matchmaking/RankedPlay/PickScreen.cs | 22 ++++++++------ 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs index fbc86e5c9777..c044a0d4c6c9 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs @@ -46,11 +46,16 @@ public partial class DiscardScreen : RankedPlaySubScreen private const int card_play_samples = 2; private Sample?[]? cardPlaySamples; - private bool timeRunningOutWarningActive; + /// + /// Whether the local user has discarded cards. + /// + private bool hasDiscardedCards; + private Sample? timeRunningOutSample; private SampleChannel? timeRunningOutSampleChannel; private DateTimeOffset stageEndTime; + private TimeSpan stageDuration; [BackgroundDependencyLoader] private void load(AudioManager audio) @@ -143,13 +148,17 @@ protected override void LoadComplete() onSelectionChanged(); } + private bool shouldPlayWarningSample + => matchInfo.Stage.Value == RankedPlayStage.CardDiscard + && stageDuration > TimeSpan.FromSeconds(warning_time_threshold) + && stageEndTime - DateTimeOffset.Now < TimeSpan.FromSeconds(warning_time_threshold) + && !hasDiscardedCards; + protected override void Update() { base.Update(); - TimeSpan remainingTime = stageEndTime - DateTimeOffset.Now; - - if (timeRunningOutWarningActive && remainingTime.TotalSeconds < warning_time_threshold) + if (shouldPlayWarningSample) { timeRunningOutSampleChannel ??= timeRunningOutSample?.GetChannel(); @@ -160,6 +169,8 @@ protected override void Update() timeRunningOutSampleChannel.Looping = true; timeRunningOutSampleChannel.Play(); } + else + timeRunningOutSampleChannel?.Stop(); } public override void OnEntering(RankedPlaySubScreen? previous) @@ -187,11 +198,11 @@ public override void OnEntering(RankedPlaySubScreen? previous) private void onCountdownStarted(MultiplayerCountdown countdown) => Scheduler.Add(() => { - if (countdown is not RankedPlayStageCountdown stageCountdown) + if (countdown is not RankedPlayStageCountdown) return; stageEndTime = DateTimeOffset.Now + countdown.TimeRemaining; - timeRunningOutWarningActive = stageCountdown.Stage == RankedPlayStage.CardDiscard; + stageDuration = countdown.TimeRemaining; }); private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add(() => @@ -199,10 +210,8 @@ private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add if (countdown is not RankedPlayStageCountdown) return; - timeRunningOutSampleChannel?.Stop(); - stageEndTime = DateTimeOffset.Now; - timeRunningOutWarningActive = false; + stageDuration = TimeSpan.Zero; }); private void onSelectionChanged() @@ -219,6 +228,8 @@ private void onDiscardButtonClicked() Client.DiscardCards(playerHand.Selection.Select(it => it.Card).ToArray()).FireAndForget(); playerHand.SelectionMode = HandSelectionMode.Disabled; + + hasDiscardedCards = true; } private readonly List discardedCards = new List(); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs index 2f59e22b0f37..0a232322ca3c 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs @@ -38,12 +38,12 @@ public partial class PickScreen : RankedPlaySubScreen private const int card_play_samples = 2; private Sample?[]? cardPlaySamples; - private bool timeRunningOutWarningActive; private Sample? timeRunningOutSample; private SampleChannel? timeRunningOutSampleChannel; private Sample? timeUpBuzzerSample; private DateTimeOffset stageEndTime; + private TimeSpan stageDuration; /// /// Whether the local user has played a card themselves. @@ -122,13 +122,17 @@ protected override void LoadComplete() } } + private bool shouldPlayWarningSample + => matchInfo.Stage.Value == RankedPlayStage.CardPlay + && stageDuration > TimeSpan.FromSeconds(warning_time_threshold) + && stageEndTime - DateTimeOffset.Now < TimeSpan.FromSeconds(warning_time_threshold) + && !hasPlayedCard; + protected override void Update() { base.Update(); - TimeSpan remainingTime = stageEndTime - DateTimeOffset.Now; - - if (timeRunningOutWarningActive && remainingTime.TotalSeconds < warning_time_threshold) + if (shouldPlayWarningSample) { timeRunningOutSampleChannel ??= timeRunningOutSample?.GetChannel(); @@ -139,6 +143,8 @@ protected override void Update() timeRunningOutSampleChannel.Looping = true; timeRunningOutSampleChannel.Play(); } + else + timeRunningOutSampleChannel?.Stop(); } public override void OnEntering(RankedPlaySubScreen? previous) @@ -184,11 +190,11 @@ public override void OnEntering(RankedPlaySubScreen? previous) private void onCountdownStarted(MultiplayerCountdown countdown) => Scheduler.Add(() => { - if (countdown is not RankedPlayStageCountdown stageCountdown) + if (countdown is not RankedPlayStageCountdown) return; stageEndTime = DateTimeOffset.Now + countdown.TimeRemaining; - timeRunningOutWarningActive = stageCountdown.Stage == RankedPlayStage.CardPlay; + stageDuration = countdown.TimeRemaining; }); private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add(() => @@ -196,10 +202,8 @@ private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add if (countdown is not RankedPlayStageCountdown stageCountdown) return; - timeRunningOutSampleChannel?.Stop(); - stageEndTime = DateTimeOffset.Now; - timeRunningOutWarningActive = false; + stageDuration = TimeSpan.Zero; if (stageCountdown.Stage == RankedPlayStage.CardPlay && !hasPlayedCard) timeUpBuzzerSample?.Play(); From a7860dd4c1ff88710d317f1eaad031bcba056172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 9 Mar 2026 11:58:38 +0100 Subject: [PATCH 782/836] Fix timeline selection box showing rotation handles closes https://github.com/ppy/osu/issues/36888. oooooooops. --- .../Screens/Edit/Compose/Components/SelectionBox.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs index 03838182a617..40eb1e66c7c1 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs @@ -286,10 +286,13 @@ private void recreateRotationHandles() dragHandles.ClearRotationHandles(); - addRotateHandle(Anchor.TopLeft); - addRotateHandle(Anchor.TopRight); - addRotateHandle(Anchor.BottomLeft); - addRotateHandle(Anchor.BottomRight); + if (canRotate.Value) + { + addRotateHandle(Anchor.TopLeft); + addRotateHandle(Anchor.TopRight); + addRotateHandle(Anchor.BottomLeft); + addRotateHandle(Anchor.BottomRight); + } } private void addRotateHandle(Anchor anchor) From c2e9b052e775c96d4b8ff1e664f08345fd268d0a Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Tue, 10 Mar 2026 02:48:27 +0500 Subject: [PATCH 783/836] Add basic flow evaluation (#36902) https://pp.huismetbenen.nl/rankings/players/stanr-aimsep --- ...eedAimEvaluator.cs => AgilityEvaluator.cs} | 23 ++-- .../Difficulty/Evaluators/FlowAimEvaluator.cs | 117 ++++++++++++++++++ .../{AimEvaluator.cs => SnapAimEvaluator.cs} | 19 ++- .../Preprocessing/OsuDifficultyHitObject.cs | 9 ++ .../Difficulty/Skills/Aim.cs | 79 ++++++++---- .../Difficulty/Skills/Speed.cs | 2 +- 6 files changed, 199 insertions(+), 50 deletions(-) rename osu.Game.Rulesets.Osu/Difficulty/Evaluators/{SpeedAimEvaluator.cs => AgilityEvaluator.cs} (53%) create mode 100644 osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlowAimEvaluator.cs rename osu.Game.Rulesets.Osu/Difficulty/Evaluators/{AimEvaluator.cs => SnapAimEvaluator.cs} (91%) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AgilityEvaluator.cs similarity index 53% rename from osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs rename to osu.Game.Rulesets.Osu/Difficulty/Evaluators/AgilityEvaluator.cs index 246aa151f581..2d0d2897a2be 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AgilityEvaluator.cs @@ -3,20 +3,18 @@ using System; using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { - public static class SpeedAimEvaluator + public static class AgilityEvaluator { - public const double SINGLE_SPACING_THRESHOLD = OsuDifficultyHitObject.NORMALISED_DIAMETER * 1.25; // 1.25 circles distance between centers + private const double distance_cap = OsuDifficultyHitObject.NORMALISED_DIAMETER * 1.25; // 1.25 circles distance between centers /// - /// Evaluates the difficulty of aiming the current object, based on: - /// - /// distance between the previous and current object - /// + /// Evaluates the difficulty of fast aiming /// public static double EvaluateDifficultyOf(DifficultyHitObject current) { @@ -29,20 +27,13 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) double travelDistance = osuPrevObj?.LazyTravelDistance ?? 0; double distance = travelDistance + osuCurrObj.LazyJumpDistance; - // Cap distance at single_spacing_threshold - distance = Math.Min(distance, SINGLE_SPACING_THRESHOLD); + double distanceScaled = Math.Min(distance, distance_cap) / distance_cap; - // Max distance bonus is 1 * `distance_multiplier` at single_spacing_threshold - double distanceBonus = Math.Pow(distance / SINGLE_SPACING_THRESHOLD, 2.9); - - // Apply increased high circle size bonus - distanceBonus *= Math.Pow(osuCurrObj.SmallCircleBonus, 1.5); - - double strain = distanceBonus * 1000 / osuCurrObj.AdjustedDeltaTime; + double strain = distanceScaled * 1000 / osuCurrObj.AdjustedDeltaTime; strain *= highBpmBonus(osuCurrObj.AdjustedDeltaTime); - return strain; + return strain * DifficultyCalculationUtils.Smootherstep(distance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS); } private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.3, Math.Pow(ms / 1000, 0.9))); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlowAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlowAimEvaluator.cs new file mode 100644 index 000000000000..61451c4f9398 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlowAimEvaluator.cs @@ -0,0 +1,117 @@ +// 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 osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Utils; +using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; +using osu.Game.Rulesets.Osu.Objects; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators +{ + public static class FlowAimEvaluator + { + private const double velocity_change_multiplier = 2.0; + + /// + /// Evaluates difficulty of "flow aim" - aiming pattern where player doesn't stop their cursor on every object and instead "flows" through them. + /// + public static double EvaluateDifficultyOf(DifficultyHitObject current, bool withSliderTravelDistance) + { + if (current.BaseObject is Spinner || current.Index <= 1 || current.Previous(0).BaseObject is Spinner) + return 0; + + var osuCurrObj = (OsuDifficultyHitObject)current; + var osuLastObj = (OsuDifficultyHitObject)current.Previous(0); + var osuLastLastObj = (OsuDifficultyHitObject)current.Previous(1); + + double currDistance = withSliderTravelDistance ? osuCurrObj.LazyJumpDistance : osuCurrObj.JumpDistance; + double prevDistance = withSliderTravelDistance ? osuLastObj.LazyJumpDistance : osuLastObj.JumpDistance; + + double currVelocity = currDistance / osuCurrObj.AdjustedDeltaTime; + + if (osuLastObj.BaseObject is Slider && withSliderTravelDistance) + { + // If the last object is a slider, then we extend the travel velocity through the slider into the current object. + double sliderDistance = osuLastObj.LazyTravelDistance + osuCurrObj.LazyJumpDistance; + currVelocity = Math.Max(currVelocity, sliderDistance / osuCurrObj.AdjustedDeltaTime); + } + + double prevVelocity = prevDistance / osuLastObj.AdjustedDeltaTime; + + double flowDifficulty = currVelocity; + + // Apply high circle size bonus to the base velocity + flowDifficulty *= osuCurrObj.SmallCircleBonus; + + // Rhythm changes are harder to flow + flowDifficulty *= 1 + Math.Min(0.25, + Math.Pow((Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) - Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime)) / 50, 4)); + + if (osuCurrObj.AngularVelocity != null) + { + // Low angular velocity flow (angles are consistent) is easier to follow than erratic flow + flowDifficulty *= 0.8 + Math.Sqrt(osuCurrObj.AngularVelocity.Value / 270.0); + } + + // If all three notes are overlapping - don't reward bonuses as you don't have to do additional movement + double overlappedNotesWeight = 1; + + if (current.Index > 2) + { + double o1 = calculateOverlapFactor(osuCurrObj, osuLastObj); + double o2 = calculateOverlapFactor(osuCurrObj, osuLastLastObj); + double o3 = calculateOverlapFactor(osuLastObj, osuLastLastObj); + + overlappedNotesWeight = 1 - o1 * o2 * o3; + } + + if (osuCurrObj.Angle != null && osuLastObj.Angle != null) + { + // Acute angles are also hard to flow + // We square root velocity to make acute angle switches in streams aren't having difficulty higher than snap + flowDifficulty += Math.Sqrt(currVelocity) * + SnapAimEvaluator.CalcAcuteAngleBonus(osuCurrObj.Angle.Value) * + overlappedNotesWeight; + } + + if (Math.Max(prevVelocity, currVelocity) != 0) + { + if (withSliderTravelDistance) + { + currVelocity = currDistance / osuCurrObj.AdjustedDeltaTime; + prevVelocity = prevDistance / osuLastObj.AdjustedDeltaTime; + } + + // Scale with ratio of difference compared to 0.5 * max dist. + double distRatio = DifficultyCalculationUtils.Smoothstep(Math.Abs(prevVelocity - currVelocity) / Math.Max(prevVelocity, currVelocity), 0, 1); + + // Reward for % distance up to 125 / strainTime for overlaps where velocity is still changing. + double overlapVelocityBuff = Math.Min(OsuDifficultyHitObject.NORMALISED_DIAMETER * 1.25 / Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime), + Math.Abs(prevVelocity - currVelocity)); + + flowDifficulty += overlapVelocityBuff * distRatio * velocity_change_multiplier; + } + + if (osuCurrObj.BaseObject is Slider) + { + // Include slider velocity to make velocity more consistent with snap + flowDifficulty += osuCurrObj.TravelDistance / osuCurrObj.TravelTime; + } + + // Final velocity is being raised to a power because flow difficulty scales harder with both high distance and time, and we want to account for that + return Math.Pow(flowDifficulty, 1.45); + } + + private static double calculateOverlapFactor(OsuDifficultyHitObject first, OsuDifficultyHitObject second) + { + var firstBase = (OsuHitObject)first.BaseObject; + var secondBase = (OsuHitObject)second.BaseObject; + double objectRadius = firstBase.Radius; + + double distance = Vector2.Distance(firstBase.StackedPosition, secondBase.StackedPosition); + return Math.Clamp(1 - Math.Pow(Math.Max(distance - objectRadius, 0) / objectRadius, 2), 0, 1); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SnapAimEvaluator.cs similarity index 91% rename from osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs rename to osu.Game.Rulesets.Osu/Difficulty/Evaluators/SnapAimEvaluator.cs index 9f9bbb7eb32b..58bf9dc48eae 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SnapAimEvaluator.cs @@ -9,12 +9,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { - public static class AimEvaluator + public static class SnapAimEvaluator { - private const double wide_angle_multiplier = 1.35; + private const double wide_angle_multiplier = 1.3; private const double acute_angle_multiplier = 2.5; private const double slider_multiplier = 1.9; - private const double velocity_change_multiplier = 1.1; + private const double velocity_change_multiplier = 1.0; private const double wiggle_multiplier = 1.02; // WARNING: Increasing this multiplier beyond 1.02 reduces difficulty as distance increases. Refer to the desmos link above the wiggle bonus calculation /// @@ -78,24 +78,23 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with if (Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) < 1.25 * Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime)) // If rhythms are the same. { - acuteAngleBonus = calcAcuteAngleBonus(currAngle); + acuteAngleBonus = CalcAcuteAngleBonus(currAngle); // Penalize angle repetition. - acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 3))); + acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(CalcAcuteAngleBonus(lastAngle), 3))); // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter acuteAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * - DifficultyCalculationUtils.Smootherstep(currDistance, diameter, diameter * 2); + DifficultyCalculationUtils.Smootherstep(currDistance, 0, diameter * 2); } wideAngleBonus = calcWideAngleBonus(currAngle); // Penalize angle repetition. - wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3)); + wideAngleBonus *= 0.25 + 0.75 * (1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3))); - // Apply full wide angle bonus for distance more than SINGLE_SPACING_THRESHOLD - wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smoothstep(currDistance, 0, SpeedAimEvaluator.SINGLE_SPACING_THRESHOLD); + wideAngleBonus *= angleBonus; // Apply wiggle bonus for jumps that are [radius, 3*diameter] in distance, with < 110 angle // https://www.desmos.com/calculator/dp0v0nvowc @@ -176,6 +175,6 @@ private static double highBpmBonus(double ms, double distance) => 1 / (1 - Math. private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); - private static double calcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40)); + public static double CalcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40)); } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 33bb6b29c8b5..848816503dc4 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -116,6 +116,8 @@ public class OsuDifficultyHitObject : DifficultyHitObject /// public double? Angle { get; private set; } + public double? AngularVelocity { get; private set; } + /// /// Selective bonus for maps with higher circle size. /// @@ -260,6 +262,13 @@ private void setDistances(double clockRate) double sliderAngle = calculateSliderAngle(lastDifficultyObject!, lastLastCursorPosition); Angle = Math.Min(angle, sliderAngle); + + if (lastLastDifficultyObject.Angle != null) + { + double angleDifference = Math.Abs(Angle.Value - lastLastDifficultyObject.Angle.Value); + double angleDifferenceAdjusted = Math.Sin(angleDifference / 2) * 180.0; + AngularVelocity = angleDifferenceAdjusted / (AdjustedDeltaTime * 0.1); + } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 9865d40b77fa..101dd2250aaf 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -28,57 +28,90 @@ public Aim(Mod[] mods, bool includeSliders) IncludeSliders = includeSliders; } - private double currentAimStrain; - private double currentSpeedStrain; + private double currentStrain; - private double skillMultiplierAim => 65.2; - private double skillMultiplierSpeed => 2.8; + private double skillMultiplierSnap => 65.2; + private double skillMultiplierAgility => 2.7; + private double skillMultiplierFlow => 262.0; private double skillMultiplierTotal => 1.0; private double meanExponent => 1.2; private readonly List sliderStrains = new List(); - private double strainDecayAim(double ms) => Math.Pow(0.15, ms / 1000); - private double strainDecaySpeed(double ms) => Math.Pow(0.3, ms / 1000); + private double strainDecay(double ms) => Math.Pow(0.15, ms / 1000); protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => - DifficultyCalculationUtils.Norm(meanExponent, - currentAimStrain * strainDecayAim(time - current.Previous(0).StartTime), - currentSpeedStrain * strainDecaySpeed(time - current.Previous(0).StartTime)) * skillMultiplierTotal; + currentStrain * strainDecay(time - current.Previous(0).StartTime); protected override double StrainValueAt(DifficultyHitObject current) { - double decayAim = strainDecayAim(((OsuDifficultyHitObject)current).AdjustedDeltaTime); - double decaySpeed = strainDecaySpeed(((OsuDifficultyHitObject)current).AdjustedDeltaTime); + double decay = strainDecay(((OsuDifficultyHitObject)current).AdjustedDeltaTime); - double aimDifficulty = AimEvaluator.EvaluateDifficultyOf(current, IncludeSliders); - double speedDifficulty = SpeedAimEvaluator.EvaluateDifficultyOf(current); + double snapDifficulty = SnapAimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * skillMultiplierSnap; + double agilityDifficulty = AgilityEvaluator.EvaluateDifficultyOf(current) * skillMultiplierAgility; + double flowDifficulty = FlowAimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * skillMultiplierFlow; if (Mods.Any(m => m is OsuModTouchDevice)) { - aimDifficulty = Math.Pow(aimDifficulty, 0.76); - speedDifficulty = Math.Pow(speedDifficulty, 0.95); + snapDifficulty = Math.Pow(snapDifficulty, 0.89); + // we don't adjust agility here since agility represents TD difficulty in a decent enough way + flowDifficulty = Math.Pow(flowDifficulty, 1.1); } if (Mods.Any(m => m is OsuModRelax)) { - speedDifficulty *= 0.0; + agilityDifficulty *= 0.0; + flowDifficulty *= 0.1; } - currentAimStrain *= decayAim; - currentAimStrain += aimDifficulty * (1 - decayAim) * skillMultiplierAim; + double totalDifficulty = calculateTotalValue(snapDifficulty, agilityDifficulty, flowDifficulty); - currentSpeedStrain *= decaySpeed; - currentSpeedStrain += speedDifficulty * (1 - decaySpeed) * skillMultiplierSpeed; - - double totalStrain = DifficultyCalculationUtils.Norm(meanExponent, currentAimStrain, currentSpeedStrain) * skillMultiplierTotal; + currentStrain *= decay; + currentStrain += totalDifficulty * (1 - decay); if (current.BaseObject is Slider) - sliderStrains.Add(totalStrain); + sliderStrains.Add(currentStrain); + + return currentStrain; + } + + private double calculateTotalValue(double snapDifficulty, double agilityDifficulty, double flowDifficulty) + { + // We compare flow to combined snap and agility because snap by itself doesn't have enough difficulty to be above flow on streams + // Agility on the other hand is supposed to measure the rate of cursor velocity changes while snapping + // So snapping every circle on a stream requires an enormous amount of agility at which point it's easier to flow + double combinedSnapDifficulty = DifficultyCalculationUtils.Norm(meanExponent, snapDifficulty, agilityDifficulty); + + double pSnap = calculateSnapFlowProbability(flowDifficulty / combinedSnapDifficulty); + double pFlow = 1 - pSnap; + + double totalDifficulty = combinedSnapDifficulty * pSnap + flowDifficulty * pFlow; + + double totalStrain = totalDifficulty * skillMultiplierTotal; return totalStrain; } + // A function that turns the ratio of snap : flow into the probability of snapping/flowing + // It has the constraints: + // P(snap) + P(flow) = 1 (the object is always either snapped or flowed) + // P(snap) = f(snap/flow), P(flow) = f(flow/snap) (ie snap and flow are symmetric and reversible) + // Therefore: f(x) + f(1/x) = 1 + // 0 <= f(x) <= 1 (cannot have negative or greater than 100% probability of snapping or flowing) + // This logistic function is a solution, which fits nicely with the general idea of interpolation and provides a tuneable constant + private static double calculateSnapFlowProbability(double ratio) + { + const double k = 7.27; + + if (ratio == 0) + return 0; + + if (double.IsNaN(ratio)) + return 1; + + return DifficultyCalculationUtils.Logistic(-k * Math.Log(ratio)); + } + public double GetDifficultSliders() { if (sliderStrains.Count == 0) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 211d9d57b9ac..a50a5cfab687 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Speed : HarmonicSkill { - private double skillMultiplier => 1.07; + private double skillMultiplier => 1.05; private readonly List sliderStrains = new List(); From f3d97c083538e09fca0ef2fad99f4c3e9ca772de Mon Sep 17 00:00:00 2001 From: kwotaq <80002984+kwotaq@users.noreply.github.com> Date: Tue, 10 Mar 2026 01:12:22 +0200 Subject: [PATCH 784/836] Penalize angle repetition depending on the difference between vectors (#36559) This is a slightly more intelligent angle repetition nerf that checks the previous vectors to see if the pattern has any rotation or not, this allows for harsh nerfs on current meta patterning like the N, X and V patterns while keeping things like rotating 1-2s and triangles less nerfed. The effect the vectors have on angle repetition is adjustable. --------- Co-authored-by: StanR --- .../Difficulty/Evaluators/SnapAimEvaluator.cs | 59 +++++++++++++++++-- .../Preprocessing/OsuDifficultyHitObject.cs | 9 +++ .../Difficulty/Skills/Aim.cs | 8 +-- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SnapAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SnapAimEvaluator.cs index 58bf9dc48eae..15d8ef033e5b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SnapAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SnapAimEvaluator.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Extensions.ObjectExtensions; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; @@ -11,11 +12,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { public static class SnapAimEvaluator { - private const double wide_angle_multiplier = 1.3; - private const double acute_angle_multiplier = 2.5; - private const double slider_multiplier = 1.9; - private const double velocity_change_multiplier = 1.0; + private const double wide_angle_multiplier = 1.05; + private const double acute_angle_multiplier = 2.41; + private const double slider_multiplier = 1.5; + private const double velocity_change_multiplier = 0.9; private const double wiggle_multiplier = 1.02; // WARNING: Increasing this multiplier beyond 1.02 reduces difficulty as distance increases. Refer to the desmos link above the wiggle bonus calculation + private const double maximum_repetition_nerf = 0.15; + private const double maximum_vector_influence = 0.5; /// /// Evaluates the difficulty of aiming the current object, based on: @@ -117,7 +120,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with if (distance < 1) { - wideAngleBonus *= 1 - 0.35 * (1 - distance); + wideAngleBonus *= 1 - 0.55 * (1 - distance); } } } @@ -149,6 +152,9 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; } + // Penalize angle repetition. + aimStrain *= vectorAngleRepetition(osuCurrObj, osuLastObj); + aimStrain += wiggleBonus * wiggle_multiplier; aimStrain += velocityChangeBonus * velocity_change_multiplier; @@ -173,6 +179,49 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with private static double highBpmBonus(double ms, double distance) => 1 / (1 - Math.Pow(0.03, Math.Pow(ms / 1000, 0.65))) * DifficultyCalculationUtils.Smootherstep(distance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS); + private static double vectorAngleRepetition(OsuDifficultyHitObject current, OsuDifficultyHitObject previous) + { + if (current.Angle == null || previous.Angle == null) + return 1; + + const double note_limit = 6; + + double constantAngleCount = 0; + + for (int index = 0; index < note_limit; index++) + { + var loopObj = (OsuDifficultyHitObject)current.Previous(index); + + if (loopObj.IsNull()) + break; + + // Only consider vectors in the same jump section, stopping to change rhythm ruins momentum + if (Math.Max(current.AdjustedDeltaTime, loopObj.AdjustedDeltaTime) > 1.1 * Math.Min(current.AdjustedDeltaTime, loopObj.AdjustedDeltaTime)) + break; + + if (loopObj.NormalisedVectorAngle.IsNotNull() && current.NormalisedVectorAngle.IsNotNull()) + { + double angleDifference = Math.Abs(current.NormalisedVectorAngle.Value - loopObj.NormalisedVectorAngle.Value); + // Refer to this desmos for tuning, constants need to be precise so that values stay within the range of 0 and 1. + // https://www.desmos.com/calculator/a8jesv5sv2 + constantAngleCount += Math.Cos(8 * Math.Min(double.DegreesToRadians(11.25), angleDifference)); + } + } + + double vectorRepetition = Math.Pow(Math.Min(0.5 / constantAngleCount, 1), 2); + + double stackFactor = DifficultyCalculationUtils.Smootherstep(current.LazyJumpDistance, 0, OsuDifficultyHitObject.NORMALISED_DIAMETER); + + double currAngle = current.Angle.Value; + double lastAngle = previous.Angle.Value; + + double angleDifferenceAdjusted = Math.Cos(2 * Math.Min(double.DegreesToRadians(45), Math.Abs(currAngle - lastAngle) * stackFactor)); + + double baseNerf = 1 - maximum_repetition_nerf * CalcAcuteAngleBonus(lastAngle) * angleDifferenceAdjusted; + + return Math.Pow(baseNerf + (1 - baseNerf) * vectorRepetition * maximum_vector_influence * stackFactor, 2); + } + private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); public static double CalcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40)); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 848816503dc4..68950829f3cf 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -118,6 +118,12 @@ public class OsuDifficultyHitObject : DifficultyHitObject public double? AngularVelocity { get; private set; } + /// + /// Angle of the vector created between current and current-1 + /// normalised to consider symmetrical vectors in any axis to be the same angle. + /// + public double? NormalisedVectorAngle { get; private set; } + /// /// Selective bonus for maps with higher circle size. /// @@ -261,6 +267,9 @@ private void setDistances(double clockRate) double angle = calculateAngle(BaseObject.StackedPosition, lastCursorPosition, lastLastCursorPosition); double sliderAngle = calculateSliderAngle(lastDifficultyObject!, lastLastCursorPosition); + Vector2 v = BaseObject.StackedPosition - lastCursorPosition; + NormalisedVectorAngle = Math.Atan2(Math.Abs(v.Y), Math.Abs(v.X)); + Angle = Math.Min(angle, sliderAngle); if (lastLastDifficultyObject.Angle != null) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 101dd2250aaf..dec678519381 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -30,10 +30,10 @@ public Aim(Mod[] mods, bool includeSliders) private double currentStrain; - private double skillMultiplierSnap => 65.2; - private double skillMultiplierAgility => 2.7; - private double skillMultiplierFlow => 262.0; - private double skillMultiplierTotal => 1.0; + private double skillMultiplierSnap => 71.0; + private double skillMultiplierAgility => 2.0; + private double skillMultiplierFlow => 238.0; + private double skillMultiplierTotal => 1.1; private double meanExponent => 1.2; private readonly List sliderStrains = new List(); From 277d53a4f1719da16cd6edf7437962e5ce8caf4b Mon Sep 17 00:00:00 2001 From: Arthur Araujo <90941580+64ArthurAraujo@users.noreply.github.com> Date: Tue, 10 Mar 2026 00:36:32 -0300 Subject: [PATCH 785/836] Adjust all selected hold notes if they have the same StartTime and Duration (#36656) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses #36267 The drag now checks all the selected objects in the blueprint container to see if they have the same `StartTime` and `Duration` as the dragged note, and if so, adjust them accordingly. --------- Co-authored-by: Bartłomiej Dach --- .../Editor/TestSceneHoldNoteTailDrag.cs | 351 ++++++++++++++++++ .../Timeline/TimelineHitObjectBlueprint.cs | 32 +- 2 files changed, 381 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNoteTailDrag.cs diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNoteTailDrag.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNoteTailDrag.cs new file mode 100644 index 000000000000..bdbf24bb95b3 --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNoteTailDrag.cs @@ -0,0 +1,351 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Testing; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Tests.Visual; +using osuTK; +using osuTK.Input; +using DragArea = osu.Game.Screens.Edit.Compose.Components.Timeline.TimelineHitObjectBlueprint.DragArea; + +namespace osu.Game.Rulesets.Mania.Tests.Editor +{ + public partial class TestSceneHoldNoteTailDrag : EditorTestScene + { + protected override Ruleset CreateEditorRuleset() => new ManiaRuleset(); + + [SetUpSteps] + public override void SetUpSteps() + { + base.SetUpSteps(); + AddStep("Clear objects", () => EditorBeatmap.Clear()); + } + + [Test] + public void TestSimpleTailDragForward() + { + AddStep("Add hold note", () => + { + EditorBeatmap.Add(new HoldNote { StartTime = 2170, Duration = 937.5 }); + }); + + AddStep("Drag tail", () => + { + var blueprintDragArea = this.ChildrenOfType().Single(); + dragForward(blueprintDragArea); + }); + + AddStep("Release tail", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddAssert("Duration is higher", () => ((HoldNote)EditorBeatmap.HitObjects.First())!.Duration > 937.5f); + } + + [Test] + public void TestSimpleTailDragBackwards() + { + AddStep("Add hold note", () => + { + EditorBeatmap.Add(new HoldNote { StartTime = 2170, Duration = 937.5 }); + }); + + AddStep("Drag tail", () => + { + var blueprintDragArea = this.ChildrenOfType().Single(); + dragBackward(blueprintDragArea); + }); + + AddStep("Release tail", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddAssert("Duration is lower", () => ((HoldNote)EditorBeatmap.HitObjects[0]).Duration < 937.5f); + } + + [Test] + public void TestSamePositionButNotSelectedDragForward() + { + AddStep("Add hold notes", () => + { + EditorBeatmap.AddRange([ + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 0 }, + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 1 } + ]); + }); + + AddStep("Drag tail", () => + { + var blueprintDragArea = this.ChildrenOfType().First(); + dragForward(blueprintDragArea); + }); + + AddStep("Release tail", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddAssert("Duration is higher, other is unchanged", () => + ((HoldNote)EditorBeatmap.HitObjects[0]).Duration > 937.5f && + ((HoldNote)EditorBeatmap.HitObjects[^1]).Duration == 937.5f + ); + } + + [Test] + public void TestSamePositionButNotSelectedDragBackward() + { + AddStep("Add hold notes", () => + { + EditorBeatmap.AddRange([ + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 0 }, + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 1 } + ]); + }); + + AddStep("Drag tail", () => + { + var blueprintDragArea = this.ChildrenOfType().First(); + dragBackward(blueprintDragArea); + }); + + AddStep("Release tail", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddAssert("Duration is lower, other is unchanged", () => + ((HoldNote)EditorBeatmap.HitObjects[0]).Duration < 937.5f && + ((HoldNote)EditorBeatmap.HitObjects[^1]).Duration == 937.5f + ); + } + + [Test] + public void TestSamePositionSelectedDragForward() + { + AddStep("Add hold notes", () => + { + EditorBeatmap.AddRange([ + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 0 }, + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 1 } + ]); + }); + + AddStep("Select all", () => + { + EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects); + }); + + AddStep("Drag tail", () => + { + var blueprintDragArea = this.ChildrenOfType().First(); + dragForward(blueprintDragArea); + }); + + AddStep("Release tail", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddAssert("Both durations are higher", () => + ((HoldNote)EditorBeatmap.HitObjects[0]).Duration > 937.5f && + ((HoldNote)EditorBeatmap.HitObjects[^1]).Duration > 937.5f + ); + } + + [Test] + public void TestSamePositionSelectedDragBackward() + { + AddStep("Add hold notes", () => + { + EditorBeatmap.AddRange([ + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 0 }, + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 1 } + ]); + }); + + AddStep("Select all", () => + { + EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects); + }); + + AddStep("Drag tail", () => + { + var blueprintDragArea = this.ChildrenOfType().First(); + dragBackward(blueprintDragArea); + }); + + AddStep("Release tail", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddAssert("Both durations are lower", () => + ((HoldNote)EditorBeatmap.HitObjects[0]).Duration < 937.5f && + ((HoldNote)EditorBeatmap.HitObjects[^1]).Duration < 937.5f + ); + } + + [Test] + public void TestSelectedButDifferentPositions() + { + AddStep("Add hold notes", () => + { + EditorBeatmap.AddRange([ + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 0 }, + new HoldNote { StartTime = 2404, Duration = 937.5, Column = 1 } + ]); + }); + + AddStep("Select all", () => + { + EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects); + }); + + AddStep("Drag tail", () => + { + var blueprintDragArea = this.ChildrenOfType().First(); + dragBackward(blueprintDragArea); + }); + + AddStep("Release tail", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddAssert("Duration is unchanged, other is lower", () => + ((HoldNote)EditorBeatmap.HitObjects[0]).Duration == 937.5f && + ((HoldNote)EditorBeatmap.HitObjects[^1]).Duration < 937.5f + ); + } + + [Test] + public void TestSelectedSameStartTimeDifferentDurations() + { + AddStep("Add hold notes", () => + { + EditorBeatmap.AddRange([ + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 0 }, + new HoldNote { StartTime = 2170, Duration = 1171.8, Column = 1 } + ]); + }); + + AddStep("Select all", () => + { + EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects); + }); + + AddStep("Drag until both match", () => + { + var blueprintDragArea = this.ChildrenOfType().First(); + InputManager.MoveMouseTo(blueprintDragArea); + InputManager.PressKey(Key.LShift); + InputManager.PressButton(MouseButton.Left); + InputManager.MoveMouseTo(new Vector2(1000, 110)); + }); + + AddStep("Continue the drag", () => + { + var blueprintDragArea = this.ChildrenOfType().First(); + dragBackward(blueprintDragArea); + }); + + AddStep("Release tail", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddAssert("Duration is unchanged, other is lower", () => + ((HoldNote)EditorBeatmap.HitObjects[0]).Duration == 937.5f && + ((HoldNote)EditorBeatmap.HitObjects[^1]).Duration < 937.5f + ); + } + + [Test] + public void TestSelectedSameDurationDifferentStartTimes() + { + AddStep("Add hold notes", () => + { + EditorBeatmap.AddRange([ + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 0 }, + new HoldNote { StartTime = 2638.7, Duration = 937.5, Column = 1 } + ]); + }); + + AddStep("Select all", () => + { + EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects); + }); + + AddStep("Drag tail", () => + { + var blueprintDragArea = this.ChildrenOfType().First(); + dragBackward(blueprintDragArea); + }); + + AddStep("Release tail", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddAssert("Duration is unchanged, other is lower", () => + ((HoldNote)EditorBeatmap.HitObjects[0]).Duration == 937.5f && + ((HoldNote)EditorBeatmap.HitObjects[^1]).Duration < 937.5f + ); + } + + [Test] + public void TestDragNoteOutsideOfSelection() + { + AddStep("Add hold notes", () => + { + EditorBeatmap.AddRange([ + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 0 }, + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 1 } + ]); + }); + + AddStep("Select the back stack slider", () => + { + EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.Last()); + }); + + AddStep("Drag tail", () => + { + var blueprintDragArea = this.ChildrenOfType().First(); + dragBackward(blueprintDragArea); + }); + + AddStep("Release tail", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddAssert("Duration is lower, other is unchanged", () => + ((HoldNote)EditorBeatmap.HitObjects[0]).Duration < 937.5f && + ((HoldNote)EditorBeatmap.HitObjects[^1]).Duration == 937.5f + ); + } + + [Test] + public void TestDragHoldNoteWithNotes() + { + AddStep("Add notes", () => + { + EditorBeatmap.AddRange([ + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 0 }, + new Note { StartTime = 2170, Column = 1 }, + new Note { StartTime = 3107.5, Column = 2 }, + new HoldNote { StartTime = 2170, Duration = 937.5, Column = 3 } + ]); + }); + + AddStep("Select all", () => + { + EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects); + }); + + AddStep("Drag tail", () => + { + var blueprintDragArea = this.ChildrenOfType().First(); + dragBackward(blueprintDragArea); + }); + + AddStep("Release tail", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddAssert("Both durations are lower", () => + { + var holdNotes = EditorBeatmap.HitObjects.OfType(); + return holdNotes.First().Duration < 937.5f && holdNotes.Last().Duration < 937.5f; + } + ); + } + + private void dragForward(DragArea dragArea) + { + InputManager.MoveMouseTo(dragArea); + InputManager.PressButton(MouseButton.Left); + InputManager.MoveMouseTo(new Vector2(1100, 110)); + } + + private void dragBackward(DragArea dragArea) + { + InputManager.MoveMouseTo(dragArea); + InputManager.PressButton(MouseButton.Left); + InputManager.MoveMouseTo(new Vector2(700, 110)); + } + } +} diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs index f60d1b023b5b..9f028009936d 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -312,6 +313,8 @@ public partial class DragArea : Circle { private readonly HitObject? hitObject; + private readonly List objsToAdjust = new List(); + [Resolved] private EditorBeatmap beatmap { get; set; } = null!; @@ -404,6 +407,23 @@ private void updateState() protected override bool OnDragStart(DragStartEvent e) { changeHandler?.BeginChange(); + + var selectionItems = beatmap.SelectedHitObjects; + + if (!selectionItems.Contains(hitObject)) + return true; + + foreach (var item in selectionItems) + { + if (item == hitObject || item is not IHasDuration durationItem) continue; + + if (Precision.AlmostEquals(durationItem.Duration, (hitObject as IHasDuration)!.Duration, 1) && + Precision.AlmostEquals(item.StartTime, hitObject!.StartTime, 1)) + { + objsToAdjust.Add(item); + } + } + return true; } @@ -456,8 +476,15 @@ protected override void OnDrag(DragEvent e) if (endTimeHitObject.EndTime == snappedTime) return; - endTimeHitObject.Duration = snappedTime - hitObject.StartTime; - beatmap.Update(hitObject); + if (!objsToAdjust.Contains(hitObject)) + objsToAdjust.Add(hitObject); + + foreach (var obj in objsToAdjust) + { + (obj as IHasDuration)!.Duration = snappedTime - obj.StartTime; + beatmap.Update(obj); + } + break; } } @@ -473,6 +500,7 @@ protected override void OnDragEnd(DragEndEvent e) changeHandler?.EndChange(); OnDragHandled?.Invoke(null); + objsToAdjust.Clear(); } } From 14bde85263a5c14b101d5e9d48c8972fc17cede5 Mon Sep 17 00:00:00 2001 From: Rudi Herouard Date: Tue, 10 Mar 2026 06:20:59 +0100 Subject: [PATCH 786/836] Fix song select navigation with home/end keys (#36879) It's a continuation of https://github.com/ppy/osu/pull/36293, but for the home and end keys. Now when using home or end keys, it selects respectively the first or last item in the carousel, instead of just scrolling. ## Before: https://github.com/user-attachments/assets/6ab08d2f-1da4-4740-9d9e-574d7a8a10c9 ## After: https://github.com/user-attachments/assets/30bab836-0006-4830-b4e9-2d85017a15e6 --- .../Carousel/Carousel.ScrollContainer.cs | 24 +++++++++++++++- osu.Game/Graphics/Carousel/Carousel.cs | 28 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs b/osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs index 5f1488513aa6..625c246c4e97 100644 --- a/osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs +++ b/osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Utils; @@ -31,10 +32,12 @@ public abstract partial class Carousel where T : notnull /// Implementation of scroll container which handles very large vertical lists by internally using double precision /// for pre-display Y values. /// - protected partial class ScrollContainer : UserTrackingScrollContainer, IKeyBindingHandler + protected partial class ScrollContainer : UserTrackingScrollContainer, IKeyBindingHandler, IKeyBindingHandler { public Action? OnPageUp { get; init; } public Action? OnPageDown { get; init; } + public Action? OnListStart { get; init; } + public Action? OnListEnd { get; init; } public readonly Container Panels; @@ -146,6 +149,25 @@ protected override bool OnKeyDown(KeyDownEvent e) return base.OnKeyDown(e); } + public new bool OnPressed(KeyBindingPressEvent e) + { + if (IsHandlingKeyboardScrolling) + { + switch (e.Action) + { + case PlatformAction.MoveBackwardLine: + OnListStart?.Invoke(); + return true; + + case PlatformAction.MoveForwardLine: + OnListEnd?.Invoke(); + return true; + } + } + + return base.OnPressed(e); + } + public bool OnPressed(KeyBindingPressEvent e) { switch (e.Action) diff --git a/osu.Game/Graphics/Carousel/Carousel.cs b/osu.Game/Graphics/Carousel/Carousel.cs index 13d3c22c1900..5164068d5391 100644 --- a/osu.Game/Graphics/Carousel/Carousel.cs +++ b/osu.Game/Graphics/Carousel/Carousel.cs @@ -319,6 +319,8 @@ protected Carousel() RelativeSizeAxes = Axes.Both, OnPageUp = () => Scheduler.AddOnce(traverseFromKey, new TraversalOperation(TraversalType.Page, -1)), OnPageDown = () => Scheduler.AddOnce(traverseFromKey, new TraversalOperation(TraversalType.Page, 1)), + OnListStart = () => Scheduler.AddOnce(traverseFromKey, new TraversalOperation(TraversalType.Edge, -1)), + OnListEnd = () => Scheduler.AddOnce(traverseFromKey, new TraversalOperation(TraversalType.Edge, 1)), }; Items.BindCollectionChanged((_, args) => @@ -554,6 +556,10 @@ private void traverseFromKey(TraversalOperation traversal) traverseKeyboardPage(traversal.Direction); break; + case TraversalType.Edge: + traverseKeyboardEdge(traversal.Direction); + break; + case TraversalType.Set: traverseSetSelection(traversal.Direction); break; @@ -572,6 +578,7 @@ private enum TraversalType Keyboard, Set, Page, + Edge, Group } @@ -682,6 +689,27 @@ private void traverseKeyboardPage(int direction) } } + /// + /// Select the first or last item in the carousel. + /// + /// Positive for last item, negative for first item. + private void traverseKeyboardEdge(int direction) + { + if (carouselItems == null || carouselItems.Count == 0) + return; + + var item = direction > 0 + ? carouselItems.LastOrDefault(x => x.IsVisible) + : carouselItems.FirstOrDefault(x => x.IsVisible); + + if (item != null && !CheckModelEquality(item.Model, currentKeyboardSelection.Model)) + { + setKeyboardSelection(item.Model); + ScrollToSelection(); + playTraversalSound(); + } + } + /// /// Select the next valid group selection relative to a current selection. /// This is generally for keyboard based traversal. From caffc7238bd493d34d6efb92ce860d691a6a77ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 10 Mar 2026 07:12:43 +0100 Subject: [PATCH 787/836] Do not forcibly log out user if user retrieval fails with a server error code (#36897) * Do not forcibly log out user if user retrieval fails with a server error code This behaviour caused users to get forcibly logged out of the game during yesterday's redis outage. From one case where logs were provided (https://discord.com/channels/188630481301012481/1097318920991559880/1480201862610423933): - User had repeated timeouts on API requests; consequently, API went into failing state - On one of the login retries `/api/v2/me` returned a 500 with no error details (`{"error":"null}` JSON response) which resulted in an instant logout as per https://github.com/ppy/osu/blob/7263551aa868911a7d9148cf2cb16f9e0325f531/osu.Game/Online/API/APIAccess.cs#L323-L324 This PR intends to only forcibly log the user out if the returned error code indicates a client error. If it is a server error, the login is preserved and a normal retry loop proceeds. This can be tested with a local web instance via following steps: 1. Start `osu-web` and a client instance connected to it. 2. Log in on the client instance. 3. Kill (`^C`) `osu-web`. 4. Trigger a few requests in the client and wait for enough of them to fail for the API to change to `Failing` state. 5. Apply ```diff diff --git a/app/Http/Controllers/UsersController.php b/app/Http/Controllers/UsersController.php index db34639abf2..392a844882a 100644 --- a/app/Http/Controllers/UsersController.php +++ b/app/Http/Controllers/UsersController.php @@ -581,6 +581,8 @@ class UsersController extends Controller */ public function me($mode = null) { + abort(500); + $user = \Auth::user(); $currentMode = $mode ?? $user->playmode; ``` 6. Start `osu-web` again. 7. On master this will log the user out forcibly. On this PR, the user will remain in `Failing` state. 8. Undo patch from step (5) (restarting web is not required). 9. On this PR, the client will be logged back in. * Update framework --------- Co-authored-by: Dean Herbert --- osu.Android.props | 2 +- osu.Game/Online/API/APIAccess.cs | 2 +- osu.Game/Online/API/APIException.cs | 6 +++++- osu.Game/Online/API/APIRequest.cs | 2 +- osu.Game/Online/API/OAuth.cs | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 7 files changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index e8daf491307b..85c0378eced0 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index 0f4e8bb3a358..0338bbfec4c5 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From 321e6989061246275f30ef80030fe560109291fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 10 Mar 2026 08:02:13 +0100 Subject: [PATCH 788/836] Improve support for import & export flows on Android via using system file picker & share sheet (#36901) https://github.com/user-attachments/assets/57d0bc9d-f081-4d04-8cb6-422a83f1a1d3 https://github.com/user-attachments/assets/208f0676-a735-4055-a422-e6a2c3847220 --- - [x] Depends on https://github.com/ppy/osu-framework/pull/6717 to work - Closes https://github.com/ppy/osu/issues/21076 - Closes https://github.com/ppy/osu/issues/22676 - Closes https://github.com/ppy/osu/issues/28666 --------- Co-authored-by: Dean Herbert --- osu.Android/AndroidManifest.xml | 21 ++++++++----------- osu.Android/Resources/xml/filepaths.xml | 6 ++++++ .../Sections/General/QuickActionSettings.cs | 20 +++++++----------- .../Sections/Maintenance/GeneralSettings.cs | 7 +++++++ osu.Game/Screens/Edit/Editor.cs | 9 +++----- 5 files changed, 32 insertions(+), 31 deletions(-) create mode 100644 osu.Android/Resources/xml/filepaths.xml diff --git a/osu.Android/AndroidManifest.xml b/osu.Android/AndroidManifest.xml index a85e711cf28f..d334888a5faa 100644 --- a/osu.Android/AndroidManifest.xml +++ b/osu.Android/AndroidManifest.xml @@ -5,16 +5,13 @@ android:supportsRtl="true" android:label="osu!" android:icon="@mipmap/ic_launcher" - android:roundIcon="@mipmap/ic_launcher" /> - - - - - + android:roundIcon="@mipmap/ic_launcher"> + + + + diff --git a/osu.Android/Resources/xml/filepaths.xml b/osu.Android/Resources/xml/filepaths.xml new file mode 100644 index 000000000000..a2356c4aabf4 --- /dev/null +++ b/osu.Android/Resources/xml/filepaths.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs index 4f988d667fec..02c1dfb8df90 100644 --- a/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Threading.Tasks; -using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -58,20 +57,15 @@ private void load(OsuColour colours, Storage storage) }, }); - bool supportsExport = RuntimeInfo.OS != RuntimeInfo.Platform.Android; - - if (supportsExport) + Add(new SettingsButtonV2 { - Add(new SettingsButtonV2 - { - Text = GeneralSettingsStrings.ExportLogs, - BackgroundColour = colours.YellowDarker.Darken(0.5f), - Keywords = new[] { @"bug", "report", "logs", "files" }, - Action = () => Task.Run(exportLogs), - }); + Text = GeneralSettingsStrings.ExportLogs, + BackgroundColour = colours.YellowDarker.Darken(0.5f), + Keywords = new[] { @"bug", "report", "logs", "files" }, + Action = () => Task.Run(exportLogs), + }); - exportStorage = (storage as OsuStorage)?.GetExportStorage() ?? storage.GetStorageForDirectory(@"exports"); - } + exportStorage = (storage as OsuStorage)?.GetExportStorage() ?? storage.GetStorageForDirectory(@"exports"); } [Resolved] diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 2c79daffb6ab..e8345c1946dd 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -47,5 +47,12 @@ private void load(OsuGameBase game, GameHost host, IPerformFromScreenRunner? per } }); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + selector?.Dispose(); + } } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 2360febccb52..452419ca4573 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -1287,12 +1287,9 @@ private IEnumerable createFileMenuItems() Hotkey = new Hotkey(GlobalAction.EditorDiscardUnsavedChanges) }; - if (RuntimeInfo.OS != RuntimeInfo.Platform.Android) - { - var export = createExportMenu(); - saveRelatedMenuItems.AddRange(export.Items); - yield return export; - } + var export = createExportMenu(); + saveRelatedMenuItems.AddRange(export.Items); + yield return export; if (RuntimeInfo.IsDesktop) { From 054ae2983d2a9184e215970489939ae17996ed51 Mon Sep 17 00:00:00 2001 From: Krzysztof Gutkowski Date: Tue, 10 Mar 2026 08:28:06 +0100 Subject: [PATCH 789/836] Extract user overlay actions button component (#36236) This PR extracts the classes used for the actions dropdown on the user profile overlay to separate components, in preparation to be used on the team overlay (#32584). Kinda RFC since I'm not sure if this is the best way to do this. Co-authored-by: Dean Herbert --- .../Header/Components/ProfileActionPopover.cs | 40 +++++ .../Header/Components/ProfileActionsButton.cs | 62 +++++++ .../Header/Components/ProfilePopoverAction.cs | 104 +++++++++++ .../Header/Components/UserActionsButton.cs | 168 +----------------- 4 files changed, 215 insertions(+), 159 deletions(-) create mode 100644 osu.Game/Overlays/Profile/Header/Components/ProfileActionPopover.cs create mode 100644 osu.Game/Overlays/Profile/Header/Components/ProfileActionsButton.cs create mode 100644 osu.Game/Overlays/Profile/Header/Components/ProfilePopoverAction.cs diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileActionPopover.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileActionPopover.cs new file mode 100644 index 000000000000..11f82772db48 --- /dev/null +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileActionPopover.cs @@ -0,0 +1,40 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.UserInterfaceV2; + +namespace osu.Game.Overlays.Profile.Header.Components +{ + public abstract partial class ProfileActionPopover : OsuPopover + { + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + private FillFlowContainer container = null!; + + protected ProfileActionPopover() + : base(false) + { + } + + [BackgroundDependencyLoader] + private void load() + { + Background.Colour = colourProvider.Background6; + + AllowableAnchors = [Anchor.BottomCentre, Anchor.TopCentre]; + + Child = container = new FillFlowContainer + { + Width = 160, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = 5, Vertical = 10 }, + }; + } + + public ProfilePopoverAction[] Actions { set => container.Children = value; } + } +} diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileActionsButton.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileActionsButton.cs new file mode 100644 index 000000000000..ff6a279be2dc --- /dev/null +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileActionsButton.cs @@ -0,0 +1,62 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.Containers; +using osuTK; + +namespace osu.Game.Overlays.Profile.Header.Components +{ + public abstract partial class ProfileActionsButton : OsuHoverContainer, IHasPopover + { + private Box background = null!; + + protected override IEnumerable EffectTargets => [background]; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + [BackgroundDependencyLoader] + private void load() + { + IdleColour = colourProvider.Background2; + HoverColour = colourProvider.Background1; + + Size = new Vector2(40); + Masking = true; + CornerRadius = 20; + + Child = new CircularContainer + { + Masking = true, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + }, + new SpriteIcon + { + Size = new Vector2(12), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Icon = FontAwesome.Solid.EllipsisV, + }, + } + }; + + Action = this.ShowPopover; + } + + public abstract Popover GetPopover(); + } +} diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfilePopoverAction.cs b/osu.Game/Overlays/Profile/Header/Components/ProfilePopoverAction.cs new file mode 100644 index 000000000000..5dd8b8050260 --- /dev/null +++ b/osu.Game/Overlays/Profile/Header/Components/ProfilePopoverAction.cs @@ -0,0 +1,104 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Overlays.Profile.Header.Components +{ + public partial class ProfilePopoverAction : OsuClickableContainer + { + private readonly IconUsage icon; + private readonly LocalisableString caption; + + private Box background = null!; + private CircularContainer indicator = null!; + + public ProfilePopoverAction(IconUsage icon, LocalisableString caption) + { + this.icon = icon; + this.caption = caption; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + RelativeSizeAxes = Content.RelativeSizeAxes = Axes.X; + AutoSizeAxes = Content.AutoSizeAxes = Axes.Y; + + Masking = true; + CornerRadius = 4; + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background5, + Alpha = 0, + }, + indicator = new Circle + { + Width = 4, + Height = 14, + X = 10, + Colour = colourProvider.Highlight1, + Anchor = Anchor.CentreLeft, + Origin = Anchor.Centre, + Alpha = 0, + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Padding = new MarginPadding { Horizontal = 25, Vertical = 5 }, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + Children = new Drawable[] + { + new SpriteIcon + { + Icon = icon, + Size = new Vector2(11), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + new OsuSpriteText + { + Text = caption, + Font = OsuFont.Style.Body, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + UseFullGlyphHeight = false, + } + } + } + }; + } + + protected override bool OnHover(HoverEvent e) + { + updateState(); + return true; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateState(); + base.OnHoverLost(e); + } + + private void updateState() + { + background.Alpha = indicator.Alpha = IsHovered ? 1 : 0; + } + } +} diff --git a/osu.Game/Overlays/Profile/Header/Components/UserActionsButton.cs b/osu.Game/Overlays/Profile/Header/Components/UserActionsButton.cs index 1a2593cff7b7..7c4e47206a0c 100644 --- a/osu.Game/Overlays/Profile/Header/Components/UserActionsButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/UserActionsButton.cs @@ -1,78 +1,26 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; using osu.Game.Users; -using osuTK; namespace osu.Game.Overlays.Profile.Header.Components { - public partial class UserActionsButton : OsuHoverContainer, IHasPopover + public partial class UserActionsButton : ProfileActionsButton { public readonly Bindable User = new Bindable(); - private Box background = null!; - - protected override IEnumerable EffectTargets => [background]; - - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; - [Resolved] private IAPIProvider api { get; set; } = null!; - [BackgroundDependencyLoader] - private void load() - { - IdleColour = colourProvider.Background2; - HoverColour = colourProvider.Background1; - - Size = new Vector2(40); - Masking = true; - CornerRadius = 20; - - Child = new CircularContainer - { - Masking = true, - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - background = new Box - { - RelativeSizeAxes = Axes.Both, - }, - new SpriteIcon - { - Size = new Vector2(12), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Icon = FontAwesome.Solid.EllipsisV, - }, - } - }; - - Action = this.ShowPopover; - } - protected override void LoadComplete() { base.LoadComplete(); @@ -80,132 +28,34 @@ protected override void LoadComplete() User.BindValueChanged(_ => Alpha = User.Value?.User.OnlineID == api.LocalUser.Value.OnlineID ? 0 : 1, true); } - public Popover GetPopover() => new UserActionPopover(User.Value!.User); + public override Popover GetPopover() => new UserActionPopover(User.Value!.User); - private partial class UserActionPopover : OsuPopover + private partial class UserActionPopover : ProfileActionPopover { private readonly APIUser user; public UserActionPopover(APIUser user) - : base(false) { this.user = user; } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider, IAPIProvider api, IDialogOverlay? dialogOverlay) + private void load(IAPIProvider api, IDialogOverlay? dialogOverlay) { - Background.Colour = colourProvider.Background6; - bool userBlocked = api.LocalUserState.Blocks.Any(b => b.TargetID == user.Id); - AllowableAnchors = [Anchor.BottomCentre, Anchor.TopCentre]; - - Child = new FillFlowContainer + Actions = new[] { - Width = 160, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Horizontal = 5, Vertical = 10 }, - Children = new Drawable[] + new ProfilePopoverAction(FontAwesome.Solid.Ban, userBlocked ? UsersStrings.BlocksButtonUnblock : UsersStrings.BlocksButtonBlock) { - new UserAction(FontAwesome.Solid.Ban, userBlocked ? UsersStrings.BlocksButtonUnblock : UsersStrings.BlocksButtonBlock) + Action = () => { - Action = () => - { - dialogOverlay?.Push(userBlocked ? ConfirmBlockActionDialog.Unblock(user) : ConfirmBlockActionDialog.Block(user)); - this.HidePopover(); - } + dialogOverlay?.Push(userBlocked ? ConfirmBlockActionDialog.Unblock(user) : ConfirmBlockActionDialog.Block(user)); + this.HidePopover(); } } }; } } - - private partial class UserAction : OsuClickableContainer - { - private readonly IconUsage icon; - private readonly LocalisableString caption; - - private Box background = null!; - private CircularContainer indicator = null!; - - public UserAction(IconUsage icon, LocalisableString caption) - { - this.icon = icon; - this.caption = caption; - } - - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) - { - RelativeSizeAxes = Content.RelativeSizeAxes = Axes.X; - AutoSizeAxes = Content.AutoSizeAxes = Axes.Y; - - Masking = true; - CornerRadius = 4; - Children = new Drawable[] - { - background = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5, - Alpha = 0, - }, - indicator = new Circle - { - Width = 4, - Height = 14, - X = 10, - Colour = colourProvider.Highlight1, - Anchor = Anchor.CentreLeft, - Origin = Anchor.Centre, - Alpha = 0, - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Padding = new MarginPadding { Horizontal = 25, Vertical = 5 }, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5, 0), - Children = new Drawable[] - { - new SpriteIcon - { - Icon = icon, - Size = new Vector2(11), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - new OsuSpriteText - { - Text = caption, - Font = OsuFont.Style.Body, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - UseFullGlyphHeight = false, - } - } - } - }; - } - - protected override bool OnHover(HoverEvent e) - { - updateState(); - return true; - } - - protected override void OnHoverLost(HoverLostEvent e) - { - updateState(); - base.OnHoverLost(e); - } - - private void updateState() - { - background.Alpha = indicator.Alpha = IsHovered ? 1 : 0; - } - } } } From 1b488949e13568c23faa0d88b18c8036f4a7dbc8 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Tue, 10 Mar 2026 10:28:27 +0300 Subject: [PATCH 790/836] Localise some more `PopupDialog`s (#36890) changes can be reviewed commit by commit --------- Co-authored-by: Dean Herbert --- osu.Game/Localisation/ButtonSystemStrings.cs | 5 + osu.Game/Localisation/DialogStrings.cs | 96 +++++++++++++++++++ osu.Game/Localisation/EditorDialogsStrings.cs | 20 ++++ osu.Game/Online/Chat/ExternalLinkOpener.cs | 4 +- osu.Game/Overlays/Comments/DrawableComment.cs | 11 ++- osu.Game/Overlays/Dialog/ConfirmDialog.cs | 9 +- osu.Game/Screens/Edit/BookmarkResetDialog.cs | 4 +- .../DeleteDifficultyConfirmationDialog.cs | 6 +- osu.Game/Screens/Edit/Editor.cs | 2 +- .../Screens/Edit/SaveRequiredPopupDialog.cs | 7 +- .../Menu/ConfirmDiscardChangesDialog.cs | 9 +- osu.Game/Screens/Menu/ConfirmExitDialog.cs | 25 +++-- osu.Game/Screens/Menu/MainMenu.cs | 2 +- .../ConfirmExitMultiplayerMatchDialog.cs | 17 ++++ .../Matchmaking/Match/ScreenMatchmaking.cs | 3 +- .../RankedPlay/RankedPlayScreen.cs | 3 +- .../Multiplayer/Match/MatchStartControl.cs | 3 +- .../Multiplayer/MultiplayerMatchSubScreen.cs | 2 +- .../Playlists/ClosePlaylistDialog.cs | 3 +- .../Select/BeatmapClearScoresDialog.cs | 5 +- 20 files changed, 191 insertions(+), 45 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Components/ConfirmExitMultiplayerMatchDialog.cs diff --git a/osu.Game/Localisation/ButtonSystemStrings.cs b/osu.Game/Localisation/ButtonSystemStrings.cs index 2bce75c01013..ecb067e0ff86 100644 --- a/osu.Game/Localisation/ButtonSystemStrings.cs +++ b/osu.Game/Localisation/ButtonSystemStrings.cs @@ -93,6 +93,11 @@ public static class ButtonSystemStrings Please bear with us as we continue to improve the game for you!"); + /// + /// "Understood" + /// + public static LocalisableString MobileDisclaimerOkButton => new TranslatableString(getKey(@"mobile_disclaimer_ok_button"), @"Understood"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/DialogStrings.cs b/osu.Game/Localisation/DialogStrings.cs index f50268dd0347..05a7055cd638 100644 --- a/osu.Game/Localisation/DialogStrings.cs +++ b/osu.Game/Localisation/DialogStrings.cs @@ -49,6 +49,102 @@ public static class DialogStrings /// public static LocalisableString StableDirectoryLocationCancelButton => new TranslatableString(getKey(@"stable_directory_location_cancel_button"), @"Actually I don't have osu!stable installed."); + /// + /// "All local scores on {0}" + /// + public static LocalisableString BeatmapClearScoresBodyText(string difficulty) => new TranslatableString(getKey(@"beatmap_clear_scores_body_text"), @"All local scores on {0}", difficulty); + + /// + /// "Are you sure you want to close the following playlist:" + /// + public static LocalisableString ClosePlaylistHeaderText => new TranslatableString(getKey(@"close_playlist_header_text"), @"Are you sure you want to close the following playlist:"); + + /// + /// "Are you sure you want to abort the match?" + /// + public static LocalisableString ConfirmAbortMatchHeaderText => new TranslatableString(getKey(@"confirm_abort_match_header_text"), @"Are you sure you want to abort the match?"); + + /// + /// "Are you sure you want to exit osu!?" + /// + public static LocalisableString ConfirmExitHeaderText => new TranslatableString(getKey(@"confirm_exit_header_text"), @"Are you sure you want to exit osu!?"); + + /// + /// "Last chance to turn back" + /// + public static LocalisableString ConfirmDialogBodyText => new TranslatableString(getKey(@"confirm_exit_body_text"), @"Last chance to turn back"); + + /// + /// "There are currently some background operations which will be aborted if you continue: + /// + /// {0}" + /// + public static LocalisableString ConfirmExitBodyTextOngoingOperations(string ongoingOperationsText) => new TranslatableString(getKey(@"confirm_exit_body_text_ongoing_operations"), @"There are currently some background operations which will be aborted if you continue: + +{0}", ongoingOperationsText); + + /// + /// "There are currently some background operations which will be aborted if you continue: + /// + /// {0} + /// + /// and {1} other operation(s)." + /// + public static LocalisableString ConfirmExitBodyTextOtherOngoingOperations(string ongoingOperationsText, int count) => new TranslatableString(getKey(@"confirm_exit_body_text_other_ongoing_operations"), @"There are currently some background operations which will be aborted if you continue: + +{0} + +and {1} other operation(s).", ongoingOperationsText, count); + + /// + /// "Let me out!" + /// + public static LocalisableString ConfirmExitOkButton => new TranslatableString(getKey(@"confirm_exit_ok_button"), @"Let me out!"); + + /// + /// "Just a little more..." + /// + public static LocalisableString ConfirmExitCancelButton => new TranslatableString(getKey(@"confirm_exit_cancel_button"), @"Just a little more..."); + + /// + /// "Are you sure you want to go back?" + /// + public static LocalisableString ConfirmDiscardChangesHeaderText => new TranslatableString(getKey(@"confirm_discard_changes_header_text"), @"Are you sure you want to go back?"); + + /// + /// "This will discard any unsaved changes" + /// + public static LocalisableString ConfirmDiscardChangesBodyText => new TranslatableString(getKey(@"confirm_discard_changes_body_text"), @"This will discard any unsaved changes"); + + /// + /// "No I didn't mean to" + /// + public static LocalisableString ConfirmDiscardChangesCancelButton => new TranslatableString(getKey(@"confirm_discard_changes_cancel_button"), @"No I didn't mean to"); + + /// + /// "Are you sure you want to open the following link in a web browser? + /// + /// {0}" + /// + public static LocalisableString ExternalLinkBodyText(string url) => new TranslatableString(getKey(@"external_link_body_text"), @"Are you sure you want to open the following link in a web browser? + +{0}", url); + + /// + /// "Open in browser" + /// + public static LocalisableString ExternalLinkOkButton => new TranslatableString(getKey(@"external_link_ok_button"), @"Open in browser"); + + /// + /// "Do you really want to delete your comment?" + /// + public static LocalisableString DeleteCommentBodyText => new TranslatableString(getKey(@"delete_comment_body_text"), @"Do you really want to delete your comment?"); + + /// + /// "Are you sure you want to leave this multiplayer match?" + /// + public static LocalisableString ConfirmExitMultiplayerMatchBodyText => new TranslatableString(getKey(@"confirm_exit_multiplayer_match_body_text"), @"Are you sure you want to leave this multiplayer match?"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/EditorDialogsStrings.cs b/osu.Game/Localisation/EditorDialogsStrings.cs index 3617dca81fdf..ea4e3d0d55a6 100644 --- a/osu.Game/Localisation/EditorDialogsStrings.cs +++ b/osu.Game/Localisation/EditorDialogsStrings.cs @@ -59,6 +59,26 @@ public static class EditorDialogsStrings ///
    public static LocalisableString DiscardUnsavedChangesDialogHeader => new TranslatableString(getKey(@"discard_unsaved_changes_dialog_header"), @"Discard all unsaved changes? This cannot be undone."); + /// + /// "The beatmap will be saved to continue with this operation." + /// + public static LocalisableString SaveRequiredDialogHeader => new TranslatableString(getKey(@"save_required_dialog_header"), @"The beatmap will be saved to continue with this operation."); + + /// + /// "Sounds good, let's go!" + /// + public static LocalisableString SoundsGood => new TranslatableString(getKey(@"sounds_good"), @"Sounds good, let's go!"); + + /// + /// "Difficulty "{0}" with {1} objects" + /// + public static LocalisableString DeleteDifficultyDetails(string difficultyName, int objectCount) => new TranslatableString(getKey(@"delete_difficulty_details"), @"Difficulty ""{0}"" with {1} objects", difficultyName, objectCount); + + /// + /// "All Bookmarks" + /// + public static LocalisableString AllBookmarks => new TranslatableString(getKey(@"all_bookmarks"), @"All Bookmarks"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Online/Chat/ExternalLinkOpener.cs b/osu.Game/Online/Chat/ExternalLinkOpener.cs index 53faafcf3661..708e9edefa17 100644 --- a/osu.Game/Online/Chat/ExternalLinkOpener.cs +++ b/osu.Game/Online/Chat/ExternalLinkOpener.cs @@ -98,7 +98,7 @@ public partial class ExternalLinkDialog : PopupDialog public ExternalLinkDialog(string url, Action openExternalLinkAction, Action copyExternalLinkAction) { HeaderText = DialogStrings.CautionHeaderText; - BodyText = $"Are you sure you want to open the following link in a web browser?\n\n{url}"; + BodyText = DialogStrings.ExternalLinkBodyText(url); Icon = FontAwesome.Solid.ExclamationTriangle; @@ -106,7 +106,7 @@ public ExternalLinkDialog(string url, Action openExternalLinkAction, Action copy { new PopupDialogOkButton { - Text = @"Open in browser", + Text = DialogStrings.ExternalLinkOkButton, Action = openExternalLinkAction }, new PopupDialogCancelButton diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 33f09b762206..c439905245d7 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -21,11 +21,12 @@ using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Logging; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Comments.Buttons; using osu.Game.Overlays.Dialog; -using osu.Game.Resources.Localisation.Web; +using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; namespace osu.Game.Overlays.Comments { @@ -324,13 +325,13 @@ private void load(OverlayColourProvider colourProvider, DrawableComment? parentC if (WasDeleted) makeDeleted(); - actionsContainer.AddLink(CommonStrings.ButtonsPermalink, () => game?.CopyToClipboard($@"{api.Endpoints.APIUrl}/comments/{Comment.Id}")); + actionsContainer.AddLink(WebCommonStrings.ButtonsPermalink, () => game?.CopyToClipboard($@"{api.Endpoints.APIUrl}/comments/{Comment.Id}")); actionsContainer.AddArbitraryDrawable(Empty().With(d => d.Width = 10)); - actionsContainer.AddLink(CommonStrings.ButtonsReply.ToLower(), toggleReply); + actionsContainer.AddLink(WebCommonStrings.ButtonsReply.ToLower(), toggleReply); actionsContainer.AddArbitraryDrawable(Empty().With(d => d.Width = 10)); if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) - actionsContainer.AddLink(CommonStrings.ButtonsDelete.ToLower(), deleteComment); + actionsContainer.AddLink(WebCommonStrings.ButtonsDelete.ToLower(), deleteComment); else actionsContainer.AddArbitraryDrawable(new CommentReportButton(Comment)); @@ -384,7 +385,7 @@ private void deleteComment() if (dialogOverlay == null) deleteCommentRequest(); else - dialogOverlay.Push(new ConfirmDialog("Do you really want to delete your comment?", deleteCommentRequest)); + dialogOverlay.Push(new ConfirmDialog(DialogStrings.DeleteCommentBodyText, deleteCommentRequest)); } /// diff --git a/osu.Game/Overlays/Dialog/ConfirmDialog.cs b/osu.Game/Overlays/Dialog/ConfirmDialog.cs index f1caac8b5d40..f6a5ca4f9ca1 100644 --- a/osu.Game/Overlays/Dialog/ConfirmDialog.cs +++ b/osu.Game/Overlays/Dialog/ConfirmDialog.cs @@ -6,7 +6,8 @@ using System; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Game.Resources.Localisation.Web; +using osu.Game.Localisation; +using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; namespace osu.Game.Overlays.Dialog { @@ -24,7 +25,7 @@ public partial class ConfirmDialog : PopupDialog public ConfirmDialog(LocalisableString message, Action onConfirm, Action onCancel = null) { HeaderText = message; - BodyText = "Last chance to turn back"; + BodyText = DialogStrings.ConfirmDialogBodyText; Icon = FontAwesome.Solid.ExclamationTriangle; @@ -32,12 +33,12 @@ public ConfirmDialog(LocalisableString message, Action onConfirm, Action onCance { new PopupDialogOkButton { - Text = @"Yes", + Text = DialogStrings.Confirm, Action = onConfirm }, new PopupDialogCancelButton { - Text = CommonStrings.ButtonsCancel, + Text = WebCommonStrings.ButtonsCancel, Action = onCancel }, }; diff --git a/osu.Game/Screens/Edit/BookmarkResetDialog.cs b/osu.Game/Screens/Edit/BookmarkResetDialog.cs index 48a0202c8671..30a61c684a3f 100644 --- a/osu.Game/Screens/Edit/BookmarkResetDialog.cs +++ b/osu.Game/Screens/Edit/BookmarkResetDialog.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Game.Localisation; using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Edit @@ -13,7 +14,7 @@ public partial class BookmarkResetDialog : DeletionDialog public BookmarkResetDialog(EditorBeatmap editorBeatmap) { editor = editorBeatmap; - BodyText = "All Bookmarks"; + BodyText = EditorDialogsStrings.AllBookmarks; } [BackgroundDependencyLoader] @@ -23,4 +24,3 @@ private void load() } } } - diff --git a/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs b/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs index 1aeb1d8a40fd..ff69689c914e 100644 --- a/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs +++ b/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs @@ -2,16 +2,16 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Game.Beatmaps; +using osu.Game.Localisation; using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Edit { public partial class DeleteDifficultyConfirmationDialog : DeletionDialog { - public DeleteDifficultyConfirmationDialog(BeatmapInfo beatmapInfo, Action deleteAction) + public DeleteDifficultyConfirmationDialog(string difficultyName, int objectCount, Action deleteAction) { - BodyText = $"\"{beatmapInfo.DifficultyName}\" difficulty"; + BodyText = EditorDialogsStrings.DeleteDifficultyDetails(difficultyName, objectCount); DangerousAction = deleteAction; } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 452419ca4573..4ba1b2fac222 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -1425,7 +1425,7 @@ private void deleteDifficulty() if (dialogOverlay == null) delete(); else - dialogOverlay.Push(new DeleteDifficultyConfirmationDialog(Beatmap.Value.BeatmapInfo, delete)); + dialogOverlay.Push(new DeleteDifficultyConfirmationDialog(playableBeatmap.BeatmapInfo.DifficultyName, editorBeatmap.HitObjects.Count, delete)); void delete() { diff --git a/osu.Game/Screens/Edit/SaveRequiredPopupDialog.cs b/osu.Game/Screens/Edit/SaveRequiredPopupDialog.cs index 618efb7cdaf4..5c690378256d 100644 --- a/osu.Game/Screens/Edit/SaveRequiredPopupDialog.cs +++ b/osu.Game/Screens/Edit/SaveRequiredPopupDialog.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Graphics.Sprites; +using osu.Game.Localisation; using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Edit @@ -11,7 +12,7 @@ public partial class SaveRequiredPopupDialog : PopupDialog { public SaveRequiredPopupDialog(Action saveAndAction) { - HeaderText = "The beatmap will be saved to continue with this operation."; + HeaderText = EditorDialogsStrings.SaveRequiredDialogHeader; Icon = FontAwesome.Regular.Save; @@ -19,12 +20,12 @@ public SaveRequiredPopupDialog(Action saveAndAction) { new PopupDialogOkButton { - Text = "Sounds good, let's go!", + Text = EditorDialogsStrings.SoundsGood, Action = saveAndAction }, new PopupDialogCancelButton { - Text = "Oops, continue editing", + Text = EditorDialogsStrings.ContinueEditing, }, }; } diff --git a/osu.Game/Screens/Menu/ConfirmDiscardChangesDialog.cs b/osu.Game/Screens/Menu/ConfirmDiscardChangesDialog.cs index 0cd3e9ce71c8..b57d786f5687 100644 --- a/osu.Game/Screens/Menu/ConfirmDiscardChangesDialog.cs +++ b/osu.Game/Screens/Menu/ConfirmDiscardChangesDialog.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Graphics.Sprites; +using osu.Game.Localisation; using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Menu @@ -16,8 +17,8 @@ public partial class ConfirmDiscardChangesDialog : PopupDialog /// An optional action to perform on cancel. public ConfirmDiscardChangesDialog(Action onConfirm, Action? onCancel = null) { - HeaderText = "Are you sure you want to go back?"; - BodyText = "This will discard any unsaved changes"; + HeaderText = DialogStrings.ConfirmDiscardChangesHeaderText; + BodyText = DialogStrings.ConfirmDiscardChangesBodyText; Icon = FontAwesome.Solid.ExclamationTriangle; @@ -25,12 +26,12 @@ public ConfirmDiscardChangesDialog(Action onConfirm, Action? onCancel = null) { new PopupDialogDangerousButton { - Text = @"Yes", + Text = DialogStrings.Confirm, Action = onConfirm }, new PopupDialogCancelButton { - Text = @"No I didn't mean to", + Text = DialogStrings.ConfirmDiscardChangesCancelButton, Action = onCancel }, }; diff --git a/osu.Game/Screens/Menu/ConfirmExitDialog.cs b/osu.Game/Screens/Menu/ConfirmExitDialog.cs index e33071e78c0f..3e085ce063b7 100644 --- a/osu.Game/Screens/Menu/ConfirmExitDialog.cs +++ b/osu.Game/Screens/Menu/ConfirmExitDialog.cs @@ -5,6 +5,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Overlays.Dialog; @@ -30,31 +31,29 @@ public ConfirmExitDialog(Action onConfirm, Action? onCancel = null) [BackgroundDependencyLoader] private void load(INotificationOverlay notifications) { - HeaderText = "Are you sure you want to exit osu!?"; + HeaderText = DialogStrings.ConfirmExitHeaderText; Icon = FontAwesome.Solid.ExclamationTriangle; if (notifications.HasOngoingOperations) { - string text = "There are currently some background operations which will be aborted if you continue:\n\n"; - var ongoingOperations = notifications.OngoingOperations.ToArray(); + string ongoingOperationsText = ongoingOperations.Take(10).Aggregate(string.Empty, (current, n) => current + $"{n.Text} ({n.Progress:0%})\n"); - foreach (var n in ongoingOperations.Take(10)) - text += $"{n.Text} ({n.Progress:0%})\n"; + LocalisableString ongoingOperationsLocalisableString; if (ongoingOperations.Length > 10) - text += $"\nand {ongoingOperations.Length - 10} other operation(s).\n"; - - text += "\nLast chance to turn back"; + ongoingOperationsLocalisableString = DialogStrings.ConfirmExitBodyTextOtherOngoingOperations(ongoingOperationsText, ongoingOperations.Length - 10); + else + ongoingOperationsLocalisableString = DialogStrings.ConfirmExitBodyTextOngoingOperations(ongoingOperationsText); - BodyText = text; + BodyText = LocalisableString.Interpolate($"{ongoingOperationsLocalisableString}\n\n{DialogStrings.ConfirmDialogBodyText}"); Buttons = new PopupDialogButton[] { new PopupDialogDangerousButton { - Text = @"Let me out!", + Text = DialogStrings.ConfirmExitOkButton, Action = onConfirm }, new PopupDialogCancelButton @@ -66,18 +65,18 @@ private void load(INotificationOverlay notifications) } else { - BodyText = "Last chance to turn back"; + BodyText = DialogStrings.ConfirmDialogBodyText; Buttons = new PopupDialogButton[] { new PopupDialogOkButton { - Text = @"Let me out!", + Text = DialogStrings.ConfirmExitOkButton, Action = onConfirm }, new PopupDialogCancelButton { - Text = @"Just a little more...", + Text = DialogStrings.ConfirmExitCancelButton, Action = onCancel }, }; diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 0820d336225f..6e7e8e7a743b 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -501,7 +501,7 @@ public MobileDisclaimerDialog(Action confirmed) { new PopupDialogOkButton { - Text = "Understood", + Text = ButtonSystemStrings.MobileDisclaimerOkButton, Action = confirmed, }, }; diff --git a/osu.Game/Screens/OnlinePlay/Components/ConfirmExitMultiplayerMatchDialog.cs b/osu.Game/Screens/OnlinePlay/Components/ConfirmExitMultiplayerMatchDialog.cs new file mode 100644 index 000000000000..ad1e053726ff --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Components/ConfirmExitMultiplayerMatchDialog.cs @@ -0,0 +1,17 @@ +// 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 osu.Game.Localisation; +using osu.Game.Overlays.Dialog; + +namespace osu.Game.Screens.OnlinePlay.Components +{ + public partial class ConfirmExitMultiplayerMatchDialog : ConfirmDialog + { + public ConfirmExitMultiplayerMatchDialog(Action onConfirm) + : base(DialogStrings.ConfirmExitMultiplayerMatchBodyText, onConfirm) + { + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs index d692783e487e..0c0c1006adfa 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs @@ -30,6 +30,7 @@ using osu.Game.Overlays.Dialog; using osu.Game.Rulesets; using osu.Game.Screens.Footer; +using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.Gameplay; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Users; @@ -378,7 +379,7 @@ public override bool OnExiting(ScreenExitEvent e) confirmDialog.PerformOkAction(); else { - dialogOverlay.Push(new ConfirmDialog("Are you sure you want to leave this multiplayer match?", () => + dialogOverlay.Push(new ConfirmExitMultiplayerMatchDialog(() => { exitConfirmed = true; if (this.IsCurrentScreen()) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayScreen.cs index c61a8e1fc57c..a6d152dfdf82 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlayScreen.cs @@ -29,6 +29,7 @@ using osu.Game.Overlays.Dialog; using osu.Game.Overlays.Volume; using osu.Game.Rulesets; +using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Matchmaking.Match; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.Gameplay; using osu.Game.Screens.OnlinePlay.Matchmaking.Queue; @@ -455,7 +456,7 @@ public override bool OnExiting(ScreenExitEvent e) confirmDialog.PerformOkAction(); else { - dialogOverlay.Push(new ConfirmDialog("Are you sure you want to leave this multiplayer match?", () => + dialogOverlay.Push(new ConfirmExitMultiplayerMatchDialog(() => { exitConfirmed = true; if (this.IsCurrentScreen()) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs index f73983217f5f..97f30035cf88 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Threading; +using osu.Game.Localisation; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.Countdown; using osu.Game.Overlays; @@ -259,7 +260,7 @@ public partial class ConfirmAbortDialog : DangerousActionDialog { public ConfirmAbortDialog(Action abortMatch, Action cancel) { - HeaderText = "Are you sure you want to abort the match?"; + HeaderText = DialogStrings.ConfirmAbortMatchHeaderText; DangerousAction = abortMatch; CancelAction = cancel; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index ed4f431d4ea7..40c1309e90a8 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -878,7 +878,7 @@ private bool ensureExitConfirmed() confirmDialog.PerformOkAction(); else { - dialogOverlay.Push(new ConfirmDialog("Are you sure you want to leave this multiplayer match?", () => + dialogOverlay.Push(new ConfirmExitMultiplayerMatchDialog(() => { ExitConfirmed = true; this.Exit(); diff --git a/osu.Game/Screens/OnlinePlay/Playlists/ClosePlaylistDialog.cs b/osu.Game/Screens/OnlinePlay/Playlists/ClosePlaylistDialog.cs index 08fed037d3a1..4dbe08e93e93 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/ClosePlaylistDialog.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/ClosePlaylistDialog.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Game.Localisation; using osu.Game.Online.Rooms; using osu.Game.Overlays.Dialog; @@ -11,7 +12,7 @@ public partial class ClosePlaylistDialog : DeletionDialog { public ClosePlaylistDialog(Room room, Action closeAction) { - HeaderText = "Are you sure you want to close the following playlist:"; + HeaderText = DialogStrings.ClosePlaylistHeaderText; BodyText = room.Name; DangerousAction = closeAction; } diff --git a/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs b/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs index e3981c85f0fd..c681f89cd03e 100644 --- a/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs +++ b/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs @@ -5,19 +5,20 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Game.Beatmaps; +using osu.Game.Localisation; using osu.Game.Overlays.Dialog; using osu.Game.Scoring; namespace osu.Game.Screens.Select { - public partial class BeatmapClearScoresDialog : DangerousActionDialog + public partial class BeatmapClearScoresDialog : DeletionDialog { [Resolved] private ScoreManager scoreManager { get; set; } = null!; public BeatmapClearScoresDialog(BeatmapInfo beatmapInfo, Action? onCompletion = null) { - BodyText = $"All local scores on {beatmapInfo.GetDisplayTitle()}"; + BodyText = DialogStrings.BeatmapClearScoresBodyText(beatmapInfo.GetDisplayTitle()); DangerousAction = () => { Task.Run(() => scoreManager.Delete(beatmapInfo)) From 9105fc15b244a0c3a4d59241d7529de7562500cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 10 Mar 2026 17:57:25 +0900 Subject: [PATCH 791/836] Fix editor not updating titlebar with new difficulty name after rename (#36908) --- osu.Game/Screens/Edit/Editor.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 4ba1b2fac222..164d02d869d9 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -188,15 +188,14 @@ public bool ReadyForUse private bool isNewBeatmap; - protected override UserActivity InitialActivity + protected override UserActivity InitialActivity => getCurrentUserActivity(); + + private UserActivity getCurrentUserActivity() { - get - { - if (Beatmap.Value.Metadata.Author.OnlineID == api.LocalUser.Value.OnlineID) - return new UserActivity.EditingBeatmap(Beatmap.Value.BeatmapInfo); + if (Beatmap.Value.Metadata.Author.OnlineID == api.LocalUser.Value.OnlineID) + return new UserActivity.EditingBeatmap(Beatmap.Value.BeatmapInfo); - return new UserActivity.ModdingBeatmap(Beatmap.Value.BeatmapInfo); - } + return new UserActivity.ModdingBeatmap(Beatmap.Value.BeatmapInfo); } protected override bool InitialBackButtonVisibility => false; @@ -604,6 +603,9 @@ internal bool Save() updateLastSavedHash(); onScreenDisplay?.Display(new BeatmapEditorToast(ToastStrings.BeatmapSaved, editorBeatmap.BeatmapInfo.GetDisplayTitle())); Saved?.Invoke(); + + // This triggers an update to the window title post-save (ie if the difficulty name changed). + Activity.Value = getCurrentUserActivity(); return true; } From 14743a14eb243922ca65205cfd72f6dad1f2ef38 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 10 Mar 2026 20:40:54 +0900 Subject: [PATCH 792/836] Fix "Deselect all" mods button becoming enabled when system mods are applied (#36913) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://github.com/ppy/osu/issues/36906. --------- Co-authored-by: Bartłomiej Dach --- .../TestSceneModSelectOverlay.cs | 29 +++++++++++++++++++ .../Overlays/Mods/DeselectAllModsButton.cs | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index d0778172d933..b4f9365c8f5e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -698,6 +698,35 @@ public void TestDeselectAllViaKey_WithSearchApplied() AddUntilStep("all mods deselected", () => !SelectedMods.Value.Any()); } + [Test] + public void TestTouchDeviceDoesNotInterfereWithDeselectAll() + { + createScreen(); + changeRuleset(0); + + AddAssert("deselect all button disabled", () => !this.ChildrenOfType().Single().Enabled.Value); + + AddStep("select TD", () => SelectedMods.Value = new Mod[] { new OsuModTouchDevice() }); + AddAssert("deselect all button still disabled", () => !this.ChildrenOfType().Single().Enabled.Value); + + AddStep("click deselect all button", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("touch mod still present", () => SelectedMods.Value, () => Is.EqualTo(new Mod[] { new OsuModTouchDevice() })); + + AddStep("select NC + TD", () => SelectedMods.Value = new Mod[] { new OsuModTouchDevice(), new OsuModNightcore() }); + AddStep("click deselect all button", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("touch mod still present", () => SelectedMods.Value, () => Is.EqualTo(new Mod[] { new OsuModTouchDevice() })); + } + [Test] public void TestDeselectAllViaButton() { diff --git a/osu.Game/Overlays/Mods/DeselectAllModsButton.cs b/osu.Game/Overlays/Mods/DeselectAllModsButton.cs index 9b8ae1e3b6b0..0e5bb4d3dad7 100644 --- a/osu.Game/Overlays/Mods/DeselectAllModsButton.cs +++ b/osu.Game/Overlays/Mods/DeselectAllModsButton.cs @@ -33,7 +33,7 @@ protected override void LoadComplete() private void updateEnabledState() { - Enabled.Value = selectedMods.Value.Any(); + Enabled.Value = selectedMods.Value.Any(m => m.Type != ModType.System); } } } From 87b37fd3860d75c0a90f7a67adb94e3267d1779b Mon Sep 17 00:00:00 2001 From: MayoCollector Date: Wed, 11 Mar 2026 02:27:03 +0900 Subject: [PATCH 793/836] Fix volume slider title text horizontal scaling on some languages (#36915) closes #36892. |master|This PR| |---|---| |![osu_2026-03-10_18-37-55](https://github.com/user-attachments/assets/15defef7-e1b8-485b-928b-886bb79215e2)|![osu_2026-03-10_18-43-40](https://github.com/user-attachments/assets/df4926f8-d960-45e2-ab98-1b455dc789b5)| --- osu.Game/Overlays/Volume/VolumeMeter.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index ec3d897a635e..e75ee140675c 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -215,6 +215,7 @@ private void load(OsuColour colours, AudioManager audio) new Container { Size = LABEL_SIZE, + AutoSizeAxes = Axes.X, CornerRadius = 10, Masking = true, Margin = new MarginPadding { Left = CircleSize + 10 }, @@ -229,6 +230,10 @@ private void load(OsuColour colours, AudioManager audio) }, new OsuSpriteText { + Margin = new MarginPadding + { + Horizontal = 32, + }, Anchor = Anchor.Centre, Origin = Anchor.Centre, Font = OsuFont.GetFont(weight: FontWeight.Bold), From e9f59752c9600557b60c25d810d36df9e76364c2 Mon Sep 17 00:00:00 2001 From: "Rian (Reza Mouna Hendrian)" <52914632+Rian8337@users.noreply.github.com> Date: Wed, 11 Mar 2026 03:42:36 +0700 Subject: [PATCH 794/836] Fix Hidden mod perfect stacks buff for osu! reading difficulty (#36918) The `OpacityAt` conditional adds `Preempt` to `StartTime` when the intention is to check for when `previousObj` is hit, which means it should just be `StartTime`. In addition to that, the third conditional's purpose is to ensure that the buff only applies if `currObj` is animating (its opacity is changing from the Hidden mod) when `previousObj` is hit. This restructures it so that it reads more cleanly and communicates its purpose better. [Conversation](https://discord.com/channels/546120878908506119/1374004990875795586/1480886152042119190) --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs index 326e98609c31..3363e2fbe067 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs @@ -131,7 +131,7 @@ private static double calculateHiddenDifficulty(OsuDifficultyHitObject currObj, var previousObj = (OsuDifficultyHitObject)currObj.Previous(0); // Buff perfect stacks only if current note is completely invisible at the time you click the previous note. - if (currObj.LazyJumpDistance == 0 && currObj.OpacityAt(previousObj.BaseObject.StartTime + previousObj.Preempt, true) == 0 && previousObj.StartTime + previousObj.Preempt > currObj.StartTime) + if (currObj.LazyJumpDistance == 0 && currObj.OpacityAt(previousObj.BaseObject.StartTime, true) == 0 && previousObj.StartTime > currObj.StartTime - currObj.Preempt) hiddenDifficulty += hidden_multiplier * 2500 / Math.Pow(currObj.AdjustedDeltaTime, 1.5); // Perfect stacks are harder the less time between notes return hiddenDifficulty; From c2c8b901d3648e46c894acecfcce6f44c72645d9 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Wed, 11 Mar 2026 02:49:45 +0500 Subject: [PATCH 795/836] Remove `OsuStrainSkill` (#36917) --- .../Difficulty/OsuDifficultyCalculator.cs | 2 +- .../Difficulty/OsuPerformanceCalculator.cs | 6 +- .../Difficulty/Skills/Aim.cs | 44 ++++++++++++- .../Difficulty/Skills/OsuStrainSkill.cs | 62 ------------------- 4 files changed, 48 insertions(+), 66 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index bf4054e75b1c..2a425712b026 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -106,7 +106,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat var simulator = new OsuLegacyScoreSimulator(); var scoreAttributes = simulator.Simulate(WorkingBeatmap, beatmap); - double baseAimPerformance = OsuStrainSkill.DifficultyToPerformance(aimRating); + double baseAimPerformance = OsuPerformanceCalculator.DifficultyToPerformance(aimRating); double baseSpeedPerformance = HarmonicSkill.DifficultyToPerformance(speedRating); double baseReadingPerformance = HarmonicSkill.DifficultyToPerformance(readingRating); double baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 5c78917184ae..bdc80b691110 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -62,6 +62,8 @@ public class OsuPerformanceCalculator : PerformanceCalculator private double aimEstimatedSliderBreaks; private double speedEstimatedSliderBreaks; + public static double DifficultyToPerformance(double difficulty) => 4.0 * Math.Pow(difficulty, 3.0); + public OsuPerformanceCalculator() : base(new OsuRuleset()) { @@ -197,7 +199,7 @@ private double computeAimValue(ScoreInfo score, OsuDifficultyAttributes attribut aimDifficulty *= sliderNerfFactor; } - double aimValue = OsuStrainSkill.DifficultyToPerformance(aimDifficulty); + double aimValue = DifficultyToPerformance(aimDifficulty); double lengthBonus = 0.95 + 0.35 * Math.Min(1.0, totalHits / 2000.0) + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); @@ -488,7 +490,7 @@ private double calculateSpeedHighDeviationNerf(OsuDifficultyAttributes attribute if (speedDeviation == null) return 0; - double speedValue = OsuStrainSkill.DifficultyToPerformance(attributes.SpeedDifficulty); + double speedValue = HarmonicSkill.DifficultyToPerformance(attributes.SpeedDifficulty); // Decides a point where the PP value achieved compared to the speed deviation is assumed to be tapped improperly. Any PP above this point is considered "excess" speed difficulty. // This is used to cause PP above the cutoff to scale logarithmically towards the original speed value thus nerfing the value. diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index dec678519381..979b854cd172 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.Linq; +using osu.Framework.Utils; using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; @@ -18,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// /// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances. /// - public class Aim : OsuStrainSkill + public class Aim : StrainSkill { public readonly bool IncludeSliders; @@ -36,6 +38,17 @@ public Aim(Mod[] mods, bool includeSliders) private double skillMultiplierTotal => 1.1; private double meanExponent => 1.2; + /// + /// The number of sections with the highest strains, which the peak strain reductions will apply to. + /// This is done in order to decrease their impact on the overall difficulty of the map for this skill. + /// + private int reducedSectionCount => 10; + + /// + /// The baseline multiplier applied to the section with the biggest strain. + /// + private double reducedStrainBaseline => 0.75; + private readonly List sliderStrains = new List(); private double strainDecay(double ms) => Math.Pow(0.15, ms / 1000); @@ -127,5 +140,34 @@ public double GetDifficultSliders() public double CountTopWeightedSliders(double difficultyValue) => OsuStrainUtils.CountTopWeightedSliders(sliderStrains, difficultyValue); + + public override double DifficultyValue() + { + double difficulty = 0; + double weight = 1; + + // Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871). + // These sections will not contribute to the difficulty. + var peaks = GetCurrentStrainPeaks().Where(p => p > 0); + + List strains = peaks.OrderDescending().ToList(); + + // We are reducing the highest strains first to account for extreme difficulty spikes + for (int i = 0; i < Math.Min(strains.Count, reducedSectionCount); i++) + { + double scale = Math.Log10(Interpolation.Lerp(1, 10, Math.Clamp((float)i / reducedSectionCount, 0, 1))); + strains[i] *= Interpolation.Lerp(reducedStrainBaseline, 1.0, scale); + } + + // Difficulty is the weighted sum of the highest strains from every section. + // We're sorting from highest to lowest strain. + foreach (double strain in strains.OrderDescending()) + { + difficulty += strain * weight; + weight *= DecayWeight; + } + + return difficulty; + } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs deleted file mode 100644 index 916b6e7b2d51..000000000000 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs +++ /dev/null @@ -1,62 +0,0 @@ -// 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.Collections.Generic; -using osu.Game.Rulesets.Difficulty.Skills; -using osu.Game.Rulesets.Mods; -using System.Linq; -using osu.Framework.Utils; - -namespace osu.Game.Rulesets.Osu.Difficulty.Skills -{ - public abstract class OsuStrainSkill : StrainSkill - { - /// - /// The number of sections with the highest strains, which the peak strain reductions will apply to. - /// This is done in order to decrease their impact on the overall difficulty of the map for this skill. - /// - protected virtual int ReducedSectionCount => 10; - - /// - /// The baseline multiplier applied to the section with the biggest strain. - /// - protected virtual double ReducedStrainBaseline => 0.75; - - protected OsuStrainSkill(Mod[] mods) - : base(mods) - { - } - - public override double DifficultyValue() - { - double difficulty = 0; - double weight = 1; - - // Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871). - // These sections will not contribute to the difficulty. - var peaks = GetCurrentStrainPeaks().Where(p => p > 0); - - List strains = peaks.OrderDescending().ToList(); - - // We are reducing the highest strains first to account for extreme difficulty spikes - for (int i = 0; i < Math.Min(strains.Count, ReducedSectionCount); i++) - { - double scale = Math.Log10(Interpolation.Lerp(1, 10, Math.Clamp((float)i / ReducedSectionCount, 0, 1))); - strains[i] *= Interpolation.Lerp(ReducedStrainBaseline, 1.0, scale); - } - - // Difficulty is the weighted sum of the highest strains from every section. - // We're sorting from highest to lowest strain. - foreach (double strain in strains.OrderDescending()) - { - difficulty += strain * weight; - weight *= DecayWeight; - } - - return difficulty; - } - - public static double DifficultyToPerformance(double difficulty) => 4.0 * Math.Pow(difficulty, 3.0); - } -} From 29e089c6203a80e23dee5a6503be47cb5f0b057e Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Wed, 11 Mar 2026 03:14:27 +0500 Subject: [PATCH 796/836] Organize osu! difficulty evaluators a bit better (#36921) --- .../Difficulty/Evaluators/{ => Aim}/AgilityEvaluator.cs | 2 +- .../Difficulty/Evaluators/{ => Aim}/FlowAimEvaluator.cs | 2 +- .../Difficulty/Evaluators/{ => Aim}/SnapAimEvaluator.cs | 2 +- .../Difficulty/Evaluators/{ => Speed}/RhythmEvaluator.cs | 2 +- .../Difficulty/Evaluators/{ => Speed}/SpeedEvaluator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) rename osu.Game.Rulesets.Osu/Difficulty/Evaluators/{ => Aim}/AgilityEvaluator.cs (96%) rename osu.Game.Rulesets.Osu/Difficulty/Evaluators/{ => Aim}/FlowAimEvaluator.cs (99%) rename osu.Game.Rulesets.Osu/Difficulty/Evaluators/{ => Aim}/SnapAimEvaluator.cs (99%) rename osu.Game.Rulesets.Osu/Difficulty/Evaluators/{ => Speed}/RhythmEvaluator.cs (99%) rename osu.Game.Rulesets.Osu/Difficulty/Evaluators/{ => Speed}/SpeedEvaluator.cs (97%) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AgilityEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs similarity index 96% rename from osu.Game.Rulesets.Osu/Difficulty/Evaluators/AgilityEvaluator.cs rename to osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs index 2d0d2897a2be..5208520bb471 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AgilityEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; -namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators +namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators.Aim { public static class AgilityEvaluator { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlowAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs similarity index 99% rename from osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlowAimEvaluator.cs rename to osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs index 61451c4f9398..924e1c346efe 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlowAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.Osu.Objects; using osuTK; -namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators +namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators.Aim { public static class FlowAimEvaluator { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SnapAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs similarity index 99% rename from osu.Game.Rulesets.Osu/Difficulty/Evaluators/SnapAimEvaluator.cs rename to osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs index 15d8ef033e5b..5df70225a1ef 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SnapAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; -namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators +namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators.Aim { public static class SnapAimEvaluator { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Speed/RhythmEvaluator.cs similarity index 99% rename from osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs rename to osu.Game.Rulesets.Osu/Difficulty/Evaluators/Speed/RhythmEvaluator.cs index bd7dcfd59262..e2ee41162b41 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Speed/RhythmEvaluator.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; -namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators +namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators.Speed { public static class RhythmEvaluator { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Speed/SpeedEvaluator.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs rename to osu.Game.Rulesets.Osu/Difficulty/Evaluators/Speed/SpeedEvaluator.cs index 5b724af2a025..65aab9e4bd64 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Speed/SpeedEvaluator.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; -namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators +namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators.Speed { public static class SpeedEvaluator { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 979b854cd172..6ff42e66a8c0 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Difficulty.Evaluators; +using osu.Game.Rulesets.Osu.Difficulty.Evaluators.Aim; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Utils; using osu.Game.Rulesets.Osu.Mods; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index a50a5cfab687..39a3a4919c35 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -5,11 +5,11 @@ using System.Collections.Generic; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Difficulty.Evaluators; using osu.Game.Rulesets.Osu.Objects; using System.Linq; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Difficulty.Utils; +using osu.Game.Rulesets.Osu.Difficulty.Evaluators.Speed; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; namespace osu.Game.Rulesets.Osu.Difficulty.Skills From 6c9a7292e7bdb6472bd218513b3626ff35351089 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Wed, 11 Mar 2026 03:48:09 +0500 Subject: [PATCH 797/836] Adjust `Speed` harmonic summation params (#36923) Slight balancing. Mostly exists to reduce extremely consistent tapping maps (i.e [Age of Tyranny](https://osu.ppy.sh/beatmapsets/2219231#osu/4704022)) influence over the summation --------- Co-authored-by: James Wilson --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 6ff42e66a8c0..b2ecb817dc59 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -34,7 +34,7 @@ public Aim(Mod[] mods, bool includeSliders) private double skillMultiplierSnap => 71.0; private double skillMultiplierAgility => 2.0; - private double skillMultiplierFlow => 238.0; + private double skillMultiplierFlow => 244.0; private double skillMultiplierTotal => 1.1; private double meanExponent => 1.2; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 39a3a4919c35..2462186c780d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Speed : HarmonicSkill { - private double skillMultiplier => 1.05; + private double skillMultiplier => 1.15; private readonly List sliderStrains = new List(); @@ -28,7 +28,7 @@ public class Speed : HarmonicSkill private double strainDecayBase => 0.3; protected override double HarmonicScale => 20; - protected override double DecayExponent => 0.85; + protected override double DecayExponent => 0.9; public Speed(Mod[] mods) : base(mods) From b0ee82dc4fb6d957baee8e7a966a46c0f40457e9 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 11 Mar 2026 03:38:40 +0000 Subject: [PATCH 798/836] Remove `OsuStrainUtils` (#36924) The only method inside this class is used in a single place ever since Speed became a harmonic skill so it doesn't really make sense to keep around to me. As a result, supersedes #33295. Also includes a fix to use `DecayWeight` for the consistent top strain, exactly the same as what we're doing for `CountTopWeightedStrains`. --- .../Difficulty/Skills/Aim.cs | 14 ++++++++-- .../Difficulty/Utils/OsuStrainUtils.cs | 26 ------------------- 2 files changed, 12 insertions(+), 28 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Difficulty/Utils/OsuStrainUtils.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index b2ecb817dc59..06522d8e8563 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -11,7 +11,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Evaluators.Aim; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; -using osu.Game.Rulesets.Osu.Difficulty.Utils; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; @@ -139,7 +138,18 @@ public double GetDifficultSliders() } public double CountTopWeightedSliders(double difficultyValue) - => OsuStrainUtils.CountTopWeightedSliders(sliderStrains, difficultyValue); + { + if (sliderStrains.Count == 0) + return 0; + + double consistentTopStrain = difficultyValue * (1 - DecayWeight); // What would the top strain be if all strain values were identical + + if (consistentTopStrain == 0) + return 0; + + // Use a weighted sum of all strains. Constants are arbitrary and give nice values + return sliderStrains.Sum(s => DifficultyCalculationUtils.Logistic(s / consistentTopStrain, 0.88, 10, 1.1)); + } public override double DifficultyValue() { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Utils/OsuStrainUtils.cs b/osu.Game.Rulesets.Osu/Difficulty/Utils/OsuStrainUtils.cs deleted file mode 100644 index 8a78192ee4cf..000000000000 --- a/osu.Game.Rulesets.Osu/Difficulty/Utils/OsuStrainUtils.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using System.Linq; -using osu.Game.Rulesets.Difficulty.Utils; - -namespace osu.Game.Rulesets.Osu.Difficulty.Utils -{ - public static class OsuStrainUtils - { - public static double CountTopWeightedSliders(IReadOnlyCollection sliderStrains, double difficultyValue) - { - if (sliderStrains.Count == 0) - return 0; - - double consistentTopStrain = difficultyValue / 10; // What would the top strain be if all strain values were identical - - if (consistentTopStrain == 0) - return 0; - - // Use a weighted sum of all strains. Constants are arbitrary and give nice values - return sliderStrains.Sum(s => DifficultyCalculationUtils.Logistic(s / consistentTopStrain, 0.88, 10, 1.1)); - } - } -} From ce571e328df9ddc12fce469fba10dbe13184c5da Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 11 Mar 2026 15:48:04 +0900 Subject: [PATCH 799/836] Ranked Play: Fix casing inconsistency in results screen (#36931) This is kind of annoying... Some hit results are given custom names (e.g. "slider tick"): https://github.com/ppy/osu/blob/87b37fd3860d75c0a90f7a67adb94e3267d1779b/osu.Game.Rulesets.Osu/OsuRuleset.cs#L301-L320 While others go through that `base` call which uses the enum descriptions (e.g. "Great"): https://github.com/ppy/osu/blob/87b37fd3860d75c0a90f7a67adb94e3267d1779b/osu.Game/Rulesets/Scoring/HitResult.cs#L53-L56 --- .../RankedPlay/ResultsScreen.ScoreStatisticsDisplay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreStatisticsDisplay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreStatisticsDisplay.cs index 217984beff4c..0f1540220011 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreStatisticsDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.ScoreStatisticsDisplay.cs @@ -3,6 +3,7 @@ using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Scoring; @@ -48,7 +49,7 @@ private void load() Children = score.GetStatisticsForDisplay().Select(it => new BeatmapTitleWedge.StatisticDifficulty { Width = 80, - Value = new BeatmapTitleWedge.StatisticDifficulty.Data(it.DisplayName, it.Count, it.Count, it.MaxCount ?? it.Count), + Value = new BeatmapTitleWedge.StatisticDifficulty.Data(it.DisplayName.ToTitle(), it.Count, it.Count, it.MaxCount ?? it.Count), AccentColour = colours.PrimaryDarker, }).ToArray(), } From 4c0657f4ca88769fcc3b1cb4fa2dcc8bb862f9e3 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 11 Mar 2026 17:04:51 +0900 Subject: [PATCH 800/836] Ranked Play: Add countdown timer to all screens (#36930) There's been [some feedback](https://discord.com/channels/90072389919997952/1476979671886205060/1477868178775216148) that there's no timer during some screens. Personally I feel like some screens shouldn't require it, but I get it. The results screen is going to be the most controversial one, where I've decided to shift the content down a bit - it would otherwise overlap with the progress bar. Another option is to make the progress bar shorter, but I feel like that makes things inconsistent. image Regarding implementation, I'm not entirely sure on it being added to every subscreen via `RankedPlaySubScreen` instead of just a single component at a top level. I did it this way because the colour scheme seems annoying to change without recreating the entire component (or otherwise all of its children) anyway. --- .../Components/RankedPlayStageDisplay.cs | 77 ++++++++++++++++--- .../Matchmaking/RankedPlay/DiscardScreen.cs | 16 ++-- .../Matchmaking/RankedPlay/EndedScreen.cs | 4 + .../Matchmaking/RankedPlay/GameplayScreen.cs | 4 + .../RankedPlay/GameplayWarmupScreen.cs | 4 + .../RankedPlay/Intro/IntroScreen.cs | 5 ++ .../RankedPlay/OpponentPickScreen.cs | 12 +-- .../Matchmaking/RankedPlay/PickScreen.cs | 10 +-- .../RankedPlay/RankedPlaySubScreen.cs | 27 ++++++- .../Matchmaking/RankedPlay/ResultsScreen.cs | 20 ++--- 10 files changed, 137 insertions(+), 42 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayStageDisplay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayStageDisplay.cs index d0fb4f9332a2..8bcd66292a80 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayStageDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayStageDisplay.cs @@ -3,7 +3,6 @@ using System; using osu.Framework.Allocation; -using osu.Framework.Audio; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; @@ -21,24 +20,20 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components { - public partial class RankedPlayStageDisplay : CompositeDrawable + public partial class RankedPlayStageDisplay : VisibilityContainer { - public required LocalisableString Heading { get; init; } - - public required LocalisableString Caption { get; init; } - - public Color4? CaptionColour { get; init; } - [Resolved] private MultiplayerClient client { get; set; } = null!; private readonly RankedPlayColourScheme colourScheme; private Drawable headingTextBackground = null!; - private OsuSpriteText headingText = null!; private Drawable progressBar = null!; private OsuSpriteText progressText = null!; + private OsuSpriteText? headingText; + private OsuSpriteText? captionText; + private DateTimeOffset countdownStartTime; private DateTimeOffset countdownEndTime; @@ -50,7 +45,7 @@ public RankedPlayStageDisplay(RankedPlayColourScheme colourScheme) } [BackgroundDependencyLoader] - private void load(AudioManager audio) + private void load() { const float phase_text_background_height = 55; Vector2 progressBarSize = new Vector2(300, 25); @@ -162,7 +157,7 @@ private void load(AudioManager audio) } ] }, - new OsuSpriteText + captionText = new OsuSpriteText { Margin = new MarginPadding { @@ -176,6 +171,54 @@ private void load(AudioManager audio) }; } + private LocalisableString heading; + + /// + /// Heading text to be displayed indicating the purpose of the current stage. + /// + public LocalisableString Heading + { + get => heading; + set + { + heading = value; + if (headingText != null) + headingText.Text = value; + } + } + + private LocalisableString caption; + + /// + /// Subtitle text to be displayed indicating the action a user should take in the current stage. + /// + public LocalisableString Caption + { + get => caption; + set + { + caption = value; + if (captionText != null) + captionText.Text = value; + } + } + + private Color4? captionColour; + + /// + /// Overrides the default caption colour from the colour scheme with a custom one. + /// + public Color4? CaptionColour + { + get => captionColour; + set + { + captionColour = value; + if (captionText != null) + captionText.Colour = value ?? colourScheme.Primary; + } + } + protected override void LoadComplete() { base.LoadComplete(); @@ -194,7 +237,7 @@ protected override void Update() { base.Update(); - headingTextBackground.Width = headingText.DrawWidth + 80; + headingTextBackground.Width = headingText!.DrawWidth + 80; TimeSpan duration = countdownEndTime - countdownStartTime; TimeSpan remaining = countdownEndTime - DateTimeOffset.Now; @@ -226,6 +269,16 @@ private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add countdownEndTime = DateTimeOffset.Now; }); + protected override void PopIn() + { + this.FadeIn(); + } + + protected override void PopOut() + { + this.FadeOut(); + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs index c044a0d4c6c9..69da87aaa08e 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs @@ -11,6 +11,7 @@ using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; +using osu.Framework.Localisation; using osu.Game.Audio; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -33,6 +34,9 @@ public partial class DiscardScreen : RankedPlaySubScreen public CardFlow CenterRow { get; private set; } = null!; + protected override LocalisableString StageHeading => "Discard Phase"; + protected override LocalisableString StageCaption => "Replace cards from your hand"; + private PlayerHandOfCards playerHand = null!; private ShearedButton discardButton = null!; private OsuTextFlowContainer explainer = null!; @@ -57,6 +61,11 @@ public partial class DiscardScreen : RankedPlaySubScreen private DateTimeOffset stageEndTime; private TimeSpan stageDuration; + public DiscardScreen() + { + StageDisplay.CaptionColour = Color4.White; + } + [BackgroundDependencyLoader] private void load(AudioManager audio) { @@ -72,13 +81,6 @@ private void load(AudioManager audio) Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - new RankedPlayStageDisplay(RankedPlayColourScheme.Blue) - { - Heading = "Discard Phase", - Caption = "Replace cards from your hand", - CaptionColour = Color4.White, - Margin = new MarginPadding { Top = 60 }, - }, discardButton = new ShearedButton { Name = "Discard Button", diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/EndedScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/EndedScreen.cs index ba0549e5fa20..b76f8a7944fa 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/EndedScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/EndedScreen.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -24,6 +25,9 @@ public partial class EndedScreen : RankedPlaySubScreen ///
    public Action? ExitRequested { get; init; } + protected override LocalisableString StageHeading => "Results"; + protected override LocalisableString StageCaption => string.Empty; + [Resolved] private RankedPlayMatchInfo matchInfo { get; set; } = null!; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayScreen.cs index 8a558b24e3d8..251c30499546 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayScreen.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK; @@ -12,6 +13,9 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay { public partial class GameplayScreen : RankedPlaySubScreen { + protected override LocalisableString StageHeading => "Gameplay"; + protected override LocalisableString StageCaption => string.Empty; + [BackgroundDependencyLoader] private void load() { diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.cs index 80f4bb4ad54c..c01a732c7411 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Game.Database; using osu.Game.Graphics.Containers; @@ -24,6 +25,9 @@ public partial class GameplayWarmupScreen : RankedPlaySubScreen { public override bool ShowBeatmapBackground => true; + protected override LocalisableString StageHeading => "Gameplay"; + protected override LocalisableString StageCaption => string.Empty; + [Cached(typeof(IBindable))] private readonly Bindable lastLookupResult = new Bindable(); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/IntroScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/IntroScreen.cs index 87fac18026bb..7cfed62015c5 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/IntroScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/IntroScreen.cs @@ -9,6 +9,7 @@ using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; using osu.Game.Database; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; @@ -20,9 +21,13 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro { public partial class IntroScreen : RankedPlaySubScreen { + protected override LocalisableString StageHeading => string.Empty; + protected override LocalisableString StageCaption => string.Empty; + public IntroScreen() { CornerPieceVisibility.Value = Visibility.Hidden; + CountdownVisibility.Value = Visibility.Hidden; } [Resolved] diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/OpponentPickScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/OpponentPickScreen.cs index 122b3ff8dd9a..aa8f392890be 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/OpponentPickScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/OpponentPickScreen.cs @@ -8,6 +8,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Graphics; +using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Game.Audio; using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay; @@ -22,6 +23,11 @@ public partial class OpponentPickScreen : RankedPlaySubScreen { public CardFlow CenterRow { get; private set; } = null!; + protected override LocalisableString StageHeading => "Pick Phase"; + protected override LocalisableString StageCaption => "Waiting for your opponent..."; + + protected override RankedPlayColourScheme ColourScheme => RankedPlayColourScheme.Red; + private PlayerHandOfCards playerHand = null!; private OpponentHandOfCards opponentHand = null!; @@ -46,12 +52,6 @@ private void load(AudioManager audio) Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - new RankedPlayStageDisplay(RankedPlayColourScheme.Red) - { - Heading = "Pick Phase", - Caption = "Waiting for your opponent...", - Margin = new MarginPadding { Top = 60 }, - }, ]; CenterColumn.Children = diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs index 0a232322ca3c..2d94e28ff3de 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs @@ -8,6 +8,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Graphics; +using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Game.Audio; using osu.Game.Online.Multiplayer; @@ -27,6 +28,9 @@ public partial class PickScreen : RankedPlaySubScreen public CardFlow CenterRow { get; private set; } = null!; + protected override LocalisableString StageHeading => "Pick Phase"; + protected override LocalisableString StageCaption => "It's your turn to play a card!"; + private PlayerHandOfCards playerHand = null!; private OpponentHandOfCards opponentHand = null!; @@ -65,12 +69,6 @@ private void load(AudioManager audio) Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - new RankedPlayStageDisplay(RankedPlayColourScheme.Blue) - { - Heading = "Pick Phase", - Caption = "It's your turn to play a card!", - Margin = new MarginPadding { Top = 60 }, - }, ]; CenterColumn.Children = diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlaySubScreen.cs index b19340107f02..46aa1d20cb0e 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlaySubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlaySubScreen.cs @@ -7,6 +7,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; using osu.Game.Online.Multiplayer; using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components; using osuTK; @@ -18,19 +19,34 @@ public abstract partial class RankedPlaySubScreen : Container public const float CENTERED_CARD_SCALE = 1.2f; public readonly Bindable CornerPieceVisibility = new Bindable(Visibility.Visible); + protected readonly Bindable CountdownVisibility = new Bindable(Visibility.Visible); public virtual bool ShowBeatmapBackground => false; + /// + /// Heading text to be displayed indicating the purpose of the current stage. + /// + protected abstract LocalisableString StageHeading { get; } + + /// + /// Subtitle text to be displayed indicating the action a user should take in the current stage. + /// + protected abstract LocalisableString StageCaption { get; } + + /// + /// The colour scheme commonly used for components of this screen. + /// + protected virtual RankedPlayColourScheme ColourScheme => RankedPlayColourScheme.Blue; + [Resolved] private MultiplayerClient client { get; set; } = null!; protected MultiplayerClient Client => client; protected override Container Content { get; } - protected readonly Container CenterColumn; - protected readonly FillFlowContainer ButtonsContainer; + protected readonly RankedPlayStageDisplay StageDisplay; protected RankedPlaySubScreen() { @@ -62,6 +78,13 @@ protected RankedPlaySubScreen() Direction = FillDirection.Vertical, Spacing = new Vector2(8) }, + StageDisplay = new RankedPlayStageDisplay(ColourScheme) + { + Heading = StageHeading, + Caption = StageCaption, + Margin = new MarginPadding { Top = 60 }, + State = { BindTarget = CountdownVisibility } + }, ]; } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.cs index 872920272a2a..129ffc61dc7d 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Transforms; +using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Framework.Utils; using osu.Game.Beatmaps; @@ -36,6 +37,9 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay { public partial class ResultsScreen : RankedPlaySubScreen { + protected override LocalisableString StageHeading => "Results"; + protected override LocalisableString StageCaption => string.Empty; + public override bool ShowBeatmapBackground => true; [Resolved] @@ -63,14 +67,11 @@ private void load() { CornerPieceVisibility.Value = Visibility.Hidden; - InternalChildren = new Drawable[] + AddInternal(loadingSpinner = new LoadingSpinner { - loadingSpinner = new LoadingSpinner - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre - }, - }; + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }); } protected override void LoadComplete() @@ -160,6 +161,9 @@ private void setScores(ScoreInfo[] scores) => Scheduler.Add(() => AddInternal(new ResultScreenContent { + RelativeSizeAxes = Axes.Both, + // A little bit of room for the countdown timer... + Margin = new MarginPadding { Top = 45 }, PlayerScore = playerScore, OpponentScore = opponentScore, PlayerDamageInfo = matchInfo.RoomState.Users[playerId].DamageInfo!, @@ -210,8 +214,6 @@ private void load() .OfType() .MaxBy(it => it.Damage)!; - RelativeSizeAxes = Axes.Both; - AddInternal(panelScaffold = new PanelScaffold { Anchor = Anchor.Centre, From d0d5d97cfea8b4664c0110ca384d57c3ef44aec5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Mar 2026 19:08:26 +0900 Subject: [PATCH 801/836] Add replay / spectator mode scrolling text back (#36911) As mentioned in https://github.com/ppy/osu/discussions/36883. This has caught me off-guard a few times. Was a quick one to make this work like it does on stable. It doesn't fit as well as stable because we have a lot of elements at the top of the screen, but I think it's better than nothing, as it lets you know you're in a replay quick obviously. I don't think we can easily localise strings with formatting in them yet. Maybe using a `MarkdownContainer` or something? --- .../TestSceneExpandedPanelMiddleContent.cs | 4 +- osu.Game/Rulesets/Mods/ModExtensions.cs | 2 + osu.Game/Screens/Play/Player.cs | 10 +++- osu.Game/Screens/Play/ReplayPlayer.cs | 25 +++++++++ osu.Game/Screens/Play/ScrollingMessage.cs | 44 +++++++++++++++ osu.Game/Screens/Play/SpectatorPlayer.cs | 20 ++++--- .../Expanded/ExpandedPanelMiddleContent.cs | 40 +------------- .../Screens/Ranking/Expanded/PlayedOnText.cs | 55 +++++++++++++++++++ 8 files changed, 150 insertions(+), 50 deletions(-) create mode 100644 osu.Game/Screens/Play/ScrollingMessage.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/PlayedOnText.cs diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs index eade5aaf5dad..df9dbf90eebe 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs @@ -67,7 +67,7 @@ public void TestMapWithUnknownMapper() AddAssert("mapped by text not present", () => this.ChildrenOfType().All(spriteText => !containsAny(spriteText.Text.ToString(), "mapped", "by"))); - AddAssert("play time displayed", () => this.ChildrenOfType().Any()); + AddAssert("play time displayed", () => this.ChildrenOfType().Any()); } [Test] @@ -137,7 +137,7 @@ public void TestWithDefaultDate() showPanel(score); }); - AddAssert("play time not displayed", () => !this.ChildrenOfType().Any()); + AddAssert("play time not displayed", () => !this.ChildrenOfType().Any()); } [Test] diff --git a/osu.Game/Rulesets/Mods/ModExtensions.cs b/osu.Game/Rulesets/Mods/ModExtensions.cs index bd2d42f3ebf4..b9f723e88e23 100644 --- a/osu.Game/Rulesets/Mods/ModExtensions.cs +++ b/osu.Game/Rulesets/Mods/ModExtensions.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.Collections.Generic; using System.Linq; using osu.Game.Beatmaps; @@ -20,6 +21,7 @@ public static Score CreateScoreFromReplayData(this ICreateReplayData mod, IBeatm Replay = replayData.Replay, ScoreInfo = { + Date = DateTimeOffset.Now, User = new APIUser { Id = replayData.User.OnlineID, diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index ba543db996fb..97c0a0b7690e 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -311,7 +311,7 @@ private void load(OsuConfigManager config, OsuGameBase game, CancellationToken c { // underlay and gameplay should have access to the skinning sources. createUnderlayComponents(Beatmap.Value), - createGameplayComponents(Beatmap.Value) + createGameplayComponents() } }, FailOverlay = new FailOverlay @@ -426,6 +426,11 @@ private void load(OsuConfigManager config, OsuGameBase game, CancellationToken c IsBreakTime.BindValueChanged(onBreakTimeChanged, true); } + /// + /// Implement to add any components which should exist above gameplay but below the HUD. + /// + protected virtual Drawable CreateOverlayComponents() => Empty(); + protected virtual GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) => new MasterGameplayClockContainer(beatmap, gameplayStart); private Drawable createUnderlayComponents(WorkingBeatmap working) @@ -451,7 +456,7 @@ private Drawable createUnderlayComponents(WorkingBeatmap working) return container; } - private Drawable createGameplayComponents(IWorkingBeatmap working) => new ScalingContainer(ScalingMode.Gameplay) + private Drawable createGameplayComponents() => new ScalingContainer(ScalingMode.Gameplay) { Children = new Drawable[] { @@ -474,6 +479,7 @@ private Drawable createOverlayComponents() Children = new[] { DimmableStoryboard.OverlayLayerContainer.CreateProxy(), + CreateOverlayComponents(), HUDOverlay = new HUDOverlay(DrawableRuleset, GameplayState.Mods, Configuration) { HoldToQuit = diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index cd769d761596..e3c0361052b3 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -12,12 +12,15 @@ using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Input.Bindings; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Screens.Ranking; +using osu.Game.Screens.Ranking.Expanded; using osu.Game.Skinning; using osu.Game.Users; @@ -97,6 +100,7 @@ private void load(OsuConfigManager config) playbackSettings.UserPlaybackRate.BindTo(master.UserPlaybackRate); HUDOverlay.PlayerSettingsOverlay.AddAtStart(playbackSettings); + AddInternal(new RulesetSkinProvidingContainer(GameplayState.Ruleset, GameplayState.Beatmap, Beatmap.Value.Skin) { Child = failIndicator = new ReplayFailIndicator(GameplayClockContainer) @@ -113,6 +117,27 @@ private void load(OsuConfigManager config) }); } + protected override Drawable CreateOverlayComponents() + { + OsuTextFlowContainer message = new OsuTextFlowContainer(cp => cp.Font = OsuFont.Style.Body) { AutoSizeAxes = Axes.Both }; + message.AddText("Watching "); + message.AddText(Score.ScoreInfo.User.Username, s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); + message.AddText(" play "); + message.AddText(Beatmap.Value.BeatmapInfo.GetDisplayTitleRomanisable(), s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); + message.AddText(" on "); + message.AddArbitraryDrawable(new PlayedOnText(Score.ScoreInfo.Date, false) + { + Font = OsuFont.Style.Body.With(weight: FontWeight.SemiBold), + }); + + return new ScrollingMessage(message) + { + Y = 100, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }; + } + protected override void PrepareReplay() { DrawableRuleset?.SetReplayScore(Score); diff --git a/osu.Game/Screens/Play/ScrollingMessage.cs b/osu.Game/Screens/Play/ScrollingMessage.cs new file mode 100644 index 000000000000..9dcd303fe141 --- /dev/null +++ b/osu.Game/Screens/Play/ScrollingMessage.cs @@ -0,0 +1,44 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Screens.Play +{ + public partial class ScrollingMessage : CompositeDrawable + { + private readonly Drawable messageContent; + + public ScrollingMessage(Drawable messageContent) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + InternalChild = this.messageContent = messageContent; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + this.FadeInFromZero(2000, Easing.OutQuint); + resetMessagePosition(); + } + + protected override void Update() + { + base.Update(); + + if (messageContent.X + messageContent.DrawWidth > 0) + messageContent.X -= (float)Clock.ElapsedFrameTime * 0.05f; + else + resetMessagePosition(); + } + + private void resetMessagePosition() + { + messageContent.X = DrawWidth + 10; + } + } +} diff --git a/osu.Game/Screens/Play/SpectatorPlayer.cs b/osu.Game/Screens/Play/SpectatorPlayer.cs index 22c966e0afbb..6d008447bb68 100644 --- a/osu.Game/Screens/Play/SpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SpectatorPlayer.cs @@ -7,7 +7,7 @@ using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.Containers; using osu.Game.Online.Spectator; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays.Types; @@ -29,17 +29,23 @@ protected SpectatorPlayer(Score score, PlayerConfiguration? configuration = null this.score = score; } - [BackgroundDependencyLoader] - private void load() + protected override Drawable CreateOverlayComponents() { - AddInternal(new OsuSpriteText + // TODO: This should be customised for `MultiplayerSpectatorPlayer` to be static and only show the player name. + // Or maybe we should completely redesign this to show the user avatar and other things if that happens. + OsuTextFlowContainer message = new OsuTextFlowContainer(cp => cp.Font = OsuFont.Style.Body) { AutoSizeAxes = Axes.Both }; + message.AddText("Watching "); + message.AddText(Score.ScoreInfo.User.Username, s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); + message.AddText(" play "); + message.AddText(Beatmap.Value.BeatmapInfo.GetDisplayTitleRomanisable(), s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); + message.AddText(" live", s => s.Font = s.Font.With(weight: FontWeight.Bold)); + + return new ScrollingMessage(message) { - Text = $"Watching {score.ScoreInfo.User.Username} playing live!", - Font = OsuFont.Default.With(size: 30), Y = 100, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - }); + }; } protected override void LoadComplete() diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 445d219c7f55..0f11b01ddec7 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -1,19 +1,15 @@ // 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.Collections.Generic; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Extensions; -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; -using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -237,7 +233,7 @@ private void load(RealmAccess realmAccess, BeatmapDifficultyCache beatmapDifficu }); if (score.Date != default) - AddInternal(new PlayedOnText(score.Date)); + AddInternal(new PlayedOnText(score.Date, true)); } protected override void LoadComplete() @@ -268,40 +264,6 @@ protected override void LoadComplete() }); } - public partial class PlayedOnText : OsuSpriteText - { - private readonly DateTimeOffset time; - private readonly Bindable prefer24HourTime = new Bindable(); - - public PlayedOnText(DateTimeOffset time) - { - this.time = time; - - Anchor = Anchor.BottomCentre; - Origin = Anchor.BottomCentre; - Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold); - } - - [BackgroundDependencyLoader] - private void load(OsuConfigManager configManager) - { - configManager.BindWith(OsuSetting.Prefer24HourTime, prefer24HourTime); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - prefer24HourTime.BindValueChanged(_ => updateDisplay(), true); - } - - private void updateDisplay() - { - Text = LocalisableString.Format("Played on {0}", - time.ToLocalTime().ToLocalisableString(prefer24HourTime.Value ? @"d MMMM yyyy HH:mm" : @"d MMMM yyyy h:mm tt")); - } - } - internal partial class ClickableMetadata : OsuHoverContainer { [Resolved] diff --git a/osu.Game/Screens/Ranking/Expanded/PlayedOnText.cs b/osu.Game/Screens/Ranking/Expanded/PlayedOnText.cs new file mode 100644 index 000000000000..9ac453bfb76c --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/PlayedOnText.cs @@ -0,0 +1,55 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Localisation; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Screens.Ranking.Expanded +{ + public partial class PlayedOnText : OsuSpriteText + { + private readonly DateTimeOffset time; + private readonly bool withPrefix; + private readonly Bindable prefer24HourTime = new Bindable(); + + public PlayedOnText(DateTimeOffset time, bool withPrefix) + { + this.time = time; + this.withPrefix = withPrefix; + + Anchor = Anchor.BottomCentre; + Origin = Anchor.BottomCentre; + Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold); + } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager configManager) + { + configManager.BindWith(OsuSetting.Prefer24HourTime, prefer24HourTime); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + prefer24HourTime.BindValueChanged(_ => updateDisplay(), true); + } + + private void updateDisplay() + { + var timeText = time.ToLocalTime().ToLocalisableString(prefer24HourTime.Value ? @"d MMMM yyyy HH:mm" : @"d MMMM yyyy h:mm tt"); + + if (withPrefix) + Text = LocalisableString.Format("Played on {0}", timeText); + else + Text = timeText; + } + } +} From 390fc521e9342778fa74f8f9ae899d21976e3519 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Wed, 11 Mar 2026 20:06:01 +0800 Subject: [PATCH 802/836] Fix avatar sometimes showing as guest in beatmap detail comment container (#36935) - close https://github.com/ppy/osu/issues/34969 The solution here is shown in the issue. I don't think this needs a test... if need I will write one --- osu.Game/Overlays/Comments/CommentsContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 5e277357a949..20b12806ceb5 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -188,7 +188,7 @@ private void load(OverlayColourProvider colourProvider) protected override void LoadComplete() { User.BindValueChanged(_ => refetchComments()); - User.BindValueChanged(e => avatar.User = e.NewValue); + User.BindValueChanged(e => avatar.User = e.NewValue, true); Sort.BindValueChanged(_ => refetchComments(), true); base.LoadComplete(); } From 94c9f16b27e2de13bfa24345ae579f16d03a85c8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2026 16:03:01 +0900 Subject: [PATCH 803/836] Update editor hitsound icons with new designs from Adarin (#36940) | Before | After | | :---: | :---: | | 2026-03-12 00 56 58@2x | 2026-03-12 01 06 04@2x | --- osu.Game/Graphics/OsuIcon.cs | 4 ++++ .../Edit/Compose/Components/ComposeBlueprintContainer.cs | 2 +- osu.Game/osu.Game.csproj | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/OsuIcon.cs b/osu.Game/Graphics/OsuIcon.cs index a02c61128528..5eccbabf9547 100644 --- a/osu.Game/Graphics/OsuIcon.cs +++ b/osu.Game/Graphics/OsuIcon.cs @@ -100,6 +100,7 @@ public static class OsuIcon public static IconUsage EditorSelect => get(OsuIconMapping.EditorSelect); public static IconUsage EditorSound => get(OsuIconMapping.EditorSound); public static IconUsage EditorWhistle => get(OsuIconMapping.EditorWhistle); + public static IconUsage EditorClap => get(OsuIconMapping.EditorClap); public static IconUsage Tortoise => get(OsuIconMapping.Tortoise); public static IconUsage Hare => get(OsuIconMapping.Hare); @@ -426,6 +427,9 @@ private enum OsuIconMapping [Description(@"Editor/whistle")] EditorWhistle, + [Description(@"Editor/clap")] + EditorClap, + [Description(@"tortoise")] Tortoise, diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index 11ae0ef56d3f..eff74bd55663 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -230,7 +230,7 @@ public static Drawable GetIconForSample(string sampleName) switch (sampleName) { case HitSampleInfo.HIT_CLAP: - return new SpriteIcon { Icon = FontAwesome.Solid.Hands }; + return new SpriteIcon { Icon = OsuIcon.EditorClap }; case HitSampleInfo.HIT_WHISTLE: return new SpriteIcon { Icon = OsuIcon.EditorWhistle }; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b4c66223ed2e..384d5412a895 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From 365b88b4a9b72fbcdab1fc6c78490ab594ab3160 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2026 21:48:22 +0900 Subject: [PATCH 804/836] Ensure folder migration screen uses a blank background to avoid readability issues (#36948) https://github.com/ppy/osu/issues/36941 --- .../Settings/Sections/Maintenance/MigrationRunScreen.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs index c0363851efaa..ce33039d688f 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs @@ -15,12 +15,15 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Screens; +using osu.Game.Screens.Backgrounds; using osuTK; namespace osu.Game.Overlays.Settings.Sections.Maintenance { public partial class MigrationRunScreen : OsuScreen { + protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack(); + private readonly DirectoryInfo destination; [Resolved(canBeNull: true)] From 28fbb83cc660f737e29d2421c3724b8cf440e386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 12 Mar 2026 14:05:39 +0100 Subject: [PATCH 805/836] Fix Simplified Rhythm mod breaking diffcalc when applied to some maps (#36947) - closes https://github.com/ppy/osu/issues/36942 - fixes https://osu.ppy.sh/community/forums/topics/2187041?n=1 ## [Ensure Simplified Rhythm mod does not produce beatmaps with objects out of order](https://github.com/ppy/osu/commit/f4807b3a42dbf46ea0e669b0ba658feaef9baca5) This is a last ditch safety. This mod has more apparent issues (see below) but this is a first step of restoring sanity. Aside than the other fix described below I have not attempted to figure out further why this is happening because the conversion logic is in over my head. I just want hard breakage to not be possible. Why this extra sort is necessary can be investigated by @Hiviexd if he's so inclined. ## [Fix `GetClosestBeatDivisor()` not working correctly with negative time instants](https://github.com/ppy/osu/commit/88dc0d8a73c712a040635af262d7519fe6d772a0) This was causing the 1/3 -> 1/2 conversion in Simplified Rhythm to engage on some maps that weren't even mapped in waltz time. Those maps had the common trait of having a timing point with a negative start time. Notably this could feasibly affect other places as well, like mania beat snap colouring, or the Synesthesia osu! mod.
    testing Tested with Simplified Rhythm engaged, with 1/6 -> 1/4 and 1/3 -> 1/2 conversion enabled [BULANOVA - NE PLACH' [oni]](https://osu.ppy.sh/beatmapsets/1740291#taiko/3664995) (1/8 snap): - No mods: 5.18* - Simplified Rhythm @ master: 0.00* - Simplified Rhythm @ f4807b3a: 3.48* - Simplified Rhythm @ 933de7ab: 5.18* [BULANOVA - NE PLACH' [inner oni]](https://osu.ppy.sh/beatmapsets/1740291#taiko/3648625) (1/8 snap): - No mods: 5.84* - Simplified Rhythm @ master: 0.00* - Simplified Rhythm @ f4807b3a: 4.13* - Simplified Rhythm @ 933de7ab: 5.84* [BULANOVA - NE PLACH' [don't cry]](https://osu.ppy.sh/beatmapsets/1740291#taiko/3557681) (1/8 snap): - No mods: 6.91* - Simplified Rhythm @ master: 0.00* - Simplified Rhythm @ f4807b3a: 4.84* - Simplified Rhythm @ 933de7ab: 6.91* [Mili - Peach Pit and Cyanide [nik's Normal]](https://osu.ppy.sh/beatmapsets/2468654#osu/5405909) (1/6 snap): - No mods: 1.63* - Simplified Rhythm @ master: 0.00* - Simplified Rhythm @ f4807b3a: 1.10* - Simplified Rhythm @ 933de7ab: 1.10* [Mili - Peach Pit and Cyanide [Ix's Hard]](https://osu.ppy.sh/beatmapsets/2468654#osu/5405906) (1/3 snap): - No mods: 2.50* - Simplified Rhythm @ master: 0.00* - Simplified Rhythm @ f4807b3a: 1.71* - Simplified Rhythm @ 933de7ab: 1.71* [Mili - Peach Pit and Cyanide [nomi's Hidden Insane]](https://osu.ppy.sh/beatmapsets/2468654#osu/5405910) (1/3 snap): - No mods: 3.93* - Simplified Rhythm @ master: 0.00* - Simplified Rhythm @ f4807b3a: 2.59* - Simplified Rhythm @ 933de7ab: 2.59* [Within Temptation - The Unforgiving [Stairway To The Skies]](https://osu.ppy.sh/beatmapsets/29157#osu/172617) (1/3 snap in editor): - No mods: 1.53* - Simplified Rhythm @ master: 0.00* - Simplified Rhythm @ f4807b3a: 1.48* - Simplified Rhythm @ 933de7ab: 1.48* [Within Temptation - The Unforgiving [Iron]](https://osu.ppy.sh/beatmapsets/29157#osu/172612) (1/6 snap in editor): - No mods: 2.76* - Simplified Rhythm @ master: 0.00* - Simplified Rhythm @ f4807b3a: 1.75* - Simplified Rhythm @ 933de7ab: 1.75* [Within Temptation - The Unforgiving [Marathon]](https://osu.ppy.sh/beatmapsets/29157#osu/156352) (1/4 snap in editor, but has 1/3 / 1/6 sections for sure): - No mods: 2.96* - Simplified Rhythm @ master: 0.00* - Simplified Rhythm @ f4807b3a: 2.75* - Simplified Rhythm @ 933de7ab: 2.75* [Halozy - Genryuu Kaiko [Higan Torrent]](https://osu.ppy.sh/beatmapsets/180138#osu/433005) (1/4 snap): - No mods: 5.37* - Simplified Rhythm @ master: 0.00* - Simplified Rhythm @ f4807b3a: 3.95* - Simplified Rhythm @ 933de7ab: 5.37*
    --- .../Mods/TaikoModSimplifiedRhythm.cs | 2 ++ .../NonVisual/ClosestBeatDivisorTest.cs | 12 ++++++++++++ .../Beatmaps/ControlPoints/ControlPointInfo.cs | 16 +++++++++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSimplifiedRhythm.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSimplifiedRhythm.cs index 2132121cd248..dfaae8e99e7d 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSimplifiedRhythm.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSimplifiedRhythm.cs @@ -122,6 +122,8 @@ void processPattern(int patternEndIndex) } } } + + taikoBeatmap.HitObjects.Sort((a, b) => a.StartTime.CompareTo(b.StartTime)); } private int getSnapBetweenNotes(ControlPointInfo controlPointInfo, Hit currentNote, Hit nextNote) diff --git a/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs b/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs index 8a53759323f2..a563bcd865e9 100644 --- a/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs +++ b/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs @@ -66,6 +66,18 @@ public void TestApproximateDivisors() assertClosestDivisors(divisors, closestDivisors, cpi); } + [Test] + public void TestNegativeTimingPointOffset() + { + var cpi = new ControlPointInfo(); + cpi.Add(-300000, new TimingControlPoint { BeatLength = 1000 }); + + double[] divisors = { 3.03d, 0.97d, 14, 13, 7.94d, 6.08d, 3.93d, 2.96d, 2.02d, 64 }; + double[] closestDivisors = { 3, 1, 16, 12, 8, 6, 4, 3, 2, 1 }; + + assertClosestDivisors(divisors, closestDivisors, cpi); + } + private static void assertClosestDivisors(IReadOnlyList divisors, IReadOnlyList closestDivisors, ControlPointInfo cpi, double step = 1) { List hitobjects = new List(); diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 8666f0112917..30a6d9516e01 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -169,7 +169,7 @@ public void RemoveGroup(ControlPointGroup group) public double GetClosestSnappedTime(double time, int beatDivisor, double? referenceTime = null) { var timingPoint = TimingPointAt(referenceTime ?? time); - double snappedTime = getClosestSnappedTime(timingPoint, time, beatDivisor); + double snappedTime = getClosestPositiveSnappedTime(timingPoint, time, beatDivisor); if (referenceTime.HasValue) return snappedTime; @@ -197,9 +197,19 @@ public int GetClosestBeatDivisor(double time, double? referenceTime = null) int closestDivisor = 0; double closestTime = double.MaxValue; + // `getClosestSnappedTime()` only returns positive time values. + // due to that, if `time` is allowed to be negative, the loop lower below could return bogus results + // as the "snapped time" will not necessarily be "closest" at that point. + // compensate for this by moving `time` by enough beat lengths to go back to the positives. + if (time < 0) + { + int offsetBeats = (int)Math.Ceiling(-time / timingPoint.BeatLength); + time += offsetBeats * timingPoint.BeatLength; + } + foreach (int divisor in BindableBeatDivisor.PREDEFINED_DIVISORS) { - double distanceFromSnap = Math.Abs(time - getClosestSnappedTime(timingPoint, time, divisor)); + double distanceFromSnap = Math.Abs(time - getClosestPositiveSnappedTime(timingPoint, time, divisor)); if (Precision.DefinitelyBigger(closestTime, distanceFromSnap)) { @@ -211,7 +221,7 @@ public int GetClosestBeatDivisor(double time, double? referenceTime = null) return closestDivisor; } - private static double getClosestSnappedTime(TimingControlPoint timingPoint, double time, int beatDivisor) + private static double getClosestPositiveSnappedTime(TimingControlPoint timingPoint, double time, int beatDivisor) { double beatLength = timingPoint.BeatLength / beatDivisor; double beats = (Math.Max(time, 0) - timingPoint.Time) / beatLength; From 1e01001a1f42961aecaf700da4cce891e684c325 Mon Sep 17 00:00:00 2001 From: "Rian (Reza Mouna Hendrian)" <52914632+Rian8337@users.noreply.github.com> Date: Fri, 13 Mar 2026 06:26:42 +0700 Subject: [PATCH 806/836] Use current object's `Preempt` when retrieving past visible objects in osu! reading difficulty (#36944) In `retrievePastVisibleObjects`, the wrong object's `Preempt` is used to determine the time where the currently assessed object becomes visible. This PR fixes that issue. Additionally, the visibility condition in `retrieveCurrentVisibleObjectDensity` is rearranged to read similarly to the one in `retrievePastVisibleObjects`. This does not change current values as none of the mods that can currently award pp modify an object's `TimePreempt` individually. The only affected mod is Freeze Frame, which gains buffs across the board as more objects are calculated to be visible now. --- .../Difficulty/Evaluators/ReadingEvaluator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs index 3363e2fbe067..926abca97125 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs @@ -168,7 +168,7 @@ private static IEnumerable retrievePastVisibleObjects(Os if (hitObject.IsNull() || current.StartTime - hitObject.StartTime > reading_window_size || - hitObject.StartTime + hitObject.Preempt < current.StartTime) // Current object not visible at the time object needs to be clicked + hitObject.StartTime < current.StartTime - current.Preempt) // Current object not visible at the time object needs to be clicked break; yield return hitObject; @@ -185,7 +185,7 @@ private static double retrieveCurrentVisibleObjectDensity(OsuDifficultyHitObject while (hitObject != null) { if (hitObject.StartTime - current.StartTime > reading_window_size || - current.StartTime + hitObject.Preempt < hitObject.StartTime) // Object not visible at the time current object needs to be clicked. + current.StartTime < hitObject.StartTime - hitObject.Preempt) // Object not visible at the time current object needs to be clicked. break; double timeBetweenCurrAndLoopObj = hitObject.StartTime - current.StartTime; From 2380fcd36dc89528dad08deeb7b37d9d37973bee Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 13 Mar 2026 08:54:19 +0300 Subject: [PATCH 807/836] Reuse existing triangles in `Triangles` background (#36951) As [per comment](https://github.com/ppy/osu/pull/36943#issuecomment-4045361755). Unfortunately I'm not able to reproduce such a big impact of triangles using linked pr (or at all really). In my case usage was low in the first place and went from 0.9% to 0.6% with this pr, so outside benchmarking would be great Improvement list: * No more sorted list. Basic list is being used which is sorted once after all the triangles added. * Out-of-bounds triangles are reused rather than removed and re-added. * On `Reset` if `AimCount` stays the same, all triangles are reused instead of being cleared and re-added. --- osu.Game/Graphics/Backgrounds/Triangles.cs | 64 +++++++++++++--------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index d22aa197bb60..f4646e5af609 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -14,8 +14,8 @@ using osu.Framework.Graphics.Primitives; using osu.Framework.Allocation; using System.Collections.Generic; +using Microsoft.Toolkit.HighPerformance; using osu.Framework.Graphics.Rendering; -using osu.Framework.Lists; using osu.Framework.Bindables; namespace osu.Game.Graphics.Backgrounds @@ -94,7 +94,7 @@ public float TriangleScale ///
    public float Velocity = 1; - private readonly SortedList parts = new SortedList(Comparer.Default); + private readonly List parts = new List(); private Random stableRandom; private IShader shader; @@ -127,9 +127,6 @@ protected override void Update() { base.Update(); - if (CreateNewTriangles) - addTriangles(false); - float adjustedAlpha = HideAlphaDiscrepancies // Cubically scale alpha to make it drop off more sharply. ? MathF.Pow(DrawColourInfo.Colour.AverageColour.Linear.A, 3) @@ -145,19 +142,31 @@ protected override void Update() // dividing by triangleScale. float movedDistance = -elapsedSeconds * Velocity * base_velocity / (DrawHeight * TriangleScale); - for (int i = 0; i < parts.Count; i++) + for (int i = parts.Count - 1; i >= 0; i--) { - TriangleParticle newParticle = parts[i]; + TriangleParticle particle = parts[i]; // Scale moved distance by the size of the triangle. Smaller triangles should move more slowly. - newParticle.Position.Y += Math.Max(0.5f, parts[i].Scale) * movedDistance; - newParticle.Colour.A = adjustedAlpha; + float newY = particle.Position.Y + Math.Max(0.5f, particle.Scale) * movedDistance; + float bottomY = newY + triangle_size * particle.Scale * equilateral_triangle_ratio / DrawHeight; - parts[i] = newParticle; + if (bottomY < 0) + { + if (!CreateNewTriangles) + { + parts.RemoveAt(i); + continue; + } + + particle.Position = getRandomPosition(false, particle.Scale); + } + else + { + particle.Position.Y = newY; + } - float bottomPos = parts[i].Position.Y + triangle_size * parts[i].Scale * equilateral_triangle_ratio / DrawHeight; - if (bottomPos < 0) - parts.RemoveAt(i); + particle.Colour.A = adjustedAlpha; + parts[i] = particle; } Invalidate(Invalidation.DrawNode); @@ -172,30 +181,33 @@ public void Reset(int? seed = null) if (seed != null) stableRandom = new Random(seed.Value); - parts.Clear(); - addTriangles(true); - } - - protected int AimCount { get; private set; } - - private void addTriangles(bool randomY) - { // Limited by the maximum size of QuadVertexBuffer for safety. const int max_triangles = ushort.MaxValue / (IRenderer.VERTICES_PER_QUAD + 2); AimCount = (int)Math.Min(max_triangles, DrawWidth * DrawHeight * 0.002f / (TriangleScale * TriangleScale) * SpawnRatio); - int currentCount = parts.Count; + if (parts.Count == AimCount) + { + var span = parts.AsSpan(); - if (AimCount - currentCount == 0) - return; + for (int i = 0; i < span.Length; i++) + span[i].Position = getRandomPosition(true, span[i].Scale); + } + else + { + parts.Clear(); + + for (int i = 0; i < AimCount; i++) + parts.Add(createTriangle(true)); - for (int i = 0; i < AimCount - currentCount; i++) - parts.Add(createTriangle(randomY)); + parts.Sort(Comparer.Default); + } Invalidate(Invalidation.DrawNode); } + protected int AimCount { get; private set; } + private TriangleParticle createTriangle(bool randomY) { TriangleParticle particle = CreateTriangle(); From fd66d7c4e4bb7a15dce6e5c8e2e2b485828fe6b5 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Sat, 14 Mar 2026 16:47:58 +0300 Subject: [PATCH 808/836] Localise some strings on `SecondFactorAuthForm` (#36961) --- osu.Game/Localisation/LoginPanelStrings.cs | 10 ++++++++++ osu.Game/Overlays/Login/SecondFactorAuthForm.cs | 9 +++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/osu.Game/Localisation/LoginPanelStrings.cs b/osu.Game/Localisation/LoginPanelStrings.cs index 925c2b91469f..243f0659065e 100644 --- a/osu.Game/Localisation/LoginPanelStrings.cs +++ b/osu.Game/Localisation/LoginPanelStrings.cs @@ -49,6 +49,16 @@ public static class LoginPanelStrings ///
    public static LocalisableString Register => new TranslatableString(getKey(@"register"), @"Register"); + /// + /// "An email has been sent to you with a verification code. Enter the code." + /// + public static LocalisableString CodeSent => new TranslatableString(getKey(@"code_sent"), @"An email has been sent to you with a verification code. Enter the code."); + + /// + /// "Enter code" + /// + public static LocalisableString EnterCode => new TranslatableString(getKey(@"enter_code"), @"Enter code"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/Login/SecondFactorAuthForm.cs b/osu.Game/Overlays/Login/SecondFactorAuthForm.cs index 2cdc4bf6a68f..38025de1d9bb 100644 --- a/osu.Game/Overlays/Login/SecondFactorAuthForm.cs +++ b/osu.Game/Overlays/Login/SecondFactorAuthForm.cs @@ -11,6 +11,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -104,12 +105,12 @@ private void showEmailVerification() { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Text = "An email has been sent to you with a verification code. Enter the code.", + Text = LoginPanelStrings.CodeSent, }, codeTextBox = new OsuTextBox { InputProperties = new TextInputProperties(TextInputType.Code), - PlaceholderText = "Enter code", + PlaceholderText = LoginPanelStrings.EnterCode, RelativeSizeAxes = Axes.X, TabbableContentContainer = this, }, @@ -169,12 +170,12 @@ private void showTotpVerification() { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Text = "Please enter the code from your authenticator app.", + Text = UserVerificationStrings.BoxTotpHeading, }, codeTextBox = new OsuNumberBox { InputProperties = new TextInputProperties(TextInputType.NumericalPassword), - PlaceholderText = "Enter code", + PlaceholderText = LoginPanelStrings.EnterCode, RelativeSizeAxes = Axes.X, TabbableContentContainer = this, }, From ed905b761dbba26156dbd089286b5e77cba389dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 14 Mar 2026 15:05:59 +0100 Subject: [PATCH 809/836] Add models for new tournament-related multiplayer operations (#36953) Continuation of https://github.com/ppy/osu-server-spectator/issues/406 Operations in question being: - (un)locking rooms / `!mp (un)lock` (prevents players from changing team, will also include slots when slots are implemented) - rolling / `!roll` (frequently used in coin toss type situations, will receive nice animation to go with it) --- .../Online/Multiplayer/MatchServerEvent.cs | 1 + .../TeamVersus/TeamVersusRoomState.cs | 3 ++ .../Online/Multiplayer/MatchUserRequest.cs | 2 ++ osu.Game/Online/Multiplayer/RollEvent.cs | 36 +++++++++++++++++++ osu.Game/Online/Multiplayer/RollRequest.cs | 24 +++++++++++++ .../Online/Multiplayer/SetLockStateRequest.cs | 24 +++++++++++++ osu.Game/Online/SignalRWorkaroundTypes.cs | 3 ++ 7 files changed, 93 insertions(+) create mode 100644 osu.Game/Online/Multiplayer/RollEvent.cs create mode 100644 osu.Game/Online/Multiplayer/RollRequest.cs create mode 100644 osu.Game/Online/Multiplayer/SetLockStateRequest.cs diff --git a/osu.Game/Online/Multiplayer/MatchServerEvent.cs b/osu.Game/Online/Multiplayer/MatchServerEvent.cs index 402de392a84c..723452d3f63b 100644 --- a/osu.Game/Online/Multiplayer/MatchServerEvent.cs +++ b/osu.Game/Online/Multiplayer/MatchServerEvent.cs @@ -19,6 +19,7 @@ namespace osu.Game.Online.Multiplayer [Union(1, typeof(CountdownStoppedEvent))] [Union(2, typeof(MatchmakingAvatarActionEvent))] [Union(3, typeof(RankedPlayCardHandReplayEvent))] + [Union(4, typeof(RollEvent))] public abstract class MatchServerEvent { } diff --git a/osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/TeamVersusRoomState.cs b/osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/TeamVersusRoomState.cs index 375842964395..d5e30bb2e08b 100644 --- a/osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/TeamVersusRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/TeamVersusRoomState.cs @@ -12,6 +12,9 @@ public class TeamVersusRoomState : MatchRoomState [Key(0)] public List Teams { get; set; } = new List(); + [Key(1)] + public bool Locked { get; set; } + public static TeamVersusRoomState CreateDefault() => new TeamVersusRoomState { diff --git a/osu.Game/Online/Multiplayer/MatchUserRequest.cs b/osu.Game/Online/Multiplayer/MatchUserRequest.cs index fdcbf756822f..bacc1a7632b4 100644 --- a/osu.Game/Online/Multiplayer/MatchUserRequest.cs +++ b/osu.Game/Online/Multiplayer/MatchUserRequest.cs @@ -21,6 +21,8 @@ namespace osu.Game.Online.Multiplayer [Union(2, typeof(StopCountdownRequest))] [Union(3, typeof(MatchmakingAvatarActionRequest))] [Union(4, typeof(RankedPlayCardHandReplayRequest))] + [Union(5, typeof(SetLockStateRequest))] + [Union(6, typeof(RollRequest))] public abstract class MatchUserRequest { } diff --git a/osu.Game/Online/Multiplayer/RollEvent.cs b/osu.Game/Online/Multiplayer/RollEvent.cs new file mode 100644 index 000000000000..8588bc6adf1a --- /dev/null +++ b/osu.Game/Online/Multiplayer/RollEvent.cs @@ -0,0 +1,36 @@ +// 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 MessagePack; + +namespace osu.Game.Online.Multiplayer +{ + /// + /// Communicates the result of a . + /// + [Serializable] + [MessagePackObject] + public class RollEvent : MatchServerEvent + { + /// + /// The ID of the user who initiated the roll. + /// + [Key(0)] + public int UserID { get; set; } + + /// + /// Determines the maximum possible result of the roll. + /// Bigger than 1. + /// + [Key(1)] + public uint Max { get; set; } + + /// + /// The actual result of the roll. + /// In the range [1, ], inclusive both ends. + /// + [Key(2)] + public uint Result { get; set; } + } +} diff --git a/osu.Game/Online/Multiplayer/RollRequest.cs b/osu.Game/Online/Multiplayer/RollRequest.cs new file mode 100644 index 000000000000..3f6be23e1e87 --- /dev/null +++ b/osu.Game/Online/Multiplayer/RollRequest.cs @@ -0,0 +1,24 @@ +// 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 MessagePack; + +namespace osu.Game.Online.Multiplayer +{ + /// + /// Requests a random roll of a number from 1 to inclusive. + /// + [Serializable] + [MessagePackObject] + public class RollRequest : MatchUserRequest + { + /// + /// Determines the maximum possible result of the roll. + /// Must be bigger than 1. + /// Defaults to 100 if not provided. + /// + [Key(0)] + public uint? Max { get; set; } + } +} diff --git a/osu.Game/Online/Multiplayer/SetLockStateRequest.cs b/osu.Game/Online/Multiplayer/SetLockStateRequest.cs new file mode 100644 index 000000000000..8f1451fdab7a --- /dev/null +++ b/osu.Game/Online/Multiplayer/SetLockStateRequest.cs @@ -0,0 +1,24 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using MessagePack; + +namespace osu.Game.Online.Multiplayer +{ + [MessagePackObject] + public class SetLockStateRequest : MatchUserRequest + { + /// + /// + /// If , s will not be able to change teams by themselves in the room, + /// only s will be able to change teams for the s. + /// + /// + /// If , any user can change their team in the room. + /// + /// + // TODO: mention slots as well when slots are reimplemented + [Key(0)] + public bool Locked { get; set; } + } +} diff --git a/osu.Game/Online/SignalRWorkaroundTypes.cs b/osu.Game/Online/SignalRWorkaroundTypes.cs index 70c6fcf2b780..06e8451205b2 100644 --- a/osu.Game/Online/SignalRWorkaroundTypes.cs +++ b/osu.Game/Online/SignalRWorkaroundTypes.cs @@ -27,8 +27,11 @@ internal static class SignalRWorkaroundTypes (typeof(ChangeTeamRequest), typeof(MatchUserRequest)), (typeof(StartMatchCountdownRequest), typeof(MatchUserRequest)), (typeof(StopCountdownRequest), typeof(MatchUserRequest)), + (typeof(SetLockStateRequest), typeof(MatchUserRequest)), + (typeof(RollRequest), typeof(MatchUserRequest)), (typeof(CountdownStartedEvent), typeof(MatchServerEvent)), (typeof(CountdownStoppedEvent), typeof(MatchServerEvent)), + (typeof(RollEvent), typeof(MatchServerEvent)), (typeof(TeamVersusRoomState), typeof(MatchRoomState)), (typeof(TeamVersusUserState), typeof(MatchUserState)), (typeof(MatchStartCountdown), typeof(MultiplayerCountdown)), From 39912e044a05480d7587b6c8d9dfd78f3f99dd0f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 14 Mar 2026 23:55:12 +0900 Subject: [PATCH 810/836] Fix weird variable naming --- osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs | 2 +- osu.Game/Overlays/Dashboard/Friends/FriendsList.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs index 408823301324..66e90e51eba1 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs @@ -178,7 +178,7 @@ private void reloadList() FriendsList newList = new FriendsList(userListToolbar.DisplayStyle.Value, apiFriends.Select(f => f.TargetUser!).ToArray()) { - OnlineStream = { BindTarget = streamControl.Current }, + StatusFilter = { BindTarget = streamControl.Current }, SortCriteria = { BindTarget = userListToolbar.SortCriteria }, SearchText = { BindTarget = searchTextBox.Current } }; diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendsList.cs b/osu.Game/Overlays/Dashboard/Friends/FriendsList.cs index c7689dff8f23..8d95222ee2d7 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendsList.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendsList.cs @@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Dashboard.Friends { public partial class FriendsList : CompositeDrawable { - public readonly IBindable OnlineStream = new Bindable(); + public readonly IBindable StatusFilter = new Bindable(); public readonly IBindable SortCriteria = new Bindable(); public readonly IBindable SearchText = new Bindable(); @@ -61,7 +61,7 @@ protected override void LoadComplete() friendPresences.BindCollectionChanged(onFriendPresencesChanged); SearchText.BindValueChanged(onSearchTextChanged, true); - OnlineStream.BindValueChanged(onFriendsStreamChanged, true); + StatusFilter.BindValueChanged(onStatusFilterChanged, true); } private void onFriendPresencesChanged(object? sender, NotifyDictionaryChangedEventArgs e) @@ -80,7 +80,7 @@ private void onSearchTextChanged(ValueChangedEvent search) searchContainer.SearchTerm = search.NewValue; } - private void onFriendsStreamChanged(ValueChangedEvent stream) + private void onStatusFilterChanged(ValueChangedEvent status) { updatePanelVisibilities(); } @@ -89,7 +89,7 @@ private void updatePanelVisibilities() { foreach (var panel in searchContainer) { - switch (OnlineStream.Value) + switch (StatusFilter.Value) { case OnlineStatus.All: panel.CanBeShown.Value = true; From 73644d87bc747be4cfc00fe5f2f1a44910ba3e3d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Mar 2026 14:15:29 +0900 Subject: [PATCH 811/836] Attempt to fix mod output including build output --- .github/workflows/update-web-mod-definitions.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update-web-mod-definitions.yml b/.github/workflows/update-web-mod-definitions.yml index b19f03ad7dd3..160872a9a114 100644 --- a/.github/workflows/update-web-mod-definitions.yml +++ b/.github/workflows/update-web-mod-definitions.yml @@ -38,8 +38,12 @@ jobs: run: ./UseLocalOsu.sh working-directory: ./osu-tools + - name: Build tools + run: dotnet build PerformanceCalculator --nologo --verbosity quiet + working-directory: ./osu-tools + - name: Regenerate mod definitions - run: dotnet run --project PerformanceCalculator -- mods > ../osu-web/database/mods.json + run: dotnet run --project PerformanceCalculator --no-build -- mods > ../osu-web/database/mods.json working-directory: ./osu-tools - name: Create pull request with changes From 5b8067a4206b4400833a088a8837c12981ff8f9c Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Mon, 16 Mar 2026 17:35:45 +0500 Subject: [PATCH 812/836] Restore precision buff in Agility (#36968) Seems like it got lost somewhere in the #36902. Great upside is that flow cs bonus can be reduced as it's supposed to be now since the bonus is made with d/t^1.65 in mind and flow is d/t. Values-wise it's a small precision buff --- .../Difficulty/Evaluators/Aim/AgilityEvaluator.cs | 2 ++ .../Difficulty/Evaluators/Aim/FlowAimEvaluator.cs | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs index 5208520bb471..10ec462198d7 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs @@ -31,6 +31,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) double strain = distanceScaled * 1000 / osuCurrObj.AdjustedDeltaTime; + strain *= osuCurrObj.SmallCircleBonus; + strain *= highBpmBonus(osuCurrObj.AdjustedDeltaTime); return strain * DifficultyCalculationUtils.Smootherstep(distance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs index 924e1c346efe..ccc4d219d5be 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs @@ -42,8 +42,9 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double flowDifficulty = currVelocity; - // Apply high circle size bonus to the base velocity - flowDifficulty *= osuCurrObj.SmallCircleBonus; + // Apply high circle size bonus to the base velocity. + // We use reduced CS bonus here because the bonus was made for an evaluator with a different d/t scaling + flowDifficulty *= Math.Pow(osuCurrObj.SmallCircleBonus, 0.75); // Rhythm changes are harder to flow flowDifficulty *= 1 + Math.Min(0.25, From a99626130490ed60bb4bf1677bdf67d9374d5811 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Mar 2026 03:58:02 +0900 Subject: [PATCH 813/836] Update lots of packages (#36996) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's been a while. Notes: - `SharpCompress` usages changed a bit. Manually adjusted these, mostly just renames or adjusted parameters. - nUnit 3 -> 4 migrated using https://gist.github.com/peppy/07994386d793a117350cb5f24b156585. there's a mode in this script to update to the newer `Assert.That` syntax but it requires fixes and couldn't really be bothered. - DeepEqual nuked as the only usage was on a disabled test. The reason it's disabled has been merged upstream, but it's failing for other (realm) reasons which I don't think is worthwhile to investigate for now. - This bumps Moq. I think the author is back in a sensible headspace and the new version has the stupid shit removed, so probably okay? Nice to be on a level playing field with packages for once in a long time. - Automapper is silly, but we've discussed this elsewhere. - `TestRealmKeyBindingStore` failures are a wildcard, but fixed by using a more standardised testing method. Dunno why, don't care. --------- Co-authored-by: Bartłomiej Dach --- ...u.Game.Rulesets.EmptyFreeform.Tests.csproj | 4 +- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 4 +- ....Game.Rulesets.EmptyScrolling.Tests.csproj | 4 +- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 4 +- osu.Desktop/osu.Desktop.csproj | 4 +- .../osu.Game.Benchmarks.csproj | 6 +- .../CatchSkinColourDecodingTest.cs | 7 +- .../osu.Game.Rulesets.Catch.Tests.csproj | 6 +- .../Editor/TestSceneObjectPlacement.cs | 2 +- .../ManiaFilterCriteriaTest.cs | 85 ++-- .../ManiaSpecialColumnTest.cs | 3 +- .../Mods/TestSceneManiaModHoldOff.cs | 3 +- .../TestSceneAutoGeneration.cs | 95 ++-- .../osu.Game.Rulesets.Mania.Tests.csproj | 6 +- .../Editor/TestSliderScaling.cs | 5 +- osu.Game.Rulesets.Osu.Tests/StackingTest.cs | 5 +- .../osu.Game.Rulesets.Osu.Tests.csproj | 8 +- .../Editor/TestSceneTaikoEditorSaving.cs | 2 +- .../osu.Game.Rulesets.Taiko.Tests.csproj | 6 +- .../Formats/LegacyBeatmapDecoderTest.cs | 349 +++++++-------- .../Formats/LegacyBeatmapEncoderTest.cs | 5 +- .../Formats/LegacyScoreDecoderTest.cs | 21 +- .../Formats/LegacyStoryboardDecoderTest.cs | 153 +++---- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 135 +++--- .../Beatmaps/Formats/ParsingTest.cs | 7 +- .../Beatmaps/IO/BeatmapImportHelper.cs | 16 +- .../Beatmaps/IO/LineBufferedReaderTest.cs | 67 +-- .../Beatmaps/IO/OszArchiveReaderTest.cs | 27 +- .../TestSceneBeatmapDifficultyCache.cs | 3 +- osu.Game.Tests/Beatmaps/WorkingBeatmapTest.cs | 7 +- osu.Game.Tests/Chat/MessageFormatterTests.cs | 417 +++++++++--------- .../Database/BeatmapImporterTests.cs | 225 +++++----- .../Database/BeatmapImporterUpdateTests.cs | 4 +- osu.Game.Tests/Database/FileStoreTests.cs | 27 +- osu.Game.Tests/Database/GeneralUsageTests.cs | 3 +- .../Database/LegacyBeatmapImporterTest.cs | 5 +- osu.Game.Tests/Database/RealmLiveTests.cs | 41 +- osu.Game.Tests/Database/RulesetStoreTests.cs | 19 +- .../Database/TestRealmKeyBindingStore.cs | 123 +++--- .../Editing/Checks/CheckAudioInVideoTest.cs | 5 +- .../Checks/CheckDelayedHitsoundsTest.cs | 5 +- .../Checks/CheckHitsoundsFormatTest.cs | 6 +- .../Editing/Checks/CheckSongFormatTest.cs | 2 +- .../Checks/CheckTooShortAudioFilesTest.cs | 11 +- .../Checks/CheckVideoResolutionTest.cs | 2 +- .../Editing/Checks/CheckZeroByteFilesTest.cs | 5 +- osu.Game.Tests/ImportTest.cs | 3 +- .../BeatmapMetadataRomanisationTest.cs | 7 +- osu.Game.Tests/Mods/ModUtilsTest.cs | 41 +- .../NonVisual/BarLineGeneratorTest.cs | 7 +- .../NonVisual/BeatmapSetInfoEqualityTest.cs | 37 +- .../NonVisual/ClosestBeatDivisorTest.cs | 3 +- ...DifficultyAdjustmentModCombinationsTest.cs | 3 +- .../NonVisual/Filtering/FilterMatchingTest.cs | 43 +- .../Filtering/FilterQueryParserTest.cs | 219 ++++----- .../NonVisual/FirstAvailableHitWindowsTest.cs | 9 +- osu.Game.Tests/NonVisual/FormatUtilsTest.cs | 5 +- .../NonVisual/FramedReplayInputHandlerTest.cs | 13 +- .../NonVisual/LimitedCapacityQueueTest.cs | 33 +- osu.Game.Tests/NonVisual/PeriodTrackerTest.cs | 19 +- .../NonVisual/Ranking/UnstableRateTest.cs | 19 +- osu.Game.Tests/NonVisual/ReverseQueueTest.cs | 41 +- .../NonVisual/SessionStaticsTest.cs | 21 +- .../Skinning/LegacySkinTextureFallbackTest.cs | 21 +- .../NonVisual/TimeDisplayExtensionTest.cs | 5 +- .../Online/Chat/MessageNotifierTest.cs | 27 +- .../Matchmaking/MatchmakingRoomStateTest.cs | 89 ++-- .../Online/TestAPIModJsonSerialization.cs | 5 +- ...TestMultiplayerMessagePackSerialization.cs | 7 +- osu.Game.Tests/Resources/TestResources.cs | 6 +- .../Rulesets/Scoring/ScoreProcessorTest.cs | 13 +- osu.Game.Tests/Scores/IO/ImportScoreTest.cs | 121 ++--- .../ScrollAlgorithms/ConstantScrollTest.cs | 29 +- .../ScrollAlgorithms/OverlappingScrollTest.cs | 35 +- .../ScrollAlgorithms/SequentialScrollTest.cs | 25 +- osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 55 +-- osu.Game.Tests/Skins/LegacySkinDecoderTest.cs | 21 +- .../Skins/TestSceneSkinResources.cs | 2 +- osu.Game.Tests/Utils/NamingUtilsTest.cs | 45 +- .../Editing/TestSceneComposerSelection.cs | 19 +- .../Editing/TestSceneEditorBeatmapCreation.cs | 2 +- .../Visual/Gameplay/TestSceneSpectator.cs | 2 +- .../Visual/Online/TestSceneDrawableChannel.cs | 3 +- osu.Game.Tests/osu.Game.Tests.csproj | 11 +- .../NonVisual/IPCLocationTest.cs | 5 +- .../NonVisual/TournamentHostTest.cs | 3 +- .../osu.Game.Tournament.Tests.csproj | 6 +- .../LocalCachedBeatmapMetadataSource.cs | 2 +- osu.Game/Database/LegacyArchiveExporter.cs | 2 +- osu.Game/Database/RealmObjectExtensions.cs | 4 +- osu.Game/IO/Archives/ZipArchiveReader.cs | 13 +- .../Sections/General/QuickActionSettings.cs | 6 +- .../Edit/Checks/Components/IssueTemplate.cs | 3 +- osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs | 2 +- osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs | 2 +- .../Edit/LegacyEditorBeatmapPatcher.cs | 15 +- .../Tests/Beatmaps/BeatmapConversionTest.cs | 3 +- .../Tests/Beatmaps/LegacyModConversionTest.cs | 8 +- osu.Game/Utils/ZipUtils.cs | 9 +- osu.Game/osu.Game.csproj | 32 +- 100 files changed, 1596 insertions(+), 1534 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj index 86f73a37d4d2..4fa8b9409900 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 51c0233942c7..bb95c675fcf8 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj index ed4e8631eafa..fc170b2c24e3 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 51c0233942c7..bb95c675fcf8 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index b0c5c953d43c..bd0f4448fc8e 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -24,8 +24,8 @@ - - + + diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj index 8a353eb2f502..104ee50fe105 100644 --- a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj +++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/osu.Game.Rulesets.Catch.Tests/CatchSkinColourDecodingTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchSkinColourDecodingTest.cs index 74b02bab9b55..3a0dea3e8ce5 100644 --- a/osu.Game.Rulesets.Catch.Tests/CatchSkinColourDecodingTest.cs +++ b/osu.Game.Rulesets.Catch.Tests/CatchSkinColourDecodingTest.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.IO.Stores; using osu.Game.Rulesets.Catch.Skinning; using osu.Game.Rulesets.Catch.Skinning.Legacy; @@ -21,9 +22,9 @@ public void TestCatchSkinColourDecoding() var skinSource = new SkinProvidingContainer(rawSkin); var skin = new CatchLegacySkinTransformer(skinSource); - Assert.AreEqual(new Color4(232, 185, 35, 255), skin.GetConfig(CatchSkinColour.HyperDash)?.Value); - Assert.AreEqual(new Color4(232, 74, 35, 255), skin.GetConfig(CatchSkinColour.HyperDashAfterImage)?.Value); - Assert.AreEqual(new Color4(0, 255, 255, 255), skin.GetConfig(CatchSkinColour.HyperDashFruit)?.Value); + ClassicAssert.AreEqual(new Color4(232, 185, 35, 255), skin.GetConfig(CatchSkinColour.HyperDash)?.Value); + ClassicAssert.AreEqual(new Color4(232, 74, 35, 255), skin.GetConfig(CatchSkinColour.HyperDashAfterImage)?.Value); + ClassicAssert.AreEqual(new Color4(0, 255, 255, 255), skin.GetConfig(CatchSkinColour.HyperDashFruit)?.Value); } private class TestLegacySkin : LegacySkin diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index fc1b13f3ad18..132bc4bed1f3 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -1,9 +1,9 @@  - - - + + + WinExe diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs index 13a116b20918..94b832e43ad9 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs @@ -42,7 +42,7 @@ public void TestSeekOnNotePlacement() AddStep("change seek setting to true", () => config.SetValue(OsuSetting.EditorAutoSeekOnPlacement, true)); placeObject(); AddUntilStep("wait for seek to complete", () => !EditorClock.IsSeeking); - AddAssert("seeked forward to object", () => EditorClock.CurrentTime, () => Is.GreaterThan(initialTime)); + AddAssert("seeked forward to object", () => EditorClock.CurrentTime, () => Is.GreaterThan(initialTime!)); } [Test] diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaFilterCriteriaTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaFilterCriteriaTest.cs index ad3cf4e05f22..49fb8ecb2ce6 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaFilterCriteriaTest.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaFilterCriteriaTest.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Mods; using osu.Game.Screens.Select; @@ -18,19 +19,19 @@ public void TestKeysEqualSingleValue() var criteria = new ManiaFilterCriteria(); criteria.TryParseCustomKeywordCriteria("keys", Operator.Equal, "1"); - Assert.True(criteria.Matches( + ClassicAssert.True(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 1 }), new FilterCriteria())); - Assert.False(criteria.Matches( + ClassicAssert.False(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 2 }), new FilterCriteria())); - Assert.False(criteria.Matches( + ClassicAssert.False(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 3 }), new FilterCriteria())); - Assert.True(criteria.Matches( + ClassicAssert.True(criteria.Matches( new BeatmapInfo(new RulesetInfo { OnlineID = 0 }, new BeatmapDifficulty { CircleSize = 4 }), new FilterCriteria { @@ -44,19 +45,19 @@ public void TestKeysEqualMultipleValues() var criteria = new ManiaFilterCriteria(); criteria.TryParseCustomKeywordCriteria("keys", Operator.Equal, "1,3,5,7"); - Assert.True(criteria.Matches( + ClassicAssert.True(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 1 }), new FilterCriteria())); - Assert.False(criteria.Matches( + ClassicAssert.False(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 2 }), new FilterCriteria())); - Assert.True(criteria.Matches( + ClassicAssert.True(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 3 }), new FilterCriteria())); - Assert.True(criteria.Matches( + ClassicAssert.True(criteria.Matches( new BeatmapInfo(new RulesetInfo { OnlineID = 0 }, new BeatmapDifficulty { CircleSize = 4 }), new FilterCriteria { @@ -70,19 +71,19 @@ public void TestKeysNotEqualSingleValue() var criteria = new ManiaFilterCriteria(); criteria.TryParseCustomKeywordCriteria("keys", Operator.NotEqual, "1"); - Assert.False(criteria.Matches( + ClassicAssert.False(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 1 }), new FilterCriteria())); - Assert.True(criteria.Matches( + ClassicAssert.True(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 2 }), new FilterCriteria())); - Assert.True(criteria.Matches( + ClassicAssert.True(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 3 }), new FilterCriteria())); - Assert.False(criteria.Matches( + ClassicAssert.False(criteria.Matches( new BeatmapInfo(new RulesetInfo { OnlineID = 0 }, new BeatmapDifficulty { CircleSize = 4 }), new FilterCriteria { @@ -96,19 +97,19 @@ public void TestKeysNotEqualMultipleValues() var criteria = new ManiaFilterCriteria(); criteria.TryParseCustomKeywordCriteria("keys", Operator.NotEqual, "1,3,5,7"); - Assert.False(criteria.Matches( + ClassicAssert.False(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 1 }), new FilterCriteria())); - Assert.True(criteria.Matches( + ClassicAssert.True(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 2 }), new FilterCriteria())); - Assert.False(criteria.Matches( + ClassicAssert.False(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 3 }), new FilterCriteria())); - Assert.False(criteria.Matches( + ClassicAssert.False(criteria.Matches( new BeatmapInfo(new RulesetInfo { OnlineID = 0 }, new BeatmapDifficulty { CircleSize = 4 }), new FilterCriteria { @@ -122,23 +123,23 @@ public void TestKeysGreaterOrEqualThan() var criteria = new ManiaFilterCriteria(); criteria.TryParseCustomKeywordCriteria("keys", Operator.GreaterOrEqual, "4"); - Assert.False(criteria.Matches( + ClassicAssert.False(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 1 }), new FilterCriteria())); - Assert.False(criteria.Matches( + ClassicAssert.False(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 2 }), new FilterCriteria())); - Assert.True(criteria.Matches( + ClassicAssert.True(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 4 }), new FilterCriteria())); - Assert.True(criteria.Matches( + ClassicAssert.True(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 5 }), new FilterCriteria())); - Assert.True(criteria.Matches( + ClassicAssert.True(criteria.Matches( new BeatmapInfo(new RulesetInfo { OnlineID = 0 }, new BeatmapDifficulty { CircleSize = 3 }), new FilterCriteria { @@ -153,23 +154,23 @@ public void TestKeysFilterIntersection() criteria.TryParseCustomKeywordCriteria("keys", Operator.Greater, "4"); criteria.TryParseCustomKeywordCriteria("keys", Operator.NotEqual, "7"); - Assert.False(criteria.Matches( + ClassicAssert.False(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 3 }), new FilterCriteria())); - Assert.False(criteria.Matches( + ClassicAssert.False(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 4 }), new FilterCriteria())); - Assert.True(criteria.Matches( + ClassicAssert.True(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 5 }), new FilterCriteria())); - Assert.False(criteria.Matches( + ClassicAssert.False(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 7 }), new FilterCriteria())); - Assert.True(criteria.Matches( + ClassicAssert.True(criteria.Matches( new BeatmapInfo(new ManiaRuleset().RulesetInfo, new BeatmapDifficulty { CircleSize = 9 }), new FilterCriteria())); } @@ -179,9 +180,9 @@ public void TestInvalidKeysFilters() { var criteria = new ManiaFilterCriteria(); - Assert.False(criteria.TryParseCustomKeywordCriteria("keys", Operator.Equal, "some text")); - Assert.False(criteria.TryParseCustomKeywordCriteria("keys", Operator.NotEqual, "4,some text")); - Assert.False(criteria.TryParseCustomKeywordCriteria("keys", Operator.GreaterOrEqual, "4,5,6")); + ClassicAssert.False(criteria.TryParseCustomKeywordCriteria("keys", Operator.Equal, "some text")); + ClassicAssert.False(criteria.TryParseCustomKeywordCriteria("keys", Operator.NotEqual, "4,some text")); + ClassicAssert.False(criteria.TryParseCustomKeywordCriteria("keys", Operator.GreaterOrEqual, "4,5,6")); } [TestCase] @@ -199,7 +200,7 @@ public void TestLnsEqual() TotalObjectCount = 0, EndTimeObjectCount = 0 }; - Assert.True(criteria.Matches(beatmapInfo1, filterCriteria)); + ClassicAssert.True(criteria.Matches(beatmapInfo1, filterCriteria)); criteria.TryParseCustomKeywordCriteria("lns", Operator.Equal, "0"); BeatmapInfo beatmapInfo2 = new BeatmapInfo(new ManiaRuleset().RulesetInfo) @@ -207,7 +208,7 @@ public void TestLnsEqual() TotalObjectCount = 100, EndTimeObjectCount = 0 }; - Assert.True(criteria.Matches(beatmapInfo2, filterCriteria)); + ClassicAssert.True(criteria.Matches(beatmapInfo2, filterCriteria)); criteria.TryParseCustomKeywordCriteria("lns", Operator.Equal, "100"); BeatmapInfo beatmapInfo3 = new BeatmapInfo(new ManiaRuleset().RulesetInfo) @@ -215,7 +216,7 @@ public void TestLnsEqual() TotalObjectCount = 100, EndTimeObjectCount = 100 }; - Assert.True(criteria.Matches(beatmapInfo3, filterCriteria)); + ClassicAssert.True(criteria.Matches(beatmapInfo3, filterCriteria)); criteria.TryParseCustomKeywordCriteria("lns", Operator.Equal, "1"); BeatmapInfo beatmapInfo4 = new BeatmapInfo(new ManiaRuleset().RulesetInfo) @@ -223,7 +224,7 @@ public void TestLnsEqual() TotalObjectCount = 100, EndTimeObjectCount = 1 }; - Assert.True(criteria.Matches(beatmapInfo4, filterCriteria)); + ClassicAssert.True(criteria.Matches(beatmapInfo4, filterCriteria)); criteria.TryParseCustomKeywordCriteria("lns", Operator.Equal, "0.1"); BeatmapInfo beatmapInfo5 = new BeatmapInfo(new ManiaRuleset().RulesetInfo) @@ -231,7 +232,7 @@ public void TestLnsEqual() TotalObjectCount = 1000, EndTimeObjectCount = 1 }; - Assert.True(criteria.Matches(beatmapInfo5, filterCriteria)); + ClassicAssert.True(criteria.Matches(beatmapInfo5, filterCriteria)); } [TestCase] @@ -249,7 +250,7 @@ public void TestLnsGreaterOrEqual() TotalObjectCount = 0, EndTimeObjectCount = 0 }; - Assert.True(criteria.Matches(beatmapInfo1, filterCriteria)); + ClassicAssert.True(criteria.Matches(beatmapInfo1, filterCriteria)); criteria.TryParseCustomKeywordCriteria("lns", Operator.GreaterOrEqual, "0"); BeatmapInfo beatmapInfo2 = new BeatmapInfo(new ManiaRuleset().RulesetInfo) @@ -257,7 +258,7 @@ public void TestLnsGreaterOrEqual() TotalObjectCount = 100, EndTimeObjectCount = 0 }; - Assert.True(criteria.Matches(beatmapInfo2, filterCriteria)); + ClassicAssert.True(criteria.Matches(beatmapInfo2, filterCriteria)); criteria.TryParseCustomKeywordCriteria("lns", Operator.GreaterOrEqual, "100"); BeatmapInfo beatmapInfo3 = new BeatmapInfo(new ManiaRuleset().RulesetInfo) @@ -265,7 +266,7 @@ public void TestLnsGreaterOrEqual() TotalObjectCount = 100, EndTimeObjectCount = 100 }; - Assert.True(criteria.Matches(beatmapInfo3, filterCriteria)); + ClassicAssert.True(criteria.Matches(beatmapInfo3, filterCriteria)); criteria.TryParseCustomKeywordCriteria("lns", Operator.GreaterOrEqual, "1"); BeatmapInfo beatmapInfo4 = new BeatmapInfo(new ManiaRuleset().RulesetInfo) @@ -273,7 +274,7 @@ public void TestLnsGreaterOrEqual() TotalObjectCount = 100, EndTimeObjectCount = 1 }; - Assert.True(criteria.Matches(beatmapInfo4, filterCriteria)); + ClassicAssert.True(criteria.Matches(beatmapInfo4, filterCriteria)); criteria.TryParseCustomKeywordCriteria("lns", Operator.GreaterOrEqual, "0.1"); BeatmapInfo beatmapInfo5 = new BeatmapInfo(new ManiaRuleset().RulesetInfo) @@ -281,7 +282,7 @@ public void TestLnsGreaterOrEqual() TotalObjectCount = 1000, EndTimeObjectCount = 1 }; - Assert.True(criteria.Matches(beatmapInfo5, filterCriteria)); + ClassicAssert.True(criteria.Matches(beatmapInfo5, filterCriteria)); } [TestCase] @@ -299,7 +300,7 @@ public void TestLnsNotManiaRuleset() TotalObjectCount = 100, EndTimeObjectCount = 50 }; - Assert.False(criteria.Matches(beatmapInfo, filterCriteria)); + ClassicAssert.False(criteria.Matches(beatmapInfo, filterCriteria)); } [TestCase] @@ -307,8 +308,8 @@ public void TestInvalidLnsFilters() { var criteria = new ManiaFilterCriteria(); - Assert.False(criteria.TryParseCustomKeywordCriteria("lns", Operator.Equal, "some text")); - Assert.False(criteria.TryParseCustomKeywordCriteria("lns", Operator.GreaterOrEqual, "1some text")); + ClassicAssert.False(criteria.TryParseCustomKeywordCriteria("lns", Operator.Equal, "some text")); + ClassicAssert.False(criteria.TryParseCustomKeywordCriteria("lns", Operator.GreaterOrEqual, "1some text")); } } } diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs index ff1f9e68940d..726d0af945a0 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using osu.Game.Rulesets.Mania.Beatmaps; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace osu.Game.Rulesets.Mania.Tests { @@ -35,7 +36,7 @@ public void Test(IEnumerable special, int columns) { var definition = new StageDefinition(columns); var results = getResults(definition); - Assert.AreEqual(special, results); + ClassicAssert.AreEqual(special, results); } private IEnumerable getResults(StageDefinition definition) diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs index f5117b61af5f..a06d389f957b 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs @@ -3,6 +3,7 @@ using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Mods; using osu.Game.Tests.Visual; @@ -20,7 +21,7 @@ public partial class TestSceneManiaModHoldOff : ModTestScene public void TestMapHasNoHoldNotes() { var testBeatmap = createModdedBeatmap(); - Assert.False(testBeatmap.HitObjects.OfType().Any()); + ClassicAssert.False(testBeatmap.HitObjects.OfType().Any()); } [Test] diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs index 9a3167b97f64..fd4eb9855c06 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs @@ -3,6 +3,7 @@ using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Testing; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; @@ -33,11 +34,11 @@ public void TestSingleNote() var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.AreEqual(generated.Frames.Count, frame_offset + 2, "Incorrect number of frames"); - Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time"); - Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect release time"); - Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1), "Key1 has not been released"); + ClassicAssert.AreEqual(generated.Frames.Count, frame_offset + 2, "Incorrect number of frames"); + ClassicAssert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time"); + ClassicAssert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect release time"); + ClassicAssert.True(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed"); + ClassicAssert.False(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1), "Key1 has not been released"); } [Test] @@ -54,11 +55,11 @@ public void TestSingleHoldNote() var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.AreEqual(generated.Frames.Count, frame_offset + 2, "Incorrect number of frames"); - Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time"); - Assert.AreEqual(3000, generated.Frames[frame_offset + 1].Time, "Incorrect release time"); - Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1), "Key1 has not been released"); + ClassicAssert.AreEqual(generated.Frames.Count, frame_offset + 2, "Incorrect number of frames"); + ClassicAssert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time"); + ClassicAssert.AreEqual(3000, generated.Frames[frame_offset + 1].Time, "Incorrect release time"); + ClassicAssert.True(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed"); + ClassicAssert.False(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1), "Key1 has not been released"); } [Test] @@ -74,11 +75,11 @@ public void TestSingleNoteChord() var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.AreEqual(generated.Frames.Count, frame_offset + 2, "Incorrect number of frames"); - Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time"); - Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect release time"); - Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been released"); + ClassicAssert.AreEqual(generated.Frames.Count, frame_offset + 2, "Incorrect number of frames"); + ClassicAssert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time"); + ClassicAssert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect release time"); + ClassicAssert.True(checkContains(generated.Frames[frame_offset], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed"); + ClassicAssert.False(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been released"); } [Test] @@ -96,13 +97,13 @@ public void TestHoldNoteChord() var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.AreEqual(generated.Frames.Count, frame_offset + 2, "Incorrect number of frames"); + ClassicAssert.AreEqual(generated.Frames.Count, frame_offset + 2, "Incorrect number of frames"); - Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time"); - Assert.AreEqual(3000, generated.Frames[frame_offset + 1].Time, "Incorrect release time"); + ClassicAssert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time"); + ClassicAssert.AreEqual(3000, generated.Frames[frame_offset + 1].Time, "Incorrect release time"); - Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been released"); + ClassicAssert.True(checkContains(generated.Frames[frame_offset], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed"); + ClassicAssert.False(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been released"); } [Test] @@ -119,15 +120,15 @@ public void TestSingleNoteStair() var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.AreEqual(generated.Frames.Count, frame_offset + 4, "Incorrect number of frames"); - Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect first note hit time"); - Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect first note release time"); - Assert.AreEqual(2000, generated.Frames[frame_offset + 2].Time, "Incorrect second note hit time"); - Assert.AreEqual(2000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 3].Time, "Incorrect second note release time"); - Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1), "Key1 has not been released"); - Assert.IsTrue(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key2), "Key2 has not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[frame_offset + 3], ManiaAction.Key2), "Key2 has not been released"); + ClassicAssert.AreEqual(generated.Frames.Count, frame_offset + 4, "Incorrect number of frames"); + ClassicAssert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect first note hit time"); + ClassicAssert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect first note release time"); + ClassicAssert.AreEqual(2000, generated.Frames[frame_offset + 2].Time, "Incorrect second note hit time"); + ClassicAssert.AreEqual(2000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 3].Time, "Incorrect second note release time"); + ClassicAssert.True(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed"); + ClassicAssert.False(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1), "Key1 has not been released"); + ClassicAssert.True(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key2), "Key2 has not been pressed"); + ClassicAssert.False(checkContains(generated.Frames[frame_offset + 3], ManiaAction.Key2), "Key2 has not been released"); } [Test] @@ -146,16 +147,16 @@ public void TestHoldNoteStair() var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.AreEqual(generated.Frames.Count, frame_offset + 4, "Incorrect number of frames"); - Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect first note hit time"); - Assert.AreEqual(3000, generated.Frames[frame_offset + 2].Time, "Incorrect first note release time"); - Assert.AreEqual(2000, generated.Frames[frame_offset + 1].Time, "Incorrect second note hit time"); - Assert.AreEqual(4000, generated.Frames[frame_offset + 3].Time, "Incorrect second note release time"); - Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed"); - Assert.IsTrue(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key1), "Key1 has not been released"); - Assert.IsTrue(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key2), "Key2 has been released"); - Assert.IsFalse(checkContains(generated.Frames[frame_offset + 3], ManiaAction.Key2), "Key2 has not been released"); + ClassicAssert.AreEqual(generated.Frames.Count, frame_offset + 4, "Incorrect number of frames"); + ClassicAssert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect first note hit time"); + ClassicAssert.AreEqual(3000, generated.Frames[frame_offset + 2].Time, "Incorrect first note release time"); + ClassicAssert.AreEqual(2000, generated.Frames[frame_offset + 1].Time, "Incorrect second note hit time"); + ClassicAssert.AreEqual(4000, generated.Frames[frame_offset + 3].Time, "Incorrect second note release time"); + ClassicAssert.True(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed"); + ClassicAssert.True(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed"); + ClassicAssert.False(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key1), "Key1 has not been released"); + ClassicAssert.True(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key2), "Key2 has been released"); + ClassicAssert.False(checkContains(generated.Frames[frame_offset + 3], ManiaAction.Key2), "Key2 has not been released"); } [Test] @@ -173,14 +174,14 @@ public void TestHoldNoteWithReleasePress() var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.AreEqual(generated.Frames.Count, frame_offset + 3, "Incorrect number of frames"); - Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect first note hit time"); - Assert.AreEqual(3000, generated.Frames[frame_offset + 1].Time, "Incorrect second note press time + first note release time"); - Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 2].Time, "Incorrect second note release time"); - Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1), "Key1 has not been released"); - Assert.IsTrue(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key2), "Key2 has not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key2), "Key2 has not been released"); + ClassicAssert.AreEqual(generated.Frames.Count, frame_offset + 3, "Incorrect number of frames"); + ClassicAssert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect first note hit time"); + ClassicAssert.AreEqual(3000, generated.Frames[frame_offset + 1].Time, "Incorrect second note press time + first note release time"); + ClassicAssert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 2].Time, "Incorrect second note release time"); + ClassicAssert.True(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed"); + ClassicAssert.False(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1), "Key1 has not been released"); + ClassicAssert.True(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key2), "Key2 has not been pressed"); + ClassicAssert.False(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key2), "Key2 has not been released"); } private bool checkContains(ReplayFrame frame, params ManiaAction[] actions) => actions.All(action => ((ManiaReplayFrame)frame).Actions.Contains(action)); diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index edb01b044ed6..8d5c4d9da61b 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -1,9 +1,9 @@  - - - + + + WinExe diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSliderScaling.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSliderScaling.cs index 52a170b84e99..4a1935061946 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSliderScaling.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSliderScaling.cs @@ -6,6 +6,7 @@ using System; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Graphics.Primitives; using osu.Framework.Testing; using osu.Framework.Utils; @@ -102,7 +103,7 @@ public void TestScalingSliderFlat() for (int i = 0; i < 100; i++) { - Assert.True(Precision.AlmostEquals(sliderPathPerfect.PositionAt(i / 100.0f), sliderPathBezier.PositionAt(i / 100.0f))); + ClassicAssert.True(Precision.AlmostEquals(sliderPathPerfect.PositionAt(i / 100.0f), sliderPathBezier.PositionAt(i / 100.0f))); } } @@ -174,7 +175,7 @@ private void assertMatchesPerfectCircle(SliderPath path) double theta = circularArcProperties.ThetaStart + (circularArcProperties.Direction * progress * circularArcProperties.ThetaRange); Vector2 vector = new Vector2((float)Math.Cos(theta), (float)Math.Sin(theta)) * circularArcProperties.Radius; - Assert.True(Precision.AlmostEquals(circularArcProperties.Centre + vector, path.PositionAt(progress), 0.01f), + ClassicAssert.True(Precision.AlmostEquals(circularArcProperties.Centre + vector, path.PositionAt(progress), 0.01f), "A perfect circle with points " + string.Join(", ", path.ControlPoints.Select(x => x.Position)) + " and radius" + circularArcProperties.Radius + "from SliderPath does not almost equal a theoretical perfect circle with " + subpoints + " subpoints" + ": " + (circularArcProperties.Centre + vector) + " - " + path.PositionAt(progress) + " = " + (circularArcProperties.Centre + vector - path.PositionAt(progress)) diff --git a/osu.Game.Rulesets.Osu.Tests/StackingTest.cs b/osu.Game.Rulesets.Osu.Tests/StackingTest.cs index f9b4dcad52a8..6daf5c59c6aa 100644 --- a/osu.Game.Rulesets.Osu.Tests/StackingTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/StackingTest.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps; using osu.Game.IO; using osu.Game.Rulesets.Mods; @@ -57,7 +58,7 @@ osu file format v14 // The last hitobject triggers the stacking for (int i = 0; i < objects.Count - 1; i++) - Assert.AreEqual(0, ((OsuHitObject)objects[i]).StackHeight); + ClassicAssert.AreEqual(0, ((OsuHitObject)objects[i]).StackHeight); } } @@ -104,7 +105,7 @@ osu file format v14 // The last hitobject triggers the stacking for (int i = 0; i < objects.Count - 1; i++) - Assert.AreEqual(0, ((OsuHitObject)objects[i]).StackHeight); + ClassicAssert.AreEqual(0, ((OsuHitObject)objects[i]).StackHeight); } } } diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 6510568555bd..15dca424f32d 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -1,10 +1,10 @@  - - - - + + + + WinExe diff --git a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoEditorSaving.cs b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoEditorSaving.cs index fb05502158df..ca99ae296cf9 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoEditorSaving.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoEditorSaving.cs @@ -35,7 +35,7 @@ public void TestTaikoSliderMultiplierInExport(float? multiplier) string export = LocalStorage.GetFiles("exports").First(); using (var stream = LocalStorage.GetStream(export)) - using (var zip = ZipArchive.Open(stream)) + using (var zip = ZipArchive.OpenArchive(stream)) { using (var osuStream = zip.Entries.First().OpenEntryStream()) using (var reader = new StreamReader(osuStream)) diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index e498989a792f..facb0d0cfbce 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -1,9 +1,9 @@  - - - + + + WinExe diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 916e1e757a94..51875a25d93e 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; @@ -42,9 +43,9 @@ public void TestDecodeBeatmapVersion() var decoder = Decoder.GetDecoder(stream); var working = new TestWorkingBeatmap(decoder.Decode(stream)); - Assert.AreEqual(6, working.Beatmap.BeatmapVersion); + ClassicAssert.AreEqual(6, working.Beatmap.BeatmapVersion); Assert.That(working.Beatmap.BeatmapInfo.Ruleset.Name, Is.Not.EqualTo("null placeholder ruleset")); - Assert.AreEqual(6, working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo, Array.Empty()).BeatmapVersion); + ClassicAssert.AreEqual(6, working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo, Array.Empty()).BeatmapVersion); } } @@ -59,10 +60,10 @@ public void TestPreviewPointWithOffsets(bool applyOffsets) ((LegacyBeatmapDecoder)decoder).ApplyOffsets = applyOffsets; var working = new TestWorkingBeatmap(decoder.Decode(stream)); - Assert.AreEqual(4, working.Beatmap.BeatmapVersion); - Assert.AreEqual(4, working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo, Array.Empty()).BeatmapVersion); + ClassicAssert.AreEqual(4, working.Beatmap.BeatmapVersion); + ClassicAssert.AreEqual(4, working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo, Array.Empty()).BeatmapVersion); - Assert.AreEqual(-1, working.BeatmapInfo.Metadata.PreviewTime); + ClassicAssert.AreEqual(-1, working.BeatmapInfo.Metadata.PreviewTime); } } @@ -78,17 +79,17 @@ public void TestDecodeBeatmapGeneral() var beatmapInfo = beatmap.BeatmapInfo; var metadata = beatmap.Metadata; - Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", metadata.AudioFile); - Assert.AreEqual(0, beatmap.AudioLeadIn); - Assert.AreEqual(164471, metadata.PreviewTime); - Assert.AreEqual(0.7f, beatmap.StackLeniency); - Assert.IsTrue(beatmapInfo.Ruleset.OnlineID == 0); - Assert.IsFalse(beatmap.LetterboxInBreaks); - Assert.IsFalse(beatmap.SpecialStyle); - Assert.IsFalse(beatmap.WidescreenStoryboard); - Assert.IsFalse(beatmap.SamplesMatchPlaybackRate); - Assert.AreEqual(CountdownType.None, beatmap.Countdown); - Assert.AreEqual(0, beatmap.CountdownOffset); + ClassicAssert.AreEqual("03. Renatus - Soleily 192kbps.mp3", metadata.AudioFile); + ClassicAssert.AreEqual(0, beatmap.AudioLeadIn); + ClassicAssert.AreEqual(164471, metadata.PreviewTime); + ClassicAssert.AreEqual(0.7f, beatmap.StackLeniency); + ClassicAssert.True(beatmapInfo.Ruleset.OnlineID == 0); + ClassicAssert.False(beatmap.LetterboxInBreaks); + ClassicAssert.False(beatmap.SpecialStyle); + ClassicAssert.False(beatmap.WidescreenStoryboard); + ClassicAssert.False(beatmap.SamplesMatchPlaybackRate); + ClassicAssert.AreEqual(CountdownType.None, beatmap.Countdown); + ClassicAssert.AreEqual(0, beatmap.CountdownOffset); } } @@ -108,13 +109,13 @@ public void TestDecodeBeatmapEditor() 95901, 106450, 116999, 119637, 130186, 140735, 151285, 161834, 164471, 175020, 185570, 196119, 206669, 209306 }; - Assert.AreEqual(expectedBookmarks.Length, beatmap.Bookmarks.Length); + ClassicAssert.AreEqual(expectedBookmarks.Length, beatmap.Bookmarks.Length); for (int i = 0; i < expectedBookmarks.Length; i++) - Assert.AreEqual(expectedBookmarks[i], beatmap.Bookmarks[i]); - Assert.AreEqual(1.8, beatmap.DistanceSpacing); - Assert.AreEqual(4, beatmap.BeatmapInfo.BeatDivisor); - Assert.AreEqual(4, beatmap.GridSize); - Assert.AreEqual(2, beatmap.TimelineZoom); + ClassicAssert.AreEqual(expectedBookmarks[i], beatmap.Bookmarks[i]); + ClassicAssert.AreEqual(1.8, beatmap.DistanceSpacing); + ClassicAssert.AreEqual(4, beatmap.BeatmapInfo.BeatDivisor); + ClassicAssert.AreEqual(4, beatmap.GridSize); + ClassicAssert.AreEqual(2, beatmap.TimelineZoom); } } @@ -130,16 +131,16 @@ public void TestDecodeBeatmapMetadata() var beatmapInfo = beatmap.BeatmapInfo; var metadata = beatmap.Metadata; - Assert.AreEqual("Renatus", metadata.Title); - Assert.AreEqual("Renatus", metadata.TitleUnicode); - Assert.AreEqual("Soleily", metadata.Artist); - Assert.AreEqual("Soleily", metadata.ArtistUnicode); - Assert.AreEqual("Gamu", metadata.Author.Username); - Assert.AreEqual("Insane", beatmapInfo.DifficultyName); - Assert.AreEqual(string.Empty, metadata.Source); - Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags); - Assert.AreEqual(557821, beatmapInfo.OnlineID); - Assert.AreEqual(241526, beatmapInfo.BeatmapSet?.OnlineID); + ClassicAssert.AreEqual("Renatus", metadata.Title); + ClassicAssert.AreEqual("Renatus", metadata.TitleUnicode); + ClassicAssert.AreEqual("Soleily", metadata.Artist); + ClassicAssert.AreEqual("Soleily", metadata.ArtistUnicode); + ClassicAssert.AreEqual("Gamu", metadata.Author.Username); + ClassicAssert.AreEqual("Insane", beatmapInfo.DifficultyName); + ClassicAssert.AreEqual(string.Empty, metadata.Source); + ClassicAssert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags); + ClassicAssert.AreEqual(557821, beatmapInfo.OnlineID); + ClassicAssert.AreEqual(241526, beatmapInfo.BeatmapSet?.OnlineID); } } @@ -153,12 +154,12 @@ public void TestDecodeBeatmapDifficulty() { var difficulty = decoder.Decode(stream).Difficulty; - Assert.AreEqual(6.5f, difficulty.DrainRate); - Assert.AreEqual(4, difficulty.CircleSize); - Assert.AreEqual(8, difficulty.OverallDifficulty); - Assert.AreEqual(9, difficulty.ApproachRate); - Assert.AreEqual(1.8, difficulty.SliderMultiplier); - Assert.AreEqual(2, difficulty.SliderTickRate); + ClassicAssert.AreEqual(6.5f, difficulty.DrainRate); + ClassicAssert.AreEqual(4, difficulty.CircleSize); + ClassicAssert.AreEqual(8, difficulty.OverallDifficulty); + ClassicAssert.AreEqual(9, difficulty.ApproachRate); + ClassicAssert.AreEqual(1.8, difficulty.SliderMultiplier); + ClassicAssert.AreEqual(2, difficulty.SliderTickRate); } } @@ -174,10 +175,10 @@ public void TestDecodeBeatmapEvents() var metadata = beatmap.Metadata; var breakPoint = beatmap.Breaks[0]; - Assert.AreEqual("machinetop_background.jpg", metadata.BackgroundFile); - Assert.AreEqual(122474, breakPoint.StartTime); - Assert.AreEqual(140135, breakPoint.EndTime); - Assert.IsTrue(breakPoint.HasEffect); + ClassicAssert.AreEqual("machinetop_background.jpg", metadata.BackgroundFile); + ClassicAssert.AreEqual(122474, breakPoint.StartTime); + ClassicAssert.AreEqual(140135, breakPoint.EndTime); + ClassicAssert.True(breakPoint.HasEffect); } } @@ -192,7 +193,7 @@ public void TestDecodeVideoWithLowercaseExtension() var beatmap = decoder.Decode(stream); var metadata = beatmap.Metadata; - Assert.AreEqual("BG.jpg", metadata.BackgroundFile); + ClassicAssert.AreEqual("BG.jpg", metadata.BackgroundFile); } } @@ -207,7 +208,7 @@ public void TestDecodeVideoWithUppercaseExtension() var beatmap = decoder.Decode(stream); var metadata = beatmap.Metadata; - Assert.AreEqual("BG.jpg", metadata.BackgroundFile); + ClassicAssert.AreEqual("BG.jpg", metadata.BackgroundFile); } } @@ -222,7 +223,7 @@ public void TestDecodeImageSpecifiedAsVideo() var beatmap = decoder.Decode(stream); var metadata = beatmap.Metadata; - Assert.AreEqual("BG.jpg", metadata.BackgroundFile); + ClassicAssert.AreEqual("BG.jpg", metadata.BackgroundFile); } } @@ -237,67 +238,67 @@ public void TestDecodeBeatmapTimingPoints() var beatmap = decoder.Decode(stream); var controlPoints = (LegacyControlPointInfo)beatmap.ControlPointInfo; - Assert.AreEqual(4, controlPoints.TimingPoints.Count); - Assert.AreEqual(5, controlPoints.DifficultyPoints.Count); - Assert.AreEqual(34, controlPoints.SamplePoints.Count); - Assert.AreEqual(8, controlPoints.EffectPoints.Count); + ClassicAssert.AreEqual(4, controlPoints.TimingPoints.Count); + ClassicAssert.AreEqual(5, controlPoints.DifficultyPoints.Count); + ClassicAssert.AreEqual(34, controlPoints.SamplePoints.Count); + ClassicAssert.AreEqual(8, controlPoints.EffectPoints.Count); var timingPoint = controlPoints.TimingPointAt(0); - Assert.AreEqual(956, timingPoint.Time); - Assert.AreEqual(329.67032967033, timingPoint.BeatLength); - Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature); - Assert.IsFalse(timingPoint.OmitFirstBarLine); + ClassicAssert.AreEqual(956, timingPoint.Time); + ClassicAssert.AreEqual(329.67032967033, timingPoint.BeatLength); + ClassicAssert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature); + ClassicAssert.False(timingPoint.OmitFirstBarLine); timingPoint = controlPoints.TimingPointAt(48428); - Assert.AreEqual(956, timingPoint.Time); - Assert.AreEqual(329.67032967033d, timingPoint.BeatLength); - Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature); - Assert.IsFalse(timingPoint.OmitFirstBarLine); + ClassicAssert.AreEqual(956, timingPoint.Time); + ClassicAssert.AreEqual(329.67032967033d, timingPoint.BeatLength); + ClassicAssert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature); + ClassicAssert.False(timingPoint.OmitFirstBarLine); timingPoint = controlPoints.TimingPointAt(119637); - Assert.AreEqual(119637, timingPoint.Time); - Assert.AreEqual(659.340659340659, timingPoint.BeatLength); - Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature); - Assert.IsFalse(timingPoint.OmitFirstBarLine); + ClassicAssert.AreEqual(119637, timingPoint.Time); + ClassicAssert.AreEqual(659.340659340659, timingPoint.BeatLength); + ClassicAssert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature); + ClassicAssert.False(timingPoint.OmitFirstBarLine); var difficultyPoint = controlPoints.DifficultyPointAt(0); - Assert.AreEqual(0, difficultyPoint.Time); - Assert.AreEqual(1.0, difficultyPoint.SliderVelocity); + ClassicAssert.AreEqual(0, difficultyPoint.Time); + ClassicAssert.AreEqual(1.0, difficultyPoint.SliderVelocity); difficultyPoint = controlPoints.DifficultyPointAt(48428); - Assert.AreEqual(0, difficultyPoint.Time); - Assert.AreEqual(1.0, difficultyPoint.SliderVelocity); + ClassicAssert.AreEqual(0, difficultyPoint.Time); + ClassicAssert.AreEqual(1.0, difficultyPoint.SliderVelocity); difficultyPoint = controlPoints.DifficultyPointAt(116999); - Assert.AreEqual(116999, difficultyPoint.Time); - Assert.AreEqual(0.75, difficultyPoint.SliderVelocity, 0.1); + ClassicAssert.AreEqual(116999, difficultyPoint.Time); + ClassicAssert.AreEqual(0.75, difficultyPoint.SliderVelocity, 0.1); var soundPoint = controlPoints.SamplePointAt(0); - Assert.AreEqual(956, soundPoint.Time); - Assert.AreEqual(HitSampleInfo.BANK_SOFT, soundPoint.SampleBank); - Assert.AreEqual(60, soundPoint.SampleVolume); + ClassicAssert.AreEqual(956, soundPoint.Time); + ClassicAssert.AreEqual(HitSampleInfo.BANK_SOFT, soundPoint.SampleBank); + ClassicAssert.AreEqual(60, soundPoint.SampleVolume); soundPoint = controlPoints.SamplePointAt(53373); - Assert.AreEqual(53373, soundPoint.Time); - Assert.AreEqual(HitSampleInfo.BANK_SOFT, soundPoint.SampleBank); - Assert.AreEqual(60, soundPoint.SampleVolume); + ClassicAssert.AreEqual(53373, soundPoint.Time); + ClassicAssert.AreEqual(HitSampleInfo.BANK_SOFT, soundPoint.SampleBank); + ClassicAssert.AreEqual(60, soundPoint.SampleVolume); soundPoint = controlPoints.SamplePointAt(119637); - Assert.AreEqual(119637, soundPoint.Time); - Assert.AreEqual(HitSampleInfo.BANK_SOFT, soundPoint.SampleBank); - Assert.AreEqual(80, soundPoint.SampleVolume); + ClassicAssert.AreEqual(119637, soundPoint.Time); + ClassicAssert.AreEqual(HitSampleInfo.BANK_SOFT, soundPoint.SampleBank); + ClassicAssert.AreEqual(80, soundPoint.SampleVolume); var effectPoint = controlPoints.EffectPointAt(0); - Assert.AreEqual(0, effectPoint.Time); - Assert.IsFalse(effectPoint.KiaiMode); + ClassicAssert.AreEqual(0, effectPoint.Time); + ClassicAssert.False(effectPoint.KiaiMode); effectPoint = controlPoints.EffectPointAt(53703); - Assert.AreEqual(53703, effectPoint.Time); - Assert.IsTrue(effectPoint.KiaiMode); + ClassicAssert.AreEqual(53703, effectPoint.Time); + ClassicAssert.True(effectPoint.KiaiMode); effectPoint = controlPoints.EffectPointAt(116637); - Assert.AreEqual(95901, effectPoint.Time); - Assert.IsFalse(effectPoint.KiaiMode); + ClassicAssert.AreEqual(95901, effectPoint.Time); + ClassicAssert.False(effectPoint.KiaiMode); } } @@ -397,9 +398,9 @@ public void TestDecodeBeatmapColours() new Color4(255, 177, 140, 255), new Color4(100, 100, 100, 255), // alpha is specified as 100, but should be ignored. }; - Assert.AreEqual(expectedColors.Length, comboColors.Count); + ClassicAssert.AreEqual(expectedColors.Length, comboColors.Count); for (int i = 0; i < expectedColors.Length; i++) - Assert.AreEqual(expectedColors[i], comboColors[i]); + ClassicAssert.AreEqual(expectedColors[i], comboColors[i]); } } @@ -426,9 +427,9 @@ public void TestComboColourCountIsLimitedToEight() new Color4(100, 100, 100, 255), new Color4(142, 199, 255, 255), }; - Assert.AreEqual(expectedColors.Length, comboColors.Count); + ClassicAssert.AreEqual(expectedColors.Length, comboColors.Count); for (int i = 0; i < expectedColors.Length; i++) - Assert.AreEqual(expectedColors[i], comboColors[i]); + ClassicAssert.AreEqual(expectedColors[i], comboColors[i]); } } @@ -464,12 +465,12 @@ public void TestDecodeBeatmapComboOffsetsOsu() new OsuBeatmapProcessor(converted).PreProcess(); new OsuBeatmapProcessor(converted).PostProcess(); - Assert.AreEqual(1, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndexWithOffsets); - Assert.AreEqual(2, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndexWithOffsets); - Assert.AreEqual(3, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndexWithOffsets); - Assert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndexWithOffsets); - Assert.AreEqual(8, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndexWithOffsets); - Assert.AreEqual(9, ((IHasComboInformation)converted.HitObjects.ElementAt(11)).ComboIndexWithOffsets); + ClassicAssert.AreEqual(1, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndexWithOffsets); + ClassicAssert.AreEqual(2, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndexWithOffsets); + ClassicAssert.AreEqual(3, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndexWithOffsets); + ClassicAssert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndexWithOffsets); + ClassicAssert.AreEqual(8, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndexWithOffsets); + ClassicAssert.AreEqual(9, ((IHasComboInformation)converted.HitObjects.ElementAt(11)).ComboIndexWithOffsets); } } @@ -487,12 +488,12 @@ public void TestDecodeBeatmapComboOffsetsCatch() new CatchBeatmapProcessor(converted).PreProcess(); new CatchBeatmapProcessor(converted).PostProcess(); - Assert.AreEqual(1, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndexWithOffsets); - Assert.AreEqual(2, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndexWithOffsets); - Assert.AreEqual(3, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndexWithOffsets); - Assert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndexWithOffsets); - Assert.AreEqual(8, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndexWithOffsets); - Assert.AreEqual(9, ((IHasComboInformation)converted.HitObjects.ElementAt(11)).ComboIndexWithOffsets); + ClassicAssert.AreEqual(1, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndexWithOffsets); + ClassicAssert.AreEqual(2, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndexWithOffsets); + ClassicAssert.AreEqual(3, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndexWithOffsets); + ClassicAssert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndexWithOffsets); + ClassicAssert.AreEqual(8, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndexWithOffsets); + ClassicAssert.AreEqual(9, ((IHasComboInformation)converted.HitObjects.ElementAt(11)).ComboIndexWithOffsets); } } @@ -508,8 +509,8 @@ public void TestDecodeBeatmapHitObjectCoordinatesLegacy() var positionData = hitObjects[0] as IHasPosition; - Assert.IsNotNull(positionData); - Assert.AreEqual(new Vector2(256, 256), positionData!.Position); + ClassicAssert.NotNull(positionData); + ClassicAssert.AreEqual(new Vector2(256, 256), positionData!.Position); } } @@ -525,8 +526,8 @@ public void TestDecodeBeatmapHitObjectCoordinatesLazer() var positionData = hitObjects[0] as IHasPosition; - Assert.IsNotNull(positionData); - Assert.AreEqual(new Vector2(256.99853f, 256.001f), positionData!.Position); + ClassicAssert.NotNull(positionData); + ClassicAssert.AreEqual(new Vector2(256.99853f, 256.001f), positionData!.Position); } } @@ -543,18 +544,18 @@ public void TestDecodeBeatmapHitObjects() var curveData = hitObjects[0] as IHasPathWithRepeats; var positionData = hitObjects[0] as IHasPosition; - Assert.IsNotNull(positionData); - Assert.IsNotNull(curveData); - Assert.AreEqual(new Vector2(192, 168), positionData!.Position); - Assert.AreEqual(956, hitObjects[0].StartTime); - Assert.IsTrue(hitObjects[0].Samples.Any(s => s.Name == HitSampleInfo.HIT_NORMAL)); + ClassicAssert.NotNull(positionData); + ClassicAssert.NotNull(curveData); + ClassicAssert.AreEqual(new Vector2(192, 168), positionData!.Position); + ClassicAssert.AreEqual(956, hitObjects[0].StartTime); + ClassicAssert.True(hitObjects[0].Samples.Any(s => s.Name == HitSampleInfo.HIT_NORMAL)); positionData = hitObjects[1] as IHasPosition; - Assert.IsNotNull(positionData); - Assert.AreEqual(new Vector2(304, 56), positionData!.Position); - Assert.AreEqual(1285, hitObjects[1].StartTime); - Assert.IsTrue(hitObjects[1].Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP)); + ClassicAssert.NotNull(positionData); + ClassicAssert.AreEqual(new Vector2(304, 56), positionData!.Position); + ClassicAssert.AreEqual(1285, hitObjects[1].StartTime); + ClassicAssert.True(hitObjects[1].Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP)); } } @@ -585,22 +586,22 @@ public void TestDecodeControlPointCustomSampleBank() { var hitObjects = decoder.Decode(stream).HitObjects; - Assert.AreEqual("Gameplay/normal-hitnormal", getTestableSampleInfo(hitObjects[0]).LookupNames.First()); - Assert.AreEqual("Gameplay/normal-hitnormal", getTestableSampleInfo(hitObjects[1]).LookupNames.First()); - Assert.AreEqual("Gameplay/normal-hitnormal2", getTestableSampleInfo(hitObjects[2]).LookupNames.First()); - Assert.AreEqual("Gameplay/normal-hitnormal", getTestableSampleInfo(hitObjects[3]).LookupNames.First()); + ClassicAssert.AreEqual("Gameplay/normal-hitnormal", getTestableSampleInfo(hitObjects[0]).LookupNames.First()); + ClassicAssert.AreEqual("Gameplay/normal-hitnormal", getTestableSampleInfo(hitObjects[1]).LookupNames.First()); + ClassicAssert.AreEqual("Gameplay/normal-hitnormal2", getTestableSampleInfo(hitObjects[2]).LookupNames.First()); + ClassicAssert.AreEqual("Gameplay/normal-hitnormal", getTestableSampleInfo(hitObjects[3]).LookupNames.First()); // The fourth object is a slider. // `Samples` of a slider are presumed to control the volume of sounds that last the entire duration of the slider // (such as ticks, slider slide sounds, etc.) // Thus, the point of query of control points used for `Samples` is just beyond the start time of the slider. - Assert.AreEqual("Gameplay/soft-hitnormal11", getTestableSampleInfo(hitObjects[4]).LookupNames.First()); + ClassicAssert.AreEqual("Gameplay/soft-hitnormal11", getTestableSampleInfo(hitObjects[4]).LookupNames.First()); // That said, the `NodeSamples` of the slider are responsible for the sounds of the slider's head / tail / repeats / large ticks etc. // Therefore, they should be read at the time instant correspondent to the given node. // This means that the tail should use bank 8 rather than 11. - Assert.AreEqual("Gameplay/soft-hitnormal11", ((ConvertSlider)hitObjects[4]).NodeSamples[0][0].LookupNames.First()); - Assert.AreEqual("Gameplay/soft-hitnormal8", ((ConvertSlider)hitObjects[4]).NodeSamples[1][0].LookupNames.First()); + ClassicAssert.AreEqual("Gameplay/soft-hitnormal11", ((ConvertSlider)hitObjects[4]).NodeSamples[0][0].LookupNames.First()); + ClassicAssert.AreEqual("Gameplay/soft-hitnormal8", ((ConvertSlider)hitObjects[4]).NodeSamples[1][0].LookupNames.First()); } static HitSampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.Samples[0]; @@ -616,9 +617,9 @@ public void TestDecodeHitObjectCustomSampleBank() { var hitObjects = decoder.Decode(stream).HitObjects; - Assert.AreEqual("Gameplay/normal-hitnormal", getTestableSampleInfo(hitObjects[0]).LookupNames.First()); - Assert.AreEqual("Gameplay/normal-hitnormal2", getTestableSampleInfo(hitObjects[1]).LookupNames.First()); - Assert.AreEqual("Gameplay/normal-hitnormal3", getTestableSampleInfo(hitObjects[2]).LookupNames.First()); + ClassicAssert.AreEqual("Gameplay/normal-hitnormal", getTestableSampleInfo(hitObjects[0]).LookupNames.First()); + ClassicAssert.AreEqual("Gameplay/normal-hitnormal2", getTestableSampleInfo(hitObjects[1]).LookupNames.First()); + ClassicAssert.AreEqual("Gameplay/normal-hitnormal3", getTestableSampleInfo(hitObjects[2]).LookupNames.First()); } static HitSampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.Samples[0]; @@ -634,11 +635,11 @@ public void TestDecodeHitObjectFileSamples() { var hitObjects = decoder.Decode(stream).HitObjects; - Assert.AreEqual("hit_1.wav", getTestableSampleInfo(hitObjects[0]).LookupNames.First()); - Assert.AreEqual("hit_2.wav", getTestableSampleInfo(hitObjects[1]).LookupNames.First()); - Assert.AreEqual("Gameplay/normal-hitnormal2", getTestableSampleInfo(hitObjects[2]).LookupNames.First()); - Assert.AreEqual("hit_1.wav", getTestableSampleInfo(hitObjects[3]).LookupNames.First()); - Assert.AreEqual(70, getTestableSampleInfo(hitObjects[3]).Volume); + ClassicAssert.AreEqual("hit_1.wav", getTestableSampleInfo(hitObjects[0]).LookupNames.First()); + ClassicAssert.AreEqual("hit_2.wav", getTestableSampleInfo(hitObjects[1]).LookupNames.First()); + ClassicAssert.AreEqual("Gameplay/normal-hitnormal2", getTestableSampleInfo(hitObjects[2]).LookupNames.First()); + ClassicAssert.AreEqual("hit_1.wav", getTestableSampleInfo(hitObjects[3]).LookupNames.First()); + ClassicAssert.AreEqual(70, getTestableSampleInfo(hitObjects[3]).Volume); } static HitSampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.Samples[0]; @@ -656,35 +657,35 @@ public void TestDecodeSliderSamples() var slider1 = (ConvertSlider)hitObjects[0]; - Assert.AreEqual(1, slider1.NodeSamples[0].Count); - Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider1.NodeSamples[0][0].Name); - Assert.AreEqual(1, slider1.NodeSamples[1].Count); - Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider1.NodeSamples[1][0].Name); - Assert.AreEqual(1, slider1.NodeSamples[2].Count); - Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider1.NodeSamples[2][0].Name); + ClassicAssert.AreEqual(1, slider1.NodeSamples[0].Count); + ClassicAssert.AreEqual(HitSampleInfo.HIT_NORMAL, slider1.NodeSamples[0][0].Name); + ClassicAssert.AreEqual(1, slider1.NodeSamples[1].Count); + ClassicAssert.AreEqual(HitSampleInfo.HIT_NORMAL, slider1.NodeSamples[1][0].Name); + ClassicAssert.AreEqual(1, slider1.NodeSamples[2].Count); + ClassicAssert.AreEqual(HitSampleInfo.HIT_NORMAL, slider1.NodeSamples[2][0].Name); var slider2 = (ConvertSlider)hitObjects[1]; - Assert.AreEqual(2, slider2.NodeSamples[0].Count); - Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[0][0].Name); - Assert.AreEqual(HitSampleInfo.HIT_CLAP, slider2.NodeSamples[0][1].Name); - Assert.AreEqual(2, slider2.NodeSamples[1].Count); - Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[1][0].Name); - Assert.AreEqual(HitSampleInfo.HIT_CLAP, slider2.NodeSamples[1][1].Name); - Assert.AreEqual(2, slider2.NodeSamples[2].Count); - Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[2][0].Name); - Assert.AreEqual(HitSampleInfo.HIT_CLAP, slider2.NodeSamples[2][1].Name); + ClassicAssert.AreEqual(2, slider2.NodeSamples[0].Count); + ClassicAssert.AreEqual(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[0][0].Name); + ClassicAssert.AreEqual(HitSampleInfo.HIT_CLAP, slider2.NodeSamples[0][1].Name); + ClassicAssert.AreEqual(2, slider2.NodeSamples[1].Count); + ClassicAssert.AreEqual(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[1][0].Name); + ClassicAssert.AreEqual(HitSampleInfo.HIT_CLAP, slider2.NodeSamples[1][1].Name); + ClassicAssert.AreEqual(2, slider2.NodeSamples[2].Count); + ClassicAssert.AreEqual(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[2][0].Name); + ClassicAssert.AreEqual(HitSampleInfo.HIT_CLAP, slider2.NodeSamples[2][1].Name); var slider3 = (ConvertSlider)hitObjects[2]; - Assert.AreEqual(2, slider3.NodeSamples[0].Count); - Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[0][0].Name); - Assert.AreEqual(HitSampleInfo.HIT_WHISTLE, slider3.NodeSamples[0][1].Name); - Assert.AreEqual(1, slider3.NodeSamples[1].Count); - Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[1][0].Name); - Assert.AreEqual(2, slider3.NodeSamples[2].Count); - Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[2][0].Name); - Assert.AreEqual(HitSampleInfo.HIT_CLAP, slider3.NodeSamples[2][1].Name); + ClassicAssert.AreEqual(2, slider3.NodeSamples[0].Count); + ClassicAssert.AreEqual(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[0][0].Name); + ClassicAssert.AreEqual(HitSampleInfo.HIT_WHISTLE, slider3.NodeSamples[0][1].Name); + ClassicAssert.AreEqual(1, slider3.NodeSamples[1].Count); + ClassicAssert.AreEqual(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[1][0].Name); + ClassicAssert.AreEqual(2, slider3.NodeSamples[2].Count); + ClassicAssert.AreEqual(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[2][0].Name); + ClassicAssert.AreEqual(HitSampleInfo.HIT_CLAP, slider3.NodeSamples[2][1].Name); } } @@ -698,7 +699,7 @@ public void TestDecodeHitObjectNullAdditionBank() { var hitObjects = decoder.Decode(stream).HitObjects; - Assert.AreEqual(hitObjects[0].Samples[0].Bank, hitObjects[0].Samples[1].Bank); + ClassicAssert.AreEqual(hitObjects[0].Samples[0].Bank, hitObjects[0].Samples[1].Bank); } } @@ -739,10 +740,10 @@ public void TestInvalidBankDefaultsToNormal() static void assertObjectHasBanks(HitObject hitObject, string normalBank, string? additionsBank = null) { - Assert.AreEqual(normalBank, hitObject.Samples[0].Bank); + ClassicAssert.AreEqual(normalBank, hitObject.Samples[0].Bank); if (additionsBank != null) - Assert.AreEqual(additionsBank, hitObject.Samples[1].Bank); + ClassicAssert.AreEqual(additionsBank, hitObject.Samples[1].Bank); } } @@ -756,11 +757,11 @@ public void TestFallbackDecoderForCorruptedHeader() using (var stream = new LineBufferedReader(resStream)) { Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); - Assert.IsInstanceOf(decoder); + ClassicAssert.IsInstanceOf(decoder); Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); - Assert.IsNotNull(beatmap); - Assert.AreEqual("Beatmap with corrupted header", beatmap.Metadata.Title); - Assert.AreEqual("Evil Hacker", beatmap.Metadata.Author.Username); + ClassicAssert.NotNull(beatmap); + ClassicAssert.AreEqual("Beatmap with corrupted header", beatmap.Metadata.Title); + ClassicAssert.AreEqual("Evil Hacker", beatmap.Metadata.Author.Username); } } @@ -774,11 +775,11 @@ public void TestFallbackDecoderForMissingHeader() using (var stream = new LineBufferedReader(resStream)) { Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); - Assert.IsInstanceOf(decoder); + ClassicAssert.IsInstanceOf(decoder); Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); - Assert.IsNotNull(beatmap); - Assert.AreEqual("Beatmap with no header", beatmap.Metadata.Title); - Assert.AreEqual("Incredibly Evil Hacker", beatmap.Metadata.Author.Username); + ClassicAssert.NotNull(beatmap); + ClassicAssert.AreEqual("Beatmap with no header", beatmap.Metadata.Title); + ClassicAssert.AreEqual("Incredibly Evil Hacker", beatmap.Metadata.Author.Username); } } @@ -792,11 +793,11 @@ public void TestDecodeFileWithEmptyLinesAtStart() using (var stream = new LineBufferedReader(resStream)) { Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); - Assert.IsInstanceOf(decoder); + ClassicAssert.IsInstanceOf(decoder); Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); - Assert.IsNotNull(beatmap); - Assert.AreEqual("Empty lines at start", beatmap.Metadata.Title); - Assert.AreEqual("Edge Case Hunter", beatmap.Metadata.Author.Username); + ClassicAssert.NotNull(beatmap); + ClassicAssert.AreEqual("Empty lines at start", beatmap.Metadata.Title); + ClassicAssert.AreEqual("Edge Case Hunter", beatmap.Metadata.Author.Username); } } @@ -810,11 +811,11 @@ public void TestDecodeFileWithEmptyLinesAndNoHeader() using (var stream = new LineBufferedReader(resStream)) { Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); - Assert.IsInstanceOf(decoder); + ClassicAssert.IsInstanceOf(decoder); Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); - Assert.IsNotNull(beatmap); - Assert.AreEqual("The dog ate the file header", beatmap.Metadata.Title); - Assert.AreEqual("Why does this keep happening", beatmap.Metadata.Author.Username); + ClassicAssert.NotNull(beatmap); + ClassicAssert.AreEqual("The dog ate the file header", beatmap.Metadata.Title); + ClassicAssert.AreEqual("Why does this keep happening", beatmap.Metadata.Author.Username); } } @@ -828,11 +829,11 @@ public void TestDecodeFileWithContentImmediatelyAfterHeader() using (var stream = new LineBufferedReader(resStream)) { Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); - Assert.IsInstanceOf(decoder); + ClassicAssert.IsInstanceOf(decoder); Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); - Assert.IsNotNull(beatmap); - Assert.AreEqual("No empty line delimiting header from contents", beatmap.Metadata.Title); - Assert.AreEqual("Edge Case Hunter", beatmap.Metadata.Author.Username); + ClassicAssert.NotNull(beatmap); + ClassicAssert.AreEqual("No empty line delimiting header from contents", beatmap.Metadata.Title); + ClassicAssert.AreEqual("Edge Case Hunter", beatmap.Metadata.Author.Username); } } @@ -855,7 +856,7 @@ public void TestAllowFallbackDecoderOverwrite() using (var stream = new LineBufferedReader(resStream)) { Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); - Assert.IsInstanceOf(decoder); + ClassicAssert.IsInstanceOf(decoder); } Assert.DoesNotThrow(LegacyDifficultyCalculatorBeatmapDecoder.Register); @@ -864,7 +865,7 @@ public void TestAllowFallbackDecoderOverwrite() using (var stream = new LineBufferedReader(resStream)) { Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); - Assert.IsInstanceOf(decoder); + ClassicAssert.IsInstanceOf(decoder); } } diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs index 35ce73389511..c18bb9e90229 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Audio.Track; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; @@ -100,7 +101,7 @@ static ControlPointInfo removeLegacyControlPointTypes(ControlPointInfo controlPo { // emulate non-legacy control points by cloning the non-legacy portion. // the assertion is that the encoder can recreate this losslessly from hitobject data. - Assert.IsInstanceOf(controlPointInfo); + ClassicAssert.IsInstanceOf(controlPointInfo); var newControlPoints = new ControlPointInfo(); @@ -129,7 +130,7 @@ private void compareBeatmaps((IBeatmap beatmap, TestLegacySkin skin) expected, ( Assert.That(actual.beatmap.HitObjects.Serialize(), Is.EqualTo(expected.beatmap.HitObjects.Serialize())); // Check skin. - Assert.IsTrue(areComboColoursEqual(expected.skin.Configuration, actual.skin.Configuration)); + ClassicAssert.True(areComboColoursEqual(expected.skin.Configuration, actual.skin.Configuration)); } [Test] diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs index 2815c9cd8fb3..1292d25d6ace 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Extensions; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; @@ -58,18 +59,18 @@ public void TestDecodeManiaReplay() { var score = decoder.Parse(resourceStream); - Assert.AreEqual(3, score.ScoreInfo.Ruleset.OnlineID); + ClassicAssert.AreEqual(3, score.ScoreInfo.Ruleset.OnlineID); - Assert.AreEqual(2, score.ScoreInfo.Statistics[HitResult.Great]); - Assert.AreEqual(1, score.ScoreInfo.Statistics[HitResult.Good]); + ClassicAssert.AreEqual(2, score.ScoreInfo.Statistics[HitResult.Great]); + ClassicAssert.AreEqual(1, score.ScoreInfo.Statistics[HitResult.Good]); - Assert.AreEqual(829_931, score.ScoreInfo.LegacyTotalScore); - Assert.AreEqual(3, score.ScoreInfo.MaxCombo); + ClassicAssert.AreEqual(829_931, score.ScoreInfo.LegacyTotalScore); + ClassicAssert.AreEqual(3, score.ScoreInfo.MaxCombo); Assert.That(score.ScoreInfo.APIMods.Select(m => m.Acronym), Is.EquivalentTo(new[] { "CL", "9K", "DS" })); Assert.That((2 * 300d + 1 * 200) / (3 * 305d), Is.EqualTo(score.ScoreInfo.Accuracy).Within(0.0001)); - Assert.AreEqual(ScoreRank.B, score.ScoreInfo.Rank); + ClassicAssert.AreEqual(ScoreRank.B, score.ScoreInfo.Rank); Assert.That(score.Replay.Frames, Has.One.Matches(frame => frame.Time == 414 && frame.Actions.SequenceEqual(new[] { ManiaAction.Key1, ManiaAction.Key18 }))); @@ -85,10 +86,10 @@ public void TestDecodeTaikoReplay() { var score = decoder.Parse(resourceStream); - Assert.AreEqual(1, score.ScoreInfo.Ruleset.OnlineID); - Assert.AreEqual(4, score.ScoreInfo.Statistics[HitResult.Great]); - Assert.AreEqual(2, score.ScoreInfo.Statistics[HitResult.LargeBonus]); - Assert.AreEqual(4, score.ScoreInfo.MaxCombo); + ClassicAssert.AreEqual(1, score.ScoreInfo.Ruleset.OnlineID); + ClassicAssert.AreEqual(4, score.ScoreInfo.Statistics[HitResult.Great]); + ClassicAssert.AreEqual(2, score.ScoreInfo.Statistics[HitResult.LargeBonus]); + ClassicAssert.AreEqual(4, score.ScoreInfo.MaxCombo); Assert.That(score.Replay.Frames, Is.Not.Empty); } diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs index b10cce6a525e..9b76bd53ec24 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs @@ -3,6 +3,7 @@ using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osuTK; using osu.Framework.Graphics; using osu.Game.Beatmaps.Formats; @@ -25,73 +26,73 @@ public void TestDecodeStoryboardEvents() { var storyboard = decoder.Decode(stream); - Assert.IsTrue(storyboard.HasDrawable); - Assert.AreEqual(6, storyboard.Layers.Count()); + ClassicAssert.True(storyboard.HasDrawable); + ClassicAssert.AreEqual(6, storyboard.Layers.Count()); StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3); - Assert.IsNotNull(background); - Assert.AreEqual(16, background.Elements.Count); - Assert.IsTrue(background.VisibleWhenFailing); - Assert.IsTrue(background.VisibleWhenPassing); - Assert.AreEqual("Background", background.Name); + ClassicAssert.NotNull(background); + ClassicAssert.AreEqual(16, background.Elements.Count); + ClassicAssert.True(background.VisibleWhenFailing); + ClassicAssert.True(background.VisibleWhenPassing); + ClassicAssert.AreEqual("Background", background.Name); StoryboardLayer fail = storyboard.Layers.Single(l => l.Depth == 2); - Assert.IsNotNull(fail); - Assert.AreEqual(0, fail.Elements.Count); - Assert.IsTrue(fail.VisibleWhenFailing); - Assert.IsFalse(fail.VisibleWhenPassing); - Assert.AreEqual("Fail", fail.Name); + ClassicAssert.NotNull(fail); + ClassicAssert.AreEqual(0, fail.Elements.Count); + ClassicAssert.True(fail.VisibleWhenFailing); + ClassicAssert.False(fail.VisibleWhenPassing); + ClassicAssert.AreEqual("Fail", fail.Name); StoryboardLayer pass = storyboard.Layers.Single(l => l.Depth == 1); - Assert.IsNotNull(pass); - Assert.AreEqual(0, pass.Elements.Count); - Assert.IsFalse(pass.VisibleWhenFailing); - Assert.IsTrue(pass.VisibleWhenPassing); - Assert.AreEqual("Pass", pass.Name); + ClassicAssert.NotNull(pass); + ClassicAssert.AreEqual(0, pass.Elements.Count); + ClassicAssert.False(pass.VisibleWhenFailing); + ClassicAssert.True(pass.VisibleWhenPassing); + ClassicAssert.AreEqual("Pass", pass.Name); StoryboardLayer foreground = storyboard.Layers.Single(l => l.Depth == 0); - Assert.IsNotNull(foreground); - Assert.AreEqual(151, foreground.Elements.Count); - Assert.IsTrue(foreground.VisibleWhenFailing); - Assert.IsTrue(foreground.VisibleWhenPassing); - Assert.AreEqual("Foreground", foreground.Name); + ClassicAssert.NotNull(foreground); + ClassicAssert.AreEqual(151, foreground.Elements.Count); + ClassicAssert.True(foreground.VisibleWhenFailing); + ClassicAssert.True(foreground.VisibleWhenPassing); + ClassicAssert.AreEqual("Foreground", foreground.Name); StoryboardLayer overlay = storyboard.Layers.Single(l => l.Depth == int.MinValue); - Assert.IsNotNull(overlay); - Assert.IsEmpty(overlay.Elements); - Assert.IsTrue(overlay.VisibleWhenFailing); - Assert.IsTrue(overlay.VisibleWhenPassing); - Assert.AreEqual("Overlay", overlay.Name); + ClassicAssert.NotNull(overlay); + ClassicAssert.IsEmpty(overlay.Elements); + ClassicAssert.True(overlay.VisibleWhenFailing); + ClassicAssert.True(overlay.VisibleWhenPassing); + ClassicAssert.AreEqual("Overlay", overlay.Name); int spriteCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSprite)); int animationCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardAnimation)); int sampleCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSampleInfo)); - Assert.AreEqual(15, spriteCount); - Assert.AreEqual(1, animationCount); - Assert.AreEqual(0, sampleCount); - Assert.AreEqual(background.Elements.Count, spriteCount + animationCount + sampleCount); + ClassicAssert.AreEqual(15, spriteCount); + ClassicAssert.AreEqual(1, animationCount); + ClassicAssert.AreEqual(0, sampleCount); + ClassicAssert.AreEqual(background.Elements.Count, spriteCount + animationCount + sampleCount); var sprite = background.Elements.ElementAt(0) as StoryboardSprite; - Assert.NotNull(sprite); - Assert.IsTrue(sprite!.HasCommands); - Assert.AreEqual(new Vector2(320, 240), sprite.InitialPosition); - Assert.IsTrue(sprite.IsDrawable); - Assert.AreEqual(Anchor.Centre, sprite.Origin); - Assert.AreEqual("SB/lyric/ja-21.png", sprite.Path); + ClassicAssert.NotNull(sprite); + ClassicAssert.True(sprite!.HasCommands); + ClassicAssert.AreEqual(new Vector2(320, 240), sprite.InitialPosition); + ClassicAssert.True(sprite.IsDrawable); + ClassicAssert.AreEqual(Anchor.Centre, sprite.Origin); + ClassicAssert.AreEqual("SB/lyric/ja-21.png", sprite.Path); var animation = background.Elements.OfType().First(); - Assert.NotNull(animation); - Assert.AreEqual(141175, animation.EndTime); - Assert.AreEqual(10, animation.FrameCount); - Assert.AreEqual(30, animation.FrameDelay); - Assert.IsTrue(animation.HasCommands); - Assert.AreEqual(new Vector2(320, 240), animation.InitialPosition); - Assert.IsTrue(animation.IsDrawable); - Assert.AreEqual(AnimationLoopType.LoopForever, animation.LoopType); - Assert.AreEqual(Anchor.Centre, animation.Origin); - Assert.AreEqual("SB/red jitter/red_0000.jpg", animation.Path); - Assert.AreEqual(78993, animation.StartTime); + ClassicAssert.NotNull(animation); + ClassicAssert.AreEqual(141175, animation.EndTime); + ClassicAssert.AreEqual(10, animation.FrameCount); + ClassicAssert.AreEqual(30, animation.FrameDelay); + ClassicAssert.True(animation.HasCommands); + ClassicAssert.AreEqual(new Vector2(320, 240), animation.InitialPosition); + ClassicAssert.True(animation.IsDrawable); + ClassicAssert.AreEqual(AnimationLoopType.LoopForever, animation.LoopType); + ClassicAssert.AreEqual(Anchor.Centre, animation.Origin); + ClassicAssert.AreEqual("SB/red jitter/red_0000.jpg", animation.Path); + ClassicAssert.AreEqual(78993, animation.StartTime); } } @@ -106,13 +107,13 @@ public void TestLoopWithoutExplicitFadeOut() var storyboard = decoder.Decode(stream); StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3); - Assert.AreEqual(1, background.Elements.Count); + ClassicAssert.AreEqual(1, background.Elements.Count); - Assert.AreEqual(2000, background.Elements[0].StartTime); - Assert.AreEqual(2000, (background.Elements[0] as StoryboardAnimation)?.EarliestTransformTime); + ClassicAssert.AreEqual(2000, background.Elements[0].StartTime); + ClassicAssert.AreEqual(2000, (background.Elements[0] as StoryboardAnimation)?.EarliestTransformTime); - Assert.AreEqual(3000, (background.Elements[0] as StoryboardAnimation)?.GetEndTime()); - Assert.AreEqual(12000, (background.Elements[0] as StoryboardAnimation)?.EndTimeForDisplay); + ClassicAssert.AreEqual(3000, (background.Elements[0] as StoryboardAnimation)?.GetEndTime()); + ClassicAssert.AreEqual(12000, (background.Elements[0] as StoryboardAnimation)?.EndTimeForDisplay); } } @@ -127,11 +128,11 @@ public void TestCorrectAnimationStartTime() var storyboard = decoder.Decode(stream); StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3); - Assert.AreEqual(1, background.Elements.Count); + ClassicAssert.AreEqual(1, background.Elements.Count); - Assert.AreEqual(2000, background.Elements[0].StartTime); + ClassicAssert.AreEqual(2000, background.Elements[0].StartTime); // This property should be used in DrawableStoryboardAnimation as a starting point for animation playback. - Assert.AreEqual(1000, (background.Elements[0] as StoryboardAnimation)?.EarliestTransformTime); + ClassicAssert.AreEqual(1000, (background.Elements[0] as StoryboardAnimation)?.EarliestTransformTime); } } @@ -146,10 +147,10 @@ public void TestNoopFadeTransformIsIgnoredForLifetime() var storyboard = decoder.Decode(stream); StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3); - Assert.AreEqual(2, background.Elements.Count); + ClassicAssert.AreEqual(2, background.Elements.Count); - Assert.AreEqual(1500, background.Elements[0].StartTime); - Assert.AreEqual(1500, background.Elements[1].StartTime); + ClassicAssert.AreEqual(1500, background.Elements[0].StartTime); + ClassicAssert.AreEqual(1500, background.Elements[1].StartTime); } } @@ -164,12 +165,12 @@ public void TestOutOfOrderStartTimes() var storyboard = decoder.Decode(stream); StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3); - Assert.AreEqual(2, background.Elements.Count); + ClassicAssert.AreEqual(2, background.Elements.Count); - Assert.AreEqual(1500, background.Elements[0].StartTime); - Assert.AreEqual(1000, background.Elements[1].StartTime); + ClassicAssert.AreEqual(1500, background.Elements[0].StartTime); + ClassicAssert.AreEqual(1000, background.Elements[1].StartTime); - Assert.AreEqual(1000, storyboard.EarliestEventTime); + ClassicAssert.AreEqual(1000, storyboard.EarliestEventTime); } } @@ -184,12 +185,12 @@ public void TestEarliestStartTimeWithLoopAlphas() var storyboard = decoder.Decode(stream); StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3); - Assert.AreEqual(2, background.Elements.Count); + ClassicAssert.AreEqual(2, background.Elements.Count); - Assert.AreEqual(1000, background.Elements[0].StartTime); - Assert.AreEqual(1000, background.Elements[1].StartTime); + ClassicAssert.AreEqual(1000, background.Elements[0].StartTime); + ClassicAssert.AreEqual(1000, background.Elements[1].StartTime); - Assert.AreEqual(1000, storyboard.EarliestEventTime); + ClassicAssert.AreEqual(1000, storyboard.EarliestEventTime); } } @@ -204,7 +205,7 @@ public void TestDecodeVariableWithSuffix() var storyboard = decoder.Decode(stream); StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3); - Assert.AreEqual(3456, ((StoryboardSprite)background.Elements.Single()).InitialPosition.X); + ClassicAssert.AreEqual(3456, ((StoryboardSprite)background.Elements.Single()).InitialPosition.X); } } @@ -221,7 +222,7 @@ public void TestDecodeVideoWithLowercaseExtension() StoryboardLayer video = storyboard.Layers.Single(l => l.Name == "Video"); Assert.That(video.Elements.Count, Is.EqualTo(1)); - Assert.AreEqual("Video.avi", ((StoryboardVideo)video.Elements[0]).Path); + ClassicAssert.AreEqual("Video.avi", ((StoryboardVideo)video.Elements[0]).Path); } } @@ -238,7 +239,7 @@ public void TestDecodeVideoWithUppercaseExtension() StoryboardLayer video = storyboard.Layers.Single(l => l.Name == "Video"); Assert.That(video.Elements.Count, Is.EqualTo(1)); - Assert.AreEqual("Video.AVI", ((StoryboardVideo)video.Elements[0]).Path); + ClassicAssert.AreEqual("Video.AVI", ((StoryboardVideo)video.Elements[0]).Path); } } @@ -268,12 +269,12 @@ public void TestDecodeOutOfRangeLoopAnimationType() var storyboard = decoder.Decode(stream); StoryboardLayer foreground = storyboard.Layers.Single(l => l.Depth == 0); - Assert.AreEqual(AnimationLoopType.LoopForever, ((StoryboardAnimation)foreground.Elements[0]).LoopType); - Assert.AreEqual(AnimationLoopType.LoopOnce, ((StoryboardAnimation)foreground.Elements[1]).LoopType); - Assert.AreEqual(AnimationLoopType.LoopForever, ((StoryboardAnimation)foreground.Elements[2]).LoopType); - Assert.AreEqual(AnimationLoopType.LoopOnce, ((StoryboardAnimation)foreground.Elements[3]).LoopType); - Assert.AreEqual(AnimationLoopType.LoopForever, ((StoryboardAnimation)foreground.Elements[4]).LoopType); - Assert.AreEqual(AnimationLoopType.LoopForever, ((StoryboardAnimation)foreground.Elements[5]).LoopType); + ClassicAssert.AreEqual(AnimationLoopType.LoopForever, ((StoryboardAnimation)foreground.Elements[0]).LoopType); + ClassicAssert.AreEqual(AnimationLoopType.LoopOnce, ((StoryboardAnimation)foreground.Elements[1]).LoopType); + ClassicAssert.AreEqual(AnimationLoopType.LoopForever, ((StoryboardAnimation)foreground.Elements[2]).LoopType); + ClassicAssert.AreEqual(AnimationLoopType.LoopOnce, ((StoryboardAnimation)foreground.Elements[3]).LoopType); + ClassicAssert.AreEqual(AnimationLoopType.LoopForever, ((StoryboardAnimation)foreground.Elements[4]).LoopType); + ClassicAssert.AreEqual(AnimationLoopType.LoopForever, ((StoryboardAnimation)foreground.Elements[5]).LoopType); } } diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index c20cf7befd10..c0c330dba5b9 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -5,8 +5,8 @@ using System.IO; using System.Linq; -using DeepEqual.Syntax; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; @@ -15,7 +15,6 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Beatmaps; -using osu.Game.Rulesets.Scoring; using osu.Game.Tests.Resources; using osuTK; @@ -33,17 +32,17 @@ public void TestDecodeMetadata() { var beatmap = decodeAsJson(normal); var meta = beatmap.BeatmapInfo.Metadata; - Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet?.OnlineID); - Assert.AreEqual("Soleily", meta.Artist); - Assert.AreEqual("Soleily", meta.ArtistUnicode); - Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); - Assert.AreEqual("Gamu", meta.Author.Username); - Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile); - Assert.AreEqual(164471, meta.PreviewTime); - Assert.AreEqual(string.Empty, meta.Source); - Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags); - Assert.AreEqual("Renatus", meta.Title); - Assert.AreEqual("Renatus", meta.TitleUnicode); + ClassicAssert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet?.OnlineID); + ClassicAssert.AreEqual("Soleily", meta.Artist); + ClassicAssert.AreEqual("Soleily", meta.ArtistUnicode); + ClassicAssert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); + ClassicAssert.AreEqual("Gamu", meta.Author.Username); + ClassicAssert.AreEqual("machinetop_background.jpg", meta.BackgroundFile); + ClassicAssert.AreEqual(164471, meta.PreviewTime); + ClassicAssert.AreEqual(string.Empty, meta.Source); + ClassicAssert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags); + ClassicAssert.AreEqual("Renatus", meta.Title); + ClassicAssert.AreEqual("Renatus", meta.TitleUnicode); } [Test] @@ -51,14 +50,14 @@ public void TestDecodeGeneral() { var beatmap = decodeAsJson(normal); var beatmapInfo = beatmap.BeatmapInfo; - Assert.AreEqual(0, beatmap.AudioLeadIn); - Assert.AreEqual(0.7f, beatmap.StackLeniency); - Assert.AreEqual(false, beatmap.SpecialStyle); - Assert.IsTrue(beatmapInfo.Ruleset.OnlineID == 0); - Assert.AreEqual(false, beatmap.LetterboxInBreaks); - Assert.AreEqual(false, beatmap.WidescreenStoryboard); - Assert.AreEqual(CountdownType.None, beatmap.Countdown); - Assert.AreEqual(0, beatmap.CountdownOffset); + ClassicAssert.AreEqual(0, beatmap.AudioLeadIn); + ClassicAssert.AreEqual(0.7f, beatmap.StackLeniency); + ClassicAssert.AreEqual(false, beatmap.SpecialStyle); + ClassicAssert.True(beatmapInfo.Ruleset.OnlineID == 0); + ClassicAssert.AreEqual(false, beatmap.LetterboxInBreaks); + ClassicAssert.AreEqual(false, beatmap.WidescreenStoryboard); + ClassicAssert.AreEqual(CountdownType.None, beatmap.Countdown); + ClassicAssert.AreEqual(0, beatmap.CountdownOffset); } [Test] @@ -73,13 +72,13 @@ public void TestDecodeEditor() 95901, 106450, 116999, 119637, 130186, 140735, 151285, 161834, 164471, 175020, 185570, 196119, 206669, 209306 }; - Assert.AreEqual(expectedBookmarks.Length, beatmap.Bookmarks.Length); + ClassicAssert.AreEqual(expectedBookmarks.Length, beatmap.Bookmarks.Length); for (int i = 0; i < expectedBookmarks.Length; i++) - Assert.AreEqual(expectedBookmarks[i], beatmap.Bookmarks[i]); - Assert.AreEqual(1.8, beatmap.DistanceSpacing); - Assert.AreEqual(4, beatmapInfo.BeatDivisor); - Assert.AreEqual(4, beatmap.GridSize); - Assert.AreEqual(2, beatmap.TimelineZoom); + ClassicAssert.AreEqual(expectedBookmarks[i], beatmap.Bookmarks[i]); + ClassicAssert.AreEqual(1.8, beatmap.DistanceSpacing); + ClassicAssert.AreEqual(4, beatmapInfo.BeatDivisor); + ClassicAssert.AreEqual(4, beatmap.GridSize); + ClassicAssert.AreEqual(2, beatmap.TimelineZoom); } [Test] @@ -87,12 +86,12 @@ public void TestDecodeDifficulty() { var beatmap = decodeAsJson(normal); var difficulty = beatmap.Difficulty; - Assert.AreEqual(6.5f, difficulty.DrainRate); - Assert.AreEqual(4, difficulty.CircleSize); - Assert.AreEqual(8, difficulty.OverallDifficulty); - Assert.AreEqual(9, difficulty.ApproachRate); - Assert.AreEqual(1.8, difficulty.SliderMultiplier); - Assert.AreEqual(2, difficulty.SliderTickRate); + ClassicAssert.AreEqual(6.5f, difficulty.DrainRate); + ClassicAssert.AreEqual(4, difficulty.CircleSize); + ClassicAssert.AreEqual(8, difficulty.OverallDifficulty); + ClassicAssert.AreEqual(9, difficulty.ApproachRate); + ClassicAssert.AreEqual(1.8, difficulty.SliderMultiplier); + ClassicAssert.AreEqual(2, difficulty.SliderTickRate); } [Test] @@ -112,19 +111,19 @@ public void TestDecodePostConverted() var curveData = beatmap.HitObjects[0] as IHasPathWithRepeats; var positionData = beatmap.HitObjects[0] as IHasPosition; - Assert.IsNotNull(positionData); - Assert.IsNotNull(curveData); - Assert.AreEqual(90, curveData.Path.Distance); - Assert.AreEqual(new Vector2(192, 168), positionData.Position); - Assert.AreEqual(956, beatmap.HitObjects[0].StartTime); - Assert.IsTrue(beatmap.HitObjects[0].Samples.Any(s => s.Name == HitSampleInfo.HIT_NORMAL)); + Assert.That(positionData, Is.Not.Null); + Assert.That(curveData, Is.Not.Null); + ClassicAssert.AreEqual(90, curveData.Path.Distance); + ClassicAssert.AreEqual(new Vector2(192, 168), positionData.Position); + ClassicAssert.AreEqual(956, beatmap.HitObjects[0].StartTime); + ClassicAssert.True(beatmap.HitObjects[0].Samples.Any(s => s.Name == HitSampleInfo.HIT_NORMAL)); positionData = beatmap.HitObjects[1] as IHasPosition; - Assert.IsNotNull(positionData); - Assert.AreEqual(new Vector2(304, 56), positionData.Position); - Assert.AreEqual(1285, beatmap.HitObjects[1].StartTime); - Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP)); + Assert.That(positionData, Is.Not.Null); + ClassicAssert.AreEqual(new Vector2(304, 56), positionData.Position); + ClassicAssert.AreEqual(1285, beatmap.HitObjects[1].StartTime); + ClassicAssert.True(beatmap.HitObjects[1].Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP)); } [Test] @@ -135,35 +134,35 @@ public void TestDecodeHitObjects() var curveData = beatmap.HitObjects[0] as IHasPathWithRepeats; var positionData = beatmap.HitObjects[0] as IHasPosition; - Assert.IsNotNull(positionData); - Assert.IsNotNull(curveData); - Assert.AreEqual(90, curveData.Path.Distance); - Assert.AreEqual(new Vector2(192, 168), positionData.Position); - Assert.AreEqual(956, beatmap.HitObjects[0].StartTime); - Assert.IsTrue(beatmap.HitObjects[0].Samples.Any(s => s.Name == HitSampleInfo.HIT_NORMAL)); + Assert.That(positionData, Is.Not.Null); + Assert.That(curveData, Is.Not.Null); + ClassicAssert.AreEqual(90, curveData.Path.Distance); + ClassicAssert.AreEqual(new Vector2(192, 168), positionData.Position); + ClassicAssert.AreEqual(956, beatmap.HitObjects[0].StartTime); + ClassicAssert.True(beatmap.HitObjects[0].Samples.Any(s => s.Name == HitSampleInfo.HIT_NORMAL)); positionData = beatmap.HitObjects[1] as IHasPosition; - Assert.IsNotNull(positionData); - Assert.AreEqual(new Vector2(304, 56), positionData.Position); - Assert.AreEqual(1285, beatmap.HitObjects[1].StartTime); - Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP)); + Assert.That(positionData, Is.Not.Null); + ClassicAssert.AreEqual(new Vector2(304, 56), positionData.Position); + ClassicAssert.AreEqual(1285, beatmap.HitObjects[1].StartTime); + ClassicAssert.True(beatmap.HitObjects[1].Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP)); } - [TestCase(normal)] - [TestCase(marathon)] - [Ignore("temporarily disabled pending DeepEqual fix (https://github.com/jamesfoster/DeepEqual/pull/35)")] - // Currently fails: - // [TestCase(with_sb)] - public void TestParity(string beatmap) - { - var legacy = decode(beatmap, out Beatmap json); - json.WithDeepEqual(legacy) - .IgnoreProperty(r => r.DeclaringType == typeof(HitWindows) - // Todo: CustomSampleBank shouldn't exist going forward, we need a conversion mechanism - || r.Name == nameof(LegacyDecoder.LegacySampleControlPoint.CustomSampleBank)) - .Assert(); - } + // [TestCase(normal)] + // [TestCase(marathon)] + // [Ignore("temporarily disabled pending DeepEqual fix (https://github.com/jamesfoster/DeepEqual/pull/35)")] + // // Currently fails: + // // [TestCase(with_sb)] + // public void TestParity(string beatmap) + // { + // var legacy = decode(beatmap, out Beatmap json); + // json.WithDeepEqual(legacy) + // .IgnoreProperty(r => r.DeclaringType == typeof(HitWindows) + // // Todo: CustomSampleBank shouldn't exist going forward, we need a conversion mechanism + // || r.Name == nameof(LegacyDecoder.LegacySampleControlPoint.CustomSampleBank)) + // .Assert(); + // } [Test] public void TestGetJsonDecoder() @@ -187,7 +186,7 @@ public void TestGetJsonDecoder() } } - Assert.IsInstanceOf(typeof(JsonBeatmapDecoder), decoder); + ClassicAssert.IsInstanceOf(typeof(JsonBeatmapDecoder), decoder); } /// diff --git a/osu.Game.Tests/Beatmaps/Formats/ParsingTest.cs b/osu.Game.Tests/Beatmaps/Formats/ParsingTest.cs index 339063633ada..8aaa5dd3f342 100644 --- a/osu.Game.Tests/Beatmaps/Formats/ParsingTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/ParsingTest.cs @@ -6,6 +6,7 @@ using System; using System.Globalization; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps.Formats; namespace osu.Game.Tests.Beatmaps.Formats @@ -33,9 +34,9 @@ public void TestNaNHandling() [TestCase(-10, 10)] public void TestValidRanges(double input, double limit = Parsing.MAX_PARSE_VALUE) { - Assert.AreEqual(Parsing.ParseInt((input).ToString(CultureInfo.InvariantCulture), (int)limit), (int)input); - Assert.AreEqual(Parsing.ParseFloat((input).ToString(CultureInfo.InvariantCulture), (float)limit), (float)input); - Assert.AreEqual(Parsing.ParseDouble((input).ToString(CultureInfo.InvariantCulture), limit), input); + ClassicAssert.AreEqual(Parsing.ParseInt((input).ToString(CultureInfo.InvariantCulture), (int)limit), (int)input); + ClassicAssert.AreEqual(Parsing.ParseFloat((input).ToString(CultureInfo.InvariantCulture), (float)limit), (float)input); + ClassicAssert.AreEqual(Parsing.ParseDouble((input).ToString(CultureInfo.InvariantCulture), limit), input); } [TestCase(double.PositiveInfinity)] diff --git a/osu.Game.Tests/Beatmaps/IO/BeatmapImportHelper.cs b/osu.Game.Tests/Beatmaps/IO/BeatmapImportHelper.cs index 055832d7536b..6e3025e99f69 100644 --- a/osu.Game.Tests/Beatmaps/IO/BeatmapImportHelper.cs +++ b/osu.Game.Tests/Beatmaps/IO/BeatmapImportHelper.cs @@ -8,7 +8,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Database; @@ -62,16 +62,16 @@ private static void ensureLoaded(OsuGameBase osu, int timeout = 60000) // TODO: add back some extra checks outside of the realm ones? // var set = queryBeatmapSets().First(); // foreach (BeatmapInfo b in set.Beatmaps) - // Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineID == b.OnlineID)); - // Assert.IsTrue(set.Beatmaps.Count > 0); + // ClassicAssert.True(set.Beatmaps.Any(c => c.OnlineID == b.OnlineID)); + // ClassicAssert.True(set.Beatmaps.Count > 0); // var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap; - // Assert.IsTrue(beatmap?.HitObjects.Any() == true); + // ClassicAssert.True(beatmap?.HitObjects.Any() == true); // beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 1))?.Beatmap; - // Assert.IsTrue(beatmap?.HitObjects.Any() == true); + // ClassicAssert.True(beatmap?.HitObjects.Any() == true); // beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 2))?.Beatmap; - // Assert.IsTrue(beatmap?.HitObjects.Any() == true); + // ClassicAssert.True(beatmap?.HitObjects.Any() == true); // beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap; - // Assert.IsTrue(beatmap?.HitObjects.Any() == true); + // ClassicAssert.True(beatmap?.HitObjects.Any() == true); } private static void waitForOrAssert(Func result, string failureMessage, int timeout = 60000) @@ -81,7 +81,7 @@ private static void waitForOrAssert(Func result, string failureMessage, in while (!result()) Thread.Sleep(200); }); - Assert.IsTrue(task.Wait(timeout), failureMessage); + ClassicAssert.True(task.Wait(timeout), failureMessage); } } } diff --git a/osu.Game.Tests/Beatmaps/IO/LineBufferedReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/LineBufferedReaderTest.cs index 5e37f01c8122..50c12a3a2495 100644 --- a/osu.Game.Tests/Beatmaps/IO/LineBufferedReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/LineBufferedReaderTest.cs @@ -5,6 +5,7 @@ using System.IO; using System.Text; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.IO; namespace osu.Game.Tests.Beatmaps.IO @@ -20,10 +21,10 @@ public void TestReadLineByLine() using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents))) using (var bufferedReader = new LineBufferedReader(stream)) { - Assert.AreEqual("line 1", bufferedReader.ReadLine()); - Assert.AreEqual("line 2", bufferedReader.ReadLine()); - Assert.AreEqual("line 3", bufferedReader.ReadLine()); - Assert.IsNull(bufferedReader.ReadLine()); + ClassicAssert.AreEqual("line 1", bufferedReader.ReadLine()); + ClassicAssert.AreEqual("line 2", bufferedReader.ReadLine()); + ClassicAssert.AreEqual("line 3", bufferedReader.ReadLine()); + ClassicAssert.Null(bufferedReader.ReadLine()); } } @@ -35,11 +36,11 @@ public void TestPeekLineOnce() using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents))) using (var bufferedReader = new LineBufferedReader(stream)) { - Assert.AreEqual("line 1", bufferedReader.ReadLine()); - Assert.AreEqual("peek this", bufferedReader.PeekLine()); - Assert.AreEqual("peek this", bufferedReader.ReadLine()); - Assert.AreEqual("line 3", bufferedReader.ReadLine()); - Assert.IsNull(bufferedReader.ReadLine()); + ClassicAssert.AreEqual("line 1", bufferedReader.ReadLine()); + ClassicAssert.AreEqual("peek this", bufferedReader.PeekLine()); + ClassicAssert.AreEqual("peek this", bufferedReader.ReadLine()); + ClassicAssert.AreEqual("line 3", bufferedReader.ReadLine()); + ClassicAssert.Null(bufferedReader.ReadLine()); } } @@ -51,14 +52,14 @@ public void TestPeekLineMultipleTimes() using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents))) using (var bufferedReader = new LineBufferedReader(stream)) { - Assert.AreEqual("peek this once", bufferedReader.PeekLine()); - Assert.AreEqual("peek this once", bufferedReader.ReadLine()); - Assert.AreEqual("line 2", bufferedReader.ReadLine()); - Assert.AreEqual("peek this a lot", bufferedReader.PeekLine()); - Assert.AreEqual("peek this a lot", bufferedReader.PeekLine()); - Assert.AreEqual("peek this a lot", bufferedReader.PeekLine()); - Assert.AreEqual("peek this a lot", bufferedReader.ReadLine()); - Assert.IsNull(bufferedReader.ReadLine()); + ClassicAssert.AreEqual("peek this once", bufferedReader.PeekLine()); + ClassicAssert.AreEqual("peek this once", bufferedReader.ReadLine()); + ClassicAssert.AreEqual("line 2", bufferedReader.ReadLine()); + ClassicAssert.AreEqual("peek this a lot", bufferedReader.PeekLine()); + ClassicAssert.AreEqual("peek this a lot", bufferedReader.PeekLine()); + ClassicAssert.AreEqual("peek this a lot", bufferedReader.PeekLine()); + ClassicAssert.AreEqual("peek this a lot", bufferedReader.ReadLine()); + ClassicAssert.Null(bufferedReader.ReadLine()); } } @@ -70,11 +71,11 @@ public void TestPeekLineAtEndOfStream() using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents))) using (var bufferedReader = new LineBufferedReader(stream)) { - Assert.AreEqual("first line", bufferedReader.ReadLine()); - Assert.AreEqual("second line", bufferedReader.ReadLine()); - Assert.IsNull(bufferedReader.PeekLine()); - Assert.IsNull(bufferedReader.ReadLine()); - Assert.IsNull(bufferedReader.PeekLine()); + ClassicAssert.AreEqual("first line", bufferedReader.ReadLine()); + ClassicAssert.AreEqual("second line", bufferedReader.ReadLine()); + ClassicAssert.Null(bufferedReader.PeekLine()); + ClassicAssert.Null(bufferedReader.ReadLine()); + ClassicAssert.Null(bufferedReader.PeekLine()); } } @@ -84,10 +85,10 @@ public void TestPeekReadLineOnEmptyStream() using (var stream = new MemoryStream()) using (var bufferedReader = new LineBufferedReader(stream)) { - Assert.IsNull(bufferedReader.PeekLine()); - Assert.IsNull(bufferedReader.ReadLine()); - Assert.IsNull(bufferedReader.ReadLine()); - Assert.IsNull(bufferedReader.PeekLine()); + ClassicAssert.Null(bufferedReader.PeekLine()); + ClassicAssert.Null(bufferedReader.ReadLine()); + ClassicAssert.Null(bufferedReader.ReadLine()); + ClassicAssert.Null(bufferedReader.PeekLine()); } } @@ -99,7 +100,7 @@ public void TestReadToEndNoPeeks() using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents))) using (var bufferedReader = new LineBufferedReader(stream)) { - Assert.AreEqual(contents, bufferedReader.ReadToEnd()); + ClassicAssert.AreEqual(contents, bufferedReader.ReadToEnd()); } } @@ -111,14 +112,14 @@ public void TestReadToEndAfterReadsAndPeeks() using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents))) using (var bufferedReader = new LineBufferedReader(stream)) { - Assert.AreEqual("this line is gone", bufferedReader.ReadLine()); - Assert.AreEqual("this one shouldn't be", bufferedReader.PeekLine()); + ClassicAssert.AreEqual("this line is gone", bufferedReader.ReadLine()); + ClassicAssert.AreEqual("this one shouldn't be", bufferedReader.PeekLine()); string[] endingLines = bufferedReader.ReadToEnd().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - Assert.AreEqual(3, endingLines.Length); - Assert.AreEqual("this one shouldn't be", endingLines[0]); - Assert.AreEqual("these ones", endingLines[1]); - Assert.AreEqual("definitely not", endingLines[2]); + ClassicAssert.AreEqual(3, endingLines.Length); + ClassicAssert.AreEqual("this one shouldn't be", endingLines[0]); + ClassicAssert.AreEqual("these ones", endingLines[1]); + ClassicAssert.AreEqual("definitely not", endingLines[2]); } } } diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index 810ea5dbd078..fbc0975cfb05 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps; using osu.Game.Tests.Resources; using osu.Game.Beatmaps.Formats; @@ -38,7 +39,7 @@ public void TestReadBeatmaps() }; string[] maps = reader.Filenames.ToArray(); foreach (string map in expected) - Assert.Contains(map, maps); + ClassicAssert.Contains(map, maps); } } @@ -56,17 +57,17 @@ public void TestReadMetadata() var meta = beatmap.Metadata; - Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet?.OnlineID); - Assert.AreEqual("Soleily", meta.Artist); - Assert.AreEqual("Soleily", meta.ArtistUnicode); - Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); - Assert.AreEqual("Deif", meta.Author.Username); - Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile); - Assert.AreEqual(164471, meta.PreviewTime); - Assert.AreEqual(string.Empty, meta.Source); - Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags); - Assert.AreEqual("Renatus", meta.Title); - Assert.AreEqual("Renatus", meta.TitleUnicode); + ClassicAssert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet?.OnlineID); + ClassicAssert.AreEqual("Soleily", meta.Artist); + ClassicAssert.AreEqual("Soleily", meta.ArtistUnicode); + ClassicAssert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); + ClassicAssert.AreEqual("Deif", meta.Author.Username); + ClassicAssert.AreEqual("machinetop_background.jpg", meta.BackgroundFile); + ClassicAssert.AreEqual(164471, meta.PreviewTime); + ClassicAssert.AreEqual(string.Empty, meta.Source); + ClassicAssert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags); + ClassicAssert.AreEqual("Renatus", meta.Title); + ClassicAssert.AreEqual("Renatus", meta.TitleUnicode); } } @@ -79,7 +80,7 @@ public void TestReadFile() using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) { - Assert.AreEqual("osu file format v13", stream.ReadLine()?.Trim()); + ClassicAssert.AreEqual("osu file format v13", stream.ReadLine()?.Trim()); } } } diff --git a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs index ca84d00bb333..fc986d0a6067 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; @@ -225,7 +226,7 @@ public void TestDifficultyRatingMapping(double starRating, DifficultyRating expe { var actualBracket = StarDifficulty.GetDifficultyRating(starRating); - Assert.AreEqual(expectedBracket, actualBracket); + ClassicAssert.AreEqual(expectedBracket, actualBracket); } private partial class TestBeatmapDifficultyCache : BeatmapDifficultyCache diff --git a/osu.Game.Tests/Beatmaps/WorkingBeatmapTest.cs b/osu.Game.Tests/Beatmaps/WorkingBeatmapTest.cs index 3c26f8e39a76..1f50574619f0 100644 --- a/osu.Game.Tests/Beatmaps/WorkingBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/WorkingBeatmapTest.cs @@ -10,6 +10,7 @@ using JetBrains.Annotations; using Moq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -29,7 +30,7 @@ public void TestGetPlayableSuccess() working.ResetEvent.Set(); - Assert.NotNull(working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo)); + ClassicAssert.NotNull(working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo)); } [Test] @@ -48,11 +49,11 @@ public void TestGetPlayableCancellationToken() loadCompleted.Set(); }, TaskCreationOptions.LongRunning); - Assert.IsTrue(loadStarted.Wait(10000)); + ClassicAssert.True(loadStarted.Wait(10000)); cts.Cancel(); - Assert.IsTrue(loadCompleted.Wait(10000)); + ClassicAssert.True(loadCompleted.Wait(10000)); working.ResetEvent.Set(); } diff --git a/osu.Game.Tests/Chat/MessageFormatterTests.cs b/osu.Game.Tests/Chat/MessageFormatterTests.cs index 1baa737a9c99..bf04ec646669 100644 --- a/osu.Game.Tests/Chat/MessageFormatterTests.cs +++ b/osu.Game.Tests/Chat/MessageFormatterTests.cs @@ -4,6 +4,7 @@ #nullable disable using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Online.Chat; namespace osu.Game.Tests.Chat @@ -31,8 +32,8 @@ public void TestUnsupportedProtocolLink() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a gopher://really-old-protocol we don't support." }); - Assert.AreEqual(result.Content, result.DisplayContent); - Assert.AreEqual(0, result.Links.Count); + ClassicAssert.AreEqual(result.Content, result.DisplayContent); + ClassicAssert.AreEqual(0, result.Links.Count); } [Test] @@ -40,8 +41,8 @@ public void TestFakeProtocolLink() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a osunotarealprotocol://completely-made-up-protocol we don't support." }); - Assert.AreEqual(result.Content, result.DisplayContent); - Assert.AreEqual(0, result.Links.Count); + ClassicAssert.AreEqual(result.Content, result.DisplayContent); + ClassicAssert.AreEqual(0, result.Links.Count); } [Test] @@ -49,9 +50,9 @@ public void TestSupportedProtocolLinkParsing() { Message result = MessageFormatter.FormatMessage(new Message { Content = "forgotspacehttps://dev.ppy.sh joinmyosump://12345 jointheosu://chan/#english" }); - Assert.AreEqual("https://dev.ppy.sh", result.Links[0].Url); - Assert.AreEqual("osump://12345", result.Links[1].Url); - Assert.AreEqual("osu://chan/#english", result.Links[2].Url); + ClassicAssert.AreEqual("https://dev.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual("osump://12345", result.Links[1].Url); + ClassicAssert.AreEqual("osu://chan/#english", result.Links[2].Url); } [Test] @@ -59,11 +60,11 @@ public void TestBareLink() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a http://www.basic-link.com/?test=test." }); - Assert.AreEqual(result.Content, result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("http://www.basic-link.com/?test=test", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(36, result.Links[0].Length); + ClassicAssert.AreEqual(result.Content, result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("http://www.basic-link.com/?test=test", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(36, result.Links[0].Length); } [TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123#osu/456")] @@ -79,12 +80,12 @@ public void TestBeatmapLinks(LinkAction expectedAction, string expectedArg, stri { Message result = MessageFormatter.FormatMessage(new Message { Content = link }); - Assert.AreEqual(result.Content, result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual(expectedAction, result.Links[0].Action); - Assert.AreEqual(expectedArg, result.Links[0].Argument); + ClassicAssert.AreEqual(result.Content, result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual(expectedAction, result.Links[0].Action); + ClassicAssert.AreEqual(expectedArg, result.Links[0].Argument); if (expectedAction == LinkAction.External) - Assert.AreEqual(link, result.Links[0].Url); + ClassicAssert.AreEqual(link, result.Links[0].Url); } [Test] @@ -95,20 +96,20 @@ public void TestMultipleComplexLinks() Content = "This is a http://test.io/link#fragment. (see https://twitter.com). Also, This string should not be altered. http://example.com/" }); - Assert.AreEqual(result.Content, result.DisplayContent); - Assert.AreEqual(3, result.Links.Count); + ClassicAssert.AreEqual(result.Content, result.DisplayContent); + ClassicAssert.AreEqual(3, result.Links.Count); - Assert.AreEqual("http://test.io/link#fragment", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(28, result.Links[0].Length); + ClassicAssert.AreEqual("http://test.io/link#fragment", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(28, result.Links[0].Length); - Assert.AreEqual("https://twitter.com", result.Links[1].Url); - Assert.AreEqual(45, result.Links[1].Index); - Assert.AreEqual(19, result.Links[1].Length); + ClassicAssert.AreEqual("https://twitter.com", result.Links[1].Url); + ClassicAssert.AreEqual(45, result.Links[1].Index); + ClassicAssert.AreEqual(19, result.Links[1].Length); - Assert.AreEqual("http://example.com/", result.Links[2].Url); - Assert.AreEqual(108, result.Links[2].Index); - Assert.AreEqual(19, result.Links[2].Length); + ClassicAssert.AreEqual("http://example.com/", result.Links[2].Url); + ClassicAssert.AreEqual(108, result.Links[2].Index); + ClassicAssert.AreEqual(19, result.Links[2].Length); } [Test] @@ -116,10 +117,10 @@ public void TestAjaxLinks() { Message result = MessageFormatter.FormatMessage(new Message { Content = "https://twitter.com/#!/hashbanglinks" }); - Assert.AreEqual(result.Content, result.DisplayContent); - Assert.AreEqual(result.Content, result.Links[0].Url); - Assert.AreEqual(0, result.Links[0].Index); - Assert.AreEqual(36, result.Links[0].Length); + ClassicAssert.AreEqual(result.Content, result.DisplayContent); + ClassicAssert.AreEqual(result.Content, result.Links[0].Url); + ClassicAssert.AreEqual(0, result.Links[0].Index); + ClassicAssert.AreEqual(36, result.Links[0].Length); } [Test] @@ -127,10 +128,10 @@ public void TestUnixHomeLinks() { Message result = MessageFormatter.FormatMessage(new Message { Content = "http://www.chiark.greenend.org.uk/~sgtatham/putty/" }); - Assert.AreEqual(result.Content, result.DisplayContent); - Assert.AreEqual(result.Content, result.Links[0].Url); - Assert.AreEqual(0, result.Links[0].Index); - Assert.AreEqual(50, result.Links[0].Length); + ClassicAssert.AreEqual(result.Content, result.DisplayContent); + ClassicAssert.AreEqual(result.Content, result.Links[0].Url); + ClassicAssert.AreEqual(0, result.Links[0].Index); + ClassicAssert.AreEqual(50, result.Links[0].Length); } [Test] @@ -138,9 +139,9 @@ public void TestInsensitiveLinks() { Message result = MessageFormatter.FormatMessage(new Message { Content = "look: http://puu.sh/7Ggh8xcC6/asf0asd9876.NEF" }); - Assert.AreEqual(result.Content, result.DisplayContent); - Assert.AreEqual(6, result.Links[0].Index); - Assert.AreEqual(39, result.Links[0].Length); + ClassicAssert.AreEqual(result.Content, result.DisplayContent); + ClassicAssert.AreEqual(6, result.Links[0].Index); + ClassicAssert.AreEqual(39, result.Links[0].Length); } [Test] @@ -148,11 +149,11 @@ public void TestWikiLink() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [[Wiki Link]]." }); - Assert.AreEqual("This is a Wiki Link.", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki Link", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(9, result.Links[0].Length); + ClassicAssert.AreEqual("This is a Wiki Link.", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://dev.ppy.sh/wiki/Wiki Link", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(9, result.Links[0].Length); } [Test] @@ -160,20 +161,20 @@ public void TestMultiWikiLink() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [[Wiki Link]] [[Wiki:Link]][[Wiki.Link]]." }); - Assert.AreEqual("This is a Wiki Link Wiki:LinkWiki.Link.", result.DisplayContent); - Assert.AreEqual(3, result.Links.Count); + ClassicAssert.AreEqual("This is a Wiki Link Wiki:LinkWiki.Link.", result.DisplayContent); + ClassicAssert.AreEqual(3, result.Links.Count); - Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki Link", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(9, result.Links[0].Length); + ClassicAssert.AreEqual("https://dev.ppy.sh/wiki/Wiki Link", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(9, result.Links[0].Length); - Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki:Link", result.Links[1].Url); - Assert.AreEqual(20, result.Links[1].Index); - Assert.AreEqual(9, result.Links[1].Length); + ClassicAssert.AreEqual("https://dev.ppy.sh/wiki/Wiki:Link", result.Links[1].Url); + ClassicAssert.AreEqual(20, result.Links[1].Index); + ClassicAssert.AreEqual(9, result.Links[1].Length); - Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki.Link", result.Links[2].Url); - Assert.AreEqual(29, result.Links[2].Index); - Assert.AreEqual(9, result.Links[2].Length); + ClassicAssert.AreEqual("https://dev.ppy.sh/wiki/Wiki.Link", result.Links[2].Url); + ClassicAssert.AreEqual(29, result.Links[2].Index); + ClassicAssert.AreEqual(9, result.Links[2].Length); } [Test] @@ -181,11 +182,11 @@ public void TestOldFormatLink() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a (simple test)[https://osu.ppy.sh] of links." }); - Assert.AreEqual("This is a simple test of links.", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(11, result.Links[0].Length); + ClassicAssert.AreEqual("This is a simple test of links.", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(11, result.Links[0].Length); } [Test] @@ -193,11 +194,11 @@ public void TestOldFormatLinkWithBalancedBrackets() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a (tricky (one))[https://osu.ppy.sh]!" }); - Assert.AreEqual("This is a tricky (one)!", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(12, result.Links[0].Length); + ClassicAssert.AreEqual("This is a tricky (one)!", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(12, result.Links[0].Length); } [Test] @@ -205,22 +206,22 @@ public void TestOldFormatLinkWithEscapedBrackets() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is (another loose bracket \\))[https://osu.ppy.sh]." }); - Assert.AreEqual("This is another loose bracket ).", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(8, result.Links[0].Index); - Assert.AreEqual(23, result.Links[0].Length); + ClassicAssert.AreEqual("This is another loose bracket ).", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(8, result.Links[0].Index); + ClassicAssert.AreEqual(23, result.Links[0].Length); } [Test] public void TestOldFormatWithBackslashes() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This link (should end with a backslash \\)[https://osu.ppy.sh]." }); - Assert.AreEqual("This link should end with a backslash \\.", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(29, result.Links[0].Length); + ClassicAssert.AreEqual("This link should end with a backslash \\.", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(29, result.Links[0].Length); } [Test] @@ -228,11 +229,11 @@ public void TestOldFormatLinkWithEscapedAndBalancedBrackets() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a (\\)super\\(\\( tricky (one))[https://osu.ppy.sh]!" }); - Assert.AreEqual("This is a )super(( tricky (one)!", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(21, result.Links[0].Length); + ClassicAssert.AreEqual("This is a )super(( tricky (one)!", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(21, result.Links[0].Length); } [Test] @@ -240,11 +241,11 @@ public void TestNewFormatLink() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [https://osu.ppy.sh simple test]." }); - Assert.AreEqual("This is a simple test.", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(11, result.Links[0].Length); + ClassicAssert.AreEqual("This is a simple test.", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(11, result.Links[0].Length); } [Test] @@ -252,11 +253,11 @@ public void TestNewFormatLinkWithEscapedBrackets() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [https://osu.ppy.sh nasty link with escaped brackets: \\] and \\[]" }); - Assert.AreEqual("This is a nasty link with escaped brackets: ] and [", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(41, result.Links[0].Length); + ClassicAssert.AreEqual("This is a nasty link with escaped brackets: ] and [", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(41, result.Links[0].Length); } [Test] @@ -264,11 +265,11 @@ public void TestNewFormatLinkWithBackslashesInside() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [https://osu.ppy.sh link \\ with \\ backslashes \\]" }); - Assert.AreEqual("This is a link \\ with \\ backslashes \\", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(27, result.Links[0].Length); + ClassicAssert.AreEqual("This is a link \\ with \\ backslashes \\", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(27, result.Links[0].Length); } [Test] @@ -276,11 +277,11 @@ public void TestNewFormatLinkWithEscapedAndBalancedBrackets() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [https://osu.ppy.sh [link [with \\] too many brackets \\[ ]]]" }); - Assert.AreEqual("This is a [link [with ] too many brackets [ ]]", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(36, result.Links[0].Length); + ClassicAssert.AreEqual("This is a [link [with ] too many brackets [ ]]", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(36, result.Links[0].Length); } [Test] @@ -288,11 +289,11 @@ public void TestMarkdownFormatLink() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [simple test](https://osu.ppy.sh)." }); - Assert.AreEqual("This is a simple test.", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(11, result.Links[0].Length); + ClassicAssert.AreEqual("This is a simple test.", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(11, result.Links[0].Length); } [Test] @@ -300,11 +301,11 @@ public void TestMarkdownFormatLinkWithBalancedBrackets() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [tricky [one]](https://osu.ppy.sh)!" }); - Assert.AreEqual("This is a tricky [one]!", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(12, result.Links[0].Length); + ClassicAssert.AreEqual("This is a tricky [one]!", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(12, result.Links[0].Length); } [Test] @@ -312,22 +313,22 @@ public void TestMarkdownFormatLinkWithEscapedBrackets() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is [another loose bracket \\]](https://osu.ppy.sh)." }); - Assert.AreEqual("This is another loose bracket ].", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(8, result.Links[0].Index); - Assert.AreEqual(23, result.Links[0].Length); + ClassicAssert.AreEqual("This is another loose bracket ].", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(8, result.Links[0].Index); + ClassicAssert.AreEqual(23, result.Links[0].Length); } [Test] public void TestMarkdownFormatWithBackslashes() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This link [should end with a backslash \\](https://osu.ppy.sh)." }); - Assert.AreEqual("This link should end with a backslash \\.", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(29, result.Links[0].Length); + ClassicAssert.AreEqual("This link should end with a backslash \\.", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(29, result.Links[0].Length); } [Test] @@ -335,11 +336,11 @@ public void TestMarkdownFormatLinkWithEscapedAndBalancedBrackets() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [\\]super\\[\\[ tricky [one]](https://osu.ppy.sh)!" }); - Assert.AreEqual("This is a ]super[[ tricky [one]!", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(21, result.Links[0].Length); + ClassicAssert.AreEqual("This is a ]super[[ tricky [one]!", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(21, result.Links[0].Length); } [Test] @@ -347,11 +348,11 @@ public void TestMarkdownFormatLinkWithInlineTitle() { Message result = MessageFormatter.FormatMessage(new Message { Content = "I haven't seen [this link format](https://osu.ppy.sh \"osu!\") before..." }); - Assert.AreEqual("I haven't seen this link format before...", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(15, result.Links[0].Index); - Assert.AreEqual(16, result.Links[0].Length); + ClassicAssert.AreEqual("I haven't seen this link format before...", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(15, result.Links[0].Index); + ClassicAssert.AreEqual(16, result.Links[0].Length); } [Test] @@ -359,11 +360,11 @@ public void TestMarkdownFormatLinkWithInlineTitleAndEscapedQuotes() { Message result = MessageFormatter.FormatMessage(new Message { Content = "I haven't seen [this link format](https://osu.ppy.sh \"inner quote \\\" just to confuse \") before..." }); - Assert.AreEqual("I haven't seen this link format before...", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(15, result.Links[0].Index); - Assert.AreEqual(16, result.Links[0].Length); + ClassicAssert.AreEqual("I haven't seen this link format before...", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(15, result.Links[0].Index); + ClassicAssert.AreEqual(16, result.Links[0].Length); } [Test] @@ -371,11 +372,11 @@ public void TestMarkdownFormatLinkWithUrlInTextAndInlineTitle() { Message result = MessageFormatter.FormatMessage(new Message { Content = "I haven't seen [https://osu.ppy.sh](https://osu.ppy.sh \"https://osu.ppy.sh\") before..." }); - Assert.AreEqual("I haven't seen https://osu.ppy.sh before...", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(15, result.Links[0].Index); - Assert.AreEqual(18, result.Links[0].Length); + ClassicAssert.AreEqual("I haven't seen https://osu.ppy.sh before...", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(15, result.Links[0].Index); + ClassicAssert.AreEqual(18, result.Links[0].Length); } [Test] @@ -383,11 +384,11 @@ public void TestMarkdownFormatLinkWithUrlAndTextInTitle() { Message result = MessageFormatter.FormatMessage(new Message { Content = "I haven't seen [oh no, text here! https://osu.ppy.sh](https://osu.ppy.sh) before..." }); - Assert.AreEqual("I haven't seen oh no, text here! https://osu.ppy.sh before...", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(15, result.Links[0].Index); - Assert.AreEqual(36, result.Links[0].Length); + ClassicAssert.AreEqual("I haven't seen oh no, text here! https://osu.ppy.sh before...", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(15, result.Links[0].Index); + ClassicAssert.AreEqual(36, result.Links[0].Length); } [Test] @@ -395,11 +396,11 @@ public void TestMarkdownFormatLinkWithMisleadingUrlInText() { Message result = MessageFormatter.FormatMessage(new Message { Content = "I haven't seen [https://google.com](https://osu.ppy.sh) before..." }); - Assert.AreEqual("I haven't seen https://google.com before...", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(15, result.Links[0].Index); - Assert.AreEqual(18, result.Links[0].Length); + ClassicAssert.AreEqual("I haven't seen https://google.com before...", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(15, result.Links[0].Index); + ClassicAssert.AreEqual(18, result.Links[0].Length); } [Test] @@ -407,11 +408,11 @@ public void TestMarkdownFormatLinkThatContractsIntoLargerLink() { Message result = MessageFormatter.FormatMessage(new Message { Content = "super broken https://[osu.ppy](https://reddit.com).sh/" }); - Assert.AreEqual("super broken https://osu.ppy.sh/", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://reddit.com", result.Links[0].Url); - Assert.AreEqual(21, result.Links[0].Index); - Assert.AreEqual(7, result.Links[0].Length); + ClassicAssert.AreEqual("super broken https://osu.ppy.sh/", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://reddit.com", result.Links[0].Url); + ClassicAssert.AreEqual(21, result.Links[0].Index); + ClassicAssert.AreEqual(7, result.Links[0].Length); } [Test] @@ -420,16 +421,16 @@ public void TestMarkdownFormatLinkDirectlyNextToRawLink() // the raw link has a port at the end of it, so that the raw link regex terminates at the port and doesn't consume display text from the formatted one Message result = MessageFormatter.FormatMessage(new Message { Content = "https://localhost:8080[https://osu.ppy.sh](https://osu.ppy.sh) should be two links" }); - Assert.AreEqual("https://localhost:8080https://osu.ppy.sh should be two links", result.DisplayContent); - Assert.AreEqual(2, result.Links.Count); + ClassicAssert.AreEqual("https://localhost:8080https://osu.ppy.sh should be two links", result.DisplayContent); + ClassicAssert.AreEqual(2, result.Links.Count); - Assert.AreEqual("https://localhost:8080", result.Links[0].Url); - Assert.AreEqual(0, result.Links[0].Index); - Assert.AreEqual(22, result.Links[0].Length); + ClassicAssert.AreEqual("https://localhost:8080", result.Links[0].Url); + ClassicAssert.AreEqual(0, result.Links[0].Index); + ClassicAssert.AreEqual(22, result.Links[0].Length); - Assert.AreEqual("https://osu.ppy.sh", result.Links[1].Url); - Assert.AreEqual(22, result.Links[1].Index); - Assert.AreEqual(18, result.Links[1].Length); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[1].Url); + ClassicAssert.AreEqual(22, result.Links[1].Index); + ClassicAssert.AreEqual(18, result.Links[1].Length); } [Test] @@ -437,10 +438,10 @@ public void TestChannelLink() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is an #english and #japanese." }); - Assert.AreEqual(result.Content, result.DisplayContent); - Assert.AreEqual(2, result.Links.Count); - Assert.AreEqual($"{OsuGameBase.OSU_PROTOCOL}chan/#english", result.Links[0].Url); - Assert.AreEqual($"{OsuGameBase.OSU_PROTOCOL}chan/#japanese", result.Links[1].Url); + ClassicAssert.AreEqual(result.Content, result.DisplayContent); + ClassicAssert.AreEqual(2, result.Links.Count); + ClassicAssert.AreEqual($"{OsuGameBase.OSU_PROTOCOL}chan/#english", result.Links[0].Url); + ClassicAssert.AreEqual($"{OsuGameBase.OSU_PROTOCOL}chan/#japanese", result.Links[1].Url); } [Test] @@ -448,20 +449,20 @@ public void TestOsuProtocol() { Message result = MessageFormatter.FormatMessage(new Message { Content = $"This is a custom protocol {OsuGameBase.OSU_PROTOCOL}chan/#english." }); - Assert.AreEqual(result.Content, result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual($"{OsuGameBase.OSU_PROTOCOL}chan/#english", result.Links[0].Url); - Assert.AreEqual(26, result.Links[0].Index); - Assert.AreEqual(19, result.Links[0].Length); + ClassicAssert.AreEqual(result.Content, result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual($"{OsuGameBase.OSU_PROTOCOL}chan/#english", result.Links[0].Url); + ClassicAssert.AreEqual(26, result.Links[0].Index); + ClassicAssert.AreEqual(19, result.Links[0].Length); result = MessageFormatter.FormatMessage(new Message { Content = $"This is a [custom protocol]({OsuGameBase.OSU_PROTOCOL}chan/#english)." }); - Assert.AreEqual("This is a custom protocol.", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual($"{OsuGameBase.OSU_PROTOCOL}chan/#english", result.Links[0].Url); - Assert.AreEqual("#english", result.Links[0].Argument); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(15, result.Links[0].Length); + ClassicAssert.AreEqual("This is a custom protocol.", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual($"{OsuGameBase.OSU_PROTOCOL}chan/#english", result.Links[0].Url); + ClassicAssert.AreEqual("#english", result.Links[0].Argument); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(15, result.Links[0].Length); } [Test] @@ -469,11 +470,11 @@ public void TestOsuMpProtocol() { Message result = MessageFormatter.FormatMessage(new Message { Content = "Join my multiplayer game osump://12346." }); - Assert.AreEqual(result.Content, result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("osump://12346", result.Links[0].Url); - Assert.AreEqual(25, result.Links[0].Index); - Assert.AreEqual(13, result.Links[0].Length); + ClassicAssert.AreEqual(result.Content, result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("osump://12346", result.Links[0].Url); + ClassicAssert.AreEqual(25, result.Links[0].Index); + ClassicAssert.AreEqual(13, result.Links[0].Length); } [Test] @@ -481,11 +482,11 @@ public void TestRecursiveBreaking() { Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [https://osu.ppy.sh [[simple test]]]." }); - Assert.AreEqual("This is a [[simple test]].", result.DisplayContent); - Assert.AreEqual(1, result.Links.Count); - Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); - Assert.AreEqual(10, result.Links[0].Index); - Assert.AreEqual(15, result.Links[0].Length); + ClassicAssert.AreEqual("This is a [[simple test]].", result.DisplayContent); + ClassicAssert.AreEqual(1, result.Links.Count); + ClassicAssert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + ClassicAssert.AreEqual(10, result.Links[0].Index); + ClassicAssert.AreEqual(15, result.Links[0].Length); } [Test] @@ -496,44 +497,44 @@ public void TestLinkComplex() Content = "This is a [http://www.simple-test.com simple test] with some [traps] and [[wiki links]]. Don't forget to visit https://osu.ppy.sh (now!)[http://google.com]\uD83D\uDE12" }); - Assert.AreEqual("This is a simple test with some [traps] and wiki links. Don't forget to visit https://osu.ppy.sh now![emoji]", result.DisplayContent); - Assert.AreEqual(4, result.Links.Count); + ClassicAssert.AreEqual("This is a simple test with some [traps] and wiki links. Don't forget to visit https://osu.ppy.sh now![emoji]", result.DisplayContent); + ClassicAssert.AreEqual(4, result.Links.Count); Link f = result.Links.Find(l => l.Url == "https://dev.ppy.sh/wiki/wiki links"); Assert.That(f, Is.Not.Null); - Assert.AreEqual(44, f.Index); - Assert.AreEqual(10, f.Length); + ClassicAssert.AreEqual(44, f.Index); + ClassicAssert.AreEqual(10, f.Length); f = result.Links.Find(l => l.Url == "http://www.simple-test.com"); Assert.That(f, Is.Not.Null); - Assert.AreEqual(10, f.Index); - Assert.AreEqual(11, f.Length); + ClassicAssert.AreEqual(10, f.Index); + ClassicAssert.AreEqual(11, f.Length); f = result.Links.Find(l => l.Url == "http://google.com"); Assert.That(f, Is.Not.Null); - Assert.AreEqual(97, f.Index); - Assert.AreEqual(4, f.Length); + ClassicAssert.AreEqual(97, f.Index); + ClassicAssert.AreEqual(4, f.Length); f = result.Links.Find(l => l.Url == "https://osu.ppy.sh"); Assert.That(f, Is.Not.Null); - Assert.AreEqual(78, f.Index); - Assert.AreEqual(18, f.Length); + ClassicAssert.AreEqual(78, f.Index); + ClassicAssert.AreEqual(18, f.Length); } [Test] public void TestEmoji() { Message result = MessageFormatter.FormatMessage(new Message { Content = "Hello world\uD83D\uDE12<--This is an emoji,There are more emojis among us:\uD83D\uDE10\uD83D\uDE00,\uD83D\uDE20" }); - Assert.AreEqual("Hello world[emoji]<--This is an emoji,There are more emojis among us:[emoji][emoji],[emoji]", result.DisplayContent); - Assert.AreEqual(result.Links.Count, 0); + ClassicAssert.AreEqual("Hello world[emoji]<--This is an emoji,There are more emojis among us:[emoji][emoji],[emoji]", result.DisplayContent); + ClassicAssert.AreEqual(result.Links.Count, 0); } [Test] public void TestEmojiWithSuccessiveParens() { Message result = MessageFormatter.FormatMessage(new Message { Content = "\uD83D\uDE10(let's hope this doesn't accidentally turn into a link)" }); - Assert.AreEqual("[emoji](let's hope this doesn't accidentally turn into a link)", result.DisplayContent); - Assert.AreEqual(result.Links.Count, 0); + ClassicAssert.AreEqual("[emoji](let's hope this doesn't accidentally turn into a link)", result.DisplayContent); + ClassicAssert.AreEqual(result.Links.Count, 0); } [Test] @@ -541,8 +542,8 @@ public void TestAbsoluteExternalLinks() { LinkDetails result = MessageFormatter.GetLinkDetails("https://google.com"); - Assert.AreEqual(LinkAction.External, result.Action); - Assert.AreEqual("https://google.com", result.Argument); + ClassicAssert.AreEqual(LinkAction.External, result.Action); + ClassicAssert.AreEqual("https://google.com", result.Argument); } [Test] @@ -550,8 +551,8 @@ public void TestRelativeExternalLinks() { LinkDetails result = MessageFormatter.GetLinkDetails("/relative"); - Assert.AreEqual(LinkAction.External, result.Action); - Assert.AreEqual("/relative", result.Argument); + ClassicAssert.AreEqual(LinkAction.External, result.Action); + ClassicAssert.AreEqual("/relative", result.Argument); } [TestCase("https://dev.ppy.sh/home/changelog", "")] @@ -560,8 +561,8 @@ public void TestChangelogLinks(string link, string expectedArg) { LinkDetails result = MessageFormatter.GetLinkDetails(link); - Assert.AreEqual(LinkAction.OpenChangelog, result.Action); - Assert.AreEqual(expectedArg, result.Argument); + ClassicAssert.AreEqual(LinkAction.OpenChangelog, result.Action); + ClassicAssert.AreEqual(expectedArg, result.Argument); } } } diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index ffe465e71370..c1b5e4ec5ac7 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Extensions; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Logging; @@ -42,7 +43,7 @@ public void TestDetachBeatmapSet() { var beatmapSet = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz")); - Assert.NotNull(beatmapSet); + ClassicAssert.NotNull(beatmapSet); Debug.Assert(beatmapSet != null); BeatmapSetInfo? detachedBeatmapSet = null; @@ -52,23 +53,23 @@ public void TestDetachBeatmapSet() detachedBeatmapSet = live.Detach(); // files are omitted - Assert.AreEqual(0, detachedBeatmapSet.Files.Count); + ClassicAssert.AreEqual(0, detachedBeatmapSet.Files.Count); - Assert.AreEqual(live.Beatmaps.Count, detachedBeatmapSet.Beatmaps.Count); - Assert.AreEqual(live.Beatmaps.Select(f => f.Difficulty).Count(), detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count()); - Assert.AreEqual(live.Metadata, detachedBeatmapSet.Metadata); + ClassicAssert.AreEqual(live.Beatmaps.Count, detachedBeatmapSet.Beatmaps.Count); + ClassicAssert.AreEqual(live.Beatmaps.Select(f => f.Difficulty).Count(), detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count()); + ClassicAssert.AreEqual(live.Metadata, detachedBeatmapSet.Metadata); }); Debug.Assert(detachedBeatmapSet != null); // Check detached instances can all be accessed without throwing. - Assert.AreEqual(0, detachedBeatmapSet.Files.Count); - Assert.NotNull(detachedBeatmapSet.Beatmaps.Count); - Assert.NotZero(detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count()); - Assert.NotNull(detachedBeatmapSet.Metadata); + ClassicAssert.AreEqual(0, detachedBeatmapSet.Files.Count); + ClassicAssert.NotNull(detachedBeatmapSet.Beatmaps.Count); + ClassicAssert.NotZero(detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count()); + ClassicAssert.NotNull(detachedBeatmapSet.Metadata); // Check cyclic reference to beatmap set - Assert.AreEqual(detachedBeatmapSet, detachedBeatmapSet.Beatmaps.First().BeatmapSet); + ClassicAssert.AreEqual(detachedBeatmapSet, detachedBeatmapSet.Beatmaps.First().BeatmapSet); } }); } @@ -84,7 +85,7 @@ public void TestUpdateDetachedBeatmapSet() { var beatmapSet = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz")); - Assert.NotNull(beatmapSet); + ClassicAssert.NotNull(beatmapSet); Debug.Assert(beatmapSet != null); // Detach at the BeatmapInfo point, similar to what GetWorkingBeatmap does. @@ -101,7 +102,7 @@ public void TestUpdateDetachedBeatmapSet() detachedBeatmapSet.Beatmaps.First().Metadata.Artist = "New Artist"; detachedBeatmapSet.Beatmaps.First().Metadata.Author = newUser; - Assert.AreNotEqual(detachedBeatmapSet.Status, BeatmapOnlineStatus.Ranked); + ClassicAssert.AreNotEqual(detachedBeatmapSet.Status, BeatmapOnlineStatus.Ranked); detachedBeatmapSet.Status = BeatmapOnlineStatus.Ranked; beatmapSet.PerformWrite(detachedBeatmapSet.CopyChangesToRealm); @@ -109,17 +110,17 @@ public void TestUpdateDetachedBeatmapSet() beatmapSet.PerformRead(s => { // Check above changes explicitly. - Assert.AreEqual(BeatmapOnlineStatus.Ranked, s.Status); - Assert.AreEqual("New Artist", s.Beatmaps.First().Metadata.Artist); - Assert.AreEqual(newUser, s.Beatmaps.First().Metadata.Author); - Assert.NotZero(s.Files.Count); + ClassicAssert.AreEqual(BeatmapOnlineStatus.Ranked, s.Status); + ClassicAssert.AreEqual("New Artist", s.Beatmaps.First().Metadata.Artist); + ClassicAssert.AreEqual(newUser, s.Beatmaps.First().Metadata.Author); + ClassicAssert.NotZero(s.Files.Count); // Check nothing was lost in the copy operation. - Assert.AreEqual(s.Files.Count, detachedBeatmapSet.Files.Count); - Assert.AreEqual(s.Files.Select(f => f.File).Count(), detachedBeatmapSet.Files.Select(f => f.File).Count()); - Assert.AreEqual(s.Beatmaps.Count, detachedBeatmapSet.Beatmaps.Count); - Assert.AreEqual(s.Beatmaps.Select(f => f.Difficulty).Count(), detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count()); - Assert.AreEqual(s.Metadata, detachedBeatmapSet.Metadata); + ClassicAssert.AreEqual(s.Files.Count, detachedBeatmapSet.Files.Count); + ClassicAssert.AreEqual(s.Files.Select(f => f.File).Count(), detachedBeatmapSet.Files.Select(f => f.File).Count()); + ClassicAssert.AreEqual(s.Beatmaps.Count, detachedBeatmapSet.Beatmaps.Count); + ClassicAssert.AreEqual(s.Beatmaps.Select(f => f.Difficulty).Count(), detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count()); + ClassicAssert.AreEqual(s.Metadata, detachedBeatmapSet.Metadata); }); } }); @@ -142,7 +143,7 @@ public void TestAddFileToAsyncImportedBeatmap() { var beatmapSet = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz")); - Assert.NotNull(beatmapSet); + ClassicAssert.NotNull(beatmapSet); Debug.Assert(beatmapSet != null); // Intentionally detach on async thread as to not trigger a refresh on the main thread. @@ -167,20 +168,20 @@ public void TestImportBeatmapThenCleanup() var imported = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz")); EnsureLoaded(realm.Realm); - Assert.AreEqual(1, realm.Realm.All().Count()); + ClassicAssert.AreEqual(1, realm.Realm.All().Count()); - Assert.NotNull(imported); + ClassicAssert.NotNull(imported); Debug.Assert(imported != null); imported.PerformWrite(s => s.DeletePending = true); - Assert.AreEqual(1, realm.Realm.All().Count(s => s.DeletePending)); + ClassicAssert.AreEqual(1, realm.Realm.All().Count(s => s.DeletePending)); } }); Logger.Log("Running with no work to purge pending deletions"); - RunTestWithRealm((realm, _) => { Assert.AreEqual(0, realm.Realm.All().Count()); }); + RunTestWithRealm((realm, _) => { ClassicAssert.AreEqual(0, realm.Realm.All().Count()); }); } [Test] @@ -208,8 +209,8 @@ public void TestAccessFileAfterImport() var beatmap = imported.Beatmaps.First(); var file = beatmap.File; - Assert.NotNull(file); - Assert.AreEqual(beatmap.Hash, file!.File.Hash); + ClassicAssert.NotNull(file); + ClassicAssert.AreEqual(beatmap.Hash, file!.File.Hash); }); } @@ -245,10 +246,10 @@ public void TestImportThenDeleteFromStream() EnsureLoaded(realm.Realm); } - Assert.NotNull(importedSet); + ClassicAssert.NotNull(importedSet); Debug.Assert(importedSet != null); - Assert.IsTrue(File.Exists(tempPath), "Stream source file somehow went missing"); + ClassicAssert.True(File.Exists(tempPath), "Stream source file somehow went missing"); File.Delete(tempPath); var imported = realm.Realm.All().First(beatmapSet => beatmapSet.ID == importedSet.ID); @@ -269,8 +270,8 @@ public void TestImportThenImport() var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm); // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash. - Assert.IsTrue(imported.ID == importedSecondTime.ID); - Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); + ClassicAssert.True(imported.ID == importedSecondTime.ID); + ClassicAssert.True(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); checkBeatmapSetCount(realm.Realm, 1); checkSingleReferencedFileCount(realm.Realm, 18); @@ -292,7 +293,7 @@ public void TestImportDirectoryWithEmptyOsuFiles() try { - using (var zip = ZipArchive.Open(temp)) + using (var zip = ZipArchive.OpenArchive(temp)) zip.WriteToDirectory(extractedFolder); foreach (var file in new DirectoryInfo(extractedFolder).GetFiles("*.osu")) @@ -304,7 +305,7 @@ public void TestImportDirectoryWithEmptyOsuFiles() } var imported = await importer.Import(new ImportTask(extractedFolder)); - Assert.IsNull(imported); + ClassicAssert.Null(imported); } finally { @@ -333,28 +334,28 @@ public void TestImportThenImportWithReZip() string hashBefore = hashFile(temp); - using (var zip = ZipArchive.Open(temp)) + using (var zip = ZipArchive.OpenArchive(temp)) zip.WriteToDirectory(extractedFolder); - using (var zip = ZipArchive.Create()) + using (var zip = ZipArchive.CreateArchive()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); } // zip files differ because different compression or encoder. - Assert.AreNotEqual(hashBefore, hashFile(temp)); + ClassicAssert.AreNotEqual(hashBefore, hashFile(temp)); var importedSecondTime = await importer.Import(new ImportTask(temp)); EnsureLoaded(realm.Realm); - Assert.NotNull(importedSecondTime); + ClassicAssert.NotNull(importedSecondTime); Debug.Assert(importedSecondTime != null); // but contents doesn't, so existing should still be used. - Assert.IsTrue(imported.ID == importedSecondTime.ID); - Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.PerformRead(s => s.Beatmaps.First().ID)); + ClassicAssert.True(imported.ID == importedSecondTime.ID); + ClassicAssert.True(imported.Beatmaps.First().ID == importedSecondTime.PerformRead(s => s.Beatmaps.First().ID)); } finally { @@ -382,7 +383,7 @@ public void TestImportThenImportWithChangedHashedFile() await createScoreForBeatmap(realm.Realm, imported.Beatmaps.First()); - using (var zip = ZipArchive.Open(temp)) + using (var zip = ZipArchive.OpenArchive(temp)) zip.WriteToDirectory(extractedFolder); // arbitrary write to hashed file @@ -390,7 +391,7 @@ public void TestImportThenImportWithChangedHashedFile() using (var sw = new FileInfo(Directory.GetFiles(extractedFolder, "*.osu").First()).AppendText()) await sw.WriteLineAsync("// changed"); - using (var zip = ZipArchive.Create()) + using (var zip = ZipArchive.CreateArchive()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); @@ -401,11 +402,11 @@ public void TestImportThenImportWithChangedHashedFile() EnsureLoaded(realm.Realm); // check the newly "imported" beatmap is not the original. - Assert.NotNull(importedSecondTime); + ClassicAssert.NotNull(importedSecondTime); Debug.Assert(importedSecondTime != null); - Assert.IsTrue(imported.ID != importedSecondTime.ID); - Assert.IsTrue(imported.Beatmaps.First().ID != importedSecondTime.PerformRead(s => s.Beatmaps.First().ID)); + ClassicAssert.True(imported.ID != importedSecondTime.ID); + ClassicAssert.True(imported.Beatmaps.First().ID != importedSecondTime.PerformRead(s => s.Beatmaps.First().ID)); } finally { @@ -501,7 +502,7 @@ public void TestImport_ThenModifyMapWithScore_ThenImport() EnsureLoaded(realm.Realm); // check the newly "imported" beatmap is not the original. - Assert.NotNull(importedSecondTime); + ClassicAssert.NotNull(importedSecondTime); Debug.Assert(importedSecondTime != null); Assert.That(imported.ID != importedSecondTime.ID); @@ -533,14 +534,14 @@ public void TestImportThenImportWithChangedFile() { var imported = await LoadOszIntoStore(importer, realm.Realm); - using (var zip = ZipArchive.Open(temp)) + using (var zip = ZipArchive.OpenArchive(temp)) zip.WriteToDirectory(extractedFolder); // arbitrary write to non-hashed file using (var sw = new FileInfo(Directory.GetFiles(extractedFolder, "*.mp3").First()).AppendText()) await sw.WriteLineAsync("text"); - using (var zip = ZipArchive.Create()) + using (var zip = ZipArchive.CreateArchive()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); @@ -550,12 +551,12 @@ public void TestImportThenImportWithChangedFile() EnsureLoaded(realm.Realm); - Assert.NotNull(importedSecondTime); + ClassicAssert.NotNull(importedSecondTime); Debug.Assert(importedSecondTime != null); // check the newly "imported" beatmap is not the original. - Assert.IsTrue(imported.ID != importedSecondTime.ID); - Assert.IsTrue(imported.Beatmaps.First().ID != importedSecondTime.PerformRead(s => s.Beatmaps.First().ID)); + ClassicAssert.True(imported.ID != importedSecondTime.ID); + ClassicAssert.True(imported.Beatmaps.First().ID != importedSecondTime.PerformRead(s => s.Beatmaps.First().ID)); } finally { @@ -581,14 +582,14 @@ public void TestImportThenImportWithDifferentFilename() { var imported = await LoadOszIntoStore(importer, realm.Realm); - using (var zip = ZipArchive.Open(temp)) + using (var zip = ZipArchive.OpenArchive(temp)) zip.WriteToDirectory(extractedFolder); // change filename var firstFile = new FileInfo(Directory.GetFiles(extractedFolder).First()); firstFile.MoveTo(Path.Combine(firstFile.DirectoryName.AsNonNull(), $"{firstFile.Name}-changed{firstFile.Extension}")); - using (var zip = ZipArchive.Create()) + using (var zip = ZipArchive.CreateArchive()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); @@ -598,12 +599,12 @@ public void TestImportThenImportWithDifferentFilename() EnsureLoaded(realm.Realm); - Assert.NotNull(importedSecondTime); + ClassicAssert.NotNull(importedSecondTime); Debug.Assert(importedSecondTime != null); // check the newly "imported" beatmap is not the original. - Assert.IsTrue(imported.ID != importedSecondTime.ID); - Assert.IsTrue(imported.Beatmaps.First().ID != importedSecondTime.PerformRead(s => s.Beatmaps.First().ID)); + ClassicAssert.True(imported.ID != importedSecondTime.ID); + ClassicAssert.True(imported.Beatmaps.First().ID != importedSecondTime.PerformRead(s => s.Beatmaps.First().ID)); } finally { @@ -636,11 +637,11 @@ public void TestImportCorruptThenImport() var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm); using (var stream = fileStorage.GetStream(firstFile.File.GetStoragePath())) - Assert.AreEqual(stream.Length, originalLength, "Corruption was not fixed on second import"); + ClassicAssert.AreEqual(stream.Length, originalLength, "Corruption was not fixed on second import"); // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash. - Assert.IsTrue(imported.ID == importedSecondTime.ID); - Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); + ClassicAssert.True(imported.ID == importedSecondTime.ID); + ClassicAssert.True(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); checkBeatmapSetCount(realm.Realm, 1); checkSingleReferencedFileCount(realm.Realm, 18); @@ -659,7 +660,7 @@ public void TestModelCreationFailureDoesntReturn() var zipStream = new MemoryStream(); - using (var zip = ZipArchive.Create()) + using (var zip = ZipArchive.CreateArchive()) zip.SaveTo(zipStream, new ZipWriterOptions(CompressionType.Deflate)); var imported = await importer.Import( @@ -672,8 +673,8 @@ public void TestModelCreationFailureDoesntReturn() checkBeatmapSetCount(realm.Realm, 0); checkBeatmapCount(realm.Realm, 0); - Assert.IsEmpty(imported); - Assert.AreEqual(ProgressNotificationState.Cancelled, progressNotification.State); + ClassicAssert.IsEmpty(imported); + ClassicAssert.AreEqual(ProgressNotificationState.Cancelled, progressNotification.State); }); } @@ -709,7 +710,7 @@ public void TestRollbackOnFailure() File.Delete(brokenTempFilename); using (var outStream = File.Open(brokenTempFilename, FileMode.CreateNew)) - using (var zip = ZipArchive.Open(brokenOsz)) + using (var zip = ZipArchive.OpenArchive(brokenOsz)) { foreach (var entry in zip.Entries.ToArray()) { @@ -737,7 +738,7 @@ public void TestRollbackOnFailure() checkSingleReferencedFileCount(realm.Realm, 18); - Assert.AreEqual(0, loggedExceptionCount); + ClassicAssert.AreEqual(0, loggedExceptionCount); File.Delete(brokenTempFilename); }); @@ -755,17 +756,17 @@ public void TestImportThenDeleteThenImportOptimisedPath() deleteBeatmapSet(imported, realm.Realm); - Assert.IsTrue(imported.DeletePending); + ClassicAssert.True(imported.DeletePending); var originalAddedDate = imported.DateAdded; var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm); // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash. - Assert.IsTrue(imported.ID == importedSecondTime.ID); - Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); - Assert.IsFalse(imported.DeletePending); - Assert.IsFalse(importedSecondTime.DeletePending); + ClassicAssert.True(imported.ID == importedSecondTime.ID); + ClassicAssert.True(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); + ClassicAssert.False(imported.DeletePending); + ClassicAssert.False(importedSecondTime.DeletePending); Assert.That(importedSecondTime.DateAdded, Is.GreaterThan(originalAddedDate)); }); } @@ -787,13 +788,13 @@ public void TestImportThenReimportWithNewDifficulty() try { - using (var zip = ZipArchive.Open(pathOriginal)) + using (var zip = ZipArchive.OpenArchive(pathOriginal)) zip.WriteToDirectory(extractedFolder); // remove one difficulty before first import new FileInfo(Directory.GetFiles(extractedFolder, "*.osu").First()).Delete(); - using (var zip = ZipArchive.Create()) + using (var zip = ZipArchive.CreateArchive()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(pathMissingOneBeatmap, new ZipWriterOptions(CompressionType.Deflate)); @@ -841,7 +842,7 @@ public void TestImportThenReimportAfterMissingFiles() deleteBeatmapSet(imported, realmFactory.Realm); - Assert.IsTrue(imported.DeletePending); + ClassicAssert.True(imported.DeletePending); // intentionally nuke all files storage.DeleteDirectory("files"); @@ -851,10 +852,10 @@ public void TestImportThenReimportAfterMissingFiles() var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Realm); // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash. - Assert.IsTrue(imported.ID == importedSecondTime.ID); - Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); - Assert.IsFalse(imported.DeletePending); - Assert.IsFalse(importedSecondTime.DeletePending); + ClassicAssert.True(imported.ID == importedSecondTime.ID); + ClassicAssert.True(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); + ClassicAssert.False(imported.DeletePending); + ClassicAssert.False(importedSecondTime.DeletePending); // check that the files now exist, even though they were deleted above. Assert.That(importedSecondTime.Files.All(f => storage.GetStorageForDirectory("files").Exists(f.File.GetStoragePath()))); @@ -873,17 +874,17 @@ public void TestImportThenDeleteThenImportNonOptimisedPath() deleteBeatmapSet(imported, realm.Realm); - Assert.IsTrue(imported.DeletePending); + ClassicAssert.True(imported.DeletePending); var originalAddedDate = imported.DateAdded; var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm); // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash. - Assert.IsTrue(imported.ID == importedSecondTime.ID); - Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); - Assert.IsFalse(imported.DeletePending); - Assert.IsFalse(importedSecondTime.DeletePending); + ClassicAssert.True(imported.ID == importedSecondTime.ID); + ClassicAssert.True(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); + ClassicAssert.False(imported.DeletePending); + ClassicAssert.False(importedSecondTime.DeletePending); Assert.That(importedSecondTime.DateAdded, Is.GreaterThan(originalAddedDate)); }); } @@ -909,8 +910,8 @@ await realm.Realm.WriteAsync(() => var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm); // check the newly "imported" beatmap has been reimported due to mismatch (even though hashes matched) - Assert.IsTrue(imported.ID != importedSecondTime.ID); - Assert.IsTrue(imported.Beatmaps.First().ID != importedSecondTime.Beatmaps.First().ID); + ClassicAssert.True(imported.ID != importedSecondTime.ID); + ClassicAssert.True(imported.Beatmaps.First().ID != importedSecondTime.Beatmaps.First().ID); }); } @@ -954,11 +955,11 @@ public void TestImportWithDuplicateBeatmapIDs() realm.Run(r => r.Refresh()); - Assert.NotNull(imported); + ClassicAssert.NotNull(imported); Debug.Assert(imported != null); - Assert.AreEqual(-1, imported.PerformRead(s => s.Beatmaps[0].OnlineID)); - Assert.AreEqual(-1, imported.PerformRead(s => s.Beatmaps[1].OnlineID)); + ClassicAssert.AreEqual(-1, imported.PerformRead(s => s.Beatmaps[0].OnlineID)); + ClassicAssert.AreEqual(-1, imported.PerformRead(s => s.Beatmaps[1].OnlineID)); }); } @@ -975,7 +976,7 @@ public void TestImportWhenFileOpen() await importer.Import(temp); EnsureLoaded(realm.Realm); File.Delete(temp); - Assert.IsFalse(File.Exists(temp), "We likely held a read lock on the file when we shouldn't"); + ClassicAssert.False(File.Exists(temp), "We likely held a read lock on the file when we shouldn't"); }); } @@ -994,10 +995,10 @@ public void TestImportWithDuplicateHashes() try { - using (var zip = ZipArchive.Open(temp)) + using (var zip = ZipArchive.OpenArchive(temp)) zip.WriteToDirectory(extractedFolder); - using (var zip = ZipArchive.Create()) + using (var zip = ZipArchive.CreateArchive()) { zip.AddAllFromDirectory(extractedFolder); zip.AddEntry("duplicate.osu", Directory.GetFiles(extractedFolder, "*.osu").First()); @@ -1030,7 +1031,7 @@ public void TestBeatmapFilesInNestedDirectoriesAreIgnored() try { - using (var zip = ZipArchive.Open(temp)) + using (var zip = ZipArchive.OpenArchive(temp)) zip.WriteToDirectory(extractedFolder); var subdirectory = Directory.CreateDirectory(Path.Combine(extractedFolder, "subdir")); @@ -1041,7 +1042,7 @@ public void TestBeatmapFilesInNestedDirectoriesAreIgnored() using (var textWriter = new StreamWriter(stream)) await textWriter.WriteLineAsync("# adding a comment so that the hashes are different"); - using (var zip = ZipArchive.Create()) + using (var zip = ZipArchive.CreateArchive()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); @@ -1075,10 +1076,10 @@ public void TestImportNestedStructure() try { - using (var zip = ZipArchive.Open(temp)) + using (var zip = ZipArchive.OpenArchive(temp)) zip.WriteToDirectory(subfolder); - using (var zip = ZipArchive.Create()) + using (var zip = ZipArchive.CreateArchive()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); @@ -1086,12 +1087,12 @@ public void TestImportNestedStructure() var imported = await importer.Import(new ImportTask(temp)); - Assert.NotNull(imported); + ClassicAssert.NotNull(imported); Debug.Assert(imported != null); EnsureLoaded(realm.Realm); - Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("subfolder"))), "Files contain common subfolder"); + ClassicAssert.False(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("subfolder"))), "Files contain common subfolder"); } finally { @@ -1125,10 +1126,10 @@ public void TestImportWithIgnoredDirectoryInArchive() try { - using (var zip = ZipArchive.Open(temp)) + using (var zip = ZipArchive.OpenArchive(temp)) zip.WriteToDirectory(dataFolder); - using (var zip = ZipArchive.Create()) + using (var zip = ZipArchive.CreateArchive()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); @@ -1136,13 +1137,13 @@ public void TestImportWithIgnoredDirectoryInArchive() var imported = await importer.Import(new ImportTask(temp)); - Assert.NotNull(imported); + ClassicAssert.NotNull(imported); Debug.Assert(imported != null); EnsureLoaded(realm.Realm); - Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("__MACOSX"))), "Files contain resource fork folder, which should be ignored"); - Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("actual_data"))), "Files contain common subfolder"); + ClassicAssert.False(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("__MACOSX"))), "Files contain resource fork folder, which should be ignored"); + ClassicAssert.False(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("actual_data"))), "Files contain common subfolder"); } finally { @@ -1182,7 +1183,7 @@ public void TestUpdateBeatmapInfo() var importedSet = await importer.Import(new ImportTask(temp)); - Assert.NotNull(importedSet); + ClassicAssert.NotNull(importedSet); EnsureLoaded(realm); @@ -1197,7 +1198,7 @@ public static async Task LoadOszIntoStore(BeatmapImporter import var importedSet = await importer.Import(new ImportTask(temp), new ImportParameters { Batch = batchImport }); - Assert.NotNull(importedSet); + ClassicAssert.NotNull(importedSet); Debug.Assert(importedSet != null); EnsureLoaded(realm); @@ -1214,7 +1215,7 @@ private void deleteBeatmapSet(BeatmapSetInfo imported, Realm realm) checkBeatmapSetCount(realm, 0); checkBeatmapSetCount(realm, 1, true); - Assert.IsTrue(realm.All().First(_ => true).DeletePending); + ClassicAssert.True(realm.All().First(_ => true).DeletePending); } private static Task createScoreForBeatmap(Realm realm, BeatmapInfo beatmap) => @@ -1230,7 +1231,7 @@ private static Task createScoreForBeatmap(Realm realm, BeatmapInfo beatmap) => private static void checkBeatmapSetCount(Realm realm, int expected, bool includeDeletePending = false) { - Assert.AreEqual(expected, includeDeletePending + ClassicAssert.AreEqual(expected, includeDeletePending ? realm.All().Count() : realm.All().Count(s => !s.DeletePending)); } @@ -1243,7 +1244,7 @@ private static string hashFile(string filename) private static void checkBeatmapCount(Realm realm, int expected) { - Assert.AreEqual(expected, realm.All().Where(_ => true).ToList().Count); + ClassicAssert.AreEqual(expected, realm.All().Where(_ => true).ToList().Count); } private static void checkSingleReferencedFileCount(Realm realm, int expected) @@ -1256,7 +1257,7 @@ private static void checkSingleReferencedFileCount(Realm realm, int expected) singleReferencedCount++; } - Assert.AreEqual(expected, singleReferencedCount); + ClassicAssert.AreEqual(expected, singleReferencedCount); } internal static void EnsureLoaded(Realm realm, int timeout = 60000) @@ -1270,7 +1271,7 @@ internal static void EnsureLoaded(Realm realm, int timeout = 60000) }, @"BeatmapSet did not import to the database in allocated time.", timeout); // ensure we were stored to beatmap database backing... - Assert.IsTrue(resultSets?.Count() == 1, $@"Incorrect result count found ({resultSets?.Count()} but should be 1)."); + ClassicAssert.True(resultSets?.Count() == 1, $@"Incorrect result count found ({resultSets?.Count()} but should be 1)."); IEnumerable queryBeatmapSets() => realm.All().Where(s => !s.DeletePending && s.OnlineID == 241526); @@ -1279,20 +1280,20 @@ internal static void EnsureLoaded(Realm realm, int timeout = 60000) // ReSharper disable once PossibleUnintendedReferenceComparison IEnumerable queryBeatmaps() => realm.All().Where(s => s.BeatmapSet != null && s.BeatmapSet == set); - Assert.AreEqual(12, queryBeatmaps().Count(), @"Beatmap count was not correct"); - Assert.AreEqual(1, queryBeatmapSets().Count(), @"Beatmapset count was not correct"); + ClassicAssert.AreEqual(12, queryBeatmaps().Count(), @"Beatmap count was not correct"); + ClassicAssert.AreEqual(1, queryBeatmapSets().Count(), @"Beatmapset count was not correct"); int countBeatmapSetBeatmaps; int countBeatmaps; - Assert.AreEqual( + ClassicAssert.AreEqual( countBeatmapSetBeatmaps = queryBeatmapSets().First().Beatmaps.Count, countBeatmaps = queryBeatmaps().Count(), $@"Incorrect database beatmap count post-import ({countBeatmaps} but should be {countBeatmapSetBeatmaps})."); foreach (BeatmapInfo b in set.Beatmaps) - Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineID == b.OnlineID)); - Assert.IsTrue(set.Beatmaps.Count > 0); + ClassicAssert.True(set.Beatmaps.Any(c => c.OnlineID == b.OnlineID)); + ClassicAssert.True(set.Beatmaps.Count > 0); } private static void waitForOrAssert(Func result, string failureMessage, int timeout = 60000) diff --git a/osu.Game.Tests/Database/BeatmapImporterUpdateTests.cs b/osu.Game.Tests/Database/BeatmapImporterUpdateTests.cs index 3f1bc5814721..016658f68bb8 100644 --- a/osu.Game.Tests/Database/BeatmapImporterUpdateTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterUpdateTests.cs @@ -680,14 +680,14 @@ private static IDisposable getBeatmapArchiveWithModifications(out string path, A string extractedFolder = $"{path}_extracted"; Directory.CreateDirectory(extractedFolder); - using (var zip = ZipArchive.Open(path)) + using (var zip = ZipArchive.OpenArchive(path)) zip.WriteToDirectory(extractedFolder); applyModifications(new DirectoryInfo(extractedFolder)); File.Delete(path); - using (var zip = ZipArchive.Create()) + using (var zip = ZipArchive.CreateArchive()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(path, new ZipWriterOptions(CompressionType.Deflate)); diff --git a/osu.Game.Tests/Database/FileStoreTests.cs b/osu.Game.Tests/Database/FileStoreTests.cs index ab9b761b8fb7..243d4eebcd06 100644 --- a/osu.Game.Tests/Database/FileStoreTests.cs +++ b/osu.Game.Tests/Database/FileStoreTests.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Logging; using osu.Game.Database; using osu.Game.Extensions; @@ -26,8 +27,8 @@ public void TestImportFile() realm.Write(() => files.Add(testData, realm)); - Assert.True(files.Storage.Exists("0/05/054edec1d0211f624fed0cbca9d4f9400b0e491c43742af2c5b0abebf0c990d8")); - Assert.True(files.Storage.Exists(realm.All().First().GetStoragePath())); + ClassicAssert.True(files.Storage.Exists("0/05/054edec1d0211f624fed0cbca9d4f9400b0e491c43742af2c5b0abebf0c990d8")); + ClassicAssert.True(files.Storage.Exists(realm.All().First().GetStoragePath())); }); } @@ -44,7 +45,7 @@ public void TestImportSameFileTwice() realm.Write(() => files.Add(testData, realm)); realm.Write(() => files.Add(testData, realm)); - Assert.AreEqual(1, realm.All().Count()); + ClassicAssert.AreEqual(1, realm.All().Count()); }); } @@ -75,15 +76,15 @@ public void TestDontPurgeReferenced() string path = file.GetStoragePath(); - Assert.True(realm.All().Any()); - Assert.True(files.Storage.Exists(path)); + ClassicAssert.True(realm.All().Any()); + ClassicAssert.True(files.Storage.Exists(path)); files.Cleanup(); Logger.Log($"Cleanup complete at {timer.ElapsedMilliseconds}"); - Assert.True(realm.All().Any()); - Assert.True(file.IsValid); - Assert.True(files.Storage.Exists(path)); + ClassicAssert.True(realm.All().Any()); + ClassicAssert.True(file.IsValid); + ClassicAssert.True(files.Storage.Exists(path)); }); } @@ -99,14 +100,14 @@ public void TestPurgeUnreferenced() string path = file.GetStoragePath(); - Assert.True(realm.All().Any()); - Assert.True(files.Storage.Exists(path)); + ClassicAssert.True(realm.All().Any()); + ClassicAssert.True(files.Storage.Exists(path)); files.Cleanup(); - Assert.False(realm.All().Any()); - Assert.False(file.IsValid); - Assert.False(files.Storage.Exists(path)); + ClassicAssert.False(realm.All().Any()); + ClassicAssert.False(file.IsValid); + ClassicAssert.False(files.Storage.Exists(path)); }); } } diff --git a/osu.Game.Tests/Database/GeneralUsageTests.cs b/osu.Game.Tests/Database/GeneralUsageTests.cs index b8073a65bc15..3550d39ab8b5 100644 --- a/osu.Game.Tests/Database/GeneralUsageTests.cs +++ b/osu.Game.Tests/Database/GeneralUsageTests.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Extensions; using osu.Game.Beatmaps; using osu.Game.Database; @@ -143,7 +144,7 @@ public void TestNestedContextCreationWithSubscription() return null; }); - Assert.IsTrue(callbackRan); + ClassicAssert.True(callbackRan); }); } diff --git a/osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs b/osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs index 016928c6d610..80be6fcfef54 100644 --- a/osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs +++ b/osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs @@ -7,6 +7,7 @@ using System.IO.Compression; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps; @@ -93,8 +94,8 @@ public void TestStableDateAddedApplied() var importedSet = realm.Realm.All().Single(); - Assert.NotNull(importedSet); - Assert.AreEqual(new DateTimeOffset(new DateTime(2000, 1, 1, 12, 0, 0, DateTimeKind.Utc)), importedSet.DateAdded); + ClassicAssert.NotNull(importedSet); + ClassicAssert.AreEqual(new DateTimeOffset(new DateTime(2000, 1, 1, 12, 0, 0, DateTimeKind.Utc)), importedSet.DateAdded); } }); } diff --git a/osu.Game.Tests/Database/RealmLiveTests.cs b/osu.Game.Tests/Database/RealmLiveTests.cs index cea30acf3f78..5035ff68c99d 100644 --- a/osu.Game.Tests/Database/RealmLiveTests.cs +++ b/osu.Game.Tests/Database/RealmLiveTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading.Tasks; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Extensions; using osu.Framework.Testing; using osu.Game.Beatmaps; @@ -25,7 +26,7 @@ public void TestLiveEquality() Live beatmap2 = realm.Run(r => r.All().First().ToLive(realm)); - Assert.AreEqual(beatmap, beatmap2); + ClassicAssert.AreEqual(beatmap, beatmap2); }); } @@ -52,7 +53,7 @@ public void TestAccessAfterStorageMigrate() using (realm.BlockAllOperations("testing")) storage.Migrate(migratedStorage); - Assert.IsFalse(liveBeatmap?.PerformRead(l => l.Hidden)); + ClassicAssert.False(liveBeatmap?.PerformRead(l => l.Hidden)); }); } } @@ -111,7 +112,7 @@ public void TestNestedWriteCalls() r.Add(beatmap))) ); - Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden)); + ClassicAssert.False(liveBeatmap.PerformRead(l => l.Hidden)); }); } @@ -126,7 +127,7 @@ public void TestAccessAfterAttach() realm.Run(r => r.Write(_ => r.Add(beatmap))); - Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden)); + ClassicAssert.False(liveBeatmap.PerformRead(l => l.Hidden)); }); } @@ -136,15 +137,15 @@ public void TestAccessNonManaged() var beatmap = new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata()); var liveBeatmap = beatmap.ToLiveUnmanaged(); - Assert.IsFalse(beatmap.Hidden); - Assert.IsFalse(liveBeatmap.Value.Hidden); - Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden)); + ClassicAssert.False(beatmap.Hidden); + ClassicAssert.False(liveBeatmap.Value.Hidden); + ClassicAssert.False(liveBeatmap.PerformRead(l => l.Hidden)); Assert.Throws(() => liveBeatmap.PerformWrite(l => l.Hidden = true)); - Assert.IsFalse(beatmap.Hidden); - Assert.IsFalse(liveBeatmap.Value.Hidden); - Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden)); + ClassicAssert.False(beatmap.Hidden); + ClassicAssert.False(liveBeatmap.Value.Hidden); + ClassicAssert.False(liveBeatmap.PerformRead(l => l.Hidden)); } [Test] @@ -159,10 +160,10 @@ public void TestTransactionRolledBackOnException() var liveBeatmap = beatmap.ToLive(realm); Assert.Throws(() => liveBeatmap.PerformWrite(l => throw new InvalidOperationException())); - Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden)); + ClassicAssert.False(liveBeatmap.PerformRead(l => l.Hidden)); liveBeatmap.PerformWrite(l => l.Hidden = true); - Assert.IsTrue(liveBeatmap.PerformRead(l => l.Hidden)); + ClassicAssert.True(liveBeatmap.PerformRead(l => l.Hidden)); }); } @@ -188,8 +189,8 @@ public void TestScopedReadWithoutContext() { liveBeatmap.PerformRead(beatmap => { - Assert.IsTrue(beatmap.IsValid); - Assert.IsFalse(beatmap.Hidden); + ClassicAssert.True(beatmap.IsValid); + ClassicAssert.False(beatmap.Hidden); }); }, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely(); }); @@ -216,7 +217,7 @@ public void TestScopedWriteWithoutContext() Task.Factory.StartNew(() => { liveBeatmap.PerformWrite(beatmap => { beatmap.Hidden = true; }); - liveBeatmap.PerformRead(beatmap => { Assert.IsTrue(beatmap.Hidden); }); + liveBeatmap.PerformRead(beatmap => { ClassicAssert.True(beatmap.Hidden); }); }, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely(); }); } @@ -333,17 +334,17 @@ public void TestLiveAssumptions() Debug.Assert(liveBeatmap != null); // not yet seen by main context - Assert.AreEqual(0, outerRealm.All().Count()); - Assert.AreEqual(0, changesTriggered); + ClassicAssert.AreEqual(0, outerRealm.All().Count()); + ClassicAssert.AreEqual(0, changesTriggered); liveBeatmap.PerformRead(resolved => { // retrieval causes an implicit refresh. even changes that aren't related to the retrieval are fired at this point. - Assert.AreEqual(2, outerRealm.All().Count()); - Assert.AreEqual(1, changesTriggered); + ClassicAssert.AreEqual(2, outerRealm.All().Count()); + ClassicAssert.AreEqual(1, changesTriggered); // can access properties without a crash. - Assert.IsFalse(resolved.Hidden); + ClassicAssert.False(resolved.Hidden); outerRealm.Write(r => { diff --git a/osu.Game.Tests/Database/RulesetStoreTests.cs b/osu.Game.Tests/Database/RulesetStoreTests.cs index 7ef2429491c5..c8e2a42d8179 100644 --- a/osu.Game.Tests/Database/RulesetStoreTests.cs +++ b/osu.Game.Tests/Database/RulesetStoreTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Catch; @@ -27,8 +28,8 @@ public void TestCreateStore() { using var rulesets = new RealmRulesetStore(realm, storage); - Assert.AreEqual(4, rulesets.AvailableRulesets.Count()); - Assert.AreEqual(4, realm.Realm.All().Count()); + ClassicAssert.AreEqual(4, rulesets.AvailableRulesets.Count()); + ClassicAssert.AreEqual(4, realm.Realm.All().Count()); }); } @@ -40,11 +41,11 @@ public void TestCreateStoreTwiceDoesntAddRulesetsAgain() using var rulesets = new RealmRulesetStore(realm, storage); using var rulesets2 = new RealmRulesetStore(realm, storage); - Assert.AreEqual(4, rulesets.AvailableRulesets.Count()); - Assert.AreEqual(4, rulesets2.AvailableRulesets.Count()); + ClassicAssert.AreEqual(4, rulesets.AvailableRulesets.Count()); + ClassicAssert.AreEqual(4, rulesets2.AvailableRulesets.Count()); - Assert.AreEqual(rulesets.AvailableRulesets.First(), rulesets2.AvailableRulesets.First()); - Assert.AreEqual(4, realm.Realm.All().Count()); + ClassicAssert.AreEqual(rulesets.AvailableRulesets.First(), rulesets2.AvailableRulesets.First()); + ClassicAssert.AreEqual(4, realm.Realm.All().Count()); }); } @@ -55,9 +56,9 @@ public void TestRetrievedRulesetsAreDetached() { using var rulesets = new RealmRulesetStore(realm, storage); - Assert.IsFalse(rulesets.AvailableRulesets.First().IsManaged); - Assert.IsFalse(rulesets.GetRuleset(0)?.IsManaged); - Assert.IsFalse(rulesets.GetRuleset("mania")?.IsManaged); + ClassicAssert.False(rulesets.AvailableRulesets.First().IsManaged); + ClassicAssert.False(rulesets.GetRuleset(0)?.IsManaged); + ClassicAssert.False(rulesets.GetRuleset("mania")?.IsManaged); }); } diff --git a/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs b/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs index e2774cef006e..004a89ddecdb 100644 --- a/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs +++ b/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs @@ -3,14 +3,11 @@ #nullable disable -using System; using System.Collections.Generic; -using System.IO; using System.Linq; using NUnit.Framework; using osu.Framework.Input; using osu.Framework.Input.Bindings; -using osu.Framework.Platform; using osu.Game.Database; using osu.Game.Input; using osu.Game.Input.Bindings; @@ -20,107 +17,95 @@ namespace osu.Game.Tests.Database { [TestFixture] - public partial class TestRealmKeyBindingStore + public partial class TestRealmKeyBindingStore : RealmTest { - private NativeStorage storage; - - private RealmKeyBindingStore keyBindingStore; - - private RealmAccess realm; - - [SetUp] - public void SetUp() - { - var directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())); - - storage = new NativeStorage(directory.FullName); - - realm = new RealmAccess(storage, "test"); - keyBindingStore = new RealmKeyBindingStore(realm, new ReadableKeyCombinationProvider()); - } - [Test] public void TestDefaultsPopulationAndQuery() { - Assert.That(queryCount(), Is.EqualTo(0)); + RunTestWithRealm((realm, _) => + { + Assert.That(queryCount(realm), Is.EqualTo(0)); - KeyBindingContainer testContainer = new TestKeyBindingContainer(); + KeyBindingContainer testContainer = new TestKeyBindingContainer(); - keyBindingStore.Register(testContainer, Enumerable.Empty()); + var keyBindingStore = new RealmKeyBindingStore(realm, new ReadableKeyCombinationProvider()); + keyBindingStore.Register(testContainer, Enumerable.Empty()); - Assert.That(queryCount(), Is.EqualTo(3)); + Assert.That(queryCount(realm), Is.EqualTo(3)); - Assert.That(queryCount(GlobalAction.Back), Is.EqualTo(1)); - Assert.That(queryCount(GlobalAction.Select), Is.EqualTo(2)); + Assert.That(queryCount(realm, GlobalAction.Back), Is.EqualTo(1)); + Assert.That(queryCount(realm, GlobalAction.Select), Is.EqualTo(2)); + }); } [Test] public void TestDefaultsPopulationRemovesExcess() { - Assert.That(queryCount(), Is.EqualTo(0)); - - KeyBindingContainer testContainer = new TestKeyBindingContainer(); - - // Add some excess bindings for an action which only supports 1. - realm.Write(r => + RunTestWithRealm((realm, _) => { - r.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.A))); - r.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.S))); - r.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.D))); - }); + Assert.That(queryCount(realm), Is.EqualTo(0)); - Assert.That(queryCount(GlobalAction.Back), Is.EqualTo(3)); + KeyBindingContainer testContainer = new TestKeyBindingContainer(); - keyBindingStore.Register(testContainer, Enumerable.Empty()); + // Add some excess bindings for an action which only supports 1. + realm.Write(r => + { + r.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.A))); + r.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.S))); + r.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.D))); + }); - Assert.That(queryCount(GlobalAction.Back), Is.EqualTo(1)); - } + Assert.That(queryCount(realm, GlobalAction.Back), Is.EqualTo(3)); - private int queryCount(GlobalAction? match = null) - { - return realm.Run(r => - { - var results = r.All(); - if (match.HasValue) - results = results.Where(k => k.ActionInt == (int)match.Value); - return results.Count(); + var keyBindingStore = new RealmKeyBindingStore(realm, new ReadableKeyCombinationProvider()); + keyBindingStore.Register(testContainer, Enumerable.Empty()); + + Assert.That(queryCount(realm, GlobalAction.Back), Is.EqualTo(1)); }); } [Test] public void TestUpdateViaQueriedReference() { - KeyBindingContainer testContainer = new TestKeyBindingContainer(); + RunTestWithRealm((realm, _) => + { + KeyBindingContainer testContainer = new TestKeyBindingContainer(); - keyBindingStore.Register(testContainer, Enumerable.Empty()); + var keyBindingStore = new RealmKeyBindingStore(realm, new ReadableKeyCombinationProvider()); + keyBindingStore.Register(testContainer, Enumerable.Empty()); - realm.Run(outerRealm => - { - var backBinding = outerRealm.All().Single(k => k.ActionInt == (int)GlobalAction.Back); + realm.Run(outerRealm => + { + var backBinding = outerRealm.All().Single(k => k.ActionInt == (int)GlobalAction.Back); - Assert.That(backBinding.KeyCombination.Keys, Is.EquivalentTo(new[] { InputKey.Escape })); + Assert.That(backBinding.KeyCombination.Keys, Is.EquivalentTo(new[] { InputKey.Escape })); - var tsr = ThreadSafeReference.Create(backBinding); + var tsr = ThreadSafeReference.Create(backBinding); - realm.Run(innerRealm => - { - var binding = innerRealm.ResolveReference(tsr)!; - innerRealm.Write(() => binding.KeyCombination = new KeyCombination(InputKey.BackSpace)); - }); + realm.Run(innerRealm => + { + var binding = innerRealm.ResolveReference(tsr)!; + innerRealm.Write(() => binding.KeyCombination = new KeyCombination(InputKey.BackSpace)); + }); - Assert.That(backBinding.KeyCombination.Keys, Is.EquivalentTo(new[] { InputKey.BackSpace })); + Assert.That(backBinding.KeyCombination.Keys, Is.EquivalentTo(new[] { InputKey.BackSpace })); - // check still correct after re-query. - backBinding = outerRealm.All().Single(k => k.ActionInt == (int)GlobalAction.Back); - Assert.That(backBinding.KeyCombination.Keys, Is.EquivalentTo(new[] { InputKey.BackSpace })); + // check still correct after re-query. + backBinding = outerRealm.All().Single(k => k.ActionInt == (int)GlobalAction.Back); + Assert.That(backBinding.KeyCombination.Keys, Is.EquivalentTo(new[] { InputKey.BackSpace })); + }); }); } - [TearDown] - public void TearDown() + private static int queryCount(RealmAccess realm, GlobalAction? match = null) { - realm.Dispose(); - storage.DeleteDirectory(string.Empty); + return realm.Run(r => + { + var results = r.All(); + if (match.HasValue) + results = results.Where(k => k.ActionInt == (int)match.Value); + return results.Count(); + }); } public partial class TestKeyBindingContainer : KeyBindingContainer diff --git a/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs b/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs index 9774a8ebb69c..ac04f6c4ffb2 100644 --- a/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs @@ -5,6 +5,7 @@ using System.Linq; using Moq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Checks; @@ -44,7 +45,7 @@ public void Setup() public void TestRegularVideoFile() { using (var resourceStream = TestResources.OpenResource("Videos/test-video.mp4")) - Assert.IsEmpty(check.Run(getContext(resourceStream))); + ClassicAssert.IsEmpty(check.Run(getContext(resourceStream))); } [Test] @@ -88,7 +89,7 @@ private BeatmapVerifierContext getContext(Stream? resourceStream) var layer = storyboard.GetLayer("Video"); layer.Add(new StoryboardVideo("abc123.mp4", 0)); - var mockWorkingBeatmap = new Mock(beatmap, null, null); + var mockWorkingBeatmap = new Mock(beatmap, null!, null!); mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns(resourceStream); mockWorkingBeatmap.As().SetupGet(w => w.Storyboard).Returns(storyboard); diff --git a/osu.Game.Tests/Editing/Checks/CheckDelayedHitsoundsTest.cs b/osu.Game.Tests/Editing/Checks/CheckDelayedHitsoundsTest.cs index 20b9643ab449..1cc89587a210 100644 --- a/osu.Game.Tests/Editing/Checks/CheckDelayedHitsoundsTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckDelayedHitsoundsTest.cs @@ -6,6 +6,7 @@ using ManagedBass; using Moq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps; using osu.Game.Models; using osu.Game.Rulesets.Edit; @@ -49,7 +50,7 @@ public void SetUp() public void TestNoDelayedHitsounds() { using var resourceStream = TestResources.OpenResource("Samples/hitsound-no-delay.wav"); - Assert.IsEmpty(check.Run(getContext(resourceStream))); + ClassicAssert.IsEmpty(check.Run(getContext(resourceStream))); } [Test] @@ -96,7 +97,7 @@ public void TestConsequentlyDelayedHitsounds() private BeatmapVerifierContext getContext(Stream? resourceStream) { - var mockWorkingBeatmap = new Mock(beatmap, null, null); + var mockWorkingBeatmap = new Mock(beatmap, null!, null!); mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns(resourceStream); return new BeatmapVerifierContext(beatmap, mockWorkingBeatmap.Object); diff --git a/osu.Game.Tests/Editing/Checks/CheckHitsoundsFormatTest.cs b/osu.Game.Tests/Editing/Checks/CheckHitsoundsFormatTest.cs index 6da391aa8dd4..0a6e0455926d 100644 --- a/osu.Game.Tests/Editing/Checks/CheckHitsoundsFormatTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckHitsoundsFormatTest.cs @@ -139,7 +139,7 @@ public void TestBeatmapAudioTracksExemptedFromCheck() Metadata = new BeatmapMetadata { AudioFile = beatmapSet.Files[0].Filename } } }; - var firstWorking = new Mock(firstPlayable, null, null); + var firstWorking = new Mock(firstPlayable, null!, null!); firstWorking.Setup(w => w.GetStream(It.IsAny())).Returns(resourceStream); var secondPlayable = new Beatmap @@ -150,7 +150,7 @@ public void TestBeatmapAudioTracksExemptedFromCheck() Metadata = new BeatmapMetadata { AudioFile = beatmapSet.Files[1].Filename } } }; - var secondWorking = new Mock(secondPlayable, null, null); + var secondWorking = new Mock(secondPlayable, null!, null!); secondWorking.Setup(w => w.GetStream(It.IsAny())).Returns(resourceStream); var context = new BeatmapVerifierContext( @@ -165,7 +165,7 @@ [new BeatmapVerifierContext.VerifiedBeatmap(secondWorking.Object, secondPlayable private BeatmapVerifierContext getContext(Stream? resourceStream) { - var mockWorkingBeatmap = new Mock(beatmap, null, null); + var mockWorkingBeatmap = new Mock(beatmap, null!, null!); mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns(resourceStream); return new BeatmapVerifierContext(beatmap, mockWorkingBeatmap.Object); diff --git a/osu.Game.Tests/Editing/Checks/CheckSongFormatTest.cs b/osu.Game.Tests/Editing/Checks/CheckSongFormatTest.cs index 98a4e1f9e95b..aab634a47f8f 100644 --- a/osu.Game.Tests/Editing/Checks/CheckSongFormatTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckSongFormatTest.cs @@ -103,7 +103,7 @@ public void TestCorruptAudio() private BeatmapVerifierContext getContext(Stream? resourceStream) { - var mockWorkingBeatmap = new Mock(beatmap, null, null); + var mockWorkingBeatmap = new Mock(beatmap, null!, null!); mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns(resourceStream); return new BeatmapVerifierContext(beatmap, mockWorkingBeatmap.Object); diff --git a/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs b/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs index b646e639556f..5ff786825b17 100644 --- a/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs @@ -7,6 +7,7 @@ using ManagedBass; using Moq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Checks; @@ -52,7 +53,7 @@ public void TestDifferentExtension() beatmap.BeatmapInfo.BeatmapSet.Files.Add(CheckTestHelpers.CreateMockFile("jpg")); // Should fail to load, but not produce an error due to the extension not being expected to load. - Assert.IsEmpty(check.Run(getContext(null))); + ClassicAssert.IsEmpty(check.Run(getContext(null))); } [Test] @@ -60,7 +61,7 @@ public void TestRegularAudioFile() { using (var resourceStream = TestResources.OpenResource("Samples/test-sample.mp3")) { - Assert.IsEmpty(check.Run(getContext(resourceStream))); + ClassicAssert.IsEmpty(check.Run(getContext(resourceStream))); } } @@ -70,7 +71,7 @@ public void TestBlankAudioFile() using (var resourceStream = TestResources.OpenResource("Samples/blank.wav")) { // This is a 0 ms duration audio file, commonly used to silence sliderslides/ticks, and so should be fine. - Assert.IsEmpty(check.Run(getContext(resourceStream))); + ClassicAssert.IsEmpty(check.Run(getContext(resourceStream))); } } @@ -91,13 +92,13 @@ public void TestMissingAudioFile() { using (var resourceStream = TestResources.OpenResource("Samples/missing.mp3")) { - Assert.IsEmpty(check.Run(getContext(resourceStream))); + ClassicAssert.IsEmpty(check.Run(getContext(resourceStream))); } } private BeatmapVerifierContext getContext(Stream? resourceStream) { - var mockWorkingBeatmap = new Mock(beatmap, null, null); + var mockWorkingBeatmap = new Mock(beatmap, null!, null!); mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns(resourceStream); return new BeatmapVerifierContext(beatmap, mockWorkingBeatmap.Object); diff --git a/osu.Game.Tests/Editing/Checks/CheckVideoResolutionTest.cs b/osu.Game.Tests/Editing/Checks/CheckVideoResolutionTest.cs index 1e16c67aabc6..3241e489f8da 100644 --- a/osu.Game.Tests/Editing/Checks/CheckVideoResolutionTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckVideoResolutionTest.cs @@ -79,7 +79,7 @@ private BeatmapVerifierContext getContext(Stream? resourceStream) var layer = storyboard.GetLayer("Video"); layer.Add(new StoryboardVideo("abc123.mp4", 0)); - var mockWorkingBeatmap = new Mock(beatmap, null, null); + var mockWorkingBeatmap = new Mock(beatmap, null!, null!); mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns(resourceStream); mockWorkingBeatmap.As().SetupGet(w => w.Storyboard).Returns(storyboard); diff --git a/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs b/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs index a39ef22b723f..1235292511b4 100644 --- a/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs @@ -5,6 +5,7 @@ using System.Linq; using Moq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Checks; @@ -40,7 +41,7 @@ public void Setup() [Test] public void TestNonZeroBytes() { - Assert.IsEmpty(check.Run(getContext(byteLength: 44))); + ClassicAssert.IsEmpty(check.Run(getContext(byteLength: 44))); } [Test] @@ -55,7 +56,7 @@ public void TestZeroBytes() [Test] public void TestMissing() { - Assert.IsEmpty(check.Run(getContextMissing())); + ClassicAssert.IsEmpty(check.Run(getContextMissing())); } private BeatmapVerifierContext getContext(long byteLength) diff --git a/osu.Game.Tests/ImportTest.cs b/osu.Game.Tests/ImportTest.cs index b1e2730703d7..4272e34d0744 100644 --- a/osu.Game.Tests/ImportTest.cs +++ b/osu.Game.Tests/ImportTest.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Platform; @@ -42,7 +43,7 @@ private void waitForOrAssert(Func result, string failureMessage, int timeo while (!result()) Thread.Sleep(200); }); - Assert.IsTrue(task.Wait(timeout), failureMessage); + ClassicAssert.True(task.Wait(timeout), failureMessage); } public partial class TestOsuGameBase : OsuGameBase diff --git a/osu.Game.Tests/Localisation/BeatmapMetadataRomanisationTest.cs b/osu.Game.Tests/Localisation/BeatmapMetadataRomanisationTest.cs index 9926acf77213..0a4a4e50a778 100644 --- a/osu.Game.Tests/Localisation/BeatmapMetadataRomanisationTest.cs +++ b/osu.Game.Tests/Localisation/BeatmapMetadataRomanisationTest.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps; namespace osu.Game.Tests.Localisation @@ -21,8 +22,8 @@ public void TestRomanisation() }; var romanisableString = metadata.GetDisplayTitleRomanisable(); - Assert.AreEqual(metadata.ToString(), romanisableString.Romanised); - Assert.AreEqual($"{metadata.ArtistUnicode} - {metadata.TitleUnicode}", romanisableString.Original); + ClassicAssert.AreEqual(metadata.ToString(), romanisableString.Romanised); + ClassicAssert.AreEqual($"{metadata.ArtistUnicode} - {metadata.TitleUnicode}", romanisableString.Original); } [Test] @@ -35,7 +36,7 @@ public void TestRomanisationNoUnicode() }; var romanisableString = metadata.GetDisplayTitleRomanisable(); - Assert.AreEqual(romanisableString.Romanised, romanisableString.Original); + ClassicAssert.AreEqual(romanisableString.Romanised, romanisableString.Original); } } } diff --git a/osu.Game.Tests/Mods/ModUtilsTest.cs b/osu.Game.Tests/Mods/ModUtilsTest.cs index 6ec4e799e62d..b05b4c00b95c 100644 --- a/osu.Game.Tests/Mods/ModUtilsTest.cs +++ b/osu.Game.Tests/Mods/ModUtilsTest.cs @@ -6,6 +6,7 @@ using System.Linq; using Moq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Localisation; using osu.Game.Online.Rooms; @@ -196,7 +197,7 @@ public void TestInvalidModScenarios(Mod[] inputMods, Type[] expectedInvalid) Assert.That(isValid, Is.EqualTo(expectedInvalid.Length == 0)); if (isValid) - Assert.IsNull(invalid); + ClassicAssert.Null(invalid); else Assert.That(invalid?.Select(t => t.GetType()), Is.EquivalentTo(expectedInvalid)); } @@ -214,21 +215,21 @@ public void TestModBelongsToRuleset() [Test] public void TestFormatScoreMultiplier() { - Assert.AreEqual(ModUtils.FormatScoreMultiplier(0.9999).ToString(), "0.99x"); - Assert.AreEqual(ModUtils.FormatScoreMultiplier(1.0).ToString(), "1.00x"); - Assert.AreEqual(ModUtils.FormatScoreMultiplier(1.0001).ToString(), "1.01x"); + ClassicAssert.AreEqual(ModUtils.FormatScoreMultiplier(0.9999).ToString(), "0.99x"); + ClassicAssert.AreEqual(ModUtils.FormatScoreMultiplier(1.0).ToString(), "1.00x"); + ClassicAssert.AreEqual(ModUtils.FormatScoreMultiplier(1.0001).ToString(), "1.01x"); - Assert.AreEqual(ModUtils.FormatScoreMultiplier(0.899999999999999).ToString(), "0.90x"); - Assert.AreEqual(ModUtils.FormatScoreMultiplier(0.9).ToString(), "0.90x"); - Assert.AreEqual(ModUtils.FormatScoreMultiplier(0.900000000000001).ToString(), "0.90x"); + ClassicAssert.AreEqual(ModUtils.FormatScoreMultiplier(0.899999999999999).ToString(), "0.90x"); + ClassicAssert.AreEqual(ModUtils.FormatScoreMultiplier(0.9).ToString(), "0.90x"); + ClassicAssert.AreEqual(ModUtils.FormatScoreMultiplier(0.900000000000001).ToString(), "0.90x"); - Assert.AreEqual(ModUtils.FormatScoreMultiplier(1.099999999999999).ToString(), "1.10x"); - Assert.AreEqual(ModUtils.FormatScoreMultiplier(1.1).ToString(), "1.10x"); - Assert.AreEqual(ModUtils.FormatScoreMultiplier(1.100000000000001).ToString(), "1.10x"); + ClassicAssert.AreEqual(ModUtils.FormatScoreMultiplier(1.099999999999999).ToString(), "1.10x"); + ClassicAssert.AreEqual(ModUtils.FormatScoreMultiplier(1.1).ToString(), "1.10x"); + ClassicAssert.AreEqual(ModUtils.FormatScoreMultiplier(1.100000000000001).ToString(), "1.10x"); - Assert.AreEqual(ModUtils.FormatScoreMultiplier(1.045).ToString(), "1.05x"); - Assert.AreEqual(ModUtils.FormatScoreMultiplier(1.05).ToString(), "1.05x"); - Assert.AreEqual(ModUtils.FormatScoreMultiplier(1.055).ToString(), "1.06x"); + ClassicAssert.AreEqual(ModUtils.FormatScoreMultiplier(1.045).ToString(), "1.05x"); + ClassicAssert.AreEqual(ModUtils.FormatScoreMultiplier(1.05).ToString(), "1.05x"); + ClassicAssert.AreEqual(ModUtils.FormatScoreMultiplier(1.055).ToString(), "1.06x"); } private static readonly object[] multiplayer_mod_test_scenarios = @@ -309,7 +310,7 @@ public void TestMultiplayerModScenarios(MultiplayerTestScenario scenario) Assert.That(isValid, Is.EqualTo(scenario.InvalidTypes.Length == 0)); if (isValid) - Assert.IsNull(invalidMods); + ClassicAssert.Null(invalidMods); else Assert.That(invalidMods?.Select(t => t.GetType()), Is.EquivalentTo(scenario.InvalidTypes)); } @@ -318,12 +319,12 @@ public void TestMultiplayerModScenarios(MultiplayerTestScenario scenario) public void TestPlaylistsModScenarios() { // The rest are tested by TestMultiplayerModScenarios. - Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModHardRock(), false, MatchType.Playlists, false)); - Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModHardRock(), true, MatchType.Playlists, false)); - Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModDoubleTime(), false, MatchType.Playlists, false)); - Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModDoubleTime(), true, MatchType.Playlists, false)); - Assert.IsTrue(ModUtils.IsValidModForMatch(new ModAdaptiveSpeed(), false, MatchType.Playlists, false)); - Assert.IsTrue(ModUtils.IsValidModForMatch(new ModAdaptiveSpeed(), true, MatchType.Playlists, false)); + ClassicAssert.True(ModUtils.IsValidModForMatch(new OsuModHardRock(), false, MatchType.Playlists, false)); + ClassicAssert.True(ModUtils.IsValidModForMatch(new OsuModHardRock(), true, MatchType.Playlists, false)); + ClassicAssert.True(ModUtils.IsValidModForMatch(new OsuModDoubleTime(), false, MatchType.Playlists, false)); + ClassicAssert.True(ModUtils.IsValidModForMatch(new OsuModDoubleTime(), true, MatchType.Playlists, false)); + ClassicAssert.True(ModUtils.IsValidModForMatch(new ModAdaptiveSpeed(), false, MatchType.Playlists, false)); + ClassicAssert.True(ModUtils.IsValidModForMatch(new ModAdaptiveSpeed(), true, MatchType.Playlists, false)); } [Test] diff --git a/osu.Game.Tests/NonVisual/BarLineGeneratorTest.cs b/osu.Game.Tests/NonVisual/BarLineGeneratorTest.cs index 0f5c13ca0ed9..e3be681a918b 100644 --- a/osu.Game.Tests/NonVisual/BarLineGeneratorTest.cs +++ b/osu.Game.Tests/NonVisual/BarLineGeneratorTest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -54,13 +55,13 @@ public void TestRoundingErrorCompensation() // every seventh bar's start time should be at least greater than the whole number we expect. // It cannot be less, as that can affect overlapping scroll algorithms // (the previous timing point might be chosen incorrectly if this is not the case) - Assert.GreaterOrEqual(barLine.StartTime, expectedTime); + ClassicAssert.GreaterOrEqual(barLine.StartTime, expectedTime); // on the other side, make sure we don't stray too far from the expected time either. - Assert.IsTrue(Precision.AlmostEquals(barLine.StartTime, expectedTime)); + ClassicAssert.True(Precision.AlmostEquals(barLine.StartTime, expectedTime)); // check major/minor lines for good measure too - Assert.AreEqual(i % signature.Numerator == 0, barLine.Major); + ClassicAssert.AreEqual(i % signature.Numerator == 0, barLine.Major); } } diff --git a/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs index a229331ef093..574d07ec02d8 100644 --- a/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs +++ b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs @@ -6,6 +6,7 @@ using System; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps; using osu.Game.Extensions; using osu.Game.Models; @@ -22,8 +23,8 @@ public void TestOnlineWithOnline() var ourInfo = new BeatmapSetInfo { OnlineID = 123 }; var otherInfo = new BeatmapSetInfo { OnlineID = 123 }; - Assert.AreNotEqual(ourInfo, otherInfo); - Assert.IsTrue(ourInfo.MatchesOnlineID(otherInfo)); + ClassicAssert.AreNotEqual(ourInfo, otherInfo); + ClassicAssert.True(ourInfo.MatchesOnlineID(otherInfo)); } [Test] @@ -32,8 +33,8 @@ public void TestAudioEqualityNoFile() var beatmapSetA = TestResources.CreateTestBeatmapSetInfo(1); var beatmapSetB = TestResources.CreateTestBeatmapSetInfo(1); - Assert.AreNotEqual(beatmapSetA, beatmapSetB); - Assert.IsTrue(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single())); + ClassicAssert.AreNotEqual(beatmapSetA, beatmapSetB); + ClassicAssert.True(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single())); } [Test] @@ -49,8 +50,8 @@ public void TestAudioEqualityCaseSensitivity() addAudioFile(beatmapSetA, "abc", "AuDiO.mP3"); addAudioFile(beatmapSetB, "abc", "audio.mp3"); - Assert.AreNotEqual(beatmapSetA, beatmapSetB); - Assert.IsTrue(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single())); + ClassicAssert.AreNotEqual(beatmapSetA, beatmapSetB); + ClassicAssert.True(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single())); } [Test] @@ -62,8 +63,8 @@ public void TestAudioEqualitySameHash() addAudioFile(beatmapSetA, "abc"); addAudioFile(beatmapSetB, "abc"); - Assert.AreNotEqual(beatmapSetA, beatmapSetB); - Assert.IsTrue(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single())); + ClassicAssert.AreNotEqual(beatmapSetA, beatmapSetB); + ClassicAssert.True(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single())); } [Test] @@ -75,8 +76,8 @@ public void TestAudioEqualityDifferentHash() addAudioFile(beatmapSetA); addAudioFile(beatmapSetB); - Assert.AreNotEqual(beatmapSetA, beatmapSetB); - Assert.IsTrue(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single())); + ClassicAssert.AreNotEqual(beatmapSetA, beatmapSetB); + ClassicAssert.True(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single())); } [Test] @@ -89,8 +90,8 @@ public void TestAudioEqualityBeatmapInfoSameHash() var beatmap1 = beatmapSet.Beatmaps.First(); var beatmap2 = beatmapSet.Beatmaps.Last(); - Assert.AreNotEqual(beatmap1, beatmap2); - Assert.IsTrue(beatmap1.AudioEquals(beatmap2)); + ClassicAssert.AreNotEqual(beatmap1, beatmap2); + ClassicAssert.True(beatmap1.AudioEquals(beatmap2)); } [Test] @@ -107,12 +108,12 @@ public void TestAudioEqualityBeatmapInfoDifferentHash() var beatmap1 = beatmapSet.Beatmaps.First(); var beatmap2 = beatmapSet.Beatmaps.Last(); - Assert.AreNotEqual(beatmap1, beatmap2); + ClassicAssert.AreNotEqual(beatmap1, beatmap2); beatmap1.Metadata.AudioFile = filename1; beatmap2.Metadata.AudioFile = filename2; - Assert.IsFalse(beatmap1.AudioEquals(beatmap2)); + ClassicAssert.False(beatmap1.AudioEquals(beatmap2)); } private static void addAudioFile(BeatmapSetInfo beatmapSetInfo, string hash = null, string filename = null) @@ -128,7 +129,7 @@ public void TestDatabasedWithDatabased() var ourInfo = new BeatmapSetInfo { ID = guid }; var otherInfo = new BeatmapSetInfo { ID = guid }; - Assert.AreEqual(ourInfo, otherInfo); + ClassicAssert.AreEqual(ourInfo, otherInfo); } [Test] @@ -137,8 +138,8 @@ public void TestDatabasedWithOnline() var ourInfo = new BeatmapSetInfo { ID = Guid.NewGuid(), OnlineID = 12 }; var otherInfo = new BeatmapSetInfo { OnlineID = 12 }; - Assert.AreNotEqual(ourInfo, otherInfo); - Assert.IsTrue(ourInfo.MatchesOnlineID(otherInfo)); + ClassicAssert.AreNotEqual(ourInfo, otherInfo); + ClassicAssert.True(ourInfo.MatchesOnlineID(otherInfo)); } [Test] @@ -147,7 +148,7 @@ public void TestCheckNullID() var ourInfo = new BeatmapSetInfo { Hash = "1" }; var otherInfo = new BeatmapSetInfo { Hash = "2" }; - Assert.AreNotEqual(ourInfo, otherInfo); + ClassicAssert.AreNotEqual(ourInfo, otherInfo); } } } diff --git a/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs b/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs index a563bcd865e9..0da3041887ff 100644 --- a/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs +++ b/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects; @@ -97,7 +98,7 @@ private static void assertClosestDivisors(IReadOnlyList divisors, IReadO }; for (int i = 0; i < divisors.Count; ++i) - Assert.AreEqual(closestDivisors[i], beatmap.ControlPointInfo.GetClosestBeatDivisor(beatmap.HitObjects[i].StartTime), $"at index {i}"); + ClassicAssert.AreEqual(closestDivisors[i], beatmap.ControlPointInfo.GetClosestBeatDivisor(beatmap.HitObjects[i].StartTime), $"at index {i}"); } } } diff --git a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs index 6b1b883ce7a9..90671093a522 100644 --- a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs +++ b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; @@ -141,7 +142,7 @@ public void TestIncompatibleWithSameInstanceViaMultiMod() private void assertCombinations(Type[][] expectedCombinations, Mod[] actualCombinations) { - Assert.AreEqual(expectedCombinations.Length, actualCombinations.Length); + ClassicAssert.AreEqual(expectedCombinations.Length, actualCombinations.Length); Assert.Multiple(() => { diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs index 5455963ff8f2..eb75f75deec3 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Rulesets; @@ -61,7 +62,7 @@ public void TestCriteriaMatchingNoRuleset() var criteria = new FilterCriteria(); var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); carouselItem.Filter(criteria); - Assert.IsFalse(carouselItem.Filtered.Value); + ClassicAssert.False(carouselItem.Filtered.Value); } [Test] @@ -74,7 +75,7 @@ public void TestCriteriaMatchingSpecificRuleset() }; var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); carouselItem.Filter(criteria); - Assert.IsTrue(carouselItem.Filtered.Value); + ClassicAssert.True(carouselItem.Filtered.Value); } [Test] @@ -88,7 +89,7 @@ public void TestCriteriaMatchingConvertedBeatmaps() }; var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); carouselItem.Filter(criteria); - Assert.IsFalse(carouselItem.Filtered.Value); + ClassicAssert.False(carouselItem.Filtered.Value); } [Test] @@ -102,7 +103,7 @@ public void TestCriteriaMatchingConvertedBeatmapsForCustomRulesets() }; var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); carouselItem.Filter(criteria); - Assert.IsFalse(carouselItem.Filtered.Value); + ClassicAssert.False(carouselItem.Filtered.Value); } [Test] @@ -123,7 +124,7 @@ public void TestCriteriaMatchingRangeMin(bool inclusive) }; var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); carouselItem.Filter(criteria); - Assert.AreEqual(!inclusive, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(!inclusive, carouselItem.Filtered.Value); } [Test] @@ -144,7 +145,7 @@ public void TestCriteriaMatchingRangeMax(bool inclusive) }; var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); carouselItem.Filter(criteria); - Assert.AreEqual(!inclusive, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(!inclusive, carouselItem.Filtered.Value); } [Test] @@ -166,7 +167,7 @@ public void TestCriteriaMatchingTerms(string terms, bool filtered) }; var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); carouselItem.Filter(criteria); - Assert.AreEqual(filtered, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(filtered, carouselItem.Filtered.Value); } [Test] @@ -195,7 +196,7 @@ public void TestCriteriaMatchingExactTerms(string terms, bool filtered) }; var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); carouselItem.Filter(criteria); - Assert.AreEqual(filtered, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(filtered, carouselItem.Filtered.Value); } [Test] @@ -215,7 +216,7 @@ public void TestCriteriaMatchingCreator(string creatorName, bool filtered) }; var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); carouselItem.Filter(criteria); - Assert.AreEqual(filtered, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(filtered, carouselItem.Filtered.Value); } [Test] @@ -236,7 +237,7 @@ public void TestCriteriaMatchingTitle(string titleName, bool filtered) }; var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); carouselItem.Filter(criteria); - Assert.AreEqual(filtered, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(filtered, carouselItem.Filtered.Value); } [Test] @@ -260,7 +261,7 @@ public void TestCriteriaMatchingArtist(string artistName, bool filtered) }; var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); carouselItem.Filter(criteria); - Assert.AreEqual(filtered, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(filtered, carouselItem.Filtered.Value); } [Test] @@ -278,7 +279,7 @@ public void TestCriteriaMatchingArtistWithNullUnicodeName(string artistName, boo }; var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); carouselItem.Filter(criteria); - Assert.AreEqual(filtered, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(filtered, carouselItem.Filtered.Value); } [TestCase("202010", true)] @@ -295,7 +296,7 @@ public void TestCriteriaMatchingBeatmapIDs(string query, bool filtered) var carouselItem = new CarouselBeatmap(beatmap); carouselItem.Filter(criteria); - Assert.AreEqual(filtered, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(filtered, carouselItem.Filtered.Value); } [Test] @@ -312,7 +313,7 @@ public void TestCriteriaNotMatchingArtist(string excludedTerm) var carouselItem = new CarouselBeatmap(beatmap); carouselItem.Filter(criteria); - Assert.True(carouselItem.Filtered.Value); + ClassicAssert.True(carouselItem.Filtered.Value); } [TestCase("simple", false)] @@ -327,7 +328,7 @@ public void TestCriteriaMatchingUserTags(string query, bool filtered) var carouselItem = new CarouselBeatmap(beatmap); carouselItem.Filter(criteria); - Assert.AreEqual(filtered, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(filtered, carouselItem.Filtered.Value); } [Test] @@ -345,7 +346,7 @@ public void TestCriteriaMatchingMultipleTagsAtOnce() var carouselItem = new CarouselBeatmap(beatmap); carouselItem.Filter(criteria); - Assert.AreEqual(false, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(false, carouselItem.Filtered.Value); } [Test] @@ -363,7 +364,7 @@ public void TestCriteriaAllTagFiltersMustMatch() var carouselItem = new CarouselBeatmap(beatmap); carouselItem.Filter(criteria); - Assert.AreEqual(true, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(true, carouselItem.Filtered.Value); } [Test] @@ -380,7 +381,7 @@ public void TestCriteriaMatchingTagExcluded() var carouselItem = new CarouselBeatmap(beatmap); carouselItem.Filter(criteria); - Assert.AreEqual(true, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(true, carouselItem.Filtered.Value); } [Test] @@ -398,7 +399,7 @@ public void TestCriteriaOneTagIncludedAndOneTagExcluded() var carouselItem = new CarouselBeatmap(beatmap); carouselItem.Filter(criteria); - Assert.AreEqual(true, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(true, carouselItem.Filtered.Value); } [Test] @@ -410,7 +411,7 @@ public void TestBeatmapMustHaveAtLeastOneTagIfUserTagFilterActive() carouselItem.BeatmapInfo.Metadata.UserTags.Clear(); carouselItem.Filter(criteria); - Assert.True(carouselItem.Filtered.Value); + ClassicAssert.True(carouselItem.Filtered.Value); } [Test] @@ -423,7 +424,7 @@ public void TestCustomRulesetCriteria([Values(null, true, false)] bool? matchCus var carouselItem = new CarouselBeatmap(beatmap); carouselItem.Filter(criteria); - Assert.AreEqual(matchCustomCriteria == false, carouselItem.Filtered.Value); + ClassicAssert.AreEqual(matchCustomCriteria == false, carouselItem.Filtered.Value); } [TestCase("title!=Title", new[] { 2, 4, 6 })] diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 6a87cc1207e8..09f85a7defa6 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Rulesets.Filter; @@ -23,8 +24,8 @@ public void TestApplyQueriesBareWords() const string query = "looking for a beatmap"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("looking for a beatmap", filterCriteria.SearchText); - Assert.AreEqual(4, filterCriteria.SearchTerms.Length); + ClassicAssert.AreEqual("looking for a beatmap", filterCriteria.SearchText); + ClassicAssert.AreEqual(4, filterCriteria.SearchTerms.Length); } [Test] @@ -33,8 +34,8 @@ public void TestApplyQueriesBareWordsWithExactMatch() const string query = "looking for \"a beatmap\"! like \"this\""; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("looking for \"a beatmap\"! like \"this\"", filterCriteria.SearchText); - Assert.AreEqual(5, filterCriteria.SearchTerms.Length); + ClassicAssert.AreEqual("looking for \"a beatmap\"! like \"this\"", filterCriteria.SearchText); + ClassicAssert.AreEqual(5, filterCriteria.SearchTerms.Length); Assert.That(filterCriteria.SearchTerms[0].SearchTerm, Is.EqualTo("a beatmap")); Assert.That(filterCriteria.SearchTerms[0].MatchMode, Is.EqualTo(FilterCriteria.MatchMode.FullPhrase)); @@ -58,8 +59,8 @@ public void TestApplyFullPhraseQueryWithExclamationPointInTerm() const string query = "looking for \"circles!\"!"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("looking for \"circles!\"!", filterCriteria.SearchText); - Assert.AreEqual(3, filterCriteria.SearchTerms.Length); + ClassicAssert.AreEqual("looking for \"circles!\"!", filterCriteria.SearchText); + ClassicAssert.AreEqual(3, filterCriteria.SearchTerms.Length); Assert.That(filterCriteria.SearchTerms[0].SearchTerm, Is.EqualTo("circles!")); Assert.That(filterCriteria.SearchTerms[0].MatchMode, Is.EqualTo(FilterCriteria.MatchMode.FullPhrase)); @@ -77,8 +78,8 @@ public void TestApplyBrokenFullPhraseQuery() const string query = "\"!"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("\"!", filterCriteria.SearchText); - Assert.AreEqual(1, filterCriteria.SearchTerms.Length); + ClassicAssert.AreEqual("\"!", filterCriteria.SearchText); + ClassicAssert.AreEqual(1, filterCriteria.SearchTerms.Length); Assert.That(filterCriteria.SearchTerms[0].SearchTerm, Is.EqualTo("!")); Assert.That(filterCriteria.SearchTerms[0].MatchMode, Is.EqualTo(FilterCriteria.MatchMode.IsolatedPhrase)); @@ -91,11 +92,11 @@ public void TestApplyStarQueries(string variant) string query = $"{variant}<4 easy"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("easy", filterCriteria.SearchText.Trim()); - Assert.AreEqual(1, filterCriteria.SearchTerms.Length); - Assert.IsNotNull(filterCriteria.StarDifficulty.Max); - Assert.AreEqual(filterCriteria.StarDifficulty.Max, 4.00d); - Assert.IsNull(filterCriteria.StarDifficulty.Min); + ClassicAssert.AreEqual("easy", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(1, filterCriteria.SearchTerms.Length); + ClassicAssert.NotNull(filterCriteria.StarDifficulty.Max); + ClassicAssert.AreEqual(filterCriteria.StarDifficulty.Max!, 4.00d); + ClassicAssert.Null(filterCriteria.StarDifficulty.Min); } [Test] @@ -104,9 +105,9 @@ public void TestStarQueriesInclusive() const string query = "stars>=6"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual(filterCriteria.StarDifficulty.Min, 6.00d); - Assert.True(filterCriteria.StarDifficulty.IsLowerInclusive); - Assert.IsNull(filterCriteria.StarDifficulty.Max); + ClassicAssert.AreEqual(filterCriteria.StarDifficulty.Min!, 6.00d); + ClassicAssert.True(filterCriteria.StarDifficulty.IsLowerInclusive); + ClassicAssert.Null(filterCriteria.StarDifficulty.Max); } /* @@ -125,12 +126,12 @@ public void TestApplyApproachRateQueries() const string query = "ar>=9 difficult"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("difficult", filterCriteria.SearchText.Trim()); - Assert.AreEqual(1, filterCriteria.SearchTerms.Length); - Assert.IsNotNull(filterCriteria.ApproachRate.Min); - Assert.Greater(filterCriteria.ApproachRate.Min, 8.9f); - Assert.Less(filterCriteria.ApproachRate.Min, 9.0f); - Assert.IsNull(filterCriteria.ApproachRate.Max); + ClassicAssert.AreEqual("difficult", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(1, filterCriteria.SearchTerms.Length); + ClassicAssert.NotNull(filterCriteria.ApproachRate.Min); + ClassicAssert.Greater(filterCriteria.ApproachRate.Min!, 8.9f); + ClassicAssert.Less(filterCriteria.ApproachRate.Min!, 9.0f); + ClassicAssert.Null(filterCriteria.ApproachRate.Max); } [Test] @@ -139,12 +140,12 @@ public void TestApplyDrainRateQueriesByDrKeyword() const string query = "dr>2 quite specific dr<:6"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("quite specific", filterCriteria.SearchText.Trim()); - Assert.AreEqual(2, filterCriteria.SearchTerms.Length); - Assert.Greater(filterCriteria.DrainRate.Min, 2.0f); - Assert.Less(filterCriteria.DrainRate.Min, 2.1f); - Assert.Greater(filterCriteria.DrainRate.Max, 6.0f); - Assert.Less(filterCriteria.DrainRate.Min, 6.1f); + ClassicAssert.AreEqual("quite specific", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(2, filterCriteria.SearchTerms.Length); + ClassicAssert.Greater(filterCriteria.DrainRate.Min!, 2.0f); + ClassicAssert.Less(filterCriteria.DrainRate.Min!, 2.1f); + ClassicAssert.Greater(filterCriteria.DrainRate.Max!, 6.0f); + ClassicAssert.Less(filterCriteria.DrainRate.Min!, 6.1f); } [Test] @@ -153,12 +154,12 @@ public void TestApplyDrainRateQueriesByHpKeyword() const string query = "hp>2 quite specific hp<=6"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("quite specific", filterCriteria.SearchText.Trim()); - Assert.AreEqual(2, filterCriteria.SearchTerms.Length); - Assert.Greater(filterCriteria.DrainRate.Min, 2.0f); - Assert.Less(filterCriteria.DrainRate.Min, 2.1f); - Assert.Greater(filterCriteria.DrainRate.Max, 6.0f); - Assert.Less(filterCriteria.DrainRate.Min, 6.1f); + ClassicAssert.AreEqual("quite specific", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(2, filterCriteria.SearchTerms.Length); + ClassicAssert.Greater(filterCriteria.DrainRate.Min!, 2.0f); + ClassicAssert.Less(filterCriteria.DrainRate.Min!, 2.1f); + ClassicAssert.Greater(filterCriteria.DrainRate.Max!, 6.0f); + ClassicAssert.Less(filterCriteria.DrainRate.Min!, 6.1f); } [Test] @@ -167,12 +168,12 @@ public void TestApplyOverallDifficultyQueries() const string query = "od>4 easy od<8"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("easy", filterCriteria.SearchText.Trim()); - Assert.AreEqual(1, filterCriteria.SearchTerms.Length); - Assert.Greater(filterCriteria.OverallDifficulty.Min, 4.0); - Assert.Less(filterCriteria.OverallDifficulty.Min, 4.1); - Assert.Greater(filterCriteria.OverallDifficulty.Max, 7.9); - Assert.Less(filterCriteria.OverallDifficulty.Max, 8.0); + ClassicAssert.AreEqual("easy", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(1, filterCriteria.SearchTerms.Length); + ClassicAssert.Greater(filterCriteria.OverallDifficulty.Min!, 4.0); + ClassicAssert.Less(filterCriteria.OverallDifficulty.Min!, 4.1); + ClassicAssert.Greater(filterCriteria.OverallDifficulty.Max!, 7.9); + ClassicAssert.Less(filterCriteria.OverallDifficulty.Max!, 8.0); } [Test] @@ -181,8 +182,8 @@ public void TestApplyBPMQueries() const string query = "bpm=200"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual(filterCriteria.BPM.Min, 199.5d); - Assert.AreEqual(filterCriteria.BPM.Max, 200.5d); + ClassicAssert.AreEqual(filterCriteria.BPM.Min!, 199.5d); + ClassicAssert.AreEqual(filterCriteria.BPM.Max!, 200.5d); } [Test] @@ -191,11 +192,11 @@ public void TestApplyBPMRangeQueries() const string query = "bpm>:200 gotta go fast"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("gotta go fast", filterCriteria.SearchText.Trim()); - Assert.AreEqual(3, filterCriteria.SearchTerms.Length); - Assert.IsNotNull(filterCriteria.BPM.Min); - Assert.AreEqual(filterCriteria.BPM.Min, 199.5d); - Assert.IsNull(filterCriteria.BPM.Max); + ClassicAssert.AreEqual("gotta go fast", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(3, filterCriteria.SearchTerms.Length); + ClassicAssert.NotNull(filterCriteria.BPM.Min); + ClassicAssert.AreEqual(filterCriteria.BPM.Min!, 199.5d); + ClassicAssert.Null(filterCriteria.BPM.Max); } private static readonly object[] correct_length_query_examples = @@ -228,10 +229,10 @@ public void TestApplyLengthQueries(string lengthQuery, TimeSpan expectedLength, string query = $"length={lengthQuery} time"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("time", filterCriteria.SearchText.Trim()); - Assert.AreEqual(1, filterCriteria.SearchTerms.Length); - Assert.AreEqual(expectedLength.TotalMilliseconds - scale.TotalMilliseconds / 2.0, filterCriteria.Length.Min); - Assert.AreEqual(expectedLength.TotalMilliseconds + scale.TotalMilliseconds / 2.0, filterCriteria.Length.Max); + ClassicAssert.AreEqual("time", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(1, filterCriteria.SearchTerms.Length); + ClassicAssert.AreEqual(expectedLength.TotalMilliseconds - scale.TotalMilliseconds / 2.0, filterCriteria.Length.Min); + ClassicAssert.AreEqual(expectedLength.TotalMilliseconds + scale.TotalMilliseconds / 2.0, filterCriteria.Length.Max); } private static readonly object[] incorrect_length_query_examples = @@ -254,7 +255,7 @@ public void TestInvalidLengthQueries(string lengthQuery) string query = $"length={lengthQuery} time"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual(false, filterCriteria.Length.HasFilter); + ClassicAssert.AreEqual(false, filterCriteria.Length.HasFilter); } [Test] @@ -263,12 +264,12 @@ public void TestApplyDivisorQueries() const string query = "that's a time signature alright! divisor:12"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("that's a time signature alright!", filterCriteria.SearchText.Trim()); - Assert.AreEqual(5, filterCriteria.SearchTerms.Length); - Assert.AreEqual(12, filterCriteria.BeatDivisor.Min); - Assert.IsTrue(filterCriteria.BeatDivisor.IsLowerInclusive); - Assert.AreEqual(12, filterCriteria.BeatDivisor.Max); - Assert.IsTrue(filterCriteria.BeatDivisor.IsUpperInclusive); + ClassicAssert.AreEqual("that's a time signature alright!", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(5, filterCriteria.SearchTerms.Length); + ClassicAssert.AreEqual(12, filterCriteria.BeatDivisor.Min); + ClassicAssert.True(filterCriteria.BeatDivisor.IsLowerInclusive); + ClassicAssert.AreEqual(12, filterCriteria.BeatDivisor.Max); + ClassicAssert.True(filterCriteria.BeatDivisor.IsUpperInclusive); } [Test] @@ -277,7 +278,7 @@ public void TestPartialStatusMatch() const string query = "status=r"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.IsNotEmpty(filterCriteria.OnlineStatus.Values); + ClassicAssert.IsNotEmpty(filterCriteria.OnlineStatus.Values); Assert.That(filterCriteria.OnlineStatus.Values, Contains.Item(BeatmapOnlineStatus.Ranked)); } @@ -287,9 +288,9 @@ public void TestApplyStatusQueries() const string query = "I want the pp status=ranked"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("I want the pp", filterCriteria.SearchText.Trim()); - Assert.AreEqual(4, filterCriteria.SearchTerms.Length); - Assert.IsNotEmpty(filterCriteria.OnlineStatus.Values); + ClassicAssert.AreEqual("I want the pp", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(4, filterCriteria.SearchTerms.Length); + ClassicAssert.IsNotEmpty(filterCriteria.OnlineStatus.Values); Assert.That(filterCriteria.OnlineStatus.Values, Contains.Item(BeatmapOnlineStatus.Ranked)); } @@ -308,7 +309,7 @@ public void TestPartialStatusNotMatch() const string query = "status!=r"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.IsNotEmpty(filterCriteria.OnlineStatus.Values); + ClassicAssert.IsNotEmpty(filterCriteria.OnlineStatus.Values); Assert.That(filterCriteria.OnlineStatus.Values, Does.Not.Contain(BeatmapOnlineStatus.Ranked)); } @@ -374,9 +375,9 @@ public void TestApplyCreatorQueries(string keyword) string query = $"beatmap specifically by {keyword}=my_fav"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("beatmap specifically by", filterCriteria.SearchText.Trim()); - Assert.AreEqual(3, filterCriteria.SearchTerms.Length); - Assert.AreEqual("my_fav", filterCriteria.Creator.SearchTerm); + ClassicAssert.AreEqual("beatmap specifically by", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(3, filterCriteria.SearchTerms.Length); + ClassicAssert.AreEqual("my_fav", filterCriteria.Creator.SearchTerm); } [Test] @@ -385,9 +386,9 @@ public void TestApplyTitleQueries() const string query = "find me songs with title=\"a certain title\" please"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("find me songs with please", filterCriteria.SearchText.Trim()); - Assert.AreEqual(5, filterCriteria.SearchTerms.Length); - Assert.AreEqual("a certain title", filterCriteria.Title.SearchTerm); + ClassicAssert.AreEqual("find me songs with please", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(5, filterCriteria.SearchTerms.Length); + ClassicAssert.AreEqual("a certain title", filterCriteria.Title.SearchTerm); Assert.That(filterCriteria.Title.MatchMode, Is.EqualTo(FilterCriteria.MatchMode.IsolatedPhrase)); } @@ -397,9 +398,9 @@ public void TestApplyArtistQueries() const string query = "find me songs by artist=singer please"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("find me songs by please", filterCriteria.SearchText.Trim()); - Assert.AreEqual(5, filterCriteria.SearchTerms.Length); - Assert.AreEqual("singer", filterCriteria.Artist.SearchTerm); + ClassicAssert.AreEqual("find me songs by please", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(5, filterCriteria.SearchTerms.Length); + ClassicAssert.AreEqual("singer", filterCriteria.Artist.SearchTerm); Assert.That(filterCriteria.Artist.MatchMode, Is.EqualTo(FilterCriteria.MatchMode.Substring)); } @@ -409,9 +410,9 @@ public void TestApplyArtistQueriesWithSpaces() const string query = "really like artist=\"name with space\" yes"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("really like yes", filterCriteria.SearchText.Trim()); - Assert.AreEqual(3, filterCriteria.SearchTerms.Length); - Assert.AreEqual("name with space", filterCriteria.Artist.SearchTerm); + ClassicAssert.AreEqual("really like yes", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(3, filterCriteria.SearchTerms.Length); + ClassicAssert.AreEqual("name with space", filterCriteria.Artist.SearchTerm); Assert.That(filterCriteria.Artist.MatchMode, Is.EqualTo(FilterCriteria.MatchMode.IsolatedPhrase)); } @@ -422,8 +423,8 @@ public void TestApplyArtistQueriesWithSpacesFullPhrase() var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.That(filterCriteria.SearchText.Trim(), Is.Empty); - Assert.AreEqual(0, filterCriteria.SearchTerms.Length); - Assert.AreEqual("The Only One", filterCriteria.Artist.SearchTerm); + ClassicAssert.AreEqual(0, filterCriteria.SearchTerms.Length); + ClassicAssert.AreEqual("The Only One", filterCriteria.Artist.SearchTerm); Assert.That(filterCriteria.Artist.MatchMode, Is.EqualTo(FilterCriteria.MatchMode.FullPhrase)); } @@ -433,9 +434,9 @@ public void TestApplyArtistQueriesOneDoubleQuote() const string query = "weird artist=double\"quote"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("weird", filterCriteria.SearchText.Trim()); - Assert.AreEqual(1, filterCriteria.SearchTerms.Length); - Assert.AreEqual("double\"quote", filterCriteria.Artist.SearchTerm); + ClassicAssert.AreEqual("weird", filterCriteria.SearchText.Trim()); + ClassicAssert.AreEqual(1, filterCriteria.SearchTerms.Length); + ClassicAssert.AreEqual("double\"quote", filterCriteria.Artist.SearchTerm); } [Test] @@ -444,7 +445,7 @@ public void TestOperatorParsing() const string query = "artist=> @@ -706,8 +707,8 @@ public void TestValidRankedDateQueries(string query, DateTimeOffset expected, Fu { var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual(true, filterCriteria.DateRanked.HasFilter); - Assert.AreEqual(expected, f(filterCriteria)); + ClassicAssert.AreEqual(true, filterCriteria.DateRanked.HasFilter); + ClassicAssert.AreEqual(expected, f(filterCriteria)); } private static readonly object[] ranked_date_invalid_test_cases = @@ -723,7 +724,7 @@ public void TestInvalidRankedDateQueries(string query) { var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual(false, filterCriteria.DateRanked.HasFilter); + ClassicAssert.AreEqual(false, filterCriteria.DateRanked.HasFilter); } private static readonly object[] submitted_date_test_cases = @@ -755,7 +756,7 @@ public void TestInvalidRankedDateQueries(string query, bool expected) { var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual(expected, filterCriteria.DateSubmitted.HasFilter); + ClassicAssert.AreEqual(expected, filterCriteria.DateSubmitted.HasFilter); } private static readonly object[] played_query_tests = @@ -781,8 +782,8 @@ public void TestPlayedQuery(string query, DateTimeOffset reference, bool matched { var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, $"played={query}"); - Assert.AreEqual(true, filterCriteria.LastPlayed.HasFilter); - Assert.AreEqual(matched, filterCriteria.LastPlayed.IsInRange(reference)); + ClassicAssert.AreEqual(true, filterCriteria.LastPlayed.HasFilter); + ClassicAssert.AreEqual(matched, filterCriteria.LastPlayed.IsInRange(reference)); } [Test] diff --git a/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs b/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs index 69c98351ad91..174d14d2268a 100644 --- a/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs +++ b/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Audio; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Judgements; @@ -37,7 +38,7 @@ public void TestResultIfOnlyParentHitWindowIsEmpty() testObject.AddNested(nested); testDrawableRuleset.HitObjects = new List { testObject }; - Assert.AreSame(testDrawableRuleset.FirstAvailableHitWindows, nested.HitWindows); + ClassicAssert.AreSame(testDrawableRuleset.FirstAvailableHitWindows, nested.HitWindows); } [Test] @@ -48,7 +49,7 @@ public void TestResultIfParentHitWindowsIsNotEmpty() testObject.AddNested(nested); testDrawableRuleset.HitObjects = new List { testObject }; - Assert.AreSame(testDrawableRuleset.FirstAvailableHitWindows, testObject.HitWindows); + ClassicAssert.AreSame(testDrawableRuleset.FirstAvailableHitWindows, testObject.HitWindows); } [Test] @@ -61,7 +62,7 @@ public void TestResultIfParentAndChildHitWindowsAreEmpty() var secondObject = new TestHitObject(new DefaultHitWindows()); testDrawableRuleset.HitObjects = new List { firstObject, secondObject }; - Assert.AreSame(testDrawableRuleset.FirstAvailableHitWindows, secondObject.HitWindows); + ClassicAssert.AreSame(testDrawableRuleset.FirstAvailableHitWindows, secondObject.HitWindows); } [Test] @@ -73,7 +74,7 @@ public void TestResultIfAllHitWindowsAreEmpty() testDrawableRuleset.HitObjects = new List { firstObject }; - Assert.IsNull(testDrawableRuleset.FirstAvailableHitWindows); + ClassicAssert.Null(testDrawableRuleset.FirstAvailableHitWindows); } [SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")] diff --git a/osu.Game.Tests/NonVisual/FormatUtilsTest.cs b/osu.Game.Tests/NonVisual/FormatUtilsTest.cs index 0fcf754cf664..169639f1d3b3 100644 --- a/osu.Game.Tests/NonVisual/FormatUtilsTest.cs +++ b/osu.Game.Tests/NonVisual/FormatUtilsTest.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Utils; namespace osu.Game.Tests.NonVisual @@ -19,7 +20,7 @@ public class FormatUtilsTest [TestCase(1, "100.00%")] public void TestAccuracyFormatting(double input, string expectedOutput) { - Assert.AreEqual(expectedOutput, input.FormatAccuracy().ToString()); + ClassicAssert.AreEqual(expectedOutput, input.FormatAccuracy().ToString()); } [TestCase(3, "3.00")] @@ -32,7 +33,7 @@ public void TestAccuracyFormatting(double input, string expectedOutput) [TestCase(4, "4.00")] public void TestStarRatingFormatting(double input, string expectedOutput) { - Assert.AreEqual(expectedOutput, input.FormatStarRating().ToString()); + ClassicAssert.AreEqual(expectedOutput, input.FormatStarRating().ToString()); } } } diff --git a/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs b/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs index ffb21f124c95..0bfca14c9a4c 100644 --- a/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs +++ b/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Replays; using osu.Game.Rulesets.Replays; @@ -223,7 +224,7 @@ public void TestReplayStreaming() // no frames are arrived yet setTime(0, null); setTime(1000, null); - Assert.IsTrue(handler.WaitingForFrame, "Should be waiting for the first frame"); + ClassicAssert.True(handler.WaitingForFrame, "Should be waiting for the first frame"); replay.Frames.Add(new TestReplayFrame(0)); replay.Frames.Add(new TestReplayFrame(1000)); @@ -231,11 +232,11 @@ public void TestReplayStreaming() // should always play from beginning setTime(1000, 0); confirmCurrentFrame(0); - Assert.IsFalse(handler.WaitingForFrame, "Should not be waiting yet"); + ClassicAssert.False(handler.WaitingForFrame, "Should not be waiting yet"); setTime(1000, 1000); confirmCurrentFrame(1); confirmNextFrame(null); - Assert.IsTrue(handler.WaitingForFrame, "Should be waiting"); + ClassicAssert.True(handler.WaitingForFrame, "Should be waiting"); // cannot seek beyond the last frame setTime(1500, null); @@ -359,17 +360,17 @@ private void fastForwardToPoint(double destination) private void setTime(double set, double? expect) { - Assert.AreEqual(expect, handler.SetFrameFromTime(set), "Unexpected return value"); + ClassicAssert.AreEqual(expect, handler.SetFrameFromTime(set), "Unexpected return value"); } private void confirmCurrentFrame(int? frame) { - Assert.AreEqual(frame is int x ? replay.Frames[x].Time : null, handler.CurrentFrame?.Time, "Unexpected current frame"); + ClassicAssert.AreEqual(frame is int x ? replay.Frames[x].Time : null, handler.CurrentFrame?.Time, "Unexpected current frame"); } private void confirmNextFrame(int? frame) { - Assert.AreEqual(frame is int x ? replay.Frames[x].Time : null, handler.NextFrame?.Time, "Unexpected next frame"); + ClassicAssert.AreEqual(frame is int x ? replay.Frames[x].Time : null, handler.NextFrame?.Time, "Unexpected next frame"); } private class TestReplayFrame : ReplayFrame diff --git a/osu.Game.Tests/NonVisual/LimitedCapacityQueueTest.cs b/osu.Game.Tests/NonVisual/LimitedCapacityQueueTest.cs index 8809ce3adc60..a33a36f2d97d 100644 --- a/osu.Game.Tests/NonVisual/LimitedCapacityQueueTest.cs +++ b/osu.Game.Tests/NonVisual/LimitedCapacityQueueTest.cs @@ -5,6 +5,7 @@ using System; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Utils; namespace osu.Game.Tests.NonVisual @@ -25,7 +26,7 @@ public void SetUp() [Test] public void TestEmptyQueue() { - Assert.AreEqual(0, queue.Count); + ClassicAssert.AreEqual(0, queue.Count); Assert.Throws(() => _ = queue[0]); @@ -35,7 +36,7 @@ public void TestEmptyQueue() foreach (int _ in queue) count++; - Assert.AreEqual(0, count); + ClassicAssert.AreEqual(0, count); } [TestCase(1)] @@ -46,14 +47,14 @@ public void TestBelowCapacity(int count) for (int i = 0; i < count; ++i) queue.Enqueue(i); - Assert.AreEqual(count, queue.Count); + ClassicAssert.AreEqual(count, queue.Count); for (int i = 0; i < count; ++i) - Assert.AreEqual(i, queue[i]); + ClassicAssert.AreEqual(i, queue[i]); int j = 0; foreach (int item in queue) - Assert.AreEqual(j++, item); + ClassicAssert.AreEqual(j++, item); for (int i = queue.Count; i < queue.Count + capacity; i++) Assert.Throws(() => _ = queue[i]); @@ -67,14 +68,14 @@ public void TestEnqueueAtFullCapacity(int count) for (int i = 0; i < count; ++i) queue.Enqueue(i); - Assert.AreEqual(capacity, queue.Count); + ClassicAssert.AreEqual(capacity, queue.Count); for (int i = 0; i < queue.Count; ++i) - Assert.AreEqual(count - capacity + i, queue[i]); + ClassicAssert.AreEqual(count - capacity + i, queue[i]); int j = count - capacity; foreach (int item in queue) - Assert.AreEqual(j++, item); + ClassicAssert.AreEqual(j++, item); for (int i = queue.Count; i < queue.Count + capacity; i++) Assert.Throws(() => _ = queue[i]); @@ -90,8 +91,8 @@ public void TestDequeueAtFullCapacity(int count) for (int i = 0; i < capacity; ++i) { - Assert.AreEqual(count - capacity + i, queue.Dequeue()); - Assert.AreEqual(2 - i, queue.Count); + ClassicAssert.AreEqual(count - capacity + i, queue.Dequeue()); + ClassicAssert.AreEqual(2 - i, queue.Count); } Assert.Throws(() => queue.Dequeue()); @@ -102,20 +103,20 @@ public void TestClearQueue() { queue.Enqueue(3); queue.Enqueue(5); - Assert.AreEqual(2, queue.Count); + ClassicAssert.AreEqual(2, queue.Count); queue.Clear(); - Assert.AreEqual(0, queue.Count); + ClassicAssert.AreEqual(0, queue.Count); Assert.Throws(() => _ = queue[0]); queue.Enqueue(7); - Assert.AreEqual(1, queue.Count); - Assert.AreEqual(7, queue[0]); + ClassicAssert.AreEqual(1, queue.Count); + ClassicAssert.AreEqual(7, queue[0]); Assert.Throws(() => _ = queue[1]); queue.Enqueue(9); - Assert.AreEqual(2, queue.Count); - Assert.AreEqual(9, queue[1]); + ClassicAssert.AreEqual(2, queue.Count); + ClassicAssert.AreEqual(9, queue[1]); } } } diff --git a/osu.Game.Tests/NonVisual/PeriodTrackerTest.cs b/osu.Game.Tests/NonVisual/PeriodTrackerTest.cs index 664a499cc389..b502aa1782fa 100644 --- a/osu.Game.Tests/NonVisual/PeriodTrackerTest.cs +++ b/osu.Game.Tests/NonVisual/PeriodTrackerTest.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Utils; using osu.Game.Utils; @@ -28,9 +29,9 @@ public void TestCheckValueInsideSinglePeriod() var tracker = new PeriodTracker(single_period); var period = single_period.Single(); - Assert.IsTrue(tracker.IsInAny(period.Start)); - Assert.IsTrue(tracker.IsInAny(getMidpoint(period))); - Assert.IsTrue(tracker.IsInAny(period.End)); + ClassicAssert.True(tracker.IsInAny(period.Start)); + ClassicAssert.True(tracker.IsInAny(getMidpoint(period))); + ClassicAssert.True(tracker.IsInAny(period.End)); } [Test] @@ -39,7 +40,7 @@ public void TestCheckValuesInsidePeriods() var tracker = new PeriodTracker(unordered_periods); foreach (var period in unordered_periods) - Assert.IsTrue(tracker.IsInAny(getMidpoint(period))); + ClassicAssert.True(tracker.IsInAny(getMidpoint(period))); } [Test] @@ -48,7 +49,7 @@ public void TestCheckValuesInRandomOrder() var tracker = new PeriodTracker(unordered_periods); foreach (var period in unordered_periods.OrderBy(_ => RNG.Next())) - Assert.IsTrue(tracker.IsInAny(getMidpoint(period))); + ClassicAssert.True(tracker.IsInAny(getMidpoint(period))); } [Test] @@ -60,12 +61,12 @@ public void TestCheckValuesOutOfPeriods() new Period(3.0, 4.0) }); - Assert.IsFalse(tracker.IsInAny(0.9), "Time before first period is being considered inside"); + ClassicAssert.False(tracker.IsInAny(0.9), "Time before first period is being considered inside"); - Assert.IsFalse(tracker.IsInAny(2.1), "Time right after first period is being considered inside"); - Assert.IsFalse(tracker.IsInAny(2.9), "Time right before second period is being considered inside"); + ClassicAssert.False(tracker.IsInAny(2.1), "Time right after first period is being considered inside"); + ClassicAssert.False(tracker.IsInAny(2.9), "Time right before second period is being considered inside"); - Assert.IsFalse(tracker.IsInAny(4.1), "Time after last period is being considered inside"); + ClassicAssert.False(tracker.IsInAny(4.1), "Time after last period is being considered inside"); } [Test] diff --git a/osu.Game.Tests/NonVisual/Ranking/UnstableRateTest.cs b/osu.Game.Tests/NonVisual/Ranking/UnstableRateTest.cs index 18ac5b496487..f68f743723d2 100644 --- a/osu.Game.Tests/NonVisual/Ranking/UnstableRateTest.cs +++ b/osu.Game.Tests/NonVisual/Ranking/UnstableRateTest.cs @@ -6,6 +6,7 @@ using System; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Utils; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; @@ -25,8 +26,8 @@ public void TestDistributedHits() var unstableRate = new UnstableRate(events); - Assert.IsNotNull(unstableRate.Value); - Assert.AreEqual(unstableRate.Value.Value, 10 * Math.Sqrt(10), Precision.DOUBLE_EPSILON); + Assert.That(unstableRate.Value, Is.Not.Null); + ClassicAssert.AreEqual(unstableRate.Value.Value, 10 * Math.Sqrt(10), Precision.DOUBLE_EPSILON); } [Test] @@ -50,8 +51,8 @@ public void TestDistributedHitsIncrementalRewind() result = events.GetRange(0, 2).CalculateUnstableRate(result); - Assert.IsNotNull(result!.Result); - Assert.AreEqual(5, result.Result, Precision.DOUBLE_EPSILON); + ClassicAssert.NotNull(result!.Result); + ClassicAssert.AreEqual(5, result.Result, Precision.DOUBLE_EPSILON); } [Test] @@ -73,8 +74,8 @@ public void TestDistributedHitsIncremental() .CalculateUnstableRate(result); } - Assert.IsNotNull(result!.Result); - Assert.AreEqual(10 * Math.Sqrt(10), result.Result, Precision.DOUBLE_EPSILON); + ClassicAssert.NotNull(result!.Result); + ClassicAssert.AreEqual(10 * Math.Sqrt(10), result.Result, Precision.DOUBLE_EPSILON); } [Test] @@ -89,7 +90,7 @@ public void TestMissesAndEmptyWindows() var unstableRate = new UnstableRate(events); - Assert.AreEqual(0, unstableRate.Value); + ClassicAssert.AreEqual(0, unstableRate.Value); } [Test] @@ -105,7 +106,7 @@ public void TestStaticRateChange() var unstableRate = new UnstableRate(events); - Assert.AreEqual(10 * 100, unstableRate.Value); + ClassicAssert.AreEqual(10 * 100, unstableRate.Value); } [Test] @@ -121,7 +122,7 @@ public void TestDynamicRateChange() var unstableRate = new UnstableRate(events); - Assert.AreEqual(10 * 100, unstableRate.Value); + ClassicAssert.AreEqual(10 * 100, unstableRate.Value); } } } diff --git a/osu.Game.Tests/NonVisual/ReverseQueueTest.cs b/osu.Game.Tests/NonVisual/ReverseQueueTest.cs index d0ad2e22a457..7b87ba248115 100644 --- a/osu.Game.Tests/NonVisual/ReverseQueueTest.cs +++ b/osu.Game.Tests/NonVisual/ReverseQueueTest.cs @@ -5,6 +5,7 @@ using System; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Rulesets.Difficulty.Utils; namespace osu.Game.Tests.NonVisual @@ -23,7 +24,7 @@ public void Setup() [Test] public void TestEmptyQueue() { - Assert.AreEqual(0, queue.Count); + ClassicAssert.AreEqual(0, queue.Count); Assert.Throws(() => { @@ -34,7 +35,7 @@ public void TestEmptyQueue() foreach (char unused in queue) count++; - Assert.AreEqual(0, count); + ClassicAssert.AreEqual(0, count); } [Test] @@ -45,21 +46,21 @@ public void TestEnqueue() queue.Enqueue('b'); queue.Enqueue('c'); - Assert.AreEqual('c', queue[0]); - Assert.AreEqual('b', queue[1]); - Assert.AreEqual('a', queue[2]); + ClassicAssert.AreEqual('c', queue[0]); + ClassicAssert.AreEqual('b', queue[1]); + ClassicAssert.AreEqual('a', queue[2]); // Assert correct values and reverse index after enqueueing beyond initial capacity of 4 queue.Enqueue('d'); queue.Enqueue('e'); queue.Enqueue('f'); - Assert.AreEqual('f', queue[0]); - Assert.AreEqual('e', queue[1]); - Assert.AreEqual('d', queue[2]); - Assert.AreEqual('c', queue[3]); - Assert.AreEqual('b', queue[4]); - Assert.AreEqual('a', queue[5]); + ClassicAssert.AreEqual('f', queue[0]); + ClassicAssert.AreEqual('e', queue[1]); + ClassicAssert.AreEqual('d', queue[2]); + ClassicAssert.AreEqual('c', queue[3]); + ClassicAssert.AreEqual('b', queue[4]); + ClassicAssert.AreEqual('a', queue[5]); } [Test] @@ -73,13 +74,13 @@ public void TestDequeue() queue.Enqueue('f'); // Assert correct item return and no longer in queue after dequeueing - Assert.AreEqual('a', queue[5]); + ClassicAssert.AreEqual('a', queue[5]); char dequeuedItem = queue.Dequeue(); - Assert.AreEqual('a', dequeuedItem); - Assert.AreEqual(5, queue.Count); - Assert.AreEqual('f', queue[0]); - Assert.AreEqual('b', queue[4]); + ClassicAssert.AreEqual('a', dequeuedItem); + ClassicAssert.AreEqual(5, queue.Count); + ClassicAssert.AreEqual('f', queue[0]); + ClassicAssert.AreEqual('b', queue[4]); Assert.Throws(() => { char unused = queue[5]; @@ -97,8 +98,8 @@ public void TestDequeue() queue.Dequeue(); queue.Dequeue(); - Assert.AreEqual(1, queue.Count); - Assert.AreEqual('i', queue[0]); + ClassicAssert.AreEqual(1, queue.Count); + ClassicAssert.AreEqual('i', queue[0]); } [Test] @@ -114,7 +115,7 @@ public void TestClear() // Assert queue is empty after clearing queue.Clear(); - Assert.AreEqual(0, queue.Count); + ClassicAssert.AreEqual(0, queue.Count); Assert.Throws(() => { char unused = queue[0]; @@ -137,7 +138,7 @@ public void TestEnumerator() // Assert items are enumerated in correct order foreach (char item in queue) { - Assert.AreEqual(expectedValues[expectedValueIndex], item); + ClassicAssert.AreEqual(expectedValues[expectedValueIndex], item); expectedValueIndex++; } } diff --git a/osu.Game.Tests/NonVisual/SessionStaticsTest.cs b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs index 5c8254b94743..b437c952160e 100644 --- a/osu.Game.Tests/NonVisual/SessionStaticsTest.cs +++ b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs @@ -5,6 +5,7 @@ using System; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Configuration; using osu.Game.Online.API.Requests.Responses; @@ -26,20 +27,20 @@ public void TestSessionStaticsReset() sessionStatics.SetValue(Static.LastHoverSoundPlaybackTime, (double?)1d); sessionStatics.SetValue(Static.SeasonalBackgrounds, new APISeasonalBackgrounds { EndDate = new DateTimeOffset(2022, 1, 1, 0, 0, 0, TimeSpan.Zero) }); - Assert.IsFalse(sessionStatics.GetBindable(Static.LoginOverlayDisplayed).IsDefault); - Assert.IsFalse(sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).IsDefault); - Assert.IsFalse(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault); - Assert.IsFalse(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault); - Assert.IsFalse(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault); + ClassicAssert.False(sessionStatics.GetBindable(Static.LoginOverlayDisplayed).IsDefault); + ClassicAssert.False(sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).IsDefault); + ClassicAssert.False(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault); + ClassicAssert.False(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault); + ClassicAssert.False(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault); sessionStatics.ResetAfterInactivity(); - Assert.IsTrue(sessionStatics.GetBindable(Static.LoginOverlayDisplayed).IsDefault); - Assert.IsTrue(sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).IsDefault); - Assert.IsTrue(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault); + ClassicAssert.True(sessionStatics.GetBindable(Static.LoginOverlayDisplayed).IsDefault); + ClassicAssert.True(sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).IsDefault); + ClassicAssert.True(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault); // some statics should not reset despite inactivity. - Assert.IsFalse(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault); - Assert.IsFalse(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault); + ClassicAssert.False(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault); + ClassicAssert.False(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault); } } } diff --git a/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs b/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs index 98cb66a234d3..2012052dc83f 100644 --- a/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs +++ b/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Audio; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Rendering.Dummy; @@ -93,9 +94,9 @@ public void TestFallbackOrder(string[] filesInStore, string requestedComponent, var texture = legacySkin.GetTexture(requestedComponent); - Assert.IsNotNull(texture); - Assert.AreEqual(textureStore.Textures[expectedTexture].Width, texture.Width); - Assert.AreEqual(expectedScale, texture.ScaleAdjust); + Assert.That(texture, Is.Not.Null); + ClassicAssert.AreEqual(textureStore.Textures[expectedTexture].Width, texture.Width); + ClassicAssert.AreEqual(expectedScale, texture.ScaleAdjust); } [Test] @@ -106,7 +107,7 @@ public void TestReturnNullOnFallbackFailure() var texture = legacySkin.GetTexture("Gameplay/osu/followpoint"); - Assert.IsNull(texture); + ClassicAssert.Null(texture); } [Test] @@ -117,15 +118,15 @@ public void TestDisallowHighResolutionSprites() var texture = legacySkin.GetTexture("hitcircle"); - Assert.IsNotNull(texture); + Assert.That(texture, Is.Not.Null); Assert.That(texture.ScaleAdjust, Is.EqualTo(1)); var twoTimesTexture = legacySkin.GetTexture("hitcircle@2x"); - Assert.IsNotNull(twoTimesTexture); + Assert.That(twoTimesTexture, Is.Not.Null); Assert.That(twoTimesTexture.ScaleAdjust, Is.EqualTo(1)); - Assert.AreNotEqual(texture, twoTimesTexture); + ClassicAssert.AreNotEqual(texture, twoTimesTexture); } [Test] @@ -136,15 +137,15 @@ public void TestAllowHighResolutionSprites() var texture = legacySkin.GetTexture("hitcircle"); - Assert.IsNotNull(texture); + Assert.That(texture, Is.Not.Null); Assert.That(texture.ScaleAdjust, Is.EqualTo(2)); var twoTimesTexture = legacySkin.GetTexture("hitcircle@2x"); - Assert.IsNotNull(twoTimesTexture); + Assert.That(twoTimesTexture, Is.Not.Null); Assert.That(twoTimesTexture.ScaleAdjust, Is.EqualTo(2)); - Assert.AreEqual(texture, twoTimesTexture); + ClassicAssert.AreEqual(texture, twoTimesTexture); } private class TestLegacySkin : LegacySkin diff --git a/osu.Game.Tests/NonVisual/TimeDisplayExtensionTest.cs b/osu.Game.Tests/NonVisual/TimeDisplayExtensionTest.cs index 10d592364d09..374659a48fce 100644 --- a/osu.Game.Tests/NonVisual/TimeDisplayExtensionTest.cs +++ b/osu.Game.Tests/NonVisual/TimeDisplayExtensionTest.cs @@ -3,6 +3,7 @@ using System; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Extensions; namespace osu.Game.Tests.NonVisual @@ -21,7 +22,7 @@ public class TimeDisplayExtensionTest [TestCaseSource(nameof(editor_formatted_duration_tests))] public void TestEditorFormat(TimeSpan input, string expectedOutput) { - Assert.AreEqual(expectedOutput, input.ToEditorFormattedString()); + ClassicAssert.AreEqual(expectedOutput, input.ToEditorFormattedString()); } private static readonly object[][] formatted_duration_tests = @@ -35,7 +36,7 @@ public void TestEditorFormat(TimeSpan input, string expectedOutput) [TestCaseSource(nameof(formatted_duration_tests))] public void TestFormattedDuration(TimeSpan input, string expectedOutput) { - Assert.AreEqual(expectedOutput, input.ToFormattedDuration().ToString()); + ClassicAssert.AreEqual(expectedOutput, input.ToFormattedDuration().ToString()); } } } diff --git a/osu.Game.Tests/Online/Chat/MessageNotifierTest.cs b/osu.Game.Tests/Online/Chat/MessageNotifierTest.cs index a391ec406634..f129accfa32d 100644 --- a/osu.Game.Tests/Online/Chat/MessageNotifierTest.cs +++ b/osu.Game.Tests/Online/Chat/MessageNotifierTest.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Online.Chat; namespace osu.Game.Tests.Online.Chat @@ -12,79 +13,79 @@ public class MessageNotifierTest [Test] public void TestContainsUsernameMidlinePositive() { - Assert.IsTrue(MessageNotifier.MatchUsername("This is a test message", "Test").Success); + ClassicAssert.True(MessageNotifier.MatchUsername("This is a test message", "Test").Success); } [Test] public void TestContainsUsernameStartOfLinePositive() { - Assert.IsTrue(MessageNotifier.MatchUsername("Test message", "Test").Success); + ClassicAssert.True(MessageNotifier.MatchUsername("Test message", "Test").Success); } [Test] public void TestContainsUsernameEndOfLinePositive() { - Assert.IsTrue(MessageNotifier.MatchUsername("This is a test", "Test").Success); + ClassicAssert.True(MessageNotifier.MatchUsername("This is a test", "Test").Success); } [Test] public void TestContainsUsernameMidlineNegative() { - Assert.IsFalse(MessageNotifier.MatchUsername("This is a testmessage for notifications", "Test").Success); + ClassicAssert.False(MessageNotifier.MatchUsername("This is a testmessage for notifications", "Test").Success); } [Test] public void TestContainsUsernameStartOfLineNegative() { - Assert.IsFalse(MessageNotifier.MatchUsername("Testmessage", "Test").Success); + ClassicAssert.False(MessageNotifier.MatchUsername("Testmessage", "Test").Success); } [Test] public void TestContainsUsernameEndOfLineNegative() { - Assert.IsFalse(MessageNotifier.MatchUsername("This is a notificationtest", "Test").Success); + ClassicAssert.False(MessageNotifier.MatchUsername("This is a notificationtest", "Test").Success); } [Test] public void TestContainsUsernameBetweenPunctuation() { - Assert.IsTrue(MessageNotifier.MatchUsername("Hello 'test'-message", "Test").Success); + ClassicAssert.True(MessageNotifier.MatchUsername("Hello 'test'-message", "Test").Success); } [Test] public void TestContainsUsernameUnicode() { - Assert.IsTrue(MessageNotifier.MatchUsername("Test \u0460\u0460 message", "\u0460\u0460").Success); + ClassicAssert.True(MessageNotifier.MatchUsername("Test \u0460\u0460 message", "\u0460\u0460").Success); } [Test] public void TestContainsUsernameUnicodeNegative() { - Assert.IsFalse(MessageNotifier.MatchUsername("Test ha\u0460\u0460o message", "\u0460\u0460").Success); + ClassicAssert.False(MessageNotifier.MatchUsername("Test ha\u0460\u0460o message", "\u0460\u0460").Success); } [Test] public void TestContainsUsernameSpecialCharactersPositive() { - Assert.IsTrue(MessageNotifier.MatchUsername("Test [#^-^#] message", "[#^-^#]").Success); + ClassicAssert.True(MessageNotifier.MatchUsername("Test [#^-^#] message", "[#^-^#]").Success); } [Test] public void TestContainsUsernameSpecialCharactersNegative() { - Assert.IsFalse(MessageNotifier.MatchUsername("Test pad[#^-^#]oru message", "[#^-^#]").Success); + ClassicAssert.False(MessageNotifier.MatchUsername("Test pad[#^-^#]oru message", "[#^-^#]").Success); } [Test] public void TestContainsUsernameAtSign() { - Assert.IsTrue(MessageNotifier.MatchUsername("@username hi", "username").Success); + ClassicAssert.True(MessageNotifier.MatchUsername("@username hi", "username").Success); } [Test] public void TestContainsUsernameColon() { - Assert.IsTrue(MessageNotifier.MatchUsername("username: hi", "username").Success); + ClassicAssert.True(MessageNotifier.MatchUsername("username: hi", "username").Success); } } } diff --git a/osu.Game.Tests/Online/Matchmaking/MatchmakingRoomStateTest.cs b/osu.Game.Tests/Online/Matchmaking/MatchmakingRoomStateTest.cs index 25766d46458e..9b99128154b4 100644 --- a/osu.Game.Tests/Online/Matchmaking/MatchmakingRoomStateTest.cs +++ b/osu.Game.Tests/Online/Matchmaking/MatchmakingRoomStateTest.cs @@ -3,6 +3,7 @@ using System; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; @@ -30,17 +31,17 @@ public void Basic() new SoloScoreInfo { UserID = 3, TotalScore = 750 }, ], placement_points); - Assert.AreEqual(8, state.Users.GetOrAdd(1).Points); - Assert.AreEqual(1, state.Users.GetOrAdd(1).Placement); - Assert.AreEqual(1, state.Users.GetOrAdd(1).Rounds.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(8, state.Users.GetOrAdd(1).Points); + ClassicAssert.AreEqual(1, state.Users.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(1, state.Users.GetOrAdd(1).Rounds.GetOrAdd(1).Placement); - Assert.AreEqual(6, state.Users.GetOrAdd(2).Points); - Assert.AreEqual(3, state.Users.GetOrAdd(2).Placement); - Assert.AreEqual(3, state.Users.GetOrAdd(2).Rounds.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(6, state.Users.GetOrAdd(2).Points); + ClassicAssert.AreEqual(3, state.Users.GetOrAdd(2).Placement); + ClassicAssert.AreEqual(3, state.Users.GetOrAdd(2).Rounds.GetOrAdd(1).Placement); - Assert.AreEqual(7, state.Users.GetOrAdd(3).Points); - Assert.AreEqual(2, state.Users.GetOrAdd(3).Placement); - Assert.AreEqual(2, state.Users.GetOrAdd(3).Rounds.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(7, state.Users.GetOrAdd(3).Points); + ClassicAssert.AreEqual(2, state.Users.GetOrAdd(3).Placement); + ClassicAssert.AreEqual(2, state.Users.GetOrAdd(3).Rounds.GetOrAdd(1).Placement); // 2 -> 1 -> 3 @@ -52,17 +53,17 @@ public void Basic() new SoloScoreInfo { UserID = 3, TotalScore = 500 }, ], placement_points); - Assert.AreEqual(15, state.Users.GetOrAdd(1).Points); - Assert.AreEqual(1, state.Users.GetOrAdd(1).Placement); - Assert.AreEqual(2, state.Users.GetOrAdd(1).Rounds.GetOrAdd(2).Placement); + ClassicAssert.AreEqual(15, state.Users.GetOrAdd(1).Points); + ClassicAssert.AreEqual(1, state.Users.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(2, state.Users.GetOrAdd(1).Rounds.GetOrAdd(2).Placement); - Assert.AreEqual(14, state.Users.GetOrAdd(2).Points); - Assert.AreEqual(2, state.Users.GetOrAdd(2).Placement); - Assert.AreEqual(1, state.Users.GetOrAdd(2).Rounds.GetOrAdd(2).Placement); + ClassicAssert.AreEqual(14, state.Users.GetOrAdd(2).Points); + ClassicAssert.AreEqual(2, state.Users.GetOrAdd(2).Placement); + ClassicAssert.AreEqual(1, state.Users.GetOrAdd(2).Rounds.GetOrAdd(2).Placement); - Assert.AreEqual(13, state.Users.GetOrAdd(3).Points); - Assert.AreEqual(3, state.Users.GetOrAdd(3).Placement); - Assert.AreEqual(3, state.Users.GetOrAdd(3).Rounds.GetOrAdd(2).Placement); + ClassicAssert.AreEqual(13, state.Users.GetOrAdd(3).Points); + ClassicAssert.AreEqual(3, state.Users.GetOrAdd(3).Placement); + ClassicAssert.AreEqual(3, state.Users.GetOrAdd(3).Rounds.GetOrAdd(2).Placement); } [Test] @@ -81,21 +82,21 @@ public void MatchingScores() new SoloScoreInfo { UserID = 4, TotalScore = 500 }, ], placement_points); - Assert.AreEqual(7, state.Users.GetOrAdd(1).Points); - Assert.AreEqual(1, state.Users.GetOrAdd(1).Placement); - Assert.AreEqual(2, state.Users.GetOrAdd(1).Rounds.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(7, state.Users.GetOrAdd(1).Points); + ClassicAssert.AreEqual(1, state.Users.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(2, state.Users.GetOrAdd(1).Rounds.GetOrAdd(1).Placement); - Assert.AreEqual(7, state.Users.GetOrAdd(2).Points); - Assert.AreEqual(2, state.Users.GetOrAdd(2).Placement); - Assert.AreEqual(2, state.Users.GetOrAdd(2).Rounds.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(7, state.Users.GetOrAdd(2).Points); + ClassicAssert.AreEqual(2, state.Users.GetOrAdd(2).Placement); + ClassicAssert.AreEqual(2, state.Users.GetOrAdd(2).Rounds.GetOrAdd(1).Placement); - Assert.AreEqual(5, state.Users.GetOrAdd(3).Points); - Assert.AreEqual(3, state.Users.GetOrAdd(3).Placement); - Assert.AreEqual(4, state.Users.GetOrAdd(3).Rounds.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(5, state.Users.GetOrAdd(3).Points); + ClassicAssert.AreEqual(3, state.Users.GetOrAdd(3).Placement); + ClassicAssert.AreEqual(4, state.Users.GetOrAdd(3).Rounds.GetOrAdd(1).Placement); - Assert.AreEqual(5, state.Users.GetOrAdd(4).Points); - Assert.AreEqual(4, state.Users.GetOrAdd(4).Placement); - Assert.AreEqual(4, state.Users.GetOrAdd(4).Rounds.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(5, state.Users.GetOrAdd(4).Points); + ClassicAssert.AreEqual(4, state.Users.GetOrAdd(4).Placement); + ClassicAssert.AreEqual(4, state.Users.GetOrAdd(4).Rounds.GetOrAdd(1).Placement); } [Test] @@ -121,8 +122,8 @@ public void RoundTieBreaker() new SoloScoreInfo { UserID = 2, TotalScore = 1000 }, ], placement_points); - Assert.AreEqual(1, state.Users.GetOrAdd(1).Placement); - Assert.AreEqual(2, state.Users.GetOrAdd(2).Placement); + ClassicAssert.AreEqual(1, state.Users.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(2, state.Users.GetOrAdd(2).Placement); } [Test] @@ -143,12 +144,12 @@ public void UserIdTieBreaker() new SoloScoreInfo { UserID = 5, TotalScore = 1000 }, ], placement_points); - Assert.AreEqual(1, state.Users.GetOrAdd(1).Placement); - Assert.AreEqual(2, state.Users.GetOrAdd(2).Placement); - Assert.AreEqual(3, state.Users.GetOrAdd(3).Placement); - Assert.AreEqual(4, state.Users.GetOrAdd(4).Placement); - Assert.AreEqual(5, state.Users.GetOrAdd(5).Placement); - Assert.AreEqual(6, state.Users.GetOrAdd(6).Placement); + ClassicAssert.AreEqual(1, state.Users.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(2, state.Users.GetOrAdd(2).Placement); + ClassicAssert.AreEqual(3, state.Users.GetOrAdd(3).Placement); + ClassicAssert.AreEqual(4, state.Users.GetOrAdd(4).Placement); + ClassicAssert.AreEqual(5, state.Users.GetOrAdd(5).Placement); + ClassicAssert.AreEqual(6, state.Users.GetOrAdd(6).Placement); } [Test] @@ -163,20 +164,20 @@ public void AbandonOrder() new SoloScoreInfo { UserID = 2, TotalScore = 500 }, ], placement_points); - Assert.AreEqual(1, state.Users.GetOrAdd(1).Placement); - Assert.AreEqual(2, state.Users.GetOrAdd(2).Placement); + ClassicAssert.AreEqual(1, state.Users.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(2, state.Users.GetOrAdd(2).Placement); state.Users.GetOrAdd(1).AbandonedAt = DateTimeOffset.Now; state.RecordScores([], placement_points); - Assert.AreEqual(2, state.Users.GetOrAdd(1).Placement); - Assert.AreEqual(1, state.Users.GetOrAdd(2).Placement); + ClassicAssert.AreEqual(2, state.Users.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(1, state.Users.GetOrAdd(2).Placement); state.Users.GetOrAdd(2).AbandonedAt = DateTimeOffset.Now - TimeSpan.FromMinutes(1); state.RecordScores([], placement_points); - Assert.AreEqual(1, state.Users.GetOrAdd(1).Placement); - Assert.AreEqual(2, state.Users.GetOrAdd(2).Placement); + ClassicAssert.AreEqual(1, state.Users.GetOrAdd(1).Placement); + ClassicAssert.AreEqual(2, state.Users.GetOrAdd(2).Placement); } } } diff --git a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs index da250c1e0579..55984278b152 100644 --- a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs +++ b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs @@ -8,6 +8,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Game.Beatmaps; @@ -36,7 +37,7 @@ public void TestUnknownMod() var converted = deserialized?.ToMod(new TestRuleset()); - Assert.NotNull(converted); + Assert.That(converted, Is.Not.Null); Assert.That(converted, Is.TypeOf(typeof(UnknownMod))); Assert.That(converted.Type, Is.EqualTo(ModType.System)); Assert.That(converted.Acronym, Is.EqualTo("WNG??")); @@ -157,7 +158,7 @@ public void TestSerialisedModSettingPresence() mod.TestSetting.Value = mod.TestSetting.Default; JObject serialised = JObject.Parse(JsonConvert.SerializeObject(new APIMod(mod))); - Assert.False(serialised.ContainsKey("settings")); + ClassicAssert.False(serialised.ContainsKey("settings")); } private class TestRuleset : Ruleset diff --git a/osu.Game.Tests/Online/TestMultiplayerMessagePackSerialization.cs b/osu.Game.Tests/Online/TestMultiplayerMessagePackSerialization.cs index c440f375fdea..da21ff6fcbf8 100644 --- a/osu.Game.Tests/Online/TestMultiplayerMessagePackSerialization.cs +++ b/osu.Game.Tests/Online/TestMultiplayerMessagePackSerialization.cs @@ -3,6 +3,7 @@ using MessagePack; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Online; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; @@ -24,7 +25,7 @@ public void TestSerialiseRoom() var deserialized = MessagePackSerializer.Deserialize(serialized); - Assert.IsTrue(deserialized.MatchState is TeamVersusRoomState); + ClassicAssert.True(deserialized.MatchState is TeamVersusRoomState); } [Test] @@ -35,7 +36,7 @@ public void TestSerialiseUserStateExpected() byte[] serialized = MessagePackSerializer.Serialize(typeof(MatchUserState), state); var deserialized = MessagePackSerializer.Deserialize(serialized); - Assert.IsTrue(deserialized is TeamVersusUserState); + ClassicAssert.True(deserialized is TeamVersusUserState); } [Test] @@ -66,7 +67,7 @@ public void TestSerialiseUnionSucceedsWithWorkaround() // works with custom resolver. var deserialized = MessagePackSerializer.Deserialize(serialized, SignalRUnionWorkaroundResolver.OPTIONS); - Assert.IsTrue(deserialized is TeamVersusUserState); + ClassicAssert.True(deserialized is TeamVersusUserState); } } } diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs index 469bc8ee7394..d7e2ea48c55d 100644 --- a/osu.Game.Tests/Resources/TestResources.cs +++ b/osu.Game.Tests/Resources/TestResources.cs @@ -9,7 +9,7 @@ using System.Linq; using System.Text; using System.Threading; -using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Extensions; using osu.Framework.IO.Stores; using osu.Framework.Logging; @@ -55,7 +55,7 @@ public static string GetQuickTestBeatmapForImport() using (var newFile = File.Create(tempPath)) stream.CopyTo(newFile); - Assert.IsTrue(File.Exists(tempPath)); + ClassicAssert.True(File.Exists(tempPath)); return tempPath; } @@ -72,7 +72,7 @@ public static string GetTestBeatmapForImport(bool virtualTrack = false) using (var newFile = File.Create(tempPath)) stream.CopyTo(newFile); - Assert.IsTrue(File.Exists(tempPath)); + ClassicAssert.True(File.Exists(tempPath)); return tempPath; } diff --git a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs index 9b87ce4bb477..db900d57fc0c 100644 --- a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs +++ b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets; @@ -174,7 +175,7 @@ public void TestEmptyBeatmap( [TestCase(HitResult.LargeBonus, HitResult.IgnoreMiss)] public void TestMinResults(HitResult hitResult, HitResult expectedMinResult) { - Assert.AreEqual(expectedMinResult, new TestJudgement(hitResult).MinResult); + ClassicAssert.AreEqual(expectedMinResult, new TestJudgement(hitResult).MinResult); } [TestCase(HitResult.None, false)] @@ -195,7 +196,7 @@ public void TestMinResults(HitResult hitResult, HitResult expectedMinResult) [TestCase(HitResult.LargeBonus, false)] public void TestAffectsCombo(HitResult hitResult, bool expectedReturnValue) { - Assert.AreEqual(expectedReturnValue, hitResult.AffectsCombo()); + ClassicAssert.AreEqual(expectedReturnValue, hitResult.AffectsCombo()); } [TestCase(HitResult.None, false)] @@ -216,7 +217,7 @@ public void TestAffectsCombo(HitResult hitResult, bool expectedReturnValue) [TestCase(HitResult.LargeBonus, false)] public void TestAffectsAccuracy(HitResult hitResult, bool expectedReturnValue) { - Assert.AreEqual(expectedReturnValue, hitResult.AffectsAccuracy()); + ClassicAssert.AreEqual(expectedReturnValue, hitResult.AffectsAccuracy()); } [TestCase(HitResult.None, false)] @@ -237,7 +238,7 @@ public void TestAffectsAccuracy(HitResult hitResult, bool expectedReturnValue) [TestCase(HitResult.LargeBonus, true)] public void TestIsBonus(HitResult hitResult, bool expectedReturnValue) { - Assert.AreEqual(expectedReturnValue, hitResult.IsBonus()); + ClassicAssert.AreEqual(expectedReturnValue, hitResult.IsBonus()); } [TestCase(HitResult.None, false)] @@ -258,7 +259,7 @@ public void TestIsBonus(HitResult hitResult, bool expectedReturnValue) [TestCase(HitResult.LargeBonus, true)] public void TestIsHit(HitResult hitResult, bool expectedReturnValue) { - Assert.AreEqual(expectedReturnValue, hitResult.IsHit()); + ClassicAssert.AreEqual(expectedReturnValue, hitResult.IsHit()); } [TestCase(HitResult.None, false)] @@ -279,7 +280,7 @@ public void TestIsHit(HitResult hitResult, bool expectedReturnValue) [TestCase(HitResult.LargeBonus, true)] public void TestIsScorable(HitResult hitResult, bool expectedReturnValue) { - Assert.AreEqual(expectedReturnValue, hitResult.IsScorable()); + ClassicAssert.AreEqual(expectedReturnValue, hitResult.IsScorable()); } #pragma warning disable CS0618 diff --git a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs index 6558834a63bc..b1144c5bc257 100644 --- a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs +++ b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Platform; @@ -57,13 +58,13 @@ public void TestBasicImport() var imported = LoadScoreIntoOsu(osu, toImport); - Assert.AreEqual(toImport.Rank, imported.Rank); - Assert.AreEqual(toImport.TotalScore, imported.TotalScore); - Assert.AreEqual(toImport.Accuracy, imported.Accuracy); - Assert.AreEqual(toImport.MaxCombo, imported.MaxCombo); - Assert.AreEqual(toImport.User.Username, imported.User.Username); - Assert.AreEqual(toImport.Date, imported.Date); - Assert.AreEqual(toImport.OnlineID, imported.OnlineID); + ClassicAssert.AreEqual(toImport.Rank, imported.Rank); + ClassicAssert.AreEqual(toImport.TotalScore, imported.TotalScore); + ClassicAssert.AreEqual(toImport.Accuracy, imported.Accuracy); + ClassicAssert.AreEqual(toImport.MaxCombo, imported.MaxCombo); + ClassicAssert.AreEqual(toImport.User.Username, imported.User.Username); + ClassicAssert.AreEqual(toImport.Date, imported.Date); + ClassicAssert.AreEqual(toImport.OnlineID, imported.OnlineID); } finally { @@ -110,13 +111,13 @@ public void TestLastPlayedUpdate(bool isLocalUser) var imported = LoadScoreIntoOsu(osu, toImport); - Assert.AreEqual(toImport.Rank, imported.Rank); - Assert.AreEqual(toImport.TotalScore, imported.TotalScore); - Assert.AreEqual(toImport.Accuracy, imported.Accuracy); - Assert.AreEqual(toImport.MaxCombo, imported.MaxCombo); - Assert.AreEqual(toImport.User.Username, imported.User.Username); - Assert.AreEqual(toImport.Date, imported.Date); - Assert.AreEqual(toImport.OnlineID, imported.OnlineID); + ClassicAssert.AreEqual(toImport.Rank, imported.Rank); + ClassicAssert.AreEqual(toImport.TotalScore, imported.TotalScore); + ClassicAssert.AreEqual(toImport.Accuracy, imported.Accuracy); + ClassicAssert.AreEqual(toImport.MaxCombo, imported.MaxCombo); + ClassicAssert.AreEqual(toImport.User.Username, imported.User.Username); + ClassicAssert.AreEqual(toImport.Date, imported.Date); + ClassicAssert.AreEqual(toImport.OnlineID, imported.OnlineID); if (isLocalUser) Assert.That(imported.BeatmapInfo!.LastPlayed, Is.EqualTo(replayDate)); @@ -165,13 +166,13 @@ public void TestLastPlayedNotUpdatedDueToNewerPlays() var imported = LoadScoreIntoOsu(osu, toImport); - Assert.AreEqual(toImport.Rank, imported.Rank); - Assert.AreEqual(toImport.TotalScore, imported.TotalScore); - Assert.AreEqual(toImport.Accuracy, imported.Accuracy); - Assert.AreEqual(toImport.MaxCombo, imported.MaxCombo); - Assert.AreEqual(toImport.User.Username, imported.User.Username); - Assert.AreEqual(toImport.Date, imported.Date); - Assert.AreEqual(toImport.OnlineID, imported.OnlineID); + ClassicAssert.AreEqual(toImport.Rank, imported.Rank); + ClassicAssert.AreEqual(toImport.TotalScore, imported.TotalScore); + ClassicAssert.AreEqual(toImport.Accuracy, imported.Accuracy); + ClassicAssert.AreEqual(toImport.MaxCombo, imported.MaxCombo); + ClassicAssert.AreEqual(toImport.User.Username, imported.User.Username); + ClassicAssert.AreEqual(toImport.Date, imported.Date); + ClassicAssert.AreEqual(toImport.OnlineID, imported.OnlineID); Assert.That(imported.BeatmapInfo!.LastPlayed, Is.EqualTo(new DateTimeOffset(2023, 10, 30, 0, 0, 0, TimeSpan.Zero))); } @@ -204,8 +205,8 @@ public void TestImportMods() var imported = LoadScoreIntoOsu(osu, toImport); - Assert.IsTrue(imported.Mods.Any(m => m is OsuModHardRock)); - Assert.IsTrue(imported.Mods.Any(m => m is OsuModDoubleTime)); + ClassicAssert.True(imported.Mods.Any(m => m is OsuModHardRock)); + ClassicAssert.True(imported.Mods.Any(m => m is OsuModDoubleTime)); Assert.That(imported.ClientVersion, Is.EqualTo(toImport.ClientVersion)); } finally @@ -269,8 +270,8 @@ public void TestImportStatistics() var imported = LoadScoreIntoOsu(osu, toImport); - Assert.AreEqual(toImport.Statistics[HitResult.Perfect], imported.Statistics[HitResult.Perfect]); - Assert.AreEqual(toImport.Statistics[HitResult.Miss], imported.Statistics[HitResult.Miss]); + ClassicAssert.AreEqual(toImport.Statistics[HitResult.Perfect], imported.Statistics[HitResult.Perfect]); + ClassicAssert.AreEqual(toImport.Statistics[HitResult.Miss], imported.Statistics[HitResult.Miss]); } finally { @@ -364,15 +365,15 @@ public void TestUserLookedUpByUsernameForOnlineScoreIfUserIDMissing() var imported = LoadScoreIntoOsu(osu, toImport); - Assert.AreEqual(toImport.Rank, imported.Rank); - Assert.AreEqual(toImport.TotalScore, imported.TotalScore); - Assert.AreEqual(toImport.Accuracy, imported.Accuracy); - Assert.AreEqual(toImport.MaxCombo, imported.MaxCombo); - Assert.AreEqual(toImport.User.Username, imported.User.Username); - Assert.AreEqual(toImport.Date, imported.Date); - Assert.AreEqual(toImport.OnlineID, imported.OnlineID); - Assert.AreEqual(toImport.User.Username, imported.RealmUser.Username); - Assert.AreEqual(1234, imported.RealmUser.OnlineID); + ClassicAssert.AreEqual(toImport.Rank, imported.Rank); + ClassicAssert.AreEqual(toImport.TotalScore, imported.TotalScore); + ClassicAssert.AreEqual(toImport.Accuracy, imported.Accuracy); + ClassicAssert.AreEqual(toImport.MaxCombo, imported.MaxCombo); + ClassicAssert.AreEqual(toImport.User.Username, imported.User.Username); + ClassicAssert.AreEqual(toImport.Date, imported.Date); + ClassicAssert.AreEqual(toImport.OnlineID, imported.OnlineID); + ClassicAssert.AreEqual(toImport.User.Username, imported.RealmUser.Username); + ClassicAssert.AreEqual(1234, imported.RealmUser.OnlineID); } finally { @@ -430,15 +431,15 @@ public void TestUserLookedUpByUsernameForLegacyOnlineScore() var imported = LoadScoreIntoOsu(osu, toImport); - Assert.AreEqual(toImport.Rank, imported.Rank); - Assert.AreEqual(toImport.TotalScore, imported.TotalScore); - Assert.AreEqual(toImport.Accuracy, imported.Accuracy); - Assert.AreEqual(toImport.MaxCombo, imported.MaxCombo); - Assert.AreEqual(toImport.User.Username, imported.User.Username); - Assert.AreEqual(toImport.Date, imported.Date); - Assert.AreEqual(toImport.OnlineID, imported.OnlineID); - Assert.AreEqual(toImport.User.Username, imported.RealmUser.Username); - Assert.AreEqual(1234, imported.RealmUser.OnlineID); + ClassicAssert.AreEqual(toImport.Rank, imported.Rank); + ClassicAssert.AreEqual(toImport.TotalScore, imported.TotalScore); + ClassicAssert.AreEqual(toImport.Accuracy, imported.Accuracy); + ClassicAssert.AreEqual(toImport.MaxCombo, imported.MaxCombo); + ClassicAssert.AreEqual(toImport.User.Username, imported.User.Username); + ClassicAssert.AreEqual(toImport.Date, imported.Date); + ClassicAssert.AreEqual(toImport.OnlineID, imported.OnlineID); + ClassicAssert.AreEqual(toImport.User.Username, imported.RealmUser.Username); + ClassicAssert.AreEqual(1234, imported.RealmUser.OnlineID); } finally { @@ -497,14 +498,14 @@ public void TestUserNotLookedUpForOfflineScoreIfUserIDMissing() var imported = LoadScoreIntoOsu(osu, toImport); - Assert.AreEqual(toImport.Rank, imported.Rank); - Assert.AreEqual(toImport.TotalScore, imported.TotalScore); - Assert.AreEqual(toImport.Accuracy, imported.Accuracy); - Assert.AreEqual(toImport.MaxCombo, imported.MaxCombo); - Assert.AreEqual(toImport.User.Username, imported.User.Username); - Assert.AreEqual(toImport.Date, imported.Date); - Assert.AreEqual(toImport.OnlineID, imported.OnlineID); - Assert.AreEqual(toImport.User.Username, imported.RealmUser.Username); + ClassicAssert.AreEqual(toImport.Rank, imported.Rank); + ClassicAssert.AreEqual(toImport.TotalScore, imported.TotalScore); + ClassicAssert.AreEqual(toImport.Accuracy, imported.Accuracy); + ClassicAssert.AreEqual(toImport.MaxCombo, imported.MaxCombo); + ClassicAssert.AreEqual(toImport.User.Username, imported.User.Username); + ClassicAssert.AreEqual(toImport.Date, imported.Date); + ClassicAssert.AreEqual(toImport.OnlineID, imported.OnlineID); + ClassicAssert.AreEqual(toImport.User.Username, imported.RealmUser.Username); Assert.That(imported.RealmUser.OnlineID, Is.LessThanOrEqualTo(1)); } finally @@ -564,15 +565,15 @@ public void TestUserLookedUpByOnlineIDIfPresent([Values] bool isOnlineScore) var imported = LoadScoreIntoOsu(osu, toImport); - Assert.AreEqual(toImport.Rank, imported.Rank); - Assert.AreEqual(toImport.TotalScore, imported.TotalScore); - Assert.AreEqual(toImport.Accuracy, imported.Accuracy); - Assert.AreEqual(toImport.MaxCombo, imported.MaxCombo); - Assert.AreEqual(toImport.Date, imported.Date); - Assert.AreEqual(toImport.OnlineID, imported.OnlineID); - Assert.AreEqual("Some other guy", imported.RealmUser.Username); - Assert.AreEqual(5555, imported.RealmUser.OnlineID); - Assert.AreEqual(CountryCode.DE, imported.RealmUser.CountryCode); + ClassicAssert.AreEqual(toImport.Rank, imported.Rank); + ClassicAssert.AreEqual(toImport.TotalScore, imported.TotalScore); + ClassicAssert.AreEqual(toImport.Accuracy, imported.Accuracy); + ClassicAssert.AreEqual(toImport.MaxCombo, imported.MaxCombo); + ClassicAssert.AreEqual(toImport.Date, imported.Date); + ClassicAssert.AreEqual(toImport.OnlineID, imported.OnlineID); + ClassicAssert.AreEqual("Some other guy", imported.RealmUser.Username); + ClassicAssert.AreEqual(5555, imported.RealmUser.OnlineID); + ClassicAssert.AreEqual(CountryCode.DE, imported.RealmUser.CountryCode); } finally { diff --git a/osu.Game.Tests/ScrollAlgorithms/ConstantScrollTest.cs b/osu.Game.Tests/ScrollAlgorithms/ConstantScrollTest.cs index 0994803d8303..94c34971d4b7 100644 --- a/osu.Game.Tests/ScrollAlgorithms/ConstantScrollTest.cs +++ b/osu.Game.Tests/ScrollAlgorithms/ConstantScrollTest.cs @@ -4,6 +4,7 @@ #nullable disable using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Rulesets.UI.Scrolling.Algorithms; namespace osu.Game.Tests.ScrollAlgorithms @@ -22,33 +23,33 @@ public void Setup() [Test] public void TestPointDisplayStartTime() { - Assert.AreEqual(-8000, algorithm.GetDisplayStartTime(2000, 0, 10000, 1)); - Assert.AreEqual(-3000, algorithm.GetDisplayStartTime(2000, 0, 5000, 1)); - Assert.AreEqual(2000, algorithm.GetDisplayStartTime(7000, 0, 5000, 1)); - Assert.AreEqual(7000, algorithm.GetDisplayStartTime(17000, 0, 10000, 1)); + ClassicAssert.AreEqual(-8000, algorithm.GetDisplayStartTime(2000, 0, 10000, 1)); + ClassicAssert.AreEqual(-3000, algorithm.GetDisplayStartTime(2000, 0, 5000, 1)); + ClassicAssert.AreEqual(2000, algorithm.GetDisplayStartTime(7000, 0, 5000, 1)); + ClassicAssert.AreEqual(7000, algorithm.GetDisplayStartTime(17000, 0, 10000, 1)); } [Test] public void TestObjectDisplayStartTime() { - Assert.AreEqual(900, algorithm.GetDisplayStartTime(2000, 50, 1000, 500)); // 2000 - (1 + 50 / 500) * 1000 - Assert.AreEqual(8900, algorithm.GetDisplayStartTime(10000, 50, 1000, 500)); // 10000 - (1 + 50 / 500) * 1000 - Assert.AreEqual(13500, algorithm.GetDisplayStartTime(15000, 250, 1000, 500)); // 15000 - (1 + 250 / 500) * 1000 - Assert.AreEqual(19000, algorithm.GetDisplayStartTime(25000, 100, 5000, 500)); // 25000 - (1 + 100 / 500) * 5000 + ClassicAssert.AreEqual(900, algorithm.GetDisplayStartTime(2000, 50, 1000, 500)); // 2000 - (1 + 50 / 500) * 1000 + ClassicAssert.AreEqual(8900, algorithm.GetDisplayStartTime(10000, 50, 1000, 500)); // 10000 - (1 + 50 / 500) * 1000 + ClassicAssert.AreEqual(13500, algorithm.GetDisplayStartTime(15000, 250, 1000, 500)); // 15000 - (1 + 250 / 500) * 1000 + ClassicAssert.AreEqual(19000, algorithm.GetDisplayStartTime(25000, 100, 5000, 500)); // 25000 - (1 + 100 / 500) * 5000 } [Test] public void TestLength() { - Assert.AreEqual(1f / 5, algorithm.GetLength(0, 1000, 5000, 1)); - Assert.AreEqual(1f / 5, algorithm.GetLength(6000, 7000, 5000, 1)); + ClassicAssert.AreEqual(1f / 5, algorithm.GetLength(0, 1000, 5000, 1)); + ClassicAssert.AreEqual(1f / 5, algorithm.GetLength(6000, 7000, 5000, 1)); } [Test] public void TestPosition() { - Assert.AreEqual(1f / 5, algorithm.PositionAt(1000, 0, 5000, 1)); - Assert.AreEqual(1f / 5, algorithm.PositionAt(6000, 5000, 5000, 1)); + ClassicAssert.AreEqual(1f / 5, algorithm.PositionAt(1000, 0, 5000, 1)); + ClassicAssert.AreEqual(1f / 5, algorithm.PositionAt(6000, 5000, 5000, 1)); } [TestCase(1000)] @@ -58,8 +59,8 @@ public void TestPosition() [TestCase(25000)] public void TestTime(double time) { - Assert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 0, 5000, 1), 0, 5000, 1), 0.001); - Assert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 5000, 5000, 1), 5000, 5000, 1), 0.001); + ClassicAssert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 0, 5000, 1), 0, 5000, 1), 0.001); + ClassicAssert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 5000, 5000, 1), 5000, 5000, 1), 0.001); } } } diff --git a/osu.Game.Tests/ScrollAlgorithms/OverlappingScrollTest.cs b/osu.Game.Tests/ScrollAlgorithms/OverlappingScrollTest.cs index c1f647cb0719..f954f13b0b11 100644 --- a/osu.Game.Tests/ScrollAlgorithms/OverlappingScrollTest.cs +++ b/osu.Game.Tests/ScrollAlgorithms/OverlappingScrollTest.cs @@ -4,6 +4,7 @@ #nullable disable using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Lists; using osu.Game.Rulesets.Timing; using osu.Game.Rulesets.UI.Scrolling.Algorithms; @@ -31,37 +32,37 @@ public void Setup() [Test] public void TestPointDisplayStartTime() { - Assert.AreEqual(1000, algorithm.GetDisplayStartTime(2000, 0, 1000, 1)); // Like constant - Assert.AreEqual(10000, algorithm.GetDisplayStartTime(10500, 0, 1000, 1)); // 10500 - (1000 * 0.5) - Assert.AreEqual(20000, algorithm.GetDisplayStartTime(22000, 0, 1000, 1)); // 23000 - (1000 / 0.5) + ClassicAssert.AreEqual(1000, algorithm.GetDisplayStartTime(2000, 0, 1000, 1)); // Like constant + ClassicAssert.AreEqual(10000, algorithm.GetDisplayStartTime(10500, 0, 1000, 1)); // 10500 - (1000 * 0.5) + ClassicAssert.AreEqual(20000, algorithm.GetDisplayStartTime(22000, 0, 1000, 1)); // 23000 - (1000 / 0.5) } [Test] public void TestObjectDisplayStartTime() { - Assert.AreEqual(900, algorithm.GetDisplayStartTime(2000, 50, 1000, 500)); // 2000 - (1 + 50 / 500) * 1000 / 1 - Assert.AreEqual(9450, algorithm.GetDisplayStartTime(10000, 50, 1000, 500)); // 10000 - (1 + 50 / 500) * 1000 / 2 - Assert.AreEqual(14250, algorithm.GetDisplayStartTime(15000, 250, 1000, 500)); // 15000 - (1 + 250 / 500) * 1000 / 2 - Assert.AreEqual(16500, algorithm.GetDisplayStartTime(18000, 250, 2000, 500)); // 18000 - (1 + 250 / 500) * 2000 / 2 - Assert.AreEqual(17800, algorithm.GetDisplayStartTime(20000, 50, 1000, 500)); // 20000 - (1 + 50 / 500) * 1000 / 0.5 - Assert.AreEqual(19800, algorithm.GetDisplayStartTime(22000, 50, 1000, 500)); // 22000 - (1 + 50 / 500) * 1000 / 0.5 + ClassicAssert.AreEqual(900, algorithm.GetDisplayStartTime(2000, 50, 1000, 500)); // 2000 - (1 + 50 / 500) * 1000 / 1 + ClassicAssert.AreEqual(9450, algorithm.GetDisplayStartTime(10000, 50, 1000, 500)); // 10000 - (1 + 50 / 500) * 1000 / 2 + ClassicAssert.AreEqual(14250, algorithm.GetDisplayStartTime(15000, 250, 1000, 500)); // 15000 - (1 + 250 / 500) * 1000 / 2 + ClassicAssert.AreEqual(16500, algorithm.GetDisplayStartTime(18000, 250, 2000, 500)); // 18000 - (1 + 250 / 500) * 2000 / 2 + ClassicAssert.AreEqual(17800, algorithm.GetDisplayStartTime(20000, 50, 1000, 500)); // 20000 - (1 + 50 / 500) * 1000 / 0.5 + ClassicAssert.AreEqual(19800, algorithm.GetDisplayStartTime(22000, 50, 1000, 500)); // 22000 - (1 + 50 / 500) * 1000 / 0.5 } [Test] public void TestLength() { - Assert.AreEqual(1f / 5, algorithm.GetLength(0, 1000, 5000, 1)); // Like constant - Assert.AreEqual(1f / 5, algorithm.GetLength(10000, 10500, 5000, 1)); // (10500 - 10000) / 0.5 / 5000 - Assert.AreEqual(1f / 5, algorithm.GetLength(20000, 22000, 5000, 1)); // (22000 - 20000) * 0.5 / 5000 + ClassicAssert.AreEqual(1f / 5, algorithm.GetLength(0, 1000, 5000, 1)); // Like constant + ClassicAssert.AreEqual(1f / 5, algorithm.GetLength(10000, 10500, 5000, 1)); // (10500 - 10000) / 0.5 / 5000 + ClassicAssert.AreEqual(1f / 5, algorithm.GetLength(20000, 22000, 5000, 1)); // (22000 - 20000) * 0.5 / 5000 } [Test] public void TestPosition() { // Basically same calculations as TestLength() - Assert.AreEqual(1f / 5, algorithm.PositionAt(1000, 0, 5000, 1)); - Assert.AreEqual(1f / 5, algorithm.PositionAt(10500, 10000, 5000, 1)); - Assert.AreEqual(1f / 5, algorithm.PositionAt(22000, 20000, 5000, 1)); + ClassicAssert.AreEqual(1f / 5, algorithm.PositionAt(1000, 0, 5000, 1)); + ClassicAssert.AreEqual(1f / 5, algorithm.PositionAt(10500, 10000, 5000, 1)); + ClassicAssert.AreEqual(1f / 5, algorithm.PositionAt(22000, 20000, 5000, 1)); } [TestCase(1000)] @@ -73,8 +74,8 @@ public void TestPosition() + "Ideally, scrolling should be changed to constant or sequential during editing of hitobjects.")] public void TestTime(double time) { - Assert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 0, 5000, 1), 0, 5000, 1), 0.001); - Assert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 5000, 5000, 1), 5000, 5000, 1), 0.001); + ClassicAssert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 0, 5000, 1), 0, 5000, 1), 0.001); + ClassicAssert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 5000, 5000, 1), 5000, 5000, 1), 0.001); } } } diff --git a/osu.Game.Tests/ScrollAlgorithms/SequentialScrollTest.cs b/osu.Game.Tests/ScrollAlgorithms/SequentialScrollTest.cs index ca6ac63619f4..e392c7030dc7 100644 --- a/osu.Game.Tests/ScrollAlgorithms/SequentialScrollTest.cs +++ b/osu.Game.Tests/ScrollAlgorithms/SequentialScrollTest.cs @@ -4,6 +4,7 @@ #nullable disable using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Lists; using osu.Game.Rulesets.Timing; using osu.Game.Rulesets.UI.Scrolling.Algorithms; @@ -32,9 +33,9 @@ public void Setup() public void TestDisplayStartTime() { // easy cases - time range adjusted for velocity fits within control point duration - Assert.AreEqual(2500, algorithm.GetDisplayStartTime(5000, 0, 2500, 1)); // 5000 - (2500 / 1) - Assert.AreEqual(13750, algorithm.GetDisplayStartTime(15000, 0, 2500, 1)); // 15000 - (2500 / 2) - Assert.AreEqual(20000, algorithm.GetDisplayStartTime(25000, 0, 2500, 1)); // 25000 - (2500 / 0.5) + ClassicAssert.AreEqual(2500, algorithm.GetDisplayStartTime(5000, 0, 2500, 1)); // 5000 - (2500 / 1) + ClassicAssert.AreEqual(13750, algorithm.GetDisplayStartTime(15000, 0, 2500, 1)); // 15000 - (2500 / 2) + ClassicAssert.AreEqual(20000, algorithm.GetDisplayStartTime(25000, 0, 2500, 1)); // 25000 - (2500 / 0.5) // hard case - time range adjusted for velocity exceeds control point duration @@ -46,24 +47,24 @@ public void TestDisplayStartTime() // minus one scroll length allowance = 12500 - 1000 = 11500 = 11.5 [scroll lengths] // therefore the start time lies within the second multiplier point (because 11.5 < 4 + 8) // its exact time position is = 10000 + 7.5 * (2500 / 2) = 19375 - Assert.AreEqual(19375, algorithm.GetDisplayStartTime(22500, 0, 2500, 1000)); + ClassicAssert.AreEqual(19375, algorithm.GetDisplayStartTime(22500, 0, 2500, 1000)); } [Test] public void TestLength() { - Assert.AreEqual(1f / 5, algorithm.GetLength(0, 1000, 5000, 1)); // Like constant - Assert.AreEqual(1f / 5, algorithm.GetLength(10000, 10500, 5000, 1)); // (10500 - 10000) / 0.5 / 5000 - Assert.AreEqual(1f / 5, algorithm.GetLength(20000, 22000, 5000, 1)); // (22000 - 20000) * 0.5 / 5000 + ClassicAssert.AreEqual(1f / 5, algorithm.GetLength(0, 1000, 5000, 1)); // Like constant + ClassicAssert.AreEqual(1f / 5, algorithm.GetLength(10000, 10500, 5000, 1)); // (10500 - 10000) / 0.5 / 5000 + ClassicAssert.AreEqual(1f / 5, algorithm.GetLength(20000, 22000, 5000, 1)); // (22000 - 20000) * 0.5 / 5000 } [Test] public void TestPosition() { // Basically same calculations as TestLength() - Assert.AreEqual(1f / 5, algorithm.PositionAt(1000, 0, 5000, 1)); - Assert.AreEqual(1f / 5, algorithm.PositionAt(10500, 10000, 5000, 1)); - Assert.AreEqual(1f / 5, algorithm.PositionAt(22000, 20000, 5000, 1)); + ClassicAssert.AreEqual(1f / 5, algorithm.PositionAt(1000, 0, 5000, 1)); + ClassicAssert.AreEqual(1f / 5, algorithm.PositionAt(10500, 10000, 5000, 1)); + ClassicAssert.AreEqual(1f / 5, algorithm.PositionAt(22000, 20000, 5000, 1)); } [TestCase(1000)] @@ -73,8 +74,8 @@ public void TestPosition() [TestCase(25000)] public void TestTime(double time) { - Assert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 0, 5000, 1), 0, 5000, 1), 0.001); - Assert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 5000, 5000, 1), 5000, 5000, 1), 0.001); + ClassicAssert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 0, 5000, 1), 0, 5000, 1), 0.001); + ClassicAssert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 5000, 5000, 1), 5000, 5000, 1), 0.001); } } } diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index 2535d5b2e295..ffb97eb5cc66 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -7,6 +7,7 @@ using System.Runtime.CompilerServices; using System.Threading.Tasks; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Allocation; using osu.Framework.Platform; using osu.Game.Database; @@ -15,6 +16,8 @@ using osu.Game.Skinning; using osu.Game.Tests.Resources; using SharpCompress.Archives.Zip; +using SharpCompress.Common; +using SharpCompress.Writers.Zip; namespace osu.Game.Tests.Skins.IO { @@ -241,21 +244,21 @@ public Task TestExportThenImportDefaultSkin() => runSkinTest(async osu => await skinManager.CurrentSkinInfo.Value.PerformRead(async s => { - Assert.IsFalse(s.Protected); - Assert.AreEqual(typeof(ArgonSkin), s.CreateInstance(skinManager).GetType()); + ClassicAssert.False(s.Protected); + ClassicAssert.AreEqual(typeof(ArgonSkin), s.CreateInstance(skinManager).GetType()); await new LegacySkinExporter(osu.Dependencies.Get()).ExportToStreamAsync(skinManager.CurrentSkinInfo.Value, exportStream); - Assert.Greater(exportStream.Length, 0); + ClassicAssert.Greater(exportStream.Length, 0); }); var imported = await skinManager.Import(new ImportTask(exportStream, "exported.osk")); imported.PerformRead(s => { - Assert.IsFalse(s.Protected); - Assert.AreNotEqual(originalSkinId, s.ID); - Assert.AreEqual(typeof(ArgonSkin), s.CreateInstance(skinManager).GetType()); + ClassicAssert.False(s.Protected); + ClassicAssert.AreNotEqual(originalSkinId, s.ID); + ClassicAssert.AreEqual(typeof(ArgonSkin), s.CreateInstance(skinManager).GetType()); }); }); @@ -274,21 +277,21 @@ public Task TestExportThenImportClassicSkin() => runSkinTest(async osu => await skinManager.CurrentSkinInfo.Value.PerformRead(async s => { - Assert.IsFalse(s.Protected); - Assert.AreEqual(typeof(DefaultLegacySkin), s.CreateInstance(skinManager).GetType()); + ClassicAssert.False(s.Protected); + ClassicAssert.AreEqual(typeof(DefaultLegacySkin), s.CreateInstance(skinManager).GetType()); await new LegacySkinExporter(osu.Dependencies.Get()).ExportToStreamAsync(skinManager.CurrentSkinInfo.Value, exportStream); - Assert.Greater(exportStream.Length, 0); + ClassicAssert.Greater(exportStream.Length, 0); }); var imported = await skinManager.Import(new ImportTask(exportStream, "exported.osk")); imported.PerformRead(s => { - Assert.IsFalse(s.Protected); - Assert.AreNotEqual(originalSkinId, s.ID); - Assert.AreEqual(typeof(DefaultLegacySkin), s.CreateInstance(skinManager).GetType()); + ClassicAssert.False(s.Protected); + ClassicAssert.AreNotEqual(originalSkinId, s.ID); + ClassicAssert.AreEqual(typeof(DefaultLegacySkin), s.CreateInstance(skinManager).GetType()); }); }); @@ -304,9 +307,9 @@ public async Task TestExternallyMountingWithSubDirectory() var osu = LoadOsuIntoHost(host); var zipStream = new MemoryStream(); - using var zip = ZipArchive.Create(); - zip.AddEntry("folder/test.png", new MemoryStream(new byte[] { 0xDE, 0xAD, 0xBE, 0xEF })); - zip.SaveTo(zipStream); + using var zip = ZipArchive.CreateArchive(); + zip.AddEntry("folder/test.png", new MemoryStream(new byte[] { 0xDE, 0xAD, 0xBE, 0xEF }), true); + zip.SaveTo(zipStream, new ZipWriterOptions(CompressionType.Deflate)); var import = await loadSkinIntoOsu(osu, new ImportTask(zipStream, "test skin.osk")); @@ -353,9 +356,9 @@ public async Task TestExternallyMountingImportWithInvalidFilename() var osu = LoadOsuIntoHost(host); var zipStream = new MemoryStream(); - using var zip = ZipArchive.Create(); - zip.AddEntry("test?.png", new MemoryStream(new byte[] { 0xDE, 0xAD, 0xBE, 0xEF })); - zip.SaveTo(zipStream); + using var zip = ZipArchive.CreateArchive(); + zip.AddEntry("test?.png", new MemoryStream(new byte[] { 0xDE, 0xAD, 0xBE, 0xEF }), true); + zip.SaveTo(zipStream, new ZipWriterOptions(CompressionType.Deflate)); var import = await loadSkinIntoOsu(osu, new ImportTask(zipStream, "test skin.osk")); @@ -419,26 +422,26 @@ private void assertImportedOnce(Live import1, Live import2) private MemoryStream createEmptyOsk() { var zipStream = new MemoryStream(); - using var zip = ZipArchive.Create(); - zip.SaveTo(zipStream); + using var zip = ZipArchive.CreateArchive(); + zip.SaveTo(zipStream, new ZipWriterOptions(CompressionType.Deflate)); return zipStream; } private MemoryStream createOskWithNonIniFile() { var zipStream = new MemoryStream(); - using var zip = ZipArchive.Create(); - zip.AddEntry("hitcircle.png", new MemoryStream(new byte[] { 0, 1, 2, 3 })); - zip.SaveTo(zipStream); + using var zip = ZipArchive.CreateArchive(); + zip.AddEntry("hitcircle.png", new MemoryStream(new byte[] { 0, 1, 2, 3 }), true); + zip.SaveTo(zipStream, new ZipWriterOptions(CompressionType.Deflate)); return zipStream; } private MemoryStream createOskWithIni(string name, string author, bool makeUnique = false, string iniFilename = @"skin.ini", bool includeSectionHeader = true) { var zipStream = new MemoryStream(); - using var zip = ZipArchive.Create(); - zip.AddEntry(iniFilename, generateSkinIni(name, author, makeUnique, includeSectionHeader)); - zip.SaveTo(zipStream); + using var zip = ZipArchive.CreateArchive(); + zip.AddEntry(iniFilename, generateSkinIni(name, author, makeUnique, includeSectionHeader), true); + zip.SaveTo(zipStream, new ZipWriterOptions(CompressionType.Deflate)); return zipStream; } diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs index 9466fdf888ad..4bf685fc9fc4 100644 --- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs +++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.IO; using osu.Game.Skinning; using osu.Game.Tests.Resources; @@ -32,9 +33,9 @@ public void TestDecodeSkinColours() new Color4(100, 100, 100, 255), // alpha is specified as 100, but should be ignored. }; - Assert.AreEqual(expectedColors.Count, comboColors?.Count); + ClassicAssert.AreEqual(expectedColors.Count, comboColors?.Count); for (int i = 0; i < expectedColors.Count; i++) - Assert.AreEqual(expectedColors[i], comboColors[i]); + ClassicAssert.AreEqual(expectedColors[i], comboColors![i]); } } @@ -49,9 +50,9 @@ public void TestDecodeEmptySkinColours() var comboColors = decoder.Decode(stream).ComboColours; var expectedColors = SkinConfiguration.DefaultComboColours; - Assert.AreEqual(expectedColors.Count, comboColors?.Count); + ClassicAssert.AreEqual(expectedColors.Count, comboColors?.Count); for (int i = 0; i < expectedColors.Count; i++) - Assert.AreEqual(expectedColors[i], comboColors[i]); + ClassicAssert.AreEqual(expectedColors[i], comboColors![i]); } } @@ -65,7 +66,7 @@ public void TestDecodeEmptySkinColoursNoFallback() { var skinConfiguration = decoder.Decode(stream); skinConfiguration.AllowDefaultComboColoursFallback = false; - Assert.IsNull(skinConfiguration.ComboColours); + ClassicAssert.Null(skinConfiguration.ComboColours); } } @@ -79,8 +80,8 @@ public void TestDecodeGeneral() { var config = decoder.Decode(stream); - Assert.AreEqual("test skin", config.SkinInfo.Name); - Assert.AreEqual("TestValue", config.ConfigDictionary["TestLookup"]); + ClassicAssert.AreEqual("test skin", config.SkinInfo.Name); + ClassicAssert.AreEqual("TestValue", config.ConfigDictionary["TestLookup"]); } } @@ -90,7 +91,7 @@ public void TestDecodeSpecifiedVersion() var decoder = new LegacySkinDecoder(); using (var resStream = TestResources.OpenResource("skin-20.ini")) using (var stream = new LineBufferedReader(resStream)) - Assert.AreEqual(2.0m, decoder.Decode(stream).LegacyVersion); + ClassicAssert.AreEqual(2.0m, decoder.Decode(stream).LegacyVersion); } [Test] @@ -99,7 +100,7 @@ public void TestStripWhitespace() var decoder = new LegacySkinDecoder(); using (var resStream = TestResources.OpenResource("skin-with-space.ini")) using (var stream = new LineBufferedReader(resStream)) - Assert.AreEqual(2.0m, decoder.Decode(stream).LegacyVersion); + ClassicAssert.AreEqual(2.0m, decoder.Decode(stream).LegacyVersion); } [Test] @@ -108,7 +109,7 @@ public void TestDecodeLatestVersion() var decoder = new LegacySkinDecoder(); using (var resStream = TestResources.OpenResource("skin-latest.ini")) using (var stream = new LineBufferedReader(resStream)) - Assert.AreEqual(SkinConfiguration.LATEST_VERSION, decoder.Decode(stream).LegacyVersion); + ClassicAssert.AreEqual(SkinConfiguration.LATEST_VERSION, decoder.Decode(stream).LegacyVersion); } [Test] diff --git a/osu.Game.Tests/Skins/TestSceneSkinResources.cs b/osu.Game.Tests/Skins/TestSceneSkinResources.cs index e77affd81706..17e9c9b65411 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinResources.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinResources.cs @@ -66,7 +66,7 @@ public void TestSampleRetrievalOrder() mockResourceStore = new Mock>(); mockResourceStore.Setup(r => r.Get(It.IsAny())) .Callback(n => lookedUpFileNames.Add(n)) - .Returns(null); + .Returns(null!); }); AddStep("query sample", () => diff --git a/osu.Game.Tests/Utils/NamingUtilsTest.cs b/osu.Game.Tests/Utils/NamingUtilsTest.cs index 1f7e06f9965d..7e85171bb4c9 100644 --- a/osu.Game.Tests/Utils/NamingUtilsTest.cs +++ b/osu.Game.Tests/Utils/NamingUtilsTest.cs @@ -3,6 +3,7 @@ using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Utils; namespace osu.Game.Tests.Utils @@ -15,7 +16,7 @@ public void TestNextBestNameEmptySet() { string nextBestName = NamingUtils.GetNextBestName(Enumerable.Empty(), "New Difficulty"); - Assert.AreEqual("New Difficulty", nextBestName); + ClassicAssert.AreEqual("New Difficulty", nextBestName); } [Test] @@ -30,7 +31,7 @@ public void TestNextBestNameNotTaken() string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty"); - Assert.AreEqual("New Difficulty", nextBestName); + ClassicAssert.AreEqual("New Difficulty", nextBestName); } [Test] @@ -45,7 +46,7 @@ public void TestNextBestNameNotTakenButClose() string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty"); - Assert.AreEqual("New Difficulty", nextBestName); + ClassicAssert.AreEqual("New Difficulty", nextBestName); } [Test] @@ -58,7 +59,7 @@ public void TestNextBestNameAlreadyTaken() string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty"); - Assert.AreEqual("New Difficulty (1)", nextBestName); + ClassicAssert.AreEqual("New Difficulty (1)", nextBestName); } [Test] @@ -71,7 +72,7 @@ public void TestNextBestNameAlreadyTakenWithDifferentCase() string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty"); - Assert.AreEqual("New Difficulty (1)", nextBestName); + ClassicAssert.AreEqual("New Difficulty (1)", nextBestName); } [Test] @@ -84,7 +85,7 @@ public void TestNextBestNameAlreadyTakenWithBrackets() string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty (copy)"); - Assert.AreEqual("New Difficulty (copy) (1)", nextBestName); + ClassicAssert.AreEqual("New Difficulty (copy) (1)", nextBestName); } [Test] @@ -100,7 +101,7 @@ public void TestNextBestNameMultipleAlreadyTaken() string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty"); - Assert.AreEqual("New Difficulty (4)", nextBestName); + ClassicAssert.AreEqual("New Difficulty (4)", nextBestName); } [Test] @@ -110,7 +111,7 @@ public void TestNextBestNameEvenMoreAlreadyTaken() string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty"); - Assert.AreEqual("New Difficulty (31)", nextBestName); + ClassicAssert.AreEqual("New Difficulty (31)", nextBestName); } [Test] @@ -126,7 +127,7 @@ public void TestNextBestNameMultipleAlreadyTakenWithGaps() string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty"); - Assert.AreEqual("New Difficulty (2)", nextBestName); + ClassicAssert.AreEqual("New Difficulty (2)", nextBestName); } [Test] @@ -134,7 +135,7 @@ public void TestNextBestFilenameEmptySet() { string nextBestFilename = NamingUtils.GetNextBestFilename(Enumerable.Empty(), "test_file.osr"); - Assert.AreEqual("test_file.osr", nextBestFilename); + ClassicAssert.AreEqual("test_file.osr", nextBestFilename); } [Test] @@ -149,7 +150,7 @@ public void TestNextBestFilenameNotTaken() string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "test_file.osr"); - Assert.AreEqual("test_file.osr", nextBestFilename); + ClassicAssert.AreEqual("test_file.osr", nextBestFilename); } [Test] @@ -164,7 +165,7 @@ public void TestNextBestFilenameNotTakenButClose() string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); - Assert.AreEqual("replay_file.osr", nextBestFilename); + ClassicAssert.AreEqual("replay_file.osr", nextBestFilename); } [Test] @@ -177,7 +178,7 @@ public void TestNextBestFilenameAlreadyTaken() string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); - Assert.AreEqual("replay_file (1).osr", nextBestFilename); + ClassicAssert.AreEqual("replay_file (1).osr", nextBestFilename); } [Test] @@ -191,7 +192,7 @@ public void TestNextBestFilenameAlreadyTakenDifferentCase() }; string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); - Assert.AreEqual("replay_file (3).osr", nextBestFilename); + ClassicAssert.AreEqual("replay_file (3).osr", nextBestFilename); } [Test] @@ -204,10 +205,10 @@ public void TestNextBestFilenameAlreadyTakenWithBrackets() }; string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); - Assert.AreEqual("replay_file (1).osr", nextBestFilename); + ClassicAssert.AreEqual("replay_file (1).osr", nextBestFilename); nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file (copy).osr"); - Assert.AreEqual("replay_file (copy) (1).osr", nextBestFilename); + ClassicAssert.AreEqual("replay_file (copy) (1).osr", nextBestFilename); } [Test] @@ -223,7 +224,7 @@ public void TestNextBestFilenameMultipleAlreadyTaken() string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); - Assert.AreEqual("replay_file (4).osr", nextBestFilename); + ClassicAssert.AreEqual("replay_file (4).osr", nextBestFilename); } [Test] @@ -240,7 +241,7 @@ public void TestNextBestFilenameMultipleAlreadyTakenWithGaps() string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); - Assert.AreEqual("replay_file (3).osr", nextBestFilename); + ClassicAssert.AreEqual("replay_file (3).osr", nextBestFilename); } [Test] @@ -254,10 +255,10 @@ public void TestNextBestFilenameNoExtensions() }; string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "surely"); - Assert.AreEqual("surely", nextBestFilename); + ClassicAssert.AreEqual("surely", nextBestFilename); nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "those"); - Assert.AreEqual("those (1)", nextBestFilename); + ClassicAssert.AreEqual("those (1)", nextBestFilename); } [Test] @@ -271,10 +272,10 @@ public void TestNextBestFilenameDifferentExtensions() }; string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); - Assert.AreEqual("replay_file (2).osr", nextBestFilename); + ClassicAssert.AreEqual("replay_file (2).osr", nextBestFilename); nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.txt"); - Assert.AreEqual("replay_file (1).txt", nextBestFilename); + ClassicAssert.AreEqual("replay_file (1).txt", nextBestFilename); } } } diff --git a/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs b/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs index 6a9ca1292cf3..df5b58f31063 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Graphics; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; @@ -662,11 +663,11 @@ public void TestShiftModifierMaintainsAspectRatio() AddStep("move mouse", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(50, 0))); - AddStep("aspect ratio does not equal", () => Assert.AreNotEqual(aspectRatioBeforeDrag, getAspectRatio())); + AddStep("aspect ratio does not equal", () => ClassicAssert.AreNotEqual(aspectRatioBeforeDrag, getAspectRatio())); AddStep("press shift", () => InputManager.PressKey(Key.ShiftLeft)); - AddStep("aspect ratio does equal", () => Assert.AreEqual(aspectRatioBeforeDrag, getAspectRatio())); + AddStep("aspect ratio does equal", () => ClassicAssert.AreEqual(aspectRatioBeforeDrag, getAspectRatio())); AddStep("end drag", () => InputManager.ReleaseButton(MouseButton.Left)); @@ -701,11 +702,11 @@ public void TestAltModifierScalesAroundCenter() AddStep("move mouse", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(50, 0))); - AddStep("center does not equal", () => Assert.AreNotEqual(centerBeforeDrag, getCenter())); + AddStep("center does not equal", () => ClassicAssert.AreNotEqual(centerBeforeDrag, getCenter())); AddStep("press alt", () => InputManager.PressKey(Key.AltLeft)); - AddStep("center does equal", () => Assert.AreEqual(centerBeforeDrag, getCenter())); + AddStep("center does equal", () => ClassicAssert.AreEqual(centerBeforeDrag, getCenter())); AddStep("end drag", () => InputManager.ReleaseButton(MouseButton.Left)); @@ -745,19 +746,19 @@ public void TestShiftAndAltModifierKeys() AddStep("move mouse", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(50, 0))); - AddStep("aspect ratio does not equal", () => Assert.AreNotEqual(aspectRatioBeforeDrag, getAspectRatio())); + AddStep("aspect ratio does not equal", () => ClassicAssert.AreNotEqual(aspectRatioBeforeDrag, getAspectRatio())); - AddStep("center does not equal", () => Assert.AreNotEqual(centerBeforeDrag, getCenter())); + AddStep("center does not equal", () => ClassicAssert.AreNotEqual(centerBeforeDrag, getCenter())); AddStep("press shift", () => InputManager.PressKey(Key.ShiftLeft)); - AddStep("aspect ratio does equal", () => Assert.AreEqual(aspectRatioBeforeDrag, getAspectRatio())); + AddStep("aspect ratio does equal", () => ClassicAssert.AreEqual(aspectRatioBeforeDrag, getAspectRatio())); - AddStep("center does not equal", () => Assert.AreNotEqual(centerBeforeDrag, getCenter())); + AddStep("center does not equal", () => ClassicAssert.AreNotEqual(centerBeforeDrag, getCenter())); AddStep("press alt", () => InputManager.PressKey(Key.AltLeft)); - AddStep("center does equal", () => Assert.AreEqual(centerBeforeDrag, getCenter())); + AddStep("center does equal", () => ClassicAssert.AreEqual(centerBeforeDrag, getCenter())); AddStep("end drag", () => InputManager.ReleaseButton(MouseButton.Left)); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index 7440697ba08a..ed91fe848ab3 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -881,7 +881,7 @@ private bool setFile(string archivePath, Func func) try { - using (var zip = ZipArchive.Open(temp)) + using (var zip = ZipArchive.OpenArchive(temp)) zip.WriteToDirectory(extractedFolder); return func(extractedFolder); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs index d8817e563cef..57d1f2692626 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs @@ -146,7 +146,7 @@ public void TestFrameStarvationAndResume() AddUntilStep("wait for frame starvation", () => replayHandler.WaitingForFrame); checkPaused(true); - AddAssert("time advanced", () => currentFrameStableTime, () => Is.GreaterThan(pausedTime)); + AddAssert("time advanced", () => currentFrameStableTime, () => Is.GreaterThan(pausedTime!)); } [Test] diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs index b475071f6eb0..fcae9ab7be40 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Framework.Utils; @@ -142,7 +143,7 @@ public void TestBackgroundAlternating() AddRepeatStep("check background", () => { // +1 because the day separator take one index - Assert.AreEqual((checkCount + 1) % 2 == 0, drawableChannel.ChildrenOfType().ToList()[checkCount].AlternatingBackground); + ClassicAssert.AreEqual((checkCount + 1) % 2 == 0, drawableChannel.ChildrenOfType().ToList()[checkCount].AlternatingBackground); checkCount++; }, 10); } diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index c86f05c25702..6f970df4c5cd 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -1,13 +1,12 @@  - - - + + - - - + + + WinExe diff --git a/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs b/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs index 6ee780809917..c488f4ae80b0 100644 --- a/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs +++ b/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Allocation; using osu.Framework.Platform; using osu.Framework.Testing; @@ -38,8 +39,8 @@ public void CheckIPCLocation() WaitForOrAssert(() => (ipc = osu.Dependencies.Get() as FileBasedIPC)?.IsLoaded == true, @"ipc could not be populated in a reasonable amount of time"); - Assert.True(ipc!.SetIPCLocation(testStableInstallDirectory)); - Assert.True(storage.AllTournaments.Exists("stable.json")); + ClassicAssert.True(ipc!.SetIPCLocation(testStableInstallDirectory)); + ClassicAssert.True(storage.AllTournaments.Exists("stable.json")); } finally { diff --git a/osu.Game.Tournament.Tests/NonVisual/TournamentHostTest.cs b/osu.Game.Tournament.Tests/NonVisual/TournamentHostTest.cs index e4a35913cc7c..eb5865bb9727 100644 --- a/osu.Game.Tournament.Tests/NonVisual/TournamentHostTest.cs +++ b/osu.Game.Tournament.Tests/NonVisual/TournamentHostTest.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Platform; namespace osu.Game.Tournament.Tests.NonVisual @@ -27,7 +28,7 @@ public static void WaitForOrAssert(Func result, string failureMessage, int while (!result()) Thread.Sleep(200); }); - Assert.IsTrue(task.Wait(timeout), failureMessage); + ClassicAssert.True(task.Wait(timeout), failureMessage); } } } diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj index 8437a1bc4e5b..83637ab25174 100644 --- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj +++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj @@ -4,9 +4,9 @@ osu.Game.Tournament.Tests.TournamentTestRunner - - - + + + WinExe diff --git a/osu.Game/Beatmaps/LocalCachedBeatmapMetadataSource.cs b/osu.Game/Beatmaps/LocalCachedBeatmapMetadataSource.cs index c591dac36faa..d9e72d7c91dd 100644 --- a/osu.Game/Beatmaps/LocalCachedBeatmapMetadataSource.cs +++ b/osu.Game/Beatmaps/LocalCachedBeatmapMetadataSource.cs @@ -205,7 +205,7 @@ public Task FetchCache() // ensure to clobber any and all existing data to avoid accidental corruption. outStream.SetLength(0); - using (var bz2 = new BZip2Stream(stream, CompressionMode.Decompress, false)) + using (var bz2 = BZip2Stream.Create(stream, CompressionMode.Decompress, false)) bz2.CopyTo(outStream); } diff --git a/osu.Game/Database/LegacyArchiveExporter.cs b/osu.Game/Database/LegacyArchiveExporter.cs index e4d3ed468170..9e8f5ad9c94f 100644 --- a/osu.Game/Database/LegacyArchiveExporter.cs +++ b/osu.Game/Database/LegacyArchiveExporter.cs @@ -38,7 +38,7 @@ public override void ExportToStream(TModel model, Stream outputStream, ProgressN { var zipWriterOptions = new ZipWriterOptions(CompressionType.Deflate) { - ArchiveEncoding = UseFixedEncoding ? ZipArchiveReader.DEFAULT_ENCODING : new ArchiveEncoding(Encoding.UTF8, Encoding.UTF8) + ArchiveEncoding = UseFixedEncoding ? ZipArchiveReader.DEFAULT_ENCODING : new ArchiveEncoding { Default = Encoding.UTF8, Password = Encoding.UTF8 } }; using (var writer = new ZipWriter(outputStream, zipWriterOptions)) diff --git a/osu.Game/Database/RealmObjectExtensions.cs b/osu.Game/Database/RealmObjectExtensions.cs index 2c4d36f7d07d..c334f1152dfc 100644 --- a/osu.Game/Database/RealmObjectExtensions.cs +++ b/osu.Game/Database/RealmObjectExtensions.cs @@ -299,7 +299,7 @@ public static IDisposable QueryAsyncWithNotifications(this IRealmCollection + return collection.SubscribeForNotifications((sender, changes) => { if (initial) { @@ -315,7 +315,7 @@ public static IDisposable QueryAsyncWithNotifications(this IRealmCollection diff --git a/osu.Game/IO/Archives/ZipArchiveReader.cs b/osu.Game/IO/Archives/ZipArchiveReader.cs index 8b9ecc74624c..44cc6b69da56 100644 --- a/osu.Game/IO/Archives/ZipArchiveReader.cs +++ b/osu.Game/IO/Archives/ZipArchiveReader.cs @@ -11,6 +11,7 @@ using Microsoft.Toolkit.HighPerformance; using osu.Framework.Extensions; using osu.Framework.IO.Stores; +using SharpCompress.Archives; using SharpCompress.Archives.Zip; using SharpCompress.Common; using SharpCompress.Readers; @@ -28,14 +29,18 @@ public sealed class ZipArchiveReader : ArchiveReader public static readonly ArchiveEncoding DEFAULT_ENCODING; private readonly Stream archiveStream; - private readonly ZipArchive archive; + private readonly IWritableArchive archive; static ZipArchiveReader() { // Required to support rare code pages. Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - DEFAULT_ENCODING = new ArchiveEncoding(Encoding.GetEncoding(932), Encoding.GetEncoding(932)); + DEFAULT_ENCODING = new ArchiveEncoding + { + Default = Encoding.GetEncoding(932), + Password = Encoding.GetEncoding(932), + }; } public ZipArchiveReader(Stream archiveStream, string name = null) @@ -43,7 +48,7 @@ public ZipArchiveReader(Stream archiveStream, string name = null) { this.archiveStream = archiveStream; - archive = ZipArchive.Open(archiveStream, new ReaderOptions + archive = ZipArchive.OpenArchive(archiveStream, new ReaderOptions { ArchiveEncoding = DEFAULT_ENCODING }); @@ -51,7 +56,7 @@ public ZipArchiveReader(Stream archiveStream, string name = null) public override Stream GetStream(string name) { - ZipArchiveEntry entry = archive.Entries.SingleOrDefault(e => e.Key == name); + IArchiveEntry entry = archive.Entries.SingleOrDefault(e => e.Key == name); if (entry == null) return null; diff --git a/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs index 02c1dfb8df90..f6fe576dc227 100644 --- a/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/QuickActionSettings.cs @@ -16,6 +16,8 @@ using osu.Game.Overlays.Notifications; using osu.Game.Utils; using SharpCompress.Archives.Zip; +using SharpCompress.Common; +using SharpCompress.Writers.Zip; namespace osu.Game.Overlays.Settings.Sections.General { @@ -93,12 +95,12 @@ private void exportLogs() var logStorage = Logger.Storage; using (var outStream = exportStorage.CreateFileSafely(archive_filename)) - using (var zip = ZipArchive.Create()) + using (var zip = ZipArchive.CreateArchive()) { foreach (string? f in logStorage.GetFiles(string.Empty, "*.log")) FileUtils.AttemptOperation(z => z.AddEntry(f, logStorage.GetStream(f), closeStream: true), zip, throwOnFailure: false); - zip.SaveTo(outStream); + zip.SaveTo(outStream, new ZipWriterOptions(CompressionType.Deflate)); } } catch diff --git a/osu.Game/Rulesets/Edit/Checks/Components/IssueTemplate.cs b/osu.Game/Rulesets/Edit/Checks/Components/IssueTemplate.cs index 97df79ecd8a6..955bc0265bcc 100644 --- a/osu.Game/Rulesets/Edit/Checks/Components/IssueTemplate.cs +++ b/osu.Game/Rulesets/Edit/Checks/Components/IssueTemplate.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using Humanizer; using osu.Framework.Graphics; using osuTK.Graphics; @@ -42,7 +41,7 @@ public IssueTemplate(ICheck check, IssueType type, string unformattedMessage) /// Returns the formatted message given the arguments used to format it. /// /// The arguments used to format the message. - public string GetMessage(params object[] args) => UnformattedMessage.FormatWith(args); + public string GetMessage(params object[] args) => string.Format(UnformattedMessage, args); /// /// Returns the colour corresponding to the type of this issue. diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs index 05070d96ecf5..a03fee5cfd96 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs @@ -188,7 +188,7 @@ private void readCompressedData(byte[] data, Action readFunc) long compressedSize = replayInStream.Length - replayInStream.Position; - using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize)) + using (var lzma = LzmaStream.Create(properties, replayInStream, compressedSize, outSize)) using (var reader = new StreamReader(lzma)) readFunc(reader); } diff --git a/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs index b575c0233754..ed1df16573f2 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs @@ -120,7 +120,7 @@ private byte[] compress(string data) using (var outStream = new MemoryStream()) { - using (var lzma = new LzmaStream(new LzmaEncoderProperties(false, 1 << 21, 255), false, outStream)) + using (var lzma = LzmaStream.Create(new LzmaEncoderProperties(false, 1 << 21, 255), false, outStream)) { outStream.Write(lzma.Properties); diff --git a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs index e84b6bfc728e..06f2279ce0c8 100644 --- a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs +++ b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs @@ -179,22 +179,25 @@ private void findChangedIndices(DiffResult result, LegacyDecoder.Sectio removedIndices = new List(); addedIndices = new List(); + string[] oldArr = result.PiecesOld.ToArray(); + string[] newArr = result.PiecesNew.ToArray(); + // Find the start and end indices of the relevant section headers in both the old and the new beatmap file. Lines changed outside of the modified ranges are ignored. - int oldSectionStartIndex = Array.IndexOf(result.PiecesOld, $"[{section}]"); + int oldSectionStartIndex = Array.IndexOf(oldArr, $"[{section}]"); if (oldSectionStartIndex == -1) return; - int oldSectionEndIndex = Array.FindIndex(result.PiecesOld, oldSectionStartIndex + 1, s => s.StartsWith('[')); + int oldSectionEndIndex = Array.FindIndex(oldArr, oldSectionStartIndex + 1, s => s.StartsWith('[')); if (oldSectionEndIndex == -1) - oldSectionEndIndex = result.PiecesOld.Length; + oldSectionEndIndex = oldArr.Length; - int newSectionStartIndex = Array.IndexOf(result.PiecesNew, $"[{section}]"); + int newSectionStartIndex = Array.IndexOf(newArr, $"[{section}]"); if (newSectionStartIndex == -1) return; - int newSectionEndIndex = Array.FindIndex(result.PiecesNew, newSectionStartIndex + 1, s => s.StartsWith('[')); + int newSectionEndIndex = Array.FindIndex(newArr, newSectionStartIndex + 1, s => s.StartsWith('[')); if (newSectionEndIndex == -1) - newSectionEndIndex = result.PiecesNew.Length; + newSectionEndIndex = newArr.Length; foreach (var block in result.DiffBlocks) { diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index b57b0daa1bb7..15cd54baadc3 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Newtonsoft.Json; using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Framework.Audio.Track; using osu.Framework.Extensions; using osu.Framework.Extensions.ObjectExtensions; @@ -133,7 +134,7 @@ private ConvertResult convert(string name, Mod[] mods) string afterConversion = beatmap.Serialize(); - Assert.AreEqual(beforeConversion, afterConversion, "Conversion altered original beatmap"); + ClassicAssert.AreEqual(beforeConversion, afterConversion, "Conversion altered original beatmap"); return new ConvertResult { diff --git a/osu.Game/Tests/Beatmaps/LegacyModConversionTest.cs b/osu.Game/Tests/Beatmaps/LegacyModConversionTest.cs index b7803f342010..4cab848648c6 100644 --- a/osu.Game/Tests/Beatmaps/LegacyModConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/LegacyModConversionTest.cs @@ -3,7 +3,7 @@ using System; using System.Linq; -using NUnit.Framework; +using NUnit.Framework.Legacy; using osu.Game.Beatmaps.Legacy; using osu.Game.Rulesets; @@ -23,11 +23,11 @@ protected void TestFromLegacy(LegacyMods legacyMods, Type[] expectedMods) { var ruleset = CreateRuleset(); var mods = ruleset.ConvertFromLegacyMods(legacyMods).ToList(); - Assert.AreEqual(expectedMods.Length, mods.Count); + ClassicAssert.AreEqual(expectedMods.Length, mods.Count); foreach (var modType in expectedMods) { - Assert.IsNotNull(mods.SingleOrDefault(mod => mod.GetType() == modType)); + ClassicAssert.NotNull(mods.SingleOrDefault(mod => mod.GetType() == modType)); } } @@ -38,7 +38,7 @@ protected void TestToLegacy(LegacyMods expectedLegacyMods, Type[] providedModTyp .Where(mod => providedModTypes.Contains(mod.GetType())) .ToArray(); var actualLegacyMods = ruleset.ConvertToLegacyMods(modInstances); - Assert.AreEqual(expectedLegacyMods, actualLegacyMods); + ClassicAssert.AreEqual(expectedLegacyMods, actualLegacyMods); } } } diff --git a/osu.Game/Utils/ZipUtils.cs b/osu.Game/Utils/ZipUtils.cs index bebeff29d8cc..8eb4c0491477 100644 --- a/osu.Game/Utils/ZipUtils.cs +++ b/osu.Game/Utils/ZipUtils.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using System.Linq; using SharpCompress.Archives.Zip; namespace osu.Game.Utils @@ -15,7 +16,7 @@ public static bool IsZipArchive(MemoryStream stream) { stream.Seek(0, SeekOrigin.Begin); - using (var arc = ZipArchive.Open(stream)) + using (var arc = ZipArchive.OpenArchive(stream)) { foreach (var entry in arc.Entries) { @@ -30,7 +31,7 @@ public static bool IsZipArchive(MemoryStream stream) // the worst case is that it's actually *not* a zip and instead a stream of binary // which *accidentally* happened to contain the magic sequence of bytes for the zip header (50 4b 05 06), // and if that's the case, then we are *misclassifying* it as a zip by returning `true` unconditionally. - return arc.Entries.Count > 0; + return arc.Entries.Any(); } } catch (Exception) @@ -50,7 +51,7 @@ public static bool IsZipArchive(string path) try { - using (var arc = ZipArchive.Open(path)) + using (var arc = ZipArchive.OpenArchive(path)) { foreach (var entry in arc.Entries) { @@ -65,7 +66,7 @@ public static bool IsZipArchive(string path) // the worst case is that it's actually *not* a zip and instead a stream of binary // which *accidentally* happened to contain the magic sequence of bytes for the zip header (50 4b 05 06), // and if that's the case, then we are *misclassifying* it as a zip by returning `true` unconditionally. - return arc.Entries.Count > 0; + return arc.Entries.Any(); } } catch (Exception) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 384d5412a895..60b3546d8513 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,18 +18,22 @@ - - - + + + NU1903 + + + + - - - - - - + + + + + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -37,11 +41,11 @@ - + - - - + + + From abf1a0059103e511fb8ddde4e71ff9580b9bf4c5 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 16 Mar 2026 19:32:34 +0000 Subject: [PATCH 814/836] Apply a few minor fixes to flow aim evaluation (#36999) Contains: - A small bug fix from initial separation merge. Snap aim only applies this bonus when slider travel distance is passed, so it should be the same for flow. Cannot find any cases where values are affected, but in theory the only difference this can make is slider factor calculations. - Apply overlapping note factor to the acute bonus, so that direction changes that overlap are awarded less. A small speed multiplier increase is included to offset this - Move angular velocity calculation out of ODHO into the flow evaluator, and fix it referencing the wrong angle (2 objects back instead of the previous object) - 2 tiny code refactors --------- Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com> --- .../Evaluators/Aim/FlowAimEvaluator.cs | 18 ++++++++++++------ .../Preprocessing/OsuDifficultyHitObject.cs | 9 --------- .../Difficulty/Skills/Speed.cs | 2 +- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs index ccc4d219d5be..d50e84f00b6b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs @@ -50,10 +50,14 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with flowDifficulty *= 1 + Math.Min(0.25, Math.Pow((Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) - Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime)) / 50, 4)); - if (osuCurrObj.AngularVelocity != null) + if (osuCurrObj.Angle != null && osuLastObj.Angle != null) { + double angleDifference = Math.Abs(osuCurrObj.Angle.Value - osuLastObj.Angle.Value); + double angleDifferenceAdjusted = Math.Sin(angleDifference / 2) * 180.0; + double angularVelocity = angleDifferenceAdjusted / (osuCurrObj.AdjustedDeltaTime * 0.1); + // Low angular velocity flow (angles are consistent) is easier to follow than erratic flow - flowDifficulty *= 0.8 + Math.Sqrt(osuCurrObj.AngularVelocity.Value / 270.0); + flowDifficulty *= 0.8 + Math.Sqrt(angularVelocity / 270.0); } // If all three notes are overlapping - don't reward bonuses as you don't have to do additional movement @@ -68,7 +72,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with overlappedNotesWeight = 1 - o1 * o2 * o3; } - if (osuCurrObj.Angle != null && osuLastObj.Angle != null) + if (osuCurrObj.Angle != null) { // Acute angles are also hard to flow // We square root velocity to make acute angle switches in streams aren't having difficulty higher than snap @@ -82,7 +86,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with if (withSliderTravelDistance) { currVelocity = currDistance / osuCurrObj.AdjustedDeltaTime; - prevVelocity = prevDistance / osuLastObj.AdjustedDeltaTime; } // Scale with ratio of difference compared to 0.5 * max dist. @@ -92,10 +95,13 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double overlapVelocityBuff = Math.Min(OsuDifficultyHitObject.NORMALISED_DIAMETER * 1.25 / Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime), Math.Abs(prevVelocity - currVelocity)); - flowDifficulty += overlapVelocityBuff * distRatio * velocity_change_multiplier; + flowDifficulty += overlapVelocityBuff * + distRatio * + overlappedNotesWeight * + velocity_change_multiplier; } - if (osuCurrObj.BaseObject is Slider) + if (osuCurrObj.BaseObject is Slider && withSliderTravelDistance) { // Include slider velocity to make velocity more consistent with snap flowDifficulty += osuCurrObj.TravelDistance / osuCurrObj.TravelTime; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 68950829f3cf..221b2c637852 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -116,8 +116,6 @@ public class OsuDifficultyHitObject : DifficultyHitObject /// public double? Angle { get; private set; } - public double? AngularVelocity { get; private set; } - /// /// Angle of the vector created between current and current-1 /// normalised to consider symmetrical vectors in any axis to be the same angle. @@ -271,13 +269,6 @@ private void setDistances(double clockRate) NormalisedVectorAngle = Math.Atan2(Math.Abs(v.Y), Math.Abs(v.X)); Angle = Math.Min(angle, sliderAngle); - - if (lastLastDifficultyObject.Angle != null) - { - double angleDifference = Math.Abs(Angle.Value - lastLastDifficultyObject.Angle.Value); - double angleDifferenceAdjusted = Math.Sin(angleDifference / 2) * 180.0; - AngularVelocity = angleDifferenceAdjusted / (AdjustedDeltaTime * 0.1); - } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 2462186c780d..cdd01187030d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Speed : HarmonicSkill { - private double skillMultiplier => 1.15; + private double skillMultiplier => 1.16; private readonly List sliderStrains = new List(); From fc82dac7aed572c5f1b02117d86a021d440c3636 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Tue, 17 Mar 2026 02:04:54 +0500 Subject: [PATCH 815/836] Remove slider velocity considerations from previous object velocity (#36806) It barely affects values at this point --------- Co-authored-by: James Wilson --- .../Difficulty/Evaluators/Aim/SnapAimEvaluator.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs index 5df70225a1ef..75ecfe89ecc1 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs @@ -36,7 +36,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with var osuCurrObj = (OsuDifficultyHitObject)current; var osuLastObj = (OsuDifficultyHitObject)current.Previous(0); - var osuLastLastObj = (OsuDifficultyHitObject)current.Previous(1); var osuLast2Obj = (OsuDifficultyHitObject)current.Previous(2); const int radius = OsuDifficultyHitObject.NORMALISED_RADIUS; @@ -53,16 +52,9 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with currVelocity = Math.Max(currVelocity, sliderDistance / osuCurrObj.AdjustedDeltaTime); } - // As above, do the same for the previous hitobject. double prevDistance = withSliderTravelDistance ? osuLastObj.LazyJumpDistance : osuLastObj.JumpDistance; double prevVelocity = prevDistance / osuLastObj.AdjustedDeltaTime; - if (osuLastLastObj.BaseObject is Slider && withSliderTravelDistance) - { - double sliderDistance = osuLastLastObj.LazyTravelDistance + osuLastObj.LazyJumpDistance; - prevVelocity = Math.Max(prevVelocity, sliderDistance / osuLastObj.AdjustedDeltaTime); - } - double wideAngleBonus = 0; double acuteAngleBonus = 0; double sliderBonus = 0; @@ -129,9 +121,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with { if (withSliderTravelDistance) { - // We want to use the average velocity over the whole object when awarding differences, not the individual jump and slider path velocities. - prevVelocity = (osuLastObj.LazyJumpDistance + osuLastLastObj.TravelDistance) / osuLastObj.AdjustedDeltaTime; - currVelocity = (osuCurrObj.LazyJumpDistance + osuLastObj.TravelDistance) / osuCurrObj.AdjustedDeltaTime; + // We want to use just the object jump without slider velocity when awarding differences + currVelocity = currDistance / osuCurrObj.AdjustedDeltaTime; } // Scale with ratio of difference compared to 0.5 * max dist. From 09bcef1bdd91849c700a10a965ea1c68a5bc5e49 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Tue, 17 Mar 2026 02:10:46 +0500 Subject: [PATCH 816/836] Adjust Aim RX multiplier (#36985) Generally deflationary on the top end and roughly the same at low end. Likely needs a more comprehensive solution, but this at least ensures that even if we don't do it the values will be sane. Co-authored-by: James Wilson --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 06522d8e8563..0c2c6a71b085 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -72,8 +72,7 @@ protected override double StrainValueAt(DifficultyHitObject current) if (Mods.Any(m => m is OsuModRelax)) { - agilityDifficulty *= 0.0; - flowDifficulty *= 0.1; + agilityDifficulty *= 0.3; } double totalDifficulty = calculateTotalValue(snapDifficulty, agilityDifficulty, flowDifficulty); From fadb1c3f2c0a2a700a94fbbf02b8e9b23c428d6d Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Tue, 17 Mar 2026 02:17:49 +0500 Subject: [PATCH 817/836] Calculate clock time when creating difficulty hit objects (#36962) This change removes `clockRate` precalculation from `DifficultyCalculator`. The idea is that clock rate should be calculated in-place (ideally for every object) since we store and access it using DHOs. This also prevents anyone from accidentally passing clock rate to skills Unfortunately osu uses clock rate to calculate OD for the whole map in `CreateDifficultyAttributes` so we can't make it completely DHO-based, but I think one single in-place call to `ModUtils.CalculateRateWithMods` in `CreateDifficultyAttributes` is fine --------- Co-authored-by: James Wilson --- .../EmptyFreeformDifficultyCalculator.cs | 6 ++--- .../PippidonDifficultyCalculator.cs | 6 ++--- .../EmptyScrollingDifficultyCalculator.cs | 6 ++--- .../PippidonDifficultyCalculator.cs | 6 ++--- .../Difficulty/CatchDifficultyCalculator.cs | 9 ++++--- .../Difficulty/ManiaDifficultyCalculator.cs | 9 ++++--- .../Difficulty/OsuDifficultyCalculator.cs | 11 +++++--- .../Difficulty/TaikoDifficultyCalculator.cs | 9 ++++--- ...DifficultyAdjustmentModCombinationsTest.cs | 6 ++--- .../TestSceneTimedDifficultyCalculation.cs | 9 ++++--- .../TestSceneBeatmapAttributeText.cs | 6 ++--- .../Difficulty/DifficultyCalculator.cs | 25 ++++++++----------- 12 files changed, 59 insertions(+), 49 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformDifficultyCalculator.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformDifficultyCalculator.cs index 312d3d5e9a64..c7851cc12f02 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformDifficultyCalculator.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformDifficultyCalculator.cs @@ -19,13 +19,13 @@ public EmptyFreeformDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap b { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills) { return new DifficultyAttributes(mods, 0); } - protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty(); + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, Mod[] mods) => Enumerable.Empty(); - protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) => Array.Empty(); + protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods) => Array.Empty(); } } diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs index f6addab279e7..852576958446 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs @@ -19,13 +19,13 @@ public PippidonDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatma { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills) { return new DifficultyAttributes(mods, 0); } - protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty(); + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, Mod[] mods) => Enumerable.Empty(); - protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) => Array.Empty(); + protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods) => Array.Empty(); } } diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingDifficultyCalculator.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingDifficultyCalculator.cs index a4dc1762d520..17139218a52d 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingDifficultyCalculator.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingDifficultyCalculator.cs @@ -19,13 +19,13 @@ public EmptyScrollingDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills) { return new DifficultyAttributes(mods, 0); } - protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty(); + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, Mod[] mods) => Enumerable.Empty(); - protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) => Array.Empty(); + protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods) => Array.Empty(); } } diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs index f6addab279e7..852576958446 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs @@ -19,13 +19,13 @@ public PippidonDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatma { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills) { return new DifficultyAttributes(mods, 0); } - protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty(); + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, Mod[] mods) => Enumerable.Empty(); - protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) => Array.Empty(); + protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods) => Array.Empty(); } } diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index ea1c31b21608..75db566009da 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -15,6 +15,7 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; +using osu.Game.Utils; namespace osu.Game.Rulesets.Catch.Difficulty { @@ -29,7 +30,7 @@ public CatchDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills) { if (beatmap.HitObjects.Count == 0) return new CatchDifficultyAttributes { Mods = mods }; @@ -44,12 +45,14 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat return attributes; } - protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, Mod[] mods) { CatchHitObject? lastObject = null; List objects = new List(); + double clockRate = ModUtils.CalculateRateWithMods(mods); + float halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.Difficulty) * 0.5f; // For circle sizes above 5.5, reduce the catcher width further to simulate imperfect gameplay. @@ -71,7 +74,7 @@ protected override IEnumerable CreateDifficultyHitObjects(I return objects; } - protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) + protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods) { return new Skill[] { diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index bcf16e68088c..1bfa3bec6d7c 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -19,6 +19,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; +using osu.Game.Utils; namespace osu.Game.Rulesets.Mania.Difficulty { @@ -36,7 +37,7 @@ public ManiaDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.MatchesOnlineID(ruleset); } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills) { if (beatmap.HitObjects.Count == 0) return new ManiaDifficultyAttributes { Mods = mods }; @@ -62,11 +63,13 @@ private static int maxComboForObject(HitObject hitObject) return 1; } - protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, Mod[] mods) { var sortedObjects = beatmap.HitObjects.ToArray(); int totalColumns = ((ManiaBeatmap)beatmap).TotalColumns; + double clockRate = ModUtils.CalculateRateWithMods(mods); + LegacySortHelper.Sort(sortedObjects, Comparer.Create((a, b) => (int)Math.Round(a.StartTime) - (int)Math.Round(b.StartTime))); List objects = new List(); @@ -88,7 +91,7 @@ protected override IEnumerable CreateDifficultyHitObjects(I // Sorting is done in CreateDifficultyHitObjects, since the full list of hitobjects is required. protected override IEnumerable SortObjects(IEnumerable input) => input; - protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) => new Skill[] + protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods) => new Skill[] { new Strain(mods, ((ManiaBeatmap)Beatmap).TotalColumns) }; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 2a425712b026..65d708cb3050 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -17,6 +17,7 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Scoring; +using osu.Game.Utils; namespace osu.Game.Rulesets.Osu.Difficulty { @@ -45,7 +46,7 @@ public static double CalculateRateAdjustedOverallDifficulty(double overallDiffic return (79.5 - hitWindowGreat) / 6; } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills) { if (beatmap.HitObjects.Count == 0) return new OsuDifficultyAttributes { Mods = mods }; @@ -77,7 +78,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat double difficultSliders = aim.GetDifficultSliders(); - double overallDifficulty = CalculateRateAdjustedOverallDifficulty(beatmap.Difficulty.OverallDifficulty, clockRate); + double overallDifficulty = CalculateRateAdjustedOverallDifficulty(beatmap.Difficulty.OverallDifficulty, ModUtils.CalculateRateWithMods(mods)); int hitCircleCount = beatmap.HitObjects.Count(h => h is HitCircle); int sliderCount = beatmap.HitObjects.Count(h => h is Slider); @@ -161,10 +162,12 @@ private double calculateStarRating(double basePerformance) return Math.Cbrt(basePerformance * OsuPerformanceCalculator.PERFORMANCE_BASE_MULTIPLIER); } - protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, Mod[] mods) { List objects = new List(); + double clockRate = ModUtils.CalculateRateWithMods(mods); + // The first jump is formed by the first two hitobjects of the map. // If the map has less than two OsuHitObjects, the enumerator will not return anything. for (int i = 1; i < beatmap.HitObjects.Count; i++) @@ -175,7 +178,7 @@ protected override IEnumerable CreateDifficultyHitObjects(I return objects; } - protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) + protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods) { var skills = new List { diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 2cb49e8a4585..64af2861eca2 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -15,6 +15,7 @@ using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm; using osu.Game.Rulesets.Taiko.Difficulty.Skills; using osu.Game.Rulesets.Taiko.Mods; +using osu.Game.Utils; namespace osu.Game.Rulesets.Taiko.Difficulty { @@ -39,7 +40,7 @@ public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) { } - protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) + protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods) { isConvert = beatmap.BeatmapInfo.Ruleset.OnlineID == 0; isRelax = mods.Any(h => h is TaikoModRelax); @@ -62,13 +63,15 @@ protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clo new TaikoModHardRock(), }; - protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, Mod[] mods) { var difficultyHitObjects = new List(); var centreObjects = new List(); var rimObjects = new List(); var noteObjects = new List(); + double clockRate = ModUtils.CalculateRateWithMods(mods); + // Generate TaikoDifficultyHitObjects from the beatmap's hit objects. for (int i = 2; i < beatmap.HitObjects.Count; i++) { @@ -92,7 +95,7 @@ protected override IEnumerable CreateDifficultyHitObjects(I return difficultyHitObjects; } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills) { if (beatmap.HitObjects.Count == 0) return new TaikoDifficultyAttributes { Mods = mods }; diff --git a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs index 90671093a522..f95e5768b0ed 100644 --- a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs +++ b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs @@ -223,17 +223,17 @@ public TestLegacyDifficultyCalculator(params Mod[] mods) protected override Mod[] DifficultyAdjustmentMods { get; } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills) { throw new NotImplementedException(); } - protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, Mod[] mods) { throw new NotImplementedException(); } - protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) + protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods) { throw new NotImplementedException(); } diff --git a/osu.Game.Tests/NonVisual/TestSceneTimedDifficultyCalculation.cs b/osu.Game.Tests/NonVisual/TestSceneTimedDifficultyCalculation.cs index daf0bec44c0c..e3c5b92b54ad 100644 --- a/osu.Game.Tests/NonVisual/TestSceneTimedDifficultyCalculation.cs +++ b/osu.Game.Tests/NonVisual/TestSceneTimedDifficultyCalculation.cs @@ -15,6 +15,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; using osu.Game.Tests.Beatmaps; +using osu.Game.Utils; namespace osu.Game.Tests.NonVisual { @@ -172,13 +173,15 @@ public TestDifficultyCalculator(IWorkingBeatmap beatmap) { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills) => new TestDifficultyAttributes { Objects = beatmap.HitObjects.ToArray() }; - protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, Mod[] mods) { List objects = new List(); + double clockRate = ModUtils.CalculateRateWithMods(mods); + foreach (var obj in beatmap.HitObjects.OfType()) { if (!obj.Skip) @@ -191,7 +194,7 @@ protected override IEnumerable CreateDifficultyHitObjects(I return objects; } - protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) => new Skill[] { new PassThroughSkill(mods) }; + protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods) => new Skill[] { new PassThroughSkill(mods) }; private class PassThroughSkill : Skill { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapAttributeText.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapAttributeText.cs index 5acd6cb0847b..36dbed3742ee 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapAttributeText.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapAttributeText.cs @@ -208,13 +208,13 @@ public TestDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills) => new DifficultyAttributes(mods, mods.OfType().SingleOrDefault()?.Difficulty.Value ?? 0); - protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, Mod[] mods) => Array.Empty(); - protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) + protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods) => Array.Empty(); } diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index 7acfbe651fe8..ec94bd704b6c 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -34,7 +34,6 @@ public abstract class DifficultyCalculator protected readonly IWorkingBeatmap WorkingBeatmap; private Mod[] playableMods; - private double clockRate; private readonly IRulesetInfo ruleset; @@ -74,10 +73,10 @@ public DifficultyAttributes Calculate([NotNull] IEnumerable mods, Cancellat // ReSharper disable once PossiblyMistakenUseOfCancellationToken preProcess(mods, cancellationToken); - var skills = CreateSkills(Beatmap, playableMods, clockRate); + var skills = CreateSkills(Beatmap, playableMods); if (!Beatmap.HitObjects.Any()) - return CreateDifficultyAttributes(Beatmap, playableMods, skills, clockRate); + return CreateDifficultyAttributes(Beatmap, playableMods, skills); foreach (var hitObject in getDifficultyHitObjects()) { @@ -88,7 +87,7 @@ public DifficultyAttributes Calculate([NotNull] IEnumerable mods, Cancellat } } - return CreateDifficultyAttributes(Beatmap, playableMods, skills, clockRate); + return CreateDifficultyAttributes(Beatmap, playableMods, skills); } /// @@ -121,7 +120,7 @@ public List CalculateTimed([NotNull] IEnumerable if (!Beatmap.HitObjects.Any()) return attribs; - var skills = CreateSkills(Beatmap, playableMods, clockRate); + var skills = CreateSkills(Beatmap, playableMods); var progressiveBeatmap = new ProgressiveCalculationBeatmap(Beatmap); var difficultyObjects = getDifficultyHitObjects().ToArray(); @@ -142,7 +141,7 @@ public List CalculateTimed([NotNull] IEnumerable currentIndex++; } - attribs.Add(new TimedDifficultyAttributes(obj.GetEndTime(), CreateDifficultyAttributes(progressiveBeatmap, playableMods, skills, clockRate))); + attribs.Add(new TimedDifficultyAttributes(obj.GetEndTime(), CreateDifficultyAttributes(progressiveBeatmap, playableMods, skills))); } return attribs; @@ -174,7 +173,7 @@ public IEnumerable CalculateAllLegacyCombinations(Cancella /// /// Retrieves the s to calculate against. /// - private IEnumerable getDifficultyHitObjects() => SortObjects(CreateDifficultyHitObjects(Beatmap, clockRate)); + private IEnumerable getDifficultyHitObjects() => SortObjects(CreateDifficultyHitObjects(Beatmap, playableMods)); /// /// Performs required tasks before every calculation. @@ -185,8 +184,6 @@ private void preProcess([NotNull] IEnumerable mods, CancellationToken cance { playableMods = mods.Select(m => m.DeepClone()).ToArray(); Beatmap = WorkingBeatmap.GetPlayableBeatmap(ruleset, playableMods, cancellationToken); - - clockRate = ModUtils.CalculateRateWithMods(playableMods); } /// @@ -277,16 +274,15 @@ static IEnumerable createDifficultyAdjustmentModCombinations(ReadOnlyMemory /// This may differ from in the case of timed calculation. /// The s that difficulty was calculated with. /// The skills which processed the beatmap. - /// The rate at which the gameplay clock is run at. - protected abstract DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate); + protected abstract DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills); /// /// Enumerates s to be processed from s in the . /// /// The providing the s to enumerate. - /// The rate at which the gameplay clock is run at. + /// Mods to create difficulty objects with. /// The enumerated s. - protected abstract IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate); + protected abstract IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, Mod[] mods); /// /// Creates the s to calculate the difficulty of an . @@ -294,9 +290,8 @@ static IEnumerable createDifficultyAdjustmentModCombinations(ReadOnlyMemory /// The whose difficulty will be calculated. /// This may differ from in the case of timed calculation. /// Mods to calculate difficulty with. - /// Clockrate to calculate difficulty with. /// The s. - protected abstract Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate); + protected abstract Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods); /// /// Used to calculate timed difficulty attributes, where only a subset of hitobjects should be visible at any point in time. From b538c1d8bf3a411a2e24095df5c77b99dc21f335 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Tue, 17 Mar 2026 02:35:49 +0500 Subject: [PATCH 818/836] Change the aim scaling slightly (#36967) This slightly buffs aim on above ~7.5 stars maps and slightly nerfs it below that --------- Co-authored-by: James Wilson --- osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs index 5826f497d623..a269704dec22 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs @@ -29,7 +29,7 @@ public double ComputeAimRating(double aimDifficultyValue) if (mods.Any(m => m is OsuModAutopilot)) return 0; - double aimRating = Math.Pow(aimDifficultyValue, 0.62) * 0.0248; + double aimRating = Math.Pow(aimDifficultyValue, 0.63) * 0.02275; if (mods.Any(m => m is OsuModRelax)) aimRating *= 0.9; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 0c2c6a71b085..47e4d7d0f9f1 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -33,7 +33,7 @@ public Aim(Mod[] mods, bool includeSliders) private double skillMultiplierSnap => 71.0; private double skillMultiplierAgility => 2.0; - private double skillMultiplierFlow => 244.0; + private double skillMultiplierFlow => 245.0; private double skillMultiplierTotal => 1.1; private double meanExponent => 1.2; From 9299f1c3b510577098e7b0d3ce250fa4cf5184e2 Mon Sep 17 00:00:00 2001 From: Natelytle Date: Fri, 20 Mar 2026 13:33:27 -0400 Subject: [PATCH 819/836] Quick update thing --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index d6844ae77ddc..f233818fba12 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -4,14 +4,12 @@ using System; using System.Collections.Generic; using System.Linq; -using osu.Framework.Utils; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Evaluators.Aim; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; -using osu.Game.Rulesets.Osu.Difficulty.Utils; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; @@ -48,8 +46,6 @@ protected override double HitProbability(double skill, double difficulty) return DifficultyCalculationUtils.Erf(skill / (Math.Sqrt(2) * difficulty)); } - private double strainDecayAim(double ms) => Math.Pow(0.15, ms / 1000); - private double strainDecaySpeed(double ms) => Math.Pow(0.3, ms / 1000); private double strainDecay(double ms) => Math.Pow(0.15, ms / 1000); protected override double StrainValueAt(DifficultyHitObject current) From c7eeccca5eb6192b70f1282a2d8fd9e133cde932 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Sun, 22 Mar 2026 23:12:23 +0500 Subject: [PATCH 820/836] Make miss penalty slightly harsher on first misses (#37040) https://www.desmos.com/calculator/naggvbcz0a This change makes first ~3 misses have harsher miss penalty, while 9+ misses get lighter penalty. 4-9 misscounts stay close to unchanged. --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index bdc80b691110..cda246132efd 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -534,7 +534,7 @@ private double calculateTraceableBonus(double sliderFactor = 1) // Miss penalty assumes that a player will miss on the hardest parts of a map, // so we use the amount of relatively difficult sections to adjust miss penalty // to make it more punishing on maps with lower amount of hard sections. - private double calculateMissPenalty(double missCount, double difficultStrainCount) => 0.96 / ((missCount / (4 * Math.Pow(Math.Log(difficultStrainCount), 0.94))) + 1); + private double calculateMissPenalty(double missCount, double difficultStrainCount) => 0.93 / (missCount / (4 * Math.Log(difficultStrainCount)) + 1); private double getComboScalingFactor(OsuDifficultyAttributes attributes) => attributes.MaxCombo <= 0 ? 1.0 : Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(attributes.MaxCombo, 0.8), 1.0); private int totalHits => countGreat + countOk + countMeh + countMiss; From 8a78900b2856f5ba5a897c1cec97039ac0dc9320 Mon Sep 17 00:00:00 2001 From: Natelytle Date: Sun, 22 Mar 2026 18:02:45 -0400 Subject: [PATCH 821/836] blonce --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index f233818fba12..0cd87f86a7fd 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -32,8 +32,8 @@ public Aim(Mod[] mods, bool includeSliders) private double skillMultiplierSnap => 355.0; private double skillMultiplierAgility => 10.0; - private double skillMultiplierFlow => 1225; - private double skillMultiplierTotal => 1.02; + private double skillMultiplierFlow => 1100; + private double skillMultiplierTotal => 1.05; private double meanExponent => 1.2; private readonly List sliderStrains = new List(); From 22ac12c346394be7c950951cdb114e9103f99e8a Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Tue, 24 Mar 2026 22:57:31 +0500 Subject: [PATCH 822/836] Undo Agility strain influence rescaling (#37081) Now that agility isn't "speedaim" that covers both snap and flow we can restore it back into it's original scaling. Arguably it should be _more_ than d/t^2 but that's a thing to explore separately --- .../Difficulty/Evaluators/Aim/AgilityEvaluator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs index 10ec462198d7..816c5bce1f2e 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs @@ -38,6 +38,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) return strain * DifficultyCalculationUtils.Smootherstep(distance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS); } - private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.3, Math.Pow(ms / 1000, 0.9))); + private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.15, ms / 1000)); } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 47e4d7d0f9f1..b0eb73256f5f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -32,7 +32,7 @@ public Aim(Mod[] mods, bool includeSliders) private double currentStrain; private double skillMultiplierSnap => 71.0; - private double skillMultiplierAgility => 2.0; + private double skillMultiplierAgility => 2.5; private double skillMultiplierFlow => 245.0; private double skillMultiplierTotal => 1.1; private double meanExponent => 1.2; From 0071c82722d71c85427e37bc7a63254cddff57e4 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:34:36 +0500 Subject: [PATCH 823/836] Adjust high CS bonuses after all the distance-time rescaling (#37088) At this point maybe having a shared small circle bonus in ODHO isn't even worth it since we have different d/t scalings in all evaluators. Bonus was made for snap (~d/t^1.65), here it's adjusted to be higher on agility (~d/t^2) and lower on flow (~d/t). Practically affects like [1 map](https://osu.ppy.sh/beatmapsets/2191876#osu/5192354) --- .../Difficulty/Evaluators/Aim/AgilityEvaluator.cs | 2 +- .../Difficulty/Evaluators/Aim/FlowAimEvaluator.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs index 816c5bce1f2e..ab500ccf351d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs @@ -31,7 +31,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) double strain = distanceScaled * 1000 / osuCurrObj.AdjustedDeltaTime; - strain *= osuCurrObj.SmallCircleBonus; + strain *= Math.Pow(osuCurrObj.SmallCircleBonus, 1.5); strain *= highBpmBonus(osuCurrObj.AdjustedDeltaTime); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs index d50e84f00b6b..9b1903e6137c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs @@ -44,7 +44,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Apply high circle size bonus to the base velocity. // We use reduced CS bonus here because the bonus was made for an evaluator with a different d/t scaling - flowDifficulty *= Math.Pow(osuCurrObj.SmallCircleBonus, 0.75); + flowDifficulty *= Math.Sqrt(osuCurrObj.SmallCircleBonus); // Rhythm changes are harder to flow flowDifficulty *= 1 + Math.Min(0.25, From 0f37874aeb15ca3d39e2b2b5d30c7ce3c9c0c9e1 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:40:09 +0500 Subject: [PATCH 824/836] Increase Aim strain decay base (#37099) This buffs longer jump sections and slightly nerfs short jump spikes. Mostly a way to slightly restore non-aimslop DT aim maps since they got hit with all the nerfs a bit too hard --------- Co-authored-by: James Wilson --- .../Difficulty/Evaluators/Aim/AgilityEvaluator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs index ab500ccf351d..98a5c7680e15 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/AgilityEvaluator.cs @@ -38,6 +38,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) return strain * DifficultyCalculationUtils.Smootherstep(distance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS); } - private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.15, ms / 1000)); + private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.2, ms / 1000)); } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index b0eb73256f5f..25d4b3fd78f0 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -32,9 +32,9 @@ public Aim(Mod[] mods, bool includeSliders) private double currentStrain; private double skillMultiplierSnap => 71.0; - private double skillMultiplierAgility => 2.5; + private double skillMultiplierAgility => 2.35; private double skillMultiplierFlow => 245.0; - private double skillMultiplierTotal => 1.1; + private double skillMultiplierTotal => 1.11; private double meanExponent => 1.2; /// @@ -50,7 +50,7 @@ public Aim(Mod[] mods, bool includeSliders) private readonly List sliderStrains = new List(); - private double strainDecay(double ms) => Math.Pow(0.15, ms / 1000); + private double strainDecay(double ms) => Math.Pow(0.2, ms / 1000); protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => currentStrain * strainDecay(time - current.Previous(0).StartTime); From b31d1b3a08605daf8d0f8f6786eeadf5ec4aeeff Mon Sep 17 00:00:00 2001 From: Givy120 <89256026+Givikap120@users.noreply.github.com> Date: Thu, 26 Mar 2026 12:47:55 +0200 Subject: [PATCH 825/836] Account for alternating angles in reading angle factor (#36466) This rework target is C-type nerf, as this map gets absurd amount of reading pp, because angles are considered very unrepetitive. What results in this score being worth absurd 1.4k pp. This PR is up to heavy discussion because it can be made much more general, touching more maps. So I wait on pp committee opinion on what of the parts can be removed. Current checks for angle to be nerfed: - The smaller angle has to be very sharp: <20 degrees, full power on <5 degrees - The larger angle has to be wide: >60 degrees, full power on >120 degrees If pattern meets all the criteria - it would be considered repetitive. For now practically no map meets this criteria to significant amount except C-type. --- .../Difficulty/Evaluators/ReadingEvaluator.cs | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs index 926abca97125..2d1d5f4d73a7 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs @@ -208,6 +208,10 @@ private static double getConstantAngleNerfFactor(OsuDifficultyHitObject current) int index = 0; double currentTimeGap = 0; + OsuDifficultyHitObject loopObjPrev0 = current; + OsuDifficultyHitObject? loopObjPrev1 = null; + OsuDifficultyHitObject? loopObjPrev2 = null; + while (currentTimeGap < minimum_angle_relevancy_time) { var loopObj = (OsuDifficultyHitObject)current.Previous(index); @@ -221,13 +225,34 @@ private static double getConstantAngleNerfFactor(OsuDifficultyHitObject current) if (loopObj.Angle.IsNotNull() && current.Angle.IsNotNull()) { double angleDifference = Math.Abs(current.Angle.Value - loopObj.Angle.Value); + double angleDifferenceAlternating = Math.PI; + + if (loopObjPrev0.Angle != null && loopObjPrev1?.Angle != null && loopObjPrev2?.Angle != null) + { + angleDifferenceAlternating = Math.Abs(loopObjPrev1.Angle.Value - loopObj.Angle.Value); + angleDifferenceAlternating += Math.Abs(loopObjPrev2.Angle.Value - loopObjPrev0.Angle.Value); + + double weight = 1.0; + + // Be sure that one of the angles is very sharp, when other is wide + weight *= DifficultyCalculationUtils.ReverseLerp(Math.Min(loopObj.Angle.Value, loopObjPrev0.Angle.Value) * 180 / Math.PI, 20, 5); + weight *= DifficultyCalculationUtils.ReverseLerp(Math.Max(loopObj.Angle.Value, loopObjPrev0.Angle.Value) * 180 / Math.PI, 60, 120); + + // Lerp between max angle difference and rescaled alternating difference, with more harsh scaling compared to normal difference + angleDifferenceAlternating = double.Lerp(Math.PI, 0.1 * angleDifferenceAlternating, weight); + } + double stackFactor = DifficultyCalculationUtils.Smootherstep(loopObj.LazyJumpDistance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS); - constantAngleCount += Math.Cos(3 * Math.Min(double.DegreesToRadians(30), angleDifference * stackFactor)) * longIntervalFactor; + constantAngleCount += Math.Cos(3 * Math.Min(double.DegreesToRadians(30), Math.Min(angleDifference, angleDifferenceAlternating) * stackFactor)) * longIntervalFactor; } currentTimeGap = current.StartTime - loopObj.StartTime; index++; + + loopObjPrev2 = loopObjPrev1; + loopObjPrev1 = loopObjPrev0; + loopObjPrev0 = loopObj; } return Math.Clamp(2 / constantAngleCount, 0.2, 1); From b0047e45703293508e42b594f24d5109f757864e Mon Sep 17 00:00:00 2001 From: Nathan Corbett <75299710+Finadoggie@users.noreply.github.com> Date: Fri, 27 Mar 2026 13:08:20 -0700 Subject: [PATCH 826/836] Use variable-length strains to fix chunking-related issues (#33351) - Closes https://github.com/ppy/osu/issues/25254 Solves chunking-related issues by starting a new chunk for every object, and allowing chunks to be different lengths. This is retrofitted to existing calculations, and doesn't have other ramifications in the way something like tr3s's continuous strains do. The effect of this can be seen in the video below. In live pp, the map would lose sr when increasing the rate at certain points, but in the video, the sr rises consistently as expected. https://github.com/user-attachments/assets/2d58946a-9e0c-4f6b-912a-71dfe75c0f8a A multiplier has been added inside `DifficultyValue()` to account for SR being slightly lower from more granular summation. When testing this rework in PerformanceCalculatorGUI, I recommend using [this fork](https://github.com/Finadoggie/osu-tools/tree/variable-length-strains). I can't guarantee that the visuals it shows are correct, but they are definitely more correct than not. Edit: Use [this fork](https://github.com/Finadoggie/osu-tools/tree/unsynced-variable-length-strains) for testing now. Old one is now for testing SynchronizedVariableLengthStrainSkill --------- Co-authored-by: tsunyoku Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com> --- .../OsuDifficultyCalculatorTest.cs | 24 ++ .../Difficulty/Skills/Aim.cs | 84 ++++-- .../Skills/VariableLengthStrainSkill.cs | 277 ++++++++++++++++++ .../Beatmaps/DifficultyCalculatorTest.cs | 6 +- 4 files changed, 371 insertions(+), 20 deletions(-) create mode 100644 osu.Game/Rulesets/Difficulty/Skills/VariableLengthStrainSkill.cs diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs index e7a6d8ecffc2..94768c15a515 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs @@ -34,6 +34,30 @@ public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxComb public void TestClassicMod(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new OsuModClassic()); + [TestCase(239, "diffcalc-test")] + [TestCase(54, "zero-length-sliders")] + [TestCase(4, "very-fast-slider")] + public void TestOffsetChanges(int expectedMaxCombo, string name) + { + const double offset_iterations = 400; + var beatmap = GetBeatmap(name); + + var attributes = CreateDifficultyCalculator(beatmap).Calculate(); + double expectedStarRating = attributes.StarRating; + + for (int i = 0; i < offset_iterations; i++) + { + foreach (var beatmapHitObject in beatmap.Beatmap.HitObjects) + beatmapHitObject.StartTime++; + + attributes = CreateDifficultyCalculator(beatmap).Calculate(); + + // Platform-dependent math functions (Pow, Cbrt, Exp, etc) may result in minute differences. + Assert.That(attributes.StarRating, Is.EqualTo(expectedStarRating).Within(0.00001)); + Assert.That(attributes.MaxCombo, Is.EqualTo(expectedMaxCombo)); + } + } + protected override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new OsuDifficultyCalculator(new OsuRuleset().RulesetInfo, beatmap); protected override Ruleset CreateRuleset() => new OsuRuleset(); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 25d4b3fd78f0..77e519c7895a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// /// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances. /// - public class Aim : StrainSkill + public class Aim : VariableLengthStrainSkill { public readonly bool IncludeSliders; @@ -41,12 +41,12 @@ public Aim(Mod[] mods, bool includeSliders) /// The number of sections with the highest strains, which the peak strain reductions will apply to. /// This is done in order to decrease their impact on the overall difficulty of the map for this skill. /// - private int reducedSectionCount => 10; + private int reducedSectionTime => 4000; /// /// The baseline multiplier applied to the section with the biggest strain. /// - private double reducedStrainBaseline => 0.75; + private double reducedStrainBaseline => 0.727; private readonly List sliderStrains = new List(); @@ -153,30 +153,80 @@ public double CountTopWeightedSliders(double difficultyValue) public override double DifficultyValue() { double difficulty = 0; - double weight = 1; + double time = 0; + var strains = getReducedStrainPeaks(); + + // Difficulty is a continuous weighted sum of the sorted strains + foreach (StrainPeak strain in strains) + { + /* Weighting function can be thought of as: + b + ∫ DecayWeight^x dx + a + where a = startTime and b = endTime + + Technically, the function below has been slightly modified from the equation above. + The real function would be + double weight = Math.Pow(DecayWeight, startTime) - Math.Pow(DecayWeight, endTime); + ... + return difficulty / Math.Log(1 / DecayWeight); + E.g. for a DecayWeight of 0.9, we're multiplying by 10 instead of 9.49122... + + This change makes it so that a map composed solely of MaxSectionLength chunks will have the exact same value when summed in this class and StrainSkill. + Doing this ensures the relationship between strain values and difficulty values remains the same between the two classes. + */ + double startTime = time; + double endTime = time + strain.SectionLength / MaxSectionLength; + + double weight = Math.Pow(DecayWeight, startTime) - Math.Pow(DecayWeight, endTime); + + difficulty += strain.Value * weight; + time = endTime; + } + + return difficulty / (1 - DecayWeight); + } + + /// + /// Returns a sorted enumerable of strain peaks with the highest values reduced. + /// + /// + private IEnumerable getReducedStrainPeaks() + { // Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871). // These sections will not contribute to the difficulty. - var peaks = GetCurrentStrainPeaks().Where(p => p > 0); + var peaks = GetCurrentStrainPeaks().Where(p => p.Value > 0); + + List strains = peaks.OrderByDescending(p => p.Value).ToList(); - List strains = peaks.OrderDescending().ToList(); + const int chunk_size = 20; + double time = 0; + int strainsToRemove = 0; // All strains are removed at the end for optimization purposes // We are reducing the highest strains first to account for extreme difficulty spikes - for (int i = 0; i < Math.Min(strains.Count, reducedSectionCount); i++) + // Strains are split into 20ms chunks to try to mitigate inconsistencies caused by reducing strains + while (strains.Count > strainsToRemove && time < reducedSectionTime) { - double scale = Math.Log10(Interpolation.Lerp(1, 10, Math.Clamp((float)i / reducedSectionCount, 0, 1))); - strains[i] *= Interpolation.Lerp(reducedStrainBaseline, 1.0, scale); - } + StrainPeak strain = strains[strainsToRemove]; - // Difficulty is the weighted sum of the highest strains from every section. - // We're sorting from highest to lowest strain. - foreach (double strain in strains.OrderDescending()) - { - difficulty += strain * weight; - weight *= DecayWeight; + for (double addedTime = 0; addedTime < strain.SectionLength; addedTime += chunk_size) + { + double scale = Math.Log10(Interpolation.Lerp(1, 10, Math.Clamp((time + addedTime) / reducedSectionTime, 0, 1))); + + strains.Add(new StrainPeak( + strain.Value * Interpolation.Lerp(reducedStrainBaseline, 1.0, scale), + Math.Min(chunk_size, strain.SectionLength - addedTime) + )); + } + + time += strain.SectionLength; + strainsToRemove++; } - return difficulty; + strains.RemoveRange(0, strainsToRemove); + + return strains.OrderByDescending(p => p.Value); } } } diff --git a/osu.Game/Rulesets/Difficulty/Skills/VariableLengthStrainSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/VariableLengthStrainSkill.cs new file mode 100644 index 000000000000..a45af7453983 --- /dev/null +++ b/osu.Game/Rulesets/Difficulty/Skills/VariableLengthStrainSkill.cs @@ -0,0 +1,277 @@ +// 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.Collections.Generic; +using System.Linq; +using osu.Framework.Extensions; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Difficulty.Skills +{ + /// + /// Similar to , but instead of strains having a fixed length, strains can be any length. + /// A new is created for each . + /// + public abstract class VariableLengthStrainSkill : Skill + { + /// + /// The weight by which each strain value decays. + /// + protected virtual double DecayWeight => 0.9; + + /// + /// The maximum length of each strain section. + /// + protected virtual int MaxSectionLength => 400; + + private double currentSectionPeak; // We also keep track of the peak strain in the current section. + private double currentSectionBegin; + private double currentSectionEnd; + + /// + /// The number of `MaxSectionLength` sections calculated such that enough of the difficulty value is preserved. + /// WARNING: This should be overridden if strains are ever used outside of , + /// or if is overridden to not use the default geometric sum. This should be removed + /// in the future when a better memory-saving technique is implemented. + /// + private double maxStoredSections => 11 / (1 - DecayWeight); + + private readonly List strainPeaks = new List(); + + private double totalLength; + + /// + /// Stores previous strains so that, if a high difficulty hit object is followed by a lower + /// difficulty hit object, the high difficulty hit object gets a full strain instead of being cut short. + /// + private readonly List<(double StrainValue, double StartTime)> queuedStrains = new List<(double, double)>(); + + protected VariableLengthStrainSkill(Mod[] mods) + : base(mods) + { + } + + /// + /// Returns the strain value at . This value is calculated with or without respect to previous objects. + /// + protected abstract double StrainValueAt(DifficultyHitObject current); + + /// + /// Process a and update current strain values accordingly. + /// + protected sealed override double ProcessInternal(DifficultyHitObject current) + { + // If we're on the first object, set up the first section to end `MaxSectionLength` after it. + if (current.Index == 0) + { + currentSectionBegin = current.StartTime; + currentSectionEnd = currentSectionBegin + MaxSectionLength; + + // No work is required for first object after calculating difficulty + currentSectionPeak = StrainValueAt(current); + return currentSectionPeak; + } + + backfillPeaks(current); + + double currentStrain = StrainValueAt(current); + + // If the current strain is larger than the current peak, begin a new peak + // Otherwise, add the current strain to the queue + if (currentStrain > currentSectionPeak) + { + // Clear the queue since none of the strains inside of it will be contributing to the difficulty. + queuedStrains.Clear(); + + // End the current section with the new peak + saveCurrentPeak(current.StartTime - currentSectionBegin); + + // Set up the new section to start at the current object with the current strain + currentSectionBegin = current.StartTime; + currentSectionEnd = currentSectionBegin + MaxSectionLength; + currentSectionPeak = currentStrain; + } + else + { + // Empty the queue of smaller elements as they won't be relevant to difficulty + while (queuedStrains.Count > 0 && queuedStrains[^1].StrainValue < currentStrain) + queuedStrains.RemoveAt(queuedStrains.Count - 1); + + queuedStrains.Add((currentStrain, current.StartTime)); + } + + return currentStrain; + } + + /// + /// Fills the space between the end of the current section and the current object, if there is any. + /// + /// The object who's is backfilled to. + private void backfillPeaks(DifficultyHitObject current) + { + // If the current object starts after the current section ends + // then we want to start a new section without any harsh drop-off. + // If we have previous strains that influence the current difficulty we will prioritise those first. + // Otherwise, start with the current object's initial strain. + while (current.StartTime > currentSectionEnd) + { + // Save the current peak, marking the end of the section. + saveCurrentPeak(currentSectionEnd - currentSectionBegin); + currentSectionBegin = currentSectionEnd; + + // If we have any strains queued, then we will use those until the object falls into the new section. + if (queuedStrains.Count > 0) + { + (double strain, double startTime) = queuedStrains[0]; + queuedStrains.RemoveAt(0); + + // We want the section to end `MaxSectionLength` after the strain we're using as an influence. + // This effectively means the queued strain will exist in its own section if the gap between the queued strain and current object is large enough. + // This is required to make sure there's no harsh difficulty difference between 2 sections if there was a large gap. + currentSectionEnd = startTime + MaxSectionLength; + startNewSectionFrom(currentSectionBegin, current); + + // If the current object's peak was higher, we don't want to override it with a lower strain. + // Only use the queued strain if it contributes more difficulty. + currentSectionPeak = Math.Max(currentSectionPeak, strain); + } + // If the queue is empty then we should start the section from the current object instead. + // The queue can be empty if we're starting off of the back of a new peak, or if we drained through all the queue + // and the current object is still later than the section end. + else + { + // We don't have any prior strains to take as a reference, so end the new section `MaxSectionLength` after it starts. + currentSectionEnd = currentSectionBegin + MaxSectionLength; + startNewSectionFrom(currentSectionBegin, current); + } + } + } + + /// + /// Saves the current peak strain level to the list of strain peaks, which will be used to calculate an overall difficulty. + /// + private void saveCurrentPeak(double sectionLength) + { + strainPeaks.AddInPlace(new StrainPeak(currentSectionPeak, sectionLength)); + totalLength += sectionLength; + + // Remove from the back of our strain peaks if there's any which are too deep to contribute to difficulty. + // `maxStoredSections` dictates for us how many sections will preserve at least 99.999% of the difficulty value. + while (totalLength > maxStoredSections * MaxSectionLength) + { + totalLength -= strainPeaks[0].SectionLength; + strainPeaks.RemoveAt(0); + } + } + + /// + /// Sets the initial strain level for a new section. + /// + /// The beginning of the new section in milliseconds. + /// The current hit object. + private void startNewSectionFrom(double time, DifficultyHitObject current) + { + // The maximum strain of the new section is not zero by default + // This means we need to capture the strain level at the beginning of the new section, and use that as the initial peak level. + currentSectionPeak = CalculateInitialStrain(time, current); + } + + /// + /// Retrieves the peak strain at a point in time. + /// + /// The time to retrieve the peak strain at. + /// The current hit object. + /// The peak strain. + protected abstract double CalculateInitialStrain(double time, DifficultyHitObject current); + + /// + /// Returns a live enumerable of the peak strains for each section of the beatmap, + /// including the peak of the current section. + /// + public IEnumerable GetCurrentStrainPeaks() => strainPeaks.Append(new StrainPeak(currentSectionPeak, currentSectionEnd - currentSectionBegin)); + + /// + /// Returns the calculated difficulty value representing all s that have been processed up to this point. + /// + public override double DifficultyValue() + { + double difficulty = 0; + + // Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871). + // These sections will not contribute to the difficulty. + var peaks = GetCurrentStrainPeaks().Where(p => p.Value > 0); + + List strains = peaks.OrderByDescending(p => (p.Value, p.SectionLength)).ToList(); + + // Time is measured in units of strains + double time = 0; + + // Difficulty is a continuous weighted sum of the sorted strains + for (int i = 0; i < strains.Count; i++) + { + /* Weighting function can be thought of as: + b + ∫ DecayWeight^x dx + a + where a = startTime and b = endTime + + Technically, the function below has been slightly modified from the equation above. + The real function would be + double weight = Math.Pow(DecayWeight, startTime) - Math.Pow(DecayWeight, endTime)) + ... + return difficulty / Math.Log(1 / DecayWeight) + E.g. for a DecayWeight of 0.9, we're multiplying by 10 instead of 9.49122... + + This change makes it so that a map composed solely of MaxSectionLength chunks will have the exact same value when summed in this class and StrainSkill. + Doing this ensures the relationship between strain values and difficulty values remains the same between the two classes. + */ + double startTime = time; + double endTime = time + strains[i].SectionLength; + + double weight = Math.Pow(DecayWeight, startTime) - Math.Pow(DecayWeight, endTime); + + difficulty += strains[i].Value * weight; + time = endTime; + } + + return difficulty / (1 - DecayWeight); + } + + /// + /// Calculates the number of strains weighted against the top strain. + /// The result is scaled by clock rate as it affects the total number of strains. + /// + public virtual double CountTopWeightedStrains(double difficultyValue) + { + if (ObjectDifficulties.Count == 0) + return 0.0; + + double consistentTopStrain = difficultyValue * (1 - DecayWeight); // What would the top strain be if all strain values were identical + + if (consistentTopStrain == 0) + return ObjectDifficulties.Count; + + // Use a weighted sum of all strains. Constants are arbitrary and give nice values + return ObjectDifficulties.Sum(s => 1.1 / (1 + Math.Exp(-10 * (s / consistentTopStrain - 0.88)))); + } + + /// + /// Used to store the difficulty of a section of a map. + /// + public readonly struct StrainPeak : IComparable + { + public StrainPeak(double value, double sectionLength) + { + Value = value; + SectionLength = Math.Round(sectionLength); + } + + public double Value { get; } + public double SectionLength { get; } + + public int CompareTo(StrainPeak other) => Value.CompareTo(other.Value); + } + } +} diff --git a/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs b/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs index 16434406b509..e98c34d603b0 100644 --- a/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs +++ b/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs @@ -23,16 +23,16 @@ public abstract class DifficultyCalculatorTest protected abstract string ResourceAssembly { get; } - protected void Test(double expectedStarRating, int expectedMaxCombo, string name, params Mod[] mods) + protected void Test(double? expectedStarRating, int expectedMaxCombo, string name, params Mod[] mods) { - var attributes = CreateDifficultyCalculator(getBeatmap(name)).Calculate(mods); + var attributes = CreateDifficultyCalculator(GetBeatmap(name)).Calculate(mods); // Platform-dependent math functions (Pow, Cbrt, Exp, etc) may result in minute differences. Assert.That(attributes.StarRating, Is.EqualTo(expectedStarRating).Within(0.00001)); Assert.That(attributes.MaxCombo, Is.EqualTo(expectedMaxCombo)); } - private IWorkingBeatmap getBeatmap(string name) + protected IWorkingBeatmap GetBeatmap(string name) { using (var resStream = openResource($"{resource_namespace}.{name}.osu")) using (var stream = new LineBufferedReader(resStream)) From 4ce4bca6a7391b4effb92bfeb029df2556ae154e Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Fri, 27 Mar 2026 23:49:21 +0300 Subject: [PATCH 827/836] Very slight overall aim buff (#37134) --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 77e519c7895a..9fbf496c82af 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -34,7 +34,7 @@ public Aim(Mod[] mods, bool includeSliders) private double skillMultiplierSnap => 71.0; private double skillMultiplierAgility => 2.35; private double skillMultiplierFlow => 245.0; - private double skillMultiplierTotal => 1.11; + private double skillMultiplierTotal => 1.12; private double meanExponent => 1.2; /// From e082550ceade7c4a0d4f4f5a470c29afe339558d Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Sun, 29 Mar 2026 22:11:24 +0300 Subject: [PATCH 828/836] Aim balancing (#37147) --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 9fbf496c82af..b6b9bf3a01c0 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -31,9 +31,9 @@ public Aim(Mod[] mods, bool includeSliders) private double currentStrain; - private double skillMultiplierSnap => 71.0; + private double skillMultiplierSnap => 70.9; private double skillMultiplierAgility => 2.35; - private double skillMultiplierFlow => 245.0; + private double skillMultiplierFlow => 243.0; private double skillMultiplierTotal => 1.12; private double meanExponent => 1.2; From c4ef081c4a308dd068c235874ac46ff334b8a46a Mon Sep 17 00:00:00 2001 From: kwotaq <80002984+kwotaq@users.noreply.github.com> Date: Sun, 29 Mar 2026 22:31:03 +0300 Subject: [PATCH 829/836] Refactor Reading strain to match the rest of the skills (#37010) This doesn't affect values as per the original refactor. Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com> --- .../Difficulty/Evaluators/ReadingEvaluator.cs | 5 +++++ osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs index 2d1d5f4d73a7..fe6d49661b9c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs @@ -48,6 +48,9 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool hidd double difficulty = DifficultyCalculationUtils.Norm(1.5, preemptDifficulty, hiddenDifficulty, noteDensityDifficulty); + // Having less time to process information is harder + difficulty *= highBpmBonus(currObj.AdjustedDeltaTime); + return difficulty; } @@ -263,5 +266,7 @@ private static double getTimeNerfFactor(double deltaTime) { return Math.Clamp(2 - deltaTime / (reading_window_size / 2), 0, 1); } + + private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.8, ms / 1000)); } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs index c548da5b8d76..414cf1f1f9b8 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs @@ -37,9 +37,11 @@ protected override double ObjectDifficultyOf(DifficultyHitObject current) { objectList.Add(current); - currentDifficulty *= strainDecay(current.DeltaTime); + double decay = strainDecay(current.DeltaTime); - currentDifficulty += ReadingEvaluator.EvaluateDifficultyOf(current, hasHiddenMod) * skillMultiplier; + currentDifficulty *= decay; + + currentDifficulty += ReadingEvaluator.EvaluateDifficultyOf(current, hasHiddenMod) * (1 - decay) * skillMultiplier; return currentDifficulty; } From f6223d19afe753b94d3a9f6474f8c44ceda50394 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Fri, 3 Apr 2026 19:09:22 +0300 Subject: [PATCH 830/836] Move Aim mod-related difficulty adjustments to after the probability calculation (#37184) Adjusting difficulty before we calculate the flow probability is technically wrong. This makes flow adjustment on RX actually work as it should instead of trying to lower the snap to achieve similar results. TD flow buff was removed because here it actually made some maps _very_ buffed. Values are mostly the same otherwise --- .../Difficulty/OsuRatingCalculator.cs | 3 -- .../Difficulty/Skills/Aim.cs | 29 ++++++++++--------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs index a269704dec22..9dc9b1afa430 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs @@ -31,9 +31,6 @@ public double ComputeAimRating(double aimDifficultyValue) double aimRating = Math.Pow(aimDifficultyValue, 0.63) * 0.02275; - if (mods.Any(m => m is OsuModRelax)) - aimRating *= 0.9; - if (mods.Any(m => m is OsuModMagnetised)) { float magnetisedStrength = mods.OfType().First().AttractionStrength.Value; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index b6b9bf3a01c0..535953336ce2 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -35,7 +35,7 @@ public Aim(Mod[] mods, bool includeSliders) private double skillMultiplierAgility => 2.35; private double skillMultiplierFlow => 243.0; private double skillMultiplierTotal => 1.12; - private double meanExponent => 1.2; + private double combinedSnapNormExponent => 1.2; /// /// The number of sections with the highest strains, which the peak strain reductions will apply to. @@ -63,18 +63,6 @@ protected override double StrainValueAt(DifficultyHitObject current) double agilityDifficulty = AgilityEvaluator.EvaluateDifficultyOf(current) * skillMultiplierAgility; double flowDifficulty = FlowAimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * skillMultiplierFlow; - if (Mods.Any(m => m is OsuModTouchDevice)) - { - snapDifficulty = Math.Pow(snapDifficulty, 0.89); - // we don't adjust agility here since agility represents TD difficulty in a decent enough way - flowDifficulty = Math.Pow(flowDifficulty, 1.1); - } - - if (Mods.Any(m => m is OsuModRelax)) - { - agilityDifficulty *= 0.3; - } - double totalDifficulty = calculateTotalValue(snapDifficulty, agilityDifficulty, flowDifficulty); currentStrain *= decay; @@ -91,11 +79,24 @@ private double calculateTotalValue(double snapDifficulty, double agilityDifficul // We compare flow to combined snap and agility because snap by itself doesn't have enough difficulty to be above flow on streams // Agility on the other hand is supposed to measure the rate of cursor velocity changes while snapping // So snapping every circle on a stream requires an enormous amount of agility at which point it's easier to flow - double combinedSnapDifficulty = DifficultyCalculationUtils.Norm(meanExponent, snapDifficulty, agilityDifficulty); + double combinedSnapDifficulty = DifficultyCalculationUtils.Norm(combinedSnapNormExponent, snapDifficulty, agilityDifficulty); double pSnap = calculateSnapFlowProbability(flowDifficulty / combinedSnapDifficulty); double pFlow = 1 - pSnap; + if (Mods.Any(m => m is OsuModTouchDevice)) + { + // we don't adjust agility here since agility represents TD difficulty in a decent enough way + snapDifficulty = Math.Pow(snapDifficulty, 0.89); + combinedSnapDifficulty = DifficultyCalculationUtils.Norm(combinedSnapNormExponent, snapDifficulty, agilityDifficulty); + } + + if (Mods.Any(m => m is OsuModRelax)) + { + combinedSnapDifficulty *= 0.75; + flowDifficulty *= 0.6; + } + double totalDifficulty = combinedSnapDifficulty * pSnap + flowDifficulty * pFlow; double totalStrain = totalDifficulty * skillMultiplierTotal; From 5049ac8e29fa56f4b2f879679876a8260cd37f0e Mon Sep 17 00:00:00 2001 From: kwotaq <80002984+kwotaq@users.noreply.github.com> Date: Sun, 12 Apr 2026 17:50:33 +0300 Subject: [PATCH 831/836] Refactor SnapAimEvaluator bonuses for better readability (#37119) This PR moves the addition of the bonuses closer to their declaration and also renames some variables and functions to more closely resemble the way they're used. The names can be discussed for I'm not sold on them either. --------- Co-authored-by: James Wilson --- .../Evaluators/Aim/FlowAimEvaluator.cs | 2 +- .../Evaluators/Aim/SnapAimEvaluator.cs | 85 +++++++++---------- 2 files changed, 39 insertions(+), 48 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs index 9b1903e6137c..cac4febf1dd6 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs @@ -77,7 +77,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Acute angles are also hard to flow // We square root velocity to make acute angle switches in streams aren't having difficulty higher than snap flowDifficulty += Math.Sqrt(currVelocity) * - SnapAimEvaluator.CalcAcuteAngleBonus(osuCurrObj.Angle.Value) * + SnapAimEvaluator.CalcAngleAcuteness(osuCurrObj.Angle.Value) * overlappedNotesWeight; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs index 75ecfe89ecc1..3a67c84ac3c5 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs @@ -55,51 +55,37 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double prevDistance = withSliderTravelDistance ? osuLastObj.LazyJumpDistance : osuLastObj.JumpDistance; double prevVelocity = prevDistance / osuLastObj.AdjustedDeltaTime; - double wideAngleBonus = 0; - double acuteAngleBonus = 0; - double sliderBonus = 0; - double velocityChangeBonus = 0; - double wiggleBonus = 0; - double aimStrain = currVelocity; // Start strain with regular velocity. + // Penalize angle repetition. + aimStrain *= vectorAngleRepetition(osuCurrObj, osuLastObj); + if (osuCurrObj.Angle != null && osuLastObj.Angle != null) { double currAngle = osuCurrObj.Angle.Value; double lastAngle = osuLastObj.Angle.Value; // Rewarding angles, take the smaller velocity as base. - double angleBonus = Math.Min(currVelocity, prevVelocity); + double velocityInfluence = Math.Min(currVelocity, prevVelocity); + + double acuteAngleBonus = 0; if (Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) < 1.25 * Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime)) // If rhythms are the same. { - acuteAngleBonus = CalcAcuteAngleBonus(currAngle); - - // Penalize angle repetition. - acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(CalcAcuteAngleBonus(lastAngle), 3))); + acuteAngleBonus = velocityInfluence * CalcAngleAcuteness(currAngle); // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter - acuteAngleBonus *= angleBonus * - DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * + acuteAngleBonus *= DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * DifficultyCalculationUtils.Smootherstep(currDistance, 0, diameter * 2); + + // Penalize angle repetition. + acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(CalcAngleAcuteness(lastAngle), 3))); } - wideAngleBonus = calcWideAngleBonus(currAngle); + double wideAngleBonus = velocityInfluence * calcAngleWideness(currAngle); // Penalize angle repetition. - wideAngleBonus *= 0.25 + 0.75 * (1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3))); - - wideAngleBonus *= angleBonus; - - // Apply wiggle bonus for jumps that are [radius, 3*diameter] in distance, with < 110 angle - // https://www.desmos.com/calculator/dp0v0nvowc - wiggleBonus = angleBonus - * DifficultyCalculationUtils.Smootherstep(currDistance, radius, diameter) - * Math.Pow(DifficultyCalculationUtils.ReverseLerp(currDistance, diameter * 3, diameter), 1.8) - * DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)) - * DifficultyCalculationUtils.Smootherstep(prevDistance, radius, diameter) - * Math.Pow(DifficultyCalculationUtils.ReverseLerp(prevDistance, diameter * 3, diameter), 1.8) - * DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)); + wideAngleBonus *= 0.25 + 0.75 * (1 - Math.Min(wideAngleBonus, Math.Pow(calcAngleWideness(lastAngle), 3))); if (osuLast2Obj != null) { @@ -115,6 +101,21 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with wideAngleBonus *= 1 - 0.55 * (1 - distance); } } + + // Add in acute angle bonus or wide angle bonus, whichever is larger. + aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier); + + // Apply wiggle bonus for jumps that are [radius, 3*diameter] in distance, with < 110 angle + // https://www.desmos.com/calculator/dp0v0nvowc + double wiggleBonus = velocityInfluence + * DifficultyCalculationUtils.Smootherstep(currDistance, radius, diameter) + * Math.Pow(DifficultyCalculationUtils.ReverseLerp(currDistance, diameter * 3, diameter), 1.8) + * DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)) + * DifficultyCalculationUtils.Smootherstep(prevDistance, radius, diameter) + * Math.Pow(DifficultyCalculationUtils.ReverseLerp(prevDistance, diameter * 3, diameter), 1.8) + * DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)); + + aimStrain += wiggleBonus * wiggle_multiplier; } if (Math.Max(prevVelocity, currVelocity) != 0) @@ -131,30 +132,20 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Reward for % distance up to 125 / strainTime for overlaps where velocity is still changing. double overlapVelocityBuff = Math.Min(diameter * 1.25 / Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime), Math.Abs(prevVelocity - currVelocity)); - velocityChangeBonus = overlapVelocityBuff * distRatio; + double velocityChangeBonus = overlapVelocityBuff * distRatio; // Penalize for rhythm changes. velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) / Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime), 2); - } - if (osuCurrObj.BaseObject is Slider) - { - // Reward sliders based on velocity. - sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; + aimStrain += velocityChangeBonus * velocity_change_multiplier; } - // Penalize angle repetition. - aimStrain *= vectorAngleRepetition(osuCurrObj, osuLastObj); - - aimStrain += wiggleBonus * wiggle_multiplier; - aimStrain += velocityChangeBonus * velocity_change_multiplier; - - // Add in acute angle bonus or wide angle bonus, whichever is larger. - aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier); - - // Add in additional slider velocity bonus. - if (withSliderTravelDistance) + // Reward sliders based on velocity. + if (osuCurrObj.BaseObject is Slider && withSliderTravelDistance) + { + double sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; aimStrain += (sliderBonus < 1 ? sliderBonus : Math.Pow(sliderBonus, 0.75)) * slider_multiplier; + } // Apply high circle size bonus aimStrain *= osuCurrObj.SmallCircleBonus; @@ -208,13 +199,13 @@ private static double vectorAngleRepetition(OsuDifficultyHitObject current, OsuD double angleDifferenceAdjusted = Math.Cos(2 * Math.Min(double.DegreesToRadians(45), Math.Abs(currAngle - lastAngle) * stackFactor)); - double baseNerf = 1 - maximum_repetition_nerf * CalcAcuteAngleBonus(lastAngle) * angleDifferenceAdjusted; + double baseNerf = 1 - maximum_repetition_nerf * CalcAngleAcuteness(lastAngle) * angleDifferenceAdjusted; return Math.Pow(baseNerf + (1 - baseNerf) * vectorRepetition * maximum_vector_influence * stackFactor, 2); } - private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); + private static double calcAngleWideness(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); - public static double CalcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40)); + public static double CalcAngleAcuteness(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40)); } } From b20b3670afb5ccf80c15198470a54510e81c6c18 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Mon, 13 Apr 2026 21:36:38 +0300 Subject: [PATCH 832/836] Fix snap angle repetition (#37286) Classic blunder. --- .../Evaluators/Aim/SnapAimEvaluator.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs index 3a67c84ac3c5..02421ffa0de7 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs @@ -72,21 +72,23 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with if (Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) < 1.25 * Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime)) // If rhythms are the same. { - acuteAngleBonus = velocityInfluence * CalcAngleAcuteness(currAngle); + acuteAngleBonus = CalcAngleAcuteness(currAngle); + + // Penalize angle repetition. It is important to do it _before_ multiplying by anything because we compare raw acuteness here + acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(CalcAngleAcuteness(lastAngle), 3))); // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter - acuteAngleBonus *= DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * + acuteAngleBonus *= velocityInfluence * DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * DifficultyCalculationUtils.Smootherstep(currDistance, 0, diameter * 2); - - // Penalize angle repetition. - acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(CalcAngleAcuteness(lastAngle), 3))); } - double wideAngleBonus = velocityInfluence * calcAngleWideness(currAngle); + double wideAngleBonus = calcAngleWideness(currAngle); - // Penalize angle repetition. + // Penalize angle repetition. It is important to do it _before_ multiplying by velocity because we compare raw wideness here wideAngleBonus *= 0.25 + 0.75 * (1 - Math.Min(wideAngleBonus, Math.Pow(calcAngleWideness(lastAngle), 3))); + wideAngleBonus *= velocityInfluence; + if (osuLast2Obj != null) { // If objects just go back and forth through a middle point - don't give as much wide bonus From a057138eafbc5818c52908dd85fc47712ea8a262 Mon Sep 17 00:00:00 2001 From: StanR <8269193+stanriders@users.noreply.github.com> Date: Wed, 15 Apr 2026 22:39:08 +0300 Subject: [PATCH 833/836] Fix low distance snap/flow relation (#37306) Currently all low spaced ( /// Evaluates the difficulty of fast aiming @@ -35,7 +34,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current) strain *= highBpmBonus(osuCurrObj.AdjustedDeltaTime); - return strain * DifficultyCalculationUtils.Smootherstep(distance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS); + return strain; } private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.2, ms / 1000)); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs index cac4febf1dd6..30f45a3226a5 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators.Aim { public static class FlowAimEvaluator { - private const double velocity_change_multiplier = 2.0; + private const double velocity_change_multiplier = 0.52; /// /// Evaluates difficulty of "flow aim" - aiming pattern where player doesn't stop their cursor on every object and instead "flows" through them. @@ -108,7 +108,10 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with } // Final velocity is being raised to a power because flow difficulty scales harder with both high distance and time, and we want to account for that - return Math.Pow(flowDifficulty, 1.45); + flowDifficulty = Math.Pow(flowDifficulty, 1.45); + + // Reduce difficulty for low spacing since spacing below radius is always to be flowed + return flowDifficulty * DifficultyCalculationUtils.Smootherstep(currDistance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS); } private static double calculateOverlapFactor(OsuDifficultyHitObject first, OsuDifficultyHitObject second) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs index 02421ffa0de7..a373df706cd5 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs @@ -152,16 +152,12 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Apply high circle size bonus aimStrain *= osuCurrObj.SmallCircleBonus; - aimStrain *= highBpmBonus(osuCurrObj.AdjustedDeltaTime, osuCurrObj.LazyJumpDistance); + aimStrain *= highBpmBonus(osuCurrObj.AdjustedDeltaTime); return aimStrain; } - // We decrease strain for distances 1 / (1 - Math.Pow(0.03, Math.Pow(ms / 1000, 0.65))) - * DifficultyCalculationUtils.Smootherstep(distance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS); + private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.03, Math.Pow(ms / 1000, 0.65))); private static double vectorAngleRepetition(OsuDifficultyHitObject current, OsuDifficultyHitObject previous) { From 5aff5a4098dade76933f3a8871a8e03ea9f71f4b Mon Sep 17 00:00:00 2001 From: piiid Date: Thu, 16 Apr 2026 16:45:53 -0400 Subject: [PATCH 834/836] Rebalance TC Bonus (#36555) --- .../Difficulty/OsuPerformanceCalculator.cs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index cda246132efd..dc3d9cd19d54 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -243,16 +243,11 @@ private double computeSpeedValue(ScoreInfo score, OsuDifficultyAttributes attrib speedValue *= calculateMissPenalty(relevantMissCount, attributes.SpeedDifficultStrainCount); } - // TC bonuses are excluded when blinds is present as the increased visual difficulty is unimportant when notes cannot be seen. if (score.Mods.Any(m => m is OsuModBlinds)) { // Increasing the speed value by object count for Blinds isn't ideal, so the minimum buff is given. speedValue *= 1.12; } - else if (score.Mods.Any(m => m is OsuModTraceable)) - { - speedValue *= 1.0 + calculateTraceableBonus(); - } double speedHighDeviationMultiplier = calculateSpeedHighDeviationNerf(attributes); speedValue *= speedHighDeviationMultiplier; @@ -514,19 +509,21 @@ private double calculateSpeedHighDeviationNerf(OsuDifficultyAttributes attribute /// private double calculateTraceableBonus(double sliderFactor = 1) { - // Start from normal curve, rewarding lower AR up to AR7 - double traceableBonus = 0.025 * (12.0 - Math.Max(approachRate, 7)); + // We want to reward slider aim less, more so at lower AR + double highApproachRateSliderVisibilityFactor = 0.5 + (Math.Pow(sliderFactor, 6) / 2); + double lowApproachRateSliderVisibilityFactor = Math.Pow(sliderFactor, 6); - // We want to reward slider aim on low AR less - double sliderVisibilityFactor = Math.Pow(sliderFactor, 3); + // Start from normal curve, rewarding lower AR up to AR7 + double traceableBonus = 0.0275; + traceableBonus += 0.025 * (12.0 - Math.Max(approachRate, 7)) * highApproachRateSliderVisibilityFactor; // For AR up to 0 - reduce reward for very low ARs when object is visible if (approachRate < 7) - traceableBonus += 0.02 * (7.0 - Math.Max(approachRate, 0)) * sliderVisibilityFactor; + traceableBonus += 0.025 * (7.0 - Math.Max(approachRate, 0)) * lowApproachRateSliderVisibilityFactor; // Starting from AR0 - cap values so they won't grow to infinity if (approachRate < 0) - traceableBonus += 0.01 * (1 - Math.Pow(1.5, approachRate)) * sliderVisibilityFactor; + traceableBonus += 0.025 * (1 - Math.Pow(1.5, approachRate)) * lowApproachRateSliderVisibilityFactor; return traceableBonus; } From 16089ad524c3e7ce42746468f2134876f52d3b9a Mon Sep 17 00:00:00 2001 From: danielthirtle Date: Sat, 18 Apr 2026 00:34:51 +1200 Subject: [PATCH 835/836] add deviation breakdown past a certain difficulty --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 0cd87f86a7fd..e6c59188a02d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -43,7 +43,16 @@ protected override double HitProbability(double skill, double difficulty) if (difficulty <= 0) return 1; if (skill <= 0) return 0; - return DifficultyCalculationUtils.Erf(skill / (Math.Sqrt(2) * difficulty)); + double baseDeviation = difficulty / skill; + // at what point does the player lose the ability to aim normally + // increasing this will like high misscount scores more than ringtone maps, and vice versa + const double limit_of_proportion = 0.727; + // how quickly does the player lose the ability to aim normally at the limit of proportion + // increasing this has a similar effect as increasing the limit of proportion, but it changes how significant the effect is across maps + const double breakdown_rate = 30; + double adjustedDeviation = baseDeviation + Math.Exp(breakdown_rate * (baseDeviation - limit_of_proportion)); + + return DifficultyCalculationUtils.Erf(1 / (Math.Sqrt(2) * adjustedDeviation)); } private double strainDecay(double ms) => Math.Pow(0.15, ms / 1000); From c175a5406e2ffa096d93606c29c3bea777ee21e6 Mon Sep 17 00:00:00 2001 From: kwotaq Date: Fri, 17 Apr 2026 15:47:40 +0300 Subject: [PATCH 836/836] merhe fix --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 8a7f032fdb22..a9bad06d3f05 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -34,7 +34,7 @@ public Aim(Mod[] mods, bool includeSliders) private double skillMultiplierAgility => 10.0; private double skillMultiplierFlow => 1100; private double skillMultiplierTotal => 1.05; - private double meanExponent => 1.2; + private double combinedSnapNormExponent => 1.2; private readonly List sliderStrains = new List();