diff --git a/osu-framework b/osu-framework index 67f3958036..d00a7df902 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 67f39580365f7d0a42f8788eae2b60881dde1c67 +Subproject commit d00a7df902074d0b3f1479904b7f322db9d39c1f diff --git a/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs b/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs index 1049a8818a..6bd9d35b80 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs @@ -85,25 +85,25 @@ namespace osu.Desktop.VisualTests.Tests Clock = new FramedClock(), Children = new Drawable[] { - new OsuHitRenderer(beatmap) + new OsuHitRenderer(beatmap, false) { Scale = new Vector2(0.5f), Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft }, - new TaikoHitRenderer(beatmap) + new TaikoHitRenderer(beatmap, false) { Scale = new Vector2(0.5f), Anchor = Anchor.TopRight, Origin = Anchor.TopRight }, - new CatchHitRenderer(beatmap) + new CatchHitRenderer(beatmap, false) { Scale = new Vector2(0.5f), Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft }, - new ManiaHitRenderer(beatmap) + new ManiaHitRenderer(beatmap, false) { Scale = new Vector2(0.5f), Anchor = Anchor.BottomRight, diff --git a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs index dceb7a9cff..8c913ae95e 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs @@ -129,8 +129,6 @@ namespace osu.Desktop.VisualTests.Tests }; Add(clockAdjustContainer); - - load(mode); } private int depth; diff --git a/osu.Desktop.VisualTests/Tests/TestCaseManiaHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseManiaHitObjects.cs index 3ad83beb73..3113b63db1 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseManiaHitObjects.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseManiaHitObjects.cs @@ -43,13 +43,8 @@ namespace osu.Desktop.VisualTests.Tests RelativeCoordinateSpace = new Vector2(1, 10000), Children = new[] { - new DrawableNote(new Note - { - StartTime = 5000 - }) - { - AccentColour = Color4.Red - } + new DrawableNote(new Note { StartTime = 5000 }) { AccentColour = Color4.Red }, + new DrawableNote(new Note { StartTime = 6000 }) { AccentColour = Color4.Red } } } } @@ -74,10 +69,7 @@ namespace osu.Desktop.VisualTests.Tests { StartTime = 5000, Duration = 1000 - }) - { - AccentColour = Color4.Red - } + }) { AccentColour = Color4.Red } } } } diff --git a/osu.Desktop.VisualTests/Tests/TestCaseMenuOverlays.cs b/osu.Desktop.VisualTests/Tests/TestCaseMenuOverlays.cs index acf98ea86b..23fe8f16db 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseMenuOverlays.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseMenuOverlays.cs @@ -12,7 +12,7 @@ namespace osu.Desktop.VisualTests.Tests { public override string Description => @"Tests pause and fail overlays"; - private PauseOverlay pauseOverlay; + private PauseContainer.PauseOverlay pauseOverlay; private FailOverlay failOverlay; private int retryCount; @@ -22,7 +22,7 @@ namespace osu.Desktop.VisualTests.Tests retryCount = 0; - Add(pauseOverlay = new PauseOverlay + Add(pauseOverlay = new PauseContainer.PauseOverlay { OnResume = () => Logger.Log(@"Resume"), OnRetry = () => Logger.Log(@"Retry"), diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs b/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs index 2427b6d12c..ba17cfc3d8 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs @@ -16,7 +16,7 @@ namespace osu.Desktop.VisualTests.Tests base.Reset(); Add(new BackButton()); - Add(new SkipButton()); + Add(new SkipButton(Clock.CurrentTime + 5000)); } } } diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index a6faf13d51..53449fd5f5 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Catch { public class CatchRuleset : Ruleset { - public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap) => new CatchHitRenderer(beatmap); + public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new CatchHitRenderer(beatmap, isForCurrentRuleset); public override IEnumerable GetModsFor(ModType type) { diff --git a/osu.Game.Rulesets.Catch/UI/CatchHitRenderer.cs b/osu.Game.Rulesets.Catch/UI/CatchHitRenderer.cs index f34585be55..179440adb3 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchHitRenderer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchHitRenderer.cs @@ -15,8 +15,8 @@ namespace osu.Game.Rulesets.Catch.UI { public class CatchHitRenderer : HitRenderer { - public CatchHitRenderer(WorkingBeatmap beatmap) - : base(beatmap) + public CatchHitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset) + : base(beatmap, isForCurrentRuleset) { } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index e51bbcdc13..933fe0787c 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -1,35 +1,153 @@ // 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.Objects; -using System.Collections.Generic; -using System; -using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Beatmaps; +using osu.Game.Rulesets.Mania.Objects; +using System; +using System.Collections.Generic; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; -using OpenTK; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Mania.Beatmaps.Patterns; +using osu.Game.Rulesets.Mania.MathUtils; +using osu.Game.Database; namespace osu.Game.Rulesets.Mania.Beatmaps { - internal class ManiaBeatmapConverter : BeatmapConverter + public class ManiaBeatmapConverter : BeatmapConverter { protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; + private Pattern lastPattern = new Pattern(); + private FastRandom random; + private Beatmap beatmap; + private bool isForCurrentRuleset; + + protected override Beatmap ConvertBeatmap(Beatmap original, bool isForCurrentRuleset) + { + this.isForCurrentRuleset = isForCurrentRuleset; + + beatmap = original; + + BeatmapDifficulty difficulty = original.BeatmapInfo.Difficulty; + + int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate); + random = new FastRandom(seed); + + return base.ConvertBeatmap(original, isForCurrentRuleset); + } + protected override IEnumerable ConvertHitObject(HitObject original, Beatmap beatmap) { - int availableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize); - - var positionData = original as IHasXPosition; - - float localWDivisor = 512.0f / availableColumns; - int column = MathHelper.Clamp((int)Math.Floor((positionData?.X ?? 1) / localWDivisor), 0, availableColumns - 1); - - yield return new Note + var maniaOriginal = original as ManiaHitObject; + if (maniaOriginal != null) { - StartTime = original.StartTime, - Column = column, - }; + yield return maniaOriginal; + yield break; + } + + var objects = isForCurrentRuleset ? generateSpecific(original) : generateConverted(original); + + if (objects == null) + yield break; + + foreach (ManiaHitObject obj in objects) + yield return obj; + } + + /// + /// Method that generates hit objects for osu!mania specific beatmaps. + /// + /// The original hit object. + /// The hit objects generated. + private IEnumerable generateSpecific(HitObject original) + { + var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern); + + Pattern newPattern = generator.Generate(); + lastPattern = newPattern; + + return newPattern.HitObjects; + } + + /// + /// Method that generates hit objects for non-osu!mania beatmaps. + /// + /// The original hit object. + /// The hit objects generated. + private IEnumerable generateConverted(HitObject original) + { + var endTimeData = original as IHasEndTime; + var distanceData = original as IHasDistance; + var positionData = original as IHasPosition; + + // Following lines currently commented out to appease resharper + + //Patterns.PatternGenerator conversion = null; + + if (distanceData != null) + { + // Slider + } + else if (endTimeData != null) + { + // Spinner + } + else if (positionData != null) + { + // Circle + } + + //if (conversion == null) + return null; + + //Pattern newPattern = conversion.Generate(); + //lastPattern = newPattern; + + //return newPattern.HitObjects; + } + + /// + /// A pattern generator for osu!mania-specific beatmaps. + /// + private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator + { + public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern) + : base(random, hitObject, beatmap, previousPattern) + { + } + + public override Pattern Generate() + { + var endTimeData = HitObject as IHasEndTime; + var positionData = HitObject as IHasXPosition; + + int column = GetColumn(positionData?.X ?? 0); + + var pattern = new Pattern(); + + if (endTimeData != null) + { + pattern.Add(new HoldNote + { + StartTime = HitObject.StartTime, + Samples = HitObject.Samples, + Duration = endTimeData.Duration, + Column = column, + }); + } + else if (positionData != null) + { + pattern.Add(new Note + { + StartTime = HitObject.StartTime, + Samples = HitObject.Samples, + Column = column + }); + } + + return pattern; + } } } } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs new file mode 100644 index 0000000000..ad07c03b96 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs @@ -0,0 +1,106 @@ +// 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.Beatmaps; +using osu.Game.Database; +using osu.Game.Rulesets.Mania.MathUtils; +using osu.Game.Rulesets.Objects; +using OpenTK; + +namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy +{ + /// + /// A pattern generator for legacy hit objects. + /// + internal abstract class PatternGenerator : Patterns.PatternGenerator + { + /// + /// The column index at which to start generating random notes. + /// + protected readonly int RandomStart; + + /// + /// The random number generator to use. + /// + protected readonly FastRandom Random; + + protected PatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern) + : base(hitObject, beatmap, previousPattern) + { + Random = random; + + RandomStart = AvailableColumns == 8 ? 1 : 0; + } + + /// + /// Converts an x-position into a column. + /// + /// The x-position. + /// Whether to treat as 7K + 1. + /// The column. + protected int GetColumn(float position, bool allowSpecial = false) + { + if (allowSpecial && AvailableColumns == 8) + { + const float local_x_divisor = 512f / 7; + return MathHelper.Clamp((int)Math.Floor(position / local_x_divisor), 0, 6) + 1; + } + + float localXDivisor = 512f / AvailableColumns; + return MathHelper.Clamp((int)Math.Floor(position / localXDivisor), 0, AvailableColumns - 1); + } + + /// + /// Generates a count of notes to be generated from 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. + /// Probability for 6 notes to be generated. + /// The amount of notes to be generated. + protected int GetRandomNoteCount(double p2, double p3, double p4 = 0, double p5 = 0, double p6 = 0) + { + double val = Random.NextDouble(); + if (val >= 1 - p6) + return 6; + if (val >= 1 - p5) + return 5; + if (val >= 1 - p4) + return 4; + if (val >= 1 - p3) + return 3; + return val >= 1 - p2 ? 2 : 1; + } + + private double? conversionDifficulty; + /// + /// A difficulty factor used for various conversion methods from osu!stable. + /// + protected double ConversionDifficulty + { + get + { + if (conversionDifficulty != null) + return conversionDifficulty.Value; + + HitObject lastObject = Beatmap.HitObjects.LastOrDefault(); + HitObject firstObject = Beatmap.HitObjects.FirstOrDefault(); + + double drainTime = (lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0); + drainTime -= Beatmap.EventInfo.TotalBreakTime; + + if (drainTime == 0) + drainTime = 10000; + + BeatmapDifficulty difficulty = Beatmap.BeatmapInfo.Difficulty; + conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + Beatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15; + conversionDifficulty = Math.Min(conversionDifficulty.Value, 12); + + return conversionDifficulty.Value; + } + } + } +} diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs new file mode 100644 index 0000000000..d4957d41a9 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs @@ -0,0 +1,65 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; + +namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy +{ + /// + /// The type of pattern to generate. Used for legacy patterns. + /// + [Flags] + internal enum PatternType + { + None = 0, + /// + /// Keep the same as last row. + /// + ForceStack = 1, + /// + /// Keep different from last row. + /// + ForceNotStack = 2, + /// + /// Keep as single note at its original position. + /// + KeepSingle = 4, + /// + /// Use a lower random value. + /// + LowProbability = 8, + /// + /// Reserved. + /// + Alternate = 16, + /// + /// Ignore the repeat count. + /// + ForceSigSlider = 32, + /// + /// Convert slider to circle. + /// + ForceNotSlider = 64, + /// + /// Notes gathered together. + /// + Gathered = 128, + Mirror = 256, + /// + /// Change 0 -> 6. + /// + Reverse = 512, + /// + /// 1 -> 5 -> 1 -> 5 like reverse. + /// + Cycle = 1024, + /// + /// Next note will be at column + 1. + /// + Stair = 2048, + /// + /// Next note will be at column - 1. + /// + ReverseStair = 4096 + } +} diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs new file mode 100644 index 0000000000..cbde1f0f53 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs @@ -0,0 +1,61 @@ +// 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; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Game.Rulesets.Mania.Objects; + +namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns +{ + /// + /// Creates a pattern containing hit objects. + /// + internal class Pattern + { + private readonly List hitObjects = new List(); + + /// + /// All the hit objects contained in this pattern. + /// + public IEnumerable HitObjects => hitObjects; + + /// + /// Whether this pattern already contains a hit object in a code. + /// + /// The column index. + /// Whether this pattern already contains a hit object in + public bool IsFilled(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(); + + /// + /// Adds a hit object to this pattern. + /// + /// The hit object to add. + public void Add(ManiaHitObject hitObject) => hitObjects.Add(hitObject); + + /// + /// Copies hit object from another pattern to this one. + /// + /// The other pattern. + public void Add(Pattern other) + { + other.HitObjects.ForEach(Add); + } + + /// + /// Clears this pattern, removing all hit objects. + /// + public void Clear() => hitObjects.Clear(); + + /// + /// Removes a hit object from this pattern. + /// + /// The hit object to remove. + public bool Remove(ManiaHitObject hitObject) => hitObjects.Remove(hitObject); + } +} diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs new file mode 100644 index 0000000000..dda4d07182 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs @@ -0,0 +1,50 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns +{ + /// + /// Generator to create a pattern from a hit object. + /// + internal abstract class PatternGenerator + { + /// + /// The number of columns available to create the pattern. + /// + protected readonly int AvailableColumns; + + /// + /// The last pattern. + /// + protected readonly Pattern PreviousPattern; + + /// + /// The hit object to create the pattern for. + /// + protected readonly HitObject HitObject; + + /// + /// The beatmap which is a part of. + /// + protected readonly Beatmap Beatmap; + + protected PatternGenerator(HitObject hitObject, Beatmap beatmap, Pattern previousPattern) + { + PreviousPattern = previousPattern; + HitObject = hitObject; + Beatmap = beatmap; + + AvailableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize); + } + + /// + /// Generates the pattern for , filled with hit objects. + /// + /// The containing the hit objects. + public abstract Pattern Generate(); + } +} diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 26614075b1..30d1846746 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania { public class ManiaRuleset : Ruleset { - public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap) => new ManiaHitRenderer(beatmap); + public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new ManiaHitRenderer(beatmap, isForCurrentRuleset); public override IEnumerable GetModsFor(ModType type) { diff --git a/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs b/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs new file mode 100644 index 0000000000..ff3fd8e4b7 --- /dev/null +++ b/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs @@ -0,0 +1,92 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; + +namespace osu.Game.Rulesets.Mania.MathUtils +{ + /// + /// A PRNG specified in http://heliosphan.org/fastrandom.html. + /// + internal class FastRandom + { + private const double uint_to_real = 1.0 / (uint.MaxValue + 1.0); + private const uint int_mask = 0x7FFFFFFF; + private const uint y = 842502087; + private const uint z = 3579807591; + private const uint w = 273326509; + private uint _x, _y = y, _z = z, _w = w; + + public FastRandom(int seed) + { + _x = (uint)seed; + } + + public FastRandom() + : this(Environment.TickCount) + { + } + + /// + /// Generates a random unsigned integer within the range [, ). + /// + /// The random value. + public uint NextUInt() + { + uint t = _x ^ _x << 11; + _x = _y; + _y = _z; + _z = _w; + return _w = _w ^ _w >> 19 ^ t ^ t >> 8; + } + + /// + /// Generates a random integer value within the range [0, ). + /// + /// The random value. + public int Next() => (int)(int_mask & NextUInt()); + + /// + /// Generates a random integer value within the range [0, ). + /// + /// The upper bound. + /// The random value. + public int Next(int upperBound) => (int)(NextDouble() * upperBound); + + /// + /// Generates a random integer value within the range [, ). + /// + /// The lower bound of the range. + /// The upper bound of the range. + /// The random value. + public int Next(int lowerBound, int upperBound) => (int)(lowerBound + NextDouble() * (upperBound - lowerBound)); + + /// + /// Generates a random double value within the range [0, 1). + /// + /// The random value. + public double NextDouble() => uint_to_real * NextUInt(); + + private uint bitBuffer; + private int bitIndex = 32; + + /// + /// Generates a reandom boolean value. Cached such that a random value is only generated once in every 32 calls. + /// + /// The random value. + public bool NextBool() + { + if (bitIndex == 32) + { + bitBuffer = NextUInt(); + bitIndex = 1; + + return (bitBuffer & 1) == 1; + } + + bitIndex++; + return ((bitBuffer >>= 1) & 1) == 1; + } + + } +} diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 767a2b3458..d9e46f4720 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables tailPiece = new NotePiece { Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre + Origin = Anchor.TopCentre } }); } @@ -61,5 +61,16 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables protected override void UpdateState(ArmedState state) { } + + protected override void Update() + { + if (Time.Current > HitObject.StartTime) + headPiece.Colour = Color4.Green; + if (Time.Current > HitObject.EndTime) + { + bodyPiece.Colour = Color4.Green; + tailPiece.Colour = Color4.Green; + } + } } } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index 0307e9162a..d33a8c48ee 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -3,8 +3,6 @@ using OpenTK.Graphics; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Objects.Drawables; @@ -15,8 +13,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables { public new TObject HitObject; - private readonly Container glowContainer; - protected DrawableManiaHitObject(TObject hitObject) : base(hitObject) { @@ -24,21 +20,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables RelativePositionAxes = Axes.Y; Y = (float)HitObject.StartTime; - - Add(glowContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - } - } - }); } public override Color4 AccentColour @@ -49,13 +30,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables if (base.AccentColour == value) return; base.AccentColour = value; - - glowContainer.EdgeEffect = new EdgeEffect - { - Type = EdgeEffectType.Glow, - Radius = 5, - Colour = value - }; } } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs index ce61a7a86f..c10aa9994b 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs @@ -19,7 +19,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces public BodyPiece() { RelativeSizeAxes = Axes.Both; - Masking = true; Children = new[] { diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs index 93aaa94f45..f6eb4aea2c 100644 --- a/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs @@ -9,5 +9,11 @@ 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; } } } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs index 986aefb2bd..0bf70017e3 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs @@ -24,8 +24,8 @@ namespace osu.Game.Rulesets.Mania.UI { public int? Columns; - public ManiaHitRenderer(WorkingBeatmap beatmap) - : base(beatmap) + public ManiaHitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset) + : base(beatmap, isForCurrentRuleset) { } @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania.UI return t; }); - double lastObjectTime = (Objects.Last() as IHasEndTime)?.EndTime ?? Objects.Last().StartTime; + double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue; // Perform some post processing of the timing changes timingChanges = timingChanges @@ -76,6 +76,10 @@ namespace osu.Game.Rulesets.Mania.UI protected override DrawableHitObject GetVisualRepresentation(ManiaHitObject h) { + var holdNote = h as HoldNote; + if (holdNote != null) + return new DrawableHoldNote(holdNote); + var note = h as Note; if (note != null) return new DrawableNote(note); diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 00deaba85d..ec426c895f 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -47,7 +47,12 @@ + + + + + diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index a8ff231cc7..854a9b5f49 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -1,15 +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.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.MathUtils; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; using OpenTK.Graphics; -using osu.Game.Rulesets.Osu.UI; +using osu.Game.Graphics; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Allocation; +using osu.Game.Screens.Ranking; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -18,9 +19,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private readonly Spinner spinner; private readonly SpinnerDisc disc; + private readonly SpinnerTicks ticks; + + private readonly Container mainContainer; + private readonly SpinnerBackground background; private readonly Container circleContainer; - private readonly DrawableHitCircle circle; + private readonly CirclePiece circle; + private readonly GlowPiece glow; + + private readonly TextAwesome symbol; + + private Color4 normalColour; + private Color4 completeColour; public DrawableSpinner(Spinner s) : base(s) { @@ -29,57 +40,91 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Origin = Anchor.Centre; Position = s.Position; - //take up full playfield. - Size = new Vector2(OsuPlayfield.BASE_SIZE.X); + RelativeSizeAxes = Axes.Both; + + // we are slightly bigger than our parent, to clip the top and bottom of the circle + Height = 1.3f; spinner = s; Children = new Drawable[] { - background = new SpinnerBackground - { - Alpha = 0, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - DiscColour = Color4.Black - }, - disc = new SpinnerDisc - { - Alpha = 0, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - DiscColour = AccentColour - }, circleContainer = new Container { AutoSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Children = new [] + Children = new Drawable[] { - circle = new DrawableHitCircle(s) + glow = new GlowPiece(), + circle = new CirclePiece { - Interactive = false, Position = Vector2.Zero, Anchor = Anchor.Centre, - } + }, + new RingPiece(), + symbol = new TextAwesome + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + UseFullGlyphHeight = true, + TextSize = 48, + Icon = FontAwesome.fa_asterisk, + Shadow = false, + }, } - } + }, + mainContainer = new AspectContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + Children = new Drawable[] + { + background = new SpinnerBackground + { + Alpha = 0.6f, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + disc = new SpinnerDisc(spinner) + { + Scale = Vector2.Zero, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + circleContainer.CreateProxy(), + ticks = new SpinnerTicks + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + } + }, }; - - background.Scale = scaleToCircle; - disc.Scale = scaleToCircle; } + public float Progress => MathHelper.Clamp(disc.RotationAbsolute / 360 / spinner.SpinsRequired, 0, 1); + protected override void CheckJudgement(bool userTriggered) { if (Time.Current < HitObject.StartTime) return; - disc.ScaleTo(Interpolation.ValueAt(Math.Sqrt(Progress), scaleToCircle, Vector2.One, 0, 1), 100); - - if (Progress >= 1) + if (Progress >= 1 && !disc.Complete) + { disc.Complete = true; + const float duration = 200; + + disc.FadeAccent(completeColour, duration); + + background.FadeAccent(completeColour, duration); + background.FadeOut(duration); + + circle.FadeColour(completeColour, duration); + glow.FadeColour(completeColour, duration); + } + if (!userTriggered && Time.Current >= spinner.EndTime) { if (Progress >= 1) @@ -106,26 +151,48 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } } - private Vector2 scaleToCircle => circle.Scale * circle.DrawWidth / DrawWidth * 0.95f; + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + normalColour = colours.SpinnerBase; - public float Progress => MathHelper.Clamp(disc.RotationAbsolute / 360 / spinner.SpinsRequired, 0, 1); + background.AccentColour = normalColour; + + completeColour = colours.YellowLight.Opacity(0.6f); + + disc.AccentColour = colours.SpinnerFill; + circle.Colour = colours.BlueDark; + glow.Colour = colours.BlueDark; + } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + circle.Rotation = disc.Rotation; + ticks.Rotation = disc.Rotation; + + float relativeCircleScale = spinner.Scale * circle.DrawHeight / mainContainer.DrawHeight; + disc.ScaleTo(relativeCircleScale + (1 - relativeCircleScale) * Progress, 200, EasingTypes.OutQuint); + + symbol.RotateTo(disc.Rotation / 2, 500, EasingTypes.OutQuint); + } protected override void UpdatePreemptState() { base.UpdatePreemptState(); - circleContainer.ScaleTo(1, 400, EasingTypes.OutElastic); + circleContainer.ScaleTo(spinner.Scale * 0.3f); + circleContainer.ScaleTo(spinner.Scale, TIME_PREEMPT / 1.4f, EasingTypes.OutQuint); - background.Delay(TIME_PREEMPT - 500); + disc.RotateTo(-720); + symbol.RotateTo(-720); - background.ScaleTo(scaleToCircle * 1.2f, 400, EasingTypes.OutQuint); - background.FadeIn(200); + mainContainer.ScaleTo(0); + mainContainer.ScaleTo(spinner.Scale * circle.DrawHeight / DrawHeight * 1.4f, TIME_PREEMPT - 150, EasingTypes.OutQuint); - background.Delay(400); - background.ScaleTo(1, 250, EasingTypes.OutQuint); - - disc.Delay(TIME_PREEMPT - 50); - disc.FadeIn(200); + mainContainer.Delay(TIME_PREEMPT - 150); + mainContainer.ScaleTo(1, 500, EasingTypes.OutQuint); } protected override void UpdateCurrentState(ArmedState state) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs index 9a90c07517..3004dafda7 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs @@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { private readonly Sprite disc; - public Func Hit; public CirclePiece() diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs index 72024bbe99..1c54f9f893 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs @@ -1,10 +1,55 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // 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; +using osu.Game.Graphics; + namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { - public class SpinnerBackground : SpinnerDisc + public class SpinnerBackground : CircularContainer, IHasAccentColour { public override bool HandleInput => false; + + protected Box Disc; + + public Color4 AccentColour + { + get + { + return Disc.Colour; + } + set + { + Disc.Colour = value; + + EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Glow, + Radius = 14, + Colour = value.Opacity(0.3f), + }; + } + } + + public SpinnerBackground() + { + RelativeSizeAxes = Axes.Both; + Masking = true; + + Children = new Drawable[] + { + Disc = new Box + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Alpha = 1, + }, + }; + } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 71adba74c7..4e4d4e30b9 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -2,13 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Transforms; using osu.Framework.Input; using osu.Game.Graphics; @@ -17,104 +12,31 @@ using OpenTK.Graphics; namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { - public class SpinnerDisc : CircularContainer + public class SpinnerDisc : CircularContainer, IHasAccentColour { - protected Sprite Disc; + private readonly Spinner spinner; - public SRGBColour DiscColour + public Color4 AccentColour { - get { return Disc.Colour; } - set { Disc.Colour = value; } + get { return background.AccentColour; } + set { background.AccentColour = value; } } - private Color4 completeColour; + private readonly SpinnerBackground background; - [BackgroundDependencyLoader] - private void load(OsuColour colours) + private const float idle_alpha = 0.2f; + private const float tracking_alpha = 0.4f; + + public SpinnerDisc(Spinner s) { - completeColour = colours.YellowLight.Opacity(0.8f); - Masking = true; - } + spinner = s; - private class SpinnerBorder : Container - { - public SpinnerBorder() - { - Origin = Anchor.Centre; - Anchor = Anchor.Centre; - RelativeSizeAxes = Axes.Both; - - layout(); - } - - private int lastLayoutDotCount; - private void layout() - { - int count = (int)(MathHelper.Pi * ScreenSpaceDrawQuad.Width / 9); - - if (count == lastLayoutDotCount) return; - - lastLayoutDotCount = count; - - while (Children.Count() < count) - { - Add(new CircularContainer - { - Colour = Color4.White, - RelativePositionAxes = Axes.Both, - Masking = true, - Origin = Anchor.Centre, - Size = new Vector2(1 / ScreenSpaceDrawQuad.Width * 2000), - Children = new[] - { - new Box - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - } - } - }); - } - - var size = new Vector2(1 / ScreenSpaceDrawQuad.Width * 2000); - - int i = 0; - foreach (var d in Children) - { - d.Size = size; - d.Position = new Vector2( - 0.5f + (float)Math.Sin((float)i / count * 2 * MathHelper.Pi) / 2, - 0.5f + (float)Math.Cos((float)i / count * 2 * MathHelper.Pi) / 2 - ); - - i++; - } - } - - protected override void Update() - { - base.Update(); - layout(); - } - } - - public SpinnerDisc() - { AlwaysReceiveInput = true; - RelativeSizeAxes = Axes.Both; Children = new Drawable[] { - Disc = new Box - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Alpha = 0.2f, - }, - new SpinnerBorder() + background = new SpinnerBackground { Alpha = idle_alpha }, }; } @@ -125,10 +47,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces set { if (value == tracking) return; - tracking = value; - Disc.FadeTo(tracking ? 0.5f : 0.2f, 100); + background.FadeTo(tracking ? tracking_alpha : idle_alpha, 100); } } @@ -139,31 +60,28 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces set { if (value == complete) return; - complete = value; - Disc.FadeColour(completeColour, 200); - updateCompleteTick(); } } protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { - Tracking = true; + Tracking |= state.Mouse.HasMainButtonPressed; return base.OnMouseDown(state, args); } protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) { - Tracking = false; + Tracking &= state.Mouse.HasMainButtonPressed; return base.OnMouseUp(state, args); } protected override bool OnMouseMove(InputState state) { Tracking |= state.Mouse.HasMainButtonPressed; - mousePosition = state.Mouse.Position; + mousePosition = Parent.ToLocalSpace(state.Mouse.NativeState.Position); return base.OnMouseMove(state); } @@ -177,13 +95,24 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces private bool updateCompleteTick() => completeTick != (completeTick = (int)(RotationAbsolute / 360)); + private bool rotationTransferred; + protected override void Update() { base.Update(); var thisAngle = -(float)MathHelper.RadiansToDegrees(Math.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2)); - if (tracking) + + bool validAndTracking = tracking && spinner.StartTime <= Time.Current && spinner.EndTime > Time.Current; + + if (validAndTracking) { + if (!rotationTransferred) + { + currentRotation = Rotation * 2; + rotationTransferred = true; + } + if (thisAngle - lastAngle > 180) lastAngle += 360; else if (lastAngle - thisAngle > 180) @@ -192,17 +121,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces currentRotation += thisAngle - lastAngle; RotationAbsolute += Math.Abs(thisAngle - lastAngle); } + lastAngle = thisAngle; if (Complete && updateCompleteTick()) { - Disc.Flush(flushType: typeof(TransformAlpha)); - Disc.FadeTo(0.75f, 30, EasingTypes.OutExpo); - Disc.Delay(30); - Disc.FadeTo(0.5f, 250, EasingTypes.OutQuint); + background.Flush(flushType: typeof(TransformAlpha)); + background.FadeTo(tracking_alpha + 0.4f, 60, EasingTypes.OutExpo); + background.Delay(60); + background.FadeTo(tracking_alpha, 250, EasingTypes.OutQuint); } - RotateTo(currentRotation, 100, EasingTypes.OutExpo); + RotateTo(currentRotation / 2, validAndTracking ? 500 : 1500, EasingTypes.OutExpo); } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs new file mode 100644 index 0000000000..dc3d18d40a --- /dev/null +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs @@ -0,0 +1,71 @@ +// 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.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; + +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 = colours.BlueDarker.Opacity(0.4f); + layout(); + } + + private void layout() + { + const int count = 18; + + for (int i = 0; i < count; i++) + { + Add(new Container + { + Colour = Color4.Black, + Alpha = 0.4f, + EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Glow, + Radius = 20, + Colour = glowColour, + }, + RelativePositionAxes = Axes.Both, + Masking = true, + CornerRadius = 5, + Size = new Vector2(60, 10), + Origin = Anchor.Centre, + Position = new Vector2( + 0.5f + (float)Math.Sin((float)i / count * 2 * MathHelper.Pi) / 2 * 0.86f, + 0.5f + (float)Math.Cos((float)i / count * 2 * MathHelper.Pi) / 2 * 0.86f + ), + Rotation = -(float)i / count * 360 + 90, + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + } + } + }); + } + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 39e911651a..af4a099e0d 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu { public class OsuRuleset : Ruleset { - public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap) => new OsuHitRenderer(beatmap); + public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new OsuHitRenderer(beatmap, isForCurrentRuleset); public override IEnumerable GetBeatmapStatistics(WorkingBeatmap beatmap) => new[] { diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs index f8365bf9ab..5ede3f56f5 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs @@ -91,25 +91,25 @@ namespace osu.Game.Rulesets.Osu.Replays // Make the cursor stay at a hitObject as long as possible (mainly for autopilot). if (h.StartTime - h.HitWindowFor(OsuScoreResult.Miss) > endTime + h.HitWindowFor(OsuScoreResult.Hit50) + 50) { - if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), prev.EndPosition.X, prev.EndPosition.Y, ReplayButtonState.None)); - if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Miss), h.Position.X, h.Position.Y, ReplayButtonState.None)); + if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None)); + if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Miss), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None)); } else if (h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50) > endTime + h.HitWindowFor(OsuScoreResult.Hit50) + 50) { - if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), prev.EndPosition.X, prev.EndPosition.Y, ReplayButtonState.None)); - if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50), h.Position.X, h.Position.Y, ReplayButtonState.None)); + if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None)); + if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None)); } else if (h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100) > endTime + h.HitWindowFor(OsuScoreResult.Hit100) + 50) { - if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit100), prev.EndPosition.X, prev.EndPosition.Y, ReplayButtonState.None)); - if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100), h.Position.X, h.Position.Y, ReplayButtonState.None)); + if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit100), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None)); + if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None)); } } private void addHitObjectReplay(OsuHitObject h) { // Default values for circles/sliders - Vector2 startPosition = h.Position; + Vector2 startPosition = h.StackedPosition; EasingTypes easing = preferredEasing; float spinnerDirection = -1; @@ -238,7 +238,7 @@ namespace osu.Game.Rulesets.Osu.Replays // TODO: Why do we delay 1 ms if the object is a spinner? There already is KEY_UP_DELAY from hEndTime. double hEndTime = ((h as IHasEndTime)?.EndTime ?? h.StartTime) + KEY_UP_DELAY; int endDelay = h is Spinner ? 1 : 0; - ReplayFrame endFrame = new ReplayFrame(hEndTime + endDelay, h.EndPosition.X, h.EndPosition.Y, ReplayButtonState.None); + ReplayFrame endFrame = new ReplayFrame(hEndTime + endDelay, h.StackedEndPosition.X, h.StackedEndPosition.Y, ReplayButtonState.None); // Decrement because we want the previous frame, not the next one int index = FindInsertionIndex(startFrame) - 1; diff --git a/osu.Game.Rulesets.Osu/UI/OsuHitRenderer.cs b/osu.Game.Rulesets.Osu/UI/OsuHitRenderer.cs index 687518e6d5..e582d2fcd3 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuHitRenderer.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuHitRenderer.cs @@ -18,8 +18,8 @@ namespace osu.Game.Rulesets.Osu.UI { public class OsuHitRenderer : HitRenderer { - public OsuHitRenderer(WorkingBeatmap beatmap) - : base(beatmap) + public OsuHitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset) + : base(beatmap, isForCurrentRuleset) { } diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 8974b1bcbd..b91bdc6a78 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -64,6 +64,7 @@ + @@ -103,9 +104,7 @@ - - - +