1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-28 20:32:55 +08:00

Split out IHasPath from IHasCurve to better define hitobjects

This commit is contained in:
Dean Herbert 2020-05-26 17:44:47 +09:00
parent a2eec5d963
commit 280b0adb1d
13 changed files with 57 additions and 43 deletions

View File

@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
switch (obj) switch (obj)
{ {
case IHasCurve curveData: case IHasPathWithRepeats curveData:
return new JuiceStream return new JuiceStream
{ {
StartTime = obj.StartTime, StartTime = obj.StartTime,

View File

@ -14,7 +14,7 @@ using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Catch.Objects namespace osu.Game.Rulesets.Catch.Objects
{ {
public class JuiceStream : CatchHitObject, IHasCurve public class JuiceStream : CatchHitObject, IHasPathWithRepeats
{ {
/// <summary> /// <summary>
/// Positional distance that results in a duration of one second, before any speed adjustments. /// Positional distance that results in a duration of one second, before any speed adjustments.

View File

@ -474,7 +474,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// <returns></returns> /// <returns></returns>
private IList<HitSampleInfo> sampleInfoListAt(double time) private IList<HitSampleInfo> sampleInfoListAt(double time)
{ {
if (!(HitObject is IHasCurve curveData)) if (!(HitObject is IHasPathWithRepeats curveData))
return HitObject.Samples; return HitObject.Samples;
double segmentTime = (EndTime - HitObject.StartTime) / spanCount; double segmentTime = (EndTime - HitObject.StartTime) / spanCount;

View File

@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
switch (original) switch (original)
{ {
case IHasCurve curveData: case IHasPathWithRepeats curveData:
return new Slider return new Slider
{ {
StartTime = original.StartTime, StartTime = original.StartTime,

View File

@ -17,7 +17,7 @@ using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Objects namespace osu.Game.Rulesets.Osu.Objects
{ {
public class Slider : OsuHitObject, IHasCurve public class Slider : OsuHitObject, IHasPathWithRepeats
{ {
public double EndTime public double EndTime
{ {

View File

@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength) if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength)
{ {
List<IList<HitSampleInfo>> allSamples = obj is IHasCurve curveData ? curveData.NodeSamples : new List<IList<HitSampleInfo>>(new[] { samples }); List<IList<HitSampleInfo>> allSamples = obj is IHasPathWithRepeats curveData ? curveData.NodeSamples : new List<IList<HitSampleInfo>>(new[] { samples });
int i = 0; int i = 0;

View File

@ -3,9 +3,7 @@
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using System; using System;
using System.Collections.Generic;
using System.Threading; using System.Threading;
using osu.Game.Audio;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
@ -17,7 +15,7 @@ using osuTK;
namespace osu.Game.Rulesets.Taiko.Objects namespace osu.Game.Rulesets.Taiko.Objects
{ {
public class DrumRoll : TaikoHitObject, IHasCurve public class DrumRoll : TaikoHitObject, IHasPath
{ {
/// <summary> /// <summary>
/// Drum roll distance that results in a duration of 1 speed-adjusted beat length. /// Drum roll distance that results in a duration of 1 speed-adjusted beat length.
@ -115,11 +113,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
double IHasDistance.Distance => Duration * Velocity; double IHasDistance.Distance => Duration * Velocity;
int IHasRepeats.RepeatCount { get => 0; set { } } SliderPath IHasPath.Path
List<IList<HitSampleInfo>> IHasRepeats.NodeSamples => new List<IList<HitSampleInfo>>();
SliderPath IHasCurve.Path
=> new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(1) }, ((IHasDistance)this).Distance / TaikoBeatmapConverter.LEGACY_VELOCITY_MULTIPLIER); => new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(1) }, ((IHasDistance)this).Distance / TaikoBeatmapConverter.LEGACY_VELOCITY_MULTIPLIER);
#endregion #endregion

View File

@ -365,7 +365,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
{ {
var hitObjects = decoder.Decode(stream).HitObjects; var hitObjects = decoder.Decode(stream).HitObjects;
var curveData = hitObjects[0] as IHasCurve; var curveData = hitObjects[0] as IHasPathWithRepeats;
var positionData = hitObjects[0] as IHasPosition; var positionData = hitObjects[0] as IHasPosition;
Assert.IsNotNull(positionData); Assert.IsNotNull(positionData);

View File

@ -95,7 +95,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
{ {
var beatmap = decodeAsJson(normal); var beatmap = decodeAsJson(normal);
var curveData = beatmap.HitObjects[0] as IHasCurve; var curveData = beatmap.HitObjects[0] as IHasPathWithRepeats;
var positionData = beatmap.HitObjects[0] as IHasPosition; var positionData = beatmap.HitObjects[0] as IHasPosition;
Assert.IsNotNull(positionData); Assert.IsNotNull(positionData);

View File

@ -233,9 +233,9 @@ namespace osu.Game.Beatmaps.Formats
writer.Write(FormattableString.Invariant($"{(int)getObjectType(hitObject)},")); writer.Write(FormattableString.Invariant($"{(int)getObjectType(hitObject)},"));
writer.Write(FormattableString.Invariant($"{(int)toLegacyHitSoundType(hitObject.Samples)},")); writer.Write(FormattableString.Invariant($"{(int)toLegacyHitSoundType(hitObject.Samples)},"));
if (hitObject is IHasCurve curveData) if (hitObject is IHasPathWithRepeats curveData)
{ {
addCurveData(writer, curveData, position); addPathData(writer, curveData, position);
writer.Write(getSampleBank(hitObject.Samples, zeroBanks: true)); writer.Write(getSampleBank(hitObject.Samples, zeroBanks: true));
} }
else else
@ -263,7 +263,7 @@ namespace osu.Game.Beatmaps.Formats
switch (hitObject) switch (hitObject)
{ {
case IHasCurve _: case IHasPath _:
type |= LegacyHitObjectType.Slider; type |= LegacyHitObjectType.Slider;
break; break;
@ -282,13 +282,13 @@ namespace osu.Game.Beatmaps.Formats
return type; return type;
} }
private void addCurveData(TextWriter writer, IHasCurve curveData, Vector2 position) private void addPathData(TextWriter writer, IHasPath pathData, Vector2 position)
{ {
PathType? lastType = null; PathType? lastType = null;
for (int i = 0; i < curveData.Path.ControlPoints.Count; i++) for (int i = 0; i < pathData.Path.ControlPoints.Count; i++)
{ {
PathControlPoint point = curveData.Path.ControlPoints[i]; PathControlPoint point = pathData.Path.ControlPoints[i];
if (point.Type.Value != null) if (point.Type.Value != null)
{ {
@ -325,23 +325,28 @@ namespace osu.Game.Beatmaps.Formats
if (i != 0) if (i != 0)
{ {
writer.Write(FormattableString.Invariant($"{position.X + point.Position.Value.X}:{position.Y + point.Position.Value.Y}")); writer.Write(FormattableString.Invariant($"{position.X + point.Position.Value.X}:{position.Y + point.Position.Value.Y}"));
writer.Write(i != curveData.Path.ControlPoints.Count - 1 ? "|" : ","); writer.Write(i != pathData.Path.ControlPoints.Count - 1 ? "|" : ",");
} }
} }
writer.Write(FormattableString.Invariant($"{curveData.RepeatCount + 1},")); var curveData = pathData as IHasPathWithRepeats;
writer.Write(FormattableString.Invariant($"{curveData.Path.Distance},"));
for (int i = 0; i < curveData.NodeSamples.Count; i++) writer.Write(FormattableString.Invariant($"{(curveData?.RepeatCount ?? 0) + 1},"));
{ writer.Write(FormattableString.Invariant($"{pathData.Path.Distance},"));
writer.Write(FormattableString.Invariant($"{(int)toLegacyHitSoundType(curveData.NodeSamples[i])}"));
writer.Write(i != curveData.NodeSamples.Count - 1 ? "|" : ",");
}
for (int i = 0; i < curveData.NodeSamples.Count; i++) if (curveData != null)
{ {
writer.Write(getSampleBank(curveData.NodeSamples[i], true)); for (int i = 0; i < curveData.NodeSamples.Count; i++)
writer.Write(i != curveData.NodeSamples.Count - 1 ? "|" : ","); {
writer.Write(FormattableString.Invariant($"{(int)toLegacyHitSoundType(curveData.NodeSamples[i])}"));
writer.Write(i != curveData.NodeSamples.Count - 1 ? "|" : ",");
}
for (int i = 0; i < curveData.NodeSamples.Count; i++)
{
writer.Write(getSampleBank(curveData.NodeSamples[i], true));
writer.Write(i != curveData.NodeSamples.Count - 1 ? "|" : ",");
}
} }
} }

View File

@ -9,7 +9,7 @@ using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Rulesets.Objects.Legacy namespace osu.Game.Rulesets.Objects.Legacy
{ {
internal abstract class ConvertSlider : ConvertHitObject, IHasCurve, IHasLegacyLastTickOffset internal abstract class ConvertSlider : ConvertHitObject, IHasPathWithRepeats, IHasLegacyLastTickOffset
{ {
/// <summary> /// <summary>
/// Scoring distance with a speed-adjusted beat length of 1 second. /// Scoring distance with a speed-adjusted beat length of 1 second.

View File

@ -0,0 +1,13 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
namespace osu.Game.Rulesets.Objects.Types
{
public interface IHasPath : IHasDistance
{
/// <summary>
/// The curve.
/// </summary>
SliderPath Path { get; }
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using osuTK; using osuTK;
namespace osu.Game.Rulesets.Objects.Types namespace osu.Game.Rulesets.Objects.Types
@ -8,15 +9,16 @@ namespace osu.Game.Rulesets.Objects.Types
/// <summary> /// <summary>
/// A HitObject that has a curve. /// A HitObject that has a curve.
/// </summary> /// </summary>
public interface IHasCurve : IHasDistance, IHasRepeats public interface IHasPathWithRepeats : IHasPath, IHasRepeats
{ {
/// <summary>
/// The curve.
/// </summary>
SliderPath Path { get; }
} }
public static class HasCurveExtensions [Obsolete("Use IHasPathWithRepeats instead.")] // can be removed 20201126
public interface IHasCurve : IHasPathWithRepeats
{
}
public static class HasPathWithRepeatsExtensions
{ {
/// <summary> /// <summary>
/// Computes the position on the curve relative to how much of the <see cref="HitObject"/> has been completed. /// Computes the position on the curve relative to how much of the <see cref="HitObject"/> has been completed.
@ -24,7 +26,7 @@ namespace osu.Game.Rulesets.Objects.Types
/// <param name="obj">The curve.</param> /// <param name="obj">The curve.</param>
/// <param name="progress">[0, 1] where 0 is the start time of the <see cref="HitObject"/> and 1 is the end time of the <see cref="HitObject"/>.</param> /// <param name="progress">[0, 1] where 0 is the start time of the <see cref="HitObject"/> and 1 is the end time of the <see cref="HitObject"/>.</param>
/// <returns>The position on the curve.</returns> /// <returns>The position on the curve.</returns>
public static Vector2 CurvePositionAt(this IHasCurve obj, double progress) public static Vector2 CurvePositionAt(this IHasPathWithRepeats obj, double progress)
=> obj.Path.PositionAt(obj.ProgressAt(progress)); => obj.Path.PositionAt(obj.ProgressAt(progress));
/// <summary> /// <summary>
@ -33,7 +35,7 @@ namespace osu.Game.Rulesets.Objects.Types
/// <param name="obj">The curve.</param> /// <param name="obj">The curve.</param>
/// <param name="progress">[0, 1] where 0 is the start time of the <see cref="HitObject"/> and 1 is the end time of the <see cref="HitObject"/>.</param> /// <param name="progress">[0, 1] where 0 is the start time of the <see cref="HitObject"/> and 1 is the end time of the <see cref="HitObject"/>.</param>
/// <returns>[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</returns> /// <returns>[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</returns>
public static double ProgressAt(this IHasCurve obj, double progress) public static double ProgressAt(this IHasPathWithRepeats obj, double progress)
{ {
double p = progress * obj.SpanCount() % 1; double p = progress * obj.SpanCount() % 1;
if (obj.SpanAt(progress) % 2 == 1) if (obj.SpanAt(progress) % 2 == 1)
@ -47,7 +49,7 @@ namespace osu.Game.Rulesets.Objects.Types
/// <param name="obj">The curve.</param> /// <param name="obj">The curve.</param>
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param> /// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
/// <returns>[0, SpanCount) where 0 is the first run.</returns> /// <returns>[0, SpanCount) where 0 is the first run.</returns>
public static int SpanAt(this IHasCurve obj, double progress) public static int SpanAt(this IHasPathWithRepeats obj, double progress)
=> (int)(progress * obj.SpanCount()); => (int)(progress * obj.SpanCount());
} }
} }