From c087578e011c6ade4411dbccfcfce80da407dba3 Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Tue, 26 Dec 2023 10:07:21 -0800 Subject: [PATCH 01/42] Force minimum cursor size for `OsuResumeOverlay` On cursor sizes below 0.3x it becomes exceedingly difficult to quickly locate and then accurately click the resume cursor on the pause overlay as it could as big as a handful of pixels. This clamps the minimum cursor size to 1x for the resume overlay, which is way more comfortable and more closely resembles stable. --- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs | 10 +++++----- osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs index ba9fda25e4..18351c20ce 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs @@ -70,10 +70,10 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor }; userCursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); - userCursorScale.ValueChanged += _ => calculateCursorScale(); + userCursorScale.ValueChanged += _ => cursorScale.Value = CalculateCursorScale(); autoCursorScale = config.GetBindable(OsuSetting.AutoCursorSize); - autoCursorScale.ValueChanged += _ => calculateCursorScale(); + autoCursorScale.ValueChanged += _ => cursorScale.Value = CalculateCursorScale(); cursorScale.BindValueChanged(e => cursorScaleContainer.Scale = new Vector2(e.NewValue), true); } @@ -81,10 +81,10 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor protected override void LoadComplete() { base.LoadComplete(); - calculateCursorScale(); + cursorScale.Value = CalculateCursorScale(); } - private void calculateCursorScale() + protected virtual float CalculateCursorScale() { float scale = userCursorScale.Value; @@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor scale *= GetScaleForCircleSize(state.Beatmap.Difficulty.CircleSize); } - cursorScale.Value = scale; + return scale; } protected override void SkinChanged(ISkinSource skin) diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs index ea49836772..f5e83f46f2 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs @@ -71,6 +71,12 @@ namespace osu.Game.Rulesets.Osu.UI RelativePositionAxes = Axes.Both; } + protected override float CalculateCursorScale() + { + // Force minimum cursor size so it's easily clickable + return Math.Max(1f, base.CalculateCursorScale()); + } + protected override bool OnHover(HoverEvent e) { updateColour(); From 14b37db3dd17d3be07a9dce5b088b59205d33815 Mon Sep 17 00:00:00 2001 From: Gabriel Del Nero <43073074+Gabixel@users.noreply.github.com> Date: Wed, 27 Dec 2023 14:35:19 +0100 Subject: [PATCH 02/42] Make `ModDaycore` sequential for `ModHalfTime` --- osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs index 59a631a7b5..bf58efc339 100644 --- a/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Mods.Input { [Key.Q] = new[] { typeof(ModEasy) }, [Key.W] = new[] { typeof(ModNoFail) }, - [Key.E] = new[] { typeof(ModHalfTime) }, + [Key.E] = new[] { typeof(ModHalfTime), typeof(ModDaycore) }, [Key.A] = new[] { typeof(ModHardRock) }, [Key.S] = new[] { typeof(ModSuddenDeath), typeof(ModPerfect) }, [Key.D] = new[] { typeof(ModDoubleTime), typeof(ModNightcore) }, From 13333f75756e587572411971524a65cda09eedab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 27 Dec 2023 15:02:19 +0100 Subject: [PATCH 03/42] Make room for `OsuIcon` to accept new icons --- osu.Game/Graphics/OsuIcon.cs | 132 ++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 64 deletions(-) diff --git a/osu.Game/Graphics/OsuIcon.cs b/osu.Game/Graphics/OsuIcon.cs index 15af8f000b..d1ad818300 100644 --- a/osu.Game/Graphics/OsuIcon.cs +++ b/osu.Game/Graphics/OsuIcon.cs @@ -7,90 +7,94 @@ namespace osu.Game.Graphics { public static class OsuIcon { - public static IconUsage Get(int icon) => new IconUsage((char)icon, "osuFont"); + #region Legacy spritesheet-based icons + + private static IconUsage get(int icon) => new IconUsage((char)icon, @"osuFont"); // ruleset icons in circles - public static IconUsage RulesetOsu => Get(0xe000); - public static IconUsage RulesetMania => Get(0xe001); - public static IconUsage RulesetCatch => Get(0xe002); - public static IconUsage RulesetTaiko => Get(0xe003); + public static IconUsage RulesetOsu => get(0xe000); + public static IconUsage RulesetMania => get(0xe001); + public static IconUsage RulesetCatch => get(0xe002); + public static IconUsage RulesetTaiko => get(0xe003); // ruleset icons without circles - public static IconUsage FilledCircle => Get(0xe004); - public static IconUsage CrossCircle => Get(0xe005); - public static IconUsage Logo => Get(0xe006); - public static IconUsage ChevronDownCircle => Get(0xe007); - public static IconUsage EditCircle => Get(0xe033); - public static IconUsage LeftCircle => Get(0xe034); - public static IconUsage RightCircle => Get(0xe035); - public static IconUsage Charts => Get(0xe036); - public static IconUsage Solo => Get(0xe037); - public static IconUsage Multi => Get(0xe038); - public static IconUsage Gear => Get(0xe039); + public static IconUsage FilledCircle => get(0xe004); + public static IconUsage CrossCircle => get(0xe005); + public static IconUsage Logo => get(0xe006); + public static IconUsage ChevronDownCircle => get(0xe007); + public static IconUsage EditCircle => get(0xe033); + public static IconUsage LeftCircle => get(0xe034); + public static IconUsage RightCircle => get(0xe035); + public static IconUsage Charts => get(0xe036); + public static IconUsage Solo => get(0xe037); + public static IconUsage Multi => get(0xe038); + public static IconUsage Gear => get(0xe039); // misc icons - public static IconUsage Bat => Get(0xe008); - public static IconUsage Bubble => Get(0xe009); - public static IconUsage BubblePop => Get(0xe02e); - public static IconUsage Dice => Get(0xe011); - public static IconUsage Heart => Get(0xe02f); - public static IconUsage HeartBreak => Get(0xe030); - public static IconUsage Hot => Get(0xe031); - public static IconUsage ListSearch => Get(0xe032); + public static IconUsage Bat => get(0xe008); + public static IconUsage Bubble => get(0xe009); + public static IconUsage BubblePop => get(0xe02e); + public static IconUsage Dice => get(0xe011); + public static IconUsage Heart => get(0xe02f); + public static IconUsage HeartBreak => get(0xe030); + public static IconUsage Hot => get(0xe031); + public static IconUsage ListSearch => get(0xe032); //osu! playstyles - public static IconUsage PlayStyleTablet => Get(0xe02a); - public static IconUsage PlayStyleMouse => Get(0xe029); - public static IconUsage PlayStyleKeyboard => Get(0xe02b); - public static IconUsage PlayStyleTouch => Get(0xe02c); + public static IconUsage PlayStyleTablet => get(0xe02a); + public static IconUsage PlayStyleMouse => get(0xe029); + public static IconUsage PlayStyleKeyboard => get(0xe02b); + public static IconUsage PlayStyleTouch => get(0xe02c); // osu! difficulties - public static IconUsage EasyOsu => Get(0xe015); - public static IconUsage NormalOsu => Get(0xe016); - public static IconUsage HardOsu => Get(0xe017); - public static IconUsage InsaneOsu => Get(0xe018); - public static IconUsage ExpertOsu => Get(0xe019); + public static IconUsage EasyOsu => get(0xe015); + public static IconUsage NormalOsu => get(0xe016); + public static IconUsage HardOsu => get(0xe017); + public static IconUsage InsaneOsu => get(0xe018); + public static IconUsage ExpertOsu => get(0xe019); // taiko difficulties - public static IconUsage EasyTaiko => Get(0xe01a); - public static IconUsage NormalTaiko => Get(0xe01b); - public static IconUsage HardTaiko => Get(0xe01c); - public static IconUsage InsaneTaiko => Get(0xe01d); - public static IconUsage ExpertTaiko => Get(0xe01e); + public static IconUsage EasyTaiko => get(0xe01a); + public static IconUsage NormalTaiko => get(0xe01b); + public static IconUsage HardTaiko => get(0xe01c); + public static IconUsage InsaneTaiko => get(0xe01d); + public static IconUsage ExpertTaiko => get(0xe01e); // fruits difficulties - public static IconUsage EasyFruits => Get(0xe01f); - public static IconUsage NormalFruits => Get(0xe020); - public static IconUsage HardFruits => Get(0xe021); - public static IconUsage InsaneFruits => Get(0xe022); - public static IconUsage ExpertFruits => Get(0xe023); + public static IconUsage EasyFruits => get(0xe01f); + public static IconUsage NormalFruits => get(0xe020); + public static IconUsage HardFruits => get(0xe021); + public static IconUsage InsaneFruits => get(0xe022); + public static IconUsage ExpertFruits => get(0xe023); // mania difficulties - public static IconUsage EasyMania => Get(0xe024); - public static IconUsage NormalMania => Get(0xe025); - public static IconUsage HardMania => Get(0xe026); - public static IconUsage InsaneMania => Get(0xe027); - public static IconUsage ExpertMania => Get(0xe028); + public static IconUsage EasyMania => get(0xe024); + public static IconUsage NormalMania => get(0xe025); + public static IconUsage HardMania => get(0xe026); + public static IconUsage InsaneMania => get(0xe027); + public static IconUsage ExpertMania => get(0xe028); // mod icons - public static IconUsage ModPerfect => Get(0xe049); - public static IconUsage ModAutopilot => Get(0xe03a); - public static IconUsage ModAuto => Get(0xe03b); - public static IconUsage ModCinema => Get(0xe03c); - public static IconUsage ModDoubleTime => Get(0xe03d); - public static IconUsage ModEasy => Get(0xe03e); - public static IconUsage ModFlashlight => Get(0xe03f); - public static IconUsage ModHalftime => Get(0xe040); - public static IconUsage ModHardRock => Get(0xe041); - public static IconUsage ModHidden => Get(0xe042); - public static IconUsage ModNightcore => Get(0xe043); - public static IconUsage ModNoFail => Get(0xe044); - public static IconUsage ModRelax => Get(0xe045); - public static IconUsage ModSpunOut => Get(0xe046); - public static IconUsage ModSuddenDeath => Get(0xe047); - public static IconUsage ModTarget => Get(0xe048); + public static IconUsage ModPerfect => get(0xe049); + public static IconUsage ModAutopilot => get(0xe03a); + public static IconUsage ModAuto => get(0xe03b); + public static IconUsage ModCinema => get(0xe03c); + public static IconUsage ModDoubleTime => get(0xe03d); + public static IconUsage ModEasy => get(0xe03e); + public static IconUsage ModFlashlight => get(0xe03f); + public static IconUsage ModHalftime => get(0xe040); + public static IconUsage ModHardRock => get(0xe041); + public static IconUsage ModHidden => get(0xe042); + public static IconUsage ModNightcore => get(0xe043); + public static IconUsage ModNoFail => get(0xe044); + public static IconUsage ModRelax => get(0xe045); + public static IconUsage ModSpunOut => get(0xe046); + public static IconUsage ModSuddenDeath => get(0xe047); + public static IconUsage ModTarget => get(0xe048); // Use "Icons/BeatmapDetails/mod-icon" instead // public static IconUsage ModBg => Get(0xe04a); + + #endregion } } From 45143a6c17e4574aab8a910a7be27e568f91c34a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 27 Dec 2023 15:17:39 +0100 Subject: [PATCH 04/42] Implement new icon store --- osu.Game/Graphics/OsuIcon.cs | 348 ++++++++++++++++++++++++++++++++++- osu.Game/OsuGameBase.cs | 1 + 2 files changed, 347 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/OsuIcon.cs b/osu.Game/Graphics/OsuIcon.cs index d1ad818300..3cd10b1315 100644 --- a/osu.Game/Graphics/OsuIcon.cs +++ b/osu.Game/Graphics/OsuIcon.cs @@ -1,7 +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.ComponentModel; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using osu.Framework.Extensions; using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Text; namespace osu.Game.Graphics { @@ -19,7 +28,6 @@ namespace osu.Game.Graphics // ruleset icons without circles public static IconUsage FilledCircle => get(0xe004); - public static IconUsage CrossCircle => get(0xe005); public static IconUsage Logo => get(0xe006); public static IconUsage ChevronDownCircle => get(0xe007); public static IconUsage EditCircle => get(0xe033); @@ -35,7 +43,6 @@ namespace osu.Game.Graphics public static IconUsage Bubble => get(0xe009); public static IconUsage BubblePop => get(0xe02e); public static IconUsage Dice => get(0xe011); - public static IconUsage Heart => get(0xe02f); public static IconUsage HeartBreak => get(0xe030); public static IconUsage Hot => get(0xe031); public static IconUsage ListSearch => get(0xe032); @@ -96,5 +103,342 @@ namespace osu.Game.Graphics // public static IconUsage ModBg => Get(0xe04a); #endregion + + #region New single-file-based icons + + public const string FONT_NAME = @"Icons"; + + public static IconUsage Audio => get(OsuIconMapping.Audio); + public static IconUsage Beatmap => get(OsuIconMapping.Beatmap); + public static IconUsage Calendar => get(OsuIconMapping.Calendar); + public static IconUsage ChangelogA => get(OsuIconMapping.ChangelogA); + public static IconUsage ChangelogB => get(OsuIconMapping.ChangelogB); + public static IconUsage Chat => get(OsuIconMapping.Chat); + public static IconUsage CheckCircle => get(OsuIconMapping.CheckCircle); + public static IconUsage CollapseA => get(OsuIconMapping.CollapseA); + public static IconUsage Collections => get(OsuIconMapping.Collections); + public static IconUsage Cross => get(OsuIconMapping.Cross); + public static IconUsage CrossCircle => get(OsuIconMapping.CrossCircle); + public static IconUsage Crown => get(OsuIconMapping.Crown); + public static IconUsage Debug => get(OsuIconMapping.Debug); + public static IconUsage Delete => get(OsuIconMapping.Delete); + public static IconUsage Details => get(OsuIconMapping.Details); + public static IconUsage Discord => get(OsuIconMapping.Discord); + public static IconUsage EllipsisHorizontal => get(OsuIconMapping.EllipsisHorizontal); + public static IconUsage EllipsisVertical => get(OsuIconMapping.EllipsisVertical); + public static IconUsage ExpandA => get(OsuIconMapping.ExpandA); + public static IconUsage ExpandB => get(OsuIconMapping.ExpandB); + public static IconUsage FeaturedArtist => get(OsuIconMapping.FeaturedArtist); + public static IconUsage FeaturedArtistCircle => get(OsuIconMapping.FeaturedArtistCircle); + public static IconUsage GameplayA => get(OsuIconMapping.GameplayA); + public static IconUsage GameplayB => get(OsuIconMapping.GameplayB); + public static IconUsage GameplayC => get(OsuIconMapping.GameplayC); + public static IconUsage Global => get(OsuIconMapping.Global); + public static IconUsage Graphics => get(OsuIconMapping.Graphics); + public static IconUsage Heart => get(OsuIconMapping.Heart); + public static IconUsage Home => get(OsuIconMapping.Home); + public static IconUsage Input => get(OsuIconMapping.Input); + public static IconUsage Maintenance => get(OsuIconMapping.Maintenance); + public static IconUsage Megaphone => get(OsuIconMapping.Megaphone); + public static IconUsage Music => get(OsuIconMapping.Music); + public static IconUsage News => get(OsuIconMapping.News); + public static IconUsage Next => get(OsuIconMapping.Next); + public static IconUsage NextCircle => get(OsuIconMapping.NextCircle); + public static IconUsage Notification => get(OsuIconMapping.Notification); + public static IconUsage Online => get(OsuIconMapping.Online); + public static IconUsage Play => get(OsuIconMapping.Play); + public static IconUsage Player => get(OsuIconMapping.Player); + public static IconUsage PlayerFollow => get(OsuIconMapping.PlayerFollow); + public static IconUsage Prev => get(OsuIconMapping.Prev); + public static IconUsage PrevCircle => get(OsuIconMapping.PrevCircle); + public static IconUsage Ranking => get(OsuIconMapping.Ranking); + public static IconUsage Rulesets => get(OsuIconMapping.Rulesets); + public static IconUsage Search => get(OsuIconMapping.Search); + public static IconUsage Settings => get(OsuIconMapping.Settings); + public static IconUsage SkinA => get(OsuIconMapping.SkinA); + public static IconUsage SkinB => get(OsuIconMapping.SkinB); + public static IconUsage Star => get(OsuIconMapping.Star); + public static IconUsage Storyboard => get(OsuIconMapping.Storyboard); + public static IconUsage Team => get(OsuIconMapping.Team); + public static IconUsage ThumbsUp => get(OsuIconMapping.ThumbsUp); + public static IconUsage Tournament => get(OsuIconMapping.Tournament); + public static IconUsage Twitter => get(OsuIconMapping.Twitter); + public static IconUsage UserInterface => get(OsuIconMapping.UserInterface); + public static IconUsage Wiki => get(OsuIconMapping.Wiki); + public static IconUsage EditorAddControlPoint => get(OsuIconMapping.EditorAddControlPoint); + public static IconUsage EditorConvertToStream => get(OsuIconMapping.EditorConvertToStream); + public static IconUsage EditorDistanceSnap => get(OsuIconMapping.EditorDistanceSnap); + public static IconUsage EditorFinish => get(OsuIconMapping.EditorFinish); + public static IconUsage EditorGridSnap => get(OsuIconMapping.EditorGridSnap); + public static IconUsage EditorNewComboA => get(OsuIconMapping.EditorNewComboA); + public static IconUsage EditorNewComboB => get(OsuIconMapping.EditorNewComboB); + public static IconUsage EditorSelect => get(OsuIconMapping.EditorSelect); + public static IconUsage EditorSound => get(OsuIconMapping.EditorSound); + public static IconUsage EditorWhistle => get(OsuIconMapping.EditorWhistle); + + private static IconUsage get(OsuIconMapping glyph) => new IconUsage((char)glyph, FONT_NAME); + + private enum OsuIconMapping + { + [Description(@"audio")] + Audio, + + [Description(@"beatmap")] + Beatmap, + + [Description(@"calendar")] + Calendar, + + [Description(@"changelog-a")] + ChangelogA, + + [Description(@"changelog-b")] + ChangelogB, + + [Description(@"chat")] + Chat, + + [Description(@"check-circle")] + CheckCircle, + + [Description(@"collapse-a")] + CollapseA, + + [Description(@"collections")] + Collections, + + [Description(@"cross")] + Cross, + + [Description(@"cross-circle")] + CrossCircle, + + [Description(@"crown")] + Crown, + + [Description(@"debug")] + Debug, + + [Description(@"delete")] + Delete, + + [Description(@"details")] + Details, + + [Description(@"discord")] + Discord, + + [Description(@"ellipsis-horizontal")] + EllipsisHorizontal, + + [Description(@"ellipsis-vertical")] + EllipsisVertical, + + [Description(@"expand-a")] + ExpandA, + + [Description(@"expand-b")] + ExpandB, + + [Description(@"featured-artist")] + FeaturedArtist, + + [Description(@"featured-artist-circle")] + FeaturedArtistCircle, + + [Description(@"gameplay-a")] + GameplayA, + + [Description(@"gameplay-b")] + GameplayB, + + [Description(@"gameplay-c")] + GameplayC, + + [Description(@"global")] + Global, + + [Description(@"graphics")] + Graphics, + + [Description(@"heart")] + Heart, + + [Description(@"home")] + Home, + + [Description(@"input")] + Input, + + [Description(@"maintenance")] + Maintenance, + + [Description(@"megaphone")] + Megaphone, + + [Description(@"music")] + Music, + + [Description(@"news")] + News, + + [Description(@"next")] + Next, + + [Description(@"next-circle")] + NextCircle, + + [Description(@"notification")] + Notification, + + [Description(@"online")] + Online, + + [Description(@"play")] + Play, + + [Description(@"player")] + Player, + + [Description(@"player-follow")] + PlayerFollow, + + [Description(@"prev")] + Prev, + + [Description(@"prev-circle")] + PrevCircle, + + [Description(@"ranking")] + Ranking, + + [Description(@"rulesets")] + Rulesets, + + [Description(@"search")] + Search, + + [Description(@"settings")] + Settings, + + [Description(@"skin-a")] + SkinA, + + [Description(@"skin-b")] + SkinB, + + [Description(@"star")] + Star, + + [Description(@"storyboard")] + Storyboard, + + [Description(@"team")] + Team, + + [Description(@"thumbs-up")] + ThumbsUp, + + [Description(@"tournament")] + Tournament, + + [Description(@"twitter")] + Twitter, + + [Description(@"user-interface")] + UserInterface, + + [Description(@"wiki")] + Wiki, + + [Description(@"Editor/add-control-point")] + EditorAddControlPoint = 1000, + + [Description(@"Editor/convert-to-stream")] + EditorConvertToStream, + + [Description(@"Editor/distance-snap")] + EditorDistanceSnap, + + [Description(@"Editor/finish")] + EditorFinish, + + [Description(@"Editor/grid-snap")] + EditorGridSnap, + + [Description(@"Editor/new-combo-a")] + EditorNewComboA, + + [Description(@"Editor/new-combo-b")] + EditorNewComboB, + + [Description(@"Editor/select")] + EditorSelect, + + [Description(@"Editor/sound")] + EditorSound, + + [Description(@"Editor/whistle")] + EditorWhistle, + } + + public class OsuIconStore : ITextureStore, ITexturedGlyphLookupStore + { + private readonly TextureStore textures; + + public OsuIconStore(TextureStore textures) + { + this.textures = textures; + } + + public ITexturedCharacterGlyph? Get(string? fontName, char character) + { + if (fontName == FONT_NAME) + return new Glyph(textures.Get($@"{fontName}/{((OsuIconMapping)character).GetDescription()}")); + + return null; + } + + public Task GetAsync(string fontName, char character) => Task.Run(() => Get(fontName, character)); + + public Texture? Get(string name, WrapMode wrapModeS, WrapMode wrapModeT) => null; + + public Texture Get(string name) => throw new NotImplementedException(); + + public Task GetAsync(string name, CancellationToken cancellationToken = default) => throw new NotImplementedException(); + + public Stream GetStream(string name) => throw new NotImplementedException(); + + public IEnumerable GetAvailableResources() => throw new NotImplementedException(); + + public Task GetAsync(string name, WrapMode wrapModeS, WrapMode wrapModeT, CancellationToken cancellationToken = default) => throw new NotImplementedException(); + + public class Glyph : ITexturedCharacterGlyph + { + public float XOffset => default; + public float YOffset => default; + public float XAdvance => default; + public float Baseline => default; + public char Character => default; + + public float GetKerning(T lastGlyph) where T : ICharacterGlyph => throw new NotImplementedException(); + + public Texture Texture { get; } + public float Width => Texture.Width; + public float Height => Texture.Height; + + public Glyph(Texture texture) + { + Texture = texture; + } + } + + public void Dispose() + { + textures.Dispose(); + } + } + + #endregion } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 48548dc1ef..b4ad21f045 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -479,6 +479,7 @@ namespace osu.Game AddFont(Resources, @"Fonts/Venera/Venera-Black"); Fonts.AddStore(new HexaconsIcons.HexaconsStore(Textures)); + Fonts.AddStore(new OsuIcon.OsuIconStore(Textures)); } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => From 69baabee627f55d87f6ba61f361e1b370bbfdd2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 27 Dec 2023 15:35:03 +0100 Subject: [PATCH 05/42] Replace hexacons in toolbar with new icons --- osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs | 2 +- osu.Game/Overlays/Changelog/ChangelogHeader.cs | 2 +- osu.Game/Overlays/ChatOverlay.cs | 2 +- osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs | 2 +- osu.Game/Overlays/News/NewsHeader.cs | 2 +- osu.Game/Overlays/NotificationOverlay.cs | 2 +- osu.Game/Overlays/NowPlayingOverlay.cs | 2 +- osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs | 2 +- osu.Game/Overlays/SettingsOverlay.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs | 2 +- osu.Game/Overlays/Wiki/WikiHeader.cs | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs index 27fab82bf3..075dfd02b0 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.BeatmapListing { Title = PageTitleStrings.MainBeatmapsetsControllerIndex; Description = NamedOverlayComponentStrings.BeatmapListingDescription; - Icon = HexaconsIcons.Beatmap; + Icon = OsuIcon.Beatmap; } } } diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs index 61ea9dc4db..f738d70370 100644 --- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs +++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs @@ -124,7 +124,7 @@ namespace osu.Game.Overlays.Changelog { Title = PageTitleStrings.MainChangelogControllerDefault; Description = NamedOverlayComponentStrings.ChangelogDescription; - Icon = HexaconsIcons.Devtools; + Icon = OsuIcon.ChangelogB; } } } diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 4aa4c59471..8f3b7031c2 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -31,7 +31,7 @@ namespace osu.Game.Overlays { public partial class ChatOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent, IKeyBindingHandler { - public IconUsage Icon => HexaconsIcons.Messaging; + public IconUsage Icon => OsuIcon.Chat; public LocalisableString Title => ChatStrings.HeaderTitle; public LocalisableString Description => ChatStrings.HeaderDescription; diff --git a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs index 104f0943dc..8fd8f6b332 100644 --- a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs +++ b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Dashboard { Title = PageTitleStrings.MainHomeControllerIndex; Description = NamedOverlayComponentStrings.DashboardDescription; - Icon = HexaconsIcons.Social; + Icon = OsuIcon.Global; } } } diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index f237ed66f2..92d71a21ef 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -69,7 +69,7 @@ namespace osu.Game.Overlays.News { Title = PageTitleStrings.MainNewsControllerDefault; Description = NamedOverlayComponentStrings.NewsDescription; - Icon = HexaconsIcons.News; + Icon = OsuIcon.News; } } } diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index f56d09f2b2..18a487a312 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -29,7 +29,7 @@ namespace osu.Game.Overlays { public partial class NotificationOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent, INotificationOverlay { - public IconUsage Icon => HexaconsIcons.Notification; + public IconUsage Icon => OsuIcon.Notification; public LocalisableString Title => NotificationsStrings.HeaderTitle; public LocalisableString Description => NotificationsStrings.HeaderDescription; diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index 425ff0935d..7ec52364d4 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 IconUsage Icon => HexaconsIcons.Music; + public IconUsage Icon => OsuIcon.Music; public LocalisableString Title => NowPlayingStrings.HeaderTitle; public LocalisableString Description => NowPlayingStrings.HeaderDescription; diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 63128fb73d..a23ec18afe 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Rankings { Title = PageTitleStrings.MainRankingControllerDefault; Description = NamedOverlayComponentStrings.RankingsDescription; - Icon = HexaconsIcons.Rankings; + Icon = OsuIcon.Ranking; } } } diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index 5735b1515a..9efd848035 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -21,7 +21,7 @@ namespace osu.Game.Overlays { public partial class SettingsOverlay : SettingsPanel, INamedOverlayComponent { - public IconUsage Icon => HexaconsIcons.Settings; + public IconUsage Icon => OsuIcon.Settings; public LocalisableString Title => SettingsStrings.HeaderTitle; public LocalisableString Description => SettingsStrings.HeaderDescription; diff --git a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs index ded0229d67..70675c1b92 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs @@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Toolbar { TooltipMain = ToolbarStrings.HomeHeaderTitle; TooltipSub = ToolbarStrings.HomeHeaderDescription; - SetIcon(HexaconsIcons.Home); + SetIcon(OsuIcon.Home); } } } diff --git a/osu.Game/Overlays/Wiki/WikiHeader.cs b/osu.Game/Overlays/Wiki/WikiHeader.cs index 9e9e565684..24eddeb0c2 100644 --- a/osu.Game/Overlays/Wiki/WikiHeader.cs +++ b/osu.Game/Overlays/Wiki/WikiHeader.cs @@ -82,7 +82,7 @@ namespace osu.Game.Overlays.Wiki { Title = PageTitleStrings.MainWikiControllerDefault; Description = NamedOverlayComponentStrings.WikiDescription; - Icon = HexaconsIcons.Wiki; + Icon = OsuIcon.Wiki; } } } From 28d9145a4c182ecb66029e0b1e52f24f7cc16acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 27 Dec 2023 15:47:29 +0100 Subject: [PATCH 06/42] Add more spacing to toolbar icons --- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index 81d2de5acb..a547fda814 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -113,7 +113,7 @@ namespace osu.Game.Overlays.Toolbar { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Size = new Vector2(26), + Size = new Vector2(20), Alpha = 0, }, DrawableText = new OsuSpriteText From c45477bd1fff8447755f7afd54bf5156e1352833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 27 Dec 2023 15:40:48 +0100 Subject: [PATCH 07/42] Use new icons in main menu wherever feasible --- osu.Game/Screens/Menu/ButtonSystem.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index ca5bef985e..b2b3fbd626 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -13,7 +13,6 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Logging; @@ -103,8 +102,8 @@ namespace osu.Game.Screens.Menu buttonArea.AddRange(new Drawable[] { - new MainMenuButton(ButtonSystemStrings.Settings, string.Empty, FontAwesome.Solid.Cog, new Color4(85, 85, 85, 255), () => OnSettings?.Invoke(), -WEDGE_WIDTH, Key.O), - backButton = new MainMenuButton(ButtonSystemStrings.Back, @"back-to-top", OsuIcon.LeftCircle, new Color4(51, 58, 94, 255), () => State = ButtonSystemState.TopLevel, + new MainMenuButton(ButtonSystemStrings.Settings, string.Empty, OsuIcon.Settings, new Color4(85, 85, 85, 255), () => OnSettings?.Invoke(), -WEDGE_WIDTH, Key.O), + backButton = new MainMenuButton(ButtonSystemStrings.Back, @"back-to-top", OsuIcon.PrevCircle, new Color4(51, 58, 94, 255), () => State = ButtonSystemState.TopLevel, -WEDGE_WIDTH) { VisibleStateMin = ButtonSystemState.Play, @@ -128,18 +127,18 @@ namespace osu.Game.Screens.Menu [BackgroundDependencyLoader] private void load(AudioManager audio, IdleTracker? idleTracker, GameHost host) { - buttonsPlay.Add(new MainMenuButton(ButtonSystemStrings.Solo, @"button-default-select", FontAwesome.Solid.User, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P)); - buttonsPlay.Add(new MainMenuButton(ButtonSystemStrings.Multi, @"button-default-select", FontAwesome.Solid.Users, new Color4(94, 63, 186, 255), onMultiplayer, 0, Key.M)); - buttonsPlay.Add(new MainMenuButton(ButtonSystemStrings.Playlists, @"button-default-select", OsuIcon.Charts, new Color4(94, 63, 186, 255), onPlaylists, 0, Key.L)); + buttonsPlay.Add(new MainMenuButton(ButtonSystemStrings.Solo, @"button-default-select", OsuIcon.Player, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P)); + buttonsPlay.Add(new MainMenuButton(ButtonSystemStrings.Multi, @"button-default-select", OsuIcon.Online, new Color4(94, 63, 186, 255), onMultiplayer, 0, Key.M)); + buttonsPlay.Add(new MainMenuButton(ButtonSystemStrings.Playlists, @"button-default-select", OsuIcon.Tournament, new Color4(94, 63, 186, 255), onPlaylists, 0, Key.L)); buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play); - buttonsEdit.Add(new MainMenuButton(EditorStrings.BeatmapEditor.ToLower(), @"button-default-select", HexaconsIcons.Beatmap, new Color4(238, 170, 0, 255), () => OnEditBeatmap?.Invoke(), WEDGE_WIDTH, Key.B)); - buttonsEdit.Add(new MainMenuButton(SkinEditorStrings.SkinEditor.ToLower(), @"button-default-select", HexaconsIcons.Editor, new Color4(220, 160, 0, 255), () => OnEditSkin?.Invoke(), 0, Key.S)); + buttonsEdit.Add(new MainMenuButton(EditorStrings.BeatmapEditor.ToLower(), @"button-default-select", OsuIcon.Beatmap, new Color4(238, 170, 0, 255), () => OnEditBeatmap?.Invoke(), WEDGE_WIDTH, Key.B)); + buttonsEdit.Add(new MainMenuButton(SkinEditorStrings.SkinEditor.ToLower(), @"button-default-select", OsuIcon.SkinB, new Color4(220, 160, 0, 255), () => OnEditSkin?.Invoke(), 0, Key.S)); buttonsEdit.ForEach(b => b.VisibleState = ButtonSystemState.Edit); buttonsTopLevel.Add(new MainMenuButton(ButtonSystemStrings.Play, @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P)); buttonsTopLevel.Add(new MainMenuButton(ButtonSystemStrings.Edit, @"button-play-select", OsuIcon.EditCircle, new Color4(238, 170, 0, 255), () => State = ButtonSystemState.Edit, 0, Key.E)); - buttonsTopLevel.Add(new MainMenuButton(ButtonSystemStrings.Browse, @"button-default-select", OsuIcon.ChevronDownCircle, new Color4(165, 204, 0, 255), () => OnBeatmapListing?.Invoke(), 0, Key.B, Key.D)); + buttonsTopLevel.Add(new MainMenuButton(ButtonSystemStrings.Browse, @"button-default-select", OsuIcon.Beatmap, new Color4(165, 204, 0, 255), () => OnBeatmapListing?.Invoke(), 0, Key.B, Key.D)); if (host.CanExit) buttonsTopLevel.Add(new MainMenuButton(ButtonSystemStrings.Exit, string.Empty, OsuIcon.CrossCircle, new Color4(238, 51, 153, 255), () => OnExit?.Invoke(), 0, Key.Q)); From 2857322a8bc3257ae26ea35567b8f1741b7a45ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 27 Dec 2023 15:53:01 +0100 Subject: [PATCH 08/42] Use new icons in settings --- osu.Game/Overlays/Settings/Sections/AudioSection.cs | 3 ++- osu.Game/Overlays/Settings/Sections/DebugSection.cs | 3 ++- osu.Game/Overlays/Settings/Sections/GameplaySection.cs | 3 ++- osu.Game/Overlays/Settings/Sections/GeneralSection.cs | 2 +- osu.Game/Overlays/Settings/Sections/GraphicsSection.cs | 3 ++- osu.Game/Overlays/Settings/Sections/InputSection.cs | 3 ++- osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs | 3 ++- osu.Game/Overlays/Settings/Sections/OnlineSection.cs | 3 ++- osu.Game/Overlays/Settings/Sections/RulesetSection.cs | 3 ++- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 3 ++- osu.Game/Overlays/Settings/Sections/UserInterfaceSection.cs | 3 ++- 11 files changed, 21 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/AudioSection.cs b/osu.Game/Overlays/Settings/Sections/AudioSection.cs index fb3d486776..1ab0d6c886 100644 --- a/osu.Game/Overlays/Settings/Sections/AudioSection.cs +++ b/osu.Game/Overlays/Settings/Sections/AudioSection.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Localisation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.Audio; @@ -17,7 +18,7 @@ namespace osu.Game.Overlays.Settings.Sections public override Drawable CreateIcon() => new SpriteIcon { - Icon = FontAwesome.Solid.VolumeUp + Icon = OsuIcon.Audio }; public override IEnumerable FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { "sound" }); diff --git a/osu.Game/Overlays/Settings/Sections/DebugSection.cs b/osu.Game/Overlays/Settings/Sections/DebugSection.cs index 33a6f4c673..b84c441057 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSection.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSection.cs @@ -5,6 +5,7 @@ using osu.Framework.Development; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Game.Graphics; using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.DebugSettings; @@ -16,7 +17,7 @@ namespace osu.Game.Overlays.Settings.Sections public override Drawable CreateIcon() => new SpriteIcon { - Icon = FontAwesome.Solid.Bug + Icon = OsuIcon.Debug }; public DebugSection() diff --git a/osu.Game/Overlays/Settings/Sections/GameplaySection.cs b/osu.Game/Overlays/Settings/Sections/GameplaySection.cs index b60689b611..463b3d1d09 100644 --- a/osu.Game/Overlays/Settings/Sections/GameplaySection.cs +++ b/osu.Game/Overlays/Settings/Sections/GameplaySection.cs @@ -4,6 +4,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Game.Graphics; using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.Gameplay; @@ -15,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections public override Drawable CreateIcon() => new SpriteIcon { - Icon = FontAwesome.Regular.DotCircle + Icon = OsuIcon.GameplayC }; public GameplaySection() diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index 2b043d40bc..2aa1008b1d 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -23,7 +23,7 @@ namespace osu.Game.Overlays.Settings.Sections public override Drawable CreateIcon() => new SpriteIcon { - Icon = FontAwesome.Solid.Cog + Icon = OsuIcon.Settings }; [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs b/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs index 98f6908512..e1fa1eef9c 100644 --- a/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs @@ -4,6 +4,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Game.Graphics; using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.Graphics; @@ -15,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections public override Drawable CreateIcon() => new SpriteIcon { - Icon = FontAwesome.Solid.Laptop + Icon = OsuIcon.Graphics }; public GraphicsSection() diff --git a/osu.Game/Overlays/Settings/Sections/InputSection.cs b/osu.Game/Overlays/Settings/Sections/InputSection.cs index a8f19cc91d..0204aa5e64 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSection.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Handlers; using osu.Framework.Localisation; using osu.Framework.Platform; +using osu.Game.Graphics; using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.Input; @@ -20,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections public override Drawable CreateIcon() => new SpriteIcon { - Icon = FontAwesome.Solid.Keyboard + Icon = OsuIcon.Input }; public InputSection(KeyBindingPanel keyConfig) diff --git a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs index bb0a952164..bd90e4c35d 100644 --- a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs +++ b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs @@ -4,6 +4,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Game.Graphics; using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.Maintenance; @@ -15,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections public override Drawable CreateIcon() => new SpriteIcon { - Icon = FontAwesome.Solid.Wrench + Icon = OsuIcon.Maintenance }; public MaintenanceSection() diff --git a/osu.Game/Overlays/Settings/Sections/OnlineSection.cs b/osu.Game/Overlays/Settings/Sections/OnlineSection.cs index c8faa3b697..1484f2c756 100644 --- a/osu.Game/Overlays/Settings/Sections/OnlineSection.cs +++ b/osu.Game/Overlays/Settings/Sections/OnlineSection.cs @@ -4,6 +4,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Game.Graphics; using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.Online; @@ -15,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections public override Drawable CreateIcon() => new SpriteIcon { - Icon = FontAwesome.Solid.GlobeAsia + Icon = OsuIcon.Online }; public OnlineSection() diff --git a/osu.Game/Overlays/Settings/Sections/RulesetSection.cs b/osu.Game/Overlays/Settings/Sections/RulesetSection.cs index aaad1ec4e2..626264151f 100644 --- a/osu.Game/Overlays/Settings/Sections/RulesetSection.cs +++ b/osu.Game/Overlays/Settings/Sections/RulesetSection.cs @@ -7,6 +7,7 @@ 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; @@ -18,7 +19,7 @@ namespace osu.Game.Overlays.Settings.Sections public override Drawable CreateIcon() => new SpriteIcon { - Icon = FontAwesome.Solid.Chess + Icon = OsuIcon.Rulesets }; [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 1d057f42c0..9b04f208a7 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -14,6 +14,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Game.Database; +using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays.SkinEditor; @@ -31,7 +32,7 @@ namespace osu.Game.Overlays.Settings.Sections public override Drawable CreateIcon() => new SpriteIcon { - Icon = FontAwesome.Solid.PaintBrush + Icon = OsuIcon.SkinB }; private static readonly Live random_skin_info = new SkinInfo diff --git a/osu.Game/Overlays/Settings/Sections/UserInterfaceSection.cs b/osu.Game/Overlays/Settings/Sections/UserInterfaceSection.cs index 2ec9e32ea9..953ede25e1 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterfaceSection.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterfaceSection.cs @@ -4,6 +4,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Game.Graphics; using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.UserInterface; @@ -15,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections public override Drawable CreateIcon() => new SpriteIcon { - Icon = FontAwesome.Solid.LayerGroup + Icon = OsuIcon.UserInterface }; public UserInterfaceSection() From 288ac930e44bd8dc5b5ab8d5f5f342228625fc0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 27 Dec 2023 16:03:57 +0100 Subject: [PATCH 09/42] Use new icons in editor Some that exist on figma are purposefully not used due to an editorial request from @peppy. --- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 3 ++- osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs | 3 ++- osu.Game/Rulesets/Edit/Tools/SelectTool.cs | 3 ++- .../Edit/Compose/Components/ComposeBlueprintContainer.cs | 6 +++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 8382317d70..448cfaf84c 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -17,6 +17,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; @@ -54,7 +55,7 @@ namespace osu.Game.Rulesets.Osu.Edit .Concat(DistanceSnapProvider.CreateTernaryButtons()) .Concat(new[] { - new TernaryButton(rectangularGridSnapToggle, "Grid Snap", () => new SpriteIcon { Icon = FontAwesome.Solid.Th }) + new TernaryButton(rectangularGridSnapToggle, "Grid Snap", () => new SpriteIcon { Icon = OsuIcon.EditorGridSnap }) }); private BindableList selectedHitObjects; diff --git a/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs b/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs index ddf539771d..b3ca59a5b0 100644 --- a/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs +++ b/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs @@ -16,6 +16,7 @@ using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Configuration; +using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Overlays; @@ -169,7 +170,7 @@ namespace osu.Game.Rulesets.Edit public IEnumerable CreateTernaryButtons() => new[] { - new TernaryButton(DistanceSnapToggle, "Distance Snap", () => new SpriteIcon { Icon = FontAwesome.Solid.Ruler }) + new TernaryButton(DistanceSnapToggle, "Distance Snap", () => new SpriteIcon { Icon = OsuIcon.EditorDistanceSnap }) }; protected override bool OnKeyDown(KeyDownEvent e) diff --git a/osu.Game/Rulesets/Edit/Tools/SelectTool.cs b/osu.Game/Rulesets/Edit/Tools/SelectTool.cs index 9640830a09..a272e9f480 100644 --- a/osu.Game/Rulesets/Edit/Tools/SelectTool.cs +++ b/osu.Game/Rulesets/Edit/Tools/SelectTool.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; namespace osu.Game.Rulesets.Edit.Tools { @@ -15,7 +16,7 @@ namespace osu.Game.Rulesets.Edit.Tools { } - public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.Solid.MousePointer }; + public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.EditorSelect }; public override PlacementBlueprint CreatePlacementBlueprint() => null; } diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index c7c7c4aa83..4fba798a26 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -225,7 +225,7 @@ namespace osu.Game.Screens.Edit.Compose.Components protected virtual IEnumerable CreateTernaryButtons() { //TODO: this should only be enabled (visible?) for rulesets that provide combo-supporting HitObjects. - yield return new TernaryButton(NewCombo, "New combo", () => new SpriteIcon { Icon = FontAwesome.Regular.DotCircle }); + yield return new TernaryButton(NewCombo, "New combo", () => new SpriteIcon { Icon = OsuIcon.EditorNewComboA }); foreach (var kvp in SelectionHandler.SelectionSampleStates) yield return new TernaryButton(kvp.Value, kvp.Key.Replace("hit", string.Empty).Titleize(), () => getIconForSample(kvp.Key)); @@ -272,10 +272,10 @@ namespace osu.Game.Screens.Edit.Compose.Components return new SpriteIcon { Icon = FontAwesome.Solid.Hands }; case HitSampleInfo.HIT_WHISTLE: - return new SpriteIcon { Icon = FontAwesome.Solid.Bullhorn }; + return new SpriteIcon { Icon = OsuIcon.EditorWhistle }; case HitSampleInfo.HIT_FINISH: - return new SpriteIcon { Icon = FontAwesome.Solid.DrumSteelpan }; + return new SpriteIcon { Icon = OsuIcon.EditorFinish }; } return null; From 53766285ce6cd5b227e933fe45da8f32bc2f6cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 27 Dec 2023 15:55:19 +0100 Subject: [PATCH 10/42] Remove remaining hexacons usages --- osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs | 2 +- osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs | 2 +- osu.Game/Overlays/Chat/ChatOverlayTopBar.cs | 2 +- osu.Game/Overlays/Profile/ProfileHeader.cs | 2 +- osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs | 2 +- osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs index 55a04b129c..5db7223bdf 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs @@ -154,7 +154,7 @@ namespace osu.Game.Tests.Visual.UserInterface public TestTitle() { Title = "title"; - Icon = HexaconsIcons.Devtools; + Icon = OsuIcon.ChangelogB; } } } diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs index eced27f35e..1df246ae77 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs @@ -60,7 +60,7 @@ namespace osu.Game.Overlays.BeatmapSet public BeatmapHeaderTitle() { Title = PageTitleStrings.MainBeatmapsetsControllerShow; - Icon = HexaconsIcons.Beatmap; + Icon = OsuIcon.Beatmap; } } } diff --git a/osu.Game/Overlays/Chat/ChatOverlayTopBar.cs b/osu.Game/Overlays/Chat/ChatOverlayTopBar.cs index 4fc9fbb6d5..3ecdb09976 100644 --- a/osu.Game/Overlays/Chat/ChatOverlayTopBar.cs +++ b/osu.Game/Overlays/Chat/ChatOverlayTopBar.cs @@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Chat { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Icon = HexaconsIcons.Messaging, + Icon = OsuIcon.Chat, Size = new Vector2(24), }, // Placeholder text diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 78343d08f1..42bec50022 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -87,7 +87,7 @@ namespace osu.Game.Overlays.Profile public ProfileHeaderTitle() { Title = PageTitleStrings.MainUsersControllerDefault; - Icon = HexaconsIcons.Profile; + Icon = OsuIcon.Player; } } } diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs index 5c77672d90..0e125d0ec0 100644 --- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Edit.Components.Menus Size = new Vector2(26), Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Icon = HexaconsIcons.Editor, + Icon = OsuIcon.EditCircle, }, text = new TextFlowContainer { diff --git a/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs b/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs index 93448c4394..022da36abc 100644 --- a/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs +++ b/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs @@ -80,7 +80,7 @@ namespace osu.Game.Screens.Edit.Setup { Title = EditorSetupStrings.BeatmapSetup.ToLower(); Description = EditorSetupStrings.BeatmapSetupDescription; - Icon = HexaconsIcons.Social; + Icon = OsuIcon.Beatmap; } } From 89e2b6358a2937ee46246f3b05b4122c7528ae95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 27 Dec 2023 15:55:37 +0100 Subject: [PATCH 11/42] Remove hexacons --- osu.Game/Graphics/HexaconsIcons.cs | 131 ----------------------------- osu.Game/OsuGameBase.cs | 1 - 2 files changed, 132 deletions(-) delete mode 100644 osu.Game/Graphics/HexaconsIcons.cs diff --git a/osu.Game/Graphics/HexaconsIcons.cs b/osu.Game/Graphics/HexaconsIcons.cs deleted file mode 100644 index 3eee5d7197..0000000000 --- a/osu.Game/Graphics/HexaconsIcons.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; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; -using osu.Framework.Text; - -namespace osu.Game.Graphics -{ - public static class HexaconsIcons - { - public const string FONT_NAME = "Icons/Hexacons"; - - public static IconUsage BeatmapPacks => get(HexaconsMapping.beatmap_packs); - public static IconUsage Beatmap => get(HexaconsMapping.beatmap); - public static IconUsage Calendar => get(HexaconsMapping.calendar); - public static IconUsage Chart => get(HexaconsMapping.chart); - public static IconUsage Community => get(HexaconsMapping.community); - public static IconUsage Contests => get(HexaconsMapping.contests); - public static IconUsage Devtools => get(HexaconsMapping.devtools); - public static IconUsage Download => get(HexaconsMapping.download); - public static IconUsage Editor => get(HexaconsMapping.editor); - public static IconUsage FeaturedArtist => get(HexaconsMapping.featured_artist); - public static IconUsage Home => get(HexaconsMapping.home); - public static IconUsage Messaging => get(HexaconsMapping.messaging); - public static IconUsage Music => get(HexaconsMapping.music); - public static IconUsage News => get(HexaconsMapping.news); - public static IconUsage Notification => get(HexaconsMapping.notification); - public static IconUsage Profile => get(HexaconsMapping.profile); - public static IconUsage Rankings => get(HexaconsMapping.rankings); - public static IconUsage Search => get(HexaconsMapping.search); - public static IconUsage Settings => get(HexaconsMapping.settings); - public static IconUsage Social => get(HexaconsMapping.social); - public static IconUsage Store => get(HexaconsMapping.store); - public static IconUsage Tournament => get(HexaconsMapping.tournament); - public static IconUsage Wiki => get(HexaconsMapping.wiki); - - private static IconUsage get(HexaconsMapping icon) => new IconUsage((char)icon, FONT_NAME); - - // Basically just converting to something we can use in a `char` lookup for FontStore/GlyphStore compatibility. - // Names should match filenames in resources. - private enum HexaconsMapping - { - beatmap_packs, - beatmap, - calendar, - chart, - community, - contests, - devtools, - download, - editor, - featured_artist, - home, - messaging, - music, - news, - notification, - profile, - rankings, - search, - settings, - social, - store, - tournament, - wiki, - } - - public class HexaconsStore : ITextureStore, ITexturedGlyphLookupStore - { - private readonly TextureStore textures; - - public HexaconsStore(TextureStore textures) - { - this.textures = textures; - } - - public void Dispose() - { - textures.Dispose(); - } - - public ITexturedCharacterGlyph? Get(string? fontName, char character) - { - if (fontName == FONT_NAME) - return new Glyph(textures.Get($"{fontName}/{((HexaconsMapping)character).ToString().Replace("_", "-")}")); - - return null; - } - - public Task GetAsync(string fontName, char character) => Task.Run(() => Get(fontName, character)); - - public Texture? Get(string name, WrapMode wrapModeS, WrapMode wrapModeT) => null; - - public Texture Get(string name) => throw new NotImplementedException(); - - public Task GetAsync(string name, CancellationToken cancellationToken = default) => throw new NotImplementedException(); - - public Stream GetStream(string name) => throw new NotImplementedException(); - - public IEnumerable GetAvailableResources() => throw new NotImplementedException(); - - public Task GetAsync(string name, WrapMode wrapModeS, WrapMode wrapModeT, CancellationToken cancellationToken = default) => throw new NotImplementedException(); - - public class Glyph : ITexturedCharacterGlyph - { - public float XOffset => default; - public float YOffset => default; - public float XAdvance => default; - public float Baseline => default; - public char Character => default; - - public float GetKerning(T lastGlyph) where T : ICharacterGlyph => throw new NotImplementedException(); - - public Texture Texture { get; } - public float Width => Texture.Width; - public float Height => Texture.Height; - - public Glyph(Texture texture) - { - Texture = texture; - } - } - } - } -} diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index b4ad21f045..5b17dc13c2 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -478,7 +478,6 @@ namespace osu.Game AddFont(Resources, @"Fonts/Venera/Venera-Bold"); AddFont(Resources, @"Fonts/Venera/Venera-Black"); - Fonts.AddStore(new HexaconsIcons.HexaconsStore(Textures)); Fonts.AddStore(new OsuIcon.OsuIconStore(Textures)); } From 655528a5370fe83b05452e220d22103824bfecc0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 03:04:13 +0900 Subject: [PATCH 12/42] 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 dd2393ff21..c7e0cc3808 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + From 5f7f1f771d2404e05a7d152d73e893e3d1c54cc0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 03:09:20 +0900 Subject: [PATCH 13/42] Reword tooltip text for dashboard --- osu.Game/Localisation/NamedOverlayComponentStrings.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Localisation/NamedOverlayComponentStrings.cs b/osu.Game/Localisation/NamedOverlayComponentStrings.cs index 475bea2a4a..72e63d699a 100644 --- a/osu.Game/Localisation/NamedOverlayComponentStrings.cs +++ b/osu.Game/Localisation/NamedOverlayComponentStrings.cs @@ -20,12 +20,12 @@ namespace osu.Game.Localisation public static LocalisableString ChangelogDescription => new TranslatableString(getKey(@"changelog_description"), @"track recent dev updates in the osu! ecosystem"); /// - /// "view your friends and other information" + /// "view your friends and spectate other players" /// - public static LocalisableString DashboardDescription => new TranslatableString(getKey(@"dashboard_description"), @"view your friends and other information"); + public static LocalisableString DashboardDescription => new TranslatableString(getKey(@"dashboard_description"), @"view your friends and spectate other players"); /// - /// "find out who's the best right now" + /// "find out who's the best right now" /// public static LocalisableString RankingsDescription => new TranslatableString(getKey(@"rankings_description"), @"find out who's the best right now"); @@ -39,6 +39,6 @@ namespace osu.Game.Localisation /// public static LocalisableString WikiDescription => new TranslatableString(getKey(@"wiki_description"), @"knowledge base"); - private static string getKey(string key) => $"{prefix}:{key}"; + private static string getKey(string key) => $@"{prefix}:{key}"; } } From 1f55ef211eda02b867327746313a32d599645d17 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 03:11:27 +0900 Subject: [PATCH 14/42] Rearrange buttons --- osu.Game/Overlays/Toolbar/Toolbar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 93294a9d30..ec1238ad1f 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -164,11 +164,11 @@ namespace osu.Game.Overlays.Toolbar { new ToolbarNewsButton(), new ToolbarChangelogButton(), + new ToolbarWikiButton(), new ToolbarRankingsButton(), new ToolbarBeatmapListingButton(), new ToolbarChatButton(), new ToolbarSocialButton(), - new ToolbarWikiButton(), new ToolbarMusicButton(), //new ToolbarButton //{ From 70aa067eb166477f29b31495da6b1a8121a0bf8c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 03:23:04 +0900 Subject: [PATCH 15/42] Adjust gradient visibility and transition --- osu.Game/Overlays/Toolbar/Toolbar.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index ec1238ad1f..52fad2ba3b 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -224,9 +224,9 @@ namespace osu.Game.Overlays.Toolbar RelativeSizeAxes = Axes.X, Anchor = Anchor.BottomLeft, Alpha = 0, - Height = 100, + Height = 80, Colour = ColourInfo.GradientVertical( - OsuColour.Gray(0).Opacity(0.9f), OsuColour.Gray(0).Opacity(0)), + OsuColour.Gray(0f).Opacity(0.7f), OsuColour.Gray(0).Opacity(0)), }, }; } @@ -241,9 +241,9 @@ namespace osu.Game.Overlays.Toolbar private void updateState() { if (ShowGradient.Value) - gradientBackground.FadeIn(transition_time, Easing.OutQuint); + gradientBackground.FadeIn(2500, Easing.OutQuint); else - gradientBackground.FadeOut(transition_time, Easing.OutQuint); + gradientBackground.FadeOut(200, Easing.OutQuint); } } From 92c4c20a51e544a27b745932334e6442d5d5d994 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 03:43:38 +0900 Subject: [PATCH 16/42] Adjust paddings and fills of toolbar buttons --- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 45 ++++++++++--------- osu.Game/Overlays/Toolbar/ToolbarClock.cs | 34 +++++++++----- .../Toolbar/ToolbarOverlayToggleButton.cs | 2 +- .../Toolbar/ToolbarRulesetSelector.cs | 1 + .../Overlays/Toolbar/ToolbarUserButton.cs | 2 +- 5 files changed, 51 insertions(+), 33 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index a547fda814..bd5faf1588 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -7,7 +7,6 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.EnumExtensions; 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; @@ -74,6 +73,8 @@ namespace osu.Game.Overlays.Toolbar private readonly SpriteText keyBindingTooltip; protected FillFlowContainer Flow; + protected readonly Container BackgroundContent; + [Resolved] private RealmAccess realm { get; set; } = null!; @@ -82,21 +83,33 @@ namespace osu.Game.Overlays.Toolbar Width = Toolbar.HEIGHT; RelativeSizeAxes = Axes.Y; + Padding = new MarginPadding(3); + Children = new Drawable[] { - HoverBackground = new Box + BackgroundContent = new Container { RelativeSizeAxes = Axes.Both, - Colour = OsuColour.Gray(80).Opacity(180), - Blending = BlendingParameters.Additive, - Alpha = 0, - }, - flashBackground = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Colour = Color4.White.Opacity(100), - Blending = BlendingParameters.Additive, + Masking = true, + CornerRadius = 6, + CornerExponent = 3f, + Children = new Drawable[] + { + HoverBackground = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(80).Opacity(180), + Blending = BlendingParameters.Additive, + Alpha = 0, + }, + flashBackground = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + Colour = Color4.White.Opacity(100), + Blending = BlendingParameters.Additive, + }, + } }, Flow = new FillFlowContainer { @@ -219,14 +232,6 @@ namespace osu.Game.Overlays.Toolbar public OpaqueBackground() { RelativeSizeAxes = Axes.Both; - Masking = true; - MaskingSmoothness = 0; - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(40), - Radius = 5, - }; Children = new Drawable[] { diff --git a/osu.Game/Overlays/Toolbar/ToolbarClock.cs b/osu.Game/Overlays/Toolbar/ToolbarClock.cs index f1310d8535..67688155ae 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarClock.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarClock.cs @@ -42,21 +42,33 @@ namespace osu.Game.Overlays.Toolbar clockDisplayMode = config.GetBindable(OsuSetting.ToolbarClockDisplayMode); prefer24HourTime = config.GetBindable(OsuSetting.Prefer24HourTime); + Padding = new MarginPadding(3); + Children = new Drawable[] { - hoverBackground = new Box + new Container { RelativeSizeAxes = Axes.Both, - Colour = OsuColour.Gray(80).Opacity(180), - Blending = BlendingParameters.Additive, - Alpha = 0, - }, - flashBackground = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Colour = Color4.White.Opacity(100), - Blending = BlendingParameters.Additive, + Masking = true, + CornerRadius = 6, + CornerExponent = 3f, + Children = new Drawable[] + { + hoverBackground = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(80).Opacity(180), + Blending = BlendingParameters.Additive, + Alpha = 0, + }, + flashBackground = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + Colour = Color4.White.Opacity(100), + Blending = BlendingParameters.Additive, + }, + } }, new FillFlowContainer { diff --git a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs index 78c976111b..37038161e1 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs @@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Toolbar public ToolbarOverlayToggleButton() { - Add(stateBackground = new Box + BackgroundContent.Add(stateBackground = new Box { RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(150).Opacity(180), diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs index 715076b368..63d11c1b9e 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs @@ -41,6 +41,7 @@ namespace osu.Game.Overlays.Toolbar new OpaqueBackground { Depth = 1, + Masking = true, }, ModeButtonLine = new Container { diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index 028decea1e..7d1b6c7404 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -40,7 +40,7 @@ namespace osu.Game.Overlays.Toolbar [BackgroundDependencyLoader] private void load(OsuColour colours, IAPIProvider api, LoginOverlay? login) { - Add(new OpaqueBackground { Depth = 1 }); + BackgroundContent.Add(new OpaqueBackground { Depth = 1 }); Flow.Add(new Container { From cf5e3e886386737385fe75cf1642e75279c7ff16 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 04:06:29 +0900 Subject: [PATCH 17/42] Breathe some colour and life into the toolbar --- .../Toolbar/ToolbarOverlayToggleButton.cs | 8 ++-- .../Toolbar/ToolbarRulesetSelector.cs | 43 +++++++++---------- .../Toolbar/ToolbarRulesetTabButton.cs | 30 +++++++------ 3 files changed, 43 insertions(+), 38 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs index 37038161e1..09b8df14a6 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs @@ -3,6 +3,7 @@ #nullable disable +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -14,7 +15,7 @@ namespace osu.Game.Overlays.Toolbar { public partial class ToolbarOverlayToggleButton : ToolbarButton { - private readonly Box stateBackground; + private Box stateBackground; private OverlayContainer stateContainer; @@ -44,12 +45,13 @@ namespace osu.Game.Overlays.Toolbar } } - public ToolbarOverlayToggleButton() + [BackgroundDependencyLoader] + private void load(OsuColour colours) { BackgroundContent.Add(stateBackground = new Box { RelativeSizeAxes = Axes.Both, - Colour = OsuColour.Gray(150).Opacity(180), + Colour = colours.Carmine.Opacity(180), Blending = BlendingParameters.Additive, Depth = 2, Alpha = 0, diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs index 63d11c1b9e..723c24597a 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs @@ -4,20 +4,19 @@ #nullable disable using System.Collections.Generic; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osuTK; -using osuTK.Graphics; -using osu.Framework.Graphics.Shapes; -using osu.Game.Rulesets; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; -using osuTK.Input; 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.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Game.Rulesets; +using osuTK; +using osuTK.Graphics; +using osuTK.Input; namespace osu.Game.Overlays.Toolbar { @@ -47,20 +46,18 @@ namespace osu.Game.Overlays.Toolbar { Size = new Vector2(Toolbar.HEIGHT, 3), Anchor = Anchor.BottomLeft, - Origin = Anchor.TopLeft, - Masking = true, - EdgeEffect = new EdgeEffectParameters + Origin = Anchor.BottomLeft, + Y = -1, + Children = new Drawable[] { - Type = EdgeEffectType.Glow, - Colour = new Color4(255, 194, 224, 100), - Radius = 15, - Roundness = 15, - }, - Child = new Box - { - RelativeSizeAxes = Axes.Both, + new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(18, 3), + } } - } + }, }); foreach (var ruleset in Rulesets.AvailableRulesets) @@ -90,7 +87,7 @@ namespace osu.Game.Overlays.Toolbar { if (SelectedTab != null) { - ModeButtonLine.MoveToX(SelectedTab.DrawPosition.X, !hasInitialPosition ? 0 : 200, Easing.OutQuint); + ModeButtonLine.MoveToX(SelectedTab.DrawPosition.X, !hasInitialPosition ? 0 : 500, Easing.OutElasticQuarter); if (hasInitialPosition) selectionSamples[SelectedTab.Value.ShortName]?.Play(); diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs index 74f76c7c89..5500f1c879 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs @@ -1,14 +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 osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; +using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Rulesets; -using osuTK.Graphics; namespace osu.Game.Overlays.Toolbar { @@ -41,27 +43,31 @@ namespace osu.Game.Overlays.Toolbar { protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds(); + [Resolved] + private OsuColour colours { get; set; } = null!; + + public RulesetButton() + { + Padding = new MarginPadding(3) + { + Bottom = 5 + }; + } + public bool Active { - set + set => Scheduler.AddOnce(() => { if (value) { - IconContainer.Colour = Color4.White; - IconContainer.EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = new Color4(255, 194, 224, 100), - Radius = 15, - Roundness = 15, - }; + IconContainer.Colour = Color4Extensions.FromHex("#00FFAA"); } else { - IconContainer.Colour = new Color4(255, 194, 224, 255); + IconContainer.Colour = colours.GrayF; IconContainer.EdgeEffect = new EdgeEffectParameters(); } - } + }); } protected override bool OnClick(ClickEvent e) From cf39bb7a18877055a58324d542b9c4feb83d1611 Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Wed, 27 Dec 2023 12:55:20 -0800 Subject: [PATCH 18/42] Fix spinner max bonus not respecting ISamplePlaybackDisabler The spinner max bonus was loaded through SkinnableSound instead of PausableSkinnableSound, leading to it not respecting the case where sample playback is globally disabled through ISamplePlaybackDisabler, and can be easily heard in situations like during the catchup period after seeking using the ArgonSongProgressBar with song volume at 0 --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index f7c1437009..bf4b07eaab 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private const float spinning_sample_initial_frequency = 1.0f; private const float spinning_sample_modulated_base_frequency = 0.5f; - private SkinnableSound maxBonusSample; + private PausableSkinnableSound maxBonusSample; /// /// The amount of bonus score gained from spinning after the required number of spins, for display purposes. @@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Looping = true, Frequency = { Value = spinning_sample_initial_frequency } }, - maxBonusSample = new SkinnableSound + maxBonusSample = new PausableSkinnableSound { MinimumSampleVolume = MINIMUM_SAMPLE_VOLUME, } From d9299a8a55bff6757358db2d46b38806817f974a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 27 Dec 2023 23:07:17 +0100 Subject: [PATCH 19/42] Implement visual appearance of "system title" message in main menu --- .../Visual/Menus/TestSceneMainMenu.cs | 30 ++++++ .../API/Requests/Responses/APISystemTitle.cs | 16 +++ osu.Game/OsuGame.cs | 5 +- osu.Game/Screens/Menu/MainMenu.cs | 15 +++ osu.Game/Screens/Menu/SystemTitle.cs | 101 ++++++++++++++++++ 5 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/Menus/TestSceneMainMenu.cs create mode 100644 osu.Game/Online/API/Requests/Responses/APISystemTitle.cs create mode 100644 osu.Game/Screens/Menu/SystemTitle.cs diff --git a/osu.Game.Tests/Visual/Menus/TestSceneMainMenu.cs b/osu.Game.Tests/Visual/Menus/TestSceneMainMenu.cs new file mode 100644 index 0000000000..85aa14f33e --- /dev/null +++ b/osu.Game.Tests/Visual/Menus/TestSceneMainMenu.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.Linq; +using NUnit.Framework; +using osu.Framework.Testing; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Screens.Menu; + +namespace osu.Game.Tests.Visual.Menus +{ + public partial class TestSceneMainMenu : OsuGameTestScene + { + [Test] + public void TestSystemTitle() + { + AddStep("set system title", () => Game.ChildrenOfType().Single().Current.Value = new APISystemTitle + { + Image = @"https://assets.ppy.sh/main-menu/project-loved-2@2x.png", + Url = @"https://osu.ppy.sh/home/news/2023-12-21-project-loved-december-2023", + }); + AddStep("set another title", () => Game.ChildrenOfType().Single().Current.Value = new APISystemTitle + { + Image = @"https://assets.ppy.sh/main-menu/wf2023-vote@2x.png", + Url = @"https://osu.ppy.sh/community/contests/189", + }); + AddStep("unset system title", () => Game.ChildrenOfType().Single().Current.Value = null); + } + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs b/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs new file mode 100644 index 0000000000..3a2342cc4c --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APISystemTitle.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 Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APISystemTitle + { + [JsonProperty(@"image")] + public string Image { get; set; } = string.Empty; + + [JsonProperty(@"url")] + public string Url { get; set; } = string.Empty; + } +} diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e7ff99ef01..37996e8832 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -995,7 +995,10 @@ namespace osu.Game }, topMostOverlayContent.Add); if (!args?.Any(a => a == @"--no-version-overlay") ?? true) - loadComponentSingleFile(versionManager = new VersionManager { Depth = int.MinValue }, ScreenContainer.Add); + { + dependencies.Cache(versionManager = new VersionManager { Depth = int.MinValue }); + loadComponentSingleFile(versionManager, ScreenContainer.Add); + } loadComponentSingleFile(osuLogo, _ => { diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index c25e62d69e..0739689daa 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -76,6 +76,9 @@ namespace osu.Game.Screens.Menu [Resolved(canBeNull: true)] private IDialogOverlay dialogOverlay { get; set; } + [Resolved(canBeNull: true)] + private VersionManager versionManager { get; set; } + protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault(); protected override bool PlayExitSound => false; @@ -91,6 +94,7 @@ namespace osu.Game.Screens.Menu private ParallaxContainer buttonsContainer; private SongTicker songTicker; private Container logoTarget; + private SystemTitle systemTitle; private Sample reappearSampleSwoosh; @@ -153,6 +157,7 @@ namespace osu.Game.Screens.Menu Margin = new MarginPadding { Right = 15, Top = 5 } }, new KiaiMenuFountains(), + systemTitle = new SystemTitle(), holdToExitGameOverlay?.CreateProxy() ?? Empty() }); @@ -263,6 +268,16 @@ namespace osu.Game.Screens.Menu } } + protected override void Update() + { + base.Update(); + + systemTitle.Margin = new MarginPadding + { + Bottom = (versionManager?.DrawHeight + 5) ?? 0 + }; + } + protected override void LogoSuspending(OsuLogo logo) { var seq = logo.FadeOut(300, Easing.InSine) diff --git a/osu.Game/Screens/Menu/SystemTitle.cs b/osu.Game/Screens/Menu/SystemTitle.cs new file mode 100644 index 0000000000..6ca9aab6c7 --- /dev/null +++ b/osu.Game/Screens/Menu/SystemTitle.cs @@ -0,0 +1,101 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Input.Events; +using osu.Framework.Platform; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Screens.Menu +{ + public partial class SystemTitle : CompositeDrawable + { + internal Bindable Current { get; } = new Bindable(); + + private Container content = null!; + private CancellationTokenSource? cancellationTokenSource; + private SystemTitleImage? currentImage; + + [BackgroundDependencyLoader] + private void load(GameHost? gameHost) + { + Anchor = Anchor.BottomCentre; + Origin = Anchor.BottomCentre; + AutoSizeAxes = Axes.Both; + + InternalChild = content = new ClickableContainer + { + AutoSizeAxes = Axes.Both, + Action = () => + { + if (!string.IsNullOrEmpty(Current.Value?.Url)) + gameHost?.OpenUrlExternally(Current.Value.Url); + } + }; + } + + protected override bool OnHover(HoverEvent e) + { + content.ScaleTo(1.1f, 500, Easing.OutBounce); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + content.ScaleTo(1f, 500, Easing.OutBounce); + base.OnHoverLost(e); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Current.BindValueChanged(_ => loadNewImage(), true); + } + + private void loadNewImage() + { + cancellationTokenSource?.Cancel(); + cancellationTokenSource = null; + currentImage?.FadeOut(500, Easing.OutQuint).Expire(); + + if (string.IsNullOrEmpty(Current.Value?.Image)) + return; + + LoadComponentAsync(new SystemTitleImage(Current.Value), loaded => + { + if (loaded.SystemTitle != Current.Value) + loaded.Dispose(); + + loaded.FadeInFromZero(500, Easing.OutQuint); + content.Add(currentImage = loaded); + }, (cancellationTokenSource ??= new CancellationTokenSource()).Token); + } + + [LongRunningLoad] + private partial class SystemTitleImage : Sprite + { + public readonly APISystemTitle SystemTitle; + + public SystemTitleImage(APISystemTitle systemTitle) + { + SystemTitle = systemTitle; + } + + [BackgroundDependencyLoader] + private void load(LargeTextureStore textureStore) + { + var texture = textureStore.Get(SystemTitle.Image); + if (SystemTitle.Image.Contains(@"@2x")) + texture.ScaleAdjust *= 2; + Texture = texture; + } + } + } +} From a3f720bc627f27d6bcc9fe36c011190010930b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 27 Dec 2023 23:31:14 +0100 Subject: [PATCH 20/42] Retrieve system title from online source --- .../API/Requests/GetSystemTitleRequest.cs | 15 ++++++++++++ .../API/Requests/Responses/APISystemTitle.cs | 2 +- osu.Game/Screens/Menu/SystemTitle.cs | 23 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Online/API/Requests/GetSystemTitleRequest.cs diff --git a/osu.Game/Online/API/Requests/GetSystemTitleRequest.cs b/osu.Game/Online/API/Requests/GetSystemTitleRequest.cs new file mode 100644 index 0000000000..52ca0c11eb --- /dev/null +++ b/osu.Game/Online/API/Requests/GetSystemTitleRequest.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 osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class GetSystemTitleRequest : OsuJsonWebRequest + { + public GetSystemTitleRequest() + : base(@"https://assets.ppy.sh/lazer-status.json") + { + } + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs b/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs index 3a2342cc4c..97bdc8355a 100644 --- a/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs +++ b/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs @@ -5,7 +5,7 @@ using Newtonsoft.Json; namespace osu.Game.Online.API.Requests.Responses { - public class APISystemTitle + public record APISystemTitle { [JsonProperty(@"image")] public string Image { get; set; } = string.Empty; diff --git a/osu.Game/Screens/Menu/SystemTitle.cs b/osu.Game/Screens/Menu/SystemTitle.cs index 6ca9aab6c7..0867fc4748 100644 --- a/osu.Game/Screens/Menu/SystemTitle.cs +++ b/osu.Game/Screens/Menu/SystemTitle.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.Threading; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -10,6 +12,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Events; using osu.Framework.Platform; +using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Screens.Menu @@ -57,6 +60,26 @@ namespace osu.Game.Screens.Menu base.LoadComplete(); Current.BindValueChanged(_ => loadNewImage(), true); + + checkForUpdates(); + Scheduler.AddDelayed(checkForUpdates, TimeSpan.FromMinutes(15).TotalMilliseconds, true); + } + + private void checkForUpdates() + { + var request = new GetSystemTitleRequest(); + Task.Run(() => request.Perform()) + .ContinueWith(r => + { + if (r.IsCompletedSuccessfully) + Schedule(() => Current.Value = request.ResponseObject); + + // if the request failed, "observe" the exception. + // it isn't very important why this failed, as it's only for display. + // the inner error will be logged by framework mechanisms anyway. + if (r.IsFaulted) + _ = r.Exception; + }); } private void loadNewImage() From ac449131edcee95d9ca61fef538aeea7010c128d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 27 Dec 2023 23:47:37 +0100 Subject: [PATCH 21/42] CodeFileSanity does not like records in standalone files --- .../API/Requests/Responses/APISystemTitle.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs b/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs index 97bdc8355a..6d5d91f8f3 100644 --- a/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs +++ b/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs @@ -1,16 +1,29 @@ // 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 Newtonsoft.Json; namespace osu.Game.Online.API.Requests.Responses { - public record APISystemTitle + public class APISystemTitle : IEquatable { [JsonProperty(@"image")] public string Image { get; set; } = string.Empty; [JsonProperty(@"url")] public string Url { get; set; } = string.Empty; + + public bool Equals(APISystemTitle? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + return Image == other.Image && Url == other.Url; + } + + public override bool Equals(object? obj) => obj is APISystemTitle other && Equals(other); + + public override int GetHashCode() => HashCode.Combine(Image, Url); } } From ef3975981376e7308f4156024929f404f9240504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 28 Dec 2023 00:09:51 +0100 Subject: [PATCH 22/42] More code quality inspections --- osu.Game/Online/API/Requests/Responses/APISystemTitle.cs | 1 + osu.Game/Screens/Menu/SystemTitle.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs b/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs index 6d5d91f8f3..bfa5c1043b 100644 --- a/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs +++ b/osu.Game/Online/API/Requests/Responses/APISystemTitle.cs @@ -24,6 +24,7 @@ namespace osu.Game.Online.API.Requests.Responses public override bool Equals(object? obj) => obj is APISystemTitle other && Equals(other); + // ReSharper disable NonReadonlyMemberInGetHashCode public override int GetHashCode() => HashCode.Combine(Image, Url); } } diff --git a/osu.Game/Screens/Menu/SystemTitle.cs b/osu.Game/Screens/Menu/SystemTitle.cs index 0867fc4748..6b976a8ed6 100644 --- a/osu.Game/Screens/Menu/SystemTitle.cs +++ b/osu.Game/Screens/Menu/SystemTitle.cs @@ -93,7 +93,7 @@ namespace osu.Game.Screens.Menu LoadComponentAsync(new SystemTitleImage(Current.Value), loaded => { - if (loaded.SystemTitle != Current.Value) + if (!loaded.SystemTitle.Equals(Current.Value)) loaded.Dispose(); loaded.FadeInFromZero(500, Easing.OutQuint); From f8d6b8e347c18e2bf0bec85cdf76aac6f0f5d7a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 14:10:52 +0900 Subject: [PATCH 23/42] Adjust toolbar animations / layering to feel better --- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index bd5faf1588..03a1cfc005 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -183,7 +183,7 @@ namespace osu.Game.Overlays.Toolbar protected override bool OnClick(ClickEvent e) { - flashBackground.FadeOutFromOne(800, Easing.OutQuint); + flashBackground.FadeIn(50).Then().FadeOutFromOne(800, Easing.OutQuint); tooltipContainer.FadeOut(100); return base.OnClick(e); } diff --git a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs index 09b8df14a6..06755a9da9 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs @@ -53,7 +53,7 @@ namespace osu.Game.Overlays.Toolbar RelativeSizeAxes = Axes.Both, Colour = colours.Carmine.Opacity(180), Blending = BlendingParameters.Additive, - Depth = 2, + Depth = float.MaxValue, Alpha = 0, }); @@ -65,11 +65,11 @@ namespace osu.Game.Overlays.Toolbar switch (state.NewValue) { case Visibility.Hidden: - stateBackground.FadeOut(200); + stateBackground.FadeOut(200, Easing.OutQuint); break; case Visibility.Visible: - stateBackground.FadeIn(200); + stateBackground.FadeIn(200, Easing.OutQuint); break; } } From ffc8778d673dd54a650066b9dc47d6252367da15 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 14:13:35 +0900 Subject: [PATCH 24/42] Fix song select leaderboard tab ordering not matching stable --- .../Select/Leaderboards/BeatmapLeaderboardScope.cs | 6 +++--- osu.Game/Screens/Select/PlayBeatmapDetailArea.cs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs index 5bcb4c27a7..e2e3404877 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs @@ -12,12 +12,12 @@ namespace osu.Game.Screens.Select.Leaderboards [Description("Local Ranking")] Local, - [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowScoreboardCountry))] - Country, - [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowScoreboardGlobal))] Global, + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowScoreboardCountry))] + Country, + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowScoreboardFriend))] Friend, } diff --git a/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs b/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs index 8a1b9ef3e1..deb1100dfc 100644 --- a/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs @@ -80,8 +80,8 @@ namespace osu.Game.Screens.Select protected override BeatmapDetailAreaTabItem[] CreateTabItems() => base.CreateTabItems().Concat(new BeatmapDetailAreaTabItem[] { new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local), - new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Country), new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Global), + new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Country), new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Friend), }).ToArray(); @@ -95,12 +95,12 @@ namespace osu.Game.Screens.Select case TabType.Local: return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local); - case TabType.Country: - return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Country); - case TabType.Global: return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Global); + case TabType.Country: + return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Country); + case TabType.Friends: return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Friend); From 93a8afe96e101a63f65e6bcca92d9707c1fde767 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 14:40:10 +0900 Subject: [PATCH 25/42] Add very simple cache-busting (30 minutes) --- osu.Game/Online/API/Requests/GetSystemTitleRequest.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/GetSystemTitleRequest.cs b/osu.Game/Online/API/Requests/GetSystemTitleRequest.cs index 52ca0c11eb..659e46bb11 100644 --- a/osu.Game/Online/API/Requests/GetSystemTitleRequest.cs +++ b/osu.Game/Online/API/Requests/GetSystemTitleRequest.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.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests @@ -8,7 +9,7 @@ namespace osu.Game.Online.API.Requests public class GetSystemTitleRequest : OsuJsonWebRequest { public GetSystemTitleRequest() - : base(@"https://assets.ppy.sh/lazer-status.json") + : base($@"https://assets.ppy.sh/lazer-status.json?{DateTimeOffset.UtcNow.ToUnixTimeSeconds() / 1800}") { } } From c70e7d340da905d081eb87863ea9588021816453 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 14:48:17 +0900 Subject: [PATCH 26/42] Adjust animation and add delay to URL open --- osu.Game/Screens/Menu/SystemTitle.cs | 37 ++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Menu/SystemTitle.cs b/osu.Game/Screens/Menu/SystemTitle.cs index 6b976a8ed6..2c8cb90b96 100644 --- a/osu.Game/Screens/Menu/SystemTitle.cs +++ b/osu.Game/Screens/Menu/SystemTitle.cs @@ -12,6 +12,8 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Events; using osu.Framework.Platform; +using osu.Framework.Threading; +using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -25,6 +27,8 @@ namespace osu.Game.Screens.Menu private CancellationTokenSource? cancellationTokenSource; private SystemTitleImage? currentImage; + private ScheduledDelegate? openUrlAction; + [BackgroundDependencyLoader] private void load(GameHost? gameHost) { @@ -32,29 +36,52 @@ namespace osu.Game.Screens.Menu Origin = Anchor.BottomCentre; AutoSizeAxes = Axes.Both; - InternalChild = content = new ClickableContainer + InternalChild = content = new OsuClickableContainer { AutoSizeAxes = Axes.Both, Action = () => { - if (!string.IsNullOrEmpty(Current.Value?.Url)) - gameHost?.OpenUrlExternally(Current.Value.Url); + // Delay slightly to allow animation to play out. + openUrlAction?.Cancel(); + openUrlAction = Scheduler.AddDelayed(() => + { + if (!string.IsNullOrEmpty(Current.Value?.Url)) + gameHost?.OpenUrlExternally(Current.Value.Url); + }, 250); } }; } protected override bool OnHover(HoverEvent e) { - content.ScaleTo(1.1f, 500, Easing.OutBounce); + content.ScaleTo(1.05f, 2000, Easing.OutQuint); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - content.ScaleTo(1f, 500, Easing.OutBounce); + content.ScaleTo(1f, 500, Easing.OutQuint); base.OnHoverLost(e); } + protected override bool OnClick(ClickEvent e) + { + //hover.FlashColour(FlashColour, 800, Easing.OutQuint); + return base.OnClick(e); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + content.ScaleTo(0.95f, 500, Easing.OutQuint); + return base.OnMouseDown(e); + } + + protected override void OnMouseUp(MouseUpEvent e) + { + content.ScaleTo(1, 500, Easing.OutElastic); + base.OnMouseUp(e); + } + protected override void LoadComplete() { base.LoadComplete(); From 289e0f00f98ea570fd0a3f6b644b4399c0e4b5ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 14:58:05 +0900 Subject: [PATCH 27/42] Add flash on click --- osu.Game/Screens/Menu/SystemTitle.cs | 37 +++++++++++++++++++++------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Menu/SystemTitle.cs b/osu.Game/Screens/Menu/SystemTitle.cs index 2c8cb90b96..667dc6e947 100644 --- a/osu.Game/Screens/Menu/SystemTitle.cs +++ b/osu.Game/Screens/Menu/SystemTitle.cs @@ -41,6 +41,8 @@ namespace osu.Game.Screens.Menu AutoSizeAxes = Axes.Both, Action = () => { + currentImage?.Flash(); + // Delay slightly to allow animation to play out. openUrlAction?.Cancel(); openUrlAction = Scheduler.AddDelayed(() => @@ -64,12 +66,6 @@ namespace osu.Game.Screens.Menu base.OnHoverLost(e); } - protected override bool OnClick(ClickEvent e) - { - //hover.FlashColour(FlashColour, 800, Easing.OutQuint); - return base.OnClick(e); - } - protected override bool OnMouseDown(MouseDownEvent e) { content.ScaleTo(0.95f, 500, Easing.OutQuint); @@ -78,7 +74,9 @@ namespace osu.Game.Screens.Menu protected override void OnMouseUp(MouseUpEvent e) { - content.ScaleTo(1, 500, Easing.OutElastic); + content + .ScaleTo(0.95f) + .ScaleTo(1, 500, Easing.OutElastic); base.OnMouseUp(e); } @@ -129,10 +127,12 @@ namespace osu.Game.Screens.Menu } [LongRunningLoad] - private partial class SystemTitleImage : Sprite + private partial class SystemTitleImage : CompositeDrawable { public readonly APISystemTitle SystemTitle; + private Sprite flash = null!; + public SystemTitleImage(APISystemTitle systemTitle) { SystemTitle = systemTitle; @@ -144,7 +144,26 @@ namespace osu.Game.Screens.Menu var texture = textureStore.Get(SystemTitle.Image); if (SystemTitle.Image.Contains(@"@2x")) texture.ScaleAdjust *= 2; - Texture = texture; + + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Sprite { Texture = texture }, + flash = new Sprite + { + Texture = texture, + Blending = BlendingParameters.Additive, + Alpha = 0, + }, + }; + } + + public void Flash() + { + flash.FadeInFromZero(50) + .Then() + .FadeOut(500, Easing.OutQuint); } } } From 481a25178658e80891a59bcdd7ad1720576854fe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 15:10:05 +0900 Subject: [PATCH 28/42] Use `HandleLink` to allow potentially opening wiki or otherwise --- osu.Game/Screens/Menu/SystemTitle.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Menu/SystemTitle.cs b/osu.Game/Screens/Menu/SystemTitle.cs index 667dc6e947..967b928b43 100644 --- a/osu.Game/Screens/Menu/SystemTitle.cs +++ b/osu.Game/Screens/Menu/SystemTitle.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Events; -using osu.Framework.Platform; using osu.Framework.Threading; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests; @@ -30,7 +29,7 @@ namespace osu.Game.Screens.Menu private ScheduledDelegate? openUrlAction; [BackgroundDependencyLoader] - private void load(GameHost? gameHost) + private void load(OsuGame? game) { Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; @@ -48,7 +47,7 @@ namespace osu.Game.Screens.Menu openUrlAction = Scheduler.AddDelayed(() => { if (!string.IsNullOrEmpty(Current.Value?.Url)) - gameHost?.OpenUrlExternally(Current.Value.Url); + game?.HandleLink(Current.Value.Url); }, 250); } }; From 972234b1e5c1a505f23fe1491d509ab343636b4c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 15:12:44 +0900 Subject: [PATCH 29/42] Move re-schedule inside continuation --- osu.Game/Screens/Menu/SystemTitle.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/SystemTitle.cs b/osu.Game/Screens/Menu/SystemTitle.cs index 967b928b43..b8510dde87 100644 --- a/osu.Game/Screens/Menu/SystemTitle.cs +++ b/osu.Game/Screens/Menu/SystemTitle.cs @@ -86,7 +86,6 @@ namespace osu.Game.Screens.Menu Current.BindValueChanged(_ => loadNewImage(), true); checkForUpdates(); - Scheduler.AddDelayed(checkForUpdates, TimeSpan.FromMinutes(15).TotalMilliseconds, true); } private void checkForUpdates() @@ -103,6 +102,8 @@ namespace osu.Game.Screens.Menu // the inner error will be logged by framework mechanisms anyway. if (r.IsFaulted) _ = r.Exception; + + Scheduler.AddDelayed(checkForUpdates, TimeSpan.FromMinutes(15).TotalMilliseconds); }); } From 0ea62d0c5d52f98c19062e8baba5e225daea8c5c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 15:16:42 +0900 Subject: [PATCH 30/42] Add initial additive blending on fade in --- osu.Game/Screens/Menu/SystemTitle.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Menu/SystemTitle.cs b/osu.Game/Screens/Menu/SystemTitle.cs index b8510dde87..8b243e8f7f 100644 --- a/osu.Game/Screens/Menu/SystemTitle.cs +++ b/osu.Game/Screens/Menu/SystemTitle.cs @@ -121,7 +121,6 @@ namespace osu.Game.Screens.Menu if (!loaded.SystemTitle.Equals(Current.Value)) loaded.Dispose(); - loaded.FadeInFromZero(500, Easing.OutQuint); content.Add(currentImage = loaded); }, (cancellationTokenSource ??= new CancellationTokenSource()).Token); } @@ -154,16 +153,25 @@ namespace osu.Game.Screens.Menu { Texture = texture, Blending = BlendingParameters.Additive, - Alpha = 0, }, }; } - public void Flash() + protected override void LoadComplete() + { + base.LoadComplete(); + + this.FadeInFromZero(500, Easing.OutQuint); + flash.FadeOutFromOne(4000, Easing.OutQuint); + } + + public Drawable Flash() { flash.FadeInFromZero(50) .Then() .FadeOut(500, Easing.OutQuint); + + return this; } } } From 6684987289a6dcbd0ab918cd9976909bead57dc1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 15:18:21 +0900 Subject: [PATCH 31/42] Reduce refresh interval slightly --- osu.Game/Screens/Menu/SystemTitle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/SystemTitle.cs b/osu.Game/Screens/Menu/SystemTitle.cs index 8b243e8f7f..bb623cacdf 100644 --- a/osu.Game/Screens/Menu/SystemTitle.cs +++ b/osu.Game/Screens/Menu/SystemTitle.cs @@ -103,7 +103,7 @@ namespace osu.Game.Screens.Menu if (r.IsFaulted) _ = r.Exception; - Scheduler.AddDelayed(checkForUpdates, TimeSpan.FromMinutes(15).TotalMilliseconds); + Scheduler.AddDelayed(checkForUpdates, TimeSpan.FromMinutes(5).TotalMilliseconds); }); } From a1867afbb43307ca775e56586bb6c86af038cc81 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 16:05:20 +0900 Subject: [PATCH 32/42] Move menu tips to main menu In preparation for removing the disclaimer screen. --- osu.Game/Configuration/OsuConfigManager.cs | 2 + osu.Game/Localisation/UserInterfaceStrings.cs | 7 +- .../UserInterface/MainMenuSettings.cs | 5 ++ osu.Game/Screens/Menu/Disclaimer.cs | 30 ------- osu.Game/Screens/Menu/MainMenu.cs | 38 +++++++- osu.Game/Screens/Menu/MenuTip.cs | 89 +++++++++++++++++++ osu.Game/Screens/Menu/SystemTitle.cs | 2 - 7 files changed, 138 insertions(+), 35 deletions(-) create mode 100644 osu.Game/Screens/Menu/MenuTip.cs diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 0df870655f..d4162b76d6 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -96,6 +96,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.MenuVoice, true); SetDefault(OsuSetting.MenuMusic, true); + SetDefault(OsuSetting.MenuTips, true); SetDefault(OsuSetting.AudioOffset, 0, -500.0, 500.0, 1); @@ -350,6 +351,7 @@ namespace osu.Game.Configuration VolumeInactive, MenuMusic, MenuVoice, + MenuTips, CursorRotation, MenuParallax, Prefer24HourTime, diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index 68c5c3ccbc..dceedca05c 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -24,6 +24,11 @@ namespace osu.Game.Localisation /// public static LocalisableString MenuCursorSize => new TranslatableString(getKey(@"menu_cursor_size"), @"Menu cursor size"); + /// + /// "Menu tips" + /// + public static LocalisableString ShowMenuTips => new TranslatableString(getKey(@"show_menu_tips"), @"Menu tips"); + /// /// "Parallax" /// @@ -154,6 +159,6 @@ namespace osu.Game.Localisation /// public static LocalisableString TrueRandom => new TranslatableString(getKey(@"true_random"), @"True Random"); - private static string getKey(string key) => $"{prefix}:{key}"; + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs index 4577fadb01..5e42c3035c 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs @@ -29,6 +29,11 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface Children = new Drawable[] { + new SettingsCheckbox + { + LabelText = UserInterfaceStrings.ShowMenuTips, + Current = config.GetBindable(OsuSetting.MenuTips) + }, new SettingsCheckbox { LabelText = UserInterfaceStrings.InterfaceVoices, diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 539d58d2d7..1afef66313 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Screens; -using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.API; @@ -122,10 +121,6 @@ namespace osu.Game.Screens.Menu textFlow.NewParagraph(); textFlow.NewParagraph(); - textFlow.AddParagraph("today's tip:", formatSemiBold); - textFlow.AddParagraph(getRandomTip(), formatRegular); - textFlow.NewParagraph(); - textFlow.NewParagraph(); iconColour = colours.Yellow; @@ -228,30 +223,5 @@ namespace osu.Game.Screens.Menu this.Push(nextScreen); }); } - - private string getRandomTip() - { - string[] tips = - { - "You can press Ctrl-T anywhere in the game to toggle the toolbar!", - "You can press Ctrl-O anywhere in the game to access options!", - "All settings are dynamic and take effect in real-time. Try pausing and changing the skin while playing!", - "New features are coming online every update. Make sure to stay up-to-date!", - "If you find the UI too large or small, try adjusting UI scale in settings!", - "Try adjusting the \"Screen Scaling\" mode to change your gameplay or UI area, even in fullscreen!", - "What used to be \"osu!direct\" is available to all users just like on the website. You can access it anywhere using Ctrl-B!", - "Seeking in replays is available by dragging on the difficulty bar at the bottom of the screen!", - "Multithreading support means that even with low \"FPS\" your input and judgements will be accurate!", - "Try scrolling down in the mod select panel to find a bunch of new fun mods!", - "Most of the web content (profiles, rankings, etc.) are available natively in-game from the icons on the toolbar!", - "Get more details, hide or delete a beatmap by right-clicking on its panel at song select!", - "All delete operations are temporary until exiting. Restore accidentally deleted content from the maintenance settings!", - "Check out the \"playlists\" system, which lets users create their own custom and permanent leaderboards!", - "Toggle advanced frame / thread statistics with Ctrl-F11!", - "Take a look under the hood at performance counters and enable verbose performance logging with Ctrl-F2!", - }; - - return tips[RNG.Next(0, tips.Length)]; - } } } diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 0739689daa..cde7da53ce 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -95,6 +95,8 @@ namespace osu.Game.Screens.Menu private SongTicker songTicker; private Container logoTarget; private SystemTitle systemTitle; + private MenuTip menuTip; + private FillFlowContainer bottomElementsFlow; private Sample reappearSampleSwoosh; @@ -157,7 +159,27 @@ namespace osu.Game.Screens.Menu Margin = new MarginPadding { Right = 15, Top = 5 } }, new KiaiMenuFountains(), - systemTitle = new SystemTitle(), + bottomElementsFlow = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Spacing = new Vector2(15), + Children = new Drawable[] + { + menuTip = new MenuTip + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + systemTitle = new SystemTitle + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + } + } + }, holdToExitGameOverlay?.CreateProxy() ?? Empty() }); @@ -220,6 +242,8 @@ namespace osu.Game.Screens.Menu if (storage is OsuStorage osuStorage && osuStorage.Error != OsuStorageError.None) dialogOverlay?.Push(new StorageErrorDialog(osuStorage, osuStorage.Error)); + + menuTip.ShowNextTip(); } [CanBeNull] @@ -272,7 +296,7 @@ namespace osu.Game.Screens.Menu { base.Update(); - systemTitle.Margin = new MarginPadding + bottomElementsFlow.Margin = new MarginPadding { Bottom = (versionManager?.DrawHeight + 5) ?? 0 }; @@ -314,6 +338,10 @@ namespace osu.Game.Screens.Menu buttonsContainer.MoveTo(new Vector2(-800, 0), FADE_OUT_DURATION, Easing.InSine); sideFlashes.FadeOut(64, Easing.OutQuint); + + bottomElementsFlow + .ScaleTo(0.9f, 1000, Easing.OutQuint) + .FadeOut(500, Easing.OutQuint); } public override void OnResuming(ScreenTransitionEvent e) @@ -330,6 +358,12 @@ namespace osu.Game.Screens.Menu preloadSongSelect(); musicController.EnsurePlayingSomething(); + + menuTip.ShowNextTip(); + + bottomElementsFlow + .ScaleTo(1, 1000, Easing.OutQuint) + .FadeIn(1000, Easing.OutQuint); } public override bool OnExiting(ScreenExitEvent e) diff --git a/osu.Game/Screens/Menu/MenuTip.cs b/osu.Game/Screens/Menu/MenuTip.cs new file mode 100644 index 0000000000..c9c8fea1c1 --- /dev/null +++ b/osu.Game/Screens/Menu/MenuTip.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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Utils; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osuTK; + +namespace osu.Game.Screens.Menu +{ + public partial class MenuTip : CompositeDrawable + { + [Resolved] + private OsuConfigManager config { get; set; } = null!; + + private LinkFlowContainer textFlow = null!; + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + textFlow = new LinkFlowContainer + { + Width = 700, + AutoSizeAxes = Axes.Y, + TextAnchor = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Spacing = new Vector2(0, 2), + }, + }; + } + + public void ShowNextTip() + { + if (!config.Get(OsuSetting.MenuTips)) return; + + static void formatRegular(SpriteText t) => t.Font = OsuFont.GetFont(size: 20, weight: FontWeight.Regular); + static void formatSemiBold(SpriteText t) => t.Font = OsuFont.GetFont(size: 20, weight: FontWeight.SemiBold); + + string tip = getRandomTip(); + + AutoSizeAxes = Axes.Both; + + textFlow.Clear(); + textFlow.AddParagraph("a tip for you:", formatSemiBold); + textFlow.AddParagraph(tip, formatRegular); + + this.FadeInFromZero(200, Easing.OutQuint) + .Delay(1000 + 80 * tip.Length) + .Then() + .FadeOutFromOne(2000, Easing.OutQuint) + .Finally(_ => AutoSizeAxes = Axes.X); + } + + private string getRandomTip() + { + string[] tips = + { + "You can press Ctrl-T anywhere in the game to toggle the toolbar!", + "You can press Ctrl-O anywhere in the game to access options!", + "All settings are dynamic and take effect in real-time. Try changing the skin while watching autoplay!", + "New features are coming online every update. Make sure to stay up-to-date!", + "If you find the UI too large or small, try adjusting UI scale in settings!", + "Try adjusting the \"Screen Scaling\" mode to change your gameplay or UI area, even in fullscreen!", + "What used to be \"osu!direct\" is available to all users just like on the website. You can access it anywhere using Ctrl-B!", + "Seeking in replays is available by dragging on the difficulty bar at the bottom of the screen!", + "Multithreading support means that even with low \"FPS\" your input and judgements will be accurate!", + "Try scrolling down in the mod select panel to find a bunch of new fun mods!", + "Most of the web content (profiles, rankings, etc.) are available natively in-game from the icons on the toolbar!", + "Get more details, hide or delete a beatmap by right-clicking on its panel at song select!", + "All delete operations are temporary until exiting. Restore accidentally deleted content from the maintenance settings!", + "Check out the \"playlists\" system, which lets users create their own custom and permanent leaderboards!", + "Toggle advanced frame / thread statistics with Ctrl-F11!", + "Take a look under the hood at performance counters and enable verbose performance logging with Ctrl-F2!", + }; + + return tips[RNG.Next(0, tips.Length)]; + } + } +} diff --git a/osu.Game/Screens/Menu/SystemTitle.cs b/osu.Game/Screens/Menu/SystemTitle.cs index bb623cacdf..060e426f8c 100644 --- a/osu.Game/Screens/Menu/SystemTitle.cs +++ b/osu.Game/Screens/Menu/SystemTitle.cs @@ -31,8 +31,6 @@ namespace osu.Game.Screens.Menu [BackgroundDependencyLoader] private void load(OsuGame? game) { - Anchor = Anchor.BottomCentre; - Origin = Anchor.BottomCentre; AutoSizeAxes = Axes.Both; InternalChild = content = new OsuClickableContainer From 222459d921f886a7dd621057752a94442bc703d6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 16:16:27 +0900 Subject: [PATCH 33/42] Add background and improve layout --- osu.Game/Screens/Menu/MainMenu.cs | 2 +- osu.Game/Screens/Menu/MenuTip.cs | 32 ++++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index cde7da53ce..e8554d077b 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -165,7 +165,7 @@ namespace osu.Game.Screens.Menu Direction = FillDirection.Vertical, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - Spacing = new Vector2(15), + Spacing = new Vector2(5), Children = new Drawable[] { menuTip = new MenuTip diff --git a/osu.Game/Screens/Menu/MenuTip.cs b/osu.Game/Screens/Menu/MenuTip.cs index c9c8fea1c1..ac23162bd0 100644 --- a/osu.Game/Screens/Menu/MenuTip.cs +++ b/osu.Game/Screens/Menu/MenuTip.cs @@ -4,12 +4,14 @@ 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.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.Menu { @@ -27,14 +29,29 @@ namespace osu.Game.Screens.Menu InternalChildren = new Drawable[] { + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerExponent = 2.5f, + CornerRadius = 15, + Children = new Drawable[] + { + new Box + { + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + Alpha = 0.4f, + }, + } + }, textFlow = new LinkFlowContainer { - Width = 700, + Width = 600, AutoSizeAxes = Axes.Y, TextAnchor = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, Spacing = new Vector2(0, 2), + Margin = new MarginPadding(10) }, }; } @@ -43,13 +60,11 @@ namespace osu.Game.Screens.Menu { if (!config.Get(OsuSetting.MenuTips)) return; - static void formatRegular(SpriteText t) => t.Font = OsuFont.GetFont(size: 20, weight: FontWeight.Regular); - static void formatSemiBold(SpriteText t) => t.Font = OsuFont.GetFont(size: 20, weight: FontWeight.SemiBold); + static void formatRegular(SpriteText t) => t.Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular); + static void formatSemiBold(SpriteText t) => t.Font = OsuFont.GetFont(size: 16, weight: FontWeight.SemiBold); string tip = getRandomTip(); - AutoSizeAxes = Axes.Both; - textFlow.Clear(); textFlow.AddParagraph("a tip for you:", formatSemiBold); textFlow.AddParagraph(tip, formatRegular); @@ -57,8 +72,7 @@ namespace osu.Game.Screens.Menu this.FadeInFromZero(200, Easing.OutQuint) .Delay(1000 + 80 * tip.Length) .Then() - .FadeOutFromOne(2000, Easing.OutQuint) - .Finally(_ => AutoSizeAxes = Axes.X); + .FadeOutFromOne(2000, Easing.OutQuint); } private string getRandomTip() From 932d03a4f8aebf8b76d43fad4c7b8ffa17e0ae95 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 16:19:12 +0900 Subject: [PATCH 34/42] Make toggle more immediately hide/show tips --- osu.Game/Screens/Menu/MainMenu.cs | 3 +-- osu.Game/Screens/Menu/MenuTip.cs | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index e8554d077b..e3fc69dc2f 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -242,8 +242,6 @@ namespace osu.Game.Screens.Menu if (storage is OsuStorage osuStorage && osuStorage.Error != OsuStorageError.None) dialogOverlay?.Push(new StorageErrorDialog(osuStorage, osuStorage.Error)); - - menuTip.ShowNextTip(); } [CanBeNull] @@ -359,6 +357,7 @@ namespace osu.Game.Screens.Menu musicController.EnsurePlayingSomething(); + // Cycle tip on resuming menuTip.ShowNextTip(); bottomElementsFlow diff --git a/osu.Game/Screens/Menu/MenuTip.cs b/osu.Game/Screens/Menu/MenuTip.cs index ac23162bd0..325fb07767 100644 --- a/osu.Game/Screens/Menu/MenuTip.cs +++ b/osu.Game/Screens/Menu/MenuTip.cs @@ -2,6 +2,7 @@ // 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; @@ -22,6 +23,8 @@ namespace osu.Game.Screens.Menu private LinkFlowContainer textFlow = null!; + private Bindable showMenuTips = null!; + [BackgroundDependencyLoader] private void load() { @@ -56,9 +59,21 @@ namespace osu.Game.Screens.Menu }; } + protected override void LoadComplete() + { + base.LoadComplete(); + + showMenuTips = config.GetBindable(OsuSetting.MenuTips); + showMenuTips.BindValueChanged(_ => ShowNextTip(), true); + } + public void ShowNextTip() { - if (!config.Get(OsuSetting.MenuTips)) return; + if (!showMenuTips.Value) + { + this.FadeOut(100, Easing.OutQuint); + return; + } static void formatRegular(SpriteText t) => t.Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular); static void formatSemiBold(SpriteText t) => t.Font = OsuFont.GetFont(size: 16, weight: FontWeight.SemiBold); From 0ad6ac8b2a2866d5b26cb044110122cd4702cd8b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 16:48:17 +0900 Subject: [PATCH 35/42] Remove unused variable --- osu.Game/Screens/Menu/MainMenu.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index e3fc69dc2f..a90d9151b5 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -94,7 +94,6 @@ namespace osu.Game.Screens.Menu private ParallaxContainer buttonsContainer; private SongTicker songTicker; private Container logoTarget; - private SystemTitle systemTitle; private MenuTip menuTip; private FillFlowContainer bottomElementsFlow; @@ -173,7 +172,7 @@ namespace osu.Game.Screens.Menu Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, }, - systemTitle = new SystemTitle + new SystemTitle { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, From b19f72481b5d3cd1ad81458601aca0404a09d8fe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 17:19:41 +0900 Subject: [PATCH 36/42] Fade out quickly on game exit sequence --- osu.Game/Screens/Menu/MainMenu.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index a90d9151b5..bc19e9cb63 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -399,6 +399,10 @@ namespace osu.Game.Screens.Menu songTicker.Hide(); this.FadeOut(3000); + + bottomElementsFlow + .FadeOut(500, Easing.OutQuint); + return base.OnExiting(e); } From 1f2339244ef739341e3429d88678e512430a47d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 17:14:16 +0900 Subject: [PATCH 37/42] Add supporter display to main menu --- .../Visual/Menus/TestSceneSupporterDisplay.cs | 37 +++++ osu.Game/Screens/Menu/MainMenu.cs | 13 ++ osu.Game/Screens/Menu/SupporterDisplay.cs | 126 ++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 osu.Game.Tests/Visual/Menus/TestSceneSupporterDisplay.cs create mode 100644 osu.Game/Screens/Menu/SupporterDisplay.cs diff --git a/osu.Game.Tests/Visual/Menus/TestSceneSupporterDisplay.cs b/osu.Game.Tests/Visual/Menus/TestSceneSupporterDisplay.cs new file mode 100644 index 0000000000..8b18adbe0d --- /dev/null +++ b/osu.Game.Tests/Visual/Menus/TestSceneSupporterDisplay.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 NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Screens.Menu; + +namespace osu.Game.Tests.Visual.Menus +{ + public partial class TestSceneSupporterDisplay : OsuTestScene + { + [Test] + public void TestBasic() + { + AddStep("create display", () => + { + Child = new SupporterDisplay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + }); + + AddStep("toggle support", () => + { + ((DummyAPIAccess)API).LocalUser.Value = new APIUser + { + Username = API.LocalUser.Value.Username, + Id = API.LocalUser.Value.Id + 1, + IsSupporter = !API.LocalUser.Value.IsSupporter, + }; + }); + } + } +} diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index bc19e9cb63..401460a498 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -96,6 +96,7 @@ namespace osu.Game.Screens.Menu private Container logoTarget; private MenuTip menuTip; private FillFlowContainer bottomElementsFlow; + private SupporterDisplay supporterDisplay; private Sample reappearSampleSwoosh; @@ -179,6 +180,12 @@ namespace osu.Game.Screens.Menu } } }, + supporterDisplay = new SupporterDisplay + { + Margin = new MarginPadding(5), + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + }, holdToExitGameOverlay?.CreateProxy() ?? Empty() }); @@ -339,6 +346,9 @@ namespace osu.Game.Screens.Menu bottomElementsFlow .ScaleTo(0.9f, 1000, Easing.OutQuint) .FadeOut(500, Easing.OutQuint); + + supporterDisplay + .FadeOut(500, Easing.OutQuint); } public override void OnResuming(ScreenTransitionEvent e) @@ -403,6 +413,9 @@ namespace osu.Game.Screens.Menu bottomElementsFlow .FadeOut(500, Easing.OutQuint); + supporterDisplay + .FadeOut(500, Easing.OutQuint); + return base.OnExiting(e); } diff --git a/osu.Game/Screens/Menu/SupporterDisplay.cs b/osu.Game/Screens/Menu/SupporterDisplay.cs new file mode 100644 index 0000000000..d8ba21cd88 --- /dev/null +++ b/osu.Game/Screens/Menu/SupporterDisplay.cs @@ -0,0 +1,126 @@ +// 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.Extensions.IEnumerableExtensions; +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.Containers; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.Menu +{ + public partial class SupporterDisplay : CompositeDrawable + { + private LinkFlowContainer supportFlow = null!; + + private Drawable heart = null!; + + private readonly IBindable currentUser = new Bindable(); + + private Box backgroundBox = null!; + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + [BackgroundDependencyLoader] + private void load() + { + Height = 40; + + AutoSizeAxes = Axes.X; + AutoSizeDuration = 1000; + AutoSizeEasing = Easing.OutQuint; + + Masking = true; + CornerExponent = 2.5f; + CornerRadius = 15; + + InternalChildren = new Drawable[] + { + backgroundBox = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.4f, + }, + supportFlow = new LinkFlowContainer + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding(10), + Spacing = new Vector2(0, 2), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + const float font_size = 14; + + static void formatSemiBold(SpriteText t) => t.Font = OsuFont.GetFont(size: font_size, weight: FontWeight.SemiBold); + + currentUser.BindTo(api.LocalUser); + currentUser.BindValueChanged(e => + { + supportFlow.Children.ForEach(d => d.FadeOut().Expire()); + + if (e.NewValue.IsSupporter) + { + supportFlow.AddText("Eternal thanks to you for supporting osu!", formatSemiBold); + + backgroundBox.FadeColour(colours.Pink, 250); + } + else + { + supportFlow.AddText("Consider becoming an ", formatSemiBold); + supportFlow.AddLink("osu!supporter", "https://osu.ppy.sh/home/support", formatSemiBold); + supportFlow.AddText(" to help support osu!'s development", formatSemiBold); + + backgroundBox.FadeColour(colours.Pink4, 250); + } + + supportFlow.AddIcon(FontAwesome.Solid.Heart, t => + { + heart = t; + + t.Padding = new MarginPadding { Left = 5, Top = 1 }; + t.Font = t.Font.With(size: font_size); + t.Origin = Anchor.Centre; + t.Colour = colours.Pink; + + Schedule(() => + { + heart?.FlashColour(Color4.White, 750, Easing.OutQuint).Loop(); + }); + }); + }, true); + + this + .FadeOut() + .Delay(1000) + .FadeInFromZero(800, Easing.OutQuint); + + Scheduler.AddDelayed(() => + { + AutoSizeEasing = Easing.In; + supportFlow.BypassAutoSizeAxes = Axes.X; + this + .Delay(200) + .FadeOut(750, Easing.Out); + }, 6000); + } + } +} From 7dc50b9baf5e6268c84b4177d3f6b14bbaa99514 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 17:18:47 +0900 Subject: [PATCH 38/42] Don't dismiss on hover, and allow dismissing via click --- osu.Game/Screens/Menu/SupporterDisplay.cs | 43 ++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/SupporterDisplay.cs b/osu.Game/Screens/Menu/SupporterDisplay.cs index d8ba21cd88..6639300f4a 100644 --- a/osu.Game/Screens/Menu/SupporterDisplay.cs +++ b/osu.Game/Screens/Menu/SupporterDisplay.cs @@ -8,6 +8,8 @@ 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.Threading; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.API; @@ -113,8 +115,47 @@ namespace osu.Game.Screens.Menu .Delay(1000) .FadeInFromZero(800, Easing.OutQuint); - Scheduler.AddDelayed(() => + scheduleDismissal(); + } + + protected override bool OnClick(ClickEvent e) + { + dismissalDelegate?.Cancel(); + + supportFlow.BypassAutoSizeAxes = Axes.X; + this.FadeOut(500, Easing.OutQuint); + return base.OnClick(e); + } + + protected override bool OnHover(HoverEvent e) + { + backgroundBox.FadeTo(0.6f, 500, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + backgroundBox.FadeTo(0.4f, 500, Easing.OutQuint); + base.OnHoverLost(e); + } + + private ScheduledDelegate? dismissalDelegate; + + private void scheduleDismissal() + { + dismissalDelegate?.Cancel(); + dismissalDelegate = Scheduler.AddDelayed(() => { + // If the user is hovering they may want to interact with the link. + // Give them more time. + if (IsHovered) + { + scheduleDismissal(); + return; + } + + dismissalDelegate?.Cancel(); + AutoSizeEasing = Easing.In; supportFlow.BypassAutoSizeAxes = Axes.X; this From bd0e2b4dde99cd20d990959ba52965cc73099977 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 17:21:29 +0900 Subject: [PATCH 39/42] Remove disclaimer screen completely --- .../Visual/Menus/TestSceneDisclaimer.cs | 29 --- osu.Game/Screens/Loader.cs | 13 +- osu.Game/Screens/Menu/Disclaimer.cs | 227 ------------------ 3 files changed, 2 insertions(+), 267 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs delete mode 100644 osu.Game/Screens/Menu/Disclaimer.cs diff --git a/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs b/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs deleted file mode 100644 index fb82b0df80..0000000000 --- a/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs +++ /dev/null @@ -1,29 +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.Online.API; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Screens.Menu; - -namespace osu.Game.Tests.Visual.Menus -{ - public partial class TestSceneDisclaimer : ScreenTestScene - { - [BackgroundDependencyLoader] - private void load() - { - AddStep("load disclaimer", () => LoadScreen(new Disclaimer())); - - AddStep("toggle support", () => - { - ((DummyAPIAccess)API).LocalUser.Value = new APIUser - { - Username = API.LocalUser.Value.Username, - Id = API.LocalUser.Value.Id + 1, - IsSupporter = !API.LocalUser.Value.IsSupporter, - }; - }); - } - } -} diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index 372cfe748e..4dba512cbd 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -21,8 +21,6 @@ namespace osu.Game.Screens { public partial class Loader : StartupScreen { - private bool showDisclaimer; - public Loader() { ValidForResume = false; @@ -35,13 +33,7 @@ namespace osu.Game.Screens private LoadingSpinner spinner; private ScheduledDelegate spinnerShow; - protected virtual OsuScreen CreateLoadableScreen() - { - if (showDisclaimer) - return new Disclaimer(getIntroSequence()); - - return getIntroSequence(); - } + protected virtual OsuScreen CreateLoadableScreen() => getIntroSequence(); private IntroScreen getIntroSequence() { @@ -107,9 +99,8 @@ namespace osu.Game.Screens } [BackgroundDependencyLoader] - private void load(OsuGameBase game, OsuConfigManager config) + private void load(OsuConfigManager config) { - showDisclaimer = game.IsDeployedBuild; introSequence = config.Get(OsuSetting.IntroSequence); } diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs deleted file mode 100644 index 1afef66313..0000000000 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ /dev/null @@ -1,227 +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 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.Sprites; -using osu.Framework.Screens; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests.Responses; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Menu -{ - public partial class Disclaimer : StartupScreen - { - private SpriteIcon icon; - private Color4 iconColour; - private LinkFlowContainer textFlow; - private LinkFlowContainer supportFlow; - - private Drawable heart; - - private const float icon_y = -85; - private const float icon_size = 30; - - private readonly OsuScreen nextScreen; - - private readonly Bindable currentUser = new Bindable(); - private FillFlowContainer fill; - - private readonly List expendableText = new List(); - - public Disclaimer(OsuScreen nextScreen = null) - { - this.nextScreen = nextScreen; - ValidForResume = false; - } - - [Resolved] - private IAPIProvider api { get; set; } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - InternalChildren = new Drawable[] - { - icon = new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Icon = OsuIcon.Logo, - Size = new Vector2(icon_size), - Y = icon_y, - }, - fill = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Y = icon_y, - Anchor = Anchor.Centre, - Origin = Anchor.TopCentre, - Children = new Drawable[] - { - textFlow = new LinkFlowContainer - { - Width = 680, - AutoSizeAxes = Axes.Y, - TextAnchor = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Spacing = new Vector2(0, 2), - }, - } - }, - supportFlow = new LinkFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - TextAnchor = Anchor.BottomCentre, - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Padding = new MarginPadding(20), - Alpha = 0, - Spacing = new Vector2(0, 2), - }, - }; - - textFlow.AddText("this is osu!", t => t.Font = t.Font.With(Typeface.Torus, 30, FontWeight.Regular)); - - expendableText.Add(textFlow.AddText("lazer", t => - { - t.Font = t.Font.With(Typeface.Torus, 30, FontWeight.Regular); - t.Colour = colours.PinkLight; - })); - - static void formatRegular(SpriteText t) => t.Font = OsuFont.GetFont(size: 20, weight: FontWeight.Regular); - static void formatSemiBold(SpriteText t) => t.Font = OsuFont.GetFont(size: 20, weight: FontWeight.SemiBold); - - textFlow.NewParagraph(); - - textFlow.AddText("the next ", formatRegular); - textFlow.AddText("major update", t => - { - t.Font = t.Font.With(Typeface.Torus, 20, FontWeight.SemiBold); - t.Colour = colours.Pink; - }); - expendableText.Add(textFlow.AddText(" coming to osu!", formatRegular)); - textFlow.AddText(".", formatRegular); - - textFlow.NewParagraph(); - textFlow.NewParagraph(); - - textFlow.NewParagraph(); - - iconColour = colours.Yellow; - - // manually transfer the user once, but only do the final bind in LoadComplete to avoid thread woes (API scheduler could run while this screen is still loading). - // the manual transfer is here to ensure all text content is loaded ahead of time as this is very early in the game load process and we want to avoid stutters. - currentUser.Value = api.LocalUser.Value; - currentUser.BindValueChanged(e => - { - supportFlow.Children.ForEach(d => d.FadeOut().Expire()); - - if (e.NewValue.IsSupporter) - { - supportFlow.AddText("Eternal thanks to you for supporting osu!", formatSemiBold); - } - else - { - supportFlow.AddText("Consider becoming an ", formatSemiBold); - supportFlow.AddLink("osu!supporter", "https://osu.ppy.sh/home/support", formatSemiBold); - supportFlow.AddText(" to help support osu!'s development", formatSemiBold); - } - - supportFlow.AddIcon(FontAwesome.Solid.Heart, t => - { - heart = t; - - t.Padding = new MarginPadding { Left = 5, Top = 3 }; - t.Font = t.Font.With(size: 20); - t.Origin = Anchor.Centre; - t.Colour = colours.Pink; - - Schedule(() => heart?.FlashColour(Color4.White, 750, Easing.OutQuint).Loop()); - }); - - if (supportFlow.IsPresent) - supportFlow.FadeInFromZero(500); - }, true); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - if (nextScreen != null) - LoadComponentAsync(nextScreen); - - ((IBindable)currentUser).BindTo(api.LocalUser); - } - - public override void OnSuspending(ScreenTransitionEvent e) - { - base.OnSuspending(e); - - // Once this screen has finished being displayed, we don't want to unnecessarily handle user change events. - currentUser.UnbindAll(); - } - - public override void OnEntering(ScreenTransitionEvent e) - { - base.OnEntering(e); - - icon.RotateTo(10); - icon.FadeOut(); - icon.ScaleTo(0.5f); - - icon.Delay(500).FadeIn(500).ScaleTo(1, 500, Easing.OutQuint); - - using (BeginDelayedSequence(3000)) - { - icon.FadeColour(iconColour, 200, Easing.OutQuint); - icon.MoveToY(icon_y * 1.3f, 500, Easing.OutCirc) - .RotateTo(-360, 520, Easing.OutQuint) - .Then() - .MoveToY(icon_y, 160, Easing.InQuart) - .FadeColour(Color4.White, 160); - - using (BeginDelayedSequence(520 + 160)) - { - fill.MoveToOffset(new Vector2(0, 15), 160, Easing.OutQuart); - Schedule(() => expendableText.SelectMany(t => t.Drawables).ForEach(t => - { - t.FadeOut(100); - t.ScaleTo(new Vector2(0, 1), 100, Easing.OutQuart); - })); - } - } - - supportFlow.FadeOut().Delay(2000).FadeIn(500); - double delay = 500; - foreach (var c in textFlow.Children) - c.FadeTo(0.001f).Delay(delay += 20).FadeIn(500); - - this - .FadeInFromZero(500) - .Then(5500) - .FadeOut(250) - .ScaleTo(0.9f, 250, Easing.InQuint) - .Finally(_ => - { - if (nextScreen != null) - this.Push(nextScreen); - }); - } - } -} From 2ec9343868693f45f7650e2209271b157222d973 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 17:35:10 +0900 Subject: [PATCH 40/42] Add the ability to spectate a user by right clicking their user panel --- osu.Game/Localisation/ContextMenuStrings.cs | 9 +++-- osu.Game/Users/UserPanel.cs | 39 +++++++++++++-------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/osu.Game/Localisation/ContextMenuStrings.cs b/osu.Game/Localisation/ContextMenuStrings.cs index 029fba67d8..cb18a2159c 100644 --- a/osu.Game/Localisation/ContextMenuStrings.cs +++ b/osu.Game/Localisation/ContextMenuStrings.cs @@ -20,9 +20,14 @@ namespace osu.Game.Localisation public static LocalisableString ViewBeatmap => new TranslatableString(getKey(@"view_beatmap"), @"View beatmap"); /// - /// "Invite player" + /// "Invite to room" /// - public static LocalisableString InvitePlayer => new TranslatableString(getKey(@"invite_player"), @"Invite player"); + public static LocalisableString InvitePlayer => new TranslatableString(getKey(@"invite_player"), @"Invite to room"); + + /// + /// "Spectate" + /// + public static LocalisableString SpectatePlayer => new TranslatableString(getKey(@"spectate_player"), @"Spectate"); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 273faf9bd1..b6a77e754d 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -13,6 +13,7 @@ using osu.Game.Overlays; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; using osu.Framework.Graphics.Cursor; +using osu.Framework.Screens; using osu.Game.Graphics.Containers; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; @@ -20,6 +21,8 @@ using osu.Game.Online.Chat; using osu.Game.Resources.Localisation.Web; using osu.Game.Localisation; using osu.Game.Online.Multiplayer; +using osu.Game.Screens; +using osu.Game.Screens.Play; namespace osu.Game.Users { @@ -60,6 +63,9 @@ namespace osu.Game.Users [Resolved] protected OverlayColourProvider? ColourProvider { get; private set; } + [Resolved] + private IPerformFromScreenRunner? performer { get; set; } + [Resolved] protected OsuColour Colours { get; private set; } = null!; @@ -113,23 +119,26 @@ namespace osu.Game.Users new OsuMenuItem(ContextMenuStrings.ViewProfile, MenuItemType.Highlighted, ViewProfile) }; - if (!User.Equals(api.LocalUser.Value)) - { - items.Add(new OsuMenuItem(UsersStrings.CardSendMessage, MenuItemType.Standard, () => - { - channelManager?.OpenPrivateChannel(User); - chatOverlay?.Show(); - })); - } + if (User.Equals(api.LocalUser.Value)) + return items.ToArray(); - if ( - // TODO: uncomment this once lazer / osu-web is updating online states - // User.IsOnline && - multiplayerClient?.Room != null && - multiplayerClient.Room.Users.All(u => u.UserID != User.Id) - ) + items.Add(new OsuMenuItem(UsersStrings.CardSendMessage, MenuItemType.Standard, () => { - items.Add(new OsuMenuItem(ContextMenuStrings.InvitePlayer, MenuItemType.Standard, () => multiplayerClient.InvitePlayer(User.Id))); + channelManager?.OpenPrivateChannel(User); + chatOverlay?.Show(); + })); + + if (User.IsOnline) + { + items.Add(new OsuMenuItem(ContextMenuStrings.SpectatePlayer, MenuItemType.Standard, () => + { + performer?.PerformFromScreen(s => s.Push(new SoloSpectatorScreen(User))); + })); + + if (multiplayerClient?.Room?.Users.All(u => u.UserID != User.Id) == true) + { + items.Add(new OsuMenuItem(ContextMenuStrings.InvitePlayer, MenuItemType.Standard, () => multiplayerClient.InvitePlayer(User.Id))); + } } return items.ToArray(); From 22eced33006f959af2bc17198eafd46779a4923b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 17:40:07 +0900 Subject: [PATCH 41/42] Show local user in online users --- osu.Game/Overlays/Dashboard/CurrentlyOnlineDisplay.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Overlays/Dashboard/CurrentlyOnlineDisplay.cs b/osu.Game/Overlays/Dashboard/CurrentlyOnlineDisplay.cs index 37ea3f9c38..ee277ff538 100644 --- a/osu.Game/Overlays/Dashboard/CurrentlyOnlineDisplay.cs +++ b/osu.Game/Overlays/Dashboard/CurrentlyOnlineDisplay.cs @@ -131,9 +131,6 @@ namespace osu.Game.Overlays.Dashboard { int userId = kvp.Key; - if (userId == api.LocalUser.Value.Id) - continue; - users.GetUserAsync(userId).ContinueWith(task => { APIUser user = task.GetResultSafely(); From e1a376c0a742d958399734683c8eb79631f37add Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2023 20:13:19 +0900 Subject: [PATCH 42/42] Fix using "Back" binding at spectator fail screen not working --- osu.Game/Screens/Play/GameplayMenuOverlay.cs | 10 +++++++++- osu.Game/Screens/Play/PauseOverlay.cs | 8 +++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index 0680842891..440b8d37b9 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -44,7 +44,15 @@ namespace osu.Game.Screens.Play /// /// Action that is invoked when is triggered. /// - protected virtual Action BackAction => () => InternalButtons.LastOrDefault()?.TriggerClick(); + protected virtual Action BackAction => () => + { + // We prefer triggering the button click as it will animate... + // but sometimes buttons aren't present (see FailOverlay's constructor as an example). + if (Buttons.Any()) + Buttons.Last().TriggerClick(); + else + OnQuit?.Invoke(); + }; /// /// Action that is invoked when is triggered. diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs index 88561ada71..2aa2793fd4 100644 --- a/osu.Game/Screens/Play/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -29,7 +29,13 @@ namespace osu.Game.Screens.Play private SkinnableSound pauseLoop; - protected override Action BackAction => () => InternalButtons.First().TriggerClick(); + protected override Action BackAction => () => + { + if (Buttons.Any()) + Buttons.First().TriggerClick(); + else + OnResume?.Invoke(); + }; [BackgroundDependencyLoader] private void load(OsuColour colours)