mirror of
https://github.com/ppy/osu.git
synced 2024-09-21 19:27:24 +08:00
Merge pull request #8818 from smoogipoo/fix-beatmap-encoder
Fix beatmap encoder by enabling untested test cases
This commit is contained in:
commit
aaa0f908d5
@ -1,14 +1,23 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Audio.Track;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
using osu.Game.IO.Serialization;
|
using osu.Game.IO.Serialization;
|
||||||
|
using osu.Game.Rulesets.Catch;
|
||||||
|
using osu.Game.Rulesets.Mania;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Rulesets.Taiko;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Beatmaps.Formats
|
namespace osu.Game.Tests.Beatmaps.Formats
|
||||||
@ -16,39 +25,91 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class LegacyBeatmapEncoderTest
|
public class LegacyBeatmapEncoderTest
|
||||||
{
|
{
|
||||||
private const string normal = "Soleily - Renatus (Gamu) [Insane].osu";
|
|
||||||
|
|
||||||
private static IEnumerable<string> allBeatmaps => TestResources.GetStore().GetAvailableResources().Where(res => res.EndsWith(".osu"));
|
private static IEnumerable<string> allBeatmaps => TestResources.GetStore().GetAvailableResources().Where(res => res.EndsWith(".osu"));
|
||||||
|
|
||||||
[TestCaseSource(nameof(allBeatmaps))]
|
[TestCaseSource(nameof(allBeatmaps))]
|
||||||
public void TestDecodeEncodedBeatmap(string name)
|
public void TestBeatmap(string name)
|
||||||
{
|
{
|
||||||
var decoded = decode(normal, out var encoded);
|
var decoded = decode(name, out var encoded);
|
||||||
|
|
||||||
|
sort(decoded);
|
||||||
|
sort(encoded);
|
||||||
|
|
||||||
Assert.That(decoded.HitObjects.Count, Is.EqualTo(encoded.HitObjects.Count));
|
|
||||||
Assert.That(encoded.Serialize(), Is.EqualTo(decoded.Serialize()));
|
Assert.That(encoded.Serialize(), Is.EqualTo(decoded.Serialize()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Beatmap decode(string filename, out Beatmap encoded)
|
private void sort(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
using (var stream = TestResources.OpenResource(filename))
|
// Sort control points to ensure a sane ordering, as they may be parsed in different orders. This works because each group contains only uniquely-typed control points.
|
||||||
|
foreach (var g in beatmap.ControlPointInfo.Groups)
|
||||||
|
{
|
||||||
|
ArrayList.Adapter((IList)g.ControlPoints).Sort(
|
||||||
|
Comparer<ControlPoint>.Create((c1, c2) => string.Compare(c1.GetType().ToString(), c2.GetType().ToString(), StringComparison.Ordinal)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IBeatmap decode(string filename, out IBeatmap encoded)
|
||||||
|
{
|
||||||
|
using (var stream = TestResources.GetStore().GetStream(filename))
|
||||||
using (var sr = new LineBufferedReader(stream))
|
using (var sr = new LineBufferedReader(stream))
|
||||||
{
|
{
|
||||||
var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr);
|
var legacyDecoded = convert(new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr));
|
||||||
|
|
||||||
using (var ms = new MemoryStream())
|
using (var ms = new MemoryStream())
|
||||||
using (var sw = new StreamWriter(ms))
|
using (var sw = new StreamWriter(ms))
|
||||||
using (var sr2 = new LineBufferedReader(ms))
|
using (var sr2 = new LineBufferedReader(ms, true))
|
||||||
{
|
{
|
||||||
new LegacyBeatmapEncoder(legacyDecoded).Encode(sw);
|
new LegacyBeatmapEncoder(legacyDecoded).Encode(sw);
|
||||||
sw.Flush();
|
|
||||||
|
|
||||||
|
sw.Flush();
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
|
|
||||||
encoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr2);
|
encoded = convert(new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr2));
|
||||||
|
|
||||||
return legacyDecoded;
|
return legacyDecoded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IBeatmap convert(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
switch (beatmap.BeatmapInfo.RulesetID)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
beatmap.BeatmapInfo.Ruleset = new OsuRuleset().RulesetInfo;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
beatmap.BeatmapInfo.Ruleset = new TaikoRuleset().RulesetInfo;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
beatmap.BeatmapInfo.Ruleset = new CatchRuleset().RulesetInfo;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
beatmap.BeatmapInfo.Ruleset = new ManiaRuleset().RulesetInfo;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TestWorkingBeatmap(beatmap).GetPlayableBeatmap(beatmap.BeatmapInfo.Ruleset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestWorkingBeatmap : WorkingBeatmap
|
||||||
|
{
|
||||||
|
private readonly IBeatmap beatmap;
|
||||||
|
|
||||||
|
public TestWorkingBeatmap(IBeatmap beatmap)
|
||||||
|
: base(beatmap.BeatmapInfo, null)
|
||||||
|
{
|
||||||
|
this.beatmap = beatmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IBeatmap GetBeatmap() => beatmap;
|
||||||
|
|
||||||
|
protected override Texture GetBackground() => throw new NotImplementedException();
|
||||||
|
|
||||||
|
protected override Track GetTrack() => throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,27 +5,27 @@ osu file format v14
|
|||||||
255,193,1000,49,0,0:0:0:0:
|
255,193,1000,49,0,0:0:0:0:
|
||||||
// Combo index = 4
|
// Combo index = 4
|
||||||
|
|
||||||
// Slider with new combo followed by circle with no new combo
|
// Spinner with new combo followed by circle with no new combo
|
||||||
256,192,2000,12,0,2000,0:0:0:0:
|
256,192,2000,12,0,2000,0:0:0:0:
|
||||||
255,193,3000,1,0,0:0:0:0:
|
255,193,3000,1,0,0:0:0:0:
|
||||||
// Combo index = 5
|
// Combo index = 5
|
||||||
|
|
||||||
// Slider without new combo followed by circle with no new combo
|
// Spinner without new combo followed by circle with no new combo
|
||||||
256,192,4000,8,0,5000,0:0:0:0:
|
256,192,4000,8,0,5000,0:0:0:0:
|
||||||
255,193,6000,1,0,0:0:0:0:
|
255,193,6000,1,0,0:0:0:0:
|
||||||
// Combo index = 5
|
// Combo index = 5
|
||||||
|
|
||||||
// Slider without new combo followed by circle with new combo
|
// Spinner without new combo followed by circle with new combo
|
||||||
256,192,7000,8,0,8000,0:0:0:0:
|
256,192,7000,8,0,8000,0:0:0:0:
|
||||||
255,193,9000,5,0,0:0:0:0:
|
255,193,9000,5,0,0:0:0:0:
|
||||||
// Combo index = 6
|
// Combo index = 6
|
||||||
|
|
||||||
// Slider with new combo and offset (1) followed by circle with new combo and offset (3)
|
// Spinner with new combo and offset (1) followed by circle with new combo and offset (3)
|
||||||
256,192,10000,28,0,11000,0:0:0:0:
|
256,192,10000,28,0,11000,0:0:0:0:
|
||||||
255,193,12000,53,0,0:0:0:0:
|
255,193,12000,53,0,0:0:0:0:
|
||||||
// Combo index = 11
|
// Combo index = 11
|
||||||
|
|
||||||
// Slider with new combo and offset (2) followed by slider with no new combo followed by circle with no new combo
|
// Spinner with new combo and offset (2) followed by slider with no new combo followed by circle with no new combo
|
||||||
256,192,13000,44,0,14000,0:0:0:0:
|
256,192,13000,44,0,14000,0:0:0:0:
|
||||||
256,192,15000,8,0,16000,0:0:0:0:
|
256,192,15000,8,0,16000,0:0:0:0:
|
||||||
255,193,17000,1,0,0:0:0:0:
|
255,193,17000,1,0,0:0:0:0:
|
||||||
|
32
osu.Game.Tests/Resources/sample-beatmap-osu.osu
Normal file
32
osu.Game.Tests/Resources/sample-beatmap-osu.osu
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
osu file format v14
|
||||||
|
|
||||||
|
[General]
|
||||||
|
SampleSet: Normal
|
||||||
|
StackLeniency: 0.7
|
||||||
|
Mode: 0
|
||||||
|
|
||||||
|
[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]
|
||||||
|
98,69,24,1,0,0:0:0:0:
|
||||||
|
419,72,200,1,2,0:0:0:0:
|
||||||
|
81,314,376,1,6,0:0:0:0:
|
||||||
|
423,321,553,1,12,0:0:0:0:
|
||||||
|
86,192,729,2,0,P|459:193|460:193,1,359.999990463257
|
||||||
|
86,192,1259,2,0,P|246:82|453:203,1,449.999988079071
|
||||||
|
86,192,1876,2,0,B|256:30|257:313|464:177,1,359.999990463257
|
||||||
|
86,55,2406,2,12,B|447:51|447:51|452:348|452:348|78:344,1,989.999973773957,14|2,0:0|0:0,0:0:0:0:
|
||||||
|
256,192,3553,12,0,4259,0:0:0:0:
|
||||||
|
67,57,4435,5,0,0:0:0:0:
|
||||||
|
440,52,4612,5,0,0:0:0:0:
|
||||||
|
86,181,4788,6,0,L|492:183,1,359.999990463257
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -10,6 +11,7 @@ using osu.Game.Audio;
|
|||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Beatmaps.Legacy;
|
using osu.Game.Beatmaps.Legacy;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Legacy;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Formats
|
namespace osu.Game.Beatmaps.Formats
|
||||||
@ -48,7 +50,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
handleEvents(writer);
|
handleEvents(writer);
|
||||||
|
|
||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
handleTimingPoints(writer);
|
handleControlPoints(writer);
|
||||||
|
|
||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
handleHitObjects(writer);
|
handleHitObjects(writer);
|
||||||
@ -58,7 +60,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
writer.WriteLine("[General]");
|
writer.WriteLine("[General]");
|
||||||
|
|
||||||
writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}"));
|
if (beatmap.Metadata.AudioFile != null) writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"AudioLeadIn: {beatmap.BeatmapInfo.AudioLeadIn}"));
|
writer.WriteLine(FormattableString.Invariant($"AudioLeadIn: {beatmap.BeatmapInfo.AudioLeadIn}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"PreviewTime: {beatmap.Metadata.PreviewTime}"));
|
writer.WriteLine(FormattableString.Invariant($"PreviewTime: {beatmap.Metadata.PreviewTime}"));
|
||||||
// Todo: Not all countdown types are supported by lazer yet
|
// Todo: Not all countdown types are supported by lazer yet
|
||||||
@ -103,15 +105,15 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
writer.WriteLine("[Metadata]");
|
writer.WriteLine("[Metadata]");
|
||||||
|
|
||||||
writer.WriteLine(FormattableString.Invariant($"Title: {beatmap.Metadata.Title}"));
|
writer.WriteLine(FormattableString.Invariant($"Title: {beatmap.Metadata.Title}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"TitleUnicode: {beatmap.Metadata.TitleUnicode}"));
|
if (beatmap.Metadata.TitleUnicode != null) writer.WriteLine(FormattableString.Invariant($"TitleUnicode: {beatmap.Metadata.TitleUnicode}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"Artist: {beatmap.Metadata.Artist}"));
|
writer.WriteLine(FormattableString.Invariant($"Artist: {beatmap.Metadata.Artist}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"ArtistUnicode: {beatmap.Metadata.ArtistUnicode}"));
|
if (beatmap.Metadata.ArtistUnicode != null) writer.WriteLine(FormattableString.Invariant($"ArtistUnicode: {beatmap.Metadata.ArtistUnicode}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"Creator: {beatmap.Metadata.AuthorString}"));
|
writer.WriteLine(FormattableString.Invariant($"Creator: {beatmap.Metadata.AuthorString}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"Version: {beatmap.BeatmapInfo.Version}"));
|
writer.WriteLine(FormattableString.Invariant($"Version: {beatmap.BeatmapInfo.Version}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"Source: {beatmap.Metadata.Source}"));
|
if (beatmap.Metadata.Source != null) writer.WriteLine(FormattableString.Invariant($"Source: {beatmap.Metadata.Source}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"Tags: {beatmap.Metadata.Tags}"));
|
if (beatmap.Metadata.Tags != null) writer.WriteLine(FormattableString.Invariant($"Tags: {beatmap.Metadata.Tags}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"BeatmapID: {beatmap.BeatmapInfo.OnlineBeatmapID ?? 0}"));
|
if (beatmap.BeatmapInfo.OnlineBeatmapID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapID: {beatmap.BeatmapInfo.OnlineBeatmapID}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"BeatmapSetID: {beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID ?? -1}"));
|
if (beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapSetID: {beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleDifficulty(TextWriter writer)
|
private void handleDifficulty(TextWriter writer)
|
||||||
@ -137,7 +139,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
writer.WriteLine(FormattableString.Invariant($"{(int)LegacyEventType.Break},{b.StartTime},{b.EndTime}"));
|
writer.WriteLine(FormattableString.Invariant($"{(int)LegacyEventType.Break},{b.StartTime},{b.EndTime}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleTimingPoints(TextWriter writer)
|
private void handleControlPoints(TextWriter writer)
|
||||||
{
|
{
|
||||||
if (beatmap.ControlPointInfo.Groups.Count == 0)
|
if (beatmap.ControlPointInfo.Groups.Count == 0)
|
||||||
return;
|
return;
|
||||||
@ -146,20 +148,30 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
foreach (var group in beatmap.ControlPointInfo.Groups)
|
foreach (var group in beatmap.ControlPointInfo.Groups)
|
||||||
{
|
{
|
||||||
var timingPoint = group.ControlPoints.OfType<TimingControlPoint>().FirstOrDefault();
|
var groupTimingPoint = group.ControlPoints.OfType<TimingControlPoint>().FirstOrDefault();
|
||||||
var difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(group.Time);
|
|
||||||
var samplePoint = beatmap.ControlPointInfo.SamplePointAt(group.Time);
|
|
||||||
var effectPoint = beatmap.ControlPointInfo.EffectPointAt(group.Time);
|
|
||||||
|
|
||||||
// Convert beat length the legacy format
|
// If the group contains a timing control point, it needs to be output separately.
|
||||||
double beatLength;
|
if (groupTimingPoint != null)
|
||||||
if (timingPoint != null)
|
{
|
||||||
beatLength = timingPoint.BeatLength;
|
writer.Write(FormattableString.Invariant($"{groupTimingPoint.Time},"));
|
||||||
else
|
writer.Write(FormattableString.Invariant($"{groupTimingPoint.BeatLength},"));
|
||||||
beatLength = -100 / difficultyPoint.SpeedMultiplier;
|
outputControlPointEffectsAt(groupTimingPoint.Time, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output any remaining effects as secondary non-timing control point.
|
||||||
|
var difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(group.Time);
|
||||||
|
writer.Write(FormattableString.Invariant($"{group.Time},"));
|
||||||
|
writer.Write(FormattableString.Invariant($"{-100 / difficultyPoint.SpeedMultiplier},"));
|
||||||
|
outputControlPointEffectsAt(group.Time, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void outputControlPointEffectsAt(double time, bool isTimingPoint)
|
||||||
|
{
|
||||||
|
var samplePoint = beatmap.ControlPointInfo.SamplePointAt(time);
|
||||||
|
var effectPoint = beatmap.ControlPointInfo.EffectPointAt(time);
|
||||||
|
|
||||||
// Apply the control point to a hit sample to uncover legacy properties (e.g. suffix)
|
// Apply the control point to a hit sample to uncover legacy properties (e.g. suffix)
|
||||||
HitSampleInfo tempHitSample = samplePoint.ApplyTo(new HitSampleInfo());
|
HitSampleInfo tempHitSample = samplePoint.ApplyTo(new ConvertHitObjectParser.LegacyHitSampleInfo());
|
||||||
|
|
||||||
// Convert effect flags to the legacy format
|
// Convert effect flags to the legacy format
|
||||||
LegacyEffectFlags effectFlags = LegacyEffectFlags.None;
|
LegacyEffectFlags effectFlags = LegacyEffectFlags.None;
|
||||||
@ -168,13 +180,11 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
if (effectPoint.OmitFirstBarLine)
|
if (effectPoint.OmitFirstBarLine)
|
||||||
effectFlags |= LegacyEffectFlags.OmitFirstBarLine;
|
effectFlags |= LegacyEffectFlags.OmitFirstBarLine;
|
||||||
|
|
||||||
writer.Write(FormattableString.Invariant($"{group.Time},"));
|
writer.Write(FormattableString.Invariant($"{(int)beatmap.ControlPointInfo.TimingPointAt(time).TimeSignature},"));
|
||||||
writer.Write(FormattableString.Invariant($"{beatLength},"));
|
|
||||||
writer.Write(FormattableString.Invariant($"{(int)beatmap.ControlPointInfo.TimingPointAt(group.Time).TimeSignature},"));
|
|
||||||
writer.Write(FormattableString.Invariant($"{(int)toLegacySampleBank(tempHitSample.Bank)},"));
|
writer.Write(FormattableString.Invariant($"{(int)toLegacySampleBank(tempHitSample.Bank)},"));
|
||||||
writer.Write(FormattableString.Invariant($"{toLegacyCustomSampleBank(tempHitSample.Suffix)},"));
|
writer.Write(FormattableString.Invariant($"{toLegacyCustomSampleBank(tempHitSample)},"));
|
||||||
writer.Write(FormattableString.Invariant($"{tempHitSample.Volume},"));
|
writer.Write(FormattableString.Invariant($"{tempHitSample.Volume},"));
|
||||||
writer.Write(FormattableString.Invariant($"{(timingPoint != null ? '1' : '0')},"));
|
writer.Write(FormattableString.Invariant($"{(isTimingPoint ? '1' : '0')},"));
|
||||||
writer.Write(FormattableString.Invariant($"{(int)effectFlags}"));
|
writer.Write(FormattableString.Invariant($"{(int)effectFlags}"));
|
||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
}
|
}
|
||||||
@ -240,7 +250,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case IHasEndTime _:
|
case IHasEndTime _:
|
||||||
type |= LegacyHitObjectType.Spinner | LegacyHitObjectType.NewCombo;
|
type |= LegacyHitObjectType.Spinner;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -326,7 +336,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
if (!banksOnly)
|
if (!banksOnly)
|
||||||
{
|
{
|
||||||
string customSampleBank = toLegacyCustomSampleBank(samples.FirstOrDefault(s => !string.IsNullOrEmpty(s.Name))?.Suffix);
|
string customSampleBank = toLegacyCustomSampleBank(samples.FirstOrDefault(s => !string.IsNullOrEmpty(s.Name)));
|
||||||
string sampleFilename = samples.FirstOrDefault(s => string.IsNullOrEmpty(s.Name))?.LookupNames.First() ?? string.Empty;
|
string sampleFilename = samples.FirstOrDefault(s => string.IsNullOrEmpty(s.Name))?.LookupNames.First() ?? string.Empty;
|
||||||
int volume = samples.FirstOrDefault()?.Volume ?? 100;
|
int volume = samples.FirstOrDefault()?.Volume ?? 100;
|
||||||
|
|
||||||
@ -382,6 +392,15 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string toLegacyCustomSampleBank(string sampleSuffix) => string.IsNullOrEmpty(sampleSuffix) ? "0" : sampleSuffix;
|
private string toLegacyCustomSampleBank(HitSampleInfo hitSampleInfo)
|
||||||
|
{
|
||||||
|
if (hitSampleInfo == null)
|
||||||
|
return "0";
|
||||||
|
|
||||||
|
if (hitSampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacy)
|
||||||
|
return legacy.CustomSampleBank.ToString(CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,13 +43,13 @@ namespace osu.Game.IO.Serialization.Converters
|
|||||||
var list = new List<T>();
|
var list = new List<T>();
|
||||||
|
|
||||||
var obj = JObject.Load(reader);
|
var obj = JObject.Load(reader);
|
||||||
var lookupTable = serializer.Deserialize<List<string>>(obj["lookup_table"].CreateReader());
|
var lookupTable = serializer.Deserialize<List<string>>(obj["$lookup_table"].CreateReader());
|
||||||
|
|
||||||
foreach (var tok in obj["items"])
|
foreach (var tok in obj["$items"])
|
||||||
{
|
{
|
||||||
var itemReader = tok.CreateReader();
|
var itemReader = tok.CreateReader();
|
||||||
|
|
||||||
var typeName = lookupTable[(int)tok["type"]];
|
var typeName = lookupTable[(int)tok["$type"]];
|
||||||
var instance = (T)Activator.CreateInstance(Type.GetType(typeName));
|
var instance = (T)Activator.CreateInstance(Type.GetType(typeName));
|
||||||
serializer.Populate(itemReader, instance);
|
serializer.Populate(itemReader, instance);
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ namespace osu.Game.IO.Serialization.Converters
|
|||||||
|
|
||||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
var list = (List<T>)value;
|
var list = (IEnumerable<T>)value;
|
||||||
|
|
||||||
var lookupTable = new List<string>();
|
var lookupTable = new List<string>();
|
||||||
var objects = new List<JObject>();
|
var objects = new List<JObject>();
|
||||||
@ -84,16 +84,16 @@ namespace osu.Game.IO.Serialization.Converters
|
|||||||
}
|
}
|
||||||
|
|
||||||
var itemObject = JObject.FromObject(item, serializer);
|
var itemObject = JObject.FromObject(item, serializer);
|
||||||
itemObject.AddFirst(new JProperty("type", typeId));
|
itemObject.AddFirst(new JProperty("$type", typeId));
|
||||||
objects.Add(itemObject);
|
objects.Add(itemObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteStartObject();
|
writer.WriteStartObject();
|
||||||
|
|
||||||
writer.WritePropertyName("lookup_table");
|
writer.WritePropertyName("$lookup_table");
|
||||||
serializer.Serialize(writer, lookupTable);
|
serializer.Serialize(writer, lookupTable);
|
||||||
|
|
||||||
writer.WritePropertyName("items");
|
writer.WritePropertyName("$items");
|
||||||
serializer.Serialize(writer, objects);
|
serializer.Serialize(writer, objects);
|
||||||
|
|
||||||
writer.WriteEndObject();
|
writer.WriteEndObject();
|
||||||
|
Loading…
Reference in New Issue
Block a user