mirror of
https://github.com/ppy/osu.git
synced 2024-11-12 10:17:32 +08:00
Merge https://github.com/ppy/osu into auto-restart-mod-perfect
This commit is contained in:
commit
ec33e63a4f
@ -10,8 +10,8 @@ before_build:
|
|||||||
- cmd: nuget restore -verbosity quiet
|
- cmd: nuget restore -verbosity quiet
|
||||||
build_script:
|
build_script:
|
||||||
- ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1'))
|
- ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1'))
|
||||||
- appveyor DownloadFile https://puu.sh/BCrS8/7faccf7876.enc # signing certificate
|
- appveyor DownloadFile https://www.dropbox.com/s/f7hv069mr5tqi2j/deanherbert.pfx.enc?dl=1 # signing certificate
|
||||||
- cmd: appveyor-tools\secure-file -decrypt 7faccf7876.enc -secret %decode_secret% -out %HOMEPATH%\deanherbert.pfx
|
- cmd: appveyor-tools\secure-file -decrypt deanherbert.pfx.enc -secret %decode_secret% -out %HOMEPATH%\deanherbert.pfx
|
||||||
- appveyor DownloadFile https://puu.sh/A6g75/fdc6f19b04.enc # deploy configuration
|
- appveyor DownloadFile https://puu.sh/A6g75/fdc6f19b04.enc # deploy configuration
|
||||||
- cd osu-deploy
|
- cd osu-deploy
|
||||||
- nuget restore -verbosity quiet
|
- nuget restore -verbosity quiet
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="System.IO.Packaging" Version="4.5.0" />
|
<PackageReference Include="System.IO.Packaging" Version="4.5.0" />
|
||||||
<PackageReference Include="ppy.squirrel.windows" Version="1.8.0.8" />
|
<PackageReference Include="ppy.squirrel.windows" Version="1.9.0.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
@ -38,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
beatmap.HitObjects.Add(new JuiceStream
|
beatmap.HitObjects.Add(new JuiceStream
|
||||||
{
|
{
|
||||||
X = 0.5f - width / 2,
|
X = 0.5f - width / 2,
|
||||||
ControlPoints = new List<Vector2>
|
ControlPoints = new[]
|
||||||
{
|
{
|
||||||
Vector2.Zero,
|
Vector2.Zero,
|
||||||
new Vector2(width * CatchPlayfield.BASE_WIDTH, 0)
|
new Vector2(width * CatchPlayfield.BASE_WIDTH, 0)
|
||||||
|
@ -146,7 +146,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
|
|
||||||
public SliderCurve Curve { get; } = new SliderCurve();
|
public SliderCurve Curve { get; } = new SliderCurve();
|
||||||
|
|
||||||
public List<Vector2> ControlPoints
|
public Vector2[] ControlPoints
|
||||||
{
|
{
|
||||||
get { return Curve.ControlPoints; }
|
get { return Curve.ControlPoints; }
|
||||||
set { Curve.ControlPoints = value; }
|
set { Curve.ControlPoints = value; }
|
||||||
|
@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
TargetColumns = (int)Math.Max(1, roundedCircleSize);
|
TargetColumns = (int)Math.Max(1, roundedCircleSize);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float percentSliderOrSpinner = (float)beatmap.HitObjects.Count(h => h is IHasEndTime) / beatmap.HitObjects.Count();
|
float percentSliderOrSpinner = (float)beatmap.HitObjects.Count(h => h is IHasEndTime) / beatmap.HitObjects.Count;
|
||||||
if (percentSliderOrSpinner < 0.2)
|
if (percentSliderOrSpinner < 0.2)
|
||||||
TargetColumns = 7;
|
TargetColumns = 7;
|
||||||
else if (percentSliderOrSpinner < 0.3 || roundedCircleSize >= 5)
|
else if (percentSliderOrSpinner < 0.3 || roundedCircleSize >= 5)
|
||||||
|
@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
drainTime = 10000;
|
drainTime = 10000;
|
||||||
|
|
||||||
BeatmapDifficulty difficulty = OriginalBeatmap.BeatmapInfo.BaseDifficulty;
|
BeatmapDifficulty difficulty = OriginalBeatmap.BeatmapInfo.BaseDifficulty;
|
||||||
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + (double)OriginalBeatmap.HitObjects.Count() / drainTime * 9f) / 38f * 5f / 1.15;
|
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + (double)OriginalBeatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15;
|
||||||
conversionDifficulty = Math.Min(conversionDifficulty.Value, 12);
|
conversionDifficulty = Math.Min(conversionDifficulty.Value, 12);
|
||||||
|
|
||||||
return conversionDifficulty.Value;
|
return conversionDifficulty.Value;
|
||||||
|
@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
StartTime = Time.Current + 1000,
|
StartTime = Time.Current + 1000,
|
||||||
Position = new Vector2(239, 176),
|
Position = new Vector2(239, 176),
|
||||||
ControlPoints = new List<Vector2>
|
ControlPoints = new[]
|
||||||
{
|
{
|
||||||
Vector2.Zero,
|
Vector2.Zero,
|
||||||
new Vector2(154, 28),
|
new Vector2(154, 28),
|
||||||
@ -141,7 +141,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
StartTime = Time.Current + 1000,
|
StartTime = Time.Current + 1000,
|
||||||
Position = new Vector2(-(distance / 2), 0),
|
Position = new Vector2(-(distance / 2), 0),
|
||||||
ControlPoints = new List<Vector2>
|
ControlPoints = new[]
|
||||||
{
|
{
|
||||||
Vector2.Zero,
|
Vector2.Zero,
|
||||||
new Vector2(distance, 0),
|
new Vector2(distance, 0),
|
||||||
@ -161,7 +161,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
StartTime = Time.Current + 1000,
|
StartTime = Time.Current + 1000,
|
||||||
Position = new Vector2(-200, 0),
|
Position = new Vector2(-200, 0),
|
||||||
ControlPoints = new List<Vector2>
|
ControlPoints = new[]
|
||||||
{
|
{
|
||||||
Vector2.Zero,
|
Vector2.Zero,
|
||||||
new Vector2(200, 200),
|
new Vector2(200, 200),
|
||||||
@ -184,7 +184,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
CurveType = CurveType.Linear,
|
CurveType = CurveType.Linear,
|
||||||
StartTime = Time.Current + 1000,
|
StartTime = Time.Current + 1000,
|
||||||
Position = new Vector2(-200, 0),
|
Position = new Vector2(-200, 0),
|
||||||
ControlPoints = new List<Vector2>
|
ControlPoints = new[]
|
||||||
{
|
{
|
||||||
Vector2.Zero,
|
Vector2.Zero,
|
||||||
new Vector2(150, 75),
|
new Vector2(150, 75),
|
||||||
@ -210,7 +210,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
CurveType = CurveType.Bezier,
|
CurveType = CurveType.Bezier,
|
||||||
StartTime = Time.Current + 1000,
|
StartTime = Time.Current + 1000,
|
||||||
Position = new Vector2(-200, 0),
|
Position = new Vector2(-200, 0),
|
||||||
ControlPoints = new List<Vector2>
|
ControlPoints = new[]
|
||||||
{
|
{
|
||||||
Vector2.Zero,
|
Vector2.Zero,
|
||||||
new Vector2(150, 75),
|
new Vector2(150, 75),
|
||||||
@ -235,7 +235,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
CurveType = CurveType.Linear,
|
CurveType = CurveType.Linear,
|
||||||
StartTime = Time.Current + 1000,
|
StartTime = Time.Current + 1000,
|
||||||
Position = new Vector2(0, 0),
|
Position = new Vector2(0, 0),
|
||||||
ControlPoints = new List<Vector2>
|
ControlPoints = new[]
|
||||||
{
|
{
|
||||||
Vector2.Zero,
|
Vector2.Zero,
|
||||||
new Vector2(-200, 0),
|
new Vector2(-200, 0),
|
||||||
@ -265,7 +265,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
StartTime = Time.Current + 1000,
|
StartTime = Time.Current + 1000,
|
||||||
Position = new Vector2(-100, 0),
|
Position = new Vector2(-100, 0),
|
||||||
CurveType = CurveType.Catmull,
|
CurveType = CurveType.Catmull,
|
||||||
ControlPoints = new List<Vector2>
|
ControlPoints = new[]
|
||||||
{
|
{
|
||||||
Vector2.Zero,
|
Vector2.Zero,
|
||||||
new Vector2(50, -50),
|
new Vector2(50, -50),
|
||||||
|
@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate;
|
double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate;
|
||||||
double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
|
double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
|
||||||
|
|
||||||
int maxCombo = beatmap.HitObjects.Count();
|
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)
|
// 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)
|
||||||
maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
|
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
|
||||||
|
|
||||||
beatmapMaxCombo = Beatmap.HitObjects.Count();
|
beatmapMaxCombo = Beatmap.HitObjects.Count;
|
||||||
// Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above)
|
// Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above)
|
||||||
beatmapMaxCombo += Beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
beatmapMaxCombo += Beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -33,8 +32,9 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
slider.NestedHitObjects.OfType<SliderTick>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
|
slider.NestedHitObjects.OfType<SliderTick>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
|
||||||
slider.NestedHitObjects.OfType<RepeatPoint>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
|
slider.NestedHitObjects.OfType<RepeatPoint>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
|
||||||
|
|
||||||
var newControlPoints = new List<Vector2>();
|
var newControlPoints = new Vector2[slider.ControlPoints.Length];
|
||||||
slider.ControlPoints.ForEach(c => newControlPoints.Add(new Vector2(c.X, -c.Y)));
|
for (int i = 0; i < slider.ControlPoints.Length; i++)
|
||||||
|
newControlPoints[i] = new Vector2(slider.ControlPoints[i].X, -slider.ControlPoints[i].Y);
|
||||||
|
|
||||||
slider.ControlPoints = newControlPoints;
|
slider.ControlPoints = newControlPoints;
|
||||||
slider.Curve?.Calculate(); // Recalculate the slider curve
|
slider.Curve?.Calculate(); // Recalculate the slider curve
|
||||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
|
|
||||||
public SliderCurve Curve { get; } = new SliderCurve();
|
public SliderCurve Curve { get; } = new SliderCurve();
|
||||||
|
|
||||||
public List<Vector2> ControlPoints
|
public Vector2[] ControlPoints
|
||||||
{
|
{
|
||||||
get { return Curve.ControlPoints; }
|
get { return Curve.ControlPoints; }
|
||||||
set { Curve.ControlPoints = value; }
|
set { Curve.ControlPoints = value; }
|
||||||
|
@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
new Slider
|
new Slider
|
||||||
{
|
{
|
||||||
Position = new Vector2(128, 256),
|
Position = new Vector2(128, 256),
|
||||||
ControlPoints = new List<Vector2>
|
ControlPoints = new[]
|
||||||
{
|
{
|
||||||
Vector2.Zero,
|
Vector2.Zero,
|
||||||
new Vector2(216, 0),
|
new Vector2(216, 0),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<!-- Contains required properties for osu!framework projects. -->
|
<!-- Contains required properties for osu!framework projects. -->
|
||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup Label="C#">
|
<PropertyGroup Label="C#">
|
||||||
<LangVersion>7</LangVersion>
|
<LangVersion>7.2</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ApplicationManifest>..\app.manifest</ApplicationManifest>
|
<ApplicationManifest>..\app.manifest</ApplicationManifest>
|
||||||
|
@ -48,7 +48,7 @@ namespace osu.Game.Beatmaps
|
|||||||
[JsonConverter(typeof(TypedListConverter<HitObject>))]
|
[JsonConverter(typeof(TypedListConverter<HitObject>))]
|
||||||
public List<T> HitObjects = new List<T>();
|
public List<T> HitObjects = new List<T>();
|
||||||
|
|
||||||
IEnumerable<HitObject> IBeatmap.HitObjects => HitObjects;
|
IReadOnlyList<HitObject> IBeatmap.HitObjects => HitObjects;
|
||||||
|
|
||||||
public virtual IEnumerable<BeatmapStatistic> GetStatistics() => Enumerable.Empty<BeatmapStatistic>();
|
public virtual IEnumerable<BeatmapStatistic> GetStatistics() => Enumerable.Empty<BeatmapStatistic>();
|
||||||
|
|
||||||
|
@ -55,39 +55,40 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
beatmap.BeatmapInfo = original.BeatmapInfo;
|
beatmap.BeatmapInfo = original.BeatmapInfo;
|
||||||
beatmap.ControlPointInfo = original.ControlPointInfo;
|
beatmap.ControlPointInfo = original.ControlPointInfo;
|
||||||
beatmap.HitObjects = original.HitObjects.SelectMany(h => convert(h, original)).ToList();
|
beatmap.HitObjects = convertHitObjects(original.HitObjects, original);
|
||||||
beatmap.Breaks = original.Breaks;
|
beatmap.Breaks = original.Breaks;
|
||||||
|
|
||||||
return beatmap;
|
return beatmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private List<T> convertHitObjects(IReadOnlyList<HitObject> hitObjects, IBeatmap beatmap)
|
||||||
/// Converts a hit object.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="original">The hit object to convert.</param>
|
|
||||||
/// <param name="beatmap">The un-converted Beatmap.</param>
|
|
||||||
/// <returns>The converted hit object.</returns>
|
|
||||||
private IEnumerable<T> convert(HitObject original, IBeatmap beatmap)
|
|
||||||
{
|
{
|
||||||
// Check if the hitobject is already the converted type
|
var result = new List<T>(hitObjects.Count);
|
||||||
T tObject = original as T;
|
|
||||||
if (tObject != null)
|
|
||||||
{
|
|
||||||
yield return tObject;
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var converted = ConvertHitObject(original, beatmap).ToList();
|
foreach (var obj in hitObjects)
|
||||||
ObjectConverted?.Invoke(original, converted);
|
|
||||||
|
|
||||||
// Convert the hit object
|
|
||||||
foreach (var obj in converted)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj is T tObj)
|
||||||
|
{
|
||||||
|
result.Add(tObj);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
yield return obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var converted = ConvertHitObject(obj, beatmap);
|
||||||
|
|
||||||
|
if (ObjectConverted != null)
|
||||||
|
{
|
||||||
|
converted = converted.ToList();
|
||||||
|
ObjectConverted.Invoke(obj, converted);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var c in converted)
|
||||||
|
{
|
||||||
|
if (c != null)
|
||||||
|
result.Add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -55,14 +55,14 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="time">The time to find the sound control point at.</param>
|
/// <param name="time">The time to find the sound control point at.</param>
|
||||||
/// <returns>The sound control point.</returns>
|
/// <returns>The sound control point.</returns>
|
||||||
public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, SamplePoints.FirstOrDefault());
|
public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, SamplePoints.Count > 0 ? SamplePoints[0] : null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds the timing control point that is active at <paramref name="time"/>.
|
/// Finds the timing control point that is active at <paramref name="time"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="time">The time to find the timing control point at.</param>
|
/// <param name="time">The time to find the timing control point at.</param>
|
||||||
/// <returns>The timing control point.</returns>
|
/// <returns>The timing control point.</returns>
|
||||||
public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, TimingPoints.FirstOrDefault());
|
public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, TimingPoints.Count > 0 ? TimingPoints[0] : null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds the maximum BPM represented by any timing control point.
|
/// Finds the maximum BPM represented by any timing control point.
|
||||||
@ -104,17 +104,26 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
if (time < list[0].Time)
|
if (time < list[0].Time)
|
||||||
return prePoint ?? new T();
|
return prePoint ?? new T();
|
||||||
|
|
||||||
int index = list.BinarySearch(new T { Time = time });
|
if (time >= list[list.Count - 1].Time)
|
||||||
|
return list[list.Count - 1];
|
||||||
|
|
||||||
// Check if we've found an exact match (t == time)
|
int l = 0;
|
||||||
if (index >= 0)
|
int r = list.Count - 2;
|
||||||
return list[index];
|
|
||||||
|
|
||||||
index = ~index;
|
while (l <= r)
|
||||||
|
{
|
||||||
|
int pivot = l + ((r - l) >> 1);
|
||||||
|
|
||||||
// BinarySearch will return the index of the first element _greater_ than the search
|
if (list[pivot].Time < time)
|
||||||
// This is the inactive point - the active point is the one before it (index - 1)
|
l = pivot + 1;
|
||||||
return list[index - 1];
|
else if (list[pivot].Time > time)
|
||||||
|
r = pivot - 1;
|
||||||
|
else
|
||||||
|
return list[pivot];
|
||||||
|
}
|
||||||
|
|
||||||
|
// l will be the first control point with Time > time, but we want the one before it
|
||||||
|
return list[l - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.BeatmapInfo.BaseDifficulty);
|
hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.BeatmapInfo.BaseDifficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool ShouldSkipLine(string line) => base.ShouldSkipLine(line) || line.StartsWith(" ") || line.StartsWith("_");
|
protected override bool ShouldSkipLine(string line) => base.ShouldSkipLine(line) || line.StartsWith(" ", StringComparison.Ordinal) || line.StartsWith("_", StringComparison.Ordinal);
|
||||||
|
|
||||||
protected override void ParseLine(Beatmap beatmap, Section section, string line)
|
protected override void ParseLine(Beatmap beatmap, Section section, string line)
|
||||||
{
|
{
|
||||||
|
@ -69,7 +69,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
protected string StripComments(string line)
|
protected string StripComments(string line)
|
||||||
{
|
{
|
||||||
var index = line.IndexOf("//", StringComparison.Ordinal);
|
var index = line.AsSpan().IndexOf("//".AsSpan());
|
||||||
if (index > 0)
|
if (index > 0)
|
||||||
return line.Substring(0, index);
|
return line.Substring(0, index);
|
||||||
return line;
|
return line;
|
||||||
|
@ -39,7 +39,7 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The hitobjects contained by this beatmap.
|
/// The hitobjects contained by this beatmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IEnumerable<HitObject> HitObjects { get; }
|
IReadOnlyList<HitObject> HitObjects { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns statistics for the <see cref="HitObjects"/> contained in this beatmap.
|
/// Returns statistics for the <see cref="HitObjects"/> contained in this beatmap.
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
if (accentColour == default(Color4))
|
if (accentColour == default)
|
||||||
accentColour = colours.PinkDarker;
|
accentColour = colours.PinkDarker;
|
||||||
updateAccentColour();
|
updateAccentColour();
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
if (accentColour == default(Color4))
|
if (accentColour == default)
|
||||||
AccentColour = colours.Blue;
|
AccentColour = colours.Blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
if (accentColour == default(Color4))
|
if (accentColour == default)
|
||||||
AccentColour = colours.Blue;
|
AccentColour = colours.Blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void ResetCount()
|
public virtual void ResetCount()
|
||||||
{
|
{
|
||||||
SetCountWithoutRolling(default(T));
|
SetCountWithoutRolling(default);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,25 +1,26 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects
|
namespace osu.Game.Rulesets.Objects
|
||||||
{
|
{
|
||||||
public class BezierApproximator
|
public readonly ref struct BezierApproximator
|
||||||
{
|
{
|
||||||
private readonly int count;
|
private readonly int count;
|
||||||
private readonly List<Vector2> controlPoints;
|
private readonly ReadOnlySpan<Vector2> controlPoints;
|
||||||
private readonly Vector2[] subdivisionBuffer1;
|
private readonly Vector2[] subdivisionBuffer1;
|
||||||
private readonly Vector2[] subdivisionBuffer2;
|
private readonly Vector2[] subdivisionBuffer2;
|
||||||
|
|
||||||
private const float tolerance = 0.25f;
|
private const float tolerance = 0.25f;
|
||||||
private const float tolerance_sq = tolerance * tolerance;
|
private const float tolerance_sq = tolerance * tolerance;
|
||||||
|
|
||||||
public BezierApproximator(List<Vector2> controlPoints)
|
public BezierApproximator(ReadOnlySpan<Vector2> controlPoints)
|
||||||
{
|
{
|
||||||
this.controlPoints = controlPoints;
|
this.controlPoints = controlPoints;
|
||||||
count = controlPoints.Count;
|
count = controlPoints.Length;
|
||||||
|
|
||||||
subdivisionBuffer1 = new Vector2[count];
|
subdivisionBuffer1 = new Vector2[count];
|
||||||
subdivisionBuffer2 = new Vector2[count * 2 - 1];
|
subdivisionBuffer2 = new Vector2[count * 2 - 1];
|
||||||
|
@ -1,40 +1,40 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects
|
namespace osu.Game.Rulesets.Objects
|
||||||
{
|
{
|
||||||
public class CatmullApproximator
|
public readonly ref struct CatmullApproximator
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of pieces to calculate for each controlpoint quadruplet.
|
/// The amount of pieces to calculate for each controlpoint quadruplet.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int detail = 50;
|
private const int detail = 50;
|
||||||
|
|
||||||
private readonly List<Vector2> controlPoints;
|
private readonly ReadOnlySpan<Vector2> controlPoints;
|
||||||
|
|
||||||
public CatmullApproximator(List<Vector2> controlPoints)
|
public CatmullApproximator(ReadOnlySpan<Vector2> controlPoints)
|
||||||
{
|
{
|
||||||
this.controlPoints = controlPoints;
|
this.controlPoints = controlPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a piecewise-linear approximation of a Catmull-Rom spline.
|
/// Creates a piecewise-linear approximation of a Catmull-Rom spline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A list of vectors representing the piecewise-linear approximation.</returns>
|
/// <returns>A list of vectors representing the piecewise-linear approximation.</returns>
|
||||||
public List<Vector2> CreateCatmull()
|
public List<Vector2> CreateCatmull()
|
||||||
{
|
{
|
||||||
var result = new List<Vector2>();
|
var result = new List<Vector2>((controlPoints.Length - 1) * detail * 2);
|
||||||
|
|
||||||
for (int i = 0; i < controlPoints.Count - 1; i++)
|
for (int i = 0; i < controlPoints.Length - 1; i++)
|
||||||
{
|
{
|
||||||
var v1 = i > 0 ? controlPoints[i - 1] : controlPoints[i];
|
var v1 = i > 0 ? controlPoints[i - 1] : controlPoints[i];
|
||||||
var v2 = controlPoints[i];
|
var v2 = controlPoints[i];
|
||||||
var v3 = i < controlPoints.Count - 1 ? controlPoints[i + 1] : v2 + v2 - v1;
|
var v3 = i < controlPoints.Length - 1 ? controlPoints[i + 1] : v2 + v2 - v1;
|
||||||
var v4 = i < controlPoints.Count - 2 ? controlPoints[i + 2] : v3 + v3 - v2;
|
var v4 = i < controlPoints.Length - 2 ? controlPoints[i + 2] : v3 + v3 - v2;
|
||||||
|
|
||||||
for (int c = 0; c < detail; c++)
|
for (int c = 0; c < detail; c++)
|
||||||
{
|
{
|
||||||
|
@ -8,21 +8,15 @@ using OpenTK;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects
|
namespace osu.Game.Rulesets.Objects
|
||||||
{
|
{
|
||||||
public class CircularArcApproximator
|
public readonly ref struct CircularArcApproximator
|
||||||
{
|
{
|
||||||
private readonly Vector2 a;
|
|
||||||
private readonly Vector2 b;
|
|
||||||
private readonly Vector2 c;
|
|
||||||
|
|
||||||
private int amountPoints;
|
|
||||||
|
|
||||||
private const float tolerance = 0.1f;
|
private const float tolerance = 0.1f;
|
||||||
|
|
||||||
public CircularArcApproximator(Vector2 a, Vector2 b, Vector2 c)
|
private readonly ReadOnlySpan<Vector2> controlPoints;
|
||||||
|
|
||||||
|
public CircularArcApproximator(ReadOnlySpan<Vector2> controlPoints)
|
||||||
{
|
{
|
||||||
this.a = a;
|
this.controlPoints = controlPoints;
|
||||||
this.b = b;
|
|
||||||
this.c = c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -31,6 +25,10 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
/// <returns>A list of vectors representing the piecewise-linear approximation.</returns>
|
/// <returns>A list of vectors representing the piecewise-linear approximation.</returns>
|
||||||
public List<Vector2> CreateArc()
|
public List<Vector2> CreateArc()
|
||||||
{
|
{
|
||||||
|
Vector2 a = controlPoints[0];
|
||||||
|
Vector2 b = controlPoints[1];
|
||||||
|
Vector2 c = controlPoints[2];
|
||||||
|
|
||||||
float aSq = (b - c).LengthSquared;
|
float aSq = (b - c).LengthSquared;
|
||||||
float bSq = (a - c).LengthSquared;
|
float bSq = (a - c).LengthSquared;
|
||||||
float cSq = (a - b).LengthSquared;
|
float cSq = (a - b).LengthSquared;
|
||||||
@ -81,7 +79,7 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
// is: 2 * Math.Acos(1 - TOLERANCE / r)
|
// is: 2 * Math.Acos(1 - TOLERANCE / r)
|
||||||
// The special case is required for extremely short sliders where the radius is smaller than
|
// The special case is required for extremely short sliders where the radius is smaller than
|
||||||
// the tolerance. This is a pathological rather than a realistic case.
|
// the tolerance. This is a pathological rather than a realistic case.
|
||||||
amountPoints = 2 * r <= tolerance ? 2 : Math.Max(2, (int)Math.Ceiling(thetaRange / (2 * Math.Acos(1 - tolerance / r))));
|
int amountPoints = 2 * r <= tolerance ? 2 : Math.Max(2, (int)Math.Ceiling(thetaRange / (2 * Math.Acos(1 - tolerance / r))));
|
||||||
|
|
||||||
List<Vector2> output = new List<Vector2>(amountPoints);
|
List<Vector2> output = new List<Vector2>(amountPoints);
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
|
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
|
||||||
{
|
{
|
||||||
newCombo |= forceNewCombo;
|
newCombo |= forceNewCombo;
|
||||||
comboOffset += extraComboOffset;
|
comboOffset += extraComboOffset;
|
||||||
|
@ -72,10 +72,18 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
{
|
{
|
||||||
CurveType curveType = CurveType.Catmull;
|
CurveType curveType = CurveType.Catmull;
|
||||||
double length = 0;
|
double length = 0;
|
||||||
var points = new List<Vector2> { Vector2.Zero };
|
|
||||||
|
|
||||||
string[] pointsplit = split[5].Split('|');
|
string[] pointSplit = split[5].Split('|');
|
||||||
foreach (string t in pointsplit)
|
|
||||||
|
int pointCount = 1;
|
||||||
|
foreach (var t in pointSplit)
|
||||||
|
if (t.Length > 1)
|
||||||
|
pointCount++;
|
||||||
|
|
||||||
|
var points = new Vector2[pointCount];
|
||||||
|
|
||||||
|
int pointIndex = 1;
|
||||||
|
foreach (string t in pointSplit)
|
||||||
{
|
{
|
||||||
if (t.Length == 1)
|
if (t.Length == 1)
|
||||||
{
|
{
|
||||||
@ -94,16 +102,18 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
curveType = CurveType.PerfectCurve;
|
curveType = CurveType.PerfectCurve;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] temp = t.Split(':');
|
string[] temp = t.Split(':');
|
||||||
points.Add(new Vector2((int)Convert.ToDouble(temp[0], CultureInfo.InvariantCulture), (int)Convert.ToDouble(temp[1], CultureInfo.InvariantCulture)) - pos);
|
points[pointIndex++] = new Vector2((int)Convert.ToDouble(temp[0], CultureInfo.InvariantCulture), (int)Convert.ToDouble(temp[1], CultureInfo.InvariantCulture)) - pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
// osu-stable special-cased colinear perfect curves to a CurveType.Linear
|
// osu-stable special-cased colinear perfect curves to a CurveType.Linear
|
||||||
bool isLinear(List<Vector2> p) => Precision.AlmostEquals(0, (p[1].Y - p[0].Y) * (p[2].X - p[0].X) - (p[1].X - p[0].X) * (p[2].Y - p[0].Y));
|
bool isLinear(Vector2[] p) => Precision.AlmostEquals(0, (p[1].Y - p[0].Y) * (p[2].X - p[0].X) - (p[1].X - p[0].X) * (p[2].Y - p[0].Y));
|
||||||
if (points.Count == 3 && curveType == CurveType.PerfectCurve && isLinear(points))
|
|
||||||
|
if (points.Length == 3 && curveType == CurveType.PerfectCurve && isLinear(points))
|
||||||
curveType = CurveType.Linear;
|
curveType = CurveType.Linear;
|
||||||
|
|
||||||
int repeatCount = Convert.ToInt32(split[6], CultureInfo.InvariantCulture);
|
int repeatCount = Convert.ToInt32(split[6], CultureInfo.InvariantCulture);
|
||||||
@ -262,7 +272,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
/// <param name="repeatCount">The slider repeat count.</param>
|
/// <param name="repeatCount">The slider repeat count.</param>
|
||||||
/// <param name="repeatSamples">The samples to be played when the repeat nodes are hit. This includes the head and tail of the slider.</param>
|
/// <param name="repeatSamples">The samples to be played when the repeat nodes are hit. This includes the head and tail of the slider.</param>
|
||||||
/// <returns>The hit object.</returns>
|
/// <returns>The hit object.</returns>
|
||||||
protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples);
|
protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a legacy Spinner-type hit object.
|
/// Creates a legacy Spinner-type hit object.
|
||||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
/// <see cref="ConvertSlider"/>s don't need a curve since they're converted to ruleset-specific hitobjects.
|
/// <see cref="ConvertSlider"/>s don't need a curve since they're converted to ruleset-specific hitobjects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SliderCurve Curve { get; } = null;
|
public SliderCurve Curve { get; } = null;
|
||||||
public List<Vector2> ControlPoints { get; set; }
|
public Vector2[] ControlPoints { get; set; }
|
||||||
public CurveType CurveType { get; set; }
|
public CurveType CurveType { get; set; }
|
||||||
|
|
||||||
public double Distance { get; set; }
|
public double Distance { get; set; }
|
||||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
|
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
|
||||||
{
|
{
|
||||||
return new ConvertSlider
|
return new ConvertSlider
|
||||||
{
|
{
|
||||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
|
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
|
||||||
{
|
{
|
||||||
newCombo |= forceNewCombo;
|
newCombo |= forceNewCombo;
|
||||||
comboOffset += extraComboOffset;
|
comboOffset += extraComboOffset;
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
|||||||
return new ConvertHit();
|
return new ConvertHit();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
|
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
|
||||||
{
|
{
|
||||||
return new ConvertSlider
|
return new ConvertSlider
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
@ -13,7 +14,7 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
{
|
{
|
||||||
public double Distance;
|
public double Distance;
|
||||||
|
|
||||||
public List<Vector2> ControlPoints;
|
public Vector2[] ControlPoints;
|
||||||
|
|
||||||
public CurveType CurveType = CurveType.PerfectCurve;
|
public CurveType CurveType = CurveType.PerfectCurve;
|
||||||
|
|
||||||
@ -22,19 +23,23 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
private readonly List<Vector2> calculatedPath = new List<Vector2>();
|
private readonly List<Vector2> calculatedPath = new List<Vector2>();
|
||||||
private readonly List<double> cumulativeLength = new List<double>();
|
private readonly List<double> cumulativeLength = new List<double>();
|
||||||
|
|
||||||
private List<Vector2> calculateSubpath(List<Vector2> subControlPoints)
|
private List<Vector2> calculateSubpath(ReadOnlySpan<Vector2> subControlPoints)
|
||||||
{
|
{
|
||||||
switch (CurveType)
|
switch (CurveType)
|
||||||
{
|
{
|
||||||
case CurveType.Linear:
|
case CurveType.Linear:
|
||||||
return subControlPoints;
|
var result = new List<Vector2>(subControlPoints.Length);
|
||||||
|
foreach (var c in subControlPoints)
|
||||||
|
result.Add(c);
|
||||||
|
|
||||||
|
return result;
|
||||||
case CurveType.PerfectCurve:
|
case CurveType.PerfectCurve:
|
||||||
//we can only use CircularArc iff we have exactly three control points and no dissection.
|
//we can only use CircularArc iff we have exactly three control points and no dissection.
|
||||||
if (ControlPoints.Count != 3 || subControlPoints.Count != 3)
|
if (ControlPoints.Length != 3 || subControlPoints.Length != 3)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Here we have exactly 3 control points. Attempt to fit a circular arc.
|
// Here we have exactly 3 control points. Attempt to fit a circular arc.
|
||||||
List<Vector2> subpath = new CircularArcApproximator(subControlPoints[0], subControlPoints[1], subControlPoints[2]).CreateArc();
|
List<Vector2> subpath = new CircularArcApproximator(subControlPoints).CreateArc();
|
||||||
|
|
||||||
// If for some reason a circular arc could not be fit to the 3 given points, fall back to a numerically stable bezier approximation.
|
// If for some reason a circular arc could not be fit to the 3 given points, fall back to a numerically stable bezier approximation.
|
||||||
if (subpath.Count == 0)
|
if (subpath.Count == 0)
|
||||||
@ -55,18 +60,23 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
// Sliders may consist of various subpaths separated by two consecutive vertices
|
// Sliders may consist of various subpaths separated by two consecutive vertices
|
||||||
// with the same position. The following loop parses these subpaths and computes
|
// with the same position. The following loop parses these subpaths and computes
|
||||||
// their shape independently, consecutively appending them to calculatedPath.
|
// their shape independently, consecutively appending them to calculatedPath.
|
||||||
List<Vector2> subControlPoints = new List<Vector2>();
|
|
||||||
for (int i = 0; i < ControlPoints.Count; ++i)
|
int start = 0;
|
||||||
|
int end = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < ControlPoints.Length; ++i)
|
||||||
{
|
{
|
||||||
subControlPoints.Add(ControlPoints[i]);
|
end++;
|
||||||
if (i == ControlPoints.Count - 1 || ControlPoints[i] == ControlPoints[i + 1])
|
|
||||||
|
if (i == ControlPoints.Length - 1 || ControlPoints[i] == ControlPoints[i + 1])
|
||||||
{
|
{
|
||||||
List<Vector2> subpath = calculateSubpath(subControlPoints);
|
ReadOnlySpan<Vector2> cpSpan = ControlPoints.AsSpan().Slice(start, end - start);
|
||||||
foreach (Vector2 t in subpath)
|
|
||||||
|
foreach (Vector2 t in calculateSubpath(cpSpan))
|
||||||
if (calculatedPath.Count == 0 || calculatedPath.Last() != t)
|
if (calculatedPath.Count == 0 || calculatedPath.Last() != t)
|
||||||
calculatedPath.Add(t);
|
calculatedPath.Add(t);
|
||||||
|
|
||||||
subControlPoints.Clear();
|
start = end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,7 +176,7 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
/// <param name="p1">End progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider).</param>
|
/// <param name="p1">End progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider).</param>
|
||||||
public void GetPathToProgress(List<Vector2> path, double p0, double p1)
|
public void GetPathToProgress(List<Vector2> path, double p0, double p1)
|
||||||
{
|
{
|
||||||
if (calculatedPath.Count == 0 && ControlPoints.Count > 0)
|
if (calculatedPath.Count == 0 && ControlPoints.Length > 0)
|
||||||
Calculate();
|
Calculate();
|
||||||
|
|
||||||
double d0 = progressToDistance(p0);
|
double d0 = progressToDistance(p0);
|
||||||
@ -193,7 +203,7 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Vector2 PositionAt(double progress)
|
public Vector2 PositionAt(double progress)
|
||||||
{
|
{
|
||||||
if (calculatedPath.Count == 0 && ControlPoints.Count > 0)
|
if (calculatedPath.Count == 0 && ControlPoints.Length > 0)
|
||||||
Calculate();
|
Calculate();
|
||||||
|
|
||||||
double d = progressToDistance(progress);
|
double d = progressToDistance(progress);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Types
|
namespace osu.Game.Rulesets.Objects.Types
|
||||||
@ -19,7 +18,7 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The control points that shape the curve.
|
/// The control points that shape the curve.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
List<Vector2> ControlPoints { get; }
|
Vector2[] ControlPoints { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The type of curve.
|
/// The type of curve.
|
||||||
|
@ -21,8 +21,8 @@ namespace osu.Game.Storyboards
|
|||||||
private Cached<double> endTimeBacking;
|
private Cached<double> endTimeBacking;
|
||||||
public double EndTime => endTimeBacking.IsValid ? endTimeBacking : endTimeBacking.Value = HasCommands ? commands.Max(c => c.EndTime) : double.MaxValue;
|
public double EndTime => endTimeBacking.IsValid ? endTimeBacking : endTimeBacking.Value = HasCommands ? commands.Max(c => c.EndTime) : double.MaxValue;
|
||||||
|
|
||||||
public T StartValue => HasCommands ? commands.OrderBy(c => c.StartTime).First().StartValue : default(T);
|
public T StartValue => HasCommands ? commands.OrderBy(c => c.StartTime).First().StartValue : default;
|
||||||
public T EndValue => HasCommands ? commands.OrderByDescending(c => c.EndTime).First().EndValue : default(T);
|
public T EndValue => HasCommands ? commands.OrderByDescending(c => c.EndTime).First().EndValue : default;
|
||||||
|
|
||||||
public void Add(Easing easing, double startTime, double endTime, T startValue, T endValue)
|
public void Add(Easing easing, double startTime, double endTime, T startValue, T endValue)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user