From af3f253b2182784c99072e3df362cbb07714c97d Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 11 Jun 2021 18:28:48 +0900 Subject: [PATCH 01/18] Refactor `ScrollingHitObjectContainer` and expose more useful methods --- .../Scrolling/ScrollingHitObjectContainer.cs | 148 +++++++----------- 1 file changed, 57 insertions(+), 91 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index f478e37e3e..d21f30eb30 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -19,6 +19,11 @@ namespace osu.Game.Rulesets.UI.Scrolling private readonly IBindable timeRange = new BindableDouble(); private readonly IBindable direction = new Bindable(); + /// + /// 0 for horizontal scroll, 1 for vertical scroll. + /// + private int scrollingAxis => direction.Value == ScrollingDirection.Left || direction.Value == ScrollingDirection.Right ? 0 : 1; + /// /// A set of top-level s which have an up-to-date layout. /// @@ -48,85 +53,65 @@ namespace osu.Game.Rulesets.UI.Scrolling } /// - /// Given a position in screen space, return the time within this column. + /// Given a position along the scrolling axis, return the time within this . /// - public double TimeAtScreenSpacePosition(Vector2 screenSpacePosition) + /// The position along the scrolling axis. + /// The time the scrolling speed is used. + public double TimeAtPosition(float position, double referenceTime) { - // convert to local space of column so we can snap and fetch correct location. - Vector2 localPosition = ToLocalSpace(screenSpacePosition); - - float position = 0; - - switch (scrollingInfo.Direction.Value) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - position = localPosition.Y; - break; - - case ScrollingDirection.Right: - case ScrollingDirection.Left: - position = localPosition.X; - break; - } - flipPositionIfRequired(ref position); - - return scrollingInfo.Algorithm.TimeAt(position, Time.Current, scrollingInfo.TimeRange.Value, scrollLength); + return scrollingInfo.Algorithm.TimeAt(position, referenceTime, timeRange.Value, scrollLength); } /// - /// Given a time, return the screen space position within this column. + /// Given a position in screen space, return the time within this . + /// + public double TimeAtScreenSpacePosition(Vector2 screenSpacePosition) + { + Vector2 localPosition = ToLocalSpace(screenSpacePosition); + return TimeAtPosition(localPosition[scrollingAxis], Time.Current); + } + + /// + /// Given a time, return the position along the scrolling axis within this at time . + /// + public float PositionAtTime(double time, double currentTime) + { + float pos = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength); + flipPositionIfRequired(ref pos); + return pos; + } + + /// + /// Given a time, return the position along the scrolling axis within this at the current time. + /// + public float PositionAtTime(double time) => PositionAtTime(time, Time.Current); + + /// + /// Given a time, return the screen space position within this . + /// In the non-scrolling axis, the center of this is returned. /// public Vector2 ScreenSpacePositionAtTime(double time) { - var pos = scrollingInfo.Algorithm.PositionAt(time, Time.Current, scrollingInfo.TimeRange.Value, scrollLength); - - flipPositionIfRequired(ref pos); - - switch (scrollingInfo.Direction.Value) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - return ToScreenSpace(new Vector2(getBreadth() / 2, pos)); - - default: - return ToScreenSpace(new Vector2(pos, getBreadth() / 2)); - } + float position = PositionAtTime(time, Time.Current); + return scrollingAxis == 0 + ? ToScreenSpace(new Vector2(position, DrawHeight / 2)) + : ToScreenSpace(new Vector2(DrawWidth / 2, position)); } - private float scrollLength + /// + /// Given a start time and end time of a scrolling object, return the length of the object along the scrolling axis. + /// + public float LengthAtTime(double startTime, double endTime) { - get - { - switch (scrollingInfo.Direction.Value) - { - case ScrollingDirection.Left: - case ScrollingDirection.Right: - return DrawWidth; - - default: - return DrawHeight; - } - } + return scrollingInfo.Algorithm.GetLength(startTime, endTime, timeRange.Value, scrollLength); } - private float getBreadth() - { - switch (scrollingInfo.Direction.Value) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - return DrawWidth; - - default: - return DrawHeight; - } - } + private float scrollLength => DrawSize[scrollingAxis]; private void flipPositionIfRequired(ref float position) { - // We're dealing with screen coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time. + // We're dealing with coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time. // The scrolling algorithm instead assumes a top anchor meaning an increase in time corresponds to an increase in position, // so when scrolling downwards the coordinates need to be flipped. @@ -237,18 +222,11 @@ namespace osu.Game.Rulesets.UI.Scrolling { if (hitObject.HitObject is IHasDuration e) { - switch (direction.Value) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - hitObject.Height = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, e.EndTime, timeRange.Value, scrollLength); - break; - - case ScrollingDirection.Left: - case ScrollingDirection.Right: - hitObject.Width = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, e.EndTime, timeRange.Value, scrollLength); - break; - } + float length = LengthAtTime(hitObject.HitObject.StartTime, e.EndTime); + if (scrollingAxis == 0) + hitObject.Width = length; + else + hitObject.Height = length; } foreach (var obj in hitObject.NestedHitObjects) @@ -262,24 +240,12 @@ namespace osu.Game.Rulesets.UI.Scrolling private void updatePosition(DrawableHitObject hitObject, double currentTime) { - switch (direction.Value) - { - case ScrollingDirection.Up: - hitObject.Y = scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength); - break; + float position = PositionAtTime(hitObject.HitObject.StartTime, currentTime); - case ScrollingDirection.Down: - hitObject.Y = -scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength); - break; - - case ScrollingDirection.Left: - hitObject.X = scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength); - break; - - case ScrollingDirection.Right: - hitObject.X = -scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength); - break; - } + if (scrollingAxis == 0) + hitObject.X = position; + else + hitObject.Y = position; } } } From 17347401cf29d825686ab775a471698c5fb68304 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 11:27:45 +0900 Subject: [PATCH 02/18] Remove unused `RankingType` enum We have `BeatmapLeaderboardScope` instead. --- osu.Game/Configuration/RankingType.cs | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 osu.Game/Configuration/RankingType.cs diff --git a/osu.Game/Configuration/RankingType.cs b/osu.Game/Configuration/RankingType.cs deleted file mode 100644 index 7701e1dd1d..0000000000 --- a/osu.Game/Configuration/RankingType.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.ComponentModel; - -namespace osu.Game.Configuration -{ - public enum RankingType - { - Local, - - [Description("Global")] - Top, - - [Description("Selected Mods")] - SelectedMod, - Friends, - Country - } -} From 8cf44547802fff912ec0a9ce42032e51df1ac0f3 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 11 Jun 2021 23:50:41 +0900 Subject: [PATCH 03/18] Use `Direction` enum instead of `int` The property is named `scrollingAxis` to distinguish from `direction`, which is of `ScrollingDirection` type (unfortunate name crash). --- .../Scrolling/ScrollingHitObjectContainer.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index d21f30eb30..b2c549244d 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -20,9 +20,9 @@ namespace osu.Game.Rulesets.UI.Scrolling private readonly IBindable direction = new Bindable(); /// - /// 0 for horizontal scroll, 1 for vertical scroll. + /// Whether the scrolling direction is horizontal or vertical. /// - private int scrollingAxis => direction.Value == ScrollingDirection.Left || direction.Value == ScrollingDirection.Right ? 0 : 1; + private Direction scrollingAxis => direction.Value == ScrollingDirection.Left || direction.Value == ScrollingDirection.Right ? Direction.Horizontal : Direction.Vertical; /// /// A set of top-level s which have an up-to-date layout. @@ -68,8 +68,8 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public double TimeAtScreenSpacePosition(Vector2 screenSpacePosition) { - Vector2 localPosition = ToLocalSpace(screenSpacePosition); - return TimeAtPosition(localPosition[scrollingAxis], Time.Current); + Vector2 position = ToLocalSpace(screenSpacePosition); + return TimeAtPosition(scrollingAxis == Direction.Horizontal ? position.X : position.Y, Time.Current); } /// @@ -77,9 +77,9 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public float PositionAtTime(double time, double currentTime) { - float pos = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength); - flipPositionIfRequired(ref pos); - return pos; + float position = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength); + flipPositionIfRequired(ref position); + return position; } /// @@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.UI.Scrolling public Vector2 ScreenSpacePositionAtTime(double time) { float position = PositionAtTime(time, Time.Current); - return scrollingAxis == 0 + return scrollingAxis == Direction.Horizontal ? ToScreenSpace(new Vector2(position, DrawHeight / 2)) : ToScreenSpace(new Vector2(DrawWidth / 2, position)); } @@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.UI.Scrolling return scrollingInfo.Algorithm.GetLength(startTime, endTime, timeRange.Value, scrollLength); } - private float scrollLength => DrawSize[scrollingAxis]; + private float scrollLength => scrollingAxis == Direction.Horizontal ? DrawWidth : DrawHeight; private void flipPositionIfRequired(ref float position) { @@ -223,7 +223,7 @@ namespace osu.Game.Rulesets.UI.Scrolling if (hitObject.HitObject is IHasDuration e) { float length = LengthAtTime(hitObject.HitObject.StartTime, e.EndTime); - if (scrollingAxis == 0) + if (scrollingAxis == Direction.Horizontal) hitObject.Width = length; else hitObject.Height = length; @@ -242,7 +242,7 @@ namespace osu.Game.Rulesets.UI.Scrolling { float position = PositionAtTime(hitObject.HitObject.StartTime, currentTime); - if (scrollingAxis == 0) + if (scrollingAxis == Direction.Horizontal) hitObject.X = position; else hitObject.Y = position; From fdb09ef4d7a7a6791f887f84b4b91ed517fd2b59 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 11 Jun 2021 23:53:01 +0900 Subject: [PATCH 04/18] Simplify `flipPositionIfRequired` using `scrollLength` --- .../UI/Scrolling/ScrollingHitObjectContainer.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index b2c549244d..283d84e8df 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -114,17 +114,8 @@ namespace osu.Game.Rulesets.UI.Scrolling // We're dealing with coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time. // The scrolling algorithm instead assumes a top anchor meaning an increase in time corresponds to an increase in position, // so when scrolling downwards the coordinates need to be flipped. - - switch (scrollingInfo.Direction.Value) - { - case ScrollingDirection.Down: - position = DrawHeight - position; - break; - - case ScrollingDirection.Right: - position = DrawWidth - position; - break; - } + if (direction.Value == ScrollingDirection.Down || direction.Value == ScrollingDirection.Right) + position = scrollLength - position; } protected override void AddDrawable(HitObjectLifetimeEntry entry, DrawableHitObject drawable) From 09f1cbde7eb13b8a72f9965ac0ee9ef933d622e3 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 14 Jun 2021 12:41:44 +0900 Subject: [PATCH 05/18] Fix `TimeAtPosition` doc comment --- .../UI/Scrolling/ScrollingHitObjectContainer.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 283d84e8df..061c9aa948 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -53,19 +53,23 @@ namespace osu.Game.Rulesets.UI.Scrolling } /// - /// Given a position along the scrolling axis, return the time within this . + /// Given a position at , return the time of the object corresponding the position. /// - /// The position along the scrolling axis. - /// The time the scrolling speed is used. - public double TimeAtPosition(float position, double referenceTime) + /// + /// If there are multiple valid time values, one arbitrary time is returned. + /// + public double TimeAtPosition(float position, double currentTime) { flipPositionIfRequired(ref position); - return scrollingInfo.Algorithm.TimeAt(position, referenceTime, timeRange.Value, scrollLength); + return scrollingInfo.Algorithm.TimeAt(position, currentTime, timeRange.Value, scrollLength); } /// - /// Given a position in screen space, return the time within this . + /// Given a position at the current time in screen space, return the time of the object corresponding the position. /// + /// + /// If there are multiple valid time values, one arbitrary time is returned. + /// public double TimeAtScreenSpacePosition(Vector2 screenSpacePosition) { Vector2 position = ToLocalSpace(screenSpacePosition); From 660bf50dc7ce71115a64a4a8168826bd5cc6cf90 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 14 Jun 2021 13:10:07 +0900 Subject: [PATCH 06/18] Clarify multiple coordinate systems - Fix wrong position is set for DHOs for down/right scrolling direction. --- .../Scrolling/ScrollingHitObjectContainer.cs | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 061c9aa948..d75954d77f 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -24,6 +24,11 @@ namespace osu.Game.Rulesets.UI.Scrolling /// private Direction scrollingAxis => direction.Value == ScrollingDirection.Left || direction.Value == ScrollingDirection.Right ? Direction.Horizontal : Direction.Vertical; + /// + /// Whether the scrolling direction is the positive-to-negative direction in the local coordinate. + /// + private bool axisInverted => direction.Value == ScrollingDirection.Down || direction.Value == ScrollingDirection.Right; + /// /// A set of top-level s which have an up-to-date layout. /// @@ -58,10 +63,10 @@ namespace osu.Game.Rulesets.UI.Scrolling /// /// If there are multiple valid time values, one arbitrary time is returned. /// - public double TimeAtPosition(float position, double currentTime) + public double TimeAtPosition(float localPosition, double currentTime) { - flipPositionIfRequired(ref position); - return scrollingInfo.Algorithm.TimeAt(position, currentTime, timeRange.Value, scrollLength); + float scrollPosition = axisInverted ? scrollLength - localPosition : localPosition; + return scrollingInfo.Algorithm.TimeAt(scrollPosition, currentTime, timeRange.Value, scrollLength); } /// @@ -72,8 +77,8 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public double TimeAtScreenSpacePosition(Vector2 screenSpacePosition) { - Vector2 position = ToLocalSpace(screenSpacePosition); - return TimeAtPosition(scrollingAxis == Direction.Horizontal ? position.X : position.Y, Time.Current); + Vector2 localPosition = ToLocalSpace(screenSpacePosition); + return TimeAtPosition(scrollingAxis == Direction.Horizontal ? localPosition.X : localPosition.Y, Time.Current); } /// @@ -81,9 +86,8 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public float PositionAtTime(double time, double currentTime) { - float position = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength); - flipPositionIfRequired(ref position); - return position; + float scrollPosition = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength); + return axisInverted ? scrollLength - scrollPosition : scrollPosition; } /// @@ -97,10 +101,10 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public Vector2 ScreenSpacePositionAtTime(double time) { - float position = PositionAtTime(time, Time.Current); + float localPosition = PositionAtTime(time, Time.Current); return scrollingAxis == Direction.Horizontal - ? ToScreenSpace(new Vector2(position, DrawHeight / 2)) - : ToScreenSpace(new Vector2(DrawWidth / 2, position)); + ? ToScreenSpace(new Vector2(localPosition, DrawHeight / 2)) + : ToScreenSpace(new Vector2(DrawWidth / 2, localPosition)); } /// @@ -113,15 +117,6 @@ namespace osu.Game.Rulesets.UI.Scrolling private float scrollLength => scrollingAxis == Direction.Horizontal ? DrawWidth : DrawHeight; - private void flipPositionIfRequired(ref float position) - { - // We're dealing with coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time. - // The scrolling algorithm instead assumes a top anchor meaning an increase in time corresponds to an increase in position, - // so when scrolling downwards the coordinates need to be flipped. - if (direction.Value == ScrollingDirection.Down || direction.Value == ScrollingDirection.Right) - position = scrollLength - position; - } - protected override void AddDrawable(HitObjectLifetimeEntry entry, DrawableHitObject drawable) { base.AddDrawable(entry, drawable); @@ -237,10 +232,14 @@ namespace osu.Game.Rulesets.UI.Scrolling { float position = PositionAtTime(hitObject.HitObject.StartTime, currentTime); + // The position returned from `PositionAtTime` is assuming the `TopLeft` anchor. + // A correction is needed because the hit objects are using a different anchor for each direction (e.g. `BottomCentre` for `Bottom` direction). + float anchorCorrection = axisInverted ? scrollLength : 0; + if (scrollingAxis == Direction.Horizontal) - hitObject.X = position; + hitObject.X = position - anchorCorrection; else - hitObject.Y = position; + hitObject.Y = position - anchorCorrection; } } } From 564682270a9bb0d49faf095bbad1a919e0915f42 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 13:18:52 +0900 Subject: [PATCH 07/18] Revert "Add nested `PlatformActionContainer` to allow testing of platform actions in visual tests" This reverts commit be91203c92ba7004f0f03b32878b3a4182092584. --- osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs index c7edc0174a..01dd7a25c8 100644 --- a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs +++ b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs @@ -4,7 +4,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Input; using osu.Framework.Testing.Input; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.Sprites; @@ -49,7 +48,7 @@ namespace osu.Game.Tests.Visual InputManager = new ManualInputManager { UseParentInput = true, - Child = new PlatformActionContainer().WithChild(mainContent) + Child = mainContent }, new Container { From 8dd48d48f683823fe511f68fafe29b778a8393fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 14:20:23 +0900 Subject: [PATCH 08/18] Add support for song select leaderboard to handle newly imported scores --- osu.Game/Online/Leaderboards/Leaderboard.cs | 6 +++--- .../Select/Leaderboards/BeatmapLeaderboard.cs | 21 ++++++++++++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index d18f189a70..c7610e0ba6 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -44,9 +44,9 @@ namespace osu.Game.Online.Leaderboards protected override Container Content => content; - private IEnumerable scores; + private ICollection scores; - public IEnumerable Scores + public ICollection Scores { get => scores; set @@ -290,7 +290,7 @@ namespace osu.Game.Online.Leaderboards getScoresRequest = FetchScores(scores => Schedule(() => { - Scores = scores; + Scores = scores.ToArray(); PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores; })); diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 8ddae67dba..2bbcb6678f 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -44,6 +44,8 @@ namespace osu.Game.Screens.Select.Leaderboards private IBindable> itemRemoved; + private IBindable> itemAdded; + /// /// Whether to apply the game's currently selected mods as a filter when retrieving scores. /// @@ -85,6 +87,9 @@ namespace osu.Game.Screens.Select.Leaderboards itemRemoved = scoreManager.ItemRemoved.GetBoundCopy(); itemRemoved.BindValueChanged(onScoreRemoved); + + itemAdded = scoreManager.ItemUpdated.GetBoundCopy(); + itemAdded.BindValueChanged(onScoreAdded); } protected override void Reset() @@ -93,7 +98,21 @@ namespace osu.Game.Screens.Select.Leaderboards TopScore = null; } - private void onScoreRemoved(ValueChangedEvent> score) => Schedule(RefreshScores); + private void onScoreRemoved(ValueChangedEvent> score) + { + if (Scope != BeatmapLeaderboardScope.Local) + return; + + Scheduler.AddOnce(RefreshScores); + } + + private void onScoreAdded(ValueChangedEvent> score) + { + if (Scope != BeatmapLeaderboardScope.Local) + return; + + Scheduler.AddOnce(RefreshScores); + } protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local; From fc442713bbd46e072c8166db9fd0dc19fdea03c8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 14:26:40 +0900 Subject: [PATCH 09/18] Debounce schedule at base class --- osu.Game/Online/Leaderboards/Leaderboard.cs | 10 +++++----- .../Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index c7610e0ba6..70e38e421d 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -126,7 +126,7 @@ namespace osu.Game.Online.Leaderboards return; scope = value; - UpdateScores(); + RefreshScores(); } } @@ -154,7 +154,7 @@ namespace osu.Game.Online.Leaderboards case PlaceholderState.NetworkFailure: replacePlaceholder(new ClickablePlaceholder(@"Couldn't fetch scores!", FontAwesome.Solid.Sync) { - Action = UpdateScores, + Action = RefreshScores }); break; @@ -254,8 +254,6 @@ namespace osu.Game.Online.Leaderboards apiState.BindValueChanged(onlineStateChanged, true); } - public void RefreshScores() => UpdateScores(); - private APIRequest getScoresRequest; protected abstract bool IsOnlineScope { get; } @@ -267,12 +265,14 @@ namespace osu.Game.Online.Leaderboards case APIState.Online: case APIState.Offline: if (IsOnlineScope) - UpdateScores(); + RefreshScores(); break; } }); + public void RefreshScores() => Scheduler.AddOnce(UpdateScores); + protected void UpdateScores() { // don't display any scores or placeholder until the first Scores_Set has been called. diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 2bbcb6678f..d6967c17a8 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -103,7 +103,7 @@ namespace osu.Game.Screens.Select.Leaderboards if (Scope != BeatmapLeaderboardScope.Local) return; - Scheduler.AddOnce(RefreshScores); + RefreshScores(); } private void onScoreAdded(ValueChangedEvent> score) @@ -111,7 +111,7 @@ namespace osu.Game.Screens.Select.Leaderboards if (Scope != BeatmapLeaderboardScope.Local) return; - Scheduler.AddOnce(RefreshScores); + RefreshScores(); } protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local; From f8b09b7c81bfa370ed4765133c1231f520b21163 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 14:26:54 +0900 Subject: [PATCH 10/18] Avoid refresh if score is not related to current display --- .../Select/Leaderboards/BeatmapLeaderboard.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index d6967c17a8..587a35c480 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -98,18 +98,22 @@ namespace osu.Game.Screens.Select.Leaderboards TopScore = null; } - private void onScoreRemoved(ValueChangedEvent> score) + private void onScoreRemoved(ValueChangedEvent> score) => + scoreStoreChanged(score); + + private void onScoreAdded(ValueChangedEvent> score) => + scoreStoreChanged(score); + + private void scoreStoreChanged(ValueChangedEvent> score) { if (Scope != BeatmapLeaderboardScope.Local) return; - RefreshScores(); - } - - private void onScoreAdded(ValueChangedEvent> score) - { - if (Scope != BeatmapLeaderboardScope.Local) - return; + if (score.NewValue.TryGetTarget(out var scoreInfo)) + { + if (Beatmap.ID != scoreInfo.BeatmapInfoID) + return; + } RefreshScores(); } From b06477a1f59fbf00546dd84fce6af2b187cf4bb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 14:35:24 +0900 Subject: [PATCH 11/18] Split out tests into individual test methods --- .../SongSelect/TestSceneBeatmapLeaderboard.cs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs index 67cd720260..2a4ad48568 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; @@ -37,18 +38,37 @@ namespace osu.Game.Tests.Visual.SongSelect Size = new Vector2(550f, 450f), Scope = BeatmapLeaderboardScope.Global, }); + } + [Test] + public void TestScoresDisplay() + { AddStep(@"New Scores", newScores); + } + + [Test] + public void TestPersonalBest() + { AddStep(@"Show personal best", showPersonalBest); + AddStep("null personal best position", showPersonalBestWithNullPosition); + } + + [Test] + public void TestPlaceholderStates() + { AddStep(@"Empty Scores", () => leaderboard.SetRetrievalState(PlaceholderState.NoScores)); AddStep(@"Network failure", () => leaderboard.SetRetrievalState(PlaceholderState.NetworkFailure)); AddStep(@"No supporter", () => leaderboard.SetRetrievalState(PlaceholderState.NotSupporter)); AddStep(@"Not logged in", () => leaderboard.SetRetrievalState(PlaceholderState.NotLoggedIn)); AddStep(@"Unavailable", () => leaderboard.SetRetrievalState(PlaceholderState.Unavailable)); AddStep(@"None selected", () => leaderboard.SetRetrievalState(PlaceholderState.NoneSelected)); + } + + [Test] + public void TestBeatmapStates() + { foreach (BeatmapSetOnlineStatus status in Enum.GetValues(typeof(BeatmapSetOnlineStatus))) AddStep($"{status} beatmap", () => showBeatmapWithStatus(status)); - AddStep("null personal best position", showPersonalBestWithNullPosition); } private void showPersonalBestWithNullPosition() From 83402a70db9088e6ddf160b8ceb3de483aedcc28 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 15:06:24 +0900 Subject: [PATCH 12/18] Fix potential null ref when no beatmap is selected --- osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 587a35c480..a86a614a05 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -111,7 +111,7 @@ namespace osu.Game.Screens.Select.Leaderboards if (score.NewValue.TryGetTarget(out var scoreInfo)) { - if (Beatmap.ID != scoreInfo.BeatmapInfoID) + if (Beatmap?.ID != scoreInfo.BeatmapInfoID) return; } From fcb0b8d825c887cb78937471e8877e2fec86c043 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 15:06:33 +0900 Subject: [PATCH 13/18] Add test coverage --- .../SongSelect/TestSceneBeatmapLeaderboard.cs | 110 +++++++++++++++--- 1 file changed, 94 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs index 2a4ad48568..184a2e59da 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs @@ -2,16 +2,22 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Graphics; +using osu.Framework.Platform; +using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Online.Leaderboards; using osu.Game.Overlays; +using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Scoring; using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Tests.Resources; using osu.Game.Users; using osuTK; @@ -24,26 +30,73 @@ namespace osu.Game.Tests.Visual.SongSelect [Cached] private readonly DialogOverlay dialogOverlay; + private ScoreManager scoreManager; + + private RulesetStore rulesetStore; + private BeatmapManager beatmapManager; + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + + dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory)); + dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default)); + dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory)); + + return dependencies; + } + public TestSceneBeatmapLeaderboard() { - Add(dialogOverlay = new DialogOverlay + AddRange(new Drawable[] { - Depth = -1 - }); - - Add(leaderboard = new FailableLeaderboard - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Size = new Vector2(550f, 450f), - Scope = BeatmapLeaderboardScope.Global, + dialogOverlay = new DialogOverlay + { + Depth = -1 + }, + leaderboard = new FailableLeaderboard + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Size = new Vector2(550f, 450f), + Scope = BeatmapLeaderboardScope.Global, + } }); } [Test] - public void TestScoresDisplay() + public void TestLocalScoresDisplay() { - AddStep(@"New Scores", newScores); + BeatmapInfo beatmapInfo = null; + + AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Local); + + AddStep(@"Set beatmap", () => + { + beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); + beatmapInfo = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First(); + + leaderboard.Beatmap = beatmapInfo; + }); + + clearScores(); + checkCount(0); + + loadMoreScores(() => beatmapInfo); + checkCount(10); + + loadMoreScores(() => beatmapInfo); + checkCount(20); + + clearScores(); + checkCount(0); + } + + [Test] + public void TestGlobalScoresDisplay() + { + AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Global); + AddStep(@"New Scores", () => leaderboard.Scores = generateSampleScores(null)); } [Test] @@ -116,9 +169,26 @@ namespace osu.Game.Tests.Visual.SongSelect }; } - private void newScores() + private void loadMoreScores(Func beatmapInfo) { - var scores = new[] + AddStep(@"Load new scores via manager", () => + { + foreach (var score in generateSampleScores(beatmapInfo())) + scoreManager.Import(score).Wait(); + }); + } + + private void clearScores() + { + AddStep("Clear all scores", () => scoreManager.Delete(scoreManager.GetAllUsableScores())); + } + + private void checkCount(int expected) => + AddUntilStep("Correct count displayed", () => leaderboard.ChildrenOfType().Count() == expected); + + private static ScoreInfo[] generateSampleScores(BeatmapInfo beatmap) + { + return new[] { new ScoreInfo { @@ -127,6 +197,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 6602580, @@ -145,6 +216,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 4608074, @@ -163,6 +235,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 1014222, @@ -181,6 +254,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 1541390, @@ -199,6 +273,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 2243452, @@ -217,6 +292,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 2705430, @@ -235,6 +311,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 7151382, @@ -253,6 +330,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 2051389, @@ -271,6 +349,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 6169483, @@ -289,6 +368,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 6702666, @@ -301,8 +381,6 @@ namespace osu.Game.Tests.Visual.SongSelect }, }, }; - - leaderboard.Scores = scores; } private void showBeatmapWithStatus(BeatmapSetOnlineStatus status) From aa5dae84b2ad3c20580d0a5f7a44aa880c9c1603 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 14 Jun 2021 16:51:17 +0900 Subject: [PATCH 14/18] Make all localisation class strings verbatim --- osu.Game/Localisation/ChatStrings.cs | 6 +++--- osu.Game/Localisation/CommonStrings.cs | 4 ++-- osu.Game/Localisation/Language.cs | 4 ++-- osu.Game/Localisation/NotificationsStrings.cs | 6 +++--- osu.Game/Localisation/NowPlayingStrings.cs | 6 +++--- osu.Game/Localisation/SettingsStrings.cs | 6 +++--- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/osu.Game/Localisation/ChatStrings.cs b/osu.Game/Localisation/ChatStrings.cs index daddb602ad..636351470b 100644 --- a/osu.Game/Localisation/ChatStrings.cs +++ b/osu.Game/Localisation/ChatStrings.cs @@ -7,17 +7,17 @@ namespace osu.Game.Localisation { public static class ChatStrings { - private const string prefix = "osu.Game.Localisation.Chat"; + private const string prefix = @"osu.Game.Localisation.Chat"; /// /// "chat" /// - public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "chat"); + public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"chat"); /// /// "join the real-time discussion" /// - public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "join the real-time discussion"); + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"join the real-time discussion"); private static string getKey(string key) => $"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index f448158191..ced0d80955 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -7,12 +7,12 @@ namespace osu.Game.Localisation { public static class CommonStrings { - private const string prefix = "osu.Game.Localisation.Common"; + private const string prefix = @"osu.Game.Localisation.Common"; /// /// "Cancel" /// - public static LocalisableString Cancel => new TranslatableString(getKey("cancel"), "Cancel"); + public static LocalisableString Cancel => new TranslatableString(getKey(@"cancel"), @"Cancel"); private static string getKey(string key) => $"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/Language.cs b/osu.Game/Localisation/Language.cs index edcf264c7f..a3e845f229 100644 --- a/osu.Game/Localisation/Language.cs +++ b/osu.Game/Localisation/Language.cs @@ -7,10 +7,10 @@ namespace osu.Game.Localisation { public enum Language { - [Description("English")] + [Description(@"English")] en, - [Description("日本語")] + [Description(@"日本語")] ja } } diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 092eec3a6b..ba28ef5560 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -7,17 +7,17 @@ namespace osu.Game.Localisation { public static class NotificationsStrings { - private const string prefix = "osu.Game.Localisation.Notifications"; + private const string prefix = @"osu.Game.Localisation.Notifications"; /// /// "notifications" /// - public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "notifications"); + public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"notifications"); /// /// "waiting for 'ya" /// - public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "waiting for 'ya"); + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"waiting for 'ya"); private static string getKey(string key) => $"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/NowPlayingStrings.cs b/osu.Game/Localisation/NowPlayingStrings.cs index d742a56895..47646b0f68 100644 --- a/osu.Game/Localisation/NowPlayingStrings.cs +++ b/osu.Game/Localisation/NowPlayingStrings.cs @@ -7,17 +7,17 @@ namespace osu.Game.Localisation { public static class NowPlayingStrings { - private const string prefix = "osu.Game.Localisation.NowPlaying"; + private const string prefix = @"osu.Game.Localisation.NowPlaying"; /// /// "now playing" /// - public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "now playing"); + public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"now playing"); /// /// "manage the currently playing track" /// - public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "manage the currently playing track"); + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"manage the currently playing track"); private static string getKey(string key) => $"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/SettingsStrings.cs b/osu.Game/Localisation/SettingsStrings.cs index cfbd392691..f4b417fa28 100644 --- a/osu.Game/Localisation/SettingsStrings.cs +++ b/osu.Game/Localisation/SettingsStrings.cs @@ -7,17 +7,17 @@ namespace osu.Game.Localisation { public static class SettingsStrings { - private const string prefix = "osu.Game.Localisation.Settings"; + private const string prefix = @"osu.Game.Localisation.Settings"; /// /// "settings" /// - public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "settings"); + public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"settings"); /// /// "change the way osu! behaves" /// - public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "change the way osu! behaves"); + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"change the way osu! behaves"); private static string getKey(string key) => $"{prefix}:{key}"; } From b327baa4dea5812234c8ef9754c61a0bfbfcba61 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 14 Jun 2021 17:47:31 +0900 Subject: [PATCH 15/18] Match any arbitrary assembly for localisations --- .../ResourceManagerLocalisationStore.cs | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/ResourceManagerLocalisationStore.cs b/osu.Game/Localisation/ResourceManagerLocalisationStore.cs index 7b21e1af42..a35ce7a9c8 100644 --- a/osu.Game/Localisation/ResourceManagerLocalisationStore.cs +++ b/osu.Game/Localisation/ResourceManagerLocalisationStore.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Linq; using System.Resources; using System.Threading.Tasks; using osu.Framework.Localisation; @@ -34,7 +35,29 @@ namespace osu.Game.Localisation lock (resourceManagers) { if (!resourceManagers.TryGetValue(ns, out var manager)) - resourceManagers[ns] = manager = new ResourceManager(ns, GetType().Assembly); + { + var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); + + // Traverse backwards through periods in the namespace to find a matching assembly. + string assemblyName = ns; + + while (!string.IsNullOrEmpty(assemblyName)) + { + var matchingAssembly = loadedAssemblies.FirstOrDefault(asm => asm.GetName().Name == assemblyName); + + if (matchingAssembly != null) + { + resourceManagers[ns] = manager = new ResourceManager(ns, matchingAssembly); + break; + } + + int lastIndex = Math.Max(0, assemblyName.LastIndexOf('.')); + assemblyName = assemblyName.Substring(0, lastIndex); + } + } + + if (manager == null) + return null; try { From 13d0eaa9fe9b7d418d544cf35ea7d0fef55ab04f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 19:03:31 +0900 Subject: [PATCH 16/18] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 13d45835be..c020b1d783 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 7eb3c84582..a7bd5f2e9f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -34,7 +34,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 3e8facaf6e..5b3efb4ba4 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From cb1e2e3d9785748718a37c43f4b01c8e9c704342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Jun 2021 21:51:32 +0200 Subject: [PATCH 17/18] Improve xmldoc --- .../Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index d75954d77f..94cc7ed095 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -25,8 +25,12 @@ namespace osu.Game.Rulesets.UI.Scrolling private Direction scrollingAxis => direction.Value == ScrollingDirection.Left || direction.Value == ScrollingDirection.Right ? Direction.Horizontal : Direction.Vertical; /// - /// Whether the scrolling direction is the positive-to-negative direction in the local coordinate. + /// The scrolling axis is inverted if objects temporally farther in the future have a smaller position value across the scrolling axis. /// + /// + /// is inverted, because given two objects, one of which is at the current time and one of which is 1000ms in the future, + /// in the current time instant the future object is spatially above the current object, and therefore has a smaller value of the Y coordinate of its position. + /// private bool axisInverted => direction.Value == ScrollingDirection.Down || direction.Value == ScrollingDirection.Right; /// @@ -58,7 +62,7 @@ namespace osu.Game.Rulesets.UI.Scrolling } /// - /// Given a position at , return the time of the object corresponding the position. + /// Given a position at , return the time of the object corresponding to the position. /// /// /// If there are multiple valid time values, one arbitrary time is returned. From 9d9c5902bbe616ffcfdc53b116f907cdb3644f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Jun 2021 22:46:56 +0200 Subject: [PATCH 18/18] Temporarily disable `dotnet format` to unblock CI --- appveyor.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index a4a0cedc66..845751ef07 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,7 +17,11 @@ build: publish_nuget: true after_build: - ps: dotnet tool restore - - ps: dotnet format --dry-run --check + + # Temporarily disabled until the tool is upgraded to 5.0. + # The version specified in .config/dotnet-tools.json (3.1.37601) won't run on .NET hosts >=5.0.7. + # - ps: dotnet format --dry-run --check + - ps: .\InspectCode.ps1 test: assemblies: