From 72b8eef36e514c430be84abb82d5eabe1288af20 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Nov 2020 15:41:56 +0900 Subject: [PATCH 01/17] Add ability to pause/resume replay playback --- .../Input/Bindings/GlobalActionContainer.cs | 6 ++++- osu.Game/Screens/Play/Player.cs | 6 ++++- osu.Game/Screens/Play/ReplayPlayer.cs | 23 ++++++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index e5d3a89a88..77f57bd637 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -69,6 +69,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.Control, InputKey.Plus }, GlobalAction.IncreaseScrollSpeed), new KeyBinding(new[] { InputKey.Control, InputKey.Minus }, GlobalAction.DecreaseScrollSpeed), new KeyBinding(InputKey.MouseMiddle, GlobalAction.PauseGameplay), + new KeyBinding(InputKey.Space, GlobalAction.PauseReplay), new KeyBinding(InputKey.Control, GlobalAction.HoldForHUD), }; @@ -175,7 +176,7 @@ namespace osu.Game.Input.Bindings [Description("Toggle notifications")] ToggleNotifications, - [Description("Pause")] + [Description("Pause Gameplay")] PauseGameplay, // Editor @@ -196,5 +197,8 @@ namespace osu.Game.Input.Bindings [Description("Random Skin")] RandomSkin, + + [Description("Pause Replay")] + PauseReplay, } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index d0a83e3c22..7979b635aa 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -339,7 +339,11 @@ namespace osu.Game.Screens.Play AlwaysVisible = { BindTarget = DrawableRuleset.HasReplayLoaded }, IsCounting = false }, - RequestSeek = GameplayClockContainer.Seek, + RequestSeek = time => + { + GameplayClockContainer.Seek(time); + GameplayClockContainer.Start(); + }, Anchor = Anchor.Centre, Origin = Anchor.Centre }, diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 3a4298f22d..2c0b766a17 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -1,12 +1,14 @@ // 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.Bindings; +using osu.Game.Input.Bindings; using osu.Game.Scoring; using osu.Game.Screens.Ranking; namespace osu.Game.Screens.Play { - public class ReplayPlayer : Player + public class ReplayPlayer : Player, IKeyBindingHandler { protected readonly Score Score; @@ -35,5 +37,24 @@ namespace osu.Game.Screens.Play return Score.ScoreInfo; } + + public bool OnPressed(GlobalAction action) + { + switch (action) + { + case GlobalAction.PauseReplay: + if (GameplayClockContainer.IsPaused.Value) + GameplayClockContainer.Start(); + else + GameplayClockContainer.Stop(); + return true; + } + + return false; + } + + public void OnReleased(GlobalAction action) + { + } } } From 1d82557d9f5158006d4c29af41d8ce583e6758f2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Nov 2020 15:42:14 +0900 Subject: [PATCH 02/17] Avoid blocking global actions when skip overlay is not actually active --- osu.Game/Screens/Play/SkipOverlay.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index b123757ded..92b304de91 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -133,6 +133,9 @@ namespace osu.Game.Screens.Play switch (action) { case GlobalAction.SkipCutscene: + if (!button.Enabled.Value) + return false; + button.Click(); return true; } From 3346c06aca2469288f1aa2a4ed48fc7595c97122 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Nov 2020 20:04:44 +0900 Subject: [PATCH 03/17] Rename variable/text to be more verbose as to toggle purpose --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 6 +++--- osu.Game/Screens/Play/ReplayPlayer.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 77f57bd637..2736c20da9 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -69,7 +69,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.Control, InputKey.Plus }, GlobalAction.IncreaseScrollSpeed), new KeyBinding(new[] { InputKey.Control, InputKey.Minus }, GlobalAction.DecreaseScrollSpeed), new KeyBinding(InputKey.MouseMiddle, GlobalAction.PauseGameplay), - new KeyBinding(InputKey.Space, GlobalAction.PauseReplay), + new KeyBinding(InputKey.Space, GlobalAction.TogglePauseReplay), new KeyBinding(InputKey.Control, GlobalAction.HoldForHUD), }; @@ -198,7 +198,7 @@ namespace osu.Game.Input.Bindings [Description("Random Skin")] RandomSkin, - [Description("Pause Replay")] - PauseReplay, + [Description("Pause / resume replay")] + TogglePauseReplay, } } diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 2c0b766a17..294d116f51 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -42,7 +42,7 @@ namespace osu.Game.Screens.Play { switch (action) { - case GlobalAction.PauseReplay: + case GlobalAction.TogglePauseReplay: if (GameplayClockContainer.IsPaused.Value) GameplayClockContainer.Start(); else From 57454bbb1c50d0af8bf9e1d2a9da5db9993e354f Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 27 Nov 2020 10:13:05 +0900 Subject: [PATCH 04/17] Remove hitObject argument from OnApply and OnFree --- .../Objects/Drawables/DrawableOsuHitObject.cs | 8 ++++---- .../Objects/Drawables/DrawableSlider.cs | 8 ++++---- .../Objects/Drawables/DrawableSliderHead.cs | 4 ++-- .../Visual/Gameplay/TestScenePoolingRuleset.cs | 4 ++-- .../Rulesets/Objects/Drawables/DrawableHitObject.cs | 10 ++++------ 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index a26db06ede..4b7f048c1b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -53,9 +53,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables }); } - protected override void OnApply(HitObject hitObject) + protected override void OnApply() { - base.OnApply(hitObject); + base.OnApply(); IndexInCurrentComboBindable.BindTo(HitObject.IndexInCurrentComboBindable); PositionBindable.BindTo(HitObject.PositionBindable); @@ -70,9 +70,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables LifetimeEnd = HitObject.GetEndTime() + HitObject.HitWindows.WindowFor(HitResult.Miss) + 1000; } - protected override void OnFree(HitObject hitObject) + protected override void OnFree() { - base.OnFree(hitObject); + base.OnFree(); IndexInCurrentComboBindable.UnbindFrom(HitObject.IndexInCurrentComboBindable); PositionBindable.UnbindFrom(HitObject.PositionBindable); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 6340367593..dd27ac990e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -86,18 +86,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Tracking.BindValueChanged(updateSlidingSample); } - protected override void OnApply(HitObject hitObject) + protected override void OnApply() { - base.OnApply(hitObject); + base.OnApply(); // Ensure that the version will change after the upcoming BindTo(). pathVersion.Value = int.MaxValue; PathVersion.BindTo(HitObject.Path.Version); } - protected override void OnFree(HitObject hitObject) + protected override void OnFree() { - base.OnFree(hitObject); + base.OnFree(); PathVersion.UnbindFrom(HitObject.Path.Version); } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs index fd0f35d20d..b5c33c0924 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs @@ -36,9 +36,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables pathVersion.BindValueChanged(_ => updatePosition()); } - protected override void OnFree(HitObject hitObject) + protected override void OnFree() { - base.OnFree(hitObject); + base.OnFree(); pathVersion.UnbindFrom(drawableSlider.PathVersion); } diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs index 3e777119c4..cd7d692b0a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs @@ -261,9 +261,9 @@ namespace osu.Game.Tests.Visual.Gameplay }); } - protected override void OnApply(HitObject hitObject) + protected override void OnApply() { - base.OnApply(hitObject); + base.OnApply(); Position = new Vector2(RNG.Next(-200, 200), RNG.Next(-200, 200)); } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 2e37e8977a..9c799bcf32 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -260,7 +260,7 @@ namespace osu.Game.Rulesets.Objects.Drawables HitObject.DefaultsApplied += onDefaultsApplied; - OnApply(hitObject); + OnApply(); HitObjectApplied?.Invoke(this); // If not loaded, the state update happens in LoadComplete(). Otherwise, the update is scheduled to allow for lifetime updates. @@ -315,7 +315,7 @@ namespace osu.Game.Rulesets.Objects.Drawables HitObject.DefaultsApplied -= onDefaultsApplied; - OnFree(HitObject); + OnFree(); HitObject = null; Result = null; @@ -340,16 +340,14 @@ namespace osu.Game.Rulesets.Objects.Drawables /// /// Invoked for this to take on any values from a newly-applied . /// - /// The being applied. - protected virtual void OnApply(HitObject hitObject) + protected virtual void OnApply() { } /// /// Invoked for this to revert any values previously taken on from the currently-applied . /// - /// The currently-applied . - protected virtual void OnFree(HitObject hitObject) + protected virtual void OnFree() { } From fe85b7d482a0aabb076387f174fbbc9ab7835e77 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 27 Nov 2020 10:18:00 +0900 Subject: [PATCH 05/17] Remove unused import --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs index b5c33c0924..3a92938d75 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs @@ -4,7 +4,6 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; From f29aa9c4fca5d157a6b610ddab4811b7734beee3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Nov 2020 14:34:12 +0900 Subject: [PATCH 06/17] Move taiko barlines to their own ScrollingHitObjectContainer to avoid being considered as a selectable object --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 35 +++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 120cf264c3..370760f03e 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.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 System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -37,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.UI private SkinnableDrawable mascot; private ProxyContainer topLevelHitContainer; - private ProxyContainer barlineContainer; + private ScrollingHitObjectContainer barlineContainer; private Container rightArea; private Container leftArea; @@ -83,10 +84,7 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - barlineContainer = new ProxyContainer - { - RelativeSizeAxes = Axes.Both, - }, + barlineContainer = new ScrollingHitObjectContainer(), new Container { Name = "Hit objects", @@ -159,18 +157,37 @@ namespace osu.Game.Rulesets.Taiko.UI public override void Add(DrawableHitObject h) { - h.OnNewResult += OnNewResult; - base.Add(h); - switch (h) { case DrawableBarLine barline: - barlineContainer.Add(barline.CreateProxy()); + barlineContainer.Add(barline); break; case DrawableTaikoHitObject taikoObject: + h.OnNewResult += OnNewResult; topLevelHitContainer.Add(taikoObject.CreateProxiedContent()); + base.Add(h); break; + + default: + throw new ArgumentException($"Unsupported {nameof(DrawableHitObject)} type"); + } + } + + public override bool Remove(DrawableHitObject h) + { + switch (h) + { + case DrawableBarLine barline: + return barlineContainer.Remove(barline); + + case DrawableTaikoHitObject _: + h.OnNewResult -= OnNewResult; + // todo: consider tidying of proxied content if required. + return base.Remove(h); + + default: + throw new ArgumentException($"Unsupported {nameof(DrawableHitObject)} type"); } } From b9b885798801e8737498704e2186bec8fe985d58 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Nov 2020 15:11:07 +0900 Subject: [PATCH 07/17] 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 6dab6edc5e..0b43fd73f5 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 54f3fcede6..e201383d51 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -26,7 +26,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 692dac909a..e5f7581404 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -88,7 +88,7 @@ - + From 1246c8ba5f9b15bef09ff8c6b0a1fd208ddbb8d6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Nov 2020 15:22:28 +0900 Subject: [PATCH 08/17] Reduce the opacity of the default skin slider ball Previous value was [hitting pure white on some brighter combo colours](https://github.com/ppy/osu/issues/10910#issuecomment-734354812). --- osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs index c5bf790377..ca5ca7ac59 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs @@ -248,7 +248,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces } private void trackingChanged(ValueChangedEvent tracking) => - box.FadeTo(tracking.NewValue ? 0.6f : 0.05f, 200, Easing.OutQuint); + box.FadeTo(tracking.NewValue ? 0.3f : 0.05f, 200, Easing.OutQuint); } } } From 7edbba58f70d8d61ddfcb6e90d57db0424751f2e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Nov 2020 16:28:29 +0900 Subject: [PATCH 09/17] Avoid updating hitobjects unnecessarily for start time changes This was firing regardless of whether the start time was changed, such as where beat snap provided the same time the object already has. The case where a change actually occurs is already handled by EditorBeatmap (see `startTimeBindables`), so it turns out this local handling is not required at all. --- osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index def5f396f1..57f9a7f221 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -496,10 +496,7 @@ namespace osu.Game.Screens.Edit.Compose.Components double offset = result.Time.Value - movementBlueprints.First().HitObject.StartTime; foreach (HitObject obj in Beatmap.SelectedHitObjects) - { obj.StartTime += offset; - Beatmap.Update(obj); - } } return true; From 18bb0cb45b944dbcb2afee1673ec1601702d6249 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Nov 2020 16:31:59 +0900 Subject: [PATCH 10/17] Remove unnecessary schedule logic from Apply's local updateState call There were cases in the editor where rewinding of transforms would leave the `DrawableHitObject` in a non-`IsPresent` state, resulting in this scheduled logic never running. This would in turn cause ghost hitobjects, which disappear under certain circumstances. Reproduction: - Open editor to empty beatmap - Place single hitcircle at current point in time - Drag editor timeline backwards to seek before zero, and wait for return to zero - Select hitcircle in playfield - Drag hitcircle to right in timeline, triggering a start time change --- .../Objects/Drawables/DrawableHitObject.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 9c799bcf32..95bc72edf6 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -263,18 +263,15 @@ namespace osu.Game.Rulesets.Objects.Drawables OnApply(); HitObjectApplied?.Invoke(this); - // If not loaded, the state update happens in LoadComplete(). Otherwise, the update is scheduled to allow for lifetime updates. + // If not loaded, the state update happens in LoadComplete(). if (IsLoaded) { - Scheduler.Add(() => - { - if (Result.IsHit) - updateState(ArmedState.Hit, true); - else if (Result.HasResult) - updateState(ArmedState.Miss, true); - else - updateState(ArmedState.Idle, true); - }); + if (Result.IsHit) + updateState(ArmedState.Hit, true); + else if (Result.HasResult) + updateState(ArmedState.Miss, true); + else + updateState(ArmedState.Idle, true); } hasHitObjectApplied = true; From a9c59eed02edba7a43c5d2bebaf21c8a25f7e3cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Nov 2020 16:56:26 +0900 Subject: [PATCH 11/17] Add test coverage of fail scenario --- .../Editing/EditorChangeHandlerTest.cs | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs b/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs index b7a41ffd1c..5064b0fd22 100644 --- a/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs +++ b/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; -using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens.Edit; @@ -44,6 +43,36 @@ namespace osu.Game.Tests.Editing Assert.That(stateChangedFired, Is.EqualTo(2)); } + [Test] + public void TestApplyThenUndoThenApplySameChange() + { + var (handler, beatmap) = createChangeHandler(); + + Assert.That(handler.CanUndo.Value, Is.False); + Assert.That(handler.CanRedo.Value, Is.False); + + string originalHash = handler.CurrentStateHash; + + addArbitraryChange(beatmap); + handler.SaveState(); + + Assert.That(handler.CanUndo.Value, Is.True); + Assert.That(handler.CanRedo.Value, Is.False); + Assert.That(stateChangedFired, Is.EqualTo(1)); + + string hash = handler.CurrentStateHash; + + // save a save without making any changes + handler.RestoreState(-1); + + Assert.That(originalHash, Is.EqualTo(handler.CurrentStateHash)); + Assert.That(stateChangedFired, Is.EqualTo(2)); + + addArbitraryChange(beatmap); + handler.SaveState(); + Assert.That(hash, Is.EqualTo(handler.CurrentStateHash)); + } + [Test] public void TestSaveSameStateDoesNotSave() { @@ -139,7 +168,7 @@ namespace osu.Game.Tests.Editing private void addArbitraryChange(EditorBeatmap beatmap) { - beatmap.Add(new HitCircle { StartTime = RNG.Next(0, 100000) }); + beatmap.Add(new HitCircle { StartTime = 2760 }); } } } From 7e34c5e239e2e9fed537ce99cde4f7b3311a6469 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Nov 2020 16:57:11 +0900 Subject: [PATCH 12/17] Fix state application always checking newest state for early abort, rather than current --- osu.Game/Screens/Edit/EditorChangeHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/EditorChangeHandler.cs b/osu.Game/Screens/Edit/EditorChangeHandler.cs index 62187aed24..2dcb416a03 100644 --- a/osu.Game/Screens/Edit/EditorChangeHandler.cs +++ b/osu.Game/Screens/Edit/EditorChangeHandler.cs @@ -76,7 +76,7 @@ namespace osu.Game.Screens.Edit var newState = stream.ToArray(); // if the previous state is binary equal we don't need to push a new one, unless this is the initial state. - if (savedStates.Count > 0 && newState.SequenceEqual(savedStates.Last())) return; + if (savedStates.Count > 0 && newState.SequenceEqual(savedStates[currentState])) return; if (currentState < savedStates.Count - 1) savedStates.RemoveRange(currentState + 1, savedStates.Count - currentState - 1); From 8ad4cf73f5c17fca110486de442a83cf11074473 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Sat, 28 Nov 2020 17:07:29 +0200 Subject: [PATCH 13/17] Scale stars from 0.4 to 1 --- osu.Game/Graphics/UserInterface/StarCounter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/StarCounter.cs b/osu.Game/Graphics/UserInterface/StarCounter.cs index b13d6485ac..f249156a59 100644 --- a/osu.Game/Graphics/UserInterface/StarCounter.cs +++ b/osu.Game/Graphics/UserInterface/StarCounter.cs @@ -147,7 +147,7 @@ namespace osu.Game.Graphics.UserInterface public override void DisplayAt(float scale) { - scale = Math.Clamp(scale, min_star_scale, 1); + scale = Math.Clamp(scale * (1 - min_star_scale) + min_star_scale, min_star_scale, 1); this.FadeTo(scale, fading_duration); Icon.ScaleTo(scale, scaling_duration, scaling_easing); From 8e0f525588a5d0e997b5a15da50045ebbb719434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Nov 2020 20:29:35 +0100 Subject: [PATCH 14/17] Rewrite existing test scene somewhat --- .../Visual/Gameplay/TestSceneStarCounter.cs | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs index 709e71d195..d6a6ef712a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs @@ -3,7 +3,6 @@ using NUnit.Framework; using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -14,44 +13,40 @@ namespace osu.Game.Tests.Visual.Gameplay [TestFixture] public class TestSceneStarCounter : OsuTestScene { + private readonly StarCounter starCounter; + private readonly OsuSpriteText starsLabel; + public TestSceneStarCounter() { - StarCounter stars = new StarCounter + starCounter = new StarCounter { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Current = 5, }; - Add(stars); + Add(starCounter); - SpriteText starsLabel = new OsuSpriteText + starsLabel = new OsuSpriteText { Origin = Anchor.Centre, Anchor = Anchor.Centre, Scale = new Vector2(2), Y = 50, - Text = stars.Current.ToString("0.00"), }; Add(starsLabel); - AddRepeatStep(@"random value", delegate - { - stars.Current = RNG.NextSingle() * (stars.StarCount + 1); - starsLabel.Text = stars.Current.ToString("0.00"); - }, 10); + setStars(5); - AddStep(@"Stop animation", delegate - { - stars.StopAnimation(); - }); + AddRepeatStep("random value", () => setStars(RNG.NextSingle() * (starCounter.StarCount + 1)), 10); + AddStep("stop animation", () => starCounter.StopAnimation()); + AddStep("reset", () => setStars(0)); + } - AddStep(@"Reset", delegate - { - stars.Current = 0; - starsLabel.Text = stars.Current.ToString("0.00"); - }); + private void setStars(float stars) + { + starCounter.Current = stars; + starsLabel.Text = starCounter.Current.ToString("0.00"); } } } From 9bf70e4e97ed84c95bb5d19eb4e7cf59391f7e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Nov 2020 20:32:08 +0100 Subject: [PATCH 15/17] Add slider test step for visual inspection purposes --- osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs index d6a6ef712a..717485bcc1 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs @@ -39,6 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay setStars(5); AddRepeatStep("random value", () => setStars(RNG.NextSingle() * (starCounter.StarCount + 1)), 10); + AddSliderStep("exact value", 0f, 10f, 5f, setStars); AddStep("stop animation", () => starCounter.StopAnimation()); AddStep("reset", () => setStars(0)); } From a3afd88387b0d4cb939adf2ff69cd3031672d06a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Nov 2020 20:35:03 +0100 Subject: [PATCH 16/17] Use Interpolation.Lerp --- osu.Game/Graphics/UserInterface/StarCounter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/StarCounter.cs b/osu.Game/Graphics/UserInterface/StarCounter.cs index f249156a59..894a21fcf3 100644 --- a/osu.Game/Graphics/UserInterface/StarCounter.cs +++ b/osu.Game/Graphics/UserInterface/StarCounter.cs @@ -147,7 +147,7 @@ namespace osu.Game.Graphics.UserInterface public override void DisplayAt(float scale) { - scale = Math.Clamp(scale * (1 - min_star_scale) + min_star_scale, min_star_scale, 1); + scale = (float)Interpolation.Lerp(min_star_scale, 1, Math.Clamp(scale, 0, 1)); this.FadeTo(scale, fading_duration); Icon.ScaleTo(scale, scaling_duration, scaling_easing); From 6bea78619a9c59aefcbd47d935233fc61496031e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 30 Nov 2020 13:33:29 +0900 Subject: [PATCH 17/17] Update comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game.Tests/Editing/EditorChangeHandlerTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs b/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs index 5064b0fd22..481cb3230e 100644 --- a/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs +++ b/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs @@ -62,7 +62,7 @@ namespace osu.Game.Tests.Editing string hash = handler.CurrentStateHash; - // save a save without making any changes + // undo a change without saving handler.RestoreState(-1); Assert.That(originalHash, Is.EqualTo(handler.CurrentStateHash));