diff --git a/osu-framework b/osu-framework index 7439250a63..30ff0e1a99 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 7439250a63dd451f34dbc08ecf68a196cf8e479f +Subproject commit 30ff0e1a99a10e735611bb3ffa35352061f52d8a 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.VisualTests/Tests/TestCaseGamefield.cs b/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs index 085100acf9..316a099e38 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs @@ -23,7 +23,7 @@ namespace osu.Desktop.Tests public override string Description => @"Showing hitobjects and what not."; - FramedOffsetClock localClock; + FramedClock localClock; protected override IFrameBasedClock Clock => localClock; @@ -32,9 +32,7 @@ namespace osu.Desktop.Tests base.Reset(); //ensure we are at offset 0 - if (localClock == null) - localClock = new FramedOffsetClock(base.Clock); - localClock.Offset = -base.Clock.CurrentTime; + localClock = new FramedClock(); List objects = new List(); diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj index 44a1aef6de..c54140b267 100644 --- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj +++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj @@ -140,7 +140,6 @@ - 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/Catch/CatchConverter.cs b/osu.Game/Beatmaps/Objects/Catch/CatchConverter.cs new file mode 100644 index 0000000000..dbd97e90bc --- /dev/null +++ b/osu.Game/Beatmaps/Objects/Catch/CatchConverter.cs @@ -0,0 +1,43 @@ +//Copyright (c) 2007-2016 ppy Pty Ltd . +//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using osu.Game.Beatmaps.Objects.Catch; +using osu.Game.Beatmaps.Objects.Osu; + +namespace osu.Game.Beatmaps.Objects.Catch +{ + class CatchConverter : HitObjectConverter + { + public override List Convert(List input) + { + List output = new List(); + + foreach (HitObject i in input) + { + CatchBaseHit h = i as CatchBaseHit; + + if (h == null) + { + OsuBaseHit o = i as OsuBaseHit; + + if (o == null) throw new Exception(@"Can't convert!"); + + h = new Fruit + { + StartTime = o.StartTime, + Position = o.Position.X, + }; + } + + output.Add(h); + } + + return output; + } + } +} diff --git a/osu.Game/Beatmaps/Objects/Catch/Drawable/DrawableFruit.cs b/osu.Game/Beatmaps/Objects/Catch/Drawable/DrawableFruit.cs new file mode 100644 index 0000000000..028afff5cc --- /dev/null +++ b/osu.Game/Beatmaps/Objects/Catch/Drawable/DrawableFruit.cs @@ -0,0 +1,42 @@ +//Copyright (c) 2007-2016 ppy Pty Ltd . +//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using osu.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transformations; +using OpenTK; + +namespace osu.Game.Beatmaps.Objects.Catch.Drawable +{ + class DrawableFruit : Sprite + { + private CatchBaseHit h; + + public DrawableFruit(CatchBaseHit h) + { + this.h = h; + + Origin = Anchor.Centre; + Scale = new Vector2(0.1f); + RelativePositionAxes = Axes.Y; + Position = new Vector2(h.Position, -0.1f); + } + + public override void Load(BaseGame game) + { + base.Load(game); + + Texture = game.Textures.Get(@"Menu/logo"); + + Transforms.Add(new TransformPosition(Clock) { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = new Vector2(h.Position, -0.1f), EndValue = new Vector2(h.Position, 0.9f) }); + Transforms.Add(new TransformAlpha(Clock) { StartTime = h.StartTime + h.Duration + 200, EndTime = h.StartTime + h.Duration + 400, StartValue = 1, EndValue = 0 }); + Expire(true); + } + } +} 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/HitObjectConverter.cs b/osu.Game/Beatmaps/Objects/HitObjectConverter.cs new file mode 100644 index 0000000000..a70526e85a --- /dev/null +++ b/osu.Game/Beatmaps/Objects/HitObjectConverter.cs @@ -0,0 +1,13 @@ +//Copyright (c) 2007-2016 ppy Pty Ltd . +//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; + +namespace osu.Game.Beatmaps.Objects +{ + public abstract class HitObjectConverter + where T : HitObject + { + public abstract List Convert(List input); + } +} diff --git a/osu.Game/Beatmaps/Objects/Mania/Drawable/DrawableNote.cs b/osu.Game/Beatmaps/Objects/Mania/Drawable/DrawableNote.cs new file mode 100644 index 0000000000..132fb6ce36 --- /dev/null +++ b/osu.Game/Beatmaps/Objects/Mania/Drawable/DrawableNote.cs @@ -0,0 +1,33 @@ +//Copyright (c) 2007-2016 ppy Pty Ltd . +//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transformations; +using OpenTK; + +namespace osu.Game.Beatmaps.Objects.Mania.Drawable +{ + public class DrawableNote : Sprite + { + private readonly ManiaBaseHit note; + + public DrawableNote(ManiaBaseHit note) + { + this.note = note; + Origin = Anchor.Centre; + Scale = new Vector2(0.1f); + } + + public override void Load(BaseGame game) + { + base.Load(game); + Texture = game.Textures.Get(@"Menu/logo"); + + Transforms.Add(new TransformPositionY(Clock) { StartTime = note.StartTime - 200, EndTime = note.StartTime, StartValue = -0.1f, EndValue = 0.9f }); + Transforms.Add(new TransformAlpha(Clock) { StartTime = note.StartTime + note.Duration + 200, EndTime = note.StartTime + note.Duration + 400, StartValue = 1, EndValue = 0 }); + Expire(true); + } + } +} diff --git a/osu.Game/Beatmaps/Objects/Mania/ManiaConverter.cs b/osu.Game/Beatmaps/Objects/Mania/ManiaConverter.cs new file mode 100644 index 0000000000..22d8f9ae9c --- /dev/null +++ b/osu.Game/Beatmaps/Objects/Mania/ManiaConverter.cs @@ -0,0 +1,46 @@ +//Copyright (c) 2007-2016 ppy Pty Ltd . +//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using osu.Game.Beatmaps.Objects.Osu; + +namespace osu.Game.Beatmaps.Objects.Mania +{ + class ManiaConverter : HitObjectConverter + { + private readonly int columns; + + public ManiaConverter(int columns) + { + this.columns = columns; + } + + public override List Convert(List input) + { + List output = new List(); + + foreach (HitObject i in input) + { + ManiaBaseHit h = i as ManiaBaseHit; + + if (h == null) + { + OsuBaseHit o = i as OsuBaseHit; + + if (o == null) throw new Exception(@"Can't convert!"); + + h = new Note + { + StartTime = o.StartTime, + Column = (int)Math.Round(o.Position.X / 512 * columns) + }; + } + + output.Add(h); + } + + return output; + } + } +} diff --git a/osu.Game/Beatmaps/Objects/Osu/Drawable/DrawableCircle.cs b/osu.Game/Beatmaps/Objects/Osu/Drawable/DrawableCircle.cs new file mode 100644 index 0000000000..f4297970e8 --- /dev/null +++ b/osu.Game/Beatmaps/Objects/Osu/Drawable/DrawableCircle.cs @@ -0,0 +1,42 @@ +//Copyright (c) 2007-2016 ppy Pty Ltd . +//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using osu.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transformations; +using OpenTK; + +namespace osu.Game.Beatmaps.Objects.Osu.Drawable +{ + class DrawableCircle : Sprite + { + private OsuBaseHit h; + + public DrawableCircle(OsuBaseHit h) + { + this.h = h; + + Origin = Anchor.Centre; + Scale = new Vector2(0.1f); + Alpha = 0; + Position = h.Position; + } + + public override void Load(BaseGame game) + { + base.Load(game); + + Texture = game.Textures.Get(@"Menu/logo"); + + Transforms.Add(new TransformAlpha(Clock) { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = 0, EndValue = 1 }); + Transforms.Add(new TransformAlpha(Clock) { StartTime = h.StartTime + h.Duration + 200, EndTime = h.StartTime + h.Duration + 400, StartValue = 1, EndValue = 0 }); + Expire(true); + } + } +} 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/OsuConverter.cs b/osu.Game/Beatmaps/Objects/Osu/OsuConverter.cs new file mode 100644 index 0000000000..5629fccd5c --- /dev/null +++ b/osu.Game/Beatmaps/Objects/Osu/OsuConverter.cs @@ -0,0 +1,21 @@ +//Copyright (c) 2007-2016 ppy Pty Ltd . +//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; + +namespace osu.Game.Beatmaps.Objects.Osu +{ + class OsuConverter : HitObjectConverter + { + public override List Convert(List input) + { + List output = new List(); + + foreach (HitObject h in input) + output.Add(h as OsuBaseHit); + + return output; + } + } +} 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/Objects/Taiko/Drawable/DrawableTaikoHit.cs b/osu.Game/Beatmaps/Objects/Taiko/Drawable/DrawableTaikoHit.cs new file mode 100644 index 0000000000..dafbe33415 --- /dev/null +++ b/osu.Game/Beatmaps/Objects/Taiko/Drawable/DrawableTaikoHit.cs @@ -0,0 +1,37 @@ +//Copyright (c) 2007-2016 ppy Pty Ltd . +//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transformations; +using OpenTK; + +namespace osu.Game.Beatmaps.Objects.Taiko.Drawable +{ + class DrawableTaikoHit : Sprite + { + private TaikoBaseHit h; + + public DrawableTaikoHit(TaikoBaseHit h) + { + this.h = h; + + Origin = Anchor.Centre; + Scale = new Vector2(0.2f); + RelativePositionAxes = Axes.Both; + Position = new Vector2(1.1f, 0.5f); + } + + public override void Load(BaseGame game) + { + base.Load(game); + + Texture = game.Textures.Get(@"Menu/logo"); + + Transforms.Add(new TransformPositionX(Clock) { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = 1.1f, EndValue = 0.1f }); + Transforms.Add(new TransformAlpha(Clock) { StartTime = h.StartTime + h.Duration + 200, EndTime = h.StartTime + h.Duration + 400, StartValue = 1, EndValue = 0 }); + Expire(true); + } + } +} diff --git a/osu.Game/Beatmaps/Objects/Taiko/TaikoBaseHit.cs b/osu.Game/Beatmaps/Objects/Taiko/TaikoBaseHit.cs index ddd8375204..6b8f241306 100644 --- a/osu.Game/Beatmaps/Objects/Taiko/TaikoBaseHit.cs +++ b/osu.Game/Beatmaps/Objects/Taiko/TaikoBaseHit.cs @@ -3,7 +3,7 @@ namespace osu.Game.Beatmaps.Objects.Taiko { - class TaikoBaseHit : HitObject + public class TaikoBaseHit : HitObject { public float Scale = 1; diff --git a/osu.Game/Beatmaps/Objects/Taiko/TaikoConverter.cs b/osu.Game/Beatmaps/Objects/Taiko/TaikoConverter.cs new file mode 100644 index 0000000000..3189a0dec7 --- /dev/null +++ b/osu.Game/Beatmaps/Objects/Taiko/TaikoConverter.cs @@ -0,0 +1,38 @@ +//Copyright (c) 2007-2016 ppy Pty Ltd . +//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using osu.Game.Beatmaps.Objects.Osu; + +namespace osu.Game.Beatmaps.Objects.Taiko +{ + class TaikoConverter : HitObjectConverter + { + public override List Convert(List input) + { + List output = new List(); + + foreach (HitObject i in input) + { + TaikoBaseHit h = i as TaikoBaseHit; + + if (h == null) + { + OsuBaseHit o = i as OsuBaseHit; + + if (o == null) throw new Exception(@"Can't convert!"); + + h = new TaikoBaseHit + { + StartTime = o.StartTime, + }; + } + + output.Add(h); + } + + return output; + } + } +} 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/GameModes/Play/Catch/CatchHitRenderer.cs b/osu.Game/GameModes/Play/Catch/CatchHitRenderer.cs index d6543360fc..d8e5aaaa35 100644 --- a/osu.Game/GameModes/Play/Catch/CatchHitRenderer.cs +++ b/osu.Game/GameModes/Play/Catch/CatchHitRenderer.cs @@ -1,82 +1,20 @@ //Copyright (c) 2007-2016 ppy Pty Ltd . //Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using System.Collections.Generic; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics; -using osu.Framework.Graphics.Transformations; using osu.Game.Beatmaps.Objects; -using osu.Game.Beatmaps.Objects.Osu; using osu.Game.Beatmaps.Objects.Catch; -using OpenTK; -using osu.Framework; +using osu.Game.Beatmaps.Objects.Catch.Drawable; namespace osu.Game.GameModes.Play.Catch { - public class CatchHitRenderer : HitRenderer + public class CatchHitRenderer : HitRenderer { - List objects; - private CatchPlayfield playfield; + protected override Playfield CreatePlayfield() => new CatchPlayfield(); - public override List Objects - { - set - { - //osu! mode requires all objects to be of CatchBaseHit type. - objects = value.ConvertAll(convertForCatch); - } - } + protected override List Convert(List objects) => new CatchConverter().Convert(objects); - private CatchBaseHit convertForCatch(HitObject input) - { - CatchBaseHit h = input as CatchBaseHit; - - if (h == null) - { - OsuBaseHit o = input as OsuBaseHit; - - if (o == null) throw new Exception(@"Can't convert!"); - - h = new Fruit() - { - StartTime = o.StartTime, - Position = o.Position.X - }; - } - - return h; - } - - public override void Load(BaseGame game) - { - base.Load(game); - - if (playfield == null) - Add(playfield = new CatchPlayfield()); - else - playfield.Clear(); - - if (objects == null) return; - - foreach (CatchBaseHit h in objects) - { - //render stuff! - Sprite s = new Sprite - { - Texture = game.Textures.Get(@"Menu/logo"), - Origin = Anchor.Centre, - Scale = new Vector2(0.1f), - RelativePositionAxes = Axes.Y, - Position = new Vector2(h.Position, -0.1f) - }; - - s.Transforms.Add(new TransformPosition(Clock) { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = new Vector2(h.Position, -0.1f), EndValue = new Vector2(h.Position, 0.9f) }); - s.Transforms.Add(new TransformAlpha(Clock) { StartTime = h.StartTime + h.Duration + 200, EndTime = h.StartTime + h.Duration + 400, StartValue = 1, EndValue = 0 }); - s.Expire(true); - - playfield.Add(s); - } - } + protected override Drawable GetVisualRepresentation(CatchBaseHit h) => new DrawableFruit(h); } } diff --git a/osu.Game/GameModes/Play/HitRenderer.cs b/osu.Game/GameModes/Play/HitRenderer.cs index 06d98da836..b18d9ebb6d 100644 --- a/osu.Game/GameModes/Play/HitRenderer.cs +++ b/osu.Game/GameModes/Play/HitRenderer.cs @@ -3,35 +3,53 @@ using System.Collections.Generic; using osu.Framework.Graphics; -using osu.Framework.Graphics.Batches; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Drawables; using osu.Game.Beatmaps.Objects; -using OpenTK; -using OpenTK.Graphics; using osu.Framework; namespace osu.Game.GameModes.Play { - public abstract class HitRenderer : Container + public abstract class HitRenderer : Container { - public abstract List Objects { set; } + private List objects; - public HitRenderer() + public List Objects { - RelativeSizeAxes = Axes.Both; + set + { + objects = Convert(value); + if (IsLoaded) + loadObjects(); + } } + private Playfield playfield; + + protected abstract Playfield CreatePlayfield(); + + protected abstract List Convert(List objects); + public override void Load(BaseGame game) { base.Load(game); - Add(new Box() + RelativeSizeAxes = Axes.Both; + + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Alpha = 0.8f, - Colour = new Color4(5, 5, 5, 255), - }); + playfield = CreatePlayfield() + }; + + loadObjects(); } + + private void loadObjects() + { + if (objects == null) return; + foreach (T h in objects) + playfield.Add(GetVisualRepresentation(h)); + } + + protected abstract Drawable GetVisualRepresentation(T h); } } diff --git a/osu.Game/GameModes/Play/Mania/ManiaHitRenderer.cs b/osu.Game/GameModes/Play/Mania/ManiaHitRenderer.cs index 1e55e552d3..302f40878b 100644 --- a/osu.Game/GameModes/Play/Mania/ManiaHitRenderer.cs +++ b/osu.Game/GameModes/Play/Mania/ManiaHitRenderer.cs @@ -1,88 +1,39 @@ //Copyright (c) 2007-2016 ppy Pty Ltd . //Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; -using System.Collections.Generic; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics; -using osu.Framework.Graphics.Transformations; using osu.Game.Beatmaps.Objects; -using osu.Game.Beatmaps.Objects.Osu; using osu.Game.Beatmaps.Objects.Mania; using OpenTK; -using osu.Framework; +using osu.Game.Beatmaps.Objects.Mania.Drawable; +using System.Collections.Generic; namespace osu.Game.GameModes.Play.Mania { - public class ManiaHitRenderer : HitRenderer + public class ManiaHitRenderer : HitRenderer { private readonly int columns; - List objects; - private ManiaPlayfield playfield; public ManiaHitRenderer(int columns = 5) { this.columns = columns; } - public override List Objects + protected override List Convert(List objects) { - set - { - //osu! mode requires all objects to be of ManiaBaseHit type. - objects = value.ConvertAll(convertForMania); - } + ManiaConverter converter = new ManiaConverter(columns); + return converter.Convert(objects); } - private ManiaBaseHit convertForMania(HitObject input) + protected override Playfield CreatePlayfield() => new ManiaPlayfield(columns); + + protected override Drawable GetVisualRepresentation(ManiaBaseHit h) { - ManiaBaseHit h = input as ManiaBaseHit; - - if (h == null) + return new DrawableNote(h) { - OsuBaseHit o = input as OsuBaseHit; - - if (o == null) throw new Exception(@"Can't convert!"); - - h = new Note() - { - StartTime = o.StartTime, - Column = (int)Math.Round(o.Position.X / 512 * columns) - }; - } - - return h; - } - - public override void Load(BaseGame game) - { - base.Load(game); - - if (playfield == null) - Add(playfield = new ManiaPlayfield(columns)); - else - playfield.Clear(); - - if (objects == null) return; - - foreach (ManiaBaseHit h in objects) - { - //render stuff! - Sprite s = new Sprite - { - Texture = game.Textures.Get(@"Menu/logo"), - Origin = Anchor.Centre, - Scale = new Vector2(0.1f), - RelativePositionAxes = Axes.Both, - Position = new Vector2((float)(h.Column + 0.5) / columns, -0.1f) - }; - - s.Transforms.Add(new TransformPositionY(Clock) { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = -0.1f, EndValue = 0.9f }); - s.Transforms.Add(new TransformAlpha(Clock) { StartTime = h.StartTime + h.Duration + 200, EndTime = h.StartTime + h.Duration + 400, StartValue = 1, EndValue = 0 }); - s.Expire(true); - - playfield.Add(s); - } + Position = new Vector2((float)(h.Column + 0.5) / columns, -0.1f), + RelativePositionAxes = Axes.Both + }; } } } diff --git a/osu.Game/GameModes/Play/Osu/OsuHitRenderer.cs b/osu.Game/GameModes/Play/Osu/OsuHitRenderer.cs index c95eca8077..130d6d212f 100644 --- a/osu.Game/GameModes/Play/Osu/OsuHitRenderer.cs +++ b/osu.Game/GameModes/Play/Osu/OsuHitRenderer.cs @@ -2,62 +2,19 @@ //Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics; -using osu.Framework.Graphics.Transformations; using osu.Game.Beatmaps.Objects; using osu.Game.Beatmaps.Objects.Osu; -using OpenTK; -using System.Diagnostics; -using osu.Framework; +using osu.Game.Beatmaps.Objects.Osu.Drawable; namespace osu.Game.GameModes.Play.Osu { - public class OsuHitRenderer : HitRenderer + public class OsuHitRenderer : HitRenderer { - List objects; - private OsuPlayfield playfield; + protected override Playfield CreatePlayfield() => new OsuPlayfield(); - public override List Objects - { - set - { - Debug.Assert(objects == null); + protected override List Convert(List objects) => new OsuConverter().Convert(objects); - //osu! mode requires all objects to be of OsuBaseHit type. - objects = value.ConvertAll(o => (OsuBaseHit)o); - } - } - - public override void Load(BaseGame game) - { - base.Load(game); - - if (playfield == null) - Add(playfield = new OsuPlayfield()); - else - playfield.Clear(); - - if (objects == null) return; - - foreach (OsuBaseHit h in objects) - { - //render stuff! - Sprite s = new Sprite - { - Texture = game.Textures.Get(@"Menu/logo"), - Origin = Anchor.Centre, - Scale = new Vector2(0.1f), - Alpha = 0, - Position = h.Position - }; - - s.Transforms.Add(new TransformAlpha(Clock) { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = 0, EndValue = 1 }); - s.Transforms.Add(new TransformAlpha(Clock) { StartTime = h.StartTime + h.Duration + 200, EndTime = h.StartTime + h.Duration + 400, StartValue = 1, EndValue = 0 }); - s.Expire(true); - - playfield.Add(s); - } - } + protected override Drawable GetVisualRepresentation(OsuBaseHit h) => new DrawableCircle(h); } } diff --git a/osu.Game/GameModes/Play/Taiko/TaikoHitRenderer.cs b/osu.Game/GameModes/Play/Taiko/TaikoHitRenderer.cs index 2874c62fca..9fab5998f5 100644 --- a/osu.Game/GameModes/Play/Taiko/TaikoHitRenderer.cs +++ b/osu.Game/GameModes/Play/Taiko/TaikoHitRenderer.cs @@ -1,81 +1,20 @@ //Copyright (c) 2007-2016 ppy Pty Ltd . //Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using System.Collections.Generic; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics; -using osu.Framework.Graphics.Transformations; using osu.Game.Beatmaps.Objects; -using osu.Game.Beatmaps.Objects.Osu; using osu.Game.Beatmaps.Objects.Taiko; -using OpenTK; -using osu.Framework; +using osu.Game.Beatmaps.Objects.Taiko.Drawable; namespace osu.Game.GameModes.Play.Taiko { - public class TaikoHitRenderer : HitRenderer + public class TaikoHitRenderer : HitRenderer { - List objects; - private TaikoPlayfield playfield; + protected override List Convert(List objects) => new TaikoConverter().Convert(objects); - public override List Objects - { - set - { - //osu! mode requires all objects to be of TaikoBaseHit type. - objects = value.ConvertAll(convertForTaiko); - } - } + protected override Playfield CreatePlayfield() => new TaikoPlayfield(); - private TaikoBaseHit convertForTaiko(HitObject input) - { - TaikoBaseHit h = input as TaikoBaseHit; - - if (h == null) - { - OsuBaseHit o = input as OsuBaseHit; - - if (o == null) throw new Exception(@"Can't convert!"); - - h = new TaikoBaseHit() - { - StartTime = o.StartTime - }; - } - - return h; - } - - public override void Load(BaseGame game) - { - base.Load(game); - - if (playfield == null) - Add(playfield = new TaikoPlayfield()); - else - playfield.Clear(); - - if (objects == null) return; - - foreach (TaikoBaseHit h in objects) - { - //render stuff! - Sprite s = new Sprite - { - Texture = game.Textures.Get(@"Menu/logo"), - Origin = Anchor.Centre, - Scale = new Vector2(0.2f), - RelativePositionAxes = Axes.Both, - Position = new Vector2(1.1f, 0.5f) - }; - - s.Transforms.Add(new TransformPositionX(Clock) { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = 1.1f, EndValue = 0.1f }); - s.Transforms.Add(new TransformAlpha(Clock) { StartTime = h.StartTime + h.Duration + 200, EndTime = h.StartTime + h.Duration + 400, StartValue = 1, EndValue = 0 }); - s.Expire(true); - - playfield.Add(s); - } - } + protected override Drawable GetVisualRepresentation(TaikoBaseHit h) => new DrawableTaikoHit(h); } -} +} \ No newline at end of file diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index bb72bdf02e..a7b2239355 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -219,7 +219,10 @@ namespace osu.Game.Online.API { //NotificationManager.ShowMessage($@"We just went {newState}!", newState == APIState.Online ? Color4.YellowGreen : Color4.OrangeRed, 5000); log.Add($@"We just went {newState}!"); - OnStateChange?.Invoke(oldState, newState); + Scheduler.Add(delegate + { + OnStateChange?.Invoke(oldState, newState); + }); } } } diff --git a/osu.Game/Online/Chat/Display/ChatLine.cs b/osu.Game/Online/Chat/Display/ChatLine.cs index a827f411bf..5032ff0b9f 100644 --- a/osu.Game/Online/Chat/Display/ChatLine.cs +++ b/osu.Game/Online/Chat/Display/ChatLine.cs @@ -56,7 +56,7 @@ namespace osu.Game.Online.Chat.Display } } }, - new Container + new AutoSizeContainer { RelativeSizeAxes = Axes.X, Padding = new MarginPadding { Left = padding + 10 }, 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 f05a95f279..29c27d8090 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -34,32 +34,56 @@ - ..\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 + - + + + + + + + + + + @@ -147,13 +171,20 @@ + + + + + + + - + {c76bf5b3-985e-4d39-95fe-97c9c879b83a} osu.Framework - + {d9a367c9-4c1a-489f-9b05-a0cea2b53b58} osu.Game.Resources @@ -165,6 +196,7 @@ + + + + \ 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..3d79d4444f 100644 --- a/osu.sln +++ b/osu.sln @@ -19,43 +19,42 @@ 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 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Deploy|Any CPU.ActiveCfg = Debug|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Deploy|Any CPU.ActiveCfg = Debug|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.ActiveCfg = Release|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.Build.0 = Release|Any CPU {0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}.Deploy|Any CPU.ActiveCfg = Debug|Any CPU {0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}.Release|Any CPU.ActiveCfg = Release|Any CPU {0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}.Release|Any CPU.Build.0 = Release|Any CPU {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Deploy|Any CPU.ActiveCfg = Debug|Any CPU {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Release|Any CPU.ActiveCfg = Release|Any CPU {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}.Release|Any CPU.Build.0 = Release|Any CPU {65DC628F-A640-4111-AB35-3A5652BC1E17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {65DC628F-A640-4111-AB35-3A5652BC1E17}.Debug|Any CPU.Build.0 = Debug|Any CPU - {65DC628F-A640-4111-AB35-3A5652BC1E17}.Deploy|Any CPU.ActiveCfg = Debug|Any CPU {65DC628F-A640-4111-AB35-3A5652BC1E17}.Release|Any CPU.ActiveCfg = Release|Any CPU {65DC628F-A640-4111-AB35-3A5652BC1E17}.Release|Any CPU.Build.0 = Release|Any CPU {69051C69-12AE-4E7D-A3E6-460D2E282312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {69051C69-12AE-4E7D-A3E6-460D2E282312}.Debug|Any CPU.Build.0 = Debug|Any CPU - {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}.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 +66,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