diff --git a/osu.Android.props b/osu.Android.props
index 8f83c9730b..c0be002bb5 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -51,8 +51,8 @@
-
+
diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs
index d9ad95f96a..3ee1b3da30 100644
--- a/osu.Desktop/OsuGameDesktop.cs
+++ b/osu.Desktop/OsuGameDesktop.cs
@@ -137,12 +137,13 @@ namespace osu.Desktop
{
base.SetHost(host);
- var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico");
-
var desktopWindow = (SDL2DesktopWindow)host.Window;
+ var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico");
+ if (iconStream != null)
+ desktopWindow.SetIconFromStream(iconStream);
+
desktopWindow.CursorState |= CursorState.Hidden;
- desktopWindow.SetIconFromStream(iconStream);
desktopWindow.Title = Name;
desktopWindow.DragDrop += f => fileDrop(new[] { f });
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
index 6f4ca30bd0..d9d0d28477 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
@@ -11,7 +11,9 @@ using osu.Framework.Graphics.Primitives;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Judgements;
+using osu.Game.Rulesets.Osu.Scoring;
using osuTK;
+using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
@@ -64,6 +66,23 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
ScaleBindable.UnbindFrom(HitObject.ScaleBindable);
}
+ protected override void UpdateInitialTransforms()
+ {
+ base.UpdateInitialTransforms();
+
+ // Dim should only be applied at a top level, as it will be implicitly applied to nested objects.
+ if (ParentHitObject == null)
+ {
+ // Of note, no one noticed this was missing for years, but it definitely feels like it should still exist.
+ // For now this is applied across all skins, and matches stable.
+ // For simplicity, dim colour is applied to the DrawableHitObject itself.
+ // We may need to make a nested container setup if this even causes a usage conflict (ie. with a mod).
+ this.FadeColour(new Color4(195, 195, 195, 255));
+ using (BeginDelayedSequence(InitialLifetimeOffset - OsuHitWindows.MISS_WINDOW))
+ this.FadeColour(Color4.White, 100);
+ }
+ }
+
protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt;
private OsuInputManager osuActionInputManager;
diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuHitWindows.cs b/osu.Game.Rulesets.Osu/Scoring/OsuHitWindows.cs
index 05fbac625e..6f55e1790f 100644
--- a/osu.Game.Rulesets.Osu/Scoring/OsuHitWindows.cs
+++ b/osu.Game.Rulesets.Osu/Scoring/OsuHitWindows.cs
@@ -1,20 +1,23 @@
// 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.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Scoring
{
public class OsuHitWindows : HitWindows
{
+ ///
+ /// osu! ruleset has a fixed miss window regardless of difficulty settings.
+ ///
+ public const double MISS_WINDOW = 400;
+
private static readonly DifficultyRange[] osu_ranges =
{
new DifficultyRange(HitResult.Great, 80, 50, 20),
new DifficultyRange(HitResult.Ok, 140, 100, 60),
new DifficultyRange(HitResult.Meh, 200, 150, 100),
- new DifficultyRange(HitResult.Miss, 400, 400, 400),
+ new DifficultyRange(HitResult.Miss, MISS_WINDOW, MISS_WINDOW, MISS_WINDOW),
};
public override bool IsHitResultAllowed(HitResult result)
diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
index 3f20f843a7..e7590df3e0 100644
--- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
+++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
@@ -8,7 +8,6 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
-using System.Threading.Tasks;
using JetBrains.Annotations;
using NUnit.Framework;
using osu.Framework.Allocation;
@@ -78,7 +77,7 @@ namespace osu.Game.Tests.Online
}
};
- beatmaps.AllowImport = new TaskCompletionSource();
+ beatmaps.AllowImport.Reset();
testBeatmapFile = TestResources.GetQuickTestBeatmapForImport();
@@ -132,7 +131,7 @@ namespace osu.Game.Tests.Online
AddStep("finish download", () => ((TestDownloadRequest)beatmapDownloader.GetExistingDownload(testBeatmapSet))!.TriggerSuccess(testBeatmapFile));
addAvailabilityCheckStep("state importing", BeatmapAvailability.Importing);
- AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true));
+ AddStep("allow importing", () => beatmaps.AllowImport.Set());
AddUntilStep("wait for import", () => beatmaps.CurrentImport != null);
AddUntilStep("ensure beatmap available", () => beatmaps.IsAvailableLocally(testBeatmapSet));
addAvailabilityCheckStep("state is locally available", BeatmapAvailability.LocallyAvailable);
@@ -141,7 +140,7 @@ namespace osu.Game.Tests.Online
[Test]
public void TestTrackerRespectsSoftDeleting()
{
- AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true));
+ AddStep("allow importing", () => beatmaps.AllowImport.Set());
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).WaitSafely());
addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable);
@@ -155,7 +154,7 @@ namespace osu.Game.Tests.Online
[Test]
public void TestTrackerRespectsChecksum()
{
- AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true));
+ AddStep("allow importing", () => beatmaps.AllowImport.Set());
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).WaitSafely());
addAvailabilityCheckStep("initially locally available", BeatmapAvailability.LocallyAvailable);
@@ -202,7 +201,7 @@ namespace osu.Game.Tests.Online
private class TestBeatmapManager : BeatmapManager
{
- public TaskCompletionSource AllowImport = new TaskCompletionSource();
+ public readonly ManualResetEventSlim AllowImport = new ManualResetEventSlim();
public Live CurrentImport { get; private set; }
@@ -229,7 +228,9 @@ namespace osu.Game.Tests.Online
public override Live ImportModel(BeatmapSetInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default)
{
- testBeatmapManager.AllowImport.Task.WaitSafely();
+ if (!testBeatmapManager.AllowImport.Wait(TimeSpan.FromSeconds(10), cancellationToken))
+ throw new TimeoutException("Timeout waiting for import to be allowed.");
+
return (testBeatmapManager.CurrentImport = base.ImportModel(item, archive, batchImport, cancellationToken));
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs
index c852685b74..60ed0012ae 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs
@@ -66,7 +66,8 @@ namespace osu.Game.Tests.Visual.Gameplay
{
AddSliderStep("score", 0, 1000000, 500000, v => scoreProcessor.TotalScore.Value = v);
AddSliderStep("accuracy", 0f, 1f, 0.5f, v => scoreProcessor.Accuracy.Value = v);
- AddSliderStep("combo", 0, 1000, 0, v => scoreProcessor.HighestCombo.Value = v);
+ AddSliderStep("combo", 0, 10000, 0, v => scoreProcessor.HighestCombo.Value = v);
+ AddStep("toggle expanded", () => leaderboard.Expanded.Value = !leaderboard.Expanded.Value);
}
[Test]
diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs
index 5e76fe1519..003cec0d07 100644
--- a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs
@@ -9,8 +9,10 @@ using NUnit.Framework;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
+using osu.Game.Configuration;
using osu.Game.Online.API;
using osu.Game.Rulesets;
+using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Osu;
using osu.Game.Scoring;
@@ -92,6 +94,31 @@ namespace osu.Game.Tests.Visual.Navigation
returnToMenu();
}
+ [Test]
+ public void TestFromSongSelectWithFilter([Values] ScorePresentType type)
+ {
+ AddStep("enter song select", () => Game.ChildrenOfType().Single().OnSolo.Invoke());
+ AddUntilStep("song select is current", () => Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect && songSelect.BeatmapSetsLoaded);
+
+ AddStep("filter to nothing", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).FilterControl.CurrentTextSearch.Value = "fdsajkl;fgewq");
+ AddUntilStep("wait for no results", () => Beatmap.IsDefault);
+
+ var firstImport = importScore(1, new CatchRuleset().RulesetInfo);
+ presentAndConfirm(firstImport, type);
+ }
+
+ [Test]
+ public void TestFromSongSelectWithConvertRulesetChange([Values] ScorePresentType type)
+ {
+ AddStep("enter song select", () => Game.ChildrenOfType().Single().OnSolo.Invoke());
+ AddUntilStep("song select is current", () => Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect && songSelect.BeatmapSetsLoaded);
+
+ AddStep("set convert to false", () => Game.LocalConfig.SetValue(OsuSetting.ShowConvertedBeatmaps, false));
+
+ var firstImport = importScore(1, new CatchRuleset().RulesetInfo);
+ presentAndConfirm(firstImport, type);
+ }
+
[Test]
public void TestFromSongSelect([Values] ScorePresentType type)
{
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 59c0af1533..939d3a63ed 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -561,9 +561,11 @@ namespace osu.Game
return;
}
+ // This should be able to be performed from song select, but that is disabled for now
+ // due to the weird decoupled ruleset logic (which can cause a crash in certain filter scenarios).
PerformFromScreen(screen =>
{
- Logger.Log($"{nameof(PresentScore)} updating beatmap ({databasedBeatmap}) and ruleset ({databasedScore.ScoreInfo.Ruleset} to match score");
+ Logger.Log($"{nameof(PresentScore)} updating beatmap ({databasedBeatmap}) and ruleset ({databasedScore.ScoreInfo.Ruleset}) to match score");
Ruleset.Value = databasedScore.ScoreInfo.Ruleset;
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap);
@@ -578,7 +580,7 @@ namespace osu.Game
screen.Push(new SoloResultsScreen(databasedScore.ScoreInfo, false));
break;
}
- }, validScreens: new[] { typeof(PlaySongSelect) });
+ });
}
public override Task Import(params ImportTask[] imports)
diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
index 28642f12a1..c64a3101b7 100644
--- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
@@ -73,8 +73,8 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
windowModes.BindTo(host.Window.SupportedWindowModes);
}
- if (host.Window is WindowsWindow windowsWindow)
- fullscreenCapability.BindTo(windowsWindow.FullscreenCapability);
+ if (host.Renderer is IWindowsRenderer windowsRenderer)
+ fullscreenCapability.BindTo(windowsRenderer.FullscreenCapability);
Children = new Drawable[]
{
diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs
index 29354e610d..2eec8253b3 100644
--- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs
+++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs
@@ -3,6 +3,7 @@
#nullable disable
+using System;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -39,8 +40,6 @@ namespace osu.Game.Screens.Play.HUD
private const float rank_text_width = 35f;
- private const float score_components_width = 85f;
-
private const float avatar_size = 25f;
private const double panel_transition_duration = 500;
@@ -161,7 +160,7 @@ namespace osu.Game.Screens.Play.HUD
{
new Dimension(GridSizeMode.Absolute, rank_text_width),
new Dimension(),
- new Dimension(GridSizeMode.AutoSize, maxSize: score_components_width),
+ new Dimension(GridSizeMode.AutoSize),
},
Content = new[]
{
@@ -286,8 +285,19 @@ namespace osu.Game.Screens.Play.HUD
LoadComponentAsync(new DrawableAvatar(User), avatarContainer.Add);
TotalScore.BindValueChanged(v => scoreText.Text = v.NewValue.ToString("N0"), true);
- Accuracy.BindValueChanged(v => accuracyText.Text = v.NewValue.FormatAccuracy(), true);
- Combo.BindValueChanged(v => comboText.Text = $"{v.NewValue}x", true);
+
+ Accuracy.BindValueChanged(v =>
+ {
+ accuracyText.Text = v.NewValue.FormatAccuracy();
+ updateDetailsWidth();
+ }, true);
+
+ Combo.BindValueChanged(v =>
+ {
+ comboText.Text = $"{v.NewValue}x";
+ updateDetailsWidth();
+ }, true);
+
HasQuit.BindValueChanged(_ => updateState());
}
@@ -303,13 +313,10 @@ namespace osu.Game.Screens.Play.HUD
private void changeExpandedState(ValueChangedEvent expanded)
{
- scoreComponents.ClearTransforms();
-
if (expanded.NewValue)
{
gridContainer.ResizeWidthTo(regular_width, panel_transition_duration, Easing.OutQuint);
- scoreComponents.ResizeWidthTo(score_components_width, panel_transition_duration, Easing.OutQuint);
scoreComponents.FadeIn(panel_transition_duration, Easing.OutQuint);
usernameText.FadeIn(panel_transition_duration, Easing.OutQuint);
@@ -318,11 +325,29 @@ namespace osu.Game.Screens.Play.HUD
{
gridContainer.ResizeWidthTo(compact_width, panel_transition_duration, Easing.OutQuint);
- scoreComponents.ResizeWidthTo(0, panel_transition_duration, Easing.OutQuint);
scoreComponents.FadeOut(text_transition_duration, Easing.OutQuint);
usernameText.FadeOut(text_transition_duration, Easing.OutQuint);
}
+
+ updateDetailsWidth();
+ }
+
+ private float? scoreComponentsTargetWidth;
+
+ private void updateDetailsWidth()
+ {
+ const float score_components_min_width = 88f;
+
+ float newWidth = Expanded.Value
+ ? Math.Max(score_components_min_width, comboText.DrawWidth + accuracyText.DrawWidth + 25)
+ : 0;
+
+ if (scoreComponentsTargetWidth == newWidth)
+ return;
+
+ scoreComponentsTargetWidth = newWidth;
+ scoreComponents.ResizeWidthTo(newWidth, panel_transition_duration, Easing.OutQuint);
}
private void updateState()
diff --git a/osu.Game/Screens/Select/FooterButtonRandom.cs b/osu.Game/Screens/Select/FooterButtonRandom.cs
index 1f56915f62..aad7fdff39 100644
--- a/osu.Game/Screens/Select/FooterButtonRandom.cs
+++ b/osu.Game/Screens/Select/FooterButtonRandom.cs
@@ -138,7 +138,8 @@ namespace osu.Game.Screens.Select
return false;
}
- TriggerClick();
+ if (!e.Repeat)
+ TriggerClick();
return true;
}
diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs
index c9d4dc7811..bacaccd68e 100644
--- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs
+++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs
@@ -261,8 +261,8 @@ namespace osu.Game.Screens.Utility
string exclusive = "unknown";
- if (host.Window is WindowsWindow windowsWindow)
- exclusive = windowsWindow.FullscreenCapability.ToString();
+ if (host.Renderer is IWindowsRenderer windowsRenderer)
+ exclusive = windowsRenderer.FullscreenCapability.ToString();
statusText.Clear();
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 434db87a80..26738673c8 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -35,7 +35,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index f395eab23c..af1e21edab 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -61,8 +61,8 @@
-
+
@@ -82,7 +82,7 @@
-
+