mirror of
https://github.com/osukey/osukey.git
synced 2025-08-04 23:24:04 +09:00
Merge branch 'master' into ruleset-replayframes
This commit is contained in:
@ -12,8 +12,16 @@ namespace osu.Game.Beatmaps
|
||||
/// Converts a Beatmap for another mode.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of HitObject stored in the Beatmap.</typeparam>
|
||||
public abstract class BeatmapConverter<T> where T : HitObject
|
||||
public abstract class BeatmapConverter<T> : IBeatmapConverter
|
||||
where T : HitObject
|
||||
{
|
||||
private event Action<HitObject, IEnumerable<HitObject>> ObjectConverted;
|
||||
event Action<HitObject, IEnumerable<HitObject>> IBeatmapConverter.ObjectConverted
|
||||
{
|
||||
add => ObjectConverted += value;
|
||||
remove => ObjectConverted -= value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a Beatmap can be converted using this Beatmap Converter.
|
||||
/// </summary>
|
||||
@ -32,6 +40,8 @@ namespace osu.Game.Beatmaps
|
||||
return ConvertBeatmap(new Beatmap(original));
|
||||
}
|
||||
|
||||
void IBeatmapConverter.Convert(Beatmap original) => Convert(original);
|
||||
|
||||
/// <summary>
|
||||
/// Performs the conversion of a Beatmap using this Beatmap Converter.
|
||||
/// </summary>
|
||||
@ -63,8 +73,11 @@ namespace osu.Game.Beatmaps
|
||||
yield break;
|
||||
}
|
||||
|
||||
var converted = ConvertHitObject(original, beatmap).ToList();
|
||||
ObjectConverted?.Invoke(original, converted);
|
||||
|
||||
// Convert the hit object
|
||||
foreach (var obj in ConvertHitObject(original, beatmap))
|
||||
foreach (var obj in converted)
|
||||
{
|
||||
if (obj == null)
|
||||
continue;
|
||||
|
25
osu.Game/Beatmaps/IBeatmapConverter.cs
Normal file
25
osu.Game/Beatmaps/IBeatmapConverter.cs
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public interface IBeatmapConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked when a <see cref="HitObject"/> has been converted.
|
||||
/// The first argument contains the <see cref="HitObject"/> that was converted.
|
||||
/// The second argument contains the <see cref="HitObject"/>s that were output from the conversion process.
|
||||
/// </summary>
|
||||
event Action<HitObject, IEnumerable<HitObject>> ObjectConverted;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Beatmap using this Beatmap Converter.
|
||||
/// </summary>
|
||||
/// <param name="original">The un-converted Beatmap.</param>
|
||||
void Convert(Beatmap beatmap);
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ using System.Globalization;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.Audio;
|
||||
using System.Linq;
|
||||
using osu.Framework.MathUtils;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy
|
||||
{
|
||||
@ -74,6 +75,11 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
points.Add(new Vector2((int)Convert.ToDouble(temp[0], CultureInfo.InvariantCulture), (int)Convert.ToDouble(temp[1], CultureInfo.InvariantCulture)) - pos);
|
||||
}
|
||||
|
||||
// osu-stable special-cased colinear perfect curves to a CurveType.Linear
|
||||
bool isLinear(List<Vector2> p) => Precision.AlmostEquals(0, (p[1].Y - p[0].Y) * (p[2].X - p[0].X) - (p[1].X - p[0].X) * (p[2].Y - p[0].Y));
|
||||
if (points.Count == 3 && curveType == CurveType.PerfectCurve && isLinear(points))
|
||||
curveType = CurveType.Linear;
|
||||
|
||||
int repeatCount = Convert.ToInt32(split[6], CultureInfo.InvariantCulture);
|
||||
|
||||
if (repeatCount > 9000)
|
||||
|
141
osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs
Normal file
141
osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs
Normal file
@ -0,0 +1,141 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps
|
||||
{
|
||||
[TestFixture]
|
||||
public abstract class BeatmapConversionTest<TConvertValue>
|
||||
where TConvertValue : IEquatable<TConvertValue>
|
||||
{
|
||||
private const string resource_namespace = "Testing.Beatmaps";
|
||||
private const string expected_conversion_suffix = "-expected-conversion";
|
||||
|
||||
protected abstract string ResourceAssembly { get; }
|
||||
|
||||
protected void Test(string name)
|
||||
{
|
||||
var ourResult = convert(name);
|
||||
var expectedResult = read(name);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
int mappingCounter = 0;
|
||||
while (true)
|
||||
{
|
||||
if (mappingCounter >= ourResult.Mappings.Count && mappingCounter >= expectedResult.Mappings.Count)
|
||||
break;
|
||||
if (mappingCounter >= ourResult.Mappings.Count)
|
||||
Assert.Fail($"A conversion did not generate any hitobjects, but should have, for hitobject at time: {expectedResult.Mappings[mappingCounter].StartTime}\n");
|
||||
else if (mappingCounter >= expectedResult.Mappings.Count)
|
||||
Assert.Fail($"A conversion generated hitobjects, but should not have, for hitobject at time: {ourResult.Mappings[mappingCounter].StartTime}\n");
|
||||
else
|
||||
{
|
||||
var counter = mappingCounter;
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
var ourMapping = ourResult.Mappings[counter];
|
||||
var expectedMapping = expectedResult.Mappings[counter];
|
||||
|
||||
int objectCounter = 0;
|
||||
while (true)
|
||||
{
|
||||
if (objectCounter >= ourMapping.Objects.Count && objectCounter >= expectedMapping.Objects.Count)
|
||||
break;
|
||||
if (objectCounter >= ourMapping.Objects.Count)
|
||||
Assert.Fail($"The conversion did not generate a hitobject, but should have, for hitobject at time: {expectedMapping.StartTime}:\n"
|
||||
+ $"Expected: {JsonConvert.SerializeObject(expectedMapping.Objects[objectCounter])}\n");
|
||||
else if (objectCounter >= expectedMapping.Objects.Count)
|
||||
Assert.Fail($"The conversion generated a hitobject, but should not have, for hitobject at time: {ourMapping.StartTime}:\n"
|
||||
+ $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n");
|
||||
else if (!EqualityComparer<TConvertValue>.Default.Equals(expectedMapping.Objects[objectCounter], ourMapping.Objects[objectCounter]))
|
||||
{
|
||||
Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}\n"
|
||||
+ $"Expected: {JsonConvert.SerializeObject(expectedMapping.Objects[objectCounter])}\n"
|
||||
+ $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n");
|
||||
}
|
||||
|
||||
objectCounter++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mappingCounter++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private ConvertResult convert(string name)
|
||||
{
|
||||
var beatmap = getBeatmap(name);
|
||||
|
||||
var result = new ConvertResult();
|
||||
|
||||
var converter = CreateConverter(beatmap);
|
||||
converter.ObjectConverted += (orig, converted) =>
|
||||
{
|
||||
converted.ForEach(h => h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty));
|
||||
|
||||
var mapping = new ConvertMapping { StartTime = orig.StartTime };
|
||||
foreach (var obj in converted)
|
||||
mapping.Objects.AddRange(CreateConvertValue(obj));
|
||||
result.Mappings.Add(mapping);
|
||||
};
|
||||
|
||||
converter.Convert(beatmap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private ConvertResult read(string name)
|
||||
{
|
||||
using (var resStream = openResource($"{resource_namespace}.{name}{expected_conversion_suffix}.json"))
|
||||
using (var reader = new StreamReader(resStream))
|
||||
{
|
||||
var contents = reader.ReadToEnd();
|
||||
return JsonConvert.DeserializeObject<ConvertResult>(contents);
|
||||
}
|
||||
}
|
||||
|
||||
private Beatmap getBeatmap(string name)
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder();
|
||||
using (var resStream = openResource($"{resource_namespace}.{name}.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
return decoder.DecodeBeatmap(stream);
|
||||
}
|
||||
|
||||
private Stream openResource(string name)
|
||||
{
|
||||
var localPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
|
||||
return Assembly.LoadFrom(Path.Combine(localPath, $"{ResourceAssembly}.dll")).GetManifestResourceStream($@"{ResourceAssembly}.Resources.{name}");
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<TConvertValue> CreateConvertValue(HitObject hitObject);
|
||||
protected abstract IBeatmapConverter CreateConverter(Beatmap beatmap);
|
||||
|
||||
private class ConvertMapping
|
||||
{
|
||||
[JsonProperty]
|
||||
public double StartTime;
|
||||
[JsonProperty]
|
||||
public List<TConvertValue> Objects = new List<TConvertValue>();
|
||||
}
|
||||
|
||||
private class ConvertResult
|
||||
{
|
||||
[JsonProperty]
|
||||
public List<ConvertMapping> Mappings = new List<ConvertMapping>();
|
||||
}
|
||||
}
|
||||
}
|
15
osu.Game/Tests/TestTestCase.cs
Normal file
15
osu.Game/Tests/TestTestCase.cs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Testing;
|
||||
|
||||
namespace osu.Game.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
internal class TestTestCase : TestCase
|
||||
{
|
||||
// This TestCase is required for nunit to not throw errors
|
||||
// See: https://github.com/nunit/nunit/issues/1118
|
||||
}
|
||||
}
|
@ -270,6 +270,7 @@
|
||||
<Compile Include="Beatmaps\Formats\JsonBeatmapDecoder.cs" />
|
||||
<Compile Include="Beatmaps\Formats\LegacyDecoder.cs" />
|
||||
<Compile Include="Beatmaps\Formats\LegacyStoryboardDecoder.cs" />
|
||||
<Compile Include="Beatmaps\IBeatmapConverter.cs" />
|
||||
<Compile Include="Configuration\DatabasedSetting.cs" />
|
||||
<Compile Include="Configuration\SettingsStore.cs" />
|
||||
<Compile Include="Configuration\DatabasedConfigManager.cs" />
|
||||
@ -886,9 +887,11 @@
|
||||
<Compile Include="Storyboards\StoryboardLayer.cs" />
|
||||
<Compile Include="Storyboards\StoryboardSample.cs" />
|
||||
<Compile Include="Storyboards\StoryboardSprite.cs" />
|
||||
<Compile Include="Tests\Beatmaps\BeatmapConversionTest.cs" />
|
||||
<Compile Include="Tests\Beatmaps\TestWorkingBeatmap.cs" />
|
||||
<Compile Include="Tests\CleanRunHeadlessGameHost.cs" />
|
||||
<Compile Include="Tests\Platform\TestStorage.cs" />
|
||||
<Compile Include="Tests\TestTestCase.cs" />
|
||||
<Compile Include="Tests\Visual\OsuTestCase.cs" />
|
||||
<Compile Include="Tests\Visual\TestCasePerformancePoints.cs" />
|
||||
<Compile Include="Tests\Visual\ScreenTestCase.cs" />
|
||||
|
Reference in New Issue
Block a user