2019-01-24 08:43:03 +00:00
|
|
|
|
// 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.
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2022-06-17 07:37:17 +00:00
|
|
|
|
#nullable disable
|
|
|
|
|
|
2017-04-17 06:44:46 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2020-09-17 08:40:05 +00:00
|
|
|
|
using System.Threading;
|
2019-12-24 07:02:16 +00:00
|
|
|
|
using osu.Game.Rulesets;
|
2017-04-18 07:05:58 +00:00
|
|
|
|
using osu.Game.Rulesets.Objects;
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2017-09-18 13:32:49 +00:00
|
|
|
|
namespace osu.Game.Beatmaps
|
2017-03-11 15:34:21 +00:00
|
|
|
|
{
|
2017-03-13 10:15:25 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Converts a Beatmap for another mode.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T">The type of HitObject stored in the Beatmap.</typeparam>
|
2018-03-02 11:19:47 +00:00
|
|
|
|
public abstract class BeatmapConverter<T> : IBeatmapConverter
|
2018-03-01 15:07:02 +00:00
|
|
|
|
where T : HitObject
|
2017-03-11 15:34:21 +00:00
|
|
|
|
{
|
2021-03-15 04:35:08 +00:00
|
|
|
|
private event Action<HitObject, IEnumerable<HitObject>> objectConverted;
|
2019-02-28 04:31:40 +00:00
|
|
|
|
|
2018-03-02 11:19:47 +00:00
|
|
|
|
event Action<HitObject, IEnumerable<HitObject>> IBeatmapConverter.ObjectConverted
|
2018-03-01 15:07:02 +00:00
|
|
|
|
{
|
2021-03-15 04:35:08 +00:00
|
|
|
|
add => objectConverted += value;
|
|
|
|
|
remove => objectConverted -= value;
|
2018-03-01 15:07:02 +00:00
|
|
|
|
}
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2018-04-19 13:04:12 +00:00
|
|
|
|
public IBeatmap Beatmap { get; }
|
|
|
|
|
|
2019-12-24 07:02:16 +00:00
|
|
|
|
protected BeatmapConverter(IBeatmap beatmap, Ruleset ruleset)
|
2018-04-19 13:04:12 +00:00
|
|
|
|
{
|
|
|
|
|
Beatmap = beatmap;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-17 06:44:46 +00:00
|
|
|
|
/// <summary>
|
2018-04-19 13:04:12 +00:00
|
|
|
|
/// Whether <see cref="Beatmap"/> can be converted by this <see cref="BeatmapConverter{T}"/>.
|
2017-04-17 06:44:46 +00:00
|
|
|
|
/// </summary>
|
2019-12-23 08:44:18 +00:00
|
|
|
|
public abstract bool CanConvert();
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2020-09-17 08:40:05 +00:00
|
|
|
|
public IBeatmap Convert(CancellationToken cancellationToken = default)
|
2017-04-18 05:24:16 +00:00
|
|
|
|
{
|
|
|
|
|
// We always operate on a clone of the original beatmap, to not modify it game-wide
|
2021-10-12 07:42:09 +00:00
|
|
|
|
var original = Beatmap.Clone();
|
|
|
|
|
|
|
|
|
|
// Shallow clone isn't enough to ensure we don't mutate beatmap info unexpectedly.
|
|
|
|
|
// Can potentially be removed after `Beatmap.Difficulty` doesn't save back to `Beatmap.BeatmapInfo`.
|
|
|
|
|
original.BeatmapInfo = original.BeatmapInfo.Clone();
|
2022-11-01 08:37:32 +00:00
|
|
|
|
original.ControlPointInfo = original.ControlPointInfo.DeepClone();
|
2021-10-12 07:42:09 +00:00
|
|
|
|
|
|
|
|
|
return ConvertBeatmap(original, cancellationToken);
|
2017-04-18 05:24:16 +00:00
|
|
|
|
}
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2017-04-17 06:44:46 +00:00
|
|
|
|
/// <summary>
|
2017-04-18 05:24:16 +00:00
|
|
|
|
/// Performs the conversion of a Beatmap using this Beatmap Converter.
|
2017-04-17 06:44:46 +00:00
|
|
|
|
/// </summary>
|
2017-04-18 05:24:16 +00:00
|
|
|
|
/// <param name="original">The un-converted Beatmap.</param>
|
2020-09-17 08:40:05 +00:00
|
|
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
2017-04-18 05:24:16 +00:00
|
|
|
|
/// <returns>The converted Beatmap.</returns>
|
2020-09-17 08:40:05 +00:00
|
|
|
|
protected virtual Beatmap<T> ConvertBeatmap(IBeatmap original, CancellationToken cancellationToken)
|
2017-04-18 05:24:16 +00:00
|
|
|
|
{
|
2018-01-03 09:44:25 +00:00
|
|
|
|
var beatmap = CreateBeatmap();
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2018-01-03 09:44:25 +00:00
|
|
|
|
beatmap.BeatmapInfo = original.BeatmapInfo;
|
|
|
|
|
beatmap.ControlPointInfo = original.ControlPointInfo;
|
2020-09-17 08:40:05 +00:00
|
|
|
|
beatmap.HitObjects = convertHitObjects(original.HitObjects, original, cancellationToken).OrderBy(s => s.StartTime).ToList();
|
2018-03-13 10:14:01 +00:00
|
|
|
|
beatmap.Breaks = original.Breaks;
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2018-01-03 09:44:25 +00:00
|
|
|
|
return beatmap;
|
2017-04-18 05:24:16 +00:00
|
|
|
|
}
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2020-09-17 08:40:05 +00:00
|
|
|
|
private List<T> convertHitObjects(IReadOnlyList<HitObject> hitObjects, IBeatmap beatmap, CancellationToken cancellationToken)
|
2017-04-18 05:24:16 +00:00
|
|
|
|
{
|
2018-10-11 11:29:26 +00:00
|
|
|
|
var result = new List<T>(hitObjects.Count);
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2018-10-11 11:29:26 +00:00
|
|
|
|
foreach (var obj in hitObjects)
|
2017-04-18 05:46:56 +00:00
|
|
|
|
{
|
2018-10-11 11:29:26 +00:00
|
|
|
|
if (obj is T tObj)
|
|
|
|
|
{
|
|
|
|
|
result.Add(tObj);
|
2017-04-18 05:46:56 +00:00
|
|
|
|
continue;
|
2018-10-11 11:29:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-17 08:40:05 +00:00
|
|
|
|
var converted = ConvertHitObject(obj, beatmap, cancellationToken);
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2021-03-15 04:35:08 +00:00
|
|
|
|
if (objectConverted != null)
|
2018-10-16 03:01:58 +00:00
|
|
|
|
{
|
|
|
|
|
converted = converted.ToList();
|
2021-03-15 04:35:08 +00:00
|
|
|
|
objectConverted.Invoke(obj, converted);
|
2018-10-16 03:01:58 +00:00
|
|
|
|
}
|
2018-10-11 11:29:26 +00:00
|
|
|
|
|
|
|
|
|
foreach (var c in converted)
|
|
|
|
|
{
|
|
|
|
|
if (c != null)
|
|
|
|
|
result.Add(c);
|
|
|
|
|
}
|
2017-04-18 05:46:56 +00:00
|
|
|
|
}
|
2018-10-11 11:29:26 +00:00
|
|
|
|
|
|
|
|
|
return result;
|
2017-04-18 05:24:16 +00:00
|
|
|
|
}
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2018-01-03 09:44:25 +00:00
|
|
|
|
/// <summary>
|
2019-04-25 08:36:17 +00:00
|
|
|
|
/// Creates the <see cref="Beatmap{T}"/> that will be returned by this <see cref="BeatmapProcessor"/>.
|
2018-01-03 09:44:25 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
protected virtual Beatmap<T> CreateBeatmap() => new Beatmap<T>();
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2017-04-18 05:24:16 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Performs the conversion of a hit object.
|
2017-11-28 12:30:03 +00:00
|
|
|
|
/// This method is generally executed sequentially for all objects in a beatmap.
|
2017-04-18 05:24:16 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="original">The hit object to convert.</param>
|
|
|
|
|
/// <param name="beatmap">The un-converted Beatmap.</param>
|
2020-09-17 08:40:05 +00:00
|
|
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
2017-04-18 05:24:16 +00:00
|
|
|
|
/// <returns>The converted hit object.</returns>
|
2021-04-09 04:56:55 +00:00
|
|
|
|
protected virtual IEnumerable<T> ConvertHitObject(HitObject original, IBeatmap beatmap, CancellationToken cancellationToken) => Enumerable.Empty<T>();
|
2017-04-17 06:44:46 +00:00
|
|
|
|
}
|
2017-03-11 15:34:21 +00:00
|
|
|
|
}
|