From 2cd07b2d3c8d6e54e82c352b17870e48bcd0c060 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Sep 2020 12:48:11 +0900 Subject: [PATCH 1/6] Fix editor crash on saving more than once I'm fixing this in the simplest way possible as this kind of issue is specific to EF core, which may cease to exist quite soon. Turns out the re-retrieval of the beatmap set causes concurrency confusion and wasn't actually needed in my final iteration of the new beatmap logic. --- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 34bb578b2a..4496f3b330 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -231,7 +231,7 @@ namespace osu.Game.Beatmaps /// The beatmap content to write, null if to be omitted. public void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) { - var setInfo = QueryBeatmapSet(s => s.Beatmaps.Any(b => b.ID == info.ID)); + var setInfo = info.BeatmapSet; using (var stream = new MemoryStream()) { From d3957e6155de4871e74d41fc7efe91b6eda53d6e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Sep 2020 18:48:02 +0900 Subject: [PATCH 2/6] Move title specification for settings groups to constructor Using an abstract property was awkward for this as it is being consumed in the underlying constructor but could not be dynamically set in time from a derived class. --- .../Gameplay/TestSceneReplaySettingsOverlay.cs | 5 ++++- .../Ladder/Components/LadderEditorSettings.cs | 7 +++++-- osu.Game/Rulesets/Edit/ToolboxGroup.cs | 3 +-- .../Play/PlayerSettings/CollectionSettings.cs | 5 ++++- .../Play/PlayerSettings/DiscussionSettings.cs | 5 ++++- .../Screens/Play/PlayerSettings/InputSettings.cs | 3 +-- .../Screens/Play/PlayerSettings/PlaybackSettings.cs | 3 +-- .../Play/PlayerSettings/PlayerSettingsGroup.cs | 13 ++++++------- .../Screens/Play/PlayerSettings/VisualSettings.cs | 3 +-- 9 files changed, 27 insertions(+), 20 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplaySettingsOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplaySettingsOverlay.cs index cdfb3beb19..f8fab784cc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplaySettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplaySettingsOverlay.cs @@ -48,7 +48,10 @@ namespace osu.Game.Tests.Visual.Gameplay private class ExampleContainer : PlayerSettingsGroup { - protected override string Title => @"example"; + public ExampleContainer() + : base("example") + { + } } } } diff --git a/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs b/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs index fa530ea2c4..b60eb814e5 100644 --- a/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs +++ b/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs @@ -20,8 +20,6 @@ namespace osu.Game.Tournament.Screens.Ladder.Components { private const int padding = 10; - protected override string Title => @"ladder"; - private SettingsDropdown roundDropdown; private PlayerCheckbox losersCheckbox; private DateTextBox dateTimeBox; @@ -34,6 +32,11 @@ namespace osu.Game.Tournament.Screens.Ladder.Components [Resolved] private LadderInfo ladderInfo { get; set; } + public LadderEditorSettings() + : base("ladder") + { + } + [BackgroundDependencyLoader] private void load() { diff --git a/osu.Game/Rulesets/Edit/ToolboxGroup.cs b/osu.Game/Rulesets/Edit/ToolboxGroup.cs index eabb834616..7e17d88e17 100644 --- a/osu.Game/Rulesets/Edit/ToolboxGroup.cs +++ b/osu.Game/Rulesets/Edit/ToolboxGroup.cs @@ -8,9 +8,8 @@ namespace osu.Game.Rulesets.Edit { public class ToolboxGroup : PlayerSettingsGroup { - protected override string Title => "toolbox"; - public ToolboxGroup() + : base("toolbox") { RelativeSizeAxes = Axes.X; Width = 1; diff --git a/osu.Game/Screens/Play/PlayerSettings/CollectionSettings.cs b/osu.Game/Screens/Play/PlayerSettings/CollectionSettings.cs index d3570a8d2d..9e7f8e7394 100644 --- a/osu.Game/Screens/Play/PlayerSettings/CollectionSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/CollectionSettings.cs @@ -10,7 +10,10 @@ namespace osu.Game.Screens.Play.PlayerSettings { public class CollectionSettings : PlayerSettingsGroup { - protected override string Title => @"collections"; + public CollectionSettings() + : base("collections") + { + } [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Screens/Play/PlayerSettings/DiscussionSettings.cs b/osu.Game/Screens/Play/PlayerSettings/DiscussionSettings.cs index bb4eea47ca..ac040774ee 100644 --- a/osu.Game/Screens/Play/PlayerSettings/DiscussionSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/DiscussionSettings.cs @@ -10,7 +10,10 @@ namespace osu.Game.Screens.Play.PlayerSettings { public class DiscussionSettings : PlayerSettingsGroup { - protected override string Title => @"discussions"; + public DiscussionSettings() + : base("discussions") + { + } [BackgroundDependencyLoader] private void load(OsuConfigManager config) diff --git a/osu.Game/Screens/Play/PlayerSettings/InputSettings.cs b/osu.Game/Screens/Play/PlayerSettings/InputSettings.cs index 7a8696e27c..725a6e86bf 100644 --- a/osu.Game/Screens/Play/PlayerSettings/InputSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/InputSettings.cs @@ -9,11 +9,10 @@ namespace osu.Game.Screens.Play.PlayerSettings { public class InputSettings : PlayerSettingsGroup { - protected override string Title => "Input settings"; - private readonly PlayerCheckbox mouseButtonsCheckbox; public InputSettings() + : base("Input Settings") { Children = new Drawable[] { diff --git a/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs b/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs index c691d161ed..24ddc277cd 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs @@ -13,8 +13,6 @@ namespace osu.Game.Screens.Play.PlayerSettings { private const int padding = 10; - protected override string Title => @"playback"; - public readonly Bindable UserPlaybackRate = new BindableDouble(1) { Default = 1, @@ -28,6 +26,7 @@ namespace osu.Game.Screens.Play.PlayerSettings private readonly OsuSpriteText multiplierText; public PlaybackSettings() + : base("playback") { Children = new Drawable[] { diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index 90424ec007..7928d41e3b 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs @@ -17,11 +17,6 @@ namespace osu.Game.Screens.Play.PlayerSettings { public abstract class PlayerSettingsGroup : Container { - /// - /// The title to be displayed in the header of this group. - /// - protected abstract string Title { get; } - private const float transition_duration = 250; private const int container_width = 270; private const int border_thickness = 2; @@ -58,7 +53,11 @@ namespace osu.Game.Screens.Play.PlayerSettings private Color4 expandedColour; - protected PlayerSettingsGroup() + /// + /// Create a new instance. + /// + /// The title to be displayed in the header of this group. + protected PlayerSettingsGroup(string title) { AutoSizeAxes = Axes.Y; Width = container_width; @@ -95,7 +94,7 @@ namespace osu.Game.Screens.Play.PlayerSettings { Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, - Text = Title.ToUpperInvariant(), + Text = title.ToUpperInvariant(), Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 17), Margin = new MarginPadding { Left = 10 }, }, diff --git a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs index d6c66d0751..e06cf5c6d5 100644 --- a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs @@ -10,8 +10,6 @@ namespace osu.Game.Screens.Play.PlayerSettings { public class VisualSettings : PlayerSettingsGroup { - protected override string Title => "Visual settings"; - private readonly PlayerSliderBar dimSliderBar; private readonly PlayerSliderBar blurSliderBar; private readonly PlayerCheckbox showStoryboardToggle; @@ -19,6 +17,7 @@ namespace osu.Game.Screens.Play.PlayerSettings private readonly PlayerCheckbox beatmapHitsoundsToggle; public VisualSettings() + : base("Visual Settings") { Children = new Drawable[] { From fb2aced3ac32d4e312913e410557885700c85933 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Sep 2020 19:14:28 +0900 Subject: [PATCH 3/6] Add toggle for distance snap --- .../Edit/OsuHitObjectComposer.cs | 13 +++++++++++++ osu.Game/Rulesets/Edit/HitObjectComposer.cs | 18 +++++++++++++++++- osu.Game/Rulesets/Edit/ToolboxGroup.cs | 4 ++-- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 37019a7a05..f87bd53ec3 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Caching; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -38,6 +39,13 @@ namespace osu.Game.Rulesets.Osu.Edit new SpinnerCompositionTool() }; + private readonly BindableBool distanceSnapToggle = new BindableBool(true) { Description = "Distance Snap" }; + + protected override IEnumerable Toggles => new[] + { + distanceSnapToggle + }; + [BackgroundDependencyLoader] private void load() { @@ -45,6 +53,7 @@ namespace osu.Game.Rulesets.Osu.Edit EditorBeatmap.SelectedHitObjects.CollectionChanged += (_, __) => updateDistanceSnapGrid(); EditorBeatmap.PlacementObject.ValueChanged += _ => updateDistanceSnapGrid(); + distanceSnapToggle.ValueChanged += _ => updateDistanceSnapGrid(); } protected override ComposeBlueprintContainer CreateBlueprintContainer(IEnumerable hitObjects) @@ -87,6 +96,10 @@ namespace osu.Game.Rulesets.Osu.Edit { distanceSnapGridContainer.Clear(); distanceSnapGridCache.Invalidate(); + distanceSnapGrid = null; + + if (!distanceSnapToggle.Value) + return; switch (BlueprintContainer.CurrentTool) { diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index f134db1ffe..ee42cd9bae 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; @@ -13,6 +14,7 @@ using osu.Framework.Input.Events; using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Mods; @@ -94,7 +96,15 @@ namespace osu.Game.Rulesets.Edit Padding = new MarginPadding { Right = 10 }, Children = new Drawable[] { - new ToolboxGroup { Child = toolboxCollection = new RadioButtonCollection { RelativeSizeAxes = Axes.X } } + new ToolboxGroup("toolbox") { Child = toolboxCollection = new RadioButtonCollection { RelativeSizeAxes = Axes.X } }, + new ToolboxGroup("toggles") + { + ChildrenEnumerable = Toggles.Select(b => new SettingsCheckbox + { + Bindable = b, + LabelText = b?.Description ?? "unknown" + }) + } } }, new Container @@ -156,6 +166,12 @@ namespace osu.Game.Rulesets.Edit /// protected abstract IReadOnlyList CompositionTools { get; } + /// + /// A collection of toggles which will be displayed to the user. + /// The display name will be decided by . + /// + protected virtual IEnumerable Toggles => Enumerable.Empty(); + /// /// Construct a relevant blueprint container. This will manage hitobject selection/placement input handling and display logic. /// diff --git a/osu.Game/Rulesets/Edit/ToolboxGroup.cs b/osu.Game/Rulesets/Edit/ToolboxGroup.cs index 7e17d88e17..22b2b05657 100644 --- a/osu.Game/Rulesets/Edit/ToolboxGroup.cs +++ b/osu.Game/Rulesets/Edit/ToolboxGroup.cs @@ -8,8 +8,8 @@ namespace osu.Game.Rulesets.Edit { public class ToolboxGroup : PlayerSettingsGroup { - public ToolboxGroup() - : base("toolbox") + public ToolboxGroup(string title) + : base(title) { RelativeSizeAxes = Axes.X; Width = 1; From d210e056294b8bd92e9828e6a7c30c3ae960d239 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Sep 2020 19:20:11 +0900 Subject: [PATCH 4/6] Add a touch of spacing between toolbox groups --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index ee42cd9bae..928cdd2ea0 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -94,6 +94,7 @@ namespace osu.Game.Rulesets.Edit Name = "Sidebar", RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Right = 10 }, + Spacing = new Vector2(10), Children = new Drawable[] { new ToolboxGroup("toolbox") { Child = toolboxCollection = new RadioButtonCollection { RelativeSizeAxes = Axes.X } }, From aeae009512aad6f33a7ba5b4a54b161460cc3ead Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 9 Sep 2020 20:11:29 +0900 Subject: [PATCH 5/6] Disable online beatmap lookups in tests --- osu.Game/Beatmaps/BeatmapManager.cs | 12 ++++++++---- osu.Game/OsuGameBase.cs | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 34bb578b2a..d53f85c68d 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -66,12 +66,14 @@ namespace osu.Game.Beatmaps private readonly RulesetStore rulesets; private readonly BeatmapStore beatmaps; private readonly AudioManager audioManager; - private readonly BeatmapOnlineLookupQueue onlineLookupQueue; private readonly TextureStore textureStore; private readonly ITrackStore trackStore; + [CanBeNull] + private readonly BeatmapOnlineLookupQueue onlineLookupQueue; + public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, GameHost host = null, - WorkingBeatmap defaultBeatmap = null) + WorkingBeatmap defaultBeatmap = null, bool performOnlineLookups = false) : base(storage, contextFactory, api, new BeatmapStore(contextFactory), host) { this.rulesets = rulesets; @@ -85,7 +87,8 @@ namespace osu.Game.Beatmaps beatmaps.ItemRemoved += removeWorkingCache; beatmaps.ItemUpdated += removeWorkingCache; - onlineLookupQueue = new BeatmapOnlineLookupQueue(api, storage); + if (performOnlineLookups) + onlineLookupQueue = new BeatmapOnlineLookupQueue(api, storage); textureStore = new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store)); trackStore = audioManager.GetTrackStore(Files.Store); @@ -142,7 +145,8 @@ namespace osu.Game.Beatmaps bool hadOnlineBeatmapIDs = beatmapSet.Beatmaps.Any(b => b.OnlineBeatmapID > 0); - await onlineLookupQueue.UpdateAsync(beatmapSet, cancellationToken); + if (onlineLookupQueue != null) + await onlineLookupQueue.UpdateAsync(beatmapSet, cancellationToken); // ensure at least one beatmap was able to retrieve or keep an online ID, else drop the set ID. if (hadOnlineBeatmapIDs && !beatmapSet.Beatmaps.Any(b => b.OnlineBeatmapID > 0)) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 4bc8f4c527..b61017f038 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -198,7 +198,7 @@ namespace osu.Game // 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)); - dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap)); + 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 // to have inter-dependent model managers. this could be obtained with an IHasForeign interface to From 12188ec3c931bc30e5bdb7e1c99f988027dbc33b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 9 Sep 2020 20:49:59 +0900 Subject: [PATCH 6/6] Fix broken RollingCounter current value --- osu.Game/Graphics/UserInterface/RollingCounter.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/RollingCounter.cs b/osu.Game/Graphics/UserInterface/RollingCounter.cs index ece1b8e22c..91a557094d 100644 --- a/osu.Game/Graphics/UserInterface/RollingCounter.cs +++ b/osu.Game/Graphics/UserInterface/RollingCounter.cs @@ -9,16 +9,20 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterface { - public abstract class RollingCounter : Container + public abstract class RollingCounter : Container, IHasCurrentValue where T : struct, IEquatable { - /// - /// The current value. - /// - public Bindable Current = new Bindable(); + private readonly BindableWithCurrent current = new BindableWithCurrent(); + + public Bindable Current + { + get => current.Current; + set => current.Current = value; + } private SpriteText displayedCountSpriteText;