From 124ac689b88e5ea7d48f5018c62454235f1eeceb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 May 2021 16:26:27 +0900 Subject: [PATCH 01/65] Add method to `PopupDialog` to press the first OK button --- osu.Game/Overlays/Dialog/PopupDialog.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 1bcbe4dd2f..df085b56f2 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -207,6 +207,11 @@ namespace osu.Game.Overlays.Dialog }; } + /// + /// Programmatically clicks the first . + /// + public void PerformOkAction() => Buttons.OfType().First().Click(); + protected override bool OnKeyDown(KeyDownEvent e) { if (e.Repeat) return false; From b83322281e2effed91b67d81aa10fd71e54f32df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 May 2021 16:27:38 +0900 Subject: [PATCH 02/65] Consume updated logic at `MainMenu` --- osu.Game/Screens/Menu/MainMenu.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index baeb86c976..e53b46f391 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; -using osuTK; -using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -22,6 +19,8 @@ using osu.Game.Screens.Edit; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Select; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.Menu { @@ -120,7 +119,7 @@ namespace osu.Game.Screens.Menu Origin = Anchor.TopRight, Margin = new MarginPadding { Right = 15, Top = 5 } }, - exitConfirmOverlay?.CreateProxy() ?? Drawable.Empty() + exitConfirmOverlay?.CreateProxy() ?? Empty() }); buttons.StateChanged += state => @@ -270,15 +269,11 @@ namespace osu.Game.Screens.Menu if (!exitConfirmed && dialogOverlay != null) { if (dialogOverlay.CurrentDialog is ConfirmExitDialog exitDialog) - { - exitConfirmed = true; - exitDialog.Buttons.First().Click(); - } + exitDialog.PerformOkAction(); else - { dialogOverlay.Push(new ConfirmExitDialog(confirmAndExit, () => exitConfirmOverlay.Abort())); - return true; - } + + return true; } buttons.State = ButtonSystemState.Exit; From 44e22b31a905b18a35ca0f84282f581c5c908440 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 May 2021 16:28:25 +0900 Subject: [PATCH 03/65] Refactor editor exit sequence to avoid any scenario where a dialog could go stray --- osu.Game/Screens/Edit/Editor.cs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 5ac3401720..5e990ff81e 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -473,25 +473,23 @@ namespace osu.Game.Screens.Edit { if (!exitConfirmed) { - // if the confirm dialog is already showing (or we can't show it, ie. in tests) exit without save. - if (dialogOverlay == null || dialogOverlay.CurrentDialog is PromptForSaveDialog) + // dialog overlay may not be available in visual tests. + if (dialogOverlay == null) { confirmExit(); - return base.OnExiting(next); + return true; + } + + // if the dialog is already displayed, confirm exit with no save. + if (dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog) + { + saveDialog.PerformOkAction(); + return true; } if (isNewBeatmap || HasUnsavedChanges) { - dialogOverlay?.Push(new PromptForSaveDialog(() => - { - confirmExit(); - this.Exit(); - }, () => - { - confirmExitWithSave(); - this.Exit(); - })); - + dialogOverlay?.Push(new PromptForSaveDialog(confirmExit, confirmExitWithSave)); return true; } } @@ -506,8 +504,10 @@ namespace osu.Game.Screens.Edit private void confirmExitWithSave() { - exitConfirmed = true; Save(); + + exitConfirmed = true; + this.Exit(); } private void confirmExit() @@ -529,6 +529,7 @@ namespace osu.Game.Screens.Edit } exitConfirmed = true; + this.Exit(); } private readonly Bindable clipboard = new Bindable(); From fc5987bf6978f565bf038d474650fb2409cf5ac8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 May 2021 16:52:34 +0900 Subject: [PATCH 04/65] Refactor `DialogOverlay` logic to avoid dismissal potentially being unhandled --- osu.Game/Overlays/Dialog/PopupDialog.cs | 6 ++++++ osu.Game/Overlays/DialogOverlay.cs | 7 ++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index df085b56f2..c04ad7afb5 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -95,6 +95,8 @@ namespace osu.Game.Overlays.Dialog } } + protected override bool StartHidden => true; + protected PopupDialog() { RelativeSizeAxes = Axes.Both; @@ -205,6 +207,10 @@ namespace osu.Game.Overlays.Dialog }, }, }; + + // It's important we start in a visible state so our state fires on hide, even before load. + // This is used by the DialogOverlay to know when the dialog was dismissed. + Show(); } /// diff --git a/osu.Game/Overlays/DialogOverlay.cs b/osu.Game/Overlays/DialogOverlay.cs index 4cc17a4c14..bc3b0e6c9a 100644 --- a/osu.Game/Overlays/DialogOverlay.cs +++ b/osu.Game/Overlays/DialogOverlay.cs @@ -35,15 +35,16 @@ namespace osu.Game.Overlays public void Push(PopupDialog dialog) { - if (dialog == CurrentDialog) return; + if (dialog == CurrentDialog || dialog.State.Value != Visibility.Visible) return; + // if any existing dialog is being displayed, dismiss it before showing a new one. CurrentDialog?.Hide(); + CurrentDialog = dialog; + CurrentDialog.State.ValueChanged += state => onDialogOnStateChanged(dialog, state.NewValue); dialogContainer.Add(CurrentDialog); - CurrentDialog.Show(); - CurrentDialog.State.ValueChanged += state => onDialogOnStateChanged(dialog, state.NewValue); Show(); } From b33d5e7a7a4c0a906d0b13f44bdaf0366f9d3938 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 May 2021 17:00:52 +0900 Subject: [PATCH 05/65] Add new test and assertions to existing `DialogOverlay` test --- .../UserInterface/TestSceneDialogOverlay.cs | 57 +++++++++++++++++-- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs index cc4a57fb83..f5cba2c900 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs @@ -2,7 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Framework.Testing; using osu.Game.Overlays; using osu.Game.Overlays.Dialog; @@ -11,13 +13,20 @@ namespace osu.Game.Tests.Visual.UserInterface [TestFixture] public class TestSceneDialogOverlay : OsuTestScene { - public TestSceneDialogOverlay() + private DialogOverlay overlay; + + [SetUpSteps] + public void SetUpSteps() { - DialogOverlay overlay; + AddStep("create dialog overlay", () => Child = overlay = new DialogOverlay()); + } - Add(overlay = new DialogOverlay()); + [Test] + public void TestBasic() + { + TestPopupDialog dialog = null; - AddStep("dialog #1", () => overlay.Push(new TestPopupDialog + AddStep("dialog #1", () => overlay.Push(dialog = new TestPopupDialog { Icon = FontAwesome.Regular.TrashAlt, HeaderText = @"Confirm deletion of", @@ -37,7 +46,9 @@ namespace osu.Game.Tests.Visual.UserInterface }, })); - AddStep("dialog #2", () => overlay.Push(new TestPopupDialog + AddAssert("first dialog displayed", () => overlay.CurrentDialog == dialog); + + AddStep("dialog #2", () => overlay.Push(dialog = new TestPopupDialog { Icon = FontAwesome.Solid.Cog, HeaderText = @"What do you want to do with", @@ -70,6 +81,42 @@ namespace osu.Game.Tests.Visual.UserInterface }, }, })); + + AddAssert("second dialog displayed", () => overlay.CurrentDialog == dialog); + } + + [Test] + public void TestDismissBeforePush() + { + AddStep("dismissed dialog push", () => + { + overlay.Push(new TestPopupDialog + { + State = { Value = Visibility.Hidden } + }); + }); + + AddAssert("no dialog pushed", () => overlay.CurrentDialog == null); + } + + [Test] + public void TestDismissBeforePushViaButtonPress() + { + AddStep("dismissed dialog push", () => + { + TestPopupDialog dialog; + overlay.Push(dialog = new TestPopupDialog + { + Buttons = new PopupDialogButton[] + { + new PopupDialogOkButton { Text = @"OK" }, + }, + }); + + dialog.PerformOkAction(); + }); + + AddAssert("no dialog pushed", () => overlay.CurrentDialog == null); } private class TestPopupDialog : PopupDialog From a639132825f38ed9c159247a7ef7b6769b7254ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 May 2021 17:58:28 +0900 Subject: [PATCH 06/65] Avoid doing any re-fetch on beatmap from test scenes --- osu.Game/Beatmaps/BeatmapManager.cs | 3 +-- osu.Game/Screens/Edit/Editor.cs | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 5e975de77c..dadc0624b3 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -286,11 +286,10 @@ namespace osu.Game.Beatmaps { if (beatmapInfo?.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) return previous; - if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - if (beatmapInfo.BeatmapSet.Files == null) + if (beatmapInfo.BeatmapSet.Files == null || beatmapInfo.ID == 0) { var info = beatmapInfo; beatmapInfo = QueryBeatmap(b => b.ID == info.ID); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 5e990ff81e..eafa5847a3 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -497,7 +497,11 @@ namespace osu.Game.Screens.Edit ApplyToBackground(b => b.FadeColour(Color4.White, 500)); resetTrack(); - Beatmap.Value = beatmapManager.GetWorkingBeatmap(Beatmap.Value.BeatmapInfo); + var refetchedBeatmap = beatmapManager.GetWorkingBeatmap(Beatmap.Value.BeatmapInfo); + + // beatmap re-fetch may not be feasible in tests. + if (!(refetchedBeatmap is DummyWorkingBeatmap)) + Beatmap.Value = refetchedBeatmap; return base.OnExiting(next); } From 9f3ea150f58247f6de0c7ed14f04282e1ae72c4b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 23:01:27 +0300 Subject: [PATCH 07/65] Fix legacy beatmap skins not falling back properly on HUD components --- osu.Game/Skinning/LegacyBeatmapSkin.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 5ee436e8bb..9ff2238e4e 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -3,6 +3,7 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Framework.IO.Stores; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -23,6 +24,25 @@ namespace osu.Game.Skinning Configuration.AllowDefaultComboColoursFallback = false; } + public override Drawable GetDrawableComponent(ISkinComponent component) + { + if (component is SkinnableTargetComponent targetComponent) + { + switch (targetComponent.Target) + { + case SkinnableTarget.MainHUDComponents: + // this should exist in LegacySkin instead, but there isn't a fallback skin for LegacySkins yet. + // therefore keep the check here until fallback default legacy skin is supported. + if (!this.HasFont(LegacyFont.Score)) + return null; + + break; + } + } + + return base.GetDrawableComponent(component); + } + public override IBindable GetConfig(TLookup lookup) { switch (lookup) From 97c84998844240a63a3ec7b32f766d03d657a1f1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 23:01:41 +0300 Subject: [PATCH 08/65] Add test coverage --- .../Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 1d0caa86e2..48b5e67814 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -46,6 +46,13 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("hud from default legacy skin", () => AssertComponentsFromExpectedSource(SkinnableTarget.MainHUDComponents, skinManager.CurrentSkin.Value)); } + [Test] + public void TestEmptyLegacyBeatmapSkinFallsBack() + { + CreateSkinTest(SkinInfo.Default, () => new LegacyBeatmapSkin(new BeatmapInfo(), null, null)); + AddAssert("hud from default skin", () => AssertComponentsFromExpectedSource(SkinnableTarget.MainHUDComponents, skinManager.CurrentSkin.Value)); + } + protected void CreateSkinTest(SkinInfo gameCurrentSkin, Func getBeatmapSkin) { CreateTest(() => From dbfaaecd9cd004e86fbfd0c741b8100e001dbabe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 May 2021 15:39:29 +0900 Subject: [PATCH 09/65] Reword comment to not mention tests driectly --- osu.Game/Screens/Edit/Editor.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index eafa5847a3..986a4efb28 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -497,9 +497,11 @@ namespace osu.Game.Screens.Edit ApplyToBackground(b => b.FadeColour(Color4.White, 500)); resetTrack(); + // To update the game-wide beatmap with any changes, perform a re-fetch on exit. + // This is required as the editor makes its local changes via EditorBeatmap + // (which are not propagated outwards to a potentially cached WorkingBeatmap). var refetchedBeatmap = beatmapManager.GetWorkingBeatmap(Beatmap.Value.BeatmapInfo); - // beatmap re-fetch may not be feasible in tests. if (!(refetchedBeatmap is DummyWorkingBeatmap)) Beatmap.Value = refetchedBeatmap; From 7980bdd384baef8e557f0f72523b878353b7dee8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 May 2021 15:41:58 +0900 Subject: [PATCH 10/65] Revert incorrectly changed requery code --- osu.Game/Beatmaps/BeatmapManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index dadc0624b3..5e975de77c 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -286,10 +286,11 @@ namespace osu.Game.Beatmaps { if (beatmapInfo?.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) return previous; + if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - if (beatmapInfo.BeatmapSet.Files == null || beatmapInfo.ID == 0) + if (beatmapInfo.BeatmapSet.Files == null) { var info = beatmapInfo; beatmapInfo = QueryBeatmap(b => b.ID == info.ID); From fdbd421040efcbd9718d95841034471f930e6291 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 May 2021 16:01:14 +0900 Subject: [PATCH 11/65] Fix editor tests failing due to empty files being specified --- .../Editing/TestSceneEditorBeatmapCreation.cs | 2 + osu.Game/Beatmaps/BeatmapManager.cs | 7 ++- osu.Game/Tests/Beatmaps/TestBeatmap.cs | 1 - osu.Game/Tests/Visual/EditorTestScene.cs | 43 ++++++++++++++++++- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index 7584c74c71..dd5e01adbb 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -24,6 +24,8 @@ namespace osu.Game.Tests.Visual.Editing protected override bool EditorComponentsReady => Editor.ChildrenOfType().SingleOrDefault()?.IsLoaded == true; + protected override bool IsolateSavingFromDatabase => false; + [Resolved] private BeatmapManager beatmapManager { get; set; } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 5e975de77c..d5dc70317c 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Linq.Expressions; @@ -240,10 +241,12 @@ namespace osu.Game.Beatmaps /// The to save the content against. The file referenced by will be replaced. /// The content to write. /// The beatmap content to write, null if to be omitted. - public void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) + public virtual void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) { var setInfo = info.BeatmapSet; + Debug.Assert(setInfo.Files != null); + using (var stream = new MemoryStream()) { using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) @@ -282,7 +285,7 @@ namespace osu.Game.Beatmaps /// The beatmap to lookup. /// The currently loaded . Allows for optimisation where elements are shared with the new beatmap. May be returned if beatmapInfo requested matches /// A instance correlating to the provided . - public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) + public virtual WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) { if (beatmapInfo?.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) return previous; diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs index fa6dc5647d..2717146c99 100644 --- a/osu.Game/Tests/Beatmaps/TestBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs @@ -29,7 +29,6 @@ namespace osu.Game.Tests.Beatmaps BeatmapInfo.Ruleset = ruleset; BeatmapInfo.RulesetID = ruleset.ID ?? 0; BeatmapInfo.BeatmapSet.Metadata = BeatmapInfo.Metadata; - BeatmapInfo.BeatmapSet.Files = new List(); BeatmapInfo.BeatmapSet.Beatmaps = new List { BeatmapInfo }; BeatmapInfo.Length = 75000; BeatmapInfo.OnlineInfo = new BeatmapOnlineInfo(); diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index a9ee8e2668..de7fdd0cf8 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -4,11 +4,18 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Platform; using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Database; +using osu.Game.IO.Archives; +using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components.Timeline; +using osu.Game.Skinning; namespace osu.Game.Tests.Visual { @@ -20,10 +27,20 @@ namespace osu.Game.Tests.Visual protected EditorClock EditorClock { get; private set; } + /// + /// Whether any saves performed by the editor should be isolate (and not persist) to the underlying . + /// + protected virtual bool IsolateSavingFromDatabase => true; + [BackgroundDependencyLoader] - private void load() + private void load(GameHost host, AudioManager audio, RulesetStore rulesets) { - Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); + var working = CreateWorkingBeatmap(Ruleset.Value); + + Beatmap.Value = working; + + if (IsolateSavingFromDatabase) + Dependencies.CacheAs(new TestBeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default, working)); } protected virtual bool EditorComponentsReady => Editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true @@ -65,5 +82,27 @@ namespace osu.Game.Tests.Visual public new bool HasUnsavedChanges => base.HasUnsavedChanges; } + + private class TestBeatmapManager : BeatmapManager + { + private readonly WorkingBeatmap testBeatmap; + + public TestBeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, GameHost host, WorkingBeatmap defaultBeatmap, WorkingBeatmap testBeatmap) + : base(storage, contextFactory, rulesets, api, audioManager, host, defaultBeatmap, false) + { + this.testBeatmap = testBeatmap; + } + + protected override string ComputeHash(BeatmapSetInfo item, ArchiveReader reader = null) + => string.Empty; + + public override WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) + => testBeatmap; + + public override void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) + { + // don't actually care about saving for this context. + } + } } } From c24712642cc567f158f2d4a7b559429567347d8b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 May 2021 17:16:38 +0900 Subject: [PATCH 12/65] Make `BeatmapSetInfo.Files` non-nullable --- osu.Game/Beatmaps/BeatmapManager.cs | 22 ++++++++++------------ osu.Game/Beatmaps/BeatmapSetInfo.cs | 10 ++++++---- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index d5dc70317c..18fbd1f5c2 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Linq.Expressions; @@ -245,8 +244,6 @@ namespace osu.Game.Beatmaps { var setInfo = info.BeatmapSet; - Debug.Assert(setInfo.Files != null); - using (var stream = new MemoryStream()) { using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) @@ -287,20 +284,21 @@ namespace osu.Game.Beatmaps /// A instance correlating to the provided . public virtual WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) { - if (beatmapInfo?.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) - return previous; - - if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) + if (beatmapInfo?.BeatmapSet == null) return DefaultBeatmap; - if (beatmapInfo.BeatmapSet.Files == null) + if (beatmapInfo == DefaultBeatmap?.BeatmapInfo) + return DefaultBeatmap; + + // if there are no files, presume the full beatmap info has not yet been fetched from the database. + if (beatmapInfo.BeatmapSet.Files.Count == 0) { - var info = beatmapInfo; - beatmapInfo = QueryBeatmap(b => b.ID == info.ID); + int lookupId = beatmapInfo.ID; + beatmapInfo = QueryBeatmap(b => b.ID == lookupId); } - if (beatmapInfo == null) - return DefaultBeatmap; + if (beatmapInfo.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) + return previous; lock (workingCache) { diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index 1ce42535a0..3b1ff4ced0 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Testing; using osu.Game.Database; @@ -31,6 +32,9 @@ namespace osu.Game.Beatmaps public List Beatmaps { get; set; } + [NotNull] + public List Files { get; set; } = new List(); + [NotMapped] public BeatmapSetOnlineInfo OnlineInfo { get; set; } @@ -57,16 +61,14 @@ namespace osu.Game.Beatmaps public string Hash { get; set; } - public string StoryboardFile => Files?.Find(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename; + public string StoryboardFile => Files.Find(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename; /// /// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null. /// The path returned is relative to the user file storage. /// /// The name of the file to get the storage path of. - public string GetPathForFile(string filename) => Files?.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; - - public List Files { get; set; } + public string GetPathForFile(string filename) => Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; public override string ToString() => Metadata?.ToString() ?? base.ToString(); From 49aa0f3a180cd203d6ca1031b0a7ef8d3c7c4deb Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 21 May 2021 10:04:45 +0700 Subject: [PATCH 13/65] initial main page --- .../Visual/Online/TestSceneWikiMainPage.cs | 36 +++++++++++++++++++ osu.Game/Overlays/Wiki/WikiMainPage.cs | 17 +++++++++ 2 files changed, 53 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs create mode 100644 osu.Game/Overlays/Wiki/WikiMainPage.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs new file mode 100644 index 0000000000..e193f5b98e --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs @@ -0,0 +1,36 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Overlays; +using osu.Game.Overlays.Wiki; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneWikiMainPage : OsuTestScene + { + [Cached] + private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Orange); + + public TestSceneWikiMainPage() + { + Children = new Drawable[] + { + new Box + { + Colour = overlayColour.Background5, + RelativeSizeAxes = Axes.Both, + }, + new BasicScrollContainer + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(20), + Child = new WikiMainPage(), + } + }; + } + } +} diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs new file mode 100644 index 0000000000..1ae1631a6e --- /dev/null +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Overlays.Wiki +{ + public class WikiMainPage : FillFlowContainer + { + public WikiMainPage() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + } + } +} From 5964ee23cb2fb95bbecd94115b10d55bfe0344fb Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 21 May 2021 09:54:54 +0700 Subject: [PATCH 14/65] add HtmlAgilityPack dependency --- osu.Game/osu.Game.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fa2945db6a..e3331cd365 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -19,6 +19,7 @@ + From 216b87691c203c35f76263859dfbe56dda9ab5d4 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 21 May 2021 10:04:45 +0700 Subject: [PATCH 15/65] add blurb --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 1ae1631a6e..cb6c80cb73 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -3,15 +3,56 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using System.Linq; +using HtmlAgilityPack; +using osu.Framework.Allocation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; namespace osu.Game.Overlays.Wiki { public class WikiMainPage : FillFlowContainer { + public string Markdown; + public WikiMainPage() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; } + + [BackgroundDependencyLoader] + private void load() + { + var html = new HtmlDocument(); + html.LoadHtml(Markdown); + + Children = new Drawable[] + { + createBlurb(html) + }; + } + + private Container createBlurb(HtmlDocument html) + { + var blurbNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page__blurb')]").First(); + + return new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding + { + Vertical = 30, + }, + Child = new OsuSpriteText + { + Text = blurbNode.InnerText, + Font = OsuFont.GetFont(size: 12), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + } + }; + } } } From 0448f6fdb362dcfe370041738f27395949a601fa Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 25 May 2021 13:21:08 +0700 Subject: [PATCH 16/65] add main page markdown --- osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs index e193f5b98e..3a2bafb128 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs @@ -28,9 +28,16 @@ namespace osu.Game.Tests.Visual.Online { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(20), - Child = new WikiMainPage(), + Child = new WikiMainPage + { + Markdown = main_page_markdown + } } }; } + + // From https://osu.ppy.sh/api/v2/wiki/en/Main_Page + private const string main_page_markdown = + "---\nlayout: main_page\n---\n\n\n\n
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; } } From 4a543c25575fe80982ac296a5b3af2e17c1ed61a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 17:49:26 +0700 Subject: [PATCH 17/65] add simple panels --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 56 ++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index cb6c80cb73..258f6a4f19 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -6,13 +6,23 @@ using osu.Framework.Graphics.Containers; using System.Linq; using HtmlAgilityPack; using osu.Framework.Allocation; +using System.Collections.Generic; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Overlays.Wiki.Markdown; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Overlays.Wiki { public class WikiMainPage : FillFlowContainer { + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + public string Markdown; public WikiMainPage() @@ -31,6 +41,7 @@ namespace osu.Game.Overlays.Wiki { createBlurb(html) }; + AddRange(createPanels(html)); } private Container createBlurb(HtmlDocument html) @@ -54,5 +65,50 @@ namespace osu.Game.Overlays.Wiki } }; } + + private IEnumerable createPanels(HtmlDocument html) + { + var panelsNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page-panel')]"); + + foreach (var panel in panelsNode) + { + var isFullWidth = panel.HasClass("wiki-main-page-panel--full"); + + yield return new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Width = isFullWidth ? 1.0f : 0.5f, + Padding = new MarginPadding(3), + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 4, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(25), + Offset = new Vector2(0, 1), + Radius = 3, + }, + Child = new Box + { + Colour = colourProvider.Background4, + RelativeSizeAxes = Axes.Both, + }, + }, + new WikiMarkdownContainer + { + Text = panel.InnerText, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } + } + }; + } + } } } From d9e898a2eea4ee56508255ce9988be9a9978aa0a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 17:56:27 +0700 Subject: [PATCH 18/65] extract WikiPanelContainer --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 44 ++------------- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 56 ++++++++++++++++++++ 2 files changed, 60 insertions(+), 40 deletions(-) create mode 100644 osu.Game/Overlays/Wiki/WikiPanelContainer.cs diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 258f6a4f19..bdd0b4dc11 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -1,28 +1,19 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; +using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using System.Linq; using HtmlAgilityPack; using osu.Framework.Allocation; -using System.Collections.Generic; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Overlays.Wiki.Markdown; -using osuTK; -using osuTK.Graphics; namespace osu.Game.Overlays.Wiki { public class WikiMainPage : FillFlowContainer { - [Resolved] - private OverlayColourProvider colourProvider { get; set; } - public string Markdown; public WikiMainPage() @@ -74,39 +65,12 @@ namespace osu.Game.Overlays.Wiki { var isFullWidth = panel.HasClass("wiki-main-page-panel--full"); - yield return new Container + yield return new WikiPanelContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Width = isFullWidth ? 1.0f : 0.5f, - Padding = new MarginPadding(3), - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 4, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(25), - Offset = new Vector2(0, 1), - Radius = 3, - }, - Child = new Box - { - Colour = colourProvider.Background4, - RelativeSizeAxes = Axes.Both, - }, - }, - new WikiMarkdownContainer - { - Text = panel.InnerText, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - } - } + Text = panel.InnerText, }; } } diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs new file mode 100644 index 0000000000..33c9369ccb --- /dev/null +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -0,0 +1,56 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Game.Overlays.Wiki.Markdown; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Wiki +{ + public class WikiPanelContainer : Container + { + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + + public string Text; + + [BackgroundDependencyLoader] + private void load() + { + Padding = new MarginPadding(3); + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 4, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(25), + Offset = new Vector2(0, 1), + Radius = 3, + }, + Child = new Box + { + Colour = colourProvider.Background4, + RelativeSizeAxes = Axes.Both, + }, + }, + new WikiMarkdownContainer + { + Text = Text, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } + }; + } + } +} From 4d222467ccb6d580de5f86b849058153fdaae745 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:00:54 +0700 Subject: [PATCH 19/65] initial WikiPanelMarkdownContainer --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 33c9369ccb..2d5d806b12 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -44,7 +44,7 @@ namespace osu.Game.Overlays.Wiki RelativeSizeAxes = Axes.Both, }, }, - new WikiMarkdownContainer + new WikiPanelMarkdownContainer { Text = Text, RelativeSizeAxes = Axes.X, @@ -52,5 +52,15 @@ namespace osu.Game.Overlays.Wiki } }; } + + private class WikiPanelMarkdownContainer : WikiMarkdownContainer + { + public WikiPanelMarkdownContainer() + { + LineSpacing = 0; + DocumentPadding = new MarginPadding(30); + DocumentMargin = new MarginPadding(0); + } + } } } From 365a0b25f28a2bc7043816dde0b1046d52cc0e36 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:03:38 +0700 Subject: [PATCH 20/65] add IsFullWidth --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 1 + osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index bdd0b4dc11..c013cbec59 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -71,6 +71,7 @@ namespace osu.Game.Overlays.Wiki AutoSizeAxes = Axes.Y, Width = isFullWidth ? 1.0f : 0.5f, Text = panel.InnerText, + IsFullWidth = isFullWidth, }; } } diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 2d5d806b12..b58ba9bb09 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -20,6 +20,8 @@ namespace osu.Game.Overlays.Wiki public string Text; + public bool IsFullWidth; + [BackgroundDependencyLoader] private void load() { @@ -49,12 +51,15 @@ namespace osu.Game.Overlays.Wiki Text = Text, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + IsFullWidth = IsFullWidth, } }; } private class WikiPanelMarkdownContainer : WikiMarkdownContainer { + public bool IsFullWidth; + public WikiPanelMarkdownContainer() { LineSpacing = 0; From 1e5f34567ae2f28598c8f08f355c84dffebd3a97 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:07:27 +0700 Subject: [PATCH 21/65] add panel heading main page --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index b58ba9bb09..00afb7b062 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -1,12 +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 Markdig.Syntax; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers.Markdown; using osu.Game.Overlays.Wiki.Markdown; using osuTK; using osuTK.Graphics; @@ -66,6 +70,33 @@ namespace osu.Game.Overlays.Wiki DocumentPadding = new MarginPadding(30); DocumentMargin = new MarginPadding(0); } + + protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new WikiPanelHeading(headingBlock) + { + IsFullWidth = IsFullWidth, + }; + } + + private class WikiPanelHeading : OsuMarkdownHeading + { + public bool IsFullWidth; + + public WikiPanelHeading(HeadingBlock headingBlock) + : base(headingBlock) + { + Margin = new MarginPadding { Bottom = 40 }; + } + + public override MarkdownTextFlowContainer CreateTextFlow() => base.CreateTextFlow().With(f => + { + f.Anchor = Anchor.TopCentre; + f.Origin = Anchor.TopCentre; + f.TextAnchor = Anchor.TopCentre; + }); + + protected override FontWeight GetFontWeightByLevel(int level) => FontWeight.Regular; + + protected override float GetFontSizeByLevel(int level) => base.GetFontSizeByLevel(IsFullWidth ? level : 3); } } } From 512d6d2f7fd7b2435b8e4920a59875df6c8c85d1 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:09:09 +0700 Subject: [PATCH 22/65] centering link inside panel --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 00afb7b062..31b939d2ac 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -71,6 +71,8 @@ namespace osu.Game.Overlays.Wiki DocumentMargin = new MarginPadding(0); } + public override MarkdownTextFlowContainer CreateTextFlow() => base.CreateTextFlow().With(f => f.TextAnchor = Anchor.TopCentre); + protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new WikiPanelHeading(headingBlock) { IsFullWidth = IsFullWidth, From cd211de7295f3dfb3464f0dcd29054423ea2ac86 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:10:56 +0700 Subject: [PATCH 23/65] make panel text bold --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 31b939d2ac..c5dd8549da 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Containers.Markdown; using osu.Game.Overlays.Wiki.Markdown; @@ -71,6 +72,8 @@ namespace osu.Game.Overlays.Wiki DocumentMargin = new MarginPadding(0); } + public override SpriteText CreateSpriteText() => base.CreateSpriteText().With(t => t.Font = t.Font.With(weight: FontWeight.Bold)); + public override MarkdownTextFlowContainer CreateTextFlow() => base.CreateTextFlow().With(f => f.TextAnchor = Anchor.TopCentre); protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new WikiPanelHeading(headingBlock) From 40688810966e0ecb29cc05fc7f17f09d26e77606 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:11:54 +0700 Subject: [PATCH 24/65] add bottom margin for paragraph --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index c5dd8549da..727cae766d 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -76,6 +76,9 @@ namespace osu.Game.Overlays.Wiki public override MarkdownTextFlowContainer CreateTextFlow() => base.CreateTextFlow().With(f => f.TextAnchor = Anchor.TopCentre); + protected override MarkdownParagraph CreateParagraph(ParagraphBlock paragraphBlock, int level) + => base.CreateParagraph(paragraphBlock, level).With(p => p.Margin = new MarginPadding { Bottom = 10 }); + protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new WikiPanelHeading(headingBlock) { IsFullWidth = IsFullWidth, From 8389d90f7ee1d1a6edb3197201c625700cac9907 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:52:20 +0700 Subject: [PATCH 25/65] add GridContainer in wiki main page --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index c013cbec59..2da5e5e928 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -30,9 +30,13 @@ namespace osu.Game.Overlays.Wiki Children = new Drawable[] { - createBlurb(html) + createBlurb(html), + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }, }; - AddRange(createPanels(html)); } private Container createBlurb(HtmlDocument html) From 24fef221e304ac4d0f1c9fff9b551c8f5d11359f Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 19:07:10 +0700 Subject: [PATCH 26/65] change createPanels method to create grid content --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 48 ++++++++++++++++++++------ 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 2da5e5e928..12c17d5225 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -61,22 +61,48 @@ namespace osu.Game.Overlays.Wiki }; } - private IEnumerable createPanels(HtmlDocument html) + private IEnumerable createPanels(HtmlDocument html) { - var panelsNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page-panel')]"); + var panelsNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page-panel')]").ToArray(); - foreach (var panel in panelsNode) + for (var i = 0; i < panelsNode.Length; i++) { - var isFullWidth = panel.HasClass("wiki-main-page-panel--full"); + var isFullWidth = panelsNode[i].HasClass("wiki-main-page-panel--full"); - yield return new WikiPanelContainer + if (isFullWidth) { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Width = isFullWidth ? 1.0f : 0.5f, - Text = panel.InnerText, - IsFullWidth = isFullWidth, - }; + yield return new Drawable[] + { + new WikiPanelContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = panelsNode[i].InnerText, + IsFullWidth = true, + Width = 2, + }, + null, + }; + } + + if (i % 2 == 1) + { + yield return new Drawable[] + { + new WikiPanelContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = panelsNode[i].InnerText, + }, + new WikiPanelContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = panelsNode[i + 1].InnerText, + }, + }; + } } } } From 10c4ba3a746ac11b9899ce5c57523f0830bbaa2d Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 19:07:22 +0700 Subject: [PATCH 27/65] add panels to grid content --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 12c17d5225..c4e43d1438 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -28,6 +28,8 @@ namespace osu.Game.Overlays.Wiki var html = new HtmlDocument(); html.LoadHtml(Markdown); + var panels = createPanels(html).ToArray(); + Children = new Drawable[] { createBlurb(html), @@ -35,6 +37,8 @@ namespace osu.Game.Overlays.Wiki { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + RowDimensions = Enumerable.Repeat(new Dimension(GridSizeMode.AutoSize), panels.Length).ToArray(), + Content = panels, }, }; } From 24960c4fb83cfea649ce22a04767abfefc748431 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 21:31:49 +0700 Subject: [PATCH 28/65] move panel spacing to ctor --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 6 ------ osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 8 +++++++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index c4e43d1438..8ff85c1404 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -79,8 +79,6 @@ namespace osu.Game.Overlays.Wiki { new WikiPanelContainer { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, Text = panelsNode[i].InnerText, IsFullWidth = true, Width = 2, @@ -95,14 +93,10 @@ namespace osu.Game.Overlays.Wiki { new WikiPanelContainer { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, Text = panelsNode[i].InnerText, }, new WikiPanelContainer { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, Text = panelsNode[i + 1].InnerText, }, }; diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 727cae766d..64f4d9fbcd 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -27,10 +27,16 @@ namespace osu.Game.Overlays.Wiki public bool IsFullWidth; + public WikiPanelContainer() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding(3); + } + [BackgroundDependencyLoader] private void load() { - Padding = new MarginPadding(3); Children = new Drawable[] { new Container From bd1454bdd1c26de28c5ec91cf6ed89dec218bc94 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 21:42:58 +0700 Subject: [PATCH 29/65] update height to max of its parent height --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 64f4d9fbcd..f0fecce8dc 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.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 Markdig.Syntax; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -23,6 +24,8 @@ namespace osu.Game.Overlays.Wiki [Resolved] private OverlayColourProvider colourProvider { get; set; } + private WikiPanelMarkdownContainer panelContainer; + public string Text; public bool IsFullWidth; @@ -30,7 +33,6 @@ namespace osu.Game.Overlays.Wiki public WikiPanelContainer() { RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; Padding = new MarginPadding(3); } @@ -57,7 +59,7 @@ namespace osu.Game.Overlays.Wiki RelativeSizeAxes = Axes.Both, }, }, - new WikiPanelMarkdownContainer + panelContainer = new WikiPanelMarkdownContainer { Text = Text, RelativeSizeAxes = Axes.X, @@ -67,6 +69,12 @@ namespace osu.Game.Overlays.Wiki }; } + protected override void Update() + { + base.Update(); + Height = Math.Max(panelContainer.Height, Parent.DrawHeight); + } + private class WikiPanelMarkdownContainer : WikiMarkdownContainer { public bool IsFullWidth; From 222c34c0a1c77113a0ceb128f37db1acfab547e0 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 21:46:41 +0700 Subject: [PATCH 30/65] fix heading font weight to light --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index f0fecce8dc..71b492b375 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -116,7 +116,7 @@ namespace osu.Game.Overlays.Wiki f.TextAnchor = Anchor.TopCentre; }); - protected override FontWeight GetFontWeightByLevel(int level) => FontWeight.Regular; + protected override FontWeight GetFontWeightByLevel(int level) => FontWeight.Light; protected override float GetFontSizeByLevel(int level) => base.GetFontSizeByLevel(IsFullWidth ? level : 3); } From a7865d3f22013bf85fb46ff1433ab3976d2c090b Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 08:46:24 +0700 Subject: [PATCH 31/65] move colour provider to BDL --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 71b492b375..ad30306475 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -21,9 +21,6 @@ namespace osu.Game.Overlays.Wiki { public class WikiPanelContainer : Container { - [Resolved] - private OverlayColourProvider colourProvider { get; set; } - private WikiPanelMarkdownContainer panelContainer; public string Text; @@ -37,7 +34,7 @@ namespace osu.Game.Overlays.Wiki } [BackgroundDependencyLoader] - private void load() + private void load(OverlayColourProvider colourProvider) { Children = new Drawable[] { From d66f07fccb10cae2aaf76020bab1c03313a11b56 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 14:04:50 +0900 Subject: [PATCH 32/65] Move text and `isFullWidth` parameters to constructor --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 14 +++---------- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 22 ++++++++++++-------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 8ff85c1404..bf4a76c3d8 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -77,10 +77,8 @@ namespace osu.Game.Overlays.Wiki { yield return new Drawable[] { - new WikiPanelContainer + new WikiPanelContainer(panelsNode[i].InnerText, true) { - Text = panelsNode[i].InnerText, - IsFullWidth = true, Width = 2, }, null, @@ -91,14 +89,8 @@ namespace osu.Game.Overlays.Wiki { yield return new Drawable[] { - new WikiPanelContainer - { - Text = panelsNode[i].InnerText, - }, - new WikiPanelContainer - { - Text = panelsNode[i + 1].InnerText, - }, + new WikiPanelContainer(panelsNode[i].InnerText), + new WikiPanelContainer(panelsNode[i + 1].InnerText), }; } } diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index ad30306475..db213e4951 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -23,12 +23,15 @@ namespace osu.Game.Overlays.Wiki { private WikiPanelMarkdownContainer panelContainer; - public string Text; + private readonly string text; - public bool IsFullWidth; + private readonly bool isFullWidth; - public WikiPanelContainer() + public WikiPanelContainer(string text, bool isFullWidth = false) { + this.text = text; + this.isFullWidth = isFullWidth; + RelativeSizeAxes = Axes.X; Padding = new MarginPadding(3); } @@ -56,12 +59,11 @@ namespace osu.Game.Overlays.Wiki RelativeSizeAxes = Axes.Both, }, }, - panelContainer = new WikiPanelMarkdownContainer + panelContainer = new WikiPanelMarkdownContainer(isFullWidth) { - Text = Text, + Text = text, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - IsFullWidth = IsFullWidth, } }; } @@ -74,10 +76,12 @@ namespace osu.Game.Overlays.Wiki private class WikiPanelMarkdownContainer : WikiMarkdownContainer { - public bool IsFullWidth; + private readonly bool isFullWidth; - public WikiPanelMarkdownContainer() + public WikiPanelMarkdownContainer(bool isFullWidth) { + this.isFullWidth = isFullWidth; + LineSpacing = 0; DocumentPadding = new MarginPadding(30); DocumentMargin = new MarginPadding(0); @@ -92,7 +96,7 @@ namespace osu.Game.Overlays.Wiki protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new WikiPanelHeading(headingBlock) { - IsFullWidth = IsFullWidth, + IsFullWidth = isFullWidth, }; } From 4fbd43fcaec8cc6af378cd750bf3165a061ff35d Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 13:24:06 +0700 Subject: [PATCH 33/65] add inline comment for width 2 --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index bf4a76c3d8..2356ec03a6 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -79,6 +79,7 @@ namespace osu.Game.Overlays.Wiki { new WikiPanelContainer(panelsNode[i].InnerText, true) { + // This is required to fill up the space of "null" drawable below. Width = 2, }, null, From c72e258bfb857e229bc8c46faffc9d12ec2ae238 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 13:34:55 +0700 Subject: [PATCH 34/65] change for to while in create panels --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 2356ec03a6..76e6b0261a 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -69,7 +69,9 @@ namespace osu.Game.Overlays.Wiki { var panelsNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page-panel')]").ToArray(); - for (var i = 0; i < panelsNode.Length; i++) + var i = 0; + + while (i < panelsNode.Length) { var isFullWidth = panelsNode[i].HasClass("wiki-main-page-panel--full"); @@ -77,7 +79,7 @@ namespace osu.Game.Overlays.Wiki { yield return new Drawable[] { - new WikiPanelContainer(panelsNode[i].InnerText, true) + new WikiPanelContainer(panelsNode[i++].InnerText, true) { // This is required to fill up the space of "null" drawable below. Width = 2, @@ -85,13 +87,12 @@ namespace osu.Game.Overlays.Wiki null, }; } - - if (i % 2 == 1) + else { yield return new Drawable[] { - new WikiPanelContainer(panelsNode[i].InnerText), - new WikiPanelContainer(panelsNode[i + 1].InnerText), + new WikiPanelContainer(panelsNode[i++].InnerText), + new WikiPanelContainer(panelsNode[i++].InnerText), }; } } From b55ac413e7ca8953450319d3212ed9a1208d1ea2 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 14:20:36 +0700 Subject: [PATCH 35/65] add many scenario of main page layout --- .../Visual/Online/TestSceneWikiMainPage.cs | 99 +++++++++++++++++-- 1 file changed, 93 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs index 3a2bafb128..7fa1a6e135 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.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 NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -15,7 +16,10 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Orange); - public TestSceneWikiMainPage() + private BasicScrollContainer container; + + [SetUp] + public void Setup() => Schedule(() => { Children = new Drawable[] { @@ -24,20 +28,103 @@ namespace osu.Game.Tests.Visual.Online Colour = overlayColour.Background5, RelativeSizeAxes = Axes.Both, }, - new BasicScrollContainer + container = new BasicScrollContainer { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(20), - Child = new WikiMainPage - { - Markdown = main_page_markdown - } } }; + }); + + [Test] + public void TestWikiMainPage() + { + AddStep("Show main page", () => + { + container.Child = new WikiMainPage + { + Markdown = main_page_markdown, + }; + }); + } + + [Test] + public void TestNonFullWidthLayout() + { + AddStep("Show Layout", () => + { + container.Child = new WikiMainPage + { + Markdown = non_full_width, + }; + }); + } + + [Test] + public void TestFullWidthAtTheEnd() + { + AddStep("Show layout", () => + { + container.Child = new WikiMainPage + { + Markdown = full_width_end, + }; + }); + } + + [Test] + public void TestFullWidthAtTheStartAndEnd() + { + AddStep("Show layout", () => + { + container.Child = new WikiMainPage + { + Markdown = full_width_start_end, + }; + }); + } + + [Test] + public void TestFullWidthInTheMiddle() + { + AddStep("Show layout", () => + { + container.Child = new WikiMainPage + { + Markdown = full_width_in_the_middle, + }; + }); + } + + [Test] + public void TestFullWidthStacking() + { + AddStep("Show layout", () => + { + container.Child = new WikiMainPage + { + Markdown = full_width_stack, + }; + }); } // From https://osu.ppy.sh/api/v2/wiki/en/Main_Page private const string main_page_markdown = "---\nlayout: main_page\n---\n\n\n\n
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; + + private const string non_full_width = + "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; + + private const string full_width_end = + "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n"; + + private const string full_width_start_end = + "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n"; + + private const string full_width_in_the_middle = + "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; + + private const string full_width_stack= + "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; } } From 820310543d56b23ed5fc99591da3f4e994a37ad2 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 14:53:22 +0700 Subject: [PATCH 36/65] fix spacing style --- osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs index 7fa1a6e135..9fb3c685b7 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs @@ -124,7 +124,7 @@ namespace osu.Game.Tests.Visual.Online private const string full_width_in_the_middle = "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; - private const string full_width_stack= + private const string full_width_stack = "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; } } From 0b600db81487a766e9d91687c7a57e6ae8517cfb Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 16:24:05 +0700 Subject: [PATCH 37/65] revert back main page test --- .../Visual/Online/TestSceneWikiMainPage.cs | 99 ++----------------- 1 file changed, 6 insertions(+), 93 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs index 9fb3c685b7..3a2bafb128 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -16,10 +15,7 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Orange); - private BasicScrollContainer container; - - [SetUp] - public void Setup() => Schedule(() => + public TestSceneWikiMainPage() { Children = new Drawable[] { @@ -28,103 +24,20 @@ namespace osu.Game.Tests.Visual.Online Colour = overlayColour.Background5, RelativeSizeAxes = Axes.Both, }, - container = new BasicScrollContainer + new BasicScrollContainer { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(20), + Child = new WikiMainPage + { + Markdown = main_page_markdown + } } }; - }); - - [Test] - public void TestWikiMainPage() - { - AddStep("Show main page", () => - { - container.Child = new WikiMainPage - { - Markdown = main_page_markdown, - }; - }); - } - - [Test] - public void TestNonFullWidthLayout() - { - AddStep("Show Layout", () => - { - container.Child = new WikiMainPage - { - Markdown = non_full_width, - }; - }); - } - - [Test] - public void TestFullWidthAtTheEnd() - { - AddStep("Show layout", () => - { - container.Child = new WikiMainPage - { - Markdown = full_width_end, - }; - }); - } - - [Test] - public void TestFullWidthAtTheStartAndEnd() - { - AddStep("Show layout", () => - { - container.Child = new WikiMainPage - { - Markdown = full_width_start_end, - }; - }); - } - - [Test] - public void TestFullWidthInTheMiddle() - { - AddStep("Show layout", () => - { - container.Child = new WikiMainPage - { - Markdown = full_width_in_the_middle, - }; - }); - } - - [Test] - public void TestFullWidthStacking() - { - AddStep("Show layout", () => - { - container.Child = new WikiMainPage - { - Markdown = full_width_stack, - }; - }); } // From https://osu.ppy.sh/api/v2/wiki/en/Main_Page private const string main_page_markdown = "---\nlayout: main_page\n---\n\n\n\n
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; - - private const string non_full_width = - "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; - - private const string full_width_end = - "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n"; - - private const string full_width_start_end = - "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n"; - - private const string full_width_in_the_middle = - "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; - - private const string full_width_stack = - "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; } } From e1836cd1b2535a2d0329e9d0a71979bd2796a414 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 17:12:15 +0700 Subject: [PATCH 38/65] add debug assert --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 76e6b0261a..bbbbc602bf 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -69,6 +70,8 @@ namespace osu.Game.Overlays.Wiki { var panelsNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page-panel')]").ToArray(); + Debug.Assert(panelsNode.Length > 1); + var i = 0; while (i < panelsNode.Length) From d24a712dd4b8b7b2dcc3bf3203e63e56276ac0ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 02:27:06 +0900 Subject: [PATCH 39/65] Move protected properties to one location and mark setters `private` where feasible --- osu.Game/OsuGameBase.cs | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 3c143c1db9..bbfaa62258 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -53,51 +53,53 @@ namespace osu.Game ///
public class OsuGameBase : Framework.Game, ICanAcceptFiles { - public const string CLIENT_STREAM_NAME = "lazer"; + public const string CLIENT_STREAM_NAME = @"lazer"; public const int SAMPLE_CONCURRENCY = 6; public bool UseDevelopmentServer { get; } - protected OsuConfigManager LocalConfig; + protected OsuConfigManager LocalConfig { get; private set; } protected SessionStatics SessionStatics { get; private set; } - protected BeatmapManager BeatmapManager; + protected BeatmapManager BeatmapManager { get; private set; } - protected ScoreManager ScoreManager; + protected ScoreManager ScoreManager { get; private set; } - protected BeatmapDifficultyCache DifficultyCache; + protected BeatmapDifficultyCache DifficultyCache { get; private set; } - protected UserLookupCache UserCache; + protected UserLookupCache UserCache { get; private set; } - protected SkinManager SkinManager; + protected SkinManager SkinManager { get; private set; } - protected RulesetStore RulesetStore; + protected RulesetStore RulesetStore { get; private set; } - protected FileStore FileStore; + protected FileStore FileStore { get; private set; } - protected KeyBindingStore KeyBindingStore; + protected KeyBindingStore KeyBindingStore { get; private set; } - protected SettingsStore SettingsStore; + protected SettingsStore SettingsStore { get; private set; } - protected RulesetConfigCache RulesetConfigCache; + protected RulesetConfigCache RulesetConfigCache { get; private set; } - protected IAPIProvider API; + protected MenuCursorContainer MenuCursorContainer { get; private set; } + + protected MusicController MusicController { get; private set; } + + protected IAPIProvider API { get; set; } + + protected Storage Storage { get; set; } + + protected Bindable Beatmap { get; private set; } // cached via load() method private SpectatorClient spectatorClient; private MultiplayerClient multiplayerClient; - protected MenuCursorContainer MenuCursorContainer; - - protected MusicController MusicController; - private Container content; protected override Container Content => content; - protected Storage Storage { get; set; } - [Cached] [Cached(typeof(IBindable))] protected readonly Bindable Ruleset = new Bindable(); @@ -119,8 +121,6 @@ namespace osu.Game /// public readonly Bindable>> AvailableMods = new Bindable>>(); - protected Bindable Beatmap { get; private set; } // cached via load() method - private Bindable fpsDisplayVisible; public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); From 4e49fbf7fbb0785019436e12e06117ce1f3f36a5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 02:30:31 +0900 Subject: [PATCH 40/65] Switch protected properties to `private` where feasible --- osu.Game/OsuGameBase.cs | 55 +++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index bbfaa62258..97f838032a 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -67,22 +67,12 @@ namespace osu.Game protected ScoreManager ScoreManager { get; private set; } - protected BeatmapDifficultyCache DifficultyCache { get; private set; } - - protected UserLookupCache UserCache { get; private set; } - protected SkinManager SkinManager { get; private set; } protected RulesetStore RulesetStore { get; private set; } - protected FileStore FileStore { get; private set; } - protected KeyBindingStore KeyBindingStore { get; private set; } - protected SettingsStore SettingsStore { get; private set; } - - protected RulesetConfigCache RulesetConfigCache { get; private set; } - protected MenuCursorContainer MenuCursorContainer { get; private set; } protected MusicController MusicController { get; private set; } @@ -93,13 +83,6 @@ namespace osu.Game protected Bindable Beatmap { get; private set; } // cached via load() method - private SpectatorClient spectatorClient; - private MultiplayerClient multiplayerClient; - - private Container content; - - protected override Container Content => content; - [Cached] [Cached(typeof(IBindable))] protected readonly Bindable Ruleset = new Bindable(); @@ -121,6 +104,24 @@ namespace osu.Game /// public readonly Bindable>> AvailableMods = new Bindable>>(); + private BeatmapDifficultyCache difficultyCache; + + private UserLookupCache userCache; + + private FileStore fileStore; + + private SettingsStore settingsStore; + + private RulesetConfigCache rulesetConfigCache; + + private SpectatorClient spectatorClient; + + private MultiplayerClient multiplayerClient; + + protected override Container Content => content; + + private Container content; + private Bindable fpsDisplayVisible; public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); @@ -246,10 +247,10 @@ namespace osu.Game var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures); dependencies.Cache(RulesetStore = new RulesetStore(contextFactory, Storage)); - dependencies.Cache(FileStore = new FileStore(contextFactory, Storage)); + dependencies.Cache(fileStore = new FileStore(contextFactory, Storage)); // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup() - dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host, () => DifficultyCache, LocalConfig)); + dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host, () => difficultyCache, LocalConfig)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap, true)); // this should likely be moved to ArchiveModelManager when another case appers where it is necessary @@ -273,19 +274,19 @@ namespace osu.Game ScoreManager.Undelete(getBeatmapScores(item), true); }); - dependencies.Cache(DifficultyCache = new BeatmapDifficultyCache()); - AddInternal(DifficultyCache); + dependencies.Cache(difficultyCache = new BeatmapDifficultyCache()); + AddInternal(difficultyCache); - dependencies.Cache(UserCache = new UserLookupCache()); - AddInternal(UserCache); + dependencies.Cache(userCache = new UserLookupCache()); + AddInternal(userCache); var scorePerformanceManager = new ScorePerformanceCache(); dependencies.Cache(scorePerformanceManager); AddInternal(scorePerformanceManager); dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore)); - dependencies.Cache(SettingsStore = new SettingsStore(contextFactory)); - dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore)); + dependencies.Cache(settingsStore = new SettingsStore(contextFactory)); + dependencies.Cache(rulesetConfigCache = new RulesetConfigCache(settingsStore)); var powerStatus = CreateBatteryInfo(); if (powerStatus != null) @@ -308,7 +309,7 @@ namespace osu.Game dependencies.CacheAs>(Beatmap); dependencies.CacheAs(Beatmap); - FileStore.Cleanup(); + fileStore.Cleanup(); // add api components to hierarchy. if (API is APIAccess apiAccess) @@ -316,7 +317,7 @@ namespace osu.Game AddInternal(spectatorClient); AddInternal(multiplayerClient); - AddInternal(RulesetConfigCache); + AddInternal(rulesetConfigCache); GlobalActionContainer globalBindings; From b8edca59ebe0db43c26c8f21dc3519de90e659d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 02:37:14 +0900 Subject: [PATCH 41/65] General function reorganisation --- osu.Game/OsuGameBase.cs | 94 ++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 97f838032a..22502b661c 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -57,8 +57,34 @@ namespace osu.Game public const int SAMPLE_CONCURRENCY = 6; + /// + /// The maximum volume at which audio tracks should playback. This can be set lower than 1 to create some head-room for sound effects. + /// + internal const double GLOBAL_TRACK_VOLUME_ADJUST = 0.5; + public bool UseDevelopmentServer { get; } + public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); + + /// + /// MD5 representation of the game executable. + /// + public string VersionHash { get; private set; } + + public bool IsDeployedBuild => AssemblyVersion.Major > 0; + + public virtual string Version + { + get + { + if (!IsDeployedBuild) + return @"local " + (DebugUtils.IsDebugBuild ? @"debug" : @"release"); + + var version = AssemblyVersion; + return $@"{version.Major}.{version.Minor}.{version.Build}"; + } + } + protected OsuConfigManager LocalConfig { get; private set; } protected SessionStatics SessionStatics { get; private set; } @@ -118,32 +144,17 @@ namespace osu.Game private MultiplayerClient multiplayerClient; + private DatabaseContextFactory contextFactory; + protected override Container Content => content; private Container content; + private DependencyContainer dependencies; + private Bindable fpsDisplayVisible; - public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); - - /// - /// MD5 representation of the game executable. - /// - public string VersionHash { get; private set; } - - public bool IsDeployedBuild => AssemblyVersion.Major > 0; - - public virtual string Version - { - get - { - if (!IsDeployedBuild) - return @"local " + (DebugUtils.IsDebugBuild ? @"debug" : @"release"); - - var version = AssemblyVersion; - return $@"{version.Major}.{version.Minor}.{version.Build}"; - } - } + private readonly BindableNumber globalTrackVolumeAdjust = new BindableNumber(GLOBAL_TRACK_VOLUME_ADJUST); public OsuGameBase() { @@ -151,23 +162,14 @@ namespace osu.Game Name = @"osu!lazer"; } - private DependencyContainer dependencies; - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => - dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - private DatabaseContextFactory contextFactory; - protected override UserInputManager CreateUserInputManager() => new OsuUserInputManager(); protected virtual BatteryInfo CreateBatteryInfo() => null; - /// - /// The maximum volume at which audio tracks should playback. This can be set lower than 1 to create some head-room for sound effects. - /// - internal const double GLOBAL_TRACK_VOLUME_ADJUST = 0.5; + protected virtual Container CreateScalingContainer() => new DrawSizePreservingFillContainer(); - private readonly BindableNumber globalTrackVolumeAdjust = new BindableNumber(GLOBAL_TRACK_VOLUME_ADJUST); + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => + dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); [BackgroundDependencyLoader] private void load() @@ -345,6 +347,19 @@ namespace osu.Game Ruleset.BindValueChanged(onRulesetChanged); } + protected override void LoadComplete() + { + base.LoadComplete(); + + // TODO: This is temporary until we reimplement the local FPS display. + // It's just to allow end-users to access the framework FPS display without knowing the shortcut key. + fpsDisplayVisible = LocalConfig.GetBindable(OsuSetting.ShowFpsDisplay); + fpsDisplayVisible.ValueChanged += visible => { FrameStatistics.Value = visible.NewValue ? FrameStatisticsMode.Minimal : FrameStatisticsMode.None; }; + fpsDisplayVisible.TriggerChange(); + + FrameStatistics.ValueChanged += e => fpsDisplayVisible.Value = e.NewValue != FrameStatisticsMode.None; + } + private void onRulesetChanged(ValueChangedEvent r) { var dict = new Dictionary>(); @@ -361,21 +376,6 @@ namespace osu.Game AvailableMods.Value = dict; } - protected virtual Container CreateScalingContainer() => new DrawSizePreservingFillContainer(); - - protected override void LoadComplete() - { - base.LoadComplete(); - - // TODO: This is temporary until we reimplement the local FPS display. - // It's just to allow end-users to access the framework FPS display without knowing the shortcut key. - fpsDisplayVisible = LocalConfig.GetBindable(OsuSetting.ShowFpsDisplay); - fpsDisplayVisible.ValueChanged += visible => { FrameStatistics.Value = visible.NewValue ? FrameStatisticsMode.Minimal : FrameStatisticsMode.None; }; - fpsDisplayVisible.TriggerChange(); - - FrameStatistics.ValueChanged += e => fpsDisplayVisible.Value = e.NewValue != FrameStatisticsMode.None; - } - private void runMigrations() { try From b4c13d837d54855a9b9b3310e5790b77f61efca9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 02:44:44 +0900 Subject: [PATCH 42/65] Move import logic out to partial class --- osu.Game/OsuGameBase.cs | 73 +------------------------------ osu.Game/OsuGameBase_Importing.cs | 57 ++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 72 deletions(-) create mode 100644 osu.Game/OsuGameBase_Importing.cs diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 22502b661c..9f73236fb0 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; -using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; @@ -41,7 +40,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Skinning; using osu.Game.Utils; -using osuTK.Input; using RuntimeInfo = osu.Framework.RuntimeInfo; namespace osu.Game @@ -51,7 +49,7 @@ namespace osu.Game /// Unlike , this class will not load any kind of UI, allowing it to be used /// for provide dependencies to test cases without interfering with them. /// - public class OsuGameBase : Framework.Game, ICanAcceptFiles + public partial class OsuGameBase : Framework.Game, ICanAcceptFiles { public const string CLIENT_STREAM_NAME = @"lazer"; @@ -399,75 +397,6 @@ namespace osu.Game } } - public override void SetHost(GameHost host) - { - base.SetHost(host); - - // may be non-null for certain tests - Storage ??= host.Storage; - - LocalConfig ??= UseDevelopmentServer - ? new DevelopmentOsuConfigManager(Storage) - : new OsuConfigManager(Storage); - } - - /// - /// Use to programatically exit the game as if the user was triggering via alt-f4. - /// Will keep persisting until an exit occurs (exit may be blocked multiple times). - /// - public void GracefullyExit() - { - if (!OnExiting()) - Exit(); - else - Scheduler.AddDelayed(GracefullyExit, 2000); - } - - protected override Storage CreateStorage(GameHost host, Storage defaultStorage) => new OsuStorage(host, defaultStorage); - - private readonly List fileImporters = new List(); - - /// - /// Register a global handler for file imports. Most recently registered will have precedence. - /// - /// The handler to register. - public void RegisterImportHandler(ICanAcceptFiles handler) => fileImporters.Insert(0, handler); - - /// - /// Unregister a global handler for file imports. - /// - /// The previously registered handler. - public void UnregisterImportHandler(ICanAcceptFiles handler) => fileImporters.Remove(handler); - - public async Task Import(params string[] paths) - { - if (paths.Length == 0) - return; - - var filesPerExtension = paths.GroupBy(p => Path.GetExtension(p).ToLowerInvariant()); - - foreach (var groups in filesPerExtension) - { - foreach (var importer in fileImporters) - { - if (importer.HandledExtensions.Contains(groups.Key)) - await importer.Import(groups.ToArray()).ConfigureAwait(false); - } - } - } - - public virtual async Task Import(params ImportTask[] tasks) - { - var tasksPerExtension = tasks.GroupBy(t => Path.GetExtension(t.Path).ToLowerInvariant()); - await Task.WhenAll(tasksPerExtension.Select(taskGroup => - { - var importer = fileImporters.FirstOrDefault(i => i.HandledExtensions.Contains(taskGroup.Key)); - return importer?.Import(taskGroup.ToArray()) ?? Task.CompletedTask; - })).ConfigureAwait(false); - } - - public IEnumerable HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions); - protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game/OsuGameBase_Importing.cs b/osu.Game/OsuGameBase_Importing.cs new file mode 100644 index 0000000000..d712da3553 --- /dev/null +++ b/osu.Game/OsuGameBase_Importing.cs @@ -0,0 +1,57 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using osu.Game.Database; + +namespace osu.Game +{ + public partial class OsuGameBase + { + private readonly List fileImporters = new List(); + + /// + /// Register a global handler for file imports. Most recently registered will have precedence. + /// + /// The handler to register. + public void RegisterImportHandler(ICanAcceptFiles handler) => fileImporters.Insert(0, handler); + + /// + /// Unregister a global handler for file imports. + /// + /// The previously registered handler. + public void UnregisterImportHandler(ICanAcceptFiles handler) => fileImporters.Remove(handler); + + public async Task Import(params string[] paths) + { + if (paths.Length == 0) + return; + + var filesPerExtension = paths.GroupBy(p => Path.GetExtension(p).ToLowerInvariant()); + + foreach (var groups in filesPerExtension) + { + foreach (var importer in fileImporters) + { + if (importer.HandledExtensions.Contains(groups.Key)) + await importer.Import(groups.ToArray()).ConfigureAwait(false); + } + } + } + + public virtual async Task Import(params ImportTask[] tasks) + { + var tasksPerExtension = tasks.GroupBy(t => Path.GetExtension(t.Path).ToLowerInvariant()); + await Task.WhenAll(tasksPerExtension.Select(taskGroup => + { + var importer = fileImporters.FirstOrDefault(i => i.HandledExtensions.Contains(taskGroup.Key)); + return importer?.Import(taskGroup.ToArray()) ?? Task.CompletedTask; + })).ConfigureAwait(false); + } + + public IEnumerable HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions); + } +} From fe6b1936cb3d69eec4646407cd2713b16112eba2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 02:45:04 +0900 Subject: [PATCH 43/65] Move `OsuUserInputManager` out from nested class --- osu.Game/Input/OsuUserInputManager.cs | 38 +++++++++++++++++++++++++++ osu.Game/OsuGameBase.cs | 32 ---------------------- 2 files changed, 38 insertions(+), 32 deletions(-) create mode 100644 osu.Game/Input/OsuUserInputManager.cs diff --git a/osu.Game/Input/OsuUserInputManager.cs b/osu.Game/Input/OsuUserInputManager.cs new file mode 100644 index 0000000000..621f1e1fc9 --- /dev/null +++ b/osu.Game/Input/OsuUserInputManager.cs @@ -0,0 +1,38 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Input; +using osuTK.Input; + +namespace osu.Game.Input +{ + public class OsuUserInputManager : UserInputManager + { + internal OsuUserInputManager() + { + } + + protected override MouseButtonEventManager CreateButtonEventManagerFor(MouseButton button) + { + switch (button) + { + case MouseButton.Right: + return new RightMouseManager(button); + } + + return base.CreateButtonEventManagerFor(button); + } + + private class RightMouseManager : MouseButtonEventManager + { + public RightMouseManager(MouseButton button) + : base(button) + { + } + + public override bool EnableDrag => true; // allow right-mouse dragging for absolute scroll in scroll containers. + public override bool EnableClick => false; + public override bool ChangeFocusOnClick => false; + } + } +} diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 9f73236fb0..659da1bc4e 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -407,37 +407,5 @@ namespace osu.Game contextFactory.FlushConnections(); } - - private class OsuUserInputManager : UserInputManager - { - protected override MouseButtonEventManager CreateButtonEventManagerFor(MouseButton button) - { - switch (button) - { - case MouseButton.Right: - return new RightMouseManager(button); - } - - return base.CreateButtonEventManagerFor(button); - } - - private class RightMouseManager : MouseButtonEventManager - { - public RightMouseManager(MouseButton button) - : base(button) - { - } - - public override bool EnableDrag => true; // allow right-mouse dragging for absolute scroll in scroll containers. - public override bool EnableClick => false; - public override bool ChangeFocusOnClick => false; - } - } - - public void Migrate(string path) - { - contextFactory.FlushConnections(); - (Storage as OsuStorage)?.Migrate(Host.GetStorage(path)); - } } } From ce96c58230db88a1ea14211ea4f4d4d927240aa3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 02:46:26 +0900 Subject: [PATCH 44/65] Move public members up --- osu.Game/OsuGameBase.cs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 659da1bc4e..dfb9bd3a99 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -160,6 +160,36 @@ namespace osu.Game Name = @"osu!lazer"; } + public override void SetHost(GameHost host) + { + base.SetHost(host); + + // may be non-null for certain tests + Storage ??= host.Storage; + + LocalConfig ??= UseDevelopmentServer + ? new DevelopmentOsuConfigManager(Storage) + : new OsuConfigManager(Storage); + } + + /// + /// Use to programatically exit the game as if the user was triggering via alt-f4. + /// Will keep persisting until an exit occurs (exit may be blocked multiple times). + /// + public void GracefullyExit() + { + if (!OnExiting()) + Exit(); + else + Scheduler.AddDelayed(GracefullyExit, 2000); + } + + public void Migrate(string path) + { + contextFactory.FlushConnections(); + (Storage as OsuStorage)?.Migrate(Host.GetStorage(path)); + } + protected override UserInputManager CreateUserInputManager() => new OsuUserInputManager(); protected virtual BatteryInfo CreateBatteryInfo() => null; @@ -169,6 +199,8 @@ namespace osu.Game protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + protected override Storage CreateStorage(GameHost host, Storage defaultStorage) => new OsuStorage(host, defaultStorage); + [BackgroundDependencyLoader] private void load() { From ead0e92d7d523b3a29a2f44e82a16fbd815ec8ff Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 28 May 2021 00:50:59 +0700 Subject: [PATCH 45/65] use select single node for blurb --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index bbbbc602bf..b34b5d9acf 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Wiki private Container createBlurb(HtmlDocument html) { - var blurbNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page__blurb')]").First(); + var blurbNode = html.DocumentNode.SelectSingleNode("//div[contains(@class, 'wiki-main-page__blurb')]"); return new Container { From 854ef0abfdc67cf87c7e20552c6db320707eb8ba Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 28 May 2021 00:55:14 +0700 Subject: [PATCH 46/65] add simple bound check --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index b34b5d9acf..c4c0b83ef4 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Wiki yield return new Drawable[] { new WikiPanelContainer(panelsNode[i++].InnerText), - new WikiPanelContainer(panelsNode[i++].InnerText), + i < panelsNode.Length ? new WikiPanelContainer(panelsNode[i++].InnerText) : null, }; } } From 1af684c4b2cb41e45f473e90285f5ac5cc192d12 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 14:15:28 +0900 Subject: [PATCH 47/65] Revert "Fix editor tests failing due to empty files being specified" This reverts commit fdbd421040efcbd9718d95841034471f930e6291. --- .../Editing/TestSceneEditorBeatmapCreation.cs | 2 - osu.Game/Beatmaps/BeatmapManager.cs | 4 +- osu.Game/Tests/Beatmaps/TestBeatmap.cs | 1 + osu.Game/Tests/Visual/EditorTestScene.cs | 43 +------------------ 4 files changed, 5 insertions(+), 45 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index dd5e01adbb..7584c74c71 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -24,8 +24,6 @@ namespace osu.Game.Tests.Visual.Editing protected override bool EditorComponentsReady => Editor.ChildrenOfType().SingleOrDefault()?.IsLoaded == true; - protected override bool IsolateSavingFromDatabase => false; - [Resolved] private BeatmapManager beatmapManager { get; set; } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 18fbd1f5c2..f459657a0e 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -240,7 +240,7 @@ namespace osu.Game.Beatmaps /// The to save the content against. The file referenced by will be replaced. /// The content to write. /// The beatmap content to write, null if to be omitted. - public virtual void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) + public void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) { var setInfo = info.BeatmapSet; @@ -282,7 +282,7 @@ namespace osu.Game.Beatmaps /// The beatmap to lookup. /// The currently loaded . Allows for optimisation where elements are shared with the new beatmap. May be returned if beatmapInfo requested matches /// A instance correlating to the provided . - public virtual WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) + public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) { if (beatmapInfo?.BeatmapSet == null) return DefaultBeatmap; diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs index 2717146c99..fa6dc5647d 100644 --- a/osu.Game/Tests/Beatmaps/TestBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs @@ -29,6 +29,7 @@ namespace osu.Game.Tests.Beatmaps BeatmapInfo.Ruleset = ruleset; BeatmapInfo.RulesetID = ruleset.ID ?? 0; BeatmapInfo.BeatmapSet.Metadata = BeatmapInfo.Metadata; + BeatmapInfo.BeatmapSet.Files = new List(); BeatmapInfo.BeatmapSet.Beatmaps = new List { BeatmapInfo }; BeatmapInfo.Length = 75000; BeatmapInfo.OnlineInfo = new BeatmapOnlineInfo(); diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index de7fdd0cf8..a9ee8e2668 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -4,18 +4,11 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Platform; using osu.Framework.Testing; -using osu.Game.Beatmaps; -using osu.Game.Database; -using osu.Game.IO.Archives; -using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components.Timeline; -using osu.Game.Skinning; namespace osu.Game.Tests.Visual { @@ -27,20 +20,10 @@ namespace osu.Game.Tests.Visual protected EditorClock EditorClock { get; private set; } - /// - /// Whether any saves performed by the editor should be isolate (and not persist) to the underlying . - /// - protected virtual bool IsolateSavingFromDatabase => true; - [BackgroundDependencyLoader] - private void load(GameHost host, AudioManager audio, RulesetStore rulesets) + private void load() { - var working = CreateWorkingBeatmap(Ruleset.Value); - - Beatmap.Value = working; - - if (IsolateSavingFromDatabase) - Dependencies.CacheAs(new TestBeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default, working)); + Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); } protected virtual bool EditorComponentsReady => Editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true @@ -82,27 +65,5 @@ namespace osu.Game.Tests.Visual public new bool HasUnsavedChanges => base.HasUnsavedChanges; } - - private class TestBeatmapManager : BeatmapManager - { - private readonly WorkingBeatmap testBeatmap; - - public TestBeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, GameHost host, WorkingBeatmap defaultBeatmap, WorkingBeatmap testBeatmap) - : base(storage, contextFactory, rulesets, api, audioManager, host, defaultBeatmap, false) - { - this.testBeatmap = testBeatmap; - } - - protected override string ComputeHash(BeatmapSetInfo item, ArchiveReader reader = null) - => string.Empty; - - public override WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) - => testBeatmap; - - public override void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) - { - // don't actually care about saving for this context. - } - } } } From 9c4f39e9681644d84b60828ee8ce613b6d81a89f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 14:15:28 +0900 Subject: [PATCH 48/65] Revert "Make `BeatmapSetInfo.Files` non-nullable" This reverts commit c24712642cc567f158f2d4a7b559429567347d8b. --- osu.Game/Beatmaps/BeatmapManager.cs | 22 ++++++++++++---------- osu.Game/Beatmaps/BeatmapSetInfo.cs | 10 ++++------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index f459657a0e..f70d29861f 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Linq.Expressions; @@ -244,6 +245,8 @@ namespace osu.Game.Beatmaps { var setInfo = info.BeatmapSet; + Debug.Assert(setInfo.Files != null); + using (var stream = new MemoryStream()) { using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) @@ -284,21 +287,20 @@ namespace osu.Game.Beatmaps /// A instance correlating to the provided . public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) { - if (beatmapInfo?.BeatmapSet == null) + if (beatmapInfo?.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) + return previous; + + if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - if (beatmapInfo == DefaultBeatmap?.BeatmapInfo) - return DefaultBeatmap; - - // if there are no files, presume the full beatmap info has not yet been fetched from the database. - if (beatmapInfo.BeatmapSet.Files.Count == 0) + if (beatmapInfo.BeatmapSet.Files == null) { - int lookupId = beatmapInfo.ID; - beatmapInfo = QueryBeatmap(b => b.ID == lookupId); + var info = beatmapInfo; + beatmapInfo = QueryBeatmap(b => b.ID == info.ID); } - if (beatmapInfo.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) - return previous; + if (beatmapInfo == null) + return DefaultBeatmap; lock (workingCache) { diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index 3b1ff4ced0..1ce42535a0 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Testing; using osu.Game.Database; @@ -32,9 +31,6 @@ namespace osu.Game.Beatmaps public List Beatmaps { get; set; } - [NotNull] - public List Files { get; set; } = new List(); - [NotMapped] public BeatmapSetOnlineInfo OnlineInfo { get; set; } @@ -61,14 +57,16 @@ namespace osu.Game.Beatmaps public string Hash { get; set; } - public string StoryboardFile => Files.Find(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename; + public string StoryboardFile => Files?.Find(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename; /// /// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null. /// The path returned is relative to the user file storage. /// /// The name of the file to get the storage path of. - public string GetPathForFile(string filename) => Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; + public string GetPathForFile(string filename) => Files?.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; + + public List Files { get; set; } public override string ToString() => Metadata?.ToString() ?? base.ToString(); From e52c0a34f82a6b93c740b4c2d3d068bc3c52196a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 14:31:09 +0900 Subject: [PATCH 49/65] Add temporary accounting for tests with null files --- osu.Game/Beatmaps/BeatmapManager.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index f70d29861f..2e2bc96c21 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -293,7 +293,11 @@ namespace osu.Game.Beatmaps if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - if (beatmapInfo.BeatmapSet.Files == null) + // files may be null in some tests. + if (beatmapInfo.BeatmapSet?.Files == null) + return DefaultBeatmap; + + if (beatmapInfo.BeatmapSet.Files.Count == 0) { var info = beatmapInfo; beatmapInfo = QueryBeatmap(b => b.ID == info.ID); From 330d61862dba5abcd539f41997e614217de3f901 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 14:41:01 +0900 Subject: [PATCH 50/65] Add a mention of why `StartHidden` is required --- osu.Game/Overlays/Dialog/PopupDialog.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index c04ad7afb5..cd02900e88 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -95,6 +95,8 @@ namespace osu.Game.Overlays.Dialog } } + // We always want dialogs to show their appear animation, so we request they start hidden. + // Normally this would not be required, but is here due to the manual Show() call that occurs before LoadComplete(). protected override bool StartHidden => true; protected PopupDialog() From 1d5e8f4a912584428dee430764e49e5c6286a17b Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 28 May 2021 17:19:36 +0900 Subject: [PATCH 51/65] Fix wrong/misleading comment of `InitialLifetimeOffset` --- .../Objects/Drawables/DrawableHitObject.cs | 15 +++------------ .../Rulesets/Objects/HitObjectLifetimeEntry.cs | 5 ++--- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index cca55819c5..5faefbf469 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -11,7 +11,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Performance; using osu.Framework.Graphics.Primitives; using osu.Framework.Threading; using osu.Game.Audio; @@ -445,9 +444,7 @@ namespace osu.Game.Rulesets.Objects.Drawables /// /// Apply (generally fade-in) transforms leading into the start time. - /// The local drawable hierarchy is recursively delayed to for convenience. - /// - /// By default this will fade in the object from zero with no duration. + /// By default, this will fade in the object from zero with no duration. /// /// /// This is called once before every . This is to ensure a good state in the case @@ -623,17 +620,11 @@ namespace osu.Game.Rulesets.Objects.Drawables protected internal new ScheduledDelegate Schedule(Action action) => base.Schedule(action); /// - /// A safe offset prior to the start time of at which this may begin displaying contents. + /// A offset prior to the start time of at which this may begin displaying contents. /// By default, s are assumed to display their contents within 10 seconds prior to the start time of . /// /// - /// This is only used as an optimisation to delay the initial update of this and may be tuned more aggressively if required. - /// It is indirectly used to decide the automatic transform offset provided to . - /// A more accurate should be set for further optimisation (in , for example). - /// - /// Only has an effect if this is not being pooled. - /// For pooled s, use instead. - /// + /// The initial transformation () starts at this offset before the start time of . /// protected virtual double InitialLifetimeOffset => 10000; diff --git a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs index 0d1eb68f07..cf62226d94 100644 --- a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs +++ b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs @@ -82,9 +82,8 @@ namespace osu.Game.Rulesets.Objects /// By default, s are assumed to display their contents within 10 seconds prior to their start time. /// /// - /// This is only used as an optimisation to delay the initial update of the and may be tuned more aggressively if required. - /// It is indirectly used to decide the automatic transform offset provided to . - /// A more accurate should be set for further optimisation (in , for example). + /// This is only used as an optimisation to delay the initial application of the to a . + /// A more accurate should be set on the hit object application, for further optimisation. /// protected virtual double InitialLifetimeOffset => 10000; From ee5eb9576fc1f47c6d250b141d8f496ca2113258 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 18:10:27 +0900 Subject: [PATCH 52/65] Fix completely wrong conditional logic --- osu.Game/Beatmaps/BeatmapManager.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 2e2bc96c21..23810367a1 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -293,11 +293,9 @@ namespace osu.Game.Beatmaps if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - // files may be null in some tests. - if (beatmapInfo.BeatmapSet?.Files == null) - return DefaultBeatmap; - - if (beatmapInfo.BeatmapSet.Files.Count == 0) + // force a re-query if files are not in a state which looks like the model has + // full database information present. + if (beatmapInfo.BeatmapSet.Files == null || beatmapInfo.BeatmapSet.Files.Count == 0) { var info = beatmapInfo; beatmapInfo = QueryBeatmap(b => b.ID == info.ID); From ba80361c4c5483f3981aa9103d365e8f3b74a27b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 18:37:33 +0900 Subject: [PATCH 53/65] Fix tests that were previously doing reference comparisons --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 643f4131dc..2eb6d3f80e 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -358,7 +358,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap.Equals(target)); // this is an important check, to make sure updateComponentFromBeatmap() was actually run - AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo == target); + AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.Equals(target)); } [Test] @@ -390,7 +390,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("has correct ruleset", () => Ruleset.Value.ID == 0); // this is an important check, to make sure updateComponentFromBeatmap() was actually run - AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo == target); + AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.Equals(target)); } [Test] @@ -781,7 +781,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3); - AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo == groupIcon.Items.First().Beatmap); + AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo.Equals(groupIcon.Items.First().Beatmap)); } [Test] From 43bf734816db2051dc88b351f8be086a47a6734c Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 28 May 2021 21:26:21 +0900 Subject: [PATCH 54/65] Reset lifetime on `HitObject.DefaultsApplied` --- osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs index 0d1eb68f07..4e11c9aeee 100644 --- a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs +++ b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs @@ -35,7 +35,9 @@ namespace osu.Game.Rulesets.Objects HitObject = hitObject; startTimeBindable.BindTo(HitObject.StartTimeBindable); - startTimeBindable.BindValueChanged(onStartTimeChanged, true); + startTimeBindable.BindValueChanged(_ => setInitialLifetime(), true); + + HitObject.DefaultsApplied += _ => setInitialLifetime(); } // The lifetime, as set by the hitobject. @@ -89,8 +91,8 @@ namespace osu.Game.Rulesets.Objects protected virtual double InitialLifetimeOffset => 10000; /// - /// Resets according to the change in start time of the . + /// Set using . /// - private void onStartTimeChanged(ValueChangedEvent startTime) => LifetimeStart = HitObject.StartTime - InitialLifetimeOffset; + private void setInitialLifetime() => LifetimeStart = HitObject.StartTime - InitialLifetimeOffset; } } From 68c5f4813e6c0e5fa0964761b5be360236964d47 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 28 May 2021 21:27:10 +0900 Subject: [PATCH 55/65] Add test of lifetime update on DefaultsApplied --- osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs index 0bec02c488..5f99b886fb 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs @@ -3,6 +3,8 @@ using NUnit.Framework; using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Tests.Visual; @@ -70,6 +72,15 @@ namespace osu.Game.Tests.Gameplay AddAssert("Lifetime is changed", () => entry.LifetimeStart == double.MinValue && entry.LifetimeEnd == 1000); } + [Test] + public void TestLifetimeUpdatedOnDefaultApplied() + { + TestLifetimeEntry entry = null; + AddStep("Create entry", () => entry = new TestLifetimeEntry(new HitObject()) { LifetimeStart = 1 }); + AddStep("ApplyDefaults", () => entry.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty())); + AddAssert("Lifetime is updated", () => entry.LifetimeStart == -TestLifetimeEntry.INITIAL_LIFETIME_OFFSET); + } + private class TestDrawableHitObject : DrawableHitObject { public const double INITIAL_LIFETIME_OFFSET = 100; From 265dfe54160221e05f2a5577fc10a21f7440d6b2 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 28 May 2021 21:51:48 +0900 Subject: [PATCH 56/65] Add test case of DHO setting LifetimeStart in OnApply --- .../Gameplay/TestSceneDrawableHitObject.cs | 22 +++++++++++++++++++ .../Objects/HitObjectLifetimeEntry.cs | 2 ++ 2 files changed, 24 insertions(+) diff --git a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs index 5f99b886fb..3de2dc72bb 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs @@ -79,17 +79,39 @@ namespace osu.Game.Tests.Gameplay AddStep("Create entry", () => entry = new TestLifetimeEntry(new HitObject()) { LifetimeStart = 1 }); AddStep("ApplyDefaults", () => entry.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty())); AddAssert("Lifetime is updated", () => entry.LifetimeStart == -TestLifetimeEntry.INITIAL_LIFETIME_OFFSET); + + TestDrawableHitObject dho = null; + AddStep("Create DHO", () => + { + dho = new TestDrawableHitObject(null); + dho.Apply(entry); + Child = dho; + dho.SetLifetimeStartOnApply = true; + }); + AddStep("ApplyDefaults", () => entry.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty())); + AddAssert("Lifetime is correct", () => dho.LifetimeStart == TestDrawableHitObject.LIFETIME_ON_APPLY && entry.LifetimeStart == TestDrawableHitObject.LIFETIME_ON_APPLY); } private class TestDrawableHitObject : DrawableHitObject { public const double INITIAL_LIFETIME_OFFSET = 100; + public const double LIFETIME_ON_APPLY = 222; protected override double InitialLifetimeOffset => INITIAL_LIFETIME_OFFSET; + public bool SetLifetimeStartOnApply; + public TestDrawableHitObject(HitObject hitObject) : base(hitObject) { } + + protected override void OnApply() + { + base.OnApply(); + + if (SetLifetimeStartOnApply) + LifetimeStart = LIFETIME_ON_APPLY; + } } private class TestLifetimeEntry : HitObjectLifetimeEntry diff --git a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs index 4e11c9aeee..3375f41cc3 100644 --- a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs +++ b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs @@ -37,6 +37,8 @@ namespace osu.Game.Rulesets.Objects startTimeBindable.BindTo(HitObject.StartTimeBindable); startTimeBindable.BindValueChanged(_ => setInitialLifetime(), true); + // It is important to subscribe to this event before applied to a DrawableHitObject. + // Otherwise DHO cannot overwrite LifetimeStart set in setInitialLifetime. HitObject.DefaultsApplied += _ => setInitialLifetime(); } From 200fecc774d7e0e79b63dc3267e339a976cc58f4 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 29 May 2021 21:22:39 +0300 Subject: [PATCH 57/65] Fix missing using directive --- osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 31d29e6807..cc53e50884 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Graphics.Containers; From 53cbf369d7a55e1c6ef5f38af9d35de8ce4739ae Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 29 May 2021 21:22:46 +0300 Subject: [PATCH 58/65] Fix potential nullref --- osu.Game/Skinning/LegacyBeatmapSkin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 04b2346c6a..caf37e5bc9 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -71,6 +71,6 @@ namespace osu.Game.Skinning } private static SkinInfo createSkinInfo(BeatmapInfo beatmap) => - new SkinInfo { Name = beatmap.ToString(), Creator = beatmap.Metadata.Author.ToString() }; + new SkinInfo { Name = beatmap.ToString(), Creator = beatmap.Metadata?.AuthorString }; } } From fbc316ea1d6cf401b0a3cf75ecb604b51f1c2211 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 27 May 2021 05:15:29 +0300 Subject: [PATCH 59/65] Fix legacy skin transformers potentially ignoring source implementations --- .../Legacy/CatchLegacySkinTransformer.cs | 20 +++++++++++-------- .../Legacy/ManiaLegacySkinTransformer.cs | 8 +++++--- .../Legacy/OsuLegacySkinTransformer.cs | 7 ++++--- .../Legacy/TaikoLegacySkinTransformer.cs | 7 ++++--- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 1b48832ed6..6efd9e88c4 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -28,12 +28,15 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { case HUDSkinComponents.ComboCounter: // catch may provide its own combo counter; hide the default. - return providesComboCounter ? Drawable.Empty() : null; + if (providesComboCounter) + return Drawable.Empty(); + + break; } } if (!(component is CatchSkinComponent catchSkinComponent)) - return null; + return Source.GetDrawableComponent(component); switch (catchSkinComponent.Component) { @@ -41,19 +44,19 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy if (GetTexture("fruit-pear") != null) return new LegacyFruitPiece(); - break; + return null; case CatchSkinComponents.Banana: if (GetTexture("fruit-bananas") != null) return new LegacyBananaPiece(); - break; + return null; case CatchSkinComponents.Droplet: if (GetTexture("fruit-drop") != null) return new LegacyDropletPiece(); - break; + return null; case CatchSkinComponents.CatcherIdle: return this.GetAnimation("fruit-catcher-idle", true, true, true) ?? @@ -71,10 +74,11 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy if (providesComboCounter) return new LegacyCatchComboCounter(Source); - break; - } + return null; - return null; + default: + return Source.GetDrawableComponent(component); + } } public override IBindable GetConfig(TLookup lookup) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 24ccae895d..6617fcefe7 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -120,12 +120,14 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy case ManiaSkinComponents.StageForeground: return new LegacyStageForeground(); + + default: + return Source.GetDrawableComponent(component); } - break; + default: + return Source.GetDrawableComponent(component); } - - return null; } private Drawable getResult(HitResult result) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 88302ebc57..f1376551f5 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy public override Drawable GetDrawableComponent(ISkinComponent component) { if (!(component is OsuSkinComponent osuComponent)) - return null; + return Source.GetDrawableComponent(component); switch (osuComponent.Component) { @@ -115,9 +115,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return new LegacyOldStyleSpinner(); return null; - } - return null; + default: + return Source.GetDrawableComponent(component); + } } public override IBindable GetConfig(TLookup lookup) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 3e506f69ce..05778a80ef 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } if (!(component is TaikoSkinComponent taikoComponent)) - return null; + return Source.GetDrawableComponent(component); switch (taikoComponent.Component) { @@ -130,9 +130,10 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy case TaikoSkinComponents.Mascot: return new DrawableTaikoMascot(); - } - return Source.GetDrawableComponent(component); + default: + return Source.GetDrawableComponent(component); + } } private string getHitName(TaikoSkinComponents component) From abb77b95b4c1e3e8a28f4c7b40b320c5ee459bc1 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Sun, 30 May 2021 13:06:28 +0900 Subject: [PATCH 60/65] Fix comment grammar --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 5faefbf469..6c688c1625 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -620,7 +620,7 @@ namespace osu.Game.Rulesets.Objects.Drawables protected internal new ScheduledDelegate Schedule(Action action) => base.Schedule(action); /// - /// A offset prior to the start time of at which this may begin displaying contents. + /// An offset prior to the start time of at which this may begin displaying contents. /// By default, s are assumed to display their contents within 10 seconds prior to the start time of . /// /// From 50d71faf565ea5f11df4d9192379de33d240e5f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 30 May 2021 17:55:10 +0900 Subject: [PATCH 61/65] Restructure lookup code to avoid repeating the base call --- .../Legacy/CatchLegacySkinTransformer.cs | 63 +++++++++---------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 6efd9e88c4..e43d88ad40 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -35,50 +35,49 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy } } - if (!(component is CatchSkinComponent catchSkinComponent)) - return Source.GetDrawableComponent(component); - - switch (catchSkinComponent.Component) + if (component is CatchSkinComponent catchSkinComponent) { - case CatchSkinComponents.Fruit: - if (GetTexture("fruit-pear") != null) - return new LegacyFruitPiece(); + switch (catchSkinComponent.Component) + { + case CatchSkinComponents.Fruit: + if (GetTexture("fruit-pear") != null) + return new LegacyFruitPiece(); - return null; + return null; - case CatchSkinComponents.Banana: - if (GetTexture("fruit-bananas") != null) - return new LegacyBananaPiece(); + case CatchSkinComponents.Banana: + if (GetTexture("fruit-bananas") != null) + return new LegacyBananaPiece(); - return null; + return null; - case CatchSkinComponents.Droplet: - if (GetTexture("fruit-drop") != null) - return new LegacyDropletPiece(); + case CatchSkinComponents.Droplet: + if (GetTexture("fruit-drop") != null) + return new LegacyDropletPiece(); - return null; + return null; - case CatchSkinComponents.CatcherIdle: - return this.GetAnimation("fruit-catcher-idle", true, true, true) ?? - this.GetAnimation("fruit-ryuuta", true, true, true); + case CatchSkinComponents.CatcherIdle: + return this.GetAnimation("fruit-catcher-idle", true, true, true) ?? + this.GetAnimation("fruit-ryuuta", true, true, true); - case CatchSkinComponents.CatcherFail: - return this.GetAnimation("fruit-catcher-fail", true, true, true) ?? - this.GetAnimation("fruit-ryuuta", true, true, true); + case CatchSkinComponents.CatcherFail: + return this.GetAnimation("fruit-catcher-fail", true, true, true) ?? + this.GetAnimation("fruit-ryuuta", true, true, true); - case CatchSkinComponents.CatcherKiai: - return this.GetAnimation("fruit-catcher-kiai", true, true, true) ?? - this.GetAnimation("fruit-ryuuta", true, true, true); + case CatchSkinComponents.CatcherKiai: + return this.GetAnimation("fruit-catcher-kiai", true, true, true) ?? + this.GetAnimation("fruit-ryuuta", true, true, true); - case CatchSkinComponents.CatchComboCounter: - if (providesComboCounter) - return new LegacyCatchComboCounter(Source); + case CatchSkinComponents.CatchComboCounter: + if (providesComboCounter) + return new LegacyCatchComboCounter(Source); - return null; - - default: - return Source.GetDrawableComponent(component); + return null; + } } + + return Source.GetDrawableComponent(component); } public override IBindable GetConfig(TLookup lookup) From 17574833fb83dd3f71bcf86acb22b3d44c0603a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 30 May 2021 19:15:59 +0900 Subject: [PATCH 62/65] Update other transformers with similar refactored logic --- .../Legacy/ManiaLegacySkinTransformer.cs | 8 +- .../Legacy/OsuLegacySkinTransformer.cs | 143 +++++++++--------- .../Legacy/TaikoLegacySkinTransformer.cs | 131 ++++++++-------- 3 files changed, 139 insertions(+), 143 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 6617fcefe7..261b8b1fad 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -120,14 +120,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy case ManiaSkinComponents.StageForeground: return new LegacyStageForeground(); - - default: - return Source.GetDrawableComponent(component); } - default: - return Source.GetDrawableComponent(component); + break; } + + return Source.GetDrawableComponent(component); } private Drawable getResult(HitResult result) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index f1376551f5..ffd4f78400 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -34,91 +34,90 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy public override Drawable GetDrawableComponent(ISkinComponent component) { - if (!(component is OsuSkinComponent osuComponent)) - return Source.GetDrawableComponent(component); - - switch (osuComponent.Component) + if (component is OsuSkinComponent osuComponent) { - case OsuSkinComponents.FollowPoint: - return this.GetAnimation(component.LookupName, true, false, true, startAtCurrentTime: false); + switch (osuComponent.Component) + { + case OsuSkinComponents.FollowPoint: + return this.GetAnimation(component.LookupName, true, false, true, startAtCurrentTime: false); - case OsuSkinComponents.SliderFollowCircle: - var followCircle = this.GetAnimation("sliderfollowcircle", true, true, true); - if (followCircle != null) - // follow circles are 2x the hitcircle resolution in legacy skins (since they are scaled down from >1x - followCircle.Scale *= 0.5f; - return followCircle; + case OsuSkinComponents.SliderFollowCircle: + var followCircle = this.GetAnimation("sliderfollowcircle", true, true, true); + if (followCircle != null) + // follow circles are 2x the hitcircle resolution in legacy skins (since they are scaled down from >1x + followCircle.Scale *= 0.5f; + return followCircle; - case OsuSkinComponents.SliderBall: - var sliderBallContent = this.GetAnimation("sliderb", true, true, animationSeparator: ""); + case OsuSkinComponents.SliderBall: + var sliderBallContent = this.GetAnimation("sliderb", true, true, animationSeparator: ""); - // todo: slider ball has a custom frame delay based on velocity - // Math.Max((150 / Velocity) * GameBase.SIXTY_FRAME_TIME, GameBase.SIXTY_FRAME_TIME); + // todo: slider ball has a custom frame delay based on velocity + // Math.Max((150 / Velocity) * GameBase.SIXTY_FRAME_TIME, GameBase.SIXTY_FRAME_TIME); - if (sliderBallContent != null) - return new LegacySliderBall(sliderBallContent); + if (sliderBallContent != null) + return new LegacySliderBall(sliderBallContent); - return null; - - case OsuSkinComponents.SliderBody: - if (hasHitCircle.Value) - return new LegacySliderBody(); - - return null; - - case OsuSkinComponents.SliderTailHitCircle: - if (hasHitCircle.Value) - return new LegacyMainCirclePiece("sliderendcircle", false); - - return null; - - case OsuSkinComponents.SliderHeadHitCircle: - if (hasHitCircle.Value) - return new LegacyMainCirclePiece("sliderstartcircle"); - - return null; - - case OsuSkinComponents.HitCircle: - if (hasHitCircle.Value) - return new LegacyMainCirclePiece(); - - return null; - - case OsuSkinComponents.Cursor: - if (Source.GetTexture("cursor") != null) - return new LegacyCursor(); - - return null; - - case OsuSkinComponents.CursorTrail: - if (Source.GetTexture("cursortrail") != null) - return new LegacyCursorTrail(); - - return null; - - case OsuSkinComponents.HitCircleText: - if (!this.HasFont(LegacyFont.HitCircle)) return null; - return new LegacySpriteText(LegacyFont.HitCircle) - { - // stable applies a blanket 0.8x scale to hitcircle fonts - Scale = new Vector2(0.8f), - }; + case OsuSkinComponents.SliderBody: + if (hasHitCircle.Value) + return new LegacySliderBody(); - case OsuSkinComponents.SpinnerBody: - bool hasBackground = Source.GetTexture("spinner-background") != null; + return null; - if (Source.GetTexture("spinner-top") != null && !hasBackground) - return new LegacyNewStyleSpinner(); - else if (hasBackground) - return new LegacyOldStyleSpinner(); + case OsuSkinComponents.SliderTailHitCircle: + if (hasHitCircle.Value) + return new LegacyMainCirclePiece("sliderendcircle", false); - return null; + return null; - default: - return Source.GetDrawableComponent(component); + case OsuSkinComponents.SliderHeadHitCircle: + if (hasHitCircle.Value) + return new LegacyMainCirclePiece("sliderstartcircle"); + + return null; + + case OsuSkinComponents.HitCircle: + if (hasHitCircle.Value) + return new LegacyMainCirclePiece(); + + return null; + + case OsuSkinComponents.Cursor: + if (Source.GetTexture("cursor") != null) + return new LegacyCursor(); + + return null; + + case OsuSkinComponents.CursorTrail: + if (Source.GetTexture("cursortrail") != null) + return new LegacyCursorTrail(); + + return null; + + case OsuSkinComponents.HitCircleText: + if (!this.HasFont(LegacyFont.HitCircle)) + return null; + + return new LegacySpriteText(LegacyFont.HitCircle) + { + // stable applies a blanket 0.8x scale to hitcircle fonts + Scale = new Vector2(0.8f), + }; + + case OsuSkinComponents.SpinnerBody: + bool hasBackground = Source.GetTexture("spinner-background") != null; + + if (Source.GetTexture("spinner-top") != null && !hasBackground) + return new LegacyNewStyleSpinner(); + else if (hasBackground) + return new LegacyOldStyleSpinner(); + + return null; + } } + + return Source.GetDrawableComponent(component); } public override IBindable GetConfig(TLookup lookup) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 05778a80ef..e0557c8617 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -38,102 +38,101 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy return Drawable.Empty().With(d => d.Expire()); } - if (!(component is TaikoSkinComponent taikoComponent)) - return Source.GetDrawableComponent(component); - - switch (taikoComponent.Component) + if (component is TaikoSkinComponent taikoComponent) { - case TaikoSkinComponents.DrumRollBody: - if (GetTexture("taiko-roll-middle") != null) - return new LegacyDrumRoll(); + switch (taikoComponent.Component) + { + case TaikoSkinComponents.DrumRollBody: + if (GetTexture("taiko-roll-middle") != null) + return new LegacyDrumRoll(); - return null; + return null; - case TaikoSkinComponents.InputDrum: - if (GetTexture("taiko-bar-left") != null) - return new LegacyInputDrum(); + case TaikoSkinComponents.InputDrum: + if (GetTexture("taiko-bar-left") != null) + return new LegacyInputDrum(); - return null; + return null; - case TaikoSkinComponents.CentreHit: - case TaikoSkinComponents.RimHit: + case TaikoSkinComponents.CentreHit: + case TaikoSkinComponents.RimHit: - if (GetTexture("taikohitcircle") != null) - return new LegacyHit(taikoComponent.Component); + if (GetTexture("taikohitcircle") != null) + return new LegacyHit(taikoComponent.Component); - return null; + return null; - case TaikoSkinComponents.DrumRollTick: - return this.GetAnimation("sliderscorepoint", false, false); + case TaikoSkinComponents.DrumRollTick: + return this.GetAnimation("sliderscorepoint", false, false); - case TaikoSkinComponents.HitTarget: - if (GetTexture("taikobigcircle") != null) - return new TaikoLegacyHitTarget(); + case TaikoSkinComponents.HitTarget: + if (GetTexture("taikobigcircle") != null) + return new TaikoLegacyHitTarget(); - return null; + return null; - case TaikoSkinComponents.PlayfieldBackgroundRight: - if (GetTexture("taiko-bar-right") != null) - return new TaikoLegacyPlayfieldBackgroundRight(); + case TaikoSkinComponents.PlayfieldBackgroundRight: + if (GetTexture("taiko-bar-right") != null) + return new TaikoLegacyPlayfieldBackgroundRight(); - return null; + return null; - case TaikoSkinComponents.PlayfieldBackgroundLeft: - // This is displayed inside LegacyInputDrum. It is required to be there for layout purposes (can be seen on legacy skins). - if (GetTexture("taiko-bar-right") != null) - return Drawable.Empty(); + case TaikoSkinComponents.PlayfieldBackgroundLeft: + // This is displayed inside LegacyInputDrum. It is required to be there for layout purposes (can be seen on legacy skins). + if (GetTexture("taiko-bar-right") != null) + return Drawable.Empty(); - return null; + return null; - case TaikoSkinComponents.BarLine: - if (GetTexture("taiko-barline") != null) - return new LegacyBarLine(); + case TaikoSkinComponents.BarLine: + if (GetTexture("taiko-barline") != null) + return new LegacyBarLine(); - return null; + return null; - case TaikoSkinComponents.TaikoExplosionMiss: + case TaikoSkinComponents.TaikoExplosionMiss: - var missSprite = this.GetAnimation(getHitName(taikoComponent.Component), true, false); - if (missSprite != null) - return new LegacyHitExplosion(missSprite); + var missSprite = this.GetAnimation(getHitName(taikoComponent.Component), true, false); + if (missSprite != null) + return new LegacyHitExplosion(missSprite); - return null; + return null; - case TaikoSkinComponents.TaikoExplosionOk: - case TaikoSkinComponents.TaikoExplosionGreat: + case TaikoSkinComponents.TaikoExplosionOk: + case TaikoSkinComponents.TaikoExplosionGreat: - var hitName = getHitName(taikoComponent.Component); - var hitSprite = this.GetAnimation(hitName, true, false); + var hitName = getHitName(taikoComponent.Component); + var hitSprite = this.GetAnimation(hitName, true, false); - if (hitSprite != null) - { - var strongHitSprite = this.GetAnimation($"{hitName}k", true, false); + if (hitSprite != null) + { + var strongHitSprite = this.GetAnimation($"{hitName}k", true, false); - return new LegacyHitExplosion(hitSprite, strongHitSprite); - } + return new LegacyHitExplosion(hitSprite, strongHitSprite); + } - return null; + return null; - case TaikoSkinComponents.TaikoExplosionKiai: - // suppress the default kiai explosion if the skin brings its own sprites. - // the drawable needs to expire as soon as possible to avoid accumulating empty drawables on the playfield. - if (hasExplosion.Value) - return Drawable.Empty().With(d => d.Expire()); + case TaikoSkinComponents.TaikoExplosionKiai: + // suppress the default kiai explosion if the skin brings its own sprites. + // the drawable needs to expire as soon as possible to avoid accumulating empty drawables on the playfield. + if (hasExplosion.Value) + return Drawable.Empty().With(d => d.Expire()); - return null; + return null; - case TaikoSkinComponents.Scroller: - if (GetTexture("taiko-slider") != null) - return new LegacyTaikoScroller(); + case TaikoSkinComponents.Scroller: + if (GetTexture("taiko-slider") != null) + return new LegacyTaikoScroller(); - return null; + return null; - case TaikoSkinComponents.Mascot: - return new DrawableTaikoMascot(); - - default: - return Source.GetDrawableComponent(component); + case TaikoSkinComponents.Mascot: + return new DrawableTaikoMascot(); + } } + + return Source.GetDrawableComponent(component); } private string getHitName(TaikoSkinComponents component) From bca8a9ea53890906a806e8f97764147bd5d2098f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 31 May 2021 10:02:02 +0900 Subject: [PATCH 63/65] Fix HandleFrame crashing when not playing --- osu.Game/Online/Spectator/SpectatorClient.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Online/Spectator/SpectatorClient.cs b/osu.Game/Online/Spectator/SpectatorClient.cs index a4fc963328..2546374b21 100644 --- a/osu.Game/Online/Spectator/SpectatorClient.cs +++ b/osu.Game/Online/Spectator/SpectatorClient.cs @@ -235,6 +235,9 @@ namespace osu.Game.Online.Spectator { Debug.Assert(ThreadSafety.IsUpdateThread); + if (!IsPlaying) + return; + if (frame is IConvertibleReplayFrame convertible) pendingFrames.Enqueue(convertible.ToLegacy(currentBeatmap)); From a4dca6f839d7973372b78023e8133b8e5f8e993f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 31 May 2021 13:39:18 +0900 Subject: [PATCH 64/65] Reorder methods around load() --- osu.Game/OsuGameBase.cs | 82 ++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index dfb9bd3a99..918f231a19 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -160,47 +160,6 @@ namespace osu.Game Name = @"osu!lazer"; } - public override void SetHost(GameHost host) - { - base.SetHost(host); - - // may be non-null for certain tests - Storage ??= host.Storage; - - LocalConfig ??= UseDevelopmentServer - ? new DevelopmentOsuConfigManager(Storage) - : new OsuConfigManager(Storage); - } - - /// - /// Use to programatically exit the game as if the user was triggering via alt-f4. - /// Will keep persisting until an exit occurs (exit may be blocked multiple times). - /// - public void GracefullyExit() - { - if (!OnExiting()) - Exit(); - else - Scheduler.AddDelayed(GracefullyExit, 2000); - } - - public void Migrate(string path) - { - contextFactory.FlushConnections(); - (Storage as OsuStorage)?.Migrate(Host.GetStorage(path)); - } - - protected override UserInputManager CreateUserInputManager() => new OsuUserInputManager(); - - protected virtual BatteryInfo CreateBatteryInfo() => null; - - protected virtual Container CreateScalingContainer() => new DrawSizePreservingFillContainer(); - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => - dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - protected override Storage CreateStorage(GameHost host, Storage defaultStorage) => new OsuStorage(host, defaultStorage); - [BackgroundDependencyLoader] private void load() { @@ -390,6 +349,47 @@ namespace osu.Game FrameStatistics.ValueChanged += e => fpsDisplayVisible.Value = e.NewValue != FrameStatisticsMode.None; } + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => + dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + + public override void SetHost(GameHost host) + { + base.SetHost(host); + + // may be non-null for certain tests + Storage ??= host.Storage; + + LocalConfig ??= UseDevelopmentServer + ? new DevelopmentOsuConfigManager(Storage) + : new OsuConfigManager(Storage); + } + + /// + /// Use to programatically exit the game as if the user was triggering via alt-f4. + /// Will keep persisting until an exit occurs (exit may be blocked multiple times). + /// + public void GracefullyExit() + { + if (!OnExiting()) + Exit(); + else + Scheduler.AddDelayed(GracefullyExit, 2000); + } + + public void Migrate(string path) + { + contextFactory.FlushConnections(); + (Storage as OsuStorage)?.Migrate(Host.GetStorage(path)); + } + + protected override UserInputManager CreateUserInputManager() => new OsuUserInputManager(); + + protected virtual BatteryInfo CreateBatteryInfo() => null; + + protected virtual Container CreateScalingContainer() => new DrawSizePreservingFillContainer(); + + protected override Storage CreateStorage(GameHost host, Storage defaultStorage) => new OsuStorage(host, defaultStorage); + private void onRulesetChanged(ValueChangedEvent r) { var dict = new Dictionary>(); From 0c101d285925cfd1e392dc383f8186a62a07a9a9 Mon Sep 17 00:00:00 2001 From: ekrctb <32995012+ekrctb@users.noreply.github.com> Date: Mon, 31 May 2021 13:41:49 +0900 Subject: [PATCH 65/65] Apply comment rewording suggestion Co-authored-by: Dan Balasescu --- osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs index 3375f41cc3..c275ba32f6 100644 --- a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs +++ b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs @@ -37,8 +37,8 @@ namespace osu.Game.Rulesets.Objects startTimeBindable.BindTo(HitObject.StartTimeBindable); startTimeBindable.BindValueChanged(_ => setInitialLifetime(), true); - // It is important to subscribe to this event before applied to a DrawableHitObject. - // Otherwise DHO cannot overwrite LifetimeStart set in setInitialLifetime. + // Subscribe to this event before the DrawableHitObject so that the local callback is invoked before the entry is re-applied as a result of DefaultsApplied. + // This way, the DrawableHitObject can use OnApply() to overwrite the LifetimeStart that was set inside setInitialLifetime(). HitObject.DefaultsApplied += _ => setInitialLifetime(); }