From 902be0d059ca8fb4033e674bacafebe5dea2b7fb Mon Sep 17 00:00:00 2001 From: LeNitrous Date: Thu, 31 Jan 2019 17:03:43 +0800 Subject: [PATCH 01/11] add grow mod --- osu-resources | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs | 53 ++++++++++++++++++++++++ osu.Game.Rulesets.Osu/OsuRuleset.cs | 1 + 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs diff --git a/osu-resources b/osu-resources index 677897728f..9880089b4e 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit 677897728f4332fa1200e0280ca02c4b987c6c47 +Subproject commit 9880089b4e8fcd78d68f30c8a40d43bf8dccca86 diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs new file mode 100644 index 0000000000..5ab1ea698b --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs @@ -0,0 +1,53 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Mods +{ + internal class OsuModGrow : Mod, IApplicableToDrawableHitObjects + { + public override string Name => "Grow"; + public override string Acronym => "GR"; + public override FontAwesome Icon => FontAwesome.fa_arrows_v; + public override ModType Type => ModType.Fun; + public override string Description => "Hit them at the right size!"; + public override double ScoreMultiplier => 1; + + public void ApplyToDrawableHitObjects(IEnumerable drawables) + { + foreach (var drawable in drawables) + { + if (drawable is DrawableSpinner spinner) + return; + + drawable.ApplyCustomUpdateState += applyCustomState; + } + } + + protected virtual void applyCustomState(DrawableHitObject drawable, ArmedState state) + { + var hitObject = (OsuHitObject) drawable.HitObject; + + double appearTime = hitObject.StartTime - hitObject.TimePreempt - 1; + double scaleDuration = hitObject.TimePreempt + 1; + + var originalScale = drawable.Scale; + drawable.Scale /= 2; + + using (drawable.BeginAbsoluteSequence(appearTime, true)) + drawable.ScaleTo(originalScale, scaleDuration, Easing.OutSine); + + if (drawable is DrawableHitCircle circle) + using (circle.BeginAbsoluteSequence(hitObject.StartTime - hitObject.TimePreempt)) + circle.ApproachCircle.Hide(); + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 12d0a28a8f..200f4af3da 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -124,6 +124,7 @@ namespace osu.Game.Rulesets.Osu return new Mod[] { new OsuModTransform(), new OsuModWiggle(), + new OsuModGrow() }; default: return new Mod[] { }; From a8d30f6aee41f38fcbdd35df05e3a010675e9f5b Mon Sep 17 00:00:00 2001 From: LeNitrous Date: Thu, 31 Jan 2019 17:05:50 +0800 Subject: [PATCH 02/11] remove unused using --- osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs index 5ab1ea698b..b64cfa3ef2 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs @@ -8,7 +8,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osuTK; namespace osu.Game.Rulesets.Osu.Mods { From 7e2f4af00dd2d47212f1208857bccc936b057e0d Mon Sep 17 00:00:00 2001 From: LeNitrous Date: Thu, 31 Jan 2019 17:58:09 +0800 Subject: [PATCH 03/11] remove whitespaces --- osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs index b64cfa3ef2..8235a2d6a9 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs @@ -26,13 +26,12 @@ namespace osu.Game.Rulesets.Osu.Mods { if (drawable is DrawableSpinner spinner) return; - drawable.ApplyCustomUpdateState += applyCustomState; } } protected virtual void applyCustomState(DrawableHitObject drawable, ArmedState state) - { + { var hitObject = (OsuHitObject) drawable.HitObject; double appearTime = hitObject.StartTime - hitObject.TimePreempt - 1; From 1b61ec4ef402aa863671c552fc7f12aad2280517 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 14 Feb 2019 18:05:23 +0900 Subject: [PATCH 04/11] First pass clean-up --- osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs | 46 +++++++++++++++--------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs index 8235a2d6a9..c7e43dc006 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs @@ -14,38 +14,50 @@ namespace osu.Game.Rulesets.Osu.Mods internal class OsuModGrow : Mod, IApplicableToDrawableHitObjects { public override string Name => "Grow"; + public override string Acronym => "GR"; + public override FontAwesome Icon => FontAwesome.fa_arrows_v; + public override ModType Type => ModType.Fun; + public override string Description => "Hit them at the right size!"; + public override double ScoreMultiplier => 1; public void ApplyToDrawableHitObjects(IEnumerable drawables) { foreach (var drawable in drawables) { - if (drawable is DrawableSpinner spinner) - return; - drawable.ApplyCustomUpdateState += applyCustomState; + switch (drawable) + { + case DrawableSpinner _: + continue; + default: + drawable.ApplyCustomUpdateState += ApplyCustomState; + break; + } } } - protected virtual void applyCustomState(DrawableHitObject drawable, ArmedState state) + protected virtual void ApplyCustomState(DrawableHitObject drawable, ArmedState state) { - var hitObject = (OsuHitObject) drawable.HitObject; + var h = (OsuHitObject)drawable.HitObject; - double appearTime = hitObject.StartTime - hitObject.TimePreempt - 1; - double scaleDuration = hitObject.TimePreempt + 1; + var scale = drawable.Scale; + using (drawable.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) + drawable.ScaleTo(scale / 2).Then().ScaleTo(scale, h.TimePreempt, Easing.OutSine); - var originalScale = drawable.Scale; - drawable.Scale /= 2; - - using (drawable.BeginAbsoluteSequence(appearTime, true)) - drawable.ScaleTo(originalScale, scaleDuration, Easing.OutSine); - - if (drawable is DrawableHitCircle circle) - using (circle.BeginAbsoluteSequence(hitObject.StartTime - hitObject.TimePreempt)) - circle.ApproachCircle.Hide(); + switch (drawable) + { + case DrawableHitCircle circle: + { + // we don't want to see the approach circle + using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) + circle.ApproachCircle.Hide(); + break; + } + } } } -} \ No newline at end of file +} From 810175235d17adca7f44647dfa496b1993ff48bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 14 Feb 2019 18:47:05 +0900 Subject: [PATCH 05/11] Fix incorrect application of scaling in some cases Isolates different usages of hitcircle scale so they can't ever cause regressions. --- osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs | 21 ++++-- .../Objects/Drawables/DrawableHitCircle.cs | 67 ++++++++++++------- 2 files changed, 59 insertions(+), 29 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs index c7e43dc006..65e9eb7a1d 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs @@ -44,19 +44,30 @@ namespace osu.Game.Rulesets.Osu.Mods { var h = (OsuHitObject)drawable.HitObject; - var scale = drawable.Scale; - using (drawable.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) - drawable.ScaleTo(scale / 2).Then().ScaleTo(scale, h.TimePreempt, Easing.OutSine); + // apply grow effect + switch (drawable) + { + case DrawableSliderHead _: + case DrawableSliderTail _: + // special cases we should *not* be scaling. + break; + case DrawableSlider _: + case DrawableHitCircle _: + { + using (drawable.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) + drawable.ScaleTo(0.5f).Then().ScaleTo(1, h.TimePreempt, Easing.OutSine); + break; + } + } + // remove approach circles switch (drawable) { case DrawableHitCircle circle: - { // we don't want to see the approach circle using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) circle.ApproachCircle.Hide(); break; - } } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index df0769982d..7dd2fa69ce 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using osuTK; @@ -27,40 +28,58 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private readonly IBindable stackHeightBindable = new Bindable(); private readonly IBindable scaleBindable = new Bindable(); + private readonly Container explodeContainer; + + private readonly Container scaleContainer; + public DrawableHitCircle(HitCircle h) : base(h) { Origin = Anchor.Centre; Position = HitObject.StackedPosition; - Scale = new Vector2(h.Scale); InternalChildren = new Drawable[] { - glow = new GlowPiece(), - circle = new CirclePiece + scaleContainer = new Container { - Hit = () => + RelativeSizeAxes = Axes.Both, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Child = explodeContainer = new Container { - if (AllJudged) - return false; + RelativeSizeAxes = Axes.Both, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Children = new Drawable[] + { + glow = new GlowPiece(), + circle = new CirclePiece + { + Hit = () => + { + if (AllJudged) + return false; - UpdateResult(true); - return true; - }, + UpdateResult(true); + return true; + }, + }, + number = new NumberPiece + { + Text = (HitObject.IndexInCurrentCombo + 1).ToString(), + }, + ring = new RingPiece(), + flash = new FlashPiece(), + explode = new ExplodePiece(), + ApproachCircle = new ApproachCircle + { + Alpha = 0, + Scale = new Vector2(4), + } + } + } }, - number = new NumberPiece - { - Text = (HitObject.IndexInCurrentCombo + 1).ToString(), - }, - ring = new RingPiece(), - flash = new FlashPiece(), - explode = new ExplodePiece(), - ApproachCircle = new ApproachCircle - { - Alpha = 0, - Scale = new Vector2(4), - } }; //may not be so correct @@ -72,7 +91,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { positionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition); stackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition); - scaleBindable.BindValueChanged(v => Scale = new Vector2(v)); + scaleBindable.BindValueChanged(v => scaleContainer.Scale = new Vector2(v), true); positionBindable.BindTo(HitObject.PositionBindable); stackHeightBindable.BindTo(HitObject.StackHeightBindable); @@ -156,8 +175,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables circle.FadeOut(); number.FadeOut(); - this.FadeOut(800) - .ScaleTo(Scale * 1.5f, 400, Easing.OutQuad); + this.FadeOut(800); + explodeContainer.ScaleTo(1.5f, 400, Easing.OutQuad); } Expire(); From 133c002d02829038d6b796dc9a4e73b9beb9e789 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Feb 2019 12:12:21 +0900 Subject: [PATCH 06/11] Fix test dlls being loaded as actual rulesets (and failing) --- osu.Game/Rulesets/RulesetStore.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 5283c5c3cf..0ebadd73d2 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -22,7 +22,8 @@ namespace osu.Game.Rulesets { AppDomain.CurrentDomain.AssemblyResolve += currentDomain_AssemblyResolve; - foreach (string file in Directory.GetFiles(Environment.CurrentDirectory, $"{ruleset_library_prefix}.*.dll")) + foreach (string file in Directory.GetFiles(Environment.CurrentDirectory, $"{ruleset_library_prefix}.*.dll") + .Where(f => !Path.GetFileName(f).Contains("Tests"))) loadRulesetFromFile(file); } @@ -124,7 +125,7 @@ namespace osu.Game.Rulesets } catch (Exception e) { - Logger.Error(e, "Failed to load ruleset"); + Logger.Error(e, $"Failed to load ruleset {filename}"); } } } From af0bb4d5e8cdb14744c7330276c115c53af55a16 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 19 Feb 2019 13:40:39 +0900 Subject: [PATCH 07/11] Remove mods from constructor --- osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs | 5 ++--- osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index b1a88b8abd..d808ee528e 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -7,13 +7,12 @@ namespace osu.Game.Rulesets.Difficulty { public class DifficultyAttributes { - public readonly Mod[] Mods; + public Mod[] Mods; public double StarRating; - public DifficultyAttributes(Mod[] mods) + public DifficultyAttributes() { - Mods = mods; } public DifficultyAttributes(Mod[] mods, double starRating) diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index d7ae527bb1..30fc698664 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -25,7 +25,8 @@ namespace osu.Game.Rulesets.Difficulty protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) { - var attributes = CreateDifficultyAttributes(mods); + var attributes = CreateDifficultyAttributes(); + attributes.Mods = mods; if (!beatmap.HitObjects.Any()) return attributes; @@ -132,8 +133,7 @@ namespace osu.Game.Rulesets.Difficulty /// /// Creates an empty . /// - /// The s which difficulty is being processed with. /// The empty . - protected abstract DifficultyAttributes CreateDifficultyAttributes(Mod[] mods); + protected abstract DifficultyAttributes CreateDifficultyAttributes(); } } From 3784b673aec8a3139c622fb9935566834ee03756 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 19 Feb 2019 13:51:19 +0900 Subject: [PATCH 08/11] History -> LimitedCapacityStack + re-xmldoc --- osu.Game/Rulesets/Difficulty/Skills/Skill.cs | 2 +- .../{History.cs => LimitedCapacityStack.cs} | 24 +++++++++++-------- 2 files changed, 15 insertions(+), 11 deletions(-) rename osu.Game/Rulesets/Difficulty/Utils/{History.cs => LimitedCapacityStack.cs} (69%) diff --git a/osu.Game/Rulesets/Difficulty/Skills/Skill.cs b/osu.Game/Rulesets/Difficulty/Skills/Skill.cs index fa7aa8f637..72bb686260 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/Skill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/Skill.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Difficulty.Skills /// /// s that were processed previously. They can affect the strain values of the following objects. /// - protected readonly History Previous = new History(2); // Contained objects not used yet + protected readonly LimitedCapacityStack Previous = new LimitedCapacityStack(2); // Contained objects not used yet private double currentStrain = 1; // We keep track of the strain level at all times throughout the beatmap. private double currentSectionPeak = 1; // We also keep track of the peak strain level in the current section. diff --git a/osu.Game/Rulesets/Difficulty/Utils/History.cs b/osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityStack.cs similarity index 69% rename from osu.Game/Rulesets/Difficulty/Utils/History.cs rename to osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityStack.cs index d6647d5119..95b7d9b19d 100644 --- a/osu.Game/Rulesets/Difficulty/Utils/History.cs +++ b/osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityStack.cs @@ -8,11 +8,13 @@ using System.Collections.Generic; namespace osu.Game.Rulesets.Difficulty.Utils { /// - /// An indexed stack with Push() only, which disposes items at the bottom after the capacity is full. - /// Indexing starts at the top of the stack. + /// An indexed stack with limited depth. Indexing starts at the top of the stack. /// - public class History : IEnumerable + public class LimitedCapacityStack : IEnumerable { + /// + /// The number of elements in the stack. + /// public int Count { get; private set; } private readonly T[] array; @@ -20,10 +22,10 @@ namespace osu.Game.Rulesets.Difficulty.Utils private int marker; // Marks the position of the most recently added item. /// - /// Initializes a new instance of the History class that is empty and has the specified capacity. + /// Constructs a new . /// - /// The number of items the History can hold. - public History(int capacity) + /// The number of items the stack can hold. + public LimitedCapacityStack(int capacity) { if (capacity < 0) throw new ArgumentOutOfRangeException(); @@ -34,8 +36,9 @@ namespace osu.Game.Rulesets.Difficulty.Utils } /// - /// The most recently added item is returned at index 0. + /// Retrieves the item at an index in the stack. /// + /// The index of the item to retrieve. The top of the stack is returned at index 0. public T this[int i] { get @@ -52,11 +55,12 @@ namespace osu.Game.Rulesets.Difficulty.Utils } /// - /// Adds the item as the most recent one in the history. - /// The oldest item is disposed if the history is full. + /// Pushes an item to this . /// - public void Push(T item) // Overwrite the oldest item instead of shifting every item by one with every addition. + /// The item to push. + public void Push(T item) { + // Overwrite the oldest item instead of shifting every item by one with every addition. if (marker == 0) marker = capacity - 1; else From 9d8ba4073c8eb5f29674cc0539961904620f5f7c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 19 Feb 2019 14:17:23 +0900 Subject: [PATCH 09/11] Add tests for LimitedCapacityStack --- .../NonVisual/LimitedCapacityStackTest.cs | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 osu.Game.Tests/NonVisual/LimitedCapacityStackTest.cs diff --git a/osu.Game.Tests/NonVisual/LimitedCapacityStackTest.cs b/osu.Game.Tests/NonVisual/LimitedCapacityStackTest.cs new file mode 100644 index 0000000000..1c78b63499 --- /dev/null +++ b/osu.Game.Tests/NonVisual/LimitedCapacityStackTest.cs @@ -0,0 +1,115 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using NUnit.Framework; +using osu.Game.Rulesets.Difficulty.Utils; + +namespace osu.Game.Tests.NonVisual +{ + [TestFixture] + public class LimitedCapacityStackTest + { + private const int capacity = 3; + + private LimitedCapacityStack stack; + + [SetUp] + public void Setup() + { + stack = new LimitedCapacityStack(capacity); + } + + [Test] + public void TestEmptyStack() + { + Assert.AreEqual(0, stack.Count); + + Assert.Throws(() => + { + int unused = stack[0]; + }); + + int count = 0; + foreach (var unused in stack) + count++; + + Assert.AreEqual(0, count); + } + + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + public void TestInRangeElements(int count) + { + // e.g. 0 -> 1 -> 2 + for (int i = 0; i < count; i++) + stack.Push(i); + + Assert.AreEqual(count, stack.Count); + + // e.g. 2 -> 1 -> 0 (reverse order) + for (int i = 0; i < stack.Count; i++) + Assert.AreEqual(count - 1 - i, stack[i]); + + // e.g. indices 3, 4, 5, 6 (out of range) + for (int i = stack.Count; i < stack.Count + capacity; i++) + { + Assert.Throws(() => + { + int unused = stack[i]; + }); + } + } + + [TestCase(4)] + [TestCase(5)] + [TestCase(6)] + public void TestOverflowElements(int count) + { + // e.g. 0 -> 1 -> 2 -> 3 + for (int i = 0; i < count; i++) + stack.Push(i); + + Assert.AreEqual(capacity, stack.Count); + + // e.g. 3 -> 2 -> 1 (reverse order) + for (int i = 0; i < stack.Count; i++) + Assert.AreEqual(count - 1 - i, stack[i]); + + // e.g. indices 3, 4, 5, 6 (out of range) + for (int i = stack.Count; i < stack.Count + capacity; i++) + { + Assert.Throws(() => + { + int unused = stack[i]; + }); + } + } + + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + [TestCase(4)] + [TestCase(5)] + [TestCase(6)] + public void TestEnumerator(int count) + { + // e.g. 0 -> 1 -> 2 -> 3 + for (int i = 0; i < count; i++) + stack.Push(i); + + int enumeratorCount = 0; + int expectedValue = count - 1; + + foreach (var item in stack) + { + Assert.AreEqual(expectedValue, item); + enumeratorCount++; + expectedValue--; + } + + Assert.AreEqual(stack.Count, enumeratorCount); + } + } +} From 93b7b51d0a018dadbe52bff79c9d1ab69a3ce4dc Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 19 Feb 2019 14:29:23 +0900 Subject: [PATCH 10/11] timeRate -> clockRate --- .../CatchLegacyDifficultyCalculator.cs | 8 ++++---- .../ManiaLegacyDifficultyCalculator.cs | 8 ++++---- .../Difficulty/OsuLegacyDifficultyCalculator.cs | 10 +++++----- .../TaikoLegacyDifficultyCalculator.cs | 8 ++++---- .../DifficultyAdjustmentModCombinationsTest.cs | 2 +- .../Rulesets/Difficulty/DifficultyCalculator.cs | 16 ++++++++-------- .../Difficulty/LegacyDifficultyCalculator.cs | 4 ++-- .../Preprocessing/DifficultyHitObject.cs | 4 ++-- 8 files changed, 30 insertions(+), 30 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchLegacyDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchLegacyDifficultyCalculator.cs index 0a0897d97b..e1f17f309b 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchLegacyDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchLegacyDifficultyCalculator.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty { } - protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double clockRate) { if (!beatmap.HitObjects.Any()) return new CatchDifficultyAttributes(mods, 0); @@ -59,12 +59,12 @@ namespace osu.Game.Rulesets.Catch.Difficulty difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime)); - if (!calculateStrainValues(difficultyHitObjects, timeRate)) + if (!calculateStrainValues(difficultyHitObjects, clockRate)) return new CatchDifficultyAttributes(mods, 0); // this is the same as osu!, so there's potential to share the implementation... maybe - double preempt = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate; - double starRating = Math.Sqrt(calculateDifficulty(difficultyHitObjects, timeRate)) * star_scaling_factor; + double preempt = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / clockRate; + double starRating = Math.Sqrt(calculateDifficulty(difficultyHitObjects, clockRate)) * star_scaling_factor; return new CatchDifficultyAttributes(mods, starRating) { diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaLegacyDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaLegacyDifficultyCalculator.cs index 02b03aca5d..833454bf32 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaLegacyDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaLegacyDifficultyCalculator.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(ruleset.RulesetInfo); } - protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double clockRate) { if (!beatmap.HitObjects.Any()) return new ManiaDifficultyAttributes(mods, 0); @@ -50,15 +50,15 @@ namespace osu.Game.Rulesets.Mania.Difficulty // Note: Stable sort is done so that the ordering of hitobjects with equal start times doesn't change difficultyHitObjects.AddRange(beatmap.HitObjects.Select(h => new ManiaHitObjectDifficulty((ManiaHitObject)h, columnCount)).OrderBy(h => h.BaseHitObject.StartTime)); - if (!calculateStrainValues(difficultyHitObjects, timeRate)) + if (!calculateStrainValues(difficultyHitObjects, clockRate)) return new ManiaDifficultyAttributes(mods, 0); - double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor; + double starRating = calculateDifficulty(difficultyHitObjects, clockRate) * star_scaling_factor; return new ManiaDifficultyAttributes(mods, starRating) { // Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future - GreatHitWindow = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate + GreatHitWindow = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / clockRate }; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyDifficultyCalculator.cs index d01f75df6b..137630fb85 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyDifficultyCalculator.cs @@ -23,19 +23,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty { } - protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double clockRate) { if (!beatmap.HitObjects.Any()) return new OsuDifficultyAttributes(mods, 0); - OsuDifficultyBeatmap difficultyBeatmap = new OsuDifficultyBeatmap(beatmap.HitObjects.Cast().ToList(), timeRate); + OsuDifficultyBeatmap difficultyBeatmap = new OsuDifficultyBeatmap(beatmap.HitObjects.Cast().ToList(), clockRate); Skill[] skills = { new Aim(), new Speed() }; - double sectionLength = section_length * timeRate; + double sectionLength = section_length * clockRate; // The first object doesn't generate a strain, so we begin with an incremented section end double currentSectionEnd = Math.Ceiling(beatmap.HitObjects.First().StartTime / sectionLength) * sectionLength; @@ -66,8 +66,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; // Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be removed in the future - double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate; - double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate; + double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / clockRate; + double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / clockRate; int maxCombo = beatmap.HitObjects.Count; // Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoLegacyDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoLegacyDifficultyCalculator.cs index 650b367e34..22ee39541b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoLegacyDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoLegacyDifficultyCalculator.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { } - protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double clockRate) { if (!beatmap.HitObjects.Any()) return new TaikoDifficultyAttributes(mods, 0); @@ -46,15 +46,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty // Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure. difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime)); - if (!calculateStrainValues(difficultyHitObjects, timeRate)) + if (!calculateStrainValues(difficultyHitObjects, clockRate)) return new TaikoDifficultyAttributes(mods, 0); - double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor; + double starRating = calculateDifficulty(difficultyHitObjects, clockRate) * star_scaling_factor; return new TaikoDifficultyAttributes(mods, starRating) { // Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future - GreatHitWindow = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate, + GreatHitWindow = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / clockRate, MaxCombo = beatmap.HitObjects.Count(h => h is Hit) }; } diff --git a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs index f57f25e1ff..cc73cd54a2 100644 --- a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs +++ b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs @@ -146,7 +146,7 @@ namespace osu.Game.Tests.NonVisual protected override Mod[] DifficultyAdjustmentMods { get; } - protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) => throw new NotImplementedException(); + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double clockRate) => throw new NotImplementedException(); } } } diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index 30fc698664..ecfca9c589 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Difficulty { } - protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double clockRate) { var attributes = CreateDifficultyAttributes(); attributes.Mods = mods; @@ -31,10 +31,10 @@ namespace osu.Game.Rulesets.Difficulty if (!beatmap.HitObjects.Any()) return attributes; - var difficultyHitObjects = CreateDifficultyHitObjects(beatmap, timeRate).OrderBy(h => h.BaseObject.StartTime).ToList(); + var difficultyHitObjects = CreateDifficultyHitObjects(beatmap, clockRate).OrderBy(h => h.BaseObject.StartTime).ToList(); var skills = CreateSkills(); - double sectionLength = SectionLength * timeRate; + double sectionLength = SectionLength * clockRate; // The first object doesn't generate a strain, so we begin with an incremented section end double currentSectionEnd = Math.Ceiling(beatmap.HitObjects.First().StartTime / sectionLength) * sectionLength; @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Difficulty foreach (Skill s in skills) s.SaveCurrentPeak(); - PopulateAttributes(attributes, beatmap, skills, timeRate); + PopulateAttributes(attributes, beatmap, skills, clockRate); return attributes; } @@ -113,16 +113,16 @@ namespace osu.Game.Rulesets.Difficulty /// The to populate with information about the difficulty of . /// The whose difficulty was processed. /// The skills which processed the difficulty. - /// The rate of time in . - protected abstract void PopulateAttributes(DifficultyAttributes attributes, IBeatmap beatmap, Skill[] skills, double timeRate); + /// The rate at which the gameplay clock is run at. + protected abstract void PopulateAttributes(DifficultyAttributes attributes, IBeatmap beatmap, Skill[] skills, double clockRate); /// /// Enumerates s to be processed from s in the . /// /// The providing the s to enumerate. - /// The rate of time in . + /// The rate at which the gameplay clock is run at. /// The enumerated s. - protected abstract IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double timeRate); + protected abstract IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate); /// /// Creates the s to calculate the difficulty of s. diff --git a/osu.Game/Rulesets/Difficulty/LegacyDifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/LegacyDifficultyCalculator.cs index 15565ef847..a1324601aa 100644 --- a/osu.Game/Rulesets/Difficulty/LegacyDifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/LegacyDifficultyCalculator.cs @@ -100,8 +100,8 @@ namespace osu.Game.Rulesets.Difficulty /// /// The to compute the difficulty for. /// The s that should be applied. - /// The rate of time in . + /// The rate at which the gameplay clock is run at. /// A structure containing the difficulty attributes. - protected abstract DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate); + protected abstract DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double clockRate); } } diff --git a/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs b/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs index 77c9b7e47f..23a8740f3d 100644 --- a/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs +++ b/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs @@ -22,11 +22,11 @@ namespace osu.Game.Rulesets.Difficulty.Preprocessing /// public readonly HitObject LastObject; - public DifficultyHitObject(HitObject hitObject, HitObject lastObject, double timeRate) + public DifficultyHitObject(HitObject hitObject, HitObject lastObject, double clockRate) { BaseObject = hitObject; LastObject = lastObject; - DeltaTime = (hitObject.StartTime - lastObject.StartTime) / timeRate; + DeltaTime = (hitObject.StartTime - lastObject.StartTime) / clockRate; } } } From 7ed461aa8c31a55775fde83f39d273c8b4383542 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 19 Feb 2019 14:30:59 +0900 Subject: [PATCH 11/11] XMLDoc DifficultyHitObject --- .../Preprocessing/DifficultyHitObject.cs | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs b/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs index 23a8740f3d..ebbffb5143 100644 --- a/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs +++ b/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs @@ -5,23 +5,32 @@ using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Difficulty.Preprocessing { + /// + /// Wraps a and provides additional information to be used for difficulty calculation. + /// public class DifficultyHitObject { /// - /// Milliseconds elapsed since the of the previous . - /// - public double DeltaTime { get; private set; } - - /// - /// The this refers to. + /// The this wraps. /// public readonly HitObject BaseObject; /// - /// The previous to . + /// The last which occurs before . /// public readonly HitObject LastObject; + /// + /// Amount of time elapsed between and . + /// + public readonly double DeltaTime; + + /// + /// Creates a new . + /// + /// The which this wraps. + /// The last which occurs before in the beatmap. + /// The rate at which the gameplay clock is run at. public DifficultyHitObject(HitObject hitObject, HitObject lastObject, double clockRate) { BaseObject = hitObject;