From 0801a211da226bcb7cc3f802cfcac829f984cdc6 Mon Sep 17 00:00:00 2001 From: ColdVolcano Date: Wed, 17 May 2017 01:14:04 -0500 Subject: [PATCH 001/112] Add a base container with beat syncing logic --- .../Containers/BeatSyncedContainer.cs | 64 +++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 2 files changed, 65 insertions(+) create mode 100644 osu.Game/Graphics/Containers/BeatSyncedContainer.cs diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs new file mode 100644 index 0000000000..1438ccf002 --- /dev/null +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -0,0 +1,64 @@ +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Timing; + +namespace osu.Game.Graphics.Containers +{ + public class BeatSyncedContainer : Container + { + private Bindable beatmap; + private int beat; + private double timingPointStart; + //This is to avoid sending new beats when not at the very start of the beat + private const int seek_tolerance = 20; + private const double min_beat_length = 1E-100; + + public BeatSyncedContainer() + { + } + + protected override void Update() + { + if (beatmap.Value != null) + { + double currentTime = beatmap.Value.Track.CurrentTime; + ControlPoint kiaiControlPoint; + ControlPoint controlPoint = beatmap.Value.Beatmap.TimingInfo.TimingPointAt(currentTime, out kiaiControlPoint); + + if (controlPoint != null) + { + double oldTimingPointStart = timingPointStart; + double beatLenght = double.MinValue; + int oldBeat = beat; + bool kiai = false; + + beatLenght = controlPoint.BeatLength; + timingPointStart = controlPoint.Time; + kiai = kiaiControlPoint?.KiaiMode ?? false; + + beat = beatLenght > min_beat_length ? (int)((currentTime - timingPointStart) / beatLenght) : 0; + + //should we handle negative beats? (before the start of the controlPoint) + //The beats before the start of the first control point are off by 1, this should do the trick + if (currentTime <= timingPointStart) + beat--; + + if ((timingPointStart != oldTimingPointStart || beat != oldBeat) && (int)((currentTime - timingPointStart) % (beatLenght)) <= seek_tolerance) + OnNewBeat(beat, controlPoint.BeatLength, controlPoint.TimeSignature, kiai); + } + } + } + + protected virtual void OnNewBeat(int newBeat, double beatLength, TimeSignatures timeSignature, bool kiai) + { + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase game) + { + beatmap = game.Beatmap; + } + } +} \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 63acdb1914..18c483fe40 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -74,6 +74,7 @@ + From 5f192cae7bb6042e5c1ac8131d4bda557d92673e Mon Sep 17 00:00:00 2001 From: ColdVolcano Date: Wed, 17 May 2017 01:18:56 -0500 Subject: [PATCH 002/112] Add missing licence header --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 1438ccf002..9d279ebb44 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -1,4 +1,7 @@ -using osu.Framework.Allocation; +// Copyright (c) 2007-2017 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.Containers; using osu.Game.Beatmaps; From 387d26a5769790142a9ac16f558758d968ad66ed Mon Sep 17 00:00:00 2001 From: ColdVolcano Date: Wed, 17 May 2017 01:26:34 -0500 Subject: [PATCH 003/112] CI Fixes --- .../Graphics/Containers/BeatSyncedContainer.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 9d279ebb44..ba25cc1d1a 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -18,10 +18,6 @@ namespace osu.Game.Graphics.Containers private const int seek_tolerance = 20; private const double min_beat_length = 1E-100; - public BeatSyncedContainer() - { - } - protected override void Update() { if (beatmap.Value != null) @@ -33,23 +29,23 @@ namespace osu.Game.Graphics.Containers if (controlPoint != null) { double oldTimingPointStart = timingPointStart; - double beatLenght = double.MinValue; + double beatLength; int oldBeat = beat; - bool kiai = false; + bool kiai; - beatLenght = controlPoint.BeatLength; + beatLength = controlPoint.BeatLength; timingPointStart = controlPoint.Time; kiai = kiaiControlPoint?.KiaiMode ?? false; - beat = beatLenght > min_beat_length ? (int)((currentTime - timingPointStart) / beatLenght) : 0; + beat = beatLength > min_beat_length ? (int)((currentTime - timingPointStart) / beatLength) : 0; //should we handle negative beats? (before the start of the controlPoint) //The beats before the start of the first control point are off by 1, this should do the trick if (currentTime <= timingPointStart) beat--; - if ((timingPointStart != oldTimingPointStart || beat != oldBeat) && (int)((currentTime - timingPointStart) % (beatLenght)) <= seek_tolerance) - OnNewBeat(beat, controlPoint.BeatLength, controlPoint.TimeSignature, kiai); + if ((timingPointStart != oldTimingPointStart || beat != oldBeat) && (currentTime - timingPointStart) % (beatLength) <= seek_tolerance) + OnNewBeat(beat, beatLength, controlPoint.TimeSignature, kiai); } } } From 198542465b81e9deb6735ff39cf594bd2d36f952 Mon Sep 17 00:00:00 2001 From: ColdVolcano Date: Wed, 17 May 2017 01:37:31 -0500 Subject: [PATCH 004/112] More CI fixes --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index ba25cc1d1a..2fc7731ef5 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -29,13 +29,10 @@ namespace osu.Game.Graphics.Containers if (controlPoint != null) { double oldTimingPointStart = timingPointStart; - double beatLength; + double beatLength = controlPoint.BeatLength; int oldBeat = beat; - bool kiai; - - beatLength = controlPoint.BeatLength; + bool kiai = kiaiControlPoint?.KiaiMode ?? false; timingPointStart = controlPoint.Time; - kiai = kiaiControlPoint?.KiaiMode ?? false; beat = beatLength > min_beat_length ? (int)((currentTime - timingPointStart) / beatLength) : 0; @@ -44,7 +41,7 @@ namespace osu.Game.Graphics.Containers if (currentTime <= timingPointStart) beat--; - if ((timingPointStart != oldTimingPointStart || beat != oldBeat) && (currentTime - timingPointStart) % (beatLength) <= seek_tolerance) + if ((timingPointStart != oldTimingPointStart || beat != oldBeat) && (int)((currentTime - timingPointStart) % beatLength) <= seek_tolerance) OnNewBeat(beat, beatLength, controlPoint.TimeSignature, kiai); } } From b9b45493e6f3f546f61c5d26034584d83265da03 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 17 May 2017 18:02:17 +0800 Subject: [PATCH 005/112] Use generic IComparable together with IEqutable for Message. --- osu.Game/Online/Chat/Channel.cs | 2 +- osu.Game/Online/Chat/Message.cs | 14 +++----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index 2925c3ccb4..93fd0a8956 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -23,7 +23,7 @@ namespace osu.Game.Online.Chat [JsonProperty(@"channel_id")] public int Id; - public readonly SortedList Messages = new SortedList((m1, m2) => m1.Id.CompareTo(m2.Id)); + public readonly SortedList Messages = new SortedList(Comparer.Default); //internal bool Joined; diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index bf53a68910..8c0cb043c4 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -8,7 +8,7 @@ using osu.Game.Users; namespace osu.Game.Online.Chat { - public class Message + public class Message : IComparable, IEquatable { [JsonProperty(@"message_id")] public readonly long Id; @@ -42,17 +42,9 @@ namespace osu.Game.Online.Chat Id = id; } - public override bool Equals(object obj) - { - var objMessage = obj as Message; + public int CompareTo(Message other) => Id.CompareTo(other.Id); - return Id == objMessage?.Id; - } - - public override int GetHashCode() - { - return Id.GetHashCode(); - } + public bool Equals(Message other) => Id == other.Id; } public enum TargetType From 6c9505fa3a053cc4fc607f366a30d1b94fe3600f Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 17 May 2017 18:11:38 +0800 Subject: [PATCH 006/112] Handle possible nulls. --- osu.Game/Online/Chat/Message.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index 8c0cb043c4..ed76ef248e 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -44,7 +44,7 @@ namespace osu.Game.Online.Chat public int CompareTo(Message other) => Id.CompareTo(other.Id); - public bool Equals(Message other) => Id == other.Id; + public bool Equals(Message other) => Id == other?.Id; } public enum TargetType From f4c7a02a6f06acb13d8ed6c20ef434863fa0c57e Mon Sep 17 00:00:00 2001 From: Javier Flores Date: Wed, 17 May 2017 09:23:04 -0500 Subject: [PATCH 007/112] Fix having negative beat when it should be 0 --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 2fc7731ef5..3b10e96398 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -38,7 +38,7 @@ namespace osu.Game.Graphics.Containers //should we handle negative beats? (before the start of the controlPoint) //The beats before the start of the first control point are off by 1, this should do the trick - if (currentTime <= timingPointStart) + if (currentTime < timingPointStart) beat--; if ((timingPointStart != oldTimingPointStart || beat != oldBeat) && (int)((currentTime - timingPointStart) % beatLength) <= seek_tolerance) @@ -57,4 +57,4 @@ namespace osu.Game.Graphics.Containers beatmap = game.Beatmap; } } -} \ No newline at end of file +} From b5d7211cd6471d58c9bcf6b78d49c9f5ce4e9a77 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 18 May 2017 01:30:24 +0800 Subject: [PATCH 008/112] Expire placeholder text. --- osu.Game/Overlays/ChatOverlay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 2836be22ae..c722d46ace 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -229,6 +229,7 @@ namespace osu.Game.Overlays Scheduler.Add(delegate { loading.FadeOut(100); + loading.Expire(); addChannel(channels.Find(c => c.Name == @"#lazer")); addChannel(channels.Find(c => c.Name == @"#osu")); From e2b1fcc0887f2ff46c87058261d5c47a1e95c96c Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 18 May 2017 01:43:11 +0800 Subject: [PATCH 009/112] Use string.Join in GetMessagesRequest. --- osu.Game/Online/API/Requests/GetMessagesRequest.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetMessagesRequest.cs b/osu.Game/Online/API/Requests/GetMessagesRequest.cs index cf52f9ccd3..858015e29b 100644 --- a/osu.Game/Online/API/Requests/GetMessagesRequest.cs +++ b/osu.Game/Online/API/Requests/GetMessagesRequest.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using System.Linq; using osu.Framework.IO.Network; using osu.Game.Online.Chat; @@ -20,10 +21,7 @@ namespace osu.Game.Online.API.Requests protected override WebRequest CreateWebRequest() { - string channelString = string.Empty; - foreach (Channel c in channels) - channelString += c.Id + ","; - channelString = channelString.TrimEnd(','); + string channelString = string.Join(",", channels.Select(x => x.Id)); var req = base.CreateWebRequest(); req.AddParameter(@"channels", channelString); From 23e2d3ef07b2fd99749245c06ad94bd8d4763699 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 18 May 2017 02:30:17 +0800 Subject: [PATCH 010/112] Use GroupBy in ChatOverlay. --- osu.Game/Overlays/ChatOverlay.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index c722d46ace..686a1d513a 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -321,11 +321,8 @@ namespace osu.Game.Overlays fetchReq = new GetMessagesRequest(careChannels, lastMessageId); fetchReq.Success += delegate (List messages) { - var ids = messages.Where(m => m.TargetType == TargetType.Channel).Select(m => m.TargetId).Distinct(); - - //batch messages per channel. - foreach (var id in ids) - careChannels.Find(c => c.Id == id)?.AddNewMessages(messages.Where(m => m.TargetId == id).ToArray()); + foreach (var group in messages.Where(m => m.TargetType == TargetType.Channel).GroupBy(m => m.TargetId)) + careChannels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId; From 88f8619e9a655f8ab29d14d3697f29793dcec58c Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 18 May 2017 02:46:12 +0800 Subject: [PATCH 011/112] More missed exceptions. --- osu.Game.Rulesets.Mania/Timing/ControlPointContainer.cs | 2 +- osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs | 2 +- osu.Game/Online/API/APIAccess.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Timing/ControlPointContainer.cs b/osu.Game.Rulesets.Mania/Timing/ControlPointContainer.cs index 6c39ba40f9..2ff97047c0 100644 --- a/osu.Game.Rulesets.Mania/Timing/ControlPointContainer.cs +++ b/osu.Game.Rulesets.Mania/Timing/ControlPointContainer.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Mania.Timing var controlPoint = drawableControlPoints.LastOrDefault(t => t.CanContain(drawable)) ?? drawableControlPoints.FirstOrDefault(); if (controlPoint == null) - throw new Exception("Could not find suitable timing section to add object to."); + throw new InvalidOperationException("Could not find suitable timing section to add object to."); controlPoint.Add(drawable); } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs index 986aefb2bd..dccc18fa8b 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Mania.UI ControlPoint firstTimingChange = Beatmap.TimingInfo.ControlPoints.FirstOrDefault(t => t.TimingChange); if (firstTimingChange == null) - throw new Exception("The Beatmap contains no timing points!"); + throw new InvalidOperationException("The Beatmap contains no timing points!"); // Generate the timing points, making non-timing changes use the previous timing change var timingChanges = Beatmap.TimingInfo.ControlPoints.Select(c => diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 2f344e0bdf..7e3bb44465 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -288,7 +288,7 @@ namespace osu.Game.Online.API { APIRequest req; while (oldQueue.TryDequeue(out req)) - req.Fail(new Exception(@"Disconnected from server")); + req.Fail(new WebException(@"Disconnected from server")); } } From ffbab6bfeb55212cb1177b46b168621e551a3996 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 18 May 2017 03:26:07 +0800 Subject: [PATCH 012/112] Tidy up DrawableChannel. --- osu.Game/Overlays/Chat/DrawableChannel.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 355aeed134..50c849f00e 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Chat public class DrawableChannel : Container { public readonly Channel Channel; - private readonly FillFlowContainer flow; + private readonly FillFlowContainer flow; private readonly ScrollContainer scroll; public DrawableChannel(Channel channel) @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Chat RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - flow = new FillFlowContainer + flow = new FillFlowContainer { Direction = FillDirection.Vertical, RelativeSizeAxes = Axes.X, @@ -63,19 +63,18 @@ namespace osu.Game.Overlays.Chat var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY)); + //up to last Channel.MAX_HISTORY messages + flow.Add(displayMessages.Select(m => new ChatLine(m))); + if (scroll.IsScrolledToEnd(10) || !flow.Children.Any()) scrollToEnd(); - //up to last Channel.MAX_HISTORY messages - foreach (Message m in displayMessages) - { - var d = new ChatLine(m); - flow.Add(d); - } + var staleMessages = flow.Children.Where(c => c.LifetimeEnd == double.MaxValue).ToArray(); + int count = staleMessages.Length - Channel.MAX_HISTORY; - while (flow.Children.Count(c => c.LifetimeEnd == double.MaxValue) > Channel.MAX_HISTORY) + for (int i = 0; i < count; i++) { - var d = flow.Children.First(c => c.LifetimeEnd == double.MaxValue); + var d = staleMessages[i]; if (!scroll.IsScrolledToEnd(10)) scroll.OffsetScrollPosition(-d.DrawHeight); d.Expire(); From cd065b8ff31ce97931cd6e560bf27763290fdccc Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 18 May 2017 05:27:20 +0800 Subject: [PATCH 013/112] Add back GetHashCode. --- osu.Game/Online/Chat/Message.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index ed76ef248e..4c7e099647 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -45,6 +45,8 @@ namespace osu.Game.Online.Chat public int CompareTo(Message other) => Id.CompareTo(other.Id); public bool Equals(Message other) => Id == other?.Id; + + public override int GetHashCode() => Id.GetHashCode(); } public enum TargetType From 2af025e630256e510c72070df391ea322971b087 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 18:09:13 +0900 Subject: [PATCH 014/112] Add IHasDistance object pattern generation. --- .../Legacy/DistanceObjectPatternGenerator.cs | 463 ++++++++++++++++++ .../osu.Game.Rulesets.Mania.csproj | 1 + 2 files changed, 464 insertions(+) create mode 100644 osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs new file mode 100644 index 0000000000..03240a2be4 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -0,0 +1,463 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Linq; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Timing; +using osu.Game.Rulesets.Mania.MathUtils; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; + +namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy +{ + /// + /// A pattern generator for IHasDistance hit objects. + /// + internal class DistanceObjectPatternGenerator : PatternGenerator + { + /// + /// Base osu! slider scoring distance. + /// + private const float osu_base_scoring_distance = 100; + + private readonly double endTime; + private readonly int repeatCount; + + private PatternType convertType; + + public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern) + : base(random, hitObject, beatmap, previousPattern) + { + ControlPoint overridePoint; + ControlPoint controlPoint = Beatmap.TimingInfo.TimingPointAt(hitObject.StartTime, out overridePoint); + + convertType = PatternType.None; + if ((overridePoint ?? controlPoint)?.KiaiMode == false) + convertType = PatternType.LowProbability; + + var distanceData = hitObject as IHasDistance; + var repeatsData = hitObject as IHasRepeats; + + repeatCount = repeatsData?.RepeatCount ?? 1; + + double speedAdjustment = beatmap.TimingInfo.SpeedMultiplierAt(hitObject.StartTime); + double speedAdjustedBeatLength = beatmap.TimingInfo.BeatLengthAt(hitObject.StartTime) * speedAdjustment; + + // The true distance, accounting for any repeats. This ends up being the drum roll distance later + double distance = distanceData.Distance * repeatCount; + + // The velocity of the osu! hit object - calculated as the velocity of a slider + double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier / speedAdjustedBeatLength; + // The duration of the osu! hit object + double osuDuration = distance / osuVelocity; + + endTime = hitObject.StartTime + osuDuration; + } + + public override Pattern Generate() + { + double segmentDuration = endTime / repeatCount; + + if (repeatCount > 1) + { + if (segmentDuration <= 90) + return generateRandomHoldNotes(HitObject.StartTime, endTime, 1); + + if (segmentDuration <= 120) + { + convertType |= PatternType.ForceNotStack; + return generateRandomNotes(HitObject.StartTime, segmentDuration, repeatCount); + } + + if (segmentDuration <= 160) + return generateStair(HitObject.StartTime, segmentDuration); + + if (segmentDuration <= 200 && ConversionDifficulty > 3) + return generateRandomMultipleNotes(HitObject.StartTime, segmentDuration, repeatCount); + + double duration = endTime - HitObject.StartTime; + if (duration >= 4000) + return generateNRandomNotes(HitObject.StartTime, endTime, 0.23, 0, 0); + + if (segmentDuration > 400 && duration < 4000 && repeatCount < AvailableColumns - 1 - RandomStart) + return generateTiledHoldNotes(HitObject.StartTime, segmentDuration, repeatCount); + + return generateHoldAndNormalNotes(HitObject.StartTime, segmentDuration); + } + + if (segmentDuration <= 110) + { + if (PreviousPattern.ColumnsFilled < AvailableColumns) + convertType |= PatternType.ForceNotStack; + else + convertType &= ~PatternType.ForceNotStack; + return generateRandomNotes(HitObject.StartTime, segmentDuration, segmentDuration < 80 ? 0 : 1); + } + + if (ConversionDifficulty > 6.5) + { + if ((convertType & PatternType.LowProbability) > 0) + return generateNRandomNotes(HitObject.StartTime, endTime, 0.78, 0.3, 0); + return generateNRandomNotes(HitObject.StartTime, endTime, 0.85, 0.36, 0.03); + } + + if (ConversionDifficulty > 4) + { + if ((convertType & PatternType.LowProbability) > 0) + return generateNRandomNotes(HitObject.StartTime, endTime, 0.43, 0.08, 0); + return generateNRandomNotes(HitObject.StartTime, endTime, 0.56, 0.18, 0); + } + + if (ConversionDifficulty > 2.5) + { + if ((convertType & PatternType.LowProbability) > 0) + return generateNRandomNotes(HitObject.StartTime, endTime, 0.3, 0, 0); + return generateNRandomNotes(HitObject.StartTime, endTime, 0.37, 0.08, 0); + } + + if ((convertType & PatternType.LowProbability) > 0) + return generateNRandomNotes(HitObject.StartTime, endTime, 0.17, 0, 0); + return generateNRandomNotes(HitObject.StartTime, endTime, 0.27, 0, 0); + } + + /// + /// Generates random hold notes that start at an span the same amount of rows. + /// + /// Start time of each hold note. + /// End time of the hold notes. + /// Number of hold notes. + /// The containing the hit objects. + private Pattern generateRandomHoldNotes(double startTime, double endTime, int noteCount) + { + // - - - - + // ■ - ■ ■ + // □ - □ □ + // ■ - ■ ■ + + var pattern = new Pattern(); + + int usableColumns = AvailableColumns - RandomStart - PreviousPattern.ColumnsFilled; + int nextColumn = Random.Next(RandomStart, AvailableColumns); + for (int i = 0; i < Math.Min(usableColumns, noteCount); i++) + { + while (pattern.IsFilled(nextColumn) || PreviousPattern.IsFilled(nextColumn)) //find available column + nextColumn = Random.Next(RandomStart, AvailableColumns); + AddToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); + } + + // This is can't be combined with the above loop due to RNG + for (int i = 0; i < noteCount - usableColumns; i++) + { + while (pattern.IsFilled(nextColumn)) + nextColumn = Random.Next(RandomStart, AvailableColumns); + AddToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); + } + + return pattern; + } + + /// + /// Generates random notes, with one note per row and no stacking. + /// + /// The start time. + /// The separation of notes between rows. + /// The number of rows. + /// The containing the hit objects. + private Pattern generateRandomNotes(double startTime, double separationTime, int repeatCount) + { + // - - - - + // x - - - + // - - x - + // - - - x + // x - - - + + var pattern = new Pattern(); + + int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); + if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnsFilled < AvailableColumns) + { + while (PreviousPattern.IsFilled(nextColumn)) + nextColumn = Random.Next(RandomStart, AvailableColumns); + } + + int lastColumn = nextColumn; + for (int i = 0; i <= repeatCount; i++) + { + AddToPattern(pattern, HitObject, nextColumn, startTime, startTime); + while (nextColumn == lastColumn) + nextColumn = Random.Next(RandomStart, AvailableColumns); + + lastColumn = nextColumn; + startTime += separationTime; + } + + return pattern; + } + + /// + /// Generates a stair of notes, with one note per row. + /// + /// The start time. + /// The separation of notes between rows. + /// The containing the hit objects. + private Pattern generateStair(double startTime, double separationTime) + { + // - - - - + // x - - - + // - x - - + // - - x - + // - - - x + // - - x - + // - x - - + // x - - - + + var pattern = new Pattern(); + + int column = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); + bool increasing = Random.NextDouble() > 0.5; + + for (int i = 0; i <= repeatCount; i++) + { + AddToPattern(pattern, HitObject, column, startTime, startTime); + startTime += separationTime; + + // Check if we're at the borders of the stage, and invert the pattern if so + if (increasing) + { + if (column >= AvailableColumns - 1) + { + increasing = false; + column--; + } + else + column++; + } + else + { + if (column <= RandomStart) + { + increasing = true; + column++; + } + else + column--; + } + } + + return pattern; + } + + /// + /// Generates random notes with 1-2 notes per row and no stacking. + /// + /// The start time. + /// The separation of notes between rows. + /// The number of rows. + /// The containing the hit objects. + private Pattern generateRandomMultipleNotes(double startTime, double separationTime, int repeatCount) + { + // - - - - + // x - - + // - x x - + // - - - x + // x - x - + + var pattern = new Pattern(); + + bool legacy = AvailableColumns >= 4 && AvailableColumns <= 8; + int interval = Random.Next(1, AvailableColumns - (legacy ? 1 : 0)); + + int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); + for (int i = 0; i <= repeatCount; i++) + { + AddToPattern(pattern, HitObject, nextColumn, startTime, startTime, 2); + + nextColumn += interval; + if (nextColumn >= AvailableColumns - RandomStart) + nextColumn = nextColumn - AvailableColumns - RandomStart + (legacy ? 1 : 0); + nextColumn += RandomStart; + + // If we're in 2K, let's not add many consecutive doubles + if (AvailableColumns > 2) + AddToPattern(pattern, HitObject, nextColumn, startTime, startTime, 2); + + nextColumn = Random.Next(RandomStart, AvailableColumns); + startTime += separationTime; + } + + return pattern; + } + + /// + /// Generates random hold notes. The amount of hold notes generated is determined by probabilities. + /// + /// The hold note start time. + /// The hold note end time. + /// The probability required for 2 hold notes to be generated. + /// The probability required for 3 hold notes to be generated. + /// The probability required for 4 hold notes to be generated. + /// The containing the hit objects. + private Pattern generateNRandomNotes(double startTime, double endTime, double p2, double p3, double p4) + { + // - - - - + // ■ - ■ ■ + // □ - □ □ + // ■ - ■ ■ + + switch (AvailableColumns) + { + case 2: + p2 = 0; + p3 = 0; + p4 = 0; + break; + case 3: + p2 = Math.Max(p2, 0.1); + p3 = 0; + p4 = 0; + break; + case 4: + p2 = Math.Max(p2, 0.3); + p3 = Math.Max(p3, 0.04); + p4 = 0; + break; + case 5: + p2 = Math.Max(p2, 0.34); + p3 = Math.Max(p3, 0.1); + p4 = Math.Max(p4, 0.03); + break; + } + + Func isDoubleSample = 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); + + if (canGenerateTwoNotes) + p2 = 1; + + return generateRandomHoldNotes(startTime, endTime, GetRandomNoteCount(p2, p3, p4)); + } + + /// + /// Generates tiled hold notes. You can think of this as a stair of hold notes. + /// + /// The first hold note start time. + /// The separation time between hold notes. + /// The amount of hold notes. + /// The containing the hit objects. + private Pattern generateTiledHoldNotes(double startTime, double separationTime, int noteCount) + { + // - - - - + // ■ ■ ■ ■ + // □ □ □ □ + // □ □ □ □ + // □ □ □ ■ + // □ □ ■ - + // □ ■ - - + // ■ - - - + + var pattern = new Pattern(); + + int columnRepeat = Math.Min(noteCount, AvailableColumns); + + int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); + if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnsFilled < AvailableColumns) + { + while (PreviousPattern.IsFilled(nextColumn)) + nextColumn = Random.Next(RandomStart, AvailableColumns); + } + + for (int i = 0; i < columnRepeat; i++) + { + while (pattern.IsFilled(nextColumn)) + nextColumn = Random.Next(RandomStart, AvailableColumns); + + AddToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); + startTime += separationTime; + } + + return pattern; + } + + /// + /// Generates a hold note alongside normal notes. + /// + /// The start time of notes. + /// The separation time between notes. + /// The containing the hit objects. + private Pattern generateHoldAndNormalNotes(double startTime, double separationTime) + { + // - - - - + // ■ x x - + // ■ - x x + // ■ x - x + // ■ - x x + + var pattern = new Pattern(); + + int holdColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); + if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnsFilled < AvailableColumns) + { + while (PreviousPattern.IsFilled(holdColumn)) + holdColumn = Random.Next(RandomStart, AvailableColumns); + } + + // Create the hold note + AddToPattern(pattern, HitObject, holdColumn, startTime, separationTime * repeatCount); + + int noteCount = 1; + if (ConversionDifficulty > 6.5) + noteCount = GetRandomNoteCount(0.63, 0); + else if (ConversionDifficulty > 4) + noteCount = GetRandomNoteCount(AvailableColumns < 6 ? 0.12 : 0.45, 0); + else if (ConversionDifficulty > 2.5) + noteCount = GetRandomNoteCount(AvailableColumns < 6 ? 0 : 0.24, 0); + noteCount = Math.Min(AvailableColumns - 1, noteCount); + + bool ignoreHead = !sampleInfoListAt(startTime).Any(s => s.Name == SampleInfo.HIT_WHISTLE || s.Name == SampleInfo.HIT_FINISH || s.Name == SampleInfo.HIT_CLAP); + int nextColumn = Random.Next(RandomStart, AvailableColumns); + + var rowPattern = new Pattern(); + for (int i = 0; i <= repeatCount; i++) + { + if (!(ignoreHead && startTime == HitObject.StartTime)) + { + for (int j = 0; j < noteCount; j++) + { + while (rowPattern.IsFilled(nextColumn) || nextColumn == holdColumn) + nextColumn = Random.Next(RandomStart, AvailableColumns); + AddToPattern(rowPattern, HitObject, nextColumn, startTime, startTime, noteCount + 1); + } + } + + pattern.Add(rowPattern); + rowPattern.Clear(); + + startTime += separationTime; + } + + return pattern; + } + + /// + /// Retrieves the sample info list at a point in time. + /// + /// The time to retrieve the sample info list from. + /// + private SampleInfoList sampleInfoListAt(double time) + { + var curveData = HitObject as IHasCurve; + + if (curveData == null) + return HitObject.Samples; + + double segmentTime = (curveData.EndTime - HitObject.StartTime) / repeatCount; + + int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime); + return curveData.RepeatSamples[index]; + } + } +} diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index ea65588a81..9de9cd703f 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -47,6 +47,7 @@ + From eae4f8b4127cb98a1717cd590ab4ac2dd2f83c4a Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 18:11:09 +0900 Subject: [PATCH 015/112] Fix compilation due to previously-removed function. --- .../Legacy/DistanceObjectPatternGenerator.cs | 58 ++++++++++++++++--- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 03240a2be4..304a32a51b 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -9,6 +9,7 @@ using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Mania.MathUtils; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Mania.Objects; namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { @@ -144,7 +145,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { while (pattern.IsFilled(nextColumn) || PreviousPattern.IsFilled(nextColumn)) //find available column nextColumn = Random.Next(RandomStart, AvailableColumns); - AddToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); + addToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); } // This is can't be combined with the above loop due to RNG @@ -152,7 +153,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { while (pattern.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); - AddToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); + addToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); } return pattern; @@ -185,7 +186,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy int lastColumn = nextColumn; for (int i = 0; i <= repeatCount; i++) { - AddToPattern(pattern, HitObject, nextColumn, startTime, startTime); + addToPattern(pattern, HitObject, nextColumn, startTime, startTime); while (nextColumn == lastColumn) nextColumn = Random.Next(RandomStart, AvailableColumns); @@ -220,7 +221,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy for (int i = 0; i <= repeatCount; i++) { - AddToPattern(pattern, HitObject, column, startTime, startTime); + addToPattern(pattern, HitObject, column, startTime, startTime); startTime += separationTime; // Check if we're at the borders of the stage, and invert the pattern if so @@ -272,7 +273,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); for (int i = 0; i <= repeatCount; i++) { - AddToPattern(pattern, HitObject, nextColumn, startTime, startTime, 2); + addToPattern(pattern, HitObject, nextColumn, startTime, startTime, 2); nextColumn += interval; if (nextColumn >= AvailableColumns - RandomStart) @@ -281,7 +282,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy // If we're in 2K, let's not add many consecutive doubles if (AvailableColumns > 2) - AddToPattern(pattern, HitObject, nextColumn, startTime, startTime, 2); + addToPattern(pattern, HitObject, nextColumn, startTime, startTime, 2); nextColumn = Random.Next(RandomStart, AvailableColumns); startTime += separationTime; @@ -375,7 +376,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy while (pattern.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); - AddToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); + addToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); startTime += separationTime; } @@ -406,7 +407,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy } // Create the hold note - AddToPattern(pattern, HitObject, holdColumn, startTime, separationTime * repeatCount); + addToPattern(pattern, HitObject, holdColumn, startTime, separationTime * repeatCount); int noteCount = 1; if (ConversionDifficulty > 6.5) @@ -429,7 +430,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { while (rowPattern.IsFilled(nextColumn) || nextColumn == holdColumn) nextColumn = Random.Next(RandomStart, AvailableColumns); - AddToPattern(rowPattern, HitObject, nextColumn, startTime, startTime, noteCount + 1); + addToPattern(rowPattern, HitObject, nextColumn, startTime, startTime, noteCount + 1); } } @@ -459,5 +460,44 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime); return curveData.RepeatSamples[index]; } + + + /// + /// Constructs and adds a note to a pattern. + /// + /// The pattern to add to. + /// The original hit object (used for samples). + /// The column to add the note to. + /// The start time of the note. + /// The end time of the note (set to for a non-hold note). + /// The number of children alongside this note (these will not be generated, but are used for volume calculations). + private void addToPattern(Pattern pattern, HitObject originalObject, int column, double startTime, double endTime, int siblings = 1) + { + ManiaHitObject newObject; + + if (startTime == endTime) + { + newObject = new Note + { + StartTime = startTime, + Samples = originalObject.Samples, + Column = column + }; + } + else + { + newObject = new HoldNote + { + StartTime = startTime, + Samples = originalObject.Samples, + Column = column, + Duration = endTime - startTime + }; + } + + // Todo: Consider siblings and write sample volumes (probably at ManiaHitObject level) + + pattern.Add(newObject); + } } } From 53a2f34f8b891e4e084b5351eb5fef1b629cc989 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 18:15:09 +0900 Subject: [PATCH 016/112] Set siblings, removing warning. --- .../Patterns/Legacy/DistanceObjectPatternGenerator.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 304a32a51b..adb0966b81 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -481,7 +481,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { StartTime = startTime, Samples = originalObject.Samples, - Column = column + Column = column, + Siblings = siblings }; } else @@ -491,12 +492,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy StartTime = startTime, Samples = originalObject.Samples, Column = column, - Duration = endTime - startTime + Duration = endTime - startTime, + Siblings = siblings }; } - // Todo: Consider siblings and write sample volumes (probably at ManiaHitObject level) - pattern.Add(newObject); } } From a30e49d21bf925586fdc19a43d760e631046c5c1 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 18:19:29 +0900 Subject: [PATCH 017/112] Add hold end samples. --- .../Patterns/Legacy/DistanceObjectPatternGenerator.cs | 5 +++-- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index adb0966b81..b2a9de4b54 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -480,7 +480,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy newObject = new Note { StartTime = startTime, - Samples = originalObject.Samples, + Samples = sampleInfoListAt(startTime), Column = column, Siblings = siblings }; @@ -490,7 +490,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy newObject = new HoldNote { StartTime = startTime, - Samples = originalObject.Samples, + Samples = sampleInfoListAt(startTime), + EndSamples = sampleInfoListAt(endTime), Column = column, Duration = endTime - startTime, Siblings = siblings diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index a25b8fbf2a..701947c381 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Audio; using osu.Game.Beatmaps.Timing; using osu.Game.Database; using osu.Game.Rulesets.Mania.Judgements; @@ -22,6 +23,11 @@ namespace osu.Game.Rulesets.Mania.Objects public double Duration { get; set; } public double EndTime => StartTime + Duration; + /// + /// The samples to be played when this hold note is released. + /// + public SampleInfoList EndSamples = new SampleInfoList(); + /// /// The key-release hit windows for this hold note. /// From 35bd608a4ac5c6a74fe466bfa96f865b06c6976f Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 18:41:44 +0900 Subject: [PATCH 018/112] Simplify method parameters, make conversion work again. --- .../Beatmaps/LegacyBeatmapConverter.cs | 4 +- .../Legacy/DistanceObjectPatternGenerator.cs | 83 +++++++++---------- 2 files changed, 40 insertions(+), 47 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs index 3aa88af62d..a69145ba75 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs @@ -9,6 +9,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Mania.Beatmaps.Patterns; using osu.Game.Rulesets.Mania.MathUtils; +using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy; namespace osu.Game.Rulesets.Mania.Beatmaps { @@ -74,10 +75,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps var distanceData = original as IHasDistance; var positionData = original as IHasPosition; - PatternGenerator conversion = null; + Patterns.PatternGenerator conversion = null; if (distanceData != null) { + conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern); // Slider } else if (endTimeData != null) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index b2a9de4b54..238e25f0c4 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -24,6 +24,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy private const float osu_base_scoring_distance = 100; private readonly double endTime; + private readonly double segmentDuration; private readonly int repeatCount; private PatternType convertType; @@ -55,37 +56,36 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy double osuDuration = distance / osuVelocity; endTime = hitObject.StartTime + osuDuration; + segmentDuration = (endTime - HitObject.StartTime) / repeatCount; } public override Pattern Generate() { - double segmentDuration = endTime / repeatCount; - if (repeatCount > 1) { if (segmentDuration <= 90) - return generateRandomHoldNotes(HitObject.StartTime, endTime, 1); + return generateRandomHoldNotes(HitObject.StartTime, 1); if (segmentDuration <= 120) { convertType |= PatternType.ForceNotStack; - return generateRandomNotes(HitObject.StartTime, segmentDuration, repeatCount); + return generateRandomNotes(HitObject.StartTime, repeatCount + 1); } if (segmentDuration <= 160) - return generateStair(HitObject.StartTime, segmentDuration); + return generateStair(HitObject.StartTime); if (segmentDuration <= 200 && ConversionDifficulty > 3) - return generateRandomMultipleNotes(HitObject.StartTime, segmentDuration, repeatCount); + return generateRandomMultipleNotes(HitObject.StartTime); double duration = endTime - HitObject.StartTime; if (duration >= 4000) - return generateNRandomNotes(HitObject.StartTime, endTime, 0.23, 0, 0); + return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0); if (segmentDuration > 400 && duration < 4000 && repeatCount < AvailableColumns - 1 - RandomStart) - return generateTiledHoldNotes(HitObject.StartTime, segmentDuration, repeatCount); + return generateTiledHoldNotes(HitObject.StartTime); - return generateHoldAndNormalNotes(HitObject.StartTime, segmentDuration); + return generateHoldAndNormalNotes(HitObject.StartTime); } if (segmentDuration <= 110) @@ -94,43 +94,42 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy convertType |= PatternType.ForceNotStack; else convertType &= ~PatternType.ForceNotStack; - return generateRandomNotes(HitObject.StartTime, segmentDuration, segmentDuration < 80 ? 0 : 1); + return generateRandomNotes(HitObject.StartTime, segmentDuration < 80 ? 1 : 2); } if (ConversionDifficulty > 6.5) { if ((convertType & PatternType.LowProbability) > 0) - return generateNRandomNotes(HitObject.StartTime, endTime, 0.78, 0.3, 0); - return generateNRandomNotes(HitObject.StartTime, endTime, 0.85, 0.36, 0.03); + return generateNRandomNotes(HitObject.StartTime, 0.78, 0.3, 0); + return generateNRandomNotes(HitObject.StartTime, 0.85, 0.36, 0.03); } if (ConversionDifficulty > 4) { if ((convertType & PatternType.LowProbability) > 0) - return generateNRandomNotes(HitObject.StartTime, endTime, 0.43, 0.08, 0); - return generateNRandomNotes(HitObject.StartTime, endTime, 0.56, 0.18, 0); + return generateNRandomNotes(HitObject.StartTime, 0.43, 0.08, 0); + return generateNRandomNotes(HitObject.StartTime, 0.56, 0.18, 0); } if (ConversionDifficulty > 2.5) { if ((convertType & PatternType.LowProbability) > 0) - return generateNRandomNotes(HitObject.StartTime, endTime, 0.3, 0, 0); - return generateNRandomNotes(HitObject.StartTime, endTime, 0.37, 0.08, 0); + return generateNRandomNotes(HitObject.StartTime, 0.3, 0, 0); + return generateNRandomNotes(HitObject.StartTime, 0.37, 0.08, 0); } if ((convertType & PatternType.LowProbability) > 0) - return generateNRandomNotes(HitObject.StartTime, endTime, 0.17, 0, 0); - return generateNRandomNotes(HitObject.StartTime, endTime, 0.27, 0, 0); + return generateNRandomNotes(HitObject.StartTime, 0.17, 0, 0); + return generateNRandomNotes(HitObject.StartTime, 0.27, 0, 0); } /// /// Generates random hold notes that start at an span the same amount of rows. /// /// Start time of each hold note. - /// End time of the hold notes. /// Number of hold notes. /// The containing the hit objects. - private Pattern generateRandomHoldNotes(double startTime, double endTime, int noteCount) + private Pattern generateRandomHoldNotes(double startTime, int noteCount) { // - - - - // ■ - ■ ■ @@ -163,10 +162,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// Generates random notes, with one note per row and no stacking. /// /// The start time. - /// The separation of notes between rows. - /// The number of rows. + /// The number of notes. /// The containing the hit objects. - private Pattern generateRandomNotes(double startTime, double separationTime, int repeatCount) + private Pattern generateRandomNotes(double startTime, int noteCount) { // - - - - // x - - - @@ -184,14 +182,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy } int lastColumn = nextColumn; - for (int i = 0; i <= repeatCount; i++) + for (int i = 0; i < noteCount; i++) { addToPattern(pattern, HitObject, nextColumn, startTime, startTime); while (nextColumn == lastColumn) nextColumn = Random.Next(RandomStart, AvailableColumns); lastColumn = nextColumn; - startTime += separationTime; + startTime += segmentDuration; } return pattern; @@ -201,9 +199,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// Generates a stair of notes, with one note per row. /// /// The start time. - /// The separation of notes between rows. /// The containing the hit objects. - private Pattern generateStair(double startTime, double separationTime) + private Pattern generateStair(double startTime) { // - - - - // x - - - @@ -222,7 +219,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy for (int i = 0; i <= repeatCount; i++) { addToPattern(pattern, HitObject, column, startTime, startTime); - startTime += separationTime; + startTime += segmentDuration; // Check if we're at the borders of the stage, and invert the pattern if so if (increasing) @@ -254,10 +251,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// Generates random notes with 1-2 notes per row and no stacking. /// /// The start time. - /// The separation of notes between rows. - /// The number of rows. /// The containing the hit objects. - private Pattern generateRandomMultipleNotes(double startTime, double separationTime, int repeatCount) + private Pattern generateRandomMultipleNotes(double startTime) { // - - - - // x - - @@ -285,7 +280,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy addToPattern(pattern, HitObject, nextColumn, startTime, startTime, 2); nextColumn = Random.Next(RandomStart, AvailableColumns); - startTime += separationTime; + startTime += segmentDuration; } return pattern; @@ -295,12 +290,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// Generates random hold notes. The amount of hold notes generated is determined by probabilities. /// /// The hold note start time. - /// The hold note end time. /// The probability required for 2 hold notes to be generated. /// The probability required for 3 hold notes to be generated. /// The probability required for 4 hold notes to be generated. /// The containing the hit objects. - private Pattern generateNRandomNotes(double startTime, double endTime, double p2, double p3, double p4) + private Pattern generateNRandomNotes(double startTime, double p2, double p3, double p4) { // - - - - // ■ - ■ ■ @@ -339,17 +333,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy if (canGenerateTwoNotes) p2 = 1; - return generateRandomHoldNotes(startTime, endTime, GetRandomNoteCount(p2, p3, p4)); + return generateRandomHoldNotes(startTime, GetRandomNoteCount(p2, p3, p4)); } /// /// Generates tiled hold notes. You can think of this as a stair of hold notes. /// /// The first hold note start time. - /// The separation time between hold notes. - /// The amount of hold notes. /// The containing the hit objects. - private Pattern generateTiledHoldNotes(double startTime, double separationTime, int noteCount) + private Pattern generateTiledHoldNotes(double startTime) { // - - - - // ■ ■ ■ ■ @@ -362,7 +354,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy var pattern = new Pattern(); - int columnRepeat = Math.Min(noteCount, AvailableColumns); + int columnRepeat = Math.Min(repeatCount, AvailableColumns); int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnsFilled < AvailableColumns) @@ -376,8 +368,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy while (pattern.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); - addToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); - startTime += separationTime; + addToPattern(pattern, HitObject, nextColumn, startTime, endTime, repeatCount); + startTime += segmentDuration; } return pattern; @@ -387,9 +379,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// Generates a hold note alongside normal notes. /// /// The start time of notes. - /// The separation time between notes. /// The containing the hit objects. - private Pattern generateHoldAndNormalNotes(double startTime, double separationTime) + private Pattern generateHoldAndNormalNotes(double startTime) { // - - - - // ■ x x - @@ -407,7 +398,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy } // Create the hold note - addToPattern(pattern, HitObject, holdColumn, startTime, separationTime * repeatCount); + addToPattern(pattern, HitObject, holdColumn, startTime, endTime); int noteCount = 1; if (ConversionDifficulty > 6.5) @@ -437,7 +428,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy pattern.Add(rowPattern); rowPattern.Clear(); - startTime += separationTime; + startTime += segmentDuration; } return pattern; @@ -455,7 +446,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy if (curveData == null) return HitObject.Samples; - double segmentTime = (curveData.EndTime - HitObject.StartTime) / repeatCount; + double segmentTime = (endTime - HitObject.StartTime) / repeatCount; int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime); return curveData.RepeatSamples[index]; From a239411808b14df9a90895bc331e798010c28861 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 19:09:02 +0900 Subject: [PATCH 019/112] Fix warnings/errors. --- .../Beatmaps/LegacyBeatmapConverter.cs | 10 ++++---- .../Legacy/DistanceObjectPatternGenerator.cs | 23 +++++++++---------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs index 17552c05ef..de826063b0 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // Following lines currently commented out to appease resharper - //PatternGenerator conversion = null; + Patterns.PatternGenerator conversion = null; if (distanceData != null) { @@ -93,13 +93,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // Circle } - //if (conversion == null) + if (conversion == null) return null; - //Pattern newPattern = conversion.Generate(); - //lastPattern = newPattern; + Pattern newPattern = conversion.Generate(); + lastPattern = newPattern; - //return newPattern.HitObjects; + return newPattern.HitObjects; } /// diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 238e25f0c4..04e2b30816 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy double speedAdjustedBeatLength = beatmap.TimingInfo.BeatLengthAt(hitObject.StartTime) * speedAdjustment; // The true distance, accounting for any repeats. This ends up being the drum roll distance later - double distance = distanceData.Distance * repeatCount; + double distance = (distanceData?.Distance ?? 0) * repeatCount; // The velocity of the osu! hit object - calculated as the velocity of a slider double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier / speedAdjustedBeatLength; @@ -144,7 +144,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { while (pattern.IsFilled(nextColumn) || PreviousPattern.IsFilled(nextColumn)) //find available column nextColumn = Random.Next(RandomStart, AvailableColumns); - addToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); + addToPattern(pattern, nextColumn, startTime, endTime, noteCount); } // This is can't be combined with the above loop due to RNG @@ -152,7 +152,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { while (pattern.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); - addToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); + addToPattern(pattern, nextColumn, startTime, endTime, noteCount); } return pattern; @@ -184,7 +184,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy int lastColumn = nextColumn; for (int i = 0; i < noteCount; i++) { - addToPattern(pattern, HitObject, nextColumn, startTime, startTime); + addToPattern(pattern, nextColumn, startTime, startTime); while (nextColumn == lastColumn) nextColumn = Random.Next(RandomStart, AvailableColumns); @@ -218,7 +218,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy for (int i = 0; i <= repeatCount; i++) { - addToPattern(pattern, HitObject, column, startTime, startTime); + addToPattern(pattern, column, startTime, startTime); startTime += segmentDuration; // Check if we're at the borders of the stage, and invert the pattern if so @@ -268,7 +268,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); for (int i = 0; i <= repeatCount; i++) { - addToPattern(pattern, HitObject, nextColumn, startTime, startTime, 2); + addToPattern(pattern, nextColumn, startTime, startTime, 2); nextColumn += interval; if (nextColumn >= AvailableColumns - RandomStart) @@ -277,7 +277,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy // If we're in 2K, let's not add many consecutive doubles if (AvailableColumns > 2) - addToPattern(pattern, HitObject, nextColumn, startTime, startTime, 2); + addToPattern(pattern, nextColumn, startTime, startTime, 2); nextColumn = Random.Next(RandomStart, AvailableColumns); startTime += segmentDuration; @@ -368,7 +368,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy while (pattern.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); - addToPattern(pattern, HitObject, nextColumn, startTime, endTime, repeatCount); + addToPattern(pattern, nextColumn, startTime, endTime, repeatCount); startTime += segmentDuration; } @@ -398,7 +398,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy } // Create the hold note - addToPattern(pattern, HitObject, holdColumn, startTime, endTime); + addToPattern(pattern, holdColumn, startTime, endTime); int noteCount = 1; if (ConversionDifficulty > 6.5) @@ -421,7 +421,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { while (rowPattern.IsFilled(nextColumn) || nextColumn == holdColumn) nextColumn = Random.Next(RandomStart, AvailableColumns); - addToPattern(rowPattern, HitObject, nextColumn, startTime, startTime, noteCount + 1); + addToPattern(rowPattern, nextColumn, startTime, startTime, noteCount + 1); } } @@ -457,12 +457,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// Constructs and adds a note to a pattern. /// /// The pattern to add to. - /// The original hit object (used for samples). /// The column to add the note to. /// The start time of the note. /// The end time of the note (set to for a non-hold note). /// The number of children alongside this note (these will not be generated, but are used for volume calculations). - private void addToPattern(Pattern pattern, HitObject originalObject, int column, double startTime, double endTime, int siblings = 1) + private void addToPattern(Pattern pattern, int column, double startTime, double endTime, int siblings = 1) { ManiaHitObject newObject; From 1f6939f57bc7443abbb73d9c775e6dfab311bd01 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 17:39:03 +0900 Subject: [PATCH 020/112] Add IHasEndTime object pattern generation. --- .../Beatmaps/LegacyBeatmapConverter.cs | 14 +-- .../Legacy/EndTimeObjectPatternGenerator.cs | 100 ++++++++++++++++++ osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 6 ++ .../osu.Game.Rulesets.Mania.csproj | 1 + 4 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs index e3045df185..3fd5b3900b 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs @@ -9,6 +9,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Mania.Beatmaps.Patterns; using osu.Game.Rulesets.Mania.MathUtils; +using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy; namespace osu.Game.Rulesets.Mania.Beatmaps { @@ -74,9 +75,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps var distanceData = original as IHasDistance; var positionData = original as IHasPosition; - // Following lines currently commented out to appease resharper - - //PatternGenerator conversion = null; + Patterns.PatternGenerator conversion = null; if (distanceData != null) { @@ -84,6 +83,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps } else if (endTimeData != null) { + conversion = new EndTimeObjectPatternGenerator(random, original, beatmap); // Spinner } else if (positionData != null) @@ -91,13 +91,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // Circle } - //if (conversion == null) + if (conversion == null) return null; - //Pattern newPattern = conversion.Generate(); - //lastPattern = newPattern; + Pattern newPattern = conversion.Generate(); + lastPattern = newPattern; - //return newPattern.HitObjects; + return newPattern.HitObjects; } /// diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs new file mode 100644 index 0000000000..cd04418ac5 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs @@ -0,0 +1,100 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mania.MathUtils; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using System.Linq; +using osu.Game.Audio; +using osu.Game.Rulesets.Mania.Objects; + +namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy +{ + internal class EndTimeObjectPatternGenerator : PatternGenerator + { + private readonly double endTime; + + public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap) + : base(random, hitObject, beatmap, new Pattern()) + { + var endtimeData = HitObject as IHasEndTime; + + endTime = endtimeData?.EndTime ?? 0; + } + + public override Pattern Generate() + { + var pattern = new Pattern(); + + bool generateHold = endTime - HitObject.StartTime >= 100; + + if (AvailableColumns == 8) + { + if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && endTime - HitObject.StartTime < 1000) + addToPattern(pattern, 0, generateHold); + else + addToPattern(pattern, getNextRandomColumn(RandomStart), generateHold); + } + else + addToPattern(pattern, getNextRandomColumn(0), generateHold); + + return pattern; + } + + /// + /// Picks a random column after a column. + /// + /// The starting column. + /// A random column after . + private int getNextRandomColumn(int start) + { + int nextColumn = Random.Next(start, AvailableColumns); + + while (PreviousPattern.IsFilled(nextColumn)) + nextColumn = Random.Next(start, AvailableColumns); + + return nextColumn; + } + + /// + /// Constructs and adds a note to a pattern. + /// + /// The pattern to add to. + /// The column to add the note to. + /// Whether to add a hold note. + private void addToPattern(Pattern pattern, int column, bool holdNote) + { + ManiaHitObject newObject; + + if (holdNote) + { + newObject = new HoldNote + { + StartTime = HitObject.StartTime, + EndSamples = HitObject.Samples, + Column = column, + Duration = endTime - HitObject.StartTime, + Siblings = 1 + }; + + newObject.Samples.Add(new SampleInfo + { + Name = SampleInfo.HIT_NORMAL + }); + } + else + { + newObject = new Note + { + StartTime = HitObject.StartTime, + Samples = HitObject.Samples, + Column = column, + Siblings = 1 + }; + } + + pattern.Add(newObject); + } + } +} diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index a25b8fbf2a..701947c381 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Audio; using osu.Game.Beatmaps.Timing; using osu.Game.Database; using osu.Game.Rulesets.Mania.Judgements; @@ -22,6 +23,11 @@ namespace osu.Game.Rulesets.Mania.Objects public double Duration { get; set; } public double EndTime => StartTime + Duration; + /// + /// The samples to be played when this hold note is released. + /// + public SampleInfoList EndSamples = new SampleInfoList(); + /// /// The key-release hit windows for this hold note. /// diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index ea65588a81..9e8d300328 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -47,6 +47,7 @@ + From b5674c8f300720c8bdd60072e0011cf60ba2b580 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 18 May 2017 19:33:02 +0900 Subject: [PATCH 021/112] Update DistanceObjectPatternGenerator.cs --- .../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 04e2b30816..d1cc638fe2 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -220,7 +220,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { addToPattern(pattern, column, startTime, startTime); startTime += segmentDuration; - + // Check if we're at the borders of the stage, and invert the pattern if so if (increasing) { From e52b87bc586512735493f1b76ce8b2e74e400ec5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 18 May 2017 19:47:16 +0900 Subject: [PATCH 022/112] Fix incorrect comment. --- .../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 d1cc638fe2..9ea4353317 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -255,7 +255,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy private Pattern generateRandomMultipleNotes(double startTime) { // - - - - - // x - - + // x - - - // - x x - // - - - x // x - x - From 793b760ff2244f0cfc6b424bffc84764b1986b1f Mon Sep 17 00:00:00 2001 From: Javier Flores Date: Thu, 18 May 2017 20:19:00 -0500 Subject: [PATCH 023/112] Cleanup logic --- .../Containers/BeatSyncedContainer.cs | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 3b10e96398..d7f5d6c112 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . +// Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; @@ -12,8 +12,8 @@ namespace osu.Game.Graphics.Containers public class BeatSyncedContainer : Container { private Bindable beatmap; - private int beat; - private double timingPointStart; + private int lastBeat; + private double lastTimingPointStart; //This is to avoid sending new beats when not at the very start of the beat private const int seek_tolerance = 20; private const double min_beat_length = 1E-100; @@ -22,27 +22,25 @@ namespace osu.Game.Graphics.Containers { if (beatmap.Value != null) { - double currentTime = beatmap.Value.Track.CurrentTime; + double trackCurrentTime = beatmap.Value.Track.CurrentTime; ControlPoint kiaiControlPoint; - ControlPoint controlPoint = beatmap.Value.Beatmap.TimingInfo.TimingPointAt(currentTime, out kiaiControlPoint); + ControlPoint controlPoint = beatmap.Value.Beatmap.TimingInfo.TimingPointAt(trackCurrentTime, out kiaiControlPoint); if (controlPoint != null) { - double oldTimingPointStart = timingPointStart; double beatLength = controlPoint.BeatLength; - int oldBeat = beat; bool kiai = kiaiControlPoint?.KiaiMode ?? false; - timingPointStart = controlPoint.Time; + double timingPointStart = controlPoint.Time; + int beat = beatLength > min_beat_length ? (int)((trackCurrentTime - timingPointStart) / beatLength) : 0; - beat = beatLength > min_beat_length ? (int)((currentTime - timingPointStart) / beatLength) : 0; - - //should we handle negative beats? (before the start of the controlPoint) //The beats before the start of the first control point are off by 1, this should do the trick - if (currentTime < timingPointStart) + if (trackCurrentTime < timingPointStart) beat--; - if ((timingPointStart != oldTimingPointStart || beat != oldBeat) && (int)((currentTime - timingPointStart) % beatLength) <= seek_tolerance) + if ((timingPointStart != lastTimingPointStart || beat != lastBeat) && (int)((trackCurrentTime - timingPointStart) % beatLength) <= seek_tolerance) OnNewBeat(beat, beatLength, controlPoint.TimeSignature, kiai); + lastBeat = beat; + lastTimingPointStart = timingPointStart; } } } From 90270ac5869d5ddb8212c67d603cacbc061b45c0 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 19 May 2017 17:48:23 +0900 Subject: [PATCH 024/112] Update to match base branch. --- .../Beatmaps/ManiaBeatmapConverter.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 933fe0787c..46ca90e02b 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -11,6 +11,7 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Mania.Beatmaps.Patterns; using osu.Game.Rulesets.Mania.MathUtils; using osu.Game.Database; +using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy; namespace osu.Game.Rulesets.Mania.Beatmaps { @@ -83,12 +84,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // Following lines currently commented out to appease resharper - //Patterns.PatternGenerator conversion = null; + Patterns.PatternGenerator conversion = null; if (distanceData != null) - { - // Slider - } + conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern); else if (endTimeData != null) { // Spinner @@ -98,13 +97,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // Circle } - //if (conversion == null) - return null; + if (conversion == null) + return null; - //Pattern newPattern = conversion.Generate(); - //lastPattern = newPattern; + Pattern newPattern = conversion.Generate(); + lastPattern = newPattern; - //return newPattern.HitObjects; + return newPattern.HitObjects; } /// From e76cb4cc3153bdc4e716f60a2a68c81bdf804bb4 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 19 May 2017 17:51:59 +0900 Subject: [PATCH 025/112] Update to match base branch. --- .../Beatmaps/ManiaBeatmapConverter.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 933fe0787c..9a93815ce3 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -11,6 +11,7 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Mania.Beatmaps.Patterns; using osu.Game.Rulesets.Mania.MathUtils; using osu.Game.Database; +using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy; namespace osu.Game.Rulesets.Mania.Beatmaps { @@ -83,28 +84,26 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // Following lines currently commented out to appease resharper - //Patterns.PatternGenerator conversion = null; + Patterns.PatternGenerator conversion = null; if (distanceData != null) { // Slider } else if (endTimeData != null) - { - // Spinner - } + conversion = new EndTimeObjectPatternGenerator(random, original, beatmap); else if (positionData != null) { // Circle } - //if (conversion == null) - return null; + if (conversion == null) + return null; - //Pattern newPattern = conversion.Generate(); - //lastPattern = newPattern; + Pattern newPattern = conversion.Generate(); + lastPattern = newPattern; - //return newPattern.HitObjects; + return newPattern.HitObjects; } /// From 6ab7a9141553fd7505d5672a0ecabc233e5bfdfc Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 19 May 2017 20:57:20 +0900 Subject: [PATCH 026/112] Add generator to generate patterns from HitObjects. --- .../Beatmaps/ManiaBeatmapConverter.cs | 50 ++- .../Legacy/HitObjectPatternGenerator.cs | 425 ++++++++++++++++++ .../osu.Game.Rulesets.Mania.csproj | 1 + 3 files changed, 469 insertions(+), 7 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 933fe0787c..e82b0dd516 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -11,11 +11,19 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Mania.Beatmaps.Patterns; using osu.Game.Rulesets.Mania.MathUtils; using osu.Game.Database; +using osu.Game.Beatmaps.Timing; +using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy; +using OpenTK; namespace osu.Game.Rulesets.Mania.Beatmaps { public class ManiaBeatmapConverter : BeatmapConverter { + /// + /// Maximum number of previous notes to consider for density calculation. + /// + private const int max_notes_for_density = 7; + protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; private Pattern lastPattern = new Pattern(); @@ -55,6 +63,26 @@ namespace osu.Game.Rulesets.Mania.Beatmaps yield return obj; } + private List prevNoteTimes = new List(max_notes_for_density); + private double density = int.MaxValue; + private void computeDensity(double newNoteTime) + { + if (prevNoteTimes.Count == max_notes_for_density) + prevNoteTimes.RemoveAt(0); + prevNoteTimes.Add(newNoteTime); + + density = (prevNoteTimes[prevNoteTimes.Count - 1] - prevNoteTimes[0]) / prevNoteTimes.Count; + } + + private double lastTime; + private Vector2 lastPosition; + private PatternType lastStair; + private void recordNote(double time, Vector2 position) + { + lastTime = time; + lastPosition = position; + } + /// /// Method that generates hit objects for osu!mania specific beatmaps. /// @@ -83,7 +111,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // Following lines currently commented out to appease resharper - //Patterns.PatternGenerator conversion = null; + Patterns.PatternGenerator conversion = null; if (distanceData != null) { @@ -95,16 +123,24 @@ namespace osu.Game.Rulesets.Mania.Beatmaps } else if (positionData != null) { - // Circle + computeDensity(original.StartTime); + + conversion = new HitObjectPatternGenerator(random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair); + + recordNote(original.StartTime, positionData.Position); } - //if (conversion == null) - return null; + if (conversion == null) + return null; - //Pattern newPattern = conversion.Generate(); - //lastPattern = newPattern; + Pattern newPattern = conversion.Generate(); + lastPattern = newPattern; - //return newPattern.HitObjects; + var stairPatternGenerator = conversion as HitObjectPatternGenerator; + if (stairPatternGenerator != null) + lastStair = stairPatternGenerator.StairType; + + return newPattern.HitObjects; } /// diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs new file mode 100644 index 0000000000..1591e0531c --- /dev/null +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -0,0 +1,425 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Linq; +using OpenTK; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Timing; +using osu.Game.Rulesets.Mania.MathUtils; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; + +namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy +{ + internal class HitObjectPatternGenerator : PatternGenerator + { + public PatternType StairType { get; private set; } + + private readonly PatternType convertType; + + public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair) + : base(random, hitObject, beatmap, previousPattern) + { + StairType = lastStair; + + ControlPoint overridePoint; + ControlPoint controlPoint = beatmap.TimingInfo.TimingPointAt(hitObject.StartTime, out overridePoint); + + var positionData = hitObject as IHasPosition; + + float positionSeparation = ((positionData?.Position ?? Vector2.Zero) - previousPosition).Length; + double timeSeparation = hitObject.StartTime - previousTime; + + double beatLength = controlPoint.BeatLength; + bool kiai = (overridePoint ?? controlPoint).KiaiMode; + + if (timeSeparation <= 125) + { + // More than 120 BPM + convertType |= PatternType.ForceNotStack; + } + + if (timeSeparation <= 80) + { + // More than 187 BPM + convertType |= PatternType.ForceNotStack | PatternType.KeepSingle; + } + else if (timeSeparation <= 95) + { + // More than 157 BPM + convertType |= PatternType.ForceNotStack | PatternType.KeepSingle | lastStair; + } + else if (timeSeparation <= 105) + { + // More than 140 BPM + convertType |= PatternType.ForceNotStack | PatternType.LowProbability; + } + else if (timeSeparation <= 125) + { + // More than 120 BPM + convertType |= PatternType.ForceNotStack; + } + else if (timeSeparation <= 135 && positionSeparation < 20) + { + // More than 111 BPM stream + convertType |= PatternType.Cycle | PatternType.KeepSingle; + } + else if (timeSeparation <= 150 & positionSeparation < 20) + { + // More than 100 BPM stream + convertType |= PatternType.ForceStack | PatternType.LowProbability; + } + else if (positionSeparation < 20 && density >= beatLength / 2.5) + { + // Low density stream + convertType |= PatternType.Reverse | PatternType.LowProbability; + } + else if (density < beatLength / 2.5 || kiai) + { + // High density + } + else + convertType |= PatternType.LowProbability; + } + + public override Pattern Generate() + { + int lastColumn = PreviousPattern.HitObjects.First().Column; + + if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Count() > 0) + { + // Generate a new pattern by copying the last hit objects in reverse-column order + var pattern = new Pattern(); + + int siblings = PreviousPattern.HitObjects.Count(h => h.Column >= RandomStart); + + for (int i = RandomStart; i < AvailableColumns; i++) + if (PreviousPattern.IsFilled(i)) + addToPattern(pattern, RandomStart + AvailableColumns - i - 1, siblings); + + return pattern; + } + + if ((convertType & PatternType.Cycle) > 0 && PreviousPattern.HitObjects.Count() == 1 + // If we convert to 7K + 1, let's not overload the special key + && (AvailableColumns != 8 || lastColumn != 0) + // Make sure the last column was not the centre column + && (AvailableColumns % 2 == 0 || lastColumn != AvailableColumns / 2)) + { + // Generate a new pattern by cycling backwards (similar to Reverse but for only one hit object) + var pattern = new Pattern(); + + int column = RandomStart + AvailableColumns - lastColumn - 1; + addToPattern(pattern, column); + + return pattern; + } + + if ((convertType & PatternType.ForceStack) > 0 && PreviousPattern.HitObjects.Count() > 0) + { + // Generate a new pattern by placing on the already filled columns + var pattern = new Pattern(); + + int siblings = PreviousPattern.HitObjects.Count(h => h.Column >= RandomStart); + + for (int i = RandomStart; i < AvailableColumns; i++) + if (PreviousPattern.IsFilled(i)) + addToPattern(pattern, i, siblings); + + return pattern; + } + + if ((convertType & PatternType.Stair) > 0 && PreviousPattern.HitObjects.Count() == 1) + { + // Generate a new pattern by placing on the next column, cycling back to the start if there is no "next" + var pattern = new Pattern(); + + int targetColumn = lastColumn + 1; + if (targetColumn == AvailableColumns) + { + targetColumn = RandomStart; + StairType = PatternType.ReverseStair; + } + + addToPattern(pattern, targetColumn, 1); + return pattern; + } + + if ((convertType & PatternType.ReverseStair) > 0 && PreviousPattern.HitObjects.Count() == 1) + { + // Generate a new pattern by placing on the previous column, cycling back to the end if there is no "previous" + var pattern = new Pattern(); + + int targetColumn = lastColumn - 1; + if (targetColumn == RandomStart - 1) + { + targetColumn = AvailableColumns - 1; + StairType = PatternType.Stair; + } + + addToPattern(pattern, targetColumn, 1); + return pattern; + } + + if ((convertType & PatternType.KeepSingle) > 0) + return generateRandomNotes(1); + + if ((convertType & PatternType.Mirror) > 0) + { + if (ConversionDifficulty > 6.5) + return generateRandomPatternWithMirrored(0.12, 0.38, 0.12); + if (ConversionDifficulty > 4) + return generateRandomPatternWithMirrored(0.12, 0.17, 0); + return generateRandomPatternWithMirrored(0.12, 0, 0); + } + + if (ConversionDifficulty > 6.5) + { + if ((convertType & PatternType.LowProbability) > 0) + return generateRandomPattern(0.78, 0.42, 0, 0); + return generateRandomPattern(1, 0.62, 0, 0); + } + + if (ConversionDifficulty > 4) + { + if ((convertType & PatternType.LowProbability) > 0) + return generateRandomPattern(0.35, 0.08, 0, 0); + return generateRandomPattern(0.52, 0.15, 0, 0); + } + + if (ConversionDifficulty > 2) + { + if ((convertType & PatternType.LowProbability) > 0) + return generateRandomPattern(0.18, 0, 0, 0); + return generateRandomPattern(0.45, 0, 0, 0); + } + + return generateRandomPattern(0, 0, 0, 0); + } + + /// + /// Generates random notes. + /// + /// This will generate as many as it can up to , accounting for + /// any stacks if is forcing no stacks. + /// + /// + /// The amount of notes to generate. + /// Custom siblings count if is not the number of siblings in this pattern. + /// The containing the hit objects. + private Pattern generateRandomNotes(int noteCount, int siblingsOverride = -1) + { + var pattern = new Pattern(); + + bool allowStacking = (convertType & PatternType.ForceNotStack) == 0; + + if (!allowStacking) + noteCount = Math.Min(noteCount, AvailableColumns - RandomStart - PreviousPattern.ColumnsFilled); + + int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); + for (int i = 0; i < noteCount; i++) + { + while (pattern.IsFilled(nextColumn) || (PreviousPattern.IsFilled(nextColumn) && !allowStacking)) + { + if ((convertType & PatternType.Gathered) > 0) + { + nextColumn++; + if (nextColumn == AvailableColumns) + nextColumn = RandomStart; + } + else + nextColumn = Random.Next(RandomStart, AvailableColumns); + } + + addToPattern(pattern, nextColumn, siblingsOverride != -1 ? siblingsOverride : noteCount); + } + + return pattern; + } + + /// + /// Whether this hit object can generate a note in the special column. + /// + private bool hasSpecialColumn() => HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP) && HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH); + + /// + /// Generates a random pattern. + /// + /// Probability for 2 notes to be generated. + /// Probability for 3 notes to be generated. + /// Probability for 4 notes to be generated. + /// Probability for 5 notes to be generated. + /// The containing the hit objects. + private Pattern generateRandomPattern(double p2, double p3, double p4, double p5) + { + var pattern = new Pattern(); + + int noteCount = getRandomNoteCount(p2, p3, p4, p5); + int siblings = noteCount; + + if (RandomStart > 0 && hasSpecialColumn(HitObject.Samples)) + { + siblings++; + addToPattern(pattern, 0, siblings); + } + + pattern.Add(generateRandomNotes(noteCount, siblings)); + + return pattern; + } + + /// + /// Generates a random pattern which has both normal and mirrored notes. + /// + /// The probability for a note to be added to the centre column. + /// Probability for 2 notes to be generated. + /// Probability for 3 notes to be generated. + /// The containing the hit objects. + private Pattern generateRandomPatternWithMirrored(double centreProbability, double p2, double p3) + { + var pattern = new Pattern(); + + bool addToCentre = false; + int noteCount = getRandomNoteCountMirrored(centreProbability, p2, p3, out addToCentre); + int siblings = noteCount; + + if (addToCentre) + siblings++; + if (RandomStart > 0 && hasSpecialColumn(HitObject.Samples)) + siblings++; + + int columnLimit = (AvailableColumns % 2 == 0 ? AvailableColumns : AvailableColumns - 1) / 2; + int nextColumn = Random.Next(RandomStart, columnLimit); + for (int i = 0; i < noteCount; i++) + { + while (pattern.IsFilled(nextColumn)) + nextColumn = Random.Next(RandomStart, columnLimit); + // Add normal note + addToPattern(pattern, nextColumn, siblings); + // Add mirrored note + addToPattern(pattern, RandomStart + AvailableColumns - nextColumn - 1); + } + + if (addToCentre) + addToPattern(pattern, AvailableColumns / 2, siblings); + + if (RandomStart > 0 && hasSpecialColumn(HitObject.Samples)) + addToPattern(pattern, 0, siblings); + + return pattern; + } + + /// + /// Generates a count of notes to be generated from a list of probabilities. + /// + /// Probability for 2 notes to be generated. + /// Probability for 3 notes to be generated. + /// Probability for 4 notes to be generated. + /// Probability for 5 notes to be generated. + /// The amount of notes to be generated. + private int getRandomNoteCount(double p2, double p3, double p4, double p5) + { + switch (AvailableColumns) + { + case 2: + p2 = 0; + p3 = 0; + p4 = 0; + p5 = 0; + break; + case 3: + p2 = Math.Max(p2, 0.1); + p3 = 0; + p4 = 0; + p5 = 0; + break; + case 4: + p2 = Math.Max(p2, 0.23); + p3 = Math.Max(p3, 0.04); + p4 = 0; + p5 = 0; + break; + case 5: + p3 = Math.Max(p3, 0.15); + p4 = Math.Max(p4, 0.03); + p5 = 0; + break; + } + + if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)) + p2 = 1; + + return GetRandomNoteCount(p2, p3, p4, p5); + } + + /// + /// Generates a count of notes to be generated from a list of probabilities. + /// + /// The probability for a note to be added to the centre column. + /// Probability for 2 notes to be generated. + /// Probability for 3 notes to be generated. + /// Whether to add a note to the centre column. + /// The amount of notes to be generated. The note to be added to the centre column will NOT be part of this count. + private int getRandomNoteCountMirrored(double centreProbability, double p2, double p3, out bool addToCentre) + { + addToCentre = false; + + if ((convertType & PatternType.ForceNotStack) > 0) + return getRandomNoteCount(p2 / 2, p2, (p2 + p3) / 2, p3); + + switch (AvailableColumns) + { + case 2: + centreProbability = 0; + p2 = 0; + p3 = 0; + break; + case 3: + centreProbability = Math.Max(centreProbability, 0.03); + p2 = Math.Max(p2, 0.1); + p3 = 0; + break; + case 4: + centreProbability = 0; + p2 = Math.Max(p2 * 2, 0.2); + p3 = 0; + break; + case 5: + centreProbability = Math.Max(centreProbability, 0.03); + p3 = 0; + break; + case 6: + centreProbability = 0; + p2 = Math.Max(p2 * 2, 0.5); + p3 = Math.Max(p3 * 2, 0.15); + break; + } + + double centreVal = Random.NextDouble(); + int noteCount = GetRandomNoteCount(p2, p3); + + addToCentre = AvailableColumns % 2 != 0 && noteCount != 3 && centreVal > 1 - centreProbability; + return noteCount; + } + + /// + /// Constructs and adds a note to a pattern. + /// + /// The pattern to add to. + /// The column to add the note to. + /// The number of children alongside this note (these will not be generated, but are used for volume calculations). + private void addToPattern(Pattern pattern, int column, int siblings = 1) + { + pattern.Add(new Note + { + StartTime = HitObject.StartTime, + Samples = HitObject.Samples, + Column = column, + Siblings = siblings + }); + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index ec426c895f..e2909504ec 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -49,6 +49,7 @@ + From f8270f31a9f6e8a1236c40132b810ff46a55239f Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 19 May 2017 21:15:29 +0900 Subject: [PATCH 027/112] Fix build errors. --- .../Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index 1591e0531c..5d3b84f57b 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -243,7 +243,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// /// Whether this hit object can generate a note in the special column. /// - private bool hasSpecialColumn() => HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP) && HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH); + private bool hasSpecialColumn => HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP) && HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH); /// /// Generates a random pattern. @@ -260,7 +260,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy int noteCount = getRandomNoteCount(p2, p3, p4, p5); int siblings = noteCount; - if (RandomStart > 0 && hasSpecialColumn(HitObject.Samples)) + if (RandomStart > 0 && hasSpecialColumn) { siblings++; addToPattern(pattern, 0, siblings); @@ -288,7 +288,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy if (addToCentre) siblings++; - if (RandomStart > 0 && hasSpecialColumn(HitObject.Samples)) + if (RandomStart > 0 && hasSpecialColumn) siblings++; int columnLimit = (AvailableColumns % 2 == 0 ? AvailableColumns : AvailableColumns - 1) / 2; @@ -306,7 +306,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy if (addToCentre) addToPattern(pattern, AvailableColumns / 2, siblings); - if (RandomStart > 0 && hasSpecialColumn(HitObject.Samples)) + if (RandomStart > 0 && hasSpecialColumn) addToPattern(pattern, 0, siblings); return pattern; From 8d94c2ef8be722d339181047cc94400ac8b2a2c5 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 19 May 2017 21:17:14 +0900 Subject: [PATCH 028/112] Fix CI errors (for now). --- osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs | 6 ++---- .../Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index e82b0dd516..53e06d451e 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -11,7 +11,6 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Mania.Beatmaps.Patterns; using osu.Game.Rulesets.Mania.MathUtils; using osu.Game.Database; -using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy; using OpenTK; @@ -136,9 +135,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps Pattern newPattern = conversion.Generate(); lastPattern = newPattern; - var stairPatternGenerator = conversion as HitObjectPatternGenerator; - if (stairPatternGenerator != null) - lastStair = stairPatternGenerator.StairType; + var stairPatternGenerator = (HitObjectPatternGenerator)conversion; + lastStair = stairPatternGenerator.StairType; return newPattern.HitObjects; } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index 5d3b84f57b..3de3d129bf 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -144,7 +144,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy StairType = PatternType.ReverseStair; } - addToPattern(pattern, targetColumn, 1); + addToPattern(pattern, targetColumn); return pattern; } @@ -160,7 +160,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy StairType = PatternType.Stair; } - addToPattern(pattern, targetColumn, 1); + addToPattern(pattern, targetColumn); return pattern; } @@ -282,7 +282,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { var pattern = new Pattern(); - bool addToCentre = false; + bool addToCentre; int noteCount = getRandomNoteCountMirrored(centreProbability, p2, p3, out addToCentre); int siblings = noteCount; From 24a813e907c19aae3dddae4c1bd4d4d2e7e4eb5a Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 20 May 2017 04:41:06 +0800 Subject: [PATCH 029/112] Basic children management of SectionsContainer. --- .../Graphics/Containers/SectionsContainer.cs | 74 +++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 2 files changed, 75 insertions(+) create mode 100644 osu.Game/Graphics/Containers/SectionsContainer.cs diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs new file mode 100644 index 0000000000..9c2485c49c --- /dev/null +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -0,0 +1,74 @@ +// Copyright (c) 2007-2017 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 System.Text; +using System.Threading.Tasks; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Graphics.Containers +{ + /// + /// A container that can scroll to each section inside it. + /// + public class SectionsContainer : Container + { + private Drawable expandableHeader, fixedHeader; + private ScrollContainer scrollContainer; + + public Drawable ExpandableHeader + { + get { return expandableHeader; } + set + { + if (value == expandableHeader) return; + + scrollContainer.Remove(expandableHeader); + expandableHeader = value; + expandableHeader.Depth = float.MinValue; + scrollContainer.Add(expandableHeader); + } + } + + public Drawable FixedHeader + { + get { return fixedHeader; } + set + { + if (value == fixedHeader) return; + + scrollContainer.Remove(fixedHeader); + fixedHeader = value; + fixedHeader.Depth = float.MinValue / 2; + scrollContainer.Add(fixedHeader); + } + } + + private List sections = new List(); + public IEnumerable Sections + { + get { return sections; } + set + { + if (value == sections) return; + + foreach (var section in sections) + scrollContainer.Remove(section); + + sections = value.ToList(); + scrollContainer.Add(value); + } + } + + public SectionsContainer() + { + Add(scrollContainer = new ScrollContainer + { + RelativeSizeAxes = Axes.Both + }); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ee906caa9b..1200276027 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -85,6 +85,7 @@ + From 058c5e18a424fcdbc5b29741ac198c1cfc17cfb3 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 20 May 2017 05:48:40 +0800 Subject: [PATCH 030/112] Scrolling support for SectionsContainer. --- .../Graphics/Containers/SectionsContainer.cs | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 9c2485c49c..3557a09622 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -26,10 +24,11 @@ namespace osu.Game.Graphics.Containers { if (value == expandableHeader) return; - scrollContainer.Remove(expandableHeader); + Remove(expandableHeader); expandableHeader = value; expandableHeader.Depth = float.MinValue; - scrollContainer.Add(expandableHeader); + Add(expandableHeader); + updateSectionMargin(); } } @@ -40,10 +39,11 @@ namespace osu.Game.Graphics.Containers { if (value == fixedHeader) return; - scrollContainer.Remove(fixedHeader); + Remove(fixedHeader); fixedHeader = value; fixedHeader.Depth = float.MinValue / 2; - scrollContainer.Add(fixedHeader); + Add(fixedHeader); + updateSectionMargin(); } } @@ -59,10 +59,25 @@ namespace osu.Game.Graphics.Containers scrollContainer.Remove(section); sections = value.ToList(); - scrollContainer.Add(value); + if (sections.Count == 0) return; + + originalSectionMargin = sections[0].Margin; + updateSectionMargin(); + scrollContainer.Add(sections); } } + private MarginPadding originalSectionMargin; + private void updateSectionMargin() + { + if (sections.Count == 0) return; + + var newMargin = originalSectionMargin; + newMargin.Top += ExpandableHeader?.Height ?? 0 + FixedHeader?.Height ?? 0; + + sections[0].Margin = newMargin; + } + public SectionsContainer() { Add(scrollContainer = new ScrollContainer @@ -70,5 +85,17 @@ namespace osu.Game.Graphics.Containers RelativeSizeAxes = Axes.Both }); } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + if (expandableHeader == null) return; + + float position = scrollContainer.Current; + float offset = Math.Max(expandableHeader.Height, position); + + expandableHeader.Y = -offset; + fixedHeader.Y = -offset + expandableHeader.Height; + } } } From e06c917c95fc50e356ee0a9000c6caa6585e9776 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 20 May 2017 06:39:01 +0800 Subject: [PATCH 031/112] Selection support of SectionsContainer. --- .../Graphics/Containers/SectionsContainer.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 3557a09622..536d53554a 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -47,6 +48,9 @@ namespace osu.Game.Graphics.Containers } } + public Bindable SelectedSection { get; } = new Bindable(); + public void ScrollToSection(Drawable section) => scrollContainer.ScrollIntoView(section); + private List sections = new List(); public IEnumerable Sections { @@ -64,6 +68,7 @@ namespace osu.Game.Graphics.Containers originalSectionMargin = sections[0].Margin; updateSectionMargin(); scrollContainer.Add(sections); + SelectedSection.Value = sections[0]; } } @@ -86,6 +91,7 @@ namespace osu.Game.Graphics.Containers }); } + float lastKnownScroll; protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); @@ -96,6 +102,28 @@ namespace osu.Game.Graphics.Containers expandableHeader.Y = -offset; fixedHeader.Y = -offset + expandableHeader.Height; + + float currentScroll = scrollContainer.Current; + if (currentScroll != lastKnownScroll) + { + lastKnownScroll = currentScroll; + + Drawable bestMatch = null; + float minDiff = float.MaxValue; + + foreach (var section in sections) + { + float diff = Math.Abs(scrollContainer.GetChildPosInContent(section) - currentScroll); + if (diff < minDiff) + { + minDiff = diff; + bestMatch = section; + } + } + + if (bestMatch != null) + SelectedSection.Value = bestMatch; + } } } } From 473441dfd4e5f3b91f1c34ff4dff3b6d1e3864ee Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 20 May 2017 07:07:27 +0800 Subject: [PATCH 032/112] Fix fields being null. --- osu.Game/Graphics/Containers/SectionsContainer.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 536d53554a..65bb318008 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -25,7 +25,8 @@ namespace osu.Game.Graphics.Containers { if (value == expandableHeader) return; - Remove(expandableHeader); + if (expandableHeader != null) + Remove(expandableHeader); expandableHeader = value; expandableHeader.Depth = float.MinValue; Add(expandableHeader); @@ -40,7 +41,8 @@ namespace osu.Game.Graphics.Containers { if (value == fixedHeader) return; - Remove(fixedHeader); + if (fixedHeader != null) + Remove(fixedHeader); fixedHeader = value; fixedHeader.Depth = float.MinValue / 2; Add(fixedHeader); From ecc222c0438b55d062a6853d8efc20a5b91f171e Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 20 May 2017 07:20:46 +0800 Subject: [PATCH 033/112] Allow custom SectionsContainer. --- .../Graphics/Containers/SectionsContainer.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 65bb318008..d46292cd9a 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -16,7 +16,8 @@ namespace osu.Game.Graphics.Containers public class SectionsContainer : Container { private Drawable expandableHeader, fixedHeader; - private ScrollContainer scrollContainer; + private readonly ScrollContainer scrollContainer; + private readonly Container sectionsContainer; public Drawable ExpandableHeader { @@ -53,6 +54,13 @@ namespace osu.Game.Graphics.Containers public Bindable SelectedSection { get; } = new Bindable(); public void ScrollToSection(Drawable section) => scrollContainer.ScrollIntoView(section); + protected virtual Container CreateSectionsContainer() + => new FillFlowContainer + { + Direction = FillDirection.Vertical, + AutoSizeAxes = Axes.Both + }; + private List sections = new List(); public IEnumerable Sections { @@ -62,14 +70,14 @@ namespace osu.Game.Graphics.Containers if (value == sections) return; foreach (var section in sections) - scrollContainer.Remove(section); + sectionsContainer.Remove(section); sections = value.ToList(); if (sections.Count == 0) return; originalSectionMargin = sections[0].Margin; updateSectionMargin(); - scrollContainer.Add(sections); + sectionsContainer.Add(sections); SelectedSection.Value = sections[0]; } } @@ -87,9 +95,10 @@ namespace osu.Game.Graphics.Containers public SectionsContainer() { - Add(scrollContainer = new ScrollContainer + Add(scrollContainer = new ScrollContainer() { - RelativeSizeAxes = Axes.Both + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { sectionsContainer = CreateSectionsContainer() } }); } From 57b9ed0f547fdcccd23aa66b5fdbe2f1e0aebd47 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sat, 20 May 2017 18:56:50 +0200 Subject: [PATCH 034/112] Do not pause a running replay if the window is not focused. --- 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 f9307595d2..3efc85d743 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -150,7 +150,7 @@ namespace osu.Game.Screens.Play FramedClock = offsetClock, OnRetry = Restart, OnQuit = Exit, - CheckCanPause = () => ValidForResume && !HasFailed, + CheckCanPause = () => ValidForResume && !HasFailed && !HitRenderer.HasReplayLoaded, Retries = RestartCount, OnPause = () => { hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; From 031fddc995fafeab7b7af3258adf4a151ca35915 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sat, 20 May 2017 19:53:18 +0200 Subject: [PATCH 035/112] Fix current beatmap track is started again when entering songselect and changing to another difficulty from the same beatmap set. --- osu.Game/Screens/Select/SongSelect.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index c352e6e034..75f23594d6 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -229,6 +229,8 @@ namespace osu.Game.Screens.Select changeBackground(Beatmap); + selectionChangeNoBounce = Beatmap.BeatmapInfo; + Content.FadeInFromZero(250); beatmapInfoWedge.State = Visibility.Visible; From da47b0a2603fddc62af2c22b755e258d8d301f61 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 21 May 2017 02:11:55 +0800 Subject: [PATCH 036/112] Fix margin and offset calculating. --- .../Graphics/Containers/SectionsContainer.cs | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index d46292cd9a..5f8ac332e4 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -29,9 +29,10 @@ namespace osu.Game.Graphics.Containers if (expandableHeader != null) Remove(expandableHeader); expandableHeader = value; + if (value == null) return; + expandableHeader.Depth = float.MinValue; Add(expandableHeader); - updateSectionMargin(); } } @@ -45,9 +46,10 @@ namespace osu.Game.Graphics.Containers if (fixedHeader != null) Remove(fixedHeader); fixedHeader = value; + if (value == null) return; + fixedHeader.Depth = float.MinValue / 2; Add(fixedHeader); - updateSectionMargin(); } } @@ -76,19 +78,19 @@ namespace osu.Game.Graphics.Containers if (sections.Count == 0) return; originalSectionMargin = sections[0].Margin; - updateSectionMargin(); sectionsContainer.Add(sections); SelectedSection.Value = sections[0]; } } + float headerHeight; private MarginPadding originalSectionMargin; private void updateSectionMargin() { if (sections.Count == 0) return; var newMargin = originalSectionMargin; - newMargin.Top += ExpandableHeader?.Height ?? 0 + FixedHeader?.Height ?? 0; + newMargin.Top += headerHeight; sections[0].Margin = newMargin; } @@ -102,23 +104,33 @@ namespace osu.Game.Graphics.Containers }); } - float lastKnownScroll; + float lastKnownScroll = float.NaN; protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); + + float height = (ExpandableHeader?.Height ?? 0) + (FixedHeader?.Height ?? 0); + if (height != headerHeight) + { + headerHeight = height; + updateSectionMargin(); + } + if (expandableHeader == null) return; - float position = scrollContainer.Current; - float offset = Math.Max(expandableHeader.Height, position); - - expandableHeader.Y = -offset; - fixedHeader.Y = -offset + expandableHeader.Height; - float currentScroll = scrollContainer.Current; if (currentScroll != lastKnownScroll) { lastKnownScroll = currentScroll; + if (expandableHeader != null) + { + float offset = Math.Min(expandableHeader.Height, currentScroll); + + expandableHeader.Y = -offset; + fixedHeader.Y = -offset + expandableHeader.Height; + } + Drawable bestMatch = null; float minDiff = float.MaxValue; From 306feb177a8fff73a9e0d46ae672cf6b56476514 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sat, 20 May 2017 20:18:29 +0200 Subject: [PATCH 037/112] Fix null pointer reference --- osu.Game/Screens/Select/SongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 75f23594d6..e9ead7c9c0 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -229,7 +229,7 @@ namespace osu.Game.Screens.Select changeBackground(Beatmap); - selectionChangeNoBounce = Beatmap.BeatmapInfo; + selectionChangeNoBounce = Beatmap?.BeatmapInfo; Content.FadeInFromZero(250); From e040f297c60b4d4df0398b5dd162585eeea4d3cb Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 21 May 2017 02:15:40 +0800 Subject: [PATCH 038/112] Set Masking = false and expose ScrollContainer. --- osu.Game/Graphics/Containers/SectionsContainer.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 5f8ac332e4..845970fde7 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -16,7 +16,7 @@ namespace osu.Game.Graphics.Containers public class SectionsContainer : Container { private Drawable expandableHeader, fixedHeader; - private readonly ScrollContainer scrollContainer; + public readonly ScrollContainer ScrollContainer; private readonly Container sectionsContainer; public Drawable ExpandableHeader @@ -54,7 +54,6 @@ namespace osu.Game.Graphics.Containers } public Bindable SelectedSection { get; } = new Bindable(); - public void ScrollToSection(Drawable section) => scrollContainer.ScrollIntoView(section); protected virtual Container CreateSectionsContainer() => new FillFlowContainer @@ -97,9 +96,10 @@ namespace osu.Game.Graphics.Containers public SectionsContainer() { - Add(scrollContainer = new ScrollContainer() + Add(ScrollContainer = new ScrollContainer() { RelativeSizeAxes = Axes.Both, + Masking = false, Children = new Drawable[] { sectionsContainer = CreateSectionsContainer() } }); } @@ -118,7 +118,7 @@ namespace osu.Game.Graphics.Containers if (expandableHeader == null) return; - float currentScroll = scrollContainer.Current; + float currentScroll = ScrollContainer.Current; if (currentScroll != lastKnownScroll) { lastKnownScroll = currentScroll; @@ -136,7 +136,7 @@ namespace osu.Game.Graphics.Containers foreach (var section in sections) { - float diff = Math.Abs(scrollContainer.GetChildPosInContent(section) - currentScroll); + float diff = Math.Abs(ScrollContainer.GetChildPosInContent(section) - currentScroll); if (diff < minDiff) { minDiff = diff; From 72621c81dc076908b67f21123b8ff0cca34b4ee0 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 21 May 2017 02:37:34 +0800 Subject: [PATCH 039/112] Handle null and invalidation of headers. --- osu.Game/Graphics/Containers/SectionsContainer.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 845970fde7..768141511c 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -33,6 +33,7 @@ namespace osu.Game.Graphics.Containers expandableHeader.Depth = float.MinValue; Add(expandableHeader); + lastKnownScroll = float.NaN; } } @@ -50,6 +51,7 @@ namespace osu.Game.Graphics.Containers fixedHeader.Depth = float.MinValue / 2; Add(fixedHeader); + lastKnownScroll = float.NaN; } } @@ -79,6 +81,7 @@ namespace osu.Game.Graphics.Containers originalSectionMargin = sections[0].Margin; sectionsContainer.Add(sections); SelectedSection.Value = sections[0]; + lastKnownScroll = float.NaN; } } @@ -104,7 +107,7 @@ namespace osu.Game.Graphics.Containers }); } - float lastKnownScroll = float.NaN; + float lastKnownScroll; protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); @@ -116,14 +119,12 @@ namespace osu.Game.Graphics.Containers updateSectionMargin(); } - if (expandableHeader == null) return; - float currentScroll = ScrollContainer.Current; if (currentScroll != lastKnownScroll) { lastKnownScroll = currentScroll; - if (expandableHeader != null) + if (expandableHeader != null && fixedHeader != null) { float offset = Math.Min(expandableHeader.Height, currentScroll); From 201b44dbf1f9421885d65f59eec11b3ca40f1182 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 21 May 2017 03:02:51 +0800 Subject: [PATCH 040/112] Do not make the name confusing. --- osu.Game/Graphics/Containers/SectionsContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 768141511c..1cf1219941 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -57,7 +57,7 @@ namespace osu.Game.Graphics.Containers public Bindable SelectedSection { get; } = new Bindable(); - protected virtual Container CreateSectionsContainer() + protected virtual Container CreateScrollContentContainer() => new FillFlowContainer { Direction = FillDirection.Vertical, @@ -103,7 +103,7 @@ namespace osu.Game.Graphics.Containers { RelativeSizeAxes = Axes.Both, Masking = false, - Children = new Drawable[] { sectionsContainer = CreateSectionsContainer() } + Children = new Drawable[] { sectionsContainer = CreateScrollContentContainer() } }); } From 93668e53a01427a2682d2dd169a2803131557a91 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 21 May 2017 03:44:03 +0800 Subject: [PATCH 041/112] Add footer support. --- .../Graphics/Containers/SectionsContainer.cs | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 1cf1219941..09a85c7dd3 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Graphics.Containers /// public class SectionsContainer : Container { - private Drawable expandableHeader, fixedHeader; + private Drawable expandableHeader, fixedHeader, footer; public readonly ScrollContainer ScrollContainer; private readonly Container sectionsContainer; @@ -31,7 +31,6 @@ namespace osu.Game.Graphics.Containers expandableHeader = value; if (value == null) return; - expandableHeader.Depth = float.MinValue; Add(expandableHeader); lastKnownScroll = float.NaN; } @@ -49,12 +48,30 @@ namespace osu.Game.Graphics.Containers fixedHeader = value; if (value == null) return; - fixedHeader.Depth = float.MinValue / 2; Add(fixedHeader); lastKnownScroll = float.NaN; } } + public Drawable Footer + { + get { return footer; } + set + { + if (value == footer) return; + + if (footer != null) + ScrollContainer.Remove(footer); + footer = value; + if (value == null) return; + + footer.Anchor |= Anchor.y2; + footer.Origin |= Anchor.y2; + ScrollContainer.Add(footer); + lastKnownScroll = float.NaN; + } + } + public Bindable SelectedSection { get; } = new Bindable(); protected virtual Container CreateScrollContentContainer() @@ -78,23 +95,23 @@ namespace osu.Game.Graphics.Containers sections = value.ToList(); if (sections.Count == 0) return; - originalSectionMargin = sections[0].Margin; sectionsContainer.Add(sections); SelectedSection.Value = sections[0]; lastKnownScroll = float.NaN; } } - float headerHeight; - private MarginPadding originalSectionMargin; - private void updateSectionMargin() + private float headerHeight, footerHeight; + private MarginPadding originalSectionsMargin; + private void updateSectionsMargin() { if (sections.Count == 0) return; - var newMargin = originalSectionMargin; + var newMargin = originalSectionsMargin; newMargin.Top += headerHeight; + newMargin.Bottom += footerHeight; - sections[0].Margin = newMargin; + sectionsContainer.Margin = newMargin; } public SectionsContainer() @@ -105,6 +122,7 @@ namespace osu.Game.Graphics.Containers Masking = false, Children = new Drawable[] { sectionsContainer = CreateScrollContentContainer() } }); + originalSectionsMargin = sectionsContainer.Margin; } float lastKnownScroll; @@ -112,11 +130,13 @@ namespace osu.Game.Graphics.Containers { base.UpdateAfterChildren(); - float height = (ExpandableHeader?.Height ?? 0) + (FixedHeader?.Height ?? 0); - if (height != headerHeight) + float headerHeight = (ExpandableHeader?.Height ?? 0) + (FixedHeader?.Height ?? 0); + float footerHeight = Footer?.Height ?? 0; + if (headerHeight != this.headerHeight || footerHeight != this.footerHeight) { - headerHeight = height; - updateSectionMargin(); + this.headerHeight = headerHeight; + this.footerHeight = footerHeight; + updateSectionsMargin(); } float currentScroll = ScrollContainer.Current; From 35712514a4baf27fb8aa891499eadcdad9e346e8 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 21 May 2017 03:50:04 +0800 Subject: [PATCH 042/112] Update settings UI using SectionsContainer basically. --- osu.Game/Overlays/SettingsOverlay.cs | 99 +++++++++++----------------- 1 file changed, 40 insertions(+), 59 deletions(-) diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index 71ad18e081..d348b2c6a1 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -7,10 +7,11 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Game.Overlays.Settings; -using System; -using osu.Game.Overlays.Settings.Sections; using osu.Framework.Input; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Settings; +using osu.Game.Overlays.Settings.Sections; namespace osu.Game.Overlays { @@ -37,6 +38,8 @@ namespace osu.Game.Overlays private SearchContainer searchContainer; + private SettingsSectionsContainer sectionsContainer; + private float lastKnownScroll; public SettingsOverlay() @@ -68,27 +71,27 @@ namespace osu.Game.Overlays Colour = Color4.Black, Alpha = 0.6f, }, - scrollContainer = new ScrollContainer + sectionsContainer = new SettingsSectionsContainer { - ScrollDraggerVisible = false, RelativeSizeAxes = Axes.Y, Width = width, Margin = new MarginPadding { Left = SIDEBAR_WIDTH }, - Children = new Drawable[] + ExpandableHeader = header = new SettingsHeader(() => sectionsContainer.ScrollContainer.Current), + FixedHeader = new SearchTextBox { - searchContainer = new SearchContainer + RelativeSizeAxes = Axes.X, + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Width = 0.95f, + Margin = new MarginPadding { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, - Children = sections, + Top = 20, + Bottom = 20 }, - footer = new SettingsFooter(), - header = new SettingsHeader(() => scrollContainer.Current) - { - Exit = Hide, - }, - } + Exit = Hide, + }, + Sections = sections, + Footer = footer = new SettingsFooter() }, sidebar = new Sidebar { @@ -104,54 +107,16 @@ namespace osu.Game.Overlays } }; - header.SearchTextBox.Current.ValueChanged += newValue => searchContainer.SearchTerm = newValue; + //header.SearchTextBox.Current.ValueChanged += newValue => searchContainer.SearchTerm = newValue; - scrollContainer.Padding = new MarginPadding { Top = game?.Toolbar.DrawHeight ?? 0 }; - } - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - //we need to update these manually because we can't put the SettingsHeader inside the SearchContainer (due to its anchoring). - searchContainer.Y = header.DrawHeight; - footer.Y = searchContainer.Y + searchContainer.DrawHeight; - } - - protected override void Update() - { - base.Update(); - - float currentScroll = scrollContainer.Current; - if (currentScroll != lastKnownScroll) - { - lastKnownScroll = currentScroll; - - SettingsSection bestCandidate = null; - float bestDistance = float.MaxValue; - - foreach (SettingsSection section in sections) - { - float distance = Math.Abs(scrollContainer.GetChildPosInContent(section) - currentScroll); - if (distance < bestDistance) - { - bestDistance = distance; - bestCandidate = section; - } - } - - var previous = sidebarButtons.SingleOrDefault(sb => sb.Selected); - var next = sidebarButtons.SingleOrDefault(sb => sb.Section == bestCandidate); - if (previous != null) previous.Selected = false; - if (next != null) next.Selected = true; - } + sectionsContainer.Padding = new MarginPadding { Top = game?.Toolbar.DrawHeight ?? 0 }; } protected override void PopIn() { base.PopIn(); - scrollContainer.MoveToX(0, TRANSITION_LENGTH, EasingTypes.OutQuint); + sectionsContainer.MoveToX(0, TRANSITION_LENGTH, EasingTypes.OutQuint); sidebar.MoveToX(0, TRANSITION_LENGTH, EasingTypes.OutQuint); FadeTo(1, TRANSITION_LENGTH / 2); @@ -162,7 +127,7 @@ namespace osu.Game.Overlays { base.PopOut(); - scrollContainer.MoveToX(-width, TRANSITION_LENGTH, EasingTypes.OutQuint); + sectionsContainer.MoveToX(-width, TRANSITION_LENGTH, EasingTypes.OutQuint); sidebar.MoveToX(-SIDEBAR_WIDTH, TRANSITION_LENGTH, EasingTypes.OutQuint); FadeTo(0, TRANSITION_LENGTH / 2); @@ -175,5 +140,21 @@ namespace osu.Game.Overlays header.SearchTextBox.TriggerFocus(state); return false; } + + private class SettingsSectionsContainer : SectionsContainer + { + public SearchContainer SearchContainer; + protected override Container CreateScrollContentContainer() + => SearchContainer = new SearchContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + }; + public SettingsSectionsContainer() + { + ScrollContainer.ScrollDraggerVisible = false; + } + } } } From a98f109d733836bb8bb6e72b93ad12d0f65bb106 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 21 May 2017 04:01:07 +0800 Subject: [PATCH 043/112] Use LayoutSize for header and footer layout. --- osu.Game/Graphics/Containers/SectionsContainer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 09a85c7dd3..b0de350930 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -130,8 +130,8 @@ namespace osu.Game.Graphics.Containers { base.UpdateAfterChildren(); - float headerHeight = (ExpandableHeader?.Height ?? 0) + (FixedHeader?.Height ?? 0); - float footerHeight = Footer?.Height ?? 0; + float headerHeight = (ExpandableHeader?.LayoutSize.Y ?? 0) + (FixedHeader?.LayoutSize.Y ?? 0); + float footerHeight = Footer?.LayoutSize.Y ?? 0; if (headerHeight != this.headerHeight || footerHeight != this.footerHeight) { this.headerHeight = headerHeight; @@ -146,10 +146,10 @@ namespace osu.Game.Graphics.Containers if (expandableHeader != null && fixedHeader != null) { - float offset = Math.Min(expandableHeader.Height, currentScroll); + float offset = Math.Min(expandableHeader.LayoutSize.Y, currentScroll); expandableHeader.Y = -offset; - fixedHeader.Y = -offset + expandableHeader.Height; + fixedHeader.Y = -offset + expandableHeader.LayoutSize.Y; } Drawable bestMatch = null; From aa409ac1a9931e45e6083ed71fe455469541932d Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 21 May 2017 04:12:16 +0800 Subject: [PATCH 044/112] Move SearchTextBox out of SettingsHeader. --- osu.Game/Overlays/Settings/SettingsHeader.cs | 60 ++------------------ osu.Game/Overlays/SettingsOverlay.cs | 46 +++++++++------ 2 files changed, 33 insertions(+), 73 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsHeader.cs b/osu.Game/Overlays/Settings/SettingsHeader.cs index 56018dc7d9..c554b54a87 100644 --- a/osu.Game/Overlays/Settings/SettingsHeader.cs +++ b/osu.Game/Overlays/Settings/SettingsHeader.cs @@ -1,34 +1,16 @@ // Copyright (c) 2007-2017 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.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using OpenTK.Graphics; namespace osu.Game.Overlays.Settings { public class SettingsHeader : Container { - public SearchTextBox SearchTextBox; - - private Box background; - - private readonly Func currentScrollOffset; - - public Action Exit; - - /// A reference to the current scroll position of the ScrollContainer we are contained within. - public SettingsHeader(Func currentScrollOffset) - { - this.currentScrollOffset = currentScrollOffset; - } - [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -37,11 +19,6 @@ namespace osu.Game.Overlays.Settings Children = new Drawable[] { - background = new Box - { - Colour = Color4.Black, - RelativeSizeAxes = Axes.Both, - }, new FillFlowContainer { AutoSizeAxes = Axes.Y, @@ -53,7 +30,8 @@ namespace osu.Game.Overlays.Settings { Text = "settings", TextSize = 40, - Margin = new MarginPadding { + Margin = new MarginPadding + { Left = SettingsOverlay.CONTENT_MARGINS, Top = Toolbar.Toolbar.TOOLTIP_HEIGHT }, @@ -63,45 +41,15 @@ namespace osu.Game.Overlays.Settings Colour = colours.Pink, Text = "Change the way osu! behaves", TextSize = 18, - Margin = new MarginPadding { + Margin = new MarginPadding + { Left = SettingsOverlay.CONTENT_MARGINS, Bottom = 30 }, }, - SearchTextBox = new SearchTextBox - { - RelativeSizeAxes = Axes.X, - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Width = 0.95f, - Margin = new MarginPadding { - Top = 20, - Bottom = 20 - }, - Exit = () => Exit(), - }, } } }; } - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - // the point at which we will start anchoring to the top. - float anchorOffset = SearchTextBox.Y; - - float scrollPosition = currentScrollOffset(); - - // we want to anchor the search field to the top of the screen when scrolling. - Margin = new MarginPadding { Top = Math.Max(0, scrollPosition - anchorOffset) }; - - // we don't want the header to scroll when scrolling beyond the upper extent. - Y = Math.Min(0, scrollPosition); - - // we get darker as scroll progresses - background.Alpha = Math.Min(1, scrollPosition / anchorOffset) * 0.5f; - } } } \ No newline at end of file diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index d348b2c6a1..05834c9823 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -27,20 +27,13 @@ namespace osu.Game.Overlays private const float sidebar_padding = 10; - private ScrollContainer scrollContainer; private Sidebar sidebar; private SidebarButton[] sidebarButtons; private SettingsSection[] sections; - private SettingsHeader header; - - private SettingsFooter footer; - - private SearchContainer searchContainer; - private SettingsSectionsContainer sectionsContainer; - private float lastKnownScroll; + private SearchTextBox searchTextBox; public SettingsOverlay() { @@ -76,8 +69,8 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Y, Width = width, Margin = new MarginPadding { Left = SIDEBAR_WIDTH }, - ExpandableHeader = header = new SettingsHeader(() => sectionsContainer.ScrollContainer.Current), - FixedHeader = new SearchTextBox + ExpandableHeader = new SettingsHeader(), + FixedHeader = searchTextBox = new SearchTextBox { RelativeSizeAxes = Axes.X, Origin = Anchor.TopCentre, @@ -91,7 +84,7 @@ namespace osu.Game.Overlays Exit = Hide, }, Sections = sections, - Footer = footer = new SettingsFooter() + Footer = new SettingsFooter() }, sidebar = new Sidebar { @@ -101,13 +94,13 @@ namespace osu.Game.Overlays { Selected = sections[0] == section, Section = section, - Action = () => scrollContainer.ScrollIntoView(section), + Action = () => sectionsContainer.ScrollContainer.ScrollIntoView(section), } ).ToArray() } }; - //header.SearchTextBox.Current.ValueChanged += newValue => searchContainer.SearchTerm = newValue; + searchTextBox.Current.ValueChanged += newValue => sectionsContainer.SearchContainer.SearchTerm = newValue; sectionsContainer.Padding = new MarginPadding { Top = game?.Toolbar.DrawHeight ?? 0 }; } @@ -120,7 +113,7 @@ namespace osu.Game.Overlays sidebar.MoveToX(0, TRANSITION_LENGTH, EasingTypes.OutQuint); FadeTo(1, TRANSITION_LENGTH / 2); - header.SearchTextBox.HoldFocus = true; + searchTextBox.HoldFocus = true; } protected override void PopOut() @@ -131,19 +124,21 @@ namespace osu.Game.Overlays sidebar.MoveToX(-SIDEBAR_WIDTH, TRANSITION_LENGTH, EasingTypes.OutQuint); FadeTo(0, TRANSITION_LENGTH / 2); - header.SearchTextBox.HoldFocus = false; - header.SearchTextBox.TriggerFocusLost(); + searchTextBox.HoldFocus = false; + searchTextBox.TriggerFocusLost(); } protected override bool OnFocus(InputState state) { - header.SearchTextBox.TriggerFocus(state); + searchTextBox.TriggerFocus(state); return false; } private class SettingsSectionsContainer : SectionsContainer { public SearchContainer SearchContainer; + private readonly Box headerBackground; + protected override Container CreateScrollContentContainer() => SearchContainer = new SearchContainer { @@ -151,9 +146,26 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.X, Direction = FillDirection.Vertical, }; + public SettingsSectionsContainer() { ScrollContainer.ScrollDraggerVisible = false; + Add(headerBackground = new Box + { + Colour = Color4.Black, + RelativeSizeAxes = Axes.X, + Depth = float.MaxValue + }); + } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + // no null check because the usage of this class is strict + headerBackground.Height = ExpandableHeader.LayoutSize.Y + FixedHeader.LayoutSize.Y; + headerBackground.Y = ExpandableHeader.Y; + headerBackground.Alpha = -ExpandableHeader.Y / ExpandableHeader.LayoutSize.Y * 0.5f; } } } From f76abe2329e2a64323075f2b064678c737ced52e Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sat, 20 May 2017 22:13:23 +0200 Subject: [PATCH 045/112] Disallow clicking through the song select footer. --- osu.Game/Screens/Select/Footer.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/Footer.cs b/osu.Game/Screens/Select/Footer.cs index 6863f209e6..339256704b 100644 --- a/osu.Game/Screens/Select/Footer.cs +++ b/osu.Game/Screens/Select/Footer.cs @@ -9,6 +9,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input; using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Menu; @@ -33,7 +34,7 @@ namespace osu.Game.Screens.Select private readonly FillFlowContainer buttons; public OsuLogo StartButton; - + /// Text on the button. /// Colour of the button. /// Hotkey of the button. @@ -68,8 +69,6 @@ namespace osu.Game.Screens.Select public Footer() { - AlwaysReceiveInput = true; - RelativeSizeAxes = Axes.X; Height = HEIGHT; Anchor = Anchor.BottomCentre; @@ -124,5 +123,13 @@ namespace osu.Game.Screens.Select updateModeLight(); } + + protected override bool InternalContains(Vector2 screenSpacePos) => base.InternalContains(screenSpacePos) || StartButton.Contains(screenSpacePos); + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true; + + protected override bool OnClick(InputState state) => true; + + protected override bool OnDragStart(InputState state) => true; } } From 97aadad1133f2c2b399263fcc650fe7db96a054f Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sat, 20 May 2017 22:16:05 +0200 Subject: [PATCH 046/112] Trimmed spaces. --- osu.Game/Screens/Select/Footer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Footer.cs b/osu.Game/Screens/Select/Footer.cs index 339256704b..136959ba79 100644 --- a/osu.Game/Screens/Select/Footer.cs +++ b/osu.Game/Screens/Select/Footer.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Select private readonly FillFlowContainer buttons; public OsuLogo StartButton; - + /// Text on the button. /// Colour of the button. /// Hotkey of the button. From 33ebc8fd49fe5b1a874b7111fbde4214c85ff450 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sat, 20 May 2017 22:23:49 +0200 Subject: [PATCH 047/112] Trimmed more whitespaces --- osu.Game/Screens/Select/Footer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/Footer.cs b/osu.Game/Screens/Select/Footer.cs index 136959ba79..32e09a5f28 100644 --- a/osu.Game/Screens/Select/Footer.cs +++ b/osu.Game/Screens/Select/Footer.cs @@ -123,9 +123,9 @@ namespace osu.Game.Screens.Select updateModeLight(); } - + protected override bool InternalContains(Vector2 screenSpacePos) => base.InternalContains(screenSpacePos) || StartButton.Contains(screenSpacePos); - + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true; protected override bool OnClick(InputState state) => true; From f06f8b4dcd67d7e77fa3c567961267ed18fab095 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 21 May 2017 04:32:15 +0800 Subject: [PATCH 048/112] Make sidebar buttons working. --- osu.Game/Overlays/Settings/SidebarButton.cs | 5 +++-- osu.Game/Overlays/SettingsOverlay.cs | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Settings/SidebarButton.cs b/osu.Game/Overlays/Settings/SidebarButton.cs index 766c6cf7e2..b6e4ad3f5e 100644 --- a/osu.Game/Overlays/Settings/SidebarButton.cs +++ b/osu.Game/Overlays/Settings/SidebarButton.cs @@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Settings private readonly Box backgroundBox; private readonly Box selectionIndicator; private readonly Container text; - public Action Action; + public Action Action; private SettingsSection section; public SettingsSection Section @@ -75,6 +75,7 @@ namespace osu.Game.Overlays.Settings { Width = Sidebar.DEFAULT_WIDTH, RelativeSizeAxes = Axes.Y, + Colour = OsuColour.Gray(0.6f), Children = new[] { headerText = new OsuSpriteText @@ -110,7 +111,7 @@ namespace osu.Game.Overlays.Settings protected override bool OnClick(InputState state) { - Action?.Invoke(); + Action?.Invoke(section); backgroundBox.FlashColour(Color4.White, 400); return true; } diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index 05834c9823..af24a057e9 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -29,7 +29,7 @@ namespace osu.Game.Overlays private Sidebar sidebar; private SidebarButton[] sidebarButtons; - private SettingsSection[] sections; + private SidebarButton selectedSidebarButton; private SettingsSectionsContainer sectionsContainer; @@ -44,7 +44,7 @@ namespace osu.Game.Overlays [BackgroundDependencyLoader(permitNulls: true)] private void load(OsuGame game) { - sections = new SettingsSection[] + var sections = new SettingsSection[] { new GeneralSection(), new GraphicsSection(), @@ -92,14 +92,23 @@ namespace osu.Game.Overlays Children = sidebarButtons = sections.Select(section => new SidebarButton { - Selected = sections[0] == section, Section = section, - Action = () => sectionsContainer.ScrollContainer.ScrollIntoView(section), + Action = sectionsContainer.ScrollContainer.ScrollIntoView, } ).ToArray() } }; + selectedSidebarButton = sidebarButtons[0]; + selectedSidebarButton.Selected = true; + + sectionsContainer.SelectedSection.ValueChanged += section => + { + selectedSidebarButton.Selected = false; + selectedSidebarButton = sidebarButtons.Single(b => b.Section == section); + selectedSidebarButton.Selected = true; + }; + searchTextBox.Current.ValueChanged += newValue => sectionsContainer.SearchContainer.SearchTerm = newValue; sectionsContainer.Padding = new MarginPadding { Top = game?.Toolbar.DrawHeight ?? 0 }; From 7357076c4d3bf368f635886ff25bc667995a9f09 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 21 May 2017 04:48:43 +0800 Subject: [PATCH 049/112] CI fixes. --- .../Graphics/Containers/SectionsContainer.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index b0de350930..7b57cb1b56 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -87,8 +87,6 @@ namespace osu.Game.Graphics.Containers get { return sections; } set { - if (value == sections) return; - foreach (var section in sections) sectionsContainer.Remove(section); @@ -102,7 +100,7 @@ namespace osu.Game.Graphics.Containers } private float headerHeight, footerHeight; - private MarginPadding originalSectionsMargin; + private readonly MarginPadding originalSectionsMargin; private void updateSectionsMargin() { if (sections.Count == 0) return; @@ -125,17 +123,17 @@ namespace osu.Game.Graphics.Containers originalSectionsMargin = sectionsContainer.Margin; } - float lastKnownScroll; + private float lastKnownScroll; protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); - float headerHeight = (ExpandableHeader?.LayoutSize.Y ?? 0) + (FixedHeader?.LayoutSize.Y ?? 0); - float footerHeight = Footer?.LayoutSize.Y ?? 0; - if (headerHeight != this.headerHeight || footerHeight != this.footerHeight) + float headerH = (ExpandableHeader?.LayoutSize.Y ?? 0) + (FixedHeader?.LayoutSize.Y ?? 0); + float footerH = Footer?.LayoutSize.Y ?? 0; + if (headerH != headerHeight || footerH != footerHeight) { - this.headerHeight = headerHeight; - this.footerHeight = footerHeight; + headerHeight = headerH; + footerHeight = footerH; updateSectionsMargin(); } From 44cad4e0acde2198881181ed9d78d9e59337cab5 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 03:04:12 +0200 Subject: [PATCH 050/112] Fix a bug that prevents the lowest beatmap group from being selected if it is not completly on-screen. --- osu.Game/Screens/Select/BeatmapCarousel.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 4df24c1314..486b0795c4 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -409,7 +409,14 @@ namespace osu.Game.Screens.Select int firstIndex = yPositions.BinarySearch(Current - Panel.MAX_HEIGHT); if (firstIndex < 0) firstIndex = ~firstIndex; int lastIndex = yPositions.BinarySearch(Current + drawHeight); - if (lastIndex < 0) lastIndex = ~lastIndex; + if (lastIndex < 0) + { + lastIndex = ~lastIndex; + + // Add the first panel of the last visible beatmap group to preload its data. + if (lastIndex != yPositions.Count) + lastIndex++; + } // Add those panels within the previously found index range that should be displayed. for (int i = firstIndex; i < lastIndex; ++i) From 18a7271dc6ad3d5a487fb8d0e4436221c6508c3c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 21 May 2017 17:07:16 +0900 Subject: [PATCH 051/112] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index d00a7df902..60e0a343d2 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit d00a7df902074d0b3f1479904b7f322db9d39c1f +Subproject commit 60e0a343d2bf590f736782e2bb2a01c132e6cac0 From 95498fe6df783eb5fd15fb55fd1d14a7e6f088e8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 21 May 2017 17:21:49 +0900 Subject: [PATCH 052/112] Adjust spinner colours making use of EdgeEffect.Hollow --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs | 2 +- .../Objects/Drawables/Pieces/SpinnerBackground.cs | 5 +++-- .../Objects/Drawables/Pieces/SpinnerDisc.cs | 2 +- .../Objects/Drawables/Pieces/SpinnerTicks.cs | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 854a9b5f49..cc5086f442 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -158,7 +158,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables background.AccentColour = normalColour; - completeColour = colours.YellowLight.Opacity(0.6f); + completeColour = colours.YellowLight.Opacity(0.75f); disc.AccentColour = colours.SpinnerFill; circle.Colour = colours.BlueDark; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs index 1c54f9f893..aa8dea50a4 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs @@ -28,9 +28,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces EdgeEffect = new EdgeEffect { + Hollow = true, Type = EdgeEffectType.Glow, - Radius = 14, - Colour = value.Opacity(0.3f), + Radius = 40, + Colour = value, }; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 4e4d4e30b9..29d6d1f147 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -127,7 +127,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces if (Complete && updateCompleteTick()) { background.Flush(flushType: typeof(TransformAlpha)); - background.FadeTo(tracking_alpha + 0.4f, 60, EasingTypes.OutExpo); + background.FadeTo(tracking_alpha + 0.2f, 60, EasingTypes.OutExpo); background.Delay(60); background.FadeTo(tracking_alpha, 250, EasingTypes.OutQuint); } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs index dc3d18d40a..c0e16288be 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces [BackgroundDependencyLoader] private void load(OsuColour colours) { - glowColour = colours.BlueDarker.Opacity(0.4f); + glowColour = Color4.Gray.Opacity(0.2f); layout(); } @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces EdgeEffect = new EdgeEffect { Type = EdgeEffectType.Glow, - Radius = 20, + Radius = 10, Colour = glowColour, }, RelativePositionAxes = Axes.Both, From 8f3ab79918585b5322fc351a6305cb41f94fff3f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 21 May 2017 17:29:00 +0900 Subject: [PATCH 053/112] Simplify SpinnerTicks & CI fixes --- .../Drawables/Pieces/SpinnerBackground.cs | 1 - .../Objects/Drawables/Pieces/SpinnerTicks.cs | 16 +--------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs index aa8dea50a4..66cf7758b9 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs @@ -2,7 +2,6 @@ // 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.Sprites; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs index c0e16288be..4dbb6bd4d6 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs @@ -2,12 +2,10 @@ // 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; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; using OpenTK; using OpenTK.Graphics; @@ -15,24 +13,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { public class SpinnerTicks : Container { - private Color4 glowColour; - public SpinnerTicks() { Origin = Anchor.Centre; Anchor = Anchor.Centre; RelativeSizeAxes = Axes.Both; - } - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - glowColour = Color4.Gray.Opacity(0.2f); - layout(); - } - - private void layout() - { const int count = 18; for (int i = 0; i < count; i++) @@ -45,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { Type = EdgeEffectType.Glow, Radius = 10, - Colour = glowColour, + Colour = Color4.Gray.Opacity(0.2f), }, RelativePositionAxes = Axes.Both, Masking = true, From 1546bbc66b812e4d57e14a32141a4f294e91f8c4 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 13:04:04 +0200 Subject: [PATCH 054/112] Updated preload condition. --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 486b0795c4..d283988fd5 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -414,7 +414,7 @@ namespace osu.Game.Screens.Select lastIndex = ~lastIndex; // Add the first panel of the last visible beatmap group to preload its data. - if (lastIndex != yPositions.Count) + if (panels[lastIndex - 1] is BeatmapSetHeader) lastIndex++; } From 662ea0ec2dee4c71074a2b53979369d9d6a88a63 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 14:00:40 +0200 Subject: [PATCH 055/112] Repeat a beatmap's track if it has ended --- osu.Game/Screens/Select/SongSelect.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index e9ead7c9c0..57d844e214 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -365,6 +365,13 @@ namespace osu.Game.Screens.Select dialogOverlay?.Push(new BeatmapDeleteDialog(Beatmap)); } + protected override void Update() + { + base.Update(); + + ensurePlayingSelected(); + } + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { if (args.Repeat) return false; From 043d1ed20a81655255abb3757b296ffa22864725 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 14:08:04 +0200 Subject: [PATCH 056/112] Updated preload condition to handle special case --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index d283988fd5..749dc97571 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -414,7 +414,7 @@ namespace osu.Game.Screens.Select lastIndex = ~lastIndex; // Add the first panel of the last visible beatmap group to preload its data. - if (panels[lastIndex - 1] is BeatmapSetHeader) + if (lastIndex != 0 && panels[lastIndex - 1] is BeatmapSetHeader) lastIndex++; } From 48f4879157a7cecd6daec2e79cfb189396177417 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 15:57:41 +0200 Subject: [PATCH 057/112] Use the track's implemented looping algorithm to loop tracks in the song select screen --- osu.Game/Screens/Select/PlaySongSelect.cs | 10 +++++++++- osu.Game/Screens/Select/SongSelect.cs | 8 +------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 8f91f1ed0f..3960a4ea65 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -65,6 +65,8 @@ namespace osu.Game.Screens.Select protected override void OnResuming(Screen last) { player = null; + Beatmap.Track.Looping = false; + base.OnResuming(last); } @@ -83,13 +85,19 @@ namespace osu.Game.Screens.Select return true; } - return base.OnExiting(next); + if (base.OnExiting(next)) + return true; + + Beatmap.Track.Looping = false; + return false; } protected override void OnSelected() { if (player != null) return; + Beatmap.Track.Looping = false; + LoadComponentAsync(player = new PlayerLoader(new Player { Beatmap = Beatmap, //eagerly set this so it's present before push. diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 57d844e214..dca65d1837 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -348,6 +348,7 @@ namespace osu.Game.Screens.Select trackManager.SetExclusive(track); if (preview) track.Seek(Beatmap.Metadata.PreviewTime); + track.Looping = true; track.Start(); } } @@ -365,13 +366,6 @@ namespace osu.Game.Screens.Select dialogOverlay?.Push(new BeatmapDeleteDialog(Beatmap)); } - protected override void Update() - { - base.Update(); - - ensurePlayingSelected(); - } - protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { if (args.Repeat) return false; From cc35cc281c4a518765a3745b6a96561f0ec7557d Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 16:10:10 +0200 Subject: [PATCH 058/112] Fixed null reference in case there are no beatmaps --- osu.Game/Screens/Select/PlaySongSelect.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 3960a4ea65..361311248b 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -87,8 +87,10 @@ namespace osu.Game.Screens.Select if (base.OnExiting(next)) return true; + + if(Beatmap != null) + Beatmap.Track.Looping = false; - Beatmap.Track.Looping = false; return false; } From ec213efc49b334b4bf90a4d0529e4d441c8151e2 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 16:13:20 +0200 Subject: [PATCH 059/112] Trimmed whitespaces --- osu.Game/Screens/Select/PlaySongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 361311248b..5bcfdb8dbd 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -87,7 +87,7 @@ namespace osu.Game.Screens.Select if (base.OnExiting(next)) return true; - + if(Beatmap != null) Beatmap.Track.Looping = false; From 7db45cb58ffc559877e9f30916d8dadf6a9623cf Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 17:09:56 +0200 Subject: [PATCH 060/112] Moved the whole looping assignments inside PlaySongSelect --- osu.Game/Screens/Select/PlaySongSelect.cs | 5 +++-- osu.Game/Screens/Select/SongSelect.cs | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 5bcfdb8dbd..eb46e766b2 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -57,7 +57,9 @@ namespace osu.Game.Screens.Select { beatmap?.Mods.BindTo(modSelect.SelectedMods); + if (Beatmap != null) Beatmap.Track.Looping = false; beatmapDetails.Beatmap = beatmap; + if(beatmap != null) beatmap.Track.Looping = true; base.OnBeatmapChanged(beatmap); } @@ -88,8 +90,7 @@ namespace osu.Game.Screens.Select if (base.OnExiting(next)) return true; - if(Beatmap != null) - Beatmap.Track.Looping = false; + if(Beatmap != null) Beatmap.Track.Looping = false; return false; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index dca65d1837..e9ead7c9c0 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -348,7 +348,6 @@ namespace osu.Game.Screens.Select trackManager.SetExclusive(track); if (preview) track.Seek(Beatmap.Metadata.PreviewTime); - track.Looping = true; track.Start(); } } From 34653eb8c033b5e5e6d40f9803162de4c0360730 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 17:20:20 +0200 Subject: [PATCH 061/112] Fixed null references --- osu.Game/Screens/Select/PlaySongSelect.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index eb46e766b2..a3fe6e3fe7 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -57,9 +57,9 @@ namespace osu.Game.Screens.Select { beatmap?.Mods.BindTo(modSelect.SelectedMods); - if (Beatmap != null) Beatmap.Track.Looping = false; + if (Beatmap != null && Beatmap.Track != null) Beatmap.Track.Looping = false; beatmapDetails.Beatmap = beatmap; - if(beatmap != null) beatmap.Track.Looping = true; + if(beatmap != null && beatmap.Track != null) beatmap.Track.Looping = true; base.OnBeatmapChanged(beatmap); } @@ -90,7 +90,7 @@ namespace osu.Game.Screens.Select if (base.OnExiting(next)) return true; - if(Beatmap != null) Beatmap.Track.Looping = false; + if(Beatmap != null && Beatmap.Track != null) Beatmap.Track.Looping = false; return false; } From 6d7f70d0ea01ec4c8cc0e60092a570730e5bed44 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 18:00:31 +0200 Subject: [PATCH 062/112] Fix CI warnings --- osu.Game/Screens/Select/PlaySongSelect.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index a3fe6e3fe7..760de63b0e 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -57,9 +57,19 @@ namespace osu.Game.Screens.Select { beatmap?.Mods.BindTo(modSelect.SelectedMods); - if (Beatmap != null && Beatmap.Track != null) Beatmap.Track.Looping = false; + if (Beatmap != null) + { + if (Beatmap.Track != null) + Beatmap.Track.Looping = false; + } + beatmapDetails.Beatmap = beatmap; - if(beatmap != null && beatmap.Track != null) beatmap.Track.Looping = true; + + if (beatmap != null) + { + if (beatmap.Track != null) + beatmap.Track.Looping = false; + } base.OnBeatmapChanged(beatmap); } @@ -90,7 +100,10 @@ namespace osu.Game.Screens.Select if (base.OnExiting(next)) return true; - if(Beatmap != null && Beatmap.Track != null) Beatmap.Track.Looping = false; + if (Beatmap != null) { + if(Beatmap.Track != null) + Beatmap.Track.Looping = false; + } return false; } From 9b87f5d8db00cbfde5e4306ded557d53b8072604 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 18:16:54 +0200 Subject: [PATCH 063/112] Reformating --- osu.Game/Screens/Select/PlaySongSelect.cs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 760de63b0e..8415fdfc34 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -57,19 +57,13 @@ namespace osu.Game.Screens.Select { beatmap?.Mods.BindTo(modSelect.SelectedMods); - if (Beatmap != null) - { - if (Beatmap.Track != null) - Beatmap.Track.Looping = false; - } + if (Beatmap?.Track != null) + Beatmap.Track.Looping = false; beatmapDetails.Beatmap = beatmap; - if (beatmap != null) - { - if (beatmap.Track != null) - beatmap.Track.Looping = false; - } + if (beatmap?.Track != null) + beatmap.Track.Looping = true; base.OnBeatmapChanged(beatmap); } @@ -100,10 +94,8 @@ namespace osu.Game.Screens.Select if (base.OnExiting(next)) return true; - if (Beatmap != null) { - if(Beatmap.Track != null) - Beatmap.Track.Looping = false; - } + if (Beatmap?.Track != null) + Beatmap.Track.Looping = false; return false; } From 974e8d1f82b0c9d582cfb7faf168ed4705ee171c Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 19:27:34 +0200 Subject: [PATCH 064/112] Fix pressing up always goes to the first beatmap group difficulty, not the last --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 749dc97571..c4aec11b6e 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -155,7 +155,7 @@ namespace osu.Game.Screens.Select index = (index + direction + groups.Count) % groups.Count; if (groups[index].State != BeatmapGroupState.Hidden) { - SelectBeatmap(groups[index].BeatmapPanels.First().Beatmap); + SelectBeatmap(direction == 1 || skipDifficulties ? groups[index].BeatmapPanels.First().Beatmap : groups[index].BeatmapPanels.Last().Beatmap); return; } } while (index != startIndex); From 6219b8e6ddba43944520c35ddcdd6febcdd6a267 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 20:27:41 +0200 Subject: [PATCH 065/112] Fixed an error with looping --- osu.Game/Screens/Select/PlaySongSelect.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 8415fdfc34..59cc325b57 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -71,7 +71,10 @@ namespace osu.Game.Screens.Select protected override void OnResuming(Screen last) { player = null; - Beatmap.Track.Looping = false; + + Beatmap.Track.Reset(); + Beatmap.Track.Start(); + Beatmap.Track.Looping = true; base.OnResuming(last); } From 5b244367ee321bd454a4704e4a64209df6aaea4c Mon Sep 17 00:00:00 2001 From: Jorolf Date: Sun, 21 May 2017 20:29:05 +0200 Subject: [PATCH 066/112] allow for solutions were the osu repository isn't at the solution level --- osu.Game/osu.Game.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ee906caa9b..acc6fd4abe 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -430,11 +430,11 @@ - + {c76bf5b3-985e-4d39-95fe-97c9c879b83a} osu.Framework - + {d9a367c9-4c1a-489f-9b05-a0cea2b53b58} osu.Game.Resources From b543b1f9fc21d9a270a5f58e28ae36dbf24d2ced Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 21:20:59 +0200 Subject: [PATCH 067/112] Remove unnecessary restart --- osu.Game/Screens/Select/PlaySongSelect.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 59cc325b57..96dc22ae5f 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -71,9 +71,7 @@ namespace osu.Game.Screens.Select protected override void OnResuming(Screen last) { player = null; - - Beatmap.Track.Reset(); - Beatmap.Track.Start(); + Beatmap.Track.Looping = true; base.OnResuming(last); From 0539584578fed738994e42dd72978bd925fdd285 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 21:33:54 +0200 Subject: [PATCH 068/112] CI fix --- osu.Game/Screens/Select/PlaySongSelect.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 96dc22ae5f..4d478b82a1 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -71,7 +71,9 @@ namespace osu.Game.Screens.Select protected override void OnResuming(Screen last) { player = null; - + + if (!Beatmap.Track.IsRunning) + Beatmap.Track.Start(); Beatmap.Track.Looping = true; base.OnResuming(last); From 40563382034351bf6d6a61484e7cb2ec07987b48 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Sun, 21 May 2017 21:35:49 +0200 Subject: [PATCH 069/112] Remove unnecessary track starting --- osu.Game/Screens/Select/PlaySongSelect.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 4d478b82a1..f96fbb87cb 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -72,8 +72,6 @@ namespace osu.Game.Screens.Select { player = null; - if (!Beatmap.Track.IsRunning) - Beatmap.Track.Start(); Beatmap.Track.Looping = true; base.OnResuming(last); From ecf81fa8d2bc802631212b24c44907e85244798f Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 08:25:48 +0900 Subject: [PATCH 070/112] Cleanup. --- .../Patterns/Legacy/DistanceObjectPatternGenerator.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 9ea4353317..4b063be222 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -47,9 +47,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy double speedAdjustment = beatmap.TimingInfo.SpeedMultiplierAt(hitObject.StartTime); double speedAdjustedBeatLength = beatmap.TimingInfo.BeatLengthAt(hitObject.StartTime) * speedAdjustment; - // The true distance, accounting for any repeats. This ends up being the drum roll distance later + // The true distance, accounting for any repeats double distance = (distanceData?.Distance ?? 0) * repeatCount; - // The velocity of the osu! hit object - calculated as the velocity of a slider double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier / speedAdjustedBeatLength; // The duration of the osu! hit object @@ -82,7 +81,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy if (duration >= 4000) return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0); - if (segmentDuration > 400 && duration < 4000 && repeatCount < AvailableColumns - 1 - RandomStart) + if (segmentDuration > 400 && repeatCount < AvailableColumns - 1 - RandomStart) return generateTiledHoldNotes(HitObject.StartTime); return generateHoldAndNormalNotes(HitObject.StartTime); From 5ef7451dba2516857a45888a247b20ccac60266e Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Mon, 22 May 2017 01:53:36 +0200 Subject: [PATCH 071/112] Improved LEFTand RIGHT key behaviour --- osu.Game/Screens/OsuScreen.cs | 9 +++++++-- osu.Game/Screens/Select/BeatmapCarousel.cs | 6 +++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 16bdd6132f..6a0e37ca6f 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -57,12 +57,17 @@ namespace osu.Game.Screens beatmap.Value = localMap; } - beatmap.ValueChanged += OnBeatmapChanged; - if (osuGame != null) ruleset.BindTo(osuGame.Ruleset); } + protected override void LoadComplete() + { + base.LoadComplete(); + + beatmap.ValueChanged += OnBeatmapChanged; + } + /// /// The global Beatmap was changed. /// diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index c4aec11b6e..ed03ff5593 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -155,7 +155,11 @@ namespace osu.Game.Screens.Select index = (index + direction + groups.Count) % groups.Count; if (groups[index].State != BeatmapGroupState.Hidden) { - SelectBeatmap(direction == 1 || skipDifficulties ? groups[index].BeatmapPanels.First().Beatmap : groups[index].BeatmapPanels.Last().Beatmap); + if (skipDifficulties) + SelectBeatmap(groups[index].SelectedPanel != null ? groups[index].SelectedPanel.Beatmap : groups[index].BeatmapPanels.First().Beatmap); + else + SelectBeatmap(direction == 1 ? groups[index].BeatmapPanels.First().Beatmap : groups[index].BeatmapPanels.Last().Beatmap); + return; } } while (index != startIndex); From e9c2b5101246054a424bad2b45763107096e7a80 Mon Sep 17 00:00:00 2001 From: MrTheMake Date: Mon, 22 May 2017 01:59:10 +0200 Subject: [PATCH 072/112] Random the difficulty too --- osu.Game/Screens/Select/BeatmapCarousel.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index ed03ff5593..2d6d212130 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -171,10 +171,8 @@ namespace osu.Game.Screens.Select if (visibleGroups.Count < 1) return; BeatmapGroup group = visibleGroups[RNG.Next(visibleGroups.Count)]; - BeatmapPanel panel = group?.BeatmapPanels.First(); - if (panel == null) - return; + BeatmapPanel panel = group.BeatmapPanels[RNG.Next(group.BeatmapPanels.Count)]; selectGroup(group, panel); } From e58ffbd87dc20424268d5e201e4d88a82183b43f Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 09:46:34 +0900 Subject: [PATCH 073/112] Remove Note Siblings. --- osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs index f6eb4aea2c..93aaa94f45 100644 --- a/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs @@ -9,11 +9,5 @@ namespace osu.Game.Rulesets.Mania.Objects public abstract class ManiaHitObject : HitObject, IHasColumn { public int Column { get; set; } - - /// - /// The number of other that start at - /// the same time as this hit object. - /// - public int Siblings { get; set; } } } From 3041b55aacd53b8ae4fc227f2d60f2373b856694 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 09:50:36 +0900 Subject: [PATCH 074/112] Remove siblings. --- .../Legacy/DistanceObjectPatternGenerator.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 4b063be222..ece278e64b 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -143,7 +143,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { while (pattern.IsFilled(nextColumn) || PreviousPattern.IsFilled(nextColumn)) //find available column nextColumn = Random.Next(RandomStart, AvailableColumns); - addToPattern(pattern, nextColumn, startTime, endTime, noteCount); + addToPattern(pattern, nextColumn, startTime, endTime); } // This is can't be combined with the above loop due to RNG @@ -151,7 +151,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { while (pattern.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); - addToPattern(pattern, nextColumn, startTime, endTime, noteCount); + addToPattern(pattern, nextColumn, startTime, endTime); } return pattern; @@ -267,7 +267,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); for (int i = 0; i <= repeatCount; i++) { - addToPattern(pattern, nextColumn, startTime, startTime, 2); + addToPattern(pattern, nextColumn, startTime, startTime); nextColumn += interval; if (nextColumn >= AvailableColumns - RandomStart) @@ -276,7 +276,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy // If we're in 2K, let's not add many consecutive doubles if (AvailableColumns > 2) - addToPattern(pattern, nextColumn, startTime, startTime, 2); + addToPattern(pattern, nextColumn, startTime, startTime); nextColumn = Random.Next(RandomStart, AvailableColumns); startTime += segmentDuration; @@ -367,7 +367,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy while (pattern.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); - addToPattern(pattern, nextColumn, startTime, endTime, repeatCount); + addToPattern(pattern, nextColumn, startTime, endTime); startTime += segmentDuration; } @@ -420,7 +420,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { while (rowPattern.IsFilled(nextColumn) || nextColumn == holdColumn) nextColumn = Random.Next(RandomStart, AvailableColumns); - addToPattern(rowPattern, nextColumn, startTime, startTime, noteCount + 1); + addToPattern(rowPattern, nextColumn, startTime, startTime); } } @@ -459,8 +459,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// The column to add the note to. /// The start time of the note. /// The end time of the note (set to for a non-hold note). - /// The number of children alongside this note (these will not be generated, but are used for volume calculations). - private void addToPattern(Pattern pattern, int column, double startTime, double endTime, int siblings = 1) + private void addToPattern(Pattern pattern, int column, double startTime, double endTime) { ManiaHitObject newObject; @@ -470,8 +469,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { StartTime = startTime, Samples = sampleInfoListAt(startTime), - Column = column, - Siblings = siblings + Column = column }; } else @@ -482,8 +480,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy Samples = sampleInfoListAt(startTime), EndSamples = sampleInfoListAt(endTime), Column = column, - Duration = endTime - startTime, - Siblings = siblings + Duration = endTime - startTime }; } From 82cf94bbff70f42a10d35d06c1b7ef07aad7a89d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 May 2017 09:50:45 +0900 Subject: [PATCH 075/112] Move spinner colours to local definition for now We don't want to start polluting the OsuColours namespace with non-UI colours. --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs | 7 +++++-- osu.Game/Graphics/OsuColour.cs | 3 --- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index cc5086f442..3722d13ffc 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -30,6 +30,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private readonly TextAwesome symbol; + private readonly Color4 baseColour = OsuColour.FromHex(@"002c3c"); + private readonly Color4 fillColour = OsuColour.FromHex(@"005b7c"); + private Color4 normalColour; private Color4 completeColour; @@ -154,13 +157,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables [BackgroundDependencyLoader] private void load(OsuColour colours) { - normalColour = colours.SpinnerBase; + normalColour = baseColour; background.AccentColour = normalColour; completeColour = colours.YellowLight.Opacity(0.75f); - disc.AccentColour = colours.SpinnerFill; + disc.AccentColour = fillColour; circle.Colour = colours.BlueDark; glow.Colour = colours.BlueDark; } diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index 697f8f4629..3d83668d07 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -87,8 +87,5 @@ namespace osu.Game.Graphics public readonly Color4 RedDarker = FromHex(@"870000"); public readonly Color4 ChatBlue = FromHex(@"17292e"); - - public readonly Color4 SpinnerBase = FromHex(@"002c3c"); - public readonly Color4 SpinnerFill = FromHex(@"005b7c"); } } From 9f2ca1acbf87c53aff1088c81d196395e5b23440 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 09:57:03 +0900 Subject: [PATCH 076/112] Remove siblings. --- .../Patterns/Legacy/EndTimeObjectPatternGenerator.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs index cd04418ac5..e84802617c 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs @@ -74,8 +74,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy StartTime = HitObject.StartTime, EndSamples = HitObject.Samples, Column = column, - Duration = endTime - HitObject.StartTime, - Siblings = 1 + Duration = endTime - HitObject.StartTime }; newObject.Samples.Add(new SampleInfo @@ -89,8 +88,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { StartTime = HitObject.StartTime, Samples = HitObject.Samples, - Column = column, - Siblings = 1 + Column = column }; } From 9de18d45a5bd4e464ce644717a1c89b0622f5839 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 10:00:11 +0900 Subject: [PATCH 077/112] Use bitshifted notation. --- .../Beatmaps/Patterns/Legacy/PatternType.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs index d4957d41a9..d645882511 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs @@ -15,51 +15,51 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// /// Keep the same as last row. /// - ForceStack = 1, + ForceStack = 1 << 0, /// /// Keep different from last row. /// - ForceNotStack = 2, + ForceNotStack = 1 << 1, /// /// Keep as single note at its original position. /// - KeepSingle = 4, + KeepSingle = 1 << 2, /// /// Use a lower random value. /// - LowProbability = 8, + LowProbability = 1 << 3, /// /// Reserved. /// - Alternate = 16, + Alternate = 1 << 4, /// /// Ignore the repeat count. /// - ForceSigSlider = 32, + ForceSigSlider = 1 << 5, /// /// Convert slider to circle. /// - ForceNotSlider = 64, + ForceNotSlider = 1 << 6, /// /// Notes gathered together. /// - Gathered = 128, - Mirror = 256, + Gathered = 1 << 7, + Mirror = 1 << 8, /// /// Change 0 -> 6. /// - Reverse = 512, + Reverse = 1 << 9, /// /// 1 -> 5 -> 1 -> 5 like reverse. /// - Cycle = 1024, + Cycle = 1 << 10, /// /// Next note will be at column + 1. /// - Stair = 2048, + Stair = 1 << 11, /// /// Next note will be at column - 1. /// - ReverseStair = 4096 + ReverseStair = 1 << 12 } } From 8c260e3364be8034d8babfb33185b0fe35d3551f Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 10:04:25 +0900 Subject: [PATCH 078/112] Renamings + refactorings to Pattern. --- .../Beatmaps/Patterns/Pattern.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs index cbde1f0f53..331b92f8a4 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs @@ -21,16 +21,16 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns public IEnumerable HitObjects => hitObjects; /// - /// Whether this pattern already contains a hit object in a code. + /// Check whether a column of this patterns contains a hit object. /// /// The column index. - /// Whether this pattern already contains a hit object in - public bool IsFilled(int column) => hitObjects.Exists(h => h.Column == column); + /// Whether the column with index contains a hit object. + public bool ColumnHasObject(int column) => hitObjects.Exists(h => h.Column == column); /// /// Amount of columns taken up by hit objects in this pattern. /// - public int ColumnsFilled => HitObjects.GroupBy(h => h.Column).Count(); + public int ColumnWithObjects => HitObjects.GroupBy(h => h.Column).Count(); /// /// Adds a hit object to this pattern. @@ -42,10 +42,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns /// Copies hit object from another pattern to this one. /// /// The other pattern. - public void Add(Pattern other) - { - other.HitObjects.ForEach(Add); - } + public void Add(Pattern other) => hitObjects.AddRange(other.HitObjects); /// /// Clears this pattern, removing all hit objects. From 0a0139adedb34bbc3ad1e0f4015f06f65fe3f8e0 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 10:12:33 +0900 Subject: [PATCH 079/112] Remove the concept of beatmap events, rename BreakEvent -> BreakPeriod. --- .../Patterns/Legacy/PatternGenerator.cs | 2 +- osu.Game/Beatmaps/Beatmap.cs | 11 +++++-- osu.Game/Beatmaps/Events/BackgroundEvent.cs | 13 -------- osu.Game/Beatmaps/Events/Event.cs | 13 -------- osu.Game/Beatmaps/Events/EventInfo.cs | 33 ------------------- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 11 ++----- .../BreakEvent.cs => Timing/BreakPeriod.cs} | 13 +++++--- osu.Game/osu.Game.csproj | 5 +-- 8 files changed, 21 insertions(+), 80 deletions(-) delete mode 100644 osu.Game/Beatmaps/Events/BackgroundEvent.cs delete mode 100644 osu.Game/Beatmaps/Events/Event.cs delete mode 100644 osu.Game/Beatmaps/Events/EventInfo.cs rename osu.Game/Beatmaps/{Events/BreakEvent.cs => Timing/BreakPeriod.cs} (70%) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs index ad07c03b96..e6e3f1d07f 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs @@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy HitObject firstObject = Beatmap.HitObjects.FirstOrDefault(); double drainTime = (lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0); - drainTime -= Beatmap.EventInfo.TotalBreakTime; + drainTime -= Beatmap.TotalBreakTime; if (drainTime == 0) drainTime = 10000; diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index a64002e0b0..608b2fcd19 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -2,11 +2,11 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK.Graphics; -using osu.Game.Beatmaps.Events; using osu.Game.Beatmaps.Timing; using osu.Game.Database; using osu.Game.Rulesets.Objects; using System.Collections.Generic; +using System.Linq; namespace osu.Game.Beatmaps { @@ -18,7 +18,7 @@ namespace osu.Game.Beatmaps { public BeatmapInfo BeatmapInfo; public TimingInfo TimingInfo = new TimingInfo(); - public EventInfo EventInfo = new EventInfo(); + public List Breaks = new List(); public readonly List ComboColors = new List { new Color4(17, 136, 170, 255), @@ -34,6 +34,11 @@ namespace osu.Game.Beatmaps /// public List HitObjects; + /// + /// Total amount of break time in the beatmap. + /// + public double TotalBreakTime => Breaks.Sum(b => b.Duration); + /// /// Constructs a new beatmap. /// @@ -42,7 +47,7 @@ namespace osu.Game.Beatmaps { BeatmapInfo = original?.BeatmapInfo ?? BeatmapInfo; TimingInfo = original?.TimingInfo ?? TimingInfo; - EventInfo = original?.EventInfo ?? EventInfo; + Breaks = original?.Breaks ?? Breaks; ComboColors = original?.ComboColors ?? ComboColors; } } diff --git a/osu.Game/Beatmaps/Events/BackgroundEvent.cs b/osu.Game/Beatmaps/Events/BackgroundEvent.cs deleted file mode 100644 index 215373bd3b..0000000000 --- a/osu.Game/Beatmaps/Events/BackgroundEvent.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -namespace osu.Game.Beatmaps.Events -{ - public class BackgroundEvent : Event - { - /// - /// The file name. - /// - public string Filename; - } -} diff --git a/osu.Game/Beatmaps/Events/Event.cs b/osu.Game/Beatmaps/Events/Event.cs deleted file mode 100644 index 3af3909462..0000000000 --- a/osu.Game/Beatmaps/Events/Event.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -namespace osu.Game.Beatmaps.Events -{ - public abstract class Event - { - /// - /// The event start time. - /// - public double StartTime; - } -} diff --git a/osu.Game/Beatmaps/Events/EventInfo.cs b/osu.Game/Beatmaps/Events/EventInfo.cs deleted file mode 100644 index 3ba3d5ba03..0000000000 --- a/osu.Game/Beatmaps/Events/EventInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.Collections.Generic; -using System.Linq; - -namespace osu.Game.Beatmaps.Events -{ - public class EventInfo - { - /// - /// All the background events. - /// - public readonly List Backgrounds = new List(); - - /// - /// All the break events. - /// - public readonly List Breaks = new List(); - - /// - /// Total duration of all breaks. - /// - public double TotalBreakTime => Breaks.Sum(b => b.Duration); - - /// - /// Retrieves the active background at a time. - /// - /// The time to retrieve the background at. - /// The background. - public BackgroundEvent BackgroundAt(double time) => Backgrounds.FirstOrDefault(b => b.StartTime <= time); - } -} diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 772c0e9c07..04208337c7 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -5,7 +5,6 @@ using System; using System.Globalization; using System.IO; using OpenTK.Graphics; -using osu.Game.Beatmaps.Events; using osu.Game.Beatmaps.Timing; using osu.Game.Beatmaps.Legacy; using osu.Game.Rulesets.Objects.Legacy; @@ -217,18 +216,12 @@ namespace osu.Game.Beatmaps.Formats case EventType.Background: string filename = split[2].Trim('"'); - beatmap.EventInfo.Backgrounds.Add(new BackgroundEvent - { - StartTime = double.Parse(split[1], NumberFormatInfo.InvariantInfo), - Filename = filename - }); - if (type == EventType.Background) beatmap.BeatmapInfo.Metadata.BackgroundFile = filename; break; case EventType.Break: - var breakEvent = new BreakEvent + var breakEvent = new BreakPeriod { StartTime = double.Parse(split[1], NumberFormatInfo.InvariantInfo), EndTime = double.Parse(split[2], NumberFormatInfo.InvariantInfo) @@ -237,7 +230,7 @@ namespace osu.Game.Beatmaps.Formats if (!breakEvent.HasEffect) return; - beatmap.EventInfo.Breaks.Add(breakEvent); + beatmap.Breaks.Add(breakEvent); break; } } diff --git a/osu.Game/Beatmaps/Events/BreakEvent.cs b/osu.Game/Beatmaps/Timing/BreakPeriod.cs similarity index 70% rename from osu.Game/Beatmaps/Events/BreakEvent.cs rename to osu.Game/Beatmaps/Timing/BreakPeriod.cs index 78e33f2fbb..fb307b7144 100644 --- a/osu.Game/Beatmaps/Events/BreakEvent.cs +++ b/osu.Game/Beatmaps/Timing/BreakPeriod.cs @@ -1,27 +1,32 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -namespace osu.Game.Beatmaps.Events +namespace osu.Game.Beatmaps.Timing { - public class BreakEvent : Event + public class BreakPeriod { /// /// The minimum duration required for a break to have any effect. /// private const double min_break_duration = 650; + /// + /// The break start time. + /// + public double StartTime; + /// /// The break end time. /// public double EndTime; /// - /// The duration of the break. + /// The break duration. /// public double Duration => EndTime - StartTime; /// - /// Whether the break has any effect. Breaks that are too short are culled before they reach the EventInfo. + /// Whether the break has any effect. Breaks that are too short are culled before they are added to the beatmap. /// public bool HasEffect => Duration >= min_break_duration; } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index acc6fd4abe..1631311ef6 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -74,10 +74,6 @@ - - - - @@ -91,6 +87,7 @@ + From cd66e2af140763698f50af017052564c4d22bece Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 10:17:08 +0900 Subject: [PATCH 080/112] Update with pattern changes. --- .../Legacy/DistanceObjectPatternGenerator.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index ece278e64b..0cad23304e 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -89,7 +89,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy if (segmentDuration <= 110) { - if (PreviousPattern.ColumnsFilled < AvailableColumns) + if (PreviousPattern.ColumnWithObjects < AvailableColumns) convertType |= PatternType.ForceNotStack; else convertType &= ~PatternType.ForceNotStack; @@ -137,11 +137,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy var pattern = new Pattern(); - int usableColumns = AvailableColumns - RandomStart - PreviousPattern.ColumnsFilled; + int usableColumns = AvailableColumns - RandomStart - PreviousPattern.ColumnWithObjects; int nextColumn = Random.Next(RandomStart, AvailableColumns); for (int i = 0; i < Math.Min(usableColumns, noteCount); i++) { - while (pattern.IsFilled(nextColumn) || PreviousPattern.IsFilled(nextColumn)) //find available column + while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn)) //find available column nextColumn = Random.Next(RandomStart, AvailableColumns); addToPattern(pattern, nextColumn, startTime, endTime); } @@ -149,7 +149,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy // This is can't be combined with the above loop due to RNG for (int i = 0; i < noteCount - usableColumns; i++) { - while (pattern.IsFilled(nextColumn)) + while (pattern.ColumnHasObject(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); addToPattern(pattern, nextColumn, startTime, endTime); } @@ -174,9 +174,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy var pattern = new Pattern(); int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); - if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnsFilled < AvailableColumns) + if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < AvailableColumns) { - while (PreviousPattern.IsFilled(nextColumn)) + while (PreviousPattern.ColumnHasObject(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); } @@ -356,15 +356,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy int columnRepeat = Math.Min(repeatCount, AvailableColumns); int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); - if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnsFilled < AvailableColumns) + if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < AvailableColumns) { - while (PreviousPattern.IsFilled(nextColumn)) + while (PreviousPattern.ColumnHasObject(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); } for (int i = 0; i < columnRepeat; i++) { - while (pattern.IsFilled(nextColumn)) + while (pattern.ColumnHasObject(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); addToPattern(pattern, nextColumn, startTime, endTime); @@ -390,9 +390,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy var pattern = new Pattern(); int holdColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); - if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnsFilled < AvailableColumns) + if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < AvailableColumns) { - while (PreviousPattern.IsFilled(holdColumn)) + while (PreviousPattern.ColumnHasObject(holdColumn)) holdColumn = Random.Next(RandomStart, AvailableColumns); } @@ -418,7 +418,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { for (int j = 0; j < noteCount; j++) { - while (rowPattern.IsFilled(nextColumn) || nextColumn == holdColumn) + while (rowPattern.ColumnHasObject(nextColumn) || nextColumn == holdColumn) nextColumn = Random.Next(RandomStart, AvailableColumns); addToPattern(rowPattern, nextColumn, startTime, startTime); } From 4ce3a7806690b7672080253bc13caaf7e9fe3813 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 22 May 2017 10:18:42 +0900 Subject: [PATCH 081/112] Update Pattern.cs --- osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs index 331b92f8a4..15d31406e9 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Rulesets.Mania.Objects; namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns From 2d11a8bdf0588a9fece729f38c8b20b59eb5159f Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 10:20:42 +0900 Subject: [PATCH 082/112] Update with pattern changes. --- .../Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs index e84802617c..1956361f5c 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { int nextColumn = Random.Next(start, AvailableColumns); - while (PreviousPattern.IsFilled(nextColumn)) + while (PreviousPattern.ColumnHasObject(nextColumn)) nextColumn = Random.Next(start, AvailableColumns); return nextColumn; From 6714a244e83f6a43c462dc47ad7f1373b16323af Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 10:23:08 +0900 Subject: [PATCH 083/112] Add check before possibly going into endless loop. --- .../Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs index 1956361f5c..8f438f9ff4 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy else addToPattern(pattern, getNextRandomColumn(RandomStart), generateHold); } - else + else if (AvailableColumns > 0) addToPattern(pattern, getNextRandomColumn(0), generateHold); return pattern; From e232968ea72463bb974b4a5d055fa92c837bf0b5 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 10:25:28 +0900 Subject: [PATCH 084/112] Fix line endings resulting in CI error. --- .../Legacy/HitObjectPatternGenerator.cs | 848 +++++++++--------- 1 file changed, 424 insertions(+), 424 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index 3de3d129bf..657ba968a2 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -1,425 +1,425 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Linq; -using OpenTK; -using osu.Game.Audio; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Timing; -using osu.Game.Rulesets.Mania.MathUtils; -using osu.Game.Rulesets.Mania.Objects; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Types; - -namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy -{ - internal class HitObjectPatternGenerator : PatternGenerator - { - public PatternType StairType { get; private set; } - - private readonly PatternType convertType; - - public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair) - : base(random, hitObject, beatmap, previousPattern) - { - StairType = lastStair; - - ControlPoint overridePoint; - ControlPoint controlPoint = beatmap.TimingInfo.TimingPointAt(hitObject.StartTime, out overridePoint); - - var positionData = hitObject as IHasPosition; - - float positionSeparation = ((positionData?.Position ?? Vector2.Zero) - previousPosition).Length; - double timeSeparation = hitObject.StartTime - previousTime; - - double beatLength = controlPoint.BeatLength; - bool kiai = (overridePoint ?? controlPoint).KiaiMode; - - if (timeSeparation <= 125) - { - // More than 120 BPM - convertType |= PatternType.ForceNotStack; - } - - if (timeSeparation <= 80) - { - // More than 187 BPM - convertType |= PatternType.ForceNotStack | PatternType.KeepSingle; - } - else if (timeSeparation <= 95) - { - // More than 157 BPM - convertType |= PatternType.ForceNotStack | PatternType.KeepSingle | lastStair; - } - else if (timeSeparation <= 105) - { - // More than 140 BPM - convertType |= PatternType.ForceNotStack | PatternType.LowProbability; - } - else if (timeSeparation <= 125) - { - // More than 120 BPM - convertType |= PatternType.ForceNotStack; - } - else if (timeSeparation <= 135 && positionSeparation < 20) - { - // More than 111 BPM stream - convertType |= PatternType.Cycle | PatternType.KeepSingle; - } - else if (timeSeparation <= 150 & positionSeparation < 20) - { - // More than 100 BPM stream - convertType |= PatternType.ForceStack | PatternType.LowProbability; - } - else if (positionSeparation < 20 && density >= beatLength / 2.5) - { - // Low density stream - convertType |= PatternType.Reverse | PatternType.LowProbability; - } - else if (density < beatLength / 2.5 || kiai) - { - // High density - } - else - convertType |= PatternType.LowProbability; - } - - public override Pattern Generate() - { - int lastColumn = PreviousPattern.HitObjects.First().Column; - - if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Count() > 0) - { - // Generate a new pattern by copying the last hit objects in reverse-column order - var pattern = new Pattern(); - - int siblings = PreviousPattern.HitObjects.Count(h => h.Column >= RandomStart); - - for (int i = RandomStart; i < AvailableColumns; i++) - if (PreviousPattern.IsFilled(i)) - addToPattern(pattern, RandomStart + AvailableColumns - i - 1, siblings); - - return pattern; - } - - if ((convertType & PatternType.Cycle) > 0 && PreviousPattern.HitObjects.Count() == 1 - // If we convert to 7K + 1, let's not overload the special key - && (AvailableColumns != 8 || lastColumn != 0) - // Make sure the last column was not the centre column - && (AvailableColumns % 2 == 0 || lastColumn != AvailableColumns / 2)) - { - // Generate a new pattern by cycling backwards (similar to Reverse but for only one hit object) - var pattern = new Pattern(); - - int column = RandomStart + AvailableColumns - lastColumn - 1; - addToPattern(pattern, column); - - return pattern; - } - - if ((convertType & PatternType.ForceStack) > 0 && PreviousPattern.HitObjects.Count() > 0) - { - // Generate a new pattern by placing on the already filled columns - var pattern = new Pattern(); - - int siblings = PreviousPattern.HitObjects.Count(h => h.Column >= RandomStart); - - for (int i = RandomStart; i < AvailableColumns; i++) - if (PreviousPattern.IsFilled(i)) - addToPattern(pattern, i, siblings); - - return pattern; - } - - if ((convertType & PatternType.Stair) > 0 && PreviousPattern.HitObjects.Count() == 1) - { - // Generate a new pattern by placing on the next column, cycling back to the start if there is no "next" - var pattern = new Pattern(); - - int targetColumn = lastColumn + 1; - if (targetColumn == AvailableColumns) - { - targetColumn = RandomStart; - StairType = PatternType.ReverseStair; - } - - addToPattern(pattern, targetColumn); - return pattern; - } - - if ((convertType & PatternType.ReverseStair) > 0 && PreviousPattern.HitObjects.Count() == 1) - { - // Generate a new pattern by placing on the previous column, cycling back to the end if there is no "previous" - var pattern = new Pattern(); - - int targetColumn = lastColumn - 1; - if (targetColumn == RandomStart - 1) - { - targetColumn = AvailableColumns - 1; - StairType = PatternType.Stair; - } - - addToPattern(pattern, targetColumn); - return pattern; - } - - if ((convertType & PatternType.KeepSingle) > 0) - return generateRandomNotes(1); - - if ((convertType & PatternType.Mirror) > 0) - { - if (ConversionDifficulty > 6.5) - return generateRandomPatternWithMirrored(0.12, 0.38, 0.12); - if (ConversionDifficulty > 4) - return generateRandomPatternWithMirrored(0.12, 0.17, 0); - return generateRandomPatternWithMirrored(0.12, 0, 0); - } - - if (ConversionDifficulty > 6.5) - { - if ((convertType & PatternType.LowProbability) > 0) - return generateRandomPattern(0.78, 0.42, 0, 0); - return generateRandomPattern(1, 0.62, 0, 0); - } - - if (ConversionDifficulty > 4) - { - if ((convertType & PatternType.LowProbability) > 0) - return generateRandomPattern(0.35, 0.08, 0, 0); - return generateRandomPattern(0.52, 0.15, 0, 0); - } - - if (ConversionDifficulty > 2) - { - if ((convertType & PatternType.LowProbability) > 0) - return generateRandomPattern(0.18, 0, 0, 0); - return generateRandomPattern(0.45, 0, 0, 0); - } - - return generateRandomPattern(0, 0, 0, 0); - } - - /// - /// Generates random notes. - /// - /// This will generate as many as it can up to , accounting for - /// any stacks if is forcing no stacks. - /// - /// - /// The amount of notes to generate. - /// Custom siblings count if is not the number of siblings in this pattern. - /// The containing the hit objects. - private Pattern generateRandomNotes(int noteCount, int siblingsOverride = -1) - { - var pattern = new Pattern(); - - bool allowStacking = (convertType & PatternType.ForceNotStack) == 0; - - if (!allowStacking) - noteCount = Math.Min(noteCount, AvailableColumns - RandomStart - PreviousPattern.ColumnsFilled); - - int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); - for (int i = 0; i < noteCount; i++) - { - while (pattern.IsFilled(nextColumn) || (PreviousPattern.IsFilled(nextColumn) && !allowStacking)) - { - if ((convertType & PatternType.Gathered) > 0) - { - nextColumn++; - if (nextColumn == AvailableColumns) - nextColumn = RandomStart; - } - else - nextColumn = Random.Next(RandomStart, AvailableColumns); - } - - addToPattern(pattern, nextColumn, siblingsOverride != -1 ? siblingsOverride : noteCount); - } - - return pattern; - } - - /// - /// Whether this hit object can generate a note in the special column. - /// - private bool hasSpecialColumn => HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP) && HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH); - - /// - /// Generates a random pattern. - /// - /// Probability for 2 notes to be generated. - /// Probability for 3 notes to be generated. - /// Probability for 4 notes to be generated. - /// Probability for 5 notes to be generated. - /// The containing the hit objects. - private Pattern generateRandomPattern(double p2, double p3, double p4, double p5) - { - var pattern = new Pattern(); - - int noteCount = getRandomNoteCount(p2, p3, p4, p5); - int siblings = noteCount; - - if (RandomStart > 0 && hasSpecialColumn) - { - siblings++; - addToPattern(pattern, 0, siblings); - } - - pattern.Add(generateRandomNotes(noteCount, siblings)); - - return pattern; - } - - /// - /// Generates a random pattern which has both normal and mirrored notes. - /// - /// The probability for a note to be added to the centre column. - /// Probability for 2 notes to be generated. - /// Probability for 3 notes to be generated. - /// The containing the hit objects. - private Pattern generateRandomPatternWithMirrored(double centreProbability, double p2, double p3) - { - var pattern = new Pattern(); - - bool addToCentre; - int noteCount = getRandomNoteCountMirrored(centreProbability, p2, p3, out addToCentre); - int siblings = noteCount; - - if (addToCentre) - siblings++; - if (RandomStart > 0 && hasSpecialColumn) - siblings++; - - int columnLimit = (AvailableColumns % 2 == 0 ? AvailableColumns : AvailableColumns - 1) / 2; - int nextColumn = Random.Next(RandomStart, columnLimit); - for (int i = 0; i < noteCount; i++) - { - while (pattern.IsFilled(nextColumn)) - nextColumn = Random.Next(RandomStart, columnLimit); - // Add normal note - addToPattern(pattern, nextColumn, siblings); - // Add mirrored note - addToPattern(pattern, RandomStart + AvailableColumns - nextColumn - 1); - } - - if (addToCentre) - addToPattern(pattern, AvailableColumns / 2, siblings); - - if (RandomStart > 0 && hasSpecialColumn) - addToPattern(pattern, 0, siblings); - - return pattern; - } - - /// - /// Generates a count of notes to be generated from a list of probabilities. - /// - /// Probability for 2 notes to be generated. - /// Probability for 3 notes to be generated. - /// Probability for 4 notes to be generated. - /// Probability for 5 notes to be generated. - /// The amount of notes to be generated. - private int getRandomNoteCount(double p2, double p3, double p4, double p5) - { - switch (AvailableColumns) - { - case 2: - p2 = 0; - p3 = 0; - p4 = 0; - p5 = 0; - break; - case 3: - p2 = Math.Max(p2, 0.1); - p3 = 0; - p4 = 0; - p5 = 0; - break; - case 4: - p2 = Math.Max(p2, 0.23); - p3 = Math.Max(p3, 0.04); - p4 = 0; - p5 = 0; - break; - case 5: - p3 = Math.Max(p3, 0.15); - p4 = Math.Max(p4, 0.03); - p5 = 0; - break; - } - - if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)) - p2 = 1; - - return GetRandomNoteCount(p2, p3, p4, p5); - } - - /// - /// Generates a count of notes to be generated from a list of probabilities. - /// - /// The probability for a note to be added to the centre column. - /// Probability for 2 notes to be generated. - /// Probability for 3 notes to be generated. - /// Whether to add a note to the centre column. - /// The amount of notes to be generated. The note to be added to the centre column will NOT be part of this count. - private int getRandomNoteCountMirrored(double centreProbability, double p2, double p3, out bool addToCentre) - { - addToCentre = false; - - if ((convertType & PatternType.ForceNotStack) > 0) - return getRandomNoteCount(p2 / 2, p2, (p2 + p3) / 2, p3); - - switch (AvailableColumns) - { - case 2: - centreProbability = 0; - p2 = 0; - p3 = 0; - break; - case 3: - centreProbability = Math.Max(centreProbability, 0.03); - p2 = Math.Max(p2, 0.1); - p3 = 0; - break; - case 4: - centreProbability = 0; - p2 = Math.Max(p2 * 2, 0.2); - p3 = 0; - break; - case 5: - centreProbability = Math.Max(centreProbability, 0.03); - p3 = 0; - break; - case 6: - centreProbability = 0; - p2 = Math.Max(p2 * 2, 0.5); - p3 = Math.Max(p3 * 2, 0.15); - break; - } - - double centreVal = Random.NextDouble(); - int noteCount = GetRandomNoteCount(p2, p3); - - addToCentre = AvailableColumns % 2 != 0 && noteCount != 3 && centreVal > 1 - centreProbability; - return noteCount; - } - - /// - /// Constructs and adds a note to a pattern. - /// - /// The pattern to add to. - /// The column to add the note to. - /// The number of children alongside this note (these will not be generated, but are used for volume calculations). - private void addToPattern(Pattern pattern, int column, int siblings = 1) - { - pattern.Add(new Note - { - StartTime = HitObject.StartTime, - Samples = HitObject.Samples, - Column = column, - Siblings = siblings - }); - } - } +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Linq; +using OpenTK; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Timing; +using osu.Game.Rulesets.Mania.MathUtils; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; + +namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy +{ + internal class HitObjectPatternGenerator : PatternGenerator + { + public PatternType StairType { get; private set; } + + private readonly PatternType convertType; + + public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair) + : base(random, hitObject, beatmap, previousPattern) + { + StairType = lastStair; + + ControlPoint overridePoint; + ControlPoint controlPoint = beatmap.TimingInfo.TimingPointAt(hitObject.StartTime, out overridePoint); + + var positionData = hitObject as IHasPosition; + + float positionSeparation = ((positionData?.Position ?? Vector2.Zero) - previousPosition).Length; + double timeSeparation = hitObject.StartTime - previousTime; + + double beatLength = controlPoint.BeatLength; + bool kiai = (overridePoint ?? controlPoint).KiaiMode; + + if (timeSeparation <= 125) + { + // More than 120 BPM + convertType |= PatternType.ForceNotStack; + } + + if (timeSeparation <= 80) + { + // More than 187 BPM + convertType |= PatternType.ForceNotStack | PatternType.KeepSingle; + } + else if (timeSeparation <= 95) + { + // More than 157 BPM + convertType |= PatternType.ForceNotStack | PatternType.KeepSingle | lastStair; + } + else if (timeSeparation <= 105) + { + // More than 140 BPM + convertType |= PatternType.ForceNotStack | PatternType.LowProbability; + } + else if (timeSeparation <= 125) + { + // More than 120 BPM + convertType |= PatternType.ForceNotStack; + } + else if (timeSeparation <= 135 && positionSeparation < 20) + { + // More than 111 BPM stream + convertType |= PatternType.Cycle | PatternType.KeepSingle; + } + else if (timeSeparation <= 150 & positionSeparation < 20) + { + // More than 100 BPM stream + convertType |= PatternType.ForceStack | PatternType.LowProbability; + } + else if (positionSeparation < 20 && density >= beatLength / 2.5) + { + // Low density stream + convertType |= PatternType.Reverse | PatternType.LowProbability; + } + else if (density < beatLength / 2.5 || kiai) + { + // High density + } + else + convertType |= PatternType.LowProbability; + } + + public override Pattern Generate() + { + int lastColumn = PreviousPattern.HitObjects.First().Column; + + if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Count() > 0) + { + // Generate a new pattern by copying the last hit objects in reverse-column order + var pattern = new Pattern(); + + int siblings = PreviousPattern.HitObjects.Count(h => h.Column >= RandomStart); + + for (int i = RandomStart; i < AvailableColumns; i++) + if (PreviousPattern.IsFilled(i)) + addToPattern(pattern, RandomStart + AvailableColumns - i - 1, siblings); + + return pattern; + } + + if ((convertType & PatternType.Cycle) > 0 && PreviousPattern.HitObjects.Count() == 1 + // If we convert to 7K + 1, let's not overload the special key + && (AvailableColumns != 8 || lastColumn != 0) + // Make sure the last column was not the centre column + && (AvailableColumns % 2 == 0 || lastColumn != AvailableColumns / 2)) + { + // Generate a new pattern by cycling backwards (similar to Reverse but for only one hit object) + var pattern = new Pattern(); + + int column = RandomStart + AvailableColumns - lastColumn - 1; + addToPattern(pattern, column); + + return pattern; + } + + if ((convertType & PatternType.ForceStack) > 0 && PreviousPattern.HitObjects.Count() > 0) + { + // Generate a new pattern by placing on the already filled columns + var pattern = new Pattern(); + + int siblings = PreviousPattern.HitObjects.Count(h => h.Column >= RandomStart); + + for (int i = RandomStart; i < AvailableColumns; i++) + if (PreviousPattern.IsFilled(i)) + addToPattern(pattern, i, siblings); + + return pattern; + } + + if ((convertType & PatternType.Stair) > 0 && PreviousPattern.HitObjects.Count() == 1) + { + // Generate a new pattern by placing on the next column, cycling back to the start if there is no "next" + var pattern = new Pattern(); + + int targetColumn = lastColumn + 1; + if (targetColumn == AvailableColumns) + { + targetColumn = RandomStart; + StairType = PatternType.ReverseStair; + } + + addToPattern(pattern, targetColumn); + return pattern; + } + + if ((convertType & PatternType.ReverseStair) > 0 && PreviousPattern.HitObjects.Count() == 1) + { + // Generate a new pattern by placing on the previous column, cycling back to the end if there is no "previous" + var pattern = new Pattern(); + + int targetColumn = lastColumn - 1; + if (targetColumn == RandomStart - 1) + { + targetColumn = AvailableColumns - 1; + StairType = PatternType.Stair; + } + + addToPattern(pattern, targetColumn); + return pattern; + } + + if ((convertType & PatternType.KeepSingle) > 0) + return generateRandomNotes(1); + + if ((convertType & PatternType.Mirror) > 0) + { + if (ConversionDifficulty > 6.5) + return generateRandomPatternWithMirrored(0.12, 0.38, 0.12); + if (ConversionDifficulty > 4) + return generateRandomPatternWithMirrored(0.12, 0.17, 0); + return generateRandomPatternWithMirrored(0.12, 0, 0); + } + + if (ConversionDifficulty > 6.5) + { + if ((convertType & PatternType.LowProbability) > 0) + return generateRandomPattern(0.78, 0.42, 0, 0); + return generateRandomPattern(1, 0.62, 0, 0); + } + + if (ConversionDifficulty > 4) + { + if ((convertType & PatternType.LowProbability) > 0) + return generateRandomPattern(0.35, 0.08, 0, 0); + return generateRandomPattern(0.52, 0.15, 0, 0); + } + + if (ConversionDifficulty > 2) + { + if ((convertType & PatternType.LowProbability) > 0) + return generateRandomPattern(0.18, 0, 0, 0); + return generateRandomPattern(0.45, 0, 0, 0); + } + + return generateRandomPattern(0, 0, 0, 0); + } + + /// + /// Generates random notes. + /// + /// This will generate as many as it can up to , accounting for + /// any stacks if is forcing no stacks. + /// + /// + /// The amount of notes to generate. + /// Custom siblings count if is not the number of siblings in this pattern. + /// The containing the hit objects. + private Pattern generateRandomNotes(int noteCount, int siblingsOverride = -1) + { + var pattern = new Pattern(); + + bool allowStacking = (convertType & PatternType.ForceNotStack) == 0; + + if (!allowStacking) + noteCount = Math.Min(noteCount, AvailableColumns - RandomStart - PreviousPattern.ColumnsFilled); + + int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); + for (int i = 0; i < noteCount; i++) + { + while (pattern.IsFilled(nextColumn) || (PreviousPattern.IsFilled(nextColumn) && !allowStacking)) + { + if ((convertType & PatternType.Gathered) > 0) + { + nextColumn++; + if (nextColumn == AvailableColumns) + nextColumn = RandomStart; + } + else + nextColumn = Random.Next(RandomStart, AvailableColumns); + } + + addToPattern(pattern, nextColumn, siblingsOverride != -1 ? siblingsOverride : noteCount); + } + + return pattern; + } + + /// + /// Whether this hit object can generate a note in the special column. + /// + private bool hasSpecialColumn => HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP) && HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH); + + /// + /// Generates a random pattern. + /// + /// Probability for 2 notes to be generated. + /// Probability for 3 notes to be generated. + /// Probability for 4 notes to be generated. + /// Probability for 5 notes to be generated. + /// The containing the hit objects. + private Pattern generateRandomPattern(double p2, double p3, double p4, double p5) + { + var pattern = new Pattern(); + + int noteCount = getRandomNoteCount(p2, p3, p4, p5); + int siblings = noteCount; + + if (RandomStart > 0 && hasSpecialColumn) + { + siblings++; + addToPattern(pattern, 0, siblings); + } + + pattern.Add(generateRandomNotes(noteCount, siblings)); + + return pattern; + } + + /// + /// Generates a random pattern which has both normal and mirrored notes. + /// + /// The probability for a note to be added to the centre column. + /// Probability for 2 notes to be generated. + /// Probability for 3 notes to be generated. + /// The containing the hit objects. + private Pattern generateRandomPatternWithMirrored(double centreProbability, double p2, double p3) + { + var pattern = new Pattern(); + + bool addToCentre; + int noteCount = getRandomNoteCountMirrored(centreProbability, p2, p3, out addToCentre); + int siblings = noteCount; + + if (addToCentre) + siblings++; + if (RandomStart > 0 && hasSpecialColumn) + siblings++; + + int columnLimit = (AvailableColumns % 2 == 0 ? AvailableColumns : AvailableColumns - 1) / 2; + int nextColumn = Random.Next(RandomStart, columnLimit); + for (int i = 0; i < noteCount; i++) + { + while (pattern.IsFilled(nextColumn)) + nextColumn = Random.Next(RandomStart, columnLimit); + // Add normal note + addToPattern(pattern, nextColumn, siblings); + // Add mirrored note + addToPattern(pattern, RandomStart + AvailableColumns - nextColumn - 1); + } + + if (addToCentre) + addToPattern(pattern, AvailableColumns / 2, siblings); + + if (RandomStart > 0 && hasSpecialColumn) + addToPattern(pattern, 0, siblings); + + return pattern; + } + + /// + /// Generates a count of notes to be generated from a list of probabilities. + /// + /// Probability for 2 notes to be generated. + /// Probability for 3 notes to be generated. + /// Probability for 4 notes to be generated. + /// Probability for 5 notes to be generated. + /// The amount of notes to be generated. + private int getRandomNoteCount(double p2, double p3, double p4, double p5) + { + switch (AvailableColumns) + { + case 2: + p2 = 0; + p3 = 0; + p4 = 0; + p5 = 0; + break; + case 3: + p2 = Math.Max(p2, 0.1); + p3 = 0; + p4 = 0; + p5 = 0; + break; + case 4: + p2 = Math.Max(p2, 0.23); + p3 = Math.Max(p3, 0.04); + p4 = 0; + p5 = 0; + break; + case 5: + p3 = Math.Max(p3, 0.15); + p4 = Math.Max(p4, 0.03); + p5 = 0; + break; + } + + if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)) + p2 = 1; + + return GetRandomNoteCount(p2, p3, p4, p5); + } + + /// + /// Generates a count of notes to be generated from a list of probabilities. + /// + /// The probability for a note to be added to the centre column. + /// Probability for 2 notes to be generated. + /// Probability for 3 notes to be generated. + /// Whether to add a note to the centre column. + /// The amount of notes to be generated. The note to be added to the centre column will NOT be part of this count. + private int getRandomNoteCountMirrored(double centreProbability, double p2, double p3, out bool addToCentre) + { + addToCentre = false; + + if ((convertType & PatternType.ForceNotStack) > 0) + return getRandomNoteCount(p2 / 2, p2, (p2 + p3) / 2, p3); + + switch (AvailableColumns) + { + case 2: + centreProbability = 0; + p2 = 0; + p3 = 0; + break; + case 3: + centreProbability = Math.Max(centreProbability, 0.03); + p2 = Math.Max(p2, 0.1); + p3 = 0; + break; + case 4: + centreProbability = 0; + p2 = Math.Max(p2 * 2, 0.2); + p3 = 0; + break; + case 5: + centreProbability = Math.Max(centreProbability, 0.03); + p3 = 0; + break; + case 6: + centreProbability = 0; + p2 = Math.Max(p2 * 2, 0.5); + p3 = Math.Max(p3 * 2, 0.15); + break; + } + + double centreVal = Random.NextDouble(); + int noteCount = GetRandomNoteCount(p2, p3); + + addToCentre = AvailableColumns % 2 != 0 && noteCount != 3 && centreVal > 1 - centreProbability; + return noteCount; + } + + /// + /// Constructs and adds a note to a pattern. + /// + /// The pattern to add to. + /// The column to add the note to. + /// The number of children alongside this note (these will not be generated, but are used for volume calculations). + private void addToPattern(Pattern pattern, int column, int siblings = 1) + { + pattern.Add(new Note + { + StartTime = HitObject.StartTime, + Samples = HitObject.Samples, + Column = column, + Siblings = siblings + }); + } + } } \ No newline at end of file From dba9dd35094acf50dc66ee4a783e04e5c13675ff Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 10:30:03 +0900 Subject: [PATCH 085/112] Remove siblings. --- .../Legacy/HitObjectPatternGenerator.cs | 42 ++++++------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index 657ba968a2..340b8d95ac 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -94,11 +94,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy // Generate a new pattern by copying the last hit objects in reverse-column order var pattern = new Pattern(); - int siblings = PreviousPattern.HitObjects.Count(h => h.Column >= RandomStart); - for (int i = RandomStart; i < AvailableColumns; i++) if (PreviousPattern.IsFilled(i)) - addToPattern(pattern, RandomStart + AvailableColumns - i - 1, siblings); + addToPattern(pattern, RandomStart + AvailableColumns - i - 1); return pattern; } @@ -123,11 +121,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy // Generate a new pattern by placing on the already filled columns var pattern = new Pattern(); - int siblings = PreviousPattern.HitObjects.Count(h => h.Column >= RandomStart); - for (int i = RandomStart; i < AvailableColumns; i++) if (PreviousPattern.IsFilled(i)) - addToPattern(pattern, i, siblings); + addToPattern(pattern, i); return pattern; } @@ -208,9 +204,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// /// /// The amount of notes to generate. - /// Custom siblings count if is not the number of siblings in this pattern. /// The containing the hit objects. - private Pattern generateRandomNotes(int noteCount, int siblingsOverride = -1) + private Pattern generateRandomNotes(int noteCount) { var pattern = new Pattern(); @@ -234,7 +229,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy nextColumn = Random.Next(RandomStart, AvailableColumns); } - addToPattern(pattern, nextColumn, siblingsOverride != -1 ? siblingsOverride : noteCount); + addToPattern(pattern, nextColumn); } return pattern; @@ -257,16 +252,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { var pattern = new Pattern(); - int noteCount = getRandomNoteCount(p2, p3, p4, p5); - int siblings = noteCount; + pattern.Add(generateRandomNotes(getRandomNoteCount(p2, p3, p4, p5))); if (RandomStart > 0 && hasSpecialColumn) - { - siblings++; - addToPattern(pattern, 0, siblings); - } - - pattern.Add(generateRandomNotes(noteCount, siblings)); + addToPattern(pattern, 0); return pattern; } @@ -284,12 +273,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy bool addToCentre; int noteCount = getRandomNoteCountMirrored(centreProbability, p2, p3, out addToCentre); - int siblings = noteCount; - - if (addToCentre) - siblings++; - if (RandomStart > 0 && hasSpecialColumn) - siblings++; int columnLimit = (AvailableColumns % 2 == 0 ? AvailableColumns : AvailableColumns - 1) / 2; int nextColumn = Random.Next(RandomStart, columnLimit); @@ -297,17 +280,18 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { while (pattern.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, columnLimit); + // Add normal note - addToPattern(pattern, nextColumn, siblings); + addToPattern(pattern, nextColumn); // Add mirrored note addToPattern(pattern, RandomStart + AvailableColumns - nextColumn - 1); } if (addToCentre) - addToPattern(pattern, AvailableColumns / 2, siblings); + addToPattern(pattern, AvailableColumns / 2); if (RandomStart > 0 && hasSpecialColumn) - addToPattern(pattern, 0, siblings); + addToPattern(pattern, 0); return pattern; } @@ -410,15 +394,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// /// The pattern to add to. /// The column to add the note to. - /// The number of children alongside this note (these will not be generated, but are used for volume calculations). - private void addToPattern(Pattern pattern, int column, int siblings = 1) + private void addToPattern(Pattern pattern, int column) { pattern.Add(new Note { StartTime = HitObject.StartTime, Samples = HitObject.Samples, - Column = column, - Siblings = siblings + Column = column }); } } From 8077ddf9442618093277c80ab6f07689054a8a76 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 10:34:12 +0900 Subject: [PATCH 086/112] Update with pattern changes. --- .../Patterns/Legacy/HitObjectPatternGenerator.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index 340b8d95ac..4b65fb7bfd 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy var pattern = new Pattern(); for (int i = RandomStart; i < AvailableColumns; i++) - if (PreviousPattern.IsFilled(i)) + if (PreviousPattern.ColumnHasObject(i)) addToPattern(pattern, RandomStart + AvailableColumns - i - 1); return pattern; @@ -122,7 +122,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy var pattern = new Pattern(); for (int i = RandomStart; i < AvailableColumns; i++) - if (PreviousPattern.IsFilled(i)) + if (PreviousPattern.ColumnHasObject(i)) addToPattern(pattern, i); return pattern; @@ -212,12 +212,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy bool allowStacking = (convertType & PatternType.ForceNotStack) == 0; if (!allowStacking) - noteCount = Math.Min(noteCount, AvailableColumns - RandomStart - PreviousPattern.ColumnsFilled); + noteCount = Math.Min(noteCount, AvailableColumns - RandomStart - PreviousPattern.ColumnWithObjects); int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); for (int i = 0; i < noteCount; i++) { - while (pattern.IsFilled(nextColumn) || (PreviousPattern.IsFilled(nextColumn) && !allowStacking)) + while (pattern.ColumnHasObject(nextColumn) || (PreviousPattern.ColumnHasObject(nextColumn) && !allowStacking)) { if ((convertType & PatternType.Gathered) > 0) { @@ -278,7 +278,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy int nextColumn = Random.Next(RandomStart, columnLimit); for (int i = 0; i < noteCount; i++) { - while (pattern.IsFilled(nextColumn)) + while (pattern.ColumnHasObject(nextColumn)) nextColumn = Random.Next(RandomStart, columnLimit); // Add normal note From f70bfd537834ed58ac6bf3c4e6ccbaea131a419d Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 13:43:53 +0900 Subject: [PATCH 087/112] CI fixes. --- osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs | 2 +- .../Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 2e9375960a..125d8cdded 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps yield return obj; } - private List prevNoteTimes = new List(max_notes_for_density); + private readonly List prevNoteTimes = new List(max_notes_for_density); private double density = int.MaxValue; private void computeDensity(double newNoteTime) { diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index 4b65fb7bfd..07438d5f2c 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -89,7 +89,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { int lastColumn = PreviousPattern.HitObjects.First().Column; - if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Count() > 0) + if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Any()) { // Generate a new pattern by copying the last hit objects in reverse-column order var pattern = new Pattern(); @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy return pattern; } - if ((convertType & PatternType.ForceStack) > 0 && PreviousPattern.HitObjects.Count() > 0) + if ((convertType & PatternType.ForceStack) > 0 && PreviousPattern.HitObjects.Any()) { // Generate a new pattern by placing on the already filled columns var pattern = new Pattern(); @@ -217,7 +217,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); for (int i = 0; i < noteCount; i++) { - while (pattern.ColumnHasObject(nextColumn) || (PreviousPattern.ColumnHasObject(nextColumn) && !allowStacking)) + while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn) && !allowStacking) { if ((convertType & PatternType.Gathered) > 0) { From d0ddd62f84ee3138b4724ba1b6b4fc477a35b2f2 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 14:10:37 +0900 Subject: [PATCH 088/112] Add ManiaHitResult to ManiaJudgement. --- .../Judgements/ManiaHitResult.cs | 18 ++++++++++++++++++ .../Judgements/ManiaJudgement.cs | 2 ++ 2 files changed, 20 insertions(+) create mode 100644 osu.Game.Rulesets.Mania/Judgements/ManiaHitResult.cs diff --git a/osu.Game.Rulesets.Mania/Judgements/ManiaHitResult.cs b/osu.Game.Rulesets.Mania/Judgements/ManiaHitResult.cs new file mode 100644 index 0000000000..08c12a8151 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Judgements/ManiaHitResult.cs @@ -0,0 +1,18 @@ +using System.ComponentModel; + +namespace osu.Game.Rulesets.Mania.Judgements +{ + public enum ManiaHitResult + { + [Description("PERFECT")] + Perfect, + [Description("GREAT")] + Great, + [Description("GOOD")] + Good, + [Description("OK")] + Ok, + [Description("BAD")] + Bad + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs index 8dafbd01a5..eb544d79fc 100644 --- a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs +++ b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs @@ -10,5 +10,7 @@ namespace osu.Game.Rulesets.Mania.Judgements public override string ResultString => string.Empty; public override string MaxResultString => string.Empty; + + public ManiaHitResult ManiaResult; } } From 409464381c09a2f059e9cb7ef1dceb5900b135c1 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 14:11:14 +0900 Subject: [PATCH 089/112] Expose HitWindows so they're accessible from the drawable hit objects. --- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 2 +- osu.Game.Rulesets.Mania/Objects/Note.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 701947c381..41bbe08d56 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Mania.Objects /// /// The key-release hit windows for this hold note. /// - protected HitWindows ReleaseHitWindows = new HitWindows(); + public HitWindows ReleaseHitWindows { get; protected set; } = new HitWindows(); public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty) { diff --git a/osu.Game.Rulesets.Mania/Objects/Note.cs b/osu.Game.Rulesets.Mania/Objects/Note.cs index 1d2e4169b5..e955f6658b 100644 --- a/osu.Game.Rulesets.Mania/Objects/Note.cs +++ b/osu.Game.Rulesets.Mania/Objects/Note.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Objects /// /// The key-press hit window for this note. /// - protected HitWindows HitWindows = new HitWindows(); + public HitWindows HitWindows { get; protected set; } = new HitWindows(); public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty) { From c9723352977ecf57fbe8cfb579d8497482dd42a8 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 15:25:37 +0900 Subject: [PATCH 090/112] Add InputTarget to capture input from columns before hit objects. --- osu.Game.Rulesets.Mania/UI/Column.cs | 34 +++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index dea00433e6..e1a925937d 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -95,6 +95,12 @@ 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 + { + KeyDown = onKeyDown, + KeyUp = onKeyUp + } } }, new Container @@ -178,12 +184,9 @@ namespace osu.Game.Rulesets.Mania.UI } } - public void Add(DrawableHitObject hitObject) - { - ControlPointContainer.Add(hitObject); - } + public void Add(DrawableHitObject hitObject) => ControlPointContainer.Add(hitObject); - protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + private bool onKeyDown(InputState state, KeyDownEventArgs args) { if (args.Repeat) return false; @@ -197,7 +200,7 @@ namespace osu.Game.Rulesets.Mania.UI return false; } - protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) + private bool onKeyUp(InputState state, KeyUpEventArgs args) { if (args.Key == Key) { @@ -207,5 +210,24 @@ namespace osu.Game.Rulesets.Mania.UI return false; } + + /// + /// This is a simple container which delegates various input events that have to be captured before the notes. + /// + private class InputTarget : Container + { + public Func KeyDown; + public Func KeyUp; + + public InputTarget() + { + RelativeSizeAxes = Axes.Both; + AlwaysPresent = true; + Alpha = 0; + } + + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => KeyDown?.Invoke(state, args) ?? false; + protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => KeyUp?.Invoke(state, args) ?? false; + } } } From 3dfe88c0684064a80947de52360b1ebbb512e186 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 15:27:38 +0900 Subject: [PATCH 091/112] Make Key a bindable, pass down to drawable hit objects. --- .../Objects/Drawables/DrawableHoldNote.cs | 6 ++++-- .../Drawables/DrawableManiaHitObject.cs | 12 ++++++++++- .../Objects/Drawables/DrawableNote.cs | 6 ++++-- osu.Game.Rulesets.Mania/UI/Column.cs | 7 ++++++- .../UI/ManiaHitRenderer.cs | 12 +++++++++-- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 21 ++++++++++--------- 6 files changed, 46 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index d9e46f4720..f9d027e7ce 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -5,6 +5,8 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Framework.Graphics; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using OpenTK.Graphics; +using osu.Framework.Configuration; +using OpenTK.Input; namespace osu.Game.Rulesets.Mania.Objects.Drawables { @@ -14,8 +16,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables private readonly BodyPiece bodyPiece; private readonly NotePiece tailPiece; - public DrawableHoldNote(HoldNote hitObject) - : base(hitObject) + public DrawableHoldNote(HoldNote hitObject, Bindable key = null) + : base(hitObject, key) { RelativeSizeAxes = Axes.Both; Height = (float)HitObject.Duration; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index d33a8c48ee..4e276fddb7 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -2,6 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK.Graphics; +using OpenTK.Input; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Objects.Drawables; @@ -11,13 +13,21 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables public abstract class DrawableManiaHitObject : DrawableHitObject where TObject : ManiaHitObject { + /// + /// The key that will trigger input for this hit object. + /// + protected Bindable Key { get; private set; } = new Bindable(); + public new TObject HitObject; - protected DrawableManiaHitObject(TObject hitObject) + protected DrawableManiaHitObject(TObject hitObject, Bindable key = null) : base(hitObject) { HitObject = hitObject; + if (key != null) + Key.BindTo(key); + RelativePositionAxes = Axes.Y; Y = (float)HitObject.StartTime; } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index b216c362f5..d0519c61a8 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -2,6 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK.Graphics; +using OpenTK.Input; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Objects.Drawables; @@ -12,8 +14,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables { private readonly NotePiece headPiece; - public DrawableNote(Note hitObject) - : base(hitObject) + public DrawableNote(Note hitObject, Bindable key = null) + : base(hitObject, key) { RelativeSizeAxes = Axes.Both; Height = 100; diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index e1a925937d..72c60b28c9 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -18,6 +18,8 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Beatmaps.Timing; +using System; +using osu.Framework.Configuration; namespace osu.Game.Rulesets.Mania.UI { @@ -33,7 +35,10 @@ namespace osu.Game.Rulesets.Mania.UI private const float column_width = 45; private const float special_column_width = 70; - public Key Key; + /// + /// The key that will trigger input actions for this column and hit objects contained inside it. + /// + public Bindable Key = new Bindable(); private readonly Box background; private readonly Container hitTargetBar; diff --git a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs index c67866dc10..4d734d231f 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs @@ -4,6 +4,8 @@ using System; using System.Linq; using OpenTK; +using OpenTK.Input; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Timing; @@ -76,13 +78,19 @@ namespace osu.Game.Rulesets.Mania.UI protected override DrawableHitObject GetVisualRepresentation(ManiaHitObject h) { + var maniaPlayfield = Playfield as ManiaPlayfield; + if (maniaPlayfield == null) + return null; + + Bindable key = maniaPlayfield.Columns.ElementAt(h.Column).Key; + var holdNote = h as HoldNote; if (holdNote != null) - return new DrawableHoldNote(holdNote); + return new DrawableHoldNote(holdNote, key); var note = h as Note; if (note != null) - return new DrawableNote(note); + return new DrawableNote(note, key); return null; } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 56a86873e9..70bdd3b13c 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -55,7 +55,8 @@ namespace osu.Game.Rulesets.Mania.UI } } - public readonly FlowContainer Columns; + private readonly FlowContainer columns; + public IEnumerable Columns => columns.Children; private readonly ControlPointContainer barlineContainer; @@ -87,7 +88,7 @@ namespace osu.Game.Rulesets.Mania.UI RelativeSizeAxes = Axes.Both, Colour = Color4.Black }, - Columns = new FillFlowContainer + columns = new FillFlowContainer { Name = "Columns", RelativeSizeAxes = Axes.Y, @@ -114,7 +115,7 @@ namespace osu.Game.Rulesets.Mania.UI }; for (int i = 0; i < columnCount; i++) - Columns.Add(new Column(timingChanges)); + columns.Add(new Column(timingChanges)); TimeSpan = time_span_default; } @@ -133,17 +134,17 @@ namespace osu.Game.Rulesets.Mania.UI // Set the special column + colour + key for (int i = 0; i < columnCount; i++) { - Column column = Columns.Children.ElementAt(i); + Column column = Columns.ElementAt(i); column.IsSpecial = isSpecialColumn(i); if (!column.IsSpecial) continue; - column.Key = Key.Space; + column.Key.Value = Key.Space; column.AccentColour = specialColumnColour; } - var nonSpecialColumns = Columns.Children.Where(c => !c.IsSpecial).ToList(); + var nonSpecialColumns = Columns.Where(c => !c.IsSpecial).ToList(); // We'll set the colours of the non-special columns in a separate loop, because the non-special // column colours are mirrored across their centre and special styles mess with this @@ -162,11 +163,11 @@ namespace osu.Game.Rulesets.Mania.UI int keyOffset = default_keys.Length / 2 - nonSpecialColumns.Count / 2 + i; if (keyOffset >= 0 && keyOffset < default_keys.Length) - column.Key = default_keys[keyOffset]; + column.Key.Value = default_keys[keyOffset]; else // There is no default key defined for this column. Let's set this to Unknown for now // however note that this will be gone after bindings are in place - column.Key = Key.Unknown; + column.Key.Value = Key.Unknown; } } @@ -189,7 +190,7 @@ namespace osu.Game.Rulesets.Mania.UI } } - public override void Add(DrawableHitObject h) => Columns.Children.ElementAt(h.HitObject.Column).Add(h); + public override void Add(DrawableHitObject h) => Columns.ElementAt(h.HitObject.Column).Add(h); protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { @@ -225,7 +226,7 @@ namespace osu.Game.Rulesets.Mania.UI timeSpan = MathHelper.Clamp(timeSpan, time_span_min, time_span_max); barlineContainer.TimeSpan = value; - Columns.Children.ForEach(c => c.ControlPointContainer.TimeSpan = value); + Columns.ForEach(c => c.ControlPointContainer.TimeSpan = value); } } From dcf3148d23578776ecb8f484b1abb551935cb037 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 15:28:51 +0900 Subject: [PATCH 092/112] Fix osu!mania failing due to 0 hp. --- osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs index 96f04f79d4..7a9572a0c7 100644 --- a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs +++ b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs @@ -22,5 +22,12 @@ namespace osu.Game.Rulesets.Mania.Scoring protected override void OnNewJudgement(ManiaJudgement judgement) { } + + protected override void Reset() + { + base.Reset(); + + Health.Value = 1; + } } } From 60e036b5f454655b3068897483a9ebd782fc2b1f Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 15:29:02 +0900 Subject: [PATCH 093/112] Fix missing reference. --- osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index adcdfd5fae..408f20033e 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -56,6 +56,7 @@ + From 9a578e036e4dac1632886458c65779be52fc1ec9 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 16:09:32 +0900 Subject: [PATCH 094/112] Add xmldoc. --- osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs index eb544d79fc..6e69da3da7 100644 --- a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs +++ b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs @@ -11,6 +11,9 @@ namespace osu.Game.Rulesets.Mania.Judgements public override string MaxResultString => string.Empty; + /// + /// The hit result. + /// public ManiaHitResult ManiaResult; } } From 0f3cf18345c347cab2e3febbfe98214d5123234b Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 16:15:52 +0900 Subject: [PATCH 095/112] Forgot license header. --- osu.Game.Rulesets.Mania/Judgements/ManiaHitResult.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Judgements/ManiaHitResult.cs b/osu.Game.Rulesets.Mania/Judgements/ManiaHitResult.cs index 08c12a8151..207a1fb251 100644 --- a/osu.Game.Rulesets.Mania/Judgements/ManiaHitResult.cs +++ b/osu.Game.Rulesets.Mania/Judgements/ManiaHitResult.cs @@ -1,3 +1,6 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + using System.ComponentModel; namespace osu.Game.Rulesets.Mania.Judgements From 62c7e97a5f4acf00f5eedc85d884654b18767e2d Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 16:28:44 +0900 Subject: [PATCH 096/112] Add helper method to easily compare time offset to hit windows. --- .../Judgements/HitWindows.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Judgements/HitWindows.cs b/osu.Game.Rulesets.Mania/Judgements/HitWindows.cs index 2a0ce88506..307c03c8eb 100644 --- a/osu.Game.Rulesets.Mania/Judgements/HitWindows.cs +++ b/osu.Game.Rulesets.Mania/Judgements/HitWindows.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Game.Database; +using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.Mania.Judgements { @@ -140,6 +141,26 @@ namespace osu.Game.Rulesets.Mania.Judgements Miss = BeatmapDifficulty.DifficultyRange(difficulty, miss_max, miss_mid, miss_min); } + /// + /// Retrieves the hit result for a time offset. + /// + /// The time offset. + /// The hit result, or null if the time offset results in a miss. + public ManiaHitResult? ResultFor(double hitOffset) + { + if (hitOffset <= Perfect / 2) + return ManiaHitResult.Perfect; + if (hitOffset <= Great / 2) + return ManiaHitResult.Great; + if (hitOffset <= Good / 2) + return ManiaHitResult.Good; + if (hitOffset <= Ok / 2) + return ManiaHitResult.Ok; + if (hitOffset <= Bad / 2) + return ManiaHitResult.Bad; + return null; + } + /// /// Constructs new hit windows which have been multiplied by a value. /// From 6f00f7f0d084b274d10531f489eda396d6708c41 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 22 May 2017 16:34:38 +0900 Subject: [PATCH 097/112] Update HitWindows.cs --- osu.Game.Rulesets.Mania/Judgements/HitWindows.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Judgements/HitWindows.cs b/osu.Game.Rulesets.Mania/Judgements/HitWindows.cs index 307c03c8eb..674d83f6f2 100644 --- a/osu.Game.Rulesets.Mania/Judgements/HitWindows.cs +++ b/osu.Game.Rulesets.Mania/Judgements/HitWindows.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Game.Database; -using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.Mania.Judgements { From f9eb448f162915e1d7293652635a417a2dbed825 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 15:29:17 +0900 Subject: [PATCH 098/112] Implement DrawableNote hits. --- .../Objects/Drawables/DrawableNote.cs | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index d0519c61a8..48cfcd66cd 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -1,10 +1,13 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using OpenTK.Graphics; using OpenTK.Input; using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Framework.Input; +using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Objects.Drawables; @@ -40,14 +43,50 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables } } - protected override void Update() + protected override void CheckJudgement(bool userTriggered) { - if (Time.Current > HitObject.StartTime) - Colour = Color4.Green; + if (!userTriggered) + { + if (Judgement.TimeOffset > HitObject.HitWindows.Bad / 2) + Judgement.Result = HitResult.Miss; + return; + } + + double offset = Math.Abs(Judgement.TimeOffset); + + if (offset > HitObject.HitWindows.Miss / 2) + return; + + ManiaHitResult? tmpResult = HitObject.HitWindows.ResultFor(offset); + + if (tmpResult.HasValue) + { + Judgement.Result = HitResult.Hit; + Judgement.ManiaResult = tmpResult.Value; + } + else + Judgement.Result = HitResult.Miss; } protected override void UpdateState(ArmedState state) { + switch (State) + { + case ArmedState.Hit: + Colour = Color4.Green; + break; + } + } + + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + { + if (Judgement.Result != HitResult.None) + return false; + + if (args.Key != Key) + return false; + + return UpdateJudgement(true); } } } From 7314a9019c96fc7717e676e17a25fdf4c7c12d22 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 16:39:30 +0900 Subject: [PATCH 099/112] Fix nullref. --- .../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 07438d5f2c..d044ee8893 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy public override Pattern Generate() { - int lastColumn = PreviousPattern.HitObjects.First().Column; + int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0; if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Any()) { From 4200e05fe702acb5673cc3c99db7f773f3a94660 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 16:42:14 +0900 Subject: [PATCH 100/112] Don't handle repeat keys. --- osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index 48cfcd66cd..42bb371975 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -86,6 +86,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables if (args.Key != Key) return false; + if (args.Repeat) + return false; + return UpdateJudgement(true); } } From 85684e5fee4b70f8f1d35d8f1fe1598a6b2add46 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 22 May 2017 15:54:58 +0800 Subject: [PATCH 101/112] Do not scroll headers to when scrolling position is negative. --- osu.Game/Graphics/Containers/SectionsContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 7b57cb1b56..5fdb5e869e 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -137,7 +137,7 @@ namespace osu.Game.Graphics.Containers updateSectionsMargin(); } - float currentScroll = ScrollContainer.Current; + float currentScroll = Math.Max(0, ScrollContainer.Current); if (currentScroll != lastKnownScroll) { lastKnownScroll = currentScroll; From 63259a34573957888ea7b94f4faa1aa82cace6e4 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 22 May 2017 15:58:01 +0800 Subject: [PATCH 102/112] Fix depth of header background. Thanks to the order of adding to parent container, the depth value is actually not needed. --- osu.Game/Overlays/SettingsOverlay.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index af24a057e9..943545e858 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -162,8 +162,7 @@ namespace osu.Game.Overlays Add(headerBackground = new Box { Colour = Color4.Black, - RelativeSizeAxes = Axes.X, - Depth = float.MaxValue + RelativeSizeAxes = Axes.X }); } From abe9c464a82cc672699075417cfb3419fb901757 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 16:56:40 +0900 Subject: [PATCH 103/112] Invert if statements. --- .../Containers/BeatSyncedContainer.cs | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index d7f5d6c112..4a2e8b6262 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -20,29 +20,29 @@ namespace osu.Game.Graphics.Containers protected override void Update() { - if (beatmap.Value != null) - { - double trackCurrentTime = beatmap.Value.Track.CurrentTime; - ControlPoint kiaiControlPoint; - ControlPoint controlPoint = beatmap.Value.Beatmap.TimingInfo.TimingPointAt(trackCurrentTime, out kiaiControlPoint); + if (beatmap.Value == null) + return; - if (controlPoint != null) - { - double beatLength = controlPoint.BeatLength; - bool kiai = kiaiControlPoint?.KiaiMode ?? false; - double timingPointStart = controlPoint.Time; - int beat = beatLength > min_beat_length ? (int)((trackCurrentTime - timingPointStart) / beatLength) : 0; + double trackCurrentTime = beatmap.Value.Track.CurrentTime; + ControlPoint kiaiControlPoint; + ControlPoint controlPoint = beatmap.Value.Beatmap.TimingInfo.TimingPointAt(trackCurrentTime, out kiaiControlPoint); - //The beats before the start of the first control point are off by 1, this should do the trick - if (trackCurrentTime < timingPointStart) - beat--; + if (controlPoint == null) + return; - if ((timingPointStart != lastTimingPointStart || beat != lastBeat) && (int)((trackCurrentTime - timingPointStart) % beatLength) <= seek_tolerance) - OnNewBeat(beat, beatLength, controlPoint.TimeSignature, kiai); - lastBeat = beat; - lastTimingPointStart = timingPointStart; - } - } + double beatLength = controlPoint.BeatLength; + bool kiai = kiaiControlPoint?.KiaiMode ?? false; + double timingPointStart = controlPoint.Time; + int beat = beatLength > min_beat_length ? (int)((trackCurrentTime - timingPointStart) / beatLength) : 0; + + //The beats before the start of the first control point are off by 1, this should do the trick + if (trackCurrentTime < timingPointStart) + beat--; + + if ((timingPointStart != lastTimingPointStart || beat != lastBeat) && (int)((trackCurrentTime - timingPointStart) % beatLength) <= seek_tolerance) + OnNewBeat(beat, beatLength, controlPoint.TimeSignature, kiai); + lastBeat = beat; + lastTimingPointStart = timingPointStart; } protected virtual void OnNewBeat(int newBeat, double beatLength, TimeSignatures timeSignature, bool kiai) From b241140496813ee12431c2a876ca81841c4a2e1b Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 16:59:44 +0900 Subject: [PATCH 104/112] Proper kiai mode detection. --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 4a2e8b6262..5f6f0b76b5 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -30,8 +30,9 @@ namespace osu.Game.Graphics.Containers if (controlPoint == null) return; + bool kiai = (controlPoint ?? controlPoint).KiaiMode; + double beatLength = controlPoint.BeatLength; - bool kiai = kiaiControlPoint?.KiaiMode ?? false; double timingPointStart = controlPoint.Time; int beat = beatLength > min_beat_length ? (int)((trackCurrentTime - timingPointStart) / beatLength) : 0; From 609aac6453a1fd48d8a3a872f3dcefd79f30a110 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 17:00:53 +0900 Subject: [PATCH 105/112] Better kiai mode detection. --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 5f6f0b76b5..521d9650d9 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -24,13 +24,13 @@ namespace osu.Game.Graphics.Containers return; double trackCurrentTime = beatmap.Value.Track.CurrentTime; - ControlPoint kiaiControlPoint; - ControlPoint controlPoint = beatmap.Value.Beatmap.TimingInfo.TimingPointAt(trackCurrentTime, out kiaiControlPoint); + ControlPoint overridePoint; + ControlPoint controlPoint = beatmap.Value.Beatmap.TimingInfo.TimingPointAt(trackCurrentTime, out overridePoint); if (controlPoint == null) return; - bool kiai = (controlPoint ?? controlPoint).KiaiMode; + bool kiai = (overridePoint ?? controlPoint).KiaiMode; double beatLength = controlPoint.BeatLength; double timingPointStart = controlPoint.Time; From f81ffa636dc1770284c3d88c9f9514bdc4a30f22 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 17:01:43 +0900 Subject: [PATCH 106/112] Use BindTo instead of taking the game's beatmap bindable. --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 521d9650d9..666d0e3f77 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -11,7 +11,8 @@ namespace osu.Game.Graphics.Containers { public class BeatSyncedContainer : Container { - private Bindable beatmap; + private Bindable beatmap = new Bindable(); + private int lastBeat; private double lastTimingPointStart; //This is to avoid sending new beats when not at the very start of the beat @@ -20,7 +21,7 @@ namespace osu.Game.Graphics.Containers protected override void Update() { - if (beatmap.Value == null) + if (beatmap.Value?.Track == null) return; double trackCurrentTime = beatmap.Value.Track.CurrentTime; @@ -53,7 +54,7 @@ namespace osu.Game.Graphics.Containers [BackgroundDependencyLoader] private void load(OsuGameBase game) { - beatmap = game.Beatmap; + beatmap.BindTo(game.Beatmap); } } } From 70d7f61f7cf38314f2f68390b9924daf526dc9b7 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 17:15:23 +0900 Subject: [PATCH 107/112] More inversion for logic simplification. --- .../Containers/BeatSyncedContainer.cs | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 666d0e3f77..8b38547037 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -11,40 +11,42 @@ namespace osu.Game.Graphics.Containers { public class BeatSyncedContainer : Container { + /// + /// A new beat will not be sent if the time since the beat is larger than this tolerance. + /// + private const int seek_tolerance = 20; + private Bindable beatmap = new Bindable(); private int lastBeat; - private double lastTimingPointStart; - //This is to avoid sending new beats when not at the very start of the beat - private const int seek_tolerance = 20; - private const double min_beat_length = 1E-100; + private ControlPoint lastControlPoint; protected override void Update() { if (beatmap.Value?.Track == null) return; - double trackCurrentTime = beatmap.Value.Track.CurrentTime; + double currentTrackTime = beatmap.Value.Track.CurrentTime; ControlPoint overridePoint; - ControlPoint controlPoint = beatmap.Value.Beatmap.TimingInfo.TimingPointAt(trackCurrentTime, out overridePoint); - - if (controlPoint == null) - return; + ControlPoint controlPoint = beatmap.Value.Beatmap.TimingInfo.TimingPointAt(currentTrackTime, out overridePoint); bool kiai = (overridePoint ?? controlPoint).KiaiMode; + int beat = controlPoint.BeatLength > 0 ? (int)((currentTrackTime - controlPoint.Time) / controlPoint.BeatLength) : 0; - double beatLength = controlPoint.BeatLength; - double timingPointStart = controlPoint.Time; - int beat = beatLength > min_beat_length ? (int)((trackCurrentTime - timingPointStart) / beatLength) : 0; - - //The beats before the start of the first control point are off by 1, this should do the trick - if (trackCurrentTime < timingPointStart) + // The beats before the start of the first control point are off by 1, this should do the trick + if (currentTrackTime < controlPoint.Time) beat--; - if ((timingPointStart != lastTimingPointStart || beat != lastBeat) && (int)((trackCurrentTime - timingPointStart) % beatLength) <= seek_tolerance) - OnNewBeat(beat, beatLength, controlPoint.TimeSignature, kiai); + if (controlPoint == lastControlPoint && beat == lastBeat) + return; + + if ((currentTrackTime - controlPoint.Time) % controlPoint.BeatLength > seek_tolerance) + return; + + OnNewBeat(beat, controlPoint.BeatLength, controlPoint.TimeSignature, kiai); + lastBeat = beat; - lastTimingPointStart = timingPointStart; + lastControlPoint = controlPoint; } protected virtual void OnNewBeat(int newBeat, double beatLength, TimeSignatures timeSignature, bool kiai) From 3235e280a9a64554e56e618ee4ff27322955a4d9 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 17:31:53 +0900 Subject: [PATCH 108/112] Add to csproj. --- osu.Game/osu.Game.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 1631311ef6..b94c19e1f8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -292,6 +292,7 @@ + From fc90cfa604d37e1b063f7f5bffbb9f2d5a3cb015 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 22 May 2017 17:50:05 +0900 Subject: [PATCH 109/112] Update BeatSyncedContainer.cs --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 8b38547037..945de822a3 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -16,7 +16,7 @@ namespace osu.Game.Graphics.Containers /// private const int seek_tolerance = 20; - private Bindable beatmap = new Bindable(); + private readonly Bindable beatmap = new Bindable(); private int lastBeat; private ControlPoint lastControlPoint; From 95c4704a9e679381274c414d69dc9a5f5a5b908a Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 20:01:28 +0900 Subject: [PATCH 110/112] Delay backwards instead of using a millisecond tolerance. --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 945de822a3..d4b042c34c 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -11,11 +11,6 @@ namespace osu.Game.Graphics.Containers { public class BeatSyncedContainer : Container { - /// - /// A new beat will not be sent if the time since the beat is larger than this tolerance. - /// - private const int seek_tolerance = 20; - private readonly Bindable beatmap = new Bindable(); private int lastBeat; @@ -40,10 +35,10 @@ namespace osu.Game.Graphics.Containers if (controlPoint == lastControlPoint && beat == lastBeat) return; - if ((currentTrackTime - controlPoint.Time) % controlPoint.BeatLength > seek_tolerance) - return; + double offsetFromBeat = (controlPoint.Time - currentTrackTime) % controlPoint.BeatLength; - OnNewBeat(beat, controlPoint.BeatLength, controlPoint.TimeSignature, kiai); + using (BeginDelayedSequence(offsetFromBeat, true)) + OnNewBeat(beat, controlPoint.BeatLength, controlPoint.TimeSignature, kiai); lastBeat = beat; lastControlPoint = controlPoint; From de575b3867fb2b91db85494d935db9c99dd934bc Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 20:02:02 +0900 Subject: [PATCH 111/112] Early return if beatLength = 0. --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index d4b042c34c..12ed015c92 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -25,8 +25,11 @@ namespace osu.Game.Graphics.Containers ControlPoint overridePoint; ControlPoint controlPoint = beatmap.Value.Beatmap.TimingInfo.TimingPointAt(currentTrackTime, out overridePoint); + if (controlPoint.BeatLength == 0) + return; + bool kiai = (overridePoint ?? controlPoint).KiaiMode; - int beat = controlPoint.BeatLength > 0 ? (int)((currentTrackTime - controlPoint.Time) / controlPoint.BeatLength) : 0; + int beat = (int)((currentTrackTime - controlPoint.Time) / controlPoint.BeatLength); // The beats before the start of the first control point are off by 1, this should do the trick if (currentTrackTime < controlPoint.Time) From adf8bb853e16da48f1bc6d9bb06312e963249353 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 22 May 2017 20:06:37 +0900 Subject: [PATCH 112/112] Move load() to be directly below ctor. --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 12ed015c92..dfb742f7d1 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -47,14 +47,14 @@ namespace osu.Game.Graphics.Containers lastControlPoint = controlPoint; } - protected virtual void OnNewBeat(int newBeat, double beatLength, TimeSignatures timeSignature, bool kiai) - { - } - [BackgroundDependencyLoader] private void load(OsuGameBase game) { beatmap.BindTo(game.Beatmap); } + + protected virtual void OnNewBeat(int newBeat, double beatLength, TimeSignatures timeSignature, bool kiai) + { + } } }