1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-13 13:32:54 +08:00

Merge branch 'master' into mania-difficulty

This commit is contained in:
Dean Herbert 2018-03-12 14:07:14 +09:00 committed by GitHub
commit 8cbcdeb665
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 251 additions and 308 deletions

View File

@ -24,7 +24,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.DecodeBeatmap(stream);
var beatmap = decoder.Decode(stream);
var beatmapInfo = beatmap.BeatmapInfo;
var metadata = beatmap.Metadata;
@ -47,7 +47,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmapInfo = decoder.DecodeBeatmap(stream).BeatmapInfo;
var beatmapInfo = decoder.Decode(stream).BeatmapInfo;
int[] expectedBookmarks =
{
@ -72,7 +72,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.DecodeBeatmap(stream);
var beatmap = decoder.Decode(stream);
var beatmapInfo = beatmap.BeatmapInfo;
var metadata = beatmap.Metadata;
@ -96,7 +96,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var difficulty = decoder.DecodeBeatmap(stream).BeatmapInfo.BaseDifficulty;
var difficulty = decoder.Decode(stream).BeatmapInfo.BaseDifficulty;
Assert.AreEqual(6.5f, difficulty.DrainRate);
Assert.AreEqual(4, difficulty.CircleSize);
@ -114,7 +114,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.DecodeBeatmap(stream);
var beatmap = decoder.Decode(stream);
var metadata = beatmap.Metadata;
var breakPoint = beatmap.Breaks[0];
@ -132,7 +132,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.DecodeBeatmap(stream);
var beatmap = decoder.Decode(stream);
var controlPoints = beatmap.ControlPointInfo;
Assert.AreEqual(4, controlPoints.TimingPoints.Count);
@ -167,7 +167,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var comboColors = decoder.DecodeBeatmap(stream).ComboColors;
var comboColors = decoder.Decode(stream).ComboColors;
Color4[] expectedColors =
{
@ -191,7 +191,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.DecodeBeatmap(stream).HitObjects;
var hitObjects = decoder.Decode(stream).HitObjects;
var curveData = hitObjects[0] as IHasCurve;
var positionData = hitObjects[0] as IHasPosition;

View File

@ -18,11 +18,11 @@ namespace osu.Game.Tests.Beatmaps.Formats
[Test]
public void TestDecodeStoryboardEvents()
{
var decoder = new LegacyBeatmapDecoder();
var decoder = new LegacyStoryboardDecoder();
using (var resStream = Resource.OpenResource("Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu"))
using (var stream = new StreamReader(resStream))
{
var storyboard = decoder.GetStoryboardDecoder().DecodeStoryboard(stream);
var storyboard = decoder.Decode(stream);
Assert.IsTrue(storyboard.HasDrawable);
Assert.AreEqual(4, storyboard.Layers.Count());

View File

@ -159,7 +159,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
using (var sr = new StreamReader(stream))
{
var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.DecodeBeatmap(sr);
var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr);
using (var ms = new MemoryStream())
using (var sw = new StreamWriter(ms))
using (var sr2 = new StreamReader(ms))
@ -168,7 +168,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
sw.Flush();
ms.Position = 0;
return (legacyDecoded, new JsonBeatmapDecoder().DecodeBeatmap(sr2));
return (legacyDecoded, new JsonBeatmapDecoder().Decode(sr2));
}
}
}

View File

@ -50,7 +50,7 @@ namespace osu.Game.Tests.Beatmaps.IO
BeatmapMetadata meta;
using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu")))
meta = Decoder.GetDecoder(stream).DecodeBeatmap(stream).Metadata;
meta = Decoder.GetDecoder<Beatmap>(stream).Decode(stream).Metadata;
Assert.AreEqual(241526, meta.OnlineBeatmapSetID);
Assert.AreEqual("Soleily", meta.Artist);

View File

@ -22,6 +22,7 @@ namespace osu.Game.Beatmaps
public BeatmapInfo BeatmapInfo = new BeatmapInfo();
public ControlPointInfo ControlPointInfo = new ControlPointInfo();
public List<BreakPeriod> Breaks = new List<BreakPeriod>();
public List<Color4> ComboColors = new List<Color4>
{
new Color4(17, 136, 170, 255),
@ -85,9 +86,13 @@ namespace osu.Game.Beatmaps
/// Constructs a new beatmap.
/// </summary>
/// <param name="original">The original beatmap to use the parameters of.</param>
public Beatmap(Beatmap original = null)
public Beatmap(Beatmap original)
: base(original)
{
}
public Beatmap()
{
}
}
}

View File

@ -301,7 +301,7 @@ namespace osu.Game.Beatmaps
BeatmapMetadata metadata;
using (var stream = new StreamReader(reader.GetStream(mapName)))
metadata = Decoder.GetDecoder(stream).DecodeBeatmap(stream).Metadata;
metadata = Decoder.GetDecoder<Beatmap>(stream).Decode(stream).Metadata;
return new BeatmapSetInfo
{
@ -328,8 +328,8 @@ namespace osu.Game.Beatmaps
raw.CopyTo(ms);
ms.Position = 0;
var decoder = Decoder.GetDecoder(sr);
Beatmap beatmap = decoder.DecodeBeatmap(sr);
var decoder = Decoder.GetDecoder<Beatmap>(sr);
Beatmap beatmap = decoder.Decode(sr);
beatmap.BeatmapInfo.Path = name;
beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash();

View File

@ -7,6 +7,7 @@ using System.Linq;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
using osu.Framework.Logging;
using osu.Game.Beatmaps.Formats;
using osu.Game.Graphics.Textures;
using osu.Game.Storyboards;
@ -30,10 +31,7 @@ namespace osu.Game.Beatmaps
try
{
using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path))))
{
Decoder decoder = Decoder.GetDecoder(stream);
return decoder.DecodeBeatmap(stream);
}
return Decoder.GetDecoder<Beatmap>(stream).Decode(stream);
}
catch
{
@ -78,23 +76,23 @@ namespace osu.Game.Beatmaps
Storyboard storyboard;
try
{
using (var beatmap = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path))))
using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path))))
{
Decoder decoder = Decoder.GetDecoder(beatmap);
var decoder = Decoder.GetDecoder<Storyboard>(stream);
// todo: support loading from both set-wide storyboard *and* beatmap specific.
if (BeatmapSetInfo?.StoryboardFile == null)
storyboard = decoder.GetStoryboardDecoder().DecodeStoryboard(beatmap);
storyboard = decoder.Decode(stream);
else
{
using (var reader = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile))))
storyboard = decoder.GetStoryboardDecoder().DecodeStoryboard(beatmap, reader);
using (var secondaryStream = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile))))
storyboard = decoder.Decode(stream, secondaryStream);
}
}
}
catch
catch (Exception e)
{
Logger.Error(e, "Storyboard failed to load");
storyboard = new Storyboard();
}

View File

@ -4,38 +4,64 @@
using System;
using System.Collections.Generic;
using System.IO;
using osu.Game.Storyboards;
using System.Linq;
namespace osu.Game.Beatmaps.Formats
{
public abstract class Decoder<TOutput> : Decoder
where TOutput : new()
{
protected virtual TOutput CreateTemplateObject() => new TOutput();
public TOutput Decode(StreamReader primaryStream, params StreamReader[] otherStreams)
{
var output = CreateTemplateObject();
foreach (StreamReader stream in new[] { primaryStream }.Concat(otherStreams))
ParseStreamInto(stream, output);
return output;
}
protected abstract void ParseStreamInto(StreamReader stream, TOutput beatmap);
}
public abstract class Decoder
{
private static readonly Dictionary<string, Func<string, Decoder>> decoders = new Dictionary<string, Func<string, Decoder>>();
private static readonly Dictionary<Type, Dictionary<string, Func<string, Decoder>>> decoders = new Dictionary<Type, Dictionary<string, Func<string, Decoder>>>();
static Decoder()
{
LegacyDecoder.Register();
LegacyBeatmapDecoder.Register();
JsonBeatmapDecoder.Register();
LegacyStoryboardDecoder.Register();
}
/// <summary>
/// Retrieves a <see cref="Decoder"/> to parse a <see cref="Beatmap"/>.
/// </summary>
/// <param name="stream">A stream pointing to the <see cref="Beatmap"/>.</param>
public static Decoder GetDecoder(StreamReader stream)
public static Decoder<T> GetDecoder<T>(StreamReader stream)
where T : new()
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));
if (!decoders.TryGetValue(typeof(T), out var typedDecoders))
throw new IOException(@"Unknown decoder type");
string line;
do
{ line = stream.ReadLine()?.Trim(); }
while (line != null && line.Length == 0);
{
line = stream.ReadLine()?.Trim();
} while (line != null && line.Length == 0);
if (line == null || !decoders.ContainsKey(line))
if (line == null)
throw new IOException(@"Unknown file format");
return decoders[line](line);
var decoder = typedDecoders.Select(d => line.StartsWith(d.Key) ? d.Value : null).FirstOrDefault();
if (decoder == null)
throw new IOException(@"Unknown file format");
return (Decoder<T>)decoder.Invoke(line);
}
/// <summary>
@ -43,41 +69,12 @@ namespace osu.Game.Beatmaps.Formats
/// </summary>
/// <param name="magic">A string in the file which triggers this decoder to be used.</param>
/// <param name="constructor">A function which constructs the <see cref="Decoder"/> given <paramref name="magic"/>.</param>
protected static void AddDecoder(string magic, Func<string, Decoder> constructor)
protected static void AddDecoder<T>(string magic, Func<string, Decoder> constructor)
{
decoders[magic] = constructor;
if (!decoders.TryGetValue(typeof(T), out var typedDecoders))
decoders.Add(typeof(T), typedDecoders = new Dictionary<string, Func<string, Decoder>>());
typedDecoders[magic] = constructor;
}
/// <summary>
/// Retrieves a <see cref="Decoder"/> to parse a <see cref="Storyboard"/>
/// </summary>
public abstract Decoder GetStoryboardDecoder();
public virtual Beatmap DecodeBeatmap(StreamReader stream)
{
var beatmap = new Beatmap
{
BeatmapInfo = new BeatmapInfo
{
Metadata = new BeatmapMetadata(),
BaseDifficulty = new BeatmapDifficulty(),
},
};
ParseBeatmap(stream, beatmap);
return beatmap;
}
protected abstract void ParseBeatmap(StreamReader stream, Beatmap beatmap);
public virtual Storyboard DecodeStoryboard(params StreamReader[] streams)
{
var storyboard = new Storyboard();
foreach (StreamReader stream in streams)
ParseStoryboard(stream, storyboard);
return storyboard;
}
protected abstract void ParseStoryboard(StreamReader stream, Storyboard storyboard);
}
}

View File

@ -3,20 +3,17 @@
using System.IO;
using osu.Game.IO.Serialization;
using osu.Game.Storyboards;
namespace osu.Game.Beatmaps.Formats
{
public class JsonBeatmapDecoder : Decoder
public class JsonBeatmapDecoder : Decoder<Beatmap>
{
public static void Register()
{
AddDecoder("{", m => new JsonBeatmapDecoder());
AddDecoder<Beatmap>("{", m => new JsonBeatmapDecoder());
}
public override Decoder GetStoryboardDecoder() => this;
protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap)
protected override void ParseStreamInto(StreamReader stream, Beatmap beatmap)
{
stream.BaseStream.Position = 0;
stream.DiscardBufferedData();
@ -26,10 +23,5 @@ namespace osu.Game.Beatmaps.Formats
foreach (var hitObject in beatmap.HitObjects)
hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty);
}
protected override void ParseStoryboard(StreamReader stream, Storyboard storyboard)
{
// throw new System.NotImplementedException();
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using OpenTK.Graphics;
using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Objects.Legacy;
@ -12,8 +13,10 @@ using osu.Framework;
namespace osu.Game.Beatmaps.Formats
{
public class LegacyBeatmapDecoder : LegacyDecoder
public class LegacyBeatmapDecoder : LegacyDecoder<Beatmap>
{
public const int LATEST_VERSION = 14;
private Beatmap beatmap;
private bool hasCustomColours;
@ -22,6 +25,11 @@ namespace osu.Game.Beatmaps.Formats
private LegacySampleBank defaultSampleBank;
private int defaultSampleVolume = 100;
public static void Register()
{
AddDecoder<Beatmap>(@"osu file format v", m => new LegacyBeatmapDecoder(int.Parse(m.Split('v').Last())));
}
/// <summary>
/// lazer's audio timings in general doesn't match stable. this is the result of user testing, albeit limited.
/// This only seems to be required on windows. We need to eventually figure out why, with a bit of luck.
@ -35,29 +43,18 @@ namespace osu.Game.Beatmaps.Formats
private readonly int offset = UniversalOffset;
public LegacyBeatmapDecoder()
public LegacyBeatmapDecoder(int version = LATEST_VERSION) : base(version)
{
}
public LegacyBeatmapDecoder(string header)
{
BeatmapVersion = int.Parse(header.Substring(17));
// BeatmapVersion 4 and lower had an incorrect offset (stable has this set as 24ms off)
offset += BeatmapVersion < 5 ? 24 : 0;
offset += FormatVersion < 5 ? 24 : 0;
}
protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap)
protected override void ParseStreamInto(StreamReader stream, Beatmap beatmap)
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
this.beatmap = beatmap;
this.beatmap.BeatmapInfo.BeatmapVersion = BeatmapVersion;
this.beatmap.BeatmapInfo.BeatmapVersion = FormatVersion;
ParseContent(stream);
base.ParseStreamInto(stream, beatmap);
// objects may be out of order *only* if a user has manually edited an .osu file.
// unfortunately there are ranked maps in this state (example: https://osu.ppy.sh/s/594828).
@ -67,14 +64,9 @@ namespace osu.Game.Beatmaps.Formats
hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.BeatmapInfo.BaseDifficulty);
}
protected override bool ShouldSkipLine(string line)
{
if (base.ShouldSkipLine(line) || line.StartsWith(" ") || line.StartsWith("_"))
return true;
return false;
}
protected override bool ShouldSkipLine(string line) => base.ShouldSkipLine(line) || line.StartsWith(" ") || line.StartsWith("_");
protected override void ProcessSection(Section section, string line)
protected override void ParseLine(Beatmap beatmap, Section section, string line)
{
switch (section)
{

View File

@ -4,47 +4,20 @@
using System;
using System.Collections.Generic;
using System.IO;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Storyboards;
namespace osu.Game.Beatmaps.Formats
{
public abstract class LegacyDecoder : Decoder
public abstract class LegacyDecoder<T> : Decoder<T>
where T : new()
{
public static void Register()
protected readonly int FormatVersion;
protected LegacyDecoder(int version)
{
AddDecoder(@"osu file format v14", m => new LegacyBeatmapDecoder(m));
AddDecoder(@"osu file format v13", m => new LegacyBeatmapDecoder(m));
AddDecoder(@"osu file format v12", m => new LegacyBeatmapDecoder(m));
AddDecoder(@"osu file format v11", m => new LegacyBeatmapDecoder(m));
AddDecoder(@"osu file format v10", m => new LegacyBeatmapDecoder(m));
AddDecoder(@"osu file format v9", m => new LegacyBeatmapDecoder(m));
AddDecoder(@"osu file format v8", m => new LegacyBeatmapDecoder(m));
AddDecoder(@"osu file format v7", m => new LegacyBeatmapDecoder(m));
AddDecoder(@"osu file format v6", m => new LegacyBeatmapDecoder(m));
AddDecoder(@"osu file format v5", m => new LegacyBeatmapDecoder(m));
AddDecoder(@"osu file format v4", m => new LegacyBeatmapDecoder(m));
AddDecoder(@"osu file format v3", m => new LegacyBeatmapDecoder(m));
// TODO: differences between versions
FormatVersion = version;
}
protected int BeatmapVersion;
public override Decoder GetStoryboardDecoder() => new LegacyStoryboardDecoder(BeatmapVersion);
public override Beatmap DecodeBeatmap(StreamReader stream) => new LegacyBeatmap(base.DecodeBeatmap(stream));
protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap)
{
throw new NotImplementedException();
}
protected override void ParseStoryboard(StreamReader stream, Storyboard storyboard)
{
throw new NotImplementedException();
}
protected void ParseContent(StreamReader stream)
protected override void ParseStreamInto(StreamReader stream, T beatmap)
{
Section section = Section.None;
@ -54,13 +27,6 @@ namespace osu.Game.Beatmaps.Formats
if (ShouldSkipLine(line))
continue;
// It's already set in ParseBeatmap... why do it again?
//if (line.StartsWith(@"osu file format v"))
//{
// Beatmap.BeatmapInfo.BeatmapVersion = int.Parse(line.Substring(17));
// continue;
//}
if (line.StartsWith(@"[") && line.EndsWith(@"]"))
{
if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section))
@ -68,18 +34,13 @@ namespace osu.Game.Beatmaps.Formats
continue;
}
ProcessSection(section, line);
ParseLine(beatmap, section, line);
}
}
protected virtual bool ShouldSkipLine(string line)
{
if (string.IsNullOrWhiteSpace(line) || line.StartsWith("//"))
return true;
return false;
}
protected virtual bool ShouldSkipLine(string line) => string.IsNullOrWhiteSpace(line) || line.StartsWith("//");
protected abstract void ProcessSection(Section section, string line);
protected abstract void ParseLine(T output, Section section, string line);
protected KeyValuePair<string, string> SplitKeyVal(string line, char separator)
{

View File

@ -2,7 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using OpenTK;
@ -13,37 +13,34 @@ using osu.Game.Storyboards;
namespace osu.Game.Beatmaps.Formats
{
public class LegacyStoryboardDecoder : LegacyDecoder
public class LegacyStoryboardDecoder : LegacyDecoder<Storyboard>
{
private Storyboard storyboard;
private StoryboardSprite storyboardSprite;
private CommandTimelineGroup timelineGroup;
private Storyboard storyboard;
private readonly Dictionary<string, string> variables = new Dictionary<string, string>();
public LegacyStoryboardDecoder()
: base(0)
{
}
public LegacyStoryboardDecoder(int beatmapVersion)
public static void Register()
{
BeatmapVersion = beatmapVersion;
// note that this isn't completely correct
AddDecoder<Storyboard>(@"osu file format v", m => new LegacyStoryboardDecoder());
AddDecoder<Storyboard>(@"[Events]", m => new LegacyStoryboardDecoder());
}
protected override void ParseStoryboard(StreamReader stream, Storyboard storyboard)
protected override void ParseStreamInto(StreamReader stream, Storyboard storyboard)
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));
if (storyboard == null)
throw new ArgumentNullException(nameof(storyboard));
this.storyboard = storyboard;
ParseContent(stream);
base.ParseStreamInto(stream, storyboard);
}
protected override void ProcessSection(Section section, string line)
protected override void ParseLine(Storyboard storyboard, Section section, string line)
{
switch (section)
{
@ -80,38 +77,38 @@ namespace osu.Game.Beatmaps.Formats
switch (type)
{
case EventType.Sprite:
{
var layer = parseLayer(split[1]);
var origin = parseOrigin(split[2]);
var path = cleanFilename(split[3]);
var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo);
var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo);
storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y));
storyboard.GetLayer(layer).Add(storyboardSprite);
}
{
var layer = parseLayer(split[1]);
var origin = parseOrigin(split[2]);
var path = cleanFilename(split[3]);
var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo);
var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo);
storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y));
storyboard.GetLayer(layer).Add(storyboardSprite);
}
break;
case EventType.Animation:
{
var layer = parseLayer(split[1]);
var origin = parseOrigin(split[2]);
var path = cleanFilename(split[3]);
var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo);
var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo);
var frameCount = int.Parse(split[6]);
var frameDelay = double.Parse(split[7], NumberFormatInfo.InvariantInfo);
var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever;
storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType);
storyboard.GetLayer(layer).Add(storyboardSprite);
}
{
var layer = parseLayer(split[1]);
var origin = parseOrigin(split[2]);
var path = cleanFilename(split[3]);
var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo);
var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo);
var frameCount = int.Parse(split[6]);
var frameDelay = double.Parse(split[7], NumberFormatInfo.InvariantInfo);
var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever;
storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType);
storyboard.GetLayer(layer).Add(storyboardSprite);
}
break;
case EventType.Sample:
{
var time = double.Parse(split[1], CultureInfo.InvariantCulture);
var layer = parseLayer(split[2]);
var path = cleanFilename(split[3]);
var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100;
storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume));
}
{
var time = double.Parse(split[1], CultureInfo.InvariantCulture);
var layer = parseLayer(split[2]);
var path = cleanFilename(split[3]);
var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100;
storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume));
}
break;
}
}
@ -124,120 +121,120 @@ namespace osu.Game.Beatmaps.Formats
switch (commandType)
{
case "T":
{
var triggerName = split[1];
var startTime = split.Length > 2 ? double.Parse(split[2], CultureInfo.InvariantCulture) : double.MinValue;
var endTime = split.Length > 3 ? double.Parse(split[3], CultureInfo.InvariantCulture) : double.MaxValue;
var groupNumber = split.Length > 4 ? int.Parse(split[4]) : 0;
timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber);
}
{
var triggerName = split[1];
var startTime = split.Length > 2 ? double.Parse(split[2], CultureInfo.InvariantCulture) : double.MinValue;
var endTime = split.Length > 3 ? double.Parse(split[3], CultureInfo.InvariantCulture) : double.MaxValue;
var groupNumber = split.Length > 4 ? int.Parse(split[4]) : 0;
timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber);
}
break;
case "L":
{
var startTime = double.Parse(split[1], CultureInfo.InvariantCulture);
var loopCount = int.Parse(split[2]);
timelineGroup = storyboardSprite?.AddLoop(startTime, loopCount);
}
{
var startTime = double.Parse(split[1], CultureInfo.InvariantCulture);
var loopCount = int.Parse(split[2]);
timelineGroup = storyboardSprite?.AddLoop(startTime, loopCount);
}
break;
default:
{
if (string.IsNullOrEmpty(split[3]))
split[3] = split[2];
var easing = (Easing)int.Parse(split[1]);
var startTime = double.Parse(split[2], CultureInfo.InvariantCulture);
var endTime = double.Parse(split[3], CultureInfo.InvariantCulture);
switch (commandType)
{
if (string.IsNullOrEmpty(split[3]))
split[3] = split[2];
var easing = (Easing)int.Parse(split[1]);
var startTime = double.Parse(split[2], CultureInfo.InvariantCulture);
var endTime = double.Parse(split[3], CultureInfo.InvariantCulture);
switch (commandType)
case "F":
{
case "F":
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue);
}
break;
case "S":
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startValue), new Vector2(endValue));
}
break;
case "V":
{
var startX = float.Parse(split[4], CultureInfo.InvariantCulture);
var startY = float.Parse(split[5], CultureInfo.InvariantCulture);
var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX;
var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY;
timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY));
}
break;
case "R":
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.Rotation.Add(easing, startTime, endTime, MathHelper.RadiansToDegrees(startValue), MathHelper.RadiansToDegrees(endValue));
}
break;
case "M":
{
var startX = float.Parse(split[4], CultureInfo.InvariantCulture);
var startY = float.Parse(split[5], CultureInfo.InvariantCulture);
var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX;
var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY;
timelineGroup?.X.Add(easing, startTime, endTime, startX, endX);
timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY);
}
break;
case "MX":
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue);
}
break;
case "MY":
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue);
}
break;
case "C":
{
var startRed = float.Parse(split[4], CultureInfo.InvariantCulture);
var startGreen = float.Parse(split[5], CultureInfo.InvariantCulture);
var startBlue = float.Parse(split[6], CultureInfo.InvariantCulture);
var endRed = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startRed;
var endGreen = split.Length > 8 ? float.Parse(split[8], CultureInfo.InvariantCulture) : startGreen;
var endBlue = split.Length > 9 ? float.Parse(split[9], CultureInfo.InvariantCulture) : startBlue;
timelineGroup?.Colour.Add(easing, startTime, endTime,
new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1),
new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1));
}
break;
case "P":
{
var type = split[4];
switch (type)
{
case "A":
timelineGroup?.BlendingMode.Add(easing, startTime, endTime, BlendingMode.Additive, startTime == endTime ? BlendingMode.Additive : BlendingMode.Inherit);
break;
case "H":
timelineGroup?.FlipH.Add(easing, startTime, endTime, true, startTime == endTime);
break;
case "V":
timelineGroup?.FlipV.Add(easing, startTime, endTime, true, startTime == endTime);
break;
}
}
break;
default:
throw new InvalidDataException($@"Unknown command type: {commandType}");
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue);
}
break;
case "S":
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startValue), new Vector2(endValue));
}
break;
case "V":
{
var startX = float.Parse(split[4], CultureInfo.InvariantCulture);
var startY = float.Parse(split[5], CultureInfo.InvariantCulture);
var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX;
var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY;
timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY));
}
break;
case "R":
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.Rotation.Add(easing, startTime, endTime, MathHelper.RadiansToDegrees(startValue), MathHelper.RadiansToDegrees(endValue));
}
break;
case "M":
{
var startX = float.Parse(split[4], CultureInfo.InvariantCulture);
var startY = float.Parse(split[5], CultureInfo.InvariantCulture);
var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX;
var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY;
timelineGroup?.X.Add(easing, startTime, endTime, startX, endX);
timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY);
}
break;
case "MX":
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue);
}
break;
case "MY":
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue);
}
break;
case "C":
{
var startRed = float.Parse(split[4], CultureInfo.InvariantCulture);
var startGreen = float.Parse(split[5], CultureInfo.InvariantCulture);
var startBlue = float.Parse(split[6], CultureInfo.InvariantCulture);
var endRed = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startRed;
var endGreen = split.Length > 8 ? float.Parse(split[8], CultureInfo.InvariantCulture) : startGreen;
var endBlue = split.Length > 9 ? float.Parse(split[9], CultureInfo.InvariantCulture) : startBlue;
timelineGroup?.Colour.Add(easing, startTime, endTime,
new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1),
new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1));
}
break;
case "P":
{
var type = split[4];
switch (type)
{
case "A":
timelineGroup?.BlendingMode.Add(easing, startTime, endTime, BlendingMode.Additive, startTime == endTime ? BlendingMode.Additive : BlendingMode.Inherit);
break;
case "H":
timelineGroup?.FlipH.Add(easing, startTime, endTime, true, startTime == endTime);
break;
case "V":
timelineGroup?.FlipV.Add(easing, startTime, endTime, true, startTime == endTime);
break;
}
}
break;
default:
throw new InvalidDataException($@"Unknown command type: {commandType}");
}
}
break;
}
}
@ -269,6 +266,7 @@ namespace osu.Game.Beatmaps.Formats
case LegacyOrigins.BottomRight:
return Anchor.BottomRight;
}
throw new InvalidDataException($@"Unknown origin: {value}");
}

View File

@ -188,8 +188,8 @@ namespace osu.Game.Rulesets.Objects.Legacy
string[] split = str.Split(':');
var bank = (LegacyDecoder.LegacySampleBank)Convert.ToInt32(split[0]);
var addbank = (LegacyDecoder.LegacySampleBank)Convert.ToInt32(split[1]);
var bank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[0]);
var addbank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[1]);
// Let's not implement this for now, because this doesn't fit nicely into the bank structure
//string sampleFile = split2.Length > 4 ? split2[4] : string.Empty;

View File

@ -112,9 +112,9 @@ namespace osu.Game.Tests.Beatmaps
using (var resStream = openResource($"{resource_namespace}.{name}.osu"))
using (var stream = new StreamReader(resStream))
{
var decoder = Decoder.GetDecoder(stream);
var decoder = Decoder.GetDecoder<Beatmap>(stream);
((LegacyBeatmapDecoder)decoder).ApplyOffsets = false;
return decoder.DecodeBeatmap(stream);
return decoder.Decode(stream);
}
}

View File

@ -65,7 +65,7 @@ namespace osu.Game.Tests.Visual
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(test_beatmap_data)))
using (var reader = new StreamReader(stream))
beatmap = Game.Beatmaps.Formats.Decoder.GetDecoder(reader).DecodeBeatmap(reader);
beatmap = Game.Beatmaps.Formats.Decoder.GetDecoder<Beatmap>(reader).Decode(reader);
return beatmap;
}