diff --git a/.vscode/launch.json b/.vscode/launch.json index f1682a2ce2..d9a6ae12ff 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "Launch", "type": "mono", "request": "launch", - "program": "${workspaceRoot}/osu.Desktop.VisualTests/bin/Debug/osu!.exe", + "program": "${workspaceRoot}/osu.Desktop/bin/Debug/osu!.exe", "args": [], "cwd": "${workspaceRoot}", "preLaunchTask": "", diff --git a/osu-framework b/osu-framework index cda05b3a64..44a3b764f0 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit cda05b3a64162eb9d8e591ffe7f79d959c39eebc +Subproject commit 44a3b764f0095573eec45ee1f68265f837896fc3 diff --git a/osu.Desktop/Beatmaps/IO/LegacyFilesystemReader.cs b/osu.Desktop/Beatmaps/IO/LegacyFilesystemReader.cs index 8282d8556a..c57498f5dd 100644 --- a/osu.Desktop/Beatmaps/IO/LegacyFilesystemReader.cs +++ b/osu.Desktop/Beatmaps/IO/LegacyFilesystemReader.cs @@ -5,6 +5,7 @@ using System.Linq; using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.IO; using osu.Game.Beatmaps; +using osu.Game.Database; namespace osu.Desktop.Beatmaps.IO { @@ -31,8 +32,7 @@ namespace osu.Desktop.Beatmaps.IO using (var stream = new StreamReader(ReadFile(beatmaps[0]))) { var decoder = BeatmapDecoder.GetDecoder(stream); - firstMap = new Beatmap(); - decoder.Decode(stream, firstMap); + firstMap = decoder.Decode(stream); } } @@ -48,11 +48,12 @@ namespace osu.Desktop.Beatmaps.IO public override BeatmapMetadata ReadMetadata() { - return firstMap.Metadata; + return firstMap.BeatmapInfo.Metadata; } public override void Dispose() { // no-op - } } + } + } } \ No newline at end of file diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs index adb203b483..d48019c446 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs @@ -26,9 +26,8 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new OsuLegacyDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { - Beatmap beatmap = new Beatmap(); - decoder.Decode(new StreamReader(stream), beatmap); - var meta = beatmap.Metadata; + var beatmap = decoder.Decode(new StreamReader(stream)); + var meta = beatmap.BeatmapInfo.Metadata; Assert.AreEqual(241526, meta.BeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); @@ -49,16 +48,15 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new OsuLegacyDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { - Beatmap beatmap = new Beatmap(); - decoder.Decode(new StreamReader(stream), beatmap); - Assert.AreEqual(0, beatmap.AudioLeadIn); - Assert.AreEqual(false, beatmap.Countdown); - Assert.AreEqual(SampleSet.Soft, beatmap.SampleSet); - Assert.AreEqual(0.7f, beatmap.StackLeniency); - Assert.AreEqual(false, beatmap.SpecialStyle); - Assert.AreEqual(PlayMode.Osu, beatmap.Mode); - Assert.AreEqual(false, beatmap.LetterboxInBreaks); - Assert.AreEqual(false, beatmap.WidescreenStoryboard); + var beatmapInfo = decoder.Decode(new StreamReader(stream)).BeatmapInfo; + Assert.AreEqual(0, beatmapInfo.AudioLeadIn); + Assert.AreEqual(false, beatmapInfo.Countdown); + Assert.AreEqual(SampleSet.Soft, beatmapInfo.SampleSet); + Assert.AreEqual(0.7f, beatmapInfo.StackLeniency); + Assert.AreEqual(false, beatmapInfo.SpecialStyle); + Assert.AreEqual(PlayMode.Osu, beatmapInfo.Mode); + Assert.AreEqual(false, beatmapInfo.LetterboxInBreaks); + Assert.AreEqual(false, beatmapInfo.WidescreenStoryboard); } } @@ -68,8 +66,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new OsuLegacyDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { - Beatmap beatmap = new Beatmap(); - decoder.Decode(new StreamReader(stream), beatmap); + var beatmap = decoder.Decode(new StreamReader(stream)).BeatmapInfo; int[] expectedBookmarks = { 11505, 22054, 32604, 43153, 53703, 64252, 74802, 85351, @@ -92,9 +89,8 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new OsuLegacyDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { - Beatmap beatmap = new Beatmap(); - decoder.Decode(new StreamReader(stream), beatmap); - var difficulty = beatmap.BaseDifficulty; + var beatmap = decoder.Decode(new StreamReader(stream)); + var difficulty = beatmap.BeatmapInfo.BaseDifficulty; Assert.AreEqual(6.5f, difficulty.DrainRate); Assert.AreEqual(4, difficulty.CircleSize); Assert.AreEqual(8, difficulty.OverallDifficulty); @@ -110,8 +106,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new OsuLegacyDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { - Beatmap beatmap = new Beatmap(); - decoder.Decode(new StreamReader(stream), beatmap); + var beatmap = decoder.Decode(new StreamReader(stream)); Color4[] expected = { new Color4(142, 199, 255, 255), @@ -132,8 +127,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new OsuLegacyDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { - Beatmap beatmap = new Beatmap(); - decoder.Decode(new StreamReader(stream), beatmap); + var beatmap = decoder.Decode(new StreamReader(stream)); var slider = beatmap.HitObjects[0] as Slider; Assert.IsNotNull(slider); Assert.AreEqual(new Vector2(192, 168), slider.Position); diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 99199e421c..438a5a2b89 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -1,69 +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 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; +using osu.Game.Database; namespace osu.Game.Beatmaps { public class Beatmap { - [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 BeatmapInfo BeatmapInfo { get; set; } 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/BeatmapSet.cs b/osu.Game/Beatmaps/BeatmapSet.cs deleted file mode 100644 index 11f82329f9..0000000000 --- a/osu.Game/Beatmaps/BeatmapSet.cs +++ /dev/null @@ -1,28 +0,0 @@ -//Copyright (c) 2007-2016 ppy Pty Ltd . -//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.Collections.Generic; -using osu.Game.Users; -using SQLite; - -namespace osu.Game.Beatmaps -{ - /// - /// A beatmap set contains multiple beatmap (difficulties). - /// - public class BeatmapSet - { - [PrimaryKey] - public int BeatmapSetID { get; set; } - [NotNull, Indexed] - public int BeatmapMetadataID { get; set; } - [Ignore] - public List Beatmaps { get; protected set; } = new List(); - [Ignore] - public BeatmapMetadata Metadata { get; set; } - [Ignore] - public User Creator { get; set; } - public string Hash { get; set; } - public string Path { get; set; } - } -} diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs index 0c6bbb02e1..92f2452484 100644 --- a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs @@ -15,11 +15,12 @@ namespace osu.Game.Beatmaps.Formats throw new IOException(@"Unknown file format"); return (BeatmapDecoder)Activator.CreateInstance(decoders[line]); } - protected static void AddDecoder(string magic) where T : BeatmapDecoder + + protected static void AddDecoder(string magic) where T : BeatmapDecoder { decoders[magic] = typeof(T); } - public abstract void Decode(TextReader stream, Beatmap beatmap); + 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 index 4250e9a7c2..9cbddc853f 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using OpenTK.Graphics; +using osu.Game.Database; using osu.Game.Beatmaps.Events; using osu.Game.Beatmaps.Objects; using osu.Game.Beatmaps.Samples; @@ -38,37 +39,38 @@ namespace osu.Game.Beatmaps.Formats private void handleGeneral(Beatmap beatmap, string key, string val) { + var metadata = beatmap.BeatmapInfo.Metadata; switch (key) { case @"AudioFilename": - beatmap.Metadata.AudioFile = val; + metadata.AudioFile = val; break; case @"AudioLeadIn": - beatmap.AudioLeadIn = int.Parse(val); + beatmap.BeatmapInfo.AudioLeadIn = int.Parse(val); break; case @"PreviewTime": - beatmap.Metadata.PreviewTime = int.Parse(val); + metadata.PreviewTime = int.Parse(val); break; case @"Countdown": - beatmap.Countdown = int.Parse(val) == 1; + beatmap.BeatmapInfo.Countdown = int.Parse(val) == 1; break; case @"SampleSet": - beatmap.SampleSet = (SampleSet)Enum.Parse(typeof(SampleSet), val); + beatmap.BeatmapInfo.SampleSet = (SampleSet)Enum.Parse(typeof(SampleSet), val); break; case @"StackLeniency": - beatmap.StackLeniency = float.Parse(val, NumberFormatInfo.InvariantInfo); + beatmap.BeatmapInfo.StackLeniency = float.Parse(val, NumberFormatInfo.InvariantInfo); break; case @"Mode": - beatmap.Mode = (PlayMode)int.Parse(val); + beatmap.BeatmapInfo.Mode = (PlayMode)int.Parse(val); break; case @"LetterboxInBreaks": - beatmap.LetterboxInBreaks = int.Parse(val) == 1; + beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(val) == 1; break; case @"SpecialStyle": - beatmap.SpecialStyle = int.Parse(val) == 1; + beatmap.BeatmapInfo.SpecialStyle = int.Parse(val) == 1; break; case @"WidescreenStoryboard": - beatmap.WidescreenStoryboard = int.Parse(val) == 1; + beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(val) == 1; break; } } @@ -78,82 +80,84 @@ namespace osu.Game.Beatmaps.Formats switch (key) { case @"Bookmarks": - beatmap.StoredBookmarks = val; + beatmap.BeatmapInfo.StoredBookmarks = val; break; case @"DistanceSpacing": - beatmap.DistanceSpacing = double.Parse(val, NumberFormatInfo.InvariantInfo); + beatmap.BeatmapInfo.DistanceSpacing = double.Parse(val, NumberFormatInfo.InvariantInfo); break; case @"BeatDivisor": - beatmap.BeatDivisor = int.Parse(val); + beatmap.BeatmapInfo.BeatDivisor = int.Parse(val); break; case @"GridSize": - beatmap.GridSize = int.Parse(val); + beatmap.BeatmapInfo.GridSize = int.Parse(val); break; case @"TimelineZoom": - beatmap.TimelineZoom = double.Parse(val, NumberFormatInfo.InvariantInfo); + beatmap.BeatmapInfo.TimelineZoom = double.Parse(val, NumberFormatInfo.InvariantInfo); break; } } private void handleMetadata(Beatmap beatmap, string key, string val) { + var metadata = beatmap.BeatmapInfo.Metadata; switch (key) { case @"Title": - beatmap.Metadata.Title = val; + metadata.Title = val; break; case @"TitleUnicode": - beatmap.Metadata.TitleUnicode = val; + metadata.TitleUnicode = val; break; case @"Artist": - beatmap.Metadata.Artist = val; + metadata.Artist = val; break; case @"ArtistUnicode": - beatmap.Metadata.ArtistUnicode = val; + metadata.ArtistUnicode = val; break; case @"Creator": - beatmap.Metadata.Author = val; + metadata.Author = val; break; case @"Version": - beatmap.Version = val; + beatmap.BeatmapInfo.Version = val; break; case @"Source": - beatmap.Metadata.Source = val; + beatmap.BeatmapInfo.Metadata.Source = val; break; case @"Tags": - beatmap.Metadata.Tags = val; + beatmap.BeatmapInfo.Metadata.Tags = val; break; case @"BeatmapID": - beatmap.BeatmapID = int.Parse(val); + beatmap.BeatmapInfo.BeatmapID = int.Parse(val); break; case @"BeatmapSetID": - beatmap.BeatmapSetID = int.Parse(val); - beatmap.Metadata.BeatmapSetID = int.Parse(val); + beatmap.BeatmapInfo.BeatmapSetID = int.Parse(val); + metadata.BeatmapSetID = int.Parse(val); break; } } private void handleDifficulty(Beatmap beatmap, string key, string val) { + var difficulty = beatmap.BeatmapInfo.BaseDifficulty; switch (key) { case @"HPDrainRate": - beatmap.BaseDifficulty.DrainRate = float.Parse(val, NumberFormatInfo.InvariantInfo); + difficulty.DrainRate = float.Parse(val, NumberFormatInfo.InvariantInfo); break; case @"CircleSize": - beatmap.BaseDifficulty.CircleSize = float.Parse(val, NumberFormatInfo.InvariantInfo); + difficulty.CircleSize = float.Parse(val, NumberFormatInfo.InvariantInfo); break; case @"OverallDifficulty": - beatmap.BaseDifficulty.OverallDifficulty = float.Parse(val, NumberFormatInfo.InvariantInfo); + difficulty.OverallDifficulty = float.Parse(val, NumberFormatInfo.InvariantInfo); break; case @"ApproachRate": - beatmap.BaseDifficulty.ApproachRate = float.Parse(val, NumberFormatInfo.InvariantInfo); + difficulty.ApproachRate = float.Parse(val, NumberFormatInfo.InvariantInfo); break; case @"SliderMultiplier": - beatmap.BaseDifficulty.SliderMultiplier = float.Parse(val, NumberFormatInfo.InvariantInfo); + difficulty.SliderMultiplier = float.Parse(val, NumberFormatInfo.InvariantInfo); break; case @"SliderTickRate": - beatmap.BaseDifficulty.SliderTickRate = float.Parse(val, NumberFormatInfo.InvariantInfo); + difficulty.SliderTickRate = float.Parse(val, NumberFormatInfo.InvariantInfo); break; } } @@ -176,7 +180,7 @@ namespace osu.Game.Beatmaps.Formats type = (EventType)_type; // TODO: Parse and store the rest of the event if (type == EventType.Background) - beatmap.Metadata.BackgroundFile = split[2].Trim('"'); + beatmap.BeatmapInfo.Metadata.BackgroundFile = split[2].Trim('"'); } private void handleTimingPoints(Beatmap beatmap, string val) @@ -202,15 +206,15 @@ namespace osu.Game.Beatmaps.Formats }); } - public override void Decode(TextReader stream, Beatmap beatmap) + public override Beatmap Decode(TextReader stream) { - // We don't overwrite these two because they're DB bound - if (beatmap.Metadata == null) beatmap.Metadata = new BeatmapMetadata(); - if (beatmap.BaseDifficulty == null) beatmap.BaseDifficulty = new BaseDifficulty(); - // These are fine though - beatmap.HitObjects = new List(); - beatmap.ControlPoints = new List(); - beatmap.ComboColors = new List(); + var beatmap = new Beatmap + { + HitObjects = new List(), + ControlPoints = new List(), + ComboColors = new List(), + BeatmapInfo = new BeatmapInfo(), + }; var section = Section.None; string line; @@ -262,10 +266,12 @@ namespace osu.Game.Beatmaps.Formats handleColours(beatmap, key, val); break; case Section.HitObjects: - beatmap.HitObjects.Add(HitObject.Parse(beatmap.Mode, val)); + beatmap.HitObjects.Add(HitObject.Parse(beatmap.BeatmapInfo.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 index 89adf26989..5f1afe3a00 100644 --- a/osu.Game/Beatmaps/IO/ArchiveReader.cs +++ b/osu.Game/Beatmaps/IO/ArchiveReader.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using osu.Framework.Platform; +using osu.Game.Database; namespace osu.Game.Beatmaps.IO { diff --git a/osu.Game/Beatmaps/IO/OszArchiveReader.cs b/osu.Game/Beatmaps/IO/OszArchiveReader.cs index 69776d0095..8b677d0145 100644 --- a/osu.Game/Beatmaps/IO/OszArchiveReader.cs +++ b/osu.Game/Beatmaps/IO/OszArchiveReader.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Security.Cryptography; using Ionic.Zip; using osu.Game.Beatmaps.Formats; +using osu.Game.Database; namespace osu.Game.Beatmaps.IO { @@ -33,8 +34,7 @@ namespace osu.Game.Beatmaps.IO using (var stream = new StreamReader(ReadFile(beatmaps[0]))) { var decoder = BeatmapDecoder.GetDecoder(stream); - firstMap = new Beatmap(); - decoder.Decode(stream, firstMap); + firstMap = decoder.Decode(stream); } } @@ -53,9 +53,10 @@ namespace osu.Game.Beatmaps.IO public override BeatmapMetadata ReadMetadata() { - return firstMap.Metadata; + return firstMap.BeatmapInfo.Metadata; } - public override void Dispose() + + public override void Dispose() { archive.Dispose(); } diff --git a/osu.Game/Beatmaps/BaseDifficulty.cs b/osu.Game/Database/BaseDifficulty.cs similarity index 85% rename from osu.Game/Beatmaps/BaseDifficulty.cs rename to osu.Game/Database/BaseDifficulty.cs index ce9e3bc624..265f933045 100644 --- a/osu.Game/Beatmaps/BaseDifficulty.cs +++ b/osu.Game/Database/BaseDifficulty.cs @@ -1,7 +1,7 @@ using System; -using SQLite; +using SQLite.Net.Attributes; -namespace osu.Game.Beatmaps +namespace osu.Game.Database { public class BaseDifficulty { diff --git a/osu.Game/Database/BeatmapDatabase.cs b/osu.Game/Database/BeatmapDatabase.cs index 7f8cf86c14..73809c6fc2 100644 --- a/osu.Game/Database/BeatmapDatabase.cs +++ b/osu.Game/Database/BeatmapDatabase.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Security.Cryptography; using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.IO; -using SQLite; +using SQLite.Net; +using SQLiteNetExtensions.Extensions; namespace osu.Game.Database { @@ -23,14 +25,18 @@ namespace osu.Game.Database connection = storage.GetDatabase(@"beatmaps"); connection.CreateTable(); connection.CreateTable(); - connection.CreateTable(); - connection.CreateTable(); + connection.CreateTable(); + connection.CreateTable(); } } - public void AddBeatmap(string path) + + public void ImportBeatmap(string path) { string hash = null; - ArchiveReader reader; + var reader = ArchiveReader.GetReader(storage, path); + var metadata = reader.ReadMetadata(); + if (connection.Table().Count(b => b.BeatmapSetID == metadata.BeatmapSetID) != 0) + return; // TODO: Update this beatmap instead if (File.Exists(path)) // Not always the case, i.e. for LegacyFilesystemReader { using (var md5 = MD5.Create()) @@ -41,60 +47,82 @@ namespace osu.Game.Database var outputPath = Path.Combine(@"beatmaps", hash.Remove(1), hash.Remove(2), hash); using (var output = storage.GetStream(outputPath, FileAccess.Write)) input.CopyTo(output); - reader = ArchiveReader.GetReader(storage, path = outputPath); } } - else - reader = ArchiveReader.GetReader(storage, path); - var metadata = reader.ReadMetadata(); - if (connection.Table().Count(b => b.BeatmapSetID == metadata.BeatmapSetID) != 0) - return; // TODO: Update this beatmap instead string[] mapNames = reader.ReadBeatmaps(); - var beatmapSet = new BeatmapSet + var beatmapSet = new BeatmapSetInfo { BeatmapSetID = metadata.BeatmapSetID, Path = path, Hash = hash, }; - var maps = new List(); + var maps = new List(); foreach (var name in mapNames) { using (var stream = new StreamReader(reader.ReadFile(name))) { var decoder = BeatmapDecoder.GetDecoder(stream); - Beatmap beatmap = new Beatmap(); - decoder.Decode(stream, beatmap); - maps.Add(beatmap); - beatmap.BaseDifficultyID = connection.Insert(beatmap.BaseDifficulty); + Beatmap beatmap = decoder.Decode(stream); + beatmap.BeatmapInfo.Path = name; + // TODO: Diff beatmap metadata with set metadata and insert if necessary + beatmap.BeatmapInfo.Metadata = null; + maps.Add(beatmap.BeatmapInfo); + connection.Insert(beatmap.BeatmapInfo.BaseDifficulty); + connection.Insert(beatmap.BeatmapInfo); + connection.UpdateWithChildren(beatmap.BeatmapInfo); } } - beatmapSet.BeatmapMetadataID = connection.Insert(metadata); connection.Insert(beatmapSet); - connection.InsertAll(maps); + beatmapSet.BeatmapMetadataID = connection.Insert(metadata); + connection.UpdateWithChildren(beatmapSet); } - public ArchiveReader GetReader(BeatmapSet beatmapSet) + + public ArchiveReader GetReader(BeatmapSetInfo beatmapSet) { return ArchiveReader.GetReader(storage, beatmapSet.Path); } - - /// - /// Given a BeatmapSet pulled from the database, loads the rest of its data from disk. - /// public void PopulateBeatmap(BeatmapSet beatmapSet) + + public BeatmapSetInfo GetBeatmapSet(int id) { + return Query().Where(s => s.BeatmapSetID == id).FirstOrDefault(); + } + + public Beatmap GetBeatmap(BeatmapInfo beatmapInfo) + { + var beatmapSet = Query() + .Where(s => s.BeatmapSetID == beatmapInfo.BeatmapSetID).FirstOrDefault(); + if (beatmapSet == null) + throw new InvalidOperationException( + $@"Beatmap set {beatmapInfo.BeatmapSetID} is not in the local database."); using (var reader = GetReader(beatmapSet)) + using (var stream = new StreamReader(reader.ReadFile(beatmapInfo.Path))) { - string[] mapNames = reader.ReadBeatmaps(); - foreach (var name in mapNames) - { - using (var stream = new StreamReader(reader.ReadFile(name))) - { - var decoder = BeatmapDecoder.GetDecoder(stream); - Beatmap beatmap = new Beatmap(); - decoder.Decode(stream, beatmap); - beatmapSet.Beatmaps.Add(beatmap); - } - } + var decoder = BeatmapDecoder.GetDecoder(stream); + return decoder.Decode(stream); } } + + public TableQuery Query() where T : class + { + return connection.Table(); + } + + readonly Type[] validTypes = new[] + { + typeof(BeatmapSetInfo), + typeof(BeatmapInfo), + typeof(BeatmapMetadata), + typeof(BaseDifficulty), + }; + + public void Update(T record, bool cascade = true) where T : class + { + if (!validTypes.Any(t => t == typeof(T))) + throw new ArgumentException(nameof(T), "Must be a type managed by BeatmapDatabase"); + if (cascade) + connection.UpdateWithChildren(record); + else + connection.Update(record); + } } } \ No newline at end of file diff --git a/osu.Game/Database/BeatmapInfo.cs b/osu.Game/Database/BeatmapInfo.cs new file mode 100644 index 0000000000..540450d19e --- /dev/null +++ b/osu.Game/Database/BeatmapInfo.cs @@ -0,0 +1,66 @@ +using System; +using System.Linq; +using osu.Game.Beatmaps.Samples; +using osu.Game.GameModes.Play; +using SQLite.Net.Attributes; +using SQLiteNetExtensions.Attributes; + +namespace osu.Game.Database +{ + public class BeatmapInfo + { + public BeatmapInfo() + { + BaseDifficulty = new BaseDifficulty(); + Metadata = new BeatmapMetadata(); + } + + [PrimaryKey] + public int BeatmapID { get; set; } + [NotNull, Indexed] + public int BeatmapSetID { get; set; } + [ForeignKey(typeof(BeatmapMetadata))] + public int BeatmapMetadataID { get; set; } + [ForeignKey(typeof(BaseDifficulty)), NotNull] + public int BaseDifficultyID { get; set; } + [OneToOne] + public BeatmapMetadata Metadata { get; set; } + [OneToOne] + public BaseDifficulty BaseDifficulty { get; set; } + + public string Path { 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/Database/BeatmapMetadata.cs similarity index 90% rename from osu.Game/Beatmaps/BeatmapMetadata.cs rename to osu.Game/Database/BeatmapMetadata.cs index 1499dde323..531779922a 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Database/BeatmapMetadata.cs @@ -2,9 +2,9 @@ //Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Game.GameModes.Play; -using SQLite; +using SQLite.Net.Attributes; -namespace osu.Game.Beatmaps +namespace osu.Game.Database { public class BeatmapMetadata { diff --git a/osu.Game/Database/BeatmapSetInfo.cs b/osu.Game/Database/BeatmapSetInfo.cs new file mode 100644 index 0000000000..97b3359510 --- /dev/null +++ b/osu.Game/Database/BeatmapSetInfo.cs @@ -0,0 +1,19 @@ +using System; +using SQLite.Net.Attributes; +using SQLiteNetExtensions.Attributes; + +namespace osu.Game.Database +{ + public class BeatmapSetInfo + { + [PrimaryKey] + public int BeatmapSetID { get; set; } + [OneToOne] + public BeatmapMetadata Metadata { get; set; } + [NotNull, ForeignKey(typeof(BeatmapMetadata))] + public int BeatmapMetadataID { get; set; } + public string Hash { get; set; } + public string Path { get; set; } + } +} + diff --git a/osu.Game/GameModes/BackgroundMode.cs b/osu.Game/GameModes/BackgroundMode.cs index d9b1c1b18f..f6ee9d10e4 100644 --- a/osu.Game/GameModes/BackgroundMode.cs +++ b/osu.Game/GameModes/BackgroundMode.cs @@ -35,7 +35,7 @@ namespace osu.Game.GameModes { base.Load(game); - Content.Scale *= 1 + (x_movement_amount / Size.X) * 2; + Content.Scale *= 1 + (x_movement_amount / DrawSize.X) * 2; } protected override void OnEntering(GameMode last) diff --git a/osu.Game/GameModes/GameModeWhiteBox.cs b/osu.Game/GameModes/GameModeWhiteBox.cs index 9c404e7241..ac3dfa148a 100644 --- a/osu.Game/GameModes/GameModeWhiteBox.cs +++ b/osu.Game/GameModes/GameModeWhiteBox.cs @@ -39,7 +39,7 @@ namespace osu.Game.GameModes popButton.Alpha = 1; Content.Alpha = 0; - textContainer.Position = new Vector2(Size.X / 16, 0); + textContainer.Position = new Vector2(DrawSize.X / 16, 0); box.ScaleTo(0.2f); box.RotateTo(-20); @@ -55,7 +55,7 @@ namespace osu.Game.GameModes protected override bool OnExiting(GameMode next) { - textContainer.MoveTo(new Vector2((Size.X / 16), 0), transition_time, EasingTypes.OutExpo); + textContainer.MoveTo(new Vector2((DrawSize.X / 16), 0), transition_time, EasingTypes.OutExpo); Content.FadeOut(transition_time, EasingTypes.OutExpo); return base.OnExiting(next); @@ -65,7 +65,7 @@ namespace osu.Game.GameModes { base.OnSuspending(next); - textContainer.MoveTo(new Vector2(-(Size.X / 16), 0), transition_time, EasingTypes.OutExpo); + textContainer.MoveTo(new Vector2(-(DrawSize.X / 16), 0), transition_time, EasingTypes.OutExpo); Content.FadeOut(transition_time, EasingTypes.OutExpo); } diff --git a/osu.Game/GameModes/Menu/ButtonSystem.cs b/osu.Game/GameModes/Menu/ButtonSystem.cs index 2f1d84b3ab..4457df3dc7 100644 --- a/osu.Game/GameModes/Menu/ButtonSystem.cs +++ b/osu.Game/GameModes/Menu/ButtonSystem.cs @@ -210,7 +210,7 @@ namespace osu.Game.GameModes.Menu case MenuState.TopLevel: buttonAreaBackground.ScaleTo(Vector2.One, 200, EasingTypes.Out); - osuLogo.MoveTo(buttonFlow.Position, 200, EasingTypes.In); + osuLogo.MoveTo(buttonFlow.DrawPosition, 200, EasingTypes.In); osuLogo.ScaleTo(0.5f, 200, EasingTypes.In); buttonArea.FadeIn(300); diff --git a/osu.Game/GameModes/Menu/FlowContainerWithOrigin.cs b/osu.Game/GameModes/Menu/FlowContainerWithOrigin.cs index 890a1948a3..d59c291d14 100644 --- a/osu.Game/GameModes/Menu/FlowContainerWithOrigin.cs +++ b/osu.Game/GameModes/Menu/FlowContainerWithOrigin.cs @@ -24,7 +24,7 @@ namespace osu.Game.GameModes.Menu if (CentreTarget == null) return base.OriginPosition; - return CentreTarget.Position + CentreTarget.Size / 2; + return CentreTarget.DrawPosition + CentreTarget.DrawSize / 2; } } } diff --git a/osu.Game/GameModes/Menu/OsuLogo.cs b/osu.Game/GameModes/Menu/OsuLogo.cs index 6e85fe34f9..cccc8b495c 100644 --- a/osu.Game/GameModes/Menu/OsuLogo.cs +++ b/osu.Game/GameModes/Menu/OsuLogo.cs @@ -24,7 +24,7 @@ namespace osu.Game.GameModes.Menu public Action Action; - public float SizeForFlow => logo == null ? 0 : logo.Size.X * logo.Scale.X * logoBounceContainer.Scale.X * 0.8f; + public float SizeForFlow => logo == null ? 0 : logo.DrawSize.X * logo.Scale.X * logoBounceContainer.Scale.X * 0.8f; private Sprite ripple; diff --git a/osu.Game/Graphics/Background/Background.cs b/osu.Game/Graphics/Background/Background.cs index a0bb99f589..0624734363 100644 --- a/osu.Game/Graphics/Background/Background.cs +++ b/osu.Game/Graphics/Background/Background.cs @@ -41,7 +41,7 @@ namespace osu.Game.Graphics.Background protected override void Update() { base.Update(); - BackgroundSprite.Scale = new Vector2(Math.Max(Size.X / BackgroundSprite.Size.X, Size.Y / BackgroundSprite.Size.Y)); + BackgroundSprite.Scale = new Vector2(Math.Max(DrawSize.X / BackgroundSprite.DrawSize.X, DrawSize.Y / BackgroundSprite.DrawSize.Y)); } } } diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index 129997e663..ad5a0a559c 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -34,7 +34,7 @@ namespace osu.Game.Graphics.Containers protected override bool OnMouseMove(InputState state) { - content.Position = (state.Mouse.Position - Size / 2) * ParallaxAmount; + content.Position = (state.Mouse.Position - DrawSize / 2) * ParallaxAmount; return base.OnMouseMove(state); } diff --git a/osu.Game/Graphics/Processing/RatioAdjust.cs b/osu.Game/Graphics/Processing/RatioAdjust.cs index 9c74f0fc66..e9804f7418 100644 --- a/osu.Game/Graphics/Processing/RatioAdjust.cs +++ b/osu.Game/Graphics/Processing/RatioAdjust.cs @@ -20,7 +20,7 @@ namespace osu.Game.Graphics.Processing protected override void Update() { base.Update(); - Vector2 parent = Parent.Size; + Vector2 parent = Parent.DrawSize; Scale = new Vector2(Math.Min(parent.Y / 768f, parent.X / 1024f)); Size = new Vector2(1 / Scale.X); diff --git a/osu.Game/Graphics/UserInterface/KeyCounter.cs b/osu.Game/Graphics/UserInterface/KeyCounter.cs index 5f48de699b..0c65740354 100644 --- a/osu.Game/Graphics/UserInterface/KeyCounter.cs +++ b/osu.Game/Graphics/UserInterface/KeyCounter.cs @@ -107,8 +107,8 @@ namespace osu.Game.Graphics.UserInterface }; //Set this manually because an element with Alpha=0 won't take it size to AutoSizeContainer, //so the size can be changing between buttonSprite and glowSprite. - Height = buttonSprite.Height; - Width = buttonSprite.Width; + Height = buttonSprite.DrawHeight; + Width = buttonSprite.DrawWidth; } private void updateGlowSprite(bool show) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 684cc42d5a..7a77ef5b0a 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -74,7 +74,7 @@ namespace osu.Game { try { - Beatmaps.AddBeatmap(message.Path); + Beatmaps.ImportBeatmap(message.Path); // TODO: Switch to beatmap list and select the new song } catch (Exception ex) diff --git a/osu.Game/Overlays/ChatConsole.cs b/osu.Game/Overlays/ChatConsole.cs index ed52ddef24..37a8bec860 100644 --- a/osu.Game/Overlays/ChatConsole.cs +++ b/osu.Game/Overlays/ChatConsole.cs @@ -144,7 +144,7 @@ namespace osu.Game.Overlays protected override void PopOut() { - MoveToY(-Size.Y, transition_length, EasingTypes.InQuint); + MoveToY(-DrawSize.Y, transition_length, EasingTypes.InQuint); FadeOut(transition_length, EasingTypes.InQuint); } } diff --git a/osu.Game/Overlays/Toolbar.cs b/osu.Game/Overlays/Toolbar.cs index e33f55e154..f771257cec 100644 --- a/osu.Game/Overlays/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar.cs @@ -35,7 +35,7 @@ namespace osu.Game.Overlays protected override void PopOut() { - MoveToY(-Size.Y, transition_time, EasingTypes.InQuint); + MoveToY(-DrawSize.Y, transition_time, EasingTypes.InQuint); FadeOut(transition_time, EasingTypes.InQuint); } diff --git a/osu.Game/Overlays/ToolbarButton.cs b/osu.Game/Overlays/ToolbarButton.cs index 3d74f7724e..41eb7a3d20 100644 --- a/osu.Game/Overlays/ToolbarButton.cs +++ b/osu.Game/Overlays/ToolbarButton.cs @@ -121,7 +121,7 @@ namespace osu.Game.Overlays base.Update(); //todo: find a way to avoid using this (autosize needs to be able to ignore certain drawables.. in this case the tooltip) - Size = new Vector2(WIDTH + (DrawableText.IsVisible ? DrawableText.Size.X : 0), 1); + Size = new Vector2(WIDTH + (DrawableText.IsVisible ? DrawableText.DrawSize.X : 0), 1); } protected override bool OnClick(InputState state) diff --git a/osu.Game/Overlays/ToolbarModeSelector.cs b/osu.Game/Overlays/ToolbarModeSelector.cs index 7f82ab3e90..77ed4ecca7 100644 --- a/osu.Game/Overlays/ToolbarModeSelector.cs +++ b/osu.Game/Overlays/ToolbarModeSelector.cs @@ -96,7 +96,7 @@ namespace osu.Game.Overlays base.UpdateLayout(); if (!activeMode.EnsureValid()) - activeMode.Refresh(() => modeButtonLine.MoveToX(activeButton.Position.X + activeButton.Size.X / 2 + padding, 200, EasingTypes.OutQuint)); + activeMode.Refresh(() => modeButtonLine.MoveToX(activeButton.DrawPosition.X + activeButton.DrawSize.X / 2 + padding, 200, EasingTypes.OutQuint)); } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 05e73fc4f1..8f029070ca 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -43,26 +43,24 @@ - - $(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 + + $(SolutionDir)\packages\SQLite.Net-PCL.3.0.5\lib\net4\SQLite.Net.Platform.Win32.dll + + + $(SolutionDir)\packages\SQLite.Net-PCL.3.0.5\lib\net40\SQLite.Net.dll + + + $(SolutionDir)\packages\SQLite.Net-PCL.3.0.5\lib\net40\SQLite.Net.Platform.Generic.dll + + + $(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll + - - @@ -168,9 +166,12 @@ - + + + + @@ -198,7 +199,4 @@ --> - - - - \ No newline at end of file + diff --git a/osu.Game/packages.config b/osu.Game/packages.config index 1f14b0038d..988b02e510 100644 --- a/osu.Game/packages.config +++ b/osu.Game/packages.config @@ -7,11 +7,6 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste - - - - - - - + +