mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 04:02:57 +08:00
Merge branch 'master' into taiko-playfield-background-skinning
This commit is contained in:
commit
b3175f9dfa
@ -41,8 +41,6 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
AccentColour = Color4.OrangeRed,
|
||||
Clock = new FramedClock(new StopwatchClock()), // No scroll
|
||||
});
|
||||
|
||||
AddStep("change direction", () => ((ScrollingTestContainer)HitObjectContainer).Flip());
|
||||
}
|
||||
|
||||
protected override Container CreateHitObjectContainer() => new ScrollingTestContainer(ScrollingDirection.Down) { RelativeSizeAxes = Axes.Both };
|
||||
|
@ -1,17 +1,59 @@
|
||||
// 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 System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
public class TestSceneNotePlacementBlueprint : ManiaPlacementBlueprintTestScene
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
this.ChildrenOfType<HitObjectContainer>().ForEach(c => c.Clear());
|
||||
|
||||
ResetPlacement();
|
||||
|
||||
((ScrollingTestContainer)HitObjectContainer).Direction = ScrollingDirection.Down;
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestPlaceBeforeCurrentTimeDownwards()
|
||||
{
|
||||
AddStep("move mouse before current time", () => InputManager.MoveMouseTo(this.ChildrenOfType<Column>().Single().ScreenSpaceDrawQuad.BottomLeft - new Vector2(0, 10)));
|
||||
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
AddAssert("note start time < 0", () => getNote().StartTime < 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPlaceAfterCurrentTimeDownwards()
|
||||
{
|
||||
AddStep("move mouse after current time", () => InputManager.MoveMouseTo(this.ChildrenOfType<Column>().Single()));
|
||||
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
AddAssert("note start time > 0", () => getNote().StartTime > 0);
|
||||
}
|
||||
|
||||
private Note getNote() => this.ChildrenOfType<DrawableNote>().FirstOrDefault()?.HitObject;
|
||||
|
||||
protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableNote((Note)hitObject);
|
||||
protected override PlacementBlueprint CreateBlueprint() => new NotePlacementBlueprint();
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ using osu.Game.Rulesets.Mania.Beatmaps.Patterns;
|
||||
using osu.Game.Rulesets.Mania.MathUtils;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy;
|
||||
using osuTK;
|
||||
using osu.Game.Audio;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
{
|
||||
@ -67,7 +66,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanConvert() => Beatmap.HitObjects.All(h => h is IHasXPosition || h is ManiaHitObject);
|
||||
public override bool CanConvert() => Beatmap.HitObjects.All(h => h is IHasXPosition);
|
||||
|
||||
protected override Beatmap<ManiaHitObject> ConvertBeatmap(IBeatmap original)
|
||||
{
|
||||
@ -239,8 +238,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
StartTime = HitObject.StartTime,
|
||||
Duration = endTimeData.Duration,
|
||||
Column = column,
|
||||
Head = { Samples = sampleInfoListAt(HitObject.StartTime) },
|
||||
Tail = { Samples = sampleInfoListAt(endTimeData.EndTime) },
|
||||
Samples = HitObject.Samples,
|
||||
NodeSamples = (HitObject as IHasRepeats)?.NodeSamples
|
||||
});
|
||||
}
|
||||
else if (HitObject is IHasXPosition)
|
||||
@ -255,22 +254,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the sample info list at a point in time.
|
||||
/// </summary>
|
||||
/// <param name="time">The time to retrieve the sample info list from.</param>
|
||||
/// <returns></returns>
|
||||
private IList<HitSampleInfo> sampleInfoListAt(double time)
|
||||
{
|
||||
if (!(HitObject is IHasCurve curveData))
|
||||
return HitObject.Samples;
|
||||
|
||||
double segmentTime = (curveData.EndTime - HitObject.StartTime) / curveData.SpanCount();
|
||||
|
||||
int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime);
|
||||
return curveData.NodeSamples[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -505,16 +505,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
}
|
||||
else
|
||||
{
|
||||
var holdNote = new HoldNote
|
||||
newObject = new HoldNote
|
||||
{
|
||||
StartTime = startTime,
|
||||
Column = column,
|
||||
Duration = endTime - startTime,
|
||||
Head = { Samples = sampleInfoListAt(startTime) },
|
||||
Tail = { Samples = sampleInfoListAt(endTime) }
|
||||
Column = column,
|
||||
Samples = HitObject.Samples,
|
||||
NodeSamples = (HitObject as IHasRepeats)?.NodeSamples
|
||||
};
|
||||
|
||||
newObject = holdNote;
|
||||
}
|
||||
|
||||
pattern.Add(newObject);
|
||||
|
@ -64,21 +64,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
if (holdNote)
|
||||
{
|
||||
var hold = new HoldNote
|
||||
newObject = new HoldNote
|
||||
{
|
||||
StartTime = HitObject.StartTime,
|
||||
Duration = endTime - HitObject.StartTime,
|
||||
Column = column,
|
||||
Duration = endTime - HitObject.StartTime
|
||||
Samples = HitObject.Samples,
|
||||
NodeSamples = (HitObject as IHasRepeats)?.NodeSamples
|
||||
};
|
||||
|
||||
if (hold.Head.Samples == null)
|
||||
hold.Head.Samples = new List<HitSampleInfo>();
|
||||
|
||||
hold.Head.Samples.Add(new HitSampleInfo { Name = HitSampleInfo.HIT_NORMAL });
|
||||
|
||||
hold.Tail.Samples = HitObject.Samples;
|
||||
|
||||
newObject = hold;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osuTK;
|
||||
@ -46,6 +47,12 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
bodyPiece.Height = (bottomPosition - topPosition).Y;
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
base.OnMouseUp(e);
|
||||
EndPlacement(true);
|
||||
}
|
||||
|
||||
private double originalStartTime;
|
||||
|
||||
public override void UpdatePosition(Vector2 screenSpacePosition)
|
||||
|
@ -50,16 +50,10 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
return base.OnMouseDown(e);
|
||||
|
||||
HitObject.Column = Column.Index;
|
||||
BeginPlacement(TimeAt(e.ScreenSpaceMousePosition));
|
||||
BeginPlacement(TimeAt(e.ScreenSpaceMousePosition), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
EndPlacement(true);
|
||||
base.OnMouseUp(e);
|
||||
}
|
||||
|
||||
public override void UpdatePosition(Vector2 screenSpacePosition)
|
||||
{
|
||||
if (!PlacementActive)
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
|
||||
@ -26,5 +27,15 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
Width = SnappedWidth;
|
||||
Position = SnappedMousePosition;
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
base.OnMouseDown(e);
|
||||
|
||||
// Place the note immediately.
|
||||
EndPlacement(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
|
||||
AddRangeInternal(new[]
|
||||
{
|
||||
bodyPiece = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HoldNoteBody, hitObject.Column), _ => new DefaultBodyPiece())
|
||||
bodyPiece = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HoldNoteBody, hitObject.Column), _ => new DefaultBodyPiece
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
})
|
||||
{
|
||||
RelativeSizeAxes = Axes.X
|
||||
},
|
||||
@ -127,6 +130,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
bodyPiece.Anchor = bodyPiece.Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
|
||||
}
|
||||
|
||||
public override void PlaySamples()
|
||||
{
|
||||
// Samples are played by the head/tail notes.
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
@ -34,7 +34,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||
|
||||
public DefaultBodyPiece()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Blending = BlendingParameters.Additive;
|
||||
|
||||
AddLayout(subtractionCache);
|
||||
|
@ -1,6 +1,8 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
@ -28,7 +30,9 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
set
|
||||
{
|
||||
duration = value;
|
||||
Tail.StartTime = EndTime;
|
||||
|
||||
if (Tail != null)
|
||||
Tail.StartTime = EndTime;
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,8 +42,12 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
set
|
||||
{
|
||||
base.StartTime = value;
|
||||
Head.StartTime = value;
|
||||
Tail.StartTime = EndTime;
|
||||
|
||||
if (Head != null)
|
||||
Head.StartTime = value;
|
||||
|
||||
if (Tail != null)
|
||||
Tail.StartTime = EndTime;
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,20 +57,26 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
set
|
||||
{
|
||||
base.Column = value;
|
||||
Head.Column = value;
|
||||
Tail.Column = value;
|
||||
|
||||
if (Head != null)
|
||||
Head.Column = value;
|
||||
|
||||
if (Tail != null)
|
||||
Tail.Column = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<IList<HitSampleInfo>> NodeSamples { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The head note of the hold.
|
||||
/// </summary>
|
||||
public readonly Note Head = new Note();
|
||||
public Note Head { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The tail note of the hold.
|
||||
/// </summary>
|
||||
public readonly TailNote Tail = new TailNote();
|
||||
public TailNote Tail { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The time between ticks of this hold.
|
||||
@ -83,8 +97,19 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
|
||||
createTicks();
|
||||
|
||||
AddNested(Head);
|
||||
AddNested(Tail);
|
||||
AddNested(Head = new Note
|
||||
{
|
||||
StartTime = StartTime,
|
||||
Column = Column,
|
||||
Samples = getNodeSamples(0),
|
||||
});
|
||||
|
||||
AddNested(Tail = new TailNote
|
||||
{
|
||||
StartTime = EndTime,
|
||||
Column = Column,
|
||||
Samples = getNodeSamples((NodeSamples?.Count - 1) ?? 1),
|
||||
});
|
||||
}
|
||||
|
||||
private void createTicks()
|
||||
@ -105,5 +130,8 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
|
||||
private IList<HitSampleInfo> getNodeSamples(int nodeIndex) =>
|
||||
nodeIndex < NodeSamples?.Count ? NodeSamples[nodeIndex] : Samples;
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,12 @@ using osu.Framework.Bindables;
|
||||
using osu.Game.Rulesets.Mania.Objects.Types;
|
||||
using osu.Game.Rulesets.Mania.Scoring;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects
|
||||
{
|
||||
public abstract class ManiaHitObject : HitObject, IHasColumn
|
||||
public abstract class ManiaHitObject : HitObject, IHasColumn, IHasXPosition
|
||||
{
|
||||
public readonly Bindable<int> ColumnBindable = new Bindable<int>();
|
||||
|
||||
@ -20,5 +21,11 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
}
|
||||
|
||||
protected override HitWindows CreateHitWindows() => new ManiaHitWindows();
|
||||
|
||||
#region LegacyBeatmapEncoder
|
||||
|
||||
float IHasXPosition.X => Column;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
/// osu! is generally slower than taiko, so a factor is added to increase
|
||||
/// speed. This must be used everywhere slider length or beat length is used.
|
||||
/// </summary>
|
||||
private const float legacy_velocity_multiplier = 1.4f;
|
||||
public const float LEGACY_VELOCITY_MULTIPLIER = 1.4f;
|
||||
|
||||
/// <summary>
|
||||
/// Because swells are easier in taiko than spinners are in osu!,
|
||||
@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
// Rewrite the beatmap info to add the slider velocity multiplier
|
||||
original.BeatmapInfo = original.BeatmapInfo.Clone();
|
||||
original.BeatmapInfo.BaseDifficulty = original.BeatmapInfo.BaseDifficulty.Clone();
|
||||
original.BeatmapInfo.BaseDifficulty.SliderMultiplier *= legacy_velocity_multiplier;
|
||||
original.BeatmapInfo.BaseDifficulty.SliderMultiplier *= LEGACY_VELOCITY_MULTIPLIER;
|
||||
|
||||
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original);
|
||||
|
||||
@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
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 * spans * legacy_velocity_multiplier;
|
||||
double distance = distanceData.Distance * spans * LEGACY_VELOCITY_MULTIPLIER;
|
||||
|
||||
// The velocity of the taiko hit object - calculated as the velocity of a drum roll
|
||||
double taikoVelocity = taiko_base_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier / speedAdjustedBeatLength;
|
||||
|
@ -3,15 +3,20 @@
|
||||
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects
|
||||
{
|
||||
public class DrumRoll : TaikoHitObject, IHasEndTime
|
||||
public class DrumRoll : TaikoHitObject, IHasCurve
|
||||
{
|
||||
/// <summary>
|
||||
/// Drum roll distance that results in a duration of 1 speed-adjusted beat length.
|
||||
@ -26,6 +31,11 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
|
||||
public double Duration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Velocity of this <see cref="DrumRoll"/>.
|
||||
/// </summary>
|
||||
public double Velocity { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Numer of ticks per beat length.
|
||||
/// </summary>
|
||||
@ -54,6 +64,10 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||
|
||||
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
||||
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
|
||||
|
||||
double scoringDistance = base_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier;
|
||||
Velocity = scoringDistance / timingPoint.BeatLength;
|
||||
|
||||
tickSpacing = timingPoint.BeatLength / TickRate;
|
||||
overallDifficulty = difficulty.OverallDifficulty;
|
||||
@ -93,5 +107,18 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
public override Judgement CreateJudgement() => new TaikoDrumRollJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
|
||||
#region LegacyBeatmapEncoder
|
||||
|
||||
double IHasDistance.Distance => Duration * Velocity;
|
||||
|
||||
int IHasRepeats.RepeatCount { get => 0; set { } }
|
||||
|
||||
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);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
30
osu.Game.Tests/Resources/sample-beatmap-catch.osu
Normal file
30
osu.Game.Tests/Resources/sample-beatmap-catch.osu
Normal file
@ -0,0 +1,30 @@
|
||||
osu file format v14
|
||||
|
||||
[General]
|
||||
SampleSet: Normal
|
||||
StackLeniency: 0.7
|
||||
Mode: 2
|
||||
|
||||
[Difficulty]
|
||||
HPDrainRate:3
|
||||
CircleSize:5
|
||||
OverallDifficulty:8
|
||||
ApproachRate:8
|
||||
SliderMultiplier:3.59999990463257
|
||||
SliderTickRate:2
|
||||
|
||||
[TimingPoints]
|
||||
24,352.941176470588,4,1,1,100,1,0
|
||||
6376,-50,4,1,1,100,0,0
|
||||
|
||||
[HitObjects]
|
||||
32,183,24,5,0,0:0:0:0:
|
||||
106,123,200,1,10,0:0:0:0:
|
||||
199,108,376,1,2,0:0:0:0:
|
||||
305,105,553,5,4,0:0:0:0:
|
||||
386,112,729,1,14,0:0:0:0:
|
||||
486,197,906,5,12,0:0:0:0:
|
||||
14,199,1082,2,0,L|473:198,1,449.999988079071
|
||||
14,199,1700,6,6,P|248:33|490:222,1,629.9999833107,0|8,0:0|0:0,0:0:0:0:
|
||||
10,190,2494,2,8,B|252:29|254:335|468:167,1,449.999988079071,10|12,0:0|0:0,0:0:0:0:
|
||||
256,192,3112,12,0,3906,0:0:0:0:
|
39
osu.Game.Tests/Resources/sample-beatmap-mania.osu
Normal file
39
osu.Game.Tests/Resources/sample-beatmap-mania.osu
Normal file
@ -0,0 +1,39 @@
|
||||
osu file format v14
|
||||
|
||||
[General]
|
||||
SampleSet: Normal
|
||||
StackLeniency: 0.7
|
||||
Mode: 3
|
||||
|
||||
[Difficulty]
|
||||
HPDrainRate:3
|
||||
CircleSize:5
|
||||
OverallDifficulty:8
|
||||
ApproachRate:8
|
||||
SliderMultiplier:3.59999990463257
|
||||
SliderTickRate:2
|
||||
|
||||
[TimingPoints]
|
||||
24,352.941176470588,4,1,1,100,1,0
|
||||
6376,-50,4,1,1,100,0,0
|
||||
|
||||
[HitObjects]
|
||||
51,192,24,1,0,0:0:0:0:
|
||||
153,192,200,1,0,0:0:0:0:
|
||||
358,192,376,1,0,0:0:0:0:
|
||||
460,192,553,1,0,0:0:0:0:
|
||||
460,192,729,128,0,1435:0:0:0:0:
|
||||
358,192,906,128,0,1612:0:0:0:0:
|
||||
256,192,1082,128,0,1788:0:0:0:0:
|
||||
153,192,1259,128,0,1965:0:0:0:0:
|
||||
51,192,1435,128,0,2141:0:0:0:0:
|
||||
51,192,2318,1,12,0:0:0:0:
|
||||
153,192,2318,1,4,0:0:0:0:
|
||||
256,192,2318,1,6,0:0:0:0:
|
||||
358,192,2318,1,14,0:0:0:0:
|
||||
460,192,2318,1,0,0:0:0:0:
|
||||
51,192,2494,128,0,2582:0:0:0:0:
|
||||
153,192,2494,128,14,2582:0:0:0:0:
|
||||
256,192,2494,128,6,2582:0:0:0:0:
|
||||
358,192,2494,128,4,2582:0:0:0:0:
|
||||
460,192,2494,128,12,2582:0:0:0:0:
|
42
osu.Game.Tests/Resources/sample-beatmap-taiko.osu
Normal file
42
osu.Game.Tests/Resources/sample-beatmap-taiko.osu
Normal file
@ -0,0 +1,42 @@
|
||||
osu file format v14
|
||||
|
||||
[General]
|
||||
SampleSet: Normal
|
||||
StackLeniency: 0.7
|
||||
Mode: 1
|
||||
|
||||
[Difficulty]
|
||||
HPDrainRate:3
|
||||
CircleSize:5
|
||||
OverallDifficulty:8
|
||||
ApproachRate:8
|
||||
SliderMultiplier:3.59999990463257
|
||||
SliderTickRate:2
|
||||
|
||||
[TimingPoints]
|
||||
24,352.941176470588,4,1,1,100,1,0
|
||||
6376,-50,4,1,1,100,0,0
|
||||
|
||||
[HitObjects]
|
||||
231,129,24,1,0,0:0:0:0:
|
||||
231,129,200,1,0,0:0:0:0:
|
||||
231,129,376,1,0,0:0:0:0:
|
||||
231,129,553,1,0,0:0:0:0:
|
||||
231,129,729,1,0,0:0:0:0:
|
||||
373,132,906,1,4,0:0:0:0:
|
||||
373,132,1082,1,4,0:0:0:0:
|
||||
373,132,1259,1,4,0:0:0:0:
|
||||
373,132,1435,1,4,0:0:0:0:
|
||||
231,129,1788,1,8,0:0:0:0:
|
||||
231,129,1964,1,8,0:0:0:0:
|
||||
231,129,2140,1,8,0:0:0:0:
|
||||
231,129,2317,1,8,0:0:0:0:
|
||||
231,129,2493,1,8,0:0:0:0:
|
||||
373,132,2670,1,12,0:0:0:0:
|
||||
373,132,2846,1,12,0:0:0:0:
|
||||
373,132,3023,1,12,0:0:0:0:
|
||||
373,132,3199,1,12,0:0:0:0:
|
||||
51,189,3553,2,0,L|150:188,1,89.9999976158143
|
||||
52,191,3906,2,0,L|512:189,1,449.999988079071
|
||||
26,196,4612,2,4,L|501:195,1,449.999988079071
|
||||
17,242,5318,2,10,P|250:69|495:243,1,629.9999833107,0|8,0:0|0:0,0:0:0:0:
|
@ -13,6 +13,7 @@ using osu.Game.Beatmaps.Legacy;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
@ -124,7 +125,12 @@ namespace osu.Game.Beatmaps.Formats
|
||||
writer.WriteLine(FormattableString.Invariant($"CircleSize: {beatmap.BeatmapInfo.BaseDifficulty.CircleSize}"));
|
||||
writer.WriteLine(FormattableString.Invariant($"OverallDifficulty: {beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty}"));
|
||||
writer.WriteLine(FormattableString.Invariant($"ApproachRate: {beatmap.BeatmapInfo.BaseDifficulty.ApproachRate}"));
|
||||
writer.WriteLine(FormattableString.Invariant($"SliderMultiplier: {beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier}"));
|
||||
|
||||
// Taiko adjusts the slider multiplier (see: TaikoBeatmapConverter.LEGACY_VELOCITY_MULTIPLIER)
|
||||
writer.WriteLine(beatmap.BeatmapInfo.RulesetID == 1
|
||||
? FormattableString.Invariant($"SliderMultiplier: {beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier / 1.4f}")
|
||||
: FormattableString.Invariant($"SliderMultiplier: {beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier}"));
|
||||
|
||||
writer.WriteLine(FormattableString.Invariant($"SliderTickRate: {beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate}"));
|
||||
}
|
||||
|
||||
@ -197,51 +203,63 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
writer.WriteLine("[HitObjects]");
|
||||
|
||||
// TODO: implement other legacy rulesets
|
||||
foreach (var h in beatmap.HitObjects)
|
||||
handleHitObject(writer, h);
|
||||
}
|
||||
|
||||
private void handleHitObject(TextWriter writer, HitObject hitObject)
|
||||
{
|
||||
Vector2 position = new Vector2(256, 192);
|
||||
|
||||
switch (beatmap.BeatmapInfo.RulesetID)
|
||||
{
|
||||
case 0:
|
||||
foreach (var h in beatmap.HitObjects)
|
||||
handleOsuHitObject(writer, h);
|
||||
position = ((IHasPosition)hitObject).Position;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
position.X = ((IHasXPosition)hitObject).X * 512;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
int totalColumns = (int)Math.Max(1, beatmap.BeatmapInfo.BaseDifficulty.CircleSize);
|
||||
position.X = (int)Math.Ceiling(((IHasXPosition)hitObject).X * (512f / totalColumns));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleOsuHitObject(TextWriter writer, HitObject hitObject)
|
||||
{
|
||||
var positionData = (IHasPosition)hitObject;
|
||||
|
||||
writer.Write(FormattableString.Invariant($"{positionData.X},"));
|
||||
writer.Write(FormattableString.Invariant($"{positionData.Y},"));
|
||||
writer.Write(FormattableString.Invariant($"{position.X},"));
|
||||
writer.Write(FormattableString.Invariant($"{position.Y},"));
|
||||
writer.Write(FormattableString.Invariant($"{hitObject.StartTime},"));
|
||||
writer.Write(FormattableString.Invariant($"{(int)getObjectType(hitObject)},"));
|
||||
|
||||
writer.Write(hitObject is IHasCurve
|
||||
? FormattableString.Invariant($"0,")
|
||||
: FormattableString.Invariant($"{(int)toLegacyHitSoundType(hitObject.Samples)},"));
|
||||
writer.Write(FormattableString.Invariant($"{(int)toLegacyHitSoundType(hitObject.Samples)},"));
|
||||
|
||||
if (hitObject is IHasCurve curveData)
|
||||
{
|
||||
addCurveData(writer, curveData, positionData);
|
||||
addCurveData(writer, curveData, position);
|
||||
writer.Write(getSampleBank(hitObject.Samples, zeroBanks: true));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hitObject is IHasEndTime endTimeData)
|
||||
writer.Write(FormattableString.Invariant($"{endTimeData.EndTime},"));
|
||||
if (hitObject is IHasEndTime _)
|
||||
addEndTimeData(writer, hitObject);
|
||||
|
||||
writer.Write(getSampleBank(hitObject.Samples));
|
||||
}
|
||||
|
||||
writer.WriteLine();
|
||||
}
|
||||
|
||||
private static LegacyHitObjectType getObjectType(HitObject hitObject)
|
||||
private LegacyHitObjectType getObjectType(HitObject hitObject)
|
||||
{
|
||||
var comboData = (IHasCombo)hitObject;
|
||||
LegacyHitObjectType type = 0;
|
||||
|
||||
var type = (LegacyHitObjectType)(comboData.ComboOffset << 4);
|
||||
if (hitObject is IHasCombo combo)
|
||||
{
|
||||
type = (LegacyHitObjectType)(combo.ComboOffset << 4);
|
||||
|
||||
if (comboData.NewCombo) type |= LegacyHitObjectType.NewCombo;
|
||||
if (combo.NewCombo)
|
||||
type |= LegacyHitObjectType.NewCombo;
|
||||
}
|
||||
|
||||
switch (hitObject)
|
||||
{
|
||||
@ -250,7 +268,10 @@ namespace osu.Game.Beatmaps.Formats
|
||||
break;
|
||||
|
||||
case IHasEndTime _:
|
||||
type |= LegacyHitObjectType.Spinner;
|
||||
if (beatmap.BeatmapInfo.RulesetID == 3)
|
||||
type |= LegacyHitObjectType.Hold;
|
||||
else
|
||||
type |= LegacyHitObjectType.Spinner;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -261,7 +282,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
return type;
|
||||
}
|
||||
|
||||
private void addCurveData(TextWriter writer, IHasCurve curveData, IHasPosition positionData)
|
||||
private void addCurveData(TextWriter writer, IHasCurve curveData, Vector2 position)
|
||||
{
|
||||
PathType? lastType = null;
|
||||
|
||||
@ -297,13 +318,13 @@ namespace osu.Game.Beatmaps.Formats
|
||||
else
|
||||
{
|
||||
// New segment with the same type - duplicate the control point
|
||||
writer.Write(FormattableString.Invariant($"{positionData.X + point.Position.Value.X}:{positionData.Y + point.Position.Value.Y}|"));
|
||||
writer.Write(FormattableString.Invariant($"{position.X + point.Position.Value.X}:{position.Y + point.Position.Value.Y}|"));
|
||||
}
|
||||
}
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
writer.Write(FormattableString.Invariant($"{positionData.X + point.Position.Value.X}:{positionData.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 ? "|" : ",");
|
||||
}
|
||||
}
|
||||
@ -324,6 +345,20 @@ namespace osu.Game.Beatmaps.Formats
|
||||
}
|
||||
}
|
||||
|
||||
private void addEndTimeData(TextWriter writer, HitObject hitObject)
|
||||
{
|
||||
var endTimeData = (IHasEndTime)hitObject;
|
||||
var type = getObjectType(hitObject);
|
||||
|
||||
char suffix = ',';
|
||||
|
||||
// Holds write the end time as if it's part of sample data.
|
||||
if (type == LegacyHitObjectType.Hold)
|
||||
suffix = ':';
|
||||
|
||||
writer.Write(FormattableString.Invariant($"{endTimeData.EndTime}{suffix}"));
|
||||
}
|
||||
|
||||
private string getSampleBank(IList<HitSampleInfo> samples, bool banksOnly = false, bool zeroBanks = false)
|
||||
{
|
||||
LegacySampleBank normalBank = toLegacySampleBank(samples.SingleOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL)?.Bank);
|
||||
|
@ -153,7 +153,7 @@ namespace osu.Game.Overlays.Comments
|
||||
request?.Cancel();
|
||||
loadCancellation?.Cancel();
|
||||
request = new GetCommentsRequest(id.Value, type.Value, Sort.Value, currentPage++, 0);
|
||||
request.Success += onSuccess;
|
||||
request.Success += res => Schedule(() => onSuccess(res));
|
||||
api.PerformAsync(request);
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,15 @@ namespace osu.Game.Rulesets.UI
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void Clear(bool disposeChildren = true)
|
||||
{
|
||||
ClearInternal(disposeChildren);
|
||||
|
||||
foreach (var kvp in startTimeMap)
|
||||
kvp.Value.bindable.UnbindAll();
|
||||
startTimeMap.Clear();
|
||||
}
|
||||
|
||||
public int IndexOf(DrawableHitObject hitObject) => IndexOfInternal(hitObject);
|
||||
|
||||
private void onStartTimeChanged(DrawableHitObject hitObject)
|
||||
|
@ -58,6 +58,14 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void Clear(bool disposeChildren = true)
|
||||
{
|
||||
base.Clear(disposeChildren);
|
||||
|
||||
initialStateCache.Invalidate();
|
||||
hitObjectInitialStateCache.Clear();
|
||||
}
|
||||
|
||||
private float scrollLength;
|
||||
|
||||
protected override void Update()
|
||||
|
@ -30,6 +30,11 @@ namespace osu.Game.Tests.Visual
|
||||
set => scrollingInfo.TimeRange.Value = value;
|
||||
}
|
||||
|
||||
public ScrollingDirection Direction
|
||||
{
|
||||
set => scrollingInfo.Direction.Value = value;
|
||||
}
|
||||
|
||||
public IScrollingInfo ScrollingInfo => scrollingInfo;
|
||||
|
||||
[Cached(Type = typeof(IScrollingInfo))]
|
||||
|
Loading…
Reference in New Issue
Block a user