diff --git a/osu-framework b/osu-framework
index 7439250a63..03730d016d 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 7439250a63dd451f34dbc08ecf68a196cf8e479f
+Subproject commit 03730d016d5d5ebd8ebda003dcae3ca3c35536c4
diff --git a/osu-resources b/osu-resources
index 6d9bbe6c83..0505cf0d3b 160000
--- a/osu-resources
+++ b/osu-resources
@@ -1 +1 @@
-Subproject commit 6d9bbe6c838e4b89b69d5ad49b37b434aa62281e
+Subproject commit 0505cf0d3b317667dbc95346f57b67fdbcdb4dee
diff --git a/osu.Desktop/Beatmaps/IO/LegacyFilesystemReader.cs b/osu.Desktop/Beatmaps/IO/LegacyFilesystemReader.cs
new file mode 100644
index 0000000000..a6367ebfab
--- /dev/null
+++ b/osu.Desktop/Beatmaps/IO/LegacyFilesystemReader.cs
@@ -0,0 +1,57 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Linq;
+using osu.Game.Beatmaps.Formats;
+using osu.Game.Beatmaps.IO;
+using osu.Game.Beatmaps;
+
+namespace osu.Desktop.Beatmaps.IO
+{
+ ///
+ /// Reads an extracted legacy beatmap from disk.
+ ///
+ public class LegacyFilesystemReader : ArchiveReader
+ {
+ static LegacyFilesystemReader()
+ {
+ AddReader((storage, path) => Directory.Exists(path));
+ }
+
+ private string basePath { get; set; }
+ private string[] beatmaps { get; set; }
+ private Beatmap firstMap { get; set; }
+
+ public LegacyFilesystemReader(string path)
+ {
+ basePath = path;
+ beatmaps = Directory.GetFiles(basePath, @"*.osu").Select(f => Path.GetFileName(f)).ToArray();
+ if (beatmaps.Length == 0)
+ throw new FileNotFoundException(@"This directory contains no beatmaps");
+ using (var stream = new StreamReader(ReadFile(beatmaps[0])))
+ {
+ var decoder = BeatmapDecoder.GetDecoder(stream);
+ firstMap = decoder.Decode(stream);
+ }
+ }
+
+ public override string[] ReadBeatmaps()
+ {
+ return beatmaps;
+ }
+
+ public override Stream ReadFile(string name)
+ {
+ return File.OpenRead(Path.Combine(basePath, name));
+ }
+
+ public override BeatmapMetadata ReadMetadata()
+ {
+ return firstMap.Metadata;
+ }
+
+ public override void Dispose()
+ {
+ // no-op
+ }
}
+}
\ No newline at end of file
diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs
index 1421086054..a1a29b918f 100644
--- a/osu.Desktop/Program.cs
+++ b/osu.Desktop/Program.cs
@@ -11,10 +11,10 @@ namespace osu.Desktop
public static class Program
{
[STAThread]
- public static void Main()
+ public static void Main(string[] args)
{
BasicGameHost host = Host.GetSuitableHost(@"osu");
- host.Add(new OsuGame());
+ host.Add(new OsuGame(args));
host.Run();
}
}
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index 5553f12019..86ca44e381 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -59,6 +59,7 @@
AllRules.ruleset
false
false
+
none
@@ -135,8 +136,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/osu.Game.Tests/Resources/Resource.cs b/osu.Game.Tests/Resources/Resource.cs
new file mode 100644
index 0000000000..46c51da5ef
--- /dev/null
+++ b/osu.Game.Tests/Resources/Resource.cs
@@ -0,0 +1,17 @@
+using System;
+using System.IO;
+using System.Reflection;
+
+namespace osu.Game.Tests.Resources
+{
+ public static class Resource
+ {
+ public static Stream OpenResource(string name)
+ {
+ return Assembly.GetExecutingAssembly().GetManifestResourceStream(
+ $@"osu.Game.Tests.Resources.{name}") ??
+ Assembly.LoadFrom("osu.Game.Resources.dll").GetManifestResourceStream(
+ $@"osu.Game.Resources.{name}");
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game.Tests/Resources/Soleily - Renatus (Gamu) [Insane].osu b/osu.Game.Tests/Resources/Soleily - Renatus (Gamu) [Insane].osu
new file mode 100644
index 0000000000..3e44dc0af8
--- /dev/null
+++ b/osu.Game.Tests/Resources/Soleily - Renatus (Gamu) [Insane].osu
@@ -0,0 +1,1002 @@
+osu file format v14
+
+[General]
+AudioFilename: 03. Renatus - Soleily 192kbps.mp3
+AudioLeadIn: 0
+PreviewTime: 164471
+Countdown: 0
+SampleSet: Soft
+StackLeniency: 0.7
+Mode: 0
+LetterboxInBreaks: 0
+WidescreenStoryboard: 0
+
+[Editor]
+Bookmarks: 11505,22054,32604,43153,53703,64252,74802,85351,95901,106450,116999,119637,130186,140735,151285,161834,164471,175020,185570,196119,206669,209306
+DistanceSpacing: 1.8
+BeatDivisor: 4
+GridSize: 4
+TimelineZoom: 2
+
+[Metadata]
+Title:Renatus
+TitleUnicode:Renatus
+Artist:Soleily
+ArtistUnicode:Soleily
+Creator:Gamu
+Version:Insane
+Source:
+Tags:MBC7 Unisphere 地球ヤバイEP Chikyu Yabai
+BeatmapID:557821
+BeatmapSetID:241526
+
+[Difficulty]
+HPDrainRate:6.5
+CircleSize:4
+OverallDifficulty:8
+ApproachRate:9
+SliderMultiplier:1.8
+SliderTickRate:2
+
+[Events]
+//Background and Video events
+0,0,"machinetop_background.jpg",0,0
+//Break Periods
+2,122474,140135
+//Storyboard Layer 0 (Background)
+//Storyboard Layer 1 (Fail)
+//Storyboard Layer 2 (Pass)
+//Storyboard Layer 3 (Foreground)
+//Storyboard Sound Samples
+
+[TimingPoints]
+956,329.67032967033,4,2,0,60,1,0
+20736,-100,4,2,0,65,0,0
+22054,-100,4,2,0,70,0,0
+43153,-100,4,2,0,60,0,0
+48428,-100,4,2,0,50,0,0
+52879,-100,4,2,0,50,0,0
+53373,-100,4,2,0,60,0,0
+53703,-100,4,2,0,70,0,1
+74719,-100,4,2,0,70,0,0
+74802,-100,4,2,0,70,0,1
+95901,-100,4,2,0,70,0,0
+116999,-133.333333333333,4,2,0,50,0,0
+117164,-133.333333333333,4,2,0,30,0,0
+117329,-79.9999999999999,4,2,0,50,0,0
+117659,-100,4,2,0,50,0,0
+118977,-100,4,2,0,60,0,0
+119307,-100,4,2,0,70,0,0
+119637,659.340659340659,4,2,0,80,1,0
+119966,-100,4,2,0,70,0,0
+120296,-100,4,2,0,60,0,0
+120626,-100,4,2,0,50,0,0
+120955,-100,4,2,0,40,0,0
+121285,-100,4,2,0,30,0,0
+121615,-100,4,2,0,20,0,0
+121944,-100,4,2,0,10,0,0
+122274,-100,4,2,0,5,0,0
+140735,-100,4,2,0,50,0,0
+151285,-80,4,2,0,60,0,0
+161834,329.67032967033,4,2,0,65,1,0
+164141,-100,4,2,0,70,0,0
+164471,-100,4,2,0,70,0,1
+185487,-100,4,2,0,70,0,0
+185570,-100,4,2,0,70,0,1
+206669,659.340659340659,4,2,0,80,1,0
+206998,-100,4,2,0,70,0,0
+207328,-100,4,2,0,60,0,0
+207658,-100,4,2,0,50,0,0
+207987,-100,4,2,0,40,0,0
+208317,-100,4,2,0,30,0,0
+208647,-100,4,2,0,20,0,0
+208976,-100,4,2,0,10,0,0
+209306,-100,4,2,0,5,0,0
+
+
+[Colours]
+Combo1 : 142,199,255
+Combo2 : 255,128,128
+Combo3 : 128,255,255
+Combo4 : 128,255,128
+Combo5 : 255,187,255
+Combo6 : 255,177,140
+
+[HitObjects]
+192,168,956,6,0,P|184:128|200:80,1,90,4|0,1:2|0:0,0:0:0:0:
+304,56,1285,1,8,0:0:0:0:
+244,236,1450,2,0,P|204:252|156:244,1,90,2|0,0:0|0:0,0:0:0:0:
+276,156,1780,2,0,P|310:181|329:226,1,90,2|8,1:2|0:0,0:0:0:0:
+300,328,2109,1,2,0:0:0:0:
+192,332,2274,6,0,L|144:340,2,45,0|0|0,1:0|0:0|0:0,0:0:0:0:
+388,300,2604,1,8,0:0:0:0:
+244,236,2769,1,0,1:0:0:0:
+232,208,2851,1,0,0:0:0:0:
+224,176,2934,1,0,0:0:0:0:
+228,144,3016,1,0,0:0:0:0:
+244,116,3098,1,0,1:0:0:0:
+332,52,3263,2,0,P|376:48|424:56,1,90,8|0,0:0|0:0,0:0:0:0:
+488,228,3593,5,0,1:0:0:0:
+460,240,3675,1,0,0:0:0:0:
+428,236,3758,1,0,0:0:0:0:
+292,160,3923,2,0,P|288:204|300:252,1,90,8|0,0:0|0:0,0:0:0:0:
+316,276,4170,1,0,0:0:0:0:
+344,292,4252,2,0,L|388:300,1,45,0|0,0:0|0:0,0:0:0:0:
+288,356,4417,2,0,L|244:364,1,45,0|0,1:0|0:0,0:0:0:0:
+168,328,4582,2,0,P|124:324|72:332,1,90,8|0,0:0|0:0,0:0:0:0:
+24,188,4912,5,0,1:0:0:0:
+56,192,4994,1,0,0:0:0:0:
+88,196,5076,1,0,0:0:0:0:
+148,108,5241,1,8,0:0:0:0:
+188,240,5406,1,0,1:0:0:0:
+188,240,5488,1,0,0:0:0:0:
+188,240,5571,2,0,L|168:328,1,90,0|0,0:0|1:0,0:0:0:0:
+260,216,5901,2,0,P|236:180|188:164,1,90,8|0,0:0|0:0,0:0:0:0:
+248,296,6230,6,0,L|348:292,1,90,0|0,1:0|0:0,0:0:0:0:
+504,232,6560,1,8,0:0:0:0:
+400,204,6725,1,0,0:0:0:0:
+392,176,6807,1,0,0:0:0:0:
+384,144,6890,1,0,0:0:0:0:
+376,116,6972,1,0,0:0:0:0:
+368,88,7054,1,0,1:0:0:0:
+188,48,7219,2,0,L|208:140,1,90,8|0,0:0|0:0,0:0:0:0:
+248,296,7549,5,0,1:0:0:0:
+207,135,7714,1,0,0:0:0:0:
+156,232,7879,1,8,0:0:0:0:
+316,191,8043,1,0,1:0:0:0:
+316,191,8126,1,0,0:0:0:0:
+316,191,8208,2,0,L|372:200,1,45,0|0,0:0|0:0,0:0:0:0:
+492,200,8373,2,0,L|447:207,1,45,0|0,1:0|0:0,0:0:0:0:
+408,136,8538,2,0,P|396:92|400:48,1,90,8|0,0:0|0:0,0:0:0:0:
+260,32,8868,5,0,1:0:0:0:
+252,64,8950,1,0,0:0:0:0:
+236,92,9032,2,0,P|204:116|148:128,1,90,0|8,0:0|0:0,0:0:0:0:
+28,188,9362,1,0,0:0:0:0:
+60,196,9445,1,0,0:0:0:0:
+88,212,9527,2,0,P|112:244|124:300,1,90,0|0,0:0|1:0,0:0:0:0:
+112,128,9857,2,0,P|152:156|184:196,1,90,8|0,0:0|0:0,0:0:0:0:
+216,288,10186,5,0,1:0:0:0:
+216,288,10269,1,0,0:0:0:0:
+216,288,10351,1,0,0:0:0:0:
+268,192,10516,1,8,0:0:0:0:
+356,128,10681,1,0,1:0:0:0:
+388,120,10763,1,0,0:0:0:0:
+420,128,10846,2,0,P|440:168|436:220,1,90,0|0,0:0|1:0,0:0:0:0:
+332,328,11175,2,0,L|280:332,1,45,8|8,0:0|0:0,0:0:0:0:
+216,288,11340,2,0,L|164:292,1,45,0|0,1:0|0:0,1:0:0:0:
+100,248,11505,5,4,1:2:0:0:
+148,116,11670,1,2,0:0:0:0:
+268,192,11835,1,10,0:0:0:0:
+136,328,11999,2,0,L|44:336,1,90,2|0,0:0|0:0,0:0:0:0:
+216,288,12329,1,2,1:2:0:0:
+148,116,12494,1,10,0:0:0:0:
+100,248,12659,1,2,0:0:0:0:
+268,192,12824,5,0,1:0:0:0:
+268,192,12906,1,0,0:0:0:0:
+268,192,12988,1,0,0:0:0:0:
+340,272,13153,2,0,P|384:276|432:264,1,90,8|0,0:0|1:0,0:0:0:0:
+452,244,13401,1,0,0:0:0:0:
+468,216,13483,2,0,L|476:124,1,90,0|0,0:0|1:0,0:0:0:0:
+368,32,13813,2,0,L|360:121,1,90,8|0,0:0|0:0,0:0:0:0:
+340,272,14142,6,0,L|316:316,2,45,0|0|0,1:0|0:0|0:0,0:0:0:0:
+452,244,14472,1,8,0:0:0:0:
+268,192,14637,1,0,0:0:0:0:
+236,188,14719,1,0,0:0:0:0:
+204,192,14802,2,0,P|172:228|160:272,1,90,0|0,0:0|1:0,0:0:0:0:
+128,140,15131,2,0,P|160:104|172:60,1,90,8|0,0:0|0:0,0:0:0:0:
+64,52,15461,6,0,L|20:68,2,45,0|0|0,1:0|0:0|0:0,0:0:0:0:
+171,64,15791,1,8,0:0:0:0:
+264,8,15956,2,0,L|356:12,1,90,0|0,1:0|0:0,0:0:0:0:
+452,56,16285,1,0,1:0:0:0:
+296,140,16450,2,0,L|206:136,1,90,8|0,0:0|0:0,0:0:0:0:
+108,184,16780,6,0,P|92:224|96:272,1,90,0|0,1:0|0:0,0:0:0:0:
+200,244,17109,1,8,0:0:0:0:
+108,108,17274,2,0,L|12:116,1,90,0|0,0:0|0:0,0:0:0:0:
+200,244,17604,1,0,1:0:0:0:
+296,140,17769,2,0,L|385:132,1,90,8|0,0:0|0:0,0:0:0:0:
+480,184,18098,5,0,1:0:0:0:
+488,216,18181,1,0,0:0:0:0:
+496,248,18263,2,0,L|492:340,1,90,0|8,0:0|0:0,0:0:0:0:
+404,224,18593,2,0,L|396:176,2,45,0|0|0,1:0|0:0|0:0,0:0:0:0:
+304,264,18923,1,0,1:0:0:0:
+200,244,19087,2,0,P|156:240|108:248,1,90,8|0,0:0|0:0,0:0:0:0:
+296,140,19417,6,0,P|340:144|388:136,1,90,0|0,1:0|0:0,0:0:0:0:
+440,44,19747,1,8,0:0:0:0:
+404,224,19912,1,0,0:0:0:0:
+404,224,19994,1,0,0:0:0:0:
+404,224,20076,2,0,L|412:320,1,90,0|0,0:0|1:0,0:0:0:0:
+200,244,20406,2,0,L|192:154,1,90,8|0,0:0|0:0,0:0:0:0:
+184,44,20736,5,4,1:2:0:0:
+152,40,20818,1,0,0:0:0:0:
+120,48,20901,1,0,0:0:0:0:
+96,68,20983,1,0,0:0:0:0:
+76,92,21065,1,2,0:3:0:0:
+64,120,21148,1,0,0:0:0:0:
+60,152,21230,1,0,1:0:0:0:
+64,184,21313,1,0,0:0:0:0:
+76,212,21395,2,0,L|96:252,3,45,0|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0:
+144,316,21725,2,0,L|188:324,3,45,0|0|2|0,0:0|0:0|0:3|0:0,0:0:0:0:
+268,340,22054,6,0,L|364:336,1,90,4|0,1:2|0:0,0:0:0:0:
+452,280,22384,1,8,0:0:0:0:
+512,188,22549,2,0,P|516:144|504:96,1,90,2|0,0:0|0:0,0:0:0:0:
+340,24,22879,2,0,P|336:68|348:116,1,90,2|8,1:2|0:0,0:0:0:0:
+420,192,23208,1,2,0:0:0:0:
+328,252,23373,6,0,L|232:240,1,90,0|0,1:0|0:0,0:0:0:0:
+64,256,23703,1,8,0:0:0:0:
+144,184,23868,2,0,P|148:140|136:88,1,90,0|0,1:0|0:0,0:0:0:0:
+40,52,24197,1,2,1:2:0:0:
+139,95,24362,1,8,0:0:0:0:
+216,20,24527,1,0,0:0:0:0:
+315,63,24692,6,0,P|360:72|408:68,1,90,2|0,1:2|0:0,0:0:0:0:
+492,132,25021,1,8,0:0:0:0:
+412,204,25186,2,0,P|403:249|407:297,1,90,2|0,0:0|0:0,0:0:0:0:
+268,328,25516,2,0,P|277:283|273:235,1,90,2|8,1:2|0:0,0:0:0:0:
+232,140,25846,2,0,P|187:131|139:135,1,90,2|0,0:0|1:0,0:0:0:0:
+64,208,26175,5,2,0:0:0:0:
+44,316,26340,1,8,0:0:0:0:
+148,280,26505,1,2,1:2:0:0:
+456,208,26835,1,2,1:2:0:0:
+476,316,26999,1,10,0:0:0:0:
+372,280,27164,1,2,0:0:0:0:
+356,172,27329,6,0,L|380:80,1,90,0|0,1:0|0:0,0:0:0:0:
+456,208,27659,1,8,0:0:0:0:
+300,236,27824,1,2,0:0:0:0:
+300,236,27906,1,0,0:0:0:0:
+300,236,27988,2,0,L|208:228,1,90,0|2,0:0|1:2,0:0:0:0:
+140,312,28318,1,8,0:0:0:0:
+372,280,28483,2,0,L|464:272,1,90,2|0,0:0|1:0,0:0:0:0:
+500,136,28813,5,2,0:0:0:0:
+432,56,28977,1,8,0:0:0:0:
+328,24,29142,2,0,P|284:24|236:28,1,90,2|0,1:2|0:0,0:0:0:0:
+80,144,29472,1,2,1:2:0:0:
+116,44,29637,1,10,0:0:0:0:
+184,128,29802,1,2,0:0:0:0:
+20,88,29966,6,0,P|1:164|73:227,1,180,2|10,1:2|0:0,0:0:0:0:
+184,128,30461,2,0,P|227:120|276:124,1,90,2|0,0:0|0:0,0:0:0:0:
+392,188,30791,1,2,1:2:0:0:
+272,260,30956,1,8,0:0:0:0:
+396,328,31120,1,0,0:0:0:0:
+256,348,31285,5,2,1:2:0:0:
+224,344,31368,1,0,1:0:0:0:
+192,340,31450,2,0,L|172:248,1,90,2|0,1:2|1:0,0:0:0:0:
+8,136,31780,2,0,L|27:223,1,90,2|0,1:2|0:0,0:0:0:0:
+56,328,32109,1,2,1:2:0:0:
+108,192,32274,1,2,1:2:0:0:
+100,160,32357,1,0,1:0:0:0:
+92,132,32439,1,2,1:2:0:0:
+84,104,32521,1,0,1:0:0:0:
+76,72,32604,6,0,P|100:112|148:136,1,90,4|0,1:2|0:0,0:0:0:0:
+240,168,32934,1,8,0:0:0:0:
+336,124,33098,2,0,L|344:80,2,45,2|0|0,0:0|0:0|0:0,0:0:0:0:
+264,248,33428,2,0,P|220:248|176:220,1,90,2|8,1:2|0:0,0:0:0:0:
+260,84,33758,1,2,0:0:0:0:
+344,212,33923,5,0,1:0:0:0:
+344,212,34005,1,0,0:0:0:0:
+344,212,34087,1,0,0:0:0:0:
+440,160,34252,1,8,0:0:0:0:
+312,320,34417,2,0,P|272:336|220:324,1,90,0|0,1:0|0:0,0:0:0:0:
+156,176,34747,2,0,P|196:160|248:172,2,90,2|8|0,1:2|0:0|0:0,0:0:0:0:
+132,280,35241,5,2,1:2:0:0:
+132,280,35324,1,0,0:0:0:0:
+132,280,35406,2,0,L|120:376,1,90,0|8,0:0|0:0,0:0:0:0:
+312,320,35736,2,0,L|300:230,1,90,2|0,0:0|0:0,0:0:0:0:
+316,124,36065,1,2,1:2:0:0:
+400,192,36230,1,8,0:0:0:0:
+300,230,36395,2,0,P|255:231|211:224,1,90,2|0,0:0|1:0,0:0:0:0:
+24,132,36725,5,0,0:0:0:0:
+132,152,36890,1,8,0:0:0:0:
+60,232,37054,1,2,1:2:0:0:
+60,232,37137,1,0,0:0:0:0:
+60,232,37219,1,0,0:0:0:0:
+92,56,37384,2,0,L|184:44,1,90,2|10,1:2|0:0,0:0:0:0:
+316,124,37714,2,0,L|226:135,1,90,2|0,0:0|1:0,0:0:0:0:
+60,232,38043,6,0,P|52:276|64:328,1,90,0|8,0:0|0:0,0:0:0:0:
+220,152,38373,2,0,P|176:144|124:156,1,90,2|0,0:0|0:0,0:0:0:0:
+176,252,38703,1,2,1:2:0:0:
+323,213,38868,2,0,L|316:124,1,90,8|2,0:0|0:0,0:0:0:0:
+332,320,39197,5,0,1:0:0:0:
+424,260,39362,1,2,0:0:0:0:
+260,272,39527,2,0,P|246:313|256:360,1,90,8|2,0:0|1:2,0:0:0:0:
+408,336,39857,1,0,0:0:0:0:
+176,252,40021,2,0,L|80:260,2,90,2|10|2,1:2|0:0|0:0,0:0:0:0:
+324,212,40516,5,2,1:2:0:0:
+324,212,40598,1,0,1:0:0:0:
+324,212,40681,1,0,1:0:0:0:
+200,336,40846,1,2,1:2:0:0:
+236,188,41010,1,2,1:2:0:0:
+236,188,41093,1,0,1:0:0:0:
+236,188,41175,1,0,1:0:0:0:
+281,357,41340,1,2,1:2:0:0:
+176,252,41505,1,2,1:2:0:0:
+176,252,41587,1,0,1:0:0:0:
+176,252,41670,1,0,1:0:0:0:
+344,297,41835,5,2,1:2:0:0:
+432,232,41999,1,2,1:2:0:0:
+444,204,42082,1,0,1:0:0:0:
+448,172,42164,1,0,1:0:0:0:
+444,140,42247,1,0,1:0:0:0:
+432,112,42329,2,0,L|440:64,2,45,2|0|0,1:2|1:0|1:0,0:0:0:0:
+236,188,42659,1,0,0:0:0:0:
+340,172,42824,1,2,0:3:0:0:
+272,88,42988,1,0,0:0:0:0:
+132,160,43153,6,0,P|148:248|220:296,1,180,4|8,1:2|0:0,0:0:0:0:
+324,320,43648,2,0,L|336:364,2,45,0|0|0,0:0|0:0|0:0,0:0:0:0:
+292,216,43977,1,0,1:0:0:0:
+396,240,44142,2,0,P|440:244|488:232,1,90,8|0,0:0|0:0,0:0:0:0:
+328,124,44472,6,0,P|284:120|236:132,1,90,0|0,1:0|0:0,0:0:0:0:
+168,212,44802,1,8,0:0:0:0:
+192,316,44966,1,0,1:0:0:0:
+140,220,45131,1,0,0:0:0:0:
+83,310,45296,1,0,1:0:0:0:
+114,205,45461,1,8,0:0:0:0:
+10,229,45626,1,0,0:0:0:0:
+106,176,45791,6,0,P|113:133|108:85,1,90,0|0,1:0|0:0,0:0:0:0:
+204,136,46120,1,8,0:0:0:0:
+256,40,46285,1,0,0:0:0:0:
+256,40,46368,1,0,0:0:0:0:
+256,40,46450,2,0,L|356:44,1,90,0|0,0:0|1:0,0:0:0:0:
+501,124,46780,2,0,L|412:128,1,90,8|0,0:0|0:0,0:0:0:0:
+324,192,47109,5,0,1:0:0:0:
+356,296,47274,1,0,0:0:0:0:
+284,216,47439,1,8,0:0:0:0:
+269,323,47604,1,0,1:0:0:0:
+237,220,47769,1,0,0:0:0:0:
+178,311,47934,1,0,1:0:0:0:
+191,203,48098,1,8,0:0:0:0:
+99,261,48263,1,0,0:0:0:0:
+156,168,48428,6,0,B|176:112|136:64|136:64|200:96,1,180,4|8,1:2|0:0,0:0:0:0:
+300,124,48923,2,0,L|392:120,1,90,0|0,0:0|0:0,0:0:0:0:
+468,48,49252,1,0,1:0:0:0:
+390,120,49417,2,0,P|390:164|406:208,1,90,8|0,0:0|0:0,0:0:0:0:
+352,344,49747,6,0,P|352:300|336:256,1,90,4|0,1:2|0:0,0:0:0:0:
+240,208,50076,1,8,0:0:0:0:
+163,320,50241,2,0,P|207:324|252:316,1,90,0|0,1:0|0:0,0:0:0:0:
+240,208,50571,1,0,1:0:0:0:
+76,296,50736,2,0,P|76:340|92:384,1,90,8|0,0:0|0:0,0:0:0:0:
+312,164,51065,6,0,P|236:124|160:184,1,180,4|8,1:2|0:0,0:0:0:0:
+247,297,51560,2,0,L|240:208,1,90,0|0,0:0|0:0,0:0:0:0:
+224,48,51890,1,0,1:0:0:0:
+332,56,52054,2,0,L|366:58,5,30,8|0|0|0|0|0,0:0|0:0|0:0|0:0|0:0|0:0,0:0:0:0:
+408,64,52384,6,0,P|420:108|416:156,1,90,0|0,1:0|0:0,0:0:0:0:
+360,260,52714,1,8,0:0:0:0:
+247,297,52879,2,0,B|203:281|159:297|159:297|115:313|71:297,1,180,0|0,1:0|1:0,0:0:0:0:
+116,196,53373,1,8,0:0:0:0:
+120,164,53456,1,0,0:0:0:0:
+124,132,53538,1,0,0:0:0:0:
+128,100,53620,1,0,0:0:0:0:
+132,68,53703,5,4,1:2:0:0:
+40,136,53868,1,0,0:0:0:0:
+204,160,54032,2,0,L|304:152,1,90,8|0,0:0|0:0,0:0:0:0:
+408,64,54362,1,0,0:0:0:0:
+408,64,54445,1,0,0:0:0:0:
+408,64,54527,2,0,P|404:112|416:160,1,90,0|8,1:0|0:0,0:0:0:0:
+484,236,54857,1,0,0:0:0:0:
+428,328,55021,5,0,1:0:0:0:
+328,296,55186,1,0,0:0:0:0:
+328,296,55269,1,0,0:0:0:0:
+328,296,55351,1,8,0:0:0:0:
+416,300,55516,1,0,1:0:0:0:
+472,208,55681,1,0,0:0:0:0:
+316,268,55846,1,0,1:0:0:0:
+460,180,56010,1,8,0:0:0:0:
+304,240,56175,1,0,0:0:0:0:
+404,272,56340,5,0,1:0:0:0:
+448,152,56505,1,0,0:0:0:0:
+448,152,56587,1,0,0:0:0:0:
+448,152,56670,2,0,P|456:112|448:60,1,90,8|0,0:0|0:0,0:0:0:0:
+268,28,56999,2,0,P|260:68|268:120,1,90,0|0,0:0|1:0,0:0:0:0:
+404,272,57329,2,0,P|444:280|496:272,2,90,8|0|0,0:0|0:0|1:0,0:0:0:0:
+304,240,57824,5,0,0:0:0:0:
+252,336,57988,1,8,0:0:0:0:
+196,244,58153,1,0,1:0:0:0:
+24,256,58318,1,0,0:0:0:0:
+116,200,58483,1,0,1:0:0:0:
+136,60,58648,1,8,0:0:0:0:
+192,152,58813,1,0,0:0:0:0:
+304,240,58977,6,0,P|348:252|396:248,1,90,0|0,1:0|0:0,0:0:0:0:
+456,116,59307,2,0,P|412:104|364:108,1,90,8|0,0:0|0:0,0:0:0:0:
+273,161,59637,1,0,0:0:0:0:
+136,60,59802,1,0,1:0:0:0:
+192,152,59966,1,8,0:0:0:0:
+23,177,60131,1,0,0:0:0:0:
+129,203,60296,5,0,1:0:0:0:
+88,304,60461,2,0,P|132:311|176:303,1,90,0|8,0:0|0:0,0:0:0:0:
+304,240,60791,1,0,1:0:0:0:
+304,240,60873,1,0,0:0:0:0:
+304,240,60956,2,0,L|312:288,3,45,0|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0:
+384,256,61285,2,0,L|392:304,3,45,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0:
+464,272,61615,5,2,1:2:0:0:
+488,168,61780,1,2,0:0:0:0:
+428,80,61945,1,10,0:0:0:0:
+332,32,62109,2,0,P|288:28|240:36,1,90,2|0,0:0|0:0,0:0:0:0:
+28,216,62439,1,2,1:2:0:0:
+88,304,62604,1,10,0:0:0:0:
+184,352,62769,2,0,P|228:356|276:348,1,90,2|0,0:0|1:0,0:0:0:0:
+384,256,63098,6,0,P|409:219|426:174,1,90,2|8,0:0|0:0,0:0:0:0:
+428,80,63428,2,0,L|420:36,2,45,2|0|0,1:2|0:0|0:0,0:0:0:0:
+456,288,63758,1,2,1:2:0:0:
+324,200,63923,1,10,1:2:0:0:
+292,204,64005,1,0,1:0:0:0:
+260,208,64087,1,2,1:2:0:0:
+228,212,64170,1,0,1:0:0:0:
+196,216,64252,5,4,1:2:0:0:
+104,160,64417,1,0,0:0:0:0:
+228,296,64582,2,0,L|320:284,1,90,8|0,0:0|0:0,0:0:0:0:
+344,112,64912,1,0,0:0:0:0:
+344,112,64994,1,0,0:0:0:0:
+344,112,65076,2,0,L|254:123,1,90,0|8,1:0|0:0,0:0:0:0:
+144,284,65406,2,0,P|148:328|176:364,1,90,0|0,0:0|1:0,0:0:0:0:
+196,216,65736,5,0,0:0:0:0:
+196,216,65818,1,0,0:0:0:0:
+196,216,65901,2,0,P|155:198|110:205,1,90,8|0,0:0|1:0,0:0:0:0:
+36,284,66230,1,0,0:0:0:0:
+4,180,66395,1,0,1:0:0:0:
+132,24,66560,1,8,0:0:0:0:
+100,128,66725,1,0,0:0:0:0:
+24,48,66890,5,0,1:0:0:0:
+212,108,67054,1,0,0:0:0:0:
+212,108,67137,1,0,0:0:0:0:
+212,108,67219,2,0,L|300:92,1,90,8|0,0:0|0:0,0:0:0:0:
+472,144,67549,2,0,L|384:160,1,90,0|0,0:0|1:0,0:0:0:0:
+196,216,67879,2,0,P|240:216|288:240,1,90,8|0,0:0|0:0,0:0:0:0:
+324,336,68208,5,0,1:0:0:0:
+144,288,68373,1,0,0:0:0:0:
+58,170,68538,1,8,0:0:0:0:
+196,215,68703,1,0,1:0:0:0:
+58,260,68868,1,0,0:0:0:0:
+144,142,69032,2,0,L|138:108,2,30,0|0|0,1:0|0:0|0:0,0:0:0:0:
+144,142,69197,2,0,P|184:124|232:132,1,90,8|0,0:0|0:0,0:0:0:0:
+312,248,69527,6,0,L|324:338,1,90,0|0,1:0|0:0,0:0:0:0:
+436,248,69857,1,8,0:0:0:0:
+432,216,69939,1,0,0:0:0:0:
+428,184,70021,1,0,0:0:0:0:
+328,120,70186,1,0,0:0:0:0:
+324,152,70269,1,0,0:0:0:0:
+320,184,70351,1,0,1:0:0:0:
+316,216,70434,1,0,0:0:0:0:
+312,248,70516,2,0,L|320:300,1,45,8|0,0:0|0:0,0:0:0:0:
+244,340,70681,2,0,L|237:295,1,45,0|0,0:0|0:0,0:0:0:0:
+216,224,70846,6,0,P|168:216|124:224,1,90,0|0,1:0|0:0,0:0:0:0:
+40,288,71175,1,8,0:0:0:0:
+2,95,71340,2,0,P|-4:139|4:184,1,90,0|0,1:0|0:0,0:0:0:0:
+164,304,71670,1,0,1:0:0:0:
+312,248,71835,1,8,0:0:0:0:
+244,340,71999,1,0,0:0:0:0:
+216,224,72164,6,0,L|228:132,1,90,0|0,1:0|0:0,0:0:0:0:
+332,148,72494,2,0,L|344:56,1,90,8|0,0:0|0:0,0:0:0:0:
+312,248,72824,1,0,0:0:0:0:
+164,304,72988,1,0,1:0:0:0:
+332,336,73153,1,8,0:0:0:0:
+360,324,73236,1,0,0:0:0:0:
+384,304,73318,1,0,0:0:0:0:
+399,276,73401,1,0,0:0:0:0:
+403,244,73483,6,0,L|396:200,3,45,4|0|2|0,1:2|0:0|0:0|1:0,0:0:0:0:
+420,112,73813,2,0,L|427:68,3,45,2|0|2|0,1:2|0:0|1:2|0:0,0:0:0:0:
+352,16,74142,2,0,L|345:60,3,45,0|0|2|0,0:0|1:0|1:2|0:0,0:0:0:0:
+332,148,74472,1,2,1:2:0:0:
+332,148,74554,1,0,1:0:0:0:
+332,148,74637,1,2,1:2:0:0:
+332,148,74719,1,0,1:0:0:0:
+332,148,74802,6,0,P|360:216|320:312,1,180,4|2,1:2|0:3,0:0:0:0:
+190,310,75296,2,0,P|151:231|180:148,1,180,4|0,1:2|0:0,0:0:0:0:
+256,56,75791,1,0,0:0:0:0:
+332,148,75956,1,2,0:3:0:0:
+179,148,76120,5,4,1:2:0:0:
+336,64,76285,1,4,1:2:0:0:
+256,224,76450,1,2,0:3:0:0:
+176,64,76615,1,4,1:2:0:0:
+256,140,76780,2,0,L|256:324,1,180,2|0,0:0|0:0,0:0:0:0:
+364,300,77274,1,2,0:3:0:0:
+148,300,77439,6,0,P|104:316|76:356,1,90,4|0,1:2|0:0,0:0:0:0:
+24,252,77769,2,0,L|16:208,3,45,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0:
+96,212,78098,2,0,L|104:168,3,45,0|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0:
+32,128,78428,2,0,L|24:84,3,45,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0:
+104,88,78758,5,2,1:2:0:0:
+204,132,78923,1,0,0:0:0:0:
+236,124,79005,1,0,0:0:0:0:
+268,116,79087,2,0,L|280:68,3,45,8|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0:
+348,100,79417,2,0,L|360:52,3,45,0|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0:
+428,84,79747,1,8,1:2:0:0:
+460,76,79829,1,0,1:0:0:0:
+492,68,79912,1,0,1:0:0:0:
+492,260,80076,6,0,P|400:248|328:296,1,180,4|2,1:2|0:3,0:0:0:0:
+144,236,80571,2,0,P|236:248|308:200,1,180,4|0,1:2|0:0,0:0:0:0:
+348,100,81065,2,0,P|348:56|336:8,1,90,0|2,0:0|0:3,0:0:0:0:
+140,48,81395,5,4,1:2:0:0:
+244,68,81560,1,4,1:2:0:0:
+144,236,81725,1,2,0:3:0:0:
+176,133,81890,1,4,1:2:0:0:
+184,304,82054,2,0,P|100:300|68:220,1,180,2|0,0:0|0:0,0:0:0:0:
+100,116,82549,1,2,0:3:0:0:
+264,244,82714,6,0,L|272:340,1,90,4|0,1:2|0:0,0:0:0:0:
+380,316,83043,1,8,0:0:0:0:
+396,288,83126,1,0,0:0:0:0:
+400,256,83208,1,0,0:0:0:0:
+396,224,83291,1,0,0:0:0:0:
+380,196,83373,2,0,L|336:176,3,45,0|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0:
+272,148,83703,1,8,0:0:0:0:
+256,120,83785,1,0,0:0:0:0:
+252,88,83868,1,0,0:0:0:0:
+256,56,83950,1,0,0:0:0:0:
+272,28,84032,6,0,L|316:8,3,45,2|0|0|0,1:2|0:0|0:0|0:0,0:0:0:0:
+360,72,84362,2,0,L|408:72,3,45,8|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0:
+421,149,84692,2,0,L|464:169,3,45,2|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0:
+443,244,85021,2,0,L|473:281,3,45,8|0|0|0,1:2|1:0|0:0|0:0,0:0:0:0:
+422,339,85351,6,0,L|240:348,1,180,4|2,1:2|0:3,0:0:0:0:
+76,172,85846,2,0,L|255:163,1,180,4|0,1:2|0:0,0:0:0:0:
+421,149,86340,2,0,P|435:107|428:56,1,90,0|2,0:0|0:3,0:0:0:0:
+228,56,86670,5,4,1:2:0:0:
+280,192,86835,1,4,1:2:0:0:
+328,96,86999,1,2,0:3:0:0:
+180,152,87164,1,4,1:2:0:0:
+28,100,87330,2,0,P|16:56|20:8,1,90,2|0,0:0|0:0,0:0:0:0:
+0,180,87659,1,0,0:0:0:0:
+28,284,87824,1,2,0:3:0:0:
+108,352,87988,6,0,P|152:360|196:356,1,90,4|0,1:2|0:0,0:0:0:0:
+276,284,88318,1,8,0:0:0:0:
+304,272,88401,1,0,0:0:0:0:
+336,268,88483,1,0,0:0:0:0:
+368,272,88565,1,0,0:0:0:0:
+396,284,88648,2,0,L|432:312,1,45,0|0,0:0|0:0,0:0:0:0:
+488,252,88813,2,0,L|452:224,1,45,0|0,1:0|0:0,0:0:0:0:
+400,164,88977,2,0,L|396:116,3,45,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0:
+316,64,89307,6,0,L|320:160,1,90,2|0,1:2|0:0,0:0:0:0:
+276,284,89637,1,8,0:0:0:0:
+248,296,89719,1,0,0:0:0:0:
+216,300,89802,1,0,1:0:0:0:
+184,296,89884,1,0,0:0:0:0:
+156,284,89966,2,0,L|120:256,1,45,0|0,0:0|0:0,0:0:0:0:
+176,200,90131,2,0,L|140:172,1,45,0|0,1:0|0:0,0:0:0:0:
+196,116,90296,2,0,L|160:88,3,45,8|0|0|0,1:2|1:0|1:0|0:0,0:0:0:0:
+92,44,90626,6,0,P|48:44|24:160,1,180,4|2,1:2|0:3,0:0:0:0:
+156,284,91120,2,0,B|200:300|244:284|244:284|288:268|332:284,1,180,4|0,1:2|0:0,0:0:0:0:
+176,200,91615,2,0,P|176:156|196:116,1,90,0|2,0:0|0:3,0:0:0:0:
+264,28,91945,6,0,L|353:39,1,90,4|0,1:2|1:0,0:0:0:0:
+453,159,92274,2,0,L|364:148,1,90,2|4,0:3|1:2,0:0:0:0:
+268,196,92604,2,0,P|260:268|328:348,1,180,2|0,0:0|0:0,0:0:0:0:
+364,248,93098,1,2,0:3:0:0:
+176,200,93263,5,4,1:2:0:0:
+72,228,93428,1,0,1:0:0:0:
+152,92,93593,1,0,1:0:0:0:
+256,64,93758,1,0,1:0:0:0:
+336,200,93923,5,0,1:0:0:0:
+440,228,94087,1,0,1:0:0:0:
+360,92,94252,1,0,1:0:0:0:
+256,64,94417,1,0,1:0:0:0:
+176,200,94582,5,2,1:2:0:0:
+168,228,94664,1,0,1:0:0:0:
+168,260,94747,1,0,1:0:0:0:
+172,292,94829,1,0,1:0:0:0:
+192,316,94912,1,0,1:0:0:0:
+220,328,94994,1,0,1:0:0:0:
+252,332,95076,1,0,1:0:0:0:
+280,320,95159,1,0,1:0:0:0:
+300,296,95241,2,0,L|308:248,3,45,2|0|0|0,1:2|1:0|1:0|1:0,0:0:0:0:
+312,172,95571,2,0,L|304:127,3,45,0|0|0|0,1:0|1:0|1:0|1:0,0:0:0:0:
+256,64,95901,6,0,P|208:56|164:60,1,90,4|0,1:2|0:0,0:0:0:0:
+76,116,96230,1,8,0:0:0:0:
+60,224,96395,1,0,0:0:0:0:
+60,224,96477,1,0,0:0:0:0:
+160,184,96642,1,0,0:0:0:0:
+160,184,96725,1,0,1:0:0:0:
+63,26,96890,2,0,L|76:116,1,90,8|0,0:0|0:0,0:0:0:0:
+136,272,97219,5,0,1:0:0:0:
+168,268,97302,1,0,0:0:0:0:
+200,264,97384,1,0,0:0:0:0:
+232,260,97466,1,0,0:0:0:0:
+264,256,97549,1,8,0:0:0:0:
+384,136,97714,1,0,1:0:0:0:
+376,168,97796,1,0,0:0:0:0:
+380,200,97879,1,0,0:0:0:0:
+392,228,97961,1,0,0:0:0:0:
+416,248,98043,2,0,P|464:260|512:260,2,90,0|8|0,1:0|0:0|0:0,0:0:0:0:
+231,105,98538,6,0,L|188:116,2,45,0|0|0,1:0|0:0|0:0,0:0:0:0:
+376,56,98868,2,0,L|420:64,1,45,8|0,0:0|0:0,0:0:0:0:
+384,136,99032,1,0,0:0:0:0:
+384,136,99115,2,0,P|340:128|304:92,1,90,0|0,0:0|0:0,0:0:0:0:
+303,18,99362,2,0,L|207:26,2,90,0|8|0,1:0|0:0|0:0,0:0:0:0:
+452,88,99857,5,0,1:0:0:0:
+465,116,99939,1,0,0:0:0:0:
+466,147,100021,1,0,0:0:0:0:
+456,177,100104,1,0,0:0:0:0:
+436,201,100186,2,0,P|416:213|389:216,3,45,8|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0:
+320,188,100516,2,0,P|300:176|273:173,3,45,0|0|0|0,0:0|1:0|1:0|0:0,0:0:0:0:
+204,200,100846,2,0,P|192:220|189:247,3,45,8|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0:
+188,320,101175,6,0,P|143:322|100:310,1,90,0|0,1:0|0:0,0:0:0:0:
+76,292,101423,1,0,0:0:0:0:
+76,292,101505,1,8,0:0:0:0:
+76,292,101587,2,0,L|72:248,1,45
+12,68,101835,2,0,L|6:24,2,45,0|0|0,0:0|0:0|1:0,0:0:0:0:
+104,140,102164,2,0,L|171:132,3,45,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0:
+224,124,102494,6,0,P|236:164|232:216,1,90,0|0,1:0|0:0,0:0:0:0:
+288,296,102824,1,8,0:0:0:0:
+288,296,102906,1,0,0:0:0:0:
+288,296,102988,2,0,P|328:284|380:288,1,90,0|0,1:0|0:0,0:0:0:0:
+404,304,103236,1,0,0:0:0:0:
+424,328,103318,1,0,1:0:0:0:
+448,188,103483,2,0,L|440:140,3,45,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0:
+424,72,103813,5,0,1:0:0:0:
+324,112,103977,1,0,0:0:0:0:
+324,112,104060,1,0,0:0:0:0:
+324,112,104142,2,0,P|280:116|232:104,1,90,8|0,0:0|0:0,0:0:0:0:
+160,28,104472,1,0,0:0:0:0:
+216,208,104637,1,0,1:0:0:0:
+216,208,104719,1,0,0:0:0:0:
+216,208,104802,1,8,0:0:0:0:
+352,240,104966,1,0,0:0:0:0:
+384,244,105049,1,0,0:0:0:0:
+416,248,105131,6,0,L|460:240,4,45,0|0|0|0|8,1:0|0:0|0:0|0:0|0:0,0:0:0:0:
+272,288,105626,1,0,1:0:0:0:
+264,320,105708,1,0,0:0:0:0:
+256,352,105791,2,0,L|204:356,5,30,0|0|0|0|0|0,0:0|0:0|0:0|1:0|0:0|0:0,0:0:0:0:
+156,332,106120,2,0,L|104:336,5,30,8|0|0|0|0|0,0:0|0:0|0:0|1:0|0:0|0:0,0:0:0:0:
+56,312,106450,5,4,1:2:0:0:
+4,188,106615,1,0,0:0:0:0:
+168,220,106780,2,0,P|127:232|79:228,1,90,8|0,0:0|0:0,0:0:0:0:
+112,124,107109,1,0,0:0:0:0:
+272,216,107274,2,0,L|264:316,1,90,0|8,1:0|0:0,0:0:0:0:
+400,268,107604,1,0,0:0:0:0:
+428,132,107769,5,0,1:0:0:0:
+428,132,107851,1,0,0:0:0:0:
+428,132,107934,1,0,0:0:0:0:
+428,132,108016,1,0,0:0:0:0:
+428,132,108098,1,8,0:0:0:0:
+332,84,108263,2,0,P|288:80|232:88,1,90,0|0,1:0|0:0,0:0:0:0:
+112,124,108593,1,0,1:0:0:0:
+148,264,108758,1,8,0:0:0:0:
+16,236,108923,1,0,0:0:0:0:
+264,126,109087,6,0,L|272:216,1,90,0|0,1:0|0:0,0:0:0:0:
+452,224,109417,2,0,L|460:320,1,90,8|0,0:0|0:0,0:0:0:0:
+360,232,109747,1,0,0:0:0:0:
+348,56,109912,1,0,1:0:0:0:
+416,140,110076,1,8,0:0:0:0:
+256,112,110241,2,0,P|212:120|160:112,1,90,0|0,0:0|1:0,0:0:0:0:
+348,56,110571,6,0,L|331:150,1,90,0|8,0:0|0:0,0:0:0:0:
+208,328,110901,2,0,L|191:239,1,90,0|0,1:0|0:0,0:0:0:0:
+184,216,111148,1,0,1:0:0:0:
+178,194,111230,1,0,1:0:0:0:
+68,272,111395,1,8,0:0:0:0:
+56,136,111560,1,0,1:0:0:0:
+178,194,111725,6,0,P|219:203|267:199,1,90,4|0,1:2|0:0,0:0:0:0:
+364,148,112054,1,8,0:0:0:0:
+384,256,112219,2,0,P|406:291|443:322,1,90,0|0,0:0|0:0,0:0:0:0:
+488,224,112549,1,0,1:0:0:0:
+304,232,112714,2,0,L|208:224,2,90,8|0|0,0:0|0:0|1:0,0:0:0:0:
+208,328,113208,6,0,L|112:320,1,90,0|8,0:0|0:0,0:0:0:0:
+26,184,113538,2,0,L|116:192,1,90,0|0,1:0|0:0,0:0:0:0:
+304,232,113868,1,0,1:0:0:0:
+116,192,114032,1,8,0:0:0:0:
+224,132,114197,1,0,0:0:0:0:
+208,328,114362,6,0,B|272:360|320:312|320:312|340:368,1,180,4|8,1:2|0:0,0:0:0:0:
+304,232,114857,2,0,P|300:184|308:140,1,90,0|0,0:0|0:0,0:0:0:0:
+384,64,115186,1,0,1:0:0:0:
+307,143,115351,1,8,0:0:0:0:
+256,48,115516,1,0,0:0:0:0:
+456,24,115681,6,0,B|482:101|420:136|420:136|440:184,1,180,4|8,1:2|0:0,0:0:0:0:
+384,64,116175,2,0,P|340:56|296:64,1,90,0|0,1:0|0:0,0:0:0:0:
+211,171,116505,1,0,1:0:0:0:
+439,181,116670,2,0,L|448:84,1,90,8|0,0:0|0:0,0:0:0:0:
+372,296,116999,6,2,L|304:292,1,67.5000025749208,2|0,0:1|0:0,0:0:0:0:
+136,252,117329,6,2,P|196:260|212:172,1,168.75,0|0,0:0|0:0,0:0:0:0:
+192,148,117659,1,2,0:3:0:0:
+164,132,117741,1,2,0:3:0:0:
+132,124,117824,1,2,1:3:0:0:
+100,132,117906,1,2,0:3:0:0:
+72,148,117988,2,0,L|52:56,1,90,2|8,0:3|0:0,0:0:0:0:
+36,244,118318,5,0,1:0:0:0:
+76,344,118483,1,0,1:0:0:0:
+184,352,118648,1,0,1:0:0:0:
+244,264,118813,1,0,1:0:0:0:
+244,264,118895,1,0,1:0:0:0:
+244,264,118977,2,0,L|288:260,3,45,2|0|2|0,1:2|0:0|0:0|0:0,0:0:0:0:
+332,328,119307,2,0,L|376:324,3,45,2|0|2|0,1:2|0:0|0:0|0:0,0:0:0:0:
+412,252,119637,5,4,1:2:0:0:
+256,192,119719,12,0,122274,0:0:0:0:
+256,192,140735,6,0,L|228:156,1,45,4|0,1:2|0:0,0:0:0:0:
+152,132,141065,2,0,P|129:129|104:136,1,45
+48,192,141395,2,0,P|40:236|52:280,1,90,8|8,0:0|0:0,0:0:0:0:
+196,352,142054,6,0,L|308:340,1,90,8|8,0:0|1:2,0:0:0:0:
+336,280,142549,1,0,0:0:0:0:
+404,324,142713,1,8,0:0:0:0:
+404,324,142878,1,8,0:0:0:0:
+292,120,143373,5,0,1:0:0:0:
+212,104,143538,1,0,0:0:0:0:
+140,140,143702,1,0,0:0:0:0:
+120,220,143867,1,0,0:0:0:0:
+144,296,144032,2,0,P|184:320|228:316,1,90,10|8,0:0|0:0,0:0:0:0:
+372,212,144691,6,0,P|327:209|290:232,1,90,10|8,0:0|1:2,0:0:0:0:
+348,288,145186,1,0,0:0:0:0:
+452,220,145351,1,10,0:0:0:0:
+452,220,145516,1,8,0:0:0:0:
+328,36,146010,5,2,1:2:0:0:
+264,88,146175,1,0,0:0:0:0:
+184,108,146340,1,0,0:0:0:0:
+104,88,146505,1,0,0:0:0:0:
+44,36,146669,1,8,0:0:0:0:
+44,36,146999,1,8,0:0:0:0:
+44,36,147329,6,0,L|24:84,1,45,8|0,0:0|0:0,0:0:0:0:
+52,156,147658,2,0,L|71:204,1,45,8|0,1:2|0:0,0:0:0:0:
+144,236,147988,1,8,0:0:0:0:
+144,236,148153,1,8,0:0:0:0:
+316,64,148647,5,0,1:0:0:0:
+380,116,148812,1,0,0:0:0:0:
+408,192,148977,1,0,0:0:0:0:
+380,268,149142,1,0,0:0:0:0:
+316,320,149307,2,0,L|224:316,1,90,10|8,0:0|0:0,0:0:0:0:
+64,248,149966,5,10,0:0:0:0:
+144,236,150131,1,0,0:0:0:0:
+188,168,150296,1,8,1:2:0:0:
+192,88,150461,1,0,0:0:0:0:
+140,24,150626,2,0,P|120:16|96:20,1,45,10|0,0:0|0:0,0:0:0:0:
+260,132,150955,2,0,P|280:140|304:136,1,45,2|0,0:0|0:0,0:0:0:0:
+476,48,151285,6,0,L|484:160,1,112.5,4|0,1:2|0:0,0:0:0:0:
+464,236,151779,1,0,0:0:0:0:
+436,308,151944,2,0,P|380:320|324:308,1,112.5,8|8,0:0|0:0,0:0:0:0:
+76,308,152604,6,0,P|132:320|188:308,1,112.5,8|8,0:0|1:2,0:0:0:0:
+256,88,153263,1,8,0:0:0:0:
+256,168,153428,1,8,0:0:0:0:
+256,168,153922,5,4,1:2:0:0:
+256,248,154087,1,0,0:0:0:0:
+324,128,154252,1,0,0:0:0:0:
+188,128,154417,1,0,0:0:0:0:
+332,212,154582,2,0,L|388:204,1,56.25,10|0,0:0|0:0,0:0:0:0:
+492,152,154911,2,0,L|436:144,1,56.25,8|0,0:0|0:0,0:0:0:0:
+324,128,155241,5,10,0:0:0:0:
+180,212,155406,1,0,0:0:0:0:
+332,212,155571,1,8,1:2:0:0:
+188,128,155735,1,0,0:0:0:0:
+256,248,155900,1,10,0:0:0:0:
+256,248,156065,2,0,L|256:304,2,56.25,0|0|0,0:0|0:0|0:0,0:0:0:0:
+180,212,156560,6,0,L|124:204,1,56.25,4|0,1:2|0:0,0:0:0:0:
+20,152,156889,2,0,L|76:144,1,56.25,0|0,0:0|0:0,0:0:0:0:
+188,128,157219,2,0,P|212:72|192:16,1,112.5,8|8,0:0|0:0,0:0:0:0:
+132,72,157713,1,0,0:0:0:0:
+180,212,157878,6,0,L|236:208,1,56.25,8|0,0:0|0:0,0:0:0:0:
+360,252,158208,2,8,L|304:248,1,56.25,8|0,1:2|0:0,0:0:0:0:
+168,292,158538,2,0,L|160:356,2,56.25,8|8|0,0:0|0:0|0:0,0:0:0:0:
+180,212,159032,1,0,0:0:0:0:
+144,140,159197,6,0,P|104:128|36:148,1,112.5,2|0,1:2|0:0,0:0:0:0:
+12,220,159691,1,0,0:0:0:0:
+36,296,159856,2,0,P|60:316|92:324,1,56.25,8|0,0:0|0:0,0:0:0:0:
+215,264,160186,2,0,P|189:273|168:292,1,56.25,8|0,0:0|0:0,0:0:0:0:
+228,344,160516,6,0,L|284:340,1,56.25,10|0,0:0|0:0,0:0:0:0:
+328,276,160845,2,0,L|384:272,1,56.25,8|0,1:2|0:0,0:0:0:0:
+428,208,161175,1,8,0:0:0:0:
+440,128,161340,1,8,0:0:0:0:
+400,60,161505,1,2,0:0:0:0:
+328,28,161669,1,0,0:0:0:0:
+212,76,161834,6,0,P|200:120|208:164,1,90,2|0,1:2|1:0,0:0:0:0:
+300,308,162163,2,0,P|312:264|304:220,1,90,2|0,1:2|1:0,0:0:0:0:
+140,236,162493,2,0,P|184:248|228:240,1,90,2|0,1:2|1:0,0:0:0:0:
+372,148,162823,2,0,P|328:136|284:144,1,90,2|0,1:2|1:0,0:0:0:0:
+104,316,163152,5,2,1:2:0:0:
+78,297,163235,1,0,1:0:0:0:
+60,270,163317,1,0,1:0:0:0:
+54,239,163399,1,0,1:0:0:0:
+58,207,163482,1,2,1:2:0:0:
+74,180,163564,1,0,1:0:0:0:
+98,159,163647,1,0,1:0:0:0:
+127,149,163729,1,0,1:0:0:0:
+158,150,163812,2,0,L|208:160,1,45,2|0,1:2|1:0,0:0:0:0:
+344,184,163976,2,0,L|294:194,1,45,0|0,1:0|1:0,0:0:0:0:
+140,236,164141,1,4,1:2:0:0:
+140,236,164471,6,0,L|232:252,1,90,4|0,1:2|0:0,0:0:0:0:
+344,184,164801,1,8,0:0:0:0:
+380,284,164965,1,0,0:0:0:0:
+368,104,165130,2,0,P|324:104|284:128,1,90,0|0,0:0|1:0,0:0:0:0:
+356,360,165460,2,0,P|400:360|440:336,1,90,8|0,0:0|0:0,0:0:0:0:
+432,208,165790,5,0,1:0:0:0:
+292,260,165954,1,0,0:0:0:0:
+344,184,166119,1,8,0:0:0:0:
+204,236,166284,1,0,1:0:0:0:
+204,236,166366,1,0,0:0:0:0:
+204,236,166449,2,0,L|216:328,1,90,0|0,0:0|1:0,0:0:0:0:
+120,208,166779,2,0,L|131:118,1,90,8|0,0:0|0:0,0:0:0:0:
+204,236,167108,5,0,1:0:0:0:
+32,216,167273,1,0,0:0:0:0:
+130,118,167438,1,8,0:0:0:0:
+110,298,167603,1,0,0:0:0:0:
+110,298,167685,1,0,0:0:0:0:
+110,298,167768,2,0,L|121:208,1,90,0|0,0:0|1:0,0:0:0:0:
+304,40,168097,2,0,L|315:130,1,90,8|0,0:0|0:0,0:0:0:0:
+328,236,168427,5,0,1:0:0:0:
+184,148,168592,1,0,0:0:0:0:
+314,129,168757,1,8,0:0:0:0:
+197,254,168921,1,0,1:0:0:0:
+197,254,169004,1,0,0:0:0:0:
+197,254,169086,2,0,P|220:292|260:312,1,90,0|0,0:0|1:0,0:0:0:0:
+409,210,169416,2,0,P|365:211|328:236,1,90,8|0,0:0|0:0,0:0:0:0:
+488,232,169746,6,0,P|487:192|464:149,1,90,0|0,1:0|0:0,0:0:0:0:
+314,129,170075,1,8,0:0:0:0:
+409,210,170240,1,0,0:0:0:0:
+332,40,170405,2,0,L|240:36,1,90,0|0,0:0|1:0,0:0:0:0:
+68,144,170735,2,0,L|157:140,1,90,8|0,0:0|0:0,0:0:0:0:
+314,129,171064,5,0,1:0:0:0:
+332,40,171229,1,0,0:0:0:0:
+324,216,171394,1,8,0:0:0:0:
+306,305,171559,1,0,1:0:0:0:
+257,178,171724,1,0,0:0:0:0:
+168,160,171888,1,0,1:0:0:0:
+384,164,172053,1,8,0:0:0:0:
+473,182,172218,1,0,0:0:0:0:
+306,305,172383,6,0,L|216:312,1,90,0|0,1:0|0:0,0:0:0:0:
+60,172,172713,1,8,0:0:0:0:
+120,260,172877,1,0,0:0:0:0:
+168,160,173042,2,0,L|172:68,1,90,0|0,0:0|1:0,0:0:0:0:
+309,216,173372,2,0,L|306:306,1,90,8|0,0:0|0:0,0:0:0:0:
+120,260,173702,5,0,1:0:0:0:
+152,256,173784,1,0,1:0:0:0:
+184,252,173866,1,0,1:0:0:0:
+309,216,174031,1,8,0:0:0:0:
+103,168,174196,1,0,1:0:0:0:
+135,164,174279,1,0,1:0:0:0:
+167,160,174361,1,0,1:0:0:0:
+292,124,174526,1,0,1:0:0:0:
+87,76,174691,1,8,1:2:0:0:
+119,72,174773,1,0,1:0:0:0:
+151,68,174855,1,0,1:0:0:0:
+276,32,175020,6,0,L|368:40,1,90,0|0,1:0|0:0,0:0:0:0:
+448,108,175350,1,8,0:0:0:0:
+292,124,175515,1,0,0:0:0:0:
+292,124,175597,1,0,0:0:0:0:
+292,124,175680,2,0,L|308:216,1,90,0|0,0:0|1:0,0:0:0:0:
+328,320,176009,1,8,0:0:0:0:
+408,248,176174,1,0,0:0:0:0:
+220,300,176339,6,0,P|176:304|128:292,1,90,0|0,1:0|0:0,0:0:0:0:
+16,120,176669,1,8,0:0:0:0:
+120,152,176834,1,0,1:0:0:0:
+120,152,176916,1,0,0:0:0:0:
+120,152,176998,2,0,L|124:200,1,45
+212,176,177163,2,0,L|239:215,1,45,0|0,1:0|0:0,0:0:0:0:
+292,124,177328,2,0,P|302:79|283:30,1,90,8|0,0:0|0:0,0:0:0:0:
+344,192,177658,6,0,P|372:156|376:104,1,90,0|0,1:0|0:0,0:0:0:0:
+212,88,177987,1,8,0:0:0:0:
+272,228,178152,1,0,0:0:0:0:
+272,228,178235,1,0,0:0:0:0:
+272,228,178317,1,0,0:0:0:0:
+292,124,178482,1,0,1:0:0:0:
+180,180,178647,1,8,0:0:0:0:
+200,284,178812,1,0,0:0:0:0:
+292,124,178976,5,0,1:0:0:0:
+288,92,179059,1,0,0:0:0:0:
+280,60,179141,2,0,P|248:24|208:14,1,90,0|8,0:0|0:0,0:0:0:0:
+22,65,179471,2,0,P|67:71|112:68,1,90,0|0,1:0|0:0,0:0:0:0:
+212,88,179801,1,0,1:0:0:0:
+22,65,179965,1,8,0:0:0:0:
+180,180,180130,5,0,0:0:0:0:
+180,180,180213,1,0,0:0:0:0:
+180,180,180295,2,0,P|184:224|172:272,1,90,0|0,1:0|0:0,0:0:0:0:
+76,216,180625,2,0,P|72:172|84:124,1,90,8|0,0:0|0:0,0:0:0:0:
+380,240,180954,2,0,P|384:284|372:332,1,90,0|0,0:0|1:0,0:0:0:0:
+276,276,181284,2,0,P|272:232|284:184,1,90,8|0,0:0|0:0,0:0:0:0:
+374,129,181614,5,0,1:0:0:0:
+300,352,181779,2,0,L|204:348,2,90,0|8|0,0:0|0:0|1:0,0:0:0:0:
+448,180,182273,1,2,0:0:0:0:
+448,180,182438,1,2,1:2:0:0:
+276,276,182603,1,10,0:0:0:0:
+276,276,182768,1,2,0:0:0:0:
+96,200,182932,6,0,L|88:108,1,90,0|0,1:0|0:0,0:0:0:0:
+96,200,183262,1,8,0:0:0:0:
+12,68,183427,2,0,P|72:24|164:68,1,180,0|0,0:0|1:0,0:0:0:0:
+140,272,183921,2,0,P|92:284|52:271,1,90,8|0,0:0|0:0,0:0:0:0:
+176,156,184251,5,0,1:0:0:0:
+208,152,184334,1,0,1:0:0:0:
+240,148,184416,1,0,1:0:0:0:
+308,64,184581,1,8,0:0:0:0:
+296,240,184746,1,0,1:0:0:0:
+312,268,184828,1,0,1:0:0:0:
+336,284,184910,1,0,1:0:0:0:
+368,292,184993,1,0,1:0:0:0:
+400,288,185075,1,0,1:0:0:0:
+464,184,185240,1,8,0:0:0:0:
+468,152,185323,1,0,0:0:0:0:
+472,120,185405,2,0,L|464:76,1,45,0|0,1:0|1:0,0:0:0:0:
+388,96,185570,6,0,P|360:132|316:148,1,90,4|0,1:2|0:0,0:0:0:0:
+224,46,185899,2,0,P|268:43|308:63,1,90,8|0,0:0|0:0,0:0:0:0:
+296,240,186229,1,0,0:0:0:0:
+308,64,186394,1,0,1:0:0:0:
+296,240,186559,2,0,L|312:332,1,90,8|0,0:0|0:0,0:0:0:0:
+464,184,186888,6,0,P|420:180|372:188,1,90,0|0,1:0|0:0,0:0:0:0:
+296,240,187218,1,8,0:0:0:0:
+136,292,187383,2,0,P|94:277|54:249,1,90,0|0,1:0|0:0,0:0:0:0:
+21,159,187713,1,0,1:0:0:0:
+104,8,187877,2,0,L|124:96,1,90,10|0,0:0|0:0,0:0:0:0:
+124,96,188207,6,0,P|152:132|196:148,1,90,0|0,1:0|0:0,0:0:0:0:
+287,46,188537,2,0,P|243:43|204:63,1,90,8|0,0:0|0:0,0:0:0:0:
+216,240,188866,1,2,0:0:0:0:
+204,64,189031,1,0,1:0:0:0:
+216,240,189196,2,0,L|200:332,1,90,8|0,0:0|0:0,0:0:0:0:
+40,240,189526,5,2,1:2:0:0:
+128,192,189691,1,0,0:0:0:0:
+216,240,189855,1,8,0:0:0:0:
+304,192,190020,1,0,1:0:0:0:
+392,240,190185,2,0,L|400:332,1,90,2|0,0:0|1:0,0:0:0:0:
+464,168,190515,2,0,L|456:76,1,90,8|0,0:0|0:0,0:0:0:0:
+392,240,190844,6,0,P|364:272|312:292,1,90,2|0,1:2|0:0,0:0:0:0:
+220,140,191174,2,0,P|248:108|296:92,1,90,8|0,0:0|0:0,0:0:0:0:
+324,96,191421,1,0,0:0:0:0:
+356,104,191504,2,0,L|340:16,1,90,0|0,0:0|1:0,0:0:0:0:
+256,276,191834,2,0,L|272:364,1,90,8|0,0:0|0:0,0:0:0:0:
+392,240,192163,5,0,1:0:0:0:
+356,104,192328,1,0,0:0:0:0:
+220,140,192493,1,8,0:0:0:0:
+256,276,192658,1,0,1:0:0:0:
+305,191,192823,1,0,0:0:0:0:
+212,56,192987,1,0,1:0:0:0:
+200,220,193152,1,10,0:0:0:0:
+200,220,193482,6,0,P|156:228|108:220,1,90,0|0,1:0|0:0,0:0:0:0:
+88,116,193812,1,8,0:0:0:0:
+16,192,193976,1,0,0:0:0:0:
+16,192,194059,1,0,0:0:0:0:
+16,192,194141,2,0,L|28:288,1,90,2|0,0:0|1:0,0:0:0:0:
+188,309,194471,2,0,L|200:220,1,90,8|0,0:0|0:0,0:0:0:0:
+216,112,194801,5,2,1:2:0:0:
+216,112,194883,1,0,1:0:0:0:
+216,112,194965,1,0,1:0:0:0:
+361,25,195130,1,8,0:0:0:0:
+294,180,195295,1,0,1:0:0:0:
+294,180,195377,1,0,1:0:0:0:
+294,180,195460,1,2,0:0:0:0:
+256,16,195625,1,0,1:0:0:0:
+384,127,195790,1,10,1:2:0:0:
+416,132,195872,1,0,1:0:0:0:
+448,140,195954,2,0,L|452:84,1,45,0|0,1:0|1:0,0:0:0:0:
+416,216,196119,6,0,P|412:264|432:312,1,90,4|0,1:2|0:0,0:0:0:0:
+304,268,196449,2,0,P|308:220|288:172,1,90,8|0,0:0|0:0,0:0:0:0:
+216,112,196779,2,0,L|120:104,1,90,0|0,0:0|1:0,0:0:0:0:
+52,248,197108,2,0,L|141:255,1,90,8|0,0:0|0:0,0:0:0:0:
+304,268,197438,5,0,1:0:0:0:
+416,216,197603,1,0,0:0:0:0:
+408,340,197768,1,8,0:0:0:0:
+332,180,197932,1,0,1:0:0:0:
+332,180,198015,1,0,0:0:0:0:
+332,180,198097,2,0,P|360:140|400:120,1,90,0|0,0:0|1:0,0:0:0:0:
+484,284,198427,1,10,0:0:0:0:
+304,268,198592,1,2,0:0:0:0:
+416,216,198757,6,0,P|428:172|420:124,1,90,2|0,1:2|0:0,0:0:0:0:
+344,52,199086,1,8,0:0:0:0:
+332,180,199251,1,0,0:0:0:0:
+164,236,199416,2,0,P|152:192|160:144,1,90,0|0,0:0|1:0,0:0:0:0:
+236,72,199746,1,8,0:0:0:0:
+248,200,199910,1,0,0:0:0:0:
+156,328,200075,6,0,L|56:320,1,90,2|0,1:2|0:0,0:0:0:0:
+164,236,200405,1,8,0:0:0:0:
+256,292,200570,2,0,P|300:296|344:284,1,90,0|0,1:0|0:0,0:0:0:0:
+432,220,200899,2,0,L|460:308,2,90,0|8|0,1:0|0:0|0:0,0:0:0:0:
+392,120,201394,5,4,1:2:0:0:
+396,32,201559,1,0,1:0:0:0:
+316,72,201724,1,0,1:0:0:0:
+256,6,201888,1,0,1:0:0:0:
+228,91,202053,1,0,1:0:0:0:
+139,87,202218,1,0,1:0:0:0:
+179,166,202383,1,0,1:0:0:0:
+113,226,202548,1,0,1:0:0:0:
+197,253,202713,5,4,1:2:0:0:
+193,342,202877,1,0,1:0:0:0:
+272,302,203042,1,0,1:0:0:0:
+332,367,203207,1,0,1:0:0:0:
+359,283,203372,1,2,1:2:0:0:
+448,287,203537,1,2,1:2:0:0:
+407,208,203702,1,2,1:2:0:0:
+472,147,203866,1,2,1:2:0:0:
+387,121,204031,5,4,1:2:0:0:
+360,100,204114,1,0,1:0:0:0:
+344,72,204196,1,0,1:0:0:0:
+336,40,204279,1,0,1:0:0:0:
+340,8,204361,1,0,1:0:0:0:
+316,28,204443,1,0,1:0:0:0:
+284,32,204526,1,0,1:0:0:0:
+252,28,204608,1,0,1:0:0:0:
+228,8,204691,2,0,L|184:20,7,45,4|0|0|0|0|0|0|0,1:2|1:0|1:0|1:0|1:0|1:0|1:0|1:0,0:0:0:0:
+112,56,205350,5,4,1:2:0:0:
+100,84,205432,1,0,1:0:0:0:
+96,116,205515,1,0,1:0:0:0:
+100,148,205597,1,0,1:0:0:0:
+112,176,205680,1,0,1:0:0:0:
+124,204,205762,1,0,1:0:0:0:
+128,236,205844,1,0,1:0:0:0:
+124,268,205927,1,0,1:0:0:0:
+112,296,206009,2,0,L|71:313,3,45,2|0|2|0,1:2|0:0|0:0|0:0,0:0:0:0:
+192,312,206339,2,0,L|175:353,3,45,2|0|2|0,1:2|0:0|0:0|0:0,0:0:0:0:
+256,264,206669,5,4,1:2:0:0:
+256,192,206751,12,0,209306,0:0:0:0:
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
new file mode 100644
index 0000000000..531e89230b
--- /dev/null
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -0,0 +1,69 @@
+
+
+
+ Debug
+ AnyCPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}
+ Library
+ osu.Game.Tests
+ osu.Game.Tests
+ v4.5
+
+
+ true
+ full
+ false
+ bin\Debug
+ DEBUG;
+ prompt
+ 4
+ false
+
+
+ true
+ bin\Release
+ prompt
+ 4
+ false
+
+
+
+
+ $(SolutionDir)\packages\NUnit.2.6.4\lib\nunit.framework.dll
+
+
+ $(SolutionDir)\packages\ppy.OpenTK.1.1.2225.3\lib\net20\OpenTK.dll
+
+
+
+
+
+
+
+
+
+
+ {0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}
+ osu.Game
+
+
+ {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}
+ osu.Game.Resources
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/osu.Game.Tests/packages.config b/osu.Game.Tests/packages.config
new file mode 100644
index 0000000000..46387efcc6
--- /dev/null
+++ b/osu.Game.Tests/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/BaseDifficulty.cs b/osu.Game/Beatmaps/BaseDifficulty.cs
new file mode 100644
index 0000000000..62acf07695
--- /dev/null
+++ b/osu.Game/Beatmaps/BaseDifficulty.cs
@@ -0,0 +1,18 @@
+using System;
+using SQLite;
+
+namespace osu.Game.Beatmaps
+{
+ public class BaseDifficulty
+ {
+ [PrimaryKey, AutoIncrement]
+ public int ID { get; set; }
+ public float DrainRate { get; set; }
+ public float CircleSize { get; set; }
+ public float OverallDifficulty { get; set; }
+ public float ApproachRate { get; set; }
+ public float SliderMultiplier { get; set; }
+ public float SliderTickRate { get; set; }
+ }
+}
+
diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs
index 2a6c976a5e..99199e421c 100644
--- a/osu.Game/Beatmaps/Beatmap.cs
+++ b/osu.Game/Beatmaps/Beatmap.cs
@@ -2,19 +2,68 @@
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
+using System.Linq;
+using OpenTK.Graphics;
using osu.Game.Beatmaps.Objects;
+using osu.Game.Beatmaps.Samples;
using osu.Game.Beatmaps.Timing;
+using osu.Game.GameModes.Play;
using osu.Game.Users;
+using SQLite;
namespace osu.Game.Beatmaps
{
public class Beatmap
{
- public List HitObjects;
-
- public List ControlPoints;
-
- public string Difficulty;
- public User Creator;
+ [PrimaryKey]
+ public int BeatmapID { get; set; }
+ [NotNull, Indexed]
+ public int BeatmapSetID { get; set; }
+ [Indexed]
+ public int BeatmapMetadataID { get; set; }
+ public int BaseDifficultyID { get; set; }
+ [Ignore]
+ public List HitObjects { get; set; }
+ [Ignore]
+ public List ControlPoints { get; set; }
+ [Ignore]
+ public BeatmapMetadata Metadata { get; set; }
+ [Ignore]
+ public BaseDifficulty BaseDifficulty { get; set; }
+ [Ignore]
+ public List ComboColors { get; set; }
+
+ // General
+ public int AudioLeadIn { get; set; }
+ public bool Countdown { get; set; }
+ public SampleSet SampleSet { get; set; }
+ public float StackLeniency { get; set; }
+ public bool SpecialStyle { get; set; }
+ public PlayMode Mode { get; set; }
+ public bool LetterboxInBreaks { get; set; }
+ public bool WidescreenStoryboard { get; set; }
+
+ // Editor
+ // This bookmarks stuff is necessary because DB doesn't know how to store int[]
+ public string StoredBookmarks { get; internal set; }
+ [Ignore]
+ public int[] Bookmarks
+ {
+ get
+ {
+ return StoredBookmarks.Split(',').Select(b => int.Parse(b)).ToArray();
+ }
+ set
+ {
+ StoredBookmarks = string.Join(",", value);
+ }
+ }
+ public double DistanceSpacing { get; set; }
+ public int BeatDivisor { get; set; }
+ public int GridSize { get; set; }
+ public double TimelineZoom { get; set; }
+
+ // Metadata
+ public string Version { get; set; }
}
}
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs
new file mode 100644
index 0000000000..1499dde323
--- /dev/null
+++ b/osu.Game/Beatmaps/BeatmapMetadata.cs
@@ -0,0 +1,26 @@
+//Copyright (c) 2007-2016 ppy Pty Ltd .
+//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.GameModes.Play;
+using SQLite;
+
+namespace osu.Game.Beatmaps
+{
+ public class BeatmapMetadata
+ {
+ [PrimaryKey]
+ public int ID { get; set; }
+
+ public int BeatmapSetID { get; set; }
+ public string Title { get; set; }
+ public string TitleUnicode { get; set; }
+ public string Artist { get; set; }
+ public string ArtistUnicode { get; set; }
+ public string Author { get; set; }
+ public string Source { get; set; }
+ public string Tags { get; set; }
+ public int PreviewTime { get; set; }
+ public string AudioFile { get; set; }
+ public string BackgroundFile { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/BeatmapSet.cs b/osu.Game/Beatmaps/BeatmapSet.cs
index 0a9e3335ab..5f1be7f9b0 100644
--- a/osu.Game/Beatmaps/BeatmapSet.cs
+++ b/osu.Game/Beatmaps/BeatmapSet.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using osu.Game.Users;
+using SQLite;
namespace osu.Game.Beatmaps
{
@@ -11,10 +12,15 @@ namespace osu.Game.Beatmaps
///
public class BeatmapSet
{
+ [PrimaryKey]
+ public int BeatmapSetID { get; set; }
+ [NotNull, Indexed]
+ public int BeatmapMetadataID { get; set; }
+ [Ignore]
public List Beatmaps { get; protected set; }
-
- public Metadata Metadata;
-
- public User Creator;
+ [Ignore]
+ public BeatmapMetadata Metadata { get; set; }
+ [Ignore]
+ public User Creator { get; set; }
}
}
diff --git a/osu.Game/Beatmaps/Events/EventType.cs b/osu.Game/Beatmaps/Events/EventType.cs
new file mode 100644
index 0000000000..cb66a42f2d
--- /dev/null
+++ b/osu.Game/Beatmaps/Events/EventType.cs
@@ -0,0 +1,14 @@
+using System;
+namespace osu.Game.Beatmaps.Events
+{
+ public enum EventType
+ {
+ Background = 0,
+ Video = 1,
+ Break = 2,
+ Colour = 3,
+ Sprite = 4,
+ Sample = 5,
+ Animation = 6
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs
new file mode 100644
index 0000000000..7302e2a4c5
--- /dev/null
+++ b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace osu.Game.Beatmaps.Formats
+{
+ public abstract class BeatmapDecoder
+ {
+ private static Dictionary decoders { get; } = new Dictionary();
+
+ public static BeatmapDecoder GetDecoder(TextReader stream)
+ {
+ var line = stream.ReadLine().Trim();
+ if (!decoders.ContainsKey(line))
+ throw new IOException(@"Unknown file format");
+ return (BeatmapDecoder)Activator.CreateInstance(decoders[line]);
+ }
+
protected static void AddDecoder(string magic) where T : BeatmapDecoder
+ {
+ decoders[magic] = typeof(T);
+ }
+
+ public abstract Beatmap Decode(TextReader stream);
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs
new file mode 100644
index 0000000000..89451c1233
--- /dev/null
+++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs
@@ -0,0 +1,272 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using OpenTK.Graphics;
+using osu.Game.Beatmaps.Events;
+using osu.Game.Beatmaps.Objects;
+using osu.Game.Beatmaps.Samples;
+using osu.Game.Beatmaps.Timing;
+using osu.Game.GameModes.Play;
+
+namespace osu.Game.Beatmaps.Formats
+{
+ public class OsuLegacyDecoder : BeatmapDecoder
+ {
+ public static void Register()
+ {
+ AddDecoder(@"osu file format v14");
+ AddDecoder(@"osu file format v13");
+ AddDecoder(@"osu file format v12");
+ AddDecoder(@"osu file format v11");
+ AddDecoder(@"osu file format v10");
+ // TODO: Not sure how far back to go, or differences between versions
+ }
+
+ private enum Section
+ {
+ None,
+ General,
+ Editor,
+ Metadata,
+ Difficulty,
+ Events,
+ TimingPoints,
+ Colours,
+ HitObjects,
+ }
+
+ private void handleGeneral(Beatmap beatmap, string key, string val)
+ {
+ switch (key)
+ {
+ case @"AudioFilename":
+ beatmap.Metadata.AudioFile = val;
+ break;
+ case @"AudioLeadIn":
+ beatmap.AudioLeadIn = int.Parse(val);
+ break;
+ case @"PreviewTime":
+ beatmap.Metadata.PreviewTime = int.Parse(val);
+ break;
+ case @"Countdown":
+ beatmap.Countdown = int.Parse(val) == 1;
+ break;
+ case @"SampleSet":
+ beatmap.SampleSet = (SampleSet)Enum.Parse(typeof(SampleSet), val);
+ break;
+ case @"StackLeniency":
+ beatmap.StackLeniency = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ break;
+ case @"Mode":
+ beatmap.Mode = (PlayMode)int.Parse(val);
+ break;
+ case @"LetterboxInBreaks":
+ beatmap.LetterboxInBreaks = int.Parse(val) == 1;
+ break;
+ case @"SpecialStyle":
+ beatmap.SpecialStyle = int.Parse(val) == 1;
+ break;
+ case @"WidescreenStoryboard":
+ beatmap.WidescreenStoryboard = int.Parse(val) == 1;
+ break;
+ }
+ }
+
+ private void handleEditor(Beatmap beatmap, string key, string val)
+ {
+ switch (key)
+ {
+ case @"Bookmarks":
+ beatmap.StoredBookmarks = val;
+ break;
+ case @"DistanceSpacing":
+ beatmap.DistanceSpacing = double.Parse(val, NumberFormatInfo.InvariantInfo);
+ break;
+ case @"BeatDivisor":
+ beatmap.BeatDivisor = int.Parse(val);
+ break;
+ case @"GridSize":
+ beatmap.GridSize = int.Parse(val);
+ break;
+ case @"TimelineZoom":
+ beatmap.TimelineZoom = double.Parse(val, NumberFormatInfo.InvariantInfo);
+ break;
+ }
+ }
+
+ private void handleMetadata(Beatmap beatmap, string key, string val)
+ {
+ switch (key)
+ {
+ case @"Title":
+ beatmap.Metadata.Title = val;
+ break;
+ case @"TitleUnicode":
+ beatmap.Metadata.TitleUnicode = val;
+ break;
+ case @"Artist":
+ beatmap.Metadata.Artist = val;
+ break;
+ case @"ArtistUnicode":
+ beatmap.Metadata.ArtistUnicode = val;
+ break;
+ case @"Creator":
+ beatmap.Metadata.Author = val;
+ break;
+ case @"Version":
+ beatmap.Version = val;
+ break;
+ case @"Source":
+ beatmap.Metadata.Source = val;
+ break;
+ case @"Tags":
+ beatmap.Metadata.Tags = val;
+ break;
+ case @"BeatmapID":
+ beatmap.BeatmapID = int.Parse(val);
+ break;
+ case @"BeatmapSetID":
+ beatmap.BeatmapSetID = int.Parse(val);
+ beatmap.Metadata.BeatmapSetID = int.Parse(val);
+ break;
+ }
+ }
+
+ private void handleDifficulty(Beatmap beatmap, string key, string val)
+ {
+ switch (key)
+ {
+ case @"HPDrainRate":
+ beatmap.BaseDifficulty.DrainRate = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ break;
+ case @"CircleSize":
+ beatmap.BaseDifficulty.CircleSize = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ break;
+ case @"OverallDifficulty":
+ beatmap.BaseDifficulty.OverallDifficulty = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ break;
+ case @"ApproachRate":
+ beatmap.BaseDifficulty.ApproachRate = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ break;
+ case @"SliderMultiplier":
+ beatmap.BaseDifficulty.SliderMultiplier = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ break;
+ case @"SliderTickRate":
+ beatmap.BaseDifficulty.SliderTickRate = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ break;
+ }
+ }
+
+ private void handleEvents(Beatmap beatmap, string val)
+ {
+ if (val.StartsWith(@"//"))
+ return;
+ if (val.StartsWith(@" "))
+ return; // TODO
+ string[] split = val.Split(',');
+ EventType type;
+ int _type;
+ if (!int.TryParse(split[0], out _type))
+ {
+ if (!Enum.TryParse(split[0], out type))
+ throw new InvalidDataException($@"Unknown event type {split[0]}");
+ }
+ else
+ type = (EventType)_type;
+ // TODO: Parse and store the rest of the event
+ if (type == EventType.Background)
+ beatmap.Metadata.BackgroundFile = split[2].Trim('"');
+ }
+
+ private void handleTimingPoints(Beatmap beatmap, string val)
+ {
+ // TODO
+ }
+
+ private void handleColours(Beatmap beatmap, string key, string val)
+ {
+ string[] split = val.Split(',');
+ if (split.Length != 3)
+ throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B): {val}");
+ byte r, g, b;
+ if (!byte.TryParse(split[0], out r) || !byte.TryParse(split[1], out g) || !byte.TryParse(split[2], out b))
+ throw new InvalidOperationException($@"Color must be specified with 8-bit integer components");
+ // Note: the combo index specified in the beatmap is discarded
+ beatmap.ComboColors.Add(new Color4
+ {
+ R = r / 255f,
+ G = g / 255f,
+ B = b / 255f,
+ A = 1f,
+ });
+ }
+
+ public override Beatmap Decode(TextReader stream)
+ {
+ var beatmap = new Beatmap
+ {
+ Metadata = new BeatmapMetadata(),
+ BaseDifficulty = new BaseDifficulty(),
+ HitObjects = new List(),
+ ControlPoints = new List(),
+ ComboColors = new List(),
+ };
+ var section = Section.None;
+ string line;
+ while (true)
+ {
+ line = stream.ReadLine();
+ if (line == null)
+ break;
+ line = line.Trim();
+ if (string.IsNullOrEmpty(line))
+ continue;
+ if (line.StartsWith(@"osu file format v"))
+ continue;
+
+ if (line.StartsWith(@"[") && line.EndsWith(@"]"))
+ {
+ if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section))
+ throw new InvalidDataException($@"Unknown osu section {line}");
+ continue;
+ }
+
+ string val = line, key = null;
+ if (section != Section.Events && section != Section.TimingPoints && section != Section.HitObjects)
+ {
+ key = val.Remove(val.IndexOf(':')).Trim();
+ val = val.Substring(val.IndexOf(':') + 1).Trim();
+ }
+ switch (section)
+ {
+ case Section.General:
+ handleGeneral(beatmap, key, val);
+ break;
+ case Section.Editor:
+ handleEditor(beatmap, key, val);
+ break;
+ case Section.Metadata:
+ handleMetadata(beatmap, key, val);
+ break;
+ case Section.Difficulty:
+ handleDifficulty(beatmap, key, val);
+ break;
+ case Section.Events:
+ handleEvents(beatmap, val);
+ break;
+ case Section.TimingPoints:
+ handleTimingPoints(beatmap, val);
+ break;
+ case Section.Colours:
+ handleColours(beatmap, key, val);
+ break;
+ case Section.HitObjects:
+ beatmap.HitObjects.Add(HitObject.Parse(beatmap.Mode, val));
+ break;
+ }
+ }
+ return beatmap;
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/IO/ArchiveReader.cs b/osu.Game/Beatmaps/IO/ArchiveReader.cs
new file mode 100644
index 0000000000..77315d4a21
--- /dev/null
+++ b/osu.Game/Beatmaps/IO/ArchiveReader.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using osu.Framework.Platform;
+
+namespace osu.Game.Beatmaps.IO
+{
+ public abstract class ArchiveReader : IDisposable
+ {
+ private class Reader
+ {
+ public Func Test { get; set; }
+ public Type Type { get; set; }
+ }
+
+ private static List readers { get; } = new List();
+
+ public static ArchiveReader GetReader(BasicStorage storage, string path)
+ {
+ foreach (var reader in readers)
+ {
+ if (reader.Test(storage, path))
+ return (ArchiveReader)Activator.CreateInstance(reader.Type, storage.GetStream(path));
+ }
+ throw new IOException(@"Unknown file format");
+ }
+
+ protected static void AddReader(Func test) where T : ArchiveReader
+ {
+ readers.Add(new Reader { Test = test, Type = typeof(T) });
+ }
+
+ ///
+ /// Reads the beatmap metadata from this archive.
+ ///
+ public abstract BeatmapMetadata ReadMetadata();
+ ///
+ /// Gets a list of beatmap file names.
+ ///
+ public abstract string[] ReadBeatmaps();
+ ///
+ /// Opens a stream for reading a specific file from this archive.
+ ///
+ public abstract Stream ReadFile(string name);
+
+ public abstract void Dispose();
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/IO/OszArchiveReader.cs b/osu.Game/Beatmaps/IO/OszArchiveReader.cs
new file mode 100644
index 0000000000..b70bee076c
--- /dev/null
+++ b/osu.Game/Beatmaps/IO/OszArchiveReader.cs
@@ -0,0 +1,61 @@
+using System;
+using System.IO;
+using System.Linq;
+using Ionic.Zip;
+using osu.Game.Beatmaps.Formats;
+
+namespace osu.Game.Beatmaps.IO
+{
+ public sealed class OszArchiveReader : ArchiveReader
+ {
+ public static void Register()
+ {
+ AddReader((storage, path) =>
+ {
+ using (var stream = storage.GetStream(path))
+ return ZipFile.IsZipFile(stream, false);
+ });
+ OsuLegacyDecoder.Register();
+ }
+
+ private ZipFile archive { get; set; }
+ private string[] beatmaps { get; set; }
+ private Beatmap firstMap { get; set; }
+
+ public OszArchiveReader(Stream archiveStream)
+ {
+ archive = ZipFile.Read(archiveStream);
+ beatmaps = archive.Entries.Where(e => e.FileName.EndsWith(@".osu"))
+ .Select(e => e.FileName).ToArray();
+ if (beatmaps.Length == 0)
+ throw new FileNotFoundException(@"This directory contains no beatmaps");
+ using (var stream = new StreamReader(ReadFile(beatmaps[0])))
+ {
+ var decoder = BeatmapDecoder.GetDecoder(stream);
+ firstMap = decoder.Decode(stream);
+ }
+ }
+
+ public override string[] ReadBeatmaps()
+ {
+ return beatmaps;
+ }
+
+ public override Stream ReadFile(string name)
+ {
+ ZipEntry entry = archive.Entries.SingleOrDefault(e => e.FileName == name);
+ if (entry == null)
+ throw new FileNotFoundException();
+ return entry.OpenReader();
+ }
+
+ public override BeatmapMetadata ReadMetadata()
+ {
+ return firstMap.Metadata;
+ }
+
public override void Dispose()
+ {
+ archive.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/Metadata.cs b/osu.Game/Beatmaps/Metadata.cs
deleted file mode 100644
index 1fa8e2438c..0000000000
--- a/osu.Game/Beatmaps/Metadata.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-//Copyright (c) 2007-2016 ppy Pty Ltd .
-//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-namespace osu.Game.Beatmaps
-{
- public class Metadata
- {
- public string Artist;
- public string Title;
- }
-}
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/Objects/HitObject.cs b/osu.Game/Beatmaps/Objects/HitObject.cs
index 74636d0a6f..16f0bb8a43 100644
--- a/osu.Game/Beatmaps/Objects/HitObject.cs
+++ b/osu.Game/Beatmaps/Objects/HitObject.cs
@@ -1,7 +1,9 @@
//Copyright (c) 2007-2016 ppy Pty Ltd .
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using osu.Game.Beatmaps.Objects.Osu;
using osu.Game.Beatmaps.Samples;
+using osu.Game.GameModes.Play;
namespace osu.Game.Beatmaps.Objects
{
@@ -16,5 +18,17 @@ namespace osu.Game.Beatmaps.Objects
public double Duration => (EndTime ?? StartTime) - StartTime;
public HitSampleInfo Sample;
+
+ public static HitObject Parse(PlayMode mode, string val)
+ {
+ //TODO: move to modular HitObjectParser system rather than static parsing. (https://github.com/ppy/osu/pull/60/files#r83135780)
+ switch (mode)
+ {
+ case PlayMode.Osu:
+ return OsuBaseHit.Parse(val);
+ default:
+ return null;
+ }
+ }
}
}
diff --git a/osu.Game/Beatmaps/Objects/Osu/OsuBaseHit.cs b/osu.Game/Beatmaps/Objects/Osu/OsuBaseHit.cs
index 8224bb7dc9..2f94c70a0e 100644
--- a/osu.Game/Beatmaps/Objects/Osu/OsuBaseHit.cs
+++ b/osu.Game/Beatmaps/Objects/Osu/OsuBaseHit.cs
@@ -1,12 +1,59 @@
//Copyright (c) 2007-2016 ppy Pty Ltd .
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System;
using OpenTK;
+using osu.Game.Beatmaps.Samples;
namespace osu.Game.Beatmaps.Objects.Osu
{
public abstract class OsuBaseHit : HitObject
{
- public Vector2 Position;
+ public Vector2 Position { get; set; }
+ public bool NewCombo { get; set; }
+
+ [Flags]
+ private enum HitObjectType
+ {
+ Circle = 1,
+ Slider = 2,
+ NewCombo = 4,
+ CircleNewCombo = 5,
+ SliderNewCombo = 6,
+ Spinner = 8,
+ ColourHax = 122,
+ Hold = 128,
+ ManiaLong = 128,
+ }
+
+ public static OsuBaseHit Parse(string val)
+ {
+ string[] split = val.Split(',');
+ var type = (HitObjectType)int.Parse(split[3]);
+ bool combo = type.HasFlag(HitObjectType.NewCombo);
+ type &= (HitObjectType)0xF;
+ type &= ~HitObjectType.NewCombo;
+ OsuBaseHit result;
+ switch (type)
+ {
+ case HitObjectType.Circle:
+ result = new Circle();
+ break;
+ case HitObjectType.Slider:
+ result = new Slider();
+ break;
+ case HitObjectType.Spinner:
+ result = new Spinner();
+ break;
+ default:
+ throw new InvalidOperationException($@"Unknown hit object type {type}");
+ }
+ result.Position = new Vector2(int.Parse(split[0]), int.Parse(split[1]));
+ result.StartTime = double.Parse(split[2]);
+ result.Sample = new HitSampleInfo { Type = (SampleType)int.Parse(split[4]) };
+ result.NewCombo = combo;
+ // TODO: "addition" field
+ return result;
+ }
}
}
diff --git a/osu.Game/Beatmaps/Objects/Osu/Spinner.cs b/osu.Game/Beatmaps/Objects/Osu/Spinner.cs
index 8426e0b529..e19af7c5ba 100644
--- a/osu.Game/Beatmaps/Objects/Osu/Spinner.cs
+++ b/osu.Game/Beatmaps/Objects/Osu/Spinner.cs
@@ -3,7 +3,7 @@
namespace osu.Game.Beatmaps.Objects.Osu
{
- public class Spinner
+ public class Spinner : OsuBaseHit
{
}
}
diff --git a/osu.Game/Beatmaps/Samples/HitSampleInfo.cs b/osu.Game/Beatmaps/Samples/HitSampleInfo.cs
index 4083a528aa..2598669336 100644
--- a/osu.Game/Beatmaps/Samples/HitSampleInfo.cs
+++ b/osu.Game/Beatmaps/Samples/HitSampleInfo.cs
@@ -5,6 +5,6 @@ namespace osu.Game.Beatmaps.Samples
{
public class HitSampleInfo : SampleInfo
{
- SampleType Type;
+ public SampleType Type { get; set; }
}
}
diff --git a/osu.Game/Database/BeatmapDatabase.cs b/osu.Game/Database/BeatmapDatabase.cs
new file mode 100644
index 0000000000..36f8776eb0
--- /dev/null
+++ b/osu.Game/Database/BeatmapDatabase.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using osu.Framework.Platform;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Formats;
+using osu.Game.Beatmaps.IO;
+using SQLite;
+
+namespace osu.Game.Database
+{
+ public class BeatmapDatabase
+ {
+ private static SQLiteConnection connection { get; set; }
+
+ public BeatmapDatabase(BasicStorage storage)
+ {
+ if (connection == null)
+ {
+ connection = storage.GetDatabase(@"beatmaps");
+ connection.CreateTable();
+ connection.CreateTable();
+ connection.CreateTable();
+ connection.CreateTable();
+ }
+ }
+
public void AddBeatmap(ArchiveReader input)
+ {
+ var metadata = input.ReadMetadata();
+ if (connection.Table().Count(b => b.BeatmapSetID == metadata.BeatmapSetID) != 0)
+ return;
+ string[] mapNames = input.ReadBeatmaps();
+ var beatmapSet = new BeatmapSet { BeatmapSetID = metadata.BeatmapSetID };
+ var maps = new List();
+ foreach (var name in mapNames)
+ {
+ using (var stream = new StreamReader(input.ReadFile(name)))
+ {
+ var decoder = BeatmapDecoder.GetDecoder(stream);
+ var beatmap = decoder.Decode(stream);
+ maps.Add(beatmap);
+ beatmap.BaseDifficultyID = connection.Insert(beatmap.BaseDifficulty);
+ }
+ }
+ beatmapSet.BeatmapMetadataID = connection.Insert(metadata);
+ connection.Insert(beatmapSet);
+ connection.InsertAll(maps);
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index fa4d5f3a9c..9eb32117c5 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -20,17 +20,31 @@ using osu.Framework;
using osu.Framework.Input;
using osu.Game.Input;
using OpenTK.Input;
+using System.IO;
+using osu.Game.Beatmaps.IO;
namespace osu.Game
{
public class OsuGame : OsuGameBase
{
+ private class ImportBeatmap
+ {
+ public string Path;
+ }
+
public Toolbar Toolbar;
public ChatConsole Chat;
public MainMenu MainMenu => intro?.ChildGameMode as MainMenu;
private Intro intro;
+ private string[] args;
+ private IpcChannel BeatmapIPC;
public Bindable PlayMode;
+
+ public OsuGame(string[] args)
+ {
+ this.args = args;
+ }
public override void SetHost(BasicGameHost host)
{
@@ -41,6 +55,35 @@ namespace osu.Game
public override void Load(BaseGame game)
{
+ BeatmapIPC = new IpcChannel(Host);
+
+ if (!Host.IsPrimaryInstance)
+ {
+ if (args.Length == 1 && File.Exists(args[0]))
+ {
+ BeatmapIPC.SendMessage(new ImportBeatmap { Path = args[0] }).Wait();
+ Console.WriteLine(@"Sent file to running instance");
+ }
+ else
+ Console.WriteLine(@"osu! does not support multiple running instances.");
+ Environment.Exit(0);
+ }
+
+ BeatmapIPC.MessageReceived += message =>
+ {
+ try
+ {
+ var reader = ArchiveReader.GetReader(Host.Storage, message.Path);
+ Beatmaps.AddBeatmap(reader);
+ // TODO: Switch to beatmap list and select the new song
+ }
+ catch (Exception ex)
+ {
+ // TODO: Show the user some info?
+ Console.WriteLine($@"Failed to import beatmap: {ex}");
+ }
+ };
+
base.Load(game);
//attach our bindables to the audio subsystem.
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index 229b306d14..ea2fecf7c2 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -5,7 +5,9 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
+using osu.Game.Beatmaps.IO;
using osu.Game.Configuration;
+using osu.Game.Database;
using osu.Game.Graphics.Cursor;
using osu.Game.Graphics.Processing;
using osu.Game.Online.API;
@@ -16,6 +18,7 @@ namespace osu.Game
public class OsuGameBase : BaseGame
{
internal OsuConfigManager Config = new OsuConfigManager();
+ internal BeatmapDatabase Beatmaps { get; private set; }
protected override string MainResourceFile => @"osu.Game.Resources.dll";
@@ -32,6 +35,9 @@ namespace osu.Game
{
base.Load(game);
+ OszArchiveReader.Register();
+ Beatmaps = new BeatmapDatabase(Host.Storage);
+
//this completely overrides the framework default. will need to change once we make a proper FontStore.
Fonts = new TextureStore() { ScaleAdjust = 0.01f };
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-Regular"));
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index bdb852c33f..0839891dd8 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -34,20 +34,35 @@
- ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
+ $(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
True
- ..\packages\ppy.OpenTK.1.1.2225.3\lib\net20\OpenTK.dll
+ $(SolutionDir)\packages\ppy.OpenTK.1.1.2225.3\lib\net20\OpenTK.dll
True
+
+ $(SolutionDir)\packages\SQLitePCLRaw.core.1.0.1\lib\net45\SQLitePCLRaw.core.dll
+
+
+ $(SolutionDir)\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.0.1\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll
+
+
+ $(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.0.1\lib\net45\SQLitePCLRaw.batteries_green.dll
+
+
+ $(SolutionDir)\packages\sqlite-net-pcl.1.2.0\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll
+
+
+ $(SolutionDir)\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll
+
-
+
@@ -148,13 +163,20 @@
+
+
+
+
+
+
+
-
+
{c76bf5b3-985e-4d39-95fe-97c9c879b83a}
osu.Framework
-
+
{d9a367c9-4c1a-489f-9b05-a0cea2b53b58}
osu.Game.Resources
@@ -166,6 +188,12 @@
+
+
+
+
+
+
-
\ No newline at end of file
+
+
+
+
diff --git a/osu.Game/packages.config b/osu.Game/packages.config
index 8c9d8076cf..1f14b0038d 100644
--- a/osu.Game/packages.config
+++ b/osu.Game/packages.config
@@ -1,9 +1,17 @@
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/osu.sln b/osu.sln
index 1454c14c82..8fba171a2f 100644
--- a/osu.sln
+++ b/osu.sln
@@ -19,11 +19,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Framework.Desktop", "os
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Desktop.VisualTests", "osu.Desktop.VisualTests\osu.Desktop.VisualTests.csproj", "{69051C69-12AE-4E7D-A3E6-460D2E282312}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Tests", "osu.Game.Tests\osu.Game.Tests.csproj", "{54377672-20B1-40AF-8087-5CF73BF3953A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Deploy|Any CPU = Deploy|Any CPU
Release|Any CPU = Release|Any CPU
+ Deploy|Any CPU = Deploy|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@@ -56,6 +59,12 @@ Global
{69051C69-12AE-4E7D-A3E6-460D2E282312}.Deploy|Any CPU.ActiveCfg = Debug|Any CPU
{69051C69-12AE-4E7D-A3E6-460D2E282312}.Release|Any CPU.ActiveCfg = Release|Any CPU
{69051C69-12AE-4E7D-A3E6-460D2E282312}.Release|Any CPU.Build.0 = Release|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Deploy|Any CPU.ActiveCfg = Release|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Deploy|Any CPU.Build.0 = Release|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {54377672-20B1-40AF-8087-5CF73BF3953A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -67,6 +76,7 @@ Global
{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58} = {0D37A2AD-80A4-464F-A1DE-1560B70F1CE3}
{65DC628F-A640-4111-AB35-3A5652BC1E17} = {7A75DFA2-DE65-4458-98AF-26AF96FFD6DC}
{69051C69-12AE-4E7D-A3E6-460D2E282312} = {0D37A2AD-80A4-464F-A1DE-1560B70F1CE3}
+ {54377672-20B1-40AF-8087-5CF73BF3953A} = {0D37A2AD-80A4-464F-A1DE-1560B70F1CE3}
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0