diff --git a/Mapperator.ConsoleApp/Mapperator.ConsoleApp.csproj b/Mapperator.ConsoleApp/Mapperator.ConsoleApp.csproj index 21a56f5..d0dc8de 100644 --- a/Mapperator.ConsoleApp/Mapperator.ConsoleApp.csproj +++ b/Mapperator.ConsoleApp/Mapperator.ConsoleApp.csproj @@ -7,16 +7,16 @@ - + - - - - - - + + + + + + diff --git a/Mapperator.ConsoleApp/Program.cs b/Mapperator.ConsoleApp/Program.cs index 584f79f..7acdc6f 100644 --- a/Mapperator.ConsoleApp/Program.cs +++ b/Mapperator.ConsoleApp/Program.cs @@ -19,17 +19,17 @@ private static int Main(string[] args) { Dataset.DatasetOptions, Dataset2.DatasetOptions2 >(args) - .MapResult( - (Count.CountOptions opts) => Count.DoDataCount(opts), - (Extract.ExtractOptions opts) => Extract.DoDataExtraction(opts), - (Build.BuildOptions opts) => Build.DoBuildGraph(opts), - (Convert.ConvertOptions opts) => Convert.DoMapConvert(opts), - (Search.SearchOptions opts) => Search.DoPatternSearch(opts), - (Analyze.AnalyzeOptions opts) => Analyze.DoVisualSpacingExtract(opts), - (Extract2.Extract2Options opts) => Extract2.DoDataExtraction(opts), - (Dataset.DatasetOptions opts) => Dataset.DoDataExtraction(opts), - (Dataset2.DatasetOptions2 opts) => Dataset2.DoDataExtraction2(opts), - _ => 1); + .MapResult( + (Count.CountOptions opts) => Count.DoDataCount(opts), + (Extract.ExtractOptions opts) => Extract.DoDataExtraction(opts), + (Build.BuildOptions opts) => Build.DoBuildGraph(opts), + (Convert.ConvertOptions opts) => Convert.DoMapConvert(opts), + (Search.SearchOptions opts) => Search.DoPatternSearch(opts), + (Analyze.AnalyzeOptions opts) => Analyze.DoVisualSpacingExtract(opts), + (Extract2.Extract2Options opts) => Extract2.DoDataExtraction(opts), + (Dataset.DatasetOptions opts) => Dataset.DoDataExtraction(opts), + (Dataset2.DatasetOptions2 opts) => Dataset2.DoDataExtraction2(opts), + _ => 1); } } } diff --git a/Mapperator.ConsoleApp/Verbs/Build.cs b/Mapperator.ConsoleApp/Verbs/Build.cs index 2f86fad..e2be7c0 100644 --- a/Mapperator.ConsoleApp/Verbs/Build.cs +++ b/Mapperator.ConsoleApp/Verbs/Build.cs @@ -23,7 +23,7 @@ public static int DoBuildGraph(BuildOptions opts) { if (opts.OutputStructName is null) throw new ArgumentNullException(nameof(opts)); if (opts.DataPath is null) throw new ArgumentNullException(nameof(opts)); - var trainData = DataSerializer.DeserializeBeatmapData(File.ReadLines(Path.ChangeExtension(opts.DataPath, ".txt"))); + var (_, trainData) = DataSerializer.DeserializeBeatmapData(File.ReadAllLines(Path.ChangeExtension(opts.DataPath, ".txt"))); var data = new RhythmDistanceTrieStructure(); if (data is not ISerializable sData) { diff --git a/Mapperator.ConsoleApp/Verbs/Convert.cs b/Mapperator.ConsoleApp/Verbs/Convert.cs index 60f36ca..f333d11 100644 --- a/Mapperator.ConsoleApp/Verbs/Convert.cs +++ b/Mapperator.ConsoleApp/Verbs/Convert.cs @@ -49,9 +49,9 @@ public static int DoMapConvert(ConvertOptions opts) { stopwatch.Start(); Console.WriteLine(Strings.Program_DoMapConvert_Extracting_data___); - var trainData = DataSerializer.DeserializeBeatmapData(File.ReadLines(Path.ChangeExtension(opts.DataPath, ".txt"))); + var (trainVersion, trainData) = DataSerializer.DeserializeBeatmapData(File.ReadAllLines(Path.ChangeExtension(opts.DataPath, ".txt"))); var map = new BeatmapEditor(Path.ChangeExtension(opts.InputBeatmapPath, ".osu")).ReadFile(); - var input = new DataExtractor().ExtractBeatmapData(map).ToArray(); + var input = new DataExtractor(trainVersion).ExtractBeatmapData(map).ToArray(); // TODO: add options to automatically add distance spacing // TODO: also add options for ignoring angles, nc, or slider attributes @@ -64,7 +64,7 @@ public static int DoMapConvert(ConvertOptions opts) { if (opts.SpacingBeatmapPath is not null) { Console.WriteLine(Strings.Program_DoMapConvert_Converting_spacing_to_reference_beatmap___); var spacingMap = new BeatmapEditor(Path.ChangeExtension(opts.SpacingBeatmapPath, ".osu")).ReadFile(); - var spacingMapData = new DataExtractor().ExtractBeatmapData(spacingMap).ToArray(); + var spacingMapData = new DataExtractor(trainVersion).ExtractBeatmapData(spacingMap).ToArray(); input = TransferSpacing(spacingMapData, input); } diff --git a/Mapperator.ConsoleApp/Verbs/Extract.cs b/Mapperator.ConsoleApp/Verbs/Extract.cs index eeaed17..e565af1 100644 --- a/Mapperator.ConsoleApp/Verbs/Extract.cs +++ b/Mapperator.ConsoleApp/Verbs/Extract.cs @@ -21,7 +21,7 @@ public static int DoDataExtraction(ExtractOptions opts) { File.WriteAllLines(Path.ChangeExtension(opts.OutputName, ".txt"), DataSerializer.SerializeBeatmapData(DbManager.GetFilteredAndRead(opts) .SelectMany(b => mirrors.Select(m => extractor.ExtractBeatmapData(b, m))) - )); + ).Prepend(DataSerializer.CurrentHeader)); return 0; } diff --git a/Mapperator.DemoApp/Mapperator.DemoApp.Game.Tests/Mapperator.DemoApp.Game.Tests.csproj b/Mapperator.DemoApp/Mapperator.DemoApp.Game.Tests/Mapperator.DemoApp.Game.Tests.csproj index 11531c4..a5162a6 100644 --- a/Mapperator.DemoApp/Mapperator.DemoApp.Game.Tests/Mapperator.DemoApp.Game.Tests.csproj +++ b/Mapperator.DemoApp/Mapperator.DemoApp.Game.Tests/Mapperator.DemoApp.Game.Tests.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/Mapperator.DemoApp/Mapperator.DemoApp.Game/MainScreen.cs b/Mapperator.DemoApp/Mapperator.DemoApp.Game/MainScreen.cs index f4c23f4..96d480b 100644 --- a/Mapperator.DemoApp/Mapperator.DemoApp.Game/MainScreen.cs +++ b/Mapperator.DemoApp/Mapperator.DemoApp.Game/MainScreen.cs @@ -222,7 +222,7 @@ private void OnBeatmapChange(ValueChangedEvent obj) pos.MaxValue = obj.NewValue.HitObjects.Count - length - 1; - pattern = new DataExtractor().ExtractBeatmapData(obj.NewValue).ToArray(); + pattern = new DataExtractor(1).ExtractBeatmapData(obj.NewValue).ToArray(); matcher = new TrieDataMatcher(dataStruct, pattern); filter = new OnScreenFilter(); judge = new SuperJudge(pattern); diff --git a/Mapperator.DemoApp/Mapperator.DemoApp.Game/MapDataStore.cs b/Mapperator.DemoApp/Mapperator.DemoApp.Game/MapDataStore.cs index e9214d5..b07a09d 100644 --- a/Mapperator.DemoApp/Mapperator.DemoApp.Game/MapDataStore.cs +++ b/Mapperator.DemoApp/Mapperator.DemoApp.Game/MapDataStore.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Collections.Generic; using System.IO; @@ -36,7 +37,10 @@ public IEnumerable> Get(string name) using Stream stream = store.GetStream(name); if (stream is null) return null; using StreamReader reader = new StreamReader(stream); - return DataSerializer.DeserializeBeatmapData(iterateLines(reader).ToArray()); + var (version, data) = DataSerializer.DeserializeBeatmapData(iterateLines(reader).ToArray()); + if (version != 1) + throw new NotImplementedException($"Data version {version} is not currently supported in MapDataStore"); + return data; } public Task>> GetAsync(string name, CancellationToken cancellationToken = new()) @@ -44,7 +48,10 @@ public IEnumerable> Get(string name) using Stream stream = store.GetStream(name); if (stream is null) return null; using StreamReader reader = new StreamReader(stream); - return Task.FromResult(DataSerializer.DeserializeBeatmapData(iterateLines(reader))); + var (version, data) = DataSerializer.DeserializeBeatmapData(iterateLines(reader)); + if (version != 1) + throw new NotImplementedException($"Data version {version} is not currently supported in MapDataStore"); + return Task.FromResult(data); } public Stream GetStream(string name) diff --git a/Mapperator.DemoApp/Mapperator.DemoApp.Game/Mapperator.DemoApp.Game.csproj b/Mapperator.DemoApp/Mapperator.DemoApp.Game/Mapperator.DemoApp.Game.csproj index e1e9db9..803dbf4 100644 --- a/Mapperator.DemoApp/Mapperator.DemoApp.Game/Mapperator.DemoApp.Game.csproj +++ b/Mapperator.DemoApp/Mapperator.DemoApp.Game/Mapperator.DemoApp.Game.csproj @@ -7,7 +7,7 @@ - - + + diff --git a/Mapperator.Tests/Mapperator.Tests.csproj b/Mapperator.Tests/Mapperator.Tests.csproj index ab773cf..8096981 100644 --- a/Mapperator.Tests/Mapperator.Tests.csproj +++ b/Mapperator.Tests/Mapperator.Tests.csproj @@ -7,10 +7,13 @@ - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Mapperator.Tests/Matching/DataStructures/RhythmDistanceTrieStructureTests.cs b/Mapperator.Tests/Matching/DataStructures/RhythmDistanceTrieStructureTests.cs index b839e14..93dca56 100644 --- a/Mapperator.Tests/Matching/DataStructures/RhythmDistanceTrieStructureTests.cs +++ b/Mapperator.Tests/Matching/DataStructures/RhythmDistanceTrieStructureTests.cs @@ -39,27 +39,27 @@ public void TestQuery() { var result = data.Trie.RetrieveSubstrings(query).ToList(); - Assert.IsTrue(result.Count > 0); + Assert.That(result.Count, Is.GreaterThan(0)); foreach (var wordPosition in result) { //var rhythmString = dataRhythmStrings[wordPosition.Value]; //Console.WriteLine(string.Join('-', Enumerable.Range(0, searchLength).Select(o => rhythmString.Span[wordPosition.CharPosition + o]))); //Console.WriteLine(string.Join('-', query.ToArray())); - Assert.IsTrue(data.WordPositionInRange(wordPosition)); - Assert.IsTrue(data.WordPositionInRange(wordPosition, searchLength - 1)); - Assert.AreEqual(searchLength, GetMatchLength(wordPosition, query)); + Assert.That(data.WordPositionInRange(wordPosition)); + Assert.That(data.WordPositionInRange(wordPosition, searchLength - 1)); + Assert.That(searchLength, Is.EqualTo(GetMatchLength(wordPosition, query))); } var (min, max) = RhythmDistanceTrieStructure.ToDistanceRange(query, 10); var rangeResult = data.Trie.RetrieveSubstringsRange(min, max).ToList(); - Assert.IsTrue(rangeResult.Count > 0); + Assert.That(rangeResult.Count > 0); foreach (var wordPosition in rangeResult) { //var rhythmString = dataRhythmStrings[wordPosition.Value]; //Console.WriteLine(string.Join('-', Enumerable.Range(0, searchLength).Select(o => rhythmString.Span[wordPosition.CharPosition + o]))); //Console.WriteLine(string.Join('-', query.ToArray())); - Assert.IsTrue(data.WordPositionInRange(wordPosition)); - Assert.IsTrue(data.WordPositionInRange(wordPosition, searchLength - 1)); - Assert.AreEqual(searchLength, GetMatchLengthRange(wordPosition, min.Span, max.Span)); + Assert.That(data.WordPositionInRange(wordPosition)); + Assert.That(data.WordPositionInRange(wordPosition, searchLength - 1)); + Assert.That(searchLength, Is.EqualTo(GetMatchLengthRange(wordPosition, min.Span, max.Span))); } } } diff --git a/Mapperator.Tests/Matching/DataStructures/RhythmDistanceTrieTests.cs b/Mapperator.Tests/Matching/DataStructures/RhythmDistanceTrieTests.cs index 8d7a983..4d96eca 100644 --- a/Mapperator.Tests/Matching/DataStructures/RhythmDistanceTrieTests.cs +++ b/Mapperator.Tests/Matching/DataStructures/RhythmDistanceTrieTests.cs @@ -37,13 +37,13 @@ public void TestRetrieveSubstringsDynamicLengthAndDistanceRange() { var result = trie.RetrieveSubstringsDynamicLengthAndDistanceRange(query, new RhythmDistanceTrie.MinLengthProvider(1)).ToArray(); - Assert.AreEqual(1, result.Length); + Assert.That(1, Is.EqualTo(result.Length)); var (pos, length, minMult, maxMult) = result[0]; Console.WriteLine(result[0]); - Assert.AreEqual(0, pos.Value); - Assert.AreEqual(0, pos.CharPosition); - Assert.AreEqual(7, length); - Assert.IsTrue(minMult < 1 && 1 < maxMult); + Assert.That(0, Is.EqualTo(pos.Value)); + Assert.That(0, Is.EqualTo(pos.CharPosition)); + Assert.That(7, Is.EqualTo(length)); + Assert.That(minMult < 1 && 1 < maxMult); } [Test] @@ -60,45 +60,45 @@ public void TestDynamicLengthRetrieveSubstringsDynamicLengthAndDistanceRange() { var result = trie.RetrieveSubstringsDynamicLengthAndDistanceRange(query, new RhythmDistanceTrie.MinLengthProvider(1)) .OrderBy(o => o.Item1.CharPosition).ToArray(); - Assert.AreEqual(5, result.Length); + Assert.That(5, Is.EqualTo(result.Length)); var (pos, length, minMult, maxMult) = result[0]; - Assert.AreEqual(1, pos.CharPosition); - Assert.AreEqual(6, length); - Assert.IsTrue(minMult < 1 && 1 < maxMult); + Assert.That(1, Is.EqualTo(pos.CharPosition)); + Assert.That(6, Is.EqualTo(length)); + Assert.That(minMult < 1 && 1 < maxMult); (pos, length, minMult, maxMult) = result[1]; - Assert.AreEqual(2, pos.CharPosition); - Assert.AreEqual(2, length); - Assert.IsTrue(minMult < 0.6 && 0.6 < maxMult); + Assert.That(2, Is.EqualTo(pos.CharPosition)); + Assert.That(2, Is.EqualTo(length)); + Assert.That(minMult < 0.6 && 0.6 < maxMult); (pos, length, minMult, maxMult) = result[2]; - Assert.AreEqual(3, pos.CharPosition); - Assert.AreEqual(1, length); - Assert.IsTrue(minMult < 0.5 && 0.5 < maxMult); + Assert.That(3, Is.EqualTo(pos.CharPosition)); + Assert.That(1, Is.EqualTo(length)); + Assert.That(minMult < 0.5 && 0.5 < maxMult); (pos, length, minMult, maxMult) = result[3]; - Assert.AreEqual(5, pos.CharPosition); - Assert.AreEqual(2, length); - Assert.IsTrue(minMult < 1 && 1 < maxMult); + Assert.That(5, Is.EqualTo(pos.CharPosition)); + Assert.That(2, Is.EqualTo(length)); + Assert.That(minMult < 1 && 1 < maxMult); (pos, length, minMult, maxMult) = result[4]; - Assert.AreEqual(6, pos.CharPosition); - Assert.AreEqual(1, length); - Assert.IsTrue(minMult < 1 && 1 < maxMult); + Assert.That(6, Is.EqualTo(pos.CharPosition)); + Assert.That(1, Is.EqualTo(length)); + Assert.That(minMult < 1 && 1 < maxMult); result = trie.RetrieveSubstringsDynamicLengthAndDistanceRange(query, new RhythmDistanceTrie.MinLengthProvider(2)) .OrderBy(o => o.Item1.CharPosition).ToArray(); - Assert.AreEqual(3, result.Length); + Assert.That(3, Is.EqualTo(result.Length)); (pos, length, _, _) = result[0]; - Assert.AreEqual(1, pos.CharPosition); - Assert.AreEqual(6, length); + Assert.That(1, Is.EqualTo(pos.CharPosition)); + Assert.That(6, Is.EqualTo(length)); (pos, length, _, _) = result[1]; - Assert.AreEqual(2, pos.CharPosition); - Assert.AreEqual(2, length); + Assert.That(2, Is.EqualTo(pos.CharPosition)); + Assert.That(2, Is.EqualTo(length)); (pos, length, _, _) = result[2]; - Assert.AreEqual(5, pos.CharPosition); - Assert.AreEqual(2, length); + Assert.That(5, Is.EqualTo(pos.CharPosition)); + Assert.That(2, Is.EqualTo(length)); result = trie.RetrieveSubstringsDynamicLengthAndDistanceRange(query, new RhythmDistanceTrie.MinLengthProvider(3)).ToArray(); - Assert.AreEqual(1, result.Length); + Assert.That(1, Is.EqualTo(result.Length)); } [Test] @@ -115,13 +115,13 @@ public void TestDynamicDistanceRetrieveSubstringsDynamicLengthAndDistanceRange() var result = trie.RetrieveSubstringsDynamicLengthAndDistanceRange(query, new RhythmDistanceTrie.MinLengthProvider(1)).ToArray(); - Assert.AreEqual(1, result.Length); + Assert.That(1, Is.EqualTo(result.Length)); var (pos, length, minMult, maxMult) = result[0]; Console.WriteLine(result[0]); - Assert.AreEqual(0, pos.Value); - Assert.AreEqual(0, pos.CharPosition); - Assert.AreEqual(7, length); - Assert.IsTrue(minMult < 0.5 && 0.5 < maxMult); + Assert.That(0, Is.EqualTo(pos.Value)); + Assert.That(0, Is.EqualTo(pos.CharPosition)); + Assert.That(7, Is.EqualTo(length)); + Assert.That(minMult < 0.5 && 0.5 < maxMult); } [Test] diff --git a/Mapperator.Tests/Matching/Matchers/TrieDataMatcherTests.cs b/Mapperator.Tests/Matching/Matchers/TrieDataMatcherTests.cs index 9bfd5b1..c9e86ee 100644 --- a/Mapperator.Tests/Matching/Matchers/TrieDataMatcherTests.cs +++ b/Mapperator.Tests/Matching/Matchers/TrieDataMatcherTests.cs @@ -27,8 +27,8 @@ public void TestQuery() { foreach (var match in result) { Console.WriteLine(match.Sequence.Length); Console.WriteLine(string.Join('-', RhythmDistanceTrieStructure.ToRhythmString(match.Sequence.Span).ToArray())); - //Assert.IsTrue(WordPositionInRange(wordPosition)); - //Assert.IsTrue(WordPositionInRange(wordPosition, searchLength)); + //Assert.That(WordPositionInRange(wordPosition)); + //Assert.That(WordPositionInRange(wordPosition, searchLength)); //Assert.AreEqual(searchLength, GetMatchLength(wordPosition, query)); } } diff --git a/Mapperator.Tests/Matching/TrieTests.cs b/Mapperator.Tests/Matching/TrieTests.cs index d4477c2..8489232 100644 --- a/Mapperator.Tests/Matching/TrieTests.cs +++ b/Mapperator.Tests/Matching/TrieTests.cs @@ -1,6 +1,7 @@ using NUnit.Framework; using System; using System.Linq; +using NUnit.Framework.Legacy; using TrieNet.Ukkonen; namespace Mapperator.Tests.Matching { diff --git a/Mapperator/DataExtractor.cs b/Mapperator/DataExtractor.cs index cca245e..891ef90 100644 --- a/Mapperator/DataExtractor.cs +++ b/Mapperator/DataExtractor.cs @@ -10,11 +10,13 @@ namespace Mapperator { public class DataExtractor { private readonly HitObjectEncoder encoder; + private readonly int dataVersion; - public DataExtractor() : this(new HitObjectEncoder()) { } + public DataExtractor(int dataVersion = DataSerializer.CurrentDataVersion) : this(new HitObjectEncoder(), dataVersion) { } - public DataExtractor(HitObjectEncoder encoder) { + public DataExtractor(HitObjectEncoder encoder, int dataVersion) { this.encoder = encoder; + this.dataVersion = dataVersion; } public IEnumerable ExtractBeatmapData(IBeatmap beatmap, bool mirror = false) { @@ -43,9 +45,17 @@ public IEnumerable ExtractBeatmapData(IEnumerable hitob var segments = 0; var controlPoints = path.ControlPoints; - for (var i = 0; i < controlPoints.Count; i++) { - if (i == controlPoints.Count - 1 || controlPoints[i] == controlPoints[i + 1] && i != controlPoints.Count - 2) { - segments++; + if (dataVersion >= 2 && slider.SliderType == PathType.Linear) { + for (var i = 0; i < controlPoints.Count - 1; i++) { + if (controlPoints[i] != controlPoints[i + 1]) { + segments++; + } + } + } else { + for (var i = 0; i < controlPoints.Count; i++) { + if (i == controlPoints.Count - 1 || controlPoints[i] == controlPoints[i + 1] && i != controlPoints.Count - 2) { + segments++; + } } } diff --git a/Mapperator/DataExtractor2.cs b/Mapperator/DataExtractor2.cs index 57e115b..9df1ac7 100644 --- a/Mapperator/DataExtractor2.cs +++ b/Mapperator/DataExtractor2.cs @@ -36,10 +36,10 @@ public IEnumerable ExtractBeatmapData(IEnumerable hito } var t = timing2.UninheritedTimingPoint.MpB / sliderTickRate; - var tick_ts = new List(); + var tickTs = new List(); while (t + 10 < slider.SpanDuration) { var t2 = t / slider.SpanDuration; - tick_ts.Add(t2); + tickTs.Add(t2); t += timing2.UninheritedTimingPoint.MpB / sliderTickRate; } @@ -48,9 +48,9 @@ public IEnumerable ExtractBeatmapData(IEnumerable hito for (int i = 0; i < slider.SpanCount; i++) { // Do ticks - for (int j = 0; j < tick_ts.Count; j++) { - var k = i % 2 == 0 ? j : tick_ts.Count - j - 1; - var t2 = tick_ts[k]; + for (int j = 0; j < tickTs.Count; j++) { + var k = i % 2 == 0 ? j : tickTs.Count - j - 1; + var t2 = tickTs[k]; var pos = path.PositionAt(t2); var time = (int)(slider.StartTime + i * slider.SpanDuration + (i % 2 == 0 ? t2 : 1 - t2) * slider.SpanDuration); diff --git a/Mapperator/DataSerializer.cs b/Mapperator/DataSerializer.cs index 8dd9dd2..9c960a2 100644 --- a/Mapperator/DataSerializer.cs +++ b/Mapperator/DataSerializer.cs @@ -5,7 +5,11 @@ namespace Mapperator { public static class DataSerializer { + public const int CurrentDataVersion = 2; private const string BeatmapSeparator = "/-\\_/-\\_/-\\"; + private const string DataHeader = "Mapperator file format v"; + + public static string CurrentHeader => $"{DataHeader}{CurrentDataVersion}"; public static IEnumerable SerializeBeatmapData(IEnumerable> data) { foreach (var beatmap in data) { @@ -21,8 +25,13 @@ public static string SerializeBeatmapDataSample(MapDataPoint data) { return data.ToString(); } - public static IEnumerable> DeserializeBeatmapData(IEnumerable data) { - return data.Split(BeatmapSeparator, beatmapData => beatmapData.Select(DeserializeBeatmapDataSample)); + public static (int, IEnumerable>) DeserializeBeatmapData(IEnumerable data) { + // ReSharper disable twice PossibleMultipleEnumeration + var firstLine = data.FirstOrDefault() ?? ""; + if (firstLine.StartsWith(DataHeader)) { + return (int.Parse(firstLine.Split('v').Last()), data.Skip(1).Split(BeatmapSeparator, beatmapData => beatmapData.Select(DeserializeBeatmapDataSample))); + } + return (1, data.Split(BeatmapSeparator, beatmapData => beatmapData.Select(DeserializeBeatmapDataSample))); } public static MapDataPoint DeserializeBeatmapDataSample(string data) { diff --git a/Mapperator/Mapperator.csproj b/Mapperator/Mapperator.csproj index 973110c..4bbe331 100644 --- a/Mapperator/Mapperator.csproj +++ b/Mapperator/Mapperator.csproj @@ -7,8 +7,8 @@ - - + +