mirror of
https://github.com/ppy/osu.git
synced 2024-12-15 15:03:10 +08:00
Merge branch 'master' into results-screen-horizontal-scroll
This commit is contained in:
commit
e8a25fea1a
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
|
|
||||||
switch (obj)
|
switch (obj)
|
||||||
{
|
{
|
||||||
case IHasCurve curveData:
|
case IHasPathWithRepeats curveData:
|
||||||
return new JuiceStream
|
return new JuiceStream
|
||||||
{
|
{
|
||||||
StartTime = obj.StartTime,
|
StartTime = obj.StartTime,
|
||||||
@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
LegacyLastTickOffset = (obj as IHasLegacyLastTickOffset)?.LegacyLastTickOffset ?? 0
|
LegacyLastTickOffset = (obj as IHasLegacyLastTickOffset)?.LegacyLastTickOffset ?? 0
|
||||||
}.Yield();
|
}.Yield();
|
||||||
|
|
||||||
case IHasEndTime endTime:
|
case IHasDuration endTime:
|
||||||
return new BananaShower
|
return new BananaShower
|
||||||
{
|
{
|
||||||
StartTime = obj.StartTime,
|
StartTime = obj.StartTime,
|
||||||
|
@ -7,7 +7,7 @@ using osu.Game.Rulesets.Objects.Types;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects
|
namespace osu.Game.Rulesets.Catch.Objects
|
||||||
{
|
{
|
||||||
public class BananaShower : CatchHitObject, IHasEndTime
|
public class BananaShower : CatchHitObject, IHasDuration
|
||||||
{
|
{
|
||||||
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
|
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ using osu.Game.Rulesets.Objects.Types;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects
|
namespace osu.Game.Rulesets.Catch.Objects
|
||||||
{
|
{
|
||||||
public class JuiceStream : CatchHitObject, IHasCurve
|
public class JuiceStream : CatchHitObject, IHasPathWithRepeats
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Positional distance that results in a duration of one second, before any speed adjustments.
|
/// Positional distance that results in a duration of one second, before any speed adjustments.
|
||||||
@ -115,15 +115,15 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double EndTime
|
public float EndX => X + this.CurvePositionAt(1).X / CatchPlayfield.BASE_WIDTH;
|
||||||
|
|
||||||
|
public double Duration
|
||||||
{
|
{
|
||||||
get => StartTime + this.SpanCount() * Path.Distance / Velocity;
|
get => this.SpanCount() * Path.Distance / Velocity;
|
||||||
set => throw new System.NotSupportedException($"Adjust via {nameof(RepeatCount)} instead"); // can be implemented if/when needed.
|
set => throw new System.NotSupportedException($"Adjust via {nameof(RepeatCount)} instead"); // can be implemented if/when needed.
|
||||||
}
|
}
|
||||||
|
|
||||||
public float EndX => X + this.CurvePositionAt(1).X / CatchPlayfield.BASE_WIDTH;
|
public double EndTime => StartTime + Duration;
|
||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
|
||||||
|
|
||||||
private readonly SliderPath path = new SliderPath();
|
private readonly SliderPath path = new SliderPath();
|
||||||
|
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 165 B |
Binary file not shown.
After Width: | Height: | Size: 899 B |
@ -156,7 +156,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
|
|
||||||
foreach (var obj in content.OfType<DrawableHitObject>())
|
foreach (var obj in content.OfType<DrawableHitObject>())
|
||||||
{
|
{
|
||||||
if (!(obj.HitObject is IHasEndTime endTime))
|
if (!(obj.HitObject is IHasDuration endTime))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
foreach (var nested in obj.NestedHitObjects)
|
foreach (var nested in obj.NestedHitObjects)
|
||||||
|
@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float percentSliderOrSpinner = (float)beatmap.HitObjects.Count(h => h is IHasEndTime) / beatmap.HitObjects.Count;
|
float percentSliderOrSpinner = (float)beatmap.HitObjects.Count(h => h is IHasDuration) / 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)
|
||||||
@ -175,7 +175,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IHasEndTime endTimeData:
|
case IHasDuration endTimeData:
|
||||||
{
|
{
|
||||||
conversion = new EndTimeObjectPatternGenerator(Random, original, beatmap, originalBeatmap);
|
conversion = new EndTimeObjectPatternGenerator(Random, original, beatmap, originalBeatmap);
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
|
|
||||||
var pattern = new Pattern();
|
var pattern = new Pattern();
|
||||||
|
|
||||||
if (HitObject is IHasEndTime endTimeData)
|
if (HitObject is IHasDuration endTimeData)
|
||||||
{
|
{
|
||||||
pattern.Add(new HoldNote
|
pattern.Add(new HoldNote
|
||||||
{
|
{
|
||||||
|
@ -474,7 +474,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private IList<HitSampleInfo> sampleInfoListAt(double time)
|
private IList<HitSampleInfo> sampleInfoListAt(double time)
|
||||||
{
|
{
|
||||||
if (!(HitObject is IHasCurve curveData))
|
if (!(HitObject is IHasPathWithRepeats curveData))
|
||||||
return HitObject.Samples;
|
return HitObject.Samples;
|
||||||
|
|
||||||
double segmentTime = (EndTime - HitObject.StartTime) / spanCount;
|
double segmentTime = (EndTime - HitObject.StartTime) / spanCount;
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, IBeatmap originalBeatmap)
|
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, IBeatmap originalBeatmap)
|
||||||
: base(random, hitObject, beatmap, new Pattern(), originalBeatmap)
|
: base(random, hitObject, beatmap, new Pattern(), originalBeatmap)
|
||||||
{
|
{
|
||||||
endTime = (HitObject as IHasEndTime)?.EndTime ?? 0;
|
endTime = (HitObject as IHasDuration)?.EndTime ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<Pattern> Generate()
|
public override IEnumerable<Pattern> Generate()
|
||||||
|
@ -13,6 +13,7 @@ using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
|||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
@ -88,7 +89,8 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
return drawableRuleset;
|
return drawableRuleset;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ComposeBlueprintContainer CreateBlueprintContainer() => new ManiaBlueprintContainer(drawableRuleset.Playfield.AllHitObjects);
|
protected override ComposeBlueprintContainer CreateBlueprintContainer(IEnumerable<DrawableHitObject> hitObjects)
|
||||||
|
=> new ManiaBlueprintContainer(hitObjects);
|
||||||
|
|
||||||
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[]
|
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[]
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a hit object which requires pressing, holding, and releasing a key.
|
/// Represents a hit object which requires pressing, holding, and releasing a key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class HoldNote : ManiaHitObject, IHasEndTime
|
public class HoldNote : ManiaHitObject, IHasDuration
|
||||||
{
|
{
|
||||||
public double EndTime
|
public double EndTime
|
||||||
{
|
{
|
||||||
|
@ -52,10 +52,10 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
|||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (leftSprite?.Height > 0)
|
if (leftSprite?.Height > 0)
|
||||||
leftSprite.Scale = new Vector2(DrawHeight / leftSprite.Height);
|
leftSprite.Scale = new Vector2(1, DrawHeight / leftSprite.Height);
|
||||||
|
|
||||||
if (rightSprite?.Height > 0)
|
if (rightSprite?.Height > 0)
|
||||||
rightSprite.Scale = new Vector2(DrawHeight / rightSprite.Height);
|
rightSprite.Scale = new Vector2(1, DrawHeight / rightSprite.Height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
|
|
||||||
switch (original)
|
switch (original)
|
||||||
{
|
{
|
||||||
case IHasCurve curveData:
|
case IHasPathWithRepeats curveData:
|
||||||
return new Slider
|
return new Slider
|
||||||
{
|
{
|
||||||
StartTime = original.StartTime,
|
StartTime = original.StartTime,
|
||||||
@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
TickDistanceMultiplier = beatmap.BeatmapInfo.BeatmapVersion < 8 ? 1f / beatmap.ControlPointInfo.DifficultyPointAt(original.StartTime).SpeedMultiplier : 1
|
TickDistanceMultiplier = beatmap.BeatmapInfo.BeatmapVersion < 8 ? 1f / beatmap.ControlPointInfo.DifficultyPointAt(original.StartTime).SpeedMultiplier : 1
|
||||||
}.Yield();
|
}.Yield();
|
||||||
|
|
||||||
case IHasEndTime endTimeData:
|
case IHasDuration endTimeData:
|
||||||
return new Spinner
|
return new Spinner
|
||||||
{
|
{
|
||||||
StartTime = original.StartTime,
|
StartTime = original.StartTime,
|
||||||
|
@ -13,6 +13,7 @@ using osu.Game.Rulesets.Edit;
|
|||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
@ -46,7 +47,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
EditorBeatmap.PlacementObject.ValueChanged += _ => updateDistanceSnapGrid();
|
EditorBeatmap.PlacementObject.ValueChanged += _ => updateDistanceSnapGrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ComposeBlueprintContainer CreateBlueprintContainer() => new OsuBlueprintContainer(HitObjects);
|
protected override ComposeBlueprintContainer CreateBlueprintContainer(IEnumerable<DrawableHitObject> hitObjects)
|
||||||
|
=> new OsuBlueprintContainer(hitObjects);
|
||||||
|
|
||||||
private DistanceSnapGrid distanceSnapGrid;
|
private DistanceSnapGrid distanceSnapGrid;
|
||||||
private Container distanceSnapGridContainer;
|
private Container distanceSnapGridContainer;
|
||||||
|
@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// already hit or beyond the hittable end time.
|
// already hit or beyond the hittable end time.
|
||||||
if (h.IsHit || (h.HitObject is IHasEndTime hasEnd && time > hasEnd.EndTime))
|
if (h.IsHit || (h.HitObject is IHasDuration hasEnd && time > hasEnd.EndTime))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
switch (h)
|
switch (h)
|
||||||
|
@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Keep wiggling sliders and spinners for their duration
|
// Keep wiggling sliders and spinners for their duration
|
||||||
if (!(osuObject is IHasEndTime endTime))
|
if (!(osuObject is IHasDuration endTime))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
amountWiggles = (int)(endTime.Duration / wiggle_duration);
|
amountWiggles = (int)(endTime.Duration / wiggle_duration);
|
||||||
|
@ -17,16 +17,16 @@ using osu.Game.Rulesets.Scoring;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
public class Slider : OsuHitObject, IHasCurve
|
public class Slider : OsuHitObject, IHasPathWithRepeats
|
||||||
{
|
{
|
||||||
public double EndTime
|
public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity;
|
||||||
|
|
||||||
|
public double Duration
|
||||||
{
|
{
|
||||||
get => StartTime + this.SpanCount() * Path.Distance / Velocity;
|
get => EndTime - StartTime;
|
||||||
set => throw new System.NotSupportedException($"Adjust via {nameof(RepeatCount)} instead"); // can be implemented if/when needed.
|
set => throw new System.NotSupportedException($"Adjust via {nameof(RepeatCount)} instead"); // can be implemented if/when needed.
|
||||||
}
|
}
|
||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
|
||||||
|
|
||||||
private readonly Cached<Vector2> endPositionCache = new Cached<Vector2>();
|
private readonly Cached<Vector2> endPositionCache = new Cached<Vector2>();
|
||||||
|
|
||||||
public override Vector2 EndPosition => endPositionCache.IsValid ? endPositionCache.Value : endPositionCache.Value = Position + this.CurvePositionAt(1);
|
public override Vector2 EndPosition => endPositionCache.IsValid ? endPositionCache.Value : endPositionCache.Value = Position + this.CurvePositionAt(1);
|
||||||
|
@ -11,7 +11,7 @@ using osu.Game.Rulesets.Scoring;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
public class Spinner : OsuHitObject, IHasEndTime
|
public class Spinner : OsuHitObject, IHasDuration
|
||||||
{
|
{
|
||||||
public double EndTime
|
public double EndTime
|
||||||
{
|
{
|
||||||
|
@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
|
|
||||||
if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength)
|
if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength)
|
||||||
{
|
{
|
||||||
List<IList<HitSampleInfo>> allSamples = obj is IHasCurve curveData ? curveData.NodeSamples : new List<IList<HitSampleInfo>>(new[] { samples });
|
List<IList<HitSampleInfo>> allSamples = obj is IHasPathWithRepeats curveData ? curveData.NodeSamples : new List<IList<HitSampleInfo>>(new[] { samples });
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IHasEndTime endTimeData:
|
case IHasDuration endTimeData:
|
||||||
{
|
{
|
||||||
double hitMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 3, 5, 7.5) * swell_hit_multiplier;
|
double hitMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 3, 5, 7.5) * swell_hit_multiplier;
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
case ArmedState.Miss:
|
case ArmedState.Miss:
|
||||||
case ArmedState.Hit:
|
case ArmedState.Hit:
|
||||||
using (BeginAbsoluteSequence(Time.Current, true))
|
using (BeginDelayedSequence(HitObject.Duration, true))
|
||||||
{
|
{
|
||||||
this.FadeOut(transition_duration, Easing.Out);
|
this.FadeOut(transition_duration, Easing.Out);
|
||||||
bodyContainer.ScaleTo(1.4f, transition_duration);
|
bodyContainer.ScaleTo(1.4f, transition_duration);
|
||||||
|
@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using osu.Game.Audio;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
@ -17,7 +15,7 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects
|
namespace osu.Game.Rulesets.Taiko.Objects
|
||||||
{
|
{
|
||||||
public class DrumRoll : TaikoHitObject, IHasCurve
|
public class DrumRoll : TaikoHitObject, IHasPath
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Drum roll distance that results in a duration of 1 speed-adjusted beat length.
|
/// Drum roll distance that results in a duration of 1 speed-adjusted beat length.
|
||||||
@ -115,11 +113,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
|
|
||||||
double IHasDistance.Distance => Duration * Velocity;
|
double IHasDistance.Distance => Duration * Velocity;
|
||||||
|
|
||||||
int IHasRepeats.RepeatCount { get => 0; set { } }
|
SliderPath IHasPath.Path
|
||||||
|
|
||||||
List<IList<HitSampleInfo>> IHasRepeats.NodeSamples => new List<IList<HitSampleInfo>>();
|
|
||||||
|
|
||||||
SliderPath IHasCurve.Path
|
|
||||||
=> new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(1) }, ((IHasDistance)this).Distance / TaikoBeatmapConverter.LEGACY_VELOCITY_MULTIPLIER);
|
=> new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(1) }, ((IHasDistance)this).Distance / TaikoBeatmapConverter.LEGACY_VELOCITY_MULTIPLIER);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -10,7 +10,7 @@ using osu.Game.Rulesets.Taiko.Judgements;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects
|
namespace osu.Game.Rulesets.Taiko.Objects
|
||||||
{
|
{
|
||||||
public class Swell : TaikoHitObject, IHasEndTime
|
public class Swell : TaikoHitObject, IHasDuration
|
||||||
{
|
{
|
||||||
public double EndTime
|
public double EndTime
|
||||||
{
|
{
|
||||||
|
@ -365,7 +365,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
var hitObjects = decoder.Decode(stream).HitObjects;
|
var hitObjects = decoder.Decode(stream).HitObjects;
|
||||||
|
|
||||||
var curveData = hitObjects[0] as IHasCurve;
|
var curveData = hitObjects[0] as IHasPathWithRepeats;
|
||||||
var positionData = hitObjects[0] as IHasPosition;
|
var positionData = hitObjects[0] as IHasPosition;
|
||||||
|
|
||||||
Assert.IsNotNull(positionData);
|
Assert.IsNotNull(positionData);
|
||||||
|
@ -95,7 +95,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
var beatmap = decodeAsJson(normal);
|
var beatmap = decodeAsJson(normal);
|
||||||
|
|
||||||
var curveData = beatmap.HitObjects[0] as IHasCurve;
|
var curveData = beatmap.HitObjects[0] as IHasPathWithRepeats;
|
||||||
var positionData = beatmap.HitObjects[0] as IHasPosition;
|
var positionData = beatmap.HitObjects[0] as IHasPosition;
|
||||||
|
|
||||||
Assert.IsNotNull(positionData);
|
Assert.IsNotNull(positionData);
|
||||||
|
@ -281,7 +281,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
yield return new TestHitObject
|
yield return new TestHitObject
|
||||||
{
|
{
|
||||||
StartTime = original.StartTime,
|
StartTime = original.StartTime,
|
||||||
EndTime = (original as IHasEndTime)?.EndTime ?? (original.StartTime + 100)
|
Duration = (original as IHasDuration)?.Duration ?? 100
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,11 +290,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
#region HitObject
|
#region HitObject
|
||||||
|
|
||||||
private class TestHitObject : ConvertHitObject, IHasEndTime
|
private class TestHitObject : ConvertHitObject, IHasDuration
|
||||||
{
|
{
|
||||||
public double EndTime { get; set; }
|
public double EndTime => StartTime + Duration;
|
||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
public double Duration { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DrawableTestHitObject : DrawableHitObject<TestHitObject>
|
private class DrawableTestHitObject : DrawableHitObject<TestHitObject>
|
||||||
|
@ -233,14 +233,14 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
writer.Write(FormattableString.Invariant($"{(int)getObjectType(hitObject)},"));
|
writer.Write(FormattableString.Invariant($"{(int)getObjectType(hitObject)},"));
|
||||||
writer.Write(FormattableString.Invariant($"{(int)toLegacyHitSoundType(hitObject.Samples)},"));
|
writer.Write(FormattableString.Invariant($"{(int)toLegacyHitSoundType(hitObject.Samples)},"));
|
||||||
|
|
||||||
if (hitObject is IHasCurve curveData)
|
if (hitObject is IHasPath path)
|
||||||
{
|
{
|
||||||
addCurveData(writer, curveData, position);
|
addPathData(writer, path, position);
|
||||||
writer.Write(getSampleBank(hitObject.Samples, zeroBanks: true));
|
writer.Write(getSampleBank(hitObject.Samples, zeroBanks: true));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (hitObject is IHasEndTime)
|
if (hitObject is IHasDuration)
|
||||||
addEndTimeData(writer, hitObject);
|
addEndTimeData(writer, hitObject);
|
||||||
|
|
||||||
writer.Write(getSampleBank(hitObject.Samples));
|
writer.Write(getSampleBank(hitObject.Samples));
|
||||||
@ -263,11 +263,11 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
switch (hitObject)
|
switch (hitObject)
|
||||||
{
|
{
|
||||||
case IHasCurve _:
|
case IHasPath _:
|
||||||
type |= LegacyHitObjectType.Slider;
|
type |= LegacyHitObjectType.Slider;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IHasEndTime _:
|
case IHasDuration _:
|
||||||
if (beatmap.BeatmapInfo.RulesetID == 3)
|
if (beatmap.BeatmapInfo.RulesetID == 3)
|
||||||
type |= LegacyHitObjectType.Hold;
|
type |= LegacyHitObjectType.Hold;
|
||||||
else
|
else
|
||||||
@ -282,13 +282,13 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCurveData(TextWriter writer, IHasCurve curveData, Vector2 position)
|
private void addPathData(TextWriter writer, IHasPath pathData, Vector2 position)
|
||||||
{
|
{
|
||||||
PathType? lastType = null;
|
PathType? lastType = null;
|
||||||
|
|
||||||
for (int i = 0; i < curveData.Path.ControlPoints.Count; i++)
|
for (int i = 0; i < pathData.Path.ControlPoints.Count; i++)
|
||||||
{
|
{
|
||||||
PathControlPoint point = curveData.Path.ControlPoints[i];
|
PathControlPoint point = pathData.Path.ControlPoints[i];
|
||||||
|
|
||||||
if (point.Type.Value != null)
|
if (point.Type.Value != null)
|
||||||
{
|
{
|
||||||
@ -325,13 +325,17 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
if (i != 0)
|
if (i != 0)
|
||||||
{
|
{
|
||||||
writer.Write(FormattableString.Invariant($"{position.X + point.Position.Value.X}:{position.Y + point.Position.Value.Y}"));
|
writer.Write(FormattableString.Invariant($"{position.X + point.Position.Value.X}:{position.Y + point.Position.Value.Y}"));
|
||||||
writer.Write(i != curveData.Path.ControlPoints.Count - 1 ? "|" : ",");
|
writer.Write(i != pathData.Path.ControlPoints.Count - 1 ? "|" : ",");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.Write(FormattableString.Invariant($"{curveData.RepeatCount + 1},"));
|
var curveData = pathData as IHasPathWithRepeats;
|
||||||
writer.Write(FormattableString.Invariant($"{curveData.Path.Distance},"));
|
|
||||||
|
|
||||||
|
writer.Write(FormattableString.Invariant($"{(curveData?.RepeatCount ?? 0) + 1},"));
|
||||||
|
writer.Write(FormattableString.Invariant($"{pathData.Path.Distance},"));
|
||||||
|
|
||||||
|
if (curveData != null)
|
||||||
|
{
|
||||||
for (int i = 0; i < curveData.NodeSamples.Count; i++)
|
for (int i = 0; i < curveData.NodeSamples.Count; i++)
|
||||||
{
|
{
|
||||||
writer.Write(FormattableString.Invariant($"{(int)toLegacyHitSoundType(curveData.NodeSamples[i])}"));
|
writer.Write(FormattableString.Invariant($"{(int)toLegacyHitSoundType(curveData.NodeSamples[i])}"));
|
||||||
@ -344,10 +348,11 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
writer.Write(i != curveData.NodeSamples.Count - 1 ? "|" : ",");
|
writer.Write(i != curveData.NodeSamples.Count - 1 ? "|" : ",");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addEndTimeData(TextWriter writer, HitObject hitObject)
|
private void addEndTimeData(TextWriter writer, HitObject hitObject)
|
||||||
{
|
{
|
||||||
var endTimeData = (IHasEndTime)hitObject;
|
var endTimeData = (IHasDuration)hitObject;
|
||||||
var type = getObjectType(hitObject);
|
var type = getObjectType(hitObject);
|
||||||
|
|
||||||
char suffix = ',';
|
char suffix = ',';
|
||||||
|
@ -63,7 +63,7 @@ namespace osu.Game.Beatmaps
|
|||||||
length = emptyLength;
|
length = emptyLength;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IHasEndTime endTime:
|
case IHasDuration endTime:
|
||||||
length = endTime.EndTime + excess_length;
|
length = endTime.EndTime + excess_length;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -48,8 +48,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
|
|
||||||
protected ComposeBlueprintContainer BlueprintContainer { get; private set; }
|
protected ComposeBlueprintContainer BlueprintContainer { get; private set; }
|
||||||
|
|
||||||
public override Playfield Playfield => drawableRulesetWrapper.Playfield;
|
|
||||||
|
|
||||||
private DrawableEditRulesetWrapper<TObject> drawableRulesetWrapper;
|
private DrawableEditRulesetWrapper<TObject> drawableRulesetWrapper;
|
||||||
|
|
||||||
protected readonly Container LayerBelowRuleset = new Container { RelativeSizeAxes = Axes.Both };
|
protected readonly Container LayerBelowRuleset = new Container { RelativeSizeAxes = Axes.Both };
|
||||||
@ -61,7 +59,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
protected HitObjectComposer(Ruleset ruleset)
|
protected HitObjectComposer(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
Ruleset = ruleset;
|
Ruleset = ruleset;
|
||||||
RelativeSizeAxes = Axes.Both;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -116,7 +113,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
drawableRulesetWrapper,
|
drawableRulesetWrapper,
|
||||||
// layers above playfield
|
// layers above playfield
|
||||||
drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer()
|
drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer()
|
||||||
.WithChild(BlueprintContainer = CreateBlueprintContainer())
|
.WithChild(BlueprintContainer = CreateBlueprintContainer(HitObjects))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -137,6 +134,51 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
EditorBeatmap.SelectedHitObjects.CollectionChanged += selectionChanged;
|
EditorBeatmap.SelectedHitObjects.CollectionChanged += selectionChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
inputManager = GetContainingInputManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Playfield Playfield => drawableRulesetWrapper.Playfield;
|
||||||
|
|
||||||
|
public override IEnumerable<DrawableHitObject> HitObjects => drawableRulesetWrapper.Playfield.AllHitObjects;
|
||||||
|
|
||||||
|
public override bool CursorInPlacementArea => drawableRulesetWrapper.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines all available composition tools, listed on the left side of the editor screen as button controls.
|
||||||
|
/// This should usually define one tool for each <see cref="HitObject"/> type used in the target ruleset.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// A "select" tool is automatically added as the first tool.
|
||||||
|
/// </remarks>
|
||||||
|
protected abstract IReadOnlyList<HitObjectCompositionTool> CompositionTools { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Construct a relevant blueprint container. This will manage hitobject selection/placement input handling and display logic.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObjects">A live collection of all <see cref="DrawableHitObject"/>s in the editor beatmap.</param>
|
||||||
|
protected virtual ComposeBlueprintContainer CreateBlueprintContainer(IEnumerable<DrawableHitObject> hitObjects)
|
||||||
|
=> new ComposeBlueprintContainer(hitObjects);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Construct a drawable ruleset for the provided ruleset.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Can be overridden to add editor-specific logical changes to a <see cref="Ruleset"/>'s standard <see cref="DrawableRuleset{TObject}"/>.
|
||||||
|
/// For example, hit animations or judgement logic may be changed to give a better editor user experience.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="ruleset">The ruleset used to construct its drawable counterpart.</param>
|
||||||
|
/// <param name="beatmap">The loaded beatmap.</param>
|
||||||
|
/// <param name="mods">The mods to be applied.</param>
|
||||||
|
/// <returns>An editor-relevant <see cref="DrawableRuleset{TObject}"/>.</returns>
|
||||||
|
protected virtual DrawableRuleset<TObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
|
||||||
|
=> (DrawableRuleset<TObject>)ruleset.CreateDrawableRulesetWith(beatmap, mods);
|
||||||
|
|
||||||
|
#region Tool selection logic
|
||||||
|
|
||||||
protected override bool OnKeyDown(KeyDownEvent e)
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
{
|
{
|
||||||
if (e.Key >= Key.Number1 && e.Key <= Key.Number9)
|
if (e.Key >= Key.Number1 && e.Key <= Key.Number9)
|
||||||
@ -153,13 +195,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
return base.OnKeyDown(e);
|
return base.OnKeyDown(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
inputManager = GetContainingInputManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void selectionChanged(object sender, NotifyCollectionChangedEventArgs changedArgs)
|
private void selectionChanged(object sender, NotifyCollectionChangedEventArgs changedArgs)
|
||||||
{
|
{
|
||||||
if (EditorBeatmap.SelectedHitObjects.Any())
|
if (EditorBeatmap.SelectedHitObjects.Any())
|
||||||
@ -179,15 +214,9 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
EditorBeatmap.SelectedHitObjects.Clear();
|
EditorBeatmap.SelectedHitObjects.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<DrawableHitObject> HitObjects => drawableRulesetWrapper.Playfield.AllHitObjects;
|
#endregion
|
||||||
|
|
||||||
public override bool CursorInPlacementArea => drawableRulesetWrapper.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position);
|
#region IPlacementHandler
|
||||||
|
|
||||||
protected abstract IReadOnlyList<HitObjectCompositionTool> CompositionTools { get; }
|
|
||||||
|
|
||||||
protected abstract ComposeBlueprintContainer CreateBlueprintContainer();
|
|
||||||
|
|
||||||
protected abstract DrawableRuleset<TObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null);
|
|
||||||
|
|
||||||
public void BeginPlacement(HitObject hitObject)
|
public void BeginPlacement(HitObject hitObject)
|
||||||
{
|
{
|
||||||
@ -209,6 +238,17 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
|
|
||||||
public void Delete(HitObject hitObject) => EditorBeatmap.Remove(hitObject);
|
public void Delete(HitObject hitObject) => EditorBeatmap.Remove(hitObject);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IPositionSnapProvider
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve the relevant <see cref="Playfield"/> at a specified screen-space position.
|
||||||
|
/// In cases where a ruleset doesn't require custom logic (due to nested playfields, for example)
|
||||||
|
/// this will return the ruleset's main playfield.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="screenSpacePosition">The screen-space position to query.</param>
|
||||||
|
/// <returns>The most relevant <see cref="Playfield"/>.</returns>
|
||||||
protected virtual Playfield PlayfieldAtScreenSpacePosition(Vector2 screenSpacePosition) => drawableRulesetWrapper.Playfield;
|
protected virtual Playfield PlayfieldAtScreenSpacePosition(Vector2 screenSpacePosition) => drawableRulesetWrapper.Playfield;
|
||||||
|
|
||||||
public override SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition)
|
public override SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition)
|
||||||
@ -257,8 +297,14 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
|
|
||||||
return DurationToDistance(referenceTime, snappedEndTime - referenceTime);
|
return DurationToDistance(referenceTime, snappedEndTime - referenceTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A non-generic definition of a HitObject composer class.
|
||||||
|
/// Generally used to access certain methods without requiring a generic type for <see cref="HitObjectComposer{T}" />.
|
||||||
|
/// </summary>
|
||||||
[Cached(typeof(HitObjectComposer))]
|
[Cached(typeof(HitObjectComposer))]
|
||||||
[Cached(typeof(IPositionSnapProvider))]
|
[Cached(typeof(IPositionSnapProvider))]
|
||||||
public abstract class HitObjectComposer : CompositeDrawable, IPositionSnapProvider
|
public abstract class HitObjectComposer : CompositeDrawable, IPositionSnapProvider
|
||||||
@ -268,10 +314,13 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The target ruleset's playfield.
|
||||||
|
/// </summary>
|
||||||
public abstract Playfield Playfield { get; }
|
public abstract Playfield Playfield { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All the <see cref="DrawableHitObject"/>s.
|
/// All <see cref="DrawableHitObject"/>s in currently loaded beatmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract IEnumerable<DrawableHitObject> HitObjects { get; }
|
public abstract IEnumerable<DrawableHitObject> HitObjects { get; }
|
||||||
|
|
||||||
@ -280,6 +329,8 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract bool CursorInPlacementArea { get; }
|
public abstract bool CursorInPlacementArea { get; }
|
||||||
|
|
||||||
|
#region IPositionSnapProvider
|
||||||
|
|
||||||
public abstract SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition);
|
public abstract SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition);
|
||||||
|
|
||||||
public abstract float GetBeatSnapDistanceAt(double referenceTime);
|
public abstract float GetBeatSnapDistanceAt(double referenceTime);
|
||||||
@ -291,5 +342,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
public abstract double GetSnappedDurationFromDistance(double referenceTime, float distance);
|
public abstract double GetSnappedDurationFromDistance(double referenceTime, float distance);
|
||||||
|
|
||||||
public abstract float GetSnappedDistanceFromDistance(double referenceTime, float distance);
|
public abstract float GetSnappedDistanceFromDistance(double referenceTime, float distance);
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,10 +175,10 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
/// Returns the end time of this object.
|
/// Returns the end time of this object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This returns the <see cref="IHasEndTime.EndTime"/> where available, falling back to <see cref="HitObject.StartTime"/> otherwise.
|
/// This returns the <see cref="IHasDuration.EndTime"/> where available, falling back to <see cref="HitObject.StartTime"/> otherwise.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="hitObject">The object.</param>
|
/// <param name="hitObject">The object.</param>
|
||||||
/// <returns>The end time of this object.</returns>
|
/// <returns>The end time of this object.</returns>
|
||||||
public static double GetEndTime(this HitObject hitObject) => (hitObject as IHasEndTime)?.EndTime ?? hitObject.StartTime;
|
public static double GetEndTime(this HitObject hitObject) => (hitObject as IHasDuration)?.EndTime ?? hitObject.StartTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double endTime)
|
protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double duration)
|
||||||
{
|
{
|
||||||
// Convert spinners don't create the new combo themselves, but force the next non-spinner hitobject to create a new combo
|
// Convert spinners don't create the new combo themselves, but force the next non-spinner hitobject to create a new combo
|
||||||
// Their combo offset is still added to that next hitobject's combo index
|
// Their combo offset is still added to that next hitobject's combo index
|
||||||
@ -65,11 +65,11 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
|||||||
|
|
||||||
return new ConvertSpinner
|
return new ConvertSpinner
|
||||||
{
|
{
|
||||||
EndTime = endTime
|
Duration = duration
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateHold(Vector2 position, bool newCombo, int comboOffset, double endTime)
|
protected override HitObject CreateHold(Vector2 position, bool newCombo, int comboOffset, double duration)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,11 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Legacy osu!catch Spinner-type, used for parsing Beatmaps.
|
/// Legacy osu!catch Spinner-type, used for parsing Beatmaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasXPosition, IHasCombo
|
internal sealed class ConvertSpinner : ConvertHitObject, IHasDuration, IHasXPosition, IHasCombo
|
||||||
{
|
{
|
||||||
public double EndTime { get; set; }
|
public double EndTime => StartTime + Duration;
|
||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
public double Duration { get; set; }
|
||||||
|
|
||||||
public float X => 256; // Required for CatchBeatmapConverter
|
public float X => 256; // Required for CatchBeatmapConverter
|
||||||
|
|
||||||
|
@ -189,9 +189,9 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
}
|
}
|
||||||
else if (type.HasFlag(LegacyHitObjectType.Spinner))
|
else if (type.HasFlag(LegacyHitObjectType.Spinner))
|
||||||
{
|
{
|
||||||
double endTime = Math.Max(startTime, Parsing.ParseDouble(split[5]) + Offset);
|
double duration = Math.Max(0, Parsing.ParseDouble(split[5]) + Offset - startTime);
|
||||||
|
|
||||||
result = CreateSpinner(new Vector2(512, 384) / 2, combo, comboOffset, endTime);
|
result = CreateSpinner(new Vector2(512, 384) / 2, combo, comboOffset, duration);
|
||||||
|
|
||||||
if (split.Length > 6)
|
if (split.Length > 6)
|
||||||
readCustomSampleBanks(split[6], bankInfo);
|
readCustomSampleBanks(split[6], bankInfo);
|
||||||
@ -209,7 +209,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
readCustomSampleBanks(string.Join(":", ss.Skip(1)), bankInfo);
|
readCustomSampleBanks(string.Join(":", ss.Skip(1)), bankInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = CreateHold(pos, combo, comboOffset, endTime + Offset);
|
result = CreateHold(pos, combo, comboOffset, endTime + Offset - startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == null)
|
if (result == null)
|
||||||
@ -321,9 +321,9 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
/// <param name="position">The position of the hit object.</param>
|
/// <param name="position">The position of the hit object.</param>
|
||||||
/// <param name="newCombo">Whether the hit object creates a new combo.</param>
|
/// <param name="newCombo">Whether the hit object creates a new combo.</param>
|
||||||
/// <param name="comboOffset">When starting a new combo, the offset of the new combo relative to the current one.</param>
|
/// <param name="comboOffset">When starting a new combo, the offset of the new combo relative to the current one.</param>
|
||||||
/// <param name="endTime">The spinner end time.</param>
|
/// <param name="duration">The spinner duration.</param>
|
||||||
/// <returns>The hit object.</returns>
|
/// <returns>The hit object.</returns>
|
||||||
protected abstract HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double endTime);
|
protected abstract HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double duration);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a legacy Hold-type hit object.
|
/// Creates a legacy Hold-type hit object.
|
||||||
@ -331,8 +331,8 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
/// <param name="position">The position of the hit object.</param>
|
/// <param name="position">The position of the hit object.</param>
|
||||||
/// <param name="newCombo">Whether the hit object creates a new combo.</param>
|
/// <param name="newCombo">Whether the hit object creates a new combo.</param>
|
||||||
/// <param name="comboOffset">When starting a new combo, the offset of the new combo relative to the current one.</param>
|
/// <param name="comboOffset">When starting a new combo, the offset of the new combo relative to the current one.</param>
|
||||||
/// <param name="endTime">The hold end time.</param>
|
/// <param name="duration">The hold duration.</param>
|
||||||
protected abstract HitObject CreateHold(Vector2 position, bool newCombo, int comboOffset, double endTime);
|
protected abstract HitObject CreateHold(Vector2 position, bool newCombo, int comboOffset, double duration);
|
||||||
|
|
||||||
private List<HitSampleInfo> convertSoundType(LegacyHitSoundType type, SampleBankInfo bankInfo)
|
private List<HitSampleInfo> convertSoundType(LegacyHitSoundType type, SampleBankInfo bankInfo)
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,10 @@ using osu.Game.Beatmaps.ControlPoints;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Legacy
|
namespace osu.Game.Rulesets.Objects.Legacy
|
||||||
{
|
{
|
||||||
internal abstract class ConvertSlider : ConvertHitObject, IHasCurve, IHasLegacyLastTickOffset
|
internal abstract class ConvertSlider : ConvertHitObject, IHasPathWithRepeats, IHasLegacyLastTickOffset,
|
||||||
|
#pragma warning disable 618
|
||||||
|
IHasCurve
|
||||||
|
#pragma warning restore 618
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Scoring distance with a speed-adjusted beat length of 1 second.
|
/// Scoring distance with a speed-adjusted beat length of 1 second.
|
||||||
@ -26,13 +29,13 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
public List<IList<HitSampleInfo>> NodeSamples { get; set; }
|
public List<IList<HitSampleInfo>> NodeSamples { get; set; }
|
||||||
public int RepeatCount { get; set; }
|
public int RepeatCount { get; set; }
|
||||||
|
|
||||||
public double EndTime
|
public double Duration
|
||||||
{
|
{
|
||||||
get => StartTime + this.SpanCount() * Distance / Velocity;
|
get => this.SpanCount() * Distance / Velocity;
|
||||||
set => throw new System.NotSupportedException($"Adjust via {nameof(RepeatCount)} instead"); // can be implemented if/when needed.
|
set => throw new System.NotSupportedException($"Adjust via {nameof(RepeatCount)} instead"); // can be implemented if/when needed.
|
||||||
}
|
}
|
||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
public double EndTime => StartTime + Duration;
|
||||||
|
|
||||||
public double Velocity = 1;
|
public double Velocity = 1;
|
||||||
|
|
||||||
|
@ -37,21 +37,21 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double endTime)
|
protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double duration)
|
||||||
{
|
{
|
||||||
return new ConvertSpinner
|
return new ConvertSpinner
|
||||||
{
|
{
|
||||||
X = position.X,
|
X = position.X,
|
||||||
EndTime = endTime
|
Duration = duration
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateHold(Vector2 position, bool newCombo, int comboOffset, double endTime)
|
protected override HitObject CreateHold(Vector2 position, bool newCombo, int comboOffset, double duration)
|
||||||
{
|
{
|
||||||
return new ConvertHold
|
return new ConvertHold
|
||||||
{
|
{
|
||||||
X = position.X,
|
X = position.X,
|
||||||
EndTime = endTime
|
Duration = duration
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,12 @@ using osu.Game.Rulesets.Objects.Types;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
||||||
{
|
{
|
||||||
internal sealed class ConvertHold : ConvertHitObject, IHasXPosition, IHasEndTime
|
internal sealed class ConvertHold : ConvertHitObject, IHasXPosition, IHasDuration
|
||||||
{
|
{
|
||||||
public float X { get; set; }
|
public float X { get; set; }
|
||||||
|
|
||||||
public double EndTime { get; set; }
|
public double Duration { get; set; }
|
||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
public double EndTime => StartTime + Duration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,11 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Legacy osu!mania Spinner-type, used for parsing Beatmaps.
|
/// Legacy osu!mania Spinner-type, used for parsing Beatmaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasXPosition
|
internal sealed class ConvertSpinner : ConvertHitObject, IHasDuration, IHasXPosition
|
||||||
{
|
{
|
||||||
public double EndTime { get; set; }
|
public double Duration { get; set; }
|
||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
public double EndTime => StartTime + Duration;
|
||||||
|
|
||||||
public float X { get; set; }
|
public float X { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double endTime)
|
protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double duration)
|
||||||
{
|
{
|
||||||
// Convert spinners don't create the new combo themselves, but force the next non-spinner hitobject to create a new combo
|
// Convert spinners don't create the new combo themselves, but force the next non-spinner hitobject to create a new combo
|
||||||
// Their combo offset is still added to that next hitobject's combo index
|
// Their combo offset is still added to that next hitobject's combo index
|
||||||
@ -66,11 +66,11 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
return new ConvertSpinner
|
return new ConvertSpinner
|
||||||
{
|
{
|
||||||
Position = position,
|
Position = position,
|
||||||
EndTime = endTime
|
Duration = duration
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateHold(Vector2 position, bool newCombo, int comboOffset, double endTime)
|
protected override HitObject CreateHold(Vector2 position, bool newCombo, int comboOffset, double duration)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,11 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Legacy osu! Spinner-type, used for parsing Beatmaps.
|
/// Legacy osu! Spinner-type, used for parsing Beatmaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasPosition, IHasCombo
|
internal sealed class ConvertSpinner : ConvertHitObject, IHasDuration, IHasPosition, IHasCombo
|
||||||
{
|
{
|
||||||
public double EndTime { get; set; }
|
public double Duration { get; set; }
|
||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
public double EndTime => StartTime + Duration;
|
||||||
|
|
||||||
public Vector2 Position { get; set; }
|
public Vector2 Position { get; set; }
|
||||||
|
|
||||||
|
@ -33,15 +33,15 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double endTime)
|
protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double duration)
|
||||||
{
|
{
|
||||||
return new ConvertSpinner
|
return new ConvertSpinner
|
||||||
{
|
{
|
||||||
EndTime = endTime
|
Duration = duration
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateHold(Vector2 position, bool newCombo, int comboOffset, double endTime)
|
protected override HitObject CreateHold(Vector2 position, bool newCombo, int comboOffset, double duration)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,10 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Legacy osu!taiko Spinner-type, used for parsing Beatmaps.
|
/// Legacy osu!taiko Spinner-type, used for parsing Beatmaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime
|
internal sealed class ConvertSpinner : ConvertHitObject, IHasDuration
|
||||||
{
|
{
|
||||||
public double EndTime { get; set; }
|
public double Duration { get; set; }
|
||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
public double EndTime => StartTime + Duration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Types
|
namespace osu.Game.Rulesets.Objects.Types
|
||||||
{
|
{
|
||||||
/// <summary>
|
[Obsolete("Use IHasPathWithRepeats instead.")] // can be removed 20201126
|
||||||
/// A HitObject that has a curve.
|
|
||||||
/// </summary>
|
|
||||||
public interface IHasCurve : IHasDistance, IHasRepeats
|
public interface IHasCurve : IHasDistance, IHasRepeats
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -16,6 +15,8 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
SliderPath Path { get; }
|
SliderPath Path { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning disable 618
|
||||||
|
[Obsolete("Use IHasPathWithRepeats instead.")] // can be removed 20201126
|
||||||
public static class HasCurveExtensions
|
public static class HasCurveExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -50,4 +51,5 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
public static int SpanAt(this IHasCurve obj, double progress)
|
public static int SpanAt(this IHasCurve obj, double progress)
|
||||||
=> (int)(progress * obj.SpanCount());
|
=> (int)(progress * obj.SpanCount());
|
||||||
}
|
}
|
||||||
|
#pragma warning restore 618
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A HitObject that has a positional length.
|
/// A HitObject that has a positional length.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHasDistance : IHasEndTime
|
public interface IHasDistance : IHasDuration
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The positional length of the HitObject.
|
/// The positional length of the HitObject.
|
||||||
|
34
osu.Game/Rulesets/Objects/Types/IHasDuration.cs
Normal file
34
osu.Game/Rulesets/Objects/Types/IHasDuration.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Objects.Types
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A HitObject that ends at a different time than its start time.
|
||||||
|
/// </summary>
|
||||||
|
#pragma warning disable 618
|
||||||
|
public interface IHasDuration : IHasEndTime
|
||||||
|
#pragma warning restore 618
|
||||||
|
{
|
||||||
|
double IHasEndTime.EndTime
|
||||||
|
{
|
||||||
|
get => EndTime;
|
||||||
|
set => Duration = (Duration - EndTime) + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double IHasEndTime.Duration => Duration;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time at which the HitObject ends.
|
||||||
|
/// </summary>
|
||||||
|
new double EndTime { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The duration of the HitObject.
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
new double Duration { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Types
|
namespace osu.Game.Rulesets.Objects.Types
|
||||||
@ -8,6 +9,7 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A HitObject that ends at a different time than its start time.
|
/// A HitObject that ends at a different time than its start time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("Use IHasDuration instead.")] // can be removed 20201126
|
||||||
public interface IHasEndTime
|
public interface IHasEndTime
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
13
osu.Game/Rulesets/Objects/Types/IHasPath.cs
Normal file
13
osu.Game/Rulesets/Objects/Types/IHasPath.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Objects.Types
|
||||||
|
{
|
||||||
|
public interface IHasPath : IHasDistance
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The curve.
|
||||||
|
/// </summary>
|
||||||
|
SliderPath Path { get; }
|
||||||
|
}
|
||||||
|
}
|
50
osu.Game/Rulesets/Objects/Types/IHasPathWithRepeats.cs
Normal file
50
osu.Game/Rulesets/Objects/Types/IHasPathWithRepeats.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Objects.Types
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A HitObject that has a curve.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once RedundantExtendsListEntry
|
||||||
|
public interface IHasPathWithRepeats : IHasPath, IHasRepeats
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HasPathWithRepeatsExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the position on the curve relative to how much of the <see cref="HitObject"/> has been completed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The curve.</param>
|
||||||
|
/// <param name="progress">[0, 1] where 0 is the start time of the <see cref="HitObject"/> and 1 is the end time of the <see cref="HitObject"/>.</param>
|
||||||
|
/// <returns>The position on the curve.</returns>
|
||||||
|
public static Vector2 CurvePositionAt(this IHasPathWithRepeats obj, double progress)
|
||||||
|
=> obj.Path.PositionAt(obj.ProgressAt(progress));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the progress along the curve relative to how much of the <see cref="HitObject"/> has been completed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The curve.</param>
|
||||||
|
/// <param name="progress">[0, 1] where 0 is the start time of the <see cref="HitObject"/> and 1 is the end time of the <see cref="HitObject"/>.</param>
|
||||||
|
/// <returns>[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</returns>
|
||||||
|
public static double ProgressAt(this IHasPathWithRepeats obj, double progress)
|
||||||
|
{
|
||||||
|
double p = progress * obj.SpanCount() % 1;
|
||||||
|
if (obj.SpanAt(progress) % 2 == 1)
|
||||||
|
p = 1 - p;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines which span of the curve the progress point is on.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The curve.</param>
|
||||||
|
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
||||||
|
/// <returns>[0, SpanCount) where 0 is the first run.</returns>
|
||||||
|
public static int SpanAt(this IHasPathWithRepeats obj, double progress)
|
||||||
|
=> (int)(progress * obj.SpanCount());
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A HitObject that spans some length.
|
/// A HitObject that spans some length.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHasRepeats : IHasEndTime
|
public interface IHasRepeats : IHasDuration
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of times the HitObject repeats.
|
/// The amount of times the HitObject repeats.
|
||||||
|
@ -270,7 +270,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
// Cant use AddOnce() since the delegate is re-constructed every invocation
|
// Cant use AddOnce() since the delegate is re-constructed every invocation
|
||||||
private void computeInitialStateRecursive(DrawableHitObject hitObject) => hitObject.Schedule(() =>
|
private void computeInitialStateRecursive(DrawableHitObject hitObject) => hitObject.Schedule(() =>
|
||||||
{
|
{
|
||||||
if (hitObject.HitObject is IHasEndTime e)
|
if (hitObject.HitObject is IHasDuration e)
|
||||||
{
|
{
|
||||||
switch (direction.Value)
|
switch (direction.Value)
|
||||||
{
|
{
|
||||||
|
@ -72,7 +72,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
|
|
||||||
shadowComponents.Add(circle);
|
shadowComponents.Add(circle);
|
||||||
|
|
||||||
if (hitObject is IHasEndTime)
|
if (hitObject is IHasDuration)
|
||||||
{
|
{
|
||||||
DragBar dragBarUnderlay;
|
DragBar dragBarUnderlay;
|
||||||
Container extensionBar;
|
Container extensionBar;
|
||||||
@ -290,13 +290,13 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
repeatHitObject.RepeatCount = proposedCount;
|
repeatHitObject.RepeatCount = proposedCount;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IHasEndTime endTimeHitObject:
|
case IHasDuration endTimeHitObject:
|
||||||
var snappedTime = Math.Max(hitObject.StartTime, beatSnapProvider.SnapTime(time));
|
var snappedTime = Math.Max(hitObject.StartTime, beatSnapProvider.SnapTime(time));
|
||||||
|
|
||||||
if (endTimeHitObject.EndTime == snappedTime)
|
if (endTimeHitObject.EndTime == snappedTime)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
endTimeHitObject.EndTime = snappedTime;
|
endTimeHitObject.Duration = snappedTime - hitObject.StartTime;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Efnt/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Efnt/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Emp3/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Emp3/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Epng/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Epng/@EntryIndexedValue">True</s:Boolean>
|
||||||
@ -905,14 +905,17 @@ private void load()
|
|||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Catmull/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Catmull/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Drawables/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Drawables/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=gameplay/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=gameplay/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=hitobject/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=hitobjects/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=hitobjects/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=keymods/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=keymods/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kiai/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kiai/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Leaderboard/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Leaderboard/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Leaderboards/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Leaderboards/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Playfield/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Playfield/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=playfields/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=resampler/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=resampler/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=ruleset/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=ruleset/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=rulesets/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=rulesets/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=ruleset_0027s/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Taiko/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Taiko/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unranked/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unranked/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
|
Loading…
Reference in New Issue
Block a user