mirror of
https://github.com/ppy/osu.git
synced 2024-12-16 05:42:54 +08:00
Merge pull request #830 from smoogipooo/controlpoint-rework
Split out ControlPoints into more specific types
This commit is contained in:
commit
acce59cdb3
@ -1 +1 @@
|
||||
Subproject commit 42e26d49b9046fcb96c123b0dfb48e06d741e162
|
||||
Subproject commit c6f030d6f1ab65a48de9ff1d0c424acb686e0149
|
@ -18,7 +18,7 @@ using osu.Game.Rulesets.Taiko.UI;
|
||||
using System.Collections.Generic;
|
||||
using osu.Desktop.VisualTests.Beatmaps;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
@ -53,8 +53,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
time += RNG.Next(50, 500);
|
||||
}
|
||||
|
||||
TimingInfo timing = new TimingInfo();
|
||||
timing.ControlPoints.Add(new ControlPoint
|
||||
var controlPointInfo = new ControlPointInfo();
|
||||
controlPointInfo.TimingPoints.Add(new TimingControlPoint
|
||||
{
|
||||
BeatLength = 200
|
||||
});
|
||||
@ -73,7 +73,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
Author = @"peppy",
|
||||
},
|
||||
},
|
||||
TimingInfo = timing
|
||||
ControlPointInfo = controlPointInfo
|
||||
});
|
||||
|
||||
Add(new Drawable[]
|
||||
|
@ -7,10 +7,10 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Timing;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
@ -27,7 +27,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
Action<int, SpecialColumnPosition> createPlayfield = (cols, pos) =>
|
||||
{
|
||||
Clear();
|
||||
Add(new ManiaPlayfield(cols, new List<ControlPoint>())
|
||||
Add(new ManiaPlayfield(cols, new List<TimingChange>())
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -41,7 +41,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
Clear();
|
||||
|
||||
ManiaPlayfield playField;
|
||||
Add(playField = new ManiaPlayfield(cols, new List<ControlPoint> { new ControlPoint { BeatLength = 200 } })
|
||||
Add(playField = new ManiaPlayfield(cols, new List<TimingChange> { new TimingChange { BeatLength = 200 } })
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
|
@ -5,11 +5,11 @@ using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Rulesets.Mania.MathUtils;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
@ -32,11 +32,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
|
||||
: base(random, hitObject, beatmap, previousPattern)
|
||||
{
|
||||
ControlPoint overridePoint;
|
||||
ControlPoint controlPoint = Beatmap.TimingInfo.TimingPointAt(hitObject.StartTime, out overridePoint);
|
||||
|
||||
convertType = PatternType.None;
|
||||
if ((overridePoint ?? controlPoint)?.KiaiMode == false)
|
||||
if (Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode)
|
||||
convertType = PatternType.LowProbability;
|
||||
|
||||
var distanceData = hitObject as IHasDistance;
|
||||
@ -44,13 +41,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
repeatCount = repeatsData?.RepeatCount ?? 1;
|
||||
|
||||
double speedAdjustment = beatmap.TimingInfo.SpeedMultiplierAt(hitObject.StartTime);
|
||||
double speedAdjustedBeatLength = beatmap.TimingInfo.BeatLengthAt(hitObject.StartTime) * speedAdjustment;
|
||||
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
||||
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(hitObject.StartTime);
|
||||
|
||||
// The true distance, accounting for any repeats
|
||||
double distance = (distanceData?.Distance ?? 0) * repeatCount;
|
||||
// The velocity of the osu! hit object - calculated as the velocity of a slider
|
||||
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier / speedAdjustedBeatLength;
|
||||
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier / (timingPoint.BeatLength * difficultyPoint.SpeedMultiplier);
|
||||
// The duration of the osu! hit object
|
||||
double osuDuration = distance / osuVelocity;
|
||||
|
||||
|
@ -6,7 +6,7 @@ using System.Linq;
|
||||
using OpenTK;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Mania.MathUtils;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -25,17 +25,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
StairType = lastStair;
|
||||
|
||||
ControlPoint overridePoint;
|
||||
ControlPoint controlPoint = beatmap.TimingInfo.TimingPointAt(hitObject.StartTime, out overridePoint);
|
||||
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
||||
EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime);
|
||||
|
||||
var positionData = hitObject as IHasPosition;
|
||||
|
||||
float positionSeparation = ((positionData?.Position ?? Vector2.Zero) - previousPosition).Length;
|
||||
double timeSeparation = hitObject.StartTime - previousTime;
|
||||
|
||||
double beatLength = controlPoint.BeatLength;
|
||||
bool kiai = (overridePoint ?? controlPoint).KiaiMode;
|
||||
|
||||
if (timeSeparation <= 125)
|
||||
{
|
||||
// More than 120 BPM
|
||||
@ -72,12 +69,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
// More than 100 BPM stream
|
||||
convertType |= PatternType.ForceStack | PatternType.LowProbability;
|
||||
}
|
||||
else if (positionSeparation < 20 && density >= beatLength / 2.5)
|
||||
else if (positionSeparation < 20 && density >= timingPoint.BeatLength / 2.5)
|
||||
{
|
||||
// Low density stream
|
||||
convertType |= PatternType.Reverse | PatternType.LowProbability;
|
||||
}
|
||||
else if (density < beatLength / 2.5 || kiai)
|
||||
else if (density < timingPoint.BeatLength / 2.5 || effectPoint.KiaiMode)
|
||||
{
|
||||
// High density
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
@ -33,9 +33,9 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
/// </summary>
|
||||
public HitWindows ReleaseHitWindows { get; protected set; } = new HitWindows();
|
||||
|
||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
||||
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplyDefaults(timing, difficulty);
|
||||
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||
|
||||
ReleaseHitWindows = HitWindows * release_window_lenience;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
|
||||
@ -17,9 +17,9 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
/// </summary>
|
||||
public HitWindows HitWindows { get; protected set; } = new HitWindows();
|
||||
|
||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
||||
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplyDefaults(timing, difficulty);
|
||||
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||
|
||||
HitWindows = new HitWindows(difficulty.OverallDifficulty);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using OpenTK;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Timing
|
||||
{
|
||||
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.Timing
|
||||
|
||||
private readonly List<DrawableControlPoint> drawableControlPoints;
|
||||
|
||||
public ControlPointContainer(IEnumerable<ControlPoint> timingChanges)
|
||||
public ControlPointContainer(IEnumerable<TimingChange> timingChanges)
|
||||
{
|
||||
drawableControlPoints = timingChanges.Select(t => new DrawableControlPoint(t)).ToList();
|
||||
Children = drawableControlPoints;
|
||||
@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Mania.Timing
|
||||
/// </summary>
|
||||
private class DrawableControlPoint : Container
|
||||
{
|
||||
private readonly ControlPoint timingChange;
|
||||
private readonly TimingChange timingChange;
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
private readonly Container content;
|
||||
@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Mania.Timing
|
||||
/// the content container will scroll at twice the normal rate.
|
||||
/// </summary>
|
||||
/// <param name="timingChange">The control point to create the drawable control point for.</param>
|
||||
public DrawableControlPoint(ControlPoint timingChange)
|
||||
public DrawableControlPoint(TimingChange timingChange)
|
||||
{
|
||||
this.timingChange = timingChange;
|
||||
|
||||
|
23
osu.Game.Rulesets.Mania/Timing/TimingChange.cs
Normal file
23
osu.Game.Rulesets.Mania/Timing/TimingChange.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Timing
|
||||
{
|
||||
public class TimingChange
|
||||
{
|
||||
/// <summary>
|
||||
/// The time at which this timing change happened.
|
||||
/// </summary>
|
||||
public double Time;
|
||||
|
||||
/// <summary>
|
||||
/// The beat length.
|
||||
/// </summary>
|
||||
public double BeatLength = 500;
|
||||
|
||||
/// <summary>
|
||||
/// The speed multiplier.
|
||||
/// </summary>
|
||||
public double SpeedMultiplier = 1;
|
||||
}
|
||||
}
|
@ -17,7 +17,6 @@ using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using System;
|
||||
using osu.Framework.Configuration;
|
||||
|
||||
@ -46,7 +45,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
public readonly ControlPointContainer ControlPointContainer;
|
||||
|
||||
public Column(IEnumerable<ControlPoint> timingChanges)
|
||||
public Column(IEnumerable<TimingChange> timingChanges)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
Width = column_width;
|
||||
|
@ -2,19 +2,22 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenTK;
|
||||
using OpenTK.Input;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Lists;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Scoring;
|
||||
using osu.Game.Rulesets.Mania.Timing;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -33,22 +36,32 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
protected override Playfield<ManiaHitObject, ManiaJudgement> CreatePlayfield()
|
||||
{
|
||||
ControlPoint firstTimingChange = Beatmap.TimingInfo.ControlPoints.FirstOrDefault(t => t.TimingChange);
|
||||
double lastSpeedMultiplier = 1;
|
||||
double lastBeatLength = 500;
|
||||
|
||||
if (firstTimingChange == null)
|
||||
throw new InvalidOperationException("The Beatmap contains no timing points!");
|
||||
// Merge timing + difficulty points
|
||||
var allPoints = new SortedList<ControlPoint>(Comparer<ControlPoint>.Default);
|
||||
allPoints.AddRange(Beatmap.ControlPointInfo.TimingPoints);
|
||||
allPoints.AddRange(Beatmap.ControlPointInfo.DifficultyPoints);
|
||||
|
||||
// Generate the timing points, making non-timing changes use the previous timing change
|
||||
var timingChanges = Beatmap.TimingInfo.ControlPoints.Select(c =>
|
||||
var timingChanges = allPoints.Select(c =>
|
||||
{
|
||||
ControlPoint t = c.Clone();
|
||||
var timingPoint = c as TimingControlPoint;
|
||||
var difficultyPoint = c as DifficultyControlPoint;
|
||||
|
||||
if (c.TimingChange)
|
||||
firstTimingChange = c;
|
||||
else
|
||||
t.BeatLength = firstTimingChange.BeatLength;
|
||||
if (timingPoint != null)
|
||||
lastBeatLength = timingPoint.BeatLength;
|
||||
|
||||
return t;
|
||||
if (difficultyPoint != null)
|
||||
lastSpeedMultiplier = difficultyPoint.SpeedMultiplier;
|
||||
|
||||
return new TimingChange
|
||||
{
|
||||
Time = c.Time,
|
||||
BeatLength = lastBeatLength,
|
||||
SpeedMultiplier = lastSpeedMultiplier
|
||||
};
|
||||
});
|
||||
|
||||
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
|
||||
|
@ -19,7 +19,6 @@ using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Timing;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osu.Framework.MathUtils;
|
||||
|
||||
@ -65,7 +64,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
private readonly int columnCount;
|
||||
|
||||
public ManiaPlayfield(int columnCount, IEnumerable<ControlPoint> timingChanges)
|
||||
public ManiaPlayfield(int columnCount, IEnumerable<TimingChange> timingChanges)
|
||||
{
|
||||
this.columnCount = columnCount;
|
||||
|
||||
|
@ -78,6 +78,7 @@
|
||||
<Compile Include="Mods\ManiaMod.cs" />
|
||||
<Compile Include="UI\SpecialColumnPosition.cs" />
|
||||
<Compile Include="Timing\ControlPointContainer.cs" />
|
||||
<Compile Include="Timing\TimingChange.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
|
||||
|
@ -6,8 +6,8 @@ using OpenTK;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
@ -68,9 +68,9 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
return OsuScoreResult.Miss;
|
||||
}
|
||||
|
||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
||||
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplyDefaults(timing, difficulty);
|
||||
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||
|
||||
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -10,6 +9,7 @@ using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Database;
|
||||
using System.Linq;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
@ -62,13 +62,16 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
public double Velocity;
|
||||
public double TickDistance;
|
||||
|
||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
||||
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplyDefaults(timing, difficulty);
|
||||
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||
|
||||
double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier / timing.SpeedMultiplierAt(StartTime);
|
||||
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
||||
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
|
||||
|
||||
Velocity = scoringDistance / timing.BeatLengthAt(StartTime);
|
||||
double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier / difficultyPoint.SpeedMultiplier;
|
||||
|
||||
Velocity = scoringDistance / timingPoint.BeatLength;
|
||||
TickDistance = scoringDistance / difficulty.SliderTickRate;
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
|
||||
public override bool NewCombo => true;
|
||||
|
||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
||||
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplyDefaults(timing, difficulty);
|
||||
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||
|
||||
SpinsRequired = (int)(Duration / 1000 * BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5));
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ using osu.Game.Database;
|
||||
using osu.Game.IO.Serialization;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
{
|
||||
@ -77,8 +78,11 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
{
|
||||
int repeats = repeatsData?.RepeatCount ?? 1;
|
||||
|
||||
double speedAdjustment = beatmap.TimingInfo.SpeedMultiplierAt(obj.StartTime);
|
||||
double speedAdjustedBeatLength = beatmap.TimingInfo.BeatLengthAt(obj.StartTime) * speedAdjustment;
|
||||
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime);
|
||||
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(obj.StartTime);
|
||||
|
||||
double speedAdjustment = difficultyPoint.SpeedMultiplier;
|
||||
double speedAdjustedBeatLength = timingPoint.BeatLength * speedAdjustment;
|
||||
|
||||
// The true distance, accounting for any repeats. This ends up being the drum roll distance later
|
||||
double distance = distanceData.Distance * repeats * legacy_velocity_multiplier;
|
||||
|
@ -5,9 +5,9 @@ using osu.Game.Rulesets.Objects.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects
|
||||
{
|
||||
@ -55,11 +55,13 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
/// </summary>
|
||||
private double tickSpacing = 100;
|
||||
|
||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
||||
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplyDefaults(timing, difficulty);
|
||||
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||
|
||||
tickSpacing = timing.BeatLengthAt(StartTime) / TickRate;
|
||||
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
||||
|
||||
tickSpacing = timingPoint.BeatLength / TickRate;
|
||||
|
||||
RequiredGoodHits = TotalTicks * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty);
|
||||
RequiredGreatHits = TotalTicks * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty);
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects
|
||||
@ -23,9 +23,9 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
/// </summary>
|
||||
public double HitWindowMiss = 95;
|
||||
|
||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
||||
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplyDefaults(timing, difficulty);
|
||||
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||
|
||||
HitWindowGreat = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 50, 35, 20);
|
||||
HitWindowGood = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 120, 80, 50);
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Taiko.UI;
|
||||
@ -31,12 +31,12 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
public const float DEFAULT_STRONG_CIRCLE_DIAMETER = DEFAULT_CIRCLE_DIAMETER * STRONG_CIRCLE_DIAMETER_SCALE;
|
||||
|
||||
/// <summary>
|
||||
/// The time taken from the initial (off-screen) spawn position to the centre of the hit target for a <see cref="ControlPoint.BeatLength"/> of 1000ms.
|
||||
/// The time taken from the initial (off-screen) spawn position to the centre of the hit target for a <see cref="TimingControlPoint.BeatLength"/> of 1000ms.
|
||||
/// </summary>
|
||||
private const double scroll_time = 6000;
|
||||
|
||||
/// <summary>
|
||||
/// Our adjusted <see cref="scroll_time"/> taking into consideration local <see cref="ControlPoint.BeatLength"/> and other speed multipliers.
|
||||
/// Our adjusted <see cref="scroll_time"/> taking into consideration local <see cref="TimingControlPoint.BeatLength"/> and other speed multipliers.
|
||||
/// </summary>
|
||||
public double ScrollTime;
|
||||
|
||||
@ -51,17 +51,17 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
/// </summary>
|
||||
public bool Kiai { get; protected set; }
|
||||
|
||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
||||
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplyDefaults(timing, difficulty);
|
||||
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||
|
||||
ScrollTime = scroll_time * (timing.BeatLengthAt(StartTime) * timing.SpeedMultiplierAt(StartTime) / 1000) / difficulty.SliderMultiplier;
|
||||
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
||||
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
|
||||
EffectControlPoint effectPoint = controlPointInfo.EffectPointAt(StartTime);
|
||||
|
||||
ControlPoint overridePoint;
|
||||
Kiai = timing.TimingPointAt(StartTime, out overridePoint).KiaiMode;
|
||||
ScrollTime = scroll_time * (timingPoint.BeatLength * difficultyPoint.SpeedMultiplier / 1000) / difficulty.SliderMultiplier;
|
||||
|
||||
if (overridePoint != null)
|
||||
Kiai |= overridePoint.KiaiMode;
|
||||
Kiai |= effectPoint.KiaiMode;
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.Taiko.Replays;
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Beatmaps;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
@ -43,7 +44,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
TaikoHitObject lastObject = Beatmap.HitObjects[Beatmap.HitObjects.Count - 1];
|
||||
double lastHitTime = 1 + (lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime;
|
||||
|
||||
var timingPoints = Beatmap.TimingInfo.ControlPoints.FindAll(cp => cp.TimingChange);
|
||||
var timingPoints = Beatmap.ControlPointInfo.TimingPoints.ToList();
|
||||
|
||||
if (timingPoints.Count == 0)
|
||||
return;
|
||||
@ -68,7 +69,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
StartTime = time,
|
||||
};
|
||||
|
||||
barLine.ApplyDefaults(Beatmap.TimingInfo, Beatmap.BeatmapInfo.Difficulty);
|
||||
barLine.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.Difficulty);
|
||||
|
||||
bool isMajor = currentBeat % (int)currentPoint.TimeSignature == 0;
|
||||
taikoPlayfield.AddBarLine(isMajor ? new DrawableBarLineMajor(barLine) : new DrawableBarLine(barLine));
|
||||
|
@ -7,6 +7,7 @@ using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
@ -17,7 +18,7 @@ namespace osu.Game.Beatmaps
|
||||
where T : HitObject
|
||||
{
|
||||
public BeatmapInfo BeatmapInfo;
|
||||
public TimingInfo TimingInfo = new TimingInfo();
|
||||
public ControlPointInfo ControlPointInfo = new ControlPointInfo();
|
||||
public List<BreakPeriod> Breaks = new List<BreakPeriod>();
|
||||
public readonly List<Color4> ComboColors = new List<Color4>
|
||||
{
|
||||
@ -46,7 +47,7 @@ namespace osu.Game.Beatmaps
|
||||
public Beatmap(Beatmap original = null)
|
||||
{
|
||||
BeatmapInfo = original?.BeatmapInfo ?? BeatmapInfo;
|
||||
TimingInfo = original?.TimingInfo ?? TimingInfo;
|
||||
ControlPointInfo = original?.ControlPointInfo ?? ControlPointInfo;
|
||||
Breaks = original?.Breaks ?? Breaks;
|
||||
ComboColors = original?.ComboColors ?? ComboColors;
|
||||
}
|
||||
|
17
osu.Game/Beatmaps/ControlPoints/ControlPoint.cs
Normal file
17
osu.Game/Beatmaps/ControlPoints/ControlPoint.cs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
|
||||
namespace osu.Game.Beatmaps.ControlPoints
|
||||
{
|
||||
public class ControlPoint : IComparable<ControlPoint>
|
||||
{
|
||||
/// <summary>
|
||||
/// The time at which the control point takes effect.
|
||||
/// </summary>
|
||||
public double Time;
|
||||
|
||||
public int CompareTo(ControlPoint other) => Time.CompareTo(other.Time);
|
||||
}
|
||||
}
|
100
osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs
Normal file
100
osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Lists;
|
||||
|
||||
namespace osu.Game.Beatmaps.ControlPoints
|
||||
{
|
||||
public class ControlPointInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// All timing points.
|
||||
/// </summary>
|
||||
public readonly SortedList<TimingControlPoint> TimingPoints = new SortedList<TimingControlPoint>(Comparer<TimingControlPoint>.Default);
|
||||
|
||||
/// <summary>
|
||||
/// All difficulty points.
|
||||
/// </summary>
|
||||
public readonly SortedList<DifficultyControlPoint> DifficultyPoints = new SortedList<DifficultyControlPoint>(Comparer<DifficultyControlPoint>.Default);
|
||||
|
||||
/// <summary>
|
||||
/// All sound points.
|
||||
/// </summary>
|
||||
public readonly SortedList<SoundControlPoint> SoundPoints = new SortedList<SoundControlPoint>(Comparer<SoundControlPoint>.Default);
|
||||
|
||||
/// <summary>
|
||||
/// All effect points.
|
||||
/// </summary>
|
||||
public readonly SortedList<EffectControlPoint> EffectPoints = new SortedList<EffectControlPoint>(Comparer<EffectControlPoint>.Default);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the difficulty control point that is active at <paramref name="time"/>.
|
||||
/// </summary>
|
||||
/// <param name="time">The time to find the difficulty control point at.</param>
|
||||
/// <returns>The difficulty control point.</returns>
|
||||
public DifficultyControlPoint DifficultyPointAt(double time) => binarySearch(DifficultyPoints, time);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the effect control point that is active at <paramref name="time"/>.
|
||||
/// </summary>
|
||||
/// <param name="time">The time to find the effect control point at.</param>
|
||||
/// <returns>The effect control point.</returns>
|
||||
public EffectControlPoint EffectPointAt(double time) => binarySearch(EffectPoints, time);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the sound control point that is active at <paramref name="time"/>.
|
||||
/// </summary>
|
||||
/// <param name="time">The time to find the sound control point at.</param>
|
||||
/// <returns>The sound control point.</returns>
|
||||
public SoundControlPoint SoundPointAt(double time) => binarySearch(SoundPoints, time);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the timing control point that is active at <paramref name="time"/>.
|
||||
/// </summary>
|
||||
/// <param name="time">The time to find the timing control point at.</param>
|
||||
/// <returns>The timing control point.</returns>
|
||||
public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the maximum BPM represented by any timing control point.
|
||||
/// </summary>
|
||||
public double BPMMaximum =>
|
||||
60000 / (TimingPoints.OrderBy(c => c.BeatLength).FirstOrDefault() ?? new TimingControlPoint()).BeatLength;
|
||||
|
||||
/// <summary>
|
||||
/// Finds the minimum BPM represented by any timing control point.
|
||||
/// </summary>
|
||||
public double BPMMinimum =>
|
||||
60000 / (TimingPoints.OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? new TimingControlPoint()).BeatLength;
|
||||
|
||||
/// <summary>
|
||||
/// Finds the mode BPM (most common BPM) represented by the control points.
|
||||
/// </summary>
|
||||
public double BPMMode =>
|
||||
60000 / (TimingPoints.GroupBy(c => c.BeatLength).OrderByDescending(grp => grp.Count()).FirstOrDefault()?.FirstOrDefault() ?? new TimingControlPoint()).BeatLength;
|
||||
|
||||
private T binarySearch<T>(SortedList<T> list, double time)
|
||||
where T : ControlPoint, new()
|
||||
{
|
||||
if (list.Count == 0)
|
||||
return new T();
|
||||
|
||||
if (time < list[0].Time)
|
||||
return new T();
|
||||
|
||||
int index = list.BinarySearch(new T() { Time = time });
|
||||
|
||||
// Check if we've found an exact match (t == time)
|
||||
if (index >= 0)
|
||||
return list[index];
|
||||
|
||||
index = ~index;
|
||||
|
||||
if (index == list.Count)
|
||||
return list[list.Count - 1];
|
||||
return list[index - 1];
|
||||
}
|
||||
}
|
||||
}
|
13
osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs
Normal file
13
osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Beatmaps.ControlPoints
|
||||
{
|
||||
public class DifficultyControlPoint : ControlPoint
|
||||
{
|
||||
/// <summary>
|
||||
/// The speed multiplier at this control point.
|
||||
/// </summary>
|
||||
public double SpeedMultiplier = 1;
|
||||
}
|
||||
}
|
18
osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs
Normal file
18
osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Beatmaps.ControlPoints
|
||||
{
|
||||
public class EffectControlPoint : ControlPoint
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether this control point enables Kiai mode.
|
||||
/// </summary>
|
||||
public bool KiaiMode;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the first bar line of this control point is ignored.
|
||||
/// </summary>
|
||||
public bool OmitFirstBarLine;
|
||||
}
|
||||
}
|
18
osu.Game/Beatmaps/ControlPoints/SoundControlPoint.cs
Normal file
18
osu.Game/Beatmaps/ControlPoints/SoundControlPoint.cs
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Beatmaps.ControlPoints
|
||||
{
|
||||
public class SoundControlPoint : ControlPoint
|
||||
{
|
||||
/// <summary>
|
||||
/// The default sample bank at this control point.
|
||||
/// </summary>
|
||||
public string SampleBank;
|
||||
|
||||
/// <summary>
|
||||
/// The default sample volume at this control point.
|
||||
/// </summary>
|
||||
public int SampleVolume;
|
||||
}
|
||||
}
|
20
osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
Normal file
20
osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
|
||||
namespace osu.Game.Beatmaps.ControlPoints
|
||||
{
|
||||
public class TimingControlPoint : ControlPoint
|
||||
{
|
||||
/// <summary>
|
||||
/// The time signature at this control point.
|
||||
/// </summary>
|
||||
public TimeSignatures TimeSignature = TimeSignatures.SimpleQuadruple;
|
||||
|
||||
/// <summary>
|
||||
/// The beat length at this control point.
|
||||
/// </summary>
|
||||
public double BeatLength = 500;
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ namespace osu.Game.Beatmaps
|
||||
Objects = CreateBeatmapConverter().Convert(beatmap, true).HitObjects;
|
||||
|
||||
foreach (var h in Objects)
|
||||
h.ApplyDefaults(beatmap.TimingInfo, beatmap.BeatmapInfo.Difficulty);
|
||||
h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.Difficulty);
|
||||
|
||||
PreprocessHitObjects();
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using OpenTK.Graphics;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Beatmaps.Legacy;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
@ -241,6 +242,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
|
||||
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
|
||||
double speedMultiplier = beatLength < 0 ? -beatLength / 100.0 : 1;
|
||||
|
||||
TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple;
|
||||
if (split.Length >= 3)
|
||||
@ -275,18 +277,48 @@ namespace osu.Game.Beatmaps.Formats
|
||||
if (stringSampleSet == @"none")
|
||||
stringSampleSet = @"normal";
|
||||
|
||||
beatmap.TimingInfo.ControlPoints.Add(new ControlPoint
|
||||
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(time);
|
||||
SoundControlPoint soundPoint = beatmap.ControlPointInfo.SoundPointAt(time);
|
||||
EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(time);
|
||||
|
||||
if (timingChange)
|
||||
{
|
||||
Time = time,
|
||||
BeatLength = beatLength,
|
||||
SpeedMultiplier = beatLength < 0 ? -beatLength / 100.0 : 1,
|
||||
TimingChange = timingChange,
|
||||
TimeSignature = timeSignature,
|
||||
SampleBank = stringSampleSet,
|
||||
SampleVolume = sampleVolume,
|
||||
KiaiMode = kiaiMode,
|
||||
OmitFirstBarLine = omitFirstBarSignature
|
||||
});
|
||||
beatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint
|
||||
{
|
||||
Time = time,
|
||||
BeatLength = beatLength,
|
||||
TimeSignature = timeSignature
|
||||
});
|
||||
}
|
||||
|
||||
if (speedMultiplier != difficultyPoint.SpeedMultiplier)
|
||||
{
|
||||
beatmap.ControlPointInfo.DifficultyPoints.Add(new DifficultyControlPoint
|
||||
{
|
||||
Time = time,
|
||||
SpeedMultiplier = speedMultiplier
|
||||
});
|
||||
}
|
||||
|
||||
if (stringSampleSet != soundPoint.SampleBank || sampleVolume != soundPoint.SampleVolume)
|
||||
{
|
||||
beatmap.ControlPointInfo.SoundPoints.Add(new SoundControlPoint
|
||||
{
|
||||
Time = time,
|
||||
SampleBank = stringSampleSet,
|
||||
SampleVolume = sampleVolume
|
||||
});
|
||||
}
|
||||
|
||||
if (kiaiMode != effectPoint.KiaiMode || omitFirstBarSignature != effectPoint.OmitFirstBarLine)
|
||||
{
|
||||
beatmap.ControlPointInfo.EffectPoints.Add(new EffectControlPoint
|
||||
{
|
||||
Time = time,
|
||||
KiaiMode = kiaiMode,
|
||||
OmitFirstBarLine = omitFirstBarSignature
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void handleColours(Beatmap beatmap, string key, string val, ref bool hasCustomColours)
|
||||
|
@ -1,20 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Beatmaps.Timing
|
||||
{
|
||||
public class ControlPoint
|
||||
{
|
||||
public string SampleBank;
|
||||
public int SampleVolume;
|
||||
public TimeSignatures TimeSignature = TimeSignatures.SimpleQuadruple;
|
||||
public double Time;
|
||||
public double BeatLength = 500;
|
||||
public double SpeedMultiplier = 1;
|
||||
public bool TimingChange = true;
|
||||
public bool KiaiMode;
|
||||
public bool OmitFirstBarLine;
|
||||
|
||||
public ControlPoint Clone() => (ControlPoint)MemberwiseClone();
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Beatmaps.Timing
|
||||
{
|
||||
public class TimingInfo
|
||||
{
|
||||
public readonly List<ControlPoint> ControlPoints = new List<ControlPoint>();
|
||||
|
||||
public double BPMMaximum => 60000 / (ControlPoints?.Where(c => c.BeatLength != 0).OrderBy(c => c.BeatLength).FirstOrDefault() ?? new ControlPoint()).BeatLength;
|
||||
public double BPMMinimum => 60000 / (ControlPoints?.Where(c => c.BeatLength != 0).OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? new ControlPoint()).BeatLength;
|
||||
public double BPMMode => BPMAt(ControlPoints.Where(c => c.BeatLength != 0).GroupBy(c => c.BeatLength).OrderByDescending(grp => grp.Count()).First().First().Time);
|
||||
|
||||
public double BPMAt(double time)
|
||||
{
|
||||
return 60000 / BeatLengthAt(time);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the speed multiplier at a time.
|
||||
/// </summary>
|
||||
/// <param name="time">The time to find the speed multiplier at.</param>
|
||||
/// <returns>The speed multiplier.</returns>
|
||||
public double SpeedMultiplierAt(double time)
|
||||
{
|
||||
ControlPoint overridePoint;
|
||||
ControlPoint timingPoint = TimingPointAt(time, out overridePoint);
|
||||
|
||||
return overridePoint?.SpeedMultiplier ?? timingPoint?.SpeedMultiplier ?? 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the beat length at a time. This is expressed in milliseconds.
|
||||
/// </summary>
|
||||
/// <param name="time">The time to find the beat length at.</param>
|
||||
/// <returns>The beat length.</returns>
|
||||
public double BeatLengthAt(double time)
|
||||
{
|
||||
ControlPoint overridePoint;
|
||||
ControlPoint timingPoint = TimingPointAt(time, out overridePoint);
|
||||
|
||||
return timingPoint.BeatLength;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the timing point at a time.
|
||||
/// </summary>
|
||||
/// <param name="time">The time to find the timing point at.</param>
|
||||
/// <param name="overridePoint">The timing point containing the velocity change of the returned timing point.</param>
|
||||
/// <returns>The timing point.</returns>
|
||||
public ControlPoint TimingPointAt(double time, out ControlPoint overridePoint)
|
||||
{
|
||||
overridePoint = null;
|
||||
|
||||
ControlPoint timingPoint = null;
|
||||
foreach (var controlPoint in ControlPoints)
|
||||
{
|
||||
// Some beatmaps have the first timingPoint (accidentally) start after the first HitObject(s).
|
||||
// This null check makes it so that the first ControlPoint that makes a timing change is used as
|
||||
// the timingPoint for those HitObject(s).
|
||||
if (controlPoint.Time <= time || timingPoint == null)
|
||||
{
|
||||
if (controlPoint.TimingChange)
|
||||
{
|
||||
timingPoint = controlPoint;
|
||||
overridePoint = null;
|
||||
}
|
||||
else
|
||||
overridePoint = controlPoint;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
return timingPoint ?? new ControlPoint();
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
|
||||
namespace osu.Game.Graphics.Containers
|
||||
@ -14,7 +15,7 @@ namespace osu.Game.Graphics.Containers
|
||||
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
||||
|
||||
private int lastBeat;
|
||||
private ControlPoint lastControlPoint;
|
||||
private TimingControlPoint lastTimingPoint;
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
@ -22,29 +23,29 @@ namespace osu.Game.Graphics.Containers
|
||||
return;
|
||||
|
||||
double currentTrackTime = beatmap.Value.Track.CurrentTime;
|
||||
ControlPoint overridePoint;
|
||||
ControlPoint controlPoint = beatmap.Value.Beatmap.TimingInfo.TimingPointAt(currentTrackTime, out overridePoint);
|
||||
|
||||
if (controlPoint.BeatLength == 0)
|
||||
TimingControlPoint timingPoint = beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(currentTrackTime);
|
||||
EffectControlPoint effectPoint = beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(currentTrackTime);
|
||||
|
||||
if (timingPoint.BeatLength == 0)
|
||||
return;
|
||||
|
||||
bool kiai = (overridePoint ?? controlPoint).KiaiMode;
|
||||
int beat = (int)((currentTrackTime - controlPoint.Time) / controlPoint.BeatLength);
|
||||
int beat = (int)((currentTrackTime - timingPoint.Time) / timingPoint.BeatLength);
|
||||
|
||||
// The beats before the start of the first control point are off by 1, this should do the trick
|
||||
if (currentTrackTime < controlPoint.Time)
|
||||
if (currentTrackTime < timingPoint.Time)
|
||||
beat--;
|
||||
|
||||
if (controlPoint == lastControlPoint && beat == lastBeat)
|
||||
if (timingPoint == lastTimingPoint && beat == lastBeat)
|
||||
return;
|
||||
|
||||
double offsetFromBeat = (controlPoint.Time - currentTrackTime) % controlPoint.BeatLength;
|
||||
double offsetFromBeat = (timingPoint.Time - currentTrackTime) % timingPoint.BeatLength;
|
||||
|
||||
using (BeginDelayedSequence(offsetFromBeat, true))
|
||||
OnNewBeat(beat, controlPoint.BeatLength, controlPoint.TimeSignature, kiai);
|
||||
OnNewBeat(beat, timingPoint.BeatLength, timingPoint.TimeSignature, effectPoint.KiaiMode);
|
||||
|
||||
lastBeat = beat;
|
||||
lastControlPoint = controlPoint;
|
||||
lastTimingPoint = timingPoint;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Beatmaps
|
||||
return new Beatmap<T>
|
||||
{
|
||||
BeatmapInfo = original.BeatmapInfo,
|
||||
TimingInfo = original.TimingInfo,
|
||||
ControlPointInfo = original.ControlPointInfo,
|
||||
HitObjects = original.HitObjects.SelectMany(h => convert(h, original)).ToList()
|
||||
};
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
|
||||
@ -33,31 +33,28 @@ namespace osu.Game.Rulesets.Objects
|
||||
/// <summary>
|
||||
/// Applies default values to this HitObject.
|
||||
/// </summary>
|
||||
/// <param name="controlPointInfo">The control points.</param>
|
||||
/// <param name="difficulty">The difficulty settings to use.</param>
|
||||
/// <param name="timing">The timing settings to use.</param>
|
||||
public virtual void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
||||
public virtual void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
ControlPoint overridePoint;
|
||||
ControlPoint timingPoint = timing.TimingPointAt(StartTime, out overridePoint);
|
||||
|
||||
ControlPoint samplePoint = overridePoint ?? timingPoint;
|
||||
SoundControlPoint soundPoint = controlPointInfo.SoundPointAt(StartTime);
|
||||
|
||||
// Initialize first sample
|
||||
Samples.ForEach(s => initializeSampleInfo(s, samplePoint));
|
||||
Samples.ForEach(s => initializeSampleInfo(s, soundPoint));
|
||||
|
||||
// Initialize any repeat samples
|
||||
var repeatData = this as IHasRepeats;
|
||||
repeatData?.RepeatSamples?.ForEach(r => r.ForEach(s => initializeSampleInfo(s, samplePoint)));
|
||||
repeatData?.RepeatSamples?.ForEach(r => r.ForEach(s => initializeSampleInfo(s, soundPoint)));
|
||||
}
|
||||
|
||||
private void initializeSampleInfo(SampleInfo sample, ControlPoint controlPoint)
|
||||
private void initializeSampleInfo(SampleInfo sample, SoundControlPoint soundPoint)
|
||||
{
|
||||
if (sample.Volume == 0)
|
||||
sample.Volume = controlPoint?.SampleVolume ?? 0;
|
||||
sample.Volume = soundPoint?.SampleVolume ?? 0;
|
||||
|
||||
// If the bank is not assigned a name, assign it from the control point
|
||||
if (string.IsNullOrEmpty(sample.Bank))
|
||||
sample.Bank = controlPoint?.SampleBank ?? @"normal";
|
||||
sample.Bank = soundPoint?.SampleBank ?? @"normal";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
// Apply defaults
|
||||
foreach (var h in Beatmap.HitObjects)
|
||||
h.ApplyDefaults(Beatmap.TimingInfo, Beatmap.BeatmapInfo.Difficulty);
|
||||
h.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.Difficulty);
|
||||
|
||||
// Post-process the beatmap
|
||||
processor.PostProcess(Beatmap);
|
||||
|
@ -123,7 +123,7 @@ namespace osu.Game.Screens.Play
|
||||
decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
|
||||
|
||||
var firstObjectTime = HitRenderer.Objects.First().StartTime;
|
||||
decoupledClock.Seek(Math.Min(0, firstObjectTime - Math.Max(Beatmap.Beatmap.TimingInfo.BeatLengthAt(firstObjectTime) * 4, Beatmap.BeatmapInfo.AudioLeadIn)));
|
||||
decoupledClock.Seek(Math.Min(0, firstObjectTime - Math.Max(Beatmap.Beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, Beatmap.BeatmapInfo.AudioLeadIn)));
|
||||
decoupledClock.ProcessFrame();
|
||||
|
||||
offsetClock = new FramedOffsetClock(decoupledClock);
|
||||
|
@ -238,12 +238,12 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
private string getBPMRange(Beatmap beatmap)
|
||||
{
|
||||
double bpmMax = beatmap.TimingInfo.BPMMaximum;
|
||||
double bpmMin = beatmap.TimingInfo.BPMMinimum;
|
||||
double bpmMax = beatmap.ControlPointInfo.BPMMaximum;
|
||||
double bpmMin = beatmap.ControlPointInfo.BPMMinimum;
|
||||
|
||||
if (Precision.AlmostEquals(bpmMin, bpmMax)) return Math.Round(bpmMin) + "bpm";
|
||||
|
||||
return Math.Round(bpmMin) + "-" + Math.Round(bpmMax) + "bpm (mostly " + Math.Round(beatmap.TimingInfo.BPMMode) + "bpm)";
|
||||
return Math.Round(bpmMin) + "-" + Math.Round(bpmMax) + "bpm (mostly " + Math.Round(beatmap.ControlPointInfo.BPMMode) + "bpm)";
|
||||
}
|
||||
|
||||
public class InfoLabel : Container
|
||||
|
@ -87,10 +87,15 @@
|
||||
<Compile Include="Overlays\Toolbar\ToolbarChatButton.cs" />
|
||||
<Compile Include="Rulesets\Beatmaps\BeatmapConverter.cs" />
|
||||
<Compile Include="Rulesets\Beatmaps\BeatmapProcessor.cs" />
|
||||
<Compile Include="Beatmaps\ControlPoints\ControlPoint.cs" />
|
||||
<Compile Include="Beatmaps\ControlPoints\ControlPointInfo.cs" />
|
||||
<Compile Include="Beatmaps\ControlPoints\DifficultyControlPoint.cs" />
|
||||
<Compile Include="Beatmaps\ControlPoints\EffectControlPoint.cs" />
|
||||
<Compile Include="Beatmaps\ControlPoints\SoundControlPoint.cs" />
|
||||
<Compile Include="Beatmaps\ControlPoints\TimingControlPoint.cs" />
|
||||
<Compile Include="Beatmaps\Legacy\LegacyBeatmap.cs" />
|
||||
<Compile Include="Beatmaps\Timing\BreakPeriod.cs" />
|
||||
<Compile Include="Beatmaps\Timing\TimeSignatures.cs" />
|
||||
<Compile Include="Beatmaps\Timing\TimingInfo.cs" />
|
||||
<Compile Include="Database\BeatmapMetrics.cs" />
|
||||
<Compile Include="Database\Database.cs" />
|
||||
<Compile Include="Database\RulesetInfo.cs" />
|
||||
@ -202,7 +207,6 @@
|
||||
<Compile Include="Beatmaps\Drawables\Panel.cs" />
|
||||
<Compile Include="Rulesets\Objects\Drawables\DrawableHitObject.cs" />
|
||||
<Compile Include="Rulesets\Objects\HitObject.cs" />
|
||||
<Compile Include="Beatmaps\Timing\ControlPoint.cs" />
|
||||
<Compile Include="Configuration\OsuConfigManager.cs" />
|
||||
<Compile Include="Overlays\Notifications\IHasCompletionTarget.cs" />
|
||||
<Compile Include="Overlays\Notifications\Notification.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user