mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 11:37:28 +08:00
Move all conversion code to LegacyBeatmapExporter
This commit is contained in:
parent
8ca801a224
commit
1d837a8725
@ -18,18 +18,14 @@ using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Utils;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
@ -411,86 +407,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
public Task Export(BeatmapSetInfo beatmap) => beatmapExporter.ExportAsync(beatmap.ToLive(Realm));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of the <see cref="BeatmapSetInfo"/> and converts all beatmaps to legacy format, then exports it as a legacy package.
|
||||
/// </summary>
|
||||
/// <param name="beatmapSetInfo"></param>
|
||||
/// <returns></returns>
|
||||
public Task ExportLegacy(BeatmapSetInfo beatmapSetInfo)
|
||||
{
|
||||
// Create a clone of the original beatmap set which we will convert to legacy format and then export
|
||||
var clone = new BeatmapSetInfo(beatmapSetInfo.Beatmaps.Select(b => b.Clone()));
|
||||
clone.Files.AddRange(beatmapSetInfo.Files.Select(f => new RealmNamedFileUsage(f.File, f.Filename)));
|
||||
|
||||
// convert all beatmaps in the cloned beatmap set to legacy format
|
||||
foreach (var beatmapInfo in clone.Beatmaps)
|
||||
{
|
||||
beatmapInfo.BeatmapSet = clone;
|
||||
beatmapInfo.ID = Guid.NewGuid();
|
||||
|
||||
var file = beatmapInfo.File;
|
||||
if (file == null)
|
||||
continue;
|
||||
|
||||
using var contentStream = RealmFileStore.Storage.GetStream(file.File.GetStoragePath());
|
||||
using var contentStreamReader = new LineBufferedReader(contentStream);
|
||||
var beatmapContent = new LegacyBeatmapDecoder().Decode(contentStreamReader);
|
||||
|
||||
using var skinStream = RealmFileStore.Storage.GetStream(file.File.GetStoragePath());
|
||||
using var skinStreamReader = new LineBufferedReader(contentStream);
|
||||
var beatmapSkin = new LegacySkin(new SkinInfo(), null!)
|
||||
{
|
||||
Configuration = new LegacySkinDecoder().Decode(skinStreamReader)
|
||||
};
|
||||
|
||||
Realm.Realm.Write(realm =>
|
||||
{
|
||||
using var stream = new MemoryStream();
|
||||
convertAndEncodeLegacyBeatmap(beatmapContent, beatmapSkin, stream);
|
||||
|
||||
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
|
||||
beatmapInfo.Hash = stream.ComputeSHA2Hash();
|
||||
|
||||
file.File = RealmFileStore.Add(stream, realm).Detach();
|
||||
});
|
||||
}
|
||||
|
||||
return legacyBeatmapExporter.ExportAsync(new RealmLiveUnmanaged<BeatmapSetInfo>(clone));
|
||||
}
|
||||
|
||||
private void convertAndEncodeLegacyBeatmap(IBeatmap beatmapContent, ISkin beatmapSkin, Stream stream)
|
||||
{
|
||||
// Convert beatmap elements to be compatible with legacy format
|
||||
// So we truncate time and position values to integers, and convert paths with multiple segments to bezier curves
|
||||
foreach (var controlPoint in beatmapContent.ControlPointInfo.AllControlPoints)
|
||||
controlPoint.Time = Math.Floor(controlPoint.Time);
|
||||
|
||||
foreach (var hitObject in beatmapContent.HitObjects)
|
||||
{
|
||||
hitObject.StartTime = Math.Floor(hitObject.StartTime);
|
||||
|
||||
if (hitObject is not IHasPath hasPath || BezierConverter.CountSegments(hasPath.Path.ControlPoints) <= 1) continue;
|
||||
|
||||
var newControlPoints = BezierConverter.ConvertToModernBezier(hasPath.Path.ControlPoints);
|
||||
|
||||
// Truncate control points to integer positions
|
||||
foreach (var pathControlPoint in newControlPoints)
|
||||
{
|
||||
pathControlPoint.Position = new Vector2(
|
||||
(float)Math.Floor(pathControlPoint.Position.X),
|
||||
(float)Math.Floor(pathControlPoint.Position.Y));
|
||||
}
|
||||
|
||||
hasPath.Path.ControlPoints.Clear();
|
||||
hasPath.Path.ControlPoints.AddRange(newControlPoints);
|
||||
}
|
||||
|
||||
// Encode to legacy format
|
||||
using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
||||
new LegacyBeatmapEncoder(beatmapContent, beatmapSkin).Encode(sw);
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
public Task ExportLegacy(BeatmapSetInfo beatmap) => legacyBeatmapExporter.ExportAsync(beatmap.ToLive(Realm));
|
||||
|
||||
private void updateHashAndMarkDirty(BeatmapSetInfo setInfo)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ namespace osu.Game.Database
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using (var stream = UserFileStorage.GetStream(file.File.GetStoragePath()))
|
||||
using (var stream = GetFileContents(model, file))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
@ -65,5 +65,7 @@ namespace osu.Game.Database
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual Stream? GetFileContents(TModel model, INamedFileUsage file) => UserFileStorage.GetStream(file.File.GetStoragePath());
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,25 @@
|
||||
// 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;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Database
|
||||
{
|
||||
/// <summary>
|
||||
/// Exporter for osu!stable legacy beatmap archives.
|
||||
/// Converts all beatmaps in the set to legacy format and exports it as a legacy package.
|
||||
/// </summary>
|
||||
public class LegacyBeatmapExporter : LegacyArchiveExporter<BeatmapSetInfo>
|
||||
{
|
||||
@ -16,6 +28,64 @@ namespace osu.Game.Database
|
||||
{
|
||||
}
|
||||
|
||||
protected override Stream? GetFileContents(BeatmapSetInfo model, INamedFileUsage file)
|
||||
{
|
||||
bool isBeatmap = model.Beatmaps.Any(o => o.Hash == file.File.Hash);
|
||||
|
||||
if (!isBeatmap)
|
||||
return base.GetFileContents(model, file);
|
||||
|
||||
// Read the beatmap contents and skin
|
||||
using var contentStream = UserFileStorage.GetStream(file.File.GetStoragePath());
|
||||
|
||||
if (contentStream == null)
|
||||
return null;
|
||||
|
||||
using var contentStreamReader = new LineBufferedReader(contentStream);
|
||||
var beatmapContent = new LegacyBeatmapDecoder().Decode(contentStreamReader);
|
||||
|
||||
using var skinStream = UserFileStorage.GetStream(file.File.GetStoragePath());
|
||||
using var skinStreamReader = new LineBufferedReader(contentStream);
|
||||
var beatmapSkin = new LegacySkin(new SkinInfo(), null!)
|
||||
{
|
||||
Configuration = new LegacySkinDecoder().Decode(skinStreamReader)
|
||||
};
|
||||
|
||||
// Convert beatmap elements to be compatible with legacy format
|
||||
// So we truncate time and position values to integers, and convert paths with multiple segments to bezier curves
|
||||
foreach (var controlPoint in beatmapContent.ControlPointInfo.AllControlPoints)
|
||||
controlPoint.Time = Math.Floor(controlPoint.Time);
|
||||
|
||||
foreach (var hitObject in beatmapContent.HitObjects)
|
||||
{
|
||||
hitObject.StartTime = Math.Floor(hitObject.StartTime);
|
||||
|
||||
if (hitObject is not IHasPath hasPath || BezierConverter.CountSegments(hasPath.Path.ControlPoints) <= 1) continue;
|
||||
|
||||
var newControlPoints = BezierConverter.ConvertToModernBezier(hasPath.Path.ControlPoints);
|
||||
|
||||
// Truncate control points to integer positions
|
||||
foreach (var pathControlPoint in newControlPoints)
|
||||
{
|
||||
pathControlPoint.Position = new Vector2(
|
||||
(float)Math.Floor(pathControlPoint.Position.X),
|
||||
(float)Math.Floor(pathControlPoint.Position.Y));
|
||||
}
|
||||
|
||||
hasPath.Path.ControlPoints.Clear();
|
||||
hasPath.Path.ControlPoints.AddRange(newControlPoints);
|
||||
}
|
||||
|
||||
// Encode to legacy format
|
||||
var stream = new MemoryStream();
|
||||
using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
||||
new LegacyBeatmapEncoder(beatmapContent, beatmapSkin).Encode(sw);
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
protected override string FileExtension => @".osz";
|
||||
}
|
||||
}
|
||||
|
@ -25,11 +25,11 @@ namespace osu.Game.Database
|
||||
|
||||
protected RealmAccess Realm { get; }
|
||||
|
||||
protected readonly RealmFileStore RealmFileStore;
|
||||
private readonly RealmFileStore realmFileStore;
|
||||
|
||||
public ModelManager(Storage storage, RealmAccess realm)
|
||||
{
|
||||
RealmFileStore = new RealmFileStore(realm, storage);
|
||||
realmFileStore = new RealmFileStore(realm, storage);
|
||||
Realm = realm;
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ namespace osu.Game.Database
|
||||
/// </summary>
|
||||
public void ReplaceFile(RealmNamedFileUsage file, Stream contents, Realm realm)
|
||||
{
|
||||
file.File = RealmFileStore.Add(contents, realm);
|
||||
file.File = realmFileStore.Add(contents, realm);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -93,7 +93,7 @@ namespace osu.Game.Database
|
||||
return;
|
||||
}
|
||||
|
||||
var file = RealmFileStore.Add(contents, realm);
|
||||
var file = realmFileStore.Add(contents, realm);
|
||||
var namedUsage = new RealmNamedFileUsage(file, filename);
|
||||
|
||||
item.Files.Add(namedUsage);
|
||||
|
Loading…
Reference in New Issue
Block a user