mirror of
https://github.com/ppy/osu.git
synced 2025-01-14 04:02:59 +08:00
Merge pull request #662 from smoogipooo/nodal-hit-sounds
Nodal hit sounds
This commit is contained in:
commit
c61f69569c
@ -10,7 +10,6 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
@ -62,15 +61,12 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
add(new DrawableSlider(new Slider
|
||||
{
|
||||
StartTime = framedClock.CurrentTime + 600,
|
||||
CurveObject = new CurvedHitObject
|
||||
ControlPoints = new List<Vector2>
|
||||
{
|
||||
ControlPoints = new List<Vector2>
|
||||
{
|
||||
new Vector2(-200, 0),
|
||||
new Vector2(400, 0),
|
||||
},
|
||||
Distance = 400
|
||||
new Vector2(-200, 0),
|
||||
new Vector2(400, 0),
|
||||
},
|
||||
Distance = 400,
|
||||
Position = new Vector2(-200, 0),
|
||||
Velocity = 1,
|
||||
TickDistance = 100,
|
||||
|
@ -19,10 +19,10 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
|
||||
protected override IEnumerable<OsuHitObject> ConvertHitObject(HitObject original, Beatmap beatmap)
|
||||
{
|
||||
IHasCurve curveData = original as IHasCurve;
|
||||
IHasEndTime endTimeData = original as IHasEndTime;
|
||||
IHasPosition positionData = original as IHasPosition;
|
||||
IHasCombo comboData = original as IHasCombo;
|
||||
var curveData = original as IHasCurve;
|
||||
var endTimeData = original as IHasEndTime;
|
||||
var positionData = original as IHasPosition;
|
||||
var comboData = original as IHasCombo;
|
||||
|
||||
if (curveData != null)
|
||||
{
|
||||
@ -30,7 +30,11 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
{
|
||||
StartTime = original.StartTime,
|
||||
Samples = original.Samples,
|
||||
CurveObject = curveData,
|
||||
ControlPoints = curveData.ControlPoints,
|
||||
CurveType = curveData.CurveType,
|
||||
Distance = curveData.Distance,
|
||||
RepeatSamples = curveData.RepeatSamples,
|
||||
RepeatCount = curveData.RepeatCount,
|
||||
Position = positionData?.Position ?? Vector2.Zero,
|
||||
NewCombo = comboData?.NewCombo ?? false
|
||||
};
|
||||
|
@ -20,24 +20,33 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
/// </summary>
|
||||
private const float base_scoring_distance = 100;
|
||||
|
||||
public IHasCurve CurveObject { get; set; }
|
||||
|
||||
public SliderCurve Curve => CurveObject.Curve;
|
||||
public readonly SliderCurve Curve = new SliderCurve();
|
||||
|
||||
public double EndTime => StartTime + RepeatCount * Curve.Distance / Velocity;
|
||||
public double Duration => EndTime - StartTime;
|
||||
|
||||
public override Vector2 EndPosition => PositionAt(1);
|
||||
|
||||
public Vector2 PositionAt(double progress) => CurveObject.PositionAt(progress);
|
||||
public double ProgressAt(double progress) => CurveObject.ProgressAt(progress);
|
||||
public int RepeatAt(double progress) => CurveObject.RepeatAt(progress);
|
||||
public List<Vector2> ControlPoints
|
||||
{
|
||||
get { return Curve.ControlPoints; }
|
||||
set { Curve.ControlPoints = value; }
|
||||
}
|
||||
|
||||
public List<Vector2> ControlPoints => CurveObject.ControlPoints;
|
||||
public CurveType CurveType => CurveObject.CurveType;
|
||||
public double Distance => CurveObject.Distance;
|
||||
public CurveType CurveType
|
||||
{
|
||||
get { return Curve.CurveType; }
|
||||
set { Curve.CurveType = value; }
|
||||
}
|
||||
|
||||
public int RepeatCount => CurveObject.RepeatCount;
|
||||
public double Distance
|
||||
{
|
||||
get { return Curve.Distance; }
|
||||
set { Curve.Distance = value; }
|
||||
}
|
||||
|
||||
public List<List<SampleInfo>> RepeatSamples { get; set; } = new List<List<SampleInfo>>();
|
||||
public int RepeatCount { get; set; } = 1;
|
||||
|
||||
private int stackHeight;
|
||||
public override int StackHeight
|
||||
@ -63,6 +72,18 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
TickDistance = scoringDistance / difficulty.SliderTickRate;
|
||||
}
|
||||
|
||||
public Vector2 PositionAt(double progress) => Curve.PositionAt(ProgressAt(progress));
|
||||
|
||||
public double ProgressAt(double progress)
|
||||
{
|
||||
double p = progress * RepeatCount % 1;
|
||||
if (RepeatAt(progress) % 2 == 1)
|
||||
p = 1 - p;
|
||||
return p;
|
||||
}
|
||||
|
||||
public int RepeatAt(double progress) => (int)(progress * RepeatCount);
|
||||
|
||||
public IEnumerable<SliderTick> Ticks
|
||||
{
|
||||
get
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using System;
|
||||
@ -28,7 +27,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
protected override void PreprocessHitObjects()
|
||||
{
|
||||
foreach (var h in Objects)
|
||||
(h as IHasCurve)?.Curve?.Calculate();
|
||||
(h as Slider)?.Curve?.Calculate();
|
||||
}
|
||||
|
||||
protected override double CalculateInternal(Dictionary<string, string> categoryDifficulty)
|
||||
@ -190,4 +189,4 @@ namespace osu.Game.Rulesets.Osu
|
||||
Aim,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
// TODO: Not sure how far back to go, or differences between versions
|
||||
}
|
||||
|
||||
private HitObjectParser parser;
|
||||
private ConvertHitObjectParser parser;
|
||||
|
||||
private LegacySampleBank defaultSampleBank;
|
||||
private int defaultSampleVolume = 100;
|
||||
@ -90,16 +90,16 @@ namespace osu.Game.Beatmaps.Formats
|
||||
switch (beatmap.BeatmapInfo.RulesetID)
|
||||
{
|
||||
case 0:
|
||||
parser = new Rulesets.Objects.Legacy.Osu.HitObjectParser();
|
||||
parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser();
|
||||
break;
|
||||
case 1:
|
||||
parser = new Rulesets.Objects.Legacy.Taiko.HitObjectParser();
|
||||
parser = new Rulesets.Objects.Legacy.Taiko.ConvertHitObjectParser();
|
||||
break;
|
||||
case 2:
|
||||
parser = new Rulesets.Objects.Legacy.Catch.HitObjectParser();
|
||||
parser = new Rulesets.Objects.Legacy.Catch.ConvertHitObjectParser();
|
||||
break;
|
||||
case 3:
|
||||
parser = new Rulesets.Objects.Legacy.Mania.HitObjectParser();
|
||||
parser = new Rulesets.Objects.Legacy.Mania.ConvertHitObjectParser();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -1,49 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects
|
||||
{
|
||||
public class CurvedHitObject : HitObject, IHasCurve
|
||||
{
|
||||
public SliderCurve Curve { get; } = new SliderCurve();
|
||||
|
||||
public int RepeatCount { get; set; } = 1;
|
||||
|
||||
public double EndTime => 0;
|
||||
public double Duration => 0;
|
||||
|
||||
public List<Vector2> ControlPoints
|
||||
{
|
||||
get { return Curve.ControlPoints; }
|
||||
set { Curve.ControlPoints = value; }
|
||||
}
|
||||
|
||||
public CurveType CurveType
|
||||
{
|
||||
get { return Curve.CurveType; }
|
||||
set { Curve.CurveType = value; }
|
||||
}
|
||||
|
||||
public double Distance
|
||||
{
|
||||
get { return Curve.Distance; }
|
||||
set { Curve.Distance = value; }
|
||||
}
|
||||
|
||||
public Vector2 PositionAt(double progress) => Curve.PositionAt(ProgressAt(progress));
|
||||
|
||||
public double ProgressAt(double progress)
|
||||
{
|
||||
var p = progress * RepeatCount % 1;
|
||||
if (RepeatAt(progress) % 2 == 1)
|
||||
p = 1 - p;
|
||||
return p;
|
||||
}
|
||||
|
||||
public int RepeatAt(double progress) => (int)(progress * RepeatCount);
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects
|
||||
@ -19,10 +20,14 @@ namespace osu.Game.Rulesets.Objects
|
||||
/// <summary>
|
||||
/// The time at which the HitObject starts.
|
||||
/// </summary>
|
||||
public double StartTime { get; set; }
|
||||
public double StartTime;
|
||||
|
||||
/// <summary>
|
||||
/// The samples to be played when this hit object is hit.
|
||||
/// <para>
|
||||
/// In the case of <see cref="IHasRepeats"/> types, this is the sample of the curve body
|
||||
/// and can be treated as the default samples for the hit object.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public List<SampleInfo> Samples = new List<SampleInfo>();
|
||||
|
||||
@ -36,17 +41,24 @@ namespace osu.Game.Rulesets.Objects
|
||||
ControlPoint overridePoint;
|
||||
ControlPoint timingPoint = timing.TimingPointAt(StartTime, out overridePoint);
|
||||
|
||||
foreach (var sample in Samples)
|
||||
{
|
||||
if (sample.Volume == 0)
|
||||
sample.Volume = (overridePoint ?? timingPoint)?.SampleVolume ?? 0;
|
||||
ControlPoint samplePoint = overridePoint ?? timingPoint;
|
||||
|
||||
// If the bank is not assigned a name, assign it from the control point
|
||||
if (!string.IsNullOrEmpty(sample.Bank))
|
||||
continue;
|
||||
// Initialize first sample
|
||||
Samples.ForEach(s => initializeSampleInfo(s, samplePoint));
|
||||
|
||||
sample.Bank = (overridePoint ?? timingPoint)?.SampleBank ?? @"normal";
|
||||
}
|
||||
// Initialize any repeat samples
|
||||
var repeatData = this as IHasRepeats;
|
||||
repeatData?.RepeatSamples?.ForEach(r => r.ForEach(s => initializeSampleInfo(s, samplePoint)));
|
||||
}
|
||||
|
||||
private void initializeSampleInfo(SampleInfo sample, ControlPoint controlPoint)
|
||||
{
|
||||
if (sample.Volume == 0)
|
||||
sample.Volume = controlPoint?.SampleVolume ?? 0;
|
||||
|
||||
// If the bank is not assigned a name, assign it from the control point
|
||||
if (string.IsNullOrEmpty(sample.Bank))
|
||||
sample.Bank = controlPoint?.SampleBank ?? @"normal";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
||||
/// <summary>
|
||||
/// Legacy osu!catch Hit-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class Hit : HitObject, IHasCombo, IHasXPosition
|
||||
internal sealed class ConvertHit : HitObject, IHasCombo, IHasXPosition
|
||||
{
|
||||
public float X { get; set; }
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@ -10,33 +11,34 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
||||
/// <summary>
|
||||
/// A HitObjectParser to parse legacy osu!catch Beatmaps.
|
||||
/// </summary>
|
||||
internal class HitObjectParser : Legacy.HitObjectParser
|
||||
internal class ConvertHitObjectParser : Legacy.ConvertHitObjectParser
|
||||
{
|
||||
protected override HitObject CreateHit(Vector2 position, bool newCombo)
|
||||
{
|
||||
return new Hit
|
||||
return new ConvertHit
|
||||
{
|
||||
X = position.X,
|
||||
NewCombo = newCombo,
|
||||
};
|
||||
}
|
||||
|
||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount)
|
||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
|
||||
{
|
||||
return new Slider
|
||||
return new ConvertSlider
|
||||
{
|
||||
X = position.X,
|
||||
NewCombo = newCombo,
|
||||
ControlPoints = controlPoints,
|
||||
Distance = length,
|
||||
CurveType = curveType,
|
||||
RepeatSamples = repeatSamples,
|
||||
RepeatCount = repeatCount
|
||||
};
|
||||
}
|
||||
|
||||
protected override HitObject CreateSpinner(Vector2 position, double endTime)
|
||||
{
|
||||
return new Spinner
|
||||
return new ConvertSpinner
|
||||
{
|
||||
EndTime = endTime
|
||||
};
|
@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
||||
/// <summary>
|
||||
/// Legacy osu!catch Slider-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class Slider : CurvedHitObject, IHasXPosition, IHasCombo
|
||||
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasXPosition, IHasCombo
|
||||
{
|
||||
public float X { get; set; }
|
||||
|
@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
||||
/// <summary>
|
||||
/// Legacy osu!catch Spinner-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class Spinner : HitObject, IHasEndTime
|
||||
internal sealed class ConvertSpinner : HitObject, IHasEndTime
|
||||
{
|
||||
public double EndTime { get; set; }
|
||||
|
@ -14,29 +14,28 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
/// <summary>
|
||||
/// A HitObjectParser to parse legacy Beatmaps.
|
||||
/// </summary>
|
||||
internal abstract class HitObjectParser : Objects.HitObjectParser
|
||||
internal abstract class ConvertHitObjectParser : HitObjectParser
|
||||
{
|
||||
public override HitObject Parse(string text)
|
||||
{
|
||||
string[] split = text.Split(',');
|
||||
var type = (HitObjectType)int.Parse(split[3]) & ~HitObjectType.ColourHax;
|
||||
bool combo = type.HasFlag(HitObjectType.NewCombo);
|
||||
type &= ~HitObjectType.NewCombo;
|
||||
ConvertHitObjectType type = (ConvertHitObjectType)int.Parse(split[3]) & ~ConvertHitObjectType.ColourHax;
|
||||
bool combo = type.HasFlag(ConvertHitObjectType.NewCombo);
|
||||
type &= ~ConvertHitObjectType.NewCombo;
|
||||
|
||||
int sampleVolume = 0;
|
||||
string normalSampleBank = null;
|
||||
string addSampleBank = null;
|
||||
var soundType = (LegacySoundType)int.Parse(split[4]);
|
||||
var bankInfo = new SampleBankInfo();
|
||||
|
||||
HitObject result;
|
||||
|
||||
if ((type & HitObjectType.Circle) > 0)
|
||||
if ((type & ConvertHitObjectType.Circle) > 0)
|
||||
{
|
||||
result = CreateHit(new Vector2(int.Parse(split[0]), int.Parse(split[1])), combo);
|
||||
|
||||
if (split.Length > 5)
|
||||
readCustomSampleBanks(split[5], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
|
||||
readCustomSampleBanks(split[5], bankInfo);
|
||||
}
|
||||
else if ((type & HitObjectType.Slider) > 0)
|
||||
else if ((type & ConvertHitObjectType.Slider) > 0)
|
||||
{
|
||||
CurveType curveType = CurveType.Catmull;
|
||||
double length = 0;
|
||||
@ -77,26 +76,74 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
if (split.Length > 7)
|
||||
length = Convert.ToDouble(split[7], CultureInfo.InvariantCulture);
|
||||
|
||||
result = CreateSlider(new Vector2(int.Parse(split[0]), int.Parse(split[1])), combo, points, length, curveType, repeatCount);
|
||||
|
||||
if (split.Length > 10)
|
||||
readCustomSampleBanks(split[10], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
|
||||
readCustomSampleBanks(split[10], bankInfo);
|
||||
|
||||
// One node for each repeat + the start and end nodes
|
||||
// Note that the first length of the slider is considered a repeat, but there are no actual repeats happening
|
||||
int nodes = Math.Max(0, repeatCount - 1) + 2;
|
||||
|
||||
// Populate node sample bank infos with the default hit object sample bank
|
||||
var nodeBankInfos = new List<SampleBankInfo>();
|
||||
for (int i = 0; i < nodes; i++)
|
||||
nodeBankInfos.Add(bankInfo.Clone());
|
||||
|
||||
// Read any per-node sample banks
|
||||
if (split.Length > 9 && split[9].Length > 0)
|
||||
{
|
||||
string[] sets = split[9].Split('|');
|
||||
for (int i = 0; i < nodes; i++)
|
||||
{
|
||||
if (i >= sets.Length)
|
||||
break;
|
||||
|
||||
SampleBankInfo info = nodeBankInfos[i];
|
||||
readCustomSampleBanks(sets[i], info);
|
||||
}
|
||||
}
|
||||
|
||||
// Populate node sound types with the default hit object sound type
|
||||
var nodeSoundTypes = new List<LegacySoundType>();
|
||||
for (int i = 0; i < nodes; i++)
|
||||
nodeSoundTypes.Add(soundType);
|
||||
|
||||
// Read any per-node sound types
|
||||
if (split.Length > 8 && split[8].Length > 0)
|
||||
{
|
||||
string[] adds = split[8].Split('|');
|
||||
for (int i = 0; i < nodes; i++)
|
||||
{
|
||||
if (i >= adds.Length)
|
||||
break;
|
||||
|
||||
int sound;
|
||||
int.TryParse(adds[i], out sound);
|
||||
nodeSoundTypes[i] = (LegacySoundType)sound;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the final per-node samples
|
||||
var nodeSamples = new List<List<SampleInfo>>(nodes);
|
||||
for (int i = 0; i <= repeatCount; i++)
|
||||
nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i]));
|
||||
|
||||
result = CreateSlider(new Vector2(int.Parse(split[0]), int.Parse(split[1])), combo, points, length, curveType, repeatCount, nodeSamples);
|
||||
}
|
||||
else if ((type & HitObjectType.Spinner) > 0)
|
||||
else if ((type & ConvertHitObjectType.Spinner) > 0)
|
||||
{
|
||||
result = CreateSpinner(new Vector2(512, 384) / 2, Convert.ToDouble(split[5], CultureInfo.InvariantCulture));
|
||||
|
||||
if (split.Length > 6)
|
||||
readCustomSampleBanks(split[6], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
|
||||
readCustomSampleBanks(split[6], bankInfo);
|
||||
}
|
||||
else if ((type & HitObjectType.Hold) > 0)
|
||||
else if ((type & ConvertHitObjectType.Hold) > 0)
|
||||
{
|
||||
// Note: Hold is generated by BMS converts
|
||||
|
||||
// Todo: Apparently end time is determined by samples??
|
||||
// Shouldn't need implementation until mania
|
||||
|
||||
result = new Hold
|
||||
result = new ConvertHold
|
||||
{
|
||||
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])),
|
||||
NewCombo = combo
|
||||
@ -106,50 +153,12 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
throw new InvalidOperationException($@"Unknown hit object type {type}");
|
||||
|
||||
result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture);
|
||||
|
||||
var soundType = (LegacySoundType)int.Parse(split[4]);
|
||||
|
||||
result.Samples.Add(new SampleInfo
|
||||
{
|
||||
Bank = normalSampleBank,
|
||||
Name = SampleInfo.HIT_NORMAL,
|
||||
Volume = sampleVolume
|
||||
});
|
||||
|
||||
if ((soundType & LegacySoundType.Finish) > 0)
|
||||
{
|
||||
result.Samples.Add(new SampleInfo
|
||||
{
|
||||
Bank = addSampleBank,
|
||||
Name = SampleInfo.HIT_FINISH,
|
||||
Volume = sampleVolume
|
||||
});
|
||||
}
|
||||
|
||||
if ((soundType & LegacySoundType.Whistle) > 0)
|
||||
{
|
||||
result.Samples.Add(new SampleInfo
|
||||
{
|
||||
Bank = addSampleBank,
|
||||
Name = SampleInfo.HIT_WHISTLE,
|
||||
Volume = sampleVolume
|
||||
});
|
||||
}
|
||||
|
||||
if ((soundType & LegacySoundType.Clap) > 0)
|
||||
{
|
||||
result.Samples.Add(new SampleInfo
|
||||
{
|
||||
Bank = addSampleBank,
|
||||
Name = SampleInfo.HIT_CLAP,
|
||||
Volume = sampleVolume
|
||||
});
|
||||
}
|
||||
result.Samples = convertSoundType(soundType, bankInfo);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void readCustomSampleBanks(string str, ref string normalSampleBank, ref string addSampleBank, ref int sampleVolume)
|
||||
private void readCustomSampleBanks(string str, SampleBankInfo bankInfo)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str))
|
||||
return;
|
||||
@ -169,9 +178,11 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
if (stringAddBank == @"none")
|
||||
stringAddBank = null;
|
||||
|
||||
normalSampleBank = stringBank;
|
||||
addSampleBank = stringAddBank;
|
||||
sampleVolume = split.Length > 3 ? int.Parse(split[3]) : 0;
|
||||
bankInfo.Normal = stringBank;
|
||||
bankInfo.Add = stringAddBank;
|
||||
|
||||
if (split.Length > 3)
|
||||
bankInfo.Volume = int.Parse(split[3]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -191,8 +202,9 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
/// <param name="length">The slider length.</param>
|
||||
/// <param name="curveType">The slider curve type.</param>
|
||||
/// <param name="repeatCount">The slider repeat count.</param>
|
||||
/// <param name="repeatSamples">The samples to be played when the repeat nodes are hit. This includes the head and tail of the slider.</param>
|
||||
/// <returns>The hit object.</returns>
|
||||
protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount);
|
||||
protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a legacy Spinner-type hit object.
|
||||
@ -202,6 +214,63 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
/// <returns>The hit object.</returns>
|
||||
protected abstract HitObject CreateSpinner(Vector2 position, double endTime);
|
||||
|
||||
private List<SampleInfo> convertSoundType(LegacySoundType type, SampleBankInfo bankInfo)
|
||||
{
|
||||
var soundTypes = new List<SampleInfo>
|
||||
{
|
||||
new SampleInfo
|
||||
{
|
||||
Bank = bankInfo.Normal,
|
||||
Name = SampleInfo.HIT_NORMAL,
|
||||
Volume = bankInfo.Volume
|
||||
}
|
||||
};
|
||||
|
||||
if ((type & LegacySoundType.Finish) > 0)
|
||||
{
|
||||
soundTypes.Add(new SampleInfo
|
||||
{
|
||||
Bank = bankInfo.Add,
|
||||
Name = SampleInfo.HIT_FINISH,
|
||||
Volume = bankInfo.Volume
|
||||
});
|
||||
}
|
||||
|
||||
if ((type & LegacySoundType.Whistle) > 0)
|
||||
{
|
||||
soundTypes.Add(new SampleInfo
|
||||
{
|
||||
Bank = bankInfo.Add,
|
||||
Name = SampleInfo.HIT_WHISTLE,
|
||||
Volume = bankInfo.Volume
|
||||
});
|
||||
}
|
||||
|
||||
if ((type & LegacySoundType.Clap) > 0)
|
||||
{
|
||||
soundTypes.Add(new SampleInfo
|
||||
{
|
||||
Bank = bankInfo.Add,
|
||||
Name = SampleInfo.HIT_CLAP,
|
||||
Volume = bankInfo.Volume
|
||||
});
|
||||
}
|
||||
|
||||
return soundTypes;
|
||||
}
|
||||
|
||||
private class SampleBankInfo
|
||||
{
|
||||
public string Normal;
|
||||
public string Add;
|
||||
public int Volume;
|
||||
|
||||
public SampleBankInfo Clone()
|
||||
{
|
||||
return (SampleBankInfo)MemberwiseClone();
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum LegacySoundType
|
||||
{
|
@ -6,7 +6,7 @@ using System;
|
||||
namespace osu.Game.Rulesets.Objects.Legacy
|
||||
{
|
||||
[Flags]
|
||||
public enum HitObjectType
|
||||
internal enum ConvertHitObjectType
|
||||
{
|
||||
Circle = 1 << 0,
|
||||
Slider = 1 << 1,
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
/// <summary>
|
||||
/// Legacy Hold-type, used for parsing "specials" in beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class Hold : HitObject, IHasPosition, IHasCombo, IHasHold
|
||||
internal sealed class ConvertHold : HitObject, IHasPosition, IHasCombo, IHasHold
|
||||
{
|
||||
public Vector2 Position { get; set; }
|
||||
|
39
osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs
Normal file
39
osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
using osu.Game.Audio;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy
|
||||
{
|
||||
internal abstract class ConvertSlider : HitObject, IHasCurve
|
||||
{
|
||||
public List<Vector2> ControlPoints { get; set; }
|
||||
public CurveType CurveType { get; set; }
|
||||
public double Distance { get; set; }
|
||||
|
||||
public List<List<SampleInfo>> RepeatSamples { get; set; }
|
||||
public int RepeatCount { get; set; } = 1;
|
||||
|
||||
public double EndTime { get; set; }
|
||||
public double Duration { get; set; }
|
||||
|
||||
public Vector2 PositionAt(double progress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public double ProgressAt(double progress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int RepeatAt(double progress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
||||
/// <summary>
|
||||
/// Legacy osu!mania Hit-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class Hit : HitObject, IHasXPosition, IHasCombo
|
||||
internal sealed class ConvertHit : HitObject, IHasXPosition, IHasCombo
|
||||
{
|
||||
public float X { get; set; }
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@ -10,33 +11,34 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
||||
/// <summary>
|
||||
/// A HitObjectParser to parse legacy osu!mania Beatmaps.
|
||||
/// </summary>
|
||||
internal class HitObjectParser : Legacy.HitObjectParser
|
||||
internal class ConvertHitObjectParser : Legacy.ConvertHitObjectParser
|
||||
{
|
||||
protected override HitObject CreateHit(Vector2 position, bool newCombo)
|
||||
{
|
||||
return new Hit
|
||||
return new ConvertHit
|
||||
{
|
||||
X = position.X,
|
||||
NewCombo = newCombo,
|
||||
};
|
||||
}
|
||||
|
||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount)
|
||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
|
||||
{
|
||||
return new Slider
|
||||
return new ConvertSlider
|
||||
{
|
||||
X = position.X,
|
||||
NewCombo = newCombo,
|
||||
ControlPoints = controlPoints,
|
||||
Distance = length,
|
||||
CurveType = curveType,
|
||||
RepeatSamples = repeatSamples,
|
||||
RepeatCount = repeatCount
|
||||
};
|
||||
}
|
||||
|
||||
protected override HitObject CreateSpinner(Vector2 position, double endTime)
|
||||
{
|
||||
return new Spinner
|
||||
return new ConvertSpinner
|
||||
{
|
||||
X = position.X,
|
||||
EndTime = endTime
|
@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
||||
/// <summary>
|
||||
/// Legacy osu!mania Slider-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class Slider : CurvedHitObject, IHasXPosition, IHasCombo
|
||||
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasXPosition, IHasCombo
|
||||
{
|
||||
public float X { get; set; }
|
||||
|
@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
||||
/// <summary>
|
||||
/// Legacy osu!mania Spinner-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class Spinner : HitObject, IHasEndTime, IHasXPosition
|
||||
internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasXPosition
|
||||
{
|
||||
public double EndTime { get; set; }
|
||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
/// <summary>
|
||||
/// Legacy osu! Hit-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class Hit : HitObject, IHasPosition, IHasCombo
|
||||
internal sealed class ConvertHit : HitObject, IHasPosition, IHasCombo
|
||||
{
|
||||
public Vector2 Position { get; set; }
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@ -10,33 +11,34 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
/// <summary>
|
||||
/// A HitObjectParser to parse legacy osu! Beatmaps.
|
||||
/// </summary>
|
||||
internal class HitObjectParser : Legacy.HitObjectParser
|
||||
internal class ConvertHitObjectParser : Legacy.ConvertHitObjectParser
|
||||
{
|
||||
protected override HitObject CreateHit(Vector2 position, bool newCombo)
|
||||
{
|
||||
return new Hit
|
||||
return new ConvertHit
|
||||
{
|
||||
Position = position,
|
||||
NewCombo = newCombo,
|
||||
};
|
||||
}
|
||||
|
||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount)
|
||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
|
||||
{
|
||||
return new Slider
|
||||
return new ConvertSlider
|
||||
{
|
||||
Position = position,
|
||||
NewCombo = newCombo,
|
||||
ControlPoints = controlPoints,
|
||||
Distance = length,
|
||||
CurveType = curveType,
|
||||
RepeatSamples = repeatSamples,
|
||||
RepeatCount = repeatCount
|
||||
};
|
||||
}
|
||||
|
||||
protected override HitObject CreateSpinner(Vector2 position, double endTime)
|
||||
{
|
||||
return new Spinner
|
||||
return new ConvertSpinner
|
||||
{
|
||||
Position = position,
|
||||
EndTime = endTime
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
/// <summary>
|
||||
/// Legacy osu! Slider-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class Slider : CurvedHitObject, IHasPosition, IHasCombo
|
||||
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasPosition, IHasCombo
|
||||
{
|
||||
public Vector2 Position { get; set; }
|
||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
/// <summary>
|
||||
/// Legacy osu! Spinner-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class Spinner : HitObject, IHasEndTime, IHasPosition
|
||||
internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasPosition
|
||||
{
|
||||
public double EndTime { get; set; }
|
||||
|
@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
||||
/// <summary>
|
||||
/// Legacy osu!taiko Hit-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class Hit : HitObject, IHasCombo
|
||||
internal sealed class ConvertHit : HitObject, IHasCombo
|
||||
{
|
||||
public bool NewCombo { get; set; }
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@ -10,31 +11,32 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
||||
/// <summary>
|
||||
/// A HitObjectParser to parse legacy osu!taiko Beatmaps.
|
||||
/// </summary>
|
||||
internal class HitObjectParser : Legacy.HitObjectParser
|
||||
internal class ConvertHitObjectParser : Legacy.ConvertHitObjectParser
|
||||
{
|
||||
protected override HitObject CreateHit(Vector2 position, bool newCombo)
|
||||
{
|
||||
return new Hit
|
||||
return new ConvertHit
|
||||
{
|
||||
NewCombo = newCombo,
|
||||
};
|
||||
}
|
||||
|
||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount)
|
||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
|
||||
{
|
||||
return new Slider
|
||||
return new ConvertSlider
|
||||
{
|
||||
NewCombo = newCombo,
|
||||
ControlPoints = controlPoints,
|
||||
Distance = length,
|
||||
CurveType = curveType,
|
||||
RepeatSamples = repeatSamples,
|
||||
RepeatCount = repeatCount
|
||||
};
|
||||
}
|
||||
|
||||
protected override HitObject CreateSpinner(Vector2 position, double endTime)
|
||||
{
|
||||
return new Spinner
|
||||
return new ConvertSpinner
|
||||
{
|
||||
EndTime = endTime
|
||||
};
|
@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
||||
/// <summary>
|
||||
/// Legacy osu!taiko Slider-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class Slider : CurvedHitObject, IHasCombo
|
||||
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasCombo
|
||||
{
|
||||
public bool NewCombo { get; set; }
|
||||
}
|
@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
||||
/// <summary>
|
||||
/// Legacy osu!taiko Spinner-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class Spinner : HitObject, IHasEndTime
|
||||
internal sealed class ConvertSpinner : HitObject, IHasEndTime
|
||||
{
|
||||
public double EndTime { get; set; }
|
||||
|
@ -11,11 +11,6 @@ namespace osu.Game.Rulesets.Objects.Types
|
||||
/// </summary>
|
||||
public interface IHasCurve : IHasDistance, IHasRepeats
|
||||
{
|
||||
/// <summary>
|
||||
/// The curve.
|
||||
/// </summary>
|
||||
SliderCurve Curve { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The control points that shape the curve.
|
||||
/// </summary>
|
||||
|
@ -1,6 +1,9 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Audio;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Types
|
||||
{
|
||||
/// <summary>
|
||||
@ -12,5 +15,10 @@ namespace osu.Game.Rulesets.Objects.Types
|
||||
/// The amount of times the HitObject repeats.
|
||||
/// </summary>
|
||||
int RepeatCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The samples to be played when each repeat node is hit (0 -> first repeat node, 1 -> second repeat node, etc).
|
||||
/// </summary>
|
||||
List<List<SampleInfo>> RepeatSamples { get; }
|
||||
}
|
||||
}
|
||||
|
@ -109,6 +109,20 @@
|
||||
<Compile Include="IO\Serialization\IJsonSerializable.cs" />
|
||||
<Compile Include="IPC\ScoreIPCChannel.cs" />
|
||||
<Compile Include="Rulesets\BeatmapStatistic.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Catch\ConvertHit.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Catch\ConvertHitObjectParser.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Catch\ConvertSlider.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Catch\ConvertSpinner.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\ConvertSlider.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Mania\ConvertHit.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Mania\ConvertHitObjectParser.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Mania\ConvertSlider.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Mania\ConvertSpinner.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Osu\ConvertHitObjectParser.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Taiko\ConvertHit.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Taiko\ConvertHitObjectParser.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Taiko\ConvertSlider.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Taiko\ConvertSpinner.cs" />
|
||||
<Compile Include="Rulesets\Mods\IApplicableToClock.cs" />
|
||||
<Compile Include="Rulesets\Mods\ModAutoplay.cs" />
|
||||
<Compile Include="Rulesets\Mods\ModCinema.cs" />
|
||||
@ -124,19 +138,6 @@
|
||||
<Compile Include="Rulesets\Mods\ModRelax.cs" />
|
||||
<Compile Include="Rulesets\Mods\ModSuddenDeath.cs" />
|
||||
<Compile Include="Rulesets\Mods\MultiMod.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Catch\Hit.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Catch\HitObjectParser.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Catch\Slider.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Catch\Spinner.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Mania\Hit.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Mania\HitObjectParser.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Mania\Slider.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Mania\Spinner.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Osu\HitObjectParser.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Taiko\Hit.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Taiko\HitObjectParser.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Taiko\Slider.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Taiko\Spinner.cs" />
|
||||
<Compile Include="Rulesets\Objects\Types\IHasXPosition.cs" />
|
||||
<Compile Include="Rulesets\Objects\Types\IHasYPosition.cs" />
|
||||
<Compile Include="Rulesets\Replays\Replay.cs" />
|
||||
@ -149,12 +150,11 @@
|
||||
<Compile Include="Rulesets\Objects\Drawables\HitResult.cs" />
|
||||
<Compile Include="Rulesets\Objects\BezierApproximator.cs" />
|
||||
<Compile Include="Rulesets\Objects\CircularArcApproximator.cs" />
|
||||
<Compile Include="Rulesets\Objects\CurvedHitObject.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Osu\Hit.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\HitObjectParser.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Hold.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Osu\Slider.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Osu\Spinner.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Osu\ConvertHit.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\ConvertHitObjectParser.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\ConvertHold.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Osu\ConvertSlider.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\Osu\ConvertSpinner.cs" />
|
||||
<Compile Include="Rulesets\Objects\SliderCurve.cs" />
|
||||
<Compile Include="Rulesets\Objects\Types\CurveType.cs" />
|
||||
<Compile Include="Rulesets\Objects\Drawables\IDrawableHitObjectWithProxiedApproach.cs" />
|
||||
@ -167,7 +167,7 @@
|
||||
<Compile Include="Rulesets\Objects\Types\IHasRepeats.cs" />
|
||||
<Compile Include="Rulesets\Objects\Types\IHasPosition.cs" />
|
||||
<Compile Include="Rulesets\Objects\Types\IHasHold.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\HitObjectType.cs" />
|
||||
<Compile Include="Rulesets\Objects\Legacy\ConvertHitObjectType.cs" />
|
||||
<Compile Include="Rulesets\Replays\ReplayButtonState.cs" />
|
||||
<Compile Include="Rulesets\Replays\ReplayFrame.cs" />
|
||||
<Compile Include="Database\RulesetDatabase.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user