diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs index 6ecbf58a52..a4b2b26624 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Catch.Tests }); } - private class TestSkin : DefaultSkin + private class TestSkin : TrianglesSkin { public bool FlipCatcherPlate { get; set; } diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs index 0630de9156..8f46bdbe6e 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy [BackgroundDependencyLoader] private void load(SkinManager skins) { - var defaultLegacySkin = skins.DefaultLegacySkin; + var defaultLegacySkin = skins.DefaultClassicSkin; // sprite names intentionally swapped to match stable member naming / ease of cross-referencing explosion1.Texture = defaultLegacySkin.GetTexture("scoreboard-explosion-2"); diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs index 0354228cca..e96a186ae4 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor [Test] public void TestDefaultSkin() { - AddStep("set default skin", () => skins.CurrentSkinInfo.Value = DefaultSkin.CreateInfo().ToLiveUnmanaged()); + AddStep("set default skin", () => skins.CurrentSkinInfo.Value = TrianglesSkin.CreateInfo().ToLiveUnmanaged()); } [Test] diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs index b5d1c4854c..7f0ecaca2b 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs @@ -170,7 +170,7 @@ namespace osu.Game.Rulesets.Osu.Tests }); AddStep("setup default legacy skin", () => { - skinManager.CurrentSkinInfo.Value = skinManager.DefaultLegacySkin.SkinInfo; + skinManager.CurrentSkinInfo.Value = skinManager.DefaultClassicSkin.SkinInfo; }); }); } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs index 0cf2ec6b7e..57734236da 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Tests hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - Child = new SkinProvidingContainer(new DefaultSkin(null)) + Child = new SkinProvidingContainer(new TrianglesSkin(null)) { RelativeSizeAxes = Axes.Both, Child = drawableHitCircle = new DrawableHitCircle(hitCircle) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 33787da8f6..1e83d6d820 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -44,6 +44,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1; + if (mods.Any(m => m is OsuModTouchDevice)) + { + aimRating = Math.Pow(aimRating, 0.8); + flashlightRating = Math.Pow(flashlightRating, 0.8); + } + if (mods.Any(h => h is OsuModRelax)) { aimRating *= 0.9; @@ -127,6 +133,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty protected override Mod[] DifficultyAdjustmentMods => new Mod[] { + new OsuModTouchDevice(), new OsuModDoubleTime(), new OsuModHalfTime(), new OsuModEasy(), diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index fb0eff5cb2..30b56ff769 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -88,12 +88,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty private double computeAimValue(ScoreInfo score, OsuDifficultyAttributes attributes) { - double rawAim = attributes.AimDifficulty; - - if (score.Mods.Any(m => m is OsuModTouchDevice)) - rawAim = Math.Pow(rawAim, 0.8); - - double aimValue = Math.Pow(5.0 * Math.Max(1.0, rawAim / 0.0675) - 4.0, 3.0) / 100000.0; + double aimValue = Math.Pow(5.0 * Math.Max(1.0, attributes.AimDifficulty / 0.0675) - 4.0, 3.0) / 100000.0; double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); @@ -233,12 +228,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (!score.Mods.Any(h => h is OsuModFlashlight)) return 0.0; - double rawFlashlight = attributes.FlashlightDifficulty; - - if (score.Mods.Any(m => m is OsuModTouchDevice)) - rawFlashlight = Math.Pow(rawFlashlight, 0.8); - - double flashlightValue = Math.Pow(rawFlashlight, 2.0) * 25.0; + double flashlightValue = Math.Pow(attributes.FlashlightDifficulty, 2.0) * 25.0; // Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses. if (effectiveMissCount > 0) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 9fc1eb7650..fdd0167ed3 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -306,7 +306,7 @@ namespace osu.Game.Tests.Beatmaps.Formats new Color4(128, 255, 128, 255), new Color4(255, 187, 255, 255), new Color4(255, 177, 140, 255), - new Color4(100, 100, 100, 100), + new Color4(100, 100, 100, 255), // alpha is specified as 100, but should be ignored. }; Assert.AreEqual(expectedColors.Length, comboColors.Count); for (int i = 0; i < expectedColors.Length; i++) diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index c3c10215a5..3cbc205eaf 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -202,7 +202,7 @@ namespace osu.Game.Tests.Skins.IO skinManager.CurrentSkinInfo.Value.PerformRead(s => { Assert.IsFalse(s.Protected); - Assert.AreEqual(typeof(DefaultSkin), s.CreateInstance(skinManager).GetType()); + Assert.AreEqual(typeof(TrianglesSkin), s.CreateInstance(skinManager).GetType()); new LegacySkinExporter(osu.Dependencies.Get()).ExportModelTo(s, exportStream); @@ -215,7 +215,7 @@ namespace osu.Game.Tests.Skins.IO { Assert.IsFalse(s.Protected); Assert.AreNotEqual(originalSkinId, s.ID); - Assert.AreEqual(typeof(DefaultSkin), s.CreateInstance(skinManager).GetType()); + Assert.AreEqual(typeof(TrianglesSkin), s.CreateInstance(skinManager).GetType()); }); return Task.CompletedTask; @@ -226,7 +226,7 @@ namespace osu.Game.Tests.Skins.IO { var skinManager = osu.Dependencies.Get(); - skinManager.CurrentSkinInfo.Value = skinManager.DefaultLegacySkin.SkinInfo; + skinManager.CurrentSkinInfo.Value = skinManager.DefaultClassicSkin.SkinInfo; skinManager.EnsureMutableSkin(); diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs index 419eb87b1a..6756f27ecd 100644 --- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs +++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs @@ -29,7 +29,7 @@ namespace osu.Game.Tests.Skins new Color4(142, 199, 255, 255), new Color4(255, 128, 128, 255), new Color4(128, 255, 255, 255), - new Color4(100, 100, 100, 100), + new Color4(100, 100, 100, 255), // alpha is specified as 100, but should be ignored. }; Assert.AreEqual(expectedColors.Count, comboColors.Count); diff --git a/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs b/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs index 3ecf560eb1..ea4aa98f86 100644 --- a/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs +++ b/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs @@ -1,12 +1,11 @@ // 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 NUnit.Framework; using osu.Framework.Graphics; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; +using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay { @@ -19,7 +18,7 @@ namespace osu.Game.Tests.Visual.Gameplay { SetContents(skin => { - var implementation = skin != null + var implementation = skin is LegacySkin ? CreateLegacyImplementation() : CreateDefaultImplementation(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index e12be6d3b4..01cc856a4a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestEmptyLegacyBeatmapSkinFallsBack() { - CreateSkinTest(DefaultSkin.CreateInfo(), () => new LegacyBeatmapSkin(new BeatmapInfo(), null)); + CreateSkinTest(TrianglesSkin.CreateInfo(), () => new LegacyBeatmapSkin(new BeatmapInfo(), null)); AddUntilStep("wait for hud load", () => Player.ChildrenOfType().All(c => c.ComponentsLoaded)); AddAssert("hud from default skin", () => AssertComponentsFromExpectedSource(SkinnableTarget.MainHUDComponents, skinManager.CurrentSkin.Value)); } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs index 26706d9465..66441c8bad 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs @@ -79,7 +79,7 @@ namespace osu.Game.Tests.Visual.Gameplay } private TestParticleSpewer createSpewer() => - new TestParticleSpewer(skinManager.DefaultLegacySkin.GetTexture("star2")) + new TestParticleSpewer(skinManager.DefaultClassicSkin.GetTexture("star2")) { Origin = Anchor.Centre, RelativePositionAxes = Axes.Both, diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs b/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs index 4ca55e8744..3757c49f18 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs @@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Navigation [Test] public void TestEditDefaultSkin() { - AddAssert("is default skin", () => skinManager.CurrentSkinInfo.Value.ID == SkinInfo.DEFAULT_SKIN); + AddAssert("is default skin", () => skinManager.CurrentSkinInfo.Value.ID == SkinInfo.TRIANGLES_SKIN); AddStep("open settings", () => { Game.Settings.Show(); }); @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("open skin editor", () => skinEditor.Show()); // Until step required as the skin editor may take time to load (and an extra scheduled frame for the mutable part). - AddUntilStep("is modified default skin", () => skinManager.CurrentSkinInfo.Value.ID != SkinInfo.DEFAULT_SKIN); + AddUntilStep("is modified default skin", () => skinManager.CurrentSkinInfo.Value.ID != SkinInfo.TRIANGLES_SKIN); AddAssert("is not protected", () => skinManager.CurrentSkinInfo.Value.PerformRead(s => !s.Protected)); AddUntilStep("export button enabled", () => Game.Settings.ChildrenOfType().SingleOrDefault()?.Enabled.Value == true); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index c8126d883c..b314d95597 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -34,6 +34,8 @@ namespace osu.Game.Tests.Visual.UserInterface [SetUp] public void SetUp() => Schedule(() => { + InputManager.MoveMouseTo(Vector2.Zero); + TimeToCompleteProgress = 2000; progressingNotifications.Clear(); @@ -230,6 +232,31 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("wait overlay not present", () => !notificationOverlay.IsPresent); } + [Test] + public void TestProgressClick() + { + ProgressNotification notification = null!; + + AddStep("add progress notification", () => + { + notification = new ProgressNotification + { + Text = @"Uploading to BSS...", + CompletionText = "Uploaded to BSS!", + }; + notificationOverlay.Post(notification); + progressingNotifications.Add(notification); + }); + + AddStep("hover over notification", () => InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType().Single())); + + AddStep("left click", () => InputManager.Click(MouseButton.Left)); + AddAssert("not cancelled", () => notification.State == ProgressNotificationState.Active); + + AddStep("right click", () => InputManager.Click(MouseButton.Right)); + AddAssert("cancelled", () => notification.State == ProgressNotificationState.Cancelled); + } + [Test] public void TestCompleteProgress() { @@ -301,7 +328,7 @@ namespace osu.Game.Tests.Visual.UserInterface { SimpleNotification notification = null!; AddStep(@"post", () => notificationOverlay.Post(notification = new BackgroundNotification { Text = @"Welcome to osu!. Enjoy your stay!" })); - AddUntilStep("check is toast", () => !notification.IsInToastTray); + AddUntilStep("check is toast", () => notification.IsInToastTray); AddAssert("light is not visible", () => notification.ChildrenOfType().Single().Alpha == 0); AddUntilStep("wait for forward to overlay", () => !notification.IsInToastTray); diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 3d65ab8e0f..9c066ada08 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -79,7 +79,7 @@ namespace osu.Game.Beatmaps.Formats switch (section) { case Section.Colours: - HandleColours(output, line); + HandleColours(output, line, false); return; } } @@ -93,7 +93,7 @@ namespace osu.Game.Beatmaps.Formats return line; } - protected void HandleColours(TModel output, string line) + protected void HandleColours(TModel output, string line, bool allowAlpha) { var pair = SplitKeyVal(line); @@ -108,7 +108,7 @@ namespace osu.Game.Beatmaps.Formats try { - byte alpha = split.Length == 4 ? byte.Parse(split[3]) : (byte)255; + byte alpha = allowAlpha && split.Length == 4 ? byte.Parse(split[3]) : (byte)255; colour = new Color4(byte.Parse(split[0]), byte.Parse(split[1]), byte.Parse(split[2]), alpha); } catch diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 5f49557685..54c545e367 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -39,7 +39,7 @@ namespace osu.Game.Configuration { // UI/selection defaults SetDefault(OsuSetting.Ruleset, string.Empty); - SetDefault(OsuSetting.Skin, SkinInfo.DEFAULT_SKIN.ToString()); + SetDefault(OsuSetting.Skin, SkinInfo.TRIANGLES_SKIN.ToString()); SetDefault(OsuSetting.BeatmapDetailTab, PlayBeatmapDetailArea.TabType.Details); SetDefault(OsuSetting.BeatmapDetailModsFilter, false); diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index cefc7da503..edcd020226 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -69,8 +69,9 @@ namespace osu.Game.Database /// 22 2022-07-31 Added ModPreset. /// 23 2022-08-01 Added LastLocalUpdate to BeatmapInfo. /// 24 2022-08-22 Added MaximumStatistics to ScoreInfo. + /// 25 2022-09-18 Remove skins to add with new naming. /// - private const int schema_version = 24; + private const int schema_version = 25; /// /// Lock object which is held during sections, blocking realm retrieval during blocking periods. @@ -870,6 +871,11 @@ namespace osu.Game.Database } break; + + case 25: + // Remove the default skins so they can be added back by SkinManager with updated naming. + migration.NewRealm.RemoveRange(migration.NewRealm.All().Where(s => s.Protected)); + break; } } diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 4e7cebf0ae..ea654e1272 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -229,8 +229,8 @@ namespace osu.Game.Overlays.Notifications protected override bool OnClick(ClickEvent e) { // Clicking with anything but left button should dismiss but not perform the activation action. - if (e.Button == MouseButton.Left) - Activated?.Invoke(); + if (e.Button == MouseButton.Left && Activated?.Invoke() == false) + return true; Close(false); return true; diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 4787b07af8..8d491a980a 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -78,8 +78,7 @@ namespace osu.Game.Overlays.Settings.Sections realmSubscription = realm.RegisterForNotifications(_ => realm.Realm.All() .Where(s => !s.DeletePending) - .OrderByDescending(s => s.Protected) // protected skins should be at the top. - .ThenBy(s => s.Name, StringComparer.OrdinalIgnoreCase), skinsChanged); + .OrderBy(s => s.Name, StringComparer.OrdinalIgnoreCase), skinsChanged); skinDropdown.Current.BindValueChanged(skin => { @@ -101,14 +100,17 @@ namespace osu.Game.Overlays.Settings.Sections if (!sender.Any()) return; - int protectedCount = sender.Count(s => s.Protected); - // For simplicity repopulate the full list. // In the future we should change this to properly handle ChangeSet events. dropdownItems.Clear(); - foreach (var skin in sender) + + dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.TRIANGLES_SKIN).ToLive(realm)); + dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.CLASSIC_SKIN).ToLive(realm)); + + dropdownItems.Add(random_skin_info); + + foreach (var skin in sender.Where(s => !s.Protected)) dropdownItems.Add(skin.ToLive(realm)); - dropdownItems.Insert(protectedCount, random_skin_info); Schedule(() => skinDropdown.Items = dropdownItems); } diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index c794c768c6..dbc4e2b2e1 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -130,7 +130,7 @@ namespace osu.Game.Screens.Backgrounds case BackgroundSource.Skin: // default skins should use the default background rotation, which won't be the case if a SkinBackground is created for them. - if (skin.Value is DefaultSkin || skin.Value is DefaultLegacySkin) + if (skin.Value is TrianglesSkin || skin.Value is DefaultLegacySkin) break; newBackground = new SkinBackground(skin.Value, getBackgroundTextureName()); diff --git a/osu.Game/Skinning/DefaultLegacySkin.cs b/osu.Game/Skinning/DefaultLegacySkin.cs index 2ebcc98c53..04f1286dc7 100644 --- a/osu.Game/Skinning/DefaultLegacySkin.cs +++ b/osu.Game/Skinning/DefaultLegacySkin.cs @@ -17,7 +17,7 @@ namespace osu.Game.Skinning public static SkinInfo CreateInfo() => new SkinInfo { ID = Skinning.SkinInfo.CLASSIC_SKIN, // this is temporary until database storage is decided upon. - Name = "osu!classic", + Name = "osu! \"classic\" (2013)", Creator = "team osu!", Protected = true, InstantiationInfo = typeof(DefaultLegacySkin).GetInvariantInstantiationInfo() diff --git a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs index 49914c53aa..0aafdd4db0 100644 --- a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs +++ b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs @@ -121,7 +121,7 @@ namespace osu.Game.Skinning break; case string when pair.Key.StartsWith("Colour", StringComparison.Ordinal): - HandleColours(currentConfig, line); + HandleColours(currentConfig, line, true); break; // Custom sprite paths diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs index e5f87b3230..11c21d432f 100644 --- a/osu.Game/Skinning/LegacySkinDecoder.cs +++ b/osu.Game/Skinning/LegacySkinDecoder.cs @@ -48,7 +48,7 @@ namespace osu.Game.Skinning // osu!catch section only has colour settings // so no harm in handling the entire section case Section.CatchTheBeat: - HandleColours(skin, line); + HandleColours(skin, line, true); return; } diff --git a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs index d5690710bb..4c35681f66 100644 --- a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs +++ b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs @@ -81,7 +81,7 @@ namespace osu.Game.Skinning } } - int lastDefaultSkinIndex = sources.IndexOf(sources.OfType().LastOrDefault()); + int lastDefaultSkinIndex = sources.IndexOf(sources.OfType().LastOrDefault()); // Ruleset resources should be given the ability to override game-wide defaults // This is achieved by placing them before the last instance of DefaultSkin. diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs index f270abd163..701dcdfc2d 100644 --- a/osu.Game/Skinning/SkinImporter.cs +++ b/osu.Game/Skinning/SkinImporter.cs @@ -232,6 +232,9 @@ namespace osu.Game.Skinning { skin.SkinInfo.PerformWrite(s => { + // Update for safety + s.InstantiationInfo = skin.GetType().GetInvariantInstantiationInfo(); + // Serialise out the SkinInfo itself. string skinInfoJson = JsonConvert.SerializeObject(s, new JsonSerializerSettings { Formatting = Formatting.Indented }); diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs index bf3cf77257..04d1216ed6 100644 --- a/osu.Game/Skinning/SkinInfo.cs +++ b/osu.Game/Skinning/SkinInfo.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using JetBrains.Annotations; using Newtonsoft.Json; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Testing; using osu.Game.Database; using osu.Game.IO; @@ -19,7 +18,7 @@ namespace osu.Game.Skinning [JsonObject(MemberSerialization.OptIn)] public class SkinInfo : RealmObject, IHasRealmFiles, IEquatable, IHasGuidPrimaryKey, ISoftDelete, IHasNamedFiles { - internal static readonly Guid DEFAULT_SKIN = new Guid("2991CFD8-2140-469A-BCB9-2EC23FBCE4AD"); + internal static readonly Guid TRIANGLES_SKIN = new Guid("2991CFD8-2140-469A-BCB9-2EC23FBCE4AD"); internal static readonly Guid CLASSIC_SKIN = new Guid("81F02CD3-EEC6-4865-AC23-FAE26A386187"); internal static readonly Guid RANDOM_SKIN = new Guid("D39DFEFB-477C-4372-B1EA-2BCEA5FB8908"); @@ -45,7 +44,16 @@ namespace osu.Game.Skinning var type = string.IsNullOrEmpty(InstantiationInfo) // handle the case of skins imported before InstantiationInfo was added. ? typeof(LegacySkin) - : Type.GetType(InstantiationInfo).AsNonNull(); + : Type.GetType(InstantiationInfo); + + if (type == null) + { + // Since the class was renamed from "DefaultSkin" to "TrianglesSkin", the type retrieval would fail + // for user modified skins. This aims to amicably handle that. + // If we ever add more default skins in the future this will need some kind of proper migration rather than + // a single fallback. + return new TrianglesSkin(this, resources); + } return (Skin)Activator.CreateInstance(type, this, resources); } diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 7ffea3b54f..a9a01dfebf 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -49,9 +49,9 @@ namespace osu.Game.Skinning public readonly Bindable CurrentSkin = new Bindable(); - public readonly Bindable> CurrentSkinInfo = new Bindable>(Skinning.DefaultSkin.CreateInfo().ToLiveUnmanaged()) + public readonly Bindable> CurrentSkinInfo = new Bindable>(TrianglesSkin.CreateInfo().ToLiveUnmanaged()) { - Default = Skinning.DefaultSkin.CreateInfo().ToLiveUnmanaged() + Default = TrianglesSkin.CreateInfo().ToLiveUnmanaged() }; private readonly SkinImporter skinImporter; @@ -59,14 +59,14 @@ namespace osu.Game.Skinning private readonly IResourceStore userFiles; /// - /// The default skin. + /// The default "triangles" skin. /// - public Skin DefaultSkin { get; } + public Skin DefaultSkinTriangles { get; } /// - /// The default legacy skin. + /// The default "classic" skin. /// - public Skin DefaultLegacySkin { get; } + public Skin DefaultClassicSkin { get; } public SkinManager(Storage storage, RealmAccess realm, GameHost host, IResourceStore resources, AudioManager audio, Scheduler scheduler) : base(storage, realm) @@ -85,8 +85,8 @@ namespace osu.Game.Skinning var defaultSkins = new[] { - DefaultLegacySkin = new DefaultLegacySkin(this), - DefaultSkin = new DefaultSkin(this), + DefaultClassicSkin = new DefaultLegacySkin(this), + DefaultSkinTriangles = new TrianglesSkin(this), }; // Ensure the default entries are present. @@ -104,7 +104,7 @@ namespace osu.Game.Skinning CurrentSkin.Value = skin.NewValue.PerformRead(GetSkin); }; - CurrentSkin.Value = DefaultSkin; + CurrentSkin.Value = DefaultSkinTriangles; CurrentSkin.ValueChanged += skin => { if (!skin.NewValue.SkinInfo.Equals(CurrentSkinInfo.Value)) @@ -125,7 +125,7 @@ namespace osu.Game.Skinning if (randomChoices.Length == 0) { - CurrentSkinInfo.Value = Skinning.DefaultSkin.CreateInfo().ToLiveUnmanaged(); + CurrentSkinInfo.Value = TrianglesSkin.CreateInfo().ToLiveUnmanaged(); return; } @@ -229,11 +229,11 @@ namespace osu.Game.Skinning { yield return CurrentSkin.Value; - if (CurrentSkin.Value is LegacySkin && CurrentSkin.Value != DefaultLegacySkin) - yield return DefaultLegacySkin; + if (CurrentSkin.Value is LegacySkin && CurrentSkin.Value != DefaultClassicSkin) + yield return DefaultClassicSkin; - if (CurrentSkin.Value != DefaultSkin) - yield return DefaultSkin; + if (CurrentSkin.Value != DefaultSkinTriangles) + yield return DefaultSkinTriangles; } } @@ -294,7 +294,7 @@ namespace osu.Game.Skinning Guid currentUserSkin = CurrentSkinInfo.Value.ID; if (items.Any(s => s.ID == currentUserSkin)) - scheduler.Add(() => CurrentSkinInfo.Value = Skinning.DefaultSkin.CreateInfo().ToLiveUnmanaged()); + scheduler.Add(() => CurrentSkinInfo.Value = TrianglesSkin.CreateInfo().ToLiveUnmanaged()); Delete(items.ToList(), silent); }); @@ -310,10 +310,10 @@ namespace osu.Game.Skinning if (skinInfo == null) { if (guid == SkinInfo.CLASSIC_SKIN) - skinInfo = DefaultLegacySkin.SkinInfo; + skinInfo = DefaultClassicSkin.SkinInfo; } - CurrentSkinInfo.Value = skinInfo ?? DefaultSkin.SkinInfo; + CurrentSkinInfo.Value = skinInfo ?? DefaultSkinTriangles.SkinInfo; } } } diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index 57beb6e803..69454de979 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -112,7 +112,7 @@ namespace osu.Game.Skinning // Temporarily used to exclude undesirable ISkin implementations static bool isUserSkin(ISkin skin) - => skin.GetType() == typeof(DefaultSkin) + => skin.GetType() == typeof(TrianglesSkin) || skin.GetType() == typeof(DefaultLegacySkin) || skin.GetType() == typeof(LegacySkin); } diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs similarity index 95% rename from osu.Game/Skinning/DefaultSkin.cs rename to osu.Game/Skinning/TrianglesSkin.cs index f10e8412b1..2c70963524 100644 --- a/osu.Game/Skinning/DefaultSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -22,26 +22,26 @@ using osuTK.Graphics; namespace osu.Game.Skinning { - public class DefaultSkin : Skin + public class TrianglesSkin : Skin { public static SkinInfo CreateInfo() => new SkinInfo { - ID = osu.Game.Skinning.SkinInfo.DEFAULT_SKIN, - Name = "osu! (triangles)", + ID = osu.Game.Skinning.SkinInfo.TRIANGLES_SKIN, + Name = "osu! \"triangles\" (2017)", Creator = "team osu!", Protected = true, - InstantiationInfo = typeof(DefaultSkin).GetInvariantInstantiationInfo() + InstantiationInfo = typeof(TrianglesSkin).GetInvariantInstantiationInfo() }; private readonly IStorageResourceProvider resources; - public DefaultSkin(IStorageResourceProvider resources) + public TrianglesSkin(IStorageResourceProvider resources) : this(CreateInfo(), resources) { } [UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)] - public DefaultSkin(SkinInfo skin, IStorageResourceProvider resources) + public TrianglesSkin(SkinInfo skin, IStorageResourceProvider resources) : base(skin, resources) { this.resources = resources; diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index 7278e1e93f..75224742a2 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -29,8 +29,9 @@ namespace osu.Game.Tests.Visual { public abstract class SkinnableTestScene : OsuGridTestScene, IStorageResourceProvider { + private TrianglesSkin trianglesSkin; private Skin metricsSkin; - private Skin defaultSkin; + private Skin legacySkin; private Skin specialSkin; private Skin oldSkin; @@ -47,8 +48,9 @@ namespace osu.Game.Tests.Visual { var dllStore = new DllResourceStore(GetType().Assembly); + trianglesSkin = new TrianglesSkin(this); metricsSkin = new TestLegacySkin(new SkinInfo { Name = "metrics-skin" }, new NamespacedResourceStore(dllStore, "Resources/metrics_skin"), this, true); - defaultSkin = new DefaultLegacySkin(this); + legacySkin = new DefaultLegacySkin(this); specialSkin = new TestLegacySkin(new SkinInfo { Name = "special-skin" }, new NamespacedResourceStore(dllStore, "Resources/special_skin"), this, true); oldSkin = new TestLegacySkin(new SkinInfo { Name = "old-skin" }, new NamespacedResourceStore(dllStore, "Resources/old_skin"), this, true); } @@ -61,9 +63,9 @@ namespace osu.Game.Tests.Visual var beatmap = CreateBeatmapForSkinProvider(); - Cell(0).Child = createProvider(null, creationFunction, beatmap); + Cell(0).Child = createProvider(trianglesSkin, creationFunction, beatmap); Cell(1).Child = createProvider(metricsSkin, creationFunction, beatmap); - Cell(2).Child = createProvider(defaultSkin, creationFunction, beatmap); + Cell(2).Child = createProvider(legacySkin, creationFunction, beatmap); Cell(3).Child = createProvider(specialSkin, creationFunction, beatmap); Cell(4).Child = createProvider(oldSkin, creationFunction, beatmap); }