diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs index 18009417cb..47575ca208 100644 --- a/osu.Desktop/Program.cs +++ b/osu.Desktop/Program.cs @@ -10,6 +10,11 @@ using osu.Framework.Desktop.Platform; using osu.Framework.Platform; using osu.Game; using osu.Game.IPC; +using osu.Game.Modes; +using osu.Game.Modes.Catch; +using osu.Game.Modes.Mania; +using osu.Game.Modes.Osu; +using osu.Game.Modes.Taiko; namespace osu.Desktop { @@ -31,6 +36,11 @@ namespace osu.Desktop } else { + Ruleset.Register(new OsuRuleset()); + Ruleset.Register(new TaikoRuleset()); + Ruleset.Register(new ManiaRuleset()); + Ruleset.Register(new CatchRuleset()); + BaseGame osu = new OsuGame(args); host.Add(osu); host.Run(); diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 28e591a558..95d3ad64c5 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -134,6 +134,18 @@ {c92a607b-1fdd-4954-9f92-03ff547d9080} osu.Game.Modes.Osu + + {58f6c80c-1253-4a0e-a465-b8c85ebeadf3} + osu.Game.Modes.Catch + + + {48f4582b-7687-4621-9cbe-5c24197cb536} + osu.Game.Modes.Mania + + + {f167e17a-7de6-4af5-b920-a5112296c695} + osu.Game.Modes.Taiko + {0d3fbf8a-7464-4cf7-8c90-3e7886df2d4d} osu.Game diff --git a/osu.Game.Mode.Osu/Objects/OsuBaseHit.cs b/osu.Game.Mode.Osu/Objects/OsuBaseHit.cs index 81c9e0b4e9..0bd3d62d9e 100644 --- a/osu.Game.Mode.Osu/Objects/OsuBaseHit.cs +++ b/osu.Game.Mode.Osu/Objects/OsuBaseHit.cs @@ -13,7 +13,7 @@ namespace osu.Game.Modes.Osu.Objects public Vector2 Position { get; set; } [Flags] - private enum HitObjectType + internal enum HitObjectType { Circle = 1, Slider = 2, @@ -25,35 +25,5 @@ namespace osu.Game.Modes.Osu.Objects 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.Mode.Osu/Objects/OsuHitObjectParser.cs b/osu.Game.Mode.Osu/Objects/OsuHitObjectParser.cs new file mode 100644 index 0000000000..81c218e8e1 --- /dev/null +++ b/osu.Game.Mode.Osu/Objects/OsuHitObjectParser.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using osu.Game.Beatmaps.Samples; +using osu.Game.Modes.Objects; +using OpenTK; + +namespace osu.Game.Modes.Osu.Objects +{ + public class OsuHitObjectParser : HitObjectParser + { + public override HitObject Parse(string text) + { + string[] split = text.Split(','); + var type = (OsuBaseHit.HitObjectType)int.Parse(split[3]); + bool combo = type.HasFlag(OsuBaseHit.HitObjectType.NewCombo); + type &= (OsuBaseHit.HitObjectType)0xF; + type &= ~OsuBaseHit.HitObjectType.NewCombo; + OsuBaseHit result; + switch (type) + { + case OsuBaseHit.HitObjectType.Circle: + result = new Circle(); + break; + case OsuBaseHit.HitObjectType.Slider: + result = new Slider(); + break; + case OsuBaseHit.HitObjectType.Spinner: + result = new Spinner(); + break; + default: + //throw new InvalidOperationException($@"Unknown hit object type {type}"); + return null; + } + 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.Mode.Osu/OsuRuleset.cs b/osu.Game.Mode.Osu/OsuRuleset.cs index 666f51f041..4e8b8fde2b 100644 --- a/osu.Game.Mode.Osu/OsuRuleset.cs +++ b/osu.Game.Mode.Osu/OsuRuleset.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using osu.Game.Modes.Objects; +using osu.Game.Modes.Osu.Objects; using osu.Game.Modes.Osu.UI; using osu.Game.Modes.UI; @@ -13,5 +14,7 @@ namespace osu.Game.Modes.Osu public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); public override HitRenderer CreateHitRendererWith(List objects) => new UI.OsuHitRenderer { Objects = objects }; + + public override HitObjectParser CreateHitObjectParser() => new OsuHitObjectParser(); } } diff --git a/osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj b/osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj index 2c38463e9d..9a5668b35e 100644 --- a/osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj +++ b/osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj @@ -41,6 +41,7 @@ + diff --git a/osu.Game.Modes.Catch/CatchRuleset.cs b/osu.Game.Modes.Catch/CatchRuleset.cs index 992d0fff59..5a55db5ede 100644 --- a/osu.Game.Modes.Catch/CatchRuleset.cs +++ b/osu.Game.Modes.Catch/CatchRuleset.cs @@ -4,15 +4,18 @@ using System.Collections.Generic; using osu.Game.Modes.Catch.UI; using osu.Game.Modes.Objects; +using osu.Game.Modes.Osu.Objects; using osu.Game.Modes.Osu.UI; using osu.Game.Modes.UI; namespace osu.Game.Modes.Catch { - class CatchRuleset : Ruleset + public class CatchRuleset : Ruleset { public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); public override HitRenderer CreateHitRendererWith(List objects) => new CatchHitRenderer { Objects = objects }; + + public override HitObjectParser CreateHitObjectParser() => new OsuHitObjectParser(); } } diff --git a/osu.Game.Modes.Mania/ManiaRuleset.cs b/osu.Game.Modes.Mania/ManiaRuleset.cs index 07f2545fd3..f92ce9ba1a 100644 --- a/osu.Game.Modes.Mania/ManiaRuleset.cs +++ b/osu.Game.Modes.Mania/ManiaRuleset.cs @@ -5,15 +5,18 @@ using System.Collections.Generic; using osu.Game.Modes.Mania.UI; using osu.Game.Modes.Objects; using osu.Game.Modes.Osu; +using osu.Game.Modes.Osu.Objects; using osu.Game.Modes.Osu.UI; using osu.Game.Modes.UI; namespace osu.Game.Modes.Mania { - class ManiaRuleset : Ruleset + public class ManiaRuleset : Ruleset { public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); public override HitRenderer CreateHitRendererWith(List objects) => new ManiaHitRenderer { Objects = objects }; + + public override HitObjectParser CreateHitObjectParser() => new OsuHitObjectParser(); } } diff --git a/osu.Game.Modes.Taiko/TaikoRuleset.cs b/osu.Game.Modes.Taiko/TaikoRuleset.cs index f8322e32dc..a85c2c7a32 100644 --- a/osu.Game.Modes.Taiko/TaikoRuleset.cs +++ b/osu.Game.Modes.Taiko/TaikoRuleset.cs @@ -3,16 +3,19 @@ using System.Collections.Generic; using osu.Game.Modes.Objects; +using osu.Game.Modes.Osu.Objects; using osu.Game.Modes.Osu.UI; using osu.Game.Modes.Taiko.UI; using osu.Game.Modes.UI; namespace osu.Game.Modes.Taiko { - class TaikoRuleset : Ruleset + public class TaikoRuleset : Ruleset { public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); public override HitRenderer CreateHitRendererWith(List objects) => new TaikoHitRenderer { Objects = objects }; + + public override HitObjectParser CreateHitObjectParser() => new OsuHitObjectParser(); } } diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs index db2e4b7d7e..90b62ef98a 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs @@ -7,6 +7,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Samples; using osu.Game.Modes; +using osu.Game.Modes.Osu; using osu.Game.Modes.Osu.Objects; using osu.Game.Screens.Play; using osu.Game.Tests.Resources; @@ -20,6 +21,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void SetUp() { OsuLegacyDecoder.Register(); + Ruleset.Register(new OsuRuleset()); } [Test] public void TestDecodeMetadata() diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 0c53ef380c..7acbdbf3d9 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -9,6 +9,10 @@ using osu.Framework.Platform; using osu.Game.Database; using osu.Game.IPC; using osu.Game.Modes; +using osu.Game.Modes.Catch; +using osu.Game.Modes.Mania; +using osu.Game.Modes.Osu; +using osu.Game.Modes.Taiko; using osu.Game.Screens.Play; namespace osu.Game.Tests.Beatmaps.IO @@ -21,6 +25,10 @@ namespace osu.Game.Tests.Beatmaps.IO [OneTimeSetUp] public void SetUp() { + Ruleset.Register(new OsuRuleset()); + Ruleset.Register(new TaikoRuleset()); + Ruleset.Register(new ManiaRuleset()); + Ruleset.Register(new CatchRuleset()); } [Test] diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index 8a0364a03b..1343ae7241 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -2,6 +2,8 @@ using System.IO; using NUnit.Framework; using osu.Game.Beatmaps.IO; +using osu.Game.Modes; +using osu.Game.Modes.Osu; using osu.Game.Tests.Resources; namespace osu.Game.Tests.Beatmaps.IO @@ -13,8 +15,9 @@ namespace osu.Game.Tests.Beatmaps.IO public void SetUp() { OszArchiveReader.Register(); + Ruleset.Register(new OsuRuleset()); } - + [Test] public void TestReadBeatmaps() { diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 646ee756d5..d59e90c2f4 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -70,6 +70,18 @@ {c92a607b-1fdd-4954-9f92-03ff547d9080} osu.Game.Modes.Osu + + {58f6c80c-1253-4a0e-a465-b8c85ebeadf3} + osu.Game.Modes.Catch + + + {48f4582b-7687-4621-9cbe-5c24197cb536} + osu.Game.Modes.Mania + + + {f167e17a-7de6-4af5-b920-a5112296c695} + osu.Game.Modes.Taiko + {0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D} osu.Game diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs index 7ff3dbac2b..b5dd0c995e 100644 --- a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs @@ -48,6 +48,8 @@ namespace osu.Game.Beatmaps.Formats new Color4(121,9,13, 255), }; + if (colours.Count == 0) return; + int i = -1; foreach (HitObject h in b.HitObjects) diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 2cf4e66927..5468e616f0 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -221,7 +221,9 @@ namespace osu.Game.Beatmaps.Formats BaseDifficulty = new BaseDifficulty(), }, }; - + + HitObjectParser parser = null; + var section = Section.None; string line; while (true) @@ -233,14 +235,14 @@ namespace osu.Game.Beatmaps.Formats 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) { @@ -251,6 +253,7 @@ namespace osu.Game.Beatmaps.Formats { case Section.General: handleGeneral(beatmap, key, val); + parser = Ruleset.GetRuleset(beatmap.BeatmapInfo.Mode).CreateHitObjectParser(); break; case Section.Editor: handleEditor(beatmap, key, val); @@ -271,13 +274,13 @@ namespace osu.Game.Beatmaps.Formats handleColours(beatmap, key, val); break; case Section.HitObjects: - var h = HitObject.Parse(beatmap.BeatmapInfo.Mode, val); - if (h != null) - beatmap.HitObjects.Add(h); + var obj = parser?.Parse(val); + if (obj != null) + beatmap.HitObjects.Add(obj); break; } } - + return beatmap; } } diff --git a/osu.Game/Modes/Objects/HitObject.cs b/osu.Game/Modes/Objects/HitObject.cs index 62c47d7059..abb88726b6 100644 --- a/osu.Game/Modes/Objects/HitObject.cs +++ b/osu.Game/Modes/Objects/HitObject.cs @@ -21,17 +21,5 @@ namespace osu.Game.Modes.Objects public double Duration => EndTime - 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 null; //return OsuBaseHit.Parse(val); - default: - return null; - } - } } } diff --git a/osu.Game/Modes/Objects/HitObjectParser.cs b/osu.Game/Modes/Objects/HitObjectParser.cs new file mode 100644 index 0000000000..261e92ff96 --- /dev/null +++ b/osu.Game/Modes/Objects/HitObjectParser.cs @@ -0,0 +1,16 @@ +//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; + +namespace osu.Game.Modes.Objects +{ + public abstract class HitObjectParser + { + public abstract HitObject Parse(string text); + } +} diff --git a/osu.Game/Modes/Ruleset.cs b/osu.Game/Modes/Ruleset.cs index 64a91f2108..7fc4b3221d 100644 --- a/osu.Game/Modes/Ruleset.cs +++ b/osu.Game/Modes/Ruleset.cs @@ -13,17 +13,19 @@ namespace osu.Game.Modes { public abstract class Ruleset { + private static List availableRulesets = new List(); + public abstract ScoreOverlay CreateScoreOverlay(); public abstract HitRenderer CreateHitRendererWith(List objects); + public abstract HitObjectParser CreateHitObjectParser(); + + public static void Register(Ruleset ruleset) => availableRulesets.Add(ruleset.GetType()); + public static Ruleset GetRuleset(PlayMode mode) { - Type type = AppDomain.CurrentDomain - .GetAssemblies() - .Where(a => a.FullName.Contains($@"osu.Game.Modes.{mode}")) - .SelectMany(a => a.GetTypes()) - .FirstOrDefault(t => t.Name == $@"{mode}Ruleset"); + Type type = availableRulesets.FirstOrDefault(t => t.Name == $@"{mode}Ruleset"); if (type == null) return null; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ede412f27c..88f78b57be 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -63,6 +63,7 @@ +