From 870ce8868cf3955754c266cec0da8fc754a91019 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Apr 2018 16:07:33 +0900 Subject: [PATCH 001/306] Make scrollabletimeline use gridcontainer --- .../Visual/TestCaseEditorComposeTimeline.cs | 3 +- .../Compose/Timeline/ScrollableTimeline.cs | 135 +++++++++--------- 2 files changed, 70 insertions(+), 68 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index d15ee32d8d..0e7ba5c900 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -34,7 +34,8 @@ namespace osu.Game.Tests.Visual { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(1000, 100) + RelativeSizeAxes = Axes.X, + Size = new Vector2(0.8f, 100) } }; } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollableTimeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollableTimeline.cs index c308b2b9f8..9ce4830e5a 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollableTimeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollableTimeline.cs @@ -33,82 +33,90 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline RelativeSizeAxes = Axes.Both, Colour = OsuColour.FromHex("111") }, - new FillFlowContainer + new GridContainer { RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] + Content = new[] { - new Container + new Drawable[] { - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Children = new Drawable[] + new Container { - new Box + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex("222") - }, - new FillFlowContainer - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Y, - Width = 160, - Padding = new MarginPadding { Horizontal = 15 }, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 4), - Children = new[] + new Box { - hitObjectsCheckbox = new OsuCheckbox { LabelText = "Hitobjects" }, - hitSoundsCheckbox = new OsuCheckbox { LabelText = "Hitsounds" }, - waveformCheckbox = new OsuCheckbox { LabelText = "Waveform" } + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex("222") + }, + new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Y, + Width = 160, + Padding = new MarginPadding { Horizontal = 15 }, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 4), + Children = new[] + { + hitObjectsCheckbox = new OsuCheckbox { LabelText = "Hitobjects" }, + hitSoundsCheckbox = new OsuCheckbox { LabelText = "Hitsounds" }, + waveformCheckbox = new OsuCheckbox { LabelText = "Waveform" } + } } } - } - }, - new Container - { - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Children = new Drawable[] + }, + new Container { - new Box + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex("333") - }, - new Container - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Masking = true, - Children = new[] + new Box { - new TimelineButton + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex("333") + }, + new Container + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Masking = true, + Children = new[] { - RelativeSizeAxes = Axes.Y, - Height = 0.5f, - Icon = FontAwesome.fa_search_plus, - Action = () => timelineContainer.Zoom++ - }, - new TimelineButton - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Y, - Height = 0.5f, - Icon = FontAwesome.fa_search_minus, - Action = () => timelineContainer.Zoom-- - }, + new TimelineButton + { + RelativeSizeAxes = Axes.Y, + Height = 0.5f, + Icon = FontAwesome.fa_search_plus, + // Action = () => timelineContainer.Zoom++ + }, + new TimelineButton + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.Y, + Height = 0.5f, + Icon = FontAwesome.fa_search_minus, + // Action = () => timelineContainer.Zoom-- + }, + } } } - } + }, + timelineContainer = new ScrollingTimelineContainer { RelativeSizeAxes = Axes.Both } }, - timelineContainer = new ScrollingTimelineContainer { RelativeSizeAxes = Axes.Y } + }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Distributed), } } }; @@ -120,12 +128,5 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline timelineContainer.Beatmap.BindTo(Beatmap); timelineContainer.WaveformVisible.BindTo(waveformCheckbox.Current); } - - protected override void Update() - { - base.Update(); - - timelineContainer.Size = new Vector2(DrawSize.X - timelineContainer.DrawPosition.X, 1); - } } } From e7aa1d9c38c500741ceb1da086a6aa73a5211c07 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Apr 2018 16:12:21 +0900 Subject: [PATCH 002/306] Temporarily remove zoom levels, simplify scrollingtimelinecontainer --- .../Timeline/ScrollingTimelineContainer.cs | 107 +----------------- 1 file changed, 3 insertions(+), 104 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs index f71607a6cf..5195a85eac 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs @@ -1,12 +1,9 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; -using OpenTK; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Graphics; @@ -14,8 +11,6 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { public class ScrollingTimelineContainer : ScrollContainer { - public readonly Bindable HitObjectsVisible = new Bindable(); - public readonly Bindable HitSoundsVisible = new Bindable(); public readonly Bindable WaveformVisible = new Bindable(); public readonly Bindable Beatmap = new Bindable(); @@ -26,6 +21,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { Masking = true; + Content.AutoSizeAxes = Axes.None; + Content.RelativeSizeAxes = Axes.Both; + Add(waveform = new BeatmapWaveformGraph { RelativeSizeAxes = Axes.Both, @@ -33,107 +31,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline Depth = float.MaxValue }); - Content.AutoSizeAxes = Axes.None; - Content.RelativeSizeAxes = Axes.Both; - waveform.Beatmap.BindTo(Beatmap); WaveformVisible.ValueChanged += waveformVisibilityChanged; - - Zoom = 10; - } - - private float minZoom = 1; - /// - /// The minimum zoom level allowed. - /// - public float MinZoom - { - get { return minZoom; } - set - { - if (value <= 0) - throw new ArgumentOutOfRangeException(nameof(value)); - if (minZoom == value) - return; - minZoom = value; - - // Update the zoom level - Zoom = Zoom; - } - } - - private float maxZoom = 30; - /// - /// The maximum zoom level allowed. - /// - public float MaxZoom - { - get { return maxZoom; } - set - { - if (value <= 0) - throw new ArgumentOutOfRangeException(nameof(value)); - if (maxZoom == value) - return; - maxZoom = value; - - // Update the zoom level - Zoom = Zoom; - } - } - - private float zoom = 1; - /// - /// The current zoom level. - /// - public float Zoom - { - get { return zoom; } - set - { - value = MathHelper.Clamp(value, MinZoom, MaxZoom); - if (zoom == value) - return; - zoom = value; - - // Make the zoom target default to the center of the graph if it hasn't been set - if (relativeContentZoomTarget == null) - relativeContentZoomTarget = ToSpaceOfOtherDrawable(DrawSize / 2, Content).X / Content.DrawSize.X; - if (localZoomTarget == null) - localZoomTarget = DrawSize.X / 2; - - Content.ResizeWidthTo(Zoom); - - // Update the scroll position to focus on the zoom target - float scrollPos = Content.DrawSize.X * relativeContentZoomTarget.Value - localZoomTarget.Value; - ScrollTo(scrollPos, false); - - relativeContentZoomTarget = null; - localZoomTarget = null; - } - } - - /// - /// Zoom target as a relative position in the space. - /// - private float? relativeContentZoomTarget; - - /// - /// Zoom target as a position in our local space. - /// - private float? localZoomTarget; - - protected override bool OnWheel(InputState state) - { - if (!state.Keyboard.ControlPressed) - return base.OnWheel(state); - - relativeContentZoomTarget = Content.ToLocalSpace(state.Mouse.NativeState.Position).X / Content.DrawSize.X; - localZoomTarget = ToLocalSpace(state.Mouse.NativeState.Position).X; - - Zoom += state.Mouse.WheelDelta; - - return true; } private void waveformVisibilityChanged(bool visible) => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); From 9bb3e56bb3a22875f746175fee15640489713232 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Apr 2018 17:05:38 +0900 Subject: [PATCH 003/306] Implement half-width overflows --- .../Timeline/ScrollingTimelineContainer.cs | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs index 5195a85eac..e031e354db 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs @@ -14,6 +14,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline public readonly Bindable WaveformVisible = new Bindable(); public readonly Bindable Beatmap = new Bindable(); + private readonly Container waveformContainer; private readonly BeatmapWaveformGraph waveform; public ScrollingTimelineContainer() @@ -21,20 +22,31 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { Masking = true; - Content.AutoSizeAxes = Axes.None; - Content.RelativeSizeAxes = Axes.Both; - - Add(waveform = new BeatmapWaveformGraph + Child = waveformContainer = new Container { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex("222"), - Depth = float.MaxValue - }); + RelativeSizeAxes = Axes.Y, + Child = waveform = new BeatmapWaveformGraph + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex("222"), + Depth = float.MaxValue + } + }; waveform.Beatmap.BindTo(Beatmap); WaveformVisible.ValueChanged += waveformVisibilityChanged; } + private float zoom = 10; + + protected override void Update() + { + base.Update(); + + waveformContainer.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; + waveformContainer.Width = DrawWidth * zoom; + } + private void waveformVisibilityChanged(bool visible) => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); } } From e3af32ad2f0f581d56ce09c30849a632e6e830b7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Apr 2018 17:07:41 +0900 Subject: [PATCH 004/306] A bit of cleanup --- .../Screens/Compose/Timeline/ScrollingTimelineContainer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs index e031e354db..07896d63be 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs @@ -34,7 +34,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline }; waveform.Beatmap.BindTo(Beatmap); - WaveformVisible.ValueChanged += waveformVisibilityChanged; + + WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); } private float zoom = 10; @@ -46,7 +47,5 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline waveformContainer.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; waveformContainer.Width = DrawWidth * zoom; } - - private void waveformVisibilityChanged(bool visible) => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); } } From 074dee3a83a9d456378a91518f4daa8bb9b26e40 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Apr 2018 18:37:51 +0900 Subject: [PATCH 005/306] Re-implement mousewheel zoom --- .../Timeline/ScrollingTimelineContainer.cs | 73 +++++++++++++++++-- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs index 07896d63be..e4b19fc2c5 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs @@ -4,8 +4,12 @@ using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Transforms; +using osu.Framework.Input; +using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Graphics; +using OpenTK; namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { @@ -15,13 +19,15 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline public readonly Bindable Beatmap = new Bindable(); private readonly Container waveformContainer; - private readonly BeatmapWaveformGraph waveform; + + private float currentZoom = 10; public ScrollingTimelineContainer() : base(Direction.Horizontal) { Masking = true; + BeatmapWaveformGraph waveform; Child = waveformContainer = new Container { RelativeSizeAxes = Axes.Y, @@ -34,18 +40,75 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline }; waveform.Beatmap.BindTo(Beatmap); - + WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); } - private float zoom = 10; - protected override void Update() { base.Update(); waveformContainer.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; - waveformContainer.Width = DrawWidth * zoom; + waveformContainer.Width = DrawWidth * currentZoom; + } + + protected override bool OnWheel(InputState state) + { + if (!state.Keyboard.ControlPressed) + return base.OnWheel(state); + + setZoomTarget(zoomTarget + state.Mouse.WheelDelta, waveformContainer.ToLocalSpace(state.Mouse.NativeState.Position).X); + return true; + } + + private float zoomTarget = 10; + private void setZoomTarget(float newZoom, float focusPoint) + { + zoomTarget = MathHelper.Clamp(newZoom, 1, 60); + transformZoomTo(zoomTarget, focusPoint, 200, Easing.OutQuint); + } + + private void transformZoomTo(float newZoom, float focusPoint, double duration = 0, Easing easing = Easing.None) + => this.TransformTo(this.PopulateTransform(new TransformZoom(focusPoint, waveformContainer.DrawWidth, DrawWidth, Current), newZoom, duration, easing)); + + private class TransformZoom : Transform + { + private readonly float focusPoint; + private readonly float focusSize; + private readonly float sizeReference; + private readonly float scrollOffset; + + public TransformZoom(float focusPoint, float focusSize, float sizeReference, float scrollOffset) + { + this.focusPoint = focusPoint; + this.focusSize = focusSize; + this.sizeReference = sizeReference; + this.scrollOffset = scrollOffset; + } + + public override string TargetMember => nameof(currentZoom); + + private float valueAt(double time) + { + if (time < StartTime) return StartValue; + if (time >= EndTime) return EndValue; + + return Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing); + } + + protected override void Apply(ScrollingTimelineContainer d, double time) + { + float newZoom = valueAt(time); + + float focusOffset = focusPoint - scrollOffset; + float expectedWidth = sizeReference * newZoom; + float targetOffset = expectedWidth * (focusPoint / focusSize) - focusOffset; + + d.currentZoom = newZoom; + d.ScrollTo(targetOffset, false); + } + + protected override void ReadIntoStartValue(ScrollingTimelineContainer d) => StartValue = d.currentZoom; } } } From eff5eddbe97dac18b954d81aa32542988ab1e822 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Apr 2018 18:41:22 +0900 Subject: [PATCH 006/306] Make zoom an int again --- .../Screens/Compose/Timeline/ScrollingTimelineContainer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs index e4b19fc2c5..5e68b931a4 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs @@ -61,14 +61,14 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline return true; } - private float zoomTarget = 10; - private void setZoomTarget(float newZoom, float focusPoint) + private int zoomTarget = 10; + private void setZoomTarget(int newZoom, float focusPoint) { zoomTarget = MathHelper.Clamp(newZoom, 1, 60); transformZoomTo(zoomTarget, focusPoint, 200, Easing.OutQuint); } - private void transformZoomTo(float newZoom, float focusPoint, double duration = 0, Easing easing = Easing.None) + private void transformZoomTo(int newZoom, float focusPoint, double duration = 0, Easing easing = Easing.None) => this.TransformTo(this.PopulateTransform(new TransformZoom(focusPoint, waveformContainer.DrawWidth, DrawWidth, Current), newZoom, duration, easing)); private class TransformZoom : Transform From 35e116cb1270dce0641d3856db21d7612d34961f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Apr 2018 19:04:07 +0900 Subject: [PATCH 007/306] Reduce ctor arguments --- .../Timeline/ScrollingTimelineContainer.cs | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs index 5e68b931a4..a24bf7c909 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs @@ -69,21 +69,34 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline } private void transformZoomTo(int newZoom, float focusPoint, double duration = 0, Easing easing = Easing.None) - => this.TransformTo(this.PopulateTransform(new TransformZoom(focusPoint, waveformContainer.DrawWidth, DrawWidth, Current), newZoom, duration, easing)); + => this.TransformTo(this.PopulateTransform(new TransformZoom(focusPoint, waveformContainer.DrawWidth), newZoom, duration, easing)); private class TransformZoom : Transform { + /// + /// The focus point in the waveform, in absolute coordinates local to the waveform. + /// private readonly float focusPoint; - private readonly float focusSize; - private readonly float sizeReference; - private readonly float scrollOffset; - public TransformZoom(float focusPoint, float focusSize, float sizeReference, float scrollOffset) + /// + /// The size of the waveform. + /// + private readonly float waveformSize; + + /// + /// The scroll offset at the start time of the transform/ + /// + private float startScrollOffset; + + /// + /// Transforms to a new value. + /// + /// The focus point in the waveform, in absolute coordinates local to the waveform. + /// The size of the waveform. + public TransformZoom(float focusPoint, float waveformSize) { this.focusPoint = focusPoint; - this.focusSize = focusSize; - this.sizeReference = sizeReference; - this.scrollOffset = scrollOffset; + this.waveformSize = waveformSize; } public override string TargetMember => nameof(currentZoom); @@ -100,15 +113,19 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { float newZoom = valueAt(time); - float focusOffset = focusPoint - scrollOffset; - float expectedWidth = sizeReference * newZoom; - float targetOffset = expectedWidth * (focusPoint / focusSize) - focusOffset; + float focusOffset = focusPoint - startScrollOffset; + float expectedWidth = d.DrawWidth * newZoom; + float targetOffset = expectedWidth * (focusPoint / waveformSize) - focusOffset; d.currentZoom = newZoom; d.ScrollTo(targetOffset, false); } - protected override void ReadIntoStartValue(ScrollingTimelineContainer d) => StartValue = d.currentZoom; + protected override void ReadIntoStartValue(ScrollingTimelineContainer d) + { + startScrollOffset = d.Current; + StartValue = d.currentZoom; + } } } } From 8da3c2c52aa79ca631fcd12573bc443a61ac9d3a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Apr 2018 19:05:19 +0900 Subject: [PATCH 008/306] Expose zoom publicly again, re-enable zoom buttons --- .../Edit/Screens/Compose/Timeline/ScrollableTimeline.cs | 4 ++-- .../Screens/Compose/Timeline/ScrollingTimelineContainer.cs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollableTimeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollableTimeline.cs index 9ce4830e5a..31466e960f 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollableTimeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollableTimeline.cs @@ -94,7 +94,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline RelativeSizeAxes = Axes.Y, Height = 0.5f, Icon = FontAwesome.fa_search_plus, - // Action = () => timelineContainer.Zoom++ + Action = () => timelineContainer.Zoom++ }, new TimelineButton { @@ -103,7 +103,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline RelativeSizeAxes = Axes.Y, Height = 0.5f, Icon = FontAwesome.fa_search_minus, - // Action = () => timelineContainer.Zoom-- + Action = () => timelineContainer.Zoom-- }, } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs index a24bf7c909..2fe5d09788 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs @@ -44,6 +44,12 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); } + public int Zoom + { + get => zoomTarget; + set => setZoomTarget(value, ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), waveformContainer).X); + } + protected override void Update() { base.Update(); From 0141cbebbab43ab85b11d0377aadae6259483448 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Apr 2018 19:08:10 +0900 Subject: [PATCH 009/306] waveformContainer -> zoomedContent --- .../Timeline/ScrollingTimelineContainer.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs index 2fe5d09788..e48b625b8b 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline public readonly Bindable WaveformVisible = new Bindable(); public readonly Bindable Beatmap = new Bindable(); - private readonly Container waveformContainer; + private readonly Container zoomedContent; private float currentZoom = 10; @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline Masking = true; BeatmapWaveformGraph waveform; - Child = waveformContainer = new Container + Child = zoomedContent = new Container { RelativeSizeAxes = Axes.Y, Child = waveform = new BeatmapWaveformGraph @@ -44,18 +44,21 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); } + /// + /// Gets or sets the content zoom of this . + /// public int Zoom { get => zoomTarget; - set => setZoomTarget(value, ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), waveformContainer).X); + set => setZoomTarget(value, ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), zoomedContent).X); } protected override void Update() { base.Update(); - waveformContainer.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; - waveformContainer.Width = DrawWidth * currentZoom; + zoomedContent.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; + zoomedContent.Width = DrawWidth * currentZoom; } protected override bool OnWheel(InputState state) @@ -63,7 +66,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline if (!state.Keyboard.ControlPressed) return base.OnWheel(state); - setZoomTarget(zoomTarget + state.Mouse.WheelDelta, waveformContainer.ToLocalSpace(state.Mouse.NativeState.Position).X); + setZoomTarget(zoomTarget + state.Mouse.WheelDelta, zoomedContent.ToLocalSpace(state.Mouse.NativeState.Position).X); return true; } @@ -75,7 +78,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline } private void transformZoomTo(int newZoom, float focusPoint, double duration = 0, Easing easing = Easing.None) - => this.TransformTo(this.PopulateTransform(new TransformZoom(focusPoint, waveformContainer.DrawWidth), newZoom, duration, easing)); + => this.TransformTo(this.PopulateTransform(new TransformZoom(focusPoint, zoomedContent.DrawWidth), newZoom, duration, easing)); private class TransformZoom : Transform { From 9a9ed1d630d9aa01ecca4ae03251d3a75124c7b4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Apr 2018 19:30:54 +0900 Subject: [PATCH 010/306] Encapsulate zoom logic into a separate class --- .../Timeline/ScrollingTimelineContainer.cs | 115 ++--------------- .../Timeline/ZoomableScrollContainer.cs | 118 ++++++++++++++++++ 2 files changed, 125 insertions(+), 108 deletions(-) create mode 100644 osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs index e48b625b8b..96dc54f1e9 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs @@ -3,40 +3,24 @@ using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Transforms; -using osu.Framework.Input; -using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Graphics; -using OpenTK; namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { - public class ScrollingTimelineContainer : ScrollContainer + public class ScrollingTimelineContainer : ZoomableScrollContainer { public readonly Bindable WaveformVisible = new Bindable(); public readonly Bindable Beatmap = new Bindable(); - private readonly Container zoomedContent; - - private float currentZoom = 10; - public ScrollingTimelineContainer() - : base(Direction.Horizontal) { - Masking = true; - BeatmapWaveformGraph waveform; - Child = zoomedContent = new Container + Child = waveform = new BeatmapWaveformGraph { - RelativeSizeAxes = Axes.Y, - Child = waveform = new BeatmapWaveformGraph - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex("222"), - Depth = float.MaxValue - } + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex("222"), + Depth = float.MaxValue }; waveform.Beatmap.BindTo(Beatmap); @@ -44,97 +28,12 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); } - /// - /// Gets or sets the content zoom of this . - /// - public int Zoom - { - get => zoomTarget; - set => setZoomTarget(value, ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), zoomedContent).X); - } - protected override void Update() { base.Update(); - zoomedContent.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; - zoomedContent.Width = DrawWidth * currentZoom; - } - - protected override bool OnWheel(InputState state) - { - if (!state.Keyboard.ControlPressed) - return base.OnWheel(state); - - setZoomTarget(zoomTarget + state.Mouse.WheelDelta, zoomedContent.ToLocalSpace(state.Mouse.NativeState.Position).X); - return true; - } - - private int zoomTarget = 10; - private void setZoomTarget(int newZoom, float focusPoint) - { - zoomTarget = MathHelper.Clamp(newZoom, 1, 60); - transformZoomTo(zoomTarget, focusPoint, 200, Easing.OutQuint); - } - - private void transformZoomTo(int newZoom, float focusPoint, double duration = 0, Easing easing = Easing.None) - => this.TransformTo(this.PopulateTransform(new TransformZoom(focusPoint, zoomedContent.DrawWidth), newZoom, duration, easing)); - - private class TransformZoom : Transform - { - /// - /// The focus point in the waveform, in absolute coordinates local to the waveform. - /// - private readonly float focusPoint; - - /// - /// The size of the waveform. - /// - private readonly float waveformSize; - - /// - /// The scroll offset at the start time of the transform/ - /// - private float startScrollOffset; - - /// - /// Transforms to a new value. - /// - /// The focus point in the waveform, in absolute coordinates local to the waveform. - /// The size of the waveform. - public TransformZoom(float focusPoint, float waveformSize) - { - this.focusPoint = focusPoint; - this.waveformSize = waveformSize; - } - - public override string TargetMember => nameof(currentZoom); - - private float valueAt(double time) - { - if (time < StartTime) return StartValue; - if (time >= EndTime) return EndValue; - - return Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing); - } - - protected override void Apply(ScrollingTimelineContainer d, double time) - { - float newZoom = valueAt(time); - - float focusOffset = focusPoint - startScrollOffset; - float expectedWidth = d.DrawWidth * newZoom; - float targetOffset = expectedWidth * (focusPoint / waveformSize) - focusOffset; - - d.currentZoom = newZoom; - d.ScrollTo(targetOffset, false); - } - - protected override void ReadIntoStartValue(ScrollingTimelineContainer d) - { - startScrollOffset = d.Current; - StartValue = d.currentZoom; - } + // We want time = 0 to be at the centre of the container when scrolled to the start + Content.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; } } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs new file mode 100644 index 0000000000..05a2882f31 --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs @@ -0,0 +1,118 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Transforms; +using osu.Framework.Input; +using osu.Framework.MathUtils; +using OpenTK; + +namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +{ + public class ZoomableScrollContainer : ScrollContainer + { + private readonly Container zoomedContent; + protected override Container Content => zoomedContent; + + private float currentZoom = 10; + + public ZoomableScrollContainer() + : base(Direction.Horizontal) + { + base.Content.Add(zoomedContent = new Container { RelativeSizeAxes = Axes.Y }); + } + + /// + /// Gets or sets the content zoom of this . + /// + public int Zoom + { + get => zoomTarget; + set => setZoomTarget(value, ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), zoomedContent).X); + } + + protected override void Update() + { + base.Update(); + + zoomedContent.Width = DrawWidth * currentZoom; + } + + protected override bool OnWheel(InputState state) + { + if (!state.Keyboard.ControlPressed) + return base.OnWheel(state); + + setZoomTarget(zoomTarget + state.Mouse.WheelDelta, zoomedContent.ToLocalSpace(state.Mouse.NativeState.Position).X); + return true; + } + + private int zoomTarget = 10; + private void setZoomTarget(int newZoom, float focusPoint) + { + zoomTarget = MathHelper.Clamp(newZoom, 1, 60); + transformZoomTo(zoomTarget, focusPoint, 200, Easing.OutQuint); + } + + private void transformZoomTo(int newZoom, float focusPoint, double duration = 0, Easing easing = Easing.None) + => this.TransformTo(this.PopulateTransform(new TransformZoom(focusPoint, zoomedContent.DrawWidth), newZoom, duration, easing)); + + private class TransformZoom : Transform + { + /// + /// The focus point in the waveform, in absolute coordinates local to the waveform. + /// + private readonly float focusPoint; + + /// + /// The size of the waveform. + /// + private readonly float waveformSize; + + /// + /// The scroll offset at the start time of the transform/ + /// + private float startScrollOffset; + + /// + /// Transforms to a new value. + /// + /// The focus point in the waveform, in absolute coordinates local to the waveform. + /// The size of the waveform. + public TransformZoom(float focusPoint, float waveformSize) + { + this.focusPoint = focusPoint; + this.waveformSize = waveformSize; + } + + public override string TargetMember => nameof(currentZoom); + + private float valueAt(double time) + { + if (time < StartTime) return StartValue; + if (time >= EndTime) return EndValue; + + return Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing); + } + + protected override void Apply(ZoomableScrollContainer d, double time) + { + float newZoom = valueAt(time); + + float focusOffset = focusPoint - startScrollOffset; + float expectedWidth = d.DrawWidth * newZoom; + float targetOffset = expectedWidth * (focusPoint / waveformSize) - focusOffset; + + d.currentZoom = newZoom; + d.ScrollTo(targetOffset, false); + } + + protected override void ReadIntoStartValue(ZoomableScrollContainer d) + { + startScrollOffset = d.Current; + StartValue = d.currentZoom; + } + } + } +} From f41d31e1db2f2a1b2d4e398662cec4bddf8cca97 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Apr 2018 19:32:23 +0900 Subject: [PATCH 011/306] ScrollableTimeline -> TimelineContainer --- .../Visual/TestCaseEditorComposeTimeline.cs | 8 ++++---- osu.Game/Screens/Edit/Screens/Compose/Compose.cs | 6 +++--- ...crollableTimeline.cs => TimelineContainer.cs} | 16 ++++++++-------- 3 files changed, 15 insertions(+), 15 deletions(-) rename osu.Game/Screens/Edit/Screens/Compose/Timeline/{ScrollableTimeline.cs => TimelineContainer.cs} (90%) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index 0e7ba5c900..5323ac44b1 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -16,9 +16,9 @@ namespace osu.Game.Tests.Visual [TestFixture] public class TestCaseEditorComposeTimeline : OsuTestCase { - public override IReadOnlyList RequiredTypes => new[] { typeof(ScrollableTimeline), typeof(ScrollingTimelineContainer), typeof(BeatmapWaveformGraph), typeof(TimelineButton) }; + public override IReadOnlyList RequiredTypes => new[] { typeof(TimelineContainer), typeof(Timeline), typeof(BeatmapWaveformGraph), typeof(TimelineButton) }; - private readonly ScrollableTimeline timeline; + private readonly TimelineContainer timelineContainer; public TestCaseEditorComposeTimeline() { @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual Origin = Anchor.TopCentre, State = Visibility.Visible }, - timeline = new ScrollableTimeline + timelineContainer = new TimelineContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load(OsuGameBase osuGame) { - timeline.Beatmap.BindTo(osuGame.Beatmap); + timelineContainer.Beatmap.BindTo(osuGame.Beatmap); } } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index 91adc8324a..d04c4c9c0f 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose { dependencies.Cache(beatDivisor); - ScrollableTimeline timeline; + TimelineContainer timelineContainer; Children = new Drawable[] { new GridContainer @@ -68,7 +68,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Right = 5 }, - Child = timeline = new ScrollableTimeline { RelativeSizeAxes = Axes.Both } + Child = timelineContainer = new TimelineContainer { RelativeSizeAxes = Axes.Both } }, new BeatDivisorControl(beatDivisor) { RelativeSizeAxes = Axes.Both } }, @@ -97,7 +97,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose }, }; - timeline.Beatmap.BindTo(Beatmap); + timelineContainer.Beatmap.BindTo(Beatmap); var ruleset = Beatmap.Value.BeatmapInfo.Ruleset?.CreateInstance(); if (ruleset == null) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollableTimeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineContainer.cs similarity index 90% rename from osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollableTimeline.cs rename to osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineContainer.cs index 31466e960f..95a8937b9b 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollableTimeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineContainer.cs @@ -12,13 +12,13 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { - public class ScrollableTimeline : CompositeDrawable + public class TimelineContainer : CompositeDrawable { public readonly Bindable Beatmap = new Bindable(); - private readonly ScrollingTimelineContainer timelineContainer; + private readonly Timeline timeline; - public ScrollableTimeline() + public TimelineContainer() { Masking = true; CornerRadius = 5; @@ -94,7 +94,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline RelativeSizeAxes = Axes.Y, Height = 0.5f, Icon = FontAwesome.fa_search_plus, - Action = () => timelineContainer.Zoom++ + Action = () => timeline.Zoom++ }, new TimelineButton { @@ -103,13 +103,13 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline RelativeSizeAxes = Axes.Y, Height = 0.5f, Icon = FontAwesome.fa_search_minus, - Action = () => timelineContainer.Zoom-- + Action = () => timeline.Zoom-- }, } } } }, - timelineContainer = new ScrollingTimelineContainer { RelativeSizeAxes = Axes.Both } + timeline = new Timeline { RelativeSizeAxes = Axes.Both } }, }, ColumnDimensions = new[] @@ -125,8 +125,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline hitSoundsCheckbox.Current.Value = true; waveformCheckbox.Current.Value = true; - timelineContainer.Beatmap.BindTo(Beatmap); - timelineContainer.WaveformVisible.BindTo(waveformCheckbox.Current); + timeline.Beatmap.BindTo(Beatmap); + timeline.WaveformVisible.BindTo(waveformCheckbox.Current); } } } From a84536d343be59f40e2905ad947bcdd135fc5054 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Apr 2018 19:33:47 +0900 Subject: [PATCH 012/306] ScrollingTimelineContainer -> Timeline --- .../Timeline/{ScrollingTimelineContainer.cs => Timeline.cs} | 4 ++-- .../Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename osu.Game/Screens/Edit/Screens/Compose/Timeline/{ScrollingTimelineContainer.cs => Timeline.cs} (88%) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs similarity index 88% rename from osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs rename to osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index 96dc54f1e9..f1086e2cf6 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -8,12 +8,12 @@ using osu.Game.Graphics; namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { - public class ScrollingTimelineContainer : ZoomableScrollContainer + public class Timeline : ZoomableScrollContainer { public readonly Bindable WaveformVisible = new Bindable(); public readonly Bindable Beatmap = new Bindable(); - public ScrollingTimelineContainer() + public Timeline() { BeatmapWaveformGraph waveform; Child = waveform = new BeatmapWaveformGraph diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs index 05a2882f31..592419b336 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline } /// - /// Gets or sets the content zoom of this . + /// Gets or sets the content zoom of this . /// public int Zoom { @@ -76,7 +76,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline private float startScrollOffset; /// - /// Transforms to a new value. + /// Transforms to a new value. /// /// The focus point in the waveform, in absolute coordinates local to the waveform. /// The size of the waveform. From d9e795fb9f7a8ee7f372e84653ec3eb870b2b92d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Apr 2018 19:40:03 +0900 Subject: [PATCH 013/306] TimelineContainer -> TimelineArea --- osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs | 8 ++++---- osu.Game/Screens/Edit/Screens/Compose/Compose.cs | 6 +++--- .../Timeline/{TimelineContainer.cs => TimelineArea.cs} | 4 ++-- .../Screens/Compose/Timeline/ZoomableScrollContainer.cs | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) rename osu.Game/Screens/Edit/Screens/Compose/Timeline/{TimelineContainer.cs => TimelineArea.cs} (96%) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index 5323ac44b1..8ffb54f2c7 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -16,9 +16,9 @@ namespace osu.Game.Tests.Visual [TestFixture] public class TestCaseEditorComposeTimeline : OsuTestCase { - public override IReadOnlyList RequiredTypes => new[] { typeof(TimelineContainer), typeof(Timeline), typeof(BeatmapWaveformGraph), typeof(TimelineButton) }; + public override IReadOnlyList RequiredTypes => new[] { typeof(TimelineArea), typeof(Timeline), typeof(BeatmapWaveformGraph), typeof(TimelineButton) }; - private readonly TimelineContainer timelineContainer; + private readonly TimelineArea timelineArea; public TestCaseEditorComposeTimeline() { @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual Origin = Anchor.TopCentre, State = Visibility.Visible }, - timelineContainer = new TimelineContainer + timelineArea = new TimelineArea { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load(OsuGameBase osuGame) { - timelineContainer.Beatmap.BindTo(osuGame.Beatmap); + timelineArea.Beatmap.BindTo(osuGame.Beatmap); } } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index d04c4c9c0f..9306a3394c 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose { dependencies.Cache(beatDivisor); - TimelineContainer timelineContainer; + TimelineArea timelineArea; Children = new Drawable[] { new GridContainer @@ -68,7 +68,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Right = 5 }, - Child = timelineContainer = new TimelineContainer { RelativeSizeAxes = Axes.Both } + Child = timelineArea = new TimelineArea { RelativeSizeAxes = Axes.Both } }, new BeatDivisorControl(beatDivisor) { RelativeSizeAxes = Axes.Both } }, @@ -97,7 +97,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose }, }; - timelineContainer.Beatmap.BindTo(Beatmap); + timelineArea.Beatmap.BindTo(Beatmap); var ruleset = Beatmap.Value.BeatmapInfo.Ruleset?.CreateInstance(); if (ruleset == null) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs similarity index 96% rename from osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineContainer.cs rename to osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs index 95a8937b9b..6793c30409 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs @@ -12,13 +12,13 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { - public class TimelineContainer : CompositeDrawable + public class TimelineArea : CompositeDrawable { public readonly Bindable Beatmap = new Bindable(); private readonly Timeline timeline; - public TimelineContainer() + public TimelineArea() { Masking = true; CornerRadius = 5; diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs index 592419b336..a5be41bb9f 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs @@ -76,7 +76,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline private float startScrollOffset; /// - /// Transforms to a new value. + /// Transforms to a new value. /// /// The focus point in the waveform, in absolute coordinates local to the waveform. /// The size of the waveform. From 9b060b1bdf496cb45c742c679b1681297d14d48f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 6 Apr 2018 15:51:40 +0900 Subject: [PATCH 014/306] Fix delay in value retrieval causing offsetting when zooming --- .../Timeline/ZoomableScrollContainer.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs index a5be41bb9f..194b689f10 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline } private void transformZoomTo(int newZoom, float focusPoint, double duration = 0, Easing easing = Easing.None) - => this.TransformTo(this.PopulateTransform(new TransformZoom(focusPoint, zoomedContent.DrawWidth), newZoom, duration, easing)); + => this.TransformTo(this.PopulateTransform(new TransformZoom(focusPoint, zoomedContent.DrawWidth, Current), newZoom, duration, easing)); private class TransformZoom : Transform { @@ -71,19 +71,21 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline private readonly float waveformSize; /// - /// The scroll offset at the start time of the transform/ + /// The scroll offset at the start of the transform. /// - private float startScrollOffset; + private readonly float scrollOffset; /// /// Transforms to a new value. /// /// The focus point in the waveform, in absolute coordinates local to the waveform. /// The size of the waveform. - public TransformZoom(float focusPoint, float waveformSize) + /// The scroll offset at the start of the transform. + public TransformZoom(float focusPoint, float waveformSize, float scrollOffset) { this.focusPoint = focusPoint; this.waveformSize = waveformSize; + this.scrollOffset = scrollOffset; } public override string TargetMember => nameof(currentZoom); @@ -100,7 +102,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { float newZoom = valueAt(time); - float focusOffset = focusPoint - startScrollOffset; + float focusOffset = focusPoint - scrollOffset; float expectedWidth = d.DrawWidth * newZoom; float targetOffset = expectedWidth * (focusPoint / waveformSize) - focusOffset; @@ -108,11 +110,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline d.ScrollTo(targetOffset, false); } - protected override void ReadIntoStartValue(ZoomableScrollContainer d) - { - startScrollOffset = d.Current; - StartValue = d.currentZoom; - } + protected override void ReadIntoStartValue(ZoomableScrollContainer d) => StartValue = d.currentZoom; } } } From f07928446d59d1199101f522baf4838e29e3c01f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 6 Apr 2018 15:52:39 +0900 Subject: [PATCH 015/306] Remove instances of "waveform" --- .../Compose/Timeline/ZoomableScrollContainer.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs index 194b689f10..ee5d336419 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs @@ -61,14 +61,14 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline private class TransformZoom : Transform { /// - /// The focus point in the waveform, in absolute coordinates local to the waveform. + /// The focus point in absolute coordinates local to the content. /// private readonly float focusPoint; /// - /// The size of the waveform. + /// The size of the content. /// - private readonly float waveformSize; + private readonly float contentSize; /// /// The scroll offset at the start of the transform. @@ -78,13 +78,13 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline /// /// Transforms to a new value. /// - /// The focus point in the waveform, in absolute coordinates local to the waveform. - /// The size of the waveform. + /// The focus point in absolute coordinates local to the content. + /// The size of the content. /// The scroll offset at the start of the transform. - public TransformZoom(float focusPoint, float waveformSize, float scrollOffset) + public TransformZoom(float focusPoint, float contentSize, float scrollOffset) { this.focusPoint = focusPoint; - this.waveformSize = waveformSize; + this.contentSize = contentSize; this.scrollOffset = scrollOffset; } @@ -104,7 +104,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline float focusOffset = focusPoint - scrollOffset; float expectedWidth = d.DrawWidth * newZoom; - float targetOffset = expectedWidth * (focusPoint / waveformSize) - focusOffset; + float targetOffset = expectedWidth * (focusPoint / contentSize) - focusOffset; d.currentZoom = newZoom; d.ScrollTo(targetOffset, false); From eda9f838366cd46f09e3bb3401cfaf7775e21daf Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Sun, 29 Apr 2018 15:32:22 +0300 Subject: [PATCH 016/306] Add activeBeatmapPreview variable for tracking beatmap preview playback --- osu.Game/Overlays/Direct/PlayButton.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 4913b11ae1..dae3b63a8f 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -18,6 +18,7 @@ namespace osu.Game.Overlays.Direct { public class PlayButton : Container { + private static PlayButton activeBeatmapPreview; public readonly Bindable Playing = new Bindable(); public Track Preview { get; private set; } @@ -131,6 +132,9 @@ namespace osu.Game.Overlays.Direct if (playing) { + if (activeBeatmapPreview != null) + activeBeatmapPreview.Playing.Value = false; + if (Preview == null) { beginAudioLoad(); @@ -140,6 +144,7 @@ namespace osu.Game.Overlays.Direct Preview.Restart(); audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); + activeBeatmapPreview = this; } else { From 56c1c2beca733efdeee32e7d9a0779e0dc4ca524 Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Sun, 29 Apr 2018 15:50:02 +0300 Subject: [PATCH 017/306] Remove redundant multiple previews handling from PaginatedBeatmapContainer --- .../Beatmaps/PaginatedBeatmapContainer.cs | 27 ++----------------- .../Profile/Sections/BeatmapsSection.cs | 10 ------- 2 files changed, 2 insertions(+), 35 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 3fec9d8697..0b06acd426 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -1,14 +1,13 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; -using OpenTK; +using System.Linq; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Direct; using osu.Game.Users; -using System.Linq; +using OpenTK; namespace osu.Game.Overlays.Profile.Sections.Beatmaps { @@ -18,10 +17,6 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps private readonly BeatmapSetType type; - private DirectPanel currentlyPlaying; - - public event Action BeganPlayingPreview; - public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, string header, string missing = "None... yet.") : base(user, header, missing) { @@ -56,28 +51,10 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps var panel = new DirectGridPanel(s.ToBeatmapSet(Rulesets)); ItemsContainer.Add(panel); - - panel.PreviewPlaying.ValueChanged += isPlaying => - { - StopPlayingPreview(); - - if (isPlaying) - { - BeganPlayingPreview?.Invoke(this); - currentlyPlaying = panel; - } - }; } }; Api.Queue(req); } - - public void StopPlayingPreview() - { - if (currentlyPlaying == null) return; - currentlyPlaying.PreviewPlaying.Value = false; - currentlyPlaying = null; - } } } diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs index 92abd20f93..367d096c16 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Linq; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Profile.Sections.Beatmaps; @@ -22,15 +21,6 @@ namespace osu.Game.Overlays.Profile.Sections new PaginatedBeatmapContainer(BeatmapSetType.Unranked, User, "Pending Beatmaps"), new PaginatedBeatmapContainer(BeatmapSetType.Graveyard, User, "Graveyarded Beatmaps"), }; - - foreach (var paginatedBeatmapContainer in Children.OfType()) - { - paginatedBeatmapContainer.BeganPlayingPreview += _ => - { - foreach (var bc in Children.OfType()) - bc.StopPlayingPreview(); - }; - } } } } From 7cffabf7f931c367eb02ce8a0fc40342d5f6122d Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Tue, 8 May 2018 22:55:48 +0300 Subject: [PATCH 018/306] Introduce PreviewTrackManager --- osu.Game/Audio/PreviewTrackManager.cs | 60 +++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 osu.Game/Audio/PreviewTrackManager.cs diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs new file mode 100644 index 0000000000..55addac8ad --- /dev/null +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -0,0 +1,60 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Track; +using osu.Framework.Configuration; +using osu.Framework.IO.Stores; + +namespace osu.Game.Audio +{ + public class PreviewTrackManager : TrackManager + { + private AudioManager audio; + private Track currentTrack; + private readonly BindableDouble muteBindable; + + public PreviewTrackManager() + : base(new OnlineStore()) + { + muteBindable = new BindableDouble(); + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio, FrameworkConfigManager config) + { + this.audio = audio; + + audio.AddItem(this); + + config.BindWith(FrameworkSetting.VolumeMusic, Volume); + } + + protected override void UpdateState() + { + if (currentTrack?.HasCompleted ?? false) + onStop(); + + base.UpdateState(); + } + + public void Play(Track track) + { + currentTrack?.Stop(); + currentTrack = track; + currentTrack.Restart(); + onPlay(); + } + + private void onPlay() => audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); + + public void Stop() + { + currentTrack?.Stop(); + onStop(); + } + + private void onStop() => audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); + } +} From ad50f7faf10cdc5c4090d5ff58db5cc906debe72 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Wed, 9 May 2018 14:51:04 +0300 Subject: [PATCH 019/306] Make PreviewTrackManager a Component in order to use DI --- osu.Game/Audio/PreviewTrackManager.cs | 60 +++++++++++++++------------ 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 55addac8ad..2e5f26bcf4 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -1,60 +1,66 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Configuration; +using osu.Framework.Graphics; using osu.Framework.IO.Stores; +using osu.Game.Beatmaps; namespace osu.Game.Audio { - public class PreviewTrackManager : TrackManager + public class PreviewTrackManager : Component { - private AudioManager audio; - private Track currentTrack; - private readonly BindableDouble muteBindable; + public event Action PlaybackStarted; + public event Action PlaybackStopped; - public PreviewTrackManager() - : base(new OnlineStore()) - { - muteBindable = new BindableDouble(); - } + private TrackManager trackManager; + private BindableDouble muteBindable; + + public Track CurrentTrack { get; private set; } [BackgroundDependencyLoader] private void load(AudioManager audio, FrameworkConfigManager config) { - this.audio = audio; + trackManager = new TrackManager(new OnlineStore()); - audio.AddItem(this); + muteBindable = new BindableDouble(); - config.BindWith(FrameworkSetting.VolumeMusic, Volume); + audio.AddItem(trackManager); + config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); + + PlaybackStarted += () => audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); + PlaybackStopped += () => audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); } - protected override void UpdateState() - { - if (currentTrack?.HasCompleted ?? false) - onStop(); + public Track Get(BeatmapSetInfo beatmapSetInfo) => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo.OnlineBeatmapSetID}.mp3"); - base.UpdateState(); + protected override void Update() + { + if (CurrentTrack?.HasCompleted ?? false) + PlaybackStopped?.Invoke(); + + base.Update(); } public void Play(Track track) { - currentTrack?.Stop(); - currentTrack = track; - currentTrack.Restart(); - onPlay(); + Stop(); + CurrentTrack = track; + track.Restart(); + PlaybackStarted?.Invoke(); } - private void onPlay() => audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); - public void Stop() { - currentTrack?.Stop(); - onStop(); + if (CurrentTrack?.IsRunning ?? false) + { + CurrentTrack?.Stop(); + PlaybackStopped?.Invoke(); + } } - - private void onStop() => audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); } } From c492f62edaac7b92d505c8d0eaf5fa2112522e4e Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Wed, 9 May 2018 14:52:46 +0300 Subject: [PATCH 020/306] Use PreviewTrackManager in the PlayButton --- osu.Game/OsuGameBase.cs | 5 ++ osu.Game/Overlays/Direct/PlayButton.cs | 112 +++++-------------------- 2 files changed, 24 insertions(+), 93 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 487cb50c9a..4d2d4d05a7 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -23,6 +23,7 @@ using osu.Game.Online.API; using osu.Framework.Graphics.Performance; using osu.Framework.Graphics.Textures; using osu.Framework.Logging; +using osu.Game.Audio; using osu.Game.Database; using osu.Game.Graphics.Textures; using osu.Game.Input; @@ -202,6 +203,10 @@ namespace osu.Game KeyBindingStore.Register(globalBinding); dependencies.Cache(globalBinding); + + PreviewTrackManager previewTrackManager; + dependencies.Cache(previewTrackManager = new PreviewTrackManager()); + Add(previewTrackManager); } private void runMigrations() diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index dae3b63a8f..082cf34d8e 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -1,24 +1,22 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK.Graphics; using osu.Framework.Allocation; -using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; -using osu.Framework.IO.Stores; +using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using OpenTK.Graphics; namespace osu.Game.Overlays.Direct { public class PlayButton : Container { - private static PlayButton activeBeatmapPreview; public readonly Bindable Playing = new Bindable(); public Track Preview { get; private set; } @@ -33,17 +31,16 @@ namespace osu.Game.Overlays.Direct beatmapSet = value; Playing.Value = false; - trackLoader = null; Preview = null; } } + private PreviewTrackManager previewTrackManager; + private Color4 hoverColour; private readonly SpriteIcon icon; private readonly LoadingAnimation loadingAnimation; - private readonly BindableDouble muteBindable = new BindableDouble(); - private const float transition_duration = 500; private bool loading @@ -79,14 +76,20 @@ namespace osu.Game.Overlays.Direct loadingAnimation = new LoadingAnimation(), }); - Playing.ValueChanged += updatePreviewTrack; + Playing.ValueChanged += playingStateChanged; } [BackgroundDependencyLoader] - private void load(OsuColour colour, AudioManager audio) + private void load(OsuColour colour, PreviewTrackManager previewTrackManager) { hoverColour = colour.Yellow; - this.audio = audio; + this.previewTrackManager = previewTrackManager; + + previewTrackManager.PlaybackStopped += () => + { + if (Preview == previewTrackManager.CurrentTrack) + Playing.Value = false; + }; } protected override bool OnClick(InputState state) @@ -108,18 +111,7 @@ namespace osu.Game.Overlays.Direct base.OnHoverLost(state); } - protected override void Update() - { - base.Update(); - - if (Preview?.HasCompleted ?? false) - { - Playing.Value = false; - Preview = null; - } - } - - private void updatePreviewTrack(bool playing) + private void playingStateChanged(bool playing) { if (playing && BeatmapSet == null) { @@ -132,25 +124,18 @@ namespace osu.Game.Overlays.Direct if (playing) { - if (activeBeatmapPreview != null) - activeBeatmapPreview.Playing.Value = false; - if (Preview == null) { - beginAudioLoad(); - return; + loading = true; + Preview = previewTrackManager.Get(beatmapSet); + loading = false; } - Preview.Restart(); - - audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); - activeBeatmapPreview = this; + previewTrackManager.Play(Preview); } else { - audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); - - Preview?.Stop(); + previewTrackManager.Stop(); loading = false; } } @@ -160,64 +145,5 @@ namespace osu.Game.Overlays.Direct base.Dispose(isDisposing); Playing.Value = false; } - - private TrackLoader trackLoader; - private AudioManager audio; - - private void beginAudioLoad() - { - if (trackLoader != null) - { - Preview = trackLoader.Preview; - Playing.TriggerChange(); - return; - } - - loading = true; - - LoadComponentAsync(trackLoader = new TrackLoader($"https://b.ppy.sh/preview/{BeatmapSet.OnlineBeatmapSetID}.mp3"), - d => - { - // We may have been replaced by another loader - if (trackLoader != d) return; - - Preview = d?.Preview; - updatePreviewTrack(Playing); - loading = false; - - Add(trackLoader); - }); - } - - private class TrackLoader : Drawable - { - private readonly string preview; - - public Track Preview; - private TrackManager trackManager; - - public TrackLoader(string preview) - { - this.preview = preview; - } - - [BackgroundDependencyLoader] - private void load(AudioManager audio, FrameworkConfigManager config) - { - // create a local trackManager to bypass the mute we are applying above. - audio.AddItem(trackManager = new TrackManager(new OnlineStore())); - - // add back the user's music volume setting (since we are no longer in the global TrackManager's hierarchy). - config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); - - Preview = trackManager.Get(preview); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - trackManager?.Dispose(); - } - } } } From 95dd2125ee91dbda04d527d1c34d236a9190c1f9 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Wed, 9 May 2018 16:22:52 +0300 Subject: [PATCH 021/306] Load PlayButton.Preview asynchronously --- osu.Game/Overlays/Direct/PlayButton.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 082cf34d8e..77c904050b 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Configuration; @@ -126,9 +127,17 @@ namespace osu.Game.Overlays.Direct { if (Preview == null) { - loading = true; - Preview = previewTrackManager.Get(beatmapSet); - loading = false; + Task.Run(() => + { + loading = true; + return Preview = previewTrackManager.Get(beatmapSet); + }) + .ContinueWith(t => + { + playingStateChanged(true); + loading = false; + }); + return; } previewTrackManager.Play(Preview); From 95a207ef56a9907fff4c892f7e36c47fbf6e843d Mon Sep 17 00:00:00 2001 From: KoziLord Date: Tue, 15 May 2018 00:17:42 +0200 Subject: [PATCH 022/306] Fixed the parallax background missing from the space occupied by the top toolbar. --- osu.Game/Screens/Ranking/Results.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 32161a0b8e..38dbf1a65d 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -160,7 +160,7 @@ namespace osu.Game.Screens.Ranking { RelativeSizeAxes = Axes.Both, ParallaxAmount = 0.01f, - Scale = new Vector2(1 / circle_outer_scale / overscan), + Scale = new Vector2(1 / circle_outer_scale), Anchor = Anchor.Centre, Origin = Anchor.Centre, Children = new Drawable[] From ca05fde14c7c9f984caf6c7fcbbdbe3ce78ed010 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Tue, 15 May 2018 00:47:03 +0200 Subject: [PATCH 023/306] Fix the Parallax Background not filling the entire Circle Container. --- osu.Game/Screens/Ranking/Results.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 38dbf1a65d..a2990d7902 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -159,8 +159,11 @@ namespace osu.Game.Screens.Ranking backgroundParallax = new ParallaxContainer { RelativeSizeAxes = Axes.Both, - ParallaxAmount = 0.01f, - Scale = new Vector2(1 / circle_outer_scale), + ParallaxAmount = 0.02f, + //Compensate for the Toolbar + Scale = new Vector2(1.06f / circle_outer_scale / overscan), + //Offset the background to account for the toolbar. + Position = new Vector2(0, -20), Anchor = Anchor.Centre, Origin = Anchor.Centre, Children = new Drawable[] From be56d8cb8253a7c710579f54377f5563e9c01170 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Tue, 15 May 2018 00:53:31 +0200 Subject: [PATCH 024/306] Change the parallax amount --- osu.Game/Screens/Ranking/Results.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index a2990d7902..17e8666ebf 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -159,7 +159,7 @@ namespace osu.Game.Screens.Ranking backgroundParallax = new ParallaxContainer { RelativeSizeAxes = Axes.Both, - ParallaxAmount = 0.02f, + ParallaxAmount = 0.01f, //Compensate for the Toolbar Scale = new Vector2(1.06f / circle_outer_scale / overscan), //Offset the background to account for the toolbar. From be1159444d2fb9cb15f0019b275fa9f6a6df48e4 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Tue, 15 May 2018 15:56:49 +0200 Subject: [PATCH 025/306] Use the absolute value of ParallaxAmount to make sure we're not scaling stuff down when using a negative ParallaxAmount --- osu.Game/Graphics/Containers/ParallaxContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index dc635ce7e7..51be40c1e8 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -45,7 +45,7 @@ namespace osu.Game.Graphics.Containers if (!parallaxEnabled) { content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, Easing.OutQuint); - content.Scale = new Vector2(1 + ParallaxAmount); + content.Scale = new Vector2(1 + System.Math.Abs(ParallaxAmount)); } }; } @@ -69,7 +69,7 @@ namespace osu.Game.Graphics.Containers double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000); content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, 1000, Easing.OutQuint); - content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + ParallaxAmount), 0, 1000, Easing.OutQuint); + content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + System.Math.Abs(ParallaxAmount)), 0, 1000, Easing.OutQuint); } firstUpdate = false; From 1e88f216f27831a8c5bc76cf09ce271be61e0580 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Wed, 16 May 2018 01:27:18 +0200 Subject: [PATCH 026/306] Revert the ParallaxContainer changes I made by accident back. --- osu.Game/Graphics/Containers/ParallaxContainer.cs | 4 ++-- osu.Game/Screens/Ranking/Results.cs | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index 51be40c1e8..dc635ce7e7 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -45,7 +45,7 @@ namespace osu.Game.Graphics.Containers if (!parallaxEnabled) { content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, Easing.OutQuint); - content.Scale = new Vector2(1 + System.Math.Abs(ParallaxAmount)); + content.Scale = new Vector2(1 + ParallaxAmount); } }; } @@ -69,7 +69,7 @@ namespace osu.Game.Graphics.Containers double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000); content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, 1000, Easing.OutQuint); - content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + System.Math.Abs(ParallaxAmount)), 0, 1000, Easing.OutQuint); + content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + ParallaxAmount), 0, 1000, Easing.OutQuint); } firstUpdate = false; diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 17e8666ebf..32161a0b8e 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -160,10 +160,7 @@ namespace osu.Game.Screens.Ranking { RelativeSizeAxes = Axes.Both, ParallaxAmount = 0.01f, - //Compensate for the Toolbar - Scale = new Vector2(1.06f / circle_outer_scale / overscan), - //Offset the background to account for the toolbar. - Position = new Vector2(0, -20), + Scale = new Vector2(1 / circle_outer_scale / overscan), Anchor = Anchor.Centre, Origin = Anchor.Centre, Children = new Drawable[] From 428d0f5deec85cfb2153d8246301f3f269865346 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Wed, 16 May 2018 01:30:16 +0200 Subject: [PATCH 027/306] Re-implement the fix after it got deleted in the previous commit. --- osu.Game/Screens/Ranking/Results.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 32161a0b8e..162c428444 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -160,8 +160,11 @@ namespace osu.Game.Screens.Ranking { RelativeSizeAxes = Axes.Both, ParallaxAmount = 0.01f, - Scale = new Vector2(1 / circle_outer_scale / overscan), + //Compensate for the Toolbar + Scale = new Vector2(1.06f / circle_outer_scale / overscan), + //Offset the background to account for the toolbar. Anchor = Anchor.Centre, + Position = new Vector2(0, -20), Origin = Anchor.Centre, Children = new Drawable[] { From 3b708f650591a015ccd1e54721981f4316fbce4b Mon Sep 17 00:00:00 2001 From: KoziLord Date: Wed, 16 May 2018 01:34:08 +0200 Subject: [PATCH 028/306] make it equal with the original codebase. --- osu.Game/Screens/Ranking/Results.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 162c428444..67949f8e14 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -160,17 +160,14 @@ namespace osu.Game.Screens.Ranking { RelativeSizeAxes = Axes.Both, ParallaxAmount = 0.01f, - //Compensate for the Toolbar - Scale = new Vector2(1.06f / circle_outer_scale / overscan), - //Offset the background to account for the toolbar. + Scale = new Vector2(1 / circle_outer_scale / overscan), Anchor = Anchor.Centre, - Position = new Vector2(0, -20), Origin = Anchor.Centre, Children = new Drawable[] { new Sprite { - RelativeSizeAxes = Axes.Both, + RelativeSsizeAxes = Axes.Both, Alpha = 0.2f, Texture = Beatmap.Value.Background, Anchor = Anchor.Centre, From 705960dabbc32591ccd36841e66e101e41133189 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Wed, 16 May 2018 01:36:26 +0200 Subject: [PATCH 029/306] Fix typo --- osu.Game/Screens/Ranking/Results.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 67949f8e14..32161a0b8e 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -167,7 +167,7 @@ namespace osu.Game.Screens.Ranking { new Sprite { - RelativeSsizeAxes = Axes.Both, + RelativeSizeAxes = Axes.Both, Alpha = 0.2f, Texture = Beatmap.Value.Background, Anchor = Anchor.Centre, From d2b2d3e2e078de26188030f79c1722e2f30d2589 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Wed, 16 May 2018 01:38:46 +0200 Subject: [PATCH 030/306] Use the absolute value of ParallaxAmount to make sure we're not scaling things down when using a negative value for the Parallax (moving against the cursor instead of with it) --- osu.Game/Graphics/Containers/ParallaxContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index dc635ce7e7..51be40c1e8 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -45,7 +45,7 @@ namespace osu.Game.Graphics.Containers if (!parallaxEnabled) { content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, Easing.OutQuint); - content.Scale = new Vector2(1 + ParallaxAmount); + content.Scale = new Vector2(1 + System.Math.Abs(ParallaxAmount)); } }; } @@ -69,7 +69,7 @@ namespace osu.Game.Graphics.Containers double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000); content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, 1000, Easing.OutQuint); - content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + ParallaxAmount), 0, 1000, Easing.OutQuint); + content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + System.Math.Abs(ParallaxAmount)), 0, 1000, Easing.OutQuint); } firstUpdate = false; From bc3d195aa21361f86490c7bd86f1f099c94fc00b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 May 2018 13:05:58 +0900 Subject: [PATCH 031/306] Fix line endings --- .../Edit/Screens/Compose/Timeline/Timeline.cs | 78 +++--- .../Screens/Compose/Timeline/TimelineArea.cs | 264 +++++++++--------- .../Timeline/ZoomableScrollContainer.cs | 232 +++++++-------- 3 files changed, 287 insertions(+), 287 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index f1086e2cf6..a9de155df8 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -1,39 +1,39 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Configuration; -using osu.Framework.Graphics; -using osu.Game.Beatmaps; -using osu.Game.Graphics; - -namespace osu.Game.Screens.Edit.Screens.Compose.Timeline -{ - public class Timeline : ZoomableScrollContainer - { - public readonly Bindable WaveformVisible = new Bindable(); - public readonly Bindable Beatmap = new Bindable(); - - public Timeline() - { - BeatmapWaveformGraph waveform; - Child = waveform = new BeatmapWaveformGraph - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex("222"), - Depth = float.MaxValue - }; - - waveform.Beatmap.BindTo(Beatmap); - - WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); - } - - protected override void Update() - { - base.Update(); - - // We want time = 0 to be at the centre of the container when scrolled to the start - Content.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; - } - } -} +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +{ + public class Timeline : ZoomableScrollContainer + { + public readonly Bindable WaveformVisible = new Bindable(); + public readonly Bindable Beatmap = new Bindable(); + + public Timeline() + { + BeatmapWaveformGraph waveform; + Child = waveform = new BeatmapWaveformGraph + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex("222"), + Depth = float.MaxValue + }; + + waveform.Beatmap.BindTo(Beatmap); + + WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); + } + + protected override void Update() + { + base.Update(); + + // We want time = 0 to be at the centre of the container when scrolled to the start + Content.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; + } + } +} diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs index 6793c30409..9b6b0bd48d 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs @@ -1,132 +1,132 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using OpenTK; -using osu.Framework.Configuration; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; - -namespace osu.Game.Screens.Edit.Screens.Compose.Timeline -{ - public class TimelineArea : CompositeDrawable - { - public readonly Bindable Beatmap = new Bindable(); - - private readonly Timeline timeline; - - public TimelineArea() - { - Masking = true; - CornerRadius = 5; - - OsuCheckbox hitObjectsCheckbox; - OsuCheckbox hitSoundsCheckbox; - OsuCheckbox waveformCheckbox; - InternalChildren = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex("111") - }, - new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex("222") - }, - new FillFlowContainer - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Y, - Width = 160, - Padding = new MarginPadding { Horizontal = 15 }, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 4), - Children = new[] - { - hitObjectsCheckbox = new OsuCheckbox { LabelText = "Hitobjects" }, - hitSoundsCheckbox = new OsuCheckbox { LabelText = "Hitsounds" }, - waveformCheckbox = new OsuCheckbox { LabelText = "Waveform" } - } - } - } - }, - new Container - { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex("333") - }, - new Container - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Masking = true, - Children = new[] - { - new TimelineButton - { - RelativeSizeAxes = Axes.Y, - Height = 0.5f, - Icon = FontAwesome.fa_search_plus, - Action = () => timeline.Zoom++ - }, - new TimelineButton - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Y, - Height = 0.5f, - Icon = FontAwesome.fa_search_minus, - Action = () => timeline.Zoom-- - }, - } - } - } - }, - timeline = new Timeline { RelativeSizeAxes = Axes.Both } - }, - }, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Distributed), - } - } - }; - - hitObjectsCheckbox.Current.Value = true; - hitSoundsCheckbox.Current.Value = true; - waveformCheckbox.Current.Value = true; - - timeline.Beatmap.BindTo(Beatmap); - timeline.WaveformVisible.BindTo(waveformCheckbox.Current); - } - } -} +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +{ + public class TimelineArea : CompositeDrawable + { + public readonly Bindable Beatmap = new Bindable(); + + private readonly Timeline timeline; + + public TimelineArea() + { + Masking = true; + CornerRadius = 5; + + OsuCheckbox hitObjectsCheckbox; + OsuCheckbox hitSoundsCheckbox; + OsuCheckbox waveformCheckbox; + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex("111") + }, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex("222") + }, + new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Y, + Width = 160, + Padding = new MarginPadding { Horizontal = 15 }, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 4), + Children = new[] + { + hitObjectsCheckbox = new OsuCheckbox { LabelText = "Hitobjects" }, + hitSoundsCheckbox = new OsuCheckbox { LabelText = "Hitsounds" }, + waveformCheckbox = new OsuCheckbox { LabelText = "Waveform" } + } + } + } + }, + new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex("333") + }, + new Container + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Masking = true, + Children = new[] + { + new TimelineButton + { + RelativeSizeAxes = Axes.Y, + Height = 0.5f, + Icon = FontAwesome.fa_search_plus, + Action = () => timeline.Zoom++ + }, + new TimelineButton + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.Y, + Height = 0.5f, + Icon = FontAwesome.fa_search_minus, + Action = () => timeline.Zoom-- + }, + } + } + } + }, + timeline = new Timeline { RelativeSizeAxes = Axes.Both } + }, + }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Distributed), + } + } + }; + + hitObjectsCheckbox.Current.Value = true; + hitSoundsCheckbox.Current.Value = true; + waveformCheckbox.Current.Value = true; + + timeline.Beatmap.BindTo(Beatmap); + timeline.WaveformVisible.BindTo(waveformCheckbox.Current); + } + } +} diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs index ee5d336419..545caf5166 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs @@ -1,116 +1,116 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Transforms; -using osu.Framework.Input; -using osu.Framework.MathUtils; -using OpenTK; - -namespace osu.Game.Screens.Edit.Screens.Compose.Timeline -{ - public class ZoomableScrollContainer : ScrollContainer - { - private readonly Container zoomedContent; - protected override Container Content => zoomedContent; - - private float currentZoom = 10; - - public ZoomableScrollContainer() - : base(Direction.Horizontal) - { - base.Content.Add(zoomedContent = new Container { RelativeSizeAxes = Axes.Y }); - } - - /// - /// Gets or sets the content zoom of this . - /// - public int Zoom - { - get => zoomTarget; - set => setZoomTarget(value, ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), zoomedContent).X); - } - - protected override void Update() - { - base.Update(); - - zoomedContent.Width = DrawWidth * currentZoom; - } - - protected override bool OnWheel(InputState state) - { - if (!state.Keyboard.ControlPressed) - return base.OnWheel(state); - - setZoomTarget(zoomTarget + state.Mouse.WheelDelta, zoomedContent.ToLocalSpace(state.Mouse.NativeState.Position).X); - return true; - } - - private int zoomTarget = 10; - private void setZoomTarget(int newZoom, float focusPoint) - { - zoomTarget = MathHelper.Clamp(newZoom, 1, 60); - transformZoomTo(zoomTarget, focusPoint, 200, Easing.OutQuint); - } - - private void transformZoomTo(int newZoom, float focusPoint, double duration = 0, Easing easing = Easing.None) - => this.TransformTo(this.PopulateTransform(new TransformZoom(focusPoint, zoomedContent.DrawWidth, Current), newZoom, duration, easing)); - - private class TransformZoom : Transform - { - /// - /// The focus point in absolute coordinates local to the content. - /// - private readonly float focusPoint; - - /// - /// The size of the content. - /// - private readonly float contentSize; - - /// - /// The scroll offset at the start of the transform. - /// - private readonly float scrollOffset; - - /// - /// Transforms to a new value. - /// - /// The focus point in absolute coordinates local to the content. - /// The size of the content. - /// The scroll offset at the start of the transform. - public TransformZoom(float focusPoint, float contentSize, float scrollOffset) - { - this.focusPoint = focusPoint; - this.contentSize = contentSize; - this.scrollOffset = scrollOffset; - } - - public override string TargetMember => nameof(currentZoom); - - private float valueAt(double time) - { - if (time < StartTime) return StartValue; - if (time >= EndTime) return EndValue; - - return Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing); - } - - protected override void Apply(ZoomableScrollContainer d, double time) - { - float newZoom = valueAt(time); - - float focusOffset = focusPoint - scrollOffset; - float expectedWidth = d.DrawWidth * newZoom; - float targetOffset = expectedWidth * (focusPoint / contentSize) - focusOffset; - - d.currentZoom = newZoom; - d.ScrollTo(targetOffset, false); - } - - protected override void ReadIntoStartValue(ZoomableScrollContainer d) => StartValue = d.currentZoom; - } - } -} +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Transforms; +using osu.Framework.Input; +using osu.Framework.MathUtils; +using OpenTK; + +namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +{ + public class ZoomableScrollContainer : ScrollContainer + { + private readonly Container zoomedContent; + protected override Container Content => zoomedContent; + + private float currentZoom = 10; + + public ZoomableScrollContainer() + : base(Direction.Horizontal) + { + base.Content.Add(zoomedContent = new Container { RelativeSizeAxes = Axes.Y }); + } + + /// + /// Gets or sets the content zoom of this . + /// + public int Zoom + { + get => zoomTarget; + set => setZoomTarget(value, ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), zoomedContent).X); + } + + protected override void Update() + { + base.Update(); + + zoomedContent.Width = DrawWidth * currentZoom; + } + + protected override bool OnWheel(InputState state) + { + if (!state.Keyboard.ControlPressed) + return base.OnWheel(state); + + setZoomTarget(zoomTarget + state.Mouse.WheelDelta, zoomedContent.ToLocalSpace(state.Mouse.NativeState.Position).X); + return true; + } + + private int zoomTarget = 10; + private void setZoomTarget(int newZoom, float focusPoint) + { + zoomTarget = MathHelper.Clamp(newZoom, 1, 60); + transformZoomTo(zoomTarget, focusPoint, 200, Easing.OutQuint); + } + + private void transformZoomTo(int newZoom, float focusPoint, double duration = 0, Easing easing = Easing.None) + => this.TransformTo(this.PopulateTransform(new TransformZoom(focusPoint, zoomedContent.DrawWidth, Current), newZoom, duration, easing)); + + private class TransformZoom : Transform + { + /// + /// The focus point in absolute coordinates local to the content. + /// + private readonly float focusPoint; + + /// + /// The size of the content. + /// + private readonly float contentSize; + + /// + /// The scroll offset at the start of the transform. + /// + private readonly float scrollOffset; + + /// + /// Transforms to a new value. + /// + /// The focus point in absolute coordinates local to the content. + /// The size of the content. + /// The scroll offset at the start of the transform. + public TransformZoom(float focusPoint, float contentSize, float scrollOffset) + { + this.focusPoint = focusPoint; + this.contentSize = contentSize; + this.scrollOffset = scrollOffset; + } + + public override string TargetMember => nameof(currentZoom); + + private float valueAt(double time) + { + if (time < StartTime) return StartValue; + if (time >= EndTime) return EndValue; + + return Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing); + } + + protected override void Apply(ZoomableScrollContainer d, double time) + { + float newZoom = valueAt(time); + + float focusOffset = focusPoint - scrollOffset; + float expectedWidth = d.DrawWidth * newZoom; + float targetOffset = expectedWidth * (focusPoint / contentSize) - focusOffset; + + d.currentZoom = newZoom; + d.ScrollTo(targetOffset, false); + } + + protected override void ReadIntoStartValue(ZoomableScrollContainer d) => StartValue = d.currentZoom; + } + } +} From 82607b3eb302f6c1689e84c3de226adf1bd679f8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 May 2018 17:53:09 +0900 Subject: [PATCH 032/306] Expose properties to control zoom --- .../Edit/Screens/Compose/Timeline/Timeline.cs | 4 ++ .../Timeline/ZoomableScrollContainer.cs | 70 +++++++++++++++++-- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index a9de155df8..9801ba12a1 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -15,6 +15,10 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline public Timeline() { + ZoomDuration = 200; + ZoomEasing = Easing.OutQuint; + Zoom = 10; + BeatmapWaveformGraph waveform; Child = waveform = new BeatmapWaveformGraph { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs index 545caf5166..72faf657ce 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Transforms; @@ -12,10 +13,21 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { public class ZoomableScrollContainer : ScrollContainer { + /// + /// The time to zoom into/out of a point. + /// All user scroll input will be overwritten during the zoom transform. + /// + public double ZoomDuration; + + /// + /// The easing with which to transform the zoom. + /// + public Easing ZoomEasing; + private readonly Container zoomedContent; protected override Container Content => zoomedContent; - private float currentZoom = 10; + private float currentZoom = 1; public ZoomableScrollContainer() : base(Direction.Horizontal) @@ -23,13 +35,59 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline base.Content.Add(zoomedContent = new Container { RelativeSizeAxes = Axes.Y }); } + private int minZoom = 1; + /// - /// Gets or sets the content zoom of this . + /// The minimum zoom level allowed. + /// + public int MinZoom + { + get => minZoom; + set + { + if (value < 1) + throw new ArgumentException($"{nameof(MinZoom)} must be >= 1.", nameof(value)); + minZoom = value; + + if (Zoom < value) + Zoom = value; + } + } + + private int maxZoom = 60; + + /// + /// The maximum zoom level allowed. + /// + public int MaxZoom + { + get => maxZoom; + set + { + if (value < 1) + throw new ArgumentException($"{nameof(MaxZoom)} must be >= 1.", nameof(value)); + maxZoom = value; + + if (Zoom > value) + Zoom = value; + } + } + + /// + /// Gets or sets the content zoom level of this . /// public int Zoom { get => zoomTarget; - set => setZoomTarget(value, ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), zoomedContent).X); + set + { + value = MathHelper.Clamp(value, MinZoom, MaxZoom); + + if (IsLoaded) + setZoomTarget(value, ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), zoomedContent).X); + else + currentZoom = zoomTarget = value; + } } protected override void Update() @@ -48,11 +106,11 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline return true; } - private int zoomTarget = 10; + private int zoomTarget = 1; private void setZoomTarget(int newZoom, float focusPoint) { - zoomTarget = MathHelper.Clamp(newZoom, 1, 60); - transformZoomTo(zoomTarget, focusPoint, 200, Easing.OutQuint); + zoomTarget = MathHelper.Clamp(newZoom, MinZoom, MaxZoom); + transformZoomTo(zoomTarget, focusPoint, ZoomDuration, ZoomEasing); } private void transformZoomTo(int newZoom, float focusPoint, double duration = 0, Easing easing = Easing.None) From 757f89871819a1164e778ae544c3d6d81d7e79e9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 May 2018 17:53:19 +0900 Subject: [PATCH 033/306] Add testcase for zoomable scroll container --- .../Visual/TestCaseZoomableScrollContainer.cs | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs diff --git a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs new file mode 100644 index 0000000000..06ec9ec63c --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs @@ -0,0 +1,142 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Shapes; +using osu.Framework.MathUtils; +using osu.Game.Graphics; +using osu.Game.Graphics.Cursor; +using osu.Game.Screens.Edit.Screens.Compose.Timeline; +using OpenTK; +using OpenTK.Graphics; +using OpenTK.Input; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseZoomableScrollContainer : ManualInputManagerTestCase + { + private readonly ZoomableScrollContainer scrollContainer; + private readonly Drawable innerBox; + + public TestCaseZoomableScrollContainer() + { + Children = new Drawable[] + { + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Height = 250, + Width = 0.75f, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(30) + }, + scrollContainer = new ZoomableScrollContainer { RelativeSizeAxes = Axes.Both } + } + }, + new MenuCursor() + }; + + scrollContainer.Add(innerBox = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal(new Color4(0.8f, 0.6f, 0.4f, 1f), new Color4(0.4f, 0.6f, 0.8f, 1f)) + }); + } + + [Test] + public void TestZoom0() + { + reset(); + AddAssert("Box at 0", () => Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft)); + AddAssert("Box width = 1x", () => Precision.AlmostEquals(boxQuad.Size, scrollQuad.Size)); + } + + [Test] + public void TestZoom10() + { + reset(); + AddStep("Set zoom = 10", () => scrollContainer.Zoom = 10); + AddAssert("Box at 1/2", () => Precision.AlmostEquals(boxQuad.Centre, scrollQuad.Centre)); + AddAssert("Box width = 10x", () => Precision.AlmostEquals(boxQuad.Size.X, 10 * scrollQuad.Size.X)); + } + + [Test] + public void TestMouseZoomInOnceOutOnce() + { + reset(); + + // Scroll in at 0.25 + AddStep("Move mouse to 0.25x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, scrollQuad.Centre.Y))); + AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); + AddStep("Scroll by 3", () => InputManager.ScrollBy(3)); + AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddAssert("Box not at 0", () => !Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft)); + AddAssert("Box 1/4 at 1/4", () => Precision.AlmostEquals(boxQuad.TopLeft.X + 0.25f * boxQuad.Size.X, scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X)); + + // Scroll out at 0.25 + AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); + AddStep("Scroll by -3", () => InputManager.ScrollBy(-3)); + AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddAssert("Box at 0", () => Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft)); + AddAssert("Box 1/4 at 1/4", () => Precision.AlmostEquals(boxQuad.TopLeft.X + 0.25f * boxQuad.Size.X, scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X)); + } + + [Test] + public void TestMouseZoomInTwiceOutTwice() + { + reset(); + + // Scroll in at 0.25 + AddStep("Move mouse to 0.25x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, scrollQuad.Centre.Y))); + AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); + AddStep("Scroll by 1", () => InputManager.ScrollBy(1)); + AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + + // Scroll in at 0.6 + AddStep("Move mouse to 0.75x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.75f * scrollQuad.Size.X, scrollQuad.Centre.Y))); + AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); + AddStep("Scroll by 1", () => InputManager.ScrollBy(1)); + AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddAssert("Box not at 0", () => !Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft)); + + // Very hard to determine actual position, so approximate + AddAssert("Box at correct position (1)", () => Precision.DefinitelyBigger(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, boxQuad.TopLeft.X + 0.25f * boxQuad.Size.X)); + AddAssert("Box at correct position (2)", () => Precision.DefinitelyBigger(scrollQuad.TopLeft.X + 0.6f * scrollQuad.Size.X, boxQuad.TopLeft.X + 0.3f * boxQuad.Size.X)); + AddAssert("Box at correct position (3)", () => Precision.DefinitelyBigger(boxQuad.TopLeft.X + 0.6f * boxQuad.Size.X, scrollQuad.TopLeft.X + 0.6f * scrollQuad.Size.X)); + + // Scroll out at 0.6 + AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); + AddStep("Scroll by -1", () => InputManager.ScrollBy(-1)); + AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + + // Scroll out at 0.25 + AddStep("Move mouse to 0.25x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, scrollQuad.Centre.Y))); + AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); + AddStep("Scroll by -1", () => InputManager.ScrollBy(-1)); + AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddAssert("Box at 0", () => Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft)); + } + + private void reset() + { + AddStep("Reset", () => + { + scrollContainer.Zoom = 0; + scrollContainer.ScrollTo(0, false); + }); + } + + private Quad scrollQuad => scrollContainer.ScreenSpaceDrawQuad; + private Quad boxQuad => innerBox.ScreenSpaceDrawQuad; + } +} From f50c1c78a25a719f1b1c1cf4ac072a991013d8f0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 May 2018 18:14:12 +0900 Subject: [PATCH 034/306] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index fac688633b..8f007de13e 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit fac688633b8fcf34ae5d0514c26b03e217161eb4 +Subproject commit 8f007de13e4a1aed46cb35e5018448f809bd5e88 From 79c64d16e43da33e3e21fdcefdd192da9eaba2b7 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 09:49:23 +0800 Subject: [PATCH 035/306] Realization on Catch Star Rating --- .../Difficulty/CatchDifficultyCalculator.cs | 160 +++++++++++++++++- .../Difficulty/CatchDifficultyHitObject.cs | 127 ++++++++++++++ 2 files changed, 285 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index f8351b7519..5351bd746d 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -1,18 +1,174 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Catch.Difficulty { public class CatchDifficultyCalculator : DifficultyCalculator { - public CatchDifficultyCalculator(IBeatmap beatmap) : base(beatmap) + private const double STAR_SCALING_FACTOR = 0.145; + private const float PLAYFIELD_WIDTH = CatchPlayfield.BASE_WIDTH; + + private readonly List difficultyHitObjects = new List(); + + public CatchDifficultyCalculator(IBeatmap beatmap) + : base(beatmap) { } - public override double Calculate(Dictionary categoryDifficulty = null) => 0; + public CatchDifficultyCalculator(IBeatmap beatmap, Mod[] mods) + : base(beatmap, mods) + { + } + + public override double Calculate(Dictionary categoryDifficulty = null) + { + + difficultyHitObjects.Clear(); + + float circleSize = Beatmap.BeatmapInfo.BaseDifficulty.CircleSize; + float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * 172; + //float catcherWidth = (float)(305.0f / 1.6f * ((102.4f * (1.0f - 0.7 * (circleSize - 5.0f)) / 5.0f) / 128.0f * 0.7f)); + float catcherWidthHalf = catcherWidth / 2; + catcherWidthHalf *= 0.8f; + + foreach (var hitObject in Beatmap.HitObjects) + { + // We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations. + if (hitObject is Fruit) + { + difficultyHitObjects.Add(new CatchDifficultyHitObject((CatchHitObject)hitObject, catcherWidthHalf)); + } + if (hitObject is JuiceStream) + { + IEnumerator nestedHitObjectsEnumerator = hitObject.NestedHitObjects.GetEnumerator(); + while (nestedHitObjectsEnumerator.MoveNext()) + { + CatchHitObject objectInJuiceStream = (CatchHitObject)nestedHitObjectsEnumerator.Current; + if (!(objectInJuiceStream is TinyDroplet)) + difficultyHitObjects.Add(new CatchDifficultyHitObject(objectInJuiceStream, catcherWidthHalf)); + } + } + } + + difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime)); + + if (!CalculateStrainValues()) return 0; + + double starRating = Math.Sqrt(CalculateDifficulty()) * STAR_SCALING_FACTOR; + + if (categoryDifficulty != null) + { + categoryDifficulty["Aim"] = starRating; + + double ar = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate; + double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate; + + categoryDifficulty["AR"] = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0; + + //categoryDifficulty.Add("AR", (preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0).ToString("0.00", GameBase.nfi)); + //categoryDifficulty.Add("Max combo", DifficultyHitObjects.Count.ToString(GameBase.nfi)); + } + + return starRating; + } + + protected bool CalculateStrainValues() + { + // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. + using (List.Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator()) + { + + if (!hitObjectsEnumerator.MoveNext()) return false; + + CatchDifficultyHitObject currentHitObject = hitObjectsEnumerator.Current; + CatchDifficultyHitObject nextHitObject; + + // First hitObject starts at strain 1. 1 is the default for strain values, so we don't need to set it here. See DifficultyHitObject. + while (hitObjectsEnumerator.MoveNext()) + { + nextHitObject = hitObjectsEnumerator.Current; + nextHitObject.CalculateStrains(currentHitObject, TimeRate); + currentHitObject = nextHitObject; + } + + return true; + } + } + + /// + /// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size STRAIN_STEP. + /// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain. + /// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage. + /// + protected const double STRAIN_STEP = 750; + + /// + /// The weighting of each strain value decays to this number * it's previous value + /// + protected const double DECAY_WEIGHT = 0.94; + + protected double CalculateDifficulty() + { + // The strain step needs to be adjusted for the algorithm to be considered equal with speed changing mods + double actualStrainStep = STRAIN_STEP * TimeRate; + + // Find the highest strain value within each strain step + List highestStrains = new List(); + double intervalEndTime = actualStrainStep; + double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval + + CatchDifficultyHitObject previousHitObject = null; + foreach (CatchDifficultyHitObject hitObject in difficultyHitObjects) + { + // While we are beyond the current interval push the currently available maximum to our strain list + while (hitObject.BaseHitObject.StartTime > intervalEndTime) + { + highestStrains.Add(maximumStrain); + + // The maximum strain of the next interval is not zero by default! We need to take the last hitObject we encountered, take its strain and apply the decay + // until the beginning of the next interval. + if (previousHitObject == null) + { + maximumStrain = 0; + } + else + { + double decay = Math.Pow(CatchDifficultyHitObject.DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000); + maximumStrain = previousHitObject.Strain * decay; + } + + // Go to the next time interval + intervalEndTime += actualStrainStep; + } + + // Obtain maximum strain + maximumStrain = Math.Max(hitObject.Strain, maximumStrain); + + previousHitObject = hitObject; + } + + + // Build the weighted sum over the highest strains for each interval + double difficulty = 0; + double weight = 1; + highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain. + + foreach (double strain in highestStrains) + { + difficulty += weight * strain; + weight *= DECAY_WEIGHT; + } + + return difficulty; + } } } diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs new file mode 100644 index 0000000000..14f9445c75 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs @@ -0,0 +1,127 @@ +using System; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.UI; +using OpenTK; + +namespace osu.Game.Rulesets.Catch.Difficulty +{ + class CatchDifficultyHitObject + { + internal static readonly double DECAY_BASE = 0.20; + private const float NORMALIZED_HITOBJECT_RADIUS = 41.0f; + private const float ABSOLUTE_PLAYER_POSITIONING_ERROR = 16f; + private float playerPositioningError; + + internal CatchHitObject BaseHitObject; + + /// + /// Measures jump difficulty. CtB doesn't have something like button pressing speed or accuracy + /// + internal double Strain = 1; + + /// + /// This is required to keep track of lazy player movement (always moving only as far as necessary) + /// Without this quick repeat sliders / weirdly shaped streams might become ridiculously overrated + /// + internal float PlayerPositionOffset; + internal float LastMovement; + + internal float NormalizedPosition; + internal float ActualNormalizedPosition => NormalizedPosition + PlayerPositionOffset; + + internal CatchDifficultyHitObject(CatchHitObject baseHitObject, float catcherWidthHalf) + { + BaseHitObject = baseHitObject; + + // We will scale everything by this factor, so we can assume a uniform CircleSize among beatmaps. + float scalingFactor = NORMALIZED_HITOBJECT_RADIUS / catcherWidthHalf; + + playerPositioningError = ABSOLUTE_PLAYER_POSITIONING_ERROR;// * scalingFactor; + NormalizedPosition = baseHitObject.X * CatchPlayfield.BASE_WIDTH * scalingFactor; + } + + private const double DIRECTION_CHANGE_BONUS = 12.5; + internal void CalculateStrains(CatchDifficultyHitObject previousHitObject, double timeRate) + { + // Rather simple, but more specialized things are inherently inaccurate due to the big difference playstyles and opinions make. + // See Taiko feedback thread. + double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate; + double decay = Math.Pow(DECAY_BASE, timeElapsed / 1000); + + // Update new position with lazy movement. + PlayerPositionOffset = + MathHelper.Clamp( + previousHitObject.ActualNormalizedPosition, + NormalizedPosition - (NORMALIZED_HITOBJECT_RADIUS - playerPositioningError), + NormalizedPosition + (NORMALIZED_HITOBJECT_RADIUS - playerPositioningError)) // Obtain new lazy position, but be stricter by allowing for an error of a certain degree of the player. + - NormalizedPosition; // Subtract HitObject position to obtain offset + + LastMovement = DistanceTo(previousHitObject); + double addition = spacingWeight(LastMovement); + + if (NormalizedPosition < previousHitObject.NormalizedPosition) + { + LastMovement = -LastMovement; + } + + CatchHitObject previousHitCircle = previousHitObject.BaseHitObject; + + double additionBonus = 0; + double sqrtTime = Math.Sqrt(Math.Max(timeElapsed, 25)); + + // Direction changes give an extra point! + if (Math.Abs(LastMovement) > 0.1) + { + if (Math.Abs(previousHitObject.LastMovement) > 0.1 && Math.Sign(LastMovement) != Math.Sign(previousHitObject.LastMovement)) + { + double bonus = DIRECTION_CHANGE_BONUS / sqrtTime; + + // Weight bonus by how + double bonusFactor = Math.Min(playerPositioningError, Math.Abs(LastMovement)) / playerPositioningError; + + // We want time to play a role twice here! + addition += bonus * bonusFactor; + + // Bonus for tougher direction switches and "almost" hyperdashes at this point + if (previousHitCircle != null && previousHitCircle.DistanceToHyperDash <= 10.0f / CatchPlayfield.BASE_WIDTH) + { + additionBonus += 0.3 * bonusFactor; + } + } + + // Base bonus for every movement, giving some weight to streams. + addition += 7.5 * Math.Min(Math.Abs(LastMovement), NORMALIZED_HITOBJECT_RADIUS * 2) / (NORMALIZED_HITOBJECT_RADIUS * 6) / sqrtTime; + } + + // Bonus for "almost" hyperdashes at corner points + if (previousHitCircle != null && previousHitCircle.DistanceToHyperDash <= 10.0f / CatchPlayfield.BASE_WIDTH) + { + if (!previousHitCircle.HyperDash) + { + additionBonus += 1.0; + } + else + { + // After a hyperdash we ARE in the correct position. Always! + PlayerPositionOffset = 0; + } + + addition *= 1.0 + additionBonus * ((10 - previousHitCircle.DistanceToHyperDash * CatchPlayfield.BASE_WIDTH) / 10); + } + + addition *= 850.0 / Math.Max(timeElapsed, 25); + + Strain = previousHitObject.Strain * decay + addition; + } + + private static double spacingWeight(float distance) + { + return Math.Pow(distance, 1.3) / 500; + } + + internal float DistanceTo(CatchDifficultyHitObject other) + { + return Math.Abs(ActualNormalizedPosition - other.ActualNormalizedPosition); + } + } +} From 6bf5ea73d5f19ba4d706f9754a7169c5ae8e5f8e Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 09:53:20 +0800 Subject: [PATCH 036/306] Fix CatcherWidth --- .../Difficulty/CatchDifficultyCalculator.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 5351bd746d..59c512c469 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -35,8 +35,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty difficultyHitObjects.Clear(); float circleSize = Beatmap.BeatmapInfo.BaseDifficulty.CircleSize; - float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * 172; - //float catcherWidth = (float)(305.0f / 1.6f * ((102.4f * (1.0f - 0.7 * (circleSize - 5.0f)) / 5.0f) / 128.0f * 0.7f)); + float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * CatcherArea.CATCHER_SIZE; float catcherWidthHalf = catcherWidth / 2; catcherWidthHalf *= 0.8f; From 0ef718a09e6269343b6a3a04b1b3f9bfaaaf7d3a Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 09:55:07 +0800 Subject: [PATCH 037/306] Fixes on categoryDifficulty --- .../Difficulty/CatchDifficultyCalculator.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 59c512c469..63570d44b0 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -72,9 +72,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate; categoryDifficulty["AR"] = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0; - - //categoryDifficulty.Add("AR", (preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0).ToString("0.00", GameBase.nfi)); - //categoryDifficulty.Add("Max combo", DifficultyHitObjects.Count.ToString(GameBase.nfi)); + categoryDifficulty["Max combo"] = difficultyHitObjects.Count; } return starRating; From 44fd4b95bd7ce7c7ec58e6dc82cd57f5447ac2b1 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 09:58:46 +0800 Subject: [PATCH 038/306] We need DistanceToHyperDash for star rating calculation --- osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index 548813fbd2..d55cdac115 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -24,6 +24,11 @@ namespace osu.Game.Rulesets.Catch.Objects public int ComboIndex { get; set; } + /// + /// The distance for a fruit to to next hyper if it's not a hyper. + /// + public float DistanceToHyperDash { get; set; } + /// /// The next fruit starts a new combo. Used for explodey. /// From 0405383e4e3eb352b2e78e428ab473f00e69fca6 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 10:12:18 +0800 Subject: [PATCH 039/306] Fixing code style --- .../Difficulty/CatchDifficultyCalculator.cs | 21 +++++-------------- .../Difficulty/CatchDifficultyHitObject.cs | 2 +- .../Difficulty/TaikoDifficultyCalculator.cs | 12 ++--------- .../Difficulty/DifficultyCalculator.cs | 15 +++++++++++++ 4 files changed, 23 insertions(+), 27 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 63570d44b0..83b5b3bb5c 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -31,7 +31,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty public override double Calculate(Dictionary categoryDifficulty = null) { - difficultyHitObjects.Clear(); float circleSize = Beatmap.BeatmapInfo.BaseDifficulty.CircleSize; @@ -83,7 +82,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. using (List.Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator()) { - if (!hitObjectsEnumerator.MoveNext()) return false; CatchDifficultyHitObject currentHitObject = hitObjectsEnumerator.Current; @@ -106,17 +104,17 @@ namespace osu.Game.Rulesets.Catch.Difficulty /// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain. /// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage. /// - protected const double STRAIN_STEP = 750; + protected const double strain_step = 750; /// /// The weighting of each strain value decays to this number * it's previous value /// - protected const double DECAY_WEIGHT = 0.94; + protected const double decay_weight = 0.94; protected double CalculateDifficulty() { // The strain step needs to be adjusted for the algorithm to be considered equal with speed changing mods - double actualStrainStep = STRAIN_STEP * TimeRate; + double actualStrainStep = strain_step * TimeRate; // Find the highest strain value within each strain step List highestStrains = new List(); @@ -153,17 +151,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty previousHitObject = hitObject; } - - // Build the weighted sum over the highest strains for each interval - double difficulty = 0; - double weight = 1; - highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain. - - foreach (double strain in highestStrains) - { - difficulty += weight * strain; - weight *= DECAY_WEIGHT; - } + // calculate maximun strain difficulty + double difficulty = StrainCalculator(highestStrains, decay_weight); return difficulty; } diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs index 14f9445c75..f4eefdd7cd 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty // We will scale everything by this factor, so we can assume a uniform CircleSize among beatmaps. float scalingFactor = NORMALIZED_HITOBJECT_RADIUS / catcherWidthHalf; - playerPositioningError = ABSOLUTE_PLAYER_POSITIONING_ERROR;// * scalingFactor; + playerPositioningError = ABSOLUTE_PLAYER_POSITIONING_ERROR; // * scalingFactor; NormalizedPosition = baseHitObject.X * CatchPlayfield.BASE_WIDTH * scalingFactor; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 57e1e65064..197464c10a 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -122,16 +122,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty previousHitObject = hitObject; } - // Build the weighted sum over the highest strains for each interval - double difficulty = 0; - double weight = 1; - highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain. - - foreach (double strain in highestStrains) - { - difficulty += weight * strain; - weight *= decay_weight; - } + // calculate maximun strain difficulty + double difficulty = StrainCalculator(highestStrains, decay_weight); return difficulty; } diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index 070bc7ddb0..348435b0d0 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -37,5 +37,20 @@ namespace osu.Game.Rulesets.Difficulty } public abstract double Calculate(Dictionary categoryDifficulty = null); + + protected double StrainCalculator(List highestStrains, double decayWeight) + { + // Build the weighted sum over the highest strains for each interval + double difficulty = 0; + double weight = 1; + highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain. + + foreach (double strain in highestStrains) + { + difficulty += weight * strain; + weight *= decayWeight; + } + return difficulty; + } } } From 886be8ce1f7c29d558e3a34f42863740c7ca6515 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 10:16:32 +0800 Subject: [PATCH 040/306] Adding lisence header --- .../Difficulty/CatchDifficultyCalculator.cs | 2 +- .../Difficulty/CatchDifficultyHitObject.cs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 83b5b3bb5c..19d1bab0ac 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty return true; } } - + /// /// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size STRAIN_STEP. /// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain. diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs index f4eefdd7cd..778ab9df28 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; using OpenTK; @@ -76,7 +79,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty { double bonus = DIRECTION_CHANGE_BONUS / sqrtTime; - // Weight bonus by how + // Weight bonus by how double bonusFactor = Math.Min(playerPositioningError, Math.Abs(LastMovement)) / playerPositioningError; // We want time to play a role twice here! From 68a929eb0c1d78e38687f55b42b61c05d6a1e9a1 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 10:39:16 +0800 Subject: [PATCH 041/306] Fixing parameters naming --- .../Difficulty/CatchDifficultyCalculator.cs | 17 +++++------ .../Difficulty/CatchDifficultyHitObject.cs | 28 +++++++++---------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 19d1bab0ac..31de9cfc8d 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -14,8 +14,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty { public class CatchDifficultyCalculator : DifficultyCalculator { - private const double STAR_SCALING_FACTOR = 0.145; - private const float PLAYFIELD_WIDTH = CatchPlayfield.BASE_WIDTH; + private const double star_scaling_factor = 0.145; + private const float playfield_width = CatchPlayfield.BASE_WIDTH; private readonly List difficultyHitObjects = new List(); @@ -54,6 +54,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty if (!(objectInJuiceStream is TinyDroplet)) difficultyHitObjects.Add(new CatchDifficultyHitObject(objectInJuiceStream, catcherWidthHalf)); } + // Dispose the enumerator after counting all fruits. + nestedHitObjectsEnumerator.Dispose(); } } @@ -61,7 +63,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty if (!CalculateStrainValues()) return 0; - double starRating = Math.Sqrt(CalculateDifficulty()) * STAR_SCALING_FACTOR; + double starRating = Math.Sqrt(CalculateDifficulty()) * star_scaling_factor; if (categoryDifficulty != null) { @@ -85,12 +87,11 @@ namespace osu.Game.Rulesets.Catch.Difficulty if (!hitObjectsEnumerator.MoveNext()) return false; CatchDifficultyHitObject currentHitObject = hitObjectsEnumerator.Current; - CatchDifficultyHitObject nextHitObject; // First hitObject starts at strain 1. 1 is the default for strain values, so we don't need to set it here. See DifficultyHitObject. while (hitObjectsEnumerator.MoveNext()) { - nextHitObject = hitObjectsEnumerator.Current; + CatchDifficultyHitObject nextHitObject = hitObjectsEnumerator.Current; nextHitObject.CalculateStrains(currentHitObject, TimeRate); currentHitObject = nextHitObject; } @@ -104,12 +105,12 @@ namespace osu.Game.Rulesets.Catch.Difficulty /// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain. /// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage. /// - protected const double strain_step = 750; + private const double strain_step = 750; /// /// The weighting of each strain value decays to this number * it's previous value /// - protected const double decay_weight = 0.94; + private const double decay_weight = 0.94; protected double CalculateDifficulty() { @@ -137,7 +138,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty } else { - double decay = Math.Pow(CatchDifficultyHitObject.DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000); + double decay = Math.Pow(CatchDifficultyHitObject.decay_base, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000); maximumStrain = previousHitObject.Strain * decay; } diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs index 778ab9df28..190c92b319 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs @@ -8,12 +8,12 @@ using OpenTK; namespace osu.Game.Rulesets.Catch.Difficulty { - class CatchDifficultyHitObject + internal class CatchDifficultyHitObject { - internal static readonly double DECAY_BASE = 0.20; - private const float NORMALIZED_HITOBJECT_RADIUS = 41.0f; - private const float ABSOLUTE_PLAYER_POSITIONING_ERROR = 16f; - private float playerPositioningError; + internal static readonly double decay_base = 0.20; + private const float normalized_hitobject_radius = 41.0f; + private const float absolute_player_positioning_error = 16f; + private readonly float playerPositioningError; internal CatchHitObject BaseHitObject; @@ -37,26 +37,26 @@ namespace osu.Game.Rulesets.Catch.Difficulty BaseHitObject = baseHitObject; // We will scale everything by this factor, so we can assume a uniform CircleSize among beatmaps. - float scalingFactor = NORMALIZED_HITOBJECT_RADIUS / catcherWidthHalf; + float scalingFactor = normalized_hitobject_radius / catcherWidthHalf; - playerPositioningError = ABSOLUTE_PLAYER_POSITIONING_ERROR; // * scalingFactor; + playerPositioningError = absolute_player_positioning_error; // * scalingFactor; NormalizedPosition = baseHitObject.X * CatchPlayfield.BASE_WIDTH * scalingFactor; } - private const double DIRECTION_CHANGE_BONUS = 12.5; + private const double direction_change_bonus = 12.5; internal void CalculateStrains(CatchDifficultyHitObject previousHitObject, double timeRate) { // Rather simple, but more specialized things are inherently inaccurate due to the big difference playstyles and opinions make. // See Taiko feedback thread. double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate; - double decay = Math.Pow(DECAY_BASE, timeElapsed / 1000); + double decay = Math.Pow(decay_base, timeElapsed / 1000); // Update new position with lazy movement. PlayerPositionOffset = MathHelper.Clamp( previousHitObject.ActualNormalizedPosition, - NormalizedPosition - (NORMALIZED_HITOBJECT_RADIUS - playerPositioningError), - NormalizedPosition + (NORMALIZED_HITOBJECT_RADIUS - playerPositioningError)) // Obtain new lazy position, but be stricter by allowing for an error of a certain degree of the player. + NormalizedPosition - (normalized_hitobject_radius - playerPositioningError), + NormalizedPosition + (normalized_hitobject_radius - playerPositioningError)) // Obtain new lazy position, but be stricter by allowing for an error of a certain degree of the player. - NormalizedPosition; // Subtract HitObject position to obtain offset LastMovement = DistanceTo(previousHitObject); @@ -77,9 +77,9 @@ namespace osu.Game.Rulesets.Catch.Difficulty { if (Math.Abs(previousHitObject.LastMovement) > 0.1 && Math.Sign(LastMovement) != Math.Sign(previousHitObject.LastMovement)) { - double bonus = DIRECTION_CHANGE_BONUS / sqrtTime; + double bonus = direction_change_bonus / sqrtTime; - // Weight bonus by how + // Weight bonus by how double bonusFactor = Math.Min(playerPositioningError, Math.Abs(LastMovement)) / playerPositioningError; // We want time to play a role twice here! @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty } // Base bonus for every movement, giving some weight to streams. - addition += 7.5 * Math.Min(Math.Abs(LastMovement), NORMALIZED_HITOBJECT_RADIUS * 2) / (NORMALIZED_HITOBJECT_RADIUS * 6) / sqrtTime; + addition += 7.5 * Math.Min(Math.Abs(LastMovement), normalized_hitobject_radius * 2) / (normalized_hitobject_radius * 6) / sqrtTime; } // Bonus for "almost" hyperdashes at corner points From 871743204b00983179fff782745cdea1bf341b5a Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 10:41:58 +0800 Subject: [PATCH 042/306] Fixing parameters naming --- osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs index 190c92b319..d9b16c2a0b 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty { double bonus = direction_change_bonus / sqrtTime; - // Weight bonus by how + // Weight bonus by how double bonusFactor = Math.Min(playerPositioningError, Math.Abs(LastMovement)) / playerPositioningError; // We want time to play a role twice here! From 2e5bc4323ad553b8f85fef881b552b8e8c9e956d Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 13:31:00 +0800 Subject: [PATCH 043/306] Fixing null reference exception bugs --- .../Difficulty/CatchDifficultyCalculator.cs | 9 +++++---- .../Difficulty/CatchDifficultyHitObject.cs | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 31de9cfc8d..2fa946f41c 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty difficultyHitObjects.Clear(); float circleSize = Beatmap.BeatmapInfo.BaseDifficulty.CircleSize; - float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * CatcherArea.CATCHER_SIZE; + float catcherWidth = ((1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f) * CatcherArea.CATCHER_SIZE; float catcherWidthHalf = catcherWidth / 2; catcherWidthHalf *= 0.8f; @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty double ar = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate; double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate; - categoryDifficulty["AR"] = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0; + categoryDifficulty["AR"] = (preEmpt > 1200.0) ? -(preEmpt - 1800.0) / 120.0 : (-(preEmpt - 1200.0) / 150.0) + 5.0; categoryDifficulty["Max combo"] = difficultyHitObjects.Count; } @@ -92,7 +92,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty while (hitObjectsEnumerator.MoveNext()) { CatchDifficultyHitObject nextHitObject = hitObjectsEnumerator.Current; - nextHitObject.CalculateStrains(currentHitObject, TimeRate); + if (nextHitObject != null) + nextHitObject.CalculateStrains(currentHitObject, TimeRate); currentHitObject = nextHitObject; } @@ -111,7 +112,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty /// The weighting of each strain value decays to this number * it's previous value /// private const double decay_weight = 0.94; - + protected double CalculateDifficulty() { // The strain step needs to be adjusted for the algorithm to be considered equal with speed changing mods diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs index d9b16c2a0b..72fc6d211b 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty { internal class CatchDifficultyHitObject { - internal static readonly double decay_base = 0.20; + internal static readonly double DECAY_BASE = 0.20; private const float normalized_hitobject_radius = 41.0f; private const float absolute_player_positioning_error = 16f; private readonly float playerPositioningError; @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty // Rather simple, but more specialized things are inherently inaccurate due to the big difference playstyles and opinions make. // See Taiko feedback thread. double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate; - double decay = Math.Pow(decay_base, timeElapsed / 1000); + double decay = Math.Pow(DECAY_BASE, timeElapsed / 1000); // Update new position with lazy movement. PlayerPositionOffset = From 6d71f7f220940eb8bcc2750dd3e192b85fa6e777 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 13:35:02 +0800 Subject: [PATCH 044/306] Minor fixes --- osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 2fa946f41c..beee332504 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty /// The weighting of each strain value decays to this number * it's previous value /// private const double decay_weight = 0.94; - + protected double CalculateDifficulty() { // The strain step needs to be adjusted for the algorithm to be considered equal with speed changing mods From 193a29860144f3e5c41b8b09c5492271ff07a2fd Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 13:36:57 +0800 Subject: [PATCH 045/306] Fixing minor bugs --- osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index beee332504..43c157df06 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -139,7 +139,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty } else { - double decay = Math.Pow(CatchDifficultyHitObject.decay_base, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000); + double decay = Math.Pow(CatchDifficultyHitObject.DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000); maximumStrain = previousHitObject.Strain * decay; } From 4784538d7349a2e1fcef059141c992524a2e2bd6 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 13:53:48 +0800 Subject: [PATCH 046/306] Fixing minor bugs --- osu-framework | 2 +- .../Difficulty/CatchDifficultyCalculator.cs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu-framework b/osu-framework index 80e78fd45b..fac688633b 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 80e78fd45bb79ca4bc46ecc05deb6058f3879faa +Subproject commit fac688633b8fcf34ae5d0514c26b03e217161eb4 diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 43c157df06..975e8eed58 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty difficultyHitObjects.Clear(); float circleSize = Beatmap.BeatmapInfo.BaseDifficulty.CircleSize; - float catcherWidth = ((1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f) * CatcherArea.CATCHER_SIZE; + float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * CatcherArea.CATCHER_SIZE; float catcherWidthHalf = catcherWidth / 2; catcherWidthHalf *= 0.8f; @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty double ar = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate; double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate; - categoryDifficulty["AR"] = (preEmpt > 1200.0) ? -(preEmpt - 1800.0) / 120.0 : (-(preEmpt - 1200.0) / 150.0) + 5.0; + categoryDifficulty["AR"] = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0; categoryDifficulty["Max combo"] = difficultyHitObjects.Count; } @@ -92,8 +92,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty while (hitObjectsEnumerator.MoveNext()) { CatchDifficultyHitObject nextHitObject = hitObjectsEnumerator.Current; - if (nextHitObject != null) - nextHitObject.CalculateStrains(currentHitObject, TimeRate); + nextHitObject?.CalculateStrains(currentHitObject, TimeRate); currentHitObject = nextHitObject; } From 49f893d5e42b3712a7801ea329128bb2701538dd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 23 May 2018 12:00:11 +0900 Subject: [PATCH 047/306] Couple the timeline to the audio --- .../Visual/TestCaseEditorComposeTimeline.cs | 13 ++- .../Edit/Screens/Compose/Timeline/Timeline.cs | 80 +++++++++++++++++++ 2 files changed, 85 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index 0776bc123e..aff7abe03d 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -14,14 +14,15 @@ using osu.Game.Screens.Edit.Screens.Compose.Timeline; namespace osu.Game.Tests.Visual { [TestFixture] - public class TestCaseEditorComposeTimeline : OsuTestCase + public class TestCaseEditorComposeTimeline : EditorClockTestCase { public override IReadOnlyList RequiredTypes => new[] { typeof(TimelineArea), typeof(Timeline), typeof(BeatmapWaveformGraph), typeof(TimelineButton) }; - private readonly TimelineArea timelineArea; - - public TestCaseEditorComposeTimeline() + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame) { + TimelineArea timelineArea; + Children = new Drawable[] { new MusicController @@ -38,11 +39,7 @@ namespace osu.Game.Tests.Visual Size = new Vector2(0.8f, 100) } }; - } - [BackgroundDependencyLoader] - private void load(OsuGameBase osuGame) - { timelineArea.Beatmap.BindTo(osuGame.Beatmap); } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index 9801ba12a1..e8d34b466c 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -1,8 +1,11 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Framework.Input; +using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Graphics; @@ -13,6 +16,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline public readonly Bindable WaveformVisible = new Bindable(); public readonly Bindable Beatmap = new Bindable(); + private IAdjustableClock adjustableClock; + public Timeline() { ZoomDuration = 200; @@ -32,12 +37,87 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); } + [BackgroundDependencyLoader] + private void load(IAdjustableClock adjustableClock) + { + this.adjustableClock = adjustableClock; + } + + private bool handlingUserInput; + private bool trackWasPlaying; + protected override void Update() { base.Update(); // We want time = 0 to be at the centre of the container when scrolled to the start Content.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; + + if (!handlingUserInput) + ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + else + adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + if (base.OnMouseDown(state, args)) + { + beginUserInput(); + return true; + } + + return false; + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + endUserInput(); + return base.OnMouseUp(state, args); + } + + private void beginUserInput() + { + handlingUserInput = true; + trackWasPlaying = adjustableClock.IsRunning; + adjustableClock.Stop(); + } + + private void endUserInput() + { + handlingUserInput = false; + if (trackWasPlaying) + adjustableClock.Start(); + } + + protected override ScrollbarContainer CreateScrollbar(Direction direction) => new TimelineScrollbar(this, direction); + + private class TimelineScrollbar : ScrollbarContainer + { + private readonly Timeline timeline; + + public TimelineScrollbar(Timeline timeline, Direction scrollDir) + : base(scrollDir) + { + this.timeline = timeline; + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + if (base.OnMouseDown(state, args)) + { + timeline.beginUserInput(); + return true; + } + + return false; + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + timeline.endUserInput(); + return base.OnMouseUp(state, args); + } } } } From f18677382c59446d4cdc307ed5969c5a4c2b71f7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 23 May 2018 12:00:23 +0900 Subject: [PATCH 048/306] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 8f007de13e..907265b750 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 8f007de13e4a1aed46cb35e5018448f809bd5e88 +Subproject commit 907265b7501964a09eb2cd89ec2257941183c65c From 6b0eeb343651bd50764199b3413c59dd946ae2df Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 23 May 2018 14:14:32 +0900 Subject: [PATCH 049/306] Rework seeking interactions to support smooth scrolling --- .../Edit/Screens/Compose/Timeline/Timeline.cs | 53 ++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index e8d34b466c..9dbaa1586d 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -43,20 +43,59 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline this.adjustableClock = adjustableClock; } - private bool handlingUserInput; + /// + /// The track's time in the previous frame. + /// + private double lastTrackTime; + + /// + /// Whether the user is currently dragging the timeline. + /// + private bool handlingDragInput; + + /// + /// Whether the track was playing before a user drag event. + /// private bool trackWasPlaying; protected override void Update() { base.Update(); - // We want time = 0 to be at the centre of the container when scrolled to the start + // The extrema of track time should be positioned at the centre of the container when scrolled to the start or end Content.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; - if (!handlingUserInput) - ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); - else + if (handlingDragInput) + { + // The user is dragging - the track should always follow the timeline adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + } + else if (adjustableClock.IsRunning) + { + // If the user hasn't provided mouse input but the track is running, always follow the track + ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + } + else + { + // The track isn't playing, so we want to smooth-scroll once more, and re-enable wheel scrolling + // There are two cases we have to be wary of: + // 1) The user scrolls on this timeline: We want the track to follow us + // 2) The user changes the track time through some other means (scrolling in the editor or overview timeline): We want to follow the track time + + // The simplest way to cover both cases is by checking that inter-frame track times are identical + if (adjustableClock.CurrentTime == lastTrackTime) + { + // The track hasn't been seeked externally + adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + } + else + { + // The track has been seeked externally + ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + } + } + + lastTrackTime = adjustableClock.CurrentTime; } protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) @@ -78,14 +117,14 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline private void beginUserInput() { - handlingUserInput = true; + handlingDragInput = true; trackWasPlaying = adjustableClock.IsRunning; adjustableClock.Stop(); } private void endUserInput() { - handlingUserInput = false; + handlingDragInput = false; if (trackWasPlaying) adjustableClock.Start(); } From a30f72b477d6353d0e785d94cd66aac6fefe50de Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 23 May 2018 14:32:00 +0900 Subject: [PATCH 050/306] Add helper methods for seeking/scrolling --- .../Screens/Edit/Screens/Compose/Timeline/Timeline.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index 9dbaa1586d..df615ad035 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -68,12 +68,12 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline if (handlingDragInput) { // The user is dragging - the track should always follow the timeline - adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + seekTrackToCurrent(); } else if (adjustableClock.IsRunning) { // If the user hasn't provided mouse input but the track is running, always follow the track - ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + scrollToTrackTime(); } else { @@ -86,16 +86,19 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline if (adjustableClock.CurrentTime == lastTrackTime) { // The track hasn't been seeked externally - adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + seekTrackToCurrent(); } else { // The track has been seeked externally - ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + scrollToTrackTime(); } } lastTrackTime = adjustableClock.CurrentTime; + + void seekTrackToCurrent() => adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + void scrollToTrackTime() => ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); } protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) From d4f68e0b673c9e258180d5290e016a3fb0e7d105 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 24 May 2018 14:26:53 +0900 Subject: [PATCH 051/306] Fix possible NaN values due to trackvirtual infinite length --- .../Edit/Screens/Compose/Timeline/Timeline.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index df615ad035..3fdde1fc1d 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Input; @@ -97,8 +98,17 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline lastTrackTime = adjustableClock.CurrentTime; - void seekTrackToCurrent() => adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); - void scrollToTrackTime() => ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + void seekTrackToCurrent() + { + if (!(Beatmap.Value.Track is TrackVirtual)) + adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + } + + void scrollToTrackTime() + { + if (!(Beatmap.Value.Track is TrackVirtual)) + ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + } } protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) From b649025e861b14506754794e6416235b1e43d205 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 24 May 2018 14:36:48 +0900 Subject: [PATCH 052/306] beginUserDrag/endUserDrag --- .../Edit/Screens/Compose/Timeline/Timeline.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index 3fdde1fc1d..0ae6cd6da2 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -115,7 +115,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { if (base.OnMouseDown(state, args)) { - beginUserInput(); + beginUserDrag(); return true; } @@ -124,18 +124,18 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) { - endUserInput(); + endUserDrag(); return base.OnMouseUp(state, args); } - private void beginUserInput() + private void beginUserDrag() { handlingDragInput = true; trackWasPlaying = adjustableClock.IsRunning; adjustableClock.Stop(); } - private void endUserInput() + private void endUserDrag() { handlingDragInput = false; if (trackWasPlaying) @@ -158,7 +158,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { if (base.OnMouseDown(state, args)) { - timeline.beginUserInput(); + timeline.beginUserDrag(); return true; } @@ -167,7 +167,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) { - timeline.endUserInput(); + timeline.endUserDrag(); return base.OnMouseUp(state, args); } } From 38e5e35743f372de3be1324d3adf0473f29d8bd1 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 25 May 2018 01:20:05 +0900 Subject: [PATCH 053/306] modify catch hyperdash behavior --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 62 ++++++++++++++--------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 181536a91e..56826d228c 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -248,37 +248,46 @@ namespace osu.Game.Rulesets.Catch.UI if (validCatch && fruit.HyperDash) { - HyperDashModifier = Math.Abs(fruit.HyperDashTarget.X - fruit.X) / Math.Abs(fruit.HyperDashTarget.StartTime - fruit.StartTime) / BASE_SPEED; - HyperDashDirection = fruit.HyperDashTarget.X - fruit.X; + var target = fruit.HyperDashTarget; + double timeDifference = target.StartTime - fruit.StartTime; + double positionDifference = target.X * CatchPlayfield.BASE_WIDTH - catcherPosition; + double velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0); + + HyperDashing = true; + hyperDashModifier = Math.Abs(velocity); + hyperDashDirection = (int)Math.Sign(velocity); + hyperDashTargetPosition = target.X; } else - HyperDashModifier = 1; + { + HyperDashing = false; + } return validCatch; } + private double hyperDashModifier = 1; + private int hyperDashDirection = 0; + private float hyperDashTargetPosition; + private bool hyperDashing = false; + /// /// Whether we are hypderdashing or not. /// - public bool HyperDashing => hyperDashModifier != 1; - - private double hyperDashModifier = 1; - - /// - /// The direction in which hyperdash is allowed. 0 allows both directions. - /// - public double HyperDashDirection; - - /// - /// The speed modifier resultant from hyperdash. Will trigger hyperdash when not equal to 1. - /// - public double HyperDashModifier + protected bool HyperDashing { - get { return hyperDashModifier; } + get => hyperDashing; set { - if (value == hyperDashModifier) return; - hyperDashModifier = value; + if (hyperDashing == value) return; + + hyperDashing = value; + + if (!HyperDashing) + { + hyperDashModifier = 1; + hyperDashDirection = 0; + } const float transition_length = 180; @@ -290,7 +299,6 @@ namespace osu.Game.Rulesets.Catch.UI } else { - HyperDashDirection = 0; this.FadeColour(Color4.White, transition_length, Easing.OutQuint); this.FadeTo(1, transition_length, Easing.OutQuint); } @@ -347,12 +355,18 @@ namespace osu.Game.Rulesets.Catch.UI var direction = Math.Sign(currentDirection); double dashModifier = Dashing ? 1 : 0.5; - - if (hyperDashModifier != 1 && (HyperDashDirection == 0 || direction == Math.Sign(HyperDashDirection))) - dashModifier = hyperDashModifier; + double speed = BASE_SPEED * dashModifier * hyperDashModifier; Scale = new Vector2(Math.Abs(Scale.X) * direction, Scale.Y); - X = (float)MathHelper.Clamp(X + direction * Clock.ElapsedFrameTime * BASE_SPEED * dashModifier, 0, 1); + X = (float)MathHelper.Clamp(X + direction * Clock.ElapsedFrameTime * speed, 0, 1); + + // Correct overshooting. + if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) || + (hyperDashDirection < 0 && hyperDashTargetPosition > X)) + { + X = hyperDashTargetPosition; + HyperDashing = false; + } } /// From 99c0e19189b95df33b332784e8a13f8a985c2181 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 25 May 2018 01:52:15 +0900 Subject: [PATCH 054/306] Fix build error --- osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs index f239290ed4..ed6600c55d 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs @@ -26,7 +26,6 @@ namespace osu.Game.Rulesets.Catch.Tests public TestCaseCatcherArea() { AddSliderStep("CircleSize", 0, 8, 5, createCatcher); - AddToggleStep("Hyperdash", t => catcherArea.ToggleHyperDash(t)); } private void createCatcher(float size) @@ -54,8 +53,6 @@ namespace osu.Game.Rulesets.Catch.Tests : base(beatmapDifficulty) { } - - public void ToggleHyperDash(bool status) => MovableCatcher.HyperDashModifier = status ? 2 : 1; } } } From be323c71477d009bb8bcda38560fa5c370bcd6f1 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 25 May 2018 02:14:56 +0900 Subject: [PATCH 055/306] Fix InspectCode issues. --- osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs | 3 +-- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs index ed6600c55d..511cda6399 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs @@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Catch.Tests public class TestCaseCatcherArea : OsuTestCase { private RulesetInfo catchRuleset; - private TestCatcherArea catcherArea; public override IReadOnlyList RequiredTypes => new[] { @@ -33,7 +32,7 @@ namespace osu.Game.Rulesets.Catch.Tests Child = new CatchInputManager(catchRuleset) { RelativeSizeAxes = Axes.Both, - Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size }) + Child = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size }) { Anchor = Anchor.CentreLeft, Origin = Anchor.BottomLeft diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 56826d228c..d57d52cf5f 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -255,7 +255,7 @@ namespace osu.Game.Rulesets.Catch.UI HyperDashing = true; hyperDashModifier = Math.Abs(velocity); - hyperDashDirection = (int)Math.Sign(velocity); + hyperDashDirection = Math.Sign(velocity); hyperDashTargetPosition = target.X; } else @@ -267,9 +267,9 @@ namespace osu.Game.Rulesets.Catch.UI } private double hyperDashModifier = 1; - private int hyperDashDirection = 0; + private int hyperDashDirection; private float hyperDashTargetPosition; - private bool hyperDashing = false; + private bool hyperDashing; /// /// Whether we are hypderdashing or not. @@ -361,8 +361,8 @@ namespace osu.Game.Rulesets.Catch.UI X = (float)MathHelper.Clamp(X + direction * Clock.ElapsedFrameTime * speed, 0, 1); // Correct overshooting. - if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) || - (hyperDashDirection < 0 && hyperDashTargetPosition > X)) + if (hyperDashDirection > 0 && hyperDashTargetPosition < X || + hyperDashDirection < 0 && hyperDashTargetPosition > X) { X = hyperDashTargetPosition; HyperDashing = false; From 498244a3089827cbd58aff593d0ec3963cf32303 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Fri, 25 May 2018 00:37:53 +0300 Subject: [PATCH 056/306] Introduce PreviewTrack class --- osu.Game/Audio/PreviewTrack.cs | 39 +++++++++++++++++ osu.Game/Audio/PreviewTrackManager.cs | 43 ++++++++----------- .../BeatmapSet/Buttons/PreviewButton.cs | 6 +-- osu.Game/Overlays/Direct/DirectPanel.cs | 16 +++---- osu.Game/Overlays/Direct/PlayButton.cs | 18 ++++---- 5 files changed, 76 insertions(+), 46 deletions(-) create mode 100644 osu.Game/Audio/PreviewTrack.cs diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs new file mode 100644 index 0000000000..10dec7c394 --- /dev/null +++ b/osu.Game/Audio/PreviewTrack.cs @@ -0,0 +1,39 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Audio.Track; + +namespace osu.Game.Audio +{ + public class PreviewTrack + { + public readonly Track Track; + private readonly Action onStart; + private readonly Action onStop; + + public event Action Stopped; + public event Action Started; + + public PreviewTrack(Track track, Action onStart, Action onStop) + { + Track = track; + this.onStart = onStart; + this.onStop = onStop; + } + + public void Start() + { + onStart?.Invoke(this); + Track.Restart(); + Started?.Invoke(); + } + + public void Stop() + { + onStop?.Invoke(); + Track.Stop(); + Stopped?.Invoke(); + } + } +} diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 2e5f26bcf4..5c7f580ca8 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -14,13 +14,13 @@ namespace osu.Game.Audio { public class PreviewTrackManager : Component { - public event Action PlaybackStarted; - public event Action PlaybackStopped; + private Action onTrackStart; + private Action onTrackStop; private TrackManager trackManager; private BindableDouble muteBindable; - public Track CurrentTrack { get; private set; } + public PreviewTrack CurrentTrack { get; private set; } [BackgroundDependencyLoader] private void load(AudioManager audio, FrameworkConfigManager config) @@ -32,35 +32,28 @@ namespace osu.Game.Audio audio.AddItem(trackManager); config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); - PlaybackStarted += () => audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); - PlaybackStopped += () => audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); + onTrackStart = track => + { + CurrentTrack?.Stop(); + audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); + CurrentTrack = track; + CurrentTrack.Stopped += () => CurrentTrack = null; + }; + onTrackStop = () => audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); } - public Track Get(BeatmapSetInfo beatmapSetInfo) => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo.OnlineBeatmapSetID}.mp3"); + public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo) => + new PreviewTrack( + trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo.OnlineBeatmapSetID}.mp3"), + onTrackStart, + onTrackStop); protected override void Update() { - if (CurrentTrack?.HasCompleted ?? false) - PlaybackStopped?.Invoke(); + if (CurrentTrack?.Track.HasCompleted ?? false) + CurrentTrack.Stop(); base.Update(); } - - public void Play(Track track) - { - Stop(); - CurrentTrack = track; - track.Restart(); - PlaybackStarted?.Invoke(); - } - - public void Stop() - { - if (CurrentTrack?.IsRunning ?? false) - { - CurrentTrack?.Stop(); - PlaybackStopped?.Invoke(); - } - } } } diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs index 08a99f1aea..78628675ac 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs @@ -2,13 +2,13 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; +using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private readonly Box bg, progress; private readonly PlayButton playButton; - private Track preview => playButton.Preview; + private PreviewTrack preview => playButton.Preview; public Bindable Playing => playButton.Playing; public BeatmapSetInfo BeatmapSet @@ -83,7 +83,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons if (Playing.Value && preview != null) { // prevent negative (potential infinite) width if a track without length was loaded - progress.Width = preview.Length > 0 ? (float)(preview.CurrentTime / preview.Length) : 0f; + progress.Width = preview.Track.Length > 0 ? (float)(preview.Track.CurrentTime / preview.Track.Length) : 0f; } else progress.Width = 0; diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index cc0123dabc..2ceefe31ef 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -4,22 +4,22 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; -using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input; +using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using OpenTK.Graphics; -using osu.Framework.Input; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests; -using osu.Framework.Configuration; -using osu.Framework.Audio.Track; +using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Overlays.Direct { @@ -37,7 +37,7 @@ namespace osu.Game.Overlays.Direct private BeatmapManager beatmaps; private BeatmapSetOverlay beatmapSetOverlay; - public Track Preview => PlayButton.Preview; + public PreviewTrack Preview => PlayButton.Preview; public Bindable PreviewPlaying => PlayButton.Playing; protected abstract PlayButton PlayButton { get; } protected abstract Box PreviewBar { get; } @@ -121,9 +121,9 @@ namespace osu.Game.Overlays.Direct { base.Update(); - if (PreviewPlaying && Preview != null && Preview.IsLoaded) + if (PreviewPlaying && Preview != null && Preview.Track.IsLoaded) { - PreviewBar.Width = (float)(Preview.CurrentTime / Preview.Length); + PreviewBar.Width = (float)(Preview.Track.CurrentTime / Preview.Track.Length); } } diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 77c904050b..1f18faaf14 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -3,7 +3,6 @@ using System.Threading.Tasks; using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -19,7 +18,7 @@ namespace osu.Game.Overlays.Direct public class PlayButton : Container { public readonly Bindable Playing = new Bindable(); - public Track Preview { get; private set; } + public PreviewTrack Preview { get; private set; } private BeatmapSetInfo beatmapSet; @@ -32,6 +31,8 @@ namespace osu.Game.Overlays.Direct beatmapSet = value; Playing.Value = false; + if (Preview != null) + Preview.Stopped -= preview_Stopped; Preview = null; } } @@ -85,12 +86,6 @@ namespace osu.Game.Overlays.Direct { hoverColour = colour.Yellow; this.previewTrackManager = previewTrackManager; - - previewTrackManager.PlaybackStopped += () => - { - if (Preview == previewTrackManager.CurrentTrack) - Playing.Value = false; - }; } protected override bool OnClick(InputState state) @@ -134,21 +129,24 @@ namespace osu.Game.Overlays.Direct }) .ContinueWith(t => { + Preview.Stopped += preview_Stopped; playingStateChanged(true); loading = false; }); return; } - previewTrackManager.Play(Preview); + Preview.Start(); } else { - previewTrackManager.Stop(); + Preview.Stop(); loading = false; } } + private void preview_Stopped() => Playing.Value = false; + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); From 9f2e09dae4cba569d6dbd1e36767f5770bfcda93 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 25 May 2018 16:21:51 +0900 Subject: [PATCH 057/306] Move PostProcessing to after control points applied and nested hit objects created. --- osu.Game/Beatmaps/WorkingBeatmap.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 66a6206c16..2e6426c056 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -116,9 +116,6 @@ namespace osu.Game.Beatmaps mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty); } - // Post-process - rulesetInstance.CreateBeatmapProcessor(converted)?.PostProcess(); - // Compute default values for hitobjects, including creating nested hitobjects in-case they're needed foreach (var obj in converted.HitObjects) obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty); @@ -127,6 +124,9 @@ namespace osu.Game.Beatmaps foreach (var obj in converted.HitObjects) mod.ApplyToHitObject(obj); + // Post-process + rulesetInstance.CreateBeatmapProcessor(converted)?.PostProcess(); + return converted; } From ca2c2097016521c16a345e6a173d4e62c78cac0a Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 25 May 2018 16:26:19 +0900 Subject: [PATCH 058/306] add FastRandom --- .../MathUtils/FastRandom.cs | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs diff --git a/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs b/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs new file mode 100644 index 0000000000..5e8256a504 --- /dev/null +++ b/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs @@ -0,0 +1,91 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; + +namespace osu.Game.Rulesets.Catch.MathUtils +{ + /// + /// A PRNG specified in http://heliosphan.org/fastrandom.html. + /// + internal class FastRandom + { + private const double int_to_real = 1.0 / (int.MaxValue + 1.0); + private const uint int_mask = 0x7FFFFFFF; + private const uint y = 842502087; + private const uint z = 3579807591; + private const uint w = 273326509; + private uint _x, _y = y, _z = z, _w = w; + + public FastRandom(int seed) + { + _x = (uint)seed; + } + + public FastRandom() + : this(Environment.TickCount) + { + } + + /// + /// Generates a random unsigned integer within the range [, ). + /// + /// The random value. + public uint NextUInt() + { + uint t = _x ^ _x << 11; + _x = _y; + _y = _z; + _z = _w; + return _w = _w ^ _w >> 19 ^ t ^ t >> 8; + } + + /// + /// Generates a random integer value within the range [0, ). + /// + /// The random value. + public int Next() => (int)(int_mask & NextUInt()); + + /// + /// Generates a random integer value within the range [0, ). + /// + /// The upper bound. + /// The random value. + public int Next(int upperBound) => (int)(NextDouble() * upperBound); + + /// + /// Generates a random integer value within the range [, ). + /// + /// The lower bound of the range. + /// The upper bound of the range. + /// The random value. + public int Next(int lowerBound, int upperBound) => (int)(lowerBound + NextDouble() * (upperBound - lowerBound)); + + /// + /// Generates a random double value within the range [0, 1). + /// + /// The random value. + public double NextDouble() => int_to_real * Next(); + + private uint bitBuffer; + private int bitIndex = 32; + + /// + /// Generates a reandom boolean value. Cached such that a random value is only generated once in every 32 calls. + /// + /// The random value. + public bool NextBool() + { + if (bitIndex == 32) + { + bitBuffer = NextUInt(); + bitIndex = 1; + + return (bitBuffer & 1) == 1; + } + + bitIndex++; + return ((bitBuffer >>= 1) & 1) == 1; + } + } +} From 8c8e87ed7af2423f8d2ab3a7cf77b98d490c17f9 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 25 May 2018 16:49:41 +0900 Subject: [PATCH 059/306] Make FastRandom public --- osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs b/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs index 5e8256a504..5b3835755a 100644 --- a/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs +++ b/osu.Game.Rulesets.Catch/MathUtils/FastRandom.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Catch.MathUtils /// /// A PRNG specified in http://heliosphan.org/fastrandom.html. /// - internal class FastRandom + public class FastRandom { private const double int_to_real = 1.0 / (int.MaxValue + 1.0); private const uint int_mask = 0x7FFFFFFF; From 26c6313dec3a1286757f157947e93f10a61f2bdc Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 25 May 2018 19:11:29 +0900 Subject: [PATCH 060/306] catch: the fruit positions are finalized on the post process --- .../Beatmaps/CatchBeatmapProcessor.cs | 45 +++++++++++++++++++ .../Objects/BananaShower.cs | 2 +- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index e16f5fcb60..91a69b5c34 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -9,6 +9,7 @@ using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Objects.Types; using OpenTK; +using osu.Game.Rulesets.Catch.MathUtils; namespace osu.Game.Rulesets.Catch.Beatmaps { @@ -21,6 +22,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps public override void PostProcess() { + finalizePosition(); + initialiseHyperDash((List)Beatmap.HitObjects); base.PostProcess(); @@ -30,6 +33,48 @@ namespace osu.Game.Rulesets.Catch.Beatmaps obj.IndexInBeatmap = index++; } + public const int RNG_SEED = 1337; + + private void finalizePosition() + { + var rng = new FastRandom(RNG_SEED); + // todo: HardRock displacement should be applied here + + foreach (var obj in Beatmap.HitObjects) + { + switch (obj) + { + case BananaShower bananaShower: + foreach (var nested in bananaShower.NestedHitObjects) + { + ((BananaShower.Banana)nested).X = (float)rng.NextDouble(); + // discarding 3 times + rng.Next(); + rng.Next(); + rng.Next(); + } + break; + case JuiceStream juiceStream: + foreach (var nested in juiceStream.NestedHitObjects) + { + if (nested is TinyDroplet tinyDroplet) + { + tinyDroplet.X += (float)rng.Next(-20, 20) / CatchPlayfield.BASE_WIDTH; + } + else if (nested is Droplet) + { + rng.Next(); // Big droplets are not slided + } + } + break; + case Fruit fruit: + break; + } + var catchHitObject = obj as CatchHitObject; + + } + } + private void initialiseHyperDash(List objects) { // todo: add difficulty adjust. diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs index a6aba42f03..ed49359c0f 100644 --- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs +++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Catch.Objects { Samples = Samples, StartTime = i, - X = RNG.NextSingle() + X = 0 // The position will be set on the post processing }); } From 456dc81f2fdd67a966a8e837c0c82fb8839a759e Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 25 May 2018 19:18:11 +0900 Subject: [PATCH 061/306] Fix InspectCode issues --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs | 6 +----- osu.Game.Rulesets.Catch/Objects/BananaShower.cs | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 91a69b5c34..869bc560a8 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps { if (nested is TinyDroplet tinyDroplet) { - tinyDroplet.X += (float)rng.Next(-20, 20) / CatchPlayfield.BASE_WIDTH; + tinyDroplet.X += rng.Next(-20, 20) / CatchPlayfield.BASE_WIDTH; } else if (nested is Droplet) { @@ -67,11 +67,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps } } break; - case Fruit fruit: - break; } - var catchHitObject = obj as CatchHitObject; - } } diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs index ed49359c0f..4590856d98 100644 --- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs +++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.MathUtils; using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Rulesets.Catch.Objects From a24589f5836d87b758ba3cafcc694676fb65d208 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Fri, 25 May 2018 22:35:15 +0300 Subject: [PATCH 062/306] Cleanup external PlayButton.Playing usage --- osu.Game/Audio/PreviewTrackManager.cs | 9 ++-- .../BeatmapSet/Buttons/PreviewButton.cs | 8 +-- osu.Game/Overlays/BeatmapSet/Details.cs | 6 ++- osu.Game/Overlays/Direct/DirectPanel.cs | 1 - osu.Game/Overlays/Direct/PlayButton.cs | 52 +++++++++---------- osu.Game/Overlays/DirectOverlay.cs | 26 ---------- 6 files changed, 37 insertions(+), 65 deletions(-) diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 5c7f580ca8..5c2656b322 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -37,14 +37,17 @@ namespace osu.Game.Audio CurrentTrack?.Stop(); audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); CurrentTrack = track; - CurrentTrack.Stopped += () => CurrentTrack = null; }; - onTrackStop = () => audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); + onTrackStop = () => + { + audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); + CurrentTrack = null; + }; } public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo) => new PreviewTrack( - trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo.OnlineBeatmapSetID}.mp3"), + trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3"), onTrackStart, onTrackStop); diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs index 78628675ac..78bc77efe8 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs @@ -66,7 +66,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons }, }; - Action = () => Playing.Value = !Playing.Value; + Action = () => playButton.TriggerOnClick(); Playing.ValueChanged += newValue => progress.FadeTo(newValue ? 1 : 0, 100); } @@ -89,12 +89,6 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons progress.Width = 0; } - protected override void Dispose(bool isDisposing) - { - Playing.Value = false; - base.Dispose(isDisposing); - } - protected override bool OnHover(InputState state) { bg.FadeColour(Color4.Black.Opacity(0.5f), 100); diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs index 5264caf936..8c16822cfc 100644 --- a/osu.Game/Overlays/BeatmapSet/Details.cs +++ b/osu.Game/Overlays/BeatmapSet/Details.cs @@ -102,7 +102,11 @@ namespace osu.Game.Overlays.BeatmapSet updateDisplay(); } - public void StopPreview() => preview.Playing.Value = false; + public void StopPreview() + { + if (preview.Playing) + preview.TriggerOnClick(); + } private class DetailBox : Container { diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 2ceefe31ef..1c7abd4cdd 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -149,7 +149,6 @@ namespace osu.Game.Overlays.Direct protected override bool OnClick(InputState state) { ShowInformation(); - PreviewPlaying.Value = false; return true; } diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 1f18faaf14..677f74540b 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -31,8 +31,6 @@ namespace osu.Game.Overlays.Direct beatmapSet = value; Playing.Value = false; - if (Preview != null) - Preview.Stopped -= preview_Stopped; Preview = null; } } @@ -90,7 +88,30 @@ namespace osu.Game.Overlays.Direct protected override bool OnClick(InputState state) { - Playing.Value = !Playing.Value; + if (!Playing.Value) + { + if (Preview == null) + { + Task.Run(() => + { + loading = true; + return Preview = previewTrackManager.Get(beatmapSet); + }) + .ContinueWith(t => + { + Preview.Started += () => Playing.Value = true; + Preview.Stopped += () => Playing.Value = false; + Preview.Start(); + loading = false; + }); + return true; + } + + Preview.Start(); + } + else + Preview?.Stop(); + return true; } @@ -118,35 +139,12 @@ namespace osu.Game.Overlays.Direct icon.Icon = playing ? FontAwesome.fa_pause : FontAwesome.fa_play; icon.FadeColour(playing || IsHovered ? hoverColour : Color4.White, 120, Easing.InOutQuint); - if (playing) + if (!playing) { - if (Preview == null) - { - Task.Run(() => - { - loading = true; - return Preview = previewTrackManager.Get(beatmapSet); - }) - .ContinueWith(t => - { - Preview.Stopped += preview_Stopped; - playingStateChanged(true); - loading = false; - }); - return; - } - - Preview.Start(); - } - else - { - Preview.Stop(); loading = false; } } - private void preview_Stopped() => Playing.Value = false; - protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index f437546888..35a6e5fc48 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -33,7 +33,6 @@ namespace osu.Game.Overlays private readonly FillFlowContainer resultCountsContainer; private readonly OsuSpriteText resultCountsText; private FillFlowContainer panels; - private DirectPanel playing; protected override Color4 BackgroundColour => OsuColour.FromHex(@"485e74"); protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"465b71"); @@ -217,12 +216,6 @@ namespace osu.Game.Overlays panels.FadeOut(200); panels.Expire(); panels = null; - - if (playing != null) - { - playing.PreviewPlaying.Value = false; - playing = null; - } } if (BeatmapSets == null) return; @@ -253,17 +246,6 @@ namespace osu.Game.Overlays { if (panels != null) ScrollFlow.Remove(panels); ScrollFlow.Add(panels = newPanels); - - foreach (DirectPanel panel in p.Children) - panel.PreviewPlaying.ValueChanged += newValue => - { - if (newValue) - { - if (playing != null && playing != panel) - playing.PreviewPlaying.Value = false; - playing = panel; - } - }; }); } @@ -313,14 +295,6 @@ namespace osu.Game.Overlays api.Queue(getSetsRequest); } - protected override void PopOut() - { - base.PopOut(); - - if (playing != null) - playing.PreviewPlaying.Value = false; - } - private int distinctCount(List list) => list.Distinct().ToArray().Length; protected override void Dispose(bool isDisposing) From 572c3f518948a1729a34e24646f252d7d65d6e1e Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Fri, 25 May 2018 23:51:05 +0300 Subject: [PATCH 063/306] Stop preview playback when an overlay is popping out --- osu.Game/Overlays/BeatmapSet/Details.cs | 6 ------ osu.Game/Overlays/BeatmapSetOverlay.cs | 15 +++++++++------ osu.Game/Overlays/DirectOverlay.cs | 13 +++++++++++-- osu.Game/Overlays/UserProfileOverlay.cs | 10 +++++++--- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs index 8c16822cfc..ccd0fa04ab 100644 --- a/osu.Game/Overlays/BeatmapSet/Details.cs +++ b/osu.Game/Overlays/BeatmapSet/Details.cs @@ -102,12 +102,6 @@ namespace osu.Game.Overlays.BeatmapSet updateDisplay(); } - public void StopPreview() - { - if (preview.Playing) - preview.TriggerOnClick(); - } - private class DetailBox : Container { private readonly Container content; diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 096f7bb63c..53bae54379 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -1,23 +1,24 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; using osu.Framework.Allocation; -using OpenTK; -using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; +using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.BeatmapSet; -using osu.Game.Rulesets; using osu.Game.Overlays.BeatmapSet.Scores; -using System.Linq; +using osu.Game.Rulesets; +using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Overlays { @@ -37,6 +38,7 @@ namespace osu.Game.Overlays private readonly ScrollContainer scroll; private BeatmapSetInfo beatmapSet; + private PreviewTrackManager previewTrackManager; public BeatmapSetInfo BeatmapSet { @@ -109,10 +111,11 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api, RulesetStore rulesets) + private void load(APIAccess api, RulesetStore rulesets, PreviewTrackManager previewTrackManager) { this.api = api; this.rulesets = rulesets; + this.previewTrackManager = previewTrackManager; } protected override void PopIn() @@ -124,7 +127,7 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); - header.Details.StopPreview(); + previewTrackManager.CurrentTrack?.Stop(); FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => BeatmapSet = null); } diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 35a6e5fc48..c69dc57342 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -4,12 +4,12 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using OpenTK; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Threading; +using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -18,6 +18,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Overlays.Direct; using osu.Game.Overlays.SearchableList; using osu.Game.Rulesets; +using OpenTK; using OpenTK.Graphics; namespace osu.Game.Overlays @@ -176,11 +177,12 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(OsuColour colours, APIAccess api, RulesetStore rulesets, BeatmapManager beatmaps) + private void load(OsuColour colours, APIAccess api, RulesetStore rulesets, BeatmapManager beatmaps, PreviewTrackManager previewTrackManager) { this.api = api; this.rulesets = rulesets; this.beatmaps = beatmaps; + this.previewTrackManager = previewTrackManager; resultCountsContainer.Colour = colours.Yellow; @@ -254,6 +256,7 @@ namespace osu.Game.Overlays private readonly Bindable currentQuery = new Bindable(); private ScheduledDelegate queryChangedDebounce; + private PreviewTrackManager previewTrackManager; private void updateSearch() { @@ -297,6 +300,12 @@ namespace osu.Game.Overlays private int distinctCount(List list) => list.Distinct().ToArray().Length; + protected override void PopOut() + { + previewTrackManager.CurrentTrack?.Stop(); + base.PopOut(); + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index a4dd0c9ec3..04a93dea23 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -2,14 +2,13 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Linq; -using OpenTK; -using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; +using osu.Game.Audio; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -18,6 +17,8 @@ using osu.Game.Online.API.Requests; using osu.Game.Overlays.Profile; using osu.Game.Overlays.Profile.Sections; using osu.Game.Users; +using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Overlays { @@ -30,6 +31,7 @@ namespace osu.Game.Overlays protected ProfileHeader Header; private SectionsContainer sectionsContainer; private ProfileTabControl tabs; + private PreviewTrackManager previewTrackManager; public const float CONTENT_X_MARGIN = 50; @@ -56,9 +58,10 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api) + private void load(APIAccess api, PreviewTrackManager previewTrackManager) { this.api = api; + this.previewTrackManager = previewTrackManager; } protected override void PopIn() @@ -70,6 +73,7 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); + previewTrackManager.CurrentTrack?.Stop(); FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out); } From ab3ac49a2d6ac9667709b61a694be91206ab9925 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Mon, 28 May 2018 21:01:56 -0300 Subject: [PATCH 064/306] Add empty Match screen. --- osu.Game.Tests/Visual/TestCaseMatch.cs | 23 ++++++++++++ .../Screens/Multi/Screens/Lounge/Lounge.cs | 2 +- osu.Game/Screens/Multi/Screens/Match.cs | 37 ------------------- osu.Game/Screens/Multi/Screens/Match/Match.cs | 19 ++++++++++ osu.Game/Screens/Multi/Screens/MatchCreate.cs | 20 ---------- 5 files changed, 43 insertions(+), 58 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseMatch.cs delete mode 100644 osu.Game/Screens/Multi/Screens/Match.cs create mode 100644 osu.Game/Screens/Multi/Screens/Match/Match.cs delete mode 100644 osu.Game/Screens/Multi/Screens/MatchCreate.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatch.cs b/osu.Game.Tests/Visual/TestCaseMatch.cs new file mode 100644 index 0000000000..9e62a19897 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseMatch.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Online.Multiplayer; +using osu.Game.Screens.Multi.Screens.Match; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseMatch : OsuTestCase + { + public TestCaseMatch() + { + Room room = new Room + { + }; + + Match match = new Match(room); + + AddStep(@"show", () => Add(match)); + AddStep(@"exit", match.Exit); + } + } +} diff --git a/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs b/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs index 60ffe2c0b9..c83ecee1f0 100644 --- a/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs +++ b/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs @@ -164,7 +164,7 @@ namespace osu.Game.Screens.Multi.Screens.Lounge // open the room if its selected and is clicked again if (room.State == SelectionState.Selected) - Push(new Match()); + Push(new Match.Match(room.Room)); } private class RoomsFilterContainer : FillFlowContainer, IHasFilterableChildren diff --git a/osu.Game/Screens/Multi/Screens/Match.cs b/osu.Game/Screens/Multi/Screens/Match.cs deleted file mode 100644 index 4ba7fe9f6a..0000000000 --- a/osu.Game/Screens/Multi/Screens/Match.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using osu.Framework.Graphics; -using osu.Framework.Screens; -using osu.Game.Screens.Backgrounds; -using osu.Game.Screens.Play; -using osu.Game.Screens.Select; -using OpenTK.Graphics; - -namespace osu.Game.Screens.Multi.Screens -{ - public class Match : ScreenWhiteBox - { - protected override IEnumerable PossibleChildren => new[] { - typeof(MatchSongSelect), - typeof(Player), - }; - - protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4"); - - protected override void OnEntering(Screen last) - { - base.OnEntering(last); - - Background.FadeColour(Color4.DarkGray, 500); - } - - protected override bool OnExiting(Screen next) - { - Background.FadeColour(Color4.White, 500); - return base.OnExiting(next); - } - } -} diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs new file mode 100644 index 0000000000..f70ed9eaa4 --- /dev/null +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Online.Multiplayer; + +namespace osu.Game.Screens.Multi.Screens.Match +{ + public class Match : MultiplayerScreen + { + private readonly Room room; + + public override string Title => room.Name.Value; + + public Match(Room room) + { + this.room = room; + } + } +} diff --git a/osu.Game/Screens/Multi/Screens/MatchCreate.cs b/osu.Game/Screens/Multi/Screens/MatchCreate.cs deleted file mode 100644 index 6b4e26d5e5..0000000000 --- a/osu.Game/Screens/Multi/Screens/MatchCreate.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; - -namespace osu.Game.Screens.Multi.Screens -{ - public class MatchCreate : ScreenWhiteBox - { - protected override IEnumerable PossibleChildren => new[] { - typeof(Match) - }; - - public MatchCreate() - { - ValidForResume = false; - } - } -} From 98819880c4a3018e2d840be335ce2a542629611d Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Mon, 28 May 2018 22:11:01 -0300 Subject: [PATCH 065/306] Add match screen header. --- osu.Game.Tests/Visual/TestCaseMatch.cs | 17 ++ .../Screens/Multi/Screens/Match/Header.cs | 169 ++++++++++++++++++ osu.Game/Screens/Multi/Screens/Match/Match.cs | 23 +++ 3 files changed, 209 insertions(+) create mode 100644 osu.Game/Screens/Multi/Screens/Match/Header.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatch.cs b/osu.Game.Tests/Visual/TestCaseMatch.cs index 9e62a19897..5dc330704d 100644 --- a/osu.Game.Tests/Visual/TestCaseMatch.cs +++ b/osu.Game.Tests/Visual/TestCaseMatch.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi.Screens.Match; @@ -12,6 +13,22 @@ namespace osu.Game.Tests.Visual { Room room = new Room { + Beatmap = + { + Value = new BeatmapInfo + { + BeatmapSet = new BeatmapSetInfo + { + OnlineInfo = new BeatmapSetOnlineInfo + { + Covers = new BeatmapSetOnlineCovers + { + Cover = @"https://assets.ppy.sh/beatmaps/765055/covers/cover.jpg?1526955337", + }, + }, + }, + }, + }, }; Match match = new Match(room); diff --git a/osu.Game/Screens/Multi/Screens/Match/Header.cs b/osu.Game/Screens/Multi/Screens/Match/Header.cs new file mode 100644 index 0000000000..b1f9e0dfc6 --- /dev/null +++ b/osu.Game/Screens/Multi/Screens/Match/Header.cs @@ -0,0 +1,169 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.SearchableList; +using OpenTK.Graphics; + +namespace osu.Game.Screens.Multi.Screens.Match +{ + public class Header : Container + { + private readonly Box tabStrip; + private readonly UpdateableBeatmapSetCover cover; + + public readonly OsuClickableContainer BeatmapButton; + + public BeatmapSetInfo BeatmapSet + { + set { cover.BeatmapSet = value; } + } + + public Header() + { + RelativeSizeAxes = Axes.X; + Height = 200; + + Children = new Drawable[] + { + cover = new UpdateableBeatmapSetCover + { + RelativeSizeAxes = Axes.Both, + Masking = true, + }, + tabStrip = new Box + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Height = 1, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING }, + Children = new Drawable[] + { + new Container + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.Y, + Width = 200, + Padding = new MarginPadding { Vertical = 5 }, + Child = BeatmapButton = new BeatmapSelectButton + { + RelativeSizeAxes = Axes.Both, + }, + }, + new PageTabControl + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + }, + }, + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + tabStrip.Colour = colours.Yellow; + } + + private class BeatmapSelectButton : OsuClickableContainer + { + private const float corner_radius = 5; + private const float bg_opacity = 0.5f; + private const float transition_duration = 100; + + private readonly Box bg; + private readonly Container border; + + public BeatmapSelectButton() + { + Masking = true; + CornerRadius = corner_radius; + + Children = new Drawable[] + { + bg = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = bg_opacity, + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = @"Exo2.0-Bold", + Text = "Select Beatmap", + }, + border = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = corner_radius, + BorderThickness = 4, + Alpha = 0f, + Child = new Box // needs a child to show the border + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0), + }, + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + border.BorderColour = colours.Yellow; + } + + protected override bool OnHover(InputState state) + { + border.FadeIn(transition_duration); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + base.OnHoverLost(state); + border.FadeOut(transition_duration); + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + bg.FadeTo(0.75f, 1000, Easing.Out); + return base.OnMouseDown(state, args); + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + bg.FadeTo(bg_opacity, transition_duration); + return base.OnMouseUp(state, args); + } + } + } + + public enum MatchHeaderPage + { + Settings, + Room, + } +} diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index f70ed9eaa4..82f5b53ee2 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -1,19 +1,42 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; +using osu.Game.Screens.Select; namespace osu.Game.Screens.Multi.Screens.Match { public class Match : MultiplayerScreen { private readonly Room room; + private readonly Bindable beatmapBind = new Bindable(); public override string Title => room.Name.Value; public Match(Room room) { this.room = room; + Header header; + + Children = new Drawable[] + { + header = new Header(), + }; + + header.BeatmapButton.Action = () => + { + Push(new MatchSongSelect()); + }; + + beatmapBind.ValueChanged += b => + { + header.BeatmapSet = b.BeatmapSet; + }; + + beatmapBind.BindTo(room.Beatmap); } } } From c8ce34b6d4a80f8c8a2414a3296e21642003f24d Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 01:51:04 -0300 Subject: [PATCH 066/306] Add Match Info. --- osu.Game.Tests/Visual/TestCaseMatch.cs | 17 +- .../Screens/Multi/Screens/Match/Header.cs | 5 +- osu.Game/Screens/Multi/Screens/Match/Info.cs | 194 ++++++++++++++++++ osu.Game/Screens/Multi/Screens/Match/Match.cs | 24 ++- 4 files changed, 234 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Screens/Multi/Screens/Match/Info.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatch.cs b/osu.Game.Tests/Visual/TestCaseMatch.cs index 5dc330704d..9c385feacb 100644 --- a/osu.Game.Tests/Visual/TestCaseMatch.cs +++ b/osu.Game.Tests/Visual/TestCaseMatch.cs @@ -1,22 +1,37 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets; using osu.Game.Screens.Multi.Screens.Match; namespace osu.Game.Tests.Visual { public class TestCaseMatch : OsuTestCase { - public TestCaseMatch() + [BackgroundDependencyLoader] + private void load(RulesetStore rulesets) { Room room = new Room { + Name = { Value = @"One Awesome Room" }, + Status = { Value = new RoomStatusOpen() }, + Availability = { Value = RoomAvailability.Public }, + Type = { Value = new GameTypeTeamVersus() }, Beatmap = { Value = new BeatmapInfo { + StarDifficulty = 5.02, + Ruleset = rulesets.GetRuleset(1), + Metadata = new BeatmapMetadata + { + Title = @"Paradigm Shift", + Artist = @"Morimori Atsushi", + AuthorString = @"eiri-", + }, BeatmapSet = new BeatmapSetInfo { OnlineInfo = new BeatmapSetOnlineInfo diff --git a/osu.Game/Screens/Multi/Screens/Match/Header.cs b/osu.Game/Screens/Multi/Screens/Match/Header.cs index b1f9e0dfc6..fde6859d95 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Header.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Header.cs @@ -20,6 +20,8 @@ namespace osu.Game.Screens.Multi.Screens.Match { public class Header : Container { + public const float HEIGHT = 200; + private readonly Box tabStrip; private readonly UpdateableBeatmapSetCover cover; @@ -33,10 +35,11 @@ namespace osu.Game.Screens.Multi.Screens.Match public Header() { RelativeSizeAxes = Axes.X; - Height = 200; + Height = HEIGHT; Children = new Drawable[] { + // todo: gradient over the cover cover = new UpdateableBeatmapSetCover { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Screens/Multi/Screens/Match/Info.cs b/osu.Game/Screens/Multi/Screens/Match/Info.cs new file mode 100644 index 0000000000..634b91cf7a --- /dev/null +++ b/osu.Game/Screens/Multi/Screens/Match/Info.cs @@ -0,0 +1,194 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Multiplayer; +using osu.Game.Overlays.SearchableList; +using osu.Game.Screens.Multi.Components; + +namespace osu.Game.Screens.Multi.Screens.Match +{ + public class Info : Container + { + public const float HEIGHT = 128; + + private readonly OsuSpriteText name, availabilityStatus; + private readonly BeatmapTypeInfo beatmapTypeInfo; + + private OsuColour colours; + + public string Name + { + set { name.Text = value; } + } + + private RoomAvailability availability; + public RoomAvailability Availability + { + set + { + if (value == availability) return; + availability = value; + + if (IsLoaded) + updateAvailabilityStatus(); + } + } + + private RoomStatus status; + public RoomStatus Status + { + set + { + if (value == status) return; + status = value; + + if (IsLoaded) + updateAvailabilityStatus(); + } + } + + public BeatmapInfo Beatmap + { + set { beatmapTypeInfo.Beatmap = value; } + } + + public GameType Type + { + set { beatmapTypeInfo.Type = value; } + } + + public Info() + { + RelativeSizeAxes = Axes.X; + Height = HEIGHT; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex(@"28242d"), + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING }, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Padding = new MarginPadding { Vertical = 20 }, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + name = new OsuSpriteText + { + TextSize = 30, + }, + availabilityStatus = new OsuSpriteText + { + TextSize = 14, + }, + }, + }, + beatmapTypeInfo = new BeatmapTypeInfo + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + }, + }, + }, + new ReadyButton + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.Y, + Width = 200, + Padding = new MarginPadding { Vertical = 10 }, + }, + }, + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + this.colours = colours; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + updateAvailabilityStatus(); + } + + private void updateAvailabilityStatus() + { + if (status != null) + { + availabilityStatus.FadeColour(status.GetAppropriateColour(colours)); + availabilityStatus.Text = $"{availability.GetDescription()}, {status.Message}"; + } + } + + private class ReadyButton : TriangleButton + { + public readonly Bindable Ready = new Bindable(); + + protected override SpriteText CreateText() => new OsuSpriteText + { + Depth = -1, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Font = @"Exo2.0-Light", + TextSize = 30, + }; + + public ReadyButton() + { + Height = 1; + Text = "Ready"; + + Action = () => Ready.Value = !Ready.Value; + } + + [BackgroundDependencyLoader] + private void load() + { + BackgroundColour = OsuColour.FromHex(@"1187aa"); + Triangles.ColourLight = OsuColour.FromHex(@"277b9c"); + Triangles.ColourDark = OsuColour.FromHex(@"1f6682"); + Triangles.TriangleScale = 1.5f; + + // todo: visually select + Ready.ValueChanged += value => + { + if (value) + Text = "Not Ready"; + else + Text = "Ready"; + }; + } + } + } +} diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index 82f5b53ee2..e83769daa0 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -12,6 +12,11 @@ namespace osu.Game.Screens.Multi.Screens.Match public class Match : MultiplayerScreen { private readonly Room room; + + private readonly Bindable nameBind = new Bindable(); + private readonly Bindable statusBind = new Bindable(); + private readonly Bindable availabilityBind = new Bindable(); + private readonly Bindable typeBind = new Bindable(); private readonly Bindable beatmapBind = new Bindable(); public override string Title => room.Name.Value; @@ -20,22 +25,33 @@ namespace osu.Game.Screens.Multi.Screens.Match { this.room = room; Header header; + Info info; Children = new Drawable[] { header = new Header(), + info = new Info + { + Margin = new MarginPadding { Top = Header.HEIGHT }, + }, }; - header.BeatmapButton.Action = () => - { - Push(new MatchSongSelect()); - }; + header.BeatmapButton.Action = () => Push(new MatchSongSelect()); + nameBind.ValueChanged += n => info.Name = n; + statusBind.ValueChanged += s => info.Status = s; + availabilityBind.ValueChanged += a => info.Availability = a; + typeBind.ValueChanged += t => info.Type = t; beatmapBind.ValueChanged += b => { header.BeatmapSet = b.BeatmapSet; + info.Beatmap = b; }; + nameBind.BindTo(room.Name); + statusBind.BindTo(room.Status); + availabilityBind.BindTo(room.Availability); + typeBind.BindTo(room.Type); beatmapBind.BindTo(room.Beatmap); } } From 77ff0640c24a5005486337b8ac3cd95369b6a3c2 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 01:53:45 -0300 Subject: [PATCH 067/306] Add a gradient over the cover in Header. --- osu.Game/Screens/Multi/Screens/Match/Header.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/Screens/Match/Header.cs b/osu.Game/Screens/Multi/Screens/Match/Header.cs index fde6859d95..1d414e338c 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Header.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Header.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; @@ -39,12 +40,16 @@ namespace osu.Game.Screens.Multi.Screens.Match Children = new Drawable[] { - // todo: gradient over the cover cover = new UpdateableBeatmapSetCover { RelativeSizeAxes = Axes.Both, Masking = true, }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0), Color4.Black.Opacity(0.5f)), + }, tabStrip = new Box { Anchor = Anchor.BottomLeft, From 3915cb7f2f7cde41e6688905cd9bfed2c8487008 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 02:42:52 -0300 Subject: [PATCH 068/306] Add Match Participants, change Room.Users to IEnumerable. --- osu.Game.Tests/Visual/TestCaseMatch.cs | 38 ++++++++++ osu.Game/Online/Multiplayer/Room.cs | 3 +- .../Screens/Multi/Components/DrawableRoom.cs | 2 +- .../Screens/Multi/Components/RoomInspector.cs | 5 +- osu.Game/Screens/Multi/Screens/Match/Match.cs | 17 +++++ .../Multi/Screens/Match/Participants.cs | 71 +++++++++++++++++++ .../Multi/Screens/MultiplayerScreen.cs | 1 + 7 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Screens/Multi/Screens/Match/Participants.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatch.cs b/osu.Game.Tests/Visual/TestCaseMatch.cs index 9c385feacb..6f41723982 100644 --- a/osu.Game.Tests/Visual/TestCaseMatch.cs +++ b/osu.Game.Tests/Visual/TestCaseMatch.cs @@ -6,6 +6,7 @@ using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets; using osu.Game.Screens.Multi.Screens.Match; +using osu.Game.Users; namespace osu.Game.Tests.Visual { @@ -44,6 +45,43 @@ namespace osu.Game.Tests.Visual }, }, }, + MaxParticipants = { Value = 5 }, + Participants = + { + Value = new[] + { + new User + { + Username = @"eiri-", + Id = 3388410, + Country = new Country { FlagName = @"US" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/3388410/00a8486a247831e1cc4375db519f611ac970bda8bc0057d78b0f540ea38c3e58.jpeg", + IsSupporter = true, + }, + new User + { + Username = @"Nepuri", + Id = 6637817, + Country = new Country { FlagName = @"DE" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/6637817/9085fc60248b6b5327a72c1dcdecf2dbedba810ae0ab6bcf7224e46b1339632a.jpeg", + IsSupporter = true, + }, + new User + { + Username = @"goheegy", + Id = 8057655, + Country = new Country { FlagName = @"GB" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/8057655/21cec27c25a11dc197a4ec6a74253dbabb495949b0e0697113352f12007018c5.jpeg", + }, + new User + { + Username = @"Alumetri", + Id = 5371497, + Country = new Country { FlagName = @"RU" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/5371497/e023b8c7fbe3613e64bd4856703517ea50fbed8a5805dc9acda9efe9897c67e2.jpeg", + }, + } + }, }; Match match = new Match(room); diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs index ae3fb5ec6e..b076afbcdb 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Multiplayer/Room.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using osu.Framework.Configuration; using osu.Game.Beatmaps; using osu.Game.Users; @@ -16,6 +17,6 @@ namespace osu.Game.Online.Multiplayer public Bindable Type = new Bindable(); public Bindable Beatmap = new Bindable(); public Bindable MaxParticipants = new Bindable(); - public Bindable Participants = new Bindable(); + public Bindable> Participants = new Bindable>(); } } diff --git a/osu.Game/Screens/Multi/Components/DrawableRoom.cs b/osu.Game/Screens/Multi/Components/DrawableRoom.cs index d31019a259..54bd0ae7cc 100644 --- a/osu.Game/Screens/Multi/Components/DrawableRoom.cs +++ b/osu.Game/Screens/Multi/Components/DrawableRoom.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Multi.Components private readonly Bindable statusBind = new Bindable(); private readonly Bindable typeBind = new Bindable(); private readonly Bindable beatmapBind = new Bindable(); - private readonly Bindable participantsBind = new Bindable(); + private readonly Bindable> participantsBind = new Bindable>(); public readonly Room Room; diff --git a/osu.Game/Screens/Multi/Components/RoomInspector.cs b/osu.Game/Screens/Multi/Components/RoomInspector.cs index 14f4feab05..22bca1efc7 100644 --- a/osu.Game/Screens/Multi/Components/RoomInspector.cs +++ b/osu.Game/Screens/Multi/Components/RoomInspector.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Configuration; @@ -33,7 +34,7 @@ namespace osu.Game.Screens.Multi.Components private readonly Bindable typeBind = new Bindable(); private readonly Bindable beatmapBind = new Bindable(); private readonly Bindable maxParticipantsBind = new Bindable(); - private readonly Bindable participantsBind = new Bindable(); + private readonly Bindable> participantsBind = new Bindable>(); private OsuColour colours; private Box statusStrip; @@ -214,7 +215,7 @@ namespace osu.Game.Screens.Multi.Components participantsBind.ValueChanged += p => { - participantCount.Count = p.Length; + participantCount.Count = p.Count(); participantInfo.Participants = p; participantsFlow.ChildrenEnumerable = p.Select(u => new UserTile(u)); }; diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index e83769daa0..3a2aef2ff4 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -1,23 +1,31 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Select; +using osu.Game.Users; namespace osu.Game.Screens.Multi.Screens.Match { public class Match : MultiplayerScreen { private readonly Room room; + private readonly Participants participants; private readonly Bindable nameBind = new Bindable(); private readonly Bindable statusBind = new Bindable(); private readonly Bindable availabilityBind = new Bindable(); private readonly Bindable typeBind = new Bindable(); private readonly Bindable beatmapBind = new Bindable(); + private readonly Bindable maxParticipantsBind = new Bindable(); + private readonly Bindable> participantsBind = new Bindable>(); + + protected override Container TransitionContent => participants; public override string Title => room.Name.Value; @@ -34,6 +42,11 @@ namespace osu.Game.Screens.Multi.Screens.Match { Margin = new MarginPadding { Top = Header.HEIGHT }, }, + participants = new Participants + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = Header.HEIGHT + Info.HEIGHT }, + }, }; header.BeatmapButton.Action = () => Push(new MatchSongSelect()); @@ -41,6 +54,8 @@ namespace osu.Game.Screens.Multi.Screens.Match statusBind.ValueChanged += s => info.Status = s; availabilityBind.ValueChanged += a => info.Availability = a; typeBind.ValueChanged += t => info.Type = t; + maxParticipantsBind.ValueChanged += m => { participants.Max = m; }; + participantsBind.ValueChanged += p => participants.Users = p; beatmapBind.ValueChanged += b => { @@ -53,6 +68,8 @@ namespace osu.Game.Screens.Multi.Screens.Match availabilityBind.BindTo(room.Availability); typeBind.BindTo(room.Type); beatmapBind.BindTo(room.Beatmap); + maxParticipantsBind.BindTo(room.MaxParticipants); + participantsBind.BindTo(room.Participants); } } } diff --git a/osu.Game/Screens/Multi/Screens/Match/Participants.cs b/osu.Game/Screens/Multi/Screens/Match/Participants.cs new file mode 100644 index 0000000000..11e27c0a18 --- /dev/null +++ b/osu.Game/Screens/Multi/Screens/Match/Participants.cs @@ -0,0 +1,71 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Overlays.SearchableList; +using osu.Game.Screens.Multi.Components; +using osu.Game.Users; +using OpenTK; + +namespace osu.Game.Screens.Multi.Screens.Match +{ + public class Participants : Container + { + private readonly ParticipantCount count; + private readonly FillFlowContainer usersFlow; + + public IEnumerable Users + { + set { + usersFlow.Children = value.Select(u => new UserPanel(u) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Width = 300, + }).ToList(); + + count.Count = value.Count(); + } + } + + public int? Max + { + set { count.Max = value; } + } + + public Participants() + { + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING }, + Children = new Drawable[] + { + new ScrollContainer + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 10 }, + Children = new Drawable[] + { + count = new ParticipantCount + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }, + usersFlow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(5), + Padding = new MarginPadding { Top = 40 }, + }, + }, + }, + }, + }; + } + } +} diff --git a/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs b/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs index 191fe66037..9daa4e732b 100644 --- a/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs +++ b/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs @@ -21,6 +21,7 @@ namespace osu.Game.Screens.Multi.Screens TransitionContent.MoveToX(200); + Content.FadeInFromZero(WaveContainer.APPEAR_DURATION, in_easing); TransitionContent.FadeInFromZero(WaveContainer.APPEAR_DURATION, in_easing); TransitionContent.MoveToX(0, WaveContainer.APPEAR_DURATION, in_easing); } From 94b54a0520d4f2d091d531786c63b527a8db2629 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 03:03:51 -0300 Subject: [PATCH 069/306] Adjust design of ReadyButton. --- osu.Game/Screens/Multi/Screens/Match/Info.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/Screens/Match/Info.cs b/osu.Game/Screens/Multi/Screens/Match/Info.cs index 634b91cf7a..88dda4a67b 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Info.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Info.cs @@ -180,13 +180,31 @@ namespace osu.Game.Screens.Multi.Screens.Match Triangles.ColourDark = OsuColour.FromHex(@"1f6682"); Triangles.TriangleScale = 1.5f; - // todo: visually select + Container active; + Add(active = new Container + { + RelativeSizeAxes = Axes.Both, + Alpha = 0f, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.15f, + Blending = BlendingMode.Additive, + }, + }); + Ready.ValueChanged += value => { if (value) + { Text = "Not Ready"; + active.FadeIn(200); + } else + { Text = "Ready"; + active.FadeOut(200); + } }; } } From b4b4a8a157a0bbcb5e99269ff3772afeff7f2545 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 03:24:38 -0300 Subject: [PATCH 070/306] Add TestCaseMatchInfo. --- osu.Game.Tests/Visual/TestCaseMatch.cs | 2 + osu.Game.Tests/Visual/TestCaseMatchInfo.cs | 59 ++++++++++++++++++++ osu.Game/Screens/Multi/Screens/Match/Info.cs | 7 ++- 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseMatchInfo.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatch.cs b/osu.Game.Tests/Visual/TestCaseMatch.cs index 6f41723982..69c1a6a0b2 100644 --- a/osu.Game.Tests/Visual/TestCaseMatch.cs +++ b/osu.Game.Tests/Visual/TestCaseMatch.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; @@ -10,6 +11,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual { + [TestFixture] public class TestCaseMatch : OsuTestCase { [BackgroundDependencyLoader] diff --git a/osu.Game.Tests/Visual/TestCaseMatchInfo.cs b/osu.Game.Tests/Visual/TestCaseMatchInfo.cs new file mode 100644 index 0000000000..f58bc0e30a --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseMatchInfo.cs @@ -0,0 +1,59 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Game.Beatmaps; +using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets; +using osu.Game.Screens.Multi.Screens.Match; + +namespace osu.Game.Tests.Visual +{ + [TestFixture] + public class TestCaseMatchInfo : OsuTestCase + { + [BackgroundDependencyLoader] + private void load(RulesetStore rulesets) + { + Info info = new Info(); + Add(info); + + AddStep(@"set name", () => info.Name = @"Room Name?"); + AddStep(@"set availability", () => info.Availability = RoomAvailability.FriendsOnly); + AddStep(@"set status", () => info.Status = new RoomStatusPlaying()); + + AddStep(@"set beatmap", () => info.Beatmap = new BeatmapInfo + { + StarDifficulty = 2.4, + Ruleset = rulesets.GetRuleset(0), + Metadata = new BeatmapMetadata + { + Title = @"My Song", + Artist = @"VisualTests", + AuthorString = @"osu!lazer", + }, + }); + + AddStep(@"set type", () => info.Type = new GameTypeTagTeam()); + + AddStep(@"change name", () => info.Name = @"Room Name!"); + AddStep(@"change availability", () => info.Availability = RoomAvailability.InviteOnly); + AddStep(@"change status", () => info.Status = new RoomStatusOpen()); + + AddStep(@"change beatmap", () => info.Beatmap = new BeatmapInfo + { + StarDifficulty = 4.2, + Ruleset = rulesets.GetRuleset(3), + Metadata = new BeatmapMetadata + { + Title = @"Your Song", + Artist = @"Tester", + AuthorString = @"Someone", + }, + }); + + AddStep(@"change type", () => info.Type = new GameTypeTeamVersus()); + } + } +} diff --git a/osu.Game/Screens/Multi/Screens/Match/Info.cs b/osu.Game/Screens/Multi/Screens/Match/Info.cs index 88dda4a67b..e2efbad269 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Info.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Info.cs @@ -24,9 +24,12 @@ namespace osu.Game.Screens.Multi.Screens.Match private readonly OsuSpriteText name, availabilityStatus; private readonly BeatmapTypeInfo beatmapTypeInfo; + private readonly ReadyButton readyButton; private OsuColour colours; + public Bindable Ready => readyButton.Ready; + public string Name { set { name.Text = value; } @@ -116,7 +119,7 @@ namespace osu.Game.Screens.Multi.Screens.Match }, }, }, - new ReadyButton + readyButton = new ReadyButton { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, @@ -146,7 +149,7 @@ namespace osu.Game.Screens.Multi.Screens.Match { if (status != null) { - availabilityStatus.FadeColour(status.GetAppropriateColour(colours)); + availabilityStatus.FadeColour(status.GetAppropriateColour(colours), 100); availabilityStatus.Text = $"{availability.GetDescription()}, {status.Message}"; } } From 8595c821b438cf2d5c8a2d7bb3d06b8d46f9a1ec Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 03:34:02 -0300 Subject: [PATCH 071/306] Add TestCaseMatchHeader. --- osu.Game.Tests/Visual/TestCaseMatchHeader.cs | 43 ++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 osu.Game.Tests/Visual/TestCaseMatchHeader.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatchHeader.cs b/osu.Game.Tests/Visual/TestCaseMatchHeader.cs new file mode 100644 index 0000000000..34f98f97c2 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseMatchHeader.cs @@ -0,0 +1,43 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Screens.Multi.Screens.Match; + +namespace osu.Game.Tests.Visual +{ + [TestFixture] + public class TestCaseMatchHeader : OsuTestCase + { + public TestCaseMatchHeader() + { + Header header = new Header(); + Add(header); + + AddStep(@"set beatmap set", () => header.BeatmapSet = new BeatmapSetInfo + { + OnlineInfo = new BeatmapSetOnlineInfo + { + Covers = new BeatmapSetOnlineCovers + { + Cover = @"https://assets.ppy.sh/beatmaps/760757/covers/cover.jpg?1526944540", + }, + }, + }); + + AddStep(@"change beatmap set", () => header.BeatmapSet = new BeatmapSetInfo + { + OnlineInfo = new BeatmapSetOnlineInfo + { + Covers = new BeatmapSetOnlineCovers + { + Cover = @"https://assets.ppy.sh/beatmaps/761883/covers/cover.jpg?1525557400", + }, + }, + }); + + AddStep(@"null beatmap set", () => header.BeatmapSet = null); + } + } +} From 7edb82eb85db1bca1bbccaabca2a625242d16f3a Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 03:53:30 -0300 Subject: [PATCH 072/306] Add TestCaseMatchParticipants. --- osu.Game.Tests/Visual/TestCaseMatchInfo.cs | 2 - .../Visual/TestCaseMatchParticipants.cs | 56 +++++++++++++++++++ .../Multi/Screens/Match/Participants.cs | 3 + 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseMatchParticipants.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatchInfo.cs b/osu.Game.Tests/Visual/TestCaseMatchInfo.cs index f58bc0e30a..da5f429363 100644 --- a/osu.Game.Tests/Visual/TestCaseMatchInfo.cs +++ b/osu.Game.Tests/Visual/TestCaseMatchInfo.cs @@ -22,7 +22,6 @@ namespace osu.Game.Tests.Visual AddStep(@"set name", () => info.Name = @"Room Name?"); AddStep(@"set availability", () => info.Availability = RoomAvailability.FriendsOnly); AddStep(@"set status", () => info.Status = new RoomStatusPlaying()); - AddStep(@"set beatmap", () => info.Beatmap = new BeatmapInfo { StarDifficulty = 2.4, @@ -40,7 +39,6 @@ namespace osu.Game.Tests.Visual AddStep(@"change name", () => info.Name = @"Room Name!"); AddStep(@"change availability", () => info.Availability = RoomAvailability.InviteOnly); AddStep(@"change status", () => info.Status = new RoomStatusOpen()); - AddStep(@"change beatmap", () => info.Beatmap = new BeatmapInfo { StarDifficulty = 4.2, diff --git a/osu.Game.Tests/Visual/TestCaseMatchParticipants.cs b/osu.Game.Tests/Visual/TestCaseMatchParticipants.cs new file mode 100644 index 0000000000..d6ae07252b --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseMatchParticipants.cs @@ -0,0 +1,56 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Screens.Multi.Screens.Match; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual +{ + [TestFixture] + public class TestCaseMatchParticipants : OsuTestCase + { + public TestCaseMatchParticipants() + { + Participants participants; + Add(participants = new Participants + { + RelativeSizeAxes = Axes.Both, + }); + + AddStep(@"set max to null", () => participants.Max = null); + AddStep(@"set users", () => participants.Users = new[] + { + new User + { + Username = @"Feppla", + Id = 4271601, + Country = new Country { FlagName = @"SE" }, + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg", + IsSupporter = true, + }, + new User + { + Username = @"Xilver", + Id = 3099689, + Country = new Country { FlagName = @"IL" }, + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg", + IsSupporter = true, + }, + new User + { + Username = @"Wucki", + Id = 5287410, + Country = new Country { FlagName = @"FI" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/5287410/5cfeaa9dd41cbce038ecdc9d781396ed4b0108089170bf7f50492ef8eadeb368.jpeg", + IsSupporter = true, + }, + }); + + AddStep(@"set max", () => participants.Max = 10); + AddStep(@"clear users", () => participants.Users = new User[] { }); + AddStep(@"set max to null", () => participants.Max = null); + } + } +} diff --git a/osu.Game/Screens/Multi/Screens/Match/Participants.cs b/osu.Game/Screens/Multi/Screens/Match/Participants.cs index 11e27c0a18..182aa1e04e 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Participants.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Participants.cs @@ -25,6 +25,7 @@ namespace osu.Game.Screens.Multi.Screens.Match Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Width = 300, + OnLoadComplete = d => d.FadeInFromZero(60), }).ToList(); count.Count = value.Count(); @@ -61,6 +62,8 @@ namespace osu.Game.Screens.Multi.Screens.Match AutoSizeAxes = Axes.Y, Spacing = new Vector2(5), Padding = new MarginPadding { Top = 40 }, + LayoutDuration = 200, + LayoutEasing = Easing.OutQuint, }, }, }, From 9a7e5a3e2c26a8113a3b3182e750ca76d1306a17 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 04:16:19 -0300 Subject: [PATCH 073/306] Update TestCaseMatch. --- osu.Game.Tests/Visual/TestCaseMatch.cs | 47 +++++++++++++++++++ osu.Game.Tests/Visual/TestCaseMatchInfo.cs | 4 +- osu.Game/Screens/Multi/Screens/Match/Match.cs | 2 +- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseMatch.cs b/osu.Game.Tests/Visual/TestCaseMatch.cs index 69c1a6a0b2..bb22358425 100644 --- a/osu.Game.Tests/Visual/TestCaseMatch.cs +++ b/osu.Game.Tests/Visual/TestCaseMatch.cs @@ -89,6 +89,53 @@ namespace osu.Game.Tests.Visual Match match = new Match(room); AddStep(@"show", () => Add(match)); + AddStep(@"null beatmap", () => room.Beatmap.Value = null); + AddStep(@"change name", () => room.Name.Value = @"Two Awesome Rooms"); + AddStep(@"change status", () => room.Status.Value = new RoomStatusPlaying()); + AddStep(@"change availability", () => room.Availability.Value = RoomAvailability.FriendsOnly); + AddStep(@"change type", () => room.Type.Value = new GameTypeTag()); + AddStep(@"change beatmap", () => room.Beatmap.Value = new BeatmapInfo + { + StarDifficulty = 4.33, + Ruleset = rulesets.GetRuleset(2), + Metadata = new BeatmapMetadata + { + Title = @"Yasashisa no Riyuu", + Artist = @"ChouCho", + AuthorString = @"celerih", + }, + BeatmapSet = new BeatmapSetInfo + { + OnlineInfo = new BeatmapSetOnlineInfo + { + Covers = new BeatmapSetOnlineCovers + { + Cover = @"https://assets.ppy.sh/beatmaps/685391/covers/cover.jpg?1524597970", + }, + }, + }, + }); + + AddStep(@"null max participants", () => room.MaxParticipants.Value = null); + AddStep(@"change participants", () => room.Participants.Value = new[] + { + new User + { + Username = @"Spectator", + Id = 702598, + Country = new Country { FlagName = @"KR" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/702598/3bbf4cb8b8d2cf8b03145000a975ff27e191ab99b0920832e7dd67386280e288.jpeg", + IsSupporter = true, + }, + new User + { + Username = @"celerih", + Id = 4696296, + Country = new Country { FlagName = @"CA" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/4696296/7f8500731d0ac66d5472569d146a7be07d9460273361913f22c038867baddaef.jpeg", + }, + }); + AddStep(@"exit", match.Exit); } } diff --git a/osu.Game.Tests/Visual/TestCaseMatchInfo.cs b/osu.Game.Tests/Visual/TestCaseMatchInfo.cs index da5f429363..205da6932f 100644 --- a/osu.Game.Tests/Visual/TestCaseMatchInfo.cs +++ b/osu.Game.Tests/Visual/TestCaseMatchInfo.cs @@ -39,6 +39,8 @@ namespace osu.Game.Tests.Visual AddStep(@"change name", () => info.Name = @"Room Name!"); AddStep(@"change availability", () => info.Availability = RoomAvailability.InviteOnly); AddStep(@"change status", () => info.Status = new RoomStatusOpen()); + AddStep(@"null beatmap", () => info.Beatmap = null); + AddStep(@"change type", () => info.Type = new GameTypeTeamVersus()); AddStep(@"change beatmap", () => info.Beatmap = new BeatmapInfo { StarDifficulty = 4.2, @@ -50,8 +52,6 @@ namespace osu.Game.Tests.Visual AuthorString = @"Someone", }, }); - - AddStep(@"change type", () => info.Type = new GameTypeTeamVersus()); } } } diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index 3a2aef2ff4..525682e9c5 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -59,7 +59,7 @@ namespace osu.Game.Screens.Multi.Screens.Match beatmapBind.ValueChanged += b => { - header.BeatmapSet = b.BeatmapSet; + header.BeatmapSet = b?.BeatmapSet; info.Beatmap = b; }; From 88ac427ba67a216dff3dc654279fa95cac013df4 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Fri, 1 Jun 2018 21:06:37 +0300 Subject: [PATCH 074/306] PreviewTrack.Owner --- osu.Game/Audio/PreviewTrack.cs | 6 +++++- osu.Game/Audio/PreviewTrackManager.cs | 6 ++++-- osu.Game/Overlays/BeatmapSetOverlay.cs | 3 ++- osu.Game/Overlays/Direct/PlayButton.cs | 14 +++++++++++++- osu.Game/Overlays/DirectOverlay.cs | 3 ++- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 10dec7c394..d182df42e4 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -3,23 +3,27 @@ using System; using osu.Framework.Audio.Track; +using osu.Framework.Graphics.Containers; namespace osu.Game.Audio { public class PreviewTrack { public readonly Track Track; + public readonly OverlayContainer Owner; + private readonly Action onStart; private readonly Action onStop; public event Action Stopped; public event Action Started; - public PreviewTrack(Track track, Action onStart, Action onStop) + public PreviewTrack(Track track, Action onStart, Action onStop, OverlayContainer owner) { Track = track; this.onStart = onStart; this.onStop = onStop; + Owner = owner; } public void Start() diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 5c2656b322..59a088d954 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -7,6 +7,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.IO.Stores; using osu.Game.Beatmaps; @@ -45,11 +46,12 @@ namespace osu.Game.Audio }; } - public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo) => + public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo, OverlayContainer previewOwner) => new PreviewTrack( trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3"), onTrackStart, - onTrackStop); + onTrackStop, + previewOwner); protected override void Update() { diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 53bae54379..cccd51a621 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -127,7 +127,8 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); - previewTrackManager.CurrentTrack?.Stop(); + if (previewTrackManager.CurrentTrack?.Owner == this) + previewTrackManager.CurrentTrack?.Stop(); FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => BeatmapSet = null); } diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 677f74540b..a5c9da4fba 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -35,6 +35,18 @@ namespace osu.Game.Overlays.Direct } } + private OverlayContainer parentOverlayContainer + { + get + { + var d = Parent; + while (!(d is OverlayContainer)) + d = d.Parent; + + return (OverlayContainer)d; + } + } + private PreviewTrackManager previewTrackManager; private Color4 hoverColour; @@ -95,7 +107,7 @@ namespace osu.Game.Overlays.Direct Task.Run(() => { loading = true; - return Preview = previewTrackManager.Get(beatmapSet); + return Preview = previewTrackManager.Get(beatmapSet, parentOverlayContainer); }) .ContinueWith(t => { diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index c69dc57342..72de8ebc84 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -302,7 +302,8 @@ namespace osu.Game.Overlays protected override void PopOut() { - previewTrackManager.CurrentTrack?.Stop(); + if (previewTrackManager.CurrentTrack?.Owner == this) + previewTrackManager.CurrentTrack?.Stop(); base.PopOut(); } From 556673266427af65322f62e4893dd224df330165 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Fri, 1 Jun 2018 21:36:30 +0300 Subject: [PATCH 075/306] Get rid of PreviewTrackManager.onTrackStart and PreviewTrackManager.onTrackStop delegates --- osu.Game/Audio/PreviewTrack.cs | 9 +----- osu.Game/Audio/PreviewTrackManager.cs | 43 ++++++++++++++------------- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index d182df42e4..1250d4864e 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -12,30 +12,23 @@ namespace osu.Game.Audio public readonly Track Track; public readonly OverlayContainer Owner; - private readonly Action onStart; - private readonly Action onStop; - public event Action Stopped; public event Action Started; - public PreviewTrack(Track track, Action onStart, Action onStop, OverlayContainer owner) + public PreviewTrack(Track track, OverlayContainer owner) { Track = track; - this.onStart = onStart; - this.onStop = onStop; Owner = owner; } public void Start() { - onStart?.Invoke(this); Track.Restart(); Started?.Invoke(); } public void Stop() { - onStop?.Invoke(); Track.Stop(); Stopped?.Invoke(); } diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 59a088d954..4189468b77 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; @@ -15,9 +14,7 @@ namespace osu.Game.Audio { public class PreviewTrackManager : Component { - private Action onTrackStart; - private Action onTrackStop; - + private AudioManager audio; private TrackManager trackManager; private BindableDouble muteBindable; @@ -27,32 +24,36 @@ namespace osu.Game.Audio private void load(AudioManager audio, FrameworkConfigManager config) { trackManager = new TrackManager(new OnlineStore()); - muteBindable = new BindableDouble(); + this.audio = audio; audio.AddItem(trackManager); - config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); - onTrackStart = track => - { - CurrentTrack?.Stop(); - audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); - CurrentTrack = track; - }; - onTrackStop = () => - { - audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); - CurrentTrack = null; - }; + config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); } - public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo, OverlayContainer previewOwner) => - new PreviewTrack( + public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo, OverlayContainer previewOwner) + { + var previewTrack = new PreviewTrack( trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3"), - onTrackStart, - onTrackStop, previewOwner); + previewTrack.Started += () => + { + CurrentTrack?.Stop(); + CurrentTrack = previewTrack; + audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); + }; + + previewTrack.Stopped += () => + { + CurrentTrack = null; + audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); + }; + + return previewTrack; + } + protected override void Update() { if (CurrentTrack?.Track.HasCompleted ?? false) From 97b473ef30ce254cadc75c76bc1630bc1c2186e3 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Fri, 1 Jun 2018 16:23:11 -0300 Subject: [PATCH 076/306] Expose tabs and hide beatmap select button in Header. --- osu.Game/Screens/Multi/Screens/Match/Header.cs | 12 +++++++++--- osu.Game/Screens/Multi/Screens/Match/Match.cs | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Multi/Screens/Match/Header.cs b/osu.Game/Screens/Multi/Screens/Match/Header.cs index 1d414e338c..7985ff5fcf 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Header.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Header.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -26,18 +27,21 @@ namespace osu.Game.Screens.Multi.Screens.Match private readonly Box tabStrip; private readonly UpdateableBeatmapSetCover cover; - public readonly OsuClickableContainer BeatmapButton; + public readonly PageTabControl Tabs; public BeatmapSetInfo BeatmapSet { set { cover.BeatmapSet = value; } } + public Action OnWantsSelectBeatmap; + public Header() { RelativeSizeAxes = Axes.X; Height = HEIGHT; + BeatmapSelectButton beatmapButton; Children = new Drawable[] { cover = new UpdateableBeatmapSetCover @@ -70,12 +74,12 @@ namespace osu.Game.Screens.Multi.Screens.Match RelativeSizeAxes = Axes.Y, Width = 200, Padding = new MarginPadding { Vertical = 5 }, - Child = BeatmapButton = new BeatmapSelectButton + Child = beatmapButton = new BeatmapSelectButton { RelativeSizeAxes = Axes.Both, }, }, - new PageTabControl + Tabs = new PageTabControl { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, @@ -84,6 +88,8 @@ namespace osu.Game.Screens.Multi.Screens.Match }, }, }; + + beatmapButton.Action = () => OnWantsSelectBeatmap?.Invoke(); } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index 525682e9c5..47fe7b9145 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Multi.Screens.Match }, }; - header.BeatmapButton.Action = () => Push(new MatchSongSelect()); + header.OnWantsSelectBeatmap = () => Push(new MatchSongSelect()); nameBind.ValueChanged += n => info.Name = n; statusBind.ValueChanged += s => info.Status = s; availabilityBind.ValueChanged += a => info.Availability = a; From 507305742013cacec3dc54feeeb630fd44971dc2 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Fri, 1 Jun 2018 16:34:03 -0300 Subject: [PATCH 077/306] Cleanup. --- osu.Game/Screens/Multi/Screens/Match/Header.cs | 2 +- osu.Game/Screens/Multi/Screens/Match/Participants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/Screens/Match/Header.cs b/osu.Game/Screens/Multi/Screens/Match/Header.cs index 7985ff5fcf..19e9dc4ad4 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Header.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Header.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Multi.Screens.Match public BeatmapSetInfo BeatmapSet { - set { cover.BeatmapSet = value; } + set => cover.BeatmapSet = value; } public Action OnWantsSelectBeatmap; diff --git a/osu.Game/Screens/Multi/Screens/Match/Participants.cs b/osu.Game/Screens/Multi/Screens/Match/Participants.cs index 182aa1e04e..9fa90f8752 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Participants.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Participants.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Multi.Screens.Match public int? Max { - set { count.Max = value; } + set => count.Max = value; } public Participants() From da8b1f996fb127f8b92a34ab90c5c085a7a2a597 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Fri, 1 Jun 2018 17:16:35 -0300 Subject: [PATCH 078/306] Override Type in Match. --- osu.Game/Screens/Multi/Screens/Match/Match.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index 47fe7b9145..3c6f141bd3 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -27,6 +27,7 @@ namespace osu.Game.Screens.Multi.Screens.Match protected override Container TransitionContent => participants; + public override string Type => "room"; public override string Title => room.Name.Value; public Match(Room room) From 330ce1904122d4169104ae500ce5338e3ba584e5 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Fri, 1 Jun 2018 23:36:25 +0300 Subject: [PATCH 079/306] Make PreviewTrack a component and use LoadComponentAsync --- osu.Game/Audio/PreviewTrack.cs | 19 +++++++++++++++---- osu.Game/Audio/PreviewTrackManager.cs | 23 +++++++++-------------- osu.Game/Overlays/Direct/PlayButton.cs | 13 ++++++------- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 1250d4864e..d8898dfede 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -2,25 +2,36 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using osu.Framework.Allocation; using osu.Framework.Audio.Track; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; namespace osu.Game.Audio { - public class PreviewTrack + public class PreviewTrack : Component { - public readonly Track Track; + public Track Track { get; private set; } public readonly OverlayContainer Owner; + private readonly BeatmapSetInfo beatmapSetInfo; + public event Action Stopped; public event Action Started; - public PreviewTrack(Track track, OverlayContainer owner) + public PreviewTrack(BeatmapSetInfo beatmapSetInfo, OverlayContainer owner) { - Track = track; + this.beatmapSetInfo = beatmapSetInfo; Owner = owner; } + [BackgroundDependencyLoader] + private void load(PreviewTrackManager previewTrackManager) + { + Track = previewTrackManager.Get(this, beatmapSetInfo); + } + public void Start() { Track.Restart(); diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 4189468b77..a3da930af0 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -6,7 +6,6 @@ using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.IO.Stores; using osu.Game.Beatmaps; @@ -32,12 +31,16 @@ namespace osu.Game.Audio config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); } - public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo, OverlayContainer previewOwner) + protected override void Update() { - var previewTrack = new PreviewTrack( - trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3"), - previewOwner); + if (CurrentTrack?.Track.HasCompleted ?? false) + CurrentTrack.Stop(); + base.Update(); + } + + public Track Get(PreviewTrack previewTrack, BeatmapSetInfo beatmapSetInfo) + { previewTrack.Started += () => { CurrentTrack?.Stop(); @@ -51,15 +54,7 @@ namespace osu.Game.Audio audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); }; - return previewTrack; - } - - protected override void Update() - { - if (CurrentTrack?.Track.HasCompleted ?? false) - CurrentTrack.Stop(); - - base.Update(); + return trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3"); } } } diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index a5c9da4fba..36d1170380 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; @@ -104,18 +103,18 @@ namespace osu.Game.Overlays.Direct { if (Preview == null) { - Task.Run(() => - { - loading = true; - return Preview = previewTrackManager.Get(beatmapSet, parentOverlayContainer); - }) - .ContinueWith(t => + loading = true; + + LoadComponentAsync( + Preview = new PreviewTrack(beatmapSet, parentOverlayContainer), + t => { Preview.Started += () => Playing.Value = true; Preview.Stopped += () => Playing.Value = false; Preview.Start(); loading = false; }); + return true; } From 70120aa14c1018f1ecb18ecc5ed50852673f7fa3 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Sat, 2 Jun 2018 12:28:16 +0300 Subject: [PATCH 080/306] Remove unused previewTrackManager variable --- osu.Game/Overlays/Direct/PlayButton.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 36d1170380..92d1acbaa4 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -46,8 +46,6 @@ namespace osu.Game.Overlays.Direct } } - private PreviewTrackManager previewTrackManager; - private Color4 hoverColour; private readonly SpriteIcon icon; private readonly LoadingAnimation loadingAnimation; @@ -94,7 +92,6 @@ namespace osu.Game.Overlays.Direct private void load(OsuColour colour, PreviewTrackManager previewTrackManager) { hoverColour = colour.Yellow; - this.previewTrackManager = previewTrackManager; } protected override bool OnClick(InputState state) From 5bb6757cbdbc24cc130cb2cbea643353032c7ae6 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Sat, 2 Jun 2018 13:03:17 +0300 Subject: [PATCH 081/306] Remove unused previewTrackManager parameter --- osu.Game/Overlays/Direct/PlayButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 92d1acbaa4..dc8042a137 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Direct } [BackgroundDependencyLoader] - private void load(OsuColour colour, PreviewTrackManager previewTrackManager) + private void load(OsuColour colour) { hoverColour = colour.Yellow; } From 9b69e1825da552b934c539ee6b499fc2feb0864a Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Sat, 2 Jun 2018 22:06:45 +0300 Subject: [PATCH 082/306] Make PreviewTrack.owner private --- osu.Game/Audio/PreviewTrack.cs | 12 +++++++++--- osu.Game/Overlays/BeatmapSetOverlay.cs | 3 +-- osu.Game/Overlays/DirectOverlay.cs | 3 +-- osu.Game/Overlays/UserProfileOverlay.cs | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index d8898dfede..cfc47497d0 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -13,7 +13,7 @@ namespace osu.Game.Audio public class PreviewTrack : Component { public Track Track { get; private set; } - public readonly OverlayContainer Owner; + private readonly OverlayContainer owner; private readonly BeatmapSetInfo beatmapSetInfo; @@ -23,7 +23,7 @@ namespace osu.Game.Audio public PreviewTrack(BeatmapSetInfo beatmapSetInfo, OverlayContainer owner) { this.beatmapSetInfo = beatmapSetInfo; - Owner = owner; + this.owner = owner; } [BackgroundDependencyLoader] @@ -38,8 +38,14 @@ namespace osu.Game.Audio Started?.Invoke(); } - public void Stop() + /// + /// Stop preview playback + /// + /// An which is probably the owner of this + public void Stop(OverlayContainer source = null) { + if (source != null && owner != source) + return; Track.Stop(); Stopped?.Invoke(); } diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index cccd51a621..234d91b9e6 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -127,8 +127,7 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); - if (previewTrackManager.CurrentTrack?.Owner == this) - previewTrackManager.CurrentTrack?.Stop(); + previewTrackManager.CurrentTrack?.Stop(this); FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => BeatmapSet = null); } diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 72de8ebc84..406554eb5e 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -302,8 +302,7 @@ namespace osu.Game.Overlays protected override void PopOut() { - if (previewTrackManager.CurrentTrack?.Owner == this) - previewTrackManager.CurrentTrack?.Stop(); + previewTrackManager.CurrentTrack?.Stop(this); base.PopOut(); } diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 04a93dea23..6a8dd30890 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -73,7 +73,7 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); - previewTrackManager.CurrentTrack?.Stop(); + previewTrackManager.CurrentTrack?.Stop(this); FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out); } From 2ccffb9ac452b443c9cb09ccf44f158cd04031ee Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 28 May 2018 01:10:41 +0900 Subject: [PATCH 083/306] Add difficulty calculation mod types --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 94 ++++++++++++++++++++++++- osu.Game.Rulesets.Osu/OsuRuleset.cs | 44 +++++++++++- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 44 +++++++++++- osu.Game/Rulesets/Mods/ModType.cs | 1 + 4 files changed, 175 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 02ecb3afda..08fecacbab 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -96,6 +96,20 @@ namespace osu.Game.Rulesets.Mania yield return new ManiaModSuddenDeath(); } + private static readonly Mod[] key_mods = + { + new MultiMod(), + new ManiaModKey1(), + new ManiaModKey2(), + new ManiaModKey3(), + new ManiaModKey4(), + new ManiaModKey5(), + new ManiaModKey6(), + new ManiaModKey7(), + new ManiaModKey8(), + new ManiaModKey9(), + }; + public override IEnumerable GetModsFor(ModType type) { switch (type) @@ -114,7 +128,6 @@ namespace osu.Game.Rulesets.Mania }, }, }; - case ModType.DifficultyIncrease: return new Mod[] { @@ -145,7 +158,6 @@ namespace osu.Game.Rulesets.Mania }, new ManiaModFlashlight(), }; - case ModType.Special: return new Mod[] { @@ -176,7 +188,85 @@ namespace osu.Game.Rulesets.Mania }, }, }; + case ModType.DifficultyCalculation: + var mods = new List(); + foreach (var keyMod in key_mods) + { + mods.AddRange(new[] + { + keyMod, + new MultiMod + { + Mods = new[] + { + keyMod, + new ManiaModDoubleTime(), + } + }, + new MultiMod + { + Mods = new[] + { + keyMod, + new ManiaModHalfTime(), + } + }, + new MultiMod + { + Mods = new[] + { + keyMod, + new ManiaModEasy(), + } + }, + new MultiMod + { + Mods = new[] + { + keyMod, + new ManiaModHardRock(), + } + }, + new MultiMod + { + Mods = new[] + { + keyMod, + new ManiaModEasy(), + new ManiaModDoubleTime(), + } + }, + new MultiMod + { + Mods = new[] + { + keyMod, + new ManiaModEasy(), + new ManiaModHalfTime(), + } + }, + new MultiMod + { + Mods = new[] + { + keyMod, + new ManiaModHardRock(), + new ManiaModDoubleTime(), + } + }, + new MultiMod + { + Mods = new[] + { + keyMod, + new ManiaModHardRock(), + new ManiaModHalfTime(), + } + }, + }); + } + return mods.ToArray(); default: return new Mod[] { }; } diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index c455bb2af6..31eff5493b 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -102,7 +102,6 @@ namespace osu.Game.Rulesets.Osu }, }, }; - case ModType.DifficultyIncrease: return new Mod[] { @@ -126,7 +125,6 @@ namespace osu.Game.Rulesets.Osu new OsuModHidden(), new OsuModFlashlight(), }; - case ModType.Special: return new Mod[] { @@ -143,7 +141,47 @@ namespace osu.Game.Rulesets.Osu }, new OsuModTarget(), }; - + case ModType.DifficultyCalculation: + return new Mod[] + { + new MultiMod(), + new OsuModDoubleTime(), + new OsuModHalfTime(), + new OsuModEasy(), + new OsuModHardRock(), + new MultiMod + { + Mods = new Mod[] + { + new OsuModEasy(), + new OsuModDoubleTime(), + } + }, + new MultiMod + { + Mods = new Mod[] + { + new OsuModEasy(), + new OsuModHalfTime(), + } + }, + new MultiMod + { + Mods = new Mod[] + { + new OsuModHardRock(), + new OsuModDoubleTime(), + } + }, + new MultiMod + { + Mods = new Mod[] + { + new OsuModHardRock(), + new OsuModHalfTime(), + } + }, + }; default: return new Mod[] { }; } diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index abaa8db597..a249646285 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -93,7 +93,6 @@ namespace osu.Game.Rulesets.Taiko }, }, }; - case ModType.DifficultyIncrease: return new Mod[] { @@ -117,7 +116,6 @@ namespace osu.Game.Rulesets.Taiko new TaikoModHidden(), new TaikoModFlashlight(), }; - case ModType.Special: return new Mod[] { @@ -133,7 +131,47 @@ namespace osu.Game.Rulesets.Taiko }, }, }; - + case ModType.DifficultyCalculation: + return new Mod[] + { + new MultiMod(), + new TaikoModDoubleTime(), + new TaikoModHalfTime(), + new TaikoModEasy(), + new TaikoModHardRock(), + new MultiMod + { + Mods = new Mod[] + { + new TaikoModEasy(), + new TaikoModDoubleTime(), + } + }, + new MultiMod + { + Mods = new Mod[] + { + new TaikoModEasy(), + new TaikoModHalfTime(), + } + }, + new MultiMod + { + Mods = new Mod[] + { + new TaikoModHardRock(), + new TaikoModDoubleTime(), + } + }, + new MultiMod + { + Mods = new Mod[] + { + new TaikoModHardRock(), + new TaikoModHalfTime(), + } + }, + }; default: return new Mod[] { }; } diff --git a/osu.Game/Rulesets/Mods/ModType.cs b/osu.Game/Rulesets/Mods/ModType.cs index 1941724879..5619899c48 100644 --- a/osu.Game/Rulesets/Mods/ModType.cs +++ b/osu.Game/Rulesets/Mods/ModType.cs @@ -8,5 +8,6 @@ namespace osu.Game.Rulesets.Mods DifficultyReduction, DifficultyIncrease, Special, + DifficultyCalculation } } From 9f27dd848a8503350ab127cc4d87e02412be2018 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Sun, 3 Jun 2018 15:29:56 +0900 Subject: [PATCH 084/306] HyperDashModifier >= 1 --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 38 +++++++++++++++-------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 6c3624aa0a..2ae1f7eb7a 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -18,6 +18,7 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; using OpenTK; using OpenTK.Graphics; +using System.Diagnostics; namespace osu.Game.Rulesets.Catch.UI { @@ -243,14 +244,21 @@ namespace osu.Game.Rulesets.Catch.UI double positionDifference = target.X * CatchPlayfield.BASE_WIDTH - catcherPosition; double velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0); - HyperDashing = true; - hyperDashModifier = Math.Abs(velocity); - hyperDashDirection = Math.Sign(velocity); - hyperDashTargetPosition = target.X; + // An edge case + if (Math.Abs(velocity) <= 1) + { + HyperDashModifier = 1; + } + else + { + hyperDashDirection = Math.Sign(velocity); + hyperDashTargetPosition = target.X; + HyperDashModifier = Math.Abs(velocity); + } } else { - HyperDashing = false; + HyperDashModifier = 1; } return validCatch; @@ -259,23 +267,27 @@ namespace osu.Game.Rulesets.Catch.UI private double hyperDashModifier = 1; private int hyperDashDirection; private float hyperDashTargetPosition; - private bool hyperDashing; /// /// Whether we are hypderdashing or not. /// - protected bool HyperDashing + public bool HyperDashing => hyperDashModifier != 1; + + /// + /// The modifier multiplied to the catcher speed. + /// It is always not less than 1 and it is greater than 1 if and only if the catcher is hyper-dashing. + /// + protected double HyperDashModifier { - get => hyperDashing; + get => hyperDashModifier; set { - if (hyperDashing == value) return; - - hyperDashing = value; + Trace.Assert(value >= 1); + if (hyperDashModifier == value) return; + hyperDashModifier = value; if (!HyperDashing) { - hyperDashModifier = 1; hyperDashDirection = 0; } @@ -355,7 +367,7 @@ namespace osu.Game.Rulesets.Catch.UI hyperDashDirection < 0 && hyperDashTargetPosition > X) { X = hyperDashTargetPosition; - HyperDashing = false; + HyperDashModifier = 1; } } From 25d3f0ead18bceec90c477fd11a3ed5ea1908e0b Mon Sep 17 00:00:00 2001 From: ekrctb Date: Sun, 3 Jun 2018 15:31:51 +0900 Subject: [PATCH 085/306] Revert TestCaseCatcherArea --- osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs | 8 ++++++-- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs index 9ec39189f8..f239290ed4 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs @@ -16,6 +16,7 @@ namespace osu.Game.Rulesets.Catch.Tests public class TestCaseCatcherArea : OsuTestCase { private RulesetInfo catchRuleset; + private TestCatcherArea catcherArea; public override IReadOnlyList RequiredTypes => new[] { @@ -25,6 +26,7 @@ namespace osu.Game.Rulesets.Catch.Tests public TestCaseCatcherArea() { AddSliderStep("CircleSize", 0, 8, 5, createCatcher); + AddToggleStep("Hyperdash", t => catcherArea.ToggleHyperDash(t)); } private void createCatcher(float size) @@ -32,10 +34,10 @@ namespace osu.Game.Rulesets.Catch.Tests Child = new CatchInputManager(catchRuleset) { RelativeSizeAxes = Axes.Both, - Child = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size }) + Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size }) { Anchor = Anchor.CentreLeft, - Origin = Anchor.TopLeft + Origin = Anchor.BottomLeft }, }; } @@ -52,6 +54,8 @@ namespace osu.Game.Rulesets.Catch.Tests : base(beatmapDifficulty) { } + + public void ToggleHyperDash(bool status) => MovableCatcher.HyperDashModifier = status ? 2 : 1; } } } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 2ae1f7eb7a..d7d4691ad0 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -277,7 +277,7 @@ namespace osu.Game.Rulesets.Catch.UI /// The modifier multiplied to the catcher speed. /// It is always not less than 1 and it is greater than 1 if and only if the catcher is hyper-dashing. /// - protected double HyperDashModifier + public double HyperDashModifier { get => hyperDashModifier; set From a5c5d11da20febe6f6eeb1772a6955818c0247f3 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Sun, 3 Jun 2018 15:42:27 +0900 Subject: [PATCH 086/306] I think I should learn how to use git --- osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs index f239290ed4..5119260c53 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.Tests Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size }) { Anchor = Anchor.CentreLeft, - Origin = Anchor.BottomLeft + Origin = Anchor.TopLeft }, }; } From 8274623ad6f691d62bdf4eee28808e3afb9588bb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Jun 2018 14:07:50 +0900 Subject: [PATCH 087/306] Cleanup multi mod constructions --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 36 ++----------- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 69 +++++-------------------- osu.Game.Rulesets.Osu/OsuRuleset.cs | 36 ++----------- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 36 ++----------- osu.Game/Rulesets/Mods/MultiMod.cs | 12 ++++- 5 files changed, 37 insertions(+), 152 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 2325a8cad9..6a9f12e2f2 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -82,36 +82,15 @@ namespace osu.Game.Rulesets.Catch { new CatchModEasy(), new CatchModNoFail(), - new MultiMod - { - Mods = new Mod[] - { - new CatchModHalfTime(), - new CatchModDaycore(), - }, - }, + new MultiMod(new CatchModHalfTime(), new CatchModDaycore()) }; case ModType.DifficultyIncrease: return new Mod[] { new CatchModHardRock(), - new MultiMod - { - Mods = new Mod[] - { - new CatchModSuddenDeath(), - new CatchModPerfect(), - }, - }, - new MultiMod - { - Mods = new Mod[] - { - new CatchModDoubleTime(), - new CatchModNightcore(), - }, - }, + new MultiMod(new CatchModSuddenDeath(), new CatchModPerfect()), + new MultiMod(new CatchModDoubleTime(), new CatchModNightcore()), new CatchModHidden(), new CatchModFlashlight(), }; @@ -122,14 +101,7 @@ namespace osu.Game.Rulesets.Catch new CatchModRelax(), null, null, - new MultiMod - { - Mods = new Mod[] - { - new CatchModAutoplay(), - new ModCinema(), - }, - }, + new MultiMod(new CatchModAutoplay(), new ModCinema()), }; default: diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 08fecacbab..84cf9bc1d3 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -119,74 +119,33 @@ namespace osu.Game.Rulesets.Mania { new ManiaModEasy(), new ManiaModNoFail(), - new MultiMod - { - Mods = new Mod[] - { - new ManiaModHalfTime(), - new ManiaModDaycore(), - }, - }, + new MultiMod(new ManiaModHalfTime(), new ManiaModDaycore()), }; case ModType.DifficultyIncrease: return new Mod[] { new ManiaModHardRock(), - new MultiMod - { - Mods = new Mod[] - { - new ManiaModSuddenDeath(), - new ManiaModPerfect(), - }, - }, - new MultiMod - { - Mods = new Mod[] - { - new ManiaModDoubleTime(), - new ManiaModNightcore(), - }, - }, - new MultiMod - { - Mods = new Mod[] - { - new ManiaModFadeIn(), - new ManiaModHidden(), - } - }, + new MultiMod(new ManiaModSuddenDeath(), new ManiaModPerfect()), + new MultiMod(new ManiaModDoubleTime(), new ManiaModNightcore()), + new MultiMod(new ManiaModFadeIn(), new ManiaModHidden()), new ManiaModFlashlight(), }; case ModType.Special: return new Mod[] { - new MultiMod - { - Mods = new Mod[] - { - new ManiaModKey4(), - new ManiaModKey5(), - new ManiaModKey6(), - new ManiaModKey7(), - new ManiaModKey8(), - new ManiaModKey9(), - new ManiaModKey1(), - new ManiaModKey2(), - new ManiaModKey3(), - }, - }, + new MultiMod(new ManiaModKey4(), + new ManiaModKey5(), + new ManiaModKey6(), + new ManiaModKey7(), + new ManiaModKey8(), + new ManiaModKey9(), + new ManiaModKey1(), + new ManiaModKey2(), + new ManiaModKey3()), new ManiaModRandom(), new ManiaModDualStages(), new ManiaModMirror(), - new MultiMod - { - Mods = new Mod[] - { - new ManiaModAutoplay(), - new ModCinema(), - }, - }, + new MultiMod(new ManiaModAutoplay(), new ModCinema()), }; case ModType.DifficultyCalculation: var mods = new List(); diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 31eff5493b..29cdb6cfb2 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -93,35 +93,14 @@ namespace osu.Game.Rulesets.Osu { new OsuModEasy(), new OsuModNoFail(), - new MultiMod - { - Mods = new Mod[] - { - new OsuModHalfTime(), - new OsuModDaycore(), - }, - }, + new MultiMod(new OsuModHalfTime(), new OsuModDaycore()), }; case ModType.DifficultyIncrease: return new Mod[] { new OsuModHardRock(), - new MultiMod - { - Mods = new Mod[] - { - new OsuModSuddenDeath(), - new OsuModPerfect(), - }, - }, - new MultiMod - { - Mods = new Mod[] - { - new OsuModDoubleTime(), - new OsuModNightcore(), - }, - }, + new MultiMod(new OsuModSuddenDeath(), new OsuModPerfect()), + new MultiMod(new OsuModDoubleTime(), new OsuModNightcore()), new OsuModHidden(), new OsuModFlashlight(), }; @@ -131,14 +110,7 @@ namespace osu.Game.Rulesets.Osu new OsuModRelax(), new OsuModAutopilot(), new OsuModSpunOut(), - new MultiMod - { - Mods = new Mod[] - { - new OsuModAutoplay(), - new ModCinema(), - }, - }, + new MultiMod(new OsuModAutoplay(), new ModCinema()), new OsuModTarget(), }; case ModType.DifficultyCalculation: diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index a249646285..c8621066a8 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -84,35 +84,14 @@ namespace osu.Game.Rulesets.Taiko { new TaikoModEasy(), new TaikoModNoFail(), - new MultiMod - { - Mods = new Mod[] - { - new TaikoModHalfTime(), - new TaikoModDaycore(), - }, - }, + new MultiMod(new TaikoModHalfTime(), new TaikoModDaycore()), }; case ModType.DifficultyIncrease: return new Mod[] { new TaikoModHardRock(), - new MultiMod - { - Mods = new Mod[] - { - new TaikoModSuddenDeath(), - new TaikoModPerfect(), - }, - }, - new MultiMod - { - Mods = new Mod[] - { - new TaikoModDoubleTime(), - new TaikoModNightcore(), - }, - }, + new MultiMod(new TaikoModSuddenDeath(), new TaikoModPerfect()), + new MultiMod(new TaikoModDoubleTime(), new TaikoModDaycore()), new TaikoModHidden(), new TaikoModFlashlight(), }; @@ -122,14 +101,7 @@ namespace osu.Game.Rulesets.Taiko new TaikoModRelax(), null, null, - new MultiMod - { - Mods = new Mod[] - { - new TaikoModAutoplay(), - new ModCinema(), - }, - }, + new MultiMod(new TaikoModAutoplay(), new ModCinema()), }; case ModType.DifficultyCalculation: return new Mod[] diff --git a/osu.Game/Rulesets/Mods/MultiMod.cs b/osu.Game/Rulesets/Mods/MultiMod.cs index 3c90a4eedb..b65773e93f 100644 --- a/osu.Game/Rulesets/Mods/MultiMod.cs +++ b/osu.Game/Rulesets/Mods/MultiMod.cs @@ -1,6 +1,9 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using System.Linq; + namespace osu.Game.Rulesets.Mods { public class MultiMod : Mod @@ -10,6 +13,13 @@ namespace osu.Game.Rulesets.Mods public override string Description => string.Empty; public override double ScoreMultiplier => 0; - public Mod[] Mods; + public Mod[] Mods { get; } + + public MultiMod(params Mod[] mods) + { + Mods = mods; + } + + public override Type[] IncompatibleMods => Mods.SelectMany(m => m.IncompatibleMods).ToArray(); } } From e19ca0c12011b86ca9cfb5093a04fe29e85172c2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Jun 2018 14:08:02 +0900 Subject: [PATCH 088/306] Add nomod mod type --- osu.Game/Rulesets/Mods/NoModMod.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 osu.Game/Rulesets/Mods/NoModMod.cs diff --git a/osu.Game/Rulesets/Mods/NoModMod.cs b/osu.Game/Rulesets/Mods/NoModMod.cs new file mode 100644 index 0000000000..dcab3538da --- /dev/null +++ b/osu.Game/Rulesets/Mods/NoModMod.cs @@ -0,0 +1,15 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Rulesets.Mods +{ + /// + /// Indicates a type of mod that doesn't do anything. + /// + public sealed class NoModMod : Mod + { + public override string Name => "No Mod"; + public override string ShortenedName => "NM"; + public override double ScoreMultiplier => 1; + } +} From 35678237591c8ff22cb479c9f0c32130471e16cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jun 2018 14:18:38 +0900 Subject: [PATCH 089/306] Reverse order of exposed objects in HitObjectContainer Closes #2740. --- osu.Game.Rulesets.Mania/UI/Column.cs | 9 +++++++-- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 4 +--- osu.Game/Rulesets/Mods/ModHidden.cs | 3 +-- osu.Game/Rulesets/UI/HitObjectContainer.cs | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 28cd1b6b39..ff1b8e506a 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -265,8 +265,13 @@ namespace osu.Game.Rulesets.Mania.UI if (action != Action) return false; - var hitObject = HitObjects.Objects.LastOrDefault(h => h.HitObject.StartTime > Time.Current) ?? HitObjects.Objects.FirstOrDefault(); - hitObject?.PlaySamples(); + var nextObject = + HitObjects.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ?? + // fallback to non-alive objects to find next off-screen object + HitObjects.Objects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ?? + HitObjects.Objects.LastOrDefault(); + + nextObject?.PlaySamples(); return true; } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index b63f85623e..f2d5631e93 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -64,9 +64,7 @@ namespace osu.Game.Rulesets.Osu.UI public override void PostProcess() { - connectionLayer.HitObjects = HitObjects.Objects - .Select(d => d.HitObject) - .OrderBy(h => h.StartTime).OfType(); + connectionLayer.HitObjects = HitObjects.Objects.Select(d => d.HitObject).OfType(); } private void onJudgement(DrawableHitObject judgedObject, Judgement judgement) diff --git a/osu.Game/Rulesets/Mods/ModHidden.cs b/osu.Game/Rulesets/Mods/ModHidden.cs index 45da628ce8..9b09f0bd6d 100644 --- a/osu.Game/Rulesets/Mods/ModHidden.cs +++ b/osu.Game/Rulesets/Mods/ModHidden.cs @@ -27,8 +27,7 @@ namespace osu.Game.Rulesets.Mods public virtual void ApplyToDrawableHitObjects(IEnumerable drawables) { - // todo: fix ordering of objects so we don't have to do this (#2740). - foreach (var d in drawables.Reverse().Skip(IncreaseFirstObjectVisibility ? 1 : 0)) + foreach (var d in drawables.Skip(IncreaseFirstObjectVisibility ? 1 : 0)) d.ApplyCustomUpdateState += ApplyHiddenState; } diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index 1b6841c9bd..af18d98561 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -11,8 +11,8 @@ namespace osu.Game.Rulesets.UI { public class HitObjectContainer : CompositeDrawable { - public virtual IEnumerable Objects => InternalChildren.Cast(); - public virtual IEnumerable AliveObjects => AliveInternalChildren.Cast(); + public IEnumerable Objects => InternalChildren.Cast().OrderBy(h => h.HitObject.StartTime); + public IEnumerable AliveObjects => AliveInternalChildren.Cast().OrderBy(h => h.HitObject.StartTime); public virtual void Add(DrawableHitObject hitObject) => AddInternal(hitObject); public virtual bool Remove(DrawableHitObject hitObject) => RemoveInternal(hitObject); From 83ff47ec80ced52260d528ec0eccbf442896e704 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Jun 2018 16:20:17 +0900 Subject: [PATCH 090/306] Rewrite difficulty mod combinations --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 3 - .../Difficulty/ManiaDifficultyCalculator.cs | 18 +++ osu.Game.Rulesets.Mania/ManiaRuleset.cs | 79 --------- osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs | 15 ++ .../Difficulty/OsuDifficultyCalculator.cs | 9 ++ osu.Game.Rulesets.Osu/OsuRuleset.cs | 41 ----- .../Difficulty/TaikoDifficultyCalculator.cs | 9 ++ osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 41 ----- ...DifficultyAdjustmentModCombinationsTest.cs | 152 ++++++++++++++++++ .../Difficulty/DifficultyCalculator.cs | 39 +++++ osu.Game/Rulesets/Mods/ModType.cs | 3 +- 11 files changed, 243 insertions(+), 166 deletions(-) create mode 100644 osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 6a9f12e2f2..d0180f1791 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -84,7 +84,6 @@ namespace osu.Game.Rulesets.Catch new CatchModNoFail(), new MultiMod(new CatchModHalfTime(), new CatchModDaycore()) }; - case ModType.DifficultyIncrease: return new Mod[] { @@ -94,7 +93,6 @@ namespace osu.Game.Rulesets.Catch new CatchModHidden(), new CatchModFlashlight(), }; - case ModType.Special: return new Mod[] { @@ -103,7 +101,6 @@ namespace osu.Game.Rulesets.Catch null, new MultiMod(new CatchModAutoplay(), new ModCinema()), }; - default: return new Mod[] { }; } diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 2517839355..ca2002b7c9 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mania.Beatmaps; +using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; @@ -141,5 +142,22 @@ namespace osu.Game.Rulesets.Mania.Difficulty return difficulty; } + + protected override Mod[] DifficultyAdjustmentMods => new Mod[] + { + new ManiaModDoubleTime(), + new ManiaModHalfTime(), + new ManiaModEasy(), + new ManiaModHardRock(), + new ManiaModKey1(), + new ManiaModKey2(), + new ManiaModKey3(), + new ManiaModKey4(), + new ManiaModKey5(), + new ManiaModKey6(), + new ManiaModKey7(), + new ManiaModKey8(), + new ManiaModKey9(), + }; } } diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 84cf9bc1d3..f6934484a2 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -147,85 +147,6 @@ namespace osu.Game.Rulesets.Mania new ManiaModMirror(), new MultiMod(new ManiaModAutoplay(), new ModCinema()), }; - case ModType.DifficultyCalculation: - var mods = new List(); - foreach (var keyMod in key_mods) - { - mods.AddRange(new[] - { - keyMod, - new MultiMod - { - Mods = new[] - { - keyMod, - new ManiaModDoubleTime(), - } - }, - new MultiMod - { - Mods = new[] - { - keyMod, - new ManiaModHalfTime(), - } - }, - new MultiMod - { - Mods = new[] - { - keyMod, - new ManiaModEasy(), - } - }, - new MultiMod - { - Mods = new[] - { - keyMod, - new ManiaModHardRock(), - } - }, - new MultiMod - { - Mods = new[] - { - keyMod, - new ManiaModEasy(), - new ManiaModDoubleTime(), - } - }, - new MultiMod - { - Mods = new[] - { - keyMod, - new ManiaModEasy(), - new ManiaModHalfTime(), - } - }, - new MultiMod - { - Mods = new[] - { - keyMod, - new ManiaModHardRock(), - new ManiaModDoubleTime(), - } - }, - new MultiMod - { - Mods = new[] - { - keyMod, - new ManiaModHardRock(), - new ManiaModHalfTime(), - } - }, - }); - } - - return mods.ToArray(); default: return new Mod[] { }; } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs index e02db68a28..6bfe295c3d 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs @@ -1,6 +1,8 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mods; @@ -24,5 +26,18 @@ namespace osu.Game.Rulesets.Mania.Mods mbc.TargetColumns = KeyCount; } + + public override Type[] IncompatibleMods => new[] + { + typeof(ManiaModKey1), + typeof(ManiaModKey2), + typeof(ManiaModKey3), + typeof(ManiaModKey4), + typeof(ManiaModKey5), + typeof(ManiaModKey6), + typeof(ManiaModKey7), + typeof(ManiaModKey8), + typeof(ManiaModKey9), + }.Except(new[] { GetType() }).ToArray(); } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 3ed072a275..94d2afbf45 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -8,6 +8,7 @@ using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Skills; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Difficulty @@ -71,5 +72,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty return starRating; } + + protected override Mod[] DifficultyAdjustmentMods => new Mod[] + { + new OsuModDoubleTime(), + new OsuModHalfTime(), + new OsuModEasy(), + new OsuModHardRock(), + }; } } diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 29cdb6cfb2..b920e889ce 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -113,47 +113,6 @@ namespace osu.Game.Rulesets.Osu new MultiMod(new OsuModAutoplay(), new ModCinema()), new OsuModTarget(), }; - case ModType.DifficultyCalculation: - return new Mod[] - { - new MultiMod(), - new OsuModDoubleTime(), - new OsuModHalfTime(), - new OsuModEasy(), - new OsuModHardRock(), - new MultiMod - { - Mods = new Mod[] - { - new OsuModEasy(), - new OsuModDoubleTime(), - } - }, - new MultiMod - { - Mods = new Mod[] - { - new OsuModEasy(), - new OsuModHalfTime(), - } - }, - new MultiMod - { - Mods = new Mod[] - { - new OsuModHardRock(), - new OsuModDoubleTime(), - } - }, - new MultiMod - { - Mods = new Mod[] - { - new OsuModHardRock(), - new OsuModHalfTime(), - } - }, - }; default: return new Mod[] { }; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 57e1e65064..bb666eb528 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Taiko.Mods; using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty @@ -62,6 +63,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty return starRating; } + protected override Mod[] DifficultyAdjustmentMods => new Mod[] + { + new TaikoModDoubleTime(), + new TaikoModHalfTime(), + new TaikoModEasy(), + new TaikoModHardRock(), + }; + private bool calculateStrainValues() { // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index c8621066a8..ccf28a2f12 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -103,47 +103,6 @@ namespace osu.Game.Rulesets.Taiko null, new MultiMod(new TaikoModAutoplay(), new ModCinema()), }; - case ModType.DifficultyCalculation: - return new Mod[] - { - new MultiMod(), - new TaikoModDoubleTime(), - new TaikoModHalfTime(), - new TaikoModEasy(), - new TaikoModHardRock(), - new MultiMod - { - Mods = new Mod[] - { - new TaikoModEasy(), - new TaikoModDoubleTime(), - } - }, - new MultiMod - { - Mods = new Mod[] - { - new TaikoModEasy(), - new TaikoModHalfTime(), - } - }, - new MultiMod - { - Mods = new Mod[] - { - new TaikoModHardRock(), - new TaikoModDoubleTime(), - } - }, - new MultiMod - { - Mods = new Mod[] - { - new TaikoModHardRock(), - new TaikoModHalfTime(), - } - }, - }; default: return new Mod[] { }; } diff --git a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs new file mode 100644 index 0000000000..fd697ba3d3 --- /dev/null +++ b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs @@ -0,0 +1,152 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using NUnit.Framework; +using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Tests.NonVisual +{ + [TestFixture] + public class DifficultyAdjustmentModCombinationsTest + { + [Test] + public void TestNoMods() + { + var combinations = new TestDifficultyCalculator().CreateDifficultyAdjustmentModCombinations(); + + Assert.AreEqual(1, combinations.Length); + Assert.IsTrue(combinations[0] is NoModMod); + } + + [Test] + public void TestSingleMod() + { + var combinations = new TestDifficultyCalculator(new ModA()).CreateDifficultyAdjustmentModCombinations(); + + Assert.AreEqual(2, combinations.Length); + Assert.IsTrue(combinations[0] is NoModMod); + Assert.IsTrue(combinations[1] is ModA); + } + + [Test] + public void TestDoubleMod() + { + var combinations = new TestDifficultyCalculator(new ModA(), new ModB()).CreateDifficultyAdjustmentModCombinations(); + + Assert.AreEqual(4, combinations.Length); + Assert.IsTrue(combinations[0] is NoModMod); + Assert.IsTrue(combinations[1] is ModA); + Assert.IsTrue(combinations[2] is MultiMod); + Assert.IsTrue(combinations[3] is ModB); + + Assert.IsTrue(((MultiMod)combinations[2]).Mods[0] is ModA); + Assert.IsTrue(((MultiMod)combinations[2]).Mods[1] is ModB); + } + + [Test] + public void TestIncompatibleMods() + { + var combinations = new TestDifficultyCalculator(new ModA(), new ModIncompatibleWithA()).CreateDifficultyAdjustmentModCombinations(); + + Assert.AreEqual(3, combinations.Length); + Assert.IsTrue(combinations[0] is NoModMod); + Assert.IsTrue(combinations[1] is ModA); + Assert.IsTrue(combinations[2] is ModIncompatibleWithA); + } + + [Test] + public void TestDoubleIncompatibleMods() + { + var combinations = new TestDifficultyCalculator(new ModA(), new ModB(), new ModIncompatibleWithA(), new ModIncompatibleWithAAndB()).CreateDifficultyAdjustmentModCombinations(); + + Assert.AreEqual(8, combinations.Length); + Assert.IsTrue(combinations[0] is NoModMod); + Assert.IsTrue(combinations[1] is ModA); + Assert.IsTrue(combinations[2] is MultiMod); + Assert.IsTrue(combinations[3] is ModB); + Assert.IsTrue(combinations[4] is MultiMod); + Assert.IsTrue(combinations[5] is ModIncompatibleWithA); + Assert.IsTrue(combinations[6] is MultiMod); + Assert.IsTrue(combinations[7] is ModIncompatibleWithAAndB); + + Assert.IsTrue(((MultiMod)combinations[2]).Mods[0] is ModA); + Assert.IsTrue(((MultiMod)combinations[2]).Mods[1] is ModB); + Assert.IsTrue(((MultiMod)combinations[4]).Mods[0] is ModB); + Assert.IsTrue(((MultiMod)combinations[4]).Mods[1] is ModIncompatibleWithA); + Assert.IsTrue(((MultiMod)combinations[6]).Mods[0] is ModIncompatibleWithA); + Assert.IsTrue(((MultiMod)combinations[6]).Mods[1] is ModIncompatibleWithAAndB); + } + + [Test] + public void TestIncompatibleThroughBaseType() + { + var combinations = new TestDifficultyCalculator(new ModAofA(), new ModIncompatibleWithAofA()).CreateDifficultyAdjustmentModCombinations(); + + Assert.AreEqual(3, combinations.Length); + Assert.IsTrue(combinations[0] is NoModMod); + Assert.IsTrue(combinations[1] is ModAofA); + Assert.IsTrue(combinations[2] is ModIncompatibleWithAofA); + } + + private class ModA : Mod + { + public override string Name => nameof(ModA); + public override string ShortenedName => nameof(ModA); + public override double ScoreMultiplier => 1; + + public override Type[] IncompatibleMods => new[] { typeof(ModIncompatibleWithA), typeof(ModIncompatibleWithAAndB) }; + } + + private class ModB : Mod + { + public override string Name => nameof(ModB); + public override string ShortenedName => nameof(ModB); + public override double ScoreMultiplier => 1; + + public override Type[] IncompatibleMods => new[] { typeof(ModIncompatibleWithAAndB) }; + } + + private class ModIncompatibleWithA : Mod + { + public override string Name => $"Incompatible With {nameof(ModA)}"; + public override string ShortenedName => $"Incompatible With {nameof(ModA)}"; + public override double ScoreMultiplier => 1; + + public override Type[] IncompatibleMods => new[] { typeof(ModA) }; + } + + private class ModAofA : ModA + { + } + + private class ModIncompatibleWithAofA : ModIncompatibleWithA + { + // Incompatible through base type + } + + private class ModIncompatibleWithAAndB : Mod + { + public override string Name => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}"; + public override string ShortenedName => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}"; + public override double ScoreMultiplier => 1; + + public override Type[] IncompatibleMods => new[] { typeof(ModA), typeof(ModB) }; + } + + private class TestDifficultyCalculator : DifficultyCalculator + { + public TestDifficultyCalculator(params Mod[] mods) + : base(null) + { + DifficultyAdjustmentMods = mods; + } + + public override double Calculate(Dictionary categoryDifficulty = null) => throw new NotImplementedException(); + + protected override Mod[] DifficultyAdjustmentMods { get; } + } + } +} diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index 070bc7ddb0..31cd9dc6f5 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Extensions.IEnumerableExtensions; @@ -36,6 +37,44 @@ namespace osu.Game.Rulesets.Difficulty { } + /// + /// Creates all combinations which adjust the difficulty. + /// + public Mod[] CreateDifficultyAdjustmentModCombinations() + { + return createDifficultyAdjustmentModCombinations(Enumerable.Empty(), DifficultyAdjustmentMods).ToArray(); + + IEnumerable createDifficultyAdjustmentModCombinations(IEnumerable currentSet, Mod[] adjustmentSet, int currentSetCount = 0, int adjustmentSetStart = 0) + { + // Initial-case: Empty current set + if (currentSetCount == 0) + yield return new NoModMod(); + + if (currentSetCount == 1) + yield return currentSet.Single(); + + if (currentSetCount > 1) + yield return new MultiMod(currentSet.ToArray()); + + // Apply mods in the adjustment set recursively. Using the entire adjustment set would result in duplicate multi-mod mod + // combinations in further recursions, so a moving subset is used to eliminate this effect + for (int i = adjustmentSetStart; i < adjustmentSet.Length; i++) + { + var adjustmentMod = adjustmentSet[i]; + if (currentSet.Any(c => c.IncompatibleMods.Any(m => m.IsInstanceOfType(adjustmentMod)))) + continue; + + foreach (var combo in createDifficultyAdjustmentModCombinations(currentSet.Append(adjustmentMod), adjustmentSet, currentSetCount + 1, i + 1)) + yield return combo; + } + } + } + + /// + /// Retrieves all s which adjust the difficulty. + /// + protected virtual Mod[] DifficultyAdjustmentMods => Array.Empty(); + public abstract double Calculate(Dictionary categoryDifficulty = null); } } diff --git a/osu.Game/Rulesets/Mods/ModType.cs b/osu.Game/Rulesets/Mods/ModType.cs index 5619899c48..913ba23701 100644 --- a/osu.Game/Rulesets/Mods/ModType.cs +++ b/osu.Game/Rulesets/Mods/ModType.cs @@ -7,7 +7,6 @@ namespace osu.Game.Rulesets.Mods { DifficultyReduction, DifficultyIncrease, - Special, - DifficultyCalculation + Special } } From dd75cd973be81bc6ae960b36fed441f2b0e92891 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jun 2018 01:13:35 +0900 Subject: [PATCH 091/306] Show UI mouse cursor when hovering volume meters during gameplay Also adds a hover animation. --- osu.Game/Overlays/Volume/VolumeMeter.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 64106967f4..04a04bc86e 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.MathUtils; using osu.Game.Graphics; @@ -189,5 +190,18 @@ namespace osu.Game.Overlays.Volume } public bool OnReleased(GlobalAction action) => false; + + private const float transition_length = 500; + + protected override bool OnHover(InputState state) + { + this.ScaleTo(1.04f, transition_length, Easing.OutExpo); + return true; + } + + protected override void OnHoverLost(InputState state) + { + this.ScaleTo(1f, transition_length, Easing.OutExpo); + } } } From 17ba129e616764855f61d980e6396527fde05783 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jun 2018 01:14:43 +0900 Subject: [PATCH 092/306] Make volume controls stay open when hovered Closes #2743. --- osu.Game/Overlays/VolumeOverlay.cs | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index f922c507f7..5a3d51c00a 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Input.Bindings; @@ -86,16 +87,10 @@ namespace osu.Game.Overlays { base.LoadComplete(); - volumeMeterMaster.Bindable.ValueChanged += _ => settingChanged(); - volumeMeterEffect.Bindable.ValueChanged += _ => settingChanged(); - volumeMeterMusic.Bindable.ValueChanged += _ => settingChanged(); - muteButton.Current.ValueChanged += _ => settingChanged(); - } - - private void settingChanged() - { - Show(); - schedulePopOut(); + volumeMeterMaster.Bindable.ValueChanged += _ => Show(); + volumeMeterEffect.Bindable.ValueChanged += _ => Show(); + volumeMeterMusic.Bindable.ValueChanged += _ => Show(); + muteButton.Current.ValueChanged += _ => Show(); } public bool Adjust(GlobalAction action) @@ -140,10 +135,22 @@ namespace osu.Game.Overlays this.FadeOut(100); } + protected override bool OnMouseMove(InputState state) + { + // keep the scheduled event correctly timed as long as we have movement. + schedulePopOut(); + return base.OnMouseMove(state); + } + private void schedulePopOut() { popOutDelegate?.Cancel(); - this.Delay(1000).Schedule(Hide, out popOutDelegate); + this.Delay(1000).Schedule(() => + { + // only actually hide if the mouse isn't within our bounds. + if (!ScreenSpaceDrawQuad.Contains(GetContainingInputManager().CurrentState.Mouse.Position)) + Hide(); + }, out popOutDelegate); } } } From 5e9a1961cb0f34897cb27106b7c8e8076621a8bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jun 2018 11:33:39 +0900 Subject: [PATCH 093/306] Greatly increase the playfield scroll speed adjust step It was so small previously that I believe many people didn't even realise it was working. --- osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index 6f86d20295..231892bdd9 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// /// The step increase/decrease of the span of time visible by the length of the scrolling axes. /// - private const double time_span_step = 50; + private const double time_span_step = 500; /// /// The span of time that is visible by the length of the scrolling axes. @@ -88,10 +88,10 @@ namespace osu.Game.Rulesets.UI.Scrolling switch (args.Key) { case Key.Minus: - this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange + time_span_step, 200, Easing.OutQuint); + this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange + time_span_step, 600, Easing.OutQuint); break; case Key.Plus: - this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange - time_span_step, 200, Easing.OutQuint); + this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange - time_span_step, 600, Easing.OutQuint); break; } } From 9b10cc4e0c7596d55abc44cf092a6f940141e531 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Jun 2018 19:53:47 +0900 Subject: [PATCH 094/306] Remove invertability of ManiaStage --- .../TestCaseManiaPlayfield.cs | 4 ---- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 9 --------- osu.Game.Rulesets.Mania/UI/ManiaStage.cs | 15 --------------- 3 files changed, 28 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseManiaPlayfield.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseManiaPlayfield.cs index b064d82a23..2ae6bc346a 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseManiaPlayfield.cs @@ -131,8 +131,6 @@ namespace osu.Game.Rulesets.Mania.Tests Origin = Anchor.Centre, }); - playfield.Inverted.Value = inverted; - return playfield; } @@ -158,8 +156,6 @@ namespace osu.Game.Rulesets.Mania.Tests Clock = new FramedClock(rateAdjustClock) }); - playfield.Inverted.Value = inverted; - for (double t = start_time; t <= start_time + duration; t += 100) { var note1 = new Note { StartTime = t, Column = 0 }; diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 4b936fc7f9..153d4698e1 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -8,7 +8,6 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Configuration; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Objects.Drawables; @@ -19,11 +18,6 @@ namespace osu.Game.Rulesets.Mania.UI { public class ManiaPlayfield : ScrollingPlayfield { - /// - /// Whether this playfield should be inverted. This flips everything inside the playfield. - /// - public readonly Bindable Inverted = new Bindable(true); - public List Columns => stages.SelectMany(x => x.Columns).ToList(); private readonly List stages = new List(); @@ -36,8 +30,6 @@ namespace osu.Game.Rulesets.Mania.UI if (stageDefinitions.Count <= 0) throw new ArgumentException("Can't have zero or fewer stages."); - Inverted.Value = true; - GridContainer playfieldGrid; InternalChild = playfieldGrid = new GridContainer { @@ -52,7 +44,6 @@ namespace osu.Game.Rulesets.Mania.UI { var newStage = new ManiaStage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction); newStage.VisibleTimeRange.BindTo(VisibleTimeRange); - newStage.Inverted.BindTo(Inverted); playfieldGrid.Content[0][i] = newStage; diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs index cb93613c7d..41af5fef38 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -28,11 +27,6 @@ namespace osu.Game.Rulesets.Mania.UI { public const float HIT_TARGET_POSITION = 50; - /// - /// Whether this playfield should be inverted. This flips everything inside the playfield. - /// - public readonly Bindable Inverted = new Bindable(true); - public IReadOnlyList Columns => columnFlow.Children; private readonly FillFlowContainer columnFlow; @@ -139,15 +133,6 @@ namespace osu.Game.Rulesets.Mania.UI AddColumn(column); } - - Inverted.ValueChanged += invertedChanged; - Inverted.TriggerChange(); - } - - private void invertedChanged(bool newValue) - { - Scale = new Vector2(1, newValue ? -1 : 1); - Judgements.Scale = Scale; } public void AddColumn(Column c) From 2ed978deaa1b32e98ff5616ebd1f2a2988fbbfb5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Jun 2018 19:55:57 +0900 Subject: [PATCH 095/306] Remove TestCaseManiaHitObjects and TestCaseManiaPlayfield --- .../TestCaseManiaHitObjects.cs | 106 ---------- .../TestCaseManiaPlayfield.cs | 181 ------------------ 2 files changed, 287 deletions(-) delete mode 100644 osu.Game.Rulesets.Mania.Tests/TestCaseManiaHitObjects.cs delete mode 100644 osu.Game.Rulesets.Mania.Tests/TestCaseManiaPlayfield.cs diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseManiaHitObjects.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseManiaHitObjects.cs deleted file mode 100644 index a4109722d4..0000000000 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseManiaHitObjects.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Mania.Objects; -using osu.Game.Rulesets.Mania.Objects.Drawables; -using osu.Game.Tests.Visual; -using OpenTK; -using OpenTK.Graphics; - -namespace osu.Game.Rulesets.Mania.Tests -{ - [TestFixture] - public class TestCaseManiaHitObjects : OsuTestCase - { - public TestCaseManiaHitObjects() - { - Note note1 = new Note(); - Note note2 = new Note(); - HoldNote holdNote = new HoldNote { StartTime = 1000 }; - - note1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - note2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - holdNote.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - - Add(new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - // Imagine that the containers containing the drawable notes are the "columns" - Children = new Drawable[] - { - new Container - { - Name = "Normal note column", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Y, - Width = 50, - Children = new[] - { - new Container - { - Name = "Timing section", - RelativeSizeAxes = Axes.Both, - RelativeChildSize = new Vector2(1, 10000), - Children = new[] - { - new DrawableNote(note1, ManiaAction.Key1) - { - Y = 5000, - LifetimeStart = double.MinValue, - LifetimeEnd = double.MaxValue, - AccentColour = Color4.Red - }, - new DrawableNote(note2, ManiaAction.Key1) - { - Y = 6000, - LifetimeStart = double.MinValue, - LifetimeEnd = double.MaxValue, - AccentColour = Color4.Red - } - } - } - } - }, - new Container - { - Name = "Hold note column", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Y, - Width = 50, - Children = new[] - { - new Container - { - Name = "Timing section", - RelativeSizeAxes = Axes.Both, - RelativeChildSize = new Vector2(1, 10000), - Children = new[] - { - new DrawableHoldNote(holdNote, ManiaAction.Key1) - { - Y = 5000, - Height = 1000, - LifetimeStart = double.MinValue, - LifetimeEnd = double.MaxValue, - AccentColour = Color4.Red, - } - } - } - } - } - } - }); - } - } -} diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseManiaPlayfield.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseManiaPlayfield.cs deleted file mode 100644 index 2ae6bc346a..0000000000 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseManiaPlayfield.cs +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using System.Linq; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Timing; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Configuration; -using osu.Game.Rulesets.Mania.Beatmaps; -using osu.Game.Rulesets.Mania.Configuration; -using osu.Game.Rulesets.Mania.Judgements; -using osu.Game.Rulesets.Mania.Objects; -using osu.Game.Rulesets.Mania.Objects.Drawables; -using osu.Game.Rulesets.Mania.UI; -using osu.Game.Rulesets.Scoring; -using osu.Game.Tests.Visual; - -namespace osu.Game.Rulesets.Mania.Tests -{ - [TestFixture] - public class TestCaseManiaPlayfield : OsuTestCase - { - private const double start_time = 500; - private const double duration = 500; - - protected override double TimePerAction => 200; - - private RulesetInfo maniaRuleset; - - public TestCaseManiaPlayfield() - { - var rng = new Random(1337); - - AddStep("1 column", () => createPlayfield(1)); - AddStep("4 columns", () => createPlayfield(4)); - AddStep("5 columns", () => createPlayfield(5)); - AddStep("8 columns", () => createPlayfield(8)); - AddStep("4 + 4 columns", () => - { - var stages = new List - { - new StageDefinition { Columns = 4 }, - new StageDefinition { Columns = 4 }, - }; - createPlayfield(stages); - }); - - AddStep("2 + 4 + 2 columns", () => - { - var stages = new List - { - new StageDefinition { Columns = 2 }, - new StageDefinition { Columns = 4 }, - new StageDefinition { Columns = 2 }, - }; - createPlayfield(stages); - }); - - AddStep("1 + 8 + 1 columns", () => - { - var stages = new List - { - new StageDefinition { Columns = 1 }, - new StageDefinition { Columns = 8 }, - new StageDefinition { Columns = 1 }, - }; - createPlayfield(stages); - }); - - AddStep("Reversed", () => createPlayfield(4, true)); - - AddStep("Notes with input", () => createPlayfieldWithNotes()); - AddStep("Notes with input (reversed)", () => createPlayfieldWithNotes(true)); - AddStep("Notes with gravity", () => createPlayfieldWithNotes()); - AddStep("Notes with gravity (reversed)", () => createPlayfieldWithNotes(true)); - - AddStep("Hit explosion", () => - { - var playfield = createPlayfield(4); - - int col = rng.Next(0, 4); - - var note = new Note { Column = col }; - note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - - var drawableNote = new DrawableNote(note, ManiaAction.Key1) - { - AccentColour = playfield.Columns.ElementAt(col).AccentColour - }; - - playfield.OnJudgement(drawableNote, new ManiaJudgement { Result = HitResult.Perfect }); - playfield.Columns[col].OnJudgement(drawableNote, new ManiaJudgement { Result = HitResult.Perfect }); - }); - } - - [BackgroundDependencyLoader] - private void load(RulesetStore rulesets, SettingsStore settings) - { - maniaRuleset = rulesets.GetRuleset(3); - - Dependencies.Cache(new ManiaConfigManager(settings, maniaRuleset, 4)); - } - - private ManiaPlayfield createPlayfield(int cols, bool inverted = false) - { - var stages = new List - { - new StageDefinition { Columns = cols }, - }; - - return createPlayfield(stages, inverted); - } - - private ManiaPlayfield createPlayfield(List stages, bool inverted = false) - { - Clear(); - - var inputManager = new ManiaInputManager(maniaRuleset, stages.Sum(g => g.Columns)) { RelativeSizeAxes = Axes.Both }; - Add(inputManager); - - ManiaPlayfield playfield; - - inputManager.Add(playfield = new ManiaPlayfield(stages) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }); - - return playfield; - } - - private void createPlayfieldWithNotes(bool inverted = false) - { - Clear(); - - var rateAdjustClock = new StopwatchClock(true) { Rate = 1 }; - - var inputManager = new ManiaInputManager(maniaRuleset, 4) { RelativeSizeAxes = Axes.Both }; - Add(inputManager); - - ManiaPlayfield playfield; - var stages = new List - { - new StageDefinition { Columns = 4 }, - }; - - inputManager.Add(playfield = new ManiaPlayfield(stages) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Clock = new FramedClock(rateAdjustClock) - }); - - for (double t = start_time; t <= start_time + duration; t += 100) - { - var note1 = new Note { StartTime = t, Column = 0 }; - var note2 = new Note { StartTime = t, Column = 3 }; - - note1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - note2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - - playfield.Add(new DrawableNote(note1, ManiaAction.Key1)); - playfield.Add(new DrawableNote(note2, ManiaAction.Key4)); - } - - var holdNote1 = new HoldNote { StartTime = start_time, Duration = duration, Column = 1 }; - var holdNote2 = new HoldNote { StartTime = start_time, Duration = duration, Column = 2 }; - - holdNote1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - holdNote2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - - playfield.Add(new DrawableHoldNote(holdNote1, ManiaAction.Key2)); - playfield.Add(new DrawableHoldNote(holdNote2, ManiaAction.Key3)); - } - } -} From 55a5dfa9b6492b1f38aaf6eb608fd48de7a49c8c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Jun 2018 20:24:33 +0900 Subject: [PATCH 096/306] Add column testcase --- .../ManiaInputTestCase.cs | 45 +++++++++++++++++++ .../TestCaseColumn.cs | 39 ++++++++++++++++ osu.Game/Rulesets/UI/RulesetInputManager.cs | 5 ++- 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Mania.Tests/ManiaInputTestCase.cs create mode 100644 osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaInputTestCase.cs b/osu.Game.Rulesets.Mania.Tests/ManiaInputTestCase.cs new file mode 100644 index 0000000000..75c8fc7e79 --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/ManiaInputTestCase.cs @@ -0,0 +1,45 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Bindings; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Mania.Tests +{ + public abstract class ManiaInputTestCase : OsuTestCase + { + private readonly Container content; + protected override Container Content => content ?? base.Content; + + protected ManiaInputTestCase(int keys) + { + base.Content.Add(content = new LocalInputManager(keys)); + } + + private class LocalInputManager : ManiaInputManager + { + public LocalInputManager(int variant) + : base(new ManiaRuleset().RulesetInfo, variant) + { + } + + protected override RulesetKeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) + => new LocalKeyBindingContainer(ruleset, variant, unique); + + private class LocalKeyBindingContainer : RulesetKeyBindingContainer + { + public LocalKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) + : base(ruleset, variant, unique) + { + } + + protected override void ReloadMappings() + { + KeyBindings = DefaultKeyBindings; + } + } + } + } +} diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs new file mode 100644 index 0000000000..8960ecb2fd --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs @@ -0,0 +1,39 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Allocation; +using osu.Game.Rulesets.Mania.UI; +using OpenTK.Graphics; + +namespace osu.Game.Rulesets.Mania.Tests +{ + [TestFixture] + public class TestCaseColumn : ManiaInputTestCase + { + public TestCaseColumn() + : base(1) + { + } + + [BackgroundDependencyLoader] + private void load() + { + Child = new ManiaInputManager(new ManiaRuleset().RulesetInfo, 1) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Height = 0.85f, + Child = new Column + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AccentColour = Color4.OrangeRed, + Action = ManiaAction.Special1 + } + }; + } + } +} diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index b35616985a..21bd61903c 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.UI protected RulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) { - InternalChild = KeyBindingContainer = new RulesetKeyBindingContainer(ruleset, variant, unique); + InternalChild = KeyBindingContainer = CreateKeyBindingContainer(ruleset, variant, unique); } #region Action mapping (for replays) @@ -247,6 +247,9 @@ namespace osu.Game.Rulesets.UI } #endregion + + protected virtual RulesetKeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) + => new RulesetKeyBindingContainer(ruleset, variant, unique); } /// From 3033294df1a583097d64b0b35f954bba13d3b2b3 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Thu, 7 Jun 2018 14:30:11 +0300 Subject: [PATCH 097/306] Stop Preview on BeatmapSet change --- osu.Game/Overlays/Direct/PlayButton.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index dc8042a137..607d6d218f 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -29,6 +29,7 @@ namespace osu.Game.Overlays.Direct if (value == beatmapSet) return; beatmapSet = value; + Preview.Stop(parentOverlayContainer); Playing.Value = false; Preview = null; } From 45dca5646181e3fb1c1c027cf41e171405471443 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Jun 2018 20:40:27 +0900 Subject: [PATCH 098/306] Cleanup testcase --- osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs index 8960ecb2fd..0f0258d395 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs @@ -20,19 +20,13 @@ namespace osu.Game.Rulesets.Mania.Tests [BackgroundDependencyLoader] private void load() { - Child = new ManiaInputManager(new ManiaRuleset().RulesetInfo, 1) + Child = new Column { Anchor = Anchor.Centre, Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, Height = 0.85f, - Child = new Column - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AccentColour = Color4.OrangeRed, - Action = ManiaAction.Special1 - } + AccentColour = Color4.OrangeRed, + Action = ManiaAction.Special1 }; } } From ab6699b1fb599c7d8d6da4f30afb7bd986c17494 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Thu, 7 Jun 2018 14:40:41 +0300 Subject: [PATCH 099/306] Stop DirectOverlay preview on search update --- osu.Game/Overlays/DirectOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 406554eb5e..fb1be8e05e 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -273,6 +273,8 @@ namespace osu.Game.Overlays if (Header.Tabs.Current.Value == DirectTab.Search && (Filter.Search.Text == string.Empty || currentQuery == string.Empty)) return; + previewTrackManager.CurrentTrack?.Stop(this); + getSetsRequest = new SearchBeatmapSetsRequest(currentQuery.Value ?? string.Empty, ((FilterControl)Filter).Ruleset.Value, Filter.DisplayStyleControl.Dropdown.Current.Value, From 4af8baefc15beaf8782f24484b063d168949822f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Jun 2018 20:49:06 +0900 Subject: [PATCH 100/306] Make the column background follow the scroll direction --- .../TestCaseColumn.cs | 35 +++++- osu.Game.Rulesets.Mania/UI/Column.cs | 32 ++--- .../UI/Components/ColumnBackground.cs | 109 ++++++++++++++++++ 3 files changed, 147 insertions(+), 29 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs index 0f0258d395..b72dd808f4 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs @@ -1,10 +1,16 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.Mania.UI.Components; +using osu.Game.Rulesets.UI.Scrolling; +using OpenTK; using OpenTK.Graphics; namespace osu.Game.Rulesets.Mania.Tests @@ -12,22 +18,41 @@ namespace osu.Game.Rulesets.Mania.Tests [TestFixture] public class TestCaseColumn : ManiaInputTestCase { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(Column), + typeof(ColumnBackground) + }; + public TestCaseColumn() - : base(1) + : base(2) { } [BackgroundDependencyLoader] private void load() { - Child = new Column + Child = new FillFlowContainer { + RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Height = 0.85f, - AccentColour = Color4.OrangeRed, - Action = ManiaAction.Special1 + Spacing = new Vector2(20, 0), + Children = new[] + { + createColumn(ScrollingDirection.Up, ManiaAction.Key1), + createColumn(ScrollingDirection.Down, ManiaAction.Key2) + } }; } + + private Column createColumn(ScrollingDirection direction, ManiaAction action) => new Column(direction) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Height = 0.85f, + AccentColour = Color4.OrangeRed, + Action = action + }; } } diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index dee113c82f..b00508eb63 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -14,6 +14,7 @@ using System; using System.Linq; using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.UI @@ -32,8 +33,7 @@ namespace osu.Game.Rulesets.Mania.UI public ManiaAction Action; - private readonly Box background; - private readonly Box backgroundOverlay; + private readonly ColumnBackground background; private readonly Container hitTargetBar; private readonly Container keyIcon; @@ -43,8 +43,8 @@ namespace osu.Game.Rulesets.Mania.UI protected override Container Content => content; private readonly Container content; - public Column() - : base(ScrollingDirection.Up) + public Column(ScrollingDirection direction = ScrollingDirection.Up) + : base(direction) { RelativeSizeAxes = Axes.Y; Width = column_width; @@ -54,22 +54,7 @@ namespace osu.Game.Rulesets.Mania.UI InternalChildren = new Drawable[] { - background = new Box - { - Name = "Background", - RelativeSizeAxes = Axes.Both, - Alpha = 0.3f - }, - backgroundOverlay = new Box - { - Name = "Background Gradient Overlay", - RelativeSizeAxes = Axes.Both, - Height = 0.5f, - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Blending = BlendingMode.Additive, - Alpha = 0 - }, + background = new ColumnBackground(direction) { RelativeSizeAxes = Axes.Both }, new Container { Name = "Hit target + hit objects", @@ -192,8 +177,7 @@ namespace osu.Game.Rulesets.Mania.UI return; accentColour = value; - background.Colour = accentColour; - backgroundOverlay.Colour = ColourInfo.GradientVertical(accentColour.Opacity(0.6f), accentColour.Opacity(0)); + background.AccentColour = value; hitTargetBar.EdgeEffect = new EdgeEffectParameters { @@ -235,7 +219,7 @@ namespace osu.Game.Rulesets.Mania.UI { if (action == Action) { - backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint); + background.IsLit = true; keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint); } @@ -246,7 +230,7 @@ namespace osu.Game.Rulesets.Mania.UI { if (action == Action) { - backgroundOverlay.FadeTo(0, 250, Easing.OutQuint); + background.IsLit = false; keyIcon.ScaleTo(1f, 125, Easing.OutQuint); } diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs new file mode 100644 index 0000000000..917d254e3a --- /dev/null +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs @@ -0,0 +1,109 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Rulesets.UI.Scrolling; +using OpenTK.Graphics; + +namespace osu.Game.Rulesets.Mania.UI.Components +{ + public class ColumnBackground : CompositeDrawable, IHasAccentColour + { + private readonly ScrollingDirection direction; + + public ColumnBackground(ScrollingDirection direction) + { + this.direction = direction; + } + + private Box background; + private Box backgroundOverlay; + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new[] + { + background = new Box + { + Name = "Background", + RelativeSizeAxes = Axes.Both, + Alpha = 0.3f + }, + backgroundOverlay = new Box + { + Name = "Background Gradient Overlay", + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, + Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, + Blending = BlendingMode.Additive, + Alpha = 0 + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + updateColours(); + } + + private Color4 accentColour; + + public Color4 AccentColour + { + get => accentColour; + set + { + if (accentColour == value) + return; + accentColour = value; + + updateColours(); + } + } + + private void updateColours() + { + if (!IsLoaded) + return; + + background.Colour = AccentColour; + + var brightPoint = AccentColour.Opacity(0.6f); + var dimPoint = AccentColour.Opacity(0); + + backgroundOverlay.Colour = ColourInfo.GradientVertical( + direction == ScrollingDirection.Up ? brightPoint : dimPoint, + direction == ScrollingDirection.Up ? dimPoint : brightPoint); + } + + private bool isLit; + + /// + /// Whether the column lighting should be visible. + /// + public bool IsLit + { + set + { + if (isLit == value) + return; + isLit = value; + + if (isLit) + backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint); + else + backgroundOverlay.FadeTo(0, 250, Easing.OutQuint); + } + } + + } +} From 1fdbd2047151f42fb1f59fdb15fabfd423bf78e4 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Thu, 7 Jun 2018 14:50:21 +0300 Subject: [PATCH 101/306] Nullref quickfix in PlayButton --- osu.Game/Overlays/Direct/PlayButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 607d6d218f..94c3cb748f 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Direct if (value == beatmapSet) return; beatmapSet = value; - Preview.Stop(parentOverlayContainer); + Preview?.Stop(parentOverlayContainer); Playing.Value = false; Preview = null; } From d49758d1497a137d486037d4c78d330b2084540e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Jun 2018 20:59:04 +0900 Subject: [PATCH 102/306] Make background handle its own lit state --- osu.Game.Rulesets.Mania/UI/Column.cs | 21 ++++++++---- .../UI/Components/ColumnBackground.cs | 32 ++++++++----------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index b00508eb63..e0ecc9d708 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -31,7 +31,20 @@ namespace osu.Game.Rulesets.Mania.UI private const float column_width = 45; private const float special_column_width = 70; - public ManiaAction Action; + private ManiaAction action; + + public ManiaAction Action + { + get => action; + set + { + if (action == value) + return; + action = value; + + background.Action = value; + } + } private readonly ColumnBackground background; private readonly Container hitTargetBar; @@ -218,10 +231,7 @@ namespace osu.Game.Rulesets.Mania.UI private bool onPressed(ManiaAction action) { if (action == Action) - { - background.IsLit = true; keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint); - } return false; } @@ -229,10 +239,7 @@ namespace osu.Game.Rulesets.Mania.UI private bool onReleased(ManiaAction action) { if (action == Action) - { - background.IsLit = false; keyIcon.ScaleTo(1f, 125, Easing.OutQuint); - } return false; } diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs index 917d254e3a..eeef5afcb0 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs @@ -7,14 +7,17 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; using osu.Game.Graphics; using osu.Game.Rulesets.UI.Scrolling; using OpenTK.Graphics; namespace osu.Game.Rulesets.Mania.UI.Components { - public class ColumnBackground : CompositeDrawable, IHasAccentColour + public class ColumnBackground : CompositeDrawable, IKeyBindingHandler, IHasAccentColour { + public ManiaAction Action; + private readonly ScrollingDirection direction; public ColumnBackground(ScrollingDirection direction) @@ -85,25 +88,18 @@ namespace osu.Game.Rulesets.Mania.UI.Components direction == ScrollingDirection.Up ? dimPoint : brightPoint); } - private bool isLit; - - /// - /// Whether the column lighting should be visible. - /// - public bool IsLit + public bool OnPressed(ManiaAction action) { - set - { - if (isLit == value) - return; - isLit = value; - - if (isLit) - backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint); - else - backgroundOverlay.FadeTo(0, 250, Easing.OutQuint); - } + if (action == Action) + backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint); + return false; } + public bool OnReleased(ManiaAction action) + { + if (action == Action) + backgroundOverlay.FadeTo(0, 250, Easing.OutQuint); + return false; + } } } From 11f067d7d6bb3e03fc6666237eddcc76be79c009 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Jun 2018 21:13:29 +0900 Subject: [PATCH 103/306] Fix background input --- osu.Game.Rulesets.Mania/UI/Column.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index e0ecc9d708..e1eb11f5e5 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -65,9 +65,12 @@ namespace osu.Game.Rulesets.Mania.UI Masking = true; CornerRadius = 5; - InternalChildren = new Drawable[] + background = new ColumnBackground(direction) { RelativeSizeAxes = Axes.Both }; + + InternalChildren = new[] { - background = new ColumnBackground(direction) { RelativeSizeAxes = Axes.Both }, + // For input purposes, the background is added at the highest depth, but is then proxied back below all other elements + background.CreateProxy(), new Container { Name = "Hit target + hit objects", @@ -158,6 +161,7 @@ namespace osu.Game.Rulesets.Mania.UI } } }, + background, TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both } }; From 207cdbdefe12d29cdd3d38b4c1d36660542e7833 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Jun 2018 21:13:57 +0900 Subject: [PATCH 104/306] Make the column key area follow the scroll direction --- .../TestCaseColumn.cs | 3 +- osu.Game.Rulesets.Mania/UI/Column.cs | 95 ++------------ .../UI/Components/ColumnKeyArea.cs | 119 ++++++++++++++++++ 3 files changed, 128 insertions(+), 89 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs index b72dd808f4..391a30e4c7 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs @@ -21,7 +21,8 @@ namespace osu.Game.Rulesets.Mania.Tests public override IReadOnlyList RequiredTypes => new[] { typeof(Column), - typeof(ColumnBackground) + typeof(ColumnBackground), + typeof(ColumnKeyArea) }; public TestCaseColumn() diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index e1eb11f5e5..5568869755 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -1,16 +1,13 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Colour; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; -using System; using System.Linq; using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Judgements; @@ -21,10 +18,6 @@ namespace osu.Game.Rulesets.Mania.UI { public class Column : ScrollingPlayfield, IKeyBindingHandler, IHasAccentColour { - private const float key_icon_size = 10; - private const float key_icon_corner_radius = 3; - private const float key_icon_border_radius = 2; - private const float hit_target_height = 10; private const float hit_target_bar_height = 2; @@ -43,12 +36,14 @@ namespace osu.Game.Rulesets.Mania.UI action = value; background.Action = value; + keyArea.Action = value; } } private readonly ColumnBackground background; + private readonly ColumnKeyArea keyArea; + private readonly Container hitTargetBar; - private readonly Container keyIcon; internal readonly Container TopLevelContainer; private readonly Container explosionContainer; @@ -112,12 +107,6 @@ namespace osu.Game.Rulesets.Mania.UI Name = "Hit objects", RelativeSizeAxes = Axes.Both, }, - // For column lighting, we need to capture input events before the notes - new InputTarget - { - Pressed = onPressed, - Released = onReleased - }, explosionContainer = new Container { Name = "Hit explosions", @@ -125,41 +114,12 @@ namespace osu.Game.Rulesets.Mania.UI } } }, - new Container + keyArea = new ColumnKeyArea(direction) { - Name = "Key", + Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, + Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, RelativeSizeAxes = Axes.X, Height = ManiaStage.HIT_TARGET_POSITION, - Children = new Drawable[] - { - new Box - { - Name = "Key gradient", - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(Color4.Black, Color4.Black.Opacity(0)), - Alpha = 0.5f - }, - keyIcon = new Container - { - Name = "Key icon", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(key_icon_size), - Masking = true, - CornerRadius = key_icon_corner_radius, - BorderThickness = 2, - BorderColour = Color4.White, // Not true - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - } - } - } - } }, background, TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both } @@ -195,6 +155,7 @@ namespace osu.Game.Rulesets.Mania.UI accentColour = value; background.AccentColour = value; + keyArea.AccentColour = value; hitTargetBar.EdgeEffect = new EdgeEffectParameters { @@ -202,13 +163,6 @@ namespace osu.Game.Rulesets.Mania.UI Radius = 5, Colour = accentColour.Opacity(0.5f), }; - - keyIcon.EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Radius = 5, - Colour = accentColour.Opacity(0.5f), - }; } } @@ -232,41 +186,6 @@ namespace osu.Game.Rulesets.Mania.UI explosionContainer.Add(new HitExplosion(judgedObject)); } - private bool onPressed(ManiaAction action) - { - if (action == Action) - keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint); - - return false; - } - - private bool onReleased(ManiaAction action) - { - if (action == Action) - keyIcon.ScaleTo(1f, 125, Easing.OutQuint); - - return false; - } - - /// - /// This is a simple container which delegates various input events that have to be captured before the notes. - /// - private class InputTarget : Container, IKeyBindingHandler - { - public Func Pressed; - public Func Released; - - public InputTarget() - { - RelativeSizeAxes = Axes.Both; - AlwaysPresent = true; - Alpha = 0; - } - - public bool OnPressed(ManiaAction action) => Pressed?.Invoke(action) ?? false; - public bool OnReleased(ManiaAction action) => Released?.Invoke(action) ?? false; - } - public bool OnPressed(ManiaAction action) { if (action != Action) diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs new file mode 100644 index 0000000000..f0884f92da --- /dev/null +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs @@ -0,0 +1,119 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; +using osu.Game.Graphics; +using osu.Game.Rulesets.UI.Scrolling; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Rulesets.Mania.UI.Components +{ + public class ColumnKeyArea : CompositeDrawable, IKeyBindingHandler, IHasAccentColour + { + private const float key_icon_size = 10; + private const float key_icon_corner_radius = 3; + + public ManiaAction Action; + + private readonly ScrollingDirection direction; + + public ColumnKeyArea(ScrollingDirection direction) + { + this.direction = direction; + } + + private Container keyIcon; + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + new Box + { + Name = "Key gradient", + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical( + direction == ScrollingDirection.Up ? Color4.Black : Color4.Black.Opacity(0), + direction == ScrollingDirection.Up ? Color4.Black.Opacity(0) : Color4.Black), + Alpha = 0.5f + }, + keyIcon = new Container + { + Name = "Key icon", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(key_icon_size), + Masking = true, + CornerRadius = key_icon_corner_radius, + BorderThickness = 2, + BorderColour = Color4.White, // Not true + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + } + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + updateColours(); + } + + private Color4 accentColour; + + public Color4 AccentColour + { + get => accentColour; + set + { + if (accentColour == value) + return; + accentColour = value; + + updateColours(); + } + } + + private void updateColours() + { + if (!IsLoaded) + return; + + keyIcon.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Radius = 5, + Colour = accentColour.Opacity(0.5f), + }; + } + + public bool OnPressed(ManiaAction action) + { + if (action == Action) + keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint); + return false; + } + + public bool OnReleased(ManiaAction action) + { + if (action == Action) + keyIcon.ScaleTo(1f, 125, Easing.OutQuint); + return false; + } + } +} From 0c359088021e5529067b76e56b84798e8ba7e3e5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Jun 2018 21:19:31 +0900 Subject: [PATCH 105/306] Reorder fields --- osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs | 6 +++--- osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs index eeef5afcb0..b71dae035e 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs @@ -20,14 +20,14 @@ namespace osu.Game.Rulesets.Mania.UI.Components private readonly ScrollingDirection direction; + private Box background; + private Box backgroundOverlay; + public ColumnBackground(ScrollingDirection direction) { this.direction = direction; } - private Box background; - private Box backgroundOverlay; - [BackgroundDependencyLoader] private void load() { diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs index f0884f92da..e7fe44171b 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs @@ -24,13 +24,13 @@ namespace osu.Game.Rulesets.Mania.UI.Components private readonly ScrollingDirection direction; + private Container keyIcon; + public ColumnKeyArea(ScrollingDirection direction) { this.direction = direction; } - private Container keyIcon; - [BackgroundDependencyLoader] private void load() { From 32037701bfad57592cb39f7b490eda33f9bafce6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Jun 2018 21:40:12 +0900 Subject: [PATCH 106/306] Make the column hitobject area follow the scroll direction --- .../TestCaseColumn.cs | 3 +- osu.Game.Rulesets.Mania/UI/Column.cs | 60 ++---------- .../UI/Components/ColumnHitObjectArea.cs | 96 +++++++++++++++++++ 3 files changed, 107 insertions(+), 52 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs index 391a30e4c7..05c7e99a18 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs @@ -22,7 +22,8 @@ namespace osu.Game.Rulesets.Mania.Tests { typeof(Column), typeof(ColumnBackground), - typeof(ColumnKeyArea) + typeof(ColumnKeyArea), + typeof(ColumnHitObjectArea) }; public TestCaseColumn() diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 5568869755..81607795fe 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -2,10 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK.Graphics; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using System.Linq; @@ -18,9 +16,6 @@ namespace osu.Game.Rulesets.Mania.UI { public class Column : ScrollingPlayfield, IKeyBindingHandler, IHasAccentColour { - private const float hit_target_height = 10; - private const float hit_target_bar_height = 2; - private const float column_width = 45; private const float special_column_width = 70; @@ -42,14 +37,12 @@ namespace osu.Game.Rulesets.Mania.UI private readonly ColumnBackground background; private readonly ColumnKeyArea keyArea; - - private readonly Container hitTargetBar; + private readonly ColumnHitObjectArea hitObjectArea; internal readonly Container TopLevelContainer; private readonly Container explosionContainer; - protected override Container Content => content; - private readonly Container content; + protected override Container Content => hitObjectArea; public Column(ScrollingDirection direction = ScrollingDirection.Up) : base(direction) @@ -70,43 +63,14 @@ namespace osu.Game.Rulesets.Mania.UI { Name = "Hit target + hit objects", RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = ManiaStage.HIT_TARGET_POSITION }, + Padding = new MarginPadding + { + Top = direction == ScrollingDirection.Up ? ManiaStage.HIT_TARGET_POSITION : 0, + Bottom = direction == ScrollingDirection.Down ? ManiaStage.HIT_TARGET_POSITION : 0, + }, Children = new Drawable[] { - new Container - { - Name = "Hit target", - RelativeSizeAxes = Axes.X, - Height = hit_target_height, - Children = new Drawable[] - { - new Box - { - Name = "Background", - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black - }, - hitTargetBar = new Container - { - Name = "Bar", - RelativeSizeAxes = Axes.X, - Height = hit_target_bar_height, - Masking = true, - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both - } - } - } - } - }, - content = new Container - { - Name = "Hit objects", - RelativeSizeAxes = Axes.Both, - }, + hitObjectArea = new ColumnHitObjectArea(direction) { RelativeSizeAxes = Axes.Both }, explosionContainer = new Container { Name = "Hit explosions", @@ -156,13 +120,7 @@ namespace osu.Game.Rulesets.Mania.UI background.AccentColour = value; keyArea.AccentColour = value; - - hitTargetBar.EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Radius = 5, - Colour = accentColour.Opacity(0.5f), - }; + hitObjectArea.AccentColour = value; } } diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs new file mode 100644 index 0000000000..31df6d5fa3 --- /dev/null +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs @@ -0,0 +1,96 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Rulesets.UI.Scrolling; +using OpenTK.Graphics; + +namespace osu.Game.Rulesets.Mania.UI.Components +{ + public class ColumnHitObjectArea : Container, IHasAccentColour + { + private const float hit_target_height = 10; + private const float hit_target_bar_height = 2; + + private Container content; + protected override Container Content => content; + + private readonly ScrollingDirection direction; + + private Container hitTargetBar; + + public ColumnHitObjectArea(ScrollingDirection direction) + { + this.direction = direction; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + new Box + { + Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, + Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Height = hit_target_height, + Colour = Color4.Black + }, + hitTargetBar = new Container + { + Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, + Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Height = hit_target_bar_height, + Masking = true, + Child = new Box { RelativeSizeAxes = Axes.Both } + }, + content = new Container + { + Name = "Hit objects", + RelativeSizeAxes = Axes.Both, + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + updateColours(); + } + + private Color4 accentColour; + + public Color4 AccentColour + { + get => accentColour; + set + { + if (accentColour == value) + return; + accentColour = value; + + updateColours(); + } + } + + private void updateColours() + { + if (!IsLoaded) + return; + + hitTargetBar.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Radius = 5, + Colour = accentColour.Opacity(0.5f), + }; + } + } +} From 0b4f5af52e31c5088fa1edba366bbb931d830e8e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 03:17:12 +0900 Subject: [PATCH 107/306] Add setting to toggle standardised or exponential scoring display Also adjusts exponential scoring to be closer to stable. Log wasn't cutting it. --- osu.Game/Configuration/OsuConfigManager.cs | 6 +++++- .../Settings/Sections/Gameplay/GeneralSettings.cs | 6 ++++++ osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 11 ++++++++--- osu.Game/Screens/Play/Player.cs | 1 + 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 597960c352..f7fe424aa9 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -5,6 +5,7 @@ using osu.Framework.Configuration; using osu.Framework.Configuration.Tracking; using osu.Framework.Platform; using osu.Game.Overlays; +using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Select; namespace osu.Game.Configuration @@ -80,6 +81,8 @@ namespace osu.Game.Configuration Set(OsuSetting.FloatingComments, false); + Set(OsuSetting.ScoreDisplayMode, ScoringMode.Standardised); + Set(OsuSetting.SpeedChangeVisualisation, SpeedChangeVisualisationMethod.Sequential); Set(OsuSetting.IncreaseFirstObjectVisibility, true); @@ -147,6 +150,7 @@ namespace osu.Game.Configuration SongSelectRightMouseScroll, BeatmapSkins, BeatmapHitsounds, - IncreaseFirstObjectVisibility + IncreaseFirstObjectVisibility, + ScoreDisplayMode } } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs index 647395cf69..9c8f5e2643 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Configuration; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Overlays.Settings.Sections.Gameplay { @@ -38,6 +39,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay LabelText = "Always show key overlay", Bindable = config.GetBindable(OsuSetting.KeyOverlay) }, + new SettingsEnumDropdown + { + LabelText = "Score display mode", + Bindable = config.GetBindable(OsuSetting.ScoreDisplayMode) + } }; } } diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 345930ed04..0568101aa7 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -65,6 +65,11 @@ namespace osu.Game.Rulesets.Scoring /// public readonly BindableInt HighestCombo = new BindableInt(); + /// + /// The used to calculate scores. + /// + public readonly Bindable Mode = new Bindable(); + /// /// Whether all s have been processed. /// @@ -169,8 +174,6 @@ namespace osu.Game.Rulesets.Scoring private const double combo_portion = 0.7; private const double max_score = 1000000; - public readonly Bindable Mode = new Bindable(); - protected sealed override bool HasCompleted => JudgedHits == MaxHits; protected int MaxHits { get; private set; } @@ -202,6 +205,8 @@ namespace osu.Game.Rulesets.Scoring Mode.Value = ScoringMode.Exponential; Mode.Disabled = true; } + + Mode.ValueChanged += _ => updateScore(); } /// @@ -296,7 +301,7 @@ namespace osu.Game.Rulesets.Scoring TotalScore.Value = max_score * (base_portion * baseScore / maxBaseScore + combo_portion * HighestCombo / maxHighestCombo) + bonusScore; break; case ScoringMode.Exponential: - TotalScore.Value = (baseScore + bonusScore) * Math.Log(HighestCombo + 1, 2); + TotalScore.Value = (baseScore + bonusScore) * Math.Max(0, HighestCombo - 1) / 25f; break; } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index fe77f85a50..94d03be3c8 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -158,6 +158,7 @@ namespace osu.Game.Screens.Play userAudioOffset.TriggerChange(); ScoreProcessor = RulesetContainer.CreateScoreProcessor(); + ScoreProcessor.Mode.BindTo(config.GetBindable(OsuSetting.ScoreDisplayMode)); Children = new Drawable[] { From 8cc31aca541db1a002177a1467f5e30a6ebe0a78 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 11:41:54 +0900 Subject: [PATCH 108/306] Reorganise API requests and response classes They were previously breaking the two-class-per-file rule. --- .../Visual/TestCaseBeatmapScoresContainer.cs | 30 ++--- .../TestCaseUserProfileRecentSection.cs | 37 +++--- .../API/Requests/GetBeatmapDetailsRequest.cs | 28 +--- .../API/Requests/GetBeatmapSetRequest.cs | 4 +- .../Online/API/Requests/GetScoresRequest.cs | 121 +----------------- .../API/Requests/GetUserBeatmapsRequest.cs | 3 +- .../GetUserMostPlayedBeatmapsRequest.cs | 30 +---- .../GetUserRecentActivitiesRequest.cs | 87 +------------ .../API/Requests/GetUserScoresRequest.cs | 3 +- .../Online/API/Requests/GetUsersRequest.cs | 11 +- .../Requests/Responses/APIBeatmapMetrics.cs | 29 +++++ .../APIBeatmapSet.cs} | 6 +- .../Requests/Responses/APIRecentActivity.cs | 89 +++++++++++++ .../Online/API/Requests/Responses/APIScore.cs | 117 +++++++++++++++++ .../API/Requests/Responses/APIScores.cs | 14 ++ .../Online/API/Requests/Responses/APIUser.cs | 14 ++ .../Responses/APIUserMostPlayedBeatmap.cs | 30 +++++ .../API/Requests/SearchBeatmapSetsRequest.cs | 3 +- .../BeatmapSet/Scores/DrawableScore.cs | 4 +- .../BeatmapSet/Scores/DrawableTopScore.cs | 6 +- .../BeatmapSet/Scores/ScoresContainer.cs | 5 +- .../Sections/Ranks/PaginatedScoreContainer.cs | 3 +- .../Sections/Recent/DrawableRecentActivity.cs | 5 +- .../PaginatedRecentActivityContainer.cs | 3 +- 24 files changed, 366 insertions(+), 316 deletions(-) create mode 100644 osu.Game/Online/API/Requests/Responses/APIBeatmapMetrics.cs rename osu.Game/Online/API/Requests/{APIResponseBeatmapSet.cs => Responses/APIBeatmapSet.cs} (97%) create mode 100644 osu.Game/Online/API/Requests/Responses/APIRecentActivity.cs create mode 100644 osu.Game/Online/API/Requests/Responses/APIScore.cs create mode 100644 osu.Game/Online/API/Requests/Responses/APIScores.cs create mode 100644 osu.Game/Online/API/Requests/Responses/APIUser.cs create mode 100644 osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs index 5be7386238..3f63bacfa6 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.MathUtils; using osu.Game.Graphics; -using osu.Game.Online.API.Requests; using osu.Game.Overlays.BeatmapSet.Scores; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; @@ -15,6 +14,7 @@ using osu.Game.Users; using System.Collections.Generic; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Osu; namespace osu.Game.Tests.Visual @@ -22,9 +22,9 @@ namespace osu.Game.Tests.Visual [System.ComponentModel.Description("in BeatmapOverlay")] public class TestCaseBeatmapScoresContainer : OsuTestCase { - private readonly IEnumerable scores; - private readonly IEnumerable anotherScores; - private readonly OnlineScore topScore; + private readonly IEnumerable scores; + private readonly IEnumerable anotherScores; + private readonly APIScore topScore; private readonly Box background; public TestCaseBeatmapScoresContainer() @@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual scores = new[] { - new OnlineScore + new APIScore { User = new User { @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual TotalScore = 1234567890, Accuracy = 1, }, - new OnlineScore + new APIScore { User = new User { @@ -102,7 +102,7 @@ namespace osu.Game.Tests.Visual TotalScore = 1234789, Accuracy = 0.9997, }, - new OnlineScore + new APIScore { User = new User { @@ -123,7 +123,7 @@ namespace osu.Game.Tests.Visual TotalScore = 12345678, Accuracy = 0.9854, }, - new OnlineScore + new APIScore { User = new User { @@ -143,7 +143,7 @@ namespace osu.Game.Tests.Visual TotalScore = 1234567, Accuracy = 0.8765, }, - new OnlineScore + new APIScore { User = new User { @@ -169,7 +169,7 @@ namespace osu.Game.Tests.Visual anotherScores = new[] { - new OnlineScore + new APIScore { User = new User { @@ -191,7 +191,7 @@ namespace osu.Game.Tests.Visual TotalScore = 1234789, Accuracy = 0.9997, }, - new OnlineScore + new APIScore { User = new User { @@ -214,7 +214,7 @@ namespace osu.Game.Tests.Visual TotalScore = 1234567890, Accuracy = 1, }, - new OnlineScore + new APIScore { User = new User { @@ -230,7 +230,7 @@ namespace osu.Game.Tests.Visual TotalScore = 123456, Accuracy = 0.6543, }, - new OnlineScore + new APIScore { User = new User { @@ -251,7 +251,7 @@ namespace osu.Game.Tests.Visual TotalScore = 12345678, Accuracy = 0.9854, }, - new OnlineScore + new APIScore { User = new User { @@ -279,7 +279,7 @@ namespace osu.Game.Tests.Visual s.Statistics.Add(HitResult.Meh, RNG.Next(2000)); } - topScore = new OnlineScore + topScore = new APIScore { User = new User { diff --git a/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs b/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs index f625bc0150..b14606780d 100644 --- a/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs +++ b/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs @@ -12,6 +12,7 @@ using osu.Game.Overlays.Profile.Sections.Recent; using System; using System.Collections.Generic; using System.Linq; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Tests.Visual { @@ -49,15 +50,15 @@ namespace osu.Game.Tests.Visual }; } - private IEnumerable createDummyActivities() + private IEnumerable createDummyActivities() { - var dummyBeatmap = new RecentActivity.RecentActivityBeatmap + var dummyBeatmap = new APIRecentActivity.RecentActivityBeatmap { Title = @"Dummy beatmap", Url = "/b/1337", }; - var dummyUser = new RecentActivity.RecentActivityUser + var dummyUser = new APIRecentActivity.RecentActivityUser { Username = "DummyReborn", Url = "/u/666", @@ -66,61 +67,61 @@ namespace osu.Game.Tests.Visual return new[] { - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.Achievement, - Achievement = new RecentActivity.RecentActivityAchievement + Achievement = new APIRecentActivity.RecentActivityAchievement { Name = @"Feelin' It", Slug = @"all-secret-feelinit", }, }, - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.BeatmapPlaycount, Count = 1337, Beatmap = dummyBeatmap, }, - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.BeatmapsetApprove, Approval = BeatmapApproval.Qualified, Beatmapset = dummyBeatmap, }, - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.BeatmapsetDelete, Beatmapset = dummyBeatmap, }, - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.BeatmapsetRevive, Beatmapset = dummyBeatmap, }, - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.BeatmapsetRevive, Beatmapset = dummyBeatmap, }, - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.BeatmapsetUpdate, Beatmapset = dummyBeatmap, }, - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.BeatmapsetUpload, Beatmapset = dummyBeatmap, }, - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.Rank, @@ -128,29 +129,29 @@ namespace osu.Game.Tests.Visual Mode = "osu!", Beatmap = dummyBeatmap, }, - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.RankLost, Mode = "osu!", Beatmap = dummyBeatmap, }, - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.UsernameChange, }, - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.UserSupportAgain, }, - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.UserSupportFirst, }, - new RecentActivity + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.UserSupportGift, diff --git a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs index b853da7e76..ab840d054f 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs @@ -1,12 +1,12 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using Newtonsoft.Json; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests { - public class GetBeatmapDetailsRequest : APIRequest + public class GetBeatmapDetailsRequest : APIRequest { private readonly BeatmapInfo beatmap; @@ -19,28 +19,4 @@ namespace osu.Game.Online.API.Requests protected override string Target => $@"beatmaps/{lookupString}"; } - - public class GetBeatmapDetailsResponse : BeatmapMetrics - { - //the online API returns some metrics as a nested object. - [JsonProperty(@"failtimes")] - private BeatmapMetrics failTimes - { - set - { - Fails = value.Fails; - Retries = value.Retries; - } - } - - //and other metrics in the beatmap set. - [JsonProperty(@"beatmapset")] - private BeatmapMetrics beatmapSet - { - set - { - Ratings = value.Ratings; - } - } - } } diff --git a/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs index 37dd77af46..d04e069cd6 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs @@ -1,9 +1,11 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Online.API.Requests.Responses; + namespace osu.Game.Online.API.Requests { - public class GetBeatmapSetRequest : APIRequest + public class GetBeatmapSetRequest : APIRequest { private readonly int id; private readonly BeatmapSetLookupType type; diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index cff6fd4ea5..3be5b91a0d 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -2,20 +2,15 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; -using System.Linq; -using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Rulesets; -using osu.Game.Users; -using osu.Game.Rulesets.Replays; -using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Select.Leaderboards; using osu.Framework.IO.Network; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests { - public class GetScoresRequest : APIRequest + public class GetScoresRequest : APIRequest { private readonly BeatmapInfo beatmap; private readonly LeaderboardScope scope; @@ -36,9 +31,9 @@ namespace osu.Game.Online.API.Requests Success += onSuccess; } - private void onSuccess(GetScoresResponse r) + private void onSuccess(APIScores r) { - foreach (OnlineScore score in r.Scores) + foreach (APIScore score in r.Scores) score.ApplyBeatmap(beatmap); } @@ -55,112 +50,4 @@ namespace osu.Game.Online.API.Requests protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores"; } - - public class GetScoresResponse - { - [JsonProperty(@"scores")] - public IEnumerable Scores; - } - - public class OnlineScore : Score - { - [JsonProperty(@"score")] - private double totalScore - { - set { TotalScore = value; } - } - - [JsonProperty(@"max_combo")] - private int maxCombo - { - set { MaxCombo = value; } - } - - [JsonProperty(@"user")] - private User user - { - set { User = value; } - } - - [JsonProperty(@"replay_data")] - private Replay replay - { - set { Replay = value; } - } - - [JsonProperty(@"mode_int")] - public int OnlineRulesetID { get; set; } - - [JsonProperty(@"score_id")] - private long onlineScoreID - { - set { OnlineScoreID = value; } - } - - [JsonProperty(@"created_at")] - private DateTimeOffset date - { - set { Date = value; } - } - - [JsonProperty(@"beatmap")] - private BeatmapInfo beatmap - { - set { Beatmap = value; } - } - - [JsonProperty(@"beatmapset")] - private BeatmapMetadata metadata - { - set { Beatmap.Metadata = value; } - } - - [JsonProperty(@"statistics")] - private Dictionary jsonStats - { - set - { - foreach (var kvp in value) - { - HitResult newKey; - switch (kvp.Key) - { - case @"count_300": - newKey = HitResult.Great; - break; - case @"count_100": - newKey = HitResult.Good; - break; - case @"count_50": - newKey = HitResult.Meh; - break; - case @"count_miss": - newKey = HitResult.Miss; - break; - default: - continue; - } - - Statistics.Add(newKey, kvp.Value); - } - } - } - - [JsonProperty(@"mods")] - private string[] modStrings { get; set; } - - public void ApplyBeatmap(BeatmapInfo beatmap) - { - Beatmap = beatmap; - ApplyRuleset(beatmap.Ruleset); - } - - public void ApplyRuleset(RulesetInfo ruleset) - { - Ruleset = ruleset; - - // Evaluate the mod string - Mods = Ruleset.CreateInstance().GetAllMods().Where(mod => modStrings.Contains(mod.ShortenedName)).ToArray(); - } - } } diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs index 48e9babd97..b847a954f6 100644 --- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs @@ -3,10 +3,11 @@ using Humanizer; using System.Collections.Generic; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests { - public class GetUserBeatmapsRequest : APIRequest> + public class GetUserBeatmapsRequest : APIRequest> { private readonly long userId; private readonly int offset; diff --git a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs index 106f3d4fb1..9a54aafa82 100644 --- a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs @@ -1,14 +1,12 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using Newtonsoft.Json; -using osu.Game.Beatmaps; -using osu.Game.Rulesets; using System.Collections.Generic; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests { - public class GetUserMostPlayedBeatmapsRequest : APIRequest> + public class GetUserMostPlayedBeatmapsRequest : APIRequest> { private readonly long userId; private readonly int offset; @@ -21,28 +19,4 @@ namespace osu.Game.Online.API.Requests protected override string Target => $@"users/{userId}/beatmapsets/most_played?offset={offset}"; } - - public class MostPlayedBeatmap - { - [JsonProperty("beatmap_id")] - public int BeatmapID; - - [JsonProperty("count")] - public int PlayCount; - - [JsonProperty] - private BeatmapInfo beatmap; - - [JsonProperty] - private APIResponseBeatmapSet beatmapSet; - - public BeatmapInfo GetBeatmapInfo(RulesetStore rulesets) - { - BeatmapSetInfo setInfo = beatmapSet.ToBeatmapSet(rulesets); - beatmap.BeatmapSet = setInfo; - beatmap.OnlineBeatmapSetID = setInfo.OnlineBeatmapSetID; - beatmap.Metadata = setInfo.Metadata; - return beatmap; - } - } } diff --git a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs index ded0e4f80d..e1cad1a532 100644 --- a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs @@ -1,15 +1,12 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using Newtonsoft.Json; -using osu.Game.Rulesets.Scoring; -using Humanizer; -using System; using System.Collections.Generic; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests { - public class GetUserRecentActivitiesRequest : APIRequest> + public class GetUserRecentActivitiesRequest : APIRequest> { private readonly long userId; private readonly int offset; @@ -23,86 +20,6 @@ namespace osu.Game.Online.API.Requests protected override string Target => $"users/{userId}/recent_activity?offset={offset}"; } - public class RecentActivity - { - [JsonProperty("id")] - public int ID; - - [JsonProperty("createdAt")] - public DateTimeOffset CreatedAt; - - [JsonProperty] - private string type - { - set => Type = (RecentActivityType)Enum.Parse(typeof(RecentActivityType), value.Pascalize()); - } - - public RecentActivityType Type; - - [JsonProperty] - private string scoreRank - { - set => ScoreRank = (ScoreRank)Enum.Parse(typeof(ScoreRank), value); - } - - public ScoreRank ScoreRank; - - [JsonProperty("rank")] - public int Rank; - - [JsonProperty("approval")] - public BeatmapApproval Approval; - - [JsonProperty("count")] - public int Count; - - [JsonProperty("mode")] - public string Mode; - - [JsonProperty("beatmap")] - public RecentActivityBeatmap Beatmap; - - [JsonProperty("beatmapset")] - public RecentActivityBeatmap Beatmapset; - - [JsonProperty("user")] - public RecentActivityUser User; - - [JsonProperty("achievement")] - public RecentActivityAchievement Achievement; - - public class RecentActivityBeatmap - { - [JsonProperty("title")] - public string Title; - - [JsonProperty("url")] - public string Url; - } - - public class RecentActivityUser - { - [JsonProperty("username")] - public string Username; - - [JsonProperty("url")] - public string Url; - - [JsonProperty("previousUsername")] - public string PreviousUsername; - } - - public class RecentActivityAchievement - { - [JsonProperty("slug")] - public string Slug; - - [JsonProperty("name")] - public string Name; - } - - } - public enum RecentActivityType { Achievement, diff --git a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs index 7757f529e0..ea14135a61 100644 --- a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs @@ -2,10 +2,11 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests { - public class GetUserScoresRequest : APIRequest> + public class GetUserScoresRequest : APIRequest> { private readonly long userId; private readonly ScoreType type; diff --git a/osu.Game/Online/API/Requests/GetUsersRequest.cs b/osu.Game/Online/API/Requests/GetUsersRequest.cs index 575d0464aa..17dd9263c9 100644 --- a/osu.Game/Online/API/Requests/GetUsersRequest.cs +++ b/osu.Game/Online/API/Requests/GetUsersRequest.cs @@ -2,19 +2,12 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; -using Newtonsoft.Json; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests { - public class GetUsersRequest : APIRequest> + public class GetUsersRequest : APIRequest> { protected override string Target => @"rankings/osu/performance"; } - - public class RankingEntry - { - [JsonProperty] - public User User; - } } diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapMetrics.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapMetrics.cs new file mode 100644 index 0000000000..e67c60cb91 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapMetrics.cs @@ -0,0 +1,29 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using Newtonsoft.Json; +using osu.Game.Beatmaps; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIBeatmapMetrics : BeatmapMetrics + { + //the online API returns some metrics as a nested object. + [JsonProperty(@"failtimes")] + private BeatmapMetrics failTimes + { + set + { + Fails = value.Fails; + Retries = value.Retries; + } + } + + //and other metrics in the beatmap set. + [JsonProperty(@"beatmapset")] + private BeatmapMetrics beatmapSet + { + set => Ratings = value.Ratings; + } + } +} diff --git a/osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs similarity index 97% rename from osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs rename to osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index 44c1216959..cbe3b929fd 100644 --- a/osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -1,16 +1,16 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Rulesets; -using System; -namespace osu.Game.Online.API.Requests +namespace osu.Game.Online.API.Requests.Responses { - public class APIResponseBeatmapSet : BeatmapMetadata // todo: this is a bit wrong... + public class APIBeatmapSet : BeatmapMetadata // todo: this is a bit wrong... { [JsonProperty(@"covers")] private BeatmapSetOnlineCovers covers { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/APIRecentActivity.cs b/osu.Game/Online/API/Requests/Responses/APIRecentActivity.cs new file mode 100644 index 0000000000..2c65a37cf8 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIRecentActivity.cs @@ -0,0 +1,89 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using Humanizer; +using Newtonsoft.Json; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIRecentActivity + { + [JsonProperty("id")] + public int ID; + + [JsonProperty("createdAt")] + public DateTimeOffset CreatedAt; + + [JsonProperty] + private string type + { + set => Type = (RecentActivityType)Enum.Parse(typeof(RecentActivityType), value.Pascalize()); + } + + public RecentActivityType Type; + + [JsonProperty] + private string scoreRank + { + set => ScoreRank = (ScoreRank)Enum.Parse(typeof(ScoreRank), value); + } + + public ScoreRank ScoreRank; + + [JsonProperty("rank")] + public int Rank; + + [JsonProperty("approval")] + public BeatmapApproval Approval; + + [JsonProperty("count")] + public int Count; + + [JsonProperty("mode")] + public string Mode; + + [JsonProperty("beatmap")] + public RecentActivityBeatmap Beatmap; + + [JsonProperty("beatmapset")] + public RecentActivityBeatmap Beatmapset; + + [JsonProperty("user")] + public RecentActivityUser User; + + [JsonProperty("achievement")] + public RecentActivityAchievement Achievement; + + public class RecentActivityBeatmap + { + [JsonProperty("title")] + public string Title; + + [JsonProperty("url")] + public string Url; + } + + public class RecentActivityUser + { + [JsonProperty("username")] + public string Username; + + [JsonProperty("url")] + public string Url; + + [JsonProperty("previousUsername")] + public string PreviousUsername; + } + + public class RecentActivityAchievement + { + [JsonProperty("slug")] + public string Slug; + + [JsonProperty("name")] + public string Name; + } + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APIScore.cs b/osu.Game/Online/API/Requests/Responses/APIScore.cs new file mode 100644 index 0000000000..a398bf46ee --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIScore.cs @@ -0,0 +1,117 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Replays; +using osu.Game.Rulesets.Scoring; +using osu.Game.Users; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIScore : Score + { + [JsonProperty(@"score")] + private double totalScore + { + set => TotalScore = value; + } + + [JsonProperty(@"max_combo")] + private int maxCombo + { + set => MaxCombo = value; + } + + [JsonProperty(@"user")] + private User user + { + set => User = value; + } + + [JsonProperty(@"replay_data")] + private Replay replay + { + set => Replay = value; + } + + [JsonProperty(@"mode_int")] + public int OnlineRulesetID { get; set; } + + [JsonProperty(@"score_id")] + private long onlineScoreID + { + set => OnlineScoreID = value; + } + + [JsonProperty(@"created_at")] + private DateTimeOffset date + { + set => Date = value; + } + + [JsonProperty(@"beatmap")] + private BeatmapInfo beatmap + { + set => Beatmap = value; + } + + [JsonProperty(@"beatmapset")] + private BeatmapMetadata metadata + { + set => Beatmap.Metadata = value; + } + + [JsonProperty(@"statistics")] + private Dictionary jsonStats + { + set + { + foreach (var kvp in value) + { + HitResult newKey; + switch (kvp.Key) + { + case @"count_300": + newKey = HitResult.Great; + break; + case @"count_100": + newKey = HitResult.Good; + break; + case @"count_50": + newKey = HitResult.Meh; + break; + case @"count_miss": + newKey = HitResult.Miss; + break; + default: + continue; + } + + Statistics.Add(newKey, kvp.Value); + } + } + } + + [JsonProperty(@"mods")] + private string[] modStrings { get; set; } + + public void ApplyBeatmap(BeatmapInfo beatmap) + { + Beatmap = beatmap; + ApplyRuleset(beatmap.Ruleset); + } + + public void ApplyRuleset(RulesetInfo ruleset) + { + Ruleset = ruleset; + + // Evaluate the mod string + Mods = Ruleset.CreateInstance().GetAllMods().Where(mod => modStrings.Contains(mod.ShortenedName)).ToArray(); + } + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APIScores.cs b/osu.Game/Online/API/Requests/Responses/APIScores.cs new file mode 100644 index 0000000000..b4213db253 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIScores.cs @@ -0,0 +1,14 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIScores + { + [JsonProperty(@"scores")] + public IEnumerable Scores; + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APIUser.cs b/osu.Game/Online/API/Requests/Responses/APIUser.cs new file mode 100644 index 0000000000..54c8451456 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIUser.cs @@ -0,0 +1,14 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using Newtonsoft.Json; +using osu.Game.Users; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIUser + { + [JsonProperty] + public User User; + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs new file mode 100644 index 0000000000..26f80321bc --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIUserMostPlayedBeatmap + { + [JsonProperty("beatmap_id")] + public int BeatmapID; + + [JsonProperty("count")] + public int PlayCount; + + [JsonProperty] + private BeatmapInfo beatmap; + + [JsonProperty] + private APIBeatmapSet beatmapSet; + + public BeatmapInfo GetBeatmapInfo(RulesetStore rulesets) + { + BeatmapSetInfo setInfo = beatmapSet.ToBeatmapSet(rulesets); + beatmap.BeatmapSet = setInfo; + beatmap.OnlineBeatmapSetID = setInfo.OnlineBeatmapSetID; + beatmap.Metadata = setInfo.Metadata; + return beatmap; + } + } +} diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index d68314f8fc..2a154d1230 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -3,13 +3,14 @@ using System.Collections.Generic; using System.ComponentModel; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Direct; using osu.Game.Rulesets; namespace osu.Game.Online.API.Requests { - public class SearchBeatmapSetsRequest : APIRequest> + public class SearchBeatmapSetsRequest : APIRequest> { private readonly string query; private readonly RulesetInfo ruleset; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs index 10e689698d..fc8b3a6800 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile.Sections.Ranks; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; @@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private readonly Box background; - public DrawableScore(int index, OnlineScore score) + public DrawableScore(int index, APIScore score) { ScoreModsContainer modsContainer; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs index 8ac79eabb4..b3ceffd35e 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile.Sections.Ranks; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; @@ -42,8 +42,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private readonly InfoColumn statistics; private readonly ScoreModsContainer modsContainer; - private OnlineScore score; - public OnlineScore Score + private APIScore score; + public APIScore Score { get { return score; } set diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 185282bec9..626de14c98 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -11,6 +11,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.BeatmapSet.Scores { @@ -28,10 +29,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores set => loadingAnimation.FadeTo(value ? 1 : 0, fade_duration); } - private IEnumerable scores; + private IEnumerable scores; private BeatmapInfo beatmap; - public IEnumerable Scores + public IEnumerable Scores { get { return scores; } set diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index 87df84e2e5..707de0a10f 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -8,6 +8,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Users; using System; using System.Linq; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile.Sections.Ranks { @@ -49,7 +50,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks MissingText.Hide(); - foreach (OnlineScore score in scores) + foreach (APIScore score in scores) { DrawableProfileScore drawableScore; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 721cc30b61..046c1b1a33 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -8,6 +8,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Screens.Select.Leaderboards; @@ -17,11 +18,11 @@ namespace osu.Game.Overlays.Profile.Sections.Recent { private APIAccess api; - private readonly RecentActivity activity; + private readonly APIRecentActivity activity; private LinkFlowContainer content; - public DrawableRecentActivity(RecentActivity activity) + public DrawableRecentActivity(APIRecentActivity activity) { this.activity = activity; } diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index 8c1108b115..ee2f2f5973 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics; using osu.Game.Online.API.Requests; using osu.Game.Users; using System.Linq; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile.Sections.Recent { @@ -36,7 +37,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent MissingText.Hide(); - foreach (RecentActivity activity in activities) + foreach (APIRecentActivity activity in activities) { ItemsContainer.Add(new DrawableRecentActivity(activity)); } From 1716975a37c53baa661e34b306bee0b5d6102a5d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 12:04:33 +0900 Subject: [PATCH 109/306] Move out APIBeatmap --- .../API/Requests/Responses/APIBeatmap.cs | 78 +++++++++++++++++++ .../API/Requests/Responses/APIBeatmapSet.cs | 74 +----------------- 2 files changed, 81 insertions(+), 71 deletions(-) create mode 100644 osu.Game/Online/API/Requests/Responses/APIBeatmap.cs diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs new file mode 100644 index 0000000000..f75d320a46 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -0,0 +1,78 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using Newtonsoft.Json; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIBeatmap : BeatmapMetadata + { + [JsonProperty(@"id")] + private int onlineBeatmapID { get; set; } + + [JsonProperty(@"playcount")] + private int playCount { get; set; } + + [JsonProperty(@"passcount")] + private int passCount { get; set; } + + [JsonProperty(@"mode_int")] + private int ruleset { get; set; } + + [JsonProperty(@"difficulty_rating")] + private double starDifficulty { get; set; } + + [JsonProperty(@"drain")] + private float drainRate { get; set; } + + [JsonProperty(@"cs")] + private float circleSize { get; set; } + + [JsonProperty(@"ar")] + private float approachRate { get; set; } + + [JsonProperty(@"accuracy")] + private float overallDifficulty { get; set; } + + [JsonProperty(@"total_length")] + private double length { get; set; } + + [JsonProperty(@"count_circles")] + private int circleCount { get; set; } + + [JsonProperty(@"count_sliders")] + private int sliderCount { get; set; } + + [JsonProperty(@"version")] + private string version { get; set; } + + public BeatmapInfo ToBeatmap(RulesetStore rulesets) + { + return new BeatmapInfo + { + Metadata = this, + Ruleset = rulesets.GetRuleset(ruleset), + StarDifficulty = starDifficulty, + OnlineBeatmapID = onlineBeatmapID, + Version = version, + BaseDifficulty = new BeatmapDifficulty + { + DrainRate = drainRate, + CircleSize = circleSize, + ApproachRate = approachRate, + OverallDifficulty = overallDifficulty, + }, + OnlineInfo = new BeatmapOnlineInfo + { + PlayCount = playCount, + PassCount = passCount, + Length = length, + CircleCount = circleCount, + SliderCount = sliderCount, + }, + }; + } + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index cbe3b929fd..f57de016a2 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -46,12 +46,13 @@ namespace osu.Game.Online.API.Requests.Responses private DateTimeOffset lastUpdated { get; set; } [JsonProperty(@"user_id")] - private long creatorId { + private long creatorId + { set { Author.Id = value; } } [JsonProperty(@"beatmaps")] - private IEnumerable beatmaps { get; set; } + private IEnumerable beatmaps { get; set; } public BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets) { @@ -76,74 +77,5 @@ namespace osu.Game.Online.API.Requests.Responses Beatmaps = beatmaps?.Select(b => b.ToBeatmap(rulesets)).ToList(), }; } - - private class APIResponseBeatmap : BeatmapMetadata - { - [JsonProperty(@"id")] - private int onlineBeatmapID { get; set; } - - [JsonProperty(@"playcount")] - private int playCount { get; set; } - - [JsonProperty(@"passcount")] - private int passCount { get; set; } - - [JsonProperty(@"mode_int")] - private int ruleset { get; set; } - - [JsonProperty(@"difficulty_rating")] - private double starDifficulty { get; set; } - - [JsonProperty(@"drain")] - private float drainRate { get; set; } - - [JsonProperty(@"cs")] - private float circleSize { get; set; } - - [JsonProperty(@"ar")] - private float approachRate { get; set; } - - [JsonProperty(@"accuracy")] - private float overallDifficulty { get; set; } - - [JsonProperty(@"total_length")] - private double length { get; set; } - - [JsonProperty(@"count_circles")] - private int circleCount { get; set; } - - [JsonProperty(@"count_sliders")] - private int sliderCount { get; set; } - - [JsonProperty(@"version")] - private string version { get; set; } - - public BeatmapInfo ToBeatmap(RulesetStore rulesets) - { - return new BeatmapInfo - { - Metadata = this, - Ruleset = rulesets.GetRuleset(ruleset), - StarDifficulty = starDifficulty, - OnlineBeatmapID = onlineBeatmapID, - Version = version, - BaseDifficulty = new BeatmapDifficulty - { - DrainRate = drainRate, - CircleSize = circleSize, - ApproachRate = approachRate, - OverallDifficulty = overallDifficulty, - }, - OnlineInfo = new BeatmapOnlineInfo - { - PlayCount = playCount, - PassCount = passCount, - Length = length, - CircleCount = circleCount, - SliderCount = sliderCount, - }, - }; - } - } } } From b45354ce97c5944bce29cfc35294f9e10ceae70d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 12:06:58 +0900 Subject: [PATCH 110/306] Add missing header --- .../API/Requests/Responses/APIUserMostPlayedBeatmap.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs index 26f80321bc..d49613eab7 100644 --- a/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs @@ -1,4 +1,7 @@ -using Newtonsoft.Json; +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Rulesets; From d1e9dba4aa46ae45ec391a5d00dd827a12effa13 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 12:21:12 +0900 Subject: [PATCH 111/306] Move beatmap lookup ability to new request --- .../API/Requests/GetBeatmapDetailsRequest.cs | 4 +--- .../Online/API/Requests/GetBeatmapRequest.cs | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 osu.Game/Online/API/Requests/GetBeatmapRequest.cs diff --git a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs index ab840d054f..e3865be5fb 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs @@ -10,13 +10,11 @@ namespace osu.Game.Online.API.Requests { private readonly BeatmapInfo beatmap; - private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}"; - public GetBeatmapDetailsRequest(BeatmapInfo beatmap) { this.beatmap = beatmap; } - protected override string Target => $@"beatmaps/{lookupString}"; + protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}"; } } diff --git a/osu.Game/Online/API/Requests/GetBeatmapRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapRequest.cs new file mode 100644 index 0000000000..9958d252ab --- /dev/null +++ b/osu.Game/Online/API/Requests/GetBeatmapRequest.cs @@ -0,0 +1,22 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class GetBeatmapRequest : APIRequest + { + private readonly BeatmapInfo beatmap; + + private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}"; + + public GetBeatmapRequest(BeatmapInfo beatmap) + { + this.beatmap = beatmap; + } + + protected override string Target => $@"beatmaps/{lookupString}"; + } +} From 8220e0c79ab20a81b15785924b044b24085bbae0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 12:46:34 +0900 Subject: [PATCH 112/306] Remove OnlineBeatmapSetID from BeatmapMetadata --- .../Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 2 +- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 2 +- osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs | 11 +++++++---- osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs | 2 -- osu.Game.Tests/Visual/TestCasePlaySongSelect.cs | 1 - osu.Game/Beatmaps/BeatmapManager.cs | 11 +++++------ osu.Game/Beatmaps/BeatmapMetadata.cs | 13 +------------ osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 1 - .../Online/API/Requests/Responses/APIBeatmap.cs | 8 ++++++-- .../Online/API/Requests/Responses/APIBeatmapSet.cs | 9 +++++++++ 10 files changed, 30 insertions(+), 30 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 4985aa9365..6a7a4eeaf7 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual(string.Empty, metadata.Source); Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags); Assert.AreEqual(557821, beatmapInfo.OnlineBeatmapID); - Assert.AreEqual(241526, metadata.OnlineBeatmapSetID); + Assert.AreEqual(241526, beatmapInfo.OnlineBeatmapSetID); } } diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 489c38c420..053485273f 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Beatmaps.Formats { var beatmap = decodeAsJson(normal); var meta = beatmap.BeatmapInfo.Metadata; - Assert.AreEqual(241526, meta.OnlineBeatmapSetID); + Assert.AreEqual(241526, beatmap.BeatmapInfo.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index f9b055ed55..665229f8c3 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -48,11 +48,14 @@ namespace osu.Game.Tests.Beatmaps.IO { var reader = new ZipArchiveReader(osz); - BeatmapMetadata meta; - using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) - meta = Decoder.GetDecoder(stream).Decode(stream).Metadata; + Beatmap beatmap; - Assert.AreEqual(241526, meta.OnlineBeatmapSetID); + using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) + beatmap = Decoder.GetDecoder(stream).Decode(stream); + + var meta = beatmap.Metadata; + + Assert.AreEqual(241526, beatmap.BeatmapInfo.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs index 4679fca855..6d2b37d981 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs @@ -449,7 +449,6 @@ namespace osu.Game.Tests.Visual Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), Metadata = new BeatmapMetadata { - OnlineBeatmapSetID = id, // Create random metadata, then we can check if sorting works based on these Artist = $"peppy{id.ToString().PadLeft(6, '0')}", Title = $"test set #{id}!", @@ -503,7 +502,6 @@ namespace osu.Game.Tests.Visual Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), Metadata = new BeatmapMetadata { - OnlineBeatmapSetID = id, // Create random metadata, then we can check if sorting works based on these Artist = $"peppy{id.ToString().PadLeft(6, '0')}", Title = $"test set #{id}!", diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 10121738f1..dab7f7e037 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -122,7 +122,6 @@ namespace osu.Game.Tests.Visual Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), Metadata = new BeatmapMetadata { - OnlineBeatmapSetID = 1234 + i, // Create random metadata, then we can check if sorting works based on these Artist = "MONACA " + RNG.Next(0, 9), Title = "Black Song " + RNG.Next(0, 9), diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 806bcc4132..589c00638f 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -306,22 +306,22 @@ namespace osu.Game.Beatmaps return hashable.ComputeSHA2Hash(); } - protected override BeatmapSetInfo CreateModel(ArchiveReader reader) + protected override BeatmapSetInfo CreateModel(ArchiveReader reader) { // let's make sure there are actually .osu files to import. string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu")); if (string.IsNullOrEmpty(mapName)) throw new InvalidOperationException("No beatmap files found in this beatmap archive."); - BeatmapMetadata metadata; + Beatmap beatmap; using (var stream = new StreamReader(reader.GetStream(mapName))) - metadata = Decoder.GetDecoder(stream).Decode(stream).Metadata; + beatmap = Decoder.GetDecoder(stream).Decode(stream); return new BeatmapSetInfo { - OnlineBeatmapSetID = metadata.OnlineBeatmapSetID, + OnlineBeatmapSetID = beatmap.BeatmapInfo.OnlineBeatmapSetID, Beatmaps = new List(), Hash = computeBeatmapSetHash(reader), - Metadata = metadata + Metadata = beatmap.Metadata }; } @@ -350,7 +350,6 @@ namespace osu.Game.Beatmaps // ensure we have the same online set ID as the set itself. beatmap.BeatmapInfo.OnlineBeatmapSetID = model.OnlineBeatmapSetID; - beatmap.BeatmapInfo.Metadata.OnlineBeatmapSetID = model.OnlineBeatmapSetID; // check that no existing beatmap exists that is imported with the same online beatmap ID. if so, give it precedence. if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue && QueryBeatmap(b => b.OnlineBeatmapID.Value == beatmap.BeatmapInfo.OnlineBeatmapID.Value) != null) diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 34147c18d2..6c1bcd0531 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -17,16 +17,6 @@ namespace osu.Game.Beatmaps [JsonIgnore] public int ID { get; set; } - private int? onlineBeatmapSetID; - - [NotMapped] - [JsonProperty(@"id")] - public int? OnlineBeatmapSetID - { - get { return onlineBeatmapSetID; } - set { onlineBeatmapSetID = value > 0 ? value : null; } - } - public string Title { get; set; } public string TitleUnicode { get; set; } public string Artist { get; set; } @@ -82,8 +72,7 @@ namespace osu.Game.Beatmaps if (other == null) return false; - return onlineBeatmapSetID == other.onlineBeatmapSetID - && Title == other.Title + return Title == other.Title && TitleUnicode == other.TitleUnicode && Artist == other.Artist && ArtistUnicode == other.ArtistUnicode diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index a83ac26fb3..ee2c608fd7 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -208,7 +208,6 @@ namespace osu.Game.Beatmaps.Formats break; case @"BeatmapSetID": beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value); - metadata.OnlineBeatmapSetID = int.Parse(pair.Value); break; } } diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index f75d320a46..01a4453657 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -10,7 +10,10 @@ namespace osu.Game.Online.API.Requests.Responses public class APIBeatmap : BeatmapMetadata { [JsonProperty(@"id")] - private int onlineBeatmapID { get; set; } + public int OnlineBeatmapID { get; set; } + + [JsonProperty(@"beatmapset_id")] + public int OnlineBeatmapSetID { get; set; } [JsonProperty(@"playcount")] private int playCount { get; set; } @@ -55,7 +58,8 @@ namespace osu.Game.Online.API.Requests.Responses Metadata = this, Ruleset = rulesets.GetRuleset(ruleset), StarDifficulty = starDifficulty, - OnlineBeatmapID = onlineBeatmapID, + OnlineBeatmapID = OnlineBeatmapID, + OnlineBeatmapSetID = OnlineBeatmapSetID, Version = version, BaseDifficulty = new BeatmapDifficulty { diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index f57de016a2..3b6bb565b0 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -15,6 +15,15 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"covers")] private BeatmapSetOnlineCovers covers { get; set; } + private int? onlineBeatmapSetID; + + [JsonProperty(@"id")] + public int? OnlineBeatmapSetID + { + get { return onlineBeatmapSetID; } + set { onlineBeatmapSetID = value > 0 ? value : null; } + } + [JsonProperty(@"preview_url")] private string preview { get; set; } From ee64760406c6217944475f5f24f3f185fb1affb4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Jun 2018 14:28:27 +0900 Subject: [PATCH 113/306] Add mania stage test case --- .../TestCaseStage.cs | 46 +++++++++++++++++++ osu.Game.Rulesets.Mania/UI/Column.cs | 2 +- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 6 +-- .../UI/ManiaRulesetContainer.cs | 2 +- osu.Game.Rulesets.Mania/UI/ManiaStage.cs | 6 +-- 5 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs new file mode 100644 index 0000000000..bcdee7b688 --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs @@ -0,0 +1,46 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Mania.Beatmaps; +using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.UI.Scrolling; +using OpenTK; + +namespace osu.Game.Rulesets.Mania.Tests +{ + [TestFixture] + public class TestCaseStage : ManiaInputTestCase + { + public TestCaseStage() + : base(4) + { + } + + [BackgroundDependencyLoader] + private void load() + { + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Spacing = new Vector2(20, 0), + Children = new[] + { + createStage(ScrollingDirection.Up, ManiaAction.Key1), + createStage(ScrollingDirection.Down, ManiaAction.Key3) + } + }; + } + + private ManiaStage createStage(ScrollingDirection direction, ManiaAction action) + { + var specialAction = ManiaAction.Special1; + return new ManiaStage(direction, 0, new StageDefinition { Columns = 2 }, ref action, ref specialAction); + } + } +} diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 81607795fe..e71a95f3dc 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Mania.UI protected override Container Content => hitObjectArea; - public Column(ScrollingDirection direction = ScrollingDirection.Up) + public Column(ScrollingDirection direction) : base(direction) { RelativeSizeAxes = Axes.Y; diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 153d4698e1..73362ab28f 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -21,8 +21,8 @@ namespace osu.Game.Rulesets.Mania.UI public List Columns => stages.SelectMany(x => x.Columns).ToList(); private readonly List stages = new List(); - public ManiaPlayfield(List stageDefinitions) - : base(ScrollingDirection.Up) + public ManiaPlayfield(ScrollingDirection direction, List stageDefinitions) + : base(direction) { if (stageDefinitions == null) throw new ArgumentNullException(nameof(stageDefinitions)); @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Mania.UI int firstColumnIndex = 0; for (int i = 0; i < stageDefinitions.Count; i++) { - var newStage = new ManiaStage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction); + var newStage = new ManiaStage(direction, firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction); newStage.VisibleTimeRange.BindTo(VisibleTimeRange); playfieldGrid.Content[0][i] = newStage; diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index 7123aab901..b7acd1d5ee 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Mania.UI BarLines.ForEach(Playfield.Add); } - protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages) + protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(ScrollingDirection.Up, Beatmap.Stages) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs index 41af5fef38..822042362f 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs @@ -43,8 +43,8 @@ namespace osu.Game.Rulesets.Mania.UI private readonly int firstColumnIndex; - public ManiaStage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction) - : base(ScrollingDirection.Up) + public ManiaStage(ScrollingDirection direction, int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction) + : base(direction) { this.firstColumnIndex = firstColumnIndex; @@ -125,7 +125,7 @@ namespace osu.Game.Rulesets.Mania.UI for (int i = 0; i < definition.Columns; i++) { var isSpecial = definition.IsSpecialColumn(i); - var column = new Column + var column = new Column(direction) { IsSpecial = isSpecial, Action = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ From b265f02d56025665f86b216e9b08e277b32b5c2c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 14:37:27 +0900 Subject: [PATCH 114/306] Add comment about scheduled invocation --- osu.Game/Online/API/APIRequest.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index dfd181b98a..c89f8ce292 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -24,6 +24,10 @@ namespace osu.Game.Online.API Success?.Invoke(((JsonWebRequest)WebRequest).ResponseObject); } + /// + /// Invoked on successful completion of an API request. + /// This will be scheduled to the API's internal scheduler (run on update thread automatically). + /// public new event APISuccessHandler Success; } @@ -52,7 +56,16 @@ namespace osu.Game.Online.API protected APIAccess API; protected WebRequest WebRequest; + /// + /// Invoked on successful completion of an API request. + /// This will be scheduled to the API's internal scheduler (run on update thread automatically). + /// public event APISuccessHandler Success; + + /// + /// Invoked on failure to complete an API request. + /// This will be scheduled to the API's internal scheduler (run on update thread automatically). + /// public event APIFailureHandler Failure; private bool cancelled; From 21c8ef576c50bccea501e36743d6c0b5fc5edbe4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 14:37:48 +0900 Subject: [PATCH 115/306] Expose result for synchronous consumption --- osu.Game/Online/API/APIRequest.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index c89f8ce292..adbedb2aac 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -14,15 +14,14 @@ namespace osu.Game.Online.API { protected override WebRequest CreateWebRequest() => new JsonWebRequest(Uri); + public T Result => ((JsonWebRequest)WebRequest).ResponseObject; + protected APIRequest() { base.Success += onSuccess; } - private void onSuccess() - { - Success?.Invoke(((JsonWebRequest)WebRequest).ResponseObject); - } + private void onSuccess() => Success?.Invoke(Result); /// /// Invoked on successful completion of an API request. From e8455dc1e41ca92d0f9d1118af1187da88aba740 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 14:38:04 +0900 Subject: [PATCH 116/306] Fix incorrect hash usage --- osu.Game/Online/API/Requests/GetBeatmapRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/GetBeatmapRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapRequest.cs index 9958d252ab..9d254ce29d 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapRequest.cs @@ -10,7 +10,7 @@ namespace osu.Game.Online.API.Requests { private readonly BeatmapInfo beatmap; - private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}"; + private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.MD5Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}"; public GetBeatmapRequest(BeatmapInfo beatmap) { From 2a48e0e44a1b299051a57a63d9d807792b40e04e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Jun 2018 14:49:45 +0900 Subject: [PATCH 117/306] Fix sequential speed change visualiser not working with 0 control points --- .../Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs index e353c07e9f..745352a4d3 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs @@ -93,6 +93,9 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers /// A positive value indicating the position at . private double positionAt(double time, double timeRange) { + if (controlPoints.Count == 0) + return time / timeRange; + double length = 0; // We need to consider all timing points until the specified time and not just the currently-active one, From d6f230f2b03a753249dbde252d73c37776fb9b8e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Jun 2018 15:16:14 +0900 Subject: [PATCH 118/306] Add notes to TestCaseColumn --- .../TestCaseColumn.cs | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs index 05c7e99a18..cd1eb43853 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs @@ -7,6 +7,10 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.UI.Scrolling; @@ -26,6 +30,8 @@ namespace osu.Game.Rulesets.Mania.Tests typeof(ColumnHitObjectArea) }; + private readonly List columns = new List(); + public TestCaseColumn() : base(2) { @@ -48,13 +54,38 @@ namespace osu.Game.Rulesets.Mania.Tests }; } - private Column createColumn(ScrollingDirection direction, ManiaAction action) => new Column(direction) + protected override void LoadComplete() { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Height = 0.85f, - AccentColour = Color4.OrangeRed, - Action = action - }; + base.LoadComplete(); + + AddStep("note", createNote); + } + + private void createNote() + { + for (int i = 0; i < columns.Count; i++) + { + var obj = new Note { Column = i, StartTime = Time.Current + 2000 }; + obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + columns[i].Add(new DrawableNote(obj, columns[i].Action)); + } + } + + private Column createColumn(ScrollingDirection direction, ManiaAction action) + { + var column = new Column(direction) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Height = 0.85f, + AccentColour = Color4.OrangeRed, + Action = action, + VisibleTimeRange = { Value = 2000 } + }; + + columns.Add(column); + return column; + } } } From 80a577f1823733be9d129d28302810d12205a11c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Jun 2018 15:16:45 +0900 Subject: [PATCH 119/306] Fix notes not scrolling correctly --- .../Drawables/DrawableManiaHitObject.cs | 23 ++++++++++++++++++- osu.Game.Rulesets.Mania/UI/Column.cs | 7 ++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index fbf1ee8460..61a7f96c91 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -3,10 +3,31 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Objects.Drawables { - public abstract class DrawableManiaHitObject : DrawableHitObject + public abstract class DrawableManiaHitObject : DrawableHitObject + { + protected DrawableManiaHitObject(ManiaHitObject hitObject) + : base(hitObject) + { + } + + /// + /// Sets the scrolling direction. + /// + public virtual ScrollingDirection Direction + { + set + { + Anchor = value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; + Origin = Anchor; + } + } + } + + public abstract class DrawableManiaHitObject : DrawableManiaHitObject where TObject : ManiaHitObject { /// diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index e71a95f3dc..6f3d82a464 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -9,6 +9,7 @@ using osu.Game.Rulesets.Objects.Drawables; using System.Linq; using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.UI.Scrolling; @@ -35,6 +36,8 @@ namespace osu.Game.Rulesets.Mania.UI } } + private readonly ScrollingDirection direction; + private readonly ColumnBackground background; private readonly ColumnKeyArea keyArea; private readonly ColumnHitObjectArea hitObjectArea; @@ -47,6 +50,7 @@ namespace osu.Game.Rulesets.Mania.UI public Column(ScrollingDirection direction) : base(direction) { + this.direction = direction; RelativeSizeAxes = Axes.Y; Width = column_width; @@ -130,6 +134,9 @@ namespace osu.Game.Rulesets.Mania.UI /// The DrawableHitObject to add. public override void Add(DrawableHitObject hitObject) { + var maniaObject = (DrawableManiaHitObject)hitObject; + maniaObject.Direction = direction; + hitObject.AccentColour = AccentColour; hitObject.OnJudgement += OnJudgement; From d73c2a1654a481294158be3c4ebc2184963dc317 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Jun 2018 15:17:22 +0900 Subject: [PATCH 120/306] Fix various note elements not following the scroll direction --- .../Objects/Drawables/DrawableNote.cs | 13 +++++++++++++ .../Objects/Drawables/Pieces/NotePiece.cs | 10 ++++++++++ 2 files changed, 23 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index 3de0a9c5cc..a8666405cc 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -9,6 +9,7 @@ using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Objects.Drawables { @@ -38,6 +39,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables }; } + public override ScrollingDirection Direction + { + set + { + base.Direction = value; + + headPiece.Direction = value; + headPiece.Anchor = Anchor; + headPiece.Origin = Origin; + } + } + public override Color4 AccentColour { get { return base.AccentColour; } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs index 9ebeb91e0c..952ddd074e 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces { @@ -42,6 +43,15 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces }; } + public ScrollingDirection Direction + { + set + { + colouredBox.Anchor = value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; + colouredBox.Origin = colouredBox.Anchor; + } + } + private Color4 accentColour; public Color4 AccentColour { From 7deaffdb62b0a2247b49fae5fcdf419ad8749fc4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Jun 2018 15:23:47 +0900 Subject: [PATCH 121/306] Fix hit explosions not following the scroll direction --- osu.Game.Rulesets.Mania/UI/Column.cs | 5 ++++- osu.Game.Rulesets.Mania/UI/HitExplosion.cs | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 6f3d82a464..26269ff537 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -148,7 +148,10 @@ namespace osu.Game.Rulesets.Mania.UI if (!judgement.IsHit || !judgedObject.DisplayJudgement) return; - explosionContainer.Add(new HitExplosion(judgedObject)); + explosionContainer.Add(new HitExplosion(judgedObject) + { + Anchor = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre + }); } public bool OnPressed(ManiaAction action) diff --git a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs index f19c3a811b..e3f0656000 100644 --- a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs @@ -21,7 +21,6 @@ namespace osu.Game.Rulesets.Mania.UI { bool isTick = judgedObject is DrawableHoldNoteTick; - Anchor = Anchor.TopCentre; Origin = Anchor.Centre; RelativeSizeAxes = Axes.X; From 955a78e76d491e438c4f54b4e26f21381faf2826 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 15:26:27 +0900 Subject: [PATCH 122/306] Remove OnlineBeatmapSetID from BeatmapInfo It should now be retrieved via the linked BeatmapSetInfo --- .../Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 2 +- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 2 +- osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs | 2 +- .../Visual/TestCaseBeatmapScoresContainer.cs | 2 +- osu.Game/Beatmaps/BeatmapInfo.cs | 14 ++------------ osu.Game/Beatmaps/BeatmapManager.cs | 9 +++------ osu.Game/Beatmaps/BeatmapSetInfo.cs | 6 +++--- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 6 ++++-- .../Online/API/Requests/Responses/APIBeatmap.cs | 5 ++++- .../Requests/Responses/APIUserMostPlayedBeatmap.cs | 1 - .../Profile/Sections/BeatmapMetadataContainer.cs | 2 +- 11 files changed, 21 insertions(+), 30 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 6a7a4eeaf7..1628423fe8 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual(string.Empty, metadata.Source); Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags); Assert.AreEqual(557821, beatmapInfo.OnlineBeatmapID); - Assert.AreEqual(241526, beatmapInfo.OnlineBeatmapSetID); + Assert.AreEqual(241526, beatmapInfo.BeatmapSet.OnlineBeatmapSetID); } } diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 053485273f..b834be71f1 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Beatmaps.Formats { var beatmap = decodeAsJson(normal); var meta = beatmap.BeatmapInfo.Metadata; - Assert.AreEqual(241526, beatmap.BeatmapInfo.OnlineBeatmapSetID); + Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index 665229f8c3..0039516c0c 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -55,7 +55,7 @@ namespace osu.Game.Tests.Beatmaps.IO var meta = beatmap.Metadata; - Assert.AreEqual(241526, beatmap.BeatmapInfo.OnlineBeatmapSetID); + Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs index 3f63bacfa6..d3098864f4 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs @@ -52,7 +52,7 @@ namespace osu.Game.Tests.Visual AddStep("remove scores", () => scoresContainer.Scores = null); AddStep("resize to big", () => container.ResizeWidthTo(1, 300)); AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300)); - AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapSetID = 1, OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo }); + AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo }); scores = new[] diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 40d62103a8..3afc3c4d32 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -23,7 +23,6 @@ namespace osu.Game.Beatmaps public int BeatmapVersion; private int? onlineBeatmapID; - private int? onlineBeatmapSetID; [JsonProperty("id")] public int? OnlineBeatmapID @@ -32,19 +31,10 @@ namespace osu.Game.Beatmaps set { onlineBeatmapID = value > 0 ? value : null; } } - [JsonProperty("beatmapset_id")] - [NotMapped] - public int? OnlineBeatmapSetID - { - get { return onlineBeatmapSetID; } - set { onlineBeatmapSetID = value > 0 ? value : null; } - } - [JsonIgnore] public int BeatmapSetInfoID { get; set; } [Required] - [JsonIgnore] public BeatmapSetInfo BeatmapSet { get; set; } public BeatmapMetadata Metadata { get; set; } @@ -141,8 +131,8 @@ namespace osu.Game.Beatmaps (Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile; public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null && - BeatmapSet.Hash == other.BeatmapSet.Hash && - (Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile; + BeatmapSet.Hash == other.BeatmapSet.Hash && + (Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile; /// /// Returns a shallow-clone of this . diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 589c00638f..526f2488ea 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -81,7 +81,7 @@ namespace osu.Game.Beatmaps protected override void Populate(BeatmapSetInfo model, ArchiveReader archive) { - model.Beatmaps = createBeatmapDifficulties(model, archive); + model.Beatmaps = createBeatmapDifficulties(archive); // remove metadata from difficulties where it matches the set foreach (BeatmapInfo b in model.Beatmaps) @@ -318,7 +318,7 @@ namespace osu.Game.Beatmaps return new BeatmapSetInfo { - OnlineBeatmapSetID = beatmap.BeatmapInfo.OnlineBeatmapSetID, + OnlineBeatmapSetID = beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID, Beatmaps = new List(), Hash = computeBeatmapSetHash(reader), Metadata = beatmap.Metadata @@ -328,7 +328,7 @@ namespace osu.Game.Beatmaps /// /// Create all required s for the provided archive. /// - private List createBeatmapDifficulties(BeatmapSetInfo model, ArchiveReader reader) + private List createBeatmapDifficulties(ArchiveReader reader) { var beatmapInfos = new List(); @@ -348,9 +348,6 @@ namespace osu.Game.Beatmaps beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash(); beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash(); - // ensure we have the same online set ID as the set itself. - beatmap.BeatmapInfo.OnlineBeatmapSetID = model.OnlineBeatmapSetID; - // check that no existing beatmap exists that is imported with the same online beatmap ID. if so, give it precedence. if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue && QueryBeatmap(b => b.OnlineBeatmapID.Value == beatmap.BeatmapInfo.OnlineBeatmapID.Value) != null) beatmap.BeatmapInfo.OnlineBeatmapID = null; diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index fa08c6cb68..ed8fbdbb26 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -22,18 +22,18 @@ namespace osu.Game.Beatmaps [NotMapped] public BeatmapSetOnlineInfo OnlineInfo { get; set; } - public double MaxStarDifficulty => Beatmaps.Max(b => b.StarDifficulty); + public double MaxStarDifficulty => Beatmaps?.Max(b => b.StarDifficulty) ?? 0; [NotMapped] public bool DeletePending { get; set; } public string Hash { get; set; } - public string StoryboardFile => Files.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename; + public string StoryboardFile => Files?.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename; public List Files { get; set; } - public override string ToString() => Metadata.ToString(); + public override string ToString() => Metadata?.ToString() ?? base.ToString(); public bool Protected { get; set; } } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index ee2c608fd7..581207607a 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -34,7 +34,8 @@ namespace osu.Game.Beatmaps.Formats private readonly int offset; - public LegacyBeatmapDecoder(int version = LATEST_VERSION) : base(version) + public LegacyBeatmapDecoder(int version = LATEST_VERSION) + : base(version) { // BeatmapVersion 4 and lower had an incorrect offset (stable has this set as 24ms off) offset = FormatVersion < 5 ? 24 : 0; @@ -135,6 +136,7 @@ namespace osu.Game.Beatmaps.Formats parser = new Rulesets.Objects.Legacy.Mania.ConvertHitObjectParser(); break; } + break; case @"LetterboxInBreaks": beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1; @@ -207,7 +209,7 @@ namespace osu.Game.Beatmaps.Formats beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value); break; case @"BeatmapSetID": - beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value); + beatmap.BeatmapInfo.BeatmapSet = new BeatmapSetInfo { OnlineBeatmapSetID = int.Parse(pair.Value) }; break; } } diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index 01a4453657..99e4392374 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -59,7 +59,10 @@ namespace osu.Game.Online.API.Requests.Responses Ruleset = rulesets.GetRuleset(ruleset), StarDifficulty = starDifficulty, OnlineBeatmapID = OnlineBeatmapID, - OnlineBeatmapSetID = OnlineBeatmapSetID, + BeatmapSet = new BeatmapSetInfo + { + OnlineBeatmapSetID = OnlineBeatmapSetID, + }, Version = version, BaseDifficulty = new BeatmapDifficulty { diff --git a/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs index d49613eab7..8a5aea9e97 100644 --- a/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs @@ -25,7 +25,6 @@ namespace osu.Game.Online.API.Requests.Responses { BeatmapSetInfo setInfo = beatmapSet.ToBeatmapSet(rulesets); beatmap.BeatmapSet = setInfo; - beatmap.OnlineBeatmapSetID = setInfo.OnlineBeatmapSetID; beatmap.Metadata = setInfo.Metadata; return beatmap; } diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs index 97079c77f3..359bfc7564 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Profile.Sections { Action = () => { - if (beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.OnlineBeatmapSetID.Value); + if (beatmap.BeatmapSet?.OnlineBeatmapSetID != null) beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.BeatmapSet.OnlineBeatmapSetID.Value); }; Child = new FillFlowContainer From c933dd4069aec242bcd1450fd2463099788e9fd3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Jun 2018 15:28:57 +0900 Subject: [PATCH 123/306] Add hold notes to TestCaseColumn --- osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs index cd1eb43853..ced64e21e9 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs @@ -59,6 +59,7 @@ namespace osu.Game.Rulesets.Mania.Tests base.LoadComplete(); AddStep("note", createNote); + AddStep("hold note", createHoldNote); } private void createNote() @@ -72,6 +73,17 @@ namespace osu.Game.Rulesets.Mania.Tests } } + private void createHoldNote() + { + for (int i = 0; i < columns.Count; i++) + { + var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 }; + obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + columns[i].Add(new DrawableHoldNote(obj, columns[i].Action)); + } + } + private Column createColumn(ScrollingDirection direction, ManiaAction action) { var column = new Column(direction) From 5c8bea82f8e53cad4d5d15ffc97bd2dd7ef644df Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Jun 2018 15:29:08 +0900 Subject: [PATCH 124/306] Fix scroll direction not applying to nested hitobjects --- .../Objects/Drawables/DrawableManiaHitObject.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index 61a7f96c91..89fe0b1945 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; using osu.Framework.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; @@ -23,6 +24,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables { Anchor = value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; Origin = Anchor; + + if (!HasNestedHitObjects) + return; + + foreach (var obj in NestedHitObjects.OfType()) + obj.Direction = value; } } } From a775d00bd87bc96c75e31ab4890db3d20b99b5d2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 15:59:45 +0900 Subject: [PATCH 125/306] Add online fetch support for online IDs --- osu.Game/Beatmaps/BeatmapManager.cs | 69 +++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 526f2488ea..895b47d62b 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -83,10 +83,29 @@ namespace osu.Game.Beatmaps { model.Beatmaps = createBeatmapDifficulties(archive); - // remove metadata from difficulties where it matches the set foreach (BeatmapInfo b in model.Beatmaps) + { + // remove metadata from difficulties where it matches the set if (model.Metadata.Equals(b.Metadata)) b.Metadata = null; + + // by setting the model here, we can update the noline set id below. + b.BeatmapSet = model; + + fetchAndPopulateOnlineIDs(b); + } + + // check if a set already exists with the same online id, delete if it does. + if (model.OnlineBeatmapSetID != null) + { + var existingOnlineId = beatmaps.ConsumableItems.FirstOrDefault(b => b.OnlineBeatmapSetID == model.OnlineBeatmapSetID); + if (existingOnlineId != null) + { + Delete(existingOnlineId); + beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID); + Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({model.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database); + } + } } protected override BeatmapSetInfo CheckForExisting(BeatmapSetInfo model) @@ -99,18 +118,6 @@ namespace osu.Game.Beatmaps return existingHashMatch; } - // check if a set already exists with the same online id - if (model.OnlineBeatmapSetID != null) - { - var existingOnlineId = beatmaps.ConsumableItems.FirstOrDefault(b => b.OnlineBeatmapSetID == model.OnlineBeatmapSetID); - if (existingOnlineId != null) - { - Delete(existingOnlineId); - beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID); - Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({model.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database); - } - } - return null; } @@ -318,7 +325,7 @@ namespace osu.Game.Beatmaps return new BeatmapSetInfo { - OnlineBeatmapSetID = beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID, + OnlineBeatmapSetID = beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID, Beatmaps = new List(), Hash = computeBeatmapSetHash(reader), Metadata = beatmap.Metadata @@ -372,6 +379,40 @@ namespace osu.Game.Beatmaps return beatmapInfos; } + /// + /// Query the API to populate mising OnlineBeatmapID / OnlineBeatmapSetID properties. + /// + /// The beatmap to populate. + /// Whether to re-query if the provided beatmap already has populated values. + /// True if population was successful. + private bool fetchAndPopulateOnlineIDs(BeatmapInfo beatmap, bool force = false) + { + if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null) + return true; + + Logger.Log("Attempting online lookup for IDs...", LoggingTarget.Database); + + try + { + var req = new GetBeatmapRequest(beatmap); + + req.Perform(api); + + var res = req.Result; + + Logger.Log($"Successfully mapped to {res.OnlineBeatmapSetID} / {res.OnlineBeatmapID}.", LoggingTarget.Database); + + beatmap.BeatmapSet.OnlineBeatmapSetID = res.OnlineBeatmapSetID; + beatmap.OnlineBeatmapID = res.OnlineBeatmapID; + return true; + } + catch (Exception e) + { + Logger.Log($"Failed ({e})", LoggingTarget.Database); + return false; + } + } + /// /// A dummy WorkingBeatmap for the purpose of retrieving a beatmap for star difficulty calculation. /// From e1bc0fa552256ee256b12ce62865ebc832986023 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 15:59:59 +0900 Subject: [PATCH 126/306] Fix csproj file ending line --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 363fc7d7bb..f5ff1fbd53 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,4 +23,4 @@ - + \ No newline at end of file From 4dfc328117ef886489825ea5770b1e137dfe330b Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Fri, 8 Jun 2018 17:46:38 +0900 Subject: [PATCH 127/306] Remove unused array --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index f6934484a2..5f803e3406 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -96,20 +96,6 @@ namespace osu.Game.Rulesets.Mania yield return new ManiaModSuddenDeath(); } - private static readonly Mod[] key_mods = - { - new MultiMod(), - new ManiaModKey1(), - new ManiaModKey2(), - new ManiaModKey3(), - new ManiaModKey4(), - new ManiaModKey5(), - new ManiaModKey6(), - new ManiaModKey7(), - new ManiaModKey8(), - new ManiaModKey9(), - }; - public override IEnumerable GetModsFor(ModType type) { switch (type) From c010ea83ca37ed5e8b3b18354cec64cfbe3ca71c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Jun 2018 18:10:07 +0900 Subject: [PATCH 128/306] Add note hitobject testcase --- .../TestCaseNotes.cs | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs new file mode 100644 index 0000000000..bb12bb35db --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs @@ -0,0 +1,165 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mania.Objects.Drawables; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Tests.Visual; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Rulesets.Mania.Tests +{ + [TestFixture] + public class TestCaseNotes : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(DrawableNote), + typeof(DrawableHoldNote) + }; + + [BackgroundDependencyLoader] + private void load() + { + Child = new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(20), + Children = new[] + { + createNoteDisplay(ScrollingDirection.Down), + createNoteDisplay(ScrollingDirection.Up), + createHoldNoteDisplay(ScrollingDirection.Down), + createHoldNoteDisplay(ScrollingDirection.Up), + } + }; + } + + private Drawable createNoteDisplay(ScrollingDirection direction) + { + var note = new Note { StartTime = 999999999 }; + note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + return new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLower()}") + { + Child = new DrawableNote(note, ManiaAction.Key1) + { + AccentColour = Color4.OrangeRed, + Direction = direction + } + }; + } + + private Drawable createHoldNoteDisplay(ScrollingDirection direction) + { + var note = new HoldNote { StartTime = 999999999, Duration = 1000 }; + note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + return new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLower()}") + { + Child = new DrawableHoldNote(note, ManiaAction.Key1) + { + RelativeSizeAxes = Axes.Both, + AccentColour = Color4.OrangeRed, + Direction = direction + } + }; + } + + private class NoteContainer : Container + { + private readonly Container content; + protected override Container Content => content; + + private readonly ScrollingDirection direction; + + public NoteContainer(ScrollingDirection direction, string description) + { + this.direction = direction; + AutoSizeAxes = Axes.Both; + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(0, 10), + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Width = 45, + Height = 100, + Children = new Drawable[] + { + new Box + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Both, + Width = 1.25f, + Colour = Color4.Black.Opacity(0.5f) + }, + content = new Container { RelativeSizeAxes = Axes.Both } + } + }, + new SpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + TextSize = 14, + Text = description + } + } + }; + } + + protected override void Update() + { + base.Update(); + + foreach (var obj in content.OfType()) + { + if (!(obj.HitObject is IHasEndTime endTime)) + continue; + + if (!obj.HasNestedHitObjects) + continue; + + foreach (var nested in obj.NestedHitObjects) + { + double finalPosition = (nested.HitObject.StartTime - obj.HitObject.StartTime) / endTime.Duration; + switch (direction) + { + case ScrollingDirection.Up: + nested.Y = (float)(finalPosition * content.DrawHeight); + break; + case ScrollingDirection.Down: + nested.Y = (float)(-finalPosition * content.DrawHeight); + break; + } + } + } + } + } + } +} From 0fb4e6b41b5fba0b9bbb75664d8627f3b85c4fc6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Jun 2018 18:16:55 +0900 Subject: [PATCH 129/306] Fix hold note body not following the scroll direction --- .../Objects/Drawables/DrawableHoldNote.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index e008fa952e..6ae78ec4d0 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Mania.Judgements; using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Objects.Drawables { @@ -75,6 +76,19 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables AddNested(tail); } + private ScrollingDirection direction; + public override ScrollingDirection Direction + { + set + { + base.Direction = value; + direction = value; + + bodyPiece.Anchor = value == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + bodyPiece.Origin = bodyPiece.Anchor; + } + } + public override Color4 AccentColour { get { return base.AccentColour; } @@ -100,7 +114,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables base.Update(); // Make the body piece not lie under the head note - bodyPiece.Y = head.Height / 2; + bodyPiece.Y = (direction == ScrollingDirection.Up ? 1 : -1) * head.Height / 2; bodyPiece.Height = DrawHeight - head.Height / 2 + tail.Height / 2; } From cc37a355d26836cf655c911f3953e1b30f2d614d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 10 Jun 2018 01:44:46 +0900 Subject: [PATCH 130/306] Add comment about matching stable scoring Also updated equation to be close to what is expected --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 0568101aa7..b6ec0617f2 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -301,7 +301,8 @@ namespace osu.Game.Rulesets.Scoring TotalScore.Value = max_score * (base_portion * baseScore / maxBaseScore + combo_portion * HighestCombo / maxHighestCombo) + bonusScore; break; case ScoringMode.Exponential: - TotalScore.Value = (baseScore + bonusScore) * Math.Max(0, HighestCombo - 1) / 25f; + // should emulate osu-stable's scoring as closely as we can (https://osu.ppy.sh/help/wiki/Score/ScoreV1) + TotalScore.Value = bonusScore + baseScore * (1 + Math.Max(0, HighestCombo - 1) / 25); break; } } From 86fb9666b250f52e07a84b8248c98ab1c3560370 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 10 Jun 2018 01:45:05 +0900 Subject: [PATCH 131/306] Rename "Exponential" to "Classic" --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index b6ec0617f2..dd4120f2fb 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -202,7 +202,7 @@ namespace osu.Game.Rulesets.Scoring if (maxBaseScore == 0 || maxHighestCombo == 0) { - Mode.Value = ScoringMode.Exponential; + Mode.Value = ScoringMode.Classic; Mode.Disabled = true; } @@ -213,7 +213,7 @@ namespace osu.Game.Rulesets.Scoring /// Simulates an autoplay of s that will be judged by this /// by adding s for each in the . /// - /// This is required for to work, otherwise will be used. + /// This is required for to work, otherwise will be used. /// /// /// The containing the s that will be judged by this . @@ -300,7 +300,7 @@ namespace osu.Game.Rulesets.Scoring case ScoringMode.Standardised: TotalScore.Value = max_score * (base_portion * baseScore / maxBaseScore + combo_portion * HighestCombo / maxHighestCombo) + bonusScore; break; - case ScoringMode.Exponential: + case ScoringMode.Classic: // should emulate osu-stable's scoring as closely as we can (https://osu.ppy.sh/help/wiki/Score/ScoreV1) TotalScore.Value = bonusScore + baseScore * (1 + Math.Max(0, HighestCombo - 1) / 25); break; @@ -328,6 +328,6 @@ namespace osu.Game.Rulesets.Scoring public enum ScoringMode { Standardised, - Exponential + Classic } } From b219c171159e67601351441f317dfe751e656a89 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 12:57:26 +0900 Subject: [PATCH 132/306] Move dependency creation under ctor --- osu.Game/Rulesets/UI/RulesetContainer.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 384b71cccc..561e77b0c9 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -73,11 +73,6 @@ namespace osu.Game.Rulesets.UI private IRulesetConfigManager rulesetConfig; private OnScreenDisplay onScreenDisplay; - private DependencyContainer dependencies; - - protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) - => dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); - /// /// A visual representation of a . /// @@ -104,6 +99,11 @@ namespace osu.Game.Rulesets.UI } } + private DependencyContainer dependencies; + + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) + => dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); + public abstract ScoreProcessor CreateScoreProcessor(); /// From 63ec36b3be32b58af43a5e5a99ebc875b9ad5f68 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 12:57:56 +0900 Subject: [PATCH 133/306] Explicitly handle null settings case + add annotations --- osu.Game/Rulesets/UI/RulesetContainer.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 561e77b0c9..f604e876e7 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -13,6 +13,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Configuration; using osu.Framework.Graphics.Cursor; using osu.Framework.Input; @@ -86,16 +87,19 @@ namespace osu.Game.Rulesets.UI } [BackgroundDependencyLoader(true)] - private void load(OnScreenDisplay onScreenDisplay, SettingsStore settings) + private void load([CanBeNull] OnScreenDisplay onScreenDisplay, [CanBeNull] SettingsStore settings) { this.onScreenDisplay = onScreenDisplay; - rulesetConfig = CreateConfig(Ruleset, settings); - - if (rulesetConfig != null) + if (settings != null) { - dependencies.Cache(rulesetConfig); - onScreenDisplay?.BeginTracking(this, rulesetConfig); + rulesetConfig = CreateConfig(Ruleset, settings); + + if (rulesetConfig != null) + { + dependencies.Cache(rulesetConfig); + onScreenDisplay?.BeginTracking(this, rulesetConfig); + } } } From 22e8a0bb6ec70a12890e39f98b122528fb81aee6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 13:13:36 +0900 Subject: [PATCH 134/306] Make ruleset config manager variants nullable --- osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs | 2 +- osu.Game/Configuration/DatabasedConfigManager.cs | 4 ++-- osu.Game/Rulesets/Configuration/RulesetConfigManager.cs | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs b/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs index ea5f590bd1..d9e360081d 100644 --- a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs +++ b/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Mania.Configuration { public class ManiaConfigManager : RulesetConfigManager { - public ManiaConfigManager(SettingsStore settings, RulesetInfo ruleset, int variant) + public ManiaConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null) : base(settings, ruleset, variant) { } diff --git a/osu.Game/Configuration/DatabasedConfigManager.cs b/osu.Game/Configuration/DatabasedConfigManager.cs index 0ef0589dff..0ede6de0f2 100644 --- a/osu.Game/Configuration/DatabasedConfigManager.cs +++ b/osu.Game/Configuration/DatabasedConfigManager.cs @@ -13,13 +13,13 @@ namespace osu.Game.Configuration { private readonly SettingsStore settings; - private readonly int variant; + private readonly int? variant; private readonly List databasedSettings; private readonly RulesetInfo ruleset; - protected DatabasedConfigManager(SettingsStore settings, RulesetInfo ruleset = null, int variant = 0) + protected DatabasedConfigManager(SettingsStore settings, RulesetInfo ruleset = null, int? variant = null) { this.settings = settings; this.ruleset = ruleset; diff --git a/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs b/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs index 4ecf1eefb2..74cece5154 100644 --- a/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs +++ b/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs @@ -8,7 +8,8 @@ namespace osu.Game.Rulesets.Configuration public abstract class RulesetConfigManager : DatabasedConfigManager, IRulesetConfigManager where T : struct { - protected RulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int variant) : base(settings, ruleset, variant) + protected RulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null) + : base(settings, ruleset, variant) { } } From eca016ec6c8a54bf37ebf1afcb6b70ba8980d563 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 13:17:08 +0900 Subject: [PATCH 135/306] Move ruleset config managers to Ruleset --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 5 +++++ osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs | 5 ----- osu.Game/Rulesets/Ruleset.cs | 8 ++++++++ osu.Game/Rulesets/UI/RulesetContainer.cs | 4 +--- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 5f803e3406..e671a3fb14 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -15,8 +15,11 @@ using osu.Game.Graphics; using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Replays.Types; using osu.Game.Beatmaps.Legacy; +using osu.Game.Configuration; +using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mania.Beatmaps; +using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Difficulty; using osu.Game.Rulesets.Scoring; @@ -150,6 +153,8 @@ namespace osu.Game.Rulesets.Mania public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame(); + public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new ManiaConfigManager(settings, RulesetInfo); + public ManiaRuleset(RulesetInfo rulesetInfo = null) : base(rulesetInfo) { diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index 7123aab901..a3145d6035 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -10,12 +10,9 @@ using osu.Framework.Input; using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Configuration; using osu.Game.Input.Handlers; -using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Mods; -using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Replays; @@ -103,7 +100,5 @@ namespace osu.Game.Rulesets.Mania.UI protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f); protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay); - - protected override IRulesetConfigManager CreateConfig(Ruleset ruleset, SettingsStore settings) => new ManiaConfigManager(settings, Ruleset.RulesetInfo, Variant); } } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 395eeab419..f7f9d59dc6 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -15,6 +15,8 @@ using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Beatmaps.Legacy; +using osu.Game.Configuration; +using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Difficulty; namespace osu.Game.Rulesets @@ -71,6 +73,12 @@ namespace osu.Game.Rulesets public virtual SettingsSubsection CreateSettings() => null; + /// + /// Creates the for this . + /// + /// The to store the settings. + public virtual IRulesetConfigManager CreateConfig(SettingsStore settings) => null; + /// /// Do not override this unless you are a legacy mode. /// diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index f604e876e7..875745edfb 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.UI if (settings != null) { - rulesetConfig = CreateConfig(Ruleset, settings); + rulesetConfig = Ruleset.CreateConfig(settings); if (rulesetConfig != null) { @@ -140,8 +140,6 @@ namespace osu.Game.Rulesets.UI /// protected virtual CursorContainer CreateCursor() => null; - protected virtual IRulesetConfigManager CreateConfig(Ruleset ruleset, SettingsStore settings) => null; - /// /// Creates a Playfield. /// From f4fbf27d42877f4c769186e972e09f40f41866e3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 13:28:50 +0900 Subject: [PATCH 136/306] Give ruleset settings a ruleset-specific config manager --- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- osu.Game.Rulesets.Osu/UI/OsuSettings.cs | 7 +++- .../Settings/RulesetSettingsSubsection.cs | 36 +++++++++++++++++++ osu.Game/Rulesets/Ruleset.cs | 2 +- 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index b920e889ce..6ab75d008f 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -130,7 +130,7 @@ namespace osu.Game.Rulesets.Osu public override string ShortName => "osu"; - public override SettingsSubsection CreateSettings() => new OsuSettings(); + public override RulesetSettingsSubsection CreateSettings() => new OsuSettings(this); public override int? LegacyID => 0; diff --git a/osu.Game.Rulesets.Osu/UI/OsuSettings.cs b/osu.Game.Rulesets.Osu/UI/OsuSettings.cs index 31ad6701fd..25c009b117 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuSettings.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuSettings.cs @@ -8,10 +8,15 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Rulesets.Osu.UI { - public class OsuSettings : SettingsSubsection + public class OsuSettings : RulesetSettingsSubsection { protected override string Header => "osu!"; + public OsuSettings(Ruleset ruleset) + : base(ruleset) + { + } + [BackgroundDependencyLoader] private void load(OsuConfigManager config) { diff --git a/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs b/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs new file mode 100644 index 0000000000..8f8c18d1f0 --- /dev/null +++ b/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs @@ -0,0 +1,36 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Game.Configuration; +using osu.Game.Rulesets; + +namespace osu.Game.Overlays.Settings +{ + /// + /// A which provides subclasses with the + /// from the 's . + /// + public abstract class RulesetSettingsSubsection : SettingsSubsection + { + private readonly Ruleset ruleset; + + protected RulesetSettingsSubsection(Ruleset ruleset) + { + this.ruleset = ruleset; + } + + private DependencyContainer dependencies; + + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) + { + dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); + + var config = ruleset.CreateConfig(dependencies.Get()); + if (config != null) + dependencies.Cache(config); + + return dependencies; + } + } +} diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index f7f9d59dc6..a39e8bb8d4 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets public abstract string Description { get; } - public virtual SettingsSubsection CreateSettings() => null; + public virtual RulesetSettingsSubsection CreateSettings() => null; /// /// Creates the for this . From ca5103615df1241e7d8aac37678e7d26e4af1fc6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Jun 2018 20:13:24 +0900 Subject: [PATCH 137/306] DI the scrolling info rather than pass by ctor --- .../ScrollingTestContainer.cs | 29 +++++++++++++ .../TestCaseColumn.cs | 12 +++++- .../TestCaseNotes.cs | 22 ++++++---- .../TestCaseStage.cs | 12 +++++- .../Objects/Drawables/DrawableHoldNote.cs | 20 ++++----- .../Drawables/DrawableManiaHitObject.cs | 41 +++++-------------- .../Objects/Drawables/DrawableNote.cs | 24 ++++------- .../Objects/Drawables/Pieces/NotePiece.cs | 12 +++--- osu.Game.Rulesets.Mania/UI/Column.cs | 10 ++--- .../UI/Components/ColumnBackground.cs | 19 ++++----- .../UI/Components/ColumnHitObjectArea.cs | 17 +++----- .../UI/Components/ColumnKeyArea.cs | 13 ++---- .../UI/ManiaRulesetContainer.cs | 16 +++++++- osu.Game.Rulesets.Mania/UI/ScrollingInfo.cs | 17 ++++++++ 14 files changed, 146 insertions(+), 118 deletions(-) create mode 100644 osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs create mode 100644 osu.Game.Rulesets.Mania/UI/ScrollingInfo.cs diff --git a/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs b/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs new file mode 100644 index 0000000000..2b86c6187b --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs @@ -0,0 +1,29 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Mania.UI; + +namespace osu.Game.Rulesets.Mania.Tests +{ + /// + /// A container which provides a to children. + /// + public class ScrollingTestContainer : Container + { + private readonly ScrollingInfo scrollingInfo; + + public ScrollingTestContainer(ScrollingInfo scrollingInfo) + { + this.scrollingInfo = scrollingInfo; + } + + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); + dependencies.Cache(scrollingInfo); + return dependencies; + } + } +} diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs index ced64e21e9..d5f43b809e 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs @@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Mania.Tests } } - private Column createColumn(ScrollingDirection direction, ManiaAction action) + private Drawable createColumn(ScrollingDirection direction, ManiaAction action) { var column = new Column(direction) { @@ -97,7 +97,15 @@ namespace osu.Game.Rulesets.Mania.Tests }; columns.Add(column); - return column; + + return new ScrollingTestContainer(new ScrollingInfo(direction)) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Child = column + }; } } } diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs index bb12bb35db..3342060fe2 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs @@ -15,6 +15,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; +using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.UI.Scrolling; @@ -58,12 +59,12 @@ namespace osu.Game.Rulesets.Mania.Tests var note = new Note { StartTime = 999999999 }; note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - return new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLower()}") + return new ScrollingTestContainer(new ScrollingInfo(direction)) { - Child = new DrawableNote(note, ManiaAction.Key1) + AutoSizeAxes = Axes.Both, + Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLower()}") { - AccentColour = Color4.OrangeRed, - Direction = direction + Child = new DrawableNote(note, ManiaAction.Key1) { AccentColour = Color4.OrangeRed } } }; } @@ -73,13 +74,16 @@ namespace osu.Game.Rulesets.Mania.Tests var note = new HoldNote { StartTime = 999999999, Duration = 1000 }; note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - return new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLower()}") + return new ScrollingTestContainer(new ScrollingInfo(direction)) { - Child = new DrawableHoldNote(note, ManiaAction.Key1) + AutoSizeAxes = Axes.Both, + Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLower()}") { - RelativeSizeAxes = Axes.Both, - AccentColour = Color4.OrangeRed, - Direction = direction + Child = new DrawableHoldNote(note, ManiaAction.Key1) + { + RelativeSizeAxes = Axes.Both, + AccentColour = Color4.OrangeRed, + } } }; } diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs index bcdee7b688..2f639494bb 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs @@ -37,10 +37,18 @@ namespace osu.Game.Rulesets.Mania.Tests }; } - private ManiaStage createStage(ScrollingDirection direction, ManiaAction action) + private Drawable createStage(ScrollingDirection direction, ManiaAction action) { var specialAction = ManiaAction.Special1; - return new ManiaStage(direction, 0, new StageDefinition { Columns = 2 }, ref action, ref specialAction); + + return new ScrollingTestContainer(new ScrollingInfo(direction)) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Child = new ManiaStage(direction, 0, new StageDefinition { Columns = 2 }, ref action, ref specialAction) + }; } } } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 6ae78ec4d0..86bbc2c11d 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; @@ -9,6 +10,7 @@ using OpenTK.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Mania.Judgements; using osu.Framework.Input.Bindings; +using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI.Scrolling; @@ -36,6 +38,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// private bool hasBroken; + private ScrollingInfo scrollingInfo; + private readonly Container tickContainer; public DrawableHoldNote(HoldNote hitObject, ManiaAction action) @@ -76,17 +80,13 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables AddNested(tail); } - private ScrollingDirection direction; - public override ScrollingDirection Direction + [BackgroundDependencyLoader] + private void load(ScrollingInfo scrollingInfo) { - set - { - base.Direction = value; - direction = value; + this.scrollingInfo = scrollingInfo; - bodyPiece.Anchor = value == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; - bodyPiece.Origin = bodyPiece.Anchor; - } + bodyPiece.Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + bodyPiece.Origin = bodyPiece.Anchor; } public override Color4 AccentColour @@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables base.Update(); // Make the body piece not lie under the head note - bodyPiece.Y = (direction == ScrollingDirection.Up ? 1 : -1) * head.Height / 2; + bodyPiece.Y = (scrollingInfo.Direction == ScrollingDirection.Up ? 1 : -1) * head.Height / 2; bodyPiece.Height = DrawHeight - head.Height / 2 + tail.Height / 2; } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index 89fe0b1945..59f93eb16a 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -1,40 +1,15 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Objects.Drawables { - public abstract class DrawableManiaHitObject : DrawableHitObject - { - protected DrawableManiaHitObject(ManiaHitObject hitObject) - : base(hitObject) - { - } - - /// - /// Sets the scrolling direction. - /// - public virtual ScrollingDirection Direction - { - set - { - Anchor = value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; - Origin = Anchor; - - if (!HasNestedHitObjects) - return; - - foreach (var obj in NestedHitObjects.OfType()) - obj.Direction = value; - } - } - } - - public abstract class DrawableManiaHitObject : DrawableManiaHitObject + public abstract class DrawableManiaHitObject : DrawableHitObject where TObject : ManiaHitObject { /// @@ -47,15 +22,19 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables protected DrawableManiaHitObject(TObject hitObject, ManiaAction? action = null) : base(hitObject) { - Anchor = Anchor.TopCentre; - Origin = Anchor.TopCentre; - HitObject = hitObject; if (action != null) Action = action.Value; } + [BackgroundDependencyLoader] + private void load(ScrollingInfo scrollingInfo) + { + Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; + Origin = Anchor; + } + protected override void UpdateState(ArmedState state) { switch (state) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index a8666405cc..7e160befdc 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using OpenTK.Graphics; using osu.Framework.Graphics; @@ -8,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI.Scrolling; @@ -29,26 +31,14 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables CornerRadius = 5; Masking = true; - InternalChildren = new Drawable[] - { - headPiece = new NotePiece - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre - } - }; + InternalChild = headPiece = new NotePiece(); } - public override ScrollingDirection Direction + [BackgroundDependencyLoader] + private void load(ScrollingInfo scrollingInfo) { - set - { - base.Direction = value; - - headPiece.Direction = value; - headPiece.Anchor = Anchor; - headPiece.Origin = Origin; - } + headPiece.Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; + headPiece.Origin = headPiece.Anchor; } public override Color4 AccentColour diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs index 952ddd074e..707d1b5479 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs @@ -1,12 +1,14 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces @@ -43,13 +45,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces }; } - public ScrollingDirection Direction + [BackgroundDependencyLoader] + private void load(ScrollingInfo scrollingInfo) { - set - { - colouredBox.Anchor = value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; - colouredBox.Origin = colouredBox.Anchor; - } + colouredBox.Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; + colouredBox.Origin = colouredBox.Anchor; } private Color4 accentColour; diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 26269ff537..f62d91a52b 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -9,7 +9,6 @@ using osu.Game.Rulesets.Objects.Drawables; using System.Linq; using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.UI.Scrolling; @@ -57,7 +56,7 @@ namespace osu.Game.Rulesets.Mania.UI Masking = true; CornerRadius = 5; - background = new ColumnBackground(direction) { RelativeSizeAxes = Axes.Both }; + background = new ColumnBackground { RelativeSizeAxes = Axes.Both }; InternalChildren = new[] { @@ -74,7 +73,7 @@ namespace osu.Game.Rulesets.Mania.UI }, Children = new Drawable[] { - hitObjectArea = new ColumnHitObjectArea(direction) { RelativeSizeAxes = Axes.Both }, + hitObjectArea = new ColumnHitObjectArea { RelativeSizeAxes = Axes.Both }, explosionContainer = new Container { Name = "Hit explosions", @@ -82,7 +81,7 @@ namespace osu.Game.Rulesets.Mania.UI } } }, - keyArea = new ColumnKeyArea(direction) + keyArea = new ColumnKeyArea { Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, @@ -134,9 +133,6 @@ namespace osu.Game.Rulesets.Mania.UI /// The DrawableHitObject to add. public override void Add(DrawableHitObject hitObject) { - var maniaObject = (DrawableManiaHitObject)hitObject; - maniaObject.Direction = direction; - hitObject.AccentColour = AccentColour; hitObject.OnJudgement += OnJudgement; diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs index b71dae035e..6492380f01 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs @@ -18,19 +18,16 @@ namespace osu.Game.Rulesets.Mania.UI.Components { public ManiaAction Action; - private readonly ScrollingDirection direction; - private Box background; private Box backgroundOverlay; - public ColumnBackground(ScrollingDirection direction) - { - this.direction = direction; - } + private ScrollingInfo scrollingInfo; [BackgroundDependencyLoader] - private void load() + private void load(ScrollingInfo scrollingInfo) { + this.scrollingInfo = scrollingInfo; + InternalChildren = new[] { background = new Box @@ -44,8 +41,8 @@ namespace osu.Game.Rulesets.Mania.UI.Components Name = "Background Gradient Overlay", RelativeSizeAxes = Axes.Both, Height = 0.5f, - Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, - Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, + Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, + Origin = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, Blending = BlendingMode.Additive, Alpha = 0 } @@ -84,8 +81,8 @@ namespace osu.Game.Rulesets.Mania.UI.Components var dimPoint = AccentColour.Opacity(0); backgroundOverlay.Colour = ColourInfo.GradientVertical( - direction == ScrollingDirection.Up ? brightPoint : dimPoint, - direction == ScrollingDirection.Up ? dimPoint : brightPoint); + scrollingInfo.Direction == ScrollingDirection.Up ? brightPoint : dimPoint, + scrollingInfo.Direction == ScrollingDirection.Up ? dimPoint : brightPoint); } public bool OnPressed(ManiaAction action) diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs index 31df6d5fa3..cdea3870ab 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs @@ -20,32 +20,25 @@ namespace osu.Game.Rulesets.Mania.UI.Components private Container content; protected override Container Content => content; - private readonly ScrollingDirection direction; - private Container hitTargetBar; - public ColumnHitObjectArea(ScrollingDirection direction) - { - this.direction = direction; - } - [BackgroundDependencyLoader] - private void load() + private void load(ScrollingInfo scrollingInfo) { InternalChildren = new Drawable[] { new Box { - Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, - Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, + Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, + Origin = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, RelativeSizeAxes = Axes.X, Height = hit_target_height, Colour = Color4.Black }, hitTargetBar = new Container { - Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, - Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, + Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, + Origin = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, RelativeSizeAxes = Axes.X, Height = hit_target_bar_height, Masking = true, diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs index e7fe44171b..56da7bc9b9 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs @@ -22,17 +22,10 @@ namespace osu.Game.Rulesets.Mania.UI.Components public ManiaAction Action; - private readonly ScrollingDirection direction; - private Container keyIcon; - public ColumnKeyArea(ScrollingDirection direction) - { - this.direction = direction; - } - [BackgroundDependencyLoader] - private void load() + private void load(ScrollingInfo scrollingInfo) { InternalChildren = new Drawable[] { @@ -41,8 +34,8 @@ namespace osu.Game.Rulesets.Mania.UI.Components Name = "Key gradient", RelativeSizeAxes = Axes.Both, Colour = ColourInfo.GradientVertical( - direction == ScrollingDirection.Up ? Color4.Black : Color4.Black.Opacity(0), - direction == ScrollingDirection.Up ? Color4.Black.Opacity(0) : Color4.Black), + scrollingInfo.Direction == ScrollingDirection.Up ? Color4.Black : Color4.Black.Opacity(0), + scrollingInfo.Direction == ScrollingDirection.Up ? Color4.Black.Opacity(0) : Color4.Black), Alpha = 0.5f }, keyIcon = new Container diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index b7acd1d5ee..54a1b08ea3 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -36,6 +36,8 @@ namespace osu.Game.Rulesets.Mania.UI public IEnumerable BarLines; + private ScrollingInfo scrollingInfo; + public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { @@ -73,7 +75,19 @@ namespace osu.Game.Rulesets.Mania.UI BarLines.ForEach(Playfield.Add); } - protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(ScrollingDirection.Up, Beatmap.Stages) + private DependencyContainer dependencies; + + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) + { + dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); + + scrollingInfo = new ScrollingInfo(ScrollingDirection.Up); + dependencies.Cache(scrollingInfo); + + return dependencies; + } + + protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(scrollingInfo.Direction, Beatmap.Stages) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania/UI/ScrollingInfo.cs b/osu.Game.Rulesets.Mania/UI/ScrollingInfo.cs new file mode 100644 index 0000000000..7772485982 --- /dev/null +++ b/osu.Game.Rulesets.Mania/UI/ScrollingInfo.cs @@ -0,0 +1,17 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.UI.Scrolling; + +namespace osu.Game.Rulesets.Mania.UI +{ + public class ScrollingInfo + { + public readonly ScrollingDirection Direction; + + public ScrollingInfo(ScrollingDirection direction) + { + Direction = direction; + } + } +} From baaf431b9ed11bff42b1487d9d6f5ac134d7e1c2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Jun 2018 21:41:20 +0900 Subject: [PATCH 138/306] Make IScrollingInfo and store direction as bindable --- .../ScrollingTestContainer.cs | 18 +++++++---- .../TestCaseColumn.cs | 2 +- .../TestCaseNotes.cs | 5 ++-- .../TestCaseStage.cs | 2 +- .../Objects/Drawables/DrawableHoldNote.cs | 13 +++----- .../Drawables/DrawableManiaHitObject.cs | 13 ++++++-- .../Objects/Drawables/DrawableNote.cs | 9 +++--- .../Objects/Drawables/Pieces/NotePiece.cs | 15 ++++++---- .../UI/Components/ColumnBackground.cs | 21 ++++++++----- .../UI/Components/ColumnHitObjectArea.cs | 30 ++++++++++++------- .../UI/Components/ColumnKeyArea.cs | 22 ++++++++++---- osu.Game.Rulesets.Mania/UI/IScrollinginfo.cs | 17 +++++++++++ .../UI/ManiaRulesetContainer.cs | 12 ++++++-- osu.Game.Rulesets.Mania/UI/ScrollingInfo.cs | 17 ----------- 14 files changed, 122 insertions(+), 74 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/UI/IScrollinginfo.cs delete mode 100644 osu.Game.Rulesets.Mania/UI/ScrollingInfo.cs diff --git a/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs b/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs index 2b86c6187b..78a98e83e8 100644 --- a/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs +++ b/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs @@ -2,28 +2,36 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Tests { /// - /// A container which provides a to children. + /// A container which provides a to children. /// public class ScrollingTestContainer : Container { - private readonly ScrollingInfo scrollingInfo; + private readonly ScrollingDirection direction; - public ScrollingTestContainer(ScrollingInfo scrollingInfo) + public ScrollingTestContainer(ScrollingDirection direction) { - this.scrollingInfo = scrollingInfo; + this.direction = direction; } protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) { var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); - dependencies.Cache(scrollingInfo); + dependencies.CacheAs(new ScrollingInfo { Direction = { Value = direction }}); return dependencies; } + + private class ScrollingInfo : IScrollingInfo + { + public readonly Bindable Direction = new Bindable(); + IBindable IScrollingInfo.Direction => Direction; + } } } diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs index d5f43b809e..72f0b046b6 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs @@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Mania.Tests columns.Add(column); - return new ScrollingTestContainer(new ScrollingInfo(direction)) + return new ScrollingTestContainer(direction) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs index 3342060fe2..4fdfac93b7 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseNotes.cs @@ -15,7 +15,6 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; -using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.UI.Scrolling; @@ -59,7 +58,7 @@ namespace osu.Game.Rulesets.Mania.Tests var note = new Note { StartTime = 999999999 }; note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - return new ScrollingTestContainer(new ScrollingInfo(direction)) + return new ScrollingTestContainer(direction) { AutoSizeAxes = Axes.Both, Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLower()}") @@ -74,7 +73,7 @@ namespace osu.Game.Rulesets.Mania.Tests var note = new HoldNote { StartTime = 999999999, Duration = 1000 }; note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - return new ScrollingTestContainer(new ScrollingInfo(direction)) + return new ScrollingTestContainer(direction) { AutoSizeAxes = Axes.Both, Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLower()}") diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs index 2f639494bb..d88896d855 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.Tests { var specialAction = ManiaAction.Special1; - return new ScrollingTestContainer(new ScrollingInfo(direction)) + return new ScrollingTestContainer(direction) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 86bbc2c11d..3448d66ce1 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Linq; -using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; @@ -10,7 +9,6 @@ using OpenTK.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Mania.Judgements; using osu.Framework.Input.Bindings; -using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI.Scrolling; @@ -38,8 +36,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// private bool hasBroken; - private ScrollingInfo scrollingInfo; - private readonly Container tickContainer; public DrawableHoldNote(HoldNote hitObject, ManiaAction action) @@ -80,12 +76,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables AddNested(tail); } - [BackgroundDependencyLoader] - private void load(ScrollingInfo scrollingInfo) + protected override void OnDirectionChanged(ScrollingDirection direction) { - this.scrollingInfo = scrollingInfo; + base.OnDirectionChanged(direction); - bodyPiece.Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + bodyPiece.Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; bodyPiece.Origin = bodyPiece.Anchor; } @@ -114,7 +109,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables base.Update(); // Make the body piece not lie under the head note - bodyPiece.Y = (scrollingInfo.Direction == ScrollingDirection.Up ? 1 : -1) * head.Height / 2; + bodyPiece.Y = (Direction.Value == ScrollingDirection.Up ? 1 : -1) * head.Height / 2; bodyPiece.Height = DrawHeight - head.Height / 2 + tail.Height / 2; } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index 59f93eb16a..01df4743c7 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Objects.Drawables; @@ -19,6 +20,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables public new TObject HitObject; + protected readonly IBindable Direction = new Bindable(); + protected DrawableManiaHitObject(TObject hitObject, ManiaAction? action = null) : base(hitObject) { @@ -29,9 +32,15 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables } [BackgroundDependencyLoader] - private void load(ScrollingInfo scrollingInfo) + private void load(IScrollingInfo scrollingInfo) { - Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; + Direction.BindTo(scrollingInfo.Direction); + Direction.BindValueChanged(OnDirectionChanged, true); + } + + protected virtual void OnDirectionChanged(ScrollingDirection direction) + { + Anchor = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; Origin = Anchor; } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index 7e160befdc..b9b3fa7824 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using OpenTK.Graphics; using osu.Framework.Graphics; @@ -9,7 +8,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; -using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI.Scrolling; @@ -34,10 +32,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables InternalChild = headPiece = new NotePiece(); } - [BackgroundDependencyLoader] - private void load(ScrollingInfo scrollingInfo) + protected override void OnDirectionChanged(ScrollingDirection direction) { - headPiece.Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; + base.OnDirectionChanged(direction); + + headPiece.Anchor = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; headPiece.Origin = headPiece.Anchor; } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs index 707d1b5479..2c36b96f72 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Configuration; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -21,6 +22,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces public const float NOTE_HEIGHT = 10; private const float head_colour_height = 6; + private readonly IBindable direction = new Bindable(); + private readonly Box colouredBox; public NotePiece() @@ -36,8 +39,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces }, colouredBox = new Box { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.X, Height = head_colour_height, Alpha = 0.2f @@ -46,10 +47,14 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces } [BackgroundDependencyLoader] - private void load(ScrollingInfo scrollingInfo) + private void load(IScrollingInfo scrollingInfo) { - colouredBox.Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; - colouredBox.Origin = colouredBox.Anchor; + direction.BindTo(scrollingInfo.Direction); + direction.BindValueChanged(direction => + { + colouredBox.Anchor = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; + colouredBox.Origin = colouredBox.Anchor; + }, true); } private Color4 accentColour; diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs index 6492380f01..50303deda7 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -21,13 +22,11 @@ namespace osu.Game.Rulesets.Mania.UI.Components private Box background; private Box backgroundOverlay; - private ScrollingInfo scrollingInfo; + private readonly IBindable direction = new Bindable(); [BackgroundDependencyLoader] - private void load(ScrollingInfo scrollingInfo) + private void load(IScrollingInfo scrollingInfo) { - this.scrollingInfo = scrollingInfo; - InternalChildren = new[] { background = new Box @@ -41,12 +40,18 @@ namespace osu.Game.Rulesets.Mania.UI.Components Name = "Background Gradient Overlay", RelativeSizeAxes = Axes.Both, Height = 0.5f, - Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, - Origin = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, Blending = BlendingMode.Additive, Alpha = 0 } }; + + direction.BindTo(scrollingInfo.Direction); + direction.BindValueChanged(direction => + { + backgroundOverlay.Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + backgroundOverlay.Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + updateColours(); + }, true); } protected override void LoadComplete() @@ -81,8 +86,8 @@ namespace osu.Game.Rulesets.Mania.UI.Components var dimPoint = AccentColour.Opacity(0); backgroundOverlay.Colour = ColourInfo.GradientVertical( - scrollingInfo.Direction == ScrollingDirection.Up ? brightPoint : dimPoint, - scrollingInfo.Direction == ScrollingDirection.Up ? dimPoint : brightPoint); + direction.Value == ScrollingDirection.Up ? brightPoint : dimPoint, + direction.Value == ScrollingDirection.Up ? dimPoint : brightPoint); } public bool OnPressed(ManiaAction action) diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs index cdea3870ab..4fa8ff4105 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -20,25 +21,25 @@ namespace osu.Game.Rulesets.Mania.UI.Components private Container content; protected override Container Content => content; - private Container hitTargetBar; + private readonly IBindable direction = new Bindable(); + + private Container hitTargetLine; [BackgroundDependencyLoader] - private void load(ScrollingInfo scrollingInfo) + private void load(IScrollingInfo scrollingInfo) { - InternalChildren = new Drawable[] + Drawable hitTargetBar; + + InternalChildren = new[] { - new Box + hitTargetBar = new Box { - Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, - Origin = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, RelativeSizeAxes = Axes.X, Height = hit_target_height, Colour = Color4.Black }, - hitTargetBar = new Container + hitTargetLine = new Container { - Anchor = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, - Origin = scrollingInfo.Direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, RelativeSizeAxes = Axes.X, Height = hit_target_bar_height, Masking = true, @@ -50,6 +51,15 @@ namespace osu.Game.Rulesets.Mania.UI.Components RelativeSizeAxes = Axes.Both, }, }; + + direction.BindTo(scrollingInfo.Direction); + direction.BindValueChanged(direction => + { + hitTargetBar.Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + hitTargetBar.Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + hitTargetLine.Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + hitTargetLine.Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + }, true); } protected override void LoadComplete() @@ -78,7 +88,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components if (!IsLoaded) return; - hitTargetBar.EdgeEffect = new EdgeEffectParameters + hitTargetLine.EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow, Radius = 5, diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs index 56da7bc9b9..4ce1614310 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -22,20 +23,21 @@ namespace osu.Game.Rulesets.Mania.UI.Components public ManiaAction Action; + private readonly IBindable direction = new Bindable(); + private Container keyIcon; [BackgroundDependencyLoader] - private void load(ScrollingInfo scrollingInfo) + private void load(IScrollingInfo scrollingInfo) { - InternalChildren = new Drawable[] + Drawable gradient; + + InternalChildren = new[] { - new Box + gradient = new Box { Name = "Key gradient", RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical( - scrollingInfo.Direction == ScrollingDirection.Up ? Color4.Black : Color4.Black.Opacity(0), - scrollingInfo.Direction == ScrollingDirection.Up ? Color4.Black.Opacity(0) : Color4.Black), Alpha = 0.5f }, keyIcon = new Container @@ -59,6 +61,14 @@ namespace osu.Game.Rulesets.Mania.UI.Components } } }; + + direction.BindTo(scrollingInfo.Direction); + direction.BindValueChanged(direction => + { + gradient.Colour = ColourInfo.GradientVertical( + direction == ScrollingDirection.Up ? Color4.Black : Color4.Black.Opacity(0), + direction == ScrollingDirection.Up ? Color4.Black.Opacity(0) : Color4.Black); + }, true); } protected override void LoadComplete() diff --git a/osu.Game.Rulesets.Mania/UI/IScrollinginfo.cs b/osu.Game.Rulesets.Mania/UI/IScrollinginfo.cs new file mode 100644 index 0000000000..ee65e9f1a5 --- /dev/null +++ b/osu.Game.Rulesets.Mania/UI/IScrollinginfo.cs @@ -0,0 +1,17 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Configuration; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.UI.Scrolling; + +namespace osu.Game.Rulesets.Mania.UI +{ + public interface IScrollingInfo + { + /// + /// The direction s should scroll in. + /// + IBindable Direction { get; } + } +} diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index 54a1b08ea3..1d32ac75eb 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Input; @@ -81,8 +82,9 @@ namespace osu.Game.Rulesets.Mania.UI { dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); - scrollingInfo = new ScrollingInfo(ScrollingDirection.Up); - dependencies.Cache(scrollingInfo); + scrollingInfo = new ScrollingInfo { Direction = { Value = ScrollingDirection.Up } }; + + dependencies.CacheAs(scrollingInfo); return dependencies; } @@ -119,5 +121,11 @@ namespace osu.Game.Rulesets.Mania.UI protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay); protected override IRulesetConfigManager CreateConfig(Ruleset ruleset, SettingsStore settings) => new ManiaConfigManager(settings, Ruleset.RulesetInfo, Variant); + + private class ScrollingInfo : IScrollingInfo + { + public readonly Bindable Direction = new Bindable(); + IBindable IScrollingInfo.Direction => Direction; + } } } diff --git a/osu.Game.Rulesets.Mania/UI/ScrollingInfo.cs b/osu.Game.Rulesets.Mania/UI/ScrollingInfo.cs deleted file mode 100644 index 7772485982..0000000000 --- a/osu.Game.Rulesets.Mania/UI/ScrollingInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Game.Rulesets.UI.Scrolling; - -namespace osu.Game.Rulesets.Mania.UI -{ - public class ScrollingInfo - { - public readonly ScrollingDirection Direction; - - public ScrollingInfo(ScrollingDirection direction) - { - Direction = direction; - } - } -} From f49b7d6e16407aa5b2d545acbf6bd12ee1ea54cf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 14:36:19 +0900 Subject: [PATCH 139/306] Add mania direction to settings --- .../Configuration/ManiaConfigManager.cs | 5 ++- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 3 ++ .../ManiaSettingsSubsection.cs | 34 +++++++++++++++++++ osu.Game.Rulesets.Mania/UI/Column.cs | 30 +++++++++------- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 2 +- .../UI/ManiaRulesetContainer.cs | 13 +++---- .../UI/ManiaScrollingDirection.cs | 13 +++++++ .../UI/ManiaScrollingPlayfield.cs | 26 ++++++++++++++ osu.Game.Rulesets.Mania/UI/ManiaStage.cs | 2 +- osu.Game/Configuration/OsuConfigManager.cs | 2 +- .../Scrolling/ScrollingHitObjectContainer.cs | 13 ++++--- .../UI/Scrolling/ScrollingPlayfield.cs | 11 ++++-- 12 files changed, 121 insertions(+), 33 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs create mode 100644 osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs create mode 100644 osu.Game.Rulesets.Mania/UI/ManiaScrollingPlayfield.cs diff --git a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs b/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs index d9e360081d..cb15d55934 100644 --- a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs +++ b/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs @@ -4,6 +4,7 @@ using osu.Framework.Configuration.Tracking; using osu.Game.Configuration; using osu.Game.Rulesets.Configuration; +using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania.Configuration { @@ -19,6 +20,7 @@ namespace osu.Game.Rulesets.Mania.Configuration base.InitialiseDefaults(); Set(ManiaSetting.ScrollTime, 1500.0, 50.0, 10000.0, 50.0); + Set(ManiaSetting.ScrollDirection, ManiaScrollingDirection.Up); } public override TrackedSettings CreateTrackedSettings() => new TrackedSettings @@ -29,6 +31,7 @@ namespace osu.Game.Rulesets.Mania.Configuration public enum ManiaSetting { - ScrollTime + ScrollTime, + ScrollDirection } } diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index e671a3fb14..ccae0b609b 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -16,6 +16,7 @@ using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Replays.Types; using osu.Game.Beatmaps.Legacy; using osu.Game.Configuration; +using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mania.Beatmaps; @@ -155,6 +156,8 @@ namespace osu.Game.Rulesets.Mania public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new ManiaConfigManager(settings, RulesetInfo); + public override RulesetSettingsSubsection CreateSettings() => new ManiaSettingsSubsection(this); + public ManiaRuleset(RulesetInfo rulesetInfo = null) : base(rulesetInfo) { diff --git a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs new file mode 100644 index 0000000000..54a7bf954d --- /dev/null +++ b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs @@ -0,0 +1,34 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Overlays.Settings; +using osu.Game.Rulesets.Mania.Configuration; +using osu.Game.Rulesets.Mania.UI; + +namespace osu.Game.Rulesets.Mania +{ + public class ManiaSettingsSubsection : RulesetSettingsSubsection + { + protected override string Header => "osu!mania"; + + public ManiaSettingsSubsection(ManiaRuleset ruleset) + : base(ruleset) + { + } + + [BackgroundDependencyLoader] + private void load(ManiaConfigManager config) + { + Children = new Drawable[] + { + new SettingsEnumDropdown + { + LabelText = "Scrolling direction", + Bindable = config.GetBindable(ManiaSetting.ScrollDirection) + } + }; + } + } +} diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index f62d91a52b..6a78143e41 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.UI { - public class Column : ScrollingPlayfield, IKeyBindingHandler, IHasAccentColour + public class Column : ManiaScrollingPlayfield, IKeyBindingHandler, IHasAccentColour { private const float column_width = 45; private const float special_column_width = 70; @@ -35,8 +35,6 @@ namespace osu.Game.Rulesets.Mania.UI } } - private readonly ScrollingDirection direction; - private readonly ColumnBackground background; private readonly ColumnKeyArea keyArea; private readonly ColumnHitObjectArea hitObjectArea; @@ -49,7 +47,6 @@ namespace osu.Game.Rulesets.Mania.UI public Column(ScrollingDirection direction) : base(direction) { - this.direction = direction; RelativeSizeAxes = Axes.Y; Width = column_width; @@ -58,19 +55,16 @@ namespace osu.Game.Rulesets.Mania.UI background = new ColumnBackground { RelativeSizeAxes = Axes.Both }; + Container hitTargetContainer; + InternalChildren = new[] { // For input purposes, the background is added at the highest depth, but is then proxied back below all other elements background.CreateProxy(), - new Container + hitTargetContainer = new Container { Name = "Hit target + hit objects", RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding - { - Top = direction == ScrollingDirection.Up ? ManiaStage.HIT_TARGET_POSITION : 0, - Bottom = direction == ScrollingDirection.Down ? ManiaStage.HIT_TARGET_POSITION : 0, - }, Children = new Drawable[] { hitObjectArea = new ColumnHitObjectArea { RelativeSizeAxes = Axes.Both }, @@ -83,8 +77,6 @@ namespace osu.Game.Rulesets.Mania.UI }, keyArea = new ColumnKeyArea { - Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, - Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft, RelativeSizeAxes = Axes.X, Height = ManiaStage.HIT_TARGET_POSITION, }, @@ -93,6 +85,18 @@ namespace osu.Game.Rulesets.Mania.UI }; TopLevelContainer.Add(explosionContainer.CreateProxy()); + + Direction.BindValueChanged(d => + { + hitTargetContainer.Padding = new MarginPadding + { + Top = d == ScrollingDirection.Up ? ManiaStage.HIT_TARGET_POSITION : 0, + Bottom = d == ScrollingDirection.Down ? ManiaStage.HIT_TARGET_POSITION : 0, + }; + + keyArea.Anchor = d == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + keyArea.Origin = d == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + }, true); } public override Axes RelativeSizeAxes => Axes.Y; @@ -146,7 +150,7 @@ namespace osu.Game.Rulesets.Mania.UI explosionContainer.Add(new HitExplosion(judgedObject) { - Anchor = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre + Anchor = Direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre }); } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 73362ab28f..2f8ad7b17e 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -16,7 +16,7 @@ using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.UI { - public class ManiaPlayfield : ScrollingPlayfield + public class ManiaPlayfield : ManiaScrollingPlayfield { public List Columns => stages.SelectMany(x => x.Columns).ToList(); private readonly List stages = new List(); diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index eaad787999..fa6fba0cd8 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -13,6 +13,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Input.Handlers; using osu.Game.Rulesets.Mania.Beatmaps; +using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; @@ -34,6 +35,7 @@ namespace osu.Game.Rulesets.Mania.UI public IEnumerable BarLines; + private readonly Bindable configDirection = new Bindable(); private ScrollingInfo scrollingInfo; public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) @@ -68,9 +70,12 @@ namespace osu.Game.Rulesets.Mania.UI } [BackgroundDependencyLoader] - private void load() + private void load(ManiaConfigManager config) { BarLines.ForEach(Playfield.Add); + + config.BindWith(ManiaSetting.ScrollDirection, configDirection); + configDirection.BindValueChanged(d => scrollingInfo.Direction.Value = (ScrollingDirection)d, true); } private DependencyContainer dependencies; @@ -78,11 +83,7 @@ namespace osu.Game.Rulesets.Mania.UI protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) { dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); - - scrollingInfo = new ScrollingInfo { Direction = { Value = ScrollingDirection.Up } }; - - dependencies.CacheAs(scrollingInfo); - + dependencies.CacheAs(scrollingInfo = new ScrollingInfo()); return dependencies; } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs b/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs new file mode 100644 index 0000000000..0fc9c1920a --- /dev/null +++ b/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs @@ -0,0 +1,13 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.UI.Scrolling; + +namespace osu.Game.Rulesets.Mania.UI +{ + public enum ManiaScrollingDirection + { + Up = ScrollingDirection.Up, + Down = ScrollingDirection.Down + } +} diff --git a/osu.Game.Rulesets.Mania/UI/ManiaScrollingPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaScrollingPlayfield.cs new file mode 100644 index 0000000000..f1ff0665cd --- /dev/null +++ b/osu.Game.Rulesets.Mania/UI/ManiaScrollingPlayfield.cs @@ -0,0 +1,26 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Game.Rulesets.UI.Scrolling; + +namespace osu.Game.Rulesets.Mania.UI +{ + public class ManiaScrollingPlayfield : ScrollingPlayfield + { + private readonly IBindable direction = new Bindable(); + + public ManiaScrollingPlayfield(ScrollingDirection direction) + : base(direction) + { + } + + [BackgroundDependencyLoader] + private void load(IScrollingInfo scrollingInfo) + { + direction.BindTo(scrollingInfo.Direction); + direction.BindValueChanged(direction => Direction.Value = direction, true); + } + } +} diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs index 822042362f..3ff14ed0c6 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.UI /// /// A collection of s. /// - internal class ManiaStage : ScrollingPlayfield + internal class ManiaStage : ManiaScrollingPlayfield { public const float HIT_TARGET_POSITION = 50; diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 597960c352..1bb2ac4678 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -147,6 +147,6 @@ namespace osu.Game.Configuration SongSelectRightMouseScroll, BeatmapSkins, BeatmapHitsounds, - IncreaseFirstObjectVisibility + IncreaseFirstObjectVisibility, } } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 36c6b07f54..c64fca6eff 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -29,17 +29,16 @@ namespace osu.Game.Rulesets.UI.Scrolling /// protected readonly SortedList ControlPoints = new SortedList(); - private readonly ScrollingDirection direction; + public readonly Bindable Direction = new Bindable(); private Cached initialStateCache = new Cached(); - public ScrollingHitObjectContainer(ScrollingDirection direction) + public ScrollingHitObjectContainer() { - this.direction = direction; - RelativeSizeAxes = Axes.Both; - TimeRange.ValueChanged += v => initialStateCache.Invalidate(); + TimeRange.ValueChanged += _ => initialStateCache.Invalidate(); + Direction.ValueChanged += _ => initialStateCache.Invalidate(); } private ISpeedChangeVisualiser speedChangeVisualiser; @@ -100,7 +99,7 @@ namespace osu.Game.Rulesets.UI.Scrolling if (!initialStateCache.IsValid) { - speedChangeVisualiser.ComputeInitialStates(Objects, direction, TimeRange, DrawSize); + speedChangeVisualiser.ComputeInitialStates(Objects, Direction, TimeRange, DrawSize); initialStateCache.Validate(); } } @@ -110,7 +109,7 @@ namespace osu.Game.Rulesets.UI.Scrolling base.UpdateAfterChildrenLife(); // We need to calculate this as soon as possible after lifetimes so that hitobjects get the final say in their positions - speedChangeVisualiser.UpdatePositions(AliveObjects, direction, Time.Current, TimeRange, DrawSize); + speedChangeVisualiser.UpdatePositions(AliveObjects, Direction, Time.Current, TimeRange, DrawSize); } } } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index 6f86d20295..b7f6844245 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public new ScrollingHitObjectContainer HitObjects => (ScrollingHitObjectContainer)base.HitObjects; - private readonly ScrollingDirection direction; + protected readonly Bindable Direction = new Bindable(); /// /// Creates a new . @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.UI.Scrolling protected ScrollingPlayfield(ScrollingDirection direction, float? customWidth = null, float? customHeight = null) : base(customWidth, customHeight) { - this.direction = direction; + Direction.Value = direction; } [BackgroundDependencyLoader] @@ -99,6 +99,11 @@ namespace osu.Game.Rulesets.UI.Scrolling return false; } - protected sealed override HitObjectContainer CreateHitObjectContainer() => new ScrollingHitObjectContainer(direction); + protected sealed override HitObjectContainer CreateHitObjectContainer() + { + var container = new ScrollingHitObjectContainer(); + container.Direction.BindTo(Direction); + return container; + } } } From be01dbae3ac4635706caf82cc4be9e19533e00d7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 14:36:56 +0900 Subject: [PATCH 140/306] Move ruleset dependency caching to CreateLocalDependencies In some cases we may want to refer to the cached configmanager dependency from subclasses. This prevents injection errors when doing so. --- osu.Game/Rulesets/UI/RulesetContainer.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 875745edfb..a7005f1d5e 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -13,7 +13,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Configuration; using osu.Framework.Graphics.Cursor; using osu.Framework.Input; @@ -86,11 +85,13 @@ namespace osu.Game.Rulesets.UI Cursor = CreateCursor(); } - [BackgroundDependencyLoader(true)] - private void load([CanBeNull] OnScreenDisplay onScreenDisplay, [CanBeNull] SettingsStore settings) + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) { - this.onScreenDisplay = onScreenDisplay; + var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); + onScreenDisplay = dependencies.Get(); + + var settings = dependencies.Get(); if (settings != null) { rulesetConfig = Ruleset.CreateConfig(settings); @@ -101,13 +102,10 @@ namespace osu.Game.Rulesets.UI onScreenDisplay?.BeginTracking(this, rulesetConfig); } } + + return dependencies; } - private DependencyContainer dependencies; - - protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) - => dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); - public abstract ScoreProcessor CreateScoreProcessor(); /// From 14b75309944a02d0ad8ff7622603ec0d4dbdb235 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 15:07:42 +0900 Subject: [PATCH 141/306] Use a global ruleset config cache --- osu.Game/OsuGameBase.cs | 3 ++ .../Settings/RulesetSettingsSubsection.cs | 3 +- osu.Game/Rulesets/RulesetConfigCache.cs | 43 +++++++++++++++++++ osu.Game/Rulesets/UI/RulesetContainer.cs | 13 ++---- 4 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Rulesets/RulesetConfigCache.cs diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index b968d7d4d0..a5779a2293 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -56,6 +56,8 @@ namespace osu.Game protected SettingsStore SettingsStore; + protected RulesetConfigCache RulesetConfigCache; + protected MenuCursorContainer MenuCursorContainer; private Container content; @@ -123,6 +125,7 @@ namespace osu.Game dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, contextFactory, Host, BeatmapManager, RulesetStore)); dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore)); dependencies.Cache(SettingsStore = new SettingsStore(contextFactory)); + dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore)); dependencies.Cache(new OsuColour()); fileImporters.Add(BeatmapManager); diff --git a/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs b/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs index 8f8c18d1f0..05104018cd 100644 --- a/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; -using osu.Game.Configuration; using osu.Game.Rulesets; namespace osu.Game.Overlays.Settings @@ -26,7 +25,7 @@ namespace osu.Game.Overlays.Settings { dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); - var config = ruleset.CreateConfig(dependencies.Get()); + var config = dependencies.Get().GetConfigFor(ruleset); if (config != null) dependencies.Cache(config); diff --git a/osu.Game/Rulesets/RulesetConfigCache.cs b/osu.Game/Rulesets/RulesetConfigCache.cs new file mode 100644 index 0000000000..52c40465f3 --- /dev/null +++ b/osu.Game/Rulesets/RulesetConfigCache.cs @@ -0,0 +1,43 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Game.Configuration; +using osu.Game.Rulesets.Configuration; + +namespace osu.Game.Rulesets +{ + /// + /// A cache that provides a single per-ruleset + /// This is done to support referring to and updating ruleset configs from multiple locations in the absence of inter-config bindings. + /// + public class RulesetConfigCache : Component + { + private readonly Dictionary configCache = new Dictionary(); + private readonly SettingsStore settingsStore; + + public RulesetConfigCache(SettingsStore settingsStore) + { + this.settingsStore = settingsStore; + } + + /// + /// Retrieves the for a . + /// + /// The to retrieve the for. + /// The defined by , null if doesn't define one. + /// If doesn't have a valid . + public IRulesetConfigManager GetConfigFor(Ruleset ruleset) + { + if (ruleset.RulesetInfo.ID == null) + throw new InvalidOperationException("The provided ruleset doesn't have a valid id."); + + if (configCache.TryGetValue(ruleset.RulesetInfo.ID.Value, out var existing)) + return existing; + + return configCache[ruleset.RulesetInfo.ID.Value] = ruleset.CreateConfig(settingsStore); + } + } +} diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index a7005f1d5e..15383946e8 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -91,16 +91,11 @@ namespace osu.Game.Rulesets.UI onScreenDisplay = dependencies.Get(); - var settings = dependencies.Get(); - if (settings != null) + rulesetConfig = dependencies.Get().GetConfigFor(Ruleset); + if (rulesetConfig != null) { - rulesetConfig = Ruleset.CreateConfig(settings); - - if (rulesetConfig != null) - { - dependencies.Cache(rulesetConfig); - onScreenDisplay?.BeginTracking(this, rulesetConfig); - } + dependencies.Cache(rulesetConfig); + onScreenDisplay?.BeginTracking(this, rulesetConfig); } return dependencies; From 162237dc46cf28225a2caa1075d97eefcac5af8c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 15:43:15 +0900 Subject: [PATCH 142/306] Fix bar lines being offset --- .../TestCaseStage.cs | 64 ++++++++++++++++++- osu.Game.Rulesets.Mania/UI/ManiaStage.cs | 18 ++++-- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs index d88896d855..0f90c1f16b 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs @@ -1,11 +1,16 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Mania.Beatmaps; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI.Scrolling; using OpenTK; @@ -15,8 +20,12 @@ namespace osu.Game.Rulesets.Mania.Tests [TestFixture] public class TestCaseStage : ManiaInputTestCase { + private const int columns = 4; + + private readonly List stages = new List(); + public TestCaseStage() - : base(4) + : base(columns) { } @@ -37,17 +46,68 @@ namespace osu.Game.Rulesets.Mania.Tests }; } + protected override void LoadComplete() + { + base.LoadComplete(); + + AddStep("note", createNote); + AddStep("hold note", createHoldNote); + AddStep("bar line", createBarLine); + } + + private void createNote() + { + foreach (var stage in stages) + { + for (int i = 0; i < stage.Columns.Count; i++) + { + var obj = new Note { Column = i, StartTime = Time.Current + 2000 }; + obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + stage.Add(new DrawableNote(obj, stage.Columns[i].Action)); + } + } + } + + private void createHoldNote() + { + foreach (var stage in stages) + { + for (int i = 0; i < stage.Columns.Count; i++) + { + var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 }; + obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + stage.Add(new DrawableHoldNote(obj, stage.Columns[i].Action)); + } + } + } + + private void createBarLine() + { + foreach (var stage in stages) + { + var obj = new BarLine { StartTime = Time.Current + 2000, ControlPoint = new TimingControlPoint() }; + obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + stage.Add(obj); + } + } + private Drawable createStage(ScrollingDirection direction, ManiaAction action) { var specialAction = ManiaAction.Special1; + var stage = new ManiaStage(direction, 0, new StageDefinition { Columns = 2 }, ref action, ref specialAction); + stages.Add(stage); + return new ScrollingTestContainer(direction) { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, - Child = new ManiaStage(direction, 0, new StageDefinition { Columns = 2 }, ref action, ref specialAction) + Child = stage }; } } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs index 3ff14ed0c6..7b68582944 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs @@ -30,8 +30,8 @@ namespace osu.Game.Rulesets.Mania.UI public IReadOnlyList Columns => columnFlow.Children; private readonly FillFlowContainer columnFlow; - protected override Container Content => content; - private readonly Container content; + protected override Container Content => barLineContainer; + private readonly Container barLineContainer; public Container Judgements => judgements; private readonly JudgementContainer judgements; @@ -100,13 +100,12 @@ namespace osu.Game.Rulesets.Mania.UI Width = 1366, // Bar lines should only be masked on the vertical axis BypassAutoSizeAxes = Axes.Both, Masking = true, - Child = content = new Container + Child = barLineContainer = new Container { Name = "Bar lines", Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.Y, - Padding = new MarginPadding { Top = HIT_TARGET_POSITION } } }, judgements = new JudgementContainer @@ -133,6 +132,15 @@ namespace osu.Game.Rulesets.Mania.UI AddColumn(column); } + + Direction.BindValueChanged(d => + { + barLineContainer.Padding = new MarginPadding + { + Top = d == ScrollingDirection.Up ? HIT_TARGET_POSITION : 0, + Bottom = d == ScrollingDirection.Down ? HIT_TARGET_POSITION : 0, + }; + }, true); } public void AddColumn(Column c) @@ -203,7 +211,7 @@ namespace osu.Game.Rulesets.Mania.UI { // Due to masking differences, it is not possible to get the width of the columns container automatically // While masking on effectively only the Y-axis, so we need to set the width of the bar line container manually - content.Width = columnFlow.Width; + barLineContainer.Width = columnFlow.Width; } } } From b51e714ae5d5997bcc952ba8dc6cd53acf08c318 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 15:44:59 +0900 Subject: [PATCH 143/306] Fix xmldoc --- osu.Game/Rulesets/RulesetConfigCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/RulesetConfigCache.cs b/osu.Game/Rulesets/RulesetConfigCache.cs index 52c40465f3..7e83ba0961 100644 --- a/osu.Game/Rulesets/RulesetConfigCache.cs +++ b/osu.Game/Rulesets/RulesetConfigCache.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Configuration; namespace osu.Game.Rulesets { /// - /// A cache that provides a single per-ruleset + /// A cache that provides a single per-ruleset. /// This is done to support referring to and updating ruleset configs from multiple locations in the absence of inter-config bindings. /// public class RulesetConfigCache : Component From b9bf3a1829002036201e96c8359519add545e172 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 15:56:30 +0900 Subject: [PATCH 144/306] Make mania scroll downwards by default --- osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs b/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs index cb15d55934..3e9c9feba1 100644 --- a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs +++ b/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Mania.Configuration base.InitialiseDefaults(); Set(ManiaSetting.ScrollTime, 1500.0, 50.0, 10000.0, 50.0); - Set(ManiaSetting.ScrollDirection, ManiaScrollingDirection.Up); + Set(ManiaSetting.ScrollDirection, ManiaScrollingDirection.Down); } public override TrackedSettings CreateTrackedSettings() => new TrackedSettings From 10d1dfa7cd4ab3a858883f695dfaa921de1c0431 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 16:10:27 +0900 Subject: [PATCH 145/306] A bit of cleanup --- .../Objects/Drawables/DrawableHoldNote.cs | 3 +-- .../Objects/Drawables/DrawableManiaHitObject.cs | 3 +-- osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs | 3 +-- .../Objects/Drawables/Pieces/NotePiece.cs | 3 +-- osu.Game.Rulesets.Mania/UI/Column.cs | 3 +-- osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs | 3 +-- osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs | 5 +---- 7 files changed, 7 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 3448d66ce1..ce0276f759 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -80,8 +80,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables { base.OnDirectionChanged(direction); - bodyPiece.Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; - bodyPiece.Origin = bodyPiece.Anchor; + bodyPiece.Anchor = bodyPiece.Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; } public override Color4 AccentColour diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index 01df4743c7..1271fae0c1 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -40,8 +40,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables protected virtual void OnDirectionChanged(ScrollingDirection direction) { - Anchor = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; - Origin = Anchor; + Anchor = Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; } protected override void UpdateState(ArmedState state) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index b9b3fa7824..fb4aa74ad1 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -36,8 +36,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables { base.OnDirectionChanged(direction); - headPiece.Anchor = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; - headPiece.Origin = headPiece.Anchor; + headPiece.Anchor = headPiece.Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; } public override Color4 AccentColour diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs index 2c36b96f72..2c74f5b168 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs @@ -52,8 +52,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(direction => { - colouredBox.Anchor = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; - colouredBox.Origin = colouredBox.Anchor; + colouredBox.Anchor = colouredBox.Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; }, true); } diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 6a78143e41..fafc875706 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -94,8 +94,7 @@ namespace osu.Game.Rulesets.Mania.UI Bottom = d == ScrollingDirection.Down ? ManiaStage.HIT_TARGET_POSITION : 0, }; - keyArea.Anchor = d == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; - keyArea.Origin = d == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + keyArea.Anchor = keyArea.Origin= d == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; }, true); } diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs index 50303deda7..9b744bd254 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs @@ -48,8 +48,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(direction => { - backgroundOverlay.Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; - backgroundOverlay.Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + backgroundOverlay.Anchor = backgroundOverlay.Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; updateColours(); }, true); } diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs index 4fa8ff4105..6d6edff3f4 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs @@ -55,10 +55,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(direction => { - hitTargetBar.Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; - hitTargetBar.Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; - hitTargetLine.Anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; - hitTargetLine.Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + hitTargetBar.Anchor = hitTargetBar.Origin = hitTargetLine.Anchor = hitTargetLine.Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; }, true); } From a36dab638aec66fe4c50eb7b874a1984910334ce Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 16:12:52 +0900 Subject: [PATCH 146/306] Improve TestCaseStage --- osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs index 0f90c1f16b..9aff853ffd 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs @@ -52,7 +52,8 @@ namespace osu.Game.Rulesets.Mania.Tests AddStep("note", createNote); AddStep("hold note", createHoldNote); - AddStep("bar line", createBarLine); + AddStep("minor bar line", () => createBarLine(false)); + AddStep("major bar line", () => createBarLine(true)); } private void createNote() @@ -83,11 +84,17 @@ namespace osu.Game.Rulesets.Mania.Tests } } - private void createBarLine() + private void createBarLine(bool major) { foreach (var stage in stages) { - var obj = new BarLine { StartTime = Time.Current + 2000, ControlPoint = new TimingControlPoint() }; + var obj = new BarLine + { + StartTime = Time.Current + 2000, + ControlPoint = new TimingControlPoint(), + BeatIndex = major ? 0 : 1 + }; + obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); stage.Add(obj); @@ -98,7 +105,7 @@ namespace osu.Game.Rulesets.Mania.Tests { var specialAction = ManiaAction.Special1; - var stage = new ManiaStage(direction, 0, new StageDefinition { Columns = 2 }, ref action, ref specialAction); + var stage = new ManiaStage(direction, 0, new StageDefinition { Columns = 2 }, ref action, ref specialAction) { VisibleTimeRange = { Value = 2000 } }; stages.Add(stage); return new ScrollingTestContainer(direction) From 3bad319dd2995c242ddc74c433a039699928f78e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 16:19:57 +0900 Subject: [PATCH 147/306] Fix filename --- .../UI/{IScrollinginfo.cs => IScrollingInfo.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename osu.Game.Rulesets.Mania/UI/{IScrollinginfo.cs => IScrollingInfo.cs} (100%) diff --git a/osu.Game.Rulesets.Mania/UI/IScrollinginfo.cs b/osu.Game.Rulesets.Mania/UI/IScrollingInfo.cs similarity index 100% rename from osu.Game.Rulesets.Mania/UI/IScrollinginfo.cs rename to osu.Game.Rulesets.Mania/UI/IScrollingInfo.cs From b9391b3c6bb8f84426767e7233d499cb633959f3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 18:18:24 +0900 Subject: [PATCH 148/306] Fix bindable not working under non-debug due to weak references --- osu.Game/Screens/Play/Player.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 94d03be3c8..04148cd558 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -158,7 +158,7 @@ namespace osu.Game.Screens.Play userAudioOffset.TriggerChange(); ScoreProcessor = RulesetContainer.CreateScoreProcessor(); - ScoreProcessor.Mode.BindTo(config.GetBindable(OsuSetting.ScoreDisplayMode)); + config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode); Children = new Drawable[] { From 8f3215f5a0b251f29e4863e50b396e91624e33e3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 20:42:04 +0900 Subject: [PATCH 149/306] Make sure taiko hitexplosions expire and get removed --- osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 4 +++- osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index ee2c1d5ad5..4dd0ba4d3d 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Taiko.UI /// internal class HitExplosion : CircularContainer { + public override bool RemoveWhenNotAlive => true; + public readonly DrawableHitObject JudgedObject; private readonly Box innerFill; @@ -66,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.UI this.ScaleTo(3f, 1000, Easing.OutQuint); this.FadeOut(500); - Expire(); + Expire(true); } /// diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs index ac3cf8305a..287d59972a 100644 --- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs @@ -14,6 +14,8 @@ namespace osu.Game.Rulesets.Taiko.UI { public class KiaiHitExplosion : CircularContainer { + public override bool RemoveWhenNotAlive => true; + public readonly DrawableHitObject JudgedObject; private readonly bool isRim; @@ -62,7 +64,7 @@ namespace osu.Game.Rulesets.Taiko.UI this.ScaleTo(new Vector2(1, 3f), 500, Easing.OutQuint); this.FadeOut(250); - Expire(); + Expire(true); } } } From b6fb01440b407e62a88852e5f9331e27d9816fba Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 20:44:26 +0900 Subject: [PATCH 150/306] Fix taiko hit states not being reverted on rewind --- .../Objects/Drawables/DrawableHit.cs | 3 +++ .../Objects/Drawables/DrawableHitStrong.cs | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index d923b2dcdf..ad361b66bc 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -86,6 +86,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (State.Value) { case ArmedState.Idle: + SecondHitAllowed = false; + validKeyPressed = false; + this.Delay(HitObject.HitWindows.HalfWindowFor(HitResult.Miss)).Expire(); break; case ArmedState.Miss: diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs index c416d50062..b431d35e16 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Judgements; @@ -46,6 +47,19 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables AddJudgement(new TaikoStrongHitJudgement { Result = HitResult.Great }); } + protected override void UpdateState(ArmedState state) + { + base.UpdateState(state); + + switch (state) + { + case ArmedState.Idle: + firstHitTime = 0; + firstKeyHeld = false; + break; + } + } + public override bool OnReleased(TaikoAction action) { if (action == firstHitAction) From 22dfe46572b2f73a0fbb790688d41a8a78d873d5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 21:45:19 +0900 Subject: [PATCH 151/306] Make taiko hitobject properly unproxy when rewound --- .../Objects/Drawables/DrawableHit.cs | 4 ++ .../Objects/Drawables/DrawableSwell.cs | 20 +++---- .../Drawables/DrawableTaikoHitObject.cs | 60 +++++++++++++++++-- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 20 +------ 4 files changed, 70 insertions(+), 34 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index d923b2dcdf..cca2753524 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -86,6 +86,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (State.Value) { case ArmedState.Idle: + UnproxyContent(); this.Delay(HitObject.HitWindows.HalfWindowFor(HitResult.Miss)).Expire(); break; case ArmedState.Miss: @@ -93,6 +94,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables .Expire(); break; case ArmedState.Hit: + if (X >= -0.05f) + ProxyContent(); + var flash = circlePiece?.FlashBox; if (flash != null) { diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 33cc29bccf..1f571544d8 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -20,12 +20,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { public class DrawableSwell : DrawableTaikoHitObject { - /// - /// Invoked when the swell has reached the hit target, i.e. when CurrentTime >= StartTime. - /// This is only ever invoked once. - /// - public event Action OnStart; - private const float target_ring_thick_border = 1.4f; private const float target_ring_thin_border = 1f; private const float target_ring_scale = 5f; @@ -40,7 +34,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private int userHits; - private bool hasStarted; + private bool hasProxied; private readonly SwellSymbolPiece symbol; public DrawableSwell(Swell swell) @@ -48,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { FillMode = FillMode.Fit; - AddInternal(bodyContainer = new Container + Content.Add(bodyContainer = new Container { RelativeSizeAxes = Axes.Both, Depth = 1, @@ -177,6 +171,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (state) { + case ArmedState.Idle: + hasProxied = false; + UnproxyContent(); + break; case ArmedState.Hit: bodyContainer.Delay(untilJudgement).ScaleTo(1.4f, out_transition_time); break; @@ -195,10 +193,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables X = Math.Max(0, X); double t = Math.Min(HitObject.StartTime, Time.Current); - if (t == HitObject.StartTime && !hasStarted) + if (t == HitObject.StartTime && !hasProxied) { - OnStart?.Invoke(); - hasStarted = true; + ProxyContent(); + hasProxied = true; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 971fd8854d..c07ee3a0fd 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -9,10 +9,62 @@ using OpenTK; using System.Linq; using osu.Game.Audio; using System.Collections.Generic; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { - public abstract class DrawableTaikoHitObject : DrawableHitObject, IKeyBindingHandler + public abstract class DrawableTaikoHitObject : DrawableHitObject, IKeyBindingHandler + { + protected readonly Container Content; + public readonly Container ProxiedContent; + + private readonly Container nonProxiedContent; + + protected DrawableTaikoHitObject(TaikoHitObject hitObject) + : base(hitObject) + { + InternalChildren = new[] + { + nonProxiedContent = new Container + { + RelativeSizeAxes = Axes.Both, + Child = Content = new Container { RelativeSizeAxes = Axes.Both } + }, + ProxiedContent = new Container { RelativeSizeAxes = Axes.Both } + }; + } + + /// + /// is proxied into an upper layer. We don't want to get masked away otherwise would too. + /// + protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => false; + + /// + /// Moves to a layer proxied above the playfield. + /// + protected void ProxyContent() + { + nonProxiedContent.Remove(Content); + ProxiedContent.Remove(Content); + ProxiedContent.Add(Content); + } + + /// + /// Moves to the normal hitobject layer. + /// + protected void UnproxyContent() + { + ProxiedContent.Remove(Content); + nonProxiedContent.Remove(Content); + nonProxiedContent.Add(Content); + } + + public abstract bool OnPressed(TaikoAction action); + public virtual bool OnReleased(TaikoAction action) => false; + } + + public abstract class DrawableTaikoHitObject : DrawableTaikoHitObject where TaikoHitType : TaikoHitObject { public override Vector2 OriginPosition => new Vector2(DrawHeight / 2); @@ -34,7 +86,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables RelativeSizeAxes = Axes.Both; Size = BaseSize = new Vector2(HitObject.IsStrong ? TaikoHitObject.DEFAULT_STRONG_SIZE : TaikoHitObject.DEFAULT_SIZE); - InternalChild = MainPiece = CreateMainPiece(); + Content.Add(MainPiece = CreateMainPiece()); MainPiece.KiaiMode = HitObject.Kiai; } @@ -44,9 +96,5 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override string SampleNamespace => "Taiko"; protected virtual TaikoPiece CreateMainPiece() => new CirclePiece(); - - public abstract bool OnPressed(TaikoAction action); - - public virtual bool OnReleased(TaikoAction action) => false; } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 417a7c2581..c638f807fe 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -216,10 +216,9 @@ namespace osu.Game.Rulesets.Taiko.UI if (barline != null) barlineContainer.Add(barline.CreateProxy()); - // Swells should be moved at the very top of the playfield when they reach the hit target - var swell = h as DrawableSwell; - if (swell != null) - swell.OnStart += () => topLevelHitContainer.Add(swell.CreateProxy()); + var taikoObject = h as DrawableTaikoHitObject; + if (taikoObject != null) + topLevelHitContainer.Add(taikoObject.ProxiedContent.CreateProxy()); } internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) @@ -244,19 +243,6 @@ namespace osu.Game.Rulesets.Taiko.UI hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == judgedObject)?.VisualiseSecondHit(); else { - if (judgedObject.X >= -0.05f && judgedObject is DrawableHit) - { - // If we're far enough away from the left stage, we should bring outselves in front of it - // Todo: The following try-catch is temporary for replay rewinding support - try - { - topLevelHitContainer.Add(judgedObject.CreateProxy()); - } - catch - { - } - } - hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim)); if (judgedObject.HitObject.Kiai) From 1b12820de9e8529df794cc3d1396ba9e4d954c29 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Mon, 11 Jun 2018 21:54:11 +0900 Subject: [PATCH 152/306] Restore a removed comment --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index cca2753524..519b56a3ed 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -94,6 +94,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables .Expire(); break; case ArmedState.Hit: + // If we're far enough away from the left stage, we should bring outselves in front of it if (X >= -0.05f) ProxyContent(); From 0f9c05d1e6dee534dbae0bcfb91c43fa3bcc7fdd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 22:32:08 +0900 Subject: [PATCH 153/306] Fix taiko swells not properly rewinding --- .../TaikoIntermediateSwellJudgement.cs | 26 +++++++++++++ .../Objects/Drawables/DrawableSwell.cs | 38 +++++++++---------- 2 files changed, 45 insertions(+), 19 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Judgements/TaikoIntermediateSwellJudgement.cs diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoIntermediateSwellJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoIntermediateSwellJudgement.cs new file mode 100644 index 0000000000..608f1f9be2 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoIntermediateSwellJudgement.cs @@ -0,0 +1,26 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Taiko.Judgements +{ + public class TaikoIntermediateSwellJudgement : TaikoJudgement + { + public override HitResult MaxResult => HitResult.Perfect; + + public override bool AffectsCombo => false; + + public TaikoIntermediateSwellJudgement() + { + Final = false; + } + + /// + /// Computes the numeric result value for the combo portion of the score. + /// + /// The result to compute the value for. + /// The numeric result value. + protected override int NumericResultFor(HitResult result) => 0; + } +} diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 33cc29bccf..5c3f8601b4 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -26,6 +25,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// public event Action OnStart; + /// + /// A judgement is only displayed when the user has complete the swell (either a hit or miss). + /// + public override bool DisplayJudgement => AllJudged; + private const float target_ring_thick_border = 1.4f; private const float target_ring_thin_border = 1f; private const float target_ring_scale = 5f; @@ -35,11 +39,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private readonly CircularContainer targetRing; private readonly CircularContainer expandingRing; - /// - /// The amount of times the user has hit this swell. - /// - private int userHits; - private bool hasStarted; private readonly SwellSymbolPiece symbol; @@ -136,9 +135,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { if (userTriggered) { - userHits++; + AddJudgement(new TaikoIntermediateSwellJudgement()); - var completion = (float)userHits / HitObject.RequiredHits; + var completion = (float)Judgements.Count / HitObject.RequiredHits; expandingRing .FadeTo(expandingRing.Alpha + MathHelper.Clamp(completion / 16, 0.1f, 0.6f), 50) @@ -149,7 +148,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint); - if (userHits == HitObject.RequiredHits) + if (Judgements.Count == HitObject.RequiredHits) AddJudgement(new TaikoJudgement { Result = HitResult.Great }); } else @@ -158,7 +157,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return; //TODO: THIS IS SHIT AND CAN'T EXIST POST-TAIKO WORLD CUP - AddJudgement(userHits > HitObject.RequiredHits / 2 + AddJudgement(Judgements.Count > HitObject.RequiredHits / 2 ? new TaikoJudgement { Result = HitResult.Good } : new TaikoJudgement { Result = HitResult.Miss }); } @@ -169,20 +168,21 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables const float preempt = 100; const float out_transition_time = 300; - double untilStartTime = HitObject.StartTime - Time.Current; - double untilJudgement = untilStartTime + (Judgements.FirstOrDefault()?.TimeOffset ?? 0) + HitObject.Duration; - - targetRing.Delay(untilStartTime - preempt).ScaleTo(target_ring_scale, preempt * 4, Easing.OutQuint); - this.Delay(untilJudgement).FadeOut(out_transition_time, Easing.Out); - switch (state) { + case ArmedState.Idle: + expandingRing.FadeTo(0); + using (BeginAbsoluteSequence(HitObject.StartTime - preempt, true)) + targetRing.ScaleTo(target_ring_scale, preempt * 4, Easing.OutQuint); + break; + case ArmedState.Miss: case ArmedState.Hit: - bodyContainer.Delay(untilJudgement).ScaleTo(1.4f, out_transition_time); + this.FadeOut(out_transition_time, Easing.Out); + bodyContainer.ScaleTo(1.4f, out_transition_time); + + Expire(); break; } - - Expire(); } protected override void Update() From 7651819fb0ea29f7f636cdd4e4e42fcfa680e24b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 12:53:53 +0900 Subject: [PATCH 154/306] Add same change to mania's hit explosions --- osu.Game.Rulesets.Mania/UI/HitExplosion.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs index f19c3a811b..bf8db63137 100644 --- a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs @@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Mania.UI { internal class HitExplosion : CompositeDrawable { + public override bool RemoveWhenNotAlive => true; + private readonly CircularContainer circle; public HitExplosion(DrawableHitObject judgedObject) From b90cdfbfd166aeb8fc26ad1bf8f51ff8d1c9b3d1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 14:33:33 +0900 Subject: [PATCH 155/306] Remove unused variable --- osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index 0a2e549509..c0557982fb 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -19,8 +19,6 @@ namespace osu.Game.Tests.Visual public TestCaseEditorComposeTimeline() { - TimelineArea timelineArea; - Children = new Drawable[] { new MusicController From 6ceac8ab0a316437d1dfed2c133927e2496c71f3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 24 May 2018 15:23:59 +0900 Subject: [PATCH 156/306] Add a centre marker to the timeline --- .../Visual/TestCaseEditorComposeTimeline.cs | 9 +++- .../Screens/Compose/Timeline/CentreMarker.cs | 52 +++++++++++++++++++ .../Edit/Screens/Compose/Timeline/Timeline.cs | 6 +++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index c0557982fb..d731ef973a 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -15,7 +15,14 @@ namespace osu.Game.Tests.Visual [TestFixture] public class TestCaseEditorComposeTimeline : EditorClockTestCase { - public override IReadOnlyList RequiredTypes => new[] { typeof(TimelineArea), typeof(Timeline), typeof(TimelineButton) }; + public override IReadOnlyList RequiredTypes => new[] + { + typeof(TimelineArea), + typeof(Timeline), + typeof(BeatmapWaveformGraph), + typeof(TimelineButton), + typeof(CentreMarker) + }; public TestCaseEditorComposeTimeline() { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs new file mode 100644 index 0000000000..8e932f307d --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs @@ -0,0 +1,52 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using OpenTK; + +namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +{ + public class CentreMarker : CompositeDrawable + { + private const float triangle_width = 20; + private const float triangle_height = 10; + private const float bar_width = 2; + + public CentreMarker() + { + RelativeSizeAxes = Axes.Y; + Size = new Vector2(20, 1); + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + InternalChildren = new Drawable[] + { + new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + Width = bar_width, + }, + new Triangle + { + Anchor = Anchor.TopCentre, + Origin = Anchor.BottomCentre, + Size = new Vector2(triangle_width, triangle_height), + Scale = new Vector2(1, -1) + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.Red; + } + } +} diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index daf67ed7f0..d5f47f5e04 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -41,6 +41,12 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline Depth = float.MaxValue }; + // We don't want the centre marker to scroll + AddInternal(new CentreMarker()); + + // Make sure that the scrollbar is above the centre marker + ChangeInternalChildDepth(Scrollbar, -1); + WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); Beatmap.BindTo(beatmap); From 7dfe171869ed7b0596c30620f55ea834636628c2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 14:31:12 +0900 Subject: [PATCH 157/306] Fix rebase error --- osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index d731ef973a..a89c5767fc 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -19,7 +19,6 @@ namespace osu.Game.Tests.Visual { typeof(TimelineArea), typeof(Timeline), - typeof(BeatmapWaveformGraph), typeof(TimelineButton), typeof(CentreMarker) }; From aaf2f66594527f0d912bedaf72e79c22e4916b5c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 15:49:42 +0900 Subject: [PATCH 158/306] Make scrolling only zoom the timeline --- .../Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs index 035e6a0804..ed26c28c80 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs @@ -99,10 +99,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline protected override bool OnScroll(InputState state) { - if (!state.Keyboard.ControlPressed) + if (state.Mouse.HasPreciseScroll) return base.OnScroll(state); - - setZoomTarget(zoomTarget + state.Mouse.ScrollDelta.X, zoomedContent.ToLocalSpace(state.Mouse.NativeState.Position).X); + setZoomTarget(zoomTarget + state.Mouse.ScrollDelta.Y, zoomedContent.ToLocalSpace(state.Mouse.NativeState.Position).X); return true; } From 3b396e38caf1211eb3b6645f81b22e86092b7904 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 15:51:48 +0900 Subject: [PATCH 159/306] Hide the scrollbar --- .../Edit/Screens/Compose/Timeline/Timeline.cs | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index daf67ed7f0..3bd7a0b96b 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -25,6 +25,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline ZoomDuration = 200; ZoomEasing = Easing.OutQuint; Zoom = 10; + ScrollbarVisible = false; } private WaveformGraph waveform; @@ -150,35 +151,5 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline if (trackWasPlaying) adjustableClock.Start(); } - - protected override ScrollbarContainer CreateScrollbar(Direction direction) => new TimelineScrollbar(this, direction); - - private class TimelineScrollbar : ScrollbarContainer - { - private readonly Timeline timeline; - - public TimelineScrollbar(Timeline timeline, Direction scrollDir) - : base(scrollDir) - { - this.timeline = timeline; - } - - protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) - { - if (base.OnMouseDown(state, args)) - { - timeline.beginUserDrag(); - return true; - } - - return false; - } - - protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) - { - timeline.endUserDrag(); - return base.OnMouseUp(state, args); - } - } } } From 34f23359bb773c8997e8e34a1e65d31374e679d9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 16:20:31 +0900 Subject: [PATCH 160/306] Fix unit tests --- .../Visual/TestCaseZoomableScrollContainer.cs | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs index 70dd67cdbd..0d6526b637 100644 --- a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs @@ -77,16 +77,12 @@ namespace osu.Game.Tests.Visual // Scroll in at 0.25 AddStep("Move mouse to 0.25x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, scrollQuad.Centre.Y))); - AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); - AddStep("Scroll by 3", () => InputManager.ScrollBy(new Vector2(3, 0))); - AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddStep("Scroll by 3", () => InputManager.ScrollBy(new Vector2(0, 3))); AddAssert("Box not at 0", () => !Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft)); AddAssert("Box 1/4 at 1/4", () => Precision.AlmostEquals(boxQuad.TopLeft.X + 0.25f * boxQuad.Size.X, scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X)); // Scroll out at 0.25 - AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); - AddStep("Scroll by -3", () => InputManager.ScrollBy(new Vector2(-3, 0))); - AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddStep("Scroll by -3", () => InputManager.ScrollBy(new Vector2(0, -3))); AddAssert("Box at 0", () => Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft)); AddAssert("Box 1/4 at 1/4", () => Precision.AlmostEquals(boxQuad.TopLeft.X + 0.25f * boxQuad.Size.X, scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X)); } @@ -98,15 +94,11 @@ namespace osu.Game.Tests.Visual // Scroll in at 0.25 AddStep("Move mouse to 0.25x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, scrollQuad.Centre.Y))); - AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); - AddStep("Scroll by 1", () => InputManager.ScrollBy(new Vector2(1, 0))); - AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddStep("Scroll by 1", () => InputManager.ScrollBy(new Vector2(0, 1))); // Scroll in at 0.6 AddStep("Move mouse to 0.75x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.75f * scrollQuad.Size.X, scrollQuad.Centre.Y))); - AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); - AddStep("Scroll by 1", () => InputManager.ScrollBy(new Vector2(1, 0))); - AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddStep("Scroll by 1", () => InputManager.ScrollBy(new Vector2(0, 1))); AddAssert("Box not at 0", () => !Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft)); // Very hard to determine actual position, so approximate @@ -115,15 +107,11 @@ namespace osu.Game.Tests.Visual AddAssert("Box at correct position (3)", () => Precision.DefinitelyBigger(boxQuad.TopLeft.X + 0.6f * boxQuad.Size.X, scrollQuad.TopLeft.X + 0.6f * scrollQuad.Size.X)); // Scroll out at 0.6 - AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); - AddStep("Scroll by -1", () => InputManager.ScrollBy(new Vector2(-1, 0))); - AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddStep("Scroll by -1", () => InputManager.ScrollBy(new Vector2(0, -1))); // Scroll out at 0.25 AddStep("Move mouse to 0.25x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, scrollQuad.Centre.Y))); - AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); - AddStep("Scroll by -1", () => InputManager.ScrollBy(new Vector2(-1, 0))); - AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddStep("Scroll by -1", () => InputManager.ScrollBy(new Vector2(0, -1))); AddAssert("Box at 0", () => Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft)); } From 93d2b5c4dea32f93186e877697cb95cf806e902b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 16:20:38 +0900 Subject: [PATCH 161/306] Adjust precision for failing test --- osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs index 0d6526b637..7fe59979a1 100644 --- a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual { reset(); AddStep("Set zoom = 10", () => scrollContainer.Zoom = 10); - AddAssert("Box at 1/2", () => Precision.AlmostEquals(boxQuad.Centre, scrollQuad.Centre)); + AddAssert("Box at 1/2", () => Precision.AlmostEquals(boxQuad.Centre, scrollQuad.Centre, 1)); AddAssert("Box width = 10x", () => Precision.AlmostEquals(boxQuad.Size.X, 10 * scrollQuad.Size.X)); } From ac1990c093a9f69eabdbe49af90182794466ee3c Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Tue, 12 Jun 2018 16:36:46 +0900 Subject: [PATCH 162/306] Remove unused using --- osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs index 7fe59979a1..8bd1b79a84 100644 --- a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs @@ -13,7 +13,6 @@ using osu.Game.Graphics.Cursor; using osu.Game.Screens.Edit.Screens.Compose.Timeline; using OpenTK; using OpenTK.Graphics; -using OpenTK.Input; namespace osu.Game.Tests.Visual { From c70c7a476bf492d6f157fabc36406093bf0eafc3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 17:59:59 +0900 Subject: [PATCH 163/306] Always display the key counter during replay/autoplay --- osu.Game/Screens/Play/KeyCounterCollection.cs | 12 ++++++++---- osu.Game/Screens/Play/Player.cs | 13 +++++++------ osu.Game/Screens/Play/ReplayPlayer.cs | 7 +++++++ 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/KeyCounterCollection.cs b/osu.Game/Screens/Play/KeyCounterCollection.cs index 8cbb9986e5..8b579f41ac 100644 --- a/osu.Game/Screens/Play/KeyCounterCollection.cs +++ b/osu.Game/Screens/Play/KeyCounterCollection.cs @@ -18,7 +18,8 @@ namespace osu.Game.Screens.Play { private const int duration = 100; - private Bindable showKeyCounter; + public readonly Bindable Visible = new Bindable(true); + private readonly Bindable alwaysVisible = new Bindable(); public KeyCounterCollection() { @@ -46,9 +47,10 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - showKeyCounter = config.GetBindable(OsuSetting.KeyOverlay); - showKeyCounter.ValueChanged += keyCounterVisibility => this.FadeTo(keyCounterVisibility ? 1 : 0, duration); - showKeyCounter.TriggerChange(); + config.BindWith(OsuSetting.KeyOverlay, alwaysVisible); + + Visible.BindValueChanged(_ => updateVisibility()); + alwaysVisible.BindValueChanged(_ => updateVisibility(), true); } //further: change default values here and in KeyCounter if needed, instead of passing them in every constructor @@ -111,6 +113,8 @@ namespace osu.Game.Screens.Play } } + private void updateVisibility() => this.FadeTo(Visible.Value || alwaysVisible.Value ? 1 : 0, duration); + public override bool HandleKeyboardInput => receptor == null; public override bool HandleMouseInput => receptor == null; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 04148cd558..5fd85ce6e7 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Play protected ScoreProcessor ScoreProcessor; protected RulesetContainer RulesetContainer; - private HUDOverlay hudOverlay; + protected HUDOverlay HudOverlay; private FailOverlay failOverlay; private DrawableStoryboard storyboard; @@ -170,9 +170,9 @@ namespace osu.Game.Screens.Play OnPause = () => { pauseContainer.Retries = RestartCount; - hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; + HudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; }, - OnResume = () => hudOverlay.KeyCounter.IsCounting = true, + OnResume = () => HudOverlay.KeyCounter.IsCounting = true, Children = new[] { storyboardContainer = new Container @@ -193,7 +193,7 @@ namespace osu.Game.Screens.Play Breaks = beatmap.Breaks }, RulesetContainer.Cursor?.CreateProxy() ?? new Container(), - hudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock) + HudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock) { Clock = Clock, // hud overlay doesn't want to use the audio clock directly ProcessCustomClock = false, @@ -228,7 +228,8 @@ namespace osu.Game.Screens.Play } }; - hudOverlay.HoldToQuit.Action = Exit; + HudOverlay.HoldToQuit.Action = Exit; + HudOverlay.KeyCounter.Visible.Value = RulesetContainer.HasReplayLoaded; if (ShowStoryboard) initializeStoryboard(false); @@ -368,7 +369,7 @@ namespace osu.Game.Screens.Play RulesetContainer?.FadeOut(fade_out_duration); Content.FadeOut(fade_out_duration); - hudOverlay?.ScaleTo(0.7f, fade_out_duration * 3, Easing.In); + HudOverlay?.ScaleTo(0.7f, fade_out_duration * 3, Easing.In); Background?.FadeTo(1f, fade_out_duration); } diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 6e2a2e4c9c..16f8a4b361 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; using osu.Game.Rulesets.Replays; namespace osu.Game.Screens.Play @@ -14,6 +15,12 @@ namespace osu.Game.Screens.Play Replay = replay; } + [BackgroundDependencyLoader] + private void load() + { + HudOverlay.KeyCounter.Visible.Value = true; + } + protected override void LoadComplete() { base.LoadComplete(); From bcfb092e53709f65391d6c7294b0f3c2762c4c2e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Jun 2018 18:03:45 +0900 Subject: [PATCH 164/306] Change step to 200 --- osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index 231892bdd9..830214803c 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// /// The step increase/decrease of the span of time visible by the length of the scrolling axes. /// - private const double time_span_step = 500; + private const double time_span_step = 200; /// /// The span of time that is visible by the length of the scrolling axes. From 67aa52fb1d79851e1049eea82f6bc4a942dd040f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 19:34:49 +0900 Subject: [PATCH 165/306] Use bindable binding --- osu.Game/Screens/Play/Player.cs | 2 +- osu.Game/Screens/Play/ReplayPlayer.cs | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 5fd85ce6e7..7e0321d81d 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -229,7 +229,7 @@ namespace osu.Game.Screens.Play }; HudOverlay.HoldToQuit.Action = Exit; - HudOverlay.KeyCounter.Visible.Value = RulesetContainer.HasReplayLoaded; + HudOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded); if (ShowStoryboard) initializeStoryboard(false); diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 16f8a4b361..6e2a2e4c9c 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Allocation; using osu.Game.Rulesets.Replays; namespace osu.Game.Screens.Play @@ -15,12 +14,6 @@ namespace osu.Game.Screens.Play Replay = replay; } - [BackgroundDependencyLoader] - private void load() - { - HudOverlay.KeyCounter.Visible.Value = true; - } - protected override void LoadComplete() { base.LoadComplete(); From ca3186f34c7b2507fef6e0900e61e5c7e9746c82 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 19:51:35 +0900 Subject: [PATCH 166/306] Create dependencies before children are loaded --- osu.Game/Tests/Visual/EditorClockTestCase.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game/Tests/Visual/EditorClockTestCase.cs b/osu.Game/Tests/Visual/EditorClockTestCase.cs index 08dc6a3bbd..521b51529e 100644 --- a/osu.Game/Tests/Visual/EditorClockTestCase.cs +++ b/osu.Game/Tests/Visual/EditorClockTestCase.cs @@ -25,13 +25,20 @@ namespace osu.Game.Tests.Visual Clock = new EditorClock(new ControlPointInfo(), 5000, BeatDivisor) { IsCoupled = false }; } + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); + + dependencies.Cache(BeatDivisor); + dependencies.CacheAs(Clock); + dependencies.CacheAs(Clock); + + return dependencies; + } + [BackgroundDependencyLoader] private void load() { - Dependencies.Cache(BeatDivisor); - Dependencies.CacheAs(Clock); - Dependencies.CacheAs(Clock); - Beatmap.BindValueChanged(beatmapChanged, true); } From 2a5a52422320cbe39cbcf03614919528c92da78f Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Tue, 12 Jun 2018 20:37:01 +0200 Subject: [PATCH 167/306] delete COMPILING.md --- COMPILING.md | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 COMPILING.md diff --git a/COMPILING.md b/COMPILING.md deleted file mode 100644 index bfcbf6bc2c..0000000000 --- a/COMPILING.md +++ /dev/null @@ -1,36 +0,0 @@ -# Linux -### 1. Requirements: -Mono >= 5.4.0 (>= 5.8.0 recommended) -Please check [here](http://www.mono-project.com/download/) for stable or [here](http://www.mono-project.com/download/alpha/) for an alpha release. -NuGet >= 4.4.0 -msbuild -git - -### 2. Cloning project -Clone the entire repository with submodules using -``` -git clone https://github.com/ppy/osu --recursive -``` -Then restore NuGet packages from the repository -``` -nuget restore -``` -### 3. Compiling -Simply run `msbuild` where `osu.sln` is located, this will create all binaries in `osu/osu.Desktop/bin/Debug`. -### 4. Optimizing -If you want additional performance you can change build type to Release with -``` -msbuild -p:Configuration=Release -``` -Additionally, mono provides an AOT utility which attempts to precompile binaries. You can utilize that by running -``` -mono --aot ./osu\!.exe -``` -### 5. Troubleshooting -You may run into trouble with NuGet versioning, as the one in packaging system is almost always out of date. Simply run -``` -nuget -sudo nuget update -self -``` -**Warning** NuGet creates few config files when it's run for the first time. -Do not run NuGet as root on the first run or you might run into very peculiar issues. From d9e7a324c0c892a1299bdd7764978b9c7596a792 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 11:30:22 +0900 Subject: [PATCH 168/306] Revert HudOverlay to private field --- osu.Game/Screens/Play/Player.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 7e0321d81d..a2ed01f5a7 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Play protected ScoreProcessor ScoreProcessor; protected RulesetContainer RulesetContainer; - protected HUDOverlay HudOverlay; + private HUDOverlay hudOverlay; private FailOverlay failOverlay; private DrawableStoryboard storyboard; @@ -170,9 +170,9 @@ namespace osu.Game.Screens.Play OnPause = () => { pauseContainer.Retries = RestartCount; - HudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; + hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; }, - OnResume = () => HudOverlay.KeyCounter.IsCounting = true, + OnResume = () => hudOverlay.KeyCounter.IsCounting = true, Children = new[] { storyboardContainer = new Container @@ -193,7 +193,7 @@ namespace osu.Game.Screens.Play Breaks = beatmap.Breaks }, RulesetContainer.Cursor?.CreateProxy() ?? new Container(), - HudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock) + hudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock) { Clock = Clock, // hud overlay doesn't want to use the audio clock directly ProcessCustomClock = false, @@ -228,8 +228,8 @@ namespace osu.Game.Screens.Play } }; - HudOverlay.HoldToQuit.Action = Exit; - HudOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded); + hudOverlay.HoldToQuit.Action = Exit; + hudOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded); if (ShowStoryboard) initializeStoryboard(false); @@ -369,7 +369,7 @@ namespace osu.Game.Screens.Play RulesetContainer?.FadeOut(fade_out_duration); Content.FadeOut(fade_out_duration); - HudOverlay?.ScaleTo(0.7f, fade_out_duration * 3, Easing.In); + hudOverlay?.ScaleTo(0.7f, fade_out_duration * 3, Easing.In); Background?.FadeTo(1f, fade_out_duration); } From a7ed3ea80b59f5d09143094eae2036f74c1c4d8c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 11:38:15 +0900 Subject: [PATCH 169/306] Rename alwaysVisible to explain where it comes from --- osu.Game/Screens/Play/KeyCounterCollection.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/KeyCounterCollection.cs b/osu.Game/Screens/Play/KeyCounterCollection.cs index 8b579f41ac..114ea83ba6 100644 --- a/osu.Game/Screens/Play/KeyCounterCollection.cs +++ b/osu.Game/Screens/Play/KeyCounterCollection.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Play private const int duration = 100; public readonly Bindable Visible = new Bindable(true); - private readonly Bindable alwaysVisible = new Bindable(); + private readonly Bindable configVisibility = new Bindable(); public KeyCounterCollection() { @@ -47,10 +47,10 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - config.BindWith(OsuSetting.KeyOverlay, alwaysVisible); + config.BindWith(OsuSetting.KeyOverlay, configVisibility); Visible.BindValueChanged(_ => updateVisibility()); - alwaysVisible.BindValueChanged(_ => updateVisibility(), true); + configVisibility.BindValueChanged(_ => updateVisibility(), true); } //further: change default values here and in KeyCounter if needed, instead of passing them in every constructor @@ -113,7 +113,7 @@ namespace osu.Game.Screens.Play } } - private void updateVisibility() => this.FadeTo(Visible.Value || alwaysVisible.Value ? 1 : 0, duration); + private void updateVisibility() => this.FadeTo(Visible.Value || configVisibility.Value ? 1 : 0, duration); public override bool HandleKeyboardInput => receptor == null; public override bool HandleMouseInput => receptor == null; From b182635aae9b160bdc77775a7cea0d4203d56548 Mon Sep 17 00:00:00 2001 From: Joehu Date: Tue, 12 Jun 2018 20:21:37 -0700 Subject: [PATCH 170/306] Fix taiko nightcore regression --- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index ccf28a2f12..225461fd6f 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -91,7 +91,7 @@ namespace osu.Game.Rulesets.Taiko { new TaikoModHardRock(), new MultiMod(new TaikoModSuddenDeath(), new TaikoModPerfect()), - new MultiMod(new TaikoModDoubleTime(), new TaikoModDaycore()), + new MultiMod(new TaikoModDoubleTime(), new TaikoModNightcore()), new TaikoModHidden(), new TaikoModFlashlight(), }; From f4cb0d7d8daf7abd57ec9d50daae1e6d8fba5d74 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 14:16:58 +0900 Subject: [PATCH 171/306] Fix memory leak due to incorrect binding --- osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs index 240d8dc396..35146dfe29 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs @@ -161,7 +161,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor }; this.beatmap.BindTo(beatmap); - beatmap.ValueChanged += v => calculateScale(); + this.beatmap.ValueChanged += v => calculateScale(); cursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); cursorScale.ValueChanged += v => calculateScale(); From 14f5c814a69b66237840ede64c389f99c56409c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 15:12:10 +0900 Subject: [PATCH 172/306] Add test for WorkingBeatmap leakage --- osu.Game/Tests/Visual/TestCasePlayer.cs | 34 ++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 3cdc496ee1..55fb9c483b 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -1,9 +1,12 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics.Shapes; +using osu.Framework.Lists; +using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -43,6 +46,7 @@ namespace osu.Game.Tests.Visual Player p = null; AddStep(ruleset.RulesetInfo.Name, () => p = loadPlayerFor(ruleset)); AddUntilStep(() => ContinueCondition(p)); + } else { @@ -51,6 +55,20 @@ namespace osu.Game.Tests.Visual Player p = null; AddStep(r.Name, () => p = loadPlayerFor(r)); AddUntilStep(() => ContinueCondition(p)); + AddAssert("no leaked beatmaps", () => + { + p = null; + + GC.Collect(); + GC.WaitForPendingFinalizers(); + int count = 0; + + workingWeakReferences.ForEachAlive(_ => count++); + + Logger.Log($"reference count {count}"); + + return count == 1; + }); } } } @@ -59,21 +77,29 @@ namespace osu.Game.Tests.Visual protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo); + private readonly WeakList workingWeakReferences = new WeakList(); + private Player loadPlayerFor(RulesetInfo ri) => loadPlayerFor(ri.CreateInstance()); private Player loadPlayerFor(Ruleset r) { var beatmap = CreateBeatmap(r); + var working = new TestWorkingBeatmap(beatmap); - Beatmap.Value = new TestWorkingBeatmap(beatmap); + workingWeakReferences.Add(working); + + Beatmap.Value = working; Beatmap.Value.Mods.Value = new[] { r.GetAllMods().First(m => m is ModNoFail) }; - if (Player != null) - Remove(Player); + Player?.Exit(); var player = CreatePlayer(r); - LoadComponentAsync(player, LoadScreen); + LoadComponentAsync(player, p => + { + Player = p; + LoadScreen(p); + }); return player; } From 39738a997eab5c7a085c44633883c9bbab155b9a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 15:26:05 +0900 Subject: [PATCH 173/306] Add check for player screens too --- osu.Game/Tests/Visual/TestCasePlayer.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 55fb9c483b..beaa6bb43a 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -6,7 +6,6 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics.Shapes; using osu.Framework.Lists; -using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -55,6 +54,7 @@ namespace osu.Game.Tests.Visual Player p = null; AddStep(r.Name, () => p = loadPlayerFor(r)); AddUntilStep(() => ContinueCondition(p)); + AddAssert("no leaked beatmaps", () => { p = null; @@ -64,9 +64,16 @@ namespace osu.Game.Tests.Visual int count = 0; workingWeakReferences.ForEachAlive(_ => count++); + return count == 1; + }); - Logger.Log($"reference count {count}"); + AddAssert("no leaked players", () => + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + int count = 0; + playerWeakReferences.ForEachAlive(_ => count++); return count == 1; }); } @@ -78,6 +85,7 @@ namespace osu.Game.Tests.Visual protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo); private readonly WeakList workingWeakReferences = new WeakList(); + private readonly WeakList playerWeakReferences = new WeakList(); private Player loadPlayerFor(RulesetInfo ri) => loadPlayerFor(ri.CreateInstance()); @@ -95,6 +103,8 @@ namespace osu.Game.Tests.Visual var player = CreatePlayer(r); + playerWeakReferences.Add(player); + LoadComponentAsync(player, p => { Player = p; From 0fdb04f57dcbba6077f8e04020bed92e6678aa08 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 15:43:00 +0900 Subject: [PATCH 174/306] Fix empty line --- osu.Game/Tests/Visual/TestCasePlayer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index beaa6bb43a..20c9646aa3 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -45,7 +45,6 @@ namespace osu.Game.Tests.Visual Player p = null; AddStep(ruleset.RulesetInfo.Name, () => p = loadPlayerFor(ruleset)); AddUntilStep(() => ContinueCondition(p)); - } else { From 2a18625b2c95f2f2fda8981365f177417e339969 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 16:46:27 +0900 Subject: [PATCH 175/306] Correctly block scroll events when hovering controls --- osu.Game/Overlays/Volume/VolumeMeter.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 451809867d..29fef48d13 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -177,12 +177,13 @@ namespace osu.Game.Overlays.Volume { float amount = adjust_step * direction; - var mouse = GetContainingInputManager().CurrentState.Mouse; - if (mouse.HasPreciseScroll) + // handle the case where the OnPressed action was actually a mouse wheel. + // this allows for precise wheel handling. + var state = GetContainingInputManager().CurrentState; + if (state.Mouse?.ScrollDelta.Y != 0) { - float scrollDelta = mouse.ScrollDelta.Y; - if (scrollDelta != 0) - amount *= Math.Abs(scrollDelta / 10); + OnScroll(state); + return; } Volume += amount; @@ -205,6 +206,14 @@ namespace osu.Game.Overlays.Volume return false; } + protected override bool OnScroll(InputState state) + { + double amount = adjust_step * state.Mouse.ScrollDelta.Y * (state.Mouse.HasPreciseScroll ? 0.5f : 1); + + Volume += Math.Sign(amount) * Math.Max(0.01, Math.Abs(amount)); + return true; + } + public bool OnReleased(GlobalAction action) => false; private const float transition_length = 500; From a55bf82fd9c4c76f269fb08fd2dbd4697194c9e0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 16:46:48 +0900 Subject: [PATCH 176/306] Handle hover blocking in VolumeOverlay to ensure correct hide scheduling --- osu.Game/Overlays/Volume/VolumeMeter.cs | 2 +- osu.Game/Overlays/VolumeOverlay.cs | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 29fef48d13..b3dd06022e 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -221,7 +221,7 @@ namespace osu.Game.Overlays.Volume protected override bool OnHover(InputState state) { this.ScaleTo(1.04f, transition_length, Easing.OutExpo); - return true; + return false; } protected override void OnHoverLost(InputState state) diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index 5a3d51c00a..a56a160e20 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -142,13 +142,18 @@ namespace osu.Game.Overlays return base.OnMouseMove(state); } + protected override bool OnHover(InputState state) + { + Show(); + return true; + } + private void schedulePopOut() { popOutDelegate?.Cancel(); this.Delay(1000).Schedule(() => { - // only actually hide if the mouse isn't within our bounds. - if (!ScreenSpaceDrawQuad.Contains(GetContainingInputManager().CurrentState.Mouse.Position)) + if (!IsHovered) Hide(); }, out popOutDelegate); } From e0b68e4e09c0838c93e3c96746b284c5110314c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 16:47:10 +0900 Subject: [PATCH 177/306] Fix hide re-schedule not triggering on noop state change --- osu.Game/Overlays/VolumeOverlay.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index a56a160e20..24afa414d6 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -122,6 +122,14 @@ namespace osu.Game.Overlays private ScheduledDelegate popOutDelegate; + public override void Show() + { + if (State == Visibility.Visible) + schedulePopOut(); + + base.Show(); + } + protected override void PopIn() { ClearTransforms(); From cee5be1d56028f9c0858a6923583ba5ed8ce9e2b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 17:03:56 +0900 Subject: [PATCH 178/306] Improve precision wheel adjustment handling --- osu.Game/Overlays/Volume/VolumeMeter.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index b3dd06022e..4d20166784 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -206,11 +206,18 @@ namespace osu.Game.Overlays.Volume return false; } + // because volume precision is set to 0.01, this local is required to keep track of more precise adjustments and only apply when possible. + private double scrollAmount; + protected override bool OnScroll(InputState state) { - double amount = adjust_step * state.Mouse.ScrollDelta.Y * (state.Mouse.HasPreciseScroll ? 0.5f : 1); + scrollAmount += adjust_step * state.Mouse.ScrollDelta.Y * (state.Mouse.HasPreciseScroll ? 0.1f : 1); - Volume += Math.Sign(amount) * Math.Max(0.01, Math.Abs(amount)); + if (Math.Abs(scrollAmount) < Bindable.Precision) + return true; + + Volume += scrollAmount; + scrollAmount = 0; return true; } From b318b770d4ea82efdb6f24b11f1cf131af77d2bd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 19:18:11 +0900 Subject: [PATCH 179/306] Fix pixellation of volume meter progress bars --- osu.Game.Tests/Visual/TestCaseVolumePieces.cs | 13 +- osu.Game/Overlays/Volume/VolumeMeter.cs | 200 +++++++++++------- 2 files changed, 139 insertions(+), 74 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseVolumePieces.cs b/osu.Game.Tests/Visual/TestCaseVolumePieces.cs index 449f48b7d7..3c5b91ccd2 100644 --- a/osu.Game.Tests/Visual/TestCaseVolumePieces.cs +++ b/osu.Game.Tests/Visual/TestCaseVolumePieces.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using osu.Framework.Graphics; using osu.Game.Overlays.Volume; +using OpenTK; using OpenTK.Graphics; namespace osu.Game.Tests.Visual @@ -17,13 +18,21 @@ namespace osu.Game.Tests.Visual { VolumeMeter meter; MuteButton mute; - Add(meter = new VolumeMeter("MASTER", 125, Color4.Blue)); + Add(meter = new VolumeMeter("MASTER", 125, Color4.Blue) { Position = new Vector2(10) }); + AddSliderStep("master volume", 0, 10, 0, i => meter.Bindable.Value = i * 0.1); + + Add(new VolumeMeter("BIG", 250, Color4.Red) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Position = new Vector2(10), + }); + Add(mute = new MuteButton { Margin = new MarginPadding { Top = 200 } }); - AddSliderStep("master volume", 0, 10, 0, i => meter.Bindable.Value = i * 0.1); AddToggleStep("mute", b => mute.Current.Value = b); } } diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index b2cf43704b..0e43945f8c 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -24,6 +24,8 @@ namespace osu.Game.Overlays.Volume public class VolumeMeter : Container, IKeyBindingHandler { private CircularProgress volumeCircle; + private CircularProgress volumeCircleGlow; + public BindableDouble Bindable { get; } = new BindableDouble { MinValue = 0, MaxValue = 1 }; private readonly float circleSize; private readonly Color4 meterColour; @@ -44,90 +46,143 @@ namespace osu.Game.Overlays.Volume [BackgroundDependencyLoader] private void load(OsuColour colours) { - Add(new Container - { - Size = new Vector2(120, 20), - CornerRadius = 10, - Masking = true, - Margin = new MarginPadding { Left = circleSize + 10 }, - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Gray1, - Alpha = 0.9f, - }, - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = "Exo2.0-Bold", - Text = name - } - } - }); + Color4 backgroundColour = colours.Gray1; CircularProgress bgProgress; - Add(new CircularContainer + const float progress_start_radius = 0.75f; + const float progress_size = 0.03f; + const float progress_end_radius = progress_start_radius + progress_size; + + const float blur_amount = 5; + + Children = new Drawable[] { - Masking = true, - Size = new Vector2(circleSize), - Children = new Drawable[] + new Container { - new Box + Size = new Vector2(circleSize), + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = colours.Gray1, - Alpha = 0.9f, - }, - bgProgress = new CircularProgress - { - RelativeSizeAxes = Axes.Both, - InnerRadius = 0.05f, - Rotation = 180, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.Gray2, - Size = new Vector2(0.8f) - }, - new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.8f), - Padding = new MarginPadding(-Blur.KernelSize(5)), - Rotation = 180, - Child = (volumeCircle = new CircularProgress + new BufferedContainer { + Alpha = 0.9f, RelativeSizeAxes = Axes.Both, - InnerRadius = 0.05f, + Children = new Drawable[] + { + new Circle + { + RelativeSizeAxes = Axes.Both, + Colour = backgroundColour, + }, + new CircularContainer + { + Masking = true, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(progress_end_radius), + Children = new Drawable[] + { + bgProgress = new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Rotation = 180, + Colour = backgroundColour, + }, + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Progress under covers for smoothing", + RelativeSizeAxes = Axes.Both, + Rotation = 180, + Child = volumeCircle = new CircularProgress + { + RelativeSizeAxes = Axes.Both, + } + }, + } + }, + new Circle + { + Name = "Inner Cover", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = backgroundColour, + Size = new Vector2(progress_start_radius), + }, + new Container + { + Name = "Progress overlay for glow", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(progress_start_radius + progress_size / 1.5f), + Rotation = 180, + Padding = new MarginPadding(-Blur.KernelSize(blur_amount)), + Child = (volumeCircleGlow = new CircularProgress + { + RelativeSizeAxes = Axes.Both, + InnerRadius = progress_size * 0.8f, + }).WithEffect(new GlowEffect + { + Colour = meterColour, + BlurSigma = new Vector2(blur_amount), + Strength = 5, + PadExtent = true + }), + }, + }, + }, + maxGlow = (text = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = "Venera", + TextSize = 0.16f * circleSize }).WithEffect(new GlowEffect { - Colour = meterColour, - Strength = 2, - PadExtent = true - }), - }, - maxGlow = (text = new OsuSpriteText + Colour = Color4.Transparent, + PadExtent = true, + }) + } + }, + new Container + { + Size = new Vector2(120, 20), + CornerRadius = 10, + Masking = true, + Margin = new MarginPadding { Left = circleSize + 10 }, + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = "Venera", - TextSize = 0.16f * circleSize - }).WithEffect(new GlowEffect - { - Colour = Color4.Transparent, - PadExtent = true, - }) + new Box + { + Alpha = 0.9f, + RelativeSizeAxes = Axes.Both, + Colour = backgroundColour, + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = "Exo2.0-Bold", + Text = name + } + } } - }); - - Bindable.ValueChanged += newVolume => { this.TransformTo("DisplayVolume", newVolume, 400, Easing.OutQuint); }; + }; + Bindable.ValueChanged += newVolume => + { + this.TransformTo("DisplayVolume", + newVolume, + 400, + Easing.OutQuint); + }; bgProgress.Current.Value = 0.75f; } @@ -158,6 +213,7 @@ namespace osu.Game.Overlays.Volume } volumeCircle.Current.Value = displayVolume * 0.75f; + volumeCircleGlow.Current.Value = displayVolume * 0.75f; } } From 1431ee1867f6f4ca4f648158a316853f3c580d16 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 14:46:25 +0900 Subject: [PATCH 180/306] Remove unused method --- osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index 31cd9dc6f5..a9bf5b1797 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -33,10 +33,6 @@ namespace osu.Game.Rulesets.Difficulty TimeRate = clock.Rate; } - protected virtual void PreprocessHitObjects() - { - } - /// /// Creates all combinations which adjust the difficulty. /// From b7a06b95944fdde0083c7f3f14bfed2132bcc074 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 15:32:07 +0900 Subject: [PATCH 181/306] Restructure of DifficultyCalculator to cleanup mod + attribute handling --- .../Difficulty/DifficultyAttributes.cs | 19 +++++++ .../Difficulty/DifficultyCalculator.cs | 51 ++++++++++++++----- osu.Game/Rulesets/Ruleset.cs | 2 +- 3 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs new file mode 100644 index 0000000000..1fdebd586f --- /dev/null +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Difficulty +{ + public class DifficultyAttributes + { + public readonly Mod[] Mods; + public readonly double StarRating; + + public DifficultyAttributes(Mod[] mods, double starRating) + { + Mods = mods; + StarRating = starRating; + } + } +} diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index a9bf5b1797..8f9651ab09 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -13,24 +13,44 @@ namespace osu.Game.Rulesets.Difficulty { public abstract class DifficultyCalculator { - protected readonly IBeatmap Beatmap; - protected readonly Mod[] Mods; + private readonly Ruleset ruleset; + private readonly WorkingBeatmap beatmap; - protected double TimeRate { get; private set; } = 1; - - protected DifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) + protected DifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) { - Beatmap = beatmap; - Mods = mods ?? new Mod[0]; - - ApplyMods(Mods); + this.ruleset = ruleset; + this.beatmap = beatmap; } - protected virtual void ApplyMods(Mod[] mods) + /// + /// Calculates the difficulty of the beatmap using a specific mod combination. + /// + /// The mods that should be applied to the beatmap. + /// A structure describing the difficulty of the beatmap. + public DifficultyAttributes Calculate(params Mod[] mods) { + beatmap.Mods.Value = mods; + IBeatmap playableBeatmap = beatmap.GetPlayableBeatmap(ruleset.RulesetInfo); + var clock = new StopwatchClock(); mods.OfType().ForEach(m => m.ApplyToClock(clock)); - TimeRate = clock.Rate; + + return Calculate(playableBeatmap, mods, clock.Rate); + } + + /// + /// Calculates the difficulty of the beatmap using all mod combinations applicable to the beatmap. + /// + /// A collection of structures describing the difficulty of the beatmap for each mod combination. + public IEnumerable CalculateAll() + { + foreach (var combination in CreateDifficultyAdjustmentModCombinations()) + { + if (combination is MultiMod multi) + yield return Calculate(multi.Mods); + else + yield return Calculate(combination); + } } /// @@ -71,6 +91,13 @@ namespace osu.Game.Rulesets.Difficulty /// protected virtual Mod[] DifficultyAdjustmentMods => Array.Empty(); - public abstract double Calculate(Dictionary categoryDifficulty = null); + /// + /// Calculates the difficulty of a using a specific combination. + /// + /// The to compute the difficulty for. + /// The s that should be applied. + /// The rate of time in . + /// A structure containing the difficulty attributes. + protected abstract DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate); } } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index a39e8bb8d4..cdc1c44306 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets public virtual IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => null; - public abstract DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null); + public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap); public virtual PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => null; From 47fc18d7c48bc7e5b5f4dce262fc76ee28626372 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 15:36:49 +0900 Subject: [PATCH 182/306] Adjust OsuDifficultyCalculator in-line with changes --- .../Difficulty/OsuDifficultyAttributes.cs | 19 ++++++++++++ .../Difficulty/OsuDifficultyCalculator.cs | 30 +++++++------------ osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- 3 files changed, 31 insertions(+), 20 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs new file mode 100644 index 0000000000..5650bc395a --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Osu.Difficulty +{ + public class OsuDifficultyAttributes : DifficultyAttributes + { + public double AimStrain { get; set; } + public double SpeedStrain { get; set; } + + public OsuDifficultyAttributes(Mod[] mods, double starRating) + : base(mods, starRating) + { + } + } +} diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 94d2afbf45..400afbc043 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -2,7 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; @@ -18,31 +18,26 @@ namespace osu.Game.Rulesets.Osu.Difficulty private const int section_length = 400; private const double difficulty_multiplier = 0.0675; - public OsuDifficultyCalculator(IBeatmap beatmap) - : base(beatmap) + public OsuDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) + : base(ruleset, beatmap) { } - public OsuDifficultyCalculator(IBeatmap beatmap, Mod[] mods) - : base(beatmap, mods) + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) { - } - - public override double Calculate(Dictionary categoryDifficulty = null) - { - OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap((List)Beatmap.HitObjects, TimeRate); + OsuDifficultyBeatmap difficultyBeatmap = new OsuDifficultyBeatmap(beatmap.HitObjects.Cast().ToList(), timeRate); Skill[] skills = { new Aim(), new Speed() }; - double sectionLength = section_length * TimeRate; + double sectionLength = section_length * timeRate; // The first object doesn't generate a strain, so we begin with an incremented section end double currentSectionEnd = 2 * sectionLength; - foreach (OsuDifficultyHitObject h in beatmap) + foreach (OsuDifficultyHitObject h in difficultyBeatmap) { while (h.BaseObject.StartTime > currentSectionEnd) { @@ -61,16 +56,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; - double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; - if (categoryDifficulty != null) + return new OsuDifficultyAttributes(mods, starRating) { - categoryDifficulty.Add("Aim", aimRating); - categoryDifficulty.Add("Speed", speedRating); - } - - return starRating; + AimStrain = aimRating, + SpeedStrain = speedRating + }; } protected override Mod[] DifficultyAdjustmentMods => new Mod[] diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 6ab75d008f..49468392f5 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -120,7 +120,7 @@ namespace osu.Game.Rulesets.Osu public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_osu_o }; - public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new OsuDifficultyCalculator(beatmap, mods); + public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(this, beatmap); public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new OsuPerformanceCalculator(this, beatmap, score); From 33c7ce1bec1a51a70b9a2da9629ef3182132bc32 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 15:47:42 +0900 Subject: [PATCH 183/306] Adjust TaikoDifficultyCalculator in-line with changes --- .../Difficulty/TaikoDifficultyCalculator.cs | 59 ++++++++----------- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- 2 files changed, 24 insertions(+), 37 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index bb666eb528..473c205293 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -27,54 +27,33 @@ namespace osu.Game.Rulesets.Taiko.Difficulty /// private const double decay_weight = 0.9; - /// - /// HitObjects are stored as a member variable. - /// - private readonly List difficultyHitObjects = new List(); - - public TaikoDifficultyCalculator(IBeatmap beatmap) - : base(beatmap) + public TaikoDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) + : base(ruleset, beatmap) { } - public TaikoDifficultyCalculator(IBeatmap beatmap, Mod[] mods) - : base(beatmap, mods) + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) { - } + var difficultyHitObjects = new List(); - public override double Calculate(Dictionary categoryDifficulty = null) - { - // Fill our custom DifficultyHitObject class, that carries additional information - difficultyHitObjects.Clear(); - - foreach (var hitObject in Beatmap.HitObjects) + foreach (var hitObject in beatmap.HitObjects) difficultyHitObjects.Add(new TaikoHitObjectDifficulty((TaikoHitObject)hitObject)); // Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure. difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime)); - if (!calculateStrainValues()) return 0; + if (!calculateStrainValues(difficultyHitObjects, timeRate)) + return new DifficultyAttributes(mods, 0); - double starRating = calculateDifficulty() * star_scaling_factor; + double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor; - if (categoryDifficulty != null) - categoryDifficulty["Strain"] = starRating; - - return starRating; + return new DifficultyAttributes(mods, starRating); } - protected override Mod[] DifficultyAdjustmentMods => new Mod[] - { - new TaikoModDoubleTime(), - new TaikoModHalfTime(), - new TaikoModEasy(), - new TaikoModHardRock(), - }; - - private bool calculateStrainValues() + private bool calculateStrainValues(List objects, double timeRate) { // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. - using (List.Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator()) + using (var hitObjectsEnumerator = objects.GetEnumerator()) { if (!hitObjectsEnumerator.MoveNext()) return false; @@ -84,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty while (hitObjectsEnumerator.MoveNext()) { var next = hitObjectsEnumerator.Current; - next?.CalculateStrains(current, TimeRate); + next?.CalculateStrains(current, timeRate); current = next; } @@ -92,9 +71,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty } } - private double calculateDifficulty() + private double calculateDifficulty(List objects, double timeRate) { - double actualStrainStep = strain_step * TimeRate; + double actualStrainStep = strain_step * timeRate; // Find the highest strain value within each strain step List highestStrains = new List(); @@ -102,7 +81,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval TaikoHitObjectDifficulty previousHitObject = null; - foreach (var hitObject in difficultyHitObjects) + foreach (var hitObject in objects) { // While we are beyond the current interval push the currently available maximum to our strain list while (hitObject.BaseHitObject.StartTime > intervalEndTime) @@ -144,5 +123,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty return difficulty; } + + protected override Mod[] DifficultyAdjustmentMods => new Mod[] + { + new TaikoModDoubleTime(), + new TaikoModHalfTime(), + new TaikoModEasy(), + new TaikoModHardRock(), + }; } } diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 225461fd6f..1b34ab68bd 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Taiko public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o }; - public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new TaikoDifficultyCalculator(beatmap, mods); + public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap); public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new TaikoPerformanceCalculator(this, beatmap, score); From 6ff06d4757f4bb00f94bb7870235b4b18bd9b920 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 15:48:56 +0900 Subject: [PATCH 184/306] Adjust CatchDifficultyCalculator in-line with changes --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- .../Difficulty/CatchDifficultyCalculator.cs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index d0180f1791..fc6e23c884 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Catch public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o }; - public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap); + public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(this, beatmap); public override int? LegacyID => 2; diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index f8351b7519..562374087e 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -1,18 +1,19 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Catch.Difficulty { public class CatchDifficultyCalculator : DifficultyCalculator { - public CatchDifficultyCalculator(IBeatmap beatmap) : base(beatmap) + public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) + : base(ruleset, beatmap) { } - public override double Calculate(Dictionary categoryDifficulty = null) => 0; + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) => new DifficultyAttributes(mods, 0); } } From 966099fabc209b34f2ac2bcc7881b0639eb465f0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 15:54:05 +0900 Subject: [PATCH 185/306] Adjust ManiaDifficultyCalculator in-line with changes --- .../Difficulty/ManiaDifficultyCalculator.cs | 47 +++++++------------ osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- 2 files changed, 18 insertions(+), 31 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index ca2002b7c9..9c091ac31a 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -29,47 +29,33 @@ namespace osu.Game.Rulesets.Mania.Difficulty /// private const double decay_weight = 0.9; - /// - /// HitObjects are stored as a member variable. - /// - private readonly List difficultyHitObjects = new List(); - - public ManiaDifficultyCalculator(IBeatmap beatmap) - : base(beatmap) + public ManiaDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) + : base(ruleset, beatmap) { } - public ManiaDifficultyCalculator(IBeatmap beatmap, Mod[] mods) - : base(beatmap, mods) + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) { - } + var difficultyHitObjects = new List(); - public override double Calculate(Dictionary categoryDifficulty = null) - { - // Fill our custom DifficultyHitObject class, that carries additional information - difficultyHitObjects.Clear(); - - int columnCount = (Beatmap as ManiaBeatmap)?.TotalColumns ?? 7; + int columnCount = ((ManiaBeatmap)beatmap).TotalColumns; // Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure. // Note: Stable sort is done so that the ordering of hitobjects with equal start times doesn't change - difficultyHitObjects.AddRange(Beatmap.HitObjects.Select(h => new ManiaHitObjectDifficulty((ManiaHitObject)h, columnCount)).OrderBy(h => h.BaseHitObject.StartTime)); + difficultyHitObjects.AddRange(beatmap.HitObjects.Select(h => new ManiaHitObjectDifficulty((ManiaHitObject)h, columnCount)).OrderBy(h => h.BaseHitObject.StartTime)); - if (!calculateStrainValues()) - return 0; + if (!calculateStrainValues(difficultyHitObjects, timeRate)) + return new DifficultyAttributes(mods, 0); - double starRating = calculateDifficulty() * star_scaling_factor; + double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor; - if (categoryDifficulty != null) - categoryDifficulty["Strain"] = starRating; - - return starRating; + return new DifficultyAttributes(mods, starRating); } - private bool calculateStrainValues() + private bool calculateStrainValues(List objects, double timeRate) { // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. - using (List.Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator()) + using (var hitObjectsEnumerator = objects.GetEnumerator()) { if (!hitObjectsEnumerator.MoveNext()) return false; @@ -80,7 +66,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty while (hitObjectsEnumerator.MoveNext()) { var next = hitObjectsEnumerator.Current; - next?.CalculateStrains(current, TimeRate); + next?.CalculateStrains(current, timeRate); current = next; } @@ -88,9 +74,9 @@ namespace osu.Game.Rulesets.Mania.Difficulty } } - private double calculateDifficulty() + private double calculateDifficulty(List objects, double timeRate) { - double actualStrainStep = strain_step * TimeRate; + double actualStrainStep = strain_step * timeRate; // Find the highest strain value within each strain step List highestStrains = new List(); @@ -98,7 +84,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval ManiaHitObjectDifficulty previousHitObject = null; - foreach (var hitObject in difficultyHitObjects) + foreach (var hitObject in objects) { // While we are beyond the current interval push the currently available maximum to our strain list while (hitObject.BaseHitObject.StartTime > intervalEndTime) @@ -159,5 +145,6 @@ namespace osu.Game.Rulesets.Mania.Difficulty new ManiaModKey8(), new ManiaModKey9(), }; + } } diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index e671a3fb14..1b7a8f77b3 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -147,7 +147,7 @@ namespace osu.Game.Rulesets.Mania public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o }; - public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap, mods); + public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new ManiaDifficultyCalculator(this, beatmap); public override int? LegacyID => 3; From 540b43313eba0932a1be122c2469d586409b3d1c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 15:57:06 +0900 Subject: [PATCH 186/306] Remove PP test cases (osu-tools/osu-server should be used instead) --- .../TestCasePerformancePoints.cs | 16 - .../TestCasePerformancePoints.cs | 16 - .../TestCasePerformancePoints.cs | 16 - .../TestCasePerformancePoints.cs | 16 - .../Tests/Visual/TestCasePerformancePoints.cs | 403 ------------------ 5 files changed, 467 deletions(-) delete mode 100644 osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs delete mode 100644 osu.Game.Rulesets.Mania.Tests/TestCasePerformancePoints.cs delete mode 100644 osu.Game.Rulesets.Osu.Tests/TestCasePerformancePoints.cs delete mode 100644 osu.Game.Rulesets.Taiko.Tests/TestCasePerformancePoints.cs delete mode 100644 osu.Game/Tests/Visual/TestCasePerformancePoints.cs diff --git a/osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs deleted file mode 100644 index 9512cf2061..0000000000 --- a/osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using NUnit.Framework; - -namespace osu.Game.Rulesets.Catch.Tests -{ - [TestFixture] - public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints - { - public TestCasePerformancePoints() - : base(new CatchRuleset()) - { - } - } -} diff --git a/osu.Game.Rulesets.Mania.Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Mania.Tests/TestCasePerformancePoints.cs deleted file mode 100644 index c15a6dd688..0000000000 --- a/osu.Game.Rulesets.Mania.Tests/TestCasePerformancePoints.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using NUnit.Framework; - -namespace osu.Game.Rulesets.Mania.Tests -{ - [TestFixture] - public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints - { - public TestCasePerformancePoints() - : base(new ManiaRuleset()) - { - } - } -} diff --git a/osu.Game.Rulesets.Osu.Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Osu.Tests/TestCasePerformancePoints.cs deleted file mode 100644 index 63026fe316..0000000000 --- a/osu.Game.Rulesets.Osu.Tests/TestCasePerformancePoints.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using NUnit.Framework; - -namespace osu.Game.Rulesets.Osu.Tests -{ - [TestFixture] - public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints - { - public TestCasePerformancePoints() - : base(new OsuRuleset()) - { - } - } -} diff --git a/osu.Game.Rulesets.Taiko.Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Taiko.Tests/TestCasePerformancePoints.cs deleted file mode 100644 index 2fd9161d13..0000000000 --- a/osu.Game.Rulesets.Taiko.Tests/TestCasePerformancePoints.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using NUnit.Framework; - -namespace osu.Game.Rulesets.Taiko.Tests -{ - [TestFixture] - public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints - { - public TestCasePerformancePoints() - : base(new TaikoRuleset()) - { - } - } -} diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs deleted file mode 100644 index dfae8fbc1d..0000000000 --- a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs +++ /dev/null @@ -1,403 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.Collections.Generic; -using System.Linq; -using OpenTK; -using OpenTK.Graphics; -using osu.Framework.Allocation; -using osu.Framework.Caching; -using osu.Framework.Configuration; -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input; -using osu.Game.Beatmaps; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Scoring; - -namespace osu.Game.Tests.Visual -{ - public abstract class TestCasePerformancePoints : OsuTestCase - { - protected TestCasePerformancePoints(Ruleset ruleset) - { - Child = new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.5f, - }, - new ScrollContainer - { - RelativeSizeAxes = Axes.Both, - Child = new BeatmapList(ruleset, Beatmap) - } - } - }, - null, - new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.5f, - }, - new ScrollContainer - { - RelativeSizeAxes = Axes.Both, - Child = new StarRatingGrid() - } - } - }, - null, - new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.5f, - }, - new ScrollContainer - { - RelativeSizeAxes = Axes.Both, - Child = new PerformanceList() - } - } - }, - } - }, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.Absolute, 20), - new Dimension(), - new Dimension(GridSizeMode.Absolute, 20) - } - }; - } - - private class BeatmapList : CompositeDrawable - { - private readonly Container beatmapDisplays; - private readonly Ruleset ruleset; - private readonly BindableBeatmap beatmapBindable; - - public BeatmapList(Ruleset ruleset, BindableBeatmap beatmapBindable) - { - this.ruleset = ruleset; - this.beatmapBindable = beatmapBindable; - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - InternalChild = beatmapDisplays = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 4) - }; - } - - [BackgroundDependencyLoader] - private void load(BeatmapManager beatmaps) - { - var sets = beatmaps.GetAllUsableBeatmapSets(); - var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID == null || b.RulesetID == ruleset.LegacyID); - - allBeatmaps.ForEach(b => beatmapDisplays.Add(new BeatmapDisplay(b, beatmapBindable))); - } - - private class BeatmapDisplay : CompositeDrawable, IHasTooltip - { - private readonly OsuSpriteText text; - private readonly BeatmapInfo beatmap; - - private readonly BindableBeatmap beatmapBindable; - - private BeatmapManager beatmaps; - - private bool isSelected; - - public string TooltipText => text.Text; - - public BeatmapDisplay(BeatmapInfo beatmap, BindableBeatmap beatmapBindable) - { - this.beatmap = beatmap; - this.beatmapBindable = beatmapBindable; - - AutoSizeAxes = Axes.Both; - InternalChild = text = new OsuSpriteText(); - - this.beatmapBindable.ValueChanged += beatmapChanged; - } - - [BackgroundDependencyLoader] - private void load(BeatmapManager beatmaps) - { - this.beatmaps = beatmaps; - - var working = beatmaps.GetWorkingBeatmap(beatmap); - text.Text = $"{working.Metadata.Artist} - {working.Metadata.Title} ({working.Metadata.AuthorString}) [{working.BeatmapInfo.Version}]"; - } - - private void beatmapChanged(WorkingBeatmap newBeatmap) - { - if (isSelected) - this.FadeColour(Color4.White, 100); - isSelected = false; - } - - protected override bool OnClick(InputState state) - { - if (beatmapBindable.Value.BeatmapInfo.ID == beatmap.ID) - return false; - - beatmapBindable.Value = beatmaps.GetWorkingBeatmap(beatmap); - isSelected = true; - return true; - } - - protected override bool OnHover(InputState state) - { - if (isSelected) - return false; - this.FadeColour(Color4.Yellow, 100); - return true; - } - - protected override void OnHoverLost(InputState state) - { - if (isSelected) - return; - this.FadeColour(Color4.White, 100); - } - } - } - - private class PerformanceList : CompositeDrawable - { - private readonly FillFlowContainer scores; - private APIAccess api; - - private readonly IBindable currentBeatmap = new Bindable(); - - public PerformanceList() - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - InternalChild = scores = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 4) - }; - } - - [BackgroundDependencyLoader] - private void load(IBindableBeatmap beatmap, APIAccess api) - { - this.api = api; - - if (!api.IsLoggedIn) - { - InternalChild = new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "Please sign in to see online scores", - }; - } - - currentBeatmap.ValueChanged += beatmapChanged; - currentBeatmap.BindTo(beatmap); - } - - private GetScoresRequest lastRequest; - private void beatmapChanged(WorkingBeatmap newBeatmap) - { - if (!IsAlive) return; - - lastRequest?.Cancel(); - scores.Clear(); - - if (!api.IsLoggedIn) - return; - - lastRequest = new GetScoresRequest(newBeatmap.BeatmapInfo, newBeatmap.BeatmapInfo.Ruleset); - lastRequest.Success += res => res.Scores.ForEach(s => scores.Add(new PerformanceDisplay(s, newBeatmap.Beatmap))); - api.Queue(lastRequest); - } - - private class PerformanceDisplay : CompositeDrawable - { - private readonly OsuSpriteText text; - - private readonly Score score; - private readonly IBeatmap beatmap; - - public PerformanceDisplay(Score score, IBeatmap beatmap) - { - this.score = score; - this.beatmap = beatmap; - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - InternalChild = text = new OsuSpriteText(); - } - - [BackgroundDependencyLoader] - private void load() - { - var ruleset = beatmap.BeatmapInfo.Ruleset.CreateInstance(); - var calculator = ruleset.CreatePerformanceCalculator(beatmap, score); - if (calculator == null) - return; - - var attributes = new Dictionary(); - double performance = calculator.Calculate(attributes); - - text.Text = $"{score.User.Username} -> online: {score.PP:n2}pp | local: {performance:n2}pp"; - } - } - } - - private class StarRatingGrid : CompositeDrawable - { - private readonly FillFlowContainer modFlow; - private readonly OsuSpriteText totalText; - private readonly FillFlowContainer categoryTexts; - - public StarRatingGrid() - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - InternalChild = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - modFlow = new FillFlowContainer - { - Name = "Checkbox flow", - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(4, 4) - }, - new FillFlowContainer - { - Name = "Information display", - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(0, 4), - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - totalText = new OsuSpriteText { TextSize = 24 }, - categoryTexts = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical - } - } - } - } - }; - } - - [BackgroundDependencyLoader] - private void load(IBindableBeatmap beatmap) - { - beatmap.ValueChanged += beatmapChanged; - } - - private Cached informationCache = new Cached(); - - private Ruleset ruleset; - private WorkingBeatmap beatmap; - - private void beatmapChanged(WorkingBeatmap newBeatmap) - { - beatmap = newBeatmap; - - modFlow.Clear(); - - ruleset = newBeatmap.BeatmapInfo.Ruleset.CreateInstance(); - foreach (var mod in ruleset.GetAllMods()) - { - var checkBox = new OsuCheckbox - { - RelativeSizeAxes = Axes.None, - Width = 50, - LabelText = mod.ShortenedName - }; - - checkBox.Current.ValueChanged += v => informationCache.Invalidate(); - modFlow.Add(checkBox); - } - - informationCache.Invalidate(); - } - - protected override void Update() - { - base.Update(); - - if (ruleset == null) - return; - - if (!informationCache.IsValid) - { - totalText.Text = string.Empty; - categoryTexts.Clear(); - - var allMods = ruleset.GetAllMods().ToList(); - Mod[] activeMods = modFlow.Where(c => c.Current.Value).Select(c => allMods.First(m => m.ShortenedName == c.LabelText)).ToArray(); - - var diffCalc = ruleset.CreateDifficultyCalculator(beatmap.Beatmap, activeMods); - if (diffCalc != null) - { - var categories = new Dictionary(); - double totalSr = diffCalc.Calculate(categories); - - totalText.Text = $"Star rating: {totalSr:n2}"; - foreach (var kvp in categories) - categoryTexts.Add(new OsuSpriteText { Text = $"{kvp.Key}: {kvp.Value:n2}" }); - } - - informationCache.Validate(); - } - } - } - } -} From 8f7334874ca3ff149c6e2cc10f0e0cd667f8c40e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 16:04:48 +0900 Subject: [PATCH 187/306] Fix up performance calculators --- .../Difficulty/ManiaPerformanceCalculator.cs | 4 ++-- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- .../Difficulty/OsuPerformanceCalculator.cs | 8 +++++--- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- .../Difficulty/TaikoPerformanceCalculator.cs | 6 +++--- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- .../DifficultyAdjustmentModCombinationsTest.cs | 8 ++++---- osu.Game/Beatmaps/BeatmapManager.cs | 3 +-- osu.Game/Beatmaps/DummyWorkingBeatmap.cs | 2 +- .../Rulesets/Difficulty/PerformanceCalculator.cs | 12 ++++++------ osu.Game/Rulesets/Ruleset.cs | 2 +- 11 files changed, 26 insertions(+), 25 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs index 93652f7610..b6089b830b 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty private int countMeh; private int countMiss; - public ManiaPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score) + public ManiaPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score) : base(ruleset, beatmap, score) { } @@ -82,7 +82,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty private double computeStrainValue() { // Obtain strain difficulty - double strainValue = Math.Pow(5 * Math.Max(1, Attributes["Strain"] / 0.2) - 4.0, 2.2) / 135.0; + double strainValue = Math.Pow(5 * Math.Max(1, Attributes.StarRating / 0.2) - 4.0, 2.2) / 135.0; // Longer maps are worth more strainValue *= 1.0 + 0.1 * Math.Min(1.0, totalHits / 1500.0); diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 1b7a8f77b3..ac5fbfdde0 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Mania { public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap) => new ManiaRulesetContainer(this, beatmap); public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap); - public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new ManiaPerformanceCalculator(this, beatmap, score); + public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new ManiaPerformanceCalculator(this, beatmap, score); public override IEnumerable ConvertLegacyMods(LegacyMods mods) { diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 57cf962fa7..3ab3cc879a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuPerformanceCalculator : PerformanceCalculator { + public new OsuDifficultyAttributes Attributes => (OsuDifficultyAttributes)base.Attributes; + private readonly int countHitCircles; private readonly int beatmapMaxCombo; @@ -37,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty private int countMeh; private int countMiss; - public OsuPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score) + public OsuPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score) : base(ruleset, beatmap, score) { countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle); @@ -102,7 +104,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty private double computeAimValue() { - double aimValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes["Aim"] / 0.0675f) - 4.0f, 3.0f) / 100000.0f; + double aimValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes.AimStrain / 0.0675f) - 4.0f, 3.0f) / 100000.0f; // Longer maps are worth more double lengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + @@ -151,7 +153,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty private double computeSpeedValue() { - double speedValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes["Speed"] / 0.0675f) - 4.0f, 3.0f) / 100000.0f; + double speedValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes.SpeedStrain / 0.0675f) - 4.0f, 3.0f) / 100000.0f; // Longer maps are worth more speedValue *= 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 49468392f5..ce80537b93 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -122,7 +122,7 @@ namespace osu.Game.Rulesets.Osu public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(this, beatmap); - public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new OsuPerformanceCalculator(this, beatmap, score); + public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new OsuPerformanceCalculator(this, beatmap, score); public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 6b1a25d667..53cfb4fd0f 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -22,10 +22,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private int countMeh; private int countMiss; - public TaikoPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score) + public TaikoPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score) : base(ruleset, beatmap, score) { - beatmapMaxCombo = beatmap.HitObjects.Count(h => h is Hit); + beatmapMaxCombo = Beatmap.HitObjects.Count(h => h is Hit); } public override double Calculate(Dictionary categoryDifficulty = null) @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private double computeStrainValue() { - double strainValue = Math.Pow(5.0 * Math.Max(1.0, Attributes["Strain"] / 0.0075) - 4.0, 2.0) / 100000.0; + double strainValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.StarRating / 0.0075) - 4.0, 2.0) / 100000.0; // Longer maps are worth more double lengthBonus = 1 + 0.1f * Math.Min(1.0, totalHits / 1500.0); diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 1b34ab68bd..7b4978694b 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Taiko public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap); - public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new TaikoPerformanceCalculator(this, beatmap, score); + public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new TaikoPerformanceCalculator(this, beatmap, score); public override int? LegacyID => 1; diff --git a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs index fd697ba3d3..49494b65b9 100644 --- a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs +++ b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs @@ -2,8 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; using NUnit.Framework; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; @@ -139,14 +139,14 @@ namespace osu.Game.Tests.NonVisual private class TestDifficultyCalculator : DifficultyCalculator { public TestDifficultyCalculator(params Mod[] mods) - : base(null) + : base(null, null) { DifficultyAdjustmentMods = mods; } - public override double Calculate(Dictionary categoryDifficulty = null) => throw new NotImplementedException(); - protected override Mod[] DifficultyAdjustmentMods { get; } + + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) => throw new NotImplementedException(); } } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 895b47d62b..5e3b66646b 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -366,8 +366,7 @@ namespace osu.Game.Beatmaps if (ruleset != null) { // TODO: this should be done in a better place once we actually need to dynamically update it. - var converted = new DummyConversionBeatmap(beatmap).GetPlayableBeatmap(ruleset); - beatmap.BeatmapInfo.StarDifficulty = ruleset.CreateInstance().CreateDifficultyCalculator(converted).Calculate(); + beatmap.BeatmapInfo.StarDifficulty = ruleset.CreateInstance().CreateDifficultyCalculator(new DummyConversionBeatmap(beatmap)).Calculate().StarRating; } else beatmap.BeatmapInfo.StarDifficulty = 0; diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index ee1fc6aec3..265c6832b2 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -62,7 +62,7 @@ namespace osu.Game.Beatmaps public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new DummyBeatmapConverter { Beatmap = beatmap }; - public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => null; + public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => null; public override string Description => "dummy"; diff --git a/osu.Game/Rulesets/Difficulty/PerformanceCalculator.cs b/osu.Game/Rulesets/Difficulty/PerformanceCalculator.cs index 07d9c80061..ba783ee87b 100644 --- a/osu.Game/Rulesets/Difficulty/PerformanceCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/PerformanceCalculator.cs @@ -13,8 +13,7 @@ namespace osu.Game.Rulesets.Difficulty { public abstract class PerformanceCalculator { - private readonly Dictionary attributes = new Dictionary(); - protected IDictionary Attributes => attributes; + protected readonly DifficultyAttributes Attributes; protected readonly Ruleset Ruleset; protected readonly IBeatmap Beatmap; @@ -22,14 +21,15 @@ namespace osu.Game.Rulesets.Difficulty protected double TimeRate { get; private set; } = 1; - protected PerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score) + protected PerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score) { Ruleset = ruleset; - Beatmap = beatmap; Score = score; - var diffCalc = ruleset.CreateDifficultyCalculator(beatmap, score.Mods); - diffCalc.Calculate(attributes); + beatmap.Mods.Value = score.Mods; + Beatmap = beatmap.GetPlayableBeatmap(ruleset.RulesetInfo); + + Attributes = ruleset.CreateDifficultyCalculator(beatmap).Calculate(score.Mods); ApplyMods(score.Mods); } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index cdc1c44306..f818523a3d 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap); - public virtual PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => null; + public virtual PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => null; public virtual HitObjectComposer CreateHitObjectComposer() => null; From af218b3d8dd16b6ae9762c122b6fcd757ec44d8f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 16:13:21 +0900 Subject: [PATCH 188/306] No need to use properties --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 5650bc395a..50a259ae55 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -8,8 +8,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuDifficultyAttributes : DifficultyAttributes { - public double AimStrain { get; set; } - public double SpeedStrain { get; set; } + public double AimStrain; + public double SpeedStrain; public OsuDifficultyAttributes(Mod[] mods, double starRating) : base(mods, starRating) From 22add2abc5a443ee63fc711a27af2e7dc60c8313 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 16:25:44 +0900 Subject: [PATCH 189/306] Move mania difficulty attributes to ManiaDifficultyCalculator --- .../Difficulty/ManiaDifficultyAttributes.cs | 18 ++++++++++++++++++ .../Difficulty/ManiaDifficultyCalculator.cs | 7 ++++++- .../Difficulty/ManiaPerformanceCalculator.cs | 8 ++++---- 3 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs new file mode 100644 index 0000000000..c7f6890b93 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs @@ -0,0 +1,18 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Mania.Difficulty +{ + public class ManiaDifficultyAttributes : DifficultyAttributes + { + public double GreatHitWindow; + + public ManiaDifficultyAttributes(Mod[] mods, double starRating) + : base(mods, starRating) + { + } + } +} diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 9c091ac31a..525426df2d 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -47,9 +47,14 @@ namespace osu.Game.Rulesets.Mania.Difficulty if (!calculateStrainValues(difficultyHitObjects, timeRate)) return new DifficultyAttributes(mods, 0); + double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor; - return new DifficultyAttributes(mods, starRating); + return new ManiaDifficultyAttributes(mods, starRating) + { + // Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future + GreatHitWindow = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate + }; } private bool calculateStrainValues(List objects, double timeRate) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs index b6089b830b..1f26bda1b2 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs @@ -13,6 +13,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty { public class ManiaPerformanceCalculator : PerformanceCalculator { + protected new ManiaDifficultyAttributes Attributes => (ManiaDifficultyAttributes)base.Attributes; + private Mod[] mods; // Score after being scaled by non-difficulty-increasing mods @@ -105,14 +107,12 @@ namespace osu.Game.Rulesets.Mania.Difficulty private double computeAccuracyValue(double strainValue) { - // Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future - double hitWindowGreat = (int)(Beatmap.HitObjects.First().HitWindows.Great / 2) / TimeRate; - if (hitWindowGreat <= 0) + if (Attributes.GreatHitWindow <= 0) return 0; // Lots of arbitrary values from testing. // Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution - double accuracyValue = Math.Max(0.0, 0.2 - (hitWindowGreat - 34) * 0.006667) + double accuracyValue = Math.Max(0.0, 0.2 - (Attributes.GreatHitWindow - 34) * 0.006667) * strainValue * Math.Pow(Math.Max(0.0, scaledScore - 960000) / 40000, 1.1); From 01dd2d79198202216c439f5827cf436957bbf1a7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 16:26:51 +0900 Subject: [PATCH 190/306] Move taiko difficulty attributes to TaikoDifficultyCalculator --- .../Difficulty/TaikoDifficultyAttributes.cs | 19 +++++++++++++++++++ .../Difficulty/TaikoDifficultyCalculator.cs | 8 +++++++- .../Difficulty/TaikoPerformanceCalculator.cs | 14 +++++--------- 3 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs new file mode 100644 index 0000000000..d18d03b1db --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Taiko.Difficulty +{ + public class TaikoDifficultyAttributes : DifficultyAttributes + { + public double GreatHitWindow; + public int MaxCombo; + + public TaikoDifficultyAttributes(Mod[] mods, double starRating) + : base(mods, starRating) + { + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 473c205293..190717e024 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; @@ -47,7 +48,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor; - return new DifficultyAttributes(mods, starRating); + return new TaikoDifficultyAttributes(mods, starRating) + { + // Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future + GreatHitWindow = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate, + MaxCombo = beatmap.HitObjects.Count(h => h is Hit) + }; } private bool calculateStrainValues(List objects, double timeRate) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 53cfb4fd0f..f530b6725c 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -8,13 +8,12 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty { public class TaikoPerformanceCalculator : PerformanceCalculator { - private readonly int beatmapMaxCombo; + protected new TaikoDifficultyAttributes Attributes => (TaikoDifficultyAttributes)base.Attributes; private Mod[] mods; private int countGreat; @@ -25,7 +24,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty public TaikoPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score) : base(ruleset, beatmap, score) { - beatmapMaxCombo = Beatmap.HitObjects.Count(h => h is Hit); } public override double Calculate(Dictionary categoryDifficulty = null) @@ -78,8 +76,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty strainValue *= Math.Pow(0.985, countMiss); // Combo scaling - if (beatmapMaxCombo > 0) - strainValue *= Math.Min(Math.Pow(Score.MaxCombo, 0.5) / Math.Pow(beatmapMaxCombo, 0.5), 1.0); + if (Attributes.MaxCombo > 0) + strainValue *= Math.Min(Math.Pow(Score.MaxCombo, 0.5) / Math.Pow(Attributes.MaxCombo, 0.5), 1.0); if (mods.Any(m => m is ModHidden)) strainValue *= 1.025; @@ -94,14 +92,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private double computeAccuracyValue() { - // Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future - double hitWindowGreat = (int)(Beatmap.HitObjects.First().HitWindows.Great / 2) / TimeRate; - if (hitWindowGreat <= 0) + if (Attributes.GreatHitWindow <= 0) return 0; // Lots of arbitrary values from testing. // Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution - double accValue = Math.Pow(150.0 / hitWindowGreat, 1.1) * Math.Pow(Score.Accuracy, 15) * 22.0; + double accValue = Math.Pow(150.0 / Attributes.GreatHitWindow, 1.1) * Math.Pow(Score.Accuracy, 15) * 22.0; // Bonus for many hitcircles - it's harder to keep good accuracy up for longer return accValue * Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); From 41abd5990cc9adcf6e3865b7149fcf9b7f1747a9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 16:27:05 +0900 Subject: [PATCH 191/306] Move osu! difficulty attributes to OsuDifficultyCalculator --- .../Difficulty/OsuDifficultyAttributes.cs | 3 ++ .../Difficulty/OsuDifficultyCalculator.cs | 13 ++++++- .../Difficulty/OsuPerformanceCalculator.cs | 39 ++++++------------- 3 files changed, 26 insertions(+), 29 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 50a259ae55..2b42eed0c5 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -10,6 +10,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public double AimStrain; public double SpeedStrain; + public double ApproachRate; + public double OverallDifficulty; + public int MaxCombo; public OsuDifficultyAttributes(Mod[] mods, double starRating) : base(mods, starRating) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 400afbc043..4386004e30 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -58,10 +58,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; + // Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future + double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate; + double preEmpt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate; + + int maxCombo = beatmap.HitObjects.Count(); + // Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above) + maxCombo += beatmap.HitObjects.OfType().Sum(s => s.NestedHitObjects.Count - 1); + return new OsuDifficultyAttributes(mods, starRating) { AimStrain = aimRating, - SpeedStrain = speedRating + SpeedStrain = speedRating, + ApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5, + OverallDifficulty = (80 - hitWindowGreat) / 6, + MaxCombo = maxCombo }; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 3ab3cc879a..d4a60dd52f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -22,16 +22,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty private Mod[] mods; - /// - /// Approach rate adjusted by mods. - /// - private double realApproachRate; - - /// - /// Overall difficulty adjusted by mods. - /// - private double realOverallDifficulty; - private double accuracy; private int scoreMaxCombo; private int countGreat; @@ -63,13 +53,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(m => !m.Ranked)) return 0; - // Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future - double hitWindowGreat = (int)(Beatmap.HitObjects.First().HitWindows.Great / 2) / TimeRate; - double preEmpt = (int)BeatmapDifficulty.DifficultyRange(Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / TimeRate; - - realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5; - realOverallDifficulty = (80 - hitWindowGreat) / 6; - // Custom multipliers for NoFail and SpunOut. double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things @@ -94,8 +77,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty categoryRatings.Add("Aim", aimValue); categoryRatings.Add("Speed", speedValue); categoryRatings.Add("Accuracy", accuracyValue); - categoryRatings.Add("OD", realOverallDifficulty); - categoryRatings.Add("AR", realApproachRate); + categoryRatings.Add("OD", Attributes.OverallDifficulty); + categoryRatings.Add("AR", Attributes.ApproachRate); categoryRatings.Add("Max Combo", beatmapMaxCombo); } @@ -120,22 +103,22 @@ namespace osu.Game.Rulesets.Osu.Difficulty aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f); double approachRateFactor = 1.0f; - if (realApproachRate > 10.33f) - approachRateFactor += 0.45f * (realApproachRate - 10.33f); - else if (realApproachRate < 8.0f) + if (Attributes.ApproachRate > 10.33f) + approachRateFactor += 0.45f * (Attributes.ApproachRate - 10.33f); + else if (Attributes.ApproachRate < 8.0f) { // HD is worth more with lower ar! if (mods.Any(h => h is OsuModHidden)) - approachRateFactor += 0.02f * (8.0f - realApproachRate); + approachRateFactor += 0.02f * (8.0f - Attributes.ApproachRate); else - approachRateFactor += 0.01f * (8.0f - realApproachRate); + approachRateFactor += 0.01f * (8.0f - Attributes.ApproachRate); } aimValue *= approachRateFactor; // We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR. if (mods.Any(h => h is OsuModHidden)) - aimValue *= 1.02 + (11.0f - realApproachRate) / 50.0; // Gives a 1.04 bonus for AR10, a 1.06 bonus for AR9, a 1.02 bonus for AR11. + aimValue *= 1.02 + (11.0f - Attributes.ApproachRate) / 50.0; // Gives a 1.04 bonus for AR10, a 1.06 bonus for AR9, a 1.02 bonus for AR11. if (mods.Any(h => h is OsuModFlashlight)) { @@ -146,7 +129,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty // Scale the aim value with accuracy _slightly_ aimValue *= 0.5f + accuracy / 2.0f; // It is important to also consider accuracy difficulty when doing that - aimValue *= 0.98f + Math.Pow(realOverallDifficulty, 2) / 2500; + aimValue *= 0.98f + Math.Pow(Attributes.OverallDifficulty, 2) / 2500; return aimValue; } @@ -172,7 +155,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty // Scale the speed value with accuracy _slightly_ speedValue *= 0.5f + accuracy / 2.0f; // It is important to also consider accuracy difficulty when doing that - speedValue *= 0.98f + Math.Pow(realOverallDifficulty, 2) / 2500; + speedValue *= 0.98f + Math.Pow(Attributes.OverallDifficulty, 2) / 2500; return speedValue; } @@ -194,7 +177,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty // Lots of arbitrary values from testing. // Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution - double accuracyValue = Math.Pow(1.52163f, realOverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f; + double accuracyValue = Math.Pow(1.52163f, Attributes.OverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f; // Bonus for many hitcircles - it's harder to keep good accuracy up for longer accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f)); From c41a50bf24635c94c719eefcde8272d4147eda4e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 14 Jun 2018 16:39:31 +0900 Subject: [PATCH 192/306] Fix combos ending with JuiceStreams never leaving the catcher's plate Closes #2634. --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index ae799875a9..b2d8e3f8a5 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -124,6 +124,9 @@ namespace osu.Game.Rulesets.Catch.Objects X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH }); } + + if (NestedHitObjects.LastOrDefault() is IHasComboInformation lastNested) + lastNested.LastInCombo = LastInCombo; } public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity; From 08b9cf75e964fd3665d3aa67ccb8e4ceff5b7e6b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 17:04:31 +0900 Subject: [PATCH 193/306] Don't compute keymod difficulties for mania-specific beatmaps These don't affect the number of keys in the beatmap at all for mania-specific beatmaps. --- .../Difficulty/ManiaDifficultyCalculator.cs | 49 +++++++++++++------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 9c091ac31a..520b9c1152 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -29,9 +29,12 @@ namespace osu.Game.Rulesets.Mania.Difficulty /// private const double decay_weight = 0.9; + private readonly bool isForCurrentRuleset; + public ManiaDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { + isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(new ManiaRuleset().RulesetInfo); } protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) @@ -129,22 +132,38 @@ namespace osu.Game.Rulesets.Mania.Difficulty return difficulty; } - protected override Mod[] DifficultyAdjustmentMods => new Mod[] + protected override Mod[] DifficultyAdjustmentMods { - new ManiaModDoubleTime(), - new ManiaModHalfTime(), - new ManiaModEasy(), - new ManiaModHardRock(), - new ManiaModKey1(), - new ManiaModKey2(), - new ManiaModKey3(), - new ManiaModKey4(), - new ManiaModKey5(), - new ManiaModKey6(), - new ManiaModKey7(), - new ManiaModKey8(), - new ManiaModKey9(), - }; + get + { + if (isForCurrentRuleset) + { + return new Mod[] + { + new ManiaModDoubleTime(), + new ManiaModHalfTime(), + new ManiaModEasy(), + new ManiaModHardRock(), + }; + } + return new Mod[] + { + new ManiaModDoubleTime(), + new ManiaModHalfTime(), + new ManiaModEasy(), + new ManiaModHardRock(), + new ManiaModKey1(), + new ManiaModKey2(), + new ManiaModKey3(), + new ManiaModKey4(), + new ManiaModKey5(), + new ManiaModKey6(), + new ManiaModKey7(), + new ManiaModKey8(), + new ManiaModKey9(), + }; + } + } } } From b25a6a33ccdde95af2a05739661b211cf0d7a3fd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 19:37:21 +0900 Subject: [PATCH 194/306] Fix 1K breaking hitcircle / slider conversions --- .../Patterns/Legacy/DistanceObjectPatternGenerator.cs | 7 +++++++ .../Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index afa9bdbbd7..f60958d581 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -58,6 +58,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy public override Pattern Generate() { + if (TotalColumns == 1) + { + var pattern = new Pattern(); + addToPattern(pattern, 0, HitObject.StartTime, endTime); + return pattern; + } + if (spanCount > 1) { if (segmentDuration <= 90) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index cec3e18ad6..c72005e3ad 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -81,6 +81,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy public override Pattern Generate() { + if (TotalColumns == 1) + { + var pattern = new Pattern(); + addToPattern(pattern, 0); + return pattern; + } + int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0; if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Any()) From a3bf16e481bc5489ba809ef97e6326c565b0fc97 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 19:37:32 +0900 Subject: [PATCH 195/306] Fix missing convert type --- .../Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index c72005e3ad..339a1b4e77 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -77,6 +77,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy } else convertType |= PatternType.LowProbability; + + if ((convertType & PatternType.KeepSingle) == 0) + { + if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && TotalColumns != 8) + convertType |= PatternType.Mirror; + else + convertType |= PatternType.Gathered; + } } public override Pattern Generate() From fd84afb89bfa052f9a13139721d74b8932fe1c0e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 19:38:48 +0900 Subject: [PATCH 196/306] Fix non-inverted calculation --- .../Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index 339a1b4e77..b4160dc98b 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -361,7 +361,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy addToCentre = false; if ((convertType & PatternType.ForceNotStack) > 0) - return getRandomNoteCount(p2 / 2, p2, (p2 + p3) / 2, p3); + return getRandomNoteCount(1 / 2f + p2 / 2, p2, (p2 + p3) / 2, p3); switch (TotalColumns) { From 5e66b021085c1214da2c350ebe96688c5aabf0f2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 18:38:27 +0900 Subject: [PATCH 197/306] Process beatmap before generating mappings --- .../Tests/Beatmaps/BeatmapConversionTest.cs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index 7470f6ebed..c5f74af770 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -84,19 +84,26 @@ namespace osu.Game.Tests.Beatmaps beatmap.BeatmapInfo.Ruleset = beatmap.BeatmapInfo.RulesetID == rulesetInstance.RulesetInfo.ID ? rulesetInstance.RulesetInfo : new RulesetInfo(); var result = new ConvertResult(); - var converter = rulesetInstance.CreateBeatmapConverter(beatmap); + + List>> conversions = new List>>(); + converter.ObjectConverted += (orig, converted) => { + conversions.Add(new KeyValuePair>(orig, converted)); converted.ForEach(h => h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty)); - - var mapping = new ConvertMapping { StartTime = orig.StartTime }; - foreach (var obj in converted) - mapping.Objects.AddRange(CreateConvertValue(obj)); - result.Mappings.Add(mapping); }; - converter.Convert(); + IBeatmap convertedBeatmap = converter.Convert(); + rulesetInstance.CreateBeatmapProcessor(convertedBeatmap).PostProcess(); + + foreach (var pair in conversions) + { + var mapping = new ConvertMapping { StartTime = pair.Key.StartTime }; + foreach (var obj in pair.Value) + mapping.Objects.AddRange(CreateConvertValue(obj)); + result.Mappings.Add(mapping); + } return result; } From 8d0e7abdd62c977ffc53d408430faf967604ced3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 21:17:27 +0900 Subject: [PATCH 198/306] Some rulesets don't have a beatmap processor --- osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index c5f74af770..4b0da3a14b 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Beatmaps var result = new ConvertResult(); var converter = rulesetInstance.CreateBeatmapConverter(beatmap); - List>> conversions = new List>>(); + var conversions = new List>>(); converter.ObjectConverted += (orig, converted) => { @@ -95,7 +95,7 @@ namespace osu.Game.Tests.Beatmaps }; IBeatmap convertedBeatmap = converter.Convert(); - rulesetInstance.CreateBeatmapProcessor(convertedBeatmap).PostProcess(); + rulesetInstance.CreateBeatmapProcessor(convertedBeatmap)?.PostProcess(); foreach (var pair in conversions) { From 024d2abfe09ea3c1200a587ebcef17311d738238 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 20:26:55 +0900 Subject: [PATCH 199/306] Always generate mappings/convert values as soon as objects are converted # Conflicts: # osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs --- osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index 4b0da3a14b..424ebe0cf3 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -86,25 +86,19 @@ namespace osu.Game.Tests.Beatmaps var result = new ConvertResult(); var converter = rulesetInstance.CreateBeatmapConverter(beatmap); - var conversions = new List>>(); - converter.ObjectConverted += (orig, converted) => { - conversions.Add(new KeyValuePair>(orig, converted)); converted.ForEach(h => h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty)); + + var mapping = new ConvertMapping { StartTime = orig.StartTime }; + foreach (var obj in converted) + mapping.Objects.AddRange(CreateConvertValue(obj)); + result.Mappings.Add(mapping); }; IBeatmap convertedBeatmap = converter.Convert(); rulesetInstance.CreateBeatmapProcessor(convertedBeatmap)?.PostProcess(); - foreach (var pair in conversions) - { - var mapping = new ConvertMapping { StartTime = pair.Key.StartTime }; - foreach (var obj in pair.Value) - mapping.Objects.AddRange(CreateConvertValue(obj)); - result.Mappings.Add(mapping); - } - return result; } From b99b520656dc8ae9cda7fc5ef1da13801e2ae858 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 20:28:29 +0900 Subject: [PATCH 200/306] Allow convertmapping to be extended --- .../Tests/Beatmaps/BeatmapConversionTest.cs | 68 +++++++++++++++---- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index 424ebe0cf3..9f15949f7b 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -16,7 +16,8 @@ using osu.Game.Rulesets.Objects; namespace osu.Game.Tests.Beatmaps { [TestFixture] - public abstract class BeatmapConversionTest + public abstract class BeatmapConversionTest + where TConvertMapping : ConvertMapping, IEquatable, new() where TConvertValue : IEquatable { private const string resource_namespace = "Testing.Beatmaps"; @@ -59,9 +60,13 @@ namespace osu.Game.Tests.Beatmaps else if (objectCounter >= expectedMapping.Objects.Count) Assert.Fail($"The conversion generated a hitobject, but should not have, for hitobject at time: {ourMapping.StartTime}:\n" + $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n"); - else if (!EqualityComparer.Default.Equals(expectedMapping.Objects[objectCounter], ourMapping.Objects[objectCounter])) + else if (!expectedMapping.Equals(ourMapping)) + Assert.Fail($"The conversion mapping differed for object at time {expectedMapping.StartTime}:\n" + + $"Expected {JsonConvert.SerializeObject(expectedMapping)}\n" + + $"Received: {JsonConvert.SerializeObject(ourMapping)}"); + else if (!expectedMapping.Objects[objectCounter].Equals(ourMapping.Objects[objectCounter])) { - Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}\n" + Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}:\n" + $"Expected: {JsonConvert.SerializeObject(expectedMapping.Objects[objectCounter])}\n" + $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n"); } @@ -90,7 +95,9 @@ namespace osu.Game.Tests.Beatmaps { converted.ForEach(h => h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty)); - var mapping = new ConvertMapping { StartTime = orig.StartTime }; + var mapping = CreateConvertMapping(); + mapping.StartTime = orig.StartTime; + foreach (var obj in converted) mapping.Objects.AddRange(CreateConvertValue(obj)); result.Mappings.Add(mapping); @@ -129,21 +136,54 @@ namespace osu.Game.Tests.Beatmaps return Assembly.LoadFrom(Path.Combine(localPath, $"{ResourceAssembly}.dll")).GetManifestResourceStream($@"{ResourceAssembly}.Resources.{name}"); } - protected abstract IEnumerable CreateConvertValue(HitObject hitObject); - protected abstract Ruleset CreateRuleset(); + /// + /// Creates the conversion mapping for a . A conversion mapping stores important information about the conversion process. + /// This is generated _after_ the has been converted. + /// + /// This should be used to validate the integrity of the conversion process after a conversion has occurred. + /// + /// + protected virtual TConvertMapping CreateConvertMapping() => new TConvertMapping(); - private class ConvertMapping - { - [JsonProperty] - public double StartTime; - [JsonProperty] - public List Objects = new List(); - } + /// + /// Creates the conversion value for a . A conversion value stores information about the converted . + /// + /// This should be used to validate the integrity of the converted . + /// + /// + /// The converted . + protected abstract IEnumerable CreateConvertValue(HitObject hitObject); + + /// + /// Creates the applicable to this . + /// + /// + protected abstract Ruleset CreateRuleset(); private class ConvertResult { [JsonProperty] - public List Mappings = new List(); + public List Mappings = new List(); } } + + public abstract class BeatmapConversionTest : BeatmapConversionTest, TConvertValue> + where TConvertValue : IEquatable + { + } + + public class ConvertMapping : IEquatable> + where TConvertValue : IEquatable + { + [JsonProperty] + public double StartTime; + + [JsonIgnore] + public List Objects = new List(); + + [JsonProperty("Objects")] + private List setObjects { set => Objects = value; } + + public virtual bool Equals(ConvertMapping other) => StartTime.Equals(other?.StartTime); + } } From a4d236408378ea34fd93af06e6c77d775072c59e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 21:29:08 +0900 Subject: [PATCH 201/306] Add one more newline --- osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index 9f15949f7b..cf4dda52a8 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Beatmaps else if (!expectedMapping.Equals(ourMapping)) Assert.Fail($"The conversion mapping differed for object at time {expectedMapping.StartTime}:\n" + $"Expected {JsonConvert.SerializeObject(expectedMapping)}\n" - + $"Received: {JsonConvert.SerializeObject(ourMapping)}"); + + $"Received: {JsonConvert.SerializeObject(ourMapping)}\n"); else if (!expectedMapping.Objects[objectCounter].Equals(ourMapping.Objects[objectCounter])) { Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}:\n" From cafdbc2d251626dd3dc624c9a7044db3e9828f5a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 18:39:26 +0900 Subject: [PATCH 202/306] Fix discarding too many RNG values, and add test --- .../CatchBeatmapConversionTest.cs | 12 +++ .../Beatmaps/CatchBeatmapProcessor.cs | 6 +- .../Beatmaps/spinner-expected-conversion.json | 74 +++++++++++++++++++ .../Resources/Testing/Beatmaps/spinner.osu | 20 +++++ 4 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-expected-conversion.json create mode 100644 osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner.osu diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs index 5b34e46247..9de0ce3565 100644 --- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs @@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Catch.Tests protected override string ResourceAssembly => "osu.Game.Rulesets.Catch"; [TestCase("basic"), Ignore("See: https://github.com/ppy/osu/issues/2232")] + [TestCase("spinner")] public new void Test(string name) { base.Test(name); @@ -35,6 +36,17 @@ namespace osu.Game.Rulesets.Catch.Tests }; } } + else if (hitObject is BananaShower shower) + { + foreach (var nested in shower.NestedHitObjects) + { + yield return new ConvertValue + { + StartTime = nested.StartTime, + Position = ((CatchHitObject)nested).X * CatchPlayfield.BASE_WIDTH + }; + } + } else { yield return new ConvertValue diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 869bc560a8..a9fbc8bcb2 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -48,10 +48,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps foreach (var nested in bananaShower.NestedHitObjects) { ((BananaShower.Banana)nested).X = (float)rng.NextDouble(); - // discarding 3 times - rng.Next(); - rng.Next(); - rng.Next(); + rng.Next(); // osu!stable retrieved a random banana type + rng.Next(); // osu!stable retrieved a random banana rotation } break; case JuiceStream juiceStream: diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-expected-conversion.json b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-expected-conversion.json new file mode 100644 index 0000000000..933adb4acc --- /dev/null +++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-expected-conversion.json @@ -0,0 +1,74 @@ +{ + "Mappings": [{ + "StartTime": 18500, + "Objects": [{ + "StartTime": 18500, + "Position": 65 + }, + { + "StartTime": 18559, + "Position": 459 + }, + { + "StartTime": 18618, + "Position": 255 + }, + { + "StartTime": 18678, + "Position": 113 + }, + { + "StartTime": 18737, + "Position": 315 + }, + { + "StartTime": 18796, + "Position": 17 + }, + { + "StartTime": 18856, + "Position": 482 + }, + { + "StartTime": 18915, + "Position": 44 + }, + { + "StartTime": 18975, + "Position": 310 + }, + { + "StartTime": 19034, + "Position": 244 + }, + { + "StartTime": 19093, + "Position": 18 + }, + { + "StartTime": 19153, + "Position": 482 + }, + { + "StartTime": 19212, + "Position": 243 + }, + { + "StartTime": 19271, + "Position": 332 + }, + { + "StartTime": 19331, + "Position": 477 + }, + { + "StartTime": 19390, + "Position": 376 + }, + { + "StartTime": 19450, + "Position": 104 + } + ] + }] +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner.osu b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner.osu new file mode 100644 index 0000000000..0fbd4dbf42 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner.osu @@ -0,0 +1,20 @@ +osu file format v14 + +[General] +Mode: 2 + +[Difficulty] +HPDrainRate:6 +CircleSize:4 +OverallDifficulty:7 +ApproachRate:8.3 +SliderMultiplier:1.6 +SliderTickRate:1 + +[TimingPoints] +500,500,4,2,1,50,1,0 +13426,-100,4,3,1,45,0,0 +14884,-100,4,2,1,50,0,0 + +[HitObjects] +256,192,18500,12,0,19450,0:0:0:0: From a97a7e13bd492a87b3ab7695307ff66bd87f0cf7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 19:52:04 +0900 Subject: [PATCH 203/306] Rework RNG discarding comment --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index a9fbc8bcb2..a146617182 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -56,13 +56,9 @@ namespace osu.Game.Rulesets.Catch.Beatmaps foreach (var nested in juiceStream.NestedHitObjects) { if (nested is TinyDroplet tinyDroplet) - { tinyDroplet.X += rng.Next(-20, 20) / CatchPlayfield.BASE_WIDTH; - } else if (nested is Droplet) - { - rng.Next(); // Big droplets are not slided - } + rng.Next(); // osu!stable retrieved a random droplet rotation } break; } From 9b403b0053519266bfb0dfb74313adcf42ff090b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 19:56:00 +0900 Subject: [PATCH 204/306] Fix non-catch beatmaps not getting properly converted Because Osu.ConvertSpinner implements IHasXPosition. --- .../Beatmaps/CatchBeatmapConverter.cs | 46 ++++++++----------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs index ad500606ed..46fe8454dc 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs @@ -27,22 +27,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps var comboData = obj as IHasCombo; var endTime = obj as IHasEndTime; - if (positionData == null) - { - if (endTime != null) - { - yield return new BananaShower - { - StartTime = obj.StartTime, - Samples = obj.Samples, - Duration = endTime.Duration, - NewCombo = comboData?.NewCombo ?? false - }; - } - - yield break; - } - if (curveData != null) { yield return new JuiceStream @@ -54,20 +38,30 @@ namespace osu.Game.Rulesets.Catch.Beatmaps Distance = curveData.Distance, RepeatSamples = curveData.RepeatSamples, RepeatCount = curveData.RepeatCount, - X = positionData.X / CatchPlayfield.BASE_WIDTH, + X = (positionData?.X ?? 0) / CatchPlayfield.BASE_WIDTH, NewCombo = comboData?.NewCombo ?? false }; - - yield break; } - - yield return new Fruit + else if (endTime != null) { - StartTime = obj.StartTime, - Samples = obj.Samples, - NewCombo = comboData?.NewCombo ?? false, - X = positionData.X / CatchPlayfield.BASE_WIDTH - }; + yield return new BananaShower + { + StartTime = obj.StartTime, + Samples = obj.Samples, + Duration = endTime.Duration, + NewCombo = comboData?.NewCombo ?? false + }; + } + else + { + yield return new Fruit + { + StartTime = obj.StartTime, + Samples = obj.Samples, + NewCombo = comboData?.NewCombo ?? false, + X = (positionData?.X ?? 0) / CatchPlayfield.BASE_WIDTH + }; + } } protected override Beatmap CreateBeatmap() => new CatchBeatmap(); From 250e8645e19ecb4f4cdbde14643cfcf25ea7e1ba Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 20:11:27 +0900 Subject: [PATCH 205/306] finalisePosition -> applyPositionOffsets --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index a146617182..1ac1643297 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps public override void PostProcess() { - finalizePosition(); + applyPositionOffsets(); initialiseHyperDash((List)Beatmap.HitObjects); @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps public const int RNG_SEED = 1337; - private void finalizePosition() + private void applyPositionOffsets() { var rng = new FastRandom(RNG_SEED); // todo: HardRock displacement should be applied here From e1f549892475d27b11121dfcb9c96cf3e9c7c414 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 21:10:54 +0900 Subject: [PATCH 206/306] Discarding 3 times is correct --- .../Beatmaps/CatchBeatmapProcessor.cs | 1 + .../Beatmaps/spinner-expected-conversion.json | 62 +++++++++---------- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 1ac1643297..2768357034 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -50,6 +50,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps ((BananaShower.Banana)nested).X = (float)rng.NextDouble(); rng.Next(); // osu!stable retrieved a random banana type rng.Next(); // osu!stable retrieved a random banana rotation + rng.Next(); // osu!stable retrieved a random banana colour } break; case JuiceStream juiceStream: diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-expected-conversion.json b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-expected-conversion.json index 933adb4acc..b69b1ae056 100644 --- a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-expected-conversion.json +++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-expected-conversion.json @@ -7,67 +7,67 @@ }, { "StartTime": 18559, - "Position": 459 + "Position": 482 }, { "StartTime": 18618, - "Position": 255 + "Position": 164 }, { "StartTime": 18678, - "Position": 113 - }, - { - "StartTime": 18737, "Position": 315 }, + { + "StartTime": 18737, + "Position": 145 + }, { "StartTime": 18796, - "Position": 17 + "Position": 159 }, { "StartTime": 18856, - "Position": 482 - }, - { - "StartTime": 18915, - "Position": 44 - }, - { - "StartTime": 18975, "Position": 310 }, + { + "StartTime": 18915, + "Position": 441 + }, + { + "StartTime": 18975, + "Position": 428 + }, { "StartTime": 19034, - "Position": 244 - }, - { - "StartTime": 19093, - "Position": 18 - }, - { - "StartTime": 19153, - "Position": 482 - }, - { - "StartTime": 19212, "Position": 243 }, + { + "StartTime": 19093, + "Position": 422 + }, + { + "StartTime": 19153, + "Position": 481 + }, + { + "StartTime": 19212, + "Position": 104 + }, { "StartTime": 19271, - "Position": 332 + "Position": 473 }, { "StartTime": 19331, - "Position": 477 + "Position": 135 }, { "StartTime": 19390, - "Position": 376 + "Position": 360 }, { "StartTime": 19450, - "Position": 104 + "Position": 123 } ] }] From ced4e61b54a320e2307cc60e395035b574747c8b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 21:11:56 +0900 Subject: [PATCH 207/306] Adjust expected output with spinner changes --- .../Beatmaps/basic-expected-conversion.json | 2226 ++++++++++------- 1 file changed, 1272 insertions(+), 954 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic-expected-conversion.json b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic-expected-conversion.json index 9357d3b75c..8ede7b6719 100644 --- a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic-expected-conversion.json +++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic-expected-conversion.json @@ -1,957 +1,1275 @@ { "Mappings": [{ - "StartTime": 500.0, - "Objects": [{ - "StartTime": 500.0, - "Position": 96.0 - }, { - "StartTime": 562.0, - "Position": 100.84 - }, { - "StartTime": 625.0, - "Position": 125.0 - }, { - "StartTime": 687.0, - "Position": 152.84 - }, { - "StartTime": 750.0, - "Position": 191.0 - }, { - "StartTime": 812.0, - "Position": 212.84 - }, { - "StartTime": 875.0, - "Position": 217.0 - }, { - "StartTime": 937.0, - "Position": 234.84 - }, { - "StartTime": 1000.0, - "Position": 256.0 - }, { - "StartTime": 1062.0, - "Position": 267.84 - }, { - "StartTime": 1125.0, - "Position": 284.0 - }, { - "StartTime": 1187.0, - "Position": 311.84 - }, { - "StartTime": 1250.0, - "Position": 350.0 - }, { - "StartTime": 1312.0, - "Position": 359.84 - }, { - "StartTime": 1375.0, - "Position": 367.0 - }, { - "StartTime": 1437.0, - "Position": 400.84 - }, { - "StartTime": 1500.0, - "Position": 416.0 - }, { - "StartTime": 1562.0, - "Position": 377.159973 - }, { - "StartTime": 1625.0, - "Position": 367.0 - }, { - "StartTime": 1687.0, - "Position": 374.159973 - }, { - "StartTime": 1750.0, - "Position": 353.0 - }, { - "StartTime": 1812.0, - "Position": 329.159973 - }, { - "StartTime": 1875.0, - "Position": 288.0 - }, { - "StartTime": 1937.0, - "Position": 259.159973 - }, { - "StartTime": 2000.0, - "Position": 256.0 - }, { - "StartTime": 2058.0, - "Position": 232.44 - }, { - "StartTime": 2116.0, - "Position": 222.879974 - }, { - "StartTime": 2174.0, - "Position": 185.319992 - }, { - "StartTime": 2232.0, - "Position": 177.76001 - }, { - "StartTime": 2290.0, - "Position": 162.200012 - }, { - "StartTime": 2348.0, - "Position": 158.639984 - }, { - "StartTime": 2406.0, - "Position": 111.079994 - }, { - "StartTime": 2500.0, - "Position": 96.0 - }] - }, { - "StartTime": 3000.0, - "Objects": [{ - "StartTime": 3000.0, - "Position": 18.0 - }, { - "StartTime": 3062.0, - "Position": 482.0 - }, { - "StartTime": 3125.0, - "Position": 243.0 - }, { - "StartTime": 3187.0, - "Position": 332.0 - }, { - "StartTime": 3250.0, - "Position": 477.0 - }, { - "StartTime": 3312.0, - "Position": 376.0 - }, { - "StartTime": 3375.0, - "Position": 104.0 - }, { - "StartTime": 3437.0, - "Position": 156.0 - }, { - "StartTime": 3500.0, - "Position": 135.0 - }, { - "StartTime": 3562.0, - "Position": 256.0 - }, { - "StartTime": 3625.0, - "Position": 360.0 - }, { - "StartTime": 3687.0, - "Position": 199.0 - }, { - "StartTime": 3750.0, - "Position": 239.0 - }, { - "StartTime": 3812.0, - "Position": 326.0 - }, { - "StartTime": 3875.0, - "Position": 393.0 - }, { - "StartTime": 3937.0, - "Position": 470.0 - }, { - "StartTime": 4000.0, - "Position": 136.0 - }] - }, { - "StartTime": 4500.0, - "Objects": [{ - "StartTime": 4500.0, - "Position": 317.0 - }, { - "StartTime": 4562.0, - "Position": 354.0 - }, { - "StartTime": 4625.0, - "Position": 414.0 - }, { - "StartTime": 4687.0, - "Position": 39.0 - }, { - "StartTime": 4750.0, - "Position": 172.0 - }, { - "StartTime": 4812.0, - "Position": 479.0 - }, { - "StartTime": 4875.0, - "Position": 18.0 - }, { - "StartTime": 4937.0, - "Position": 151.0 - }, { - "StartTime": 5000.0, - "Position": 342.0 - }, { - "StartTime": 5062.0, - "Position": 400.0 - }, { - "StartTime": 5125.0, - "Position": 420.0 - }, { - "StartTime": 5187.0, - "Position": 90.0 - }, { - "StartTime": 5250.0, - "Position": 220.0 - }, { - "StartTime": 5312.0, - "Position": 80.0 - }, { - "StartTime": 5375.0, - "Position": 421.0 - }, { - "StartTime": 5437.0, - "Position": 473.0 - }, { - "StartTime": 5500.0, - "Position": 97.0 - }] - }, { - "StartTime": 6000.0, - "Objects": [{ - "StartTime": 6000.0, - "Position": 105.0 - }, { - "StartTime": 6062.0, - "Position": 249.0 - }, { - "StartTime": 6125.0, - "Position": 163.0 - }, { - "StartTime": 6187.0, - "Position": 194.0 - }, { - "StartTime": 6250.0, - "Position": 106.0 - }, { - "StartTime": 6312.0, - "Position": 212.0 - }, { - "StartTime": 6375.0, - "Position": 257.0 - }, { - "StartTime": 6437.0, - "Position": 461.0 - }, { - "StartTime": 6500.0, - "Position": 79.0 - }] - }, { - "StartTime": 7000.0, - "Objects": [{ - "StartTime": 7000.0, - "Position": 256.0 - }, { - "StartTime": 7062.0, - "Position": 294.84 - }, { - "StartTime": 7125.0, - "Position": 279.0 - }, { - "StartTime": 7187.0, - "Position": 309.84 - }, { - "StartTime": 7250.0, - "Position": 336.0 - }, { - "StartTime": 7312.0, - "Position": 322.16 - }, { - "StartTime": 7375.0, - "Position": 308.0 - }, { - "StartTime": 7437.0, - "Position": 263.16 - }, { - "StartTime": 7500.0, - "Position": 256.0 - }, { - "StartTime": 7562.0, - "Position": 261.84 - }, { - "StartTime": 7625.0, - "Position": 277.0 - }, { - "StartTime": 7687.0, - "Position": 318.84 - }, { - "StartTime": 7750.0, - "Position": 336.0 - }, { - "StartTime": 7803.0, - "Position": 305.04 - }, { - "StartTime": 7857.0, - "Position": 307.76 - }, { - "StartTime": 7910.0, - "Position": 297.8 - }, { - "StartTime": 8000.0, - "Position": 256.0 - }] - }, { - "StartTime": 8500.0, - "Objects": [{ - "StartTime": 8500.0, - "Position": 32.0 - }, { - "StartTime": 8562.0, - "Position": 22.8515015 - }, { - "StartTime": 8625.0, - "Position": 28.5659637 - }, { - "StartTime": 8687.0, - "Position": 50.3433228 - }, { - "StartTime": 8750.0, - "Position": 56.58974 - }, { - "StartTime": 8812.0, - "Position": 64.23422 - }, { - "StartTime": 8875.0, - "Position": 67.7117844 - }, { - "StartTime": 8937.0, - "Position": 90.52607 - }, { - "StartTime": 9000.0, - "Position": 101.81015 - }, { - "StartTime": 9062.0, - "Position": 113.478188 - }, { - "StartTime": 9125.0, - "Position": 159.414444 - }, { - "StartTime": 9187.0, - "Position": 155.1861 - }, { - "StartTime": 9250.0, - "Position": 179.600418 - }, { - "StartTime": 9312.0, - "Position": 212.293015 - }, { - "StartTime": 9375.0, - "Position": 197.2076 - }, { - "StartTime": 9437.0, - "Position": 243.438324 - }, { - "StartTime": 9500.0, - "Position": 237.2304 - }, { - "StartTime": 9562.0, - "Position": 241.253983 - }, { - "StartTime": 9625.0, - "Position": 258.950623 - }, { - "StartTime": 9687.0, - "Position": 253.3786 - }, { - "StartTime": 9750.0, - "Position": 270.8865 - }, { - "StartTime": 9812.0, - "Position": 244.38974 - }, { - "StartTime": 9875.0, - "Position": 242.701874 - }, { - "StartTime": 9937.0, - "Position": 256.2331 - }, { - "StartTime": 10000.0, - "Position": 270.339874 - }, { - "StartTime": 10062.0, - "Position": 275.9349 - }, { - "StartTime": 10125.0, - "Position": 297.2969 - }, { - "StartTime": 10187.0, - "Position": 307.834137 - }, { - "StartTime": 10250.0, - "Position": 321.6449 - }, { - "StartTime": 10312.0, - "Position": 357.746338 - }, { - "StartTime": 10375.0, - "Position": 358.21875 - }, { - "StartTime": 10437.0, - "Position": 394.943 - }, { - "StartTime": 10500.0, - "Position": 401.0588 - }, { - "StartTime": 10558.0, - "Position": 418.21347 - }, { - "StartTime": 10616.0, - "Position": 424.6034 - }, { - "StartTime": 10674.0, - "Position": 455.835754 - }, { - "StartTime": 10732.0, - "Position": 477.5042 - }, { - "StartTime": 10790.0, - "Position": 476.290955 - }, { - "StartTime": 10848.0, - "Position": 470.943237 - }, { - "StartTime": 10906.0, - "Position": 503.3372 - }, { - "StartTime": 10999.0, - "Position": 508.166229 - }] - }, { - "StartTime": 11500.0, - "Objects": [{ - "StartTime": 11500.0, - "Position": 321.0 - }, { - "StartTime": 11562.0, - "Position": 17.0 - }, { - "StartTime": 11625.0, - "Position": 173.0 - }, { - "StartTime": 11687.0, - "Position": 170.0 - }, { - "StartTime": 11750.0, - "Position": 447.0 - }, { - "StartTime": 11812.0, - "Position": 218.0 - }, { - "StartTime": 11875.0, - "Position": 394.0 - }, { - "StartTime": 11937.0, - "Position": 46.0 - }, { - "StartTime": 12000.0, - "Position": 480.0 - }] - }, { - "StartTime": 12500.0, - "Objects": [{ - "StartTime": 12500.0, - "Position": 512.0 - }, { - "StartTime": 12562.0, - "Position": 491.3132 - }, { - "StartTime": 12625.0, - "Position": 484.3089 - }, { - "StartTime": 12687.0, - "Position": 454.6221 - }, { - "StartTime": 12750.0, - "Position": 433.617767 - }, { - "StartTime": 12812.0, - "Position": 399.930969 - }, { - "StartTime": 12875.0, - "Position": 395.926666 - }, { - "StartTime": 12937.0, - "Position": 361.239868 - }, { - "StartTime": 13000.0, - "Position": 353.235535 - }, { - "StartTime": 13062.0, - "Position": 314.548767 - }, { - "StartTime": 13125.0, - "Position": 315.544434 - }, { - "StartTime": 13187.0, - "Position": 288.857635 - }, { - "StartTime": 13250.0, - "Position": 254.853333 - }, { - "StartTime": 13312.0, - "Position": 239.166534 - }, { - "StartTime": 13375.0, - "Position": 240.1622 - }, { - "StartTime": 13437.0, - "Position": 212.4754 - }, { - "StartTime": 13500.0, - "Position": 194.471069 - }, { - "StartTime": 13562.0, - "Position": 161.784271 - }, { - "StartTime": 13625.0, - "Position": 145.779968 - }, { - "StartTime": 13687.0, - "Position": 129.09314 - }, { - "StartTime": 13750.0, - "Position": 104.088837 - }, { - "StartTime": 13812.0, - "Position": 95.40204 - }, { - "StartTime": 13875.0, - "Position": 61.3977356 - }, { - "StartTime": 13937.0, - "Position": 56.710907 - }, { - "StartTime": 14000.0, - "Position": 35.7066345 - }, { - "StartTime": 14062.0, - "Position": 5.019806 - }, { - "StartTime": 14125.0, - "Position": 0.0 - }, { - "StartTime": 14187.0, - "Position": 39.7696266 - }, { - "StartTime": 14250.0, - "Position": 23.0119171 - }, { - "StartTime": 14312.0, - "Position": 75.94882 - }, { - "StartTime": 14375.0, - "Position": 98.19112 - }, { - "StartTime": 14437.0, - "Position": 82.12803 - }, { - "StartTime": 14500.0, - "Position": 118.370323 - }, { - "StartTime": 14562.0, - "Position": 149.307236 - }, { - "StartTime": 14625.0, - "Position": 168.549515 - }, { - "StartTime": 14687.0, - "Position": 190.486435 - }, { - "StartTime": 14750.0, - "Position": 186.728714 - }, { - "StartTime": 14812.0, - "Position": 199.665634 - }, { - "StartTime": 14875.0, - "Position": 228.907928 - }, { - "StartTime": 14937.0, - "Position": 264.844849 - }, { - "StartTime": 15000.0, - "Position": 271.087128 - }, { - "StartTime": 15062.0, - "Position": 290.024017 - }, { - "StartTime": 15125.0, - "Position": 302.266327 - }, { - "StartTime": 15187.0, - "Position": 344.203247 - }, { - "StartTime": 15250.0, - "Position": 356.445526 - }, { - "StartTime": 15312.0, - "Position": 359.382446 - }, { - "StartTime": 15375.0, - "Position": 401.624725 - }, { - "StartTime": 15437.0, - "Position": 388.561646 - }, { - "StartTime": 15500.0, - "Position": 423.803925 - }, { - "StartTime": 15562.0, - "Position": 425.740845 - }, { - "StartTime": 15625.0, - "Position": 449.983124 - }, { - "StartTime": 15687.0, - "Position": 468.920044 - }, { - "StartTime": 15750.0, - "Position": 492.162323 - }, { - "StartTime": 15812.0, - "Position": 506.784332 - }, { - "StartTime": 15875.0, - "Position": 474.226227 - }, { - "StartTime": 15937.0, - "Position": 482.978638 - }, { - "StartTime": 16000.0, - "Position": 446.420532 - }, { - "StartTime": 16058.0, - "Position": 418.4146 - }, { - "StartTime": 16116.0, - "Position": 425.408844 - }, { - "StartTime": 16174.0, - "Position": 383.402924 - }, { - "StartTime": 16232.0, - "Position": 363.397156 - }, { - "StartTime": 16290.0, - "Position": 343.391235 - }, { - "StartTime": 16348.0, - "Position": 328.385468 - }, { - "StartTime": 16406.0, - "Position": 322.3797 - }, { - "StartTime": 16500.0, - "Position": 291.1977 - }] - }, { - "StartTime": 17000.0, - "Objects": [{ - "StartTime": 17000.0, - "Position": 256.0 - }, { - "StartTime": 17062.0, - "Position": 228.16 - }, { - "StartTime": 17125.0, - "Position": 234.0 - }, { - "StartTime": 17187.0, - "Position": 202.16 - }, { - "StartTime": 17250.0, - "Position": 176.0 - }, { - "StartTime": 17312.0, - "Position": 210.84 - }, { - "StartTime": 17375.0, - "Position": 221.0 - }, { - "StartTime": 17437.0, - "Position": 219.84 - }, { - "StartTime": 17500.0, - "Position": 256.0 - }, { - "StartTime": 17562.0, - "Position": 219.16 - }, { - "StartTime": 17625.0, - "Position": 228.0 - }, { - "StartTime": 17687.0, - "Position": 203.16 - }, { - "StartTime": 17750.0, - "Position": 176.0 - }, { - "StartTime": 17803.0, - "Position": 174.959991 - }, { - "StartTime": 17857.0, - "Position": 214.23999 - }, { - "StartTime": 17910.0, - "Position": 228.200012 - }, { - "StartTime": 18000.0, - "Position": 256.0 - }] - }, { - "StartTime": 18500.0, - "Objects": [{ - "StartTime": 18500.0, - "Position": 362.0 - }, { - "StartTime": 18559.0, - "Position": 249.0 - }, { - "StartTime": 18618.0, - "Position": 357.0 - }, { - "StartTime": 18678.0, - "Position": 167.0 - }, { - "StartTime": 18737.0, - "Position": 477.0 - }, { - "StartTime": 18796.0, - "Position": 411.0 - }, { - "StartTime": 18856.0, - "Position": 254.0 - }, { - "StartTime": 18915.0, - "Position": 308.0 - }, { - "StartTime": 18975.0, - "Position": 399.0 - }, { - "StartTime": 19034.0, - "Position": 176.0 - }, { - "StartTime": 19093.0, - "Position": 14.0 - }, { - "StartTime": 19153.0, - "Position": 258.0 - }, { - "StartTime": 19212.0, - "Position": 221.0 - }, { - "StartTime": 19271.0, - "Position": 481.0 - }, { - "StartTime": 19331.0, - "Position": 92.0 - }, { - "StartTime": 19390.0, - "Position": 211.0 - }, { - "StartTime": 19450.0, - "Position": 135.0 - }] - }, { - "StartTime": 19875.0, - "Objects": [{ - "StartTime": 19875.0, - "Position": 216.0 - }, { - "StartTime": 19937.0, - "Position": 215.307053 - }, { - "StartTime": 20000.0, - "Position": 236.036865 - }, { - "StartTime": 20062.0, - "Position": 236.312088 - }, { - "StartTime": 20125.0, - "Position": 235.838928 - }, { - "StartTime": 20187.0, - "Position": 269.9743 - }, { - "StartTime": 20250.0, - "Position": 285.999146 - }, { - "StartTime": 20312.0, - "Position": 283.669067 - }, { - "StartTime": 20375.0, - "Position": 317.446747 - }, { - "StartTime": 20437.0, - "Position": 330.750275 - }, { - "StartTime": 20500.0, - "Position": 344.0156 - }, { - "StartTime": 20562.0, - "Position": 318.472168 - }, { - "StartTime": 20625.0, - "Position": 309.165466 - }, { - "StartTime": 20687.0, - "Position": 317.044617 - }, { - "StartTime": 20750.0, - "Position": 280.457367 - }, { - "StartTime": 20812.0, - "Position": 272.220581 - }, { - "StartTime": 20875.0, - "Position": 270.3294 - }, { - "StartTime": 20937.0, - "Position": 262.57605 - }, { - "StartTime": 21000.0, - "Position": 244.803329 - }, { - "StartTime": 21062.0, - "Position": 215.958359 - }, { - "StartTime": 21125.0, - "Position": 177.79332 - }, { - "StartTime": 21187.0, - "Position": 190.948349 - }, { - "StartTime": 21250.0, - "Position": 158.78334 - }, { - "StartTime": 21312.0, - "Position": 136.93837 - }, { - "StartTime": 21375.0, - "Position": 119.121056 - }, { - "StartTime": 21437.0, - "Position": 132.387573 - }, { - "StartTime": 21500.0, - "Position": 124.503014 - }, { - "StartTime": 21562.0, - "Position": 118.749374 - }, { - "StartTime": 21625.0, - "Position": 123.165535 - }, { - "StartTime": 21687.0, - "Position": 96.02999 - }, { - "StartTime": 21750.0, - "Position": 118.547928 - }, { - "StartTime": 21812.0, - "Position": 128.856232 - }, { - "StartTime": 21875.0, - "Position": 124.28746 - }, { - "StartTime": 21937.0, - "Position": 150.754929 - }, { - "StartTime": 22000.0, - "Position": 149.528732 - }, { - "StartTime": 22062.0, - "Position": 145.1691 - }, { - "StartTime": 22125.0, - "Position": 182.802155 - }, { - "StartTime": 22187.0, - "Position": 178.6452 - }, { - "StartTime": 22250.0, - "Position": 213.892181 - }, { - "StartTime": 22312.0, - "Position": 218.713028 - }, { - "StartTime": 22375.0, - "Position": 240.4715 - }, { - "StartTime": 22437.0, - "Position": 239.371887 - }, { - "StartTime": 22500.0, - "Position": 261.907257 - }, { - "StartTime": 22562.0, - "Position": 314.353119 - }, { - "StartTime": 22625.0, - "Position": 299.273376 - }, { - "StartTime": 22687.0, - "Position": 356.98288 - }, { - "StartTime": 22750.0, - "Position": 339.078552 - }, { - "StartTime": 22812.0, - "Position": 377.8958 - }, { - "StartTime": 22875.0, - "Position": 398.054047 - }, { - "StartTime": 22937.0, - "Position": 398.739441 - }, { - "StartTime": 23000.0, - "Position": 407.178467 - }, { - "StartTime": 23062.0, - "Position": 444.8687 - }, { - "StartTime": 23125.0, - "Position": 417.069977 - }, { - "StartTime": 23187.0, - "Position": 454.688477 - }, { - "StartTime": 23250.0, - "Position": 428.9612 - }, { - "StartTime": 23312.0, - "Position": 441.92807 - }, { - "StartTime": 23375.0, - "Position": 439.749878 - }, { - "StartTime": 23433.0, - "Position": 455.644684 - }, { - "StartTime": 23491.0, - "Position": 440.7359 - }, { - "StartTime": 23549.0, - "Position": 430.0944 - }, { - "StartTime": 23607.0, - "Position": 420.796173 - }, { - "StartTime": 23665.0, - "Position": 435.897461 - }, { - "StartTime": 23723.0, - "Position": 418.462555 - }, { - "StartTime": 23781.0, - "Position": 405.53775 - }, { - "StartTime": 23874.0, - "Position": 408.720825 - }] - }] + "StartTime": 500, + "Objects": [{ + "StartTime": 500, + "Position": 96 + }, + { + "StartTime": 562, + "Position": 100.84 + }, + { + "StartTime": 625, + "Position": 125 + }, + { + "StartTime": 687, + "Position": 152.84 + }, + { + "StartTime": 750, + "Position": 191 + }, + { + "StartTime": 812, + "Position": 212.84 + }, + { + "StartTime": 875, + "Position": 217 + }, + { + "StartTime": 937, + "Position": 234.84 + }, + { + "StartTime": 1000, + "Position": 256 + }, + { + "StartTime": 1062, + "Position": 267.84 + }, + { + "StartTime": 1125, + "Position": 284 + }, + { + "StartTime": 1187, + "Position": 311.84 + }, + { + "StartTime": 1250, + "Position": 350 + }, + { + "StartTime": 1312, + "Position": 359.84 + }, + { + "StartTime": 1375, + "Position": 367 + }, + { + "StartTime": 1437, + "Position": 400.84 + }, + { + "StartTime": 1500, + "Position": 416 + }, + { + "StartTime": 1562, + "Position": 377.159973 + }, + { + "StartTime": 1625, + "Position": 367 + }, + { + "StartTime": 1687, + "Position": 374.159973 + }, + { + "StartTime": 1750, + "Position": 353 + }, + { + "StartTime": 1812, + "Position": 329.159973 + }, + { + "StartTime": 1875, + "Position": 288 + }, + { + "StartTime": 1937, + "Position": 259.159973 + }, + { + "StartTime": 2000, + "Position": 256 + }, + { + "StartTime": 2062, + "Position": 231.159988 + }, + { + "StartTime": 2125, + "Position": 220 + }, + { + "StartTime": 2187, + "Position": 181.159988 + }, + { + "StartTime": 2250, + "Position": 172 + }, + { + "StartTime": 2312, + "Position": 155.159988 + }, + { + "StartTime": 2375, + "Position": 150 + }, + { + "StartTime": 2437, + "Position": 101.159988 + }, + { + "StartTime": 2500, + "Position": 96 + } + ] + }, + { + "StartTime": 3000, + "Objects": [{ + "StartTime": 3000, + "Position": 18 + }, + { + "StartTime": 3062, + "Position": 249 + }, + { + "StartTime": 3125, + "Position": 184 + }, + { + "StartTime": 3187, + "Position": 477 + }, + { + "StartTime": 3250, + "Position": 43 + }, + { + "StartTime": 3312, + "Position": 494 + }, + { + "StartTime": 3375, + "Position": 135 + }, + { + "StartTime": 3437, + "Position": 30 + }, + { + "StartTime": 3500, + "Position": 11 + }, + { + "StartTime": 3562, + "Position": 239 + }, + { + "StartTime": 3625, + "Position": 505 + }, + { + "StartTime": 3687, + "Position": 353 + }, + { + "StartTime": 3750, + "Position": 136 + }, + { + "StartTime": 3812, + "Position": 135 + }, + { + "StartTime": 3875, + "Position": 346 + }, + { + "StartTime": 3937, + "Position": 39 + }, + { + "StartTime": 4000, + "Position": 300 + } + ] + }, + { + "StartTime": 4500, + "Objects": [{ + "StartTime": 4500, + "Position": 398 + }, + { + "StartTime": 4562, + "Position": 151 + }, + { + "StartTime": 4625, + "Position": 73 + }, + { + "StartTime": 4687, + "Position": 311 + }, + { + "StartTime": 4750, + "Position": 90 + }, + { + "StartTime": 4812, + "Position": 264 + }, + { + "StartTime": 4875, + "Position": 477 + }, + { + "StartTime": 4937, + "Position": 473 + }, + { + "StartTime": 5000, + "Position": 120 + }, + { + "StartTime": 5062, + "Position": 115 + }, + { + "StartTime": 5125, + "Position": 163 + }, + { + "StartTime": 5187, + "Position": 447 + }, + { + "StartTime": 5250, + "Position": 72 + }, + { + "StartTime": 5312, + "Position": 257 + }, + { + "StartTime": 5375, + "Position": 153 + }, + { + "StartTime": 5437, + "Position": 388 + }, + { + "StartTime": 5500, + "Position": 336 + } + ] + }, + { + "StartTime": 6000, + "Objects": [{ + "StartTime": 6000, + "Position": 13 + }, + { + "StartTime": 6062, + "Position": 429 + }, + { + "StartTime": 6125, + "Position": 381 + }, + { + "StartTime": 6187, + "Position": 186 + }, + { + "StartTime": 6250, + "Position": 267 + }, + { + "StartTime": 6312, + "Position": 305 + }, + { + "StartTime": 6375, + "Position": 456 + }, + { + "StartTime": 6437, + "Position": 26 + }, + { + "StartTime": 6500, + "Position": 238 + } + ] + }, + { + "StartTime": 7000, + "Objects": [{ + "StartTime": 7000, + "Position": 256 + }, + { + "StartTime": 7062, + "Position": 262.84 + }, + { + "StartTime": 7125, + "Position": 295 + }, + { + "StartTime": 7187, + "Position": 303.84 + }, + { + "StartTime": 7250, + "Position": 336 + }, + { + "StartTime": 7312, + "Position": 319.16 + }, + { + "StartTime": 7375, + "Position": 306 + }, + { + "StartTime": 7437, + "Position": 272.16 + }, + { + "StartTime": 7500, + "Position": 256 + }, + { + "StartTime": 7562, + "Position": 255.84 + }, + { + "StartTime": 7625, + "Position": 300 + }, + { + "StartTime": 7687, + "Position": 320.84 + }, + { + "StartTime": 7750, + "Position": 336 + }, + { + "StartTime": 7812, + "Position": 316.16 + }, + { + "StartTime": 7875, + "Position": 278 + }, + { + "StartTime": 7937, + "Position": 257.16 + }, + { + "StartTime": 8000, + "Position": 256 + } + ] + }, + { + "StartTime": 8500, + "Objects": [{ + "StartTime": 8500, + "Position": 32 + }, + { + "StartTime": 8562, + "Position": 21.8515015 + }, + { + "StartTime": 8625, + "Position": 44.5659637 + }, + { + "StartTime": 8687, + "Position": 33.3433228 + }, + { + "StartTime": 8750, + "Position": 63.58974 + }, + { + "StartTime": 8812, + "Position": 71.23422 + }, + { + "StartTime": 8875, + "Position": 62.7117844 + }, + { + "StartTime": 8937, + "Position": 65.52607 + }, + { + "StartTime": 9000, + "Position": 101.81015 + }, + { + "StartTime": 9062, + "Position": 134.47818 + }, + { + "StartTime": 9125, + "Position": 141.414444 + }, + { + "StartTime": 9187, + "Position": 164.1861 + }, + { + "StartTime": 9250, + "Position": 176.600418 + }, + { + "StartTime": 9312, + "Position": 184.293015 + }, + { + "StartTime": 9375, + "Position": 212.2076 + }, + { + "StartTime": 9437, + "Position": 236.438324 + }, + { + "StartTime": 9500, + "Position": 237.2304 + }, + { + "StartTime": 9562, + "Position": 241.253983 + }, + { + "StartTime": 9625, + "Position": 233.950623 + }, + { + "StartTime": 9687, + "Position": 265.3786 + }, + { + "StartTime": 9750, + "Position": 236.8865 + }, + { + "StartTime": 9812, + "Position": 273.38974 + }, + { + "StartTime": 9875, + "Position": 267.701874 + }, + { + "StartTime": 9937, + "Position": 263.2331 + }, + { + "StartTime": 10000, + "Position": 270.339874 + }, + { + "StartTime": 10062, + "Position": 291.9349 + }, + { + "StartTime": 10125, + "Position": 294.2969 + }, + { + "StartTime": 10187, + "Position": 307.834137 + }, + { + "StartTime": 10250, + "Position": 310.6449 + }, + { + "StartTime": 10312, + "Position": 344.746338 + }, + { + "StartTime": 10375, + "Position": 349.21875 + }, + { + "StartTime": 10437, + "Position": 373.943 + }, + { + "StartTime": 10500, + "Position": 401.0588 + }, + { + "StartTime": 10562, + "Position": 422.44046 + }, + { + "StartTime": 10625, + "Position": 434.209717 + }, + { + "StartTime": 10687, + "Position": 437.275177 + }, + { + "StartTime": 10750, + "Position": 456.6923 + }, + { + "StartTime": 10812, + "Position": 490.584229 + }, + { + "StartTime": 10875, + "Position": 493.13208 + }, + { + "StartTime": 10937, + "Position": 496.8966 + }, + { + "StartTime": 10999, + "Position": 508.166229 + } + ] + }, + { + "StartTime": 11500, + "Objects": [{ + "StartTime": 11500, + "Position": 97 + }, + { + "StartTime": 11562, + "Position": 267 + }, + { + "StartTime": 11625, + "Position": 116 + }, + { + "StartTime": 11687, + "Position": 451 + }, + { + "StartTime": 11750, + "Position": 414 + }, + { + "StartTime": 11812, + "Position": 88 + }, + { + "StartTime": 11875, + "Position": 257 + }, + { + "StartTime": 11937, + "Position": 175 + }, + { + "StartTime": 12000, + "Position": 38 + } + ] + }, + { + "StartTime": 12500, + "Objects": [{ + "StartTime": 12500, + "Position": 512 + }, + { + "StartTime": 12562, + "Position": 494.3132 + }, + { + "StartTime": 12625, + "Position": 461.3089 + }, + { + "StartTime": 12687, + "Position": 469.6221 + }, + { + "StartTime": 12750, + "Position": 441.617767 + }, + { + "StartTime": 12812, + "Position": 402.930969 + }, + { + "StartTime": 12875, + "Position": 407.926666 + }, + { + "StartTime": 12937, + "Position": 364.239868 + }, + { + "StartTime": 13000, + "Position": 353.235535 + }, + { + "StartTime": 13062, + "Position": 320.548767 + }, + { + "StartTime": 13125, + "Position": 303.544434 + }, + { + "StartTime": 13187, + "Position": 295.857635 + }, + { + "StartTime": 13250, + "Position": 265.853333 + }, + { + "StartTime": 13312, + "Position": 272.166534 + }, + { + "StartTime": 13375, + "Position": 240.1622 + }, + { + "StartTime": 13437, + "Position": 229.4754 + }, + { + "StartTime": 13500, + "Position": 194.471069 + }, + { + "StartTime": 13562, + "Position": 158.784271 + }, + { + "StartTime": 13625, + "Position": 137.779968 + }, + { + "StartTime": 13687, + "Position": 147.09314 + }, + { + "StartTime": 13750, + "Position": 122.088837 + }, + { + "StartTime": 13812, + "Position": 77.40204 + }, + { + "StartTime": 13875, + "Position": 79.3977356 + }, + { + "StartTime": 13937, + "Position": 56.710907 + }, + { + "StartTime": 14000, + "Position": 35.7066345 + }, + { + "StartTime": 14062, + "Position": 1.01980591 + }, + { + "StartTime": 14125, + "Position": 0 + }, + { + "StartTime": 14187, + "Position": 21.7696266 + }, + { + "StartTime": 14250, + "Position": 49.0119171 + }, + { + "StartTime": 14312, + "Position": 48.9488258 + }, + { + "StartTime": 14375, + "Position": 87.19112 + }, + { + "StartTime": 14437, + "Position": 97.12803 + }, + { + "StartTime": 14500, + "Position": 118.370323 + }, + { + "StartTime": 14562, + "Position": 130.307236 + }, + { + "StartTime": 14625, + "Position": 154.549515 + }, + { + "StartTime": 14687, + "Position": 190.486435 + }, + { + "StartTime": 14750, + "Position": 211.728714 + }, + { + "StartTime": 14812, + "Position": 197.665634 + }, + { + "StartTime": 14875, + "Position": 214.907928 + }, + { + "StartTime": 14937, + "Position": 263.844849 + }, + { + "StartTime": 15000, + "Position": 271.087128 + }, + { + "StartTime": 15062, + "Position": 270.024017 + }, + { + "StartTime": 15125, + "Position": 308.266327 + }, + { + "StartTime": 15187, + "Position": 313.203247 + }, + { + "StartTime": 15250, + "Position": 328.445526 + }, + { + "StartTime": 15312, + "Position": 370.382446 + }, + { + "StartTime": 15375, + "Position": 387.624725 + }, + { + "StartTime": 15437, + "Position": 421.561646 + }, + { + "StartTime": 15500, + "Position": 423.803925 + }, + { + "StartTime": 15562, + "Position": 444.740845 + }, + { + "StartTime": 15625, + "Position": 469.983124 + }, + { + "StartTime": 15687, + "Position": 473.920044 + }, + { + "StartTime": 15750, + "Position": 501.162323 + }, + { + "StartTime": 15812, + "Position": 488.784332 + }, + { + "StartTime": 15875, + "Position": 466.226227 + }, + { + "StartTime": 15937, + "Position": 445.978638 + }, + { + "StartTime": 16000, + "Position": 446.420532 + }, + { + "StartTime": 16062, + "Position": 427.1729 + }, + { + "StartTime": 16125, + "Position": 417.6148 + }, + { + "StartTime": 16187, + "Position": 370.367218 + }, + { + "StartTime": 16250, + "Position": 365.8091 + }, + { + "StartTime": 16312, + "Position": 343.561523 + }, + { + "StartTime": 16375, + "Position": 332.003418 + }, + { + "StartTime": 16437, + "Position": 327.755829 + }, + { + "StartTime": 16500, + "Position": 291.1977 + } + ] + }, + { + "StartTime": 17000, + "Objects": [{ + "StartTime": 17000, + "Position": 256 + }, + { + "StartTime": 17062, + "Position": 247.16 + }, + { + "StartTime": 17125, + "Position": 211 + }, + { + "StartTime": 17187, + "Position": 183.16 + }, + { + "StartTime": 17250, + "Position": 176 + }, + { + "StartTime": 17312, + "Position": 204.84 + }, + { + "StartTime": 17375, + "Position": 218 + }, + { + "StartTime": 17437, + "Position": 231.84 + }, + { + "StartTime": 17500, + "Position": 256 + }, + { + "StartTime": 17562, + "Position": 229.16 + }, + { + "StartTime": 17625, + "Position": 227 + }, + { + "StartTime": 17687, + "Position": 186.16 + }, + { + "StartTime": 17750, + "Position": 176 + }, + { + "StartTime": 17812, + "Position": 214.84 + }, + { + "StartTime": 17875, + "Position": 203 + }, + { + "StartTime": 17937, + "Position": 233.84 + }, + { + "StartTime": 18000, + "Position": 256 + } + ] + }, + { + "StartTime": 18500, + "Objects": [{ + "StartTime": 18500, + "Position": 437 + }, + { + "StartTime": 18559, + "Position": 289 + }, + { + "StartTime": 18618, + "Position": 464 + }, + { + "StartTime": 18678, + "Position": 36 + }, + { + "StartTime": 18737, + "Position": 378 + }, + { + "StartTime": 18796, + "Position": 297 + }, + { + "StartTime": 18856, + "Position": 418 + }, + { + "StartTime": 18915, + "Position": 329 + }, + { + "StartTime": 18975, + "Position": 338 + }, + { + "StartTime": 19034, + "Position": 394 + }, + { + "StartTime": 19093, + "Position": 40 + }, + { + "StartTime": 19153, + "Position": 13 + }, + { + "StartTime": 19212, + "Position": 80 + }, + { + "StartTime": 19271, + "Position": 138 + }, + { + "StartTime": 19331, + "Position": 311 + }, + { + "StartTime": 19390, + "Position": 216 + }, + { + "StartTime": 19450, + "Position": 310 + } + ] + }, + { + "StartTime": 19875, + "Objects": [{ + "StartTime": 19875, + "Position": 216 + }, + { + "StartTime": 19937, + "Position": 228.307053 + }, + { + "StartTime": 20000, + "Position": 214.036865 + }, + { + "StartTime": 20062, + "Position": 224.312088 + }, + { + "StartTime": 20125, + "Position": 253.838928 + }, + { + "StartTime": 20187, + "Position": 259.9743 + }, + { + "StartTime": 20250, + "Position": 299.999146 + }, + { + "StartTime": 20312, + "Position": 289.669067 + }, + { + "StartTime": 20375, + "Position": 317.446747 + }, + { + "StartTime": 20437, + "Position": 344.750275 + }, + { + "StartTime": 20500, + "Position": 328.0156 + }, + { + "StartTime": 20562, + "Position": 331.472168 + }, + { + "StartTime": 20625, + "Position": 302.165466 + }, + { + "StartTime": 20687, + "Position": 303.044617 + }, + { + "StartTime": 20750, + "Position": 306.457367 + }, + { + "StartTime": 20812, + "Position": 265.220581 + }, + { + "StartTime": 20875, + "Position": 270.3294 + }, + { + "StartTime": 20937, + "Position": 257.57605 + }, + { + "StartTime": 21000, + "Position": 247.803329 + }, + { + "StartTime": 21062, + "Position": 225.958359 + }, + { + "StartTime": 21125, + "Position": 201.79332 + }, + { + "StartTime": 21187, + "Position": 170.948349 + }, + { + "StartTime": 21250, + "Position": 146.78334 + }, + { + "StartTime": 21312, + "Position": 149.93837 + }, + { + "StartTime": 21375, + "Position": 119.121056 + }, + { + "StartTime": 21437, + "Position": 133.387573 + }, + { + "StartTime": 21500, + "Position": 117.503014 + }, + { + "StartTime": 21562, + "Position": 103.749374 + }, + { + "StartTime": 21625, + "Position": 127.165535 + }, + { + "StartTime": 21687, + "Position": 113.029991 + }, + { + "StartTime": 21750, + "Position": 101.547928 + }, + { + "StartTime": 21812, + "Position": 133.856232 + }, + { + "StartTime": 21875, + "Position": 124.28746 + }, + { + "StartTime": 21937, + "Position": 121.754929 + }, + { + "StartTime": 22000, + "Position": 155.528732 + }, + { + "StartTime": 22062, + "Position": 142.1691 + }, + { + "StartTime": 22125, + "Position": 186.802155 + }, + { + "StartTime": 22187, + "Position": 198.6452 + }, + { + "StartTime": 22250, + "Position": 191.892181 + }, + { + "StartTime": 22312, + "Position": 232.713028 + }, + { + "StartTime": 22375, + "Position": 240.4715 + }, + { + "StartTime": 22437, + "Position": 278.3719 + }, + { + "StartTime": 22500, + "Position": 288.907257 + }, + { + "StartTime": 22562, + "Position": 297.353119 + }, + { + "StartTime": 22625, + "Position": 301.273376 + }, + { + "StartTime": 22687, + "Position": 339.98288 + }, + { + "StartTime": 22750, + "Position": 353.078552 + }, + { + "StartTime": 22812, + "Position": 363.8958 + }, + { + "StartTime": 22875, + "Position": 398.054047 + }, + { + "StartTime": 22937, + "Position": 419.739441 + }, + { + "StartTime": 23000, + "Position": 435.178467 + }, + { + "StartTime": 23062, + "Position": 420.8687 + }, + { + "StartTime": 23125, + "Position": 448.069977 + }, + { + "StartTime": 23187, + "Position": 425.688477 + }, + { + "StartTime": 23250, + "Position": 426.9612 + }, + { + "StartTime": 23312, + "Position": 454.92807 + }, + { + "StartTime": 23375, + "Position": 439.749878 + }, + { + "StartTime": 23437, + "Position": 440.540833 + }, + { + "StartTime": 23500, + "Position": 445.371735 + }, + { + "StartTime": 23562, + "Position": 431.408173 + }, + { + "StartTime": 23625, + "Position": 414.647522 + }, + { + "StartTime": 23687, + "Position": 406.2767 + }, + { + "StartTime": 23750, + "Position": 407.2297 + }, + { + "StartTime": 23812, + "Position": 403.716827 + }, + { + "StartTime": 23874, + "Position": 408.720825 + } + ] + } + ] } \ No newline at end of file From 6867a398cadb5826dfa8c8e6088dea5ab97a74ab Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 21:12:08 +0900 Subject: [PATCH 208/306] Add one more test case --- .../CatchBeatmapConversionTest.cs | 1 + ...inner-and-circles-expected-conversion.json | 65 +++++++++++++++++++ .../Testing/Beatmaps/spinner-and-circles.osu | 24 +++++++ 3 files changed, 90 insertions(+) create mode 100644 osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-and-circles-expected-conversion.json create mode 100644 osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-and-circles.osu diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs index 9de0ce3565..820929bb4c 100644 --- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs @@ -18,6 +18,7 @@ namespace osu.Game.Rulesets.Catch.Tests [TestCase("basic"), Ignore("See: https://github.com/ppy/osu/issues/2232")] [TestCase("spinner")] + [TestCase("spinner-and-circles")] public new void Test(string name) { base.Test(name); diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-and-circles-expected-conversion.json b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-and-circles-expected-conversion.json new file mode 100644 index 0000000000..dd81947f1c --- /dev/null +++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-and-circles-expected-conversion.json @@ -0,0 +1,65 @@ +{ + "Mappings": [{ + "StartTime": 2589, + "Objects": [{ + "StartTime": 2589, + "Position": 256 + }] + }, + { + "StartTime": 2915, + "Objects": [{ + "StartTime": 2915, + "Position": 65 + }, + { + "StartTime": 2916, + "Position": 482 + } + ] + }, + { + "StartTime": 3078, + "Objects": [{ + "StartTime": 3078, + "Position": 164 + }, + { + "StartTime": 3079, + "Position": 315 + } + ] + }, + { + "StartTime": 3241, + "Objects": [{ + "StartTime": 3241, + "Position": 145 + }, + { + "StartTime": 3242, + "Position": 159 + } + ] + }, + { + "StartTime": 3404, + "Objects": [{ + "StartTime": 3404, + "Position": 310 + }, + { + "StartTime": 3405, + "Position": 441 + } + ] + }, + { + "StartTime": 5197, + "Objects": [{ + "StartTime": 5197, + "Position": 256 + }] + } + ] +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-and-circles.osu b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-and-circles.osu new file mode 100644 index 0000000000..9a90768428 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/spinner-and-circles.osu @@ -0,0 +1,24 @@ +osu file format v14 + +[General] +StackLeniency: 0.7 +Mode: 2 + +[Difficulty] +HPDrainRate:5 +CircleSize:2 +OverallDifficulty:5 +ApproachRate:8 +SliderMultiplier:1.4 +SliderTickRate:4 + +[TimingPoints] +2589,326.086956521739,4,2,1,70,1,0 + +[HitObjects] +256,192,2589,5,0,0:0:0:0: +256,192,2915,12,0,2916,0:0:0:0: +256,192,3078,12,0,3079,0:0:0:0: +256,192,3241,12,0,3242,0:0:0:0: +256,192,3404,12,0,3405,0:0:0:0: +256,192,5197,5,0,0:0:0:0: From 31bd59442f9bef317802e2a0f6f605c1c833125b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 21:15:10 +0900 Subject: [PATCH 209/306] Remove banana positioning comment --- osu.Game.Rulesets.Catch/Objects/BananaShower.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs index 4590856d98..4dd491966c 100644 --- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs +++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs @@ -30,8 +30,7 @@ namespace osu.Game.Rulesets.Catch.Objects AddNested(new Banana { Samples = Samples, - StartTime = i, - X = 0 // The position will be set on the post processing + StartTime = i }); } From e840083ab4b6315b2f1c4ff24fc5940dfb81c363 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 22:22:29 +0900 Subject: [PATCH 210/306] Oops fix incorrectly changed file --- .../Beatmaps/basic-expected-conversion.json | 136 +++++++++--------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic-expected-conversion.json b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic-expected-conversion.json index 8ede7b6719..b65d54a565 100644 --- a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic-expected-conversion.json +++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic-expected-conversion.json @@ -102,32 +102,32 @@ "Position": 256 }, { - "StartTime": 2062, - "Position": 231.159988 + "StartTime": 2058, + "Position": 232.44 }, { - "StartTime": 2125, - "Position": 220 + "StartTime": 2116, + "Position": 222.879974 }, { - "StartTime": 2187, - "Position": 181.159988 + "StartTime": 2174, + "Position": 185.319992 }, { - "StartTime": 2250, - "Position": 172 + "StartTime": 2232, + "Position": 177.76001 }, { - "StartTime": 2312, - "Position": 155.159988 + "StartTime": 2290, + "Position": 162.200012 }, { - "StartTime": 2375, - "Position": 150 + "StartTime": 2348, + "Position": 158.639984 }, { - "StartTime": 2437, - "Position": 101.159988 + "StartTime": 2406, + "Position": 111.079994 }, { "StartTime": 2500, @@ -374,16 +374,16 @@ "Position": 336 }, { - "StartTime": 7812, - "Position": 316.16 + "StartTime": 7803, + "Position": 319.04 }, { - "StartTime": 7875, - "Position": 278 + "StartTime": 7857, + "Position": 283.76 }, { - "StartTime": 7937, - "Position": 257.16 + "StartTime": 7910, + "Position": 265.8 }, { "StartTime": 8000, @@ -526,32 +526,32 @@ "Position": 401.0588 }, { - "StartTime": 10562, - "Position": 422.44046 + "StartTime": 10558, + "Position": 421.21347 }, { - "StartTime": 10625, - "Position": 434.209717 + "StartTime": 10616, + "Position": 431.6034 }, { - "StartTime": 10687, - "Position": 437.275177 + "StartTime": 10674, + "Position": 433.835754 }, { - "StartTime": 10750, - "Position": 456.6923 + "StartTime": 10732, + "Position": 452.5042 }, { - "StartTime": 10812, - "Position": 490.584229 + "StartTime": 10790, + "Position": 486.290955 }, { - "StartTime": 10875, - "Position": 493.13208 + "StartTime": 10848, + "Position": 488.943237 }, { - "StartTime": 10937, - "Position": 496.8966 + "StartTime": 10906, + "Position": 493.3372 }, { "StartTime": 10999, @@ -830,32 +830,32 @@ "Position": 446.420532 }, { - "StartTime": 16062, - "Position": 427.1729 + "StartTime": 16058, + "Position": 428.4146 }, { - "StartTime": 16125, - "Position": 417.6148 + "StartTime": 16116, + "Position": 420.408844 }, { - "StartTime": 16187, - "Position": 370.367218 + "StartTime": 16174, + "Position": 374.402924 }, { - "StartTime": 16250, - "Position": 365.8091 + "StartTime": 16232, + "Position": 371.397156 }, { - "StartTime": 16312, - "Position": 343.561523 + "StartTime": 16290, + "Position": 350.391235 }, { - "StartTime": 16375, - "Position": 332.003418 + "StartTime": 16348, + "Position": 340.385468 }, { - "StartTime": 16437, - "Position": 327.755829 + "StartTime": 16406, + "Position": 337.3797 }, { "StartTime": 16500, @@ -918,16 +918,16 @@ "Position": 176 }, { - "StartTime": 17812, - "Position": 214.84 + "StartTime": 17803, + "Position": 211.959991 }, { - "StartTime": 17875, - "Position": 203 + "StartTime": 17857, + "Position": 197.23999 }, { - "StartTime": 17937, - "Position": 233.84 + "StartTime": 17910, + "Position": 225.200012 }, { "StartTime": 18000, @@ -1238,32 +1238,32 @@ "Position": 439.749878 }, { - "StartTime": 23437, - "Position": 440.540833 + "StartTime": 23433, + "Position": 440.644684 }, { - "StartTime": 23500, - "Position": 445.371735 + "StartTime": 23491, + "Position": 445.7359 }, { - "StartTime": 23562, - "Position": 431.408173 + "StartTime": 23549, + "Position": 432.0944 }, { - "StartTime": 23625, - "Position": 414.647522 + "StartTime": 23607, + "Position": 415.796173 }, { - "StartTime": 23687, - "Position": 406.2767 + "StartTime": 23665, + "Position": 407.897461 }, { - "StartTime": 23750, - "Position": 407.2297 + "StartTime": 23723, + "Position": 409.462555 }, { - "StartTime": 23812, - "Position": 403.716827 + "StartTime": 23781, + "Position": 406.53775 }, { "StartTime": 23874, From b97c415c50a17423c6e10e9255fb47ee0a622c77 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 14:16:58 +0900 Subject: [PATCH 211/306] Fix memory leak due to incorrect binding --- osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs index 240d8dc396..35146dfe29 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs @@ -161,7 +161,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor }; this.beatmap.BindTo(beatmap); - beatmap.ValueChanged += v => calculateScale(); + this.beatmap.ValueChanged += v => calculateScale(); cursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); cursorScale.ValueChanged += v => calculateScale(); From caeddc861ab7cdfc65813c185417c8ec4950b43d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 15:12:10 +0900 Subject: [PATCH 212/306] Add test for WorkingBeatmap leakage --- osu.Game/Tests/Visual/TestCasePlayer.cs | 34 ++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 3cdc496ee1..55fb9c483b 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -1,9 +1,12 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics.Shapes; +using osu.Framework.Lists; +using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -43,6 +46,7 @@ namespace osu.Game.Tests.Visual Player p = null; AddStep(ruleset.RulesetInfo.Name, () => p = loadPlayerFor(ruleset)); AddUntilStep(() => ContinueCondition(p)); + } else { @@ -51,6 +55,20 @@ namespace osu.Game.Tests.Visual Player p = null; AddStep(r.Name, () => p = loadPlayerFor(r)); AddUntilStep(() => ContinueCondition(p)); + AddAssert("no leaked beatmaps", () => + { + p = null; + + GC.Collect(); + GC.WaitForPendingFinalizers(); + int count = 0; + + workingWeakReferences.ForEachAlive(_ => count++); + + Logger.Log($"reference count {count}"); + + return count == 1; + }); } } } @@ -59,21 +77,29 @@ namespace osu.Game.Tests.Visual protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo); + private readonly WeakList workingWeakReferences = new WeakList(); + private Player loadPlayerFor(RulesetInfo ri) => loadPlayerFor(ri.CreateInstance()); private Player loadPlayerFor(Ruleset r) { var beatmap = CreateBeatmap(r); + var working = new TestWorkingBeatmap(beatmap); - Beatmap.Value = new TestWorkingBeatmap(beatmap); + workingWeakReferences.Add(working); + + Beatmap.Value = working; Beatmap.Value.Mods.Value = new[] { r.GetAllMods().First(m => m is ModNoFail) }; - if (Player != null) - Remove(Player); + Player?.Exit(); var player = CreatePlayer(r); - LoadComponentAsync(player, LoadScreen); + LoadComponentAsync(player, p => + { + Player = p; + LoadScreen(p); + }); return player; } From cb73f215ac126c21553b9f691e134e1bc64f8592 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 15:26:05 +0900 Subject: [PATCH 213/306] Add check for player screens too --- osu.Game/Tests/Visual/TestCasePlayer.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 55fb9c483b..beaa6bb43a 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -6,7 +6,6 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics.Shapes; using osu.Framework.Lists; -using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -55,6 +54,7 @@ namespace osu.Game.Tests.Visual Player p = null; AddStep(r.Name, () => p = loadPlayerFor(r)); AddUntilStep(() => ContinueCondition(p)); + AddAssert("no leaked beatmaps", () => { p = null; @@ -64,9 +64,16 @@ namespace osu.Game.Tests.Visual int count = 0; workingWeakReferences.ForEachAlive(_ => count++); + return count == 1; + }); - Logger.Log($"reference count {count}"); + AddAssert("no leaked players", () => + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + int count = 0; + playerWeakReferences.ForEachAlive(_ => count++); return count == 1; }); } @@ -78,6 +85,7 @@ namespace osu.Game.Tests.Visual protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo); private readonly WeakList workingWeakReferences = new WeakList(); + private readonly WeakList playerWeakReferences = new WeakList(); private Player loadPlayerFor(RulesetInfo ri) => loadPlayerFor(ri.CreateInstance()); @@ -95,6 +103,8 @@ namespace osu.Game.Tests.Visual var player = CreatePlayer(r); + playerWeakReferences.Add(player); + LoadComponentAsync(player, p => { Player = p; From d259b31893b6deb0c08e49ae643a190cea0068e0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 15:43:00 +0900 Subject: [PATCH 214/306] Fix empty line --- osu.Game/Tests/Visual/TestCasePlayer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index beaa6bb43a..20c9646aa3 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -45,7 +45,6 @@ namespace osu.Game.Tests.Visual Player p = null; AddStep(ruleset.RulesetInfo.Name, () => p = loadPlayerFor(ruleset)); AddUntilStep(() => ContinueCondition(p)); - } else { From 9709a40c5455b2191a5b806e788b520484cb149e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 21:46:47 +0900 Subject: [PATCH 215/306] Fix conversion test failing --- .../CatchBeatmapConversionTest.cs | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs index 820929bb4c..89e8361a72 100644 --- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using Newtonsoft.Json; using NUnit.Framework; using osu.Framework.MathUtils; using osu.Game.Rulesets.Catch.Objects; @@ -29,33 +30,15 @@ namespace osu.Game.Rulesets.Catch.Tests if (hitObject is JuiceStream stream) { foreach (var nested in stream.NestedHitObjects) - { - yield return new ConvertValue - { - StartTime = nested.StartTime, - Position = ((CatchHitObject)nested).X * CatchPlayfield.BASE_WIDTH - }; - } + yield return new ConvertValue((CatchHitObject)nested); } else if (hitObject is BananaShower shower) { foreach (var nested in shower.NestedHitObjects) - { - yield return new ConvertValue - { - StartTime = nested.StartTime, - Position = ((CatchHitObject)nested).X * CatchPlayfield.BASE_WIDTH - }; - } + yield return new ConvertValue((CatchHitObject)nested); } else - { - yield return new ConvertValue - { - StartTime = hitObject.StartTime, - Position = ((CatchHitObject)hitObject).X * CatchPlayfield.BASE_WIDTH - }; - } + yield return new ConvertValue((CatchHitObject)hitObject); } protected override Ruleset CreateRuleset() => new CatchRuleset(); @@ -68,8 +51,31 @@ namespace osu.Game.Rulesets.Catch.Tests /// private const float conversion_lenience = 2; - public double StartTime; - public float Position; + [JsonIgnore] + public readonly CatchHitObject HitObject; + + public ConvertValue(CatchHitObject hitObject) + { + HitObject = hitObject; + startTime = 0; + position = 0; + } + + private double startTime; + + public double StartTime + { + get => HitObject?.StartTime ?? startTime; + set => startTime = value; + } + + private float position; + + public float Position + { + get => HitObject?.X * CatchPlayfield.BASE_WIDTH ?? position; + set => position = value; + } public bool Equals(ConvertValue other) => Precision.AlmostEquals(StartTime, other.StartTime, conversion_lenience) From 4a19f22b3d798201734ac71859204cddb815fc37 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 15 Jun 2018 13:38:42 +0900 Subject: [PATCH 216/306] Remove custom migration exception This was hiding the true error message from ever hitting logs. Made to help disagnose #2711. --- osu.Game/Database/OsuDbContext.cs | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 4b0de57c4c..bf57644caf 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -181,24 +181,6 @@ namespace osu.Game.Database } } - public void Migrate() - { - try - { - Database.Migrate(); - } - catch (Exception e) - { - throw new MigrationFailedException(e); - } - } - } - - public class MigrationFailedException : Exception - { - public MigrationFailedException(Exception exception) - : base("sqlite-net migration failed", exception) - { - } + public void Migrate() => Database.Migrate(); } } From 069d939e292bc072423fe8852d2ae003e80ebfe9 Mon Sep 17 00:00:00 2001 From: Joehu Date: Thu, 14 Jun 2018 21:53:01 -0700 Subject: [PATCH 217/306] Remove "from" prefix from sources on direct panels --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 2 +- osu.Game/Overlays/Direct/DirectListPanel.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 723e9e8b35..e286837746 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -149,7 +149,7 @@ namespace osu.Game.Overlays.Direct { new OsuSpriteText { - Text = $"{SetInfo.Metadata.Source}", + Text = SetInfo.Metadata.Source, TextSize = 14, Shadow = false, Colour = colours.Gray5, diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index 6e3483604b..812a0e2073 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -160,7 +160,7 @@ namespace osu.Game.Overlays.Direct }, new OsuSpriteText { - Text = $"from {SetInfo.Metadata.Source}", + Text = SetInfo.Metadata.Source, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, TextSize = 14, From 149d94116bef6b2cbe96aba8901922fb2de7c53c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 15 Jun 2018 15:44:47 +0900 Subject: [PATCH 218/306] Fix droplets not bouncing off catcher's plate immediately --- .../Drawable/DrawableCatchHitObject.cs | 2 + .../Objects/Drawable/DrawableDroplet.cs | 2 + osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 63 +++++++++++-------- 3 files changed, 40 insertions(+), 27 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs index 3dbda708e5..e3564b5967 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs @@ -42,6 +42,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { public virtual bool CanBePlated => false; + public virtual bool StaysOnPlate => CanBePlated; + protected DrawableCatchHitObject(CatchHitObject hitObject) : base(hitObject) { diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs index a19d67ebbe..5c8a7c4a7c 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs @@ -13,6 +13,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { private Pulp pulp; + public override bool StaysOnPlate => false; + public DrawableDroplet(Droplet h) : base(h) { diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index d8c7b5130d..b62e9997d4 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -48,6 +48,16 @@ namespace osu.Game.Rulesets.Catch.UI public void OnJudgement(DrawableCatchHitObject fruit, Judgement judgement) { + void runAfterLoaded(Action action) + { + // this is required to make this run after the last caught fruit runs UpdateState at least once. + // TODO: find a better alternative + if (lastPlateableFruit.IsLoaded) + action(); + else + lastPlateableFruit.OnLoadComplete = _ => action(); + } + if (judgement.IsHit && fruit.CanBePlated) { var caughtFruit = (DrawableCatchHitObject)GetVisualRepresentation?.Invoke(fruit.HitObject); @@ -63,21 +73,17 @@ namespace osu.Game.Rulesets.Catch.UI caughtFruit.LifetimeEnd = double.MaxValue; MovableCatcher.Add(caughtFruit); - lastPlateableFruit = caughtFruit; + + if (!fruit.StaysOnPlate) + runAfterLoaded(() => MovableCatcher.Explode(caughtFruit)); + } if (fruit.HitObject.LastInCombo) { if (judgement.IsHit) - { - // this is required to make this run after the last caught fruit runs UpdateState at least once. - // TODO: find a better alternative - if (lastPlateableFruit.IsLoaded) - MovableCatcher.Explode(); - else - lastPlateableFruit.OnLoadComplete = _ => { MovableCatcher.Explode(); }; - } + runAfterLoaded(() => MovableCatcher.Explode()); else MovableCatcher.Drop(); } @@ -378,28 +384,31 @@ namespace osu.Game.Rulesets.Catch.UI var fruit = caughtFruit.ToArray(); foreach (var f in fruit) + Explode(f); + } + + public void Explode(DrawableHitObject fruit) + { + var originalX = fruit.X * Scale.X; + + if (ExplodingFruitTarget != null) { - var originalX = f.X * Scale.X; + fruit.Anchor = Anchor.TopLeft; + fruit.Position = caughtFruit.ToSpaceOfOtherDrawable(fruit.DrawPosition, ExplodingFruitTarget); - if (ExplodingFruitTarget != null) - { - f.Anchor = Anchor.TopLeft; - f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget); + caughtFruit.Remove(fruit); - caughtFruit.Remove(f); - - ExplodingFruitTarget.Add(f); - } - - f.MoveToY(f.Y - 50, 250, Easing.OutSine) - .Then() - .MoveToY(f.Y + 50, 500, Easing.InSine); - - f.MoveToX(f.X + originalX * 6, 1000); - f.FadeOut(750); - - f.Expire(); + ExplodingFruitTarget.Add(fruit); } + + fruit.MoveToY(fruit.Y - 50, 250, Easing.OutSine) + .Then() + .MoveToY(fruit.Y + 50, 500, Easing.InSine); + + fruit.MoveToX(fruit.X + originalX * 6, 1000); + fruit.FadeOut(750); + + fruit.Expire(); } private class CatcherSprite : Sprite From 1c27ef644a53340f8d3883128789ae71bbc6cb8a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 15 Jun 2018 16:12:11 +0900 Subject: [PATCH 219/306] Fix music controller drag activating from anywhere on the screen --- osu.Game/Overlays/MusicController.cs | 61 +++++++++++++++------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index d96bb40165..a57d5fd183 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -66,34 +66,6 @@ namespace osu.Game.Overlays AlwaysPresent = true; } - private Vector2 dragStart; - - protected override bool OnDragStart(InputState state) - { - base.OnDragStart(state); - dragStart = state.Mouse.Position; - return true; - } - - protected override bool OnDrag(InputState state) - { - if (base.OnDrag(state)) return true; - - Vector2 change = state.Mouse.Position - dragStart; - - // Diminish the drag distance as we go further to simulate "rubber band" feeling. - change *= change.Length <= 0 ? 0 : (float)Math.Pow(change.Length, 0.7f) / change.Length; - - dragContainer.MoveTo(change); - return true; - } - - protected override bool OnDragEnd(InputState state) - { - dragContainer.MoveTo(Vector2.Zero, 800, Easing.OutElastic); - return base.OnDragEnd(state); - } - [BackgroundDependencyLoader] private void load(BindableBeatmap beatmap, BeatmapManager beatmaps, OsuColour colours, LocalisationEngine localisation) { @@ -103,7 +75,7 @@ namespace osu.Game.Overlays Children = new Drawable[] { - dragContainer = new Container + dragContainer = new DragContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -470,5 +442,36 @@ namespace osu.Game.Overlays sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4"); } } + + private class DragContainer : Container + { + private Vector2 dragStart; + + protected override bool OnDragStart(InputState state) + { + base.OnDragStart(state); + dragStart = state.Mouse.Position; + return true; + } + + protected override bool OnDrag(InputState state) + { + if (base.OnDrag(state)) return true; + + Vector2 change = state.Mouse.Position - dragStart; + + // Diminish the drag distance as we go further to simulate "rubber band" feeling. + change *= change.Length <= 0 ? 0 : (float)Math.Pow(change.Length, 0.7f) / change.Length; + + this.MoveTo(change); + return true; + } + + protected override bool OnDragEnd(InputState state) + { + this.MoveTo(Vector2.Zero, 800, Easing.OutElastic); + return base.OnDragEnd(state); + } + } } } From a2950b1d80d6efeece366c6be4b807a88d434dc6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 15 Jun 2018 16:12:18 +0900 Subject: [PATCH 220/306] Fix incorrect comment --- osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 0186a170c9..062f8d27aa 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -33,7 +33,7 @@ namespace osu.Game.Graphics.Containers /// /// Whether mouse input should be blocked screen-wide while this overlay is visible. - /// Performing mouse actions outside of the valid extents will hide the overlay but pass the events through. + /// Performing mouse actions outside of the valid extents will hide the overlay and block the input. /// public virtual bool BlockScreenWideMouse => BlockPassThroughMouse; From aaf3ef240e4e40a49768bf051ed8157ad1e5894e Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Fri, 15 Jun 2018 17:07:07 +0900 Subject: [PATCH 221/306] Remove easily-confused comment --- osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 062f8d27aa..0528f7b3ae 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -33,7 +33,7 @@ namespace osu.Game.Graphics.Containers /// /// Whether mouse input should be blocked screen-wide while this overlay is visible. - /// Performing mouse actions outside of the valid extents will hide the overlay and block the input. + /// Performing mouse actions outside of the valid extents will hide the overlay. /// public virtual bool BlockScreenWideMouse => BlockPassThroughMouse; From 5d105cd08d036d78009733546c80711c1503e592 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 15 Jun 2018 17:15:04 +0900 Subject: [PATCH 222/306] Avoid errors being logged when importing beatmaps while logged out --- osu.Game/Beatmaps/BeatmapManager.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 895b47d62b..0b45aa9506 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -390,6 +390,9 @@ namespace osu.Game.Beatmaps if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null) return true; + if (api.State != APIState.Online) + return false; + Logger.Log("Attempting online lookup for IDs...", LoggingTarget.Database); try From 4eda017fa55824d12e9eac8c52894cea8e9c32ee Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 17 Jun 2018 17:54:05 +0900 Subject: [PATCH 223/306] Fix CI error --- osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs index 8f90b6d87e..9b48ec17bd 100644 --- a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs +++ b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs @@ -114,7 +114,7 @@ namespace osu.Game.Tests.Visual private class TestPlayfield : ScrollingPlayfield { - public readonly ScrollingDirection Direction; + public new readonly ScrollingDirection Direction; public TestPlayfield(ScrollingDirection direction) : base(direction) From 457531910294897c15cdfbc5337672d138c0ef1d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 17 Jun 2018 17:56:46 +0900 Subject: [PATCH 224/306] Privatise the proxied content --- .../Objects/Drawables/DrawableTaikoHitObject.cs | 17 +++++++++++------ osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index c07ee3a0fd..e712d62a26 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables public abstract class DrawableTaikoHitObject : DrawableHitObject, IKeyBindingHandler { protected readonly Container Content; - public readonly Container ProxiedContent; + private readonly Container proxiedContent; private readonly Container nonProxiedContent; @@ -31,12 +31,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables RelativeSizeAxes = Axes.Both, Child = Content = new Container { RelativeSizeAxes = Axes.Both } }, - ProxiedContent = new Container { RelativeSizeAxes = Axes.Both } + proxiedContent = new Container { RelativeSizeAxes = Axes.Both } }; } /// - /// is proxied into an upper layer. We don't want to get masked away otherwise would too. + /// is proxied into an upper layer. We don't want to get masked away otherwise would too. /// protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => false; @@ -46,8 +46,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected void ProxyContent() { nonProxiedContent.Remove(Content); - ProxiedContent.Remove(Content); - ProxiedContent.Add(Content); + proxiedContent.Remove(Content); + proxiedContent.Add(Content); } /// @@ -55,11 +55,16 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// protected void UnproxyContent() { - ProxiedContent.Remove(Content); + proxiedContent.Remove(Content); nonProxiedContent.Remove(Content); nonProxiedContent.Add(Content); } + /// + /// Creates a proxy for the content of this . + /// + public Drawable CreateProxiedContent() => proxiedContent.CreateProxy(); + public abstract bool OnPressed(TaikoAction action); public virtual bool OnReleased(TaikoAction action) => false; } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index c638f807fe..7fdd3cd1e2 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -218,7 +218,7 @@ namespace osu.Game.Rulesets.Taiko.UI var taikoObject = h as DrawableTaikoHitObject; if (taikoObject != null) - topLevelHitContainer.Add(taikoObject.ProxiedContent.CreateProxy()); + topLevelHitContainer.Add(taikoObject.CreateProxiedContent()); } internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) From 0a99d21938a252071189eab06d40f909d098e138 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 17 Jun 2018 18:01:28 +0900 Subject: [PATCH 225/306] Use the passed-in ruleset --- osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 520b9c1152..5d5adb8e66 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty public ManiaDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { - isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(new ManiaRuleset().RulesetInfo); + isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(ruleset.RulesetInfo); } protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) From 6c100caba763b333cd099e37033c70e02cac224b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 15:09:03 +0900 Subject: [PATCH 226/306] Use existing instance of beatmap rather than adding more resources --- .../Beatmaps/IO/ImportBeatmapTest.cs | 4 +- osu.Game.Tests/Visual/TestCaseWaveform.cs | 16 +----- osu.Game.Tests/WaveformTestBeatmap.cs | 55 +++++++++++++++++++ 3 files changed, 60 insertions(+), 15 deletions(-) create mode 100644 osu.Game.Tests/WaveformTestBeatmap.cs diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 1c9696901c..616ba132fd 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Beatmaps.IO [TestFixture] public class ImportBeatmapTest { - private const string osz_path = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz"; + public const string TEST_OSZ_PATH = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz"; [Test] public void TestImportWhenClosed() @@ -265,7 +265,7 @@ namespace osu.Game.Tests.Beatmaps.IO private string createTemporaryBeatmap() { var temp = Path.GetTempFileName() + ".osz"; - File.Copy(osz_path, temp, true); + File.Copy(TEST_OSZ_PATH, temp, true); Assert.IsTrue(File.Exists(temp)); return temp; } diff --git a/osu.Game.Tests/Visual/TestCaseWaveform.cs b/osu.Game.Tests/Visual/TestCaseWaveform.cs index 983b98016e..46d46863ad 100644 --- a/osu.Game.Tests/Visual/TestCaseWaveform.cs +++ b/osu.Game.Tests/Visual/TestCaseWaveform.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics.Audio; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; -using osu.Game.Overlays; namespace osu.Game.Tests.Visual { @@ -20,22 +19,14 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load() { + Beatmap.Value = new WaveformTestBeatmap(); + FillFlowContainer flow; Child = flow = new FillFlowContainer { RelativeSizeAxes = Axes.Both, Direction = FillDirection.Vertical, Spacing = new Vector2(0, 10), - Children = new Drawable[] - { - new MusicController - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Y = 100, - State = Visibility.Visible - }, - } }; for (int i = 1; i <= 16; i *= 2) @@ -44,10 +35,9 @@ namespace osu.Game.Tests.Visual { RelativeSizeAxes = Axes.Both, Resolution = 1f / i, + Waveform = Beatmap.Value.Waveform, }; - Beatmap.ValueChanged += b => newDisplay.Waveform = b.Waveform; - flow.Add(new Container { RelativeSizeAxes = Axes.X, diff --git a/osu.Game.Tests/WaveformTestBeatmap.cs b/osu.Game.Tests/WaveformTestBeatmap.cs new file mode 100644 index 0000000000..17aa7db14d --- /dev/null +++ b/osu.Game.Tests/WaveformTestBeatmap.cs @@ -0,0 +1,55 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.IO; +using System.Linq; +using osu.Framework.Audio.Track; +using osu.Framework.Graphics.Textures; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Formats; +using osu.Game.IO.Archives; +using osu.Game.Tests.Beatmaps.IO; + +namespace osu.Game.Tests +{ + /// + /// A that is used for testcases that include waveforms. + /// + public class WaveformTestBeatmap : WorkingBeatmap + { + private readonly ZipArchiveReader reader; + private readonly FileStream stream; + + public WaveformTestBeatmap() + : base(new BeatmapInfo()) + { + stream = File.OpenRead(ImportBeatmapTest.TEST_OSZ_PATH); + reader = new ZipArchiveReader(stream); + } + + public override void Dispose() + { + base.Dispose(); + stream?.Dispose(); + reader?.Dispose(); + } + + protected override IBeatmap GetBeatmap() => createTestBeatmap(); + + protected override Texture GetBackground() => null; + + protected override Waveform GetWaveform() => new Waveform(getAudioStream()); + + protected override Track GetTrack() => new TrackBass(getAudioStream()); + + private Stream getAudioStream() => reader.GetStream(reader.Filenames.First(f => f.EndsWith(".mp3"))); + private Stream getBeatmapStream() => reader.GetStream(reader.Filenames.First(f => f.EndsWith(".osu"))); + + private Beatmap createTestBeatmap() + { + using (var beatmapStream = getBeatmapStream()) + using (var beatmapReader = new StreamReader(beatmapStream)) + return Decoder.GetDecoder(beatmapReader).Decode(beatmapReader); + } + } +} From 0695615c6a21ff53e11c6e53ef52147841304b66 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 15:10:08 +0900 Subject: [PATCH 227/306] Remove MusicController from compose timeline testcase --- .../Visual/TestCaseEditorComposeTimeline.cs | 104 +++++++++++++++++- 1 file changed, 98 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index c0557982fb..bb0e6156f6 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -4,11 +4,17 @@ using System; using System.Collections.Generic; using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Configuration; using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Overlays; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Timing; +using osu.Game.Beatmaps; using osu.Game.Screens.Edit.Screens.Compose.Timeline; +using OpenTK.Graphics; namespace osu.Game.Tests.Visual { @@ -17,15 +23,23 @@ namespace osu.Game.Tests.Visual { public override IReadOnlyList RequiredTypes => new[] { typeof(TimelineArea), typeof(Timeline), typeof(TimelineButton) }; - public TestCaseEditorComposeTimeline() + [BackgroundDependencyLoader] + private void load() { + Beatmap.Value = new WaveformTestBeatmap(); + Children = new Drawable[] { - new MusicController + new FillFlowContainer { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - State = Visibility.Visible + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 5), + Children = new Drawable[] + { + new StartStopButton(), + new AudioVisualiser(), + } }, new TimelineArea { @@ -36,5 +50,83 @@ namespace osu.Game.Tests.Visual } }; } + + private class AudioVisualiser : CompositeDrawable + { + private readonly Drawable marker; + + private readonly IBindable beatmap = new Bindable(); + private IAdjustableClock adjustableClock; + + public AudioVisualiser() + { + Size = new Vector2(250, 25); + + InternalChildren = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.25f, + }, + marker = new Box + { + RelativePositionAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Width = 2, + } + }; + } + + [BackgroundDependencyLoader] + private void load(IAdjustableClock adjustableClock, IBindableBeatmap beatmap) + { + this.adjustableClock = adjustableClock; + this.beatmap.BindTo(beatmap); + } + + protected override void Update() + { + base.Update(); + marker.X = (float)(adjustableClock.CurrentTime / beatmap.Value.Track.Length); + } + } + + private class StartStopButton : Button + { + private IAdjustableClock adjustableClock; + private bool started; + + public StartStopButton() + { + BackgroundColour = Color4.SlateGray; + Size = new Vector2(100, 50); + Text = "Start"; + + Action = onClick; + } + + [BackgroundDependencyLoader] + private void load(IAdjustableClock adjustableClock) + { + this.adjustableClock = adjustableClock; + } + + private void onClick() + { + if (started) + { + adjustableClock.Stop(); + Text = "Start"; + } + else + { + adjustableClock.Start(); + Text = "Stop"; + } + + started = !started; + } + } } } From 08f172ba982f8c4880a516dc565e373b3f7d0ab0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 15 Jun 2018 15:38:19 +0900 Subject: [PATCH 228/306] Make testcase work on appveyor (no BASS) --- osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index bb0e6156f6..5aa17bca7d 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -88,7 +88,9 @@ namespace osu.Game.Tests.Visual protected override void Update() { base.Update(); - marker.X = (float)(adjustableClock.CurrentTime / beatmap.Value.Track.Length); + + if (beatmap.Value.Track.IsLoaded) + marker.X = (float)(adjustableClock.CurrentTime / beatmap.Value.Track.Length); } } From 5b344525e1889e6c4fbd8a5cedccc812827a314e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Jun 2018 00:27:18 +0900 Subject: [PATCH 229/306] Move proxy state check to base class --- .../Objects/Drawables/DrawableSwell.cs | 7 +------ .../Objects/Drawables/DrawableTaikoHitObject.cs | 12 ++++++++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 1f571544d8..df36a475d6 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -34,7 +34,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private int userHits; - private bool hasProxied; private readonly SwellSymbolPiece symbol; public DrawableSwell(Swell swell) @@ -172,7 +171,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (state) { case ArmedState.Idle: - hasProxied = false; UnproxyContent(); break; case ArmedState.Hit: @@ -193,11 +191,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables X = Math.Max(0, X); double t = Math.Min(HitObject.StartTime, Time.Current); - if (t == HitObject.StartTime && !hasProxied) - { + if (t == HitObject.StartTime) ProxyContent(); - hasProxied = true; - } } private bool? lastWasCentre; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index e712d62a26..a6d61f1a5a 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -40,23 +40,31 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => false; + private bool isProxied; + /// /// Moves to a layer proxied above the playfield. + /// Does nothing is content is already proxied. /// protected void ProxyContent() { + if (isProxied) return; + isProxied = true; + nonProxiedContent.Remove(Content); - proxiedContent.Remove(Content); proxiedContent.Add(Content); } /// /// Moves to the normal hitobject layer. + /// Does nothing is content is not currently proxied. /// protected void UnproxyContent() { + if (!isProxied) return; + isProxied = false; + proxiedContent.Remove(Content); - nonProxiedContent.Remove(Content); nonProxiedContent.Add(Content); } From 6fa72c510f2b0229267053a4d7e460f69ce0f309 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Jun 2018 00:48:35 +0900 Subject: [PATCH 230/306] Avoid listing the base mods twice --- .../Difficulty/ManiaDifficultyCalculator.cs | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 5d5adb8e66..5fa113224d 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -136,23 +136,20 @@ namespace osu.Game.Rulesets.Mania.Difficulty { get { - if (isForCurrentRuleset) - { - return new Mod[] - { - new ManiaModDoubleTime(), - new ManiaModHalfTime(), - new ManiaModEasy(), - new ManiaModHardRock(), - }; - } - - return new Mod[] + var mods = new Mod[] { new ManiaModDoubleTime(), new ManiaModHalfTime(), new ManiaModEasy(), new ManiaModHardRock(), + }; + + if (isForCurrentRuleset) + return mods; + + // if we are a convert, we can be played in any key mod. + return mods.Concat(new Mod[] + { new ManiaModKey1(), new ManiaModKey2(), new ManiaModKey3(), @@ -162,7 +159,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty new ManiaModKey7(), new ManiaModKey8(), new ManiaModKey9(), - }; + }).ToArray(); } } } From 31f9d0161df4b9f2fd19e6a7e9304f52766d2154 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Jun 2018 03:03:09 +0900 Subject: [PATCH 231/306] Add a comment about precision scroll behaviour --- .../Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs index ed26c28c80..0bfea68e50 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs @@ -100,7 +100,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline protected override bool OnScroll(InputState state) { if (state.Mouse.HasPreciseScroll) + // for now, we don't support zoom when using a precision scroll device. this needs gesture support. return base.OnScroll(state); + setZoomTarget(zoomTarget + state.Mouse.ScrollDelta.Y, zoomedContent.ToLocalSpace(state.Mouse.NativeState.Position).X); return true; } From bec6e3083ec27fd25205a343470f0c9c6ad7a43b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Jun 2018 03:19:21 +0900 Subject: [PATCH 232/306] Remove scrollbar depth change as scrollbar is hidden now --- osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index 489233e256..36f76b013a 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -45,9 +45,6 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline // We don't want the centre marker to scroll AddInternal(new CentreMarker()); - // Make sure that the scrollbar is above the centre marker - ChangeInternalChildDepth(Scrollbar, -1); - WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); Beatmap.BindTo(beatmap); From b1d059a67dbe34b17d6389b3a97b33a463ecc0ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Jun 2018 04:31:47 +0900 Subject: [PATCH 233/306] Add some colours to the compose-mode timeline --- .../Screens/Edit/Screens/Compose/Timeline/Timeline.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index 36f76b013a..e993d36551 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Configuration; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Audio; using osu.Framework.Input; @@ -31,14 +32,17 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline private WaveformGraph waveform; [BackgroundDependencyLoader] - private void load(IBindableBeatmap beatmap, IAdjustableClock adjustableClock) + private void load(IBindableBeatmap beatmap, IAdjustableClock adjustableClock, OsuColour colours) { this.adjustableClock = adjustableClock; Child = waveform = new WaveformGraph { RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex("222"), + Colour = colours.Blue.Opacity(0.2f), + LowColour = colours.BlueLighter, + MidColour = colours.BlueDark, + HighColour = colours.BlueDarker, Depth = float.MaxValue }; From 0d154621b6198a3dc57e4a6507ab44a921ee6d6f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 18 Jun 2018 16:03:00 +0900 Subject: [PATCH 234/306] Cleanup testcase --- .../Visual/TestCaseEditorSeekSnapping.cs | 63 +++++++------------ 1 file changed, 23 insertions(+), 40 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs b/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs index 94b99d483c..5ab183f09b 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs @@ -1,8 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; -using System.Collections.Generic; +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -10,9 +9,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Tests.Beatmaps; using OpenTK; @@ -22,8 +18,6 @@ namespace osu.Game.Tests.Visual { public class TestCaseEditorSeekSnapping : EditorClockTestCase { - public override IReadOnlyList RequiredTypes => new[] { typeof(HitObjectComposer) }; - public TestCaseEditorSeekSnapping() { BeatDivisor.Value = 4; @@ -56,22 +50,13 @@ namespace osu.Game.Tests.Visual Beatmap.Value = new TestWorkingBeatmap(testBeatmap); Child = new TimingPointVisualiser(testBeatmap, 5000) { Clock = Clock }; - - testSeekNoSnapping(); - testSeekSnappingOnBeat(); - testSeekSnappingInBetweenBeat(); - testSeekForwardNoSnapping(); - testSeekForwardSnappingOnBeat(); - testSeekForwardSnappingFromInBetweenBeat(); - testSeekBackwardSnappingOnBeat(); - testSeekBackwardSnappingFromInBetweenBeat(); - testSeekingWithFloatingPointBeatLength(); } /// /// Tests whether time is correctly seeked without snapping. /// - private void testSeekNoSnapping() + [Test] + public void TestSeekNoSnapping() { reset(); @@ -94,7 +79,8 @@ namespace osu.Game.Tests.Visual /// Tests whether seeking to exact beat times puts us on the beat time. /// These are the white/yellow ticks on the graph. /// - private void testSeekSnappingOnBeat() + [Test] + public void TestSeekSnappingOnBeat() { reset(); @@ -117,9 +103,9 @@ namespace osu.Game.Tests.Visual /// /// Tests whether seeking to somewhere in the middle between beats puts us on the expected beats. /// For example, snapping between a white/yellow beat should put us on either the yellow or white, depending on which one we're closer too. - /// If /// - private void testSeekSnappingInBetweenBeat() + [Test] + public void TestSeekSnappingInBetweenBeat() { reset(); @@ -140,7 +126,8 @@ namespace osu.Game.Tests.Visual /// /// Tests that when seeking forward with no beat snapping, beats are never explicitly snapped to, nor the next timing point (if we've skipped it). /// - private void testSeekForwardNoSnapping() + [Test] + public void TestSeekForwardNoSnapping() { reset(); @@ -159,7 +146,8 @@ namespace osu.Game.Tests.Visual /// /// Tests that when seeking forward with beat snapping, all beats are snapped to and timing points are never skipped. /// - private void testSeekForwardSnappingOnBeat() + [Test] + public void TestSeekForwardSnappingOnBeat() { reset(); @@ -181,7 +169,8 @@ namespace osu.Game.Tests.Visual /// Tests that when seeking forward from in-between two beats, the next beat or timing point is snapped to, and no beats are skipped. /// This will also test being extremely close to the next beat/timing point, to ensure rounding is not an issue. /// - private void testSeekForwardSnappingFromInBetweenBeat() + [Test] + public void TestSeekForwardSnappingFromInBetweenBeat() { reset(); @@ -214,7 +203,8 @@ namespace osu.Game.Tests.Visual /// /// Tests that when seeking backward with no beat snapping, beats are never explicitly snapped to, nor the next timing point (if we've skipped it). /// - private void testSeekBackwardNoSnapping() + [Test] + public void TestSeekBackwardNoSnapping() { reset(); @@ -236,7 +226,8 @@ namespace osu.Game.Tests.Visual /// /// Tests that when seeking backward with beat snapping, all beats are snapped to and timing points are never skipped. /// - private void testSeekBackwardSnappingOnBeat() + [Test] + public void TestSeekBackwardSnappingOnBeat() { reset(); @@ -259,7 +250,8 @@ namespace osu.Game.Tests.Visual /// Tests that when seeking backward from in-between two beats, the previous beat or timing point is snapped to, and no beats are skipped. /// This will also test being extremely close to the previous beat/timing point, to ensure rounding is not an issue. /// - private void testSeekBackwardSnappingFromInBetweenBeat() + [Test] + public void TestSeekBackwardSnappingFromInBetweenBeat() { reset(); @@ -280,7 +272,8 @@ namespace osu.Game.Tests.Visual /// /// Tests that there are no rounding issues when snapping to beats within a timing point with a floating-point beatlength. /// - private void testSeekingWithFloatingPointBeatLength() + [Test] + public void TestSeekingWithFloatingPointBeatLength() { reset(); @@ -288,7 +281,7 @@ namespace osu.Game.Tests.Visual AddStep("Seek(0)", () => Clock.Seek(0)); - for (int i = 0; i < 20; i++) + for (int i = 0; i < 9; i++) { AddStep("SeekForward, Snap", () => { @@ -298,7 +291,7 @@ namespace osu.Game.Tests.Visual AddAssert("Time > lastTime", () => Clock.CurrentTime > lastTime); } - for (int i = 0; i < 20; i++) + for (int i = 0; i < 9; i++) { AddStep("SeekBackward, Snap", () => { @@ -316,16 +309,6 @@ namespace osu.Game.Tests.Visual AddStep("Reset", () => Clock.Seek(0)); } - private class TestHitObjectComposer : HitObjectComposer - { - public TestHitObjectComposer(Ruleset ruleset) - : base(ruleset) - { - } - - protected override IReadOnlyList CompositionTools => new ICompositionTool[0]; - } - private class TimingPointVisualiser : CompositeDrawable { private readonly double length; From ffc5d7bd4378c8aa61ac3a2a2e4645ae59504849 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 18 Jun 2018 16:28:17 +0900 Subject: [PATCH 235/306] Fix some incorrect test case values --- osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs b/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs index 5ab183f09b..d6771ebd21 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs @@ -210,15 +210,13 @@ namespace osu.Game.Tests.Visual AddStep("Seek(450)", () => Clock.Seek(450)); AddStep("SeekBackward", () => Clock.SeekBackward()); - AddAssert("Time = 425", () => Clock.CurrentTime == 425); + AddAssert("Time = 400", () => Clock.CurrentTime == 400); AddStep("SeekBackward", () => Clock.SeekBackward()); - AddAssert("Time = 375", () => Clock.CurrentTime == 375); + AddAssert("Time = 350", () => Clock.CurrentTime == 350); AddStep("SeekBackward", () => Clock.SeekBackward()); - AddAssert("Time = 325", () => Clock.CurrentTime == 325); + AddAssert("Time = 150", () => Clock.CurrentTime == 150); AddStep("SeekBackward", () => Clock.SeekBackward()); - AddAssert("Time = 125", () => Clock.CurrentTime == 125); - AddStep("SeekBackward", () => Clock.SeekBackward()); - AddAssert("Time = 25", () => Clock.CurrentTime == 25); + AddAssert("Time = 50", () => Clock.CurrentTime == 50); AddStep("SeekBackward", () => Clock.SeekBackward()); AddAssert("Time = 0", () => Clock.CurrentTime == 0); } From 01b909eaa7d2eed0e98795c935651c0d8edcb930 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 18 Jun 2018 17:05:18 +0900 Subject: [PATCH 236/306] Add testfixture annotation --- osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs b/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs index d6771ebd21..dace6e20ef 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorSeekSnapping.cs @@ -16,6 +16,7 @@ using OpenTK.Graphics; namespace osu.Game.Tests.Visual { + [TestFixture] public class TestCaseEditorSeekSnapping : EditorClockTestCase { public TestCaseEditorSeekSnapping() From dbc50e35d58998313e7c022852fe81dacb424e8a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 18 Jun 2018 18:02:26 +0900 Subject: [PATCH 237/306] Fix the timeline and editor fighting over track seeking --- .../Edit/Screens/Compose/Timeline/Timeline.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index e993d36551..5624d2e69f 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -62,9 +62,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline } /// - /// The track's time in the previous frame. + /// The timeline's last scroll position. /// - private double lastTrackTime; + private double lastScrollPosition; /// /// Whether the user is currently dragging the timeline. @@ -100,20 +100,20 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline // 1) The user scrolls on this timeline: We want the track to follow us // 2) The user changes the track time through some other means (scrolling in the editor or overview timeline): We want to follow the track time - // The simplest way to cover both cases is by checking that inter-frame track times are identical - if (adjustableClock.CurrentTime == lastTrackTime) + // The simplest way to cover both cases is by checking whether the inter-frame timeline positions are identical + if (Current != lastScrollPosition) { - // The track hasn't been seeked externally + // The timeline has moved, seek the track seekTrackToCurrent(); } else { - // The track has been seeked externally + // The timeline hasn't moved, scroll to the track time scrollToTrackTime(); } } - lastTrackTime = adjustableClock.CurrentTime; + lastScrollPosition = Current; void seekTrackToCurrent() { From 6d318d35ee8096884707666e2b6a09451daa7824 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 18 Jun 2018 18:56:54 +0900 Subject: [PATCH 238/306] Fix not being able to seek by other means during flick-scroll --- .../Edit/Screens/Compose/Timeline/Timeline.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index 5624d2e69f..59be7dac65 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -62,9 +62,14 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline } /// - /// The timeline's last scroll position. + /// The timeline's scroll position in the last frame. /// - private double lastScrollPosition; + private float lastScrollPosition; + + /// + /// The track time in the last frame. + /// + private double lastTrackTime; /// /// Whether the user is currently dragging the timeline. @@ -100,20 +105,15 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline // 1) The user scrolls on this timeline: We want the track to follow us // 2) The user changes the track time through some other means (scrolling in the editor or overview timeline): We want to follow the track time - // The simplest way to cover both cases is by checking whether the inter-frame timeline positions are identical - if (Current != lastScrollPosition) - { - // The timeline has moved, seek the track + // The simplest way to cover both cases is by checking whether the scroll position has changed and the audio hasn't been changed externally + if (Current != lastScrollPosition && adjustableClock.CurrentTime == lastTrackTime) seekTrackToCurrent(); - } else - { - // The timeline hasn't moved, scroll to the track time scrollToTrackTime(); - } } lastScrollPosition = Current; + lastTrackTime = adjustableClock.CurrentTime; void seekTrackToCurrent() { From 54e60d8bc2182c8a6cdd5b78e2ed75e02b2199e7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 18 Jun 2018 19:27:08 +0900 Subject: [PATCH 239/306] Fix test appveyor tests failing due to lack of audio manager --- .../Screens/Edit/Screens/Compose/Timeline/Timeline.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index 59be7dac65..d0c4afed98 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -117,14 +117,21 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline void seekTrackToCurrent() { + var track = Beatmap.Value.Track; + if (track is TrackVirtual || !track.IsLoaded) + return; + if (!(Beatmap.Value.Track is TrackVirtual)) adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); } void scrollToTrackTime() { - if (!(Beatmap.Value.Track is TrackVirtual)) - ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + var track = Beatmap.Value.Track; + if (track is TrackVirtual || !track.IsLoaded) + return; + + ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); } } From 8c671f93fc9476439b4e306a0c0c7ba2299603be Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 18 Jun 2018 19:32:04 +0900 Subject: [PATCH 240/306] Always perform non-seeked scroll in the editor while audio is playing --- osu.Game/Screens/Edit/Editor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index d4f66c2f09..379484bae6 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -181,9 +181,9 @@ namespace osu.Game.Screens.Edit protected override bool OnScroll(InputState state) { if (state.Mouse.ScrollDelta.X + state.Mouse.ScrollDelta.Y > 0) - clock.SeekBackward(true); + clock.SeekBackward(!clock.IsRunning); else - clock.SeekForward(true); + clock.SeekForward(!clock.IsRunning); return true; } From 4aa89de2d76d38af34f2f19b9ef6ad7858d3c974 Mon Sep 17 00:00:00 2001 From: Tom Arrow Date: Mon, 18 Jun 2018 17:22:01 +0200 Subject: [PATCH 241/306] Fix reverse arrow displayed with incorrect angle --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs index b3bc2930d8..26f3ee6bb4 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using osu.Framework.Graphics; +using osu.Framework.MathUtils; using osu.Game.Rulesets.Objects.Drawables; using OpenTK; using osu.Game.Graphics; @@ -89,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables // find the next vector2 in the curve which is not equal to our current position to infer a rotation. for (int i = searchStart; i >= 0 && i < curve.Count; i += direction) { - if (curve[i] == Position) + if (Precision.AlmostEquals(curve[i], Position)) continue; Rotation = MathHelper.RadiansToDegrees((float)Math.Atan2(curve[i].Y - Position.Y, curve[i].X - Position.X)); From a0f1143287c884d41a67338382e96d5c077df838 Mon Sep 17 00:00:00 2001 From: Michael Manis Date: Mon, 18 Jun 2018 19:14:44 -0400 Subject: [PATCH 242/306] Add padding to 'show more' button --- osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index 1e0406c125..b1b5e3a075 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -64,6 +64,7 @@ namespace osu.Game.Overlays.Profile.Sections { TextSize = 14, Text = "show more", + Padding = new MarginPadding {Top = 10, Bottom = 10, Left = 15, Right = 15 }, } }, ShowMoreLoading = new LoadingAnimation From 15f3a05c831f637c94fc33a958c0eb6c5963e8b9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Jun 2018 19:28:21 +0900 Subject: [PATCH 243/306] Update rider configuration names --- .../{VisualTests__netcoreapp2_1_.xml => VisualTests.xml} | 5 ++--- .../runConfigurations/{osu___netcoreapp2_1_.xml => osu_.xml} | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) rename .idea/.idea.osu/.idea/runConfigurations/{VisualTests__netcoreapp2_1_.xml => VisualTests.xml} (85%) rename .idea/.idea.osu/.idea/runConfigurations/{osu___netcoreapp2_1_.xml => osu_.xml} (86%) diff --git a/.idea/.idea.osu/.idea/runConfigurations/VisualTests__netcoreapp2_1_.xml b/.idea/.idea.osu/.idea/runConfigurations/VisualTests.xml similarity index 85% rename from .idea/.idea.osu/.idea/runConfigurations/VisualTests__netcoreapp2_1_.xml rename to .idea/.idea.osu/.idea/runConfigurations/VisualTests.xml index 2d3a848922..bf5a1f64e0 100644 --- a/.idea/.idea.osu/.idea/runConfigurations/VisualTests__netcoreapp2_1_.xml +++ b/.idea/.idea.osu/.idea/runConfigurations/VisualTests.xml @@ -1,12 +1,11 @@ - + /// The type of HitObject contained by this RulesetContainer. From d753df65a57bb1bc20e02138dc60f393133ad596 Mon Sep 17 00:00:00 2001 From: Tom Arrow Date: Tue, 19 Jun 2018 18:04:53 +0200 Subject: [PATCH 246/306] Remove default bindings for right actions --- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 7b4978694b..b41a6f3c38 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -32,9 +32,7 @@ namespace osu.Game.Rulesets.Taiko new KeyBinding(InputKey.J, TaikoAction.RightCentre), new KeyBinding(InputKey.K, TaikoAction.RightRim), new KeyBinding(InputKey.MouseLeft, TaikoAction.LeftCentre), - new KeyBinding(InputKey.MouseLeft, TaikoAction.RightCentre), new KeyBinding(InputKey.MouseRight, TaikoAction.LeftRim), - new KeyBinding(InputKey.MouseRight, TaikoAction.RightRim), }; public override IEnumerable ConvertLegacyMods(LegacyMods mods) From d7f65d62e06ac0d04559c7c1fb652cd03973c3c7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Jun 2018 10:45:35 +0900 Subject: [PATCH 247/306] Use vertical/horizontal pair instead --- osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index b1b5e3a075..6dbb9b9ba3 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -64,7 +64,7 @@ namespace osu.Game.Overlays.Profile.Sections { TextSize = 14, Text = "show more", - Padding = new MarginPadding {Top = 10, Bottom = 10, Left = 15, Right = 15 }, + Padding = new MarginPadding {Vertical = 10, Horizontal = 15 }, } }, ShowMoreLoading = new LoadingAnimation From f0c72438a3320fbfa6eeb752e447e1b2dfe965e2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Jun 2018 17:06:02 +0900 Subject: [PATCH 248/306] Group ValueChanged attachment with bindings --- osu.Game/Screens/Multi/Screens/Match/Match.cs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index 3c6f141bd3..b231ed89e5 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -51,26 +51,31 @@ namespace osu.Game.Screens.Multi.Screens.Match }; header.OnWantsSelectBeatmap = () => Push(new MatchSongSelect()); - nameBind.ValueChanged += n => info.Name = n; - statusBind.ValueChanged += s => info.Status = s; - availabilityBind.ValueChanged += a => info.Availability = a; - typeBind.ValueChanged += t => info.Type = t; - maxParticipantsBind.ValueChanged += m => { participants.Max = m; }; - participantsBind.ValueChanged += p => participants.Users = p; - beatmapBind.ValueChanged += b => + beatmapBind.BindTo(room.Beatmap); + beatmapBind.BindValueChanged(b => { header.BeatmapSet = b?.BeatmapSet; info.Beatmap = b; - }; + }, true); nameBind.BindTo(room.Name); + nameBind.BindValueChanged(n => info.Name = n, true); + statusBind.BindTo(room.Status); + statusBind.BindValueChanged(s => info.Status = s, true); + availabilityBind.BindTo(room.Availability); + availabilityBind.BindValueChanged(a => info.Availability = a, true); + typeBind.BindTo(room.Type); - beatmapBind.BindTo(room.Beatmap); + typeBind.BindValueChanged(t => info.Type = t, true); + maxParticipantsBind.BindTo(room.MaxParticipants); + maxParticipantsBind.BindValueChanged(m => { participants.Max = m; }, true); + participantsBind.BindTo(room.Participants); + participantsBind.BindValueChanged(p => participants.Users = p, true); } } } From 9d7e5b492009ed883e99655397cb026a96587fcd Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 20 Jun 2018 17:23:55 +0900 Subject: [PATCH 249/306] Clamp juice stream position --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs | 2 +- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 2768357034..b0344d9a2d 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps foreach (var nested in juiceStream.NestedHitObjects) { if (nested is TinyDroplet tinyDroplet) - tinyDroplet.X += rng.Next(-20, 20) / CatchPlayfield.BASE_WIDTH; + tinyDroplet.X = MathHelper.Clamp(tinyDroplet.X + rng.Next(-20, 20) / CatchPlayfield.BASE_WIDTH, 0, 1); else if (nested is Droplet) rng.Next(); // osu!stable retrieved a random droplet rotation } diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index b2d8e3f8a5..a4c4faacfa 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -89,7 +89,7 @@ namespace osu.Game.Rulesets.Catch.Objects AddNested(new TinyDroplet { StartTime = t, - X = X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, + X = MathHelper.Clamp(X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, 0, 1), Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, @@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Catch.Objects AddNested(new Droplet { StartTime = time, - X = X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, + X = MathHelper.Clamp(X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, 0, 1), Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, @@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.Catch.Objects { Samples = Samples, StartTime = spanStartTime + spanDuration, - X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH + X = MathHelper.Clamp(X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH, 0, 1) }); } From 39649747aaad9092a32d2d97e1897ecaecded170 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Jun 2018 17:25:22 +0900 Subject: [PATCH 250/306] Simplify and synchronise multiplayer screen transitions --- .../Multi/Screens/MultiplayerScreen.cs | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs b/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs index 327d21a589..00c2613d54 100644 --- a/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs +++ b/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs @@ -10,9 +10,6 @@ namespace osu.Game.Screens.Multi.Screens { public abstract class MultiplayerScreen : OsuScreen { - private const Easing in_easing = Easing.OutQuint; - private const Easing out_easing = Easing.InSine; - protected virtual Container TransitionContent => Content; /// @@ -24,17 +21,15 @@ namespace osu.Game.Screens.Multi.Screens { base.OnEntering(last); - TransitionContent.MoveToX(200); - - Content.FadeInFromZero(WaveContainer.APPEAR_DURATION, in_easing); - TransitionContent.FadeInFromZero(WaveContainer.APPEAR_DURATION, in_easing); - TransitionContent.MoveToX(0, WaveContainer.APPEAR_DURATION, in_easing); + Content.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint); + TransitionContent.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint); + TransitionContent.MoveToX(200).MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint); } protected override bool OnExiting(Screen next) { - Content.FadeOut(WaveContainer.DISAPPEAR_DURATION, out_easing); - TransitionContent.MoveToX(200, WaveContainer.DISAPPEAR_DURATION, out_easing); + Content.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint); + TransitionContent.MoveToX(200, WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint); return base.OnExiting(next); } @@ -43,16 +38,16 @@ namespace osu.Game.Screens.Multi.Screens { base.OnResuming(last); - Content.FadeIn(WaveContainer.APPEAR_DURATION, in_easing); - TransitionContent.MoveToX(0, WaveContainer.APPEAR_DURATION, in_easing); + Content.FadeIn(WaveContainer.APPEAR_DURATION, Easing.OutQuint); + TransitionContent.MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint); } protected override void OnSuspending(Screen next) { base.OnSuspending(next); - Content.FadeOut(WaveContainer.DISAPPEAR_DURATION, out_easing); - TransitionContent.MoveToX(-200, WaveContainer.DISAPPEAR_DURATION, out_easing); + Content.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint); + TransitionContent.MoveToX(-200, WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint); } } } From 96100a2200b424b774b4fb778b7affb41c3c434d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Jun 2018 17:41:48 +0900 Subject: [PATCH 251/306] Remove schedule logic (seems unnecessary) --- osu.Game/Screens/Multi/Screens/Match/Header.cs | 4 ++-- osu.Game/Screens/Multi/Screens/Match/Match.cs | 2 +- osu.Game/Screens/Select/MatchSongSelect.cs | 7 +------ 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Multi/Screens/Match/Header.cs b/osu.Game/Screens/Multi/Screens/Match/Header.cs index 19e9dc4ad4..2bd015a2d1 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Header.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Header.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Multi.Screens.Match set => cover.BeatmapSet = value; } - public Action OnWantsSelectBeatmap; + public Action OnRequestSelectBeatmap; public Header() { @@ -89,7 +89,7 @@ namespace osu.Game.Screens.Multi.Screens.Match }, }; - beatmapButton.Action = () => OnWantsSelectBeatmap?.Invoke(); + beatmapButton.Action = () => OnRequestSelectBeatmap?.Invoke(); } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index b231ed89e5..ce3f7825a4 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -50,7 +50,7 @@ namespace osu.Game.Screens.Multi.Screens.Match }, }; - header.OnWantsSelectBeatmap = () => Push(new MatchSongSelect()); + header.OnRequestSelectBeatmap = () => Push(new MatchSongSelect()); beatmapBind.BindTo(room.Beatmap); beatmapBind.BindValueChanged(b => diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index a0c96d0cee..339392d5cf 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -7,12 +7,7 @@ namespace osu.Game.Screens.Select { protected override bool OnStart() { - Schedule(() => - { - // needs to be scheduled else we enter an infinite feedback loop. - if (IsCurrentScreen) Exit(); - }); - + if (IsCurrentScreen) Exit(); return true; } } From 516b1c5495a17e89428989ab20aaa269123042ce Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 20 Jun 2018 18:29:23 +0900 Subject: [PATCH 252/306] Fix droplet position clamping --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs | 8 +++++--- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index b0344d9a2d..7fa0d256da 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -56,10 +56,12 @@ namespace osu.Game.Rulesets.Catch.Beatmaps case JuiceStream juiceStream: foreach (var nested in juiceStream.NestedHitObjects) { - if (nested is TinyDroplet tinyDroplet) - tinyDroplet.X = MathHelper.Clamp(tinyDroplet.X + rng.Next(-20, 20) / CatchPlayfield.BASE_WIDTH, 0, 1); - else if (nested is Droplet) + var hitObject = (CatchHitObject)nested; + if (hitObject is TinyDroplet) + hitObject.X += rng.Next(-20, 20) / CatchPlayfield.BASE_WIDTH; + else if (hitObject is Droplet) rng.Next(); // osu!stable retrieved a random droplet rotation + hitObject.X = MathHelper.Clamp(hitObject.X, 0, 1); } break; } diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index a4c4faacfa..b2d8e3f8a5 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -89,7 +89,7 @@ namespace osu.Game.Rulesets.Catch.Objects AddNested(new TinyDroplet { StartTime = t, - X = MathHelper.Clamp(X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, 0, 1), + X = X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, @@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Catch.Objects AddNested(new Droplet { StartTime = time, - X = MathHelper.Clamp(X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, 0, 1), + X = X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, @@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.Catch.Objects { Samples = Samples, StartTime = spanStartTime + spanDuration, - X = MathHelper.Clamp(X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH, 0, 1) + X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH }); } From 9194fd8dfe89e453819662ad4aafbc3ffe945f94 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 20 Jun 2018 20:08:27 +0900 Subject: [PATCH 253/306] don't expose HyperDashModifier directly --- .../TestCaseCatcherArea.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 59 ++++++++----------- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs index 5119260c53..0ba6398ced 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Catch.Tests { } - public void ToggleHyperDash(bool status) => MovableCatcher.HyperDashModifier = status ? 2 : 1; + public void ToggleHyperDash(bool status) => MovableCatcher.SetHyperdashState(status ? 2 : 1); } } } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 3c0a6aec30..b74d53eef0 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -18,7 +18,6 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; using OpenTK; using OpenTK.Graphics; -using System.Diagnostics; namespace osu.Game.Rulesets.Catch.UI { @@ -250,21 +249,11 @@ namespace osu.Game.Rulesets.Catch.UI double positionDifference = target.X * CatchPlayfield.BASE_WIDTH - catcherPosition; double velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0); - // An edge case - if (Math.Abs(velocity) <= 1) - { - HyperDashModifier = 1; - } - else - { - hyperDashDirection = Math.Sign(velocity); - hyperDashTargetPosition = target.X; - HyperDashModifier = Math.Abs(velocity); - } + SetHyperdashState(Math.Abs(velocity), target.X); } else { - HyperDashModifier = 1; + SetHyperdashState(); } return validCatch; @@ -279,37 +268,39 @@ namespace osu.Game.Rulesets.Catch.UI /// public bool HyperDashing => hyperDashModifier != 1; + private const float hyperdash_transition_length = 180; + /// - /// The modifier multiplied to the catcher speed. - /// It is always not less than 1 and it is greater than 1 if and only if the catcher is hyper-dashing. + /// Set hyperdash state. /// - public double HyperDashModifier + /// The speed multiplier. If this is less or equals to 1, this catcher will be non-hyperdashing state. + /// When this catcher crosses this position, this catcher ends hyperdashing. + public void SetHyperdashState(double modifier = 1, float targetPosition = -1) { - get => hyperDashModifier; - set + bool previouslyHyperDashing = HyperDashing; + if (modifier <= 1 || X == targetPosition) { - Trace.Assert(value >= 1); - if (hyperDashModifier == value) return; - hyperDashModifier = value; + hyperDashModifier = 1; + hyperDashDirection = 0; - if (!HyperDashing) + if (previouslyHyperDashing) { - hyperDashDirection = 0; + this.FadeColour(Color4.White, hyperdash_transition_length, Easing.OutQuint); + this.FadeTo(1, hyperdash_transition_length, Easing.OutQuint); } + } + else + { + hyperDashModifier = modifier; + hyperDashDirection = Math.Sign(targetPosition - X); + hyperDashTargetPosition = targetPosition; - const float transition_length = 180; - - if (HyperDashing) + if (!previouslyHyperDashing) { - this.FadeColour(Color4.OrangeRed, transition_length, Easing.OutQuint); - this.FadeTo(0.2f, transition_length, Easing.OutQuint); + this.FadeColour(Color4.OrangeRed, hyperdash_transition_length, Easing.OutQuint); + this.FadeTo(0.2f, hyperdash_transition_length, Easing.OutQuint); Trail = true; } - else - { - this.FadeColour(Color4.White, transition_length, Easing.OutQuint); - this.FadeTo(1, transition_length, Easing.OutQuint); - } } } @@ -373,7 +364,7 @@ namespace osu.Game.Rulesets.Catch.UI hyperDashDirection < 0 && hyperDashTargetPosition > X) { X = hyperDashTargetPosition; - HyperDashModifier = 1; + SetHyperdashState(); } } From 2697579448b3212d7ecfeec4f31d7cc0278c1ecd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 09:54:13 +0900 Subject: [PATCH 254/306] Give TestLounge a background to make transitions work correctly --- osu.Game.Tests/Visual/TestCaseLounge.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Tests/Visual/TestCaseLounge.cs b/osu.Game.Tests/Visual/TestCaseLounge.cs index b96d705d5c..c5e0d1c4bf 100644 --- a/osu.Game.Tests/Visual/TestCaseLounge.cs +++ b/osu.Game.Tests/Visual/TestCaseLounge.cs @@ -8,6 +8,8 @@ using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets; +using osu.Game.Screens; +using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Multi.Screens.Lounge; using osu.Game.Users; @@ -198,6 +200,8 @@ namespace osu.Game.Tests.Visual private class TestLounge : Lounge { + protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault(); + public IEnumerable ChildRooms => RoomsContainer.Children.Where(r => r.MatchingFilter); public Room SelectedRoom => Inspector.Room; From 4c068097c81f5eabb29fe944e4420f8552a8daf5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 10:12:12 +0900 Subject: [PATCH 255/306] Change required child to use same structure as other use cases --- osu.Game/Screens/Multi/Screens/Match/Header.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/Screens/Match/Header.cs b/osu.Game/Screens/Multi/Screens/Match/Header.cs index 2bd015a2d1..02e717d4be 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Header.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Header.cs @@ -133,11 +133,12 @@ namespace osu.Game.Screens.Multi.Screens.Match Masking = true, CornerRadius = corner_radius, BorderThickness = 4, - Alpha = 0f, + Alpha = 0, Child = new Box // needs a child to show the border { RelativeSizeAxes = Axes.Both, - Colour = Color4.Black.Opacity(0), + Alpha = 0, + AlwaysPresent = true }, }, }; From 2a42418dbf6fbbe3f4537d2736bd627517809e87 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 10:19:37 +0900 Subject: [PATCH 256/306] Tidy up ReadyButton --- osu.Game/Screens/Multi/Screens/Match/Info.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Multi/Screens/Match/Info.cs b/osu.Game/Screens/Multi/Screens/Match/Info.cs index e2efbad269..ec93eb90b1 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Info.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Info.cs @@ -15,6 +15,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Overlays.SearchableList; using osu.Game.Screens.Multi.Components; +using OpenTK; namespace osu.Game.Screens.Multi.Screens.Match { @@ -124,7 +125,7 @@ namespace osu.Game.Screens.Multi.Screens.Match Anchor = Anchor.TopRight, Origin = Anchor.TopRight, RelativeSizeAxes = Axes.Y, - Width = 200, + Size = new Vector2(200, 1), Padding = new MarginPadding { Vertical = 10 }, }, }, @@ -167,14 +168,6 @@ namespace osu.Game.Screens.Multi.Screens.Match TextSize = 30, }; - public ReadyButton() - { - Height = 1; - Text = "Ready"; - - Action = () => Ready.Value = !Ready.Value; - } - [BackgroundDependencyLoader] private void load() { @@ -196,7 +189,9 @@ namespace osu.Game.Screens.Multi.Screens.Match }, }); - Ready.ValueChanged += value => + Action = () => Ready.Value = !Ready.Value; + + Ready.BindValueChanged(value => { if (value) { @@ -208,7 +203,7 @@ namespace osu.Game.Screens.Multi.Screens.Match Text = "Ready"; active.FadeOut(200); } - }; + }, true); } } } From 48989df6ebfa81a4a68cd6034f14b39ecea4b71a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Jun 2018 12:04:14 +0900 Subject: [PATCH 257/306] Make sure that 0 SR is returned when there are no hitobjects --- .../Difficulty/ManiaDifficultyCalculator.cs | 3 +++ osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 3 +++ .../Difficulty/TaikoDifficultyCalculator.cs | 3 +++ 3 files changed, 9 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 0c899372c0..7b4d4b12ed 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -39,6 +39,9 @@ namespace osu.Game.Rulesets.Mania.Difficulty protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) { + if (!beatmap.HitObjects.Any()) + return new ManiaDifficultyAttributes(mods, 0); + var difficultyHitObjects = new List(); int columnCount = ((ManiaBeatmap)beatmap).TotalColumns; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 4386004e30..62fafd8196 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -25,6 +25,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) { + if (!beatmap.HitObjects.Any()) + return new OsuDifficultyAttributes(mods, 0); + OsuDifficultyBeatmap difficultyBeatmap = new OsuDifficultyBeatmap(beatmap.HitObjects.Cast().ToList(), timeRate); Skill[] skills = { diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 190717e024..8b527c2c82 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -35,6 +35,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) { + if (!beatmap.HitObjects.Any()) + return new TaikoDifficultyAttributes(mods, 0); + var difficultyHitObjects = new List(); foreach (var hitObject in beatmap.HitObjects) From 5d0c84783528fb3acead1f75327de5ddd413314a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Jun 2018 12:26:15 +0900 Subject: [PATCH 258/306] Fix post-merge errors --- .../Difficulty/CatchDifficultyAttributes.cs | 20 ++++ .../Difficulty/CatchDifficultyCalculator.cs | 98 ++++++++++--------- .../Difficulty/CatchDifficultyHitObject.cs | 2 +- .../Difficulty/TaikoDifficultyCalculator.cs | 12 ++- 4 files changed, 82 insertions(+), 50 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs new file mode 100644 index 0000000000..687cd03152 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs @@ -0,0 +1,20 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Catch.Difficulty +{ + public class CatchDifficultyAttributes : DifficultyAttributes + { + public double AimRating; + public double ApproachRate; + public int MaxCombo; + + public CatchDifficultyAttributes(Mod[] mods, double starRating) + : base(mods, starRating) + { + } + } +} diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index acdec851d8..520a980d26 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -2,6 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Internal; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; @@ -13,31 +15,39 @@ namespace osu.Game.Rulesets.Catch.Difficulty { public class CatchDifficultyCalculator : DifficultyCalculator { + + /// + /// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size STRAIN_STEP. + /// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain. + /// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage. + /// + private const double strain_step = 750; + + /// + /// The weighting of each strain value decays to this number * it's previous value + /// + private const double decay_weight = 0.94; + private const double star_scaling_factor = 0.145; - private const float playfield_width = CatchPlayfield.BASE_WIDTH; - private readonly List difficultyHitObjects = new List(); - - public CatchDifficultyCalculator(IBeatmap beatmap) - : base(beatmap) + public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) + : base(ruleset, beatmap) { } - public CatchDifficultyCalculator(IBeatmap beatmap, Mod[] mods) - : base(beatmap, mods) + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) { - } + if (!beatmap.HitObjects.Any()) + return new CatchDifficultyAttributes(mods, 0); - public override double Calculate(Dictionary categoryDifficulty = null) - { - difficultyHitObjects.Clear(); - - float circleSize = Beatmap.BeatmapInfo.BaseDifficulty.CircleSize; + float circleSize = beatmap.BeatmapInfo.BaseDifficulty.CircleSize; float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * CatcherArea.CATCHER_SIZE; float catcherWidthHalf = catcherWidth / 2; catcherWidthHalf *= 0.8f; - foreach (var hitObject in Beatmap.HitObjects) + var difficultyHitObjects = new List(); + + foreach (var hitObject in beatmap.HitObjects) { // We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations. if (hitObject is Fruit) @@ -60,28 +70,26 @@ namespace osu.Game.Rulesets.Catch.Difficulty difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime)); - if (!CalculateStrainValues()) return 0; + if (!calculateStrainValues(difficultyHitObjects, timeRate)) + return new CatchDifficultyAttributes(mods, 0); - double starRating = Math.Sqrt(CalculateDifficulty()) * star_scaling_factor; + double ar = beatmap.BeatmapInfo.BaseDifficulty.ApproachRate; + double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / timeRate; - if (categoryDifficulty != null) + double starRating = Math.Sqrt(calculateDifficulty(difficultyHitObjects, timeRate)) * star_scaling_factor; + + return new CatchDifficultyAttributes(mods, starRating) { - categoryDifficulty["Aim"] = starRating; - - double ar = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate; - double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate; - - categoryDifficulty["AR"] = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0; - categoryDifficulty["Max combo"] = difficultyHitObjects.Count; - } - - return starRating; + AimRating = starRating, + ApproachRate = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0, + MaxCombo = difficultyHitObjects.Count + }; } - protected bool CalculateStrainValues() + private bool calculateStrainValues(List objects, double timeRate) { // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. - using (List.Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator()) + using (var hitObjectsEnumerator = objects.GetEnumerator()) { if (!hitObjectsEnumerator.MoveNext()) return false; @@ -91,7 +99,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty while (hitObjectsEnumerator.MoveNext()) { CatchDifficultyHitObject nextHitObject = hitObjectsEnumerator.Current; - nextHitObject?.CalculateStrains(currentHitObject, TimeRate); + nextHitObject?.CalculateStrains(currentHitObject, timeRate); currentHitObject = nextHitObject; } @@ -99,22 +107,10 @@ namespace osu.Game.Rulesets.Catch.Difficulty } } - /// - /// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size STRAIN_STEP. - /// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain. - /// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage. - /// - private const double strain_step = 750; - - /// - /// The weighting of each strain value decays to this number * it's previous value - /// - private const double decay_weight = 0.94; - - protected double CalculateDifficulty() + private double calculateDifficulty(List objects, double timeRate) { // The strain step needs to be adjusted for the algorithm to be considered equal with speed changing mods - double actualStrainStep = strain_step * TimeRate; + double actualStrainStep = strain_step * timeRate; // Find the highest strain value within each strain step List highestStrains = new List(); @@ -122,7 +118,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval CatchDifficultyHitObject previousHitObject = null; - foreach (CatchDifficultyHitObject hitObject in difficultyHitObjects) + foreach (CatchDifficultyHitObject hitObject in objects) { // While we are beyond the current interval push the currently available maximum to our strain list while (hitObject.BaseHitObject.StartTime > intervalEndTime) @@ -151,8 +147,16 @@ namespace osu.Game.Rulesets.Catch.Difficulty previousHitObject = hitObject; } - // calculate maximun strain difficulty - double difficulty = StrainCalculator(highestStrains, decay_weight); + // Build the weighted sum over the highest strains for each interval + double difficulty = 0; + double weight = 1; + highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain. + + foreach (double strain in highestStrains) + { + difficulty += weight * strain; + weight *= decay_weight; + } return difficulty; } diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs index 72fc6d211b..720c1d8653 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs @@ -8,7 +8,7 @@ using OpenTK; namespace osu.Game.Rulesets.Catch.Difficulty { - internal class CatchDifficultyHitObject + public class CatchDifficultyHitObject { internal static readonly double DECAY_BASE = 0.20; private const float normalized_hitobject_radius = 41.0f; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 446dcfd0b4..473c205293 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -110,8 +110,16 @@ namespace osu.Game.Rulesets.Taiko.Difficulty previousHitObject = hitObject; } - // calculate maximun strain difficulty - double difficulty = StrainCalculator(highestStrains, decay_weight); + // Build the weighted sum over the highest strains for each interval + double difficulty = 0; + double weight = 1; + highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain. + + foreach (double strain in highestStrains) + { + difficulty += weight * strain; + weight *= decay_weight; + } return difficulty; } From 5f2d1d4a1e93289b55aad46fa7ddf74ff39798f2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 12:48:44 +0900 Subject: [PATCH 259/306] Dim TestCase background a bit --- osu.Game/Tests/OsuTestBrowser.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Tests/OsuTestBrowser.cs b/osu.Game/Tests/OsuTestBrowser.cs index 738bb2d642..217af8eb77 100644 --- a/osu.Game/Tests/OsuTestBrowser.cs +++ b/osu.Game/Tests/OsuTestBrowser.cs @@ -3,6 +3,7 @@ using osu.Framework.Platform; using osu.Framework.Testing; +using osu.Game.Graphics; using osu.Game.Screens.Backgrounds; namespace osu.Game.Tests @@ -13,7 +14,11 @@ namespace osu.Game.Tests { base.LoadComplete(); - LoadComponentAsync(new BackgroundScreenDefault { Depth = 10 }, AddInternal); + LoadComponentAsync(new BackgroundScreenDefault + { + Colour = OsuColour.Gray(0.5f), + Depth = 10 + }, AddInternal); // Have to construct this here, rather than in the constructor, because // we depend on some dependencies to be loaded within OsuGameBase.load(). From df0083e3d938d404855a73be9895656a3efb95f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 12:48:57 +0900 Subject: [PATCH 260/306] Add tests for ParallaxContainer --- .../Visual/TestCaseParallaxContainer.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 osu.Game.Tests/Visual/TestCaseParallaxContainer.cs diff --git a/osu.Game.Tests/Visual/TestCaseParallaxContainer.cs b/osu.Game.Tests/Visual/TestCaseParallaxContainer.cs new file mode 100644 index 0000000000..8c12589c6f --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseParallaxContainer.cs @@ -0,0 +1,26 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Graphics.Containers; +using osu.Game.Screens.Backgrounds; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseParallaxContainer : OsuTestCase + { + public TestCaseParallaxContainer() + { + ParallaxContainer parallax; + + Add(parallax = new ParallaxContainer + { + Child = new BackgroundScreenDefault { Alpha = 0.8f } + }); + + AddStep("default parallax", () => parallax.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT); + AddStep("high parallax", () => parallax.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * 10); + AddStep("no parallax", () => parallax.ParallaxAmount = 0); + AddStep("negative parallax", () => parallax.ParallaxAmount = -ParallaxContainer.DEFAULT_PARALLAX_AMOUNT); + } + } +} From 74f732038f7542fe489bf6fe409e2a2db93a3a79 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 12:49:07 +0900 Subject: [PATCH 261/306] Add documentation for negative values of ParallaxAmount --- osu.Game/Graphics/Containers/ParallaxContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index 51be40c1e8..8e1e5d54fa 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -16,6 +16,9 @@ namespace osu.Game.Graphics.Containers { public const float DEFAULT_PARALLAX_AMOUNT = 0.02f; + /// + /// The amount of parallax movement. Negative values will reverse the direction of parallax relative to user input. + /// public float ParallaxAmount = DEFAULT_PARALLAX_AMOUNT; private Bindable parallaxEnabled; From 9314f49bc384774479f6ee9e92e6b5c1731fbed1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Jun 2018 12:57:59 +0900 Subject: [PATCH 262/306] Expose the catch width from the Catcher --- .../Difficulty/CatchDifficultyCalculator.cs | 10 ++++------ osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 12 +++++++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 520a980d26..33ee1c0184 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -40,10 +40,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty if (!beatmap.HitObjects.Any()) return new CatchDifficultyAttributes(mods, 0); - float circleSize = beatmap.BeatmapInfo.BaseDifficulty.CircleSize; - float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * CatcherArea.CATCHER_SIZE; - float catcherWidthHalf = catcherWidth / 2; - catcherWidthHalf *= 0.8f; + var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty); + float halfCatchWidth = catcher.CatchWidth * 0.5f; var difficultyHitObjects = new List(); @@ -52,7 +50,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty // We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations. if (hitObject is Fruit) { - difficultyHitObjects.Add(new CatchDifficultyHitObject((CatchHitObject)hitObject, catcherWidthHalf)); + difficultyHitObjects.Add(new CatchDifficultyHitObject((CatchHitObject)hitObject, halfCatchWidth)); } if (hitObject is JuiceStream) { @@ -61,7 +59,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty { CatchHitObject objectInJuiceStream = (CatchHitObject)nestedHitObjectsEnumerator.Current; if (!(objectInJuiceStream is TinyDroplet)) - difficultyHitObjects.Add(new CatchDifficultyHitObject(objectInJuiceStream, catcherWidthHalf)); + difficultyHitObjects.Add(new CatchDifficultyHitObject(objectInJuiceStream, halfCatchWidth)); } // Dispose the enumerator after counting all fruits. nestedHitObjectsEnumerator.Dispose(); diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index b62e9997d4..8e61e8cabe 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -105,6 +106,11 @@ namespace osu.Game.Rulesets.Catch.UI public class Catcher : Container, IKeyBindingHandler { + /// + /// Width of the area that can be used to attempt catches during gameplay. + /// + internal float CatchWidth => CATCHER_SIZE * Math.Abs(Scale.X); + private Container caughtFruit; public Container ExplodingFruitTarget; @@ -232,15 +238,15 @@ namespace osu.Game.Rulesets.Catch.UI /// Whether the catch is possible. public bool AttemptCatch(CatchHitObject fruit) { - double halfCatcherWidth = CATCHER_SIZE * Math.Abs(Scale.X) * 0.5f; + float halfCatchWidth = CatchWidth * 0.5f; // this stuff wil disappear once we move fruit to non-relative coordinate space in the future. var catchObjectPosition = fruit.X * CatchPlayfield.BASE_WIDTH; var catcherPosition = Position.X * CatchPlayfield.BASE_WIDTH; var validCatch = - catchObjectPosition >= catcherPosition - halfCatcherWidth && - catchObjectPosition <= catcherPosition + halfCatcherWidth; + catchObjectPosition >= catcherPosition - halfCatchWidth && + catchObjectPosition <= catcherPosition + halfCatchWidth; if (validCatch && fruit.HyperDash) { From afcf91a4c591980c5d633b07f60a46015931743c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Jun 2018 13:12:22 +0900 Subject: [PATCH 263/306] What the... --- osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 33ee1c0184..4dd9cd10db 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Internal; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 8e61e8cabe..3b4a7b13e7 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -3,7 +3,6 @@ using System; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; From 6aa0ca5cc98dd2d245f05fe30c461616798940ec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 14:13:20 +0900 Subject: [PATCH 264/306] Add (one-way) migration for existing users --- osu.Desktop/osu.Desktop.csproj | 1 + ...111_UpdateTaikoDefaultBindings.Designer.cs | 376 ++++++++++++++++++ ...180621044111_UpdateTaikoDefaultBindings.cs | 19 + .../Migrations/OsuDbContextModelSnapshot.cs | 8 +- 4 files changed, 399 insertions(+), 5 deletions(-) create mode 100644 osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.Designer.cs create mode 100644 osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.cs diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 3cf95e9b3e..29d3b0e394 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -30,6 +30,7 @@ + diff --git a/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.Designer.cs b/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.Designer.cs new file mode 100644 index 0000000000..aaa11e88b6 --- /dev/null +++ b/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.Designer.cs @@ -0,0 +1,376 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using osu.Game.Database; + +namespace osu.Game.Migrations +{ + [DbContext(typeof(OsuDbContext))] + [Migration("20180621044111_UpdateTaikoDefaultBindings")] + partial class UpdateTaikoDefaultBindings + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.1-rtm-30846"); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("ApproachRate"); + + b.Property("CircleSize"); + + b.Property("DrainRate"); + + b.Property("OverallDifficulty"); + + b.Property("SliderMultiplier"); + + b.Property("SliderTickRate"); + + b.HasKey("ID"); + + b.ToTable("BeatmapDifficulty"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("AudioLeadIn"); + + b.Property("BaseDifficultyID"); + + b.Property("BeatDivisor"); + + b.Property("BeatmapSetInfoID"); + + b.Property("Countdown"); + + b.Property("DistanceSpacing"); + + b.Property("GridSize"); + + b.Property("Hash"); + + b.Property("Hidden"); + + b.Property("LetterboxInBreaks"); + + b.Property("MD5Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapID"); + + b.Property("Path"); + + b.Property("RulesetID"); + + b.Property("SpecialStyle"); + + b.Property("StackLeniency"); + + b.Property("StarDifficulty"); + + b.Property("StoredBookmarks"); + + b.Property("TimelineZoom"); + + b.Property("Version"); + + b.Property("WidescreenStoryboard"); + + b.HasKey("ID"); + + b.HasIndex("BaseDifficultyID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("Hash"); + + b.HasIndex("MD5Hash"); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapID") + .IsUnique(); + + b.HasIndex("RulesetID"); + + b.ToTable("BeatmapInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Artist"); + + b.Property("ArtistUnicode"); + + b.Property("AudioFile"); + + b.Property("AuthorString") + .HasColumnName("Author"); + + b.Property("BackgroundFile"); + + b.Property("PreviewTime"); + + b.Property("Source"); + + b.Property("Tags"); + + b.Property("Title"); + + b.Property("TitleUnicode"); + + b.HasKey("ID"); + + b.ToTable("BeatmapMetadata"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("BeatmapSetInfoID"); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.HasKey("ID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("FileInfoID"); + + b.ToTable("BeatmapSetFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("DeletePending"); + + b.Property("Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapSetID"); + + b.Property("Protected"); + + b.HasKey("ID"); + + b.HasIndex("DeletePending"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapSetID") + .IsUnique(); + + b.ToTable("BeatmapSetInfo"); + }); + + modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("IntKey") + .HasColumnName("Key"); + + b.Property("RulesetID"); + + b.Property("StringValue") + .HasColumnName("Value"); + + b.Property("Variant"); + + b.HasKey("ID"); + + b.HasIndex("RulesetID", "Variant"); + + b.ToTable("Settings"); + }); + + modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("IntAction") + .HasColumnName("Action"); + + b.Property("KeysString") + .HasColumnName("Keys"); + + b.Property("RulesetID"); + + b.Property("Variant"); + + b.HasKey("ID"); + + b.HasIndex("IntAction"); + + b.HasIndex("RulesetID", "Variant"); + + b.ToTable("KeyBinding"); + }); + + modelBuilder.Entity("osu.Game.IO.FileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Hash"); + + b.Property("ReferenceCount"); + + b.HasKey("ID"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("ReferenceCount"); + + b.ToTable("FileInfo"); + }); + + modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Available"); + + b.Property("InstantiationInfo"); + + b.Property("Name"); + + b.Property("ShortName"); + + b.HasKey("ID"); + + b.HasIndex("Available"); + + b.HasIndex("ShortName") + .IsUnique(); + + b.ToTable("RulesetInfo"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.Property("SkinInfoID"); + + b.HasKey("ID"); + + b.HasIndex("FileInfoID"); + + b.HasIndex("SkinInfoID"); + + b.ToTable("SkinFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Creator"); + + b.Property("DeletePending"); + + b.Property("Name"); + + b.HasKey("ID"); + + b.ToTable("SkinInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") + .WithMany() + .HasForeignKey("BaseDifficultyID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") + .WithMany("Beatmaps") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("Beatmaps") + .HasForeignKey("MetadataID"); + + b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") + .WithMany() + .HasForeignKey("RulesetID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") + .WithMany("Files") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("BeatmapSets") + .HasForeignKey("MetadataID"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => + { + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Skinning.SkinInfo") + .WithMany("Files") + .HasForeignKey("SkinInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.cs b/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.cs new file mode 100644 index 0000000000..98ce5def08 --- /dev/null +++ b/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.cs @@ -0,0 +1,19 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using osu.Framework.Logging; + +namespace osu.Game.Migrations +{ + public partial class UpdateTaikoDefaultBindings : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.Sql("DELETE FROM KeyBinding WHERE RulesetID = 1"); + Logger.Log("osu!taiko bindings have been reset due to new defaults", LoggingTarget.Runtime, LogLevel.Important); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + // we can't really tell if these should be restored or not, so let's just not do so. + } + } +} diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index d750d50b5b..bd80cb743b 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -1,11 +1,9 @@ // +using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using osu.Game.Database; -using System; namespace osu.Game.Migrations { @@ -16,7 +14,7 @@ namespace osu.Game.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.0.3-rtm-10026"); + .HasAnnotation("ProductVersion", "2.1.1-rtm-30846"); modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => { From 566d125658a8e1071b27ee2e2a70babd94f9c8ed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 14:28:40 +0900 Subject: [PATCH 265/306] Change order of default initialisation to look better in settings --- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index b41a6f3c38..609fd27bb4 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -27,12 +27,12 @@ namespace osu.Game.Rulesets.Taiko public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] { + new KeyBinding(InputKey.MouseLeft, TaikoAction.LeftCentre), + new KeyBinding(InputKey.MouseRight, TaikoAction.LeftRim), new KeyBinding(InputKey.D, TaikoAction.LeftRim), new KeyBinding(InputKey.F, TaikoAction.LeftCentre), new KeyBinding(InputKey.J, TaikoAction.RightCentre), new KeyBinding(InputKey.K, TaikoAction.RightRim), - new KeyBinding(InputKey.MouseLeft, TaikoAction.LeftCentre), - new KeyBinding(InputKey.MouseRight, TaikoAction.LeftRim), }; public override IEnumerable ConvertLegacyMods(LegacyMods mods) From ed17a241f5551172df87be804c094e951a694ab8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 14:43:02 +0900 Subject: [PATCH 266/306] Decrease notification font size --- osu.Game/Overlays/Notifications/SimpleNotification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index a78bc8da81..25a832941e 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -59,7 +59,7 @@ namespace osu.Game.Overlays.Notifications } }); - Content.Add(textDrawable = new OsuTextFlowContainer(t => t.TextSize = 16) + Content.Add(textDrawable = new OsuTextFlowContainer(t => t.TextSize = 14) { Colour = OsuColour.Gray(128), AutoSizeAxes = Axes.Y, From 87d94591e466e5ced6570d640dc0257d4d9486f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 14:43:38 +0900 Subject: [PATCH 267/306] Start displaying notifications earlier Also show important notifications and more in total. --- osu.Game/OsuGame.cs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 36c76851c6..7f66c9fe8c 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -101,6 +101,8 @@ namespace osu.Game public OsuGame(string[] args = null) { this.args = args; + + forwardLoggedErrorsToNotifications(); } public void ToggleSettings() => settings.ToggleVisibility(); @@ -305,8 +307,6 @@ namespace osu.Game Depth = -6, }, overlayContent.Add); - forwardLoggedErrorsToNotifications(); - dependencies.Cache(settings); dependencies.Cache(onscreenDisplay); dependencies.Cache(social); @@ -394,31 +394,33 @@ namespace osu.Game private void forwardLoggedErrorsToNotifications() { - int recentErrorCount = 0; + int recentLogCount = 0; const double debounce = 5000; Logger.NewEntry += entry => { - if (entry.Level < LogLevel.Error || entry.Target == null) return; + if (entry.Level < LogLevel.Important || entry.Target == null) return; - if (recentErrorCount < 2) + if (recentLogCount < 3) { - notifications.Post(new SimpleNotification + bool lastDisplayable = recentLogCount == recentLogCount - 1; + + Schedule(() => notifications.Post(new SimpleNotification { - Icon = FontAwesome.fa_bomb, - Text = (recentErrorCount == 0 ? entry.Message : "Subsequent errors occurred and have been logged.") + "\nClick to view log files.", + Icon = entry.Level == LogLevel.Important ? FontAwesome.fa_exclamation_circle : FontAwesome.fa_bomb, + Text = (!lastDisplayable ? entry.Message : "Subsequent messages have been logged.") + "\n\nClick to view log files.", Activated = () => { Host.Storage.GetStorageForDirectory("logs").OpenInNativeExplorer(); return true; } - }); + })); } - Interlocked.Increment(ref recentErrorCount); + Interlocked.Increment(ref recentLogCount); - Scheduler.AddDelayed(() => Interlocked.Decrement(ref recentErrorCount), debounce); + Scheduler.AddDelayed(() => Interlocked.Decrement(ref recentLogCount), debounce); }; } From 6ec0aaee91d4713d730f66ce6e70ab763053fc15 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 14:50:42 +0900 Subject: [PATCH 268/306] Split out logic for subsequent log message and apply action to only itself --- osu.Game/OsuGame.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 7f66c9fe8c..ba8685b5b2 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -402,14 +402,22 @@ namespace osu.Game { if (entry.Level < LogLevel.Important || entry.Target == null) return; - if (recentLogCount < 3) - { - bool lastDisplayable = recentLogCount == recentLogCount - 1; + const int short_term_display_limit = 3; + if (recentLogCount < short_term_display_limit) + { Schedule(() => notifications.Post(new SimpleNotification { Icon = entry.Level == LogLevel.Important ? FontAwesome.fa_exclamation_circle : FontAwesome.fa_bomb, - Text = (!lastDisplayable ? entry.Message : "Subsequent messages have been logged.") + "\n\nClick to view log files.", + Text = entry.Message, + })); + } + else if (recentLogCount == short_term_display_limit) + { + Schedule(() => notifications.Post(new SimpleNotification + { + Icon = FontAwesome.fa_ellipsis_h, + Text = "Subsequent messages have been logged. Click to view log files.", Activated = () => { Host.Storage.GetStorageForDirectory("logs").OpenInNativeExplorer(); @@ -419,7 +427,6 @@ namespace osu.Game } Interlocked.Increment(ref recentLogCount); - Scheduler.AddDelayed(() => Interlocked.Decrement(ref recentLogCount), debounce); }; } From a9cb214aa908a2fbbce3742d34c2f69b9f4093f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 16:21:08 +0900 Subject: [PATCH 269/306] Replace usage of GetEnumerator --- .../Difficulty/CatchDifficultyCalculator.cs | 36 ++++++------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 4dd9cd10db..20bdaf875d 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -9,7 +9,6 @@ using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; -using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Catch.Difficulty { @@ -53,17 +52,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty difficultyHitObjects.Add(new CatchDifficultyHitObject((CatchHitObject)hitObject, halfCatchWidth)); } if (hitObject is JuiceStream) - { - IEnumerator nestedHitObjectsEnumerator = hitObject.NestedHitObjects.GetEnumerator(); - while (nestedHitObjectsEnumerator.MoveNext()) - { - CatchHitObject objectInJuiceStream = (CatchHitObject)nestedHitObjectsEnumerator.Current; - if (!(objectInJuiceStream is TinyDroplet)) - difficultyHitObjects.Add(new CatchDifficultyHitObject(objectInJuiceStream, halfCatchWidth)); - } - // Dispose the enumerator after counting all fruits. - nestedHitObjectsEnumerator.Dispose(); - } + difficultyHitObjects.AddRange(hitObject.NestedHitObjects.OfType().Where(o => !(o is TinyDroplet)).Select(o => new CatchDifficultyHitObject(o, halfCatchWidth))); } difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime)); @@ -86,23 +75,20 @@ namespace osu.Game.Rulesets.Catch.Difficulty private bool calculateStrainValues(List objects, double timeRate) { + CatchDifficultyHitObject lastObject = null; + + if (!objects.Any()) return false; + // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. - using (var hitObjectsEnumerator = objects.GetEnumerator()) + foreach (var currentObject in objects) { - if (!hitObjectsEnumerator.MoveNext()) return false; + if (lastObject != null) + currentObject.CalculateStrains(lastObject, timeRate); - CatchDifficultyHitObject currentHitObject = hitObjectsEnumerator.Current; - - // First hitObject starts at strain 1. 1 is the default for strain values, so we don't need to set it here. See DifficultyHitObject. - while (hitObjectsEnumerator.MoveNext()) - { - CatchDifficultyHitObject nextHitObject = hitObjectsEnumerator.Current; - nextHitObject?.CalculateStrains(currentHitObject, timeRate); - currentHitObject = nextHitObject; - } - - return true; + lastObject = currentObject; } + + return true; } private double calculateDifficulty(List objects, double timeRate) From c60b8bba351821f5943435cbf99657095b23b329 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 17:04:57 +0900 Subject: [PATCH 270/306] Fix race condition in TestCaseLounge --- osu.Game.Tests/Visual/TestCaseLounge.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/TestCaseLounge.cs b/osu.Game.Tests/Visual/TestCaseLounge.cs index c5e0d1c4bf..59cf59bb52 100644 --- a/osu.Game.Tests/Visual/TestCaseLounge.cs +++ b/osu.Game.Tests/Visual/TestCaseLounge.cs @@ -167,6 +167,7 @@ namespace osu.Game.Tests.Visual AddStep(@"set rooms", () => lounge.Rooms = rooms); selectAssert(1); AddStep(@"open room 1", () => clickRoom(1)); + AddUntilStep(() => !lounge.IsCurrentScreen, "wait until room current"); AddStep(@"make lounge current", lounge.MakeCurrent); filterAssert(@"THE FINAL", LoungeTab.Public, 1); filterAssert(string.Empty, LoungeTab.Public, 2); From 4982efce889d82dd2a026e640c23097b9789f8c9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 17:22:59 +0900 Subject: [PATCH 271/306] Remove vscode files from long-gone deploy project --- osu.Desktop.Deploy/.vscode/launch.json | 29 ------------ osu.Desktop.Deploy/.vscode/tasks.json | 64 -------------------------- 2 files changed, 93 deletions(-) delete mode 100644 osu.Desktop.Deploy/.vscode/launch.json delete mode 100644 osu.Desktop.Deploy/.vscode/tasks.json diff --git a/osu.Desktop.Deploy/.vscode/launch.json b/osu.Desktop.Deploy/.vscode/launch.json deleted file mode 100644 index 8c35d211bd..0000000000 --- a/osu.Desktop.Deploy/.vscode/launch.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [{ - "name": "Deploy (Debug)", - "request": "launch", - "type": "mono", - "program": "${workspaceRoot}/bin/Debug/net471/osu.Desktop.Deploy.exe", - "cwd": "${workspaceRoot}", - "preLaunchTask": "Build (Debug)", - "runtimeExecutable": null, - "env": {}, - "console": "internalConsole" - }, - { - "name": "Deploy (Release)", - "request": "launch", - "type": "clr", - "program": "${workspaceRoot}/bin/Release/net471/osu.Desktop.Deploy.exe", - "cwd": "${workspaceRoot}", - "preLaunchTask": "Build (Release)", - "runtimeExecutable": null, - "env": {}, - "console": "internalConsole" - } - ] -} \ No newline at end of file diff --git a/osu.Desktop.Deploy/.vscode/tasks.json b/osu.Desktop.Deploy/.vscode/tasks.json deleted file mode 100644 index 35bf9e7a0e..0000000000 --- a/osu.Desktop.Deploy/.vscode/tasks.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "command": "msbuild", - "type": "shell", - "suppressTaskName": true, - "args": [ - "/property:GenerateFullPaths=true", - "/property:DebugType=portable", - "/verbosity:minimal", - "/m" //parallel compiling support. - ], - "tasks": [{ - "taskName": "Build (Debug)", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [ - "$msCompile" - ] - }, - { - "taskName": "Build (Release)", - "group": "build", - "args": [ - "/property:Configuration=Release" - ], - "problemMatcher": [ - "$msCompile" - ] - }, - { - "taskName": "Clean (Debug)", - "args": [ - "/target:Clean" - ], - "problemMatcher": [ - "$msCompile" - ] - }, - { - "taskName": "Clean (Release)", - "args": [ - "/target:Clean", - "/property:Configuration=Release" - ], - "problemMatcher": [ - "$msCompile" - ] - }, - { - "taskName": "Clean All", - "dependsOn": [ - "Clean (Debug)", - "Clean (Release)" - ], - "problemMatcher": [ - "$msCompile" - ] - } - ] -} \ No newline at end of file From c64f64814f2a44bce3856fbcdfdcb530a474c7b9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 17:32:10 +0900 Subject: [PATCH 272/306] Remove unnecessary AimRating --- .../Difficulty/CatchDifficultyAttributes.cs | 1 - .../Difficulty/CatchDifficultyCalculator.cs | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs index 687cd03152..f6535380c8 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs @@ -8,7 +8,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty { public class CatchDifficultyAttributes : DifficultyAttributes { - public double AimRating; public double ApproachRate; public int MaxCombo; diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 20bdaf875d..108c9ada14 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -60,14 +60,12 @@ namespace osu.Game.Rulesets.Catch.Difficulty if (!calculateStrainValues(difficultyHitObjects, timeRate)) return new CatchDifficultyAttributes(mods, 0); - double ar = beatmap.BeatmapInfo.BaseDifficulty.ApproachRate; - double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / timeRate; - + // this is the same as osu!, so there's potential to share the implementation... maybe + double preEmpt = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate; double starRating = Math.Sqrt(calculateDifficulty(difficultyHitObjects, timeRate)) * star_scaling_factor; return new CatchDifficultyAttributes(mods, starRating) { - AimRating = starRating, ApproachRate = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0, MaxCombo = difficultyHitObjects.Count }; From 34498f7f86eb6e0baa7113d6ba59122c608febdc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jun 2018 17:49:04 +0900 Subject: [PATCH 273/306] Use var where possible --- osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 108c9ada14..3d1013aad3 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty double actualStrainStep = strain_step * timeRate; // Find the highest strain value within each strain step - List highestStrains = new List(); + var highestStrains = new List(); double intervalEndTime = actualStrainStep; double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval From b2066c5d739d55e05d8a6dfb9f77f9e84f91fb29 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Jun 2018 16:19:07 +0900 Subject: [PATCH 274/306] Rework preview tracks to reduce usage complexities --- osu.Game/Audio/IPreviewTrackOwner.cs | 16 ++++ osu.Game/Audio/PreviewTrack.cs | 88 +++++++++++++------ osu.Game/Audio/PreviewTrackManager.cs | 59 +++++++++---- .../Containers/OsuFocusedOverlayContainer.cs | 24 ++++- .../BeatmapSet/Buttons/PreviewButton.cs | 2 +- osu.Game/Overlays/BeatmapSetOverlay.cs | 7 +- osu.Game/Overlays/Direct/DirectPanel.cs | 4 +- osu.Game/Overlays/Direct/PlayButton.cs | 48 +++++----- osu.Game/Overlays/DirectOverlay.cs | 8 +- osu.Game/Overlays/UserProfileOverlay.cs | 6 +- 10 files changed, 172 insertions(+), 90 deletions(-) create mode 100644 osu.Game/Audio/IPreviewTrackOwner.cs diff --git a/osu.Game/Audio/IPreviewTrackOwner.cs b/osu.Game/Audio/IPreviewTrackOwner.cs new file mode 100644 index 0000000000..f166096601 --- /dev/null +++ b/osu.Game/Audio/IPreviewTrackOwner.cs @@ -0,0 +1,16 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Audio +{ + /// + /// Interface for objects that can own s. + /// + /// + /// s can cancel the currently playing through the + /// global if they're the owner of the playing . + /// + public interface IPreviewTrackOwner + { + } +} diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index cfc47497d0..59baa86f80 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -5,49 +5,87 @@ using System; using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; +using osu.Framework.Threading; namespace osu.Game.Audio { - public class PreviewTrack : Component + public abstract class PreviewTrack : Component { - public Track Track { get; private set; } - private readonly OverlayContainer owner; - - private readonly BeatmapSetInfo beatmapSetInfo; - public event Action Stopped; public event Action Started; - public PreviewTrack(BeatmapSetInfo beatmapSetInfo, OverlayContainer owner) - { - this.beatmapSetInfo = beatmapSetInfo; - this.owner = owner; - } + private Track track; + private bool wasPlaying; [BackgroundDependencyLoader] - private void load(PreviewTrackManager previewTrackManager) + private void load() { - Track = previewTrackManager.Get(this, beatmapSetInfo); - } + track = GetTrack(); - public void Start() - { - Track.Restart(); - Started?.Invoke(); + if (track != null) + track.Looping = false; } /// - /// Stop preview playback + /// Length of the track. /// - /// An which is probably the owner of this - public void Stop(OverlayContainer source = null) + public double Length => track?.Length ?? 0; + + /// + /// The current track time. + /// + public double CurrentTime => track?.CurrentTime ?? 0; + + /// + /// Whether the track is loaded. + /// + public bool TrackLoaded => track?.IsLoaded ?? false; + + protected override void Update() { - if (source != null && owner != source) + base.Update(); + + // Todo: Track currently doesn't signal its completion, so we have to handle it manually + if (track != null && wasPlaying && track.HasCompleted) + Stop(); + } + + private ScheduledDelegate startDelegate; + + public void Start() => startDelegate = Schedule(() => + { + if (!IsLoaded) return; - Track.Stop(); + + if (track == null) + return; + + if (wasPlaying) + return; + wasPlaying = true; + + track.Restart(); + Started?.Invoke(); + }); + + public void Stop() + { + startDelegate?.Cancel(); + + if (!IsLoaded) + return; + + if (track == null) + return; + + if (!wasPlaying) + return; + wasPlaying = false; + + track.Stop(); Stopped?.Invoke(); } + + protected abstract Track GetTrack(); } } diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index a3da930af0..499e4a1eea 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -13,17 +13,17 @@ namespace osu.Game.Audio { public class PreviewTrackManager : Component { + private readonly BindableDouble muteBindable = new BindableDouble(); + private AudioManager audio; private TrackManager trackManager; - private BindableDouble muteBindable; - public PreviewTrack CurrentTrack { get; private set; } + private TrackManagerPreviewTrack current; [BackgroundDependencyLoader] private void load(AudioManager audio, FrameworkConfigManager config) { trackManager = new TrackManager(new OnlineStore()); - muteBindable = new BindableDouble(); this.audio = audio; audio.AddItem(trackManager); @@ -31,30 +31,55 @@ namespace osu.Game.Audio config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); } - protected override void Update() + public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo) { - if (CurrentTrack?.Track.HasCompleted ?? false) - CurrentTrack.Stop(); + var track = new TrackManagerPreviewTrack(beatmapSetInfo, trackManager); - base.Update(); - } - - public Track Get(PreviewTrack previewTrack, BeatmapSetInfo beatmapSetInfo) - { - previewTrack.Started += () => + track.Started += () => { - CurrentTrack?.Stop(); - CurrentTrack = previewTrack; + current?.Stop(); + current = track; audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); }; - previewTrack.Stopped += () => + track.Stopped += () => { - CurrentTrack = null; + current = null; audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); }; - return trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3"); + return track; + } + + public void Stop(IPreviewTrackOwner source) + { + if (current?.Owner != source) + return; + + current?.Stop(); + current = null; + } + + private class TrackManagerPreviewTrack : PreviewTrack + { + public IPreviewTrackOwner Owner { get; private set; } + + private readonly BeatmapSetInfo beatmapSetInfo; + private readonly TrackManager trackManager; + + public TrackManagerPreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager) + { + this.beatmapSetInfo = beatmapSetInfo; + this.trackManager = trackManager; + } + + [BackgroundDependencyLoader] + private void load(IPreviewTrackOwner owner) + { + Owner = owner; + } + + protected override Track GetTrack() => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3"); } } } diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 0528f7b3ae..e3179b5631 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -8,20 +8,32 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input; using OpenTK; using osu.Framework.Configuration; +using osu.Game.Audio; using osu.Game.Overlays; namespace osu.Game.Graphics.Containers { - public class OsuFocusedOverlayContainer : FocusedOverlayContainer + public class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner { private SampleChannel samplePopIn; private SampleChannel samplePopOut; + private PreviewTrackManager previewTrackManager; + protected readonly Bindable OverlayActivationMode = new Bindable(OverlayActivation.All); - [BackgroundDependencyLoader(true)] - private void load(OsuGame osuGame, AudioManager audio) + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) { + var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); + dependencies.CacheAs(this); + return dependencies; + } + + [BackgroundDependencyLoader(true)] + private void load(OsuGame osuGame, AudioManager audio, PreviewTrackManager previewTrackManager) + { + this.previewTrackManager = previewTrackManager; + if (osuGame != null) OverlayActivationMode.BindTo(osuGame.OverlayActivationMode); @@ -66,5 +78,11 @@ namespace osu.Game.Graphics.Containers break; } } + + protected override void PopOut() + { + base.PopOut(); + previewTrackManager.Stop(this); + } } } diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs index 78bc77efe8..505b7a7540 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs @@ -83,7 +83,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons if (Playing.Value && preview != null) { // prevent negative (potential infinite) width if a track without length was loaded - progress.Width = preview.Track.Length > 0 ? (float)(preview.Track.CurrentTime / preview.Track.Length) : 0f; + progress.Width = preview.Length > 0 ? (float)(preview.CurrentTime / preview.Length) : 0f; } else progress.Width = 0; diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 234d91b9e6..88f0a72ddf 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; -using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -38,7 +37,6 @@ namespace osu.Game.Overlays private readonly ScrollContainer scroll; private BeatmapSetInfo beatmapSet; - private PreviewTrackManager previewTrackManager; public BeatmapSetInfo BeatmapSet { @@ -111,11 +109,10 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api, RulesetStore rulesets, PreviewTrackManager previewTrackManager) + private void load(APIAccess api, RulesetStore rulesets) { this.api = api; this.rulesets = rulesets; - this.previewTrackManager = previewTrackManager; } protected override void PopIn() @@ -127,8 +124,6 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); - previewTrackManager.CurrentTrack?.Stop(this); - FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => BeatmapSet = null); } diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 93f28194e4..e63c290ce5 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -113,9 +113,9 @@ namespace osu.Game.Overlays.Direct { base.Update(); - if (PreviewPlaying && Preview != null && Preview.Track.IsLoaded) + if (PreviewPlaying && Preview != null && Preview.TrackLoaded) { - PreviewBar.Width = (float)(Preview.Track.CurrentTime / Preview.Track.Length); + PreviewBar.Width = (float)(Preview.CurrentTime / Preview.Length); } } diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index e6f409cbce..d9881f2b23 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -29,21 +29,14 @@ namespace osu.Game.Overlays.Direct if (value == beatmapSet) return; beatmapSet = value; - Preview?.Stop(parentOverlayContainer); + if (Preview != null) + { + Preview.Stop(); + RemoveInternal(Preview); + Preview = null; + } + Playing.Value = false; - Preview = null; - } - } - - private OverlayContainer parentOverlayContainer - { - get - { - var d = Parent; - while (!(d is OverlayContainer)) - d = d.Parent; - - return (OverlayContainer)d; } } @@ -89,9 +82,13 @@ namespace osu.Game.Overlays.Direct Playing.ValueChanged += playingStateChanged; } + private PreviewTrackManager previewTrackManager; + [BackgroundDependencyLoader] - private void load(OsuColour colour) + private void load(OsuColour colour, PreviewTrackManager previewTrackManager) { + this.previewTrackManager = previewTrackManager; + hoverColour = colour.Yellow; } @@ -103,15 +100,18 @@ namespace osu.Game.Overlays.Direct { loading = true; - LoadComponentAsync( - Preview = new PreviewTrack(beatmapSet, parentOverlayContainer), - t => - { - Preview.Started += () => Playing.Value = true; - Preview.Stopped += () => Playing.Value = false; - Preview.Start(); - loading = false; - }); + Preview = previewTrackManager.Get(beatmapSet); + Preview.Started += () => Playing.Value = true; + Preview.Stopped += () => Playing.Value = false; + + LoadComponentAsync(Preview, t => + { + AddInternal(t); + + Preview.Start(); + + loading = false; + }); return true; } diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 5f5ef44949..c28ecb3c9f 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -262,7 +262,7 @@ namespace osu.Game.Overlays if (Header.Tabs.Current.Value == DirectTab.Search && (Filter.Search.Text == string.Empty || currentQuery == string.Empty)) return; - previewTrackManager.CurrentTrack?.Stop(this); + previewTrackManager.Stop(this); getSetsRequest = new SearchBeatmapSetsRequest(currentQuery.Value ?? string.Empty, ((FilterControl)Filter).Ruleset.Value, @@ -289,12 +289,6 @@ namespace osu.Game.Overlays private int distinctCount(List list) => list.Distinct().ToArray().Length; - protected override void PopOut() - { - previewTrackManager.CurrentTrack?.Stop(this); - base.PopOut(); - } - public class ResultCounts { public readonly int Artists; diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 6a8dd30890..745f2f3def 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; -using osu.Game.Audio; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -31,7 +30,6 @@ namespace osu.Game.Overlays protected ProfileHeader Header; private SectionsContainer sectionsContainer; private ProfileTabControl tabs; - private PreviewTrackManager previewTrackManager; public const float CONTENT_X_MARGIN = 50; @@ -58,10 +56,9 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api, PreviewTrackManager previewTrackManager) + private void load(APIAccess api) { this.api = api; - this.previewTrackManager = previewTrackManager; } protected override void PopIn() @@ -73,7 +70,6 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); - previewTrackManager.CurrentTrack?.Stop(this); FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out); } From 40ed3fdd05df4d11d01edbac79373b91c03bcbf3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Jun 2018 18:45:32 +0900 Subject: [PATCH 275/306] Fix possible incorrect order of events due to threaded load --- osu.Game/Overlays/Direct/PlayButton.cs | 36 ++++++++++++++------------ 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index d9881f2b23..4bf6cf2bf7 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -96,27 +96,29 @@ namespace osu.Game.Overlays.Direct { if (!Playing.Value) { - if (Preview == null) + if (Preview != null) { - loading = true; - - Preview = previewTrackManager.Get(beatmapSet); - Preview.Started += () => Playing.Value = true; - Preview.Stopped += () => Playing.Value = false; - - LoadComponentAsync(Preview, t => - { - AddInternal(t); - - Preview.Start(); - - loading = false; - }); - + Preview.Start(); return true; } - Preview.Start(); + loading = true; + + var loadingPreview = previewTrackManager.Get(beatmapSet); + loadingPreview.Started += () => Playing.Value = true; + loadingPreview.Stopped += () => Playing.Value = false; + + LoadComponentAsync(Preview = loadingPreview, t => + { + if (Preview != loadingPreview) + return; + + AddInternal(t); + + Preview.Start(); + + loading = false; + }); } else Preview?.Stop(); From 63a6fc25963ef227429f02ba7bce093e0a441a0d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Jun 2018 18:54:42 +0900 Subject: [PATCH 276/306] XMLDoc all the things --- osu.Game/Audio/PreviewTrack.cs | 16 ++++++++++++++++ osu.Game/Audio/PreviewTrackManager.cs | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 59baa86f80..5fd3dbfe8f 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -11,7 +11,14 @@ namespace osu.Game.Audio { public abstract class PreviewTrack : Component { + /// + /// Invoked when this has stopped playing. + /// public event Action Stopped; + + /// + /// Invoked when this has started playing. + /// public event Action Started; private Track track; @@ -52,6 +59,9 @@ namespace osu.Game.Audio private ScheduledDelegate startDelegate; + /// + /// Starts playing this . + /// public void Start() => startDelegate = Schedule(() => { if (!IsLoaded) @@ -68,6 +78,9 @@ namespace osu.Game.Audio Started?.Invoke(); }); + /// + /// Stops playing this . + /// public void Stop() { startDelegate?.Cancel(); @@ -86,6 +99,9 @@ namespace osu.Game.Audio Stopped?.Invoke(); } + /// + /// Retrieves the audio track. + /// protected abstract Track GetTrack(); } } diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 499e4a1eea..8febf8e621 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -11,6 +11,9 @@ using osu.Game.Beatmaps; namespace osu.Game.Audio { + /// + /// A central store for the retrieval of s. + /// public class PreviewTrackManager : Component { private readonly BindableDouble muteBindable = new BindableDouble(); @@ -31,6 +34,11 @@ namespace osu.Game.Audio config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); } + /// + /// Retrieves a for a . + /// + /// The to retrieve the preview track for. + /// The playable . public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo) { var track = new TrackManagerPreviewTrack(beatmapSetInfo, trackManager); @@ -51,6 +59,15 @@ namespace osu.Game.Audio return track; } + /// + /// Stops the currently playing . + /// + /// + /// Only the immediate owner (an object that implements ) of the playing + /// can globally stop the currently playing . The object holding a reference to the + /// can always stop the themselves through . + /// + /// The which may be the owner of the . public void Stop(IPreviewTrackOwner source) { if (current?.Owner != source) From 1932399521c87a672f657422a853bfbfec44fc7d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Jun 2018 19:31:07 +0900 Subject: [PATCH 277/306] Add testcases --- .../Visual/TestCasePreviewTrackManager.cs | 131 ++++++++++++++++++ osu.Game/Audio/PreviewTrack.cs | 5 + osu.Game/Audio/PreviewTrackManager.cs | 9 +- 3 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs diff --git a/osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs b/osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs new file mode 100644 index 0000000000..b394202706 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs @@ -0,0 +1,131 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio.Track; +using osu.Framework.Graphics.Containers; +using osu.Game.Audio; +using osu.Game.Beatmaps; + +namespace osu.Game.Tests.Visual +{ + public class TestCasePreviewTrackManager : OsuTestCase, IPreviewTrackOwner + { + private readonly PreviewTrackManager trackManager = new TestPreviewTrackManager(); + + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); + dependencies.CacheAs(trackManager); + dependencies.CacheAs(this); + return dependencies; + } + + [BackgroundDependencyLoader] + private void load() + { + AddInternal(trackManager); + } + + [Test] + public void TestStartStop() + { + PreviewTrack track = null; + + AddStep("get track", () => track = getOwnedTrack()); + AddStep("start", () => track.Start()); + AddAssert("started", () => track.IsRunning); + AddStep("stop", () => track.Stop()); + AddAssert("stopped", () => !track.IsRunning); + } + + [Test] + public void TestStartMultipleTracks() + { + PreviewTrack track1 = null; + PreviewTrack track2 = null; + + AddStep("get tracks", () => + { + track1 = getOwnedTrack(); + track2 = getOwnedTrack(); + }); + + AddStep("start track 1", () => track1.Start()); + AddStep("start track 2", () => track2.Start()); + AddAssert("track 1 stopped", () => !track1.IsRunning); + AddAssert("track 2 started", () => track2.IsRunning); + } + + [Test] + public void TestCancelFromOwner() + { + PreviewTrack track = null; + + AddStep("get track", () => track = getOwnedTrack()); + AddStep("start", () => track.Start()); + AddStep("stop by owner", () => trackManager.Stop(this)); + AddAssert("stopped", () => !track.IsRunning); + } + + [Test] + public void TestCancelFromNonOwner() + { + TestTrackOwner owner = null; + PreviewTrack track = null; + + AddStep("get track", () => AddInternal(owner = new TestTrackOwner(track = getTrack()))); + AddStep("start", () => track.Start()); + AddStep("attempt stop", () => trackManager.Stop(this)); + AddAssert("not stopped", () => track.IsRunning); + AddStep("stop by true owner", () => trackManager.Stop(owner)); + AddAssert("stopped", () => !track.IsRunning); + } + + private PreviewTrack getTrack() => trackManager.Get(null); + + private PreviewTrack getOwnedTrack() + { + var track = getTrack(); + + AddInternal(track); + + return track; + } + + private class TestTrackOwner : CompositeDrawable, IPreviewTrackOwner + { + private readonly PreviewTrack track; + + public TestTrackOwner(PreviewTrack track) + { + this.track = track; + + AddInternal(track); + } + + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); + dependencies.CacheAs(this); + return dependencies; + } + } + + private class TestPreviewTrackManager : PreviewTrackManager + { + protected override TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager) => new TestPreviewTrack(beatmapSetInfo, trackManager); + + protected class TestPreviewTrack : TrackManagerPreviewTrack + { + public TestPreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager) + : base(beatmapSetInfo, trackManager) + { + } + + protected override Track GetTrack() => new TrackVirtual { Length = 100000 }; + } + } + } +} diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 5fd3dbfe8f..50366e35eb 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -48,6 +48,11 @@ namespace osu.Game.Audio /// public bool TrackLoaded => track?.IsLoaded ?? false; + /// + /// Whether the track is playing. + /// + public bool IsRunning => track?.IsRunning ?? false; + protected override void Update() { base.Update(); diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 8febf8e621..56bedc9dd2 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -41,7 +41,7 @@ namespace osu.Game.Audio /// The playable . public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo) { - var track = new TrackManagerPreviewTrack(beatmapSetInfo, trackManager); + var track = CreatePreviewTrack(beatmapSetInfo, trackManager); track.Started += () => { @@ -77,7 +77,12 @@ namespace osu.Game.Audio current = null; } - private class TrackManagerPreviewTrack : PreviewTrack + /// + /// Creates the . + /// + protected virtual TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager) => new TrackManagerPreviewTrack(beatmapSetInfo, trackManager); + + protected class TrackManagerPreviewTrack : PreviewTrack { public IPreviewTrackOwner Owner { get; private set; } From 15bb301d14bf0a6c0ee7a1c9fa3e6dfe22f68c5f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Jun 2018 19:37:42 +0900 Subject: [PATCH 278/306] Remove unused field --- osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs b/osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs index b394202706..7d02519007 100644 --- a/osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs +++ b/osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs @@ -96,12 +96,8 @@ namespace osu.Game.Tests.Visual private class TestTrackOwner : CompositeDrawable, IPreviewTrackOwner { - private readonly PreviewTrack track; - public TestTrackOwner(PreviewTrack track) { - this.track = track; - AddInternal(track); } From 4b2b1f51f946d858aa44dd65872cb3dbe068e272 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Jun 2018 12:12:59 +0900 Subject: [PATCH 279/306] Apply some code review --- osu.Game/Audio/PreviewTrack.cs | 21 ++----- osu.Game/Overlays/Direct/PlayButton.cs | 87 +++++++++++--------------- 2 files changed, 44 insertions(+), 64 deletions(-) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 50366e35eb..3c9122b941 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -22,15 +22,12 @@ namespace osu.Game.Audio public event Action Started; private Track track; - private bool wasPlaying; + private bool hasStarted; [BackgroundDependencyLoader] private void load() { track = GetTrack(); - - if (track != null) - track.Looping = false; } /// @@ -58,7 +55,7 @@ namespace osu.Game.Audio base.Update(); // Todo: Track currently doesn't signal its completion, so we have to handle it manually - if (track != null && wasPlaying && track.HasCompleted) + if (hasStarted && track.HasCompleted) Stop(); } @@ -69,15 +66,12 @@ namespace osu.Game.Audio /// public void Start() => startDelegate = Schedule(() => { - if (!IsLoaded) - return; - if (track == null) return; - if (wasPlaying) + if (hasStarted) return; - wasPlaying = true; + hasStarted = true; track.Restart(); Started?.Invoke(); @@ -90,15 +84,12 @@ namespace osu.Game.Audio { startDelegate?.Cancel(); - if (!IsLoaded) - return; - if (track == null) return; - if (!wasPlaying) + if (!hasStarted) return; - wasPlaying = false; + hasStarted = false; track.Stop(); Stopped?.Invoke(); diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 4bf6cf2bf7..4b91a3d700 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Direct { public class PlayButton : Container { - public readonly Bindable Playing = new Bindable(); + public readonly BindableBool Playing = new BindableBool(); public PreviewTrack Preview { get; private set; } private BeatmapSetInfo beatmapSet; @@ -29,12 +29,9 @@ namespace osu.Game.Overlays.Direct if (value == beatmapSet) return; beatmapSet = value; - if (Preview != null) - { - Preview.Stop(); - RemoveInternal(Preview); - Preview = null; - } + Preview?.Stop(); + Preview?.Expire(); + Preview = null; Playing.Value = false; } @@ -51,15 +48,9 @@ namespace osu.Game.Overlays.Direct set { if (value) - { loadingAnimation.Show(); - icon.FadeOut(transition_duration * 5, Easing.OutQuint); - } else - { loadingAnimation.Hide(); - icon.FadeIn(transition_duration, Easing.OutQuint); - } } } @@ -94,35 +85,7 @@ namespace osu.Game.Overlays.Direct protected override bool OnClick(InputState state) { - if (!Playing.Value) - { - if (Preview != null) - { - Preview.Start(); - return true; - } - - loading = true; - - var loadingPreview = previewTrackManager.Get(beatmapSet); - loadingPreview.Started += () => Playing.Value = true; - loadingPreview.Stopped += () => Playing.Value = false; - - LoadComponentAsync(Preview = loadingPreview, t => - { - if (Preview != loadingPreview) - return; - - AddInternal(t); - - Preview.Start(); - - loading = false; - }); - } - else - Preview?.Stop(); - + Playing.Toggle(); return true; } @@ -141,17 +104,43 @@ namespace osu.Game.Overlays.Direct private void playingStateChanged(bool playing) { - if (playing && BeatmapSet == null) - { - Playing.Value = false; - return; - } - icon.Icon = playing ? FontAwesome.fa_stop : FontAwesome.fa_play; icon.FadeColour(playing || IsHovered ? hoverColour : Color4.White, 120, Easing.InOutQuint); - if (!playing) + if (playing) { + if (BeatmapSet == null) + { + Playing.Value = false; + return; + } + + if (Preview != null) + { + Preview.Start(); + return; + } + + loading = true; + + LoadComponentAsync(Preview = previewTrackManager.Get(beatmapSet), preview => + { + // beatmapset may have changed. + if (Preview != preview) + return; + + AddInternal(preview); + loading = false; + preview.Stopped += () => Playing.Value = false; + + // user may have changed their mind. + if (Playing) + preview.Start(); + }); + } + else + { + Preview?.Stop(); loading = false; } } From 73e13e2d63c3d9a6509cb0c664399f458781b3a8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Jun 2018 12:35:43 +0900 Subject: [PATCH 280/306] Rename Stop to StopAnyPlaying for clarity --- osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs | 6 +++--- osu.Game/Audio/PreviewTrackManager.cs | 8 ++++---- .../Graphics/Containers/OsuFocusedOverlayContainer.cs | 2 +- osu.Game/Overlays/DirectOverlay.cs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs b/osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs index 7d02519007..d711d501fe 100644 --- a/osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs +++ b/osu.Game.Tests/Visual/TestCasePreviewTrackManager.cs @@ -65,7 +65,7 @@ namespace osu.Game.Tests.Visual AddStep("get track", () => track = getOwnedTrack()); AddStep("start", () => track.Start()); - AddStep("stop by owner", () => trackManager.Stop(this)); + AddStep("stop by owner", () => trackManager.StopAnyPlaying(this)); AddAssert("stopped", () => !track.IsRunning); } @@ -77,9 +77,9 @@ namespace osu.Game.Tests.Visual AddStep("get track", () => AddInternal(owner = new TestTrackOwner(track = getTrack()))); AddStep("start", () => track.Start()); - AddStep("attempt stop", () => trackManager.Stop(this)); + AddStep("attempt stop", () => trackManager.StopAnyPlaying(this)); AddAssert("not stopped", () => track.IsRunning); - AddStep("stop by true owner", () => trackManager.Stop(owner)); + AddStep("stop by true owner", () => trackManager.StopAnyPlaying(owner)); AddAssert("stopped", () => !track.IsRunning); } diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 56bedc9dd2..07fbe86ff4 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -60,7 +60,7 @@ namespace osu.Game.Audio } /// - /// Stops the currently playing . + /// Stops any currently playing . /// /// /// Only the immediate owner (an object that implements ) of the playing @@ -68,12 +68,12 @@ namespace osu.Game.Audio /// can always stop the themselves through . /// /// The which may be the owner of the . - public void Stop(IPreviewTrackOwner source) + public void StopAnyPlaying(IPreviewTrackOwner source) { - if (current?.Owner != source) + if (current == null || current.Owner != source) return; - current?.Stop(); + current.Stop(); current = null; } diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index e3179b5631..d6b6595b69 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -82,7 +82,7 @@ namespace osu.Game.Graphics.Containers protected override void PopOut() { base.PopOut(); - previewTrackManager.Stop(this); + previewTrackManager.StopAnyPlaying(this); } } } diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index c28ecb3c9f..423211659d 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -262,7 +262,7 @@ namespace osu.Game.Overlays if (Header.Tabs.Current.Value == DirectTab.Search && (Filter.Search.Text == string.Empty || currentQuery == string.Empty)) return; - previewTrackManager.Stop(this); + previewTrackManager.StopAnyPlaying(this); getSetsRequest = new SearchBeatmapSetsRequest(currentQuery.Value ?? string.Empty, ((FilterControl)Filter).Ruleset.Value, From 206f913a4c102a0a9e6fbc966c7ae3fea810ac3e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 22 Jun 2018 13:31:32 +0900 Subject: [PATCH 281/306] Make mute button not handle hover --- osu.Game/Overlays/Volume/MuteButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Volume/MuteButton.cs b/osu.Game/Overlays/Volume/MuteButton.cs index b62c639ee3..d0aa58e668 100644 --- a/osu.Game/Overlays/Volume/MuteButton.cs +++ b/osu.Game/Overlays/Volume/MuteButton.cs @@ -66,7 +66,7 @@ namespace osu.Game.Overlays.Volume protected override bool OnHover(InputState state) { this.TransformTo("BorderColour", hoveredColour, 500, Easing.OutQuint); - return true; + return false; } protected override void OnHoverLost(InputState state) From 72aee8344e5d1795d1700dce26ac7ef9ce841ef3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 22 Jun 2018 13:32:00 +0900 Subject: [PATCH 282/306] Always call schedulePopOut --- osu.Game/Overlays/VolumeOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index 24afa414d6..6a55dbad26 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -152,7 +152,7 @@ namespace osu.Game.Overlays protected override bool OnHover(InputState state) { - Show(); + schedulePopOut(); return true; } From 67a067ffa51f7b9d873172b1d19b82652d79bd45 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 22 Jun 2018 13:32:19 +0900 Subject: [PATCH 283/306] Fix overlay not disappearing when losing hover from the last pixel OnMouseMove isn't invoked when hover is lost. --- osu.Game/Overlays/VolumeOverlay.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index 6a55dbad26..1c9c615bbb 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -156,6 +156,12 @@ namespace osu.Game.Overlays return true; } + protected override void OnHoverLost(InputState state) + { + schedulePopOut(); + base.OnHoverLost(state); + } + private void schedulePopOut() { popOutDelegate?.Cancel(); From 0b5bfea9f4b28890e04960df6d9df3596ee844fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Jun 2018 16:49:47 +0900 Subject: [PATCH 284/306] Add a simple Pull Request template --- .github/pull_request_template.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..221e4746cb --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,8 @@ +Add any details pertaining to developers above the break. + +- [ ] Depends on #PR +- Closes #ISSUE + +--- + +Add a sentence or two describing this change in plain english. This will be displayed on the [changelog](https://osu.ppy.sh/home/changelog). A single screenshot or short gif is also welcomed. \ No newline at end of file From 78ccbcabf36b0f6ee2ecb40dcc3230482dd3b504 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Jun 2018 17:34:29 +0900 Subject: [PATCH 285/306] Fix API getting stuck in an endless loop under a certain unauthorized scenario --- osu.Game/Online/API/APIAccess.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 8c5fc58878..c7ba2d4a11 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -148,7 +148,7 @@ namespace osu.Game.Online.API // The Success callback event is fired on the main thread, so we should wait for that to run before proceeding. // Without this, we will end up circulating this Connecting loop multiple times and queueing up many web requests // before actually going online. - while (State != APIState.Online) + while (State > APIState.Offline) Thread.Sleep(500); break; @@ -158,7 +158,6 @@ namespace osu.Game.Online.API if (authentication.RequestAccessToken() == null) { Logout(false); - State = APIState.Offline; continue; } @@ -208,6 +207,14 @@ namespace osu.Game.Online.API { HttpStatusCode statusCode = (we.Response as HttpWebResponse)?.StatusCode ?? (we.Status == WebExceptionStatus.UnknownError ? HttpStatusCode.NotAcceptable : HttpStatusCode.RequestTimeout); + // special cases for un-typed but useful message responses. + switch (we.Message) + { + case "Unauthorized": + statusCode = HttpStatusCode.Unauthorized; + break; + } + switch (statusCode) { case HttpStatusCode.Unauthorized: @@ -292,6 +299,7 @@ namespace osu.Game.Online.API password = null; authentication.Clear(); LocalUser.Value = createGuestUser(); + State = APIState.Offline; } private static User createGuestUser() => new User From d6084c0b30abbe8fe536ba32bfdf6dddcc7ccb78 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 11 Jun 2018 23:00:26 +0900 Subject: [PATCH 286/306] Adapt to new input handling changes --- osu.Desktop/OsuGameDesktop.cs | 2 +- .../Replays/CatchFramedReplayInputHandler.cs | 6 +-- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 3 +- .../Replays/ManiaFramedReplayInputHandler.cs | 2 +- .../Replays/OsuReplayInputHandler.cs | 9 +++-- .../Replays/TaikoFramedReplayInputHandler.cs | 2 +- osu.Game/Input/Handlers/ReplayInputHandler.cs | 8 ++-- .../Replays/FramedReplayInputHandler.cs | 5 ++- osu.Game/Rulesets/UI/RulesetInputManager.cs | 38 +++++++++++++++---- osu.Game/Screens/Play/HUD/QuitButton.cs | 5 ++- osu.Game/Tests/Platform/TestStorage.cs | 2 +- .../Visual/ManualInputManagerTestCase.cs | 2 +- osu.Game/osu.Game.csproj | 2 +- 13 files changed, 57 insertions(+), 29 deletions(-) diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index 844db4a80f..64adcecba4 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -73,7 +73,7 @@ namespace osu.Desktop } public StableStorage() - : base(string.Empty) + : base(string.Empty, null) { } } diff --git a/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs b/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs index 6a9d1bdbc7..8d3d898655 100644 --- a/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs +++ b/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs @@ -28,9 +28,9 @@ namespace osu.Game.Rulesets.Catch.Replays } } - public override List GetPendingStates() + public override List GetPendingInputs() { - if (!Position.HasValue) return new List(); + if (!Position.HasValue) return new List(); var actions = new List(); @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Catch.Replays else if (Position.Value < CurrentFrame.Position) actions.Add(CatchAction.MoveLeft); - return new List + return new List { new CatchReplayState { diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 3b4a7b13e7..30f4979255 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -16,6 +16,7 @@ using osu.Game.Rulesets.Catch.Objects.Drawable; using osu.Game.Rulesets.Catch.Replays; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI; using OpenTK; using OpenTK.Graphics; @@ -93,7 +94,7 @@ namespace osu.Game.Rulesets.Catch.UI { base.UpdateAfterChildren(); - var state = GetContainingInputManager().CurrentState as CatchFramedReplayInputHandler.CatchReplayState; + var state = (GetContainingInputManager().CurrentState as RulesetInputManagerInputState)?.LastReplayState as CatchFramedReplayInputHandler.CatchReplayState; if (state?.CatcherX != null) MovableCatcher.X = state.CatcherX.Value; diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs b/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs index c71db745e0..29eeb1cab5 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs @@ -17,6 +17,6 @@ namespace osu.Game.Rulesets.Mania.Replays protected override bool IsImportant(ManiaReplayFrame frame) => frame.Actions.Any(); - public override List GetPendingStates() => new List { new ReplayState { PressedActions = CurrentFrame.Actions } }; + public override List GetPendingInputs() => new List { new ReplayState { PressedActions = CurrentFrame.Actions } }; } } diff --git a/osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs b/osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs index f9e5bfa89b..2eed41d13f 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs @@ -30,13 +30,16 @@ namespace osu.Game.Rulesets.Osu.Replays } } - public override List GetPendingStates() + public override List GetPendingInputs() { - return new List + return new List { + new MousePositionAbsoluteInput + { + Position = GamefieldToScreenSpace(Position ?? Vector2.Zero) + }, new ReplayState { - Mouse = new ReplayMouseState(GamefieldToScreenSpace(Position ?? Vector2.Zero)), PressedActions = CurrentFrame.Actions } }; diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs index 6ccbd575e5..eae033401e 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs @@ -17,6 +17,6 @@ namespace osu.Game.Rulesets.Taiko.Replays protected override bool IsImportant(TaikoReplayFrame frame) => frame.Actions.Any(); - public override List GetPendingStates() => new List { new ReplayState { PressedActions = CurrentFrame.Actions } }; + public override List GetPendingInputs() => new List { new ReplayState { PressedActions = CurrentFrame.Actions } }; } } diff --git a/osu.Game/Input/Handlers/ReplayInputHandler.cs b/osu.Game/Input/Handlers/ReplayInputHandler.cs index 5454dd0c9f..57a2e5df6d 100644 --- a/osu.Game/Input/Handlers/ReplayInputHandler.cs +++ b/osu.Game/Input/Handlers/ReplayInputHandler.cs @@ -32,16 +32,14 @@ namespace osu.Game.Input.Handlers public override int Priority => 0; - public class ReplayState : InputState + public class ReplayState : IInput where T : struct { public List PressedActions; - public override InputState Clone() + public void Apply(InputState state, IInputStateChangeHandler handler) { - var clone = (ReplayState)base.Clone(); - clone.PressedActions = new List(PressedActions); - return clone; + handler.HandleCustomInput(state, this); } } } diff --git a/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs b/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs index 0f5490a182..f13d96b35e 100644 --- a/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs +++ b/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs @@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Replays return true; } - public override List GetPendingStates() => new List(); + public override List GetPendingInputs() => new List(); public bool AtLastFrame => currentFrameIndex == Frames.Count - 1; public bool AtFirstFrame => currentFrameIndex == 0; @@ -119,7 +119,8 @@ namespace osu.Game.Rulesets.Replays { public ReplayKeyboardState(List keys) { - Keys = keys; + foreach (var key in keys) + Keys.Add(key); } } } diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 58a66a5224..f8c4fff5b8 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -15,6 +15,7 @@ using osu.Game.Input.Bindings; using osu.Game.Input.Handlers; using osu.Game.Screens.Play; using OpenTK.Input; +using static osu.Game.Input.Handlers.ReplayInputHandler; namespace osu.Game.Rulesets.UI { @@ -29,6 +30,18 @@ namespace osu.Game.Rulesets.UI } } + protected override InputState CreateInitialState() + { + var state = base.CreateInitialState(); + return new RulesetInputManagerInputState + { + Mouse = state.Mouse, + Keyboard = state.Keyboard, + Joystick = state.Joystick, + LastReplayState = null + }; + } + protected readonly KeyBindingContainer KeyBindingContainer; protected override Container Content => KeyBindingContainer; @@ -42,13 +55,18 @@ namespace osu.Game.Rulesets.UI private List lastPressedActions = new List(); - protected override void HandleNewState(InputState state) + public override void HandleCustomInput(InputState state, IInput input) { - base.HandleNewState(state); + if (!(input is ReplayState replayState)) + { + base.HandleCustomInput(state, input); + return; + } - var replayState = state as ReplayInputHandler.ReplayState; - - if (replayState == null) return; + if (state is RulesetInputManagerInputState inputState) + { + inputState.LastReplayState = replayState; + } // Here we handle states specifically coming from a replay source. // These have extra action information rather than keyboard keys or mouse buttons. @@ -80,7 +98,7 @@ namespace osu.Game.Rulesets.UI if (replayInputHandler != null) RemoveHandler(replayInputHandler); replayInputHandler = value; - UseParentState = replayInputHandler == null; + UseParentInput = replayInputHandler == null; if (replayInputHandler != null) AddHandler(replayInputHandler); @@ -123,7 +141,7 @@ namespace osu.Game.Rulesets.UI protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState; - private bool isAttached => replayInputHandler != null && !UseParentState; + private bool isAttached => replayInputHandler != null && !UseParentInput; private const int max_catch_up_updates_per_frame = 50; @@ -267,4 +285,10 @@ namespace osu.Game.Rulesets.UI { void Attach(KeyCounterCollection keyCounter); } + + public class RulesetInputManagerInputState : InputState + where T : struct + { + public ReplayState LastReplayState; + } } diff --git a/osu.Game/Screens/Play/HUD/QuitButton.cs b/osu.Game/Screens/Play/HUD/QuitButton.cs index d0aa0dad92..29382c25f3 100644 --- a/osu.Game/Screens/Play/HUD/QuitButton.cs +++ b/osu.Game/Screens/Play/HUD/QuitButton.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -182,14 +183,14 @@ namespace osu.Game.Screens.Play.HUD protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { - if (!pendingAnimation && state.Mouse.Buttons.Count == 1) + if (!pendingAnimation && state.Mouse.Buttons.Count() == 1) BeginConfirm(); return true; } protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) { - if (state.Mouse.Buttons.Count == 0) + if (!state.Mouse.Buttons.Any()) AbortConfirm(); return true; } diff --git a/osu.Game/Tests/Platform/TestStorage.cs b/osu.Game/Tests/Platform/TestStorage.cs index 883aae2184..5b31c7b4d0 100644 --- a/osu.Game/Tests/Platform/TestStorage.cs +++ b/osu.Game/Tests/Platform/TestStorage.cs @@ -7,7 +7,7 @@ namespace osu.Game.Tests.Platform { public class TestStorage : DesktopStorage { - public TestStorage(string baseName) : base(baseName) + public TestStorage(string baseName) : base(baseName, null) { } diff --git a/osu.Game/Tests/Visual/ManualInputManagerTestCase.cs b/osu.Game/Tests/Visual/ManualInputManagerTestCase.cs index 132a655c15..01676ad56e 100644 --- a/osu.Game/Tests/Visual/ManualInputManagerTestCase.cs +++ b/osu.Game/Tests/Visual/ManualInputManagerTestCase.cs @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual /// protected void ReturnUserInput() { - AddStep("Return user input", () => InputManager.UseParentState = true); + AddStep("Return user input", () => InputManager.UseParentInput = true); } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index f0bc330994..9cc538f70f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From 09b2025fad5ebfb9723965ef2e0c89b7bb177a00 Mon Sep 17 00:00:00 2001 From: nl-tatatat Date: Sun, 24 Jun 2018 04:48:38 -0500 Subject: [PATCH 287/306] Update TaikoRulesetContainer.cs Remove code that I am almost 100% sure that makes barlines every 1/1 instead of 4/1. --- osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index 313c205981..abcd763aba 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -70,8 +70,6 @@ namespace osu.Game.Rulesets.Taiko.UI Playfield.Add(isMajor ? new DrawableBarLineMajor(barLine) : new DrawableBarLine(barLine)); double bl = currentPoint.BeatLength; - if (bl < 800) - bl *= (int)currentPoint.TimeSignature; time += bl; currentBeat++; From 55364af56c9143142ed110c1662762a605ce8a4a Mon Sep 17 00:00:00 2001 From: Jean-Denis Boivin Date: Sun, 24 Jun 2018 14:55:27 -0400 Subject: [PATCH 288/306] I guess you meant an "or" ? --- .../Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index f60958d581..c6fa465a0f 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -329,7 +329,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy break; } - bool isDoubleSample(SampleInfo sample) => sample.Name == SampleInfo.HIT_CLAP && sample.Name == SampleInfo.HIT_FINISH; + bool isDoubleSample(SampleInfo sample) => sample.Name == SampleInfo.HIT_CLAP || sample.Name == SampleInfo.HIT_FINISH; bool canGenerateTwoNotes = (convertType & PatternType.LowProbability) == 0; canGenerateTwoNotes &= HitObject.Samples.Any(isDoubleSample) || sampleInfoListAt(HitObject.StartTime).Any(isDoubleSample); From b0cd227e810da959ec7abf834d173425218e8b19 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Jun 2018 14:05:29 +0900 Subject: [PATCH 289/306] Fix race condition in TestCaseLounge (attempt 2) --- osu.Game.Tests/Visual/TestCaseLounge.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseLounge.cs b/osu.Game.Tests/Visual/TestCaseLounge.cs index 59cf59bb52..174873b011 100644 --- a/osu.Game.Tests/Visual/TestCaseLounge.cs +++ b/osu.Game.Tests/Visual/TestCaseLounge.cs @@ -167,7 +167,7 @@ namespace osu.Game.Tests.Visual AddStep(@"set rooms", () => lounge.Rooms = rooms); selectAssert(1); AddStep(@"open room 1", () => clickRoom(1)); - AddUntilStep(() => !lounge.IsCurrentScreen, "wait until room current"); + AddUntilStep(() => lounge.ChildScreen?.IsCurrentScreen == true, "wait until room current"); AddStep(@"make lounge current", lounge.MakeCurrent); filterAssert(@"THE FINAL", LoungeTab.Public, 1); filterAssert(string.Empty, LoungeTab.Public, 2); From 70e9f7cb8d38a8a64f7ae418dbbba9c09b460fad Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Jun 2018 15:55:09 +0900 Subject: [PATCH 290/306] Always proxy taiko hits when hit --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 519b56a3ed..d3f050df6f 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -95,8 +95,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables break; case ArmedState.Hit: // If we're far enough away from the left stage, we should bring outselves in front of it - if (X >= -0.05f) - ProxyContent(); + ProxyContent(); var flash = circlePiece?.FlashBox; if (flash != null) From 185789bc7f3d8c6a6e3683f2e2226de5c39e0fb0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Jun 2018 16:13:15 +0900 Subject: [PATCH 291/306] Remove unused variable --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index b2f7de4ef2..408b37e377 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -33,8 +33,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private readonly CircularContainer targetRing; private readonly CircularContainer expandingRing; - private bool hasStarted; - private readonly SwellSymbolPiece symbol; public DrawableSwell(Swell swell) From d7133f059d3d3a537769dedbb739da268b15d078 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Jun 2018 16:53:12 +0900 Subject: [PATCH 292/306] Fix incorrect implementation --- osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index abcd763aba..999e33e51a 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -69,9 +69,7 @@ namespace osu.Game.Rulesets.Taiko.UI bool isMajor = currentBeat % (int)currentPoint.TimeSignature == 0; Playfield.Add(isMajor ? new DrawableBarLineMajor(barLine) : new DrawableBarLine(barLine)); - double bl = currentPoint.BeatLength; - - time += bl; + time += currentPoint.BeatLength * (int)currentPoint.TimeSignature; currentBeat++; } } From a3978278419d595388a0ce1a8df8be112be5a511 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Jun 2018 19:28:38 +0900 Subject: [PATCH 293/306] Reduce line length --- osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs index 6d6edff3f4..b5dfb0949a 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs @@ -55,7 +55,10 @@ namespace osu.Game.Rulesets.Mania.UI.Components direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(direction => { - hitTargetBar.Anchor = hitTargetBar.Origin = hitTargetLine.Anchor = hitTargetLine.Origin = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + Anchor anchor = direction == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + + hitTargetBar.Anchor = hitTargetBar.Origin = anchor; + hitTargetLine.Anchor = hitTargetLine.Origin = anchor; }, true); } From cd74ec705e020e02b9b5ea22a10354ddd4c4be44 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Jun 2018 20:31:06 +0900 Subject: [PATCH 294/306] Fix possible mis-ordering of scroll position updates 1. Checking whether the scroll position has changed must be done _after_ Current is updated in base.UpdateAfterChildren. This was causing the timeline to sometimes not provide smooth scrolling while the track is not running. 2. We can't just move all code to UpdateAfterChildren to fulfill (1) - we need the code to follow the track time to still run prior to base.UpdateAfterChildren, so that it modifies Current prior to base.UpdateAfterChildren changing to position. --- .../Edit/Screens/Compose/Timeline/Timeline.cs | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index d0c4afed98..e6a04bf1e7 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -88,21 +88,21 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline // The extrema of track time should be positioned at the centre of the container when scrolled to the start or end Content.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; - if (handlingDragInput) - { - // The user is dragging - the track should always follow the timeline - seekTrackToCurrent(); - } - else if (adjustableClock.IsRunning) - { - // If the user hasn't provided mouse input but the track is running, always follow the track + // This needs to happen after transforms are updated, but before the scroll position is updated in base.UpdateAfterChildren + if (adjustableClock.IsRunning) scrollToTrackTime(); - } - else + } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + if (handlingDragInput) + seekTrackToCurrent(); + else if (!adjustableClock.IsRunning) { - // The track isn't playing, so we want to smooth-scroll once more, and re-enable wheel scrolling - // There are two cases we have to be wary of: - // 1) The user scrolls on this timeline: We want the track to follow us + // The track isn't running. There are two cases we have to be wary of: + // 1) The user flick-drags on this timeline: We want the track to follow us // 2) The user changes the track time through some other means (scrolling in the editor or overview timeline): We want to follow the track time // The simplest way to cover both cases is by checking whether the scroll position has changed and the audio hasn't been changed externally @@ -114,25 +114,25 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline lastScrollPosition = Current; lastTrackTime = adjustableClock.CurrentTime; + } - void seekTrackToCurrent() - { - var track = Beatmap.Value.Track; - if (track is TrackVirtual || !track.IsLoaded) - return; + private void seekTrackToCurrent() + { + var track = Beatmap.Value.Track; + if (track is TrackVirtual || !track.IsLoaded) + return; - if (!(Beatmap.Value.Track is TrackVirtual)) - adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); - } + if (!(Beatmap.Value.Track is TrackVirtual)) + adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + } - void scrollToTrackTime() - { - var track = Beatmap.Value.Track; - if (track is TrackVirtual || !track.IsLoaded) - return; + private void scrollToTrackTime() + { + var track = Beatmap.Value.Track; + if (track is TrackVirtual || !track.IsLoaded) + return; - ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); - } + ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); } protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) From 563cb46b4aa38773348e8aed6f8367e578352eb3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Jun 2018 12:02:04 +0900 Subject: [PATCH 295/306] Update framework and other nuget dependencies --- osu.Desktop/osu.Desktop.csproj | 2 +- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 2 +- osu.Game/osu.Game.csproj | 10 +++++----- osu.TestProject.props | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 29d3b0e394..0289db20f0 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -29,7 +29,7 @@ - + diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index ffe1560627..6ba36a51d1 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -186,7 +186,7 @@ namespace osu.Game.Overlays.KeyBinding { if (bindTarget.IsHovered) { - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(state)); + bindTarget.UpdateKeyCombination(new KeyCombination(new[] { state.Mouse.ScrollDelta.Y > 0 ? InputKey.MouseWheelUp : InputKey.MouseWheelDown })); finalise(); return true; } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9cc538f70f..9668d40fd5 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -14,12 +14,12 @@ - - - + + + - - + + diff --git a/osu.TestProject.props b/osu.TestProject.props index 8f7128f8b7..c2e6048a60 100644 --- a/osu.TestProject.props +++ b/osu.TestProject.props @@ -11,7 +11,7 @@ - + From 96191fc3cefcebe4866eafbe78a296353d94efd5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Jun 2018 13:02:29 +0900 Subject: [PATCH 296/306] Move transition variable back to being local to function --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index b74d53eef0..24edcbfc98 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -268,8 +268,6 @@ namespace osu.Game.Rulesets.Catch.UI /// public bool HyperDashing => hyperDashModifier != 1; - private const float hyperdash_transition_length = 180; - /// /// Set hyperdash state. /// @@ -277,6 +275,8 @@ namespace osu.Game.Rulesets.Catch.UI /// When this catcher crosses this position, this catcher ends hyperdashing. public void SetHyperdashState(double modifier = 1, float targetPosition = -1) { + const float hyperdash_transition_length = 180; + bool previouslyHyperDashing = HyperDashing; if (modifier <= 1 || X == targetPosition) { From f1dfe04bd9ee23ceb3b763be6b5d08ccb59b0472 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 26 Jun 2018 20:13:44 +0900 Subject: [PATCH 297/306] Fix broken conditional --- osu.Game/Online/API/APIAccess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index c7ba2d4a11..12935a5ffe 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -148,7 +148,7 @@ namespace osu.Game.Online.API // The Success callback event is fired on the main thread, so we should wait for that to run before proceeding. // Without this, we will end up circulating this Connecting loop multiple times and queueing up many web requests // before actually going online. - while (State > APIState.Offline) + while (State > APIState.Offline && State < APIState.Online) Thread.Sleep(500); break; From 1a8aa6eab10d677a0622b111bbab5d796730b58e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Jun 2018 20:13:55 +0900 Subject: [PATCH 298/306] Fix regression causing new combos to once again not be respected --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs | 4 ++++ osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 7fa0d256da..8473f5a36c 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -30,7 +30,11 @@ namespace osu.Game.Rulesets.Catch.Beatmaps int index = 0; foreach (var obj in Beatmap.HitObjects.OfType()) + { obj.IndexInBeatmap = index++; + if (obj.LastInCombo && obj.NestedHitObjects.LastOrDefault() is IHasComboInformation lastNested) + lastNested.LastInCombo = true; + } } public const int RNG_SEED = 1337; diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index b2d8e3f8a5..6fe9692c26 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -42,7 +42,6 @@ namespace osu.Game.Rulesets.Catch.Objects protected override void CreateNestedHitObjects() { base.CreateNestedHitObjects(); - createTicks(); } @@ -124,9 +123,6 @@ namespace osu.Game.Rulesets.Catch.Objects X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH }); } - - if (NestedHitObjects.LastOrDefault() is IHasComboInformation lastNested) - lastNested.LastInCombo = LastInCombo; } public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity; From 8a81fba1ea6524adf58eaceb02e6d6aa2404e1ae Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 26 Jun 2018 20:34:22 +0900 Subject: [PATCH 299/306] Other input states need to be considered for wheel bindings --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 6ba36a51d1..a12f9dee7e 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -186,7 +186,7 @@ namespace osu.Game.Overlays.KeyBinding { if (bindTarget.IsHovered) { - bindTarget.UpdateKeyCombination(new KeyCombination(new[] { state.Mouse.ScrollDelta.Y > 0 ? InputKey.MouseWheelUp : InputKey.MouseWheelDown })); + bindTarget.UpdateKeyCombination(new KeyCombination(KeyCombination.FromInputState(state).Keys.Append(state.Mouse.ScrollDelta.Y > 0 ? InputKey.MouseWheelUp : InputKey.MouseWheelDown))); finalise(); return true; } From 80501de4b993e894ac48aa02eaa8f112c838cc5c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 22:20:34 +0900 Subject: [PATCH 300/306] Add legacy slider offsets --- .../Beatmaps/CatchBeatmapConverter.cs | 4 +++- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 9 +++++++++ .../Beatmaps/OsuBeatmapConverter.cs | 4 +++- osu.Game.Rulesets.Osu/Objects/Slider.cs | 10 ++++++++++ osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs | 4 +++- .../Objects/Types/IHasLegacyLastTickOffset.cs | 14 ++++++++++++++ 6 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 osu.Game/Rulesets/Objects/Types/IHasLegacyLastTickOffset.cs diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs index 46fe8454dc..68a8dfb7d3 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs @@ -26,6 +26,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps var positionData = obj as IHasXPosition; var comboData = obj as IHasCombo; var endTime = obj as IHasEndTime; + var legacyOffset = obj as IHasLegacyLastTickOffset; if (curveData != null) { @@ -39,7 +40,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps RepeatSamples = curveData.RepeatSamples, RepeatCount = curveData.RepeatCount, X = (positionData?.X ?? 0) / CatchPlayfield.BASE_WIDTH, - NewCombo = comboData?.NewCombo ?? false + NewCombo = comboData?.NewCombo ?? false, + LegacyLastTickOffset = legacyOffset?.LegacyLastTickOffset ?? 0 }; } else if (endTime != null) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 6fe9692c26..0344189af5 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -77,6 +77,13 @@ namespace osu.Game.Rulesets.Catch.Objects double time = spanStartTime + timeProgress * spanDuration; + if (LegacyLastTickOffset != null) + { + // If we're the last tick, apply the legacy offset + if (span == this.SpanCount() - 1 && d + tickDistance > length) + time = Math.Max(StartTime + Duration / 2, time - LegacyLastTickOffset.Value); + } + double tinyTickInterval = time - lastDropletTime; while (tinyTickInterval > 100) tinyTickInterval /= 2; @@ -152,5 +159,7 @@ namespace osu.Game.Rulesets.Catch.Objects get { return Curve.CurveType; } set { Curve.CurveType = value; } } + + public double? LegacyLastTickOffset { get; set; } } } diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index 80eb808f6e..405493cde4 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -27,6 +27,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps var endTimeData = original as IHasEndTime; var positionData = original as IHasPosition; var comboData = original as IHasCombo; + var legacyOffset = original as IHasLegacyLastTickOffset; if (curveData != null) { @@ -40,7 +41,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps RepeatSamples = curveData.RepeatSamples, RepeatCount = curveData.RepeatCount, Position = positionData?.Position ?? Vector2.Zero, - NewCombo = comboData?.NewCombo ?? false + NewCombo = comboData?.NewCombo ?? false, + LegacyLastTickOffset = legacyOffset?.LegacyLastTickOffset }; } else if (endTimeData != null) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 7f4407370f..d74c902f4c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using OpenTK; using osu.Game.Rulesets.Objects.Types; using System.Collections.Generic; @@ -45,6 +46,8 @@ namespace osu.Game.Rulesets.Osu.Objects set { Curve.Distance = value; } } + public double? LegacyLastTickOffset { get; set; } + /// /// The position of the cursor at the point of completion of this if it was hit /// with as few movements as possible. This is set and used by difficulty calculation. @@ -91,6 +94,13 @@ namespace osu.Game.Rulesets.Osu.Objects createSliderEnds(); createTicks(); createRepeatPoints(); + + if (LegacyLastTickOffset != null) + { + var lastObject = NestedHitObjects.Last(); + if (!(lastObject is SliderCircle)) + lastObject.StartTime = Math.Max(StartTime + Duration / 2, lastObject.StartTime - LegacyLastTickOffset.Value); + } } private void createSliderEnds() diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index 17848d1e6e..ef1eecec3d 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -10,7 +10,7 @@ using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Rulesets.Objects.Legacy { - internal abstract class ConvertSlider : HitObject, IHasCurve + internal abstract class ConvertSlider : HitObject, IHasCurve, IHasLegacyLastTickOffset { /// /// Scoring distance with a speed-adjusted beat length of 1 second. @@ -45,5 +45,7 @@ namespace osu.Game.Rulesets.Objects.Legacy Velocity = scoringDistance / timingPoint.BeatLength; } + + public double LegacyLastTickOffset => 36; } } diff --git a/osu.Game/Rulesets/Objects/Types/IHasLegacyLastTickOffset.cs b/osu.Game/Rulesets/Objects/Types/IHasLegacyLastTickOffset.cs new file mode 100644 index 0000000000..ab2573e933 --- /dev/null +++ b/osu.Game/Rulesets/Objects/Types/IHasLegacyLastTickOffset.cs @@ -0,0 +1,14 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Rulesets.Objects.Types +{ + /// + /// A type of which may require the last tick to be offset. + /// This is specific to osu!stable conversion, and should not be used elsewhere. + /// + public interface IHasLegacyLastTickOffset + { + double LegacyLastTickOffset { get; } + } +} From 8e4dd58e6893560040293925d962309caa91abca Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 22:23:19 +0900 Subject: [PATCH 301/306] Restore ignored unit tests --- osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs index 89e8361a72..e18a277cba 100644 --- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.Tests { protected override string ResourceAssembly => "osu.Game.Rulesets.Catch"; - [TestCase("basic"), Ignore("See: https://github.com/ppy/osu/issues/2232")] + [TestCase("basic")] [TestCase("spinner")] [TestCase("spinner-and-circles")] public new void Test(string name) From de3708ea3aaee6e631bfe0575d973958485fd7d3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 23:43:58 +0900 Subject: [PATCH 302/306] Public + explicitly define test fixtures --- osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs | 5 +++-- osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs | 5 +++-- osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs | 5 +++-- osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs index e18a277cba..4b95a6754e 100644 --- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs @@ -13,7 +13,8 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Rulesets.Catch.Tests { - internal class CatchBeatmapConversionTest : BeatmapConversionTest + [TestFixture] + public class CatchBeatmapConversionTest : BeatmapConversionTest { protected override string ResourceAssembly => "osu.Game.Rulesets.Catch"; @@ -44,7 +45,7 @@ namespace osu.Game.Rulesets.Catch.Tests protected override Ruleset CreateRuleset() => new CatchRuleset(); } - internal struct ConvertValue : IEquatable + public struct ConvertValue : IEquatable { /// /// A sane value to account for osu!stable using ints everwhere. diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs index 5ae899f6d6..73555dcecb 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs @@ -12,7 +12,8 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Rulesets.Mania.Tests { - internal class ManiaBeatmapConversionTest : BeatmapConversionTest + [TestFixture] + public class ManiaBeatmapConversionTest : BeatmapConversionTest { protected override string ResourceAssembly => "osu.Game.Rulesets.Mania"; @@ -36,7 +37,7 @@ namespace osu.Game.Rulesets.Mania.Tests protected override Ruleset CreateRuleset() => new ManiaRuleset(); } - internal struct ConvertValue : IEquatable + public struct ConvertValue : IEquatable { /// /// A sane value to account for osu!stable using ints everwhere. diff --git a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs index 386ae5eb05..228fcf020f 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs @@ -13,7 +13,8 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Tests { - internal class OsuBeatmapConversionTest : BeatmapConversionTest + [TestFixture] + public class OsuBeatmapConversionTest : BeatmapConversionTest { protected override string ResourceAssembly => "osu.Game.Rulesets.Osu"; @@ -43,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Tests protected override Ruleset CreateRuleset() => new OsuRuleset(); } - internal struct ConvertValue : IEquatable + public struct ConvertValue : IEquatable { /// /// A sane value to account for osu!stable using ints everwhere. diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs index 11586e340b..db8480c742 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs @@ -12,7 +12,8 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Rulesets.Taiko.Tests { - internal class TaikoBeatmapConversionTest : BeatmapConversionTest + [TestFixture] + public class TaikoBeatmapConversionTest : BeatmapConversionTest { protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko"; @@ -41,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Tests protected override Ruleset CreateRuleset() => new TaikoRuleset(); } - internal struct ConvertValue : IEquatable + public struct ConvertValue : IEquatable { /// /// A sane value to account for osu!stable using ints everwhere. From 0366b0f081700640209d6eb927d6bf4e97e9043d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 23:46:43 +0900 Subject: [PATCH 303/306] The tail circle will always be the last hitobject --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index d74c902f4c..2ebe5efd0f 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -96,11 +96,7 @@ namespace osu.Game.Rulesets.Osu.Objects createRepeatPoints(); if (LegacyLastTickOffset != null) - { - var lastObject = NestedHitObjects.Last(); - if (!(lastObject is SliderCircle)) - lastObject.StartTime = Math.Max(StartTime + Duration / 2, lastObject.StartTime - LegacyLastTickOffset.Value); - } + TailCircle.StartTime = Math.Max(StartTime + Duration / 2, TailCircle.StartTime - LegacyLastTickOffset.Value); } private void createSliderEnds() From 6f65ad33f06e769ea72e3b25e7a5676a699bb1c3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 01:27:33 +0900 Subject: [PATCH 304/306] Output one value per slider nested hitobject --- .../OsuBeatmapConversionTest.cs | 41 +- .../Beatmaps/basic-expected-conversion.json | 374 ++++++++++++------ ...ear-perfect-curve-expected-conversion.json | 23 +- 3 files changed, 287 insertions(+), 151 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs index 228fcf020f..4139685eaa 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs @@ -9,7 +9,6 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Tests.Beatmaps; -using OpenTK; namespace osu.Game.Rulesets.Osu.Tests { @@ -27,17 +26,23 @@ namespace osu.Game.Rulesets.Osu.Tests protected override IEnumerable CreateConvertValue(HitObject hitObject) { - var startPosition = (hitObject as IHasPosition)?.Position ?? new Vector2(256, 192); - var endPosition = (hitObject as Slider)?.EndPosition ?? startPosition; - - yield return new ConvertValue + switch (hitObject) { - StartTime = hitObject.StartTime, - EndTime = (hitObject as IHasEndTime)?.EndTime ?? hitObject.StartTime, - StartX = startPosition.X, - StartY = startPosition.Y, - EndX = endPosition.X, - EndY = endPosition.Y + case Slider slider: + foreach (var nested in slider.NestedHitObjects) + yield return createConvertValue(nested); + break; + default: + yield return createConvertValue(hitObject); + break; + } + + ConvertValue createConvertValue(HitObject obj) => new ConvertValue + { + StartTime = obj.StartTime, + EndTime = (obj as IHasEndTime)?.EndTime ?? obj.StartTime, + X = (obj as IHasPosition)?.X ?? 256, + Y = (obj as IHasPosition)?.Y ?? 192, }; } @@ -53,17 +58,13 @@ namespace osu.Game.Rulesets.Osu.Tests public double StartTime; public double EndTime; - public float StartX; - public float StartY; - public float EndX; - public float EndY; + public float X; + public float Y; public bool Equals(ConvertValue other) - => Precision.AlmostEquals(StartTime, other.StartTime) + => Precision.AlmostEquals(StartTime, other.StartTime, conversion_lenience) && Precision.AlmostEquals(EndTime, other.EndTime, conversion_lenience) - && Precision.AlmostEquals(StartX, other.StartX) - && Precision.AlmostEquals(StartY, other.StartY, conversion_lenience) - && Precision.AlmostEquals(EndX, other.EndX, conversion_lenience) - && Precision.AlmostEquals(EndY, other.EndY, conversion_lenience); + && Precision.AlmostEquals(X, other.X, conversion_lenience) + && Precision.AlmostEquals(Y, other.Y, conversion_lenience); } } diff --git a/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/basic-expected-conversion.json b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/basic-expected-conversion.json index b82fddbe79..491adc2b50 100644 --- a/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/basic-expected-conversion.json +++ b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/basic-expected-conversion.json @@ -1,124 +1,256 @@ { "Mappings": [{ - "StartTime": 500, - "Objects": [{ - "StartTime": 500, - "EndTime": 2500, - "StartX": 96, - "StartY": 192, - "EndX": 96, - "EndY": 192 - }] - }, - { - "StartTime": 3000, - "Objects": [{ - "StartTime": 3000, - "EndTime": 4000, - "StartX": 256, - "StartY": 192, - "EndX": 256, - "EndY": 192 - }] - }, - { - "StartTime": 4500, - "Objects": [{ - "StartTime": 4500, - "EndTime": 5500, - "StartX": 256, - "StartY": 192, - "EndX": 256, - "EndY": 192 - }] - }, - { - "StartTime": 6000, - "Objects": [{ - "StartTime": 6000, - "EndTime": 6500, - "StartX": 256, - "StartY": 192, - "EndX": 256, - "EndY": 192 - }] - }, - { - "StartTime": 7000, - "Objects": [{ - "StartTime": 7000, - "EndTime": 8000, - "StartX": 256, - "StartY": 128, - "EndX": 256, - "EndY": 128 - }] - }, - { - "StartTime": 8500, - "Objects": [{ - "StartTime": 8500, - "EndTime": 10999, - "StartX": 32, - "StartY": 192, - "EndX": 508.166229, - "EndY": 153.299271 - }] - }, - { - "StartTime": 11500, - "Objects": [{ - "StartTime": 11500, - "EndTime": 12000, - "StartX": 256, - "StartY": 192, - "EndX": 256, - "EndY": 192 - }] - }, - { - "StartTime": 12500, - "Objects": [{ - "StartTime": 12500, - "EndTime": 16500, - "StartX": 512, - "StartY": 320, - "EndX": 291.1977, - "EndY": 40.799427 - }] - }, - { - "StartTime": 17000, - "Objects": [{ - "StartTime": 17000, - "EndTime": 18000, - "StartX": 256, - "StartY": 256, - "EndX": 256, - "EndY": 256 - }] - }, - { - "StartTime": 18500, - "Objects": [{ - "StartTime": 18500, - "EndTime": 19450, - "StartX": 256, - "StartY": 192, - "EndX": 256, - "EndY": 192 - }] - }, - { - "StartTime": 19875, - "Objects": [{ - "StartTime": 19875, - "EndTime": 23874, - "StartX": 216, - "StartY": 231, - "EndX": 408.720825, - "EndY": 339.810455 - }] - } - ] + "StartTime": 500.0, + "Objects": [{ + "StartTime": 500.0, + "EndTime": 500.0, + "X": 96.0, + "Y": 192.0 + }, { + "StartTime": 1000.0, + "EndTime": 1000.0, + "X": 256.0, + "Y": 192.0 + }, { + "StartTime": 1500.0, + "EndTime": 1500.0, + "X": 416.0, + "Y": 192.0 + }, { + "StartTime": 2000.0, + "EndTime": 2000.0, + "X": 256.0, + "Y": 192.0 + }, { + "StartTime": 2464.0, + "EndTime": 2464.0, + "X": 96.0, + "Y": 192.0 + }] + }, { + "StartTime": 3000.0, + "Objects": [{ + "StartTime": 3000.0, + "EndTime": 4000.0, + "X": 256.0, + "Y": 192.0 + }] + }, { + "StartTime": 4500.0, + "Objects": [{ + "StartTime": 4500.0, + "EndTime": 5500.0, + "X": 256.0, + "Y": 192.0 + }] + }, { + "StartTime": 6000.0, + "Objects": [{ + "StartTime": 6000.0, + "EndTime": 6500.0, + "X": 256.0, + "Y": 192.0 + }] + }, { + "StartTime": 7000.0, + "Objects": [{ + "StartTime": 7000.0, + "EndTime": 7000.0, + "X": 256.0, + "Y": 128.0 + }, { + "StartTime": 7250.0, + "EndTime": 7250.0, + "X": 336.0, + "Y": 128.0 + }, { + "StartTime": 7500.0, + "EndTime": 7500.0, + "X": 256.0, + "Y": 128.0 + }, { + "StartTime": 7750.0, + "EndTime": 7750.0, + "X": 336.0, + "Y": 128.0 + }, { + "StartTime": 7964.0, + "EndTime": 7964.0, + "X": 256.0, + "Y": 128.0 + }] + }, { + "StartTime": 8500.0, + "Objects": [{ + "StartTime": 8500.0, + "EndTime": 8500.0, + "X": 32.0, + "Y": 192.0 + }, { + "StartTime": 9000.0, + "EndTime": 9000.0, + "X": 101.81015, + "Y": 326.4915 + }, { + "StartTime": 9500.0, + "EndTime": 9500.0, + "X": 237.2304, + "Y": 276.282928 + }, { + "StartTime": 10000.0, + "EndTime": 10000.0, + "X": 270.339874, + "Y": 121.1423 + }, { + "StartTime": 10500.0, + "EndTime": 10500.0, + "X": 401.0588, + "Y": 49.1515045 + }, { + "StartTime": 10964.0, + "EndTime": 10964.0, + "X": 508.166229, + "Y": 153.299271 + }] + }, { + "StartTime": 11500.0, + "Objects": [{ + "StartTime": 11500.0, + "EndTime": 12000.0, + "X": 256.0, + "Y": 192.0 + }] + }, { + "StartTime": 12500.0, + "Objects": [{ + "StartTime": 12500.0, + "EndTime": 12500.0, + "X": 512.0, + "Y": 320.0 + }, { + "StartTime": 13000.0, + "EndTime": 13000.0, + "X": 353.235535, + "Y": 300.154449 + }, { + "StartTime": 13500.0, + "EndTime": 13500.0, + "X": 194.471069, + "Y": 280.3089 + }, { + "StartTime": 14000.0, + "EndTime": 14000.0, + "X": 35.7066345, + "Y": 260.463318 + }, { + "StartTime": 14500.0, + "EndTime": 14500.0, + "X": 118.370323, + "Y": 219.009277 + }, { + "StartTime": 15000.0, + "EndTime": 15000.0, + "X": 271.087128, + "Y": 171.285278 + }, { + "StartTime": 15500.0, + "EndTime": 15500.0, + "X": 423.803925, + "Y": 123.561279 + }, { + "StartTime": 16000.0, + "EndTime": 16000.0, + "X": 446.420532, + "Y": 79.60513 + }, { + "StartTime": 16464.0, + "EndTime": 16464.0, + "X": 291.1977, + "Y": 40.799427 + }] + }, { + "StartTime": 17000.0, + "Objects": [{ + "StartTime": 17000.0, + "EndTime": 17000.0, + "X": 256.0, + "Y": 256.0 + }, { + "StartTime": 17250.0, + "EndTime": 17250.0, + "X": 176.0, + "Y": 256.0 + }, { + "StartTime": 17500.0, + "EndTime": 17500.0, + "X": 256.0, + "Y": 256.0 + }, { + "StartTime": 17750.0, + "EndTime": 17750.0, + "X": 176.0, + "Y": 256.0 + }, { + "StartTime": 17964.0, + "EndTime": 17964.0, + "X": 256.0, + "Y": 256.0 + }] + }, { + "StartTime": 18500.0, + "Objects": [{ + "StartTime": 18500.0, + "EndTime": 19450.0, + "X": 256.0, + "Y": 192.0 + }] + }, { + "StartTime": 19875.0, + "Objects": [{ + "StartTime": 19875.0, + "EndTime": 19875.0, + "X": 216.0, + "Y": 231.0 + }, { + "StartTime": 20375.0, + "EndTime": 20375.0, + "X": 317.446747, + "Y": 171.345245 + }, { + "StartTime": 20875.0, + "EndTime": 20875.0, + "X": 270.3294, + "Y": 310.4395 + }, { + "StartTime": 21375.0, + "EndTime": 21375.0, + "X": 119.121056, + "Y": 322.8657 + }, { + "StartTime": 21875.0, + "EndTime": 21875.0, + "X": 124.28746, + "Y": 165.224731 + }, { + "StartTime": 22375.0, + "EndTime": 22375.0, + "X": 240.4715, + "Y": 62.65587 + }, { + "StartTime": 22875.0, + "EndTime": 22875.0, + "X": 398.054047, + "Y": 39.064167 + }, { + "StartTime": 23375.0, + "EndTime": 23375.0, + "X": 439.749878, + "Y": 183.668091 + }, { + "StartTime": 23839.0, + "EndTime": 23839.0, + "X": 408.720825, + "Y": 339.810455 + }] + }] } \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/colinear-perfect-curve-expected-conversion.json b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/colinear-perfect-curve-expected-conversion.json index 7fe038658c..96e4bf1637 100644 --- a/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/colinear-perfect-curve-expected-conversion.json +++ b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/colinear-perfect-curve-expected-conversion.json @@ -1,13 +1,16 @@ { - "Mappings": [{ - "StartTime": 118858, - "Objects": [{ - "StartTime": 118858, - "EndTime": 119088, - "StartX": 219, - "StartY": 215, - "EndX": 239.6507, - "EndY": 29.1437378 + "Mappings": [{ + "StartTime": 118858.0, + "Objects": [{ + "StartTime": 118858.0, + "EndTime": 118858.0, + "X": 219.0, + "Y": 215.0 + }, { + "StartTime": 119052.0, + "EndTime": 119052.0, + "X": 239.6507, + "Y": 29.1437378 + }] }] - }] } \ No newline at end of file From 0e6cc78d9aef5b5c5db2297baed14fe8bd944aae Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 01:28:28 +0900 Subject: [PATCH 305/306] Add slider ticks conversion test --- .../OsuBeatmapConversionTest.cs | 1 + .../slider-ticks-expected-conversion.json | 331 ++++++++++++++++++ .../Testing/Beatmaps/slider-ticks.osu | 20 ++ 3 files changed, 352 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks-expected-conversion.json create mode 100644 osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks.osu diff --git a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs index 4139685eaa..0bcf105575 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs @@ -19,6 +19,7 @@ namespace osu.Game.Rulesets.Osu.Tests [TestCase("basic")] [TestCase("colinear-perfect-curve")] + [TestCase("slider-ticks")] public new void Test(string name) { base.Test(name); diff --git a/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks-expected-conversion.json b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks-expected-conversion.json new file mode 100644 index 0000000000..9c049c7cd6 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks-expected-conversion.json @@ -0,0 +1,331 @@ +{ + "Mappings": [{ + "StartTime": 500.0, + "Objects": [{ + "StartTime": 500.0, + "EndTime": 500.0, + "X": 96.0, + "Y": 192.0 + }, { + "StartTime": 624.0, + "EndTime": 624.0, + "X": 105.921242, + "Y": 192.0 + }, { + "StartTime": 749.0, + "EndTime": 749.0, + "X": 115.922493, + "Y": 192.0 + }, { + "StartTime": 874.0, + "EndTime": 874.0, + "X": 125.923737, + "Y": 192.0 + }, { + "StartTime": 999.0, + "EndTime": 999.0, + "X": 135.924988, + "Y": 192.0 + }, { + "StartTime": 1124.0, + "EndTime": 1124.0, + "X": 145.926239, + "Y": 192.0 + }, { + "StartTime": 1249.0, + "EndTime": 1249.0, + "X": 155.92749, + "Y": 192.0 + }, { + "StartTime": 1374.0, + "EndTime": 1374.0, + "X": 165.928741, + "Y": 192.0 + }, { + "StartTime": 1499.0, + "EndTime": 1499.0, + "X": 175.93, + "Y": 192.0 + }, { + "StartTime": 1624.0, + "EndTime": 1624.0, + "X": 185.931244, + "Y": 192.0 + }, { + "StartTime": 1749.0, + "EndTime": 1749.0, + "X": 195.9325, + "Y": 192.0 + }, { + "StartTime": 1874.0, + "EndTime": 1874.0, + "X": 205.933746, + "Y": 192.0 + }, { + "StartTime": 1999.0, + "EndTime": 1999.0, + "X": 215.935, + "Y": 192.0 + }, { + "StartTime": 2124.0, + "EndTime": 2124.0, + "X": 225.936234, + "Y": 192.0 + }, { + "StartTime": 2249.0, + "EndTime": 2249.0, + "X": 235.9375, + "Y": 192.0 + }, { + "StartTime": 2374.0, + "EndTime": 2374.0, + "X": 245.938751, + "Y": 192.0 + }, { + "StartTime": 2499.0, + "EndTime": 2499.0, + "X": 255.94, + "Y": 192.0 + }, { + "StartTime": 2624.0, + "EndTime": 2624.0, + "X": 265.941223, + "Y": 192.0 + }, { + "StartTime": 2749.0, + "EndTime": 2749.0, + "X": 275.9425, + "Y": 192.0 + }, { + "StartTime": 2874.0, + "EndTime": 2874.0, + "X": 285.943756, + "Y": 192.0 + }, { + "StartTime": 2999.0, + "EndTime": 2999.0, + "X": 295.945, + "Y": 192.0 + }, { + "StartTime": 3124.0, + "EndTime": 3124.0, + "X": 305.946259, + "Y": 192.0 + }, { + "StartTime": 3249.0, + "EndTime": 3249.0, + "X": 315.9475, + "Y": 192.0 + }, { + "StartTime": 3374.0, + "EndTime": 3374.0, + "X": 325.94873, + "Y": 192.0 + }, { + "StartTime": 3499.0, + "EndTime": 3499.0, + "X": 335.949982, + "Y": 192.0 + }, { + "StartTime": 3624.0, + "EndTime": 3624.0, + "X": 345.951233, + "Y": 192.0 + }, { + "StartTime": 3749.0, + "EndTime": 3749.0, + "X": 355.952484, + "Y": 192.0 + }, { + "StartTime": 3874.0, + "EndTime": 3874.0, + "X": 365.953766, + "Y": 192.0 + }, { + "StartTime": 3999.0, + "EndTime": 3999.0, + "X": 375.955, + "Y": 192.0 + }, { + "StartTime": 4124.0, + "EndTime": 4124.0, + "X": 385.956238, + "Y": 192.0 + }, { + "StartTime": 4249.0, + "EndTime": 4249.0, + "X": 395.9575, + "Y": 192.0 + }, { + "StartTime": 4374.0, + "EndTime": 4374.0, + "X": 405.95874, + "Y": 192.0 + }, { + "StartTime": 4499.0, + "EndTime": 4499.0, + "X": 415.960022, + "Y": 192.0 + }, { + "StartTime": 4624.0, + "EndTime": 4624.0, + "X": 406.038757, + "Y": 192.0 + }, { + "StartTime": 4749.0, + "EndTime": 4749.0, + "X": 396.0375, + "Y": 192.0 + }, { + "StartTime": 4874.0, + "EndTime": 4874.0, + "X": 386.036255, + "Y": 192.0 + }, { + "StartTime": 4999.0, + "EndTime": 4999.0, + "X": 376.035034, + "Y": 192.0 + }, { + "StartTime": 5124.0, + "EndTime": 5124.0, + "X": 366.033752, + "Y": 192.0 + }, { + "StartTime": 5249.0, + "EndTime": 5249.0, + "X": 356.0325, + "Y": 192.0 + }, { + "StartTime": 5374.0, + "EndTime": 5374.0, + "X": 346.03125, + "Y": 192.0 + }, { + "StartTime": 5499.0, + "EndTime": 5499.0, + "X": 336.030029, + "Y": 192.0 + }, { + "StartTime": 5624.0, + "EndTime": 5624.0, + "X": 326.028748, + "Y": 192.0 + }, { + "StartTime": 5749.0, + "EndTime": 5749.0, + "X": 316.0275, + "Y": 192.0 + }, { + "StartTime": 5874.0, + "EndTime": 5874.0, + "X": 306.026245, + "Y": 192.0 + }, { + "StartTime": 5999.0, + "EndTime": 5999.0, + "X": 296.025, + "Y": 192.0 + }, { + "StartTime": 6124.0, + "EndTime": 6124.0, + "X": 286.023773, + "Y": 192.0 + }, { + "StartTime": 6249.0, + "EndTime": 6249.0, + "X": 276.022522, + "Y": 192.0 + }, { + "StartTime": 6374.0, + "EndTime": 6374.0, + "X": 266.02124, + "Y": 192.0 + }, { + "StartTime": 6499.0, + "EndTime": 6499.0, + "X": 256.02, + "Y": 192.0 + }, { + "StartTime": 6624.0, + "EndTime": 6624.0, + "X": 246.018768, + "Y": 192.0 + }, { + "StartTime": 6749.0, + "EndTime": 6749.0, + "X": 236.017517, + "Y": 192.0 + }, { + "StartTime": 6874.0, + "EndTime": 6874.0, + "X": 226.016251, + "Y": 192.0 + }, { + "StartTime": 6999.0, + "EndTime": 6999.0, + "X": 216.014984, + "Y": 192.0 + }, { + "StartTime": 7124.0, + "EndTime": 7124.0, + "X": 206.013733, + "Y": 192.0 + }, { + "StartTime": 7249.0, + "EndTime": 7249.0, + "X": 196.012512, + "Y": 192.0 + }, { + "StartTime": 7374.0, + "EndTime": 7374.0, + "X": 186.011261, + "Y": 192.0 + }, { + "StartTime": 7499.0, + "EndTime": 7499.0, + "X": 176.01, + "Y": 192.0 + }, { + "StartTime": 7624.0, + "EndTime": 7624.0, + "X": 166.008728, + "Y": 192.0 + }, { + "StartTime": 7749.0, + "EndTime": 7749.0, + "X": 156.0075, + "Y": 192.0 + }, { + "StartTime": 7874.0, + "EndTime": 7874.0, + "X": 146.006256, + "Y": 192.0 + }, { + "StartTime": 7999.0, + "EndTime": 7999.0, + "X": 136.005, + "Y": 192.0 + }, { + "StartTime": 8124.0, + "EndTime": 8124.0, + "X": 126.003738, + "Y": 192.0 + }, { + "StartTime": 8249.0, + "EndTime": 8249.0, + "X": 116.002518, + "Y": 192.0 + }, { + "StartTime": 8374.0, + "EndTime": 8374.0, + "X": 106.001259, + "Y": 192.0 + }, { + "StartTime": 8463.0, + "EndTime": 8463.0, + "X": 96.0, + "Y": 192.0 + }] + }] +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks.osu b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks.osu new file mode 100644 index 0000000000..fd835efbc8 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks.osu @@ -0,0 +1,20 @@ +osu file format v14 + +[General] +StackLeniency: 0.7 + +[Difficulty] +HPDrainRate:6 +CircleSize:4 +OverallDifficulty:7 +ApproachRate:8.3 +SliderMultiplier:0.400000005960464 +SliderTickRate:4 + +[TimingPoints] +500,500,4,2,1,50,1,0 +13426,-100,4,3,1,45,0,0 +14884,-100,4,2,1,50,0,0 + +[HitObjects] +96,192,500,6,0,L|416:192,2,320.000004768372 From 10220a61a59abf2c00a9c06d784a5faa0da53a06 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Jun 2018 12:18:00 +0900 Subject: [PATCH 306/306] Use playfield size constants where possible --- osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs | 5 +++-- osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs index 0bcf105575..3fa039d946 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs @@ -8,6 +8,7 @@ using osu.Framework.MathUtils; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.UI; using osu.Game.Tests.Beatmaps; namespace osu.Game.Rulesets.Osu.Tests @@ -42,8 +43,8 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = obj.StartTime, EndTime = (obj as IHasEndTime)?.EndTime ?? obj.StartTime, - X = (obj as IHasPosition)?.X ?? 256, - Y = (obj as IHasPosition)?.Y ?? 192, + X = (obj as IHasPosition)?.X ?? OsuPlayfield.BASE_SIZE.X / 2, + Y = (obj as IHasPosition)?.Y ?? OsuPlayfield.BASE_SIZE.Y / 2, }; } diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs index 324d0502c1..bb0bd891b3 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs @@ -6,6 +6,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Osu.Objects; using System; using System.Collections.Generic; +using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Replays; using osu.Game.Users; @@ -18,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Replays /// /// Constants (for spinners). /// - protected static readonly Vector2 SPINNER_CENTRE = new Vector2(256, 192); + protected static readonly Vector2 SPINNER_CENTRE = OsuPlayfield.BASE_SIZE / 2; protected const float SPIN_RADIUS = 50; ///