mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 13:37:25 +08:00
Split out BeatmapDatabase into BeatmapStore
Hide database functionality at a lower level in preparation from eventually making it private.
This commit is contained in:
parent
fce580d717
commit
9e20a02c0a
@ -5,7 +5,8 @@ using System.Collections.Generic;
|
||||
using osu.Desktop.VisualTests.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
|
||||
@ -13,7 +14,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
internal class TestCasePlaySongSelect : TestCase
|
||||
{
|
||||
private readonly BeatmapStore db;
|
||||
private readonly BeatmapStore store;
|
||||
|
||||
public override string Description => @"with fake data";
|
||||
|
||||
@ -23,21 +24,21 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
PlaySongSelect songSelect;
|
||||
|
||||
if (db == null)
|
||||
if (store == null)
|
||||
{
|
||||
var storage = new TestStorage(@"TestCasePlaySongSelect");
|
||||
|
||||
var backingDatabase = storage.GetDatabase(@"client");
|
||||
|
||||
rulesets = new RulesetDatabase(storage, backingDatabase);
|
||||
db = new BeatmapStore(storage, backingDatabase, rulesets);
|
||||
rulesets = new RulesetDatabase(backingDatabase);
|
||||
store = new BeatmapStore(storage, backingDatabase, rulesets);
|
||||
|
||||
var sets = new List<BeatmapSetInfo>();
|
||||
|
||||
for (int i = 0; i < 100; i += 10)
|
||||
sets.Add(createTestBeatmapSet(i));
|
||||
|
||||
db.Import(sets);
|
||||
store.Database.Import(sets);
|
||||
}
|
||||
|
||||
Add(songSelect = new PlaySongSelect());
|
||||
@ -48,21 +49,12 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
|
||||
}
|
||||
|
||||
//protected override void Dispose(bool isDisposing)
|
||||
//{
|
||||
// if (oldDb != null)
|
||||
// db = null;
|
||||
|
||||
// base.Dispose(isDisposing);
|
||||
//}
|
||||
|
||||
private BeatmapSetInfo createTestBeatmapSet(int i)
|
||||
{
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 1234 + i,
|
||||
Hash = "d8e8fca2dc0f896fd7cb4cb0031ba249",
|
||||
Path = string.Empty,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
OnlineBeatmapSetID = 1234 + i,
|
||||
|
@ -15,12 +15,12 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
internal class TestCaseResults : TestCase
|
||||
{
|
||||
private BeatmapDatabase db;
|
||||
private BeatmapStore db;
|
||||
|
||||
public override string Description => @"Results after playing.";
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(BeatmapDatabase db)
|
||||
private void load(BeatmapStore db)
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
@ -33,7 +33,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
|
||||
if (beatmap == null)
|
||||
{
|
||||
var beatmapInfo = db.Query<BeatmapInfo>().FirstOrDefault(b => b.RulesetID == 0);
|
||||
var beatmapInfo = db.Database.Query<BeatmapInfo>().FirstOrDefault(b => b.RulesetID == 0);
|
||||
if (beatmapInfo != null)
|
||||
beatmap = db.GetWorkingBeatmap(beatmapInfo);
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ namespace osu.Desktop
|
||||
var filePaths = dropData.Select(f => f.ToString()).ToArray();
|
||||
|
||||
if (filePaths.All(f => Path.GetExtension(f) == @".osz"))
|
||||
Task.Run(() => BeatmapDatabase.Import(filePaths));
|
||||
Task.Run(() => BeatmapStore.Import(filePaths));
|
||||
else if (filePaths.All(f => Path.GetExtension(f) == @".osr"))
|
||||
Task.Run(() =>
|
||||
{
|
||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
Assert.IsTrue(File.Exists(temp));
|
||||
|
||||
osu.Dependencies.Get<BeatmapDatabase>().Import(temp);
|
||||
osu.Dependencies.Get<BeatmapStore>().Import(temp);
|
||||
|
||||
ensureLoaded(osu);
|
||||
|
||||
@ -80,7 +80,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
Assert.IsTrue(File.Exists(temp), "Temporary file copy never substantiated");
|
||||
|
||||
using (File.OpenRead(temp))
|
||||
osu.Dependencies.Get<BeatmapDatabase>().Import(temp);
|
||||
osu.Dependencies.Get<BeatmapStore>().Import(temp);
|
||||
|
||||
ensureLoaded(osu);
|
||||
|
||||
@ -106,7 +106,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
//reset beatmap database (sqlite and storage backing)
|
||||
osu.Dependencies.Get<RulesetDatabase>().Reset();
|
||||
osu.Dependencies.Get<BeatmapDatabase>().Reset();
|
||||
osu.Dependencies.Get<BeatmapStore>().Reset();
|
||||
|
||||
return osu;
|
||||
}
|
||||
@ -117,8 +117,8 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
Action waitAction = () =>
|
||||
{
|
||||
while (!(resultSets = osu.Dependencies.Get<BeatmapDatabase>()
|
||||
.Query<BeatmapSetInfo>().Where(s => s.OnlineBeatmapSetID == 241526)).Any())
|
||||
while (!(resultSets = osu.Dependencies.Get<BeatmapStore>().Database.
|
||||
Query<BeatmapSetInfo>().Where(s => s.OnlineBeatmapSetID == 241526)).Any())
|
||||
Thread.Sleep(50);
|
||||
};
|
||||
|
||||
@ -134,15 +134,15 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
//if we don't re-check here, the set will be inserted but the beatmaps won't be present yet.
|
||||
waitAction = () =>
|
||||
{
|
||||
while ((resultBeatmaps = osu.Dependencies.Get<BeatmapDatabase>()
|
||||
.GetAllWithChildren<BeatmapInfo>(s => s.OnlineBeatmapSetID == 241526 && s.BaseDifficultyID > 0)).Count() != 12)
|
||||
while ((resultBeatmaps = osu.Dependencies.Get<BeatmapStore>().Database.
|
||||
GetAllWithChildren<BeatmapInfo>(s => s.OnlineBeatmapSetID == 241526 && s.BaseDifficultyID > 0)).Count() != 12)
|
||||
Thread.Sleep(50);
|
||||
};
|
||||
|
||||
Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(timeout),
|
||||
@"Beatmaps did not import to the database in allocated time");
|
||||
|
||||
var set = osu.Dependencies.Get<BeatmapDatabase>().GetChildren(resultSets.First());
|
||||
var set = osu.Dependencies.Get<BeatmapStore>().Database.GetChildren(resultSets.First());
|
||||
|
||||
Assert.IsTrue(set.Beatmaps.Count == resultBeatmaps.Count(),
|
||||
$@"Incorrect database beatmap count post-import ({resultBeatmaps.Count()} but should be {set.Beatmaps.Count}).");
|
||||
@ -152,16 +152,16 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
Assert.IsTrue(set.Beatmaps.Count > 0);
|
||||
|
||||
var beatmap = osu.Dependencies.Get<BeatmapDatabase>().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap;
|
||||
var beatmap = osu.Dependencies.Get<BeatmapStore>().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap;
|
||||
Assert.IsTrue(beatmap?.HitObjects.Count > 0);
|
||||
|
||||
beatmap = osu.Dependencies.Get<BeatmapDatabase>().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 1))?.Beatmap;
|
||||
beatmap = osu.Dependencies.Get<BeatmapStore>().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 1))?.Beatmap;
|
||||
Assert.IsTrue(beatmap?.HitObjects.Count > 0);
|
||||
|
||||
beatmap = osu.Dependencies.Get<BeatmapDatabase>().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 2))?.Beatmap;
|
||||
beatmap = osu.Dependencies.Get<BeatmapStore>().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 2))?.Beatmap;
|
||||
Assert.IsTrue(beatmap?.HitObjects.Count > 0);
|
||||
|
||||
beatmap = osu.Dependencies.Get<BeatmapDatabase>().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap;
|
||||
beatmap = osu.Dependencies.Get<BeatmapStore>().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap;
|
||||
Assert.IsTrue(beatmap?.HitObjects.Count > 0);
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,77 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.Beatmaps.IO;
|
||||
using osu.Game.IPC;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Screens.Menu;
|
||||
using SQLite.Net;
|
||||
using SQLiteNetExtensions.Extensions;
|
||||
|
||||
namespace osu.Game.Database
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public class BeatmapStore : DatabaseBacking
|
||||
/// <summary>
|
||||
/// Handles the storage and retrieval of Beatmaps/BeatmapSets to the database backing
|
||||
/// </summary>
|
||||
public class BeatmapDatabase : DatabaseStore
|
||||
{
|
||||
private readonly RulesetDatabase rulesets;
|
||||
|
||||
public event Action<BeatmapSetInfo> BeatmapSetAdded;
|
||||
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
|
||||
|
||||
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
|
||||
private BeatmapIPCChannel ipc;
|
||||
|
||||
/// <summary>
|
||||
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
||||
/// </summary>
|
||||
public WorkingBeatmap DefaultBeatmap { private get; set; }
|
||||
|
||||
public BeatmapStore(Storage storage, SQLiteConnection connection, RulesetDatabase rulesets, IIpcHost importHost = null) : base(storage, connection)
|
||||
public BeatmapDatabase(SQLiteConnection connection) : base(connection)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
if (importHost != null)
|
||||
ipc = new BeatmapIPCChannel(importHost, this);
|
||||
}
|
||||
|
||||
protected override Type[] ValidTypes => new[] {
|
||||
typeof(BeatmapSetInfo),
|
||||
typeof(BeatmapInfo),
|
||||
typeof(BeatmapMetadata),
|
||||
typeof(BeatmapDifficulty),
|
||||
};
|
||||
|
||||
protected override void Prepare(bool reset = false)
|
||||
{
|
||||
Connection.CreateTable<BeatmapMetadata>();
|
||||
Connection.CreateTable<BeatmapDifficulty>();
|
||||
Connection.CreateTable<BeatmapSetInfo>();
|
||||
Connection.CreateTable<BeatmapInfo>();
|
||||
|
||||
if (reset)
|
||||
{
|
||||
Connection.DropTable<BeatmapMetadata>();
|
||||
Connection.DropTable<BeatmapDifficulty>();
|
||||
Connection.DropTable<BeatmapSetInfo>();
|
||||
Connection.DropTable<BeatmapInfo>();
|
||||
}
|
||||
|
||||
deletePending();
|
||||
}
|
||||
|
||||
public void Import(IEnumerable<BeatmapSetInfo> beatmapSets)
|
||||
{
|
||||
lock (Connection)
|
||||
{
|
||||
Connection.BeginTransaction();
|
||||
|
||||
foreach (var s in beatmapSets)
|
||||
{
|
||||
Connection.InsertOrReplaceWithChildren(s, true);
|
||||
BeatmapSetAdded?.Invoke(s);
|
||||
}
|
||||
|
||||
Connection.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete(IEnumerable<BeatmapSetInfo> beatmapSets)
|
||||
{
|
||||
foreach (var s in beatmapSets)
|
||||
{
|
||||
s.DeletePending = true;
|
||||
Update(s, false);
|
||||
BeatmapSetRemoved?.Invoke(s);
|
||||
}
|
||||
}
|
||||
|
||||
private void deletePending()
|
||||
@ -50,8 +84,6 @@ namespace osu.Game.Database
|
||||
|
||||
try
|
||||
{
|
||||
Storage.Delete(b.Path);
|
||||
|
||||
foreach (var i in b.Beatmaps)
|
||||
{
|
||||
if (i.Metadata != null) Connection.Delete(i.Metadata);
|
||||
@ -73,231 +105,5 @@ namespace osu.Game.Database
|
||||
//see https://github.com/praeclarum/sqlite-net/issues/326
|
||||
Connection.Query<BeatmapSetInfo>("UPDATE BeatmapSetInfo SET DeletePending = 0 WHERE DeletePending IS NULL");
|
||||
}
|
||||
|
||||
protected override void Prepare(bool reset = false)
|
||||
{
|
||||
Connection.CreateTable<BeatmapMetadata>();
|
||||
Connection.CreateTable<BeatmapDifficulty>();
|
||||
Connection.CreateTable<BeatmapSetInfo>();
|
||||
Connection.CreateTable<BeatmapInfo>();
|
||||
|
||||
if (reset)
|
||||
{
|
||||
Storage.DeleteDatabase(@"beatmaps");
|
||||
|
||||
foreach (var setInfo in Query<BeatmapSetInfo>())
|
||||
{
|
||||
if (Storage.Exists(setInfo.Path))
|
||||
Storage.Delete(setInfo.Path);
|
||||
}
|
||||
|
||||
Connection.DeleteAll<BeatmapMetadata>();
|
||||
Connection.DeleteAll<BeatmapDifficulty>();
|
||||
Connection.DeleteAll<BeatmapSetInfo>();
|
||||
Connection.DeleteAll<BeatmapInfo>();
|
||||
}
|
||||
|
||||
deletePending();
|
||||
}
|
||||
|
||||
protected override Type[] ValidTypes => new[] {
|
||||
typeof(BeatmapSetInfo),
|
||||
typeof(BeatmapInfo),
|
||||
typeof(BeatmapMetadata),
|
||||
typeof(BeatmapDifficulty),
|
||||
};
|
||||
|
||||
public void Import(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
Import(ArchiveReader.GetReader(Storage, path));
|
||||
|
||||
// We may or may not want to delete the file depending on where it is stored.
|
||||
// e.g. reconstructing/repairing database with beatmaps from default storage.
|
||||
// Also, not always a single file, i.e. for LegacyFilesystemReader
|
||||
// TODO: Add a check to prevent files from storage to be deleted.
|
||||
try
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, $@"Could not delete file at {path}");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e = e.InnerException ?? e;
|
||||
Logger.Error(e, @"Could not import beatmap set");
|
||||
}
|
||||
}
|
||||
|
||||
public void Import(ArchiveReader archiveReader)
|
||||
{
|
||||
BeatmapSetInfo set = getBeatmapSet(archiveReader);
|
||||
|
||||
//If we have an ID then we already exist in the database.
|
||||
if (set.ID == 0)
|
||||
Import(new[] { set });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Import multiple <see cref="BeatmapSetInfo"/> from <paramref name="paths"/>.
|
||||
/// </summary>
|
||||
/// <param name="paths">Multiple locations on disk</param>
|
||||
public void Import(params string[] paths)
|
||||
{
|
||||
foreach (string p in paths)
|
||||
{
|
||||
//In case the file was imported twice and deleted after the first time
|
||||
if (File.Exists(p))
|
||||
Import(p);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Duplicates content from <paramref name="path"/> to storage and returns a representing <see cref="BeatmapSetInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="path">Content location</param>
|
||||
/// <returns><see cref="BeatmapSetInfo"/></returns>
|
||||
private BeatmapSetInfo getBeatmapSet(string path) => getBeatmapSet(ArchiveReader.GetReader(Storage, path));
|
||||
|
||||
private BeatmapSetInfo getBeatmapSet(ArchiveReader archiveReader)
|
||||
{
|
||||
BeatmapMetadata metadata;
|
||||
|
||||
using (var stream = new StreamReader(archiveReader.GetStream(archiveReader.BeatmapFilenames[0])))
|
||||
metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata;
|
||||
|
||||
string hash;
|
||||
string path;
|
||||
|
||||
using (var input = archiveReader.GetUnderlyingStream())
|
||||
{
|
||||
hash = input.GetMd5Hash();
|
||||
input.Seek(0, SeekOrigin.Begin);
|
||||
path = Path.Combine(@"beatmaps", hash.Remove(1), hash.Remove(2), hash);
|
||||
if (!Storage.Exists(path))
|
||||
using (var output = Storage.GetStream(path, FileAccess.Write))
|
||||
input.CopyTo(output);
|
||||
}
|
||||
|
||||
var existing = Connection.Table<BeatmapSetInfo>().FirstOrDefault(b => b.Hash == hash);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
GetChildren(existing);
|
||||
|
||||
if (existing.DeletePending)
|
||||
{
|
||||
existing.DeletePending = false;
|
||||
Update(existing, false);
|
||||
BeatmapSetAdded?.Invoke(existing);
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
|
||||
var beatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = metadata.OnlineBeatmapSetID,
|
||||
Beatmaps = new List<BeatmapInfo>(),
|
||||
Path = path,
|
||||
Hash = hash,
|
||||
Metadata = metadata
|
||||
};
|
||||
|
||||
using (var archive = ArchiveReader.GetReader(Storage, path))
|
||||
{
|
||||
string[] mapNames = archive.BeatmapFilenames;
|
||||
foreach (var name in mapNames)
|
||||
using (var raw = archive.GetStream(name))
|
||||
using (var ms = new MemoryStream()) //we need a memory stream so we can seek and shit
|
||||
using (var sr = new StreamReader(ms))
|
||||
{
|
||||
raw.CopyTo(ms);
|
||||
ms.Position = 0;
|
||||
|
||||
var decoder = BeatmapDecoder.GetDecoder(sr);
|
||||
Beatmap beatmap = decoder.Decode(sr);
|
||||
|
||||
beatmap.BeatmapInfo.Path = name;
|
||||
beatmap.BeatmapInfo.Hash = ms.GetMd5Hash();
|
||||
|
||||
// TODO: Diff beatmap metadata with set metadata and leave it here if necessary
|
||||
beatmap.BeatmapInfo.Metadata = null;
|
||||
|
||||
// TODO: this should be done in a better place once we actually need to dynamically update it.
|
||||
beatmap.BeatmapInfo.Ruleset = rulesets.Query<RulesetInfo>().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID);
|
||||
beatmap.BeatmapInfo.StarDifficulty = rulesets.Query<RulesetInfo>().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID)?.CreateInstance()?.CreateDifficultyCalculator(beatmap).Calculate() ?? 0;
|
||||
|
||||
beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo);
|
||||
}
|
||||
beatmapSet.StoryboardFile = archive.StoryboardFilename;
|
||||
}
|
||||
|
||||
return beatmapSet;
|
||||
}
|
||||
|
||||
public void Import(IEnumerable<BeatmapSetInfo> beatmapSets)
|
||||
{
|
||||
lock (Connection)
|
||||
{
|
||||
Connection.BeginTransaction();
|
||||
|
||||
foreach (var s in beatmapSets)
|
||||
{
|
||||
Connection.InsertOrReplaceWithChildren(s, true);
|
||||
BeatmapSetAdded?.Invoke(s);
|
||||
}
|
||||
|
||||
Connection.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete(BeatmapSetInfo beatmapSet)
|
||||
{
|
||||
beatmapSet.DeletePending = true;
|
||||
Update(beatmapSet, false);
|
||||
|
||||
BeatmapSetRemoved?.Invoke(beatmapSet);
|
||||
}
|
||||
|
||||
public ArchiveReader GetReader(BeatmapSetInfo beatmapSet)
|
||||
{
|
||||
if (string.IsNullOrEmpty(beatmapSet.Path))
|
||||
return null;
|
||||
|
||||
return ArchiveReader.GetReader(Storage, beatmapSet.Path);
|
||||
}
|
||||
|
||||
public BeatmapSetInfo GetBeatmapSet(int id)
|
||||
{
|
||||
return Query<BeatmapSetInfo>().FirstOrDefault(s => s.OnlineBeatmapSetID == id);
|
||||
}
|
||||
|
||||
public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null, bool withStoryboard = false)
|
||||
{
|
||||
if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo)
|
||||
return DefaultBeatmap;
|
||||
|
||||
if (beatmapInfo.BeatmapSet == null || beatmapInfo.Ruleset == null)
|
||||
beatmapInfo = GetChildren(beatmapInfo, true);
|
||||
|
||||
if (beatmapInfo.BeatmapSet == null)
|
||||
throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoID} is not in the local database.");
|
||||
|
||||
if (beatmapInfo.Metadata == null)
|
||||
beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata;
|
||||
|
||||
WorkingBeatmap working = new BeatmapStoreWorkingBeatmap(this, beatmapInfo);
|
||||
|
||||
previous?.TransferTo(working);
|
||||
|
||||
return working;
|
||||
}
|
||||
|
||||
public bool Exists(BeatmapSetInfo beatmapSet) => Storage.Exists(beatmapSet.Path);
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.IO;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.Beatmaps.IO;
|
||||
|
||||
namespace osu.Game.Database
|
||||
{
|
||||
internal class BeatmapDatabaseWorkingBeatmap : WorkingBeatmap
|
||||
{
|
||||
private readonly BeatmapStore store;
|
||||
|
||||
public BeatmapDatabaseWorkingBeatmap(BeatmapStore store, BeatmapInfo beatmapInfo)
|
||||
: base(beatmapInfo)
|
||||
{
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
private ArchiveReader getReader() => store?.GetReader(BeatmapSetInfo);
|
||||
|
||||
protected override Beatmap GetBeatmap()
|
||||
{
|
||||
try
|
||||
{
|
||||
Beatmap beatmap;
|
||||
|
||||
using (var reader = getReader())
|
||||
{
|
||||
BeatmapDecoder decoder;
|
||||
using (var stream = new StreamReader(reader.GetStream(BeatmapInfo.Path)))
|
||||
{
|
||||
decoder = BeatmapDecoder.GetDecoder(stream);
|
||||
beatmap = decoder.Decode(stream);
|
||||
}
|
||||
|
||||
if (beatmap == null || BeatmapSetInfo.StoryboardFile == null)
|
||||
return beatmap;
|
||||
|
||||
using (var stream = new StreamReader(reader.GetStream(BeatmapSetInfo.StoryboardFile)))
|
||||
decoder.Decode(stream, beatmap);
|
||||
}
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
protected override Texture GetBackground()
|
||||
{
|
||||
if (Metadata?.BackgroundFile == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
using (var reader = getReader())
|
||||
return new TextureStore(new RawTextureLoaderStore(reader), false).Get(Metadata.BackgroundFile);
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
protected override Track GetTrack()
|
||||
{
|
||||
try
|
||||
{
|
||||
var trackData = getReader()?.GetStream(Metadata.AudioFile);
|
||||
return trackData == null ? null : new TrackBass(trackData);
|
||||
}
|
||||
catch { return new TrackVirtual(); }
|
||||
}
|
||||
}
|
||||
}
|
212
osu.Game/Beatmaps/BeatmapStore.cs
Normal file
212
osu.Game/Beatmaps/BeatmapStore.cs
Normal file
@ -0,0 +1,212 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.Beatmaps.IO;
|
||||
using osu.Game.IPC;
|
||||
using osu.Game.Rulesets;
|
||||
using SQLite.Net;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles the storage and retrieval of Beatmaps/WorkingBeatmaps.
|
||||
/// </summary>
|
||||
public class BeatmapStore
|
||||
{
|
||||
// todo: make this private
|
||||
public readonly BeatmapDatabase Database;
|
||||
|
||||
private readonly Storage storage;
|
||||
|
||||
private readonly RulesetDatabase rulesets;
|
||||
|
||||
public event Action<BeatmapSetInfo> BeatmapSetAdded;
|
||||
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
|
||||
|
||||
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
|
||||
private BeatmapIPCChannel ipc;
|
||||
|
||||
/// <summary>
|
||||
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
||||
/// </summary>
|
||||
public WorkingBeatmap DefaultBeatmap { private get; set; }
|
||||
|
||||
public BeatmapStore(Storage storage, SQLiteConnection connection, RulesetDatabase rulesets, IIpcHost importHost = null)
|
||||
{
|
||||
Database = new BeatmapDatabase(connection);
|
||||
Database.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s);
|
||||
Database.BeatmapSetRemoved += s => BeatmapSetRemoved?.Invoke(s);
|
||||
|
||||
this.storage = storage;
|
||||
this.rulesets = rulesets;
|
||||
if (importHost != null)
|
||||
ipc = new BeatmapIPCChannel(importHost, this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Import multiple <see cref="BeatmapSetInfo"/> from filesystem <paramref name="paths"/>.
|
||||
/// </summary>
|
||||
/// <param name="paths">Multiple locations on disk.</param>
|
||||
public void Import(params string[] paths)
|
||||
{
|
||||
foreach (string path in paths)
|
||||
{
|
||||
try
|
||||
{
|
||||
Import(ArchiveReader.GetReader(storage, path));
|
||||
|
||||
// We may or may not want to delete the file depending on where it is stored.
|
||||
// e.g. reconstructing/repairing database with beatmaps from default storage.
|
||||
// Also, not always a single file, i.e. for LegacyFilesystemReader
|
||||
// TODO: Add a check to prevent files from storage to be deleted.
|
||||
try
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, $@"Could not delete file at {path}");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e = e.InnerException ?? e;
|
||||
Logger.Error(e, @"Could not import beatmap set");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Import a beatmap from an <see cref="ArchiveReader"/>.
|
||||
/// </summary>
|
||||
/// <param name="archiveReader">The beatmap to be imported.</param>
|
||||
public void Import(ArchiveReader archiveReader)
|
||||
{
|
||||
BeatmapSetInfo set = importToStorage(archiveReader);
|
||||
|
||||
//If we have an ID then we already exist in the database.
|
||||
if (set.ID == 0)
|
||||
Database.Import(new[] { set });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete a beatmap from the store.
|
||||
/// </summary>
|
||||
/// <param name="beatmapSet">The beatmap to delete.</param>
|
||||
public void Delete(BeatmapSetInfo beatmapSet) => Database.Delete(new[] { beatmapSet });
|
||||
|
||||
public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null)
|
||||
{
|
||||
if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo)
|
||||
return DefaultBeatmap;
|
||||
|
||||
if (beatmapInfo.BeatmapSet == null || beatmapInfo.Ruleset == null)
|
||||
beatmapInfo = Database.GetChildren(beatmapInfo, true);
|
||||
|
||||
if (beatmapInfo.BeatmapSet == null)
|
||||
throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoID} is not in the local database.");
|
||||
|
||||
if (beatmapInfo.Metadata == null)
|
||||
beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata;
|
||||
|
||||
WorkingBeatmap working = new BeatmapStoreWorkingBeatmap(() => string.IsNullOrEmpty(beatmapInfo.BeatmapSet.Path) ? null : ArchiveReader.GetReader(storage, beatmapInfo.BeatmapSet.Path), beatmapInfo);
|
||||
|
||||
previous?.TransferTo(working);
|
||||
|
||||
return working;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the store to an empty state.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
Database.Reset();
|
||||
}
|
||||
|
||||
private BeatmapSetInfo importToStorage(ArchiveReader archiveReader)
|
||||
{
|
||||
BeatmapMetadata metadata;
|
||||
|
||||
using (var stream = new StreamReader(archiveReader.GetStream(archiveReader.BeatmapFilenames[0])))
|
||||
metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata;
|
||||
|
||||
string hash;
|
||||
string path;
|
||||
|
||||
using (var input = archiveReader.GetUnderlyingStream())
|
||||
{
|
||||
hash = input.GetMd5Hash();
|
||||
input.Seek(0, SeekOrigin.Begin);
|
||||
path = Path.Combine(@"beatmaps", hash.Remove(1), hash.Remove(2), hash);
|
||||
if (!storage.Exists(path))
|
||||
using (var output = storage.GetStream(path, FileAccess.Write))
|
||||
input.CopyTo(output);
|
||||
}
|
||||
|
||||
var existing = Database.Query<BeatmapSetInfo>().FirstOrDefault(b => b.Hash == hash);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
Database.GetChildren(existing);
|
||||
|
||||
if (existing.DeletePending)
|
||||
{
|
||||
existing.DeletePending = false;
|
||||
Database.Update(existing, false);
|
||||
BeatmapSetAdded?.Invoke(existing);
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
|
||||
var beatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = metadata.OnlineBeatmapSetID,
|
||||
Beatmaps = new List<BeatmapInfo>(),
|
||||
Path = path,
|
||||
Hash = hash,
|
||||
Metadata = metadata
|
||||
};
|
||||
|
||||
using (var archive = ArchiveReader.GetReader(storage, path))
|
||||
{
|
||||
string[] mapNames = archive.BeatmapFilenames;
|
||||
foreach (var name in mapNames)
|
||||
using (var raw = archive.GetStream(name))
|
||||
using (var ms = new MemoryStream()) //we need a memory stream so we can seek and shit
|
||||
using (var sr = new StreamReader(ms))
|
||||
{
|
||||
raw.CopyTo(ms);
|
||||
ms.Position = 0;
|
||||
|
||||
var decoder = BeatmapDecoder.GetDecoder(sr);
|
||||
Beatmap beatmap = decoder.Decode(sr);
|
||||
|
||||
beatmap.BeatmapInfo.Path = name;
|
||||
beatmap.BeatmapInfo.Hash = ms.GetMd5Hash();
|
||||
|
||||
// TODO: Diff beatmap metadata with set metadata and leave it here if necessary
|
||||
beatmap.BeatmapInfo.Metadata = null;
|
||||
|
||||
// TODO: this should be done in a better place once we actually need to dynamically update it.
|
||||
beatmap.BeatmapInfo.Ruleset = rulesets.Query<RulesetInfo>().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID);
|
||||
beatmap.BeatmapInfo.StarDifficulty = rulesets.Query<RulesetInfo>().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID)?.CreateInstance()?.CreateDifficultyCalculator(beatmap).Calculate() ?? 0;
|
||||
|
||||
beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo);
|
||||
}
|
||||
beatmapSet.StoryboardFile = archive.StoryboardFilename;
|
||||
}
|
||||
|
||||
return beatmapSet;
|
||||
}
|
||||
}
|
||||
}
|
70
osu.Game/Beatmaps/BeatmapStoreWorkingBeatmap.cs
Normal file
70
osu.Game/Beatmaps/BeatmapStoreWorkingBeatmap.cs
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
internal class BeatmapStoreWorkingBeatmap : WorkingBeatmap
|
||||
{
|
||||
private readonly Func<IResourceStore<byte[]>> getStore;
|
||||
|
||||
public BeatmapStoreWorkingBeatmap(Func<IResourceStore<byte[]>> getStore, BeatmapInfo beatmapInfo)
|
||||
: base(beatmapInfo)
|
||||
{
|
||||
this.getStore = getStore;
|
||||
}
|
||||
|
||||
protected override Beatmap GetBeatmap()
|
||||
{
|
||||
try
|
||||
{
|
||||
Beatmap beatmap;
|
||||
|
||||
BeatmapDecoder decoder;
|
||||
using (var stream = new StreamReader(getStore().GetStream(BeatmapInfo.Path)))
|
||||
{
|
||||
decoder = BeatmapDecoder.GetDecoder(stream);
|
||||
beatmap = decoder.Decode(stream);
|
||||
}
|
||||
|
||||
if (beatmap == null || BeatmapSetInfo.StoryboardFile == null)
|
||||
return beatmap;
|
||||
|
||||
using (var stream = new StreamReader(getStore().GetStream(BeatmapSetInfo.StoryboardFile)))
|
||||
decoder.Decode(stream, beatmap);
|
||||
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
protected override Texture GetBackground()
|
||||
{
|
||||
if (Metadata?.BackgroundFile == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
return new TextureStore(new RawTextureLoaderStore(getStore()), false).Get(Metadata.BackgroundFile);
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
protected override Track GetTrack()
|
||||
{
|
||||
try
|
||||
{
|
||||
var trackData = getStore().GetStream(Metadata.AudioFile);
|
||||
return trackData == null ? null : new TrackBass(trackData);
|
||||
}
|
||||
catch { return new TrackVirtual(); }
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
@ -59,10 +58,10 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
public BeatmapGroup(BeatmapSetInfo beatmapSet, BeatmapDatabase database)
|
||||
public BeatmapGroup(BeatmapSetInfo beatmapSet, BeatmapStore store)
|
||||
{
|
||||
BeatmapSet = beatmapSet;
|
||||
WorkingBeatmap beatmap = database.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault());
|
||||
WorkingBeatmap beatmap = store.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault());
|
||||
|
||||
Header = new BeatmapSetHeader(beatmap)
|
||||
{
|
||||
|
@ -6,20 +6,17 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using SQLite.Net;
|
||||
using SQLiteNetExtensions.Extensions;
|
||||
|
||||
namespace osu.Game.Database
|
||||
{
|
||||
public abstract class DatabaseBacking
|
||||
public abstract class DatabaseStore
|
||||
{
|
||||
protected SQLiteConnection Connection { get; }
|
||||
protected Storage Storage { get; }
|
||||
|
||||
protected DatabaseBacking(Storage storage, SQLiteConnection connection)
|
||||
protected DatabaseStore(SQLiteConnection connection)
|
||||
{
|
||||
Storage = storage;
|
||||
Connection = connection;
|
||||
|
||||
try
|
@ -10,9 +10,9 @@ namespace osu.Game.IPC
|
||||
{
|
||||
public class BeatmapIPCChannel : IpcChannel<BeatmapImportMessage>
|
||||
{
|
||||
private readonly BeatmapDatabase beatmaps;
|
||||
private readonly BeatmapStore beatmaps;
|
||||
|
||||
public BeatmapIPCChannel(IIpcHost host, BeatmapDatabase beatmaps = null)
|
||||
public BeatmapIPCChannel(IIpcHost host, BeatmapStore beatmaps = null)
|
||||
: base(host)
|
||||
{
|
||||
this.beatmaps = beatmaps;
|
||||
|
@ -99,7 +99,7 @@ namespace osu.Game
|
||||
if (args?.Length > 0)
|
||||
{
|
||||
var paths = args.Where(a => !a.StartsWith(@"-"));
|
||||
Task.Run(() => BeatmapDatabase.Import(paths.ToArray()));
|
||||
Task.Run(() => BeatmapStore.Import(paths.ToArray()));
|
||||
}
|
||||
|
||||
dependencies.Cache(this);
|
||||
@ -140,7 +140,7 @@ namespace osu.Game
|
||||
return;
|
||||
}
|
||||
|
||||
Beatmap.Value = BeatmapDatabase.GetWorkingBeatmap(s.Beatmap);
|
||||
Beatmap.Value = BeatmapStore.GetWorkingBeatmap(s.Beatmap);
|
||||
|
||||
menu.Push(new PlayerLoader(new ReplayPlayer(s.Replay)));
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ namespace osu.Game
|
||||
{
|
||||
protected OsuConfigManager LocalConfig;
|
||||
|
||||
protected BeatmapDatabase BeatmapDatabase;
|
||||
protected BeatmapStore BeatmapStore;
|
||||
|
||||
protected RulesetDatabase RulesetDatabase;
|
||||
|
||||
@ -95,9 +95,9 @@ namespace osu.Game
|
||||
|
||||
SQLiteConnection connection = Host.Storage.GetDatabase(@"client");
|
||||
|
||||
dependencies.Cache(RulesetDatabase = new RulesetDatabase(Host.Storage, connection));
|
||||
dependencies.Cache(BeatmapDatabase = new BeatmapDatabase(Host.Storage, connection, RulesetDatabase, Host));
|
||||
dependencies.Cache(ScoreDatabase = new ScoreDatabase(Host.Storage, connection, Host, BeatmapDatabase));
|
||||
dependencies.Cache(RulesetDatabase = new RulesetDatabase(connection));
|
||||
dependencies.Cache(BeatmapStore = new BeatmapStore(Host.Storage, connection, RulesetDatabase, Host));
|
||||
dependencies.Cache(ScoreDatabase = new ScoreDatabase(Host.Storage, connection, Host, BeatmapStore));
|
||||
dependencies.Cache(new OsuColour());
|
||||
|
||||
//this completely overrides the framework default. will need to change once we make a proper FontStore.
|
||||
@ -129,7 +129,7 @@ namespace osu.Game
|
||||
|
||||
var defaultBeatmap = new DummyWorkingBeatmap(this);
|
||||
Beatmap = new NonNullableBindable<WorkingBeatmap>(defaultBeatmap);
|
||||
BeatmapDatabase.DefaultBeatmap = defaultBeatmap;
|
||||
BeatmapStore.DefaultBeatmap = defaultBeatmap;
|
||||
|
||||
OszArchiveReader.Register();
|
||||
|
||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Overlays.Music
|
||||
private FilterControl filter;
|
||||
private PlaylistList list;
|
||||
|
||||
private BeatmapDatabase beatmaps;
|
||||
private BeatmapStore beatmaps;
|
||||
|
||||
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
||||
|
||||
@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Music
|
||||
private InputManager inputManager;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGameBase game, BeatmapDatabase beatmaps, OsuColour colours, UserInputManager inputManager)
|
||||
private void load(OsuGameBase game, BeatmapStore beatmaps, OsuColour colours, UserInputManager inputManager)
|
||||
{
|
||||
this.inputManager = inputManager;
|
||||
this.beatmaps = beatmaps;
|
||||
@ -77,7 +77,7 @@ namespace osu.Game.Overlays.Music
|
||||
},
|
||||
};
|
||||
|
||||
list.BeatmapSets = BeatmapSets = beatmaps.GetAllWithChildren<BeatmapSetInfo>(b => !b.DeletePending).ToList();
|
||||
list.BeatmapSets = BeatmapSets = beatmaps.Database.GetAllWithChildren<BeatmapSetInfo>(b => !b.DeletePending).ToList();
|
||||
|
||||
beatmaps.BeatmapSetAdded += s => list.AddBeatmapSet(s);
|
||||
beatmaps.BeatmapSetRemoved += s => list.RemoveBeatmapSet(s);
|
||||
|
@ -6,21 +6,19 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Database;
|
||||
using SQLite.Net;
|
||||
|
||||
namespace osu.Game.Database
|
||||
namespace osu.Game.Rulesets
|
||||
{
|
||||
/// <summary>
|
||||
/// Todo: All of this needs to be moved to a RulesetDatabase.
|
||||
/// </summary>
|
||||
public class RulesetDatabase : Database
|
||||
public class RulesetDatabase : DatabaseStore
|
||||
{
|
||||
public IEnumerable<RulesetInfo> AllRulesets => Query<RulesetInfo>().Where(r => r.Available);
|
||||
|
||||
public RulesetDatabase(Storage storage, SQLiteConnection connection)
|
||||
: base(storage, connection)
|
||||
public RulesetDatabase(SQLiteConnection connection) : base(connection)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -2,10 +2,9 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Game.Rulesets;
|
||||
using SQLite.Net.Attributes;
|
||||
|
||||
namespace osu.Game.Database
|
||||
namespace osu.Game.Rulesets
|
||||
{
|
||||
public class RulesetInfo
|
||||
{
|
||||
|
@ -6,16 +6,17 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.IO.Legacy;
|
||||
using osu.Game.IPC;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SQLite.Net;
|
||||
|
||||
namespace osu.Game.Database
|
||||
namespace osu.Game.Rulesets.Scoring
|
||||
{
|
||||
public class ScoreDatabase : DatabaseBacking
|
||||
public class ScoreDatabase : DatabaseStore
|
||||
{
|
||||
private readonly Storage storage;
|
||||
|
||||
@ -27,7 +28,7 @@ namespace osu.Game.Database
|
||||
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
|
||||
private ScoreIPCChannel ipc;
|
||||
|
||||
public ScoreDatabase(Storage storage, SQLiteConnection connection, IIpcHost importHost = null, BeatmapStore beatmaps = null, RulesetDatabase rulesets = null) : base(storage, connection)
|
||||
public ScoreDatabase(Storage storage, SQLiteConnection connection, IIpcHost importHost = null, BeatmapStore beatmaps = null, RulesetDatabase rulesets = null) : base(connection)
|
||||
{
|
||||
this.storage = storage;
|
||||
this.beatmaps = beatmaps;
|
||||
@ -53,7 +54,7 @@ namespace osu.Game.Database
|
||||
var version = sr.ReadInt32();
|
||||
/* score.FileChecksum = */
|
||||
var beatmapHash = sr.ReadString();
|
||||
score.Beatmap = beatmaps.Query<BeatmapInfo>().FirstOrDefault(b => b.Hash == beatmapHash);
|
||||
score.Beatmap = beatmaps.Database.Query<BeatmapInfo>().FirstOrDefault(b => b.Hash == beatmapHash);
|
||||
/* score.PlayerName = */
|
||||
sr.ReadString();
|
||||
/* var localScoreChecksum = */
|
||||
|
@ -67,7 +67,7 @@ namespace osu.Game.Screens.Menu
|
||||
private Track track;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, OsuConfigManager config, BeatmapDatabase beatmaps, Framework.Game game)
|
||||
private void load(AudioManager audio, OsuConfigManager config, BeatmapStore beatmaps, Framework.Game game)
|
||||
{
|
||||
menuVoice = config.GetBindable<bool>(OsuSetting.MenuVoice);
|
||||
menuMusic = config.GetBindable<bool>(OsuSetting.MenuMusic);
|
||||
@ -76,7 +76,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
if (!menuMusic)
|
||||
{
|
||||
var query = beatmaps.Query<BeatmapSetInfo>().Where(b => !b.DeletePending);
|
||||
var query = beatmaps.Database.Query<BeatmapSetInfo>().Where(b => !b.DeletePending);
|
||||
int count = query.Count();
|
||||
if (count > 0)
|
||||
setInfo = query.ElementAt(RNG.Next(0, count - 1));
|
||||
@ -84,7 +84,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
if (setInfo == null)
|
||||
{
|
||||
var query = beatmaps.Query<BeatmapSetInfo>().Where(b => b.Hash == MENU_MUSIC_BEATMAP_HASH);
|
||||
var query = beatmaps.Database.Query<BeatmapSetInfo>().Where(b => b.Hash == MENU_MUSIC_BEATMAP_HASH);
|
||||
|
||||
setInfo = query.FirstOrDefault();
|
||||
|
||||
@ -96,11 +96,11 @@ namespace osu.Game.Screens.Menu
|
||||
setInfo = query.First();
|
||||
|
||||
setInfo.DeletePending = true;
|
||||
beatmaps.Update(setInfo, false);
|
||||
beatmaps.Database.Update(setInfo, false);
|
||||
}
|
||||
}
|
||||
|
||||
beatmaps.GetChildren(setInfo);
|
||||
beatmaps.Database.GetChildren(setInfo);
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
|
||||
|
||||
track = Beatmap.Value.Track;
|
||||
|
@ -68,7 +68,7 @@ namespace osu.Game.Screens.Select
|
||||
/// <summary>
|
||||
/// Required for now unfortunately.
|
||||
/// </summary>
|
||||
private BeatmapDatabase database;
|
||||
private BeatmapStore store;
|
||||
|
||||
private readonly Container<Panel> scrollableContent;
|
||||
|
||||
@ -289,7 +289,7 @@ namespace osu.Game.Screens.Select
|
||||
b.Metadata = beatmapSet.Metadata;
|
||||
}
|
||||
|
||||
return new BeatmapGroup(beatmapSet, database)
|
||||
return new BeatmapGroup(beatmapSet, store)
|
||||
{
|
||||
SelectionChanged = (g, p) => selectGroup(g, p),
|
||||
StartRequested = b => StartRequested?.Invoke(),
|
||||
@ -298,9 +298,9 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(BeatmapDatabase database, OsuConfigManager config)
|
||||
private void load(BeatmapStore store, OsuConfigManager config)
|
||||
{
|
||||
this.database = database;
|
||||
this.store = store;
|
||||
|
||||
randomType = config.GetBindable<SelectionRandomType>(OsuSetting.SelectionRandomType);
|
||||
}
|
||||
|
@ -11,12 +11,12 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
public class BeatmapDeleteDialog : PopupDialog
|
||||
{
|
||||
private BeatmapDatabase database;
|
||||
private BeatmapStore store;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(BeatmapDatabase beatmapDatabase)
|
||||
private void load(BeatmapStore beatmapStore)
|
||||
{
|
||||
database = beatmapDatabase;
|
||||
store = beatmapStore;
|
||||
}
|
||||
|
||||
public BeatmapDeleteDialog(WorkingBeatmap beatmap)
|
||||
@ -34,7 +34,7 @@ namespace osu.Game.Screens.Select
|
||||
Action = () =>
|
||||
{
|
||||
beatmap.Dispose();
|
||||
database.Delete(beatmap.BeatmapSetInfo);
|
||||
store.Delete(beatmap.BeatmapSetInfo);
|
||||
},
|
||||
},
|
||||
new PopupDialogCancelButton
|
||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Screens.Select
|
||||
public abstract class SongSelect : OsuScreen
|
||||
{
|
||||
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
|
||||
private BeatmapDatabase database;
|
||||
private BeatmapStore store;
|
||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap();
|
||||
|
||||
private readonly BeatmapCarousel carousel;
|
||||
@ -154,7 +154,7 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(BeatmapDatabase beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours, UserInputManager input)
|
||||
private void load(BeatmapStore beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours, UserInputManager input)
|
||||
{
|
||||
if (Footer != null)
|
||||
{
|
||||
@ -164,14 +164,14 @@ namespace osu.Game.Screens.Select
|
||||
BeatmapOptions.AddButton(@"Delete", @"Beatmap", FontAwesome.fa_trash, colours.Pink, promptDelete, Key.Number4, float.MaxValue);
|
||||
}
|
||||
|
||||
if (database == null)
|
||||
database = beatmaps;
|
||||
if (store == null)
|
||||
store = beatmaps;
|
||||
|
||||
if (osu != null)
|
||||
ruleset.BindTo(osu.Ruleset);
|
||||
|
||||
database.BeatmapSetAdded += onBeatmapSetAdded;
|
||||
database.BeatmapSetRemoved += onBeatmapSetRemoved;
|
||||
store.BeatmapSetAdded += onBeatmapSetAdded;
|
||||
store.BeatmapSetRemoved += onBeatmapSetRemoved;
|
||||
|
||||
dialogOverlay = dialog;
|
||||
|
||||
@ -180,7 +180,7 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
initialAddSetsTask = new CancellationTokenSource();
|
||||
|
||||
carousel.Beatmaps = database.GetAllWithChildren<BeatmapSetInfo>(b => !b.DeletePending);
|
||||
carousel.Beatmaps = store.Database.GetAllWithChildren<BeatmapSetInfo>(b => !b.DeletePending);
|
||||
|
||||
Beatmap.ValueChanged += beatmap_ValueChanged;
|
||||
|
||||
@ -230,7 +230,7 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
bool preview = beatmap?.BeatmapSetInfoID != Beatmap.Value.BeatmapInfo.BeatmapSetInfoID;
|
||||
|
||||
Beatmap.Value = database.GetWorkingBeatmap(beatmap, Beatmap);
|
||||
Beatmap.Value = store.GetWorkingBeatmap(beatmap, Beatmap);
|
||||
ensurePlayingSelected(preview);
|
||||
}
|
||||
|
||||
@ -341,10 +341,10 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (database != null)
|
||||
if (store != null)
|
||||
{
|
||||
database.BeatmapSetAdded -= onBeatmapSetAdded;
|
||||
database.BeatmapSetRemoved -= onBeatmapSetRemoved;
|
||||
store.BeatmapSetAdded -= onBeatmapSetAdded;
|
||||
store.BeatmapSetRemoved -= onBeatmapSetRemoved;
|
||||
}
|
||||
|
||||
initialAddSetsTask?.Cancel();
|
||||
|
@ -74,6 +74,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="Audio\SampleInfo.cs" />
|
||||
<Compile Include="Audio\SampleInfoList.cs" />
|
||||
<Compile Include="Beatmaps\BeatmapDatabase.cs" />
|
||||
<Compile Include="Beatmaps\Drawables\BeatmapBackgroundSprite.cs" />
|
||||
<Compile Include="Beatmaps\DifficultyCalculator.cs" />
|
||||
<Compile Include="Beatmaps\DummyWorkingBeatmap.cs" />
|
||||
@ -125,10 +126,10 @@
|
||||
<Compile Include="Beatmaps\Legacy\LegacyBeatmap.cs" />
|
||||
<Compile Include="Beatmaps\Timing\BreakPeriod.cs" />
|
||||
<Compile Include="Beatmaps\Timing\TimeSignatures.cs" />
|
||||
<Compile Include="Database\BeatmapMetrics.cs" />
|
||||
<Compile Include="Database\Database.cs" />
|
||||
<Compile Include="Beatmaps\BeatmapMetrics.cs" />
|
||||
<Compile Include="Database\DatabaseStore.cs" />
|
||||
<Compile Include="Rulesets\RulesetInfo.cs" />
|
||||
<Compile Include="Database\ScoreDatabase.cs" />
|
||||
<Compile Include="Rulesets\Scoring\ScoreDatabase.cs" />
|
||||
<Compile Include="Graphics\Backgrounds\Triangles.cs" />
|
||||
<Compile Include="Graphics\Cursor\CursorTrail.cs" />
|
||||
<Compile Include="Graphics\Cursor\GameplayCursor.cs" />
|
||||
@ -215,7 +216,7 @@
|
||||
<Compile Include="Rulesets\Objects\Legacy\ConvertHitObjectType.cs" />
|
||||
<Compile Include="Rulesets\Replays\ReplayButtonState.cs" />
|
||||
<Compile Include="Rulesets\Replays\ReplayFrame.cs" />
|
||||
<Compile Include="Database\RulesetDatabase.cs" />
|
||||
<Compile Include="Rulesets\RulesetDatabase.cs" />
|
||||
<Compile Include="Rulesets\Scoring\Score.cs" />
|
||||
<Compile Include="Rulesets\Scoring\ScoreProcessor.cs" />
|
||||
<Compile Include="Rulesets\Timing\SpeedAdjustmentContainer.cs" />
|
||||
@ -390,10 +391,10 @@
|
||||
<Compile Include="Beatmaps\Formats\OsuLegacyDecoder.cs" />
|
||||
<Compile Include="Beatmaps\IO\OszArchiveReader.cs" />
|
||||
<Compile Include="Graphics\UserInterface\Volume\VolumeMeter.cs" />
|
||||
<Compile Include="Database\BeatmapSetInfo.cs" />
|
||||
<Compile Include="Database\BeatmapMetadata.cs" />
|
||||
<Compile Include="Database\BeatmapInfo.cs" />
|
||||
<Compile Include="Database\BeatmapDifficulty.cs" />
|
||||
<Compile Include="Beatmaps\BeatmapSetInfo.cs" />
|
||||
<Compile Include="Beatmaps\BeatmapMetadata.cs" />
|
||||
<Compile Include="Beatmaps\BeatmapInfo.cs" />
|
||||
<Compile Include="Beatmaps\BeatmapDifficulty.cs" />
|
||||
<Compile Include="Beatmaps\BeatmapStoreWorkingBeatmap.cs" />
|
||||
<Compile Include="Graphics\UserInterface\OsuButton.cs" />
|
||||
<Compile Include="Overlays\Settings\Sections\MaintenanceSection.cs" />
|
||||
@ -488,10 +489,10 @@
|
||||
<Compile Include="Overlays\Direct\DirectPanel.cs" />
|
||||
<Compile Include="Overlays\Direct\DirectGridPanel.cs" />
|
||||
<Compile Include="Overlays\Direct\DirectListPanel.cs" />
|
||||
<Compile Include="Database\BeatmapOnlineInfo.cs" />
|
||||
<Compile Include="Beatmaps\BeatmapOnlineInfo.cs" />
|
||||
<Compile Include="Graphics\Containers\ReverseChildIDFillFlowContainer.cs" />
|
||||
<Compile Include="Database\RankStatus.cs" />
|
||||
<Compile Include="Database\BeatmapSetOnlineInfo.cs" />
|
||||
<Compile Include="Beatmaps\RankStatus.cs" />
|
||||
<Compile Include="Beatmaps\BeatmapSetOnlineInfo.cs" />
|
||||
<Compile Include="Online\API\Requests\GetBeatmapSetsRequest.cs" />
|
||||
<Compile Include="Overlays\SearchableList\SearchableListHeader.cs" />
|
||||
<Compile Include="Overlays\SearchableList\HeaderTabControl.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user