mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 19:22:54 +08:00
Merge branch 'master' of git://github.com/ppy/osu into ranks-section
This commit is contained in:
commit
4720a47363
@ -1 +1 @@
|
||||
Subproject commit 05a8b2637623bd8ac6c1619b728ea9b4cca35b8a
|
||||
Subproject commit 5a9ca94fc31bc796b45572eb3d0b27b46556c586
|
@ -3,9 +3,9 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Screens.Select;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
|
@ -4,8 +4,9 @@
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
@ -14,7 +15,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
public override string Description => @"osu!direct overlay";
|
||||
|
||||
private DirectOverlay direct;
|
||||
private RulesetDatabase rulesets;
|
||||
private RulesetStore rulesets;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
@ -28,7 +29,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetDatabase rulesets)
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
}
|
||||
|
@ -7,8 +7,9 @@ using osu.Framework.Testing;
|
||||
using osu.Game.Screens.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Database;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
@ -16,7 +17,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Select your favourite room";
|
||||
|
||||
private RulesetDatabase rulesets;
|
||||
private RulesetStore rulesets;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
@ -124,7 +125,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetDatabase rulesets)
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ using osu.Framework.MathUtils;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -19,17 +18,18 @@ using System.Collections.Generic;
|
||||
using osu.Desktop.VisualTests.Beatmaps;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
internal class TestCaseGamefield : TestCase
|
||||
{
|
||||
private RulesetDatabase rulesets;
|
||||
private RulesetStore rulesets;
|
||||
|
||||
public override string Description => @"Showing hitobjects and what not.";
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetDatabase rulesets)
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using OpenTK;
|
||||
|
||||
@ -18,11 +18,11 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
private ModSelectOverlay modSelect;
|
||||
private ModDisplay modDisplay;
|
||||
|
||||
private RulesetDatabase rulesets;
|
||||
private RulesetStore rulesets;
|
||||
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetDatabase rulesets)
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
}
|
||||
|
@ -5,7 +5,9 @@ using System.Collections.Generic;
|
||||
using osu.Desktop.VisualTests.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
|
||||
@ -13,31 +15,28 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
internal class TestCasePlaySongSelect : TestCase
|
||||
{
|
||||
private readonly BeatmapDatabase db;
|
||||
private readonly BeatmapManager manager;
|
||||
|
||||
public override string Description => @"with fake data";
|
||||
|
||||
private readonly RulesetDatabase rulesets;
|
||||
private readonly RulesetStore rulesets;
|
||||
|
||||
public TestCasePlaySongSelect()
|
||||
{
|
||||
PlaySongSelect songSelect;
|
||||
|
||||
if (db == null)
|
||||
if (manager == null)
|
||||
{
|
||||
var storage = new TestStorage(@"TestCasePlaySongSelect");
|
||||
|
||||
var backingDatabase = storage.GetDatabase(@"client");
|
||||
backingDatabase.CreateTable<StoreVersion>();
|
||||
|
||||
rulesets = new RulesetDatabase(storage, backingDatabase);
|
||||
db = new BeatmapDatabase(storage, backingDatabase, rulesets);
|
||||
|
||||
var sets = new List<BeatmapSetInfo>();
|
||||
rulesets = new RulesetStore(backingDatabase);
|
||||
manager = new BeatmapManager(storage, null, backingDatabase, rulesets);
|
||||
|
||||
for (int i = 0; i < 100; i += 10)
|
||||
sets.Add(createTestBeatmapSet(i));
|
||||
|
||||
db.Import(sets);
|
||||
manager.Import(createTestBeatmapSet(i));
|
||||
}
|
||||
|
||||
Add(songSelect = new PlaySongSelect());
|
||||
@ -48,21 +47,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,
|
||||
|
@ -6,7 +6,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using OpenTK;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Screens.Play;
|
||||
@ -14,18 +13,19 @@ using OpenTK.Graphics;
|
||||
using osu.Desktop.VisualTests.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
internal class TestCasePlayer : TestCase
|
||||
{
|
||||
protected Player Player;
|
||||
private RulesetDatabase rulesets;
|
||||
private RulesetStore rulesets;
|
||||
|
||||
public override string Description => @"Showing everything to play the game.";
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetDatabase rulesets)
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
}
|
||||
|
@ -3,11 +3,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Users;
|
||||
@ -16,14 +14,14 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
internal class TestCaseResults : TestCase
|
||||
{
|
||||
private BeatmapDatabase db;
|
||||
private BeatmapManager beatmaps;
|
||||
|
||||
public override string Description => @"Results after playing.";
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(BeatmapDatabase db)
|
||||
private void load(BeatmapManager beatmaps)
|
||||
{
|
||||
this.db = db;
|
||||
this.beatmaps = beatmaps;
|
||||
}
|
||||
|
||||
private WorkingBeatmap beatmap;
|
||||
@ -34,9 +32,9 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
|
||||
if (beatmap == null)
|
||||
{
|
||||
var beatmapInfo = db.Query<BeatmapInfo>().FirstOrDefault(b => b.RulesetID == 0);
|
||||
var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0);
|
||||
if (beatmapInfo != null)
|
||||
beatmap = db.GetWorkingBeatmap(beatmapInfo);
|
||||
beatmap = beatmaps.GetWorkingBeatmap(beatmapInfo);
|
||||
}
|
||||
|
||||
Add(new Results(new Score
|
||||
|
@ -4,10 +4,11 @@
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Screens.Multiplayer;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Users;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
@ -15,7 +16,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"from the multiplayer lobby";
|
||||
|
||||
private RulesetDatabase rulesets;
|
||||
private RulesetStore rulesets;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
@ -135,7 +136,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetDatabase rulesets)
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
}
|
||||
|
@ -1,43 +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 System.Linq;
|
||||
using osu.Game.Beatmaps.IO;
|
||||
|
||||
namespace osu.Desktop.Beatmaps.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads an extracted legacy beatmap from disk.
|
||||
/// </summary>
|
||||
public class LegacyFilesystemReader : ArchiveReader
|
||||
{
|
||||
public static void Register() => AddReader<LegacyFilesystemReader>((storage, path) => Directory.Exists(path));
|
||||
|
||||
private readonly string basePath;
|
||||
|
||||
public LegacyFilesystemReader(string path)
|
||||
{
|
||||
basePath = path;
|
||||
|
||||
BeatmapFilenames = Directory.GetFiles(basePath, @"*.osu").Select(Path.GetFileName).ToArray();
|
||||
|
||||
if (BeatmapFilenames.Length == 0)
|
||||
throw new FileNotFoundException(@"This directory contains no beatmaps");
|
||||
|
||||
StoryboardFilename = Directory.GetFiles(basePath, @"*.osb").Select(Path.GetFileName).FirstOrDefault();
|
||||
}
|
||||
|
||||
public override Stream GetStream(string name)
|
||||
{
|
||||
return File.OpenRead(Path.Combine(basePath, name));
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
public override Stream GetUnderlyingStream() => null;
|
||||
}
|
||||
}
|
@ -65,11 +65,11 @@ 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(() => BeatmapManager.Import(filePaths));
|
||||
else if (filePaths.All(f => Path.GetExtension(f) == @".osr"))
|
||||
Task.Run(() =>
|
||||
{
|
||||
var score = ScoreDatabase.ReadReplayFile(filePaths.First());
|
||||
var score = ScoreStore.ReadReplayFile(filePaths.First());
|
||||
Schedule(() => LoadScore(score));
|
||||
});
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using osu.Desktop.Beatmaps.IO;
|
||||
using osu.Framework.Desktop;
|
||||
using osu.Framework.Desktop.Platform;
|
||||
using osu.Game.IPC;
|
||||
@ -15,8 +14,6 @@ namespace osu.Desktop
|
||||
[STAThread]
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
LegacyFilesystemReader.Register();
|
||||
|
||||
// Back up the cwd before DesktopGameHost changes it
|
||||
var cwd = Environment.CurrentDirectory;
|
||||
|
||||
|
@ -228,7 +228,6 @@
|
||||
<Compile Include="OsuGameDesktop.cs" />
|
||||
<Compile Include="Overlays\VersionManager.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Beatmaps\IO\LegacyFilesystemReader.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -10,7 +10,6 @@ using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps.Patterns;
|
||||
using osu.Game.Rulesets.Mania.MathUtils;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy;
|
||||
using OpenTK;
|
||||
using osu.Game.Audio;
|
||||
|
@ -4,7 +4,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Mania.MathUtils;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using OpenTK;
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Judgements
|
||||
{
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects
|
||||
|
@ -4,7 +4,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
@ -1,12 +1,12 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
|
@ -6,9 +6,9 @@ using osu.Game.Rulesets.Objects.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Database;
|
||||
using System.Linq;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
|
@ -8,7 +8,6 @@ using osu.Game.Rulesets.Taiko.Objects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.IO.Serialization;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Beatmaps;
|
||||
|
@ -5,8 +5,8 @@ using osu.Game.Rulesets.Objects.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects
|
||||
{
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Taiko.UI;
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using System;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
|
@ -16,12 +16,6 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
[TestFixture]
|
||||
public class OsuLegacyDecoderTest
|
||||
{
|
||||
[OneTimeSetUpAttribute]
|
||||
public void SetUp()
|
||||
{
|
||||
OsuLegacyDecoder.Register();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeMetadata()
|
||||
{
|
||||
|
@ -10,9 +10,10 @@ using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Desktop.Platform;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.IPC;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps.IO
|
||||
{
|
||||
@ -33,7 +34,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
Assert.IsTrue(File.Exists(temp));
|
||||
|
||||
osu.Dependencies.Get<BeatmapDatabase>().Import(temp);
|
||||
osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||
|
||||
ensureLoaded(osu);
|
||||
|
||||
@ -79,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<BeatmapManager>().Import(temp);
|
||||
|
||||
ensureLoaded(osu);
|
||||
|
||||
@ -104,8 +105,8 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
Thread.Sleep(1);
|
||||
|
||||
//reset beatmap database (sqlite and storage backing)
|
||||
osu.Dependencies.Get<RulesetDatabase>().Reset();
|
||||
osu.Dependencies.Get<BeatmapDatabase>().Reset();
|
||||
osu.Dependencies.Get<RulesetStore>().Reset();
|
||||
osu.Dependencies.Get<BeatmapManager>().Reset();
|
||||
|
||||
return osu;
|
||||
}
|
||||
@ -114,10 +115,11 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
{
|
||||
IEnumerable<BeatmapSetInfo> resultSets = null;
|
||||
|
||||
var store = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
Action waitAction = () =>
|
||||
{
|
||||
while (!(resultSets = osu.Dependencies.Get<BeatmapDatabase>()
|
||||
.Query<BeatmapSetInfo>().Where(s => s.OnlineBeatmapSetID == 241526)).Any())
|
||||
while (!(resultSets = store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526)).Any())
|
||||
Thread.Sleep(50);
|
||||
};
|
||||
|
||||
@ -133,15 +135,14 @@ 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 = store.QueryBeatmaps(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 = store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526).First();
|
||||
|
||||
Assert.IsTrue(set.Beatmaps.Count == resultBeatmaps.Count(),
|
||||
$@"Incorrect database beatmap count post-import ({resultBeatmaps.Count()} but should be {set.Beatmaps.Count}).");
|
||||
@ -151,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 = store.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 = store.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 = store.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 = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap;
|
||||
Assert.IsTrue(beatmap?.HitObjects.Count > 0);
|
||||
}
|
||||
}
|
||||
|
@ -2,23 +2,18 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.IO;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps.IO
|
||||
{
|
||||
[TestFixture]
|
||||
public class OszArchiveReaderTest
|
||||
{
|
||||
[OneTimeSetUpAttribute]
|
||||
public void SetUp()
|
||||
{
|
||||
OszArchiveReader.Register();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestReadBeatmaps()
|
||||
{
|
||||
@ -40,7 +35,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
"Soleily - Renatus (MMzz) [Muzukashii].osu",
|
||||
"Soleily - Renatus (MMzz) [Oni].osu"
|
||||
};
|
||||
var maps = reader.BeatmapFilenames;
|
||||
var maps = reader.Filenames.ToArray();
|
||||
foreach (var map in expected)
|
||||
Assert.Contains(map, maps);
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using OpenTK.Graphics;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
using SQLite.Net.Attributes;
|
||||
|
||||
namespace osu.Game.Database
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public class BeatmapDifficulty
|
||||
{
|
@ -1,14 +1,15 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.IO.Serialization;
|
||||
using SQLite.Net.Attributes;
|
||||
using SQLiteNetExtensions.Attributes;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.IO.Serialization;
|
||||
using osu.Game.Rulesets;
|
||||
using SQLite.Net.Attributes;
|
||||
using SQLiteNetExtensions.Attributes;
|
||||
|
||||
namespace osu.Game.Database
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable
|
||||
{
|
||||
@ -60,7 +61,7 @@ namespace osu.Game.Database
|
||||
[ForeignKey(typeof(RulesetInfo))]
|
||||
public int RulesetID { get; set; }
|
||||
|
||||
[OneToOne(CascadeOperations = CascadeOperation.All)]
|
||||
[OneToOne(CascadeOperations = CascadeOperation.CascadeRead)]
|
||||
public RulesetInfo Ruleset { get; set; }
|
||||
|
||||
public bool LetterboxInBreaks { get; set; }
|
||||
@ -94,11 +95,11 @@ namespace osu.Game.Database
|
||||
}
|
||||
|
||||
public bool AudioEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
|
||||
BeatmapSet.Path == other.BeatmapSet.Path &&
|
||||
BeatmapSet.Hash == other.BeatmapSet.Hash &&
|
||||
(Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile;
|
||||
|
||||
public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
|
||||
BeatmapSet.Path == other.BeatmapSet.Path &&
|
||||
BeatmapSet.Hash == other.BeatmapSet.Hash &&
|
||||
(Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile;
|
||||
}
|
||||
}
|
394
osu.Game/Beatmaps/BeatmapManager.cs
Normal file
394
osu.Game/Beatmaps/BeatmapManager.cs
Normal file
@ -0,0 +1,394 @@
|
||||
// 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 System.Linq.Expressions;
|
||||
using Ionic.Zip;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.Beatmaps.IO;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.IPC;
|
||||
using osu.Game.Rulesets;
|
||||
using SQLite.Net;
|
||||
using FileInfo = osu.Game.IO.FileInfo;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles the storage and retrieval of Beatmaps/WorkingBeatmaps.
|
||||
/// </summary>
|
||||
public class BeatmapManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Fired when a new <see cref="BeatmapSetInfo"/> becomes available in the database.
|
||||
/// </summary>
|
||||
public event Action<BeatmapSetInfo> BeatmapSetAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a <see cref="BeatmapSetInfo"/> is removed from the database.
|
||||
/// </summary>
|
||||
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
||||
/// </summary>
|
||||
public WorkingBeatmap DefaultBeatmap { private get; set; }
|
||||
|
||||
private readonly Storage storage;
|
||||
|
||||
private readonly FileStore files;
|
||||
|
||||
private readonly RulesetStore rulesets;
|
||||
|
||||
private readonly BeatmapStore beatmaps;
|
||||
|
||||
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
|
||||
private BeatmapIPCChannel ipc;
|
||||
|
||||
public BeatmapManager(Storage storage, FileStore files, SQLiteConnection connection, RulesetStore rulesets, IIpcHost importHost = null)
|
||||
{
|
||||
beatmaps = new BeatmapStore(connection);
|
||||
beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s);
|
||||
beatmaps.BeatmapSetRemoved += s => BeatmapSetRemoved?.Invoke(s);
|
||||
|
||||
this.storage = storage;
|
||||
this.files = files;
|
||||
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
|
||||
{
|
||||
using (ArchiveReader reader = getReaderFrom(path))
|
||||
Import(reader);
|
||||
|
||||
// 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 BeatmapSetInfo Import(ArchiveReader archiveReader)
|
||||
{
|
||||
BeatmapSetInfo set = importToStorage(archiveReader);
|
||||
Import(set);
|
||||
return set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Import a beatmap from a <see cref="BeatmapSetInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="beatmapSetInfo">The beatmap to be imported.</param>
|
||||
public void Import(BeatmapSetInfo beatmapSetInfo)
|
||||
{
|
||||
// If we have an ID then we already exist in the database.
|
||||
if (beatmapSetInfo.ID != 0) return;
|
||||
|
||||
beatmaps.Add(beatmapSetInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete a beatmap from the manager.
|
||||
/// Is a no-op for already deleted beatmaps.
|
||||
/// </summary>
|
||||
/// <param name="beatmapSet">The beatmap to delete.</param>
|
||||
public void Delete(BeatmapSetInfo beatmapSet)
|
||||
{
|
||||
if (!beatmaps.Delete(beatmapSet)) return;
|
||||
|
||||
if (!beatmapSet.Protected)
|
||||
files.Dereference(beatmapSet.Files);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="BeatmapSetInfo"/> to a usable state if it has previously been deleted but not yet purged.
|
||||
/// Is a no-op for already usable beatmaps.
|
||||
/// </summary>
|
||||
/// <param name="beatmapSet">The beatmap to restore.</param>
|
||||
public void Undelete(BeatmapSetInfo beatmapSet)
|
||||
{
|
||||
if (!beatmaps.Undelete(beatmapSet)) return;
|
||||
|
||||
files.Reference(beatmapSet.Files);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a <see cref="WorkingBeatmap"/> instance for the provided <see cref="BeatmapInfo"/>
|
||||
/// </summary>
|
||||
/// <param name="beatmapInfo">The beatmap to lookup.</param>
|
||||
/// <param name="previous">The currently loaded <see cref="WorkingBeatmap"/>. Allows for optimisation where elements are shared with the new beatmap.</param>
|
||||
/// <returns>A <see cref="WorkingBeatmap"/> instance correlating to the provided <see cref="BeatmapInfo"/>.</returns>
|
||||
public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null)
|
||||
{
|
||||
if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo)
|
||||
return DefaultBeatmap;
|
||||
|
||||
beatmaps.Populate(beatmapInfo);
|
||||
|
||||
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 BeatmapManagerWorkingBeatmap(files.Store, beatmapInfo);
|
||||
|
||||
previous?.TransferTo(working);
|
||||
|
||||
return working;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the manager to an empty state.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
beatmaps.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>The first result for the provided query, or null if no results were found.</returns>
|
||||
public BeatmapSetInfo QueryBeatmapSet(Func<BeatmapSetInfo, bool> query)
|
||||
{
|
||||
BeatmapSetInfo set = beatmaps.Query<BeatmapSetInfo>().FirstOrDefault(query);
|
||||
|
||||
if (set != null)
|
||||
beatmaps.Populate(set);
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>Results from the provided query.</returns>
|
||||
public List<BeatmapSetInfo> QueryBeatmapSets(Expression<Func<BeatmapSetInfo, bool>> query) => beatmaps.QueryAndPopulate(query);
|
||||
|
||||
/// <summary>
|
||||
/// Perform a lookup query on available <see cref="BeatmapInfo"/>s.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>The first result for the provided query, or null if no results were found.</returns>
|
||||
public BeatmapInfo QueryBeatmap(Func<BeatmapInfo, bool> query)
|
||||
{
|
||||
BeatmapInfo set = beatmaps.Query<BeatmapInfo>().FirstOrDefault(query);
|
||||
|
||||
if (set != null)
|
||||
beatmaps.Populate(set);
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform a lookup query on available <see cref="BeatmapInfo"/>s.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>Results from the provided query.</returns>
|
||||
public List<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>> query) => beatmaps.QueryAndPopulate(query);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="ArchiveReader"/> from a valid storage path.
|
||||
/// </summary>
|
||||
/// <param name="path">A file or folder path resolving the beatmap content.</param>
|
||||
/// <returns>A reader giving access to the beatmap's content.</returns>
|
||||
private ArchiveReader getReaderFrom(string path)
|
||||
{
|
||||
if (ZipFile.IsZipFile(path))
|
||||
return new OszArchiveReader(storage.GetStream(path));
|
||||
else
|
||||
return new LegacyFilesystemReader(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Import a beamap into our local <see cref="FileStore"/> storage.
|
||||
/// If the beatmap is already imported, the existing instance will be returned.
|
||||
/// </summary>
|
||||
/// <param name="reader">The beatmap archive to be read.</param>
|
||||
/// <returns>The imported beatmap, or an existing instance if it is already present.</returns>
|
||||
private BeatmapSetInfo importToStorage(ArchiveReader reader)
|
||||
{
|
||||
// for now, concatenate all .osu files in the set to create a unique hash.
|
||||
MemoryStream hashable = new MemoryStream();
|
||||
foreach (string file in reader.Filenames.Where(f => f.EndsWith(".osu")))
|
||||
using (Stream s = reader.GetStream(file))
|
||||
s.CopyTo(hashable);
|
||||
|
||||
var hash = hashable.ComputeSHA2Hash();
|
||||
|
||||
// check if this beatmap has already been imported and exit early if so.
|
||||
var beatmapSet = beatmaps.QueryAndPopulate<BeatmapSetInfo>().FirstOrDefault(b => b.Hash == hash);
|
||||
if (beatmapSet != null)
|
||||
{
|
||||
Undelete(beatmapSet);
|
||||
return beatmapSet;
|
||||
}
|
||||
|
||||
List<FileInfo> fileInfos = new List<FileInfo>();
|
||||
|
||||
// import files to manager
|
||||
foreach (string file in reader.Filenames)
|
||||
using (Stream s = reader.GetStream(file))
|
||||
fileInfos.Add(files.Add(s, file));
|
||||
|
||||
BeatmapMetadata metadata;
|
||||
|
||||
using (var stream = new StreamReader(reader.GetStream(reader.Filenames.First(f => f.EndsWith(".osu")))))
|
||||
metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata;
|
||||
|
||||
beatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = metadata.OnlineBeatmapSetID,
|
||||
Beatmaps = new List<BeatmapInfo>(),
|
||||
Hash = hash,
|
||||
Files = fileInfos,
|
||||
Metadata = metadata
|
||||
};
|
||||
|
||||
var mapNames = reader.Filenames.Where(f => f.EndsWith(".osu"));
|
||||
|
||||
foreach (var name in mapNames)
|
||||
{
|
||||
using (var raw = reader.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.ComputeSHA2Hash();
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
return beatmapSet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s.
|
||||
/// </summary>
|
||||
/// <param name="populate">Whether returned objects should be pre-populated with all data.</param>
|
||||
/// <returns>A list of available <see cref="BeatmapSetInfo"/>.</returns>
|
||||
public List<BeatmapSetInfo> GetAllUsableBeatmapSets(bool populate = true)
|
||||
{
|
||||
if (populate)
|
||||
return beatmaps.QueryAndPopulate<BeatmapSetInfo>(b => !b.DeletePending).ToList();
|
||||
else
|
||||
return beatmaps.Query<BeatmapSetInfo>(b => !b.DeletePending).ToList();
|
||||
}
|
||||
|
||||
protected class BeatmapManagerWorkingBeatmap : WorkingBeatmap
|
||||
{
|
||||
private readonly IResourceStore<byte[]> store;
|
||||
|
||||
public BeatmapManagerWorkingBeatmap(IResourceStore<byte[]> store, BeatmapInfo beatmapInfo)
|
||||
: base(beatmapInfo)
|
||||
{
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
protected override Beatmap GetBeatmap()
|
||||
{
|
||||
try
|
||||
{
|
||||
Beatmap beatmap;
|
||||
|
||||
BeatmapDecoder decoder;
|
||||
using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path))))
|
||||
{
|
||||
decoder = BeatmapDecoder.GetDecoder(stream);
|
||||
beatmap = decoder.Decode(stream);
|
||||
}
|
||||
|
||||
if (beatmap == null || BeatmapSetInfo.StoryboardFile == null)
|
||||
return beatmap;
|
||||
|
||||
using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile))))
|
||||
decoder.Decode(stream, beatmap);
|
||||
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
private string getPathForFile(string filename) => BeatmapSetInfo.Files.First(f => f.Filename == filename).StoragePath;
|
||||
|
||||
protected override Texture GetBackground()
|
||||
{
|
||||
if (Metadata?.BackgroundFile == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
return new TextureStore(new RawTextureLoaderStore(store), false).Get(getPathForFile(Metadata.BackgroundFile));
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
protected override Track GetTrack()
|
||||
{
|
||||
try
|
||||
{
|
||||
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile));
|
||||
return trackData == null ? null : new TrackBass(trackData);
|
||||
}
|
||||
catch { return new TrackVirtual(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using SQLite.Net.Attributes;
|
||||
|
||||
namespace osu.Game.Database
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public class BeatmapMetadata
|
||||
{
|
@ -4,7 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace osu.Game.Database
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
/// <summary>
|
||||
/// Beatmap metrics based on acculumated online data from community plays.
|
@ -3,7 +3,7 @@
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace osu.Game.Database
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
/// <summary>
|
||||
/// Beatmap info retrieved for previewing locally without having the beatmap downloaded.
|
17
osu.Game/Beatmaps/BeatmapSetFileInfo.cs
Normal file
17
osu.Game/Beatmaps/BeatmapSetFileInfo.cs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.IO;
|
||||
using SQLiteNetExtensions.Attributes;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public class BeatmapSetFileInfo
|
||||
{
|
||||
[ForeignKey(typeof(BeatmapSetInfo))]
|
||||
public int BeatmapSetInfoID { get; set; }
|
||||
|
||||
[ForeignKey(typeof(FileInfo))]
|
||||
public int FileInfoID { get; set; }
|
||||
}
|
||||
}
|
@ -3,10 +3,11 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.IO;
|
||||
using SQLite.Net.Attributes;
|
||||
using SQLiteNetExtensions.Attributes;
|
||||
|
||||
namespace osu.Game.Database
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public class BeatmapSetInfo
|
||||
{
|
||||
@ -34,8 +35,11 @@ namespace osu.Game.Database
|
||||
|
||||
public string Hash { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
public string StoryboardFile => Files.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename;
|
||||
|
||||
public string StoryboardFile { get; set; }
|
||||
[ManyToMany(typeof(BeatmapSetFileInfo), CascadeOperations = CascadeOperation.CascadeRead)]
|
||||
public List<FileInfo> Files { get; set; }
|
||||
|
||||
public bool Protected { get; set; }
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace osu.Game.Database
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
/// <summary>
|
||||
/// Beatmap set info retrieved for previewing locally without having the set downloaded.
|
153
osu.Game/Beatmaps/BeatmapStore.cs
Normal file
153
osu.Game/Beatmaps/BeatmapStore.cs
Normal file
@ -0,0 +1,153 @@
|
||||
// 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 osu.Framework.Logging;
|
||||
using osu.Game.Database;
|
||||
using SQLite.Net;
|
||||
using SQLiteNetExtensions.Extensions;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles the storage and retrieval of Beatmaps/BeatmapSets to the database backing
|
||||
/// </summary>
|
||||
public class BeatmapStore : DatabaseBackedStore
|
||||
{
|
||||
public event Action<BeatmapSetInfo> BeatmapSetAdded;
|
||||
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// The current version of this store. Used for migrations (see <see cref="PerformMigration(int, int)"/>).
|
||||
/// The initial version is 1.
|
||||
/// </summary>
|
||||
protected override int StoreVersion => 1;
|
||||
|
||||
public BeatmapStore(SQLiteConnection connection)
|
||||
: base(connection)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Type[] ValidTypes => new[]
|
||||
{
|
||||
typeof(BeatmapSetInfo),
|
||||
typeof(BeatmapInfo),
|
||||
typeof(BeatmapMetadata),
|
||||
typeof(BeatmapDifficulty),
|
||||
};
|
||||
|
||||
protected override void Prepare(bool reset = false)
|
||||
{
|
||||
if (reset)
|
||||
{
|
||||
Connection.DropTable<BeatmapMetadata>();
|
||||
Connection.DropTable<BeatmapDifficulty>();
|
||||
Connection.DropTable<BeatmapSetInfo>();
|
||||
Connection.DropTable<BeatmapSetFileInfo>();
|
||||
Connection.DropTable<BeatmapInfo>();
|
||||
}
|
||||
|
||||
Connection.CreateTable<BeatmapMetadata>();
|
||||
Connection.CreateTable<BeatmapDifficulty>();
|
||||
Connection.CreateTable<BeatmapSetInfo>();
|
||||
Connection.CreateTable<BeatmapSetFileInfo>();
|
||||
Connection.CreateTable<BeatmapInfo>();
|
||||
|
||||
cleanupPendingDeletions();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform migrations between two store versions.
|
||||
/// </summary>
|
||||
/// <param name="currentVersion">The current store version. This will be zero on a fresh database initialisation.</param>
|
||||
/// <param name="newVersion">The target version which we are migrating to (equal to the current <see cref="StoreVersion"/>).</param>
|
||||
protected override void PerformMigration(int currentVersion, int newVersion)
|
||||
{
|
||||
base.PerformMigration(currentVersion, newVersion);
|
||||
|
||||
while (currentVersion++ < newVersion)
|
||||
{
|
||||
switch (currentVersion)
|
||||
{
|
||||
case 1:
|
||||
// initialising from a version before we had versioning (or a fresh install).
|
||||
|
||||
// force adding of Protected column (not automatically migrated).
|
||||
Connection.MigrateTable<BeatmapSetInfo>();
|
||||
|
||||
// remove all existing beatmaps.
|
||||
foreach (var b in Connection.GetAllWithChildren<BeatmapSetInfo>(null, true))
|
||||
Connection.Delete(b, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a <see cref="BeatmapSetInfo"/> to the database.
|
||||
/// </summary>
|
||||
/// <param name="beatmapSet">The beatmap to add.</param>
|
||||
public void Add(BeatmapSetInfo beatmapSet)
|
||||
{
|
||||
Connection.RunInTransaction(() =>
|
||||
{
|
||||
Connection.InsertOrReplaceWithChildren(beatmapSet, true);
|
||||
});
|
||||
|
||||
BeatmapSetAdded?.Invoke(beatmapSet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete a <see cref="BeatmapSetInfo"/> to the database.
|
||||
/// </summary>
|
||||
/// <param name="beatmapSet">The beatmap to delete.</param>
|
||||
/// <returns>Whether the beatmap's <see cref="BeatmapSetInfo.DeletePending"/> was changed.</returns>
|
||||
public bool Delete(BeatmapSetInfo beatmapSet)
|
||||
{
|
||||
if (beatmapSet.DeletePending) return false;
|
||||
|
||||
beatmapSet.DeletePending = true;
|
||||
Connection.Update(beatmapSet);
|
||||
|
||||
BeatmapSetRemoved?.Invoke(beatmapSet);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restore a previously deleted <see cref="BeatmapSetInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="beatmapSet">The beatmap to restore.</param>
|
||||
/// <returns>Whether the beatmap's <see cref="BeatmapSetInfo.DeletePending"/> was changed.</returns>
|
||||
public bool Undelete(BeatmapSetInfo beatmapSet)
|
||||
{
|
||||
if (!beatmapSet.DeletePending) return false;
|
||||
|
||||
beatmapSet.DeletePending = false;
|
||||
Connection.Update(beatmapSet);
|
||||
|
||||
BeatmapSetAdded?.Invoke(beatmapSet);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void cleanupPendingDeletions()
|
||||
{
|
||||
foreach (var b in QueryAndPopulate<BeatmapSetInfo>(b => b.DeletePending && !b.Protected))
|
||||
{
|
||||
try
|
||||
{
|
||||
// many-to-many join table entries are not automatically tidied.
|
||||
Connection.Table<BeatmapSetFileInfo>().Delete(f => f.BeatmapSetInfoID == b.ID);
|
||||
Connection.Delete(b, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, $@"Could not delete beatmap {b}");
|
||||
}
|
||||
}
|
||||
|
||||
//this is required because sqlite migrations don't work, initially inserting nulls into this field.
|
||||
//see https://github.com/praeclarum/sqlite-net/issues/326
|
||||
Connection.Query<BeatmapSetInfo>("UPDATE BeatmapSetInfo SET DeletePending = 0 WHERE DeletePending IS NULL");
|
||||
}
|
||||
}
|
||||
}
|
@ -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, BeatmapManager manager)
|
||||
{
|
||||
BeatmapSet = beatmapSet;
|
||||
WorkingBeatmap beatmap = database.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault());
|
||||
WorkingBeatmap beatmap = manager.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault());
|
||||
|
||||
Header = new BeatmapSetHeader(beatmap)
|
||||
{
|
||||
|
@ -6,7 +6,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
@ -4,7 +4,6 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
@ -5,7 +5,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
@ -5,7 +5,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
@ -13,6 +12,11 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
private static readonly Dictionary<string, Type> decoders = new Dictionary<string, Type>();
|
||||
|
||||
static BeatmapDecoder()
|
||||
{
|
||||
OsuLegacyDecoder.Register();
|
||||
}
|
||||
|
||||
public static BeatmapDecoder GetDecoder(StreamReader stream)
|
||||
{
|
||||
string line = stream.ReadLine()?.Trim();
|
||||
|
@ -5,45 +5,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Platform;
|
||||
|
||||
namespace osu.Game.Beatmaps.IO
|
||||
{
|
||||
public abstract class ArchiveReader : IDisposable, IResourceStore<byte[]>
|
||||
{
|
||||
private class Reader
|
||||
{
|
||||
public Func<Storage, string, bool> Test;
|
||||
public Type Type;
|
||||
}
|
||||
|
||||
private static readonly List<Reader> readers = new List<Reader>();
|
||||
|
||||
public static ArchiveReader GetReader(Storage storage, string path)
|
||||
{
|
||||
foreach (var reader in readers)
|
||||
{
|
||||
if (reader.Test(storage, path))
|
||||
return (ArchiveReader)Activator.CreateInstance(reader.Type, storage.GetStream(path));
|
||||
}
|
||||
throw new IOException(@"Unknown file format");
|
||||
}
|
||||
|
||||
protected static void AddReader<T>(Func<Storage, string, bool> test) where T : ArchiveReader
|
||||
{
|
||||
readers.Add(new Reader { Test = test, Type = typeof(T) });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of beatmap file names.
|
||||
/// </summary>
|
||||
public string[] BeatmapFilenames { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// The storyboard filename. Null if no storyboard is present.
|
||||
/// </summary>
|
||||
public string StoryboardFilename { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Opens a stream for reading a specific file from this archive.
|
||||
/// </summary>
|
||||
@ -51,6 +17,8 @@ namespace osu.Game.Beatmaps.IO
|
||||
|
||||
public abstract void Dispose();
|
||||
|
||||
public abstract IEnumerable<string> Filenames { get; }
|
||||
|
||||
public virtual byte[] Get(string name)
|
||||
{
|
||||
using (Stream input = GetStream(name))
|
||||
|
33
osu.Game/Beatmaps/IO/LegacyFilesystemReader.cs
Normal file
33
osu.Game/Beatmaps/IO/LegacyFilesystemReader.cs
Normal file
@ -0,0 +1,33 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Beatmaps.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads an extracted legacy beatmap from disk.
|
||||
/// </summary>
|
||||
public class LegacyFilesystemReader : ArchiveReader
|
||||
{
|
||||
private readonly string path;
|
||||
|
||||
public LegacyFilesystemReader(string path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public override Stream GetStream(string name) => File.OpenRead(Path.Combine(path, name));
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Filenames => Directory.GetFiles(path).Select(Path.GetFileName).ToArray();
|
||||
|
||||
public override Stream GetUnderlyingStream() => null;
|
||||
}
|
||||
}
|
@ -1,25 +1,15 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Ionic.Zip;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
|
||||
namespace osu.Game.Beatmaps.IO
|
||||
{
|
||||
public sealed class OszArchiveReader : ArchiveReader
|
||||
{
|
||||
public static void Register()
|
||||
{
|
||||
AddReader<OszArchiveReader>((storage, path) =>
|
||||
{
|
||||
using (var stream = storage.GetStream(path))
|
||||
return stream != null && ZipFile.IsZipFile(stream, false);
|
||||
});
|
||||
OsuLegacyDecoder.Register();
|
||||
}
|
||||
|
||||
private readonly Stream archiveStream;
|
||||
private readonly ZipFile archive;
|
||||
|
||||
@ -27,13 +17,6 @@ namespace osu.Game.Beatmaps.IO
|
||||
{
|
||||
this.archiveStream = archiveStream;
|
||||
archive = ZipFile.Read(archiveStream);
|
||||
|
||||
BeatmapFilenames = archive.Entries.Where(e => e.FileName.EndsWith(@".osu")).Select(e => e.FileName).ToArray();
|
||||
|
||||
if (BeatmapFilenames.Length == 0)
|
||||
throw new FileNotFoundException(@"This directory contains no beatmaps");
|
||||
|
||||
StoryboardFilename = archive.Entries.Where(e => e.FileName.EndsWith(@".osb")).Select(e => e.FileName).FirstOrDefault();
|
||||
}
|
||||
|
||||
public override Stream GetStream(string name)
|
||||
@ -41,7 +24,16 @@ namespace osu.Game.Beatmaps.IO
|
||||
ZipEntry entry = archive.Entries.SingleOrDefault(e => e.FileName == name);
|
||||
if (entry == null)
|
||||
throw new FileNotFoundException();
|
||||
return entry.OpenReader();
|
||||
|
||||
// allow seeking
|
||||
MemoryStream copy = new MemoryStream();
|
||||
|
||||
using (Stream s = entry.OpenReader())
|
||||
s.CopyTo(copy);
|
||||
|
||||
copy.Position = 0;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
@ -50,6 +42,8 @@ namespace osu.Game.Beatmaps.IO
|
||||
archiveStream.Dispose();
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Filenames => archive.Entries.Select(e => e.FileName).ToArray();
|
||||
|
||||
public override Stream GetUnderlyingStream() => archiveStream;
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace osu.Game.Database
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public enum RankStatus
|
||||
{
|
@ -4,7 +4,6 @@
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -1,303 +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;
|
||||
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.Screens.Menu;
|
||||
using SQLite.Net;
|
||||
using SQLiteNetExtensions.Extensions;
|
||||
|
||||
namespace osu.Game.Database
|
||||
{
|
||||
public class BeatmapDatabase : Database
|
||||
{
|
||||
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 BeatmapDatabase(Storage storage, SQLiteConnection connection, RulesetDatabase rulesets, IIpcHost importHost = null) : base(storage, connection)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
if (importHost != null)
|
||||
ipc = new BeatmapIPCChannel(importHost, this);
|
||||
}
|
||||
|
||||
private void deletePending()
|
||||
{
|
||||
foreach (var b in GetAllWithChildren<BeatmapSetInfo>(b => b.DeletePending))
|
||||
{
|
||||
if (b.Hash == Intro.MENU_MUSIC_BEATMAP_HASH)
|
||||
// this is a bit hacky, but will do for now.
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
Storage.Delete(b.Path);
|
||||
|
||||
foreach (var i in b.Beatmaps)
|
||||
{
|
||||
if (i.Metadata != null) Connection.Delete(i.Metadata);
|
||||
if (i.Difficulty != null) Connection.Delete(i.Difficulty);
|
||||
|
||||
Connection.Delete(i);
|
||||
}
|
||||
|
||||
if (b.Metadata != null) Connection.Delete(b.Metadata);
|
||||
Connection.Delete(b);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, $@"Could not delete beatmap {b}");
|
||||
}
|
||||
}
|
||||
|
||||
//this is required because sqlite migrations don't work, initially inserting nulls into this field.
|
||||
//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 DatabaseWorkingBeatmap(this, beatmapInfo);
|
||||
|
||||
previous?.TransferTo(working);
|
||||
|
||||
return working;
|
||||
}
|
||||
|
||||
public bool Exists(BeatmapSetInfo beatmapSet) => Storage.Exists(beatmapSet.Path);
|
||||
}
|
||||
}
|
@ -1,80 +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;
|
||||
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 Database
|
||||
{
|
||||
protected SQLiteConnection Connection { get; }
|
||||
protected Storage Storage { get; }
|
||||
|
||||
protected Database(Storage storage, SQLiteConnection connection)
|
||||
{
|
||||
Storage = storage;
|
||||
Connection = connection;
|
||||
|
||||
try
|
||||
{
|
||||
Prepare();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, $@"Failed to initialise the {GetType()}! Trying again with a clean database...");
|
||||
Prepare(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepare this database for use.
|
||||
/// </summary>
|
||||
protected abstract void Prepare(bool reset = false);
|
||||
|
||||
/// <summary>
|
||||
/// Reset this database to a default state. Undo all changes to database and storage backings.
|
||||
/// </summary>
|
||||
public void Reset() => Prepare(true);
|
||||
|
||||
public TableQuery<T> Query<T>() where T : class
|
||||
{
|
||||
return Connection.Table<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is expensive. Use with caution.
|
||||
/// </summary>
|
||||
public List<T> GetAllWithChildren<T>(Expression<Func<T, bool>> filter = null, bool recursive = true)
|
||||
where T : class
|
||||
{
|
||||
return Connection.GetAllWithChildren(filter, recursive);
|
||||
}
|
||||
|
||||
public T GetChildren<T>(T item, bool recursive = false)
|
||||
{
|
||||
if (item == null) return default(T);
|
||||
|
||||
Connection.GetChildren(item, recursive);
|
||||
return item;
|
||||
}
|
||||
|
||||
protected abstract Type[] ValidTypes { get; }
|
||||
|
||||
public void Update<T>(T record, bool cascade = true) where T : class
|
||||
{
|
||||
if (ValidTypes.All(t => t != typeof(T)))
|
||||
throw new ArgumentException("Must be a type managed by BeatmapDatabase", nameof(T));
|
||||
if (cascade)
|
||||
Connection.UpdateWithChildren(record);
|
||||
else
|
||||
Connection.Update(record);
|
||||
}
|
||||
}
|
||||
}
|
116
osu.Game/Database/DatabaseBackedStore.cs
Normal file
116
osu.Game/Database/DatabaseBackedStore.cs
Normal file
@ -0,0 +1,116 @@
|
||||
// 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.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 DatabaseBackedStore
|
||||
{
|
||||
protected readonly Storage Storage;
|
||||
protected readonly SQLiteConnection Connection;
|
||||
|
||||
protected virtual int StoreVersion => 1;
|
||||
|
||||
protected DatabaseBackedStore(SQLiteConnection connection, Storage storage = null)
|
||||
{
|
||||
Storage = storage;
|
||||
Connection = connection;
|
||||
|
||||
try
|
||||
{
|
||||
Prepare();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, $@"Failed to initialise the {GetType()}! Trying again with a clean database...");
|
||||
Prepare(true);
|
||||
}
|
||||
|
||||
checkMigrations();
|
||||
}
|
||||
|
||||
private void checkMigrations()
|
||||
{
|
||||
var storeName = GetType().Name;
|
||||
|
||||
var reportedVersion = Connection.Table<StoreVersion>().FirstOrDefault(s => s.StoreName == storeName) ?? new StoreVersion
|
||||
{
|
||||
StoreName = storeName,
|
||||
Version = 0
|
||||
};
|
||||
|
||||
if (reportedVersion.Version != StoreVersion)
|
||||
PerformMigration(reportedVersion.Version, reportedVersion.Version = StoreVersion);
|
||||
|
||||
Connection.InsertOrReplace(reportedVersion);
|
||||
}
|
||||
|
||||
protected virtual void PerformMigration(int currentVersion, int newVersion)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepare this database for use.
|
||||
/// </summary>
|
||||
protected abstract void Prepare(bool reset = false);
|
||||
|
||||
/// <summary>
|
||||
/// Reset this database to a default state. Undo all changes to database and storage backings.
|
||||
/// </summary>
|
||||
public void Reset() => Prepare(true);
|
||||
|
||||
|
||||
public TableQuery<T> Query<T>(Expression<Func<T, bool>> filter = null) where T : class
|
||||
{
|
||||
checkType(typeof(T));
|
||||
|
||||
var query = Connection.Table<T>();
|
||||
|
||||
if (filter != null)
|
||||
query = query.Where(filter);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query and populate results.
|
||||
/// </summary>
|
||||
/// <param name="filter">An optional filter to refine results.</param>
|
||||
/// <returns></returns>
|
||||
public List<T> QueryAndPopulate<T>(Expression<Func<T, bool>> filter = null)
|
||||
where T : class
|
||||
{
|
||||
checkType(typeof(T));
|
||||
|
||||
return Connection.GetAllWithChildren(filter, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate a database-backed item.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="recursive">Whether population should recurse beyond a single level.</param>
|
||||
public void Populate<T>(T item, bool recursive = true)
|
||||
{
|
||||
checkType(item.GetType());
|
||||
|
||||
Connection.GetChildren(item, recursive);
|
||||
}
|
||||
|
||||
private void checkType(Type type)
|
||||
{
|
||||
if (!ValidTypes.Contains(type))
|
||||
throw new InvalidOperationException($"The requested operation specified a type of {type}, which is invalid for this {nameof(DatabaseBackedStore)}.");
|
||||
}
|
||||
|
||||
protected abstract Type[] ValidTypes { get; }
|
||||
}
|
||||
}
|
@ -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 DatabaseWorkingBeatmap : WorkingBeatmap
|
||||
{
|
||||
private readonly BeatmapDatabase database;
|
||||
|
||||
public DatabaseWorkingBeatmap(BeatmapDatabase database, BeatmapInfo beatmapInfo)
|
||||
: base(beatmapInfo)
|
||||
{
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
private ArchiveReader getReader() => database?.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(); }
|
||||
}
|
||||
}
|
||||
}
|
15
osu.Game/Database/StoreVersion.cs
Normal file
15
osu.Game/Database/StoreVersion.cs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using SQLite.Net.Attributes;
|
||||
|
||||
namespace osu.Game.Database
|
||||
{
|
||||
public class StoreVersion
|
||||
{
|
||||
[PrimaryKey]
|
||||
public string StoreName { get; set; }
|
||||
|
||||
public int Version { get; set; }
|
||||
}
|
||||
}
|
@ -13,7 +13,6 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Graphics.Cursor
|
||||
{
|
||||
|
@ -13,6 +13,9 @@ namespace osu.Game.Graphics
|
||||
|
||||
public static Color4 FromHex(string hex)
|
||||
{
|
||||
if (hex[0] == '#')
|
||||
hex = hex.Substring(1);
|
||||
|
||||
switch (hex.Length)
|
||||
{
|
||||
default:
|
||||
|
24
osu.Game/IO/FileInfo.cs
Normal file
24
osu.Game/IO/FileInfo.cs
Normal file
@ -0,0 +1,24 @@
|
||||
// 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 SQLite.Net.Attributes;
|
||||
|
||||
namespace osu.Game.IO
|
||||
{
|
||||
public class FileInfo
|
||||
{
|
||||
[PrimaryKey, AutoIncrement]
|
||||
public int ID { get; set; }
|
||||
|
||||
public string Filename { get; set; }
|
||||
|
||||
[Indexed(Unique = true)]
|
||||
public string Hash { get; set; }
|
||||
|
||||
public string StoragePath => Path.Combine(Hash.Remove(1), Hash.Remove(2), Hash);
|
||||
|
||||
[Indexed]
|
||||
public int ReferenceCount { get; set; }
|
||||
}
|
||||
}
|
114
osu.Game/IO/FileStore.cs
Normal file
114
osu.Game/IO/FileStore.cs
Normal file
@ -0,0 +1,114 @@
|
||||
// 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.IO.Stores;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Database;
|
||||
using SQLite.Net;
|
||||
|
||||
namespace osu.Game.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles the Store and retrieval of Files/FileSets to the database backing
|
||||
/// </summary>
|
||||
public class FileStore : DatabaseBackedStore
|
||||
{
|
||||
private const string prefix = "files";
|
||||
|
||||
public readonly ResourceStore<byte[]> Store;
|
||||
|
||||
public FileStore(SQLiteConnection connection, Storage storage) : base(connection, storage)
|
||||
{
|
||||
Store = new NamespacedResourceStore<byte[]>(new StorageBackedResourceStore(storage), prefix);
|
||||
}
|
||||
|
||||
protected override Type[] ValidTypes => new[] {
|
||||
typeof(FileInfo),
|
||||
};
|
||||
|
||||
protected override void Prepare(bool reset = false)
|
||||
{
|
||||
if (reset)
|
||||
Connection.DropTable<FileInfo>();
|
||||
|
||||
Connection.CreateTable<FileInfo>();
|
||||
|
||||
deletePending();
|
||||
}
|
||||
|
||||
public FileInfo Add(Stream data, string filename = null)
|
||||
{
|
||||
string hash = data.ComputeSHA2Hash();
|
||||
|
||||
var info = new FileInfo
|
||||
{
|
||||
Filename = filename,
|
||||
Hash = hash,
|
||||
};
|
||||
|
||||
var existing = Connection.Table<FileInfo>().FirstOrDefault(f => f.Hash == info.Hash);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
info = existing;
|
||||
}
|
||||
else
|
||||
{
|
||||
string path = Path.Combine(prefix, info.StoragePath);
|
||||
|
||||
data.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if (!Storage.Exists(path))
|
||||
using (var output = Storage.GetStream(path, FileAccess.Write))
|
||||
data.CopyTo(output);
|
||||
|
||||
data.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
Connection.Insert(info);
|
||||
}
|
||||
|
||||
Reference(new[] { info });
|
||||
return info;
|
||||
}
|
||||
|
||||
public void Reference(IEnumerable<FileInfo> files)
|
||||
{
|
||||
foreach (var f in files)
|
||||
{
|
||||
f.ReferenceCount++;
|
||||
Connection.Update(f);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dereference(IEnumerable<FileInfo> files)
|
||||
{
|
||||
foreach (var f in files)
|
||||
{
|
||||
f.ReferenceCount--;
|
||||
Connection.Update(f);
|
||||
}
|
||||
}
|
||||
|
||||
private void deletePending()
|
||||
{
|
||||
foreach (var f in QueryAndPopulate<FileInfo>(f => f.ReferenceCount < 1))
|
||||
{
|
||||
try
|
||||
{
|
||||
Connection.Delete(f);
|
||||
Storage.Delete(Path.Combine(prefix, f.Hash));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, $@"Could not delete beatmap {f}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,15 +4,15 @@
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Game.IPC
|
||||
{
|
||||
public class BeatmapIPCChannel : IpcChannel<BeatmapImportMessage>
|
||||
{
|
||||
private readonly BeatmapDatabase beatmaps;
|
||||
private readonly BeatmapManager beatmaps;
|
||||
|
||||
public BeatmapIPCChannel(IIpcHost host, BeatmapDatabase beatmaps = null)
|
||||
public BeatmapIPCChannel(IIpcHost host, BeatmapManager beatmaps = null)
|
||||
: base(host)
|
||||
{
|
||||
this.beatmaps = beatmaps;
|
||||
|
@ -4,15 +4,15 @@
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.IPC
|
||||
{
|
||||
public class ScoreIPCChannel : IpcChannel<ScoreImportMessage>
|
||||
{
|
||||
private readonly ScoreDatabase scores;
|
||||
private readonly ScoreStore scores;
|
||||
|
||||
public ScoreIPCChannel(IIpcHost host, ScoreDatabase scores = null)
|
||||
public ScoreIPCChannel(IIpcHost host, ScoreStore scores = null)
|
||||
: base(host)
|
||||
{
|
||||
this.scores = scores;
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
|
@ -4,9 +4,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Direct;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
@ -48,7 +49,7 @@ namespace osu.Game.Online.API.Requests
|
||||
[JsonProperty(@"beatmaps")]
|
||||
private IEnumerable<GetBeatmapSetsBeatmapResponse> beatmaps { get; set; }
|
||||
|
||||
public BeatmapSetInfo ToBeatmapSet(RulesetDatabase rulesets)
|
||||
public BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets)
|
||||
{
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
@ -78,7 +79,7 @@ namespace osu.Game.Online.API.Requests
|
||||
[JsonProperty(@"difficulty_rating")]
|
||||
private double starDifficulty { get; set; }
|
||||
|
||||
public BeatmapInfo ToBeatmap(RulesetDatabase rulesets)
|
||||
public BeatmapInfo ToBeatmap(RulesetStore rulesets)
|
||||
{
|
||||
return new BeatmapInfo
|
||||
{
|
||||
|
@ -4,7 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.IO.Network;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Online.Multiplayer
|
||||
|
@ -21,10 +21,10 @@ using OpenTK;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game
|
||||
@ -99,13 +99,13 @@ namespace osu.Game
|
||||
if (args?.Length > 0)
|
||||
{
|
||||
var paths = args.Where(a => !a.StartsWith(@"-"));
|
||||
Task.Run(() => BeatmapDatabase.Import(paths.ToArray()));
|
||||
Task.Run(() => BeatmapManager.Import(paths.ToArray()));
|
||||
}
|
||||
|
||||
dependencies.Cache(this);
|
||||
|
||||
configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset);
|
||||
Ruleset.Value = RulesetDatabase.GetRuleset(configRuleset.Value);
|
||||
Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value);
|
||||
Ruleset.ValueChanged += r => configRuleset.Value = r.ID ?? 0;
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ namespace osu.Game
|
||||
return;
|
||||
}
|
||||
|
||||
Beatmap.Value = BeatmapDatabase.GetWorkingBeatmap(s.Beatmap);
|
||||
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(s.Beatmap);
|
||||
|
||||
menu.Push(new PlayerLoader(new ReplayPlayer(s.Replay)));
|
||||
}
|
||||
|
@ -11,15 +11,17 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.IO;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Graphics.Processing;
|
||||
using osu.Game.Online.API;
|
||||
using SQLite.Net;
|
||||
using osu.Framework.Graphics.Performance;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game
|
||||
{
|
||||
@ -27,11 +29,13 @@ namespace osu.Game
|
||||
{
|
||||
protected OsuConfigManager LocalConfig;
|
||||
|
||||
protected BeatmapDatabase BeatmapDatabase;
|
||||
protected BeatmapManager BeatmapManager;
|
||||
|
||||
protected RulesetDatabase RulesetDatabase;
|
||||
protected RulesetStore RulesetStore;
|
||||
|
||||
protected ScoreDatabase ScoreDatabase;
|
||||
protected FileStore FileStore;
|
||||
|
||||
protected ScoreStore ScoreStore;
|
||||
|
||||
protected override string MainResourceFile => @"osu.Game.Resources.dll";
|
||||
|
||||
@ -94,9 +98,12 @@ 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));
|
||||
connection.CreateTable<StoreVersion>();
|
||||
|
||||
dependencies.Cache(RulesetStore = new RulesetStore(connection));
|
||||
dependencies.Cache(FileStore = new FileStore(connection, Host.Storage));
|
||||
dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, FileStore, connection, RulesetStore, Host));
|
||||
dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, connection, Host, BeatmapManager));
|
||||
dependencies.Cache(new OsuColour());
|
||||
|
||||
//this completely overrides the framework default. will need to change once we make a proper FontStore.
|
||||
@ -128,9 +135,7 @@ namespace osu.Game
|
||||
|
||||
var defaultBeatmap = new DummyWorkingBeatmap(this);
|
||||
Beatmap = new NonNullableBindable<WorkingBeatmap>(defaultBeatmap);
|
||||
BeatmapDatabase.DefaultBeatmap = defaultBeatmap;
|
||||
|
||||
OszArchiveReader.Register();
|
||||
BeatmapManager.DefaultBeatmap = defaultBeatmap;
|
||||
|
||||
dependencies.Cache(API = new APIAccess
|
||||
{
|
||||
|
@ -13,6 +13,7 @@ using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Overlays.Chat
|
||||
{
|
||||
@ -164,10 +165,12 @@ namespace osu.Game.Overlays.Chat
|
||||
Padding = new MarginPadding { Left = message_padding + padding },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
new OsuTextFlowContainer(t =>
|
||||
{
|
||||
t.TextSize = text_size;
|
||||
})
|
||||
{
|
||||
Text = Message.Content,
|
||||
TextSize = text_size,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ namespace osu.Game.Overlays
|
||||
private readonly ChatTabControl channelTabs;
|
||||
|
||||
private readonly Container chatContainer;
|
||||
private readonly Container tabsArea;
|
||||
private readonly Box chatBackground;
|
||||
private readonly Box tabBackground;
|
||||
|
||||
@ -144,7 +145,7 @@ namespace osu.Game.Overlays
|
||||
loading = new LoadingAnimation(),
|
||||
}
|
||||
},
|
||||
new Container
|
||||
tabsArea = new Container
|
||||
{
|
||||
Name = @"tabs area",
|
||||
RelativeSizeAxes = Axes.X,
|
||||
@ -191,10 +192,13 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
private double startDragChatHeight;
|
||||
private bool isDragging;
|
||||
|
||||
protected override bool OnDragStart(InputState state)
|
||||
{
|
||||
if (!channelTabs.IsHovered)
|
||||
isDragging = tabsArea.IsHovered;
|
||||
|
||||
if (!isDragging)
|
||||
return base.OnDragStart(state);
|
||||
|
||||
startDragChatHeight = chatHeight.Value;
|
||||
@ -202,11 +206,21 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
protected override bool OnDrag(InputState state)
|
||||
{
|
||||
if (isDragging)
|
||||
{
|
||||
Trace.Assert(state.Mouse.PositionMouseDown != null);
|
||||
|
||||
chatHeight.Value = startDragChatHeight - (state.Mouse.Position.Y - state.Mouse.PositionMouseDown.Value.Y) / Parent.DrawSize.Y;
|
||||
return base.OnDrag(state);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool OnDragEnd(InputState state)
|
||||
{
|
||||
isDragging = false;
|
||||
return base.OnDragEnd(state);
|
||||
}
|
||||
|
||||
public void APIStateChanged(APIAccess api, APIState state)
|
||||
|
@ -8,10 +8,10 @@ using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
|
@ -9,11 +9,11 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Database;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
|
@ -6,8 +6,8 @@ using OpenTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
|
@ -7,10 +7,11 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Overlays.SearchableList;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
@ -33,7 +34,7 @@ namespace osu.Game.Overlays.Direct
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuGame game, RulesetDatabase rulesets, OsuColour colours)
|
||||
private void load(OsuGame game, RulesetStore rulesets, OsuColour colours)
|
||||
{
|
||||
DisplayStyleControl.Dropdown.AccentColour = colours.BlueDark;
|
||||
|
||||
|
@ -9,13 +9,14 @@ using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays.Direct;
|
||||
using osu.Game.Overlays.SearchableList;
|
||||
using osu.Game.Rulesets;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
@ -25,7 +26,7 @@ namespace osu.Game.Overlays
|
||||
private const float panel_padding = 10f;
|
||||
|
||||
private APIAccess api;
|
||||
private RulesetDatabase rulesets;
|
||||
private RulesetStore rulesets;
|
||||
|
||||
private readonly FillFlowContainer resultCountsContainer;
|
||||
private readonly OsuSpriteText resultCountsText;
|
||||
@ -160,7 +161,7 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, APIAccess api, RulesetDatabase rulesets)
|
||||
private void load(OsuColour colours, APIAccess api, RulesetStore rulesets)
|
||||
{
|
||||
this.api = api;
|
||||
this.rulesets = rulesets;
|
||||
|
@ -15,8 +15,8 @@ using osu.Game.Rulesets.Mods;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Database;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
@ -48,7 +48,7 @@ namespace osu.Game.Overlays.Mods
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(OsuColour colours, OsuGame osu, RulesetDatabase rulesets)
|
||||
private void load(OsuColour colours, OsuGame osu, RulesetStore rulesets)
|
||||
{
|
||||
lowMultiplierColour = colours.Red;
|
||||
highMultiplierColour = colours.Green;
|
||||
|
@ -9,7 +9,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
|
@ -6,7 +6,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Overlays.Music
|
||||
|
@ -9,7 +9,6 @@ using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
@ -27,7 +26,7 @@ namespace osu.Game.Overlays.Music
|
||||
private FilterControl filter;
|
||||
private PlaylistList list;
|
||||
|
||||
private BeatmapDatabase beatmaps;
|
||||
private BeatmapManager beatmaps;
|
||||
|
||||
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
||||
|
||||
@ -35,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, BeatmapManager beatmaps, OsuColour colours, UserInputManager inputManager)
|
||||
{
|
||||
this.inputManager = inputManager;
|
||||
this.beatmaps = beatmaps;
|
||||
@ -78,8 +77,9 @@ namespace osu.Game.Overlays.Music
|
||||
},
|
||||
};
|
||||
|
||||
list.BeatmapSets = BeatmapSets = beatmaps.GetAllWithChildren<BeatmapSetInfo>(b => !b.DeletePending).ToList();
|
||||
list.BeatmapSets = BeatmapSets = beatmaps.GetAllUsableBeatmapSets();
|
||||
|
||||
// todo: these should probably be above the query.
|
||||
beatmaps.BeatmapSetAdded += s => list.AddBeatmapSet(s);
|
||||
beatmaps.BeatmapSetRemoved += s => list.RemoveBeatmapSet(s);
|
||||
|
||||
|
@ -18,7 +18,6 @@ using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Threading;
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Overlays.Settings.Sections.Gameplay;
|
||||
using osu.Game.Rulesets;
|
||||
@ -26,7 +25,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetDatabase rulesets)
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
foreach(Ruleset ruleset in rulesets.AllRulesets.Select(info => info.CreateInstance()))
|
||||
{
|
||||
|
@ -5,9 +5,9 @@ using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Settings
|
||||
public class SettingsFooter : FillFlowContainer
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGameBase game, OsuColour colours, RulesetDatabase rulesets)
|
||||
private void load(OsuGameBase game, OsuColour colours, RulesetStore rulesets)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Toolbar
|
||||
|
@ -6,11 +6,11 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Caching;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Database;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Overlays.Toolbar
|
||||
{
|
||||
@ -65,7 +65,7 @@ namespace osu.Game.Overlays.Toolbar
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetDatabase rulesets, OsuGame game)
|
||||
private void load(RulesetStore rulesets, OsuGame game)
|
||||
{
|
||||
foreach (var r in rulesets.AllRulesets)
|
||||
{
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects
|
||||
|
@ -6,8 +6,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy
|
||||
{
|
||||
|
@ -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,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.
|
||||
/// Todo: All of this needs to be moved to a RulesetStore.
|
||||
/// </summary>
|
||||
public class RulesetDatabase : Database
|
||||
public class RulesetStore : DatabaseBackedStore
|
||||
{
|
||||
public IEnumerable<RulesetInfo> AllRulesets => Query<RulesetInfo>().Where(r => r.Available);
|
||||
|
||||
public RulesetDatabase(Storage storage, SQLiteConnection connection)
|
||||
: base(storage, connection)
|
||||
public RulesetStore(SQLiteConnection connection) : base(connection)
|
||||
{
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
@ -4,30 +4,30 @@
|
||||
using System;
|
||||
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 : Database
|
||||
public class ScoreStore : DatabaseBackedStore
|
||||
{
|
||||
private readonly Storage storage;
|
||||
|
||||
private readonly BeatmapDatabase beatmaps;
|
||||
private readonly RulesetDatabase rulesets;
|
||||
private readonly BeatmapManager beatmaps;
|
||||
private readonly RulesetStore rulesets;
|
||||
|
||||
private const string replay_folder = @"replays";
|
||||
|
||||
// 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, BeatmapDatabase beatmaps = null, RulesetDatabase rulesets = null) : base(storage, connection)
|
||||
public ScoreStore(Storage storage, SQLiteConnection connection, IIpcHost importHost = null, BeatmapManager beatmaps = null, RulesetStore rulesets = null) : base(connection)
|
||||
{
|
||||
this.storage = storage;
|
||||
this.beatmaps = beatmaps;
|
||||
@ -53,7 +53,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.QueryBeatmap(b => b.Hash == beatmapHash);
|
||||
/* score.PlayerName = */
|
||||
sr.ReadString();
|
||||
/* var localScoreChecksum = */
|
@ -9,9 +9,9 @@ using osu.Framework.Configuration;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.IO;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using OpenTK.Graphics;
|
||||
@ -22,7 +22,7 @@ namespace osu.Game.Screens.Menu
|
||||
{
|
||||
private readonly OsuLogo logo;
|
||||
|
||||
public const string MENU_MUSIC_BEATMAP_HASH = "21c1271b91234385978b5418881fdd88";
|
||||
private const string menu_music_beatmap_hash = "715a09144f885d746644c1983e285044";
|
||||
|
||||
/// <summary>
|
||||
/// Whether we have loaded the menu previously.
|
||||
@ -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, BeatmapManager beatmaps, Framework.Game game)
|
||||
{
|
||||
menuVoice = config.GetBindable<bool>(OsuSetting.MenuVoice);
|
||||
menuMusic = config.GetBindable<bool>(OsuSetting.MenuMusic);
|
||||
@ -76,31 +76,25 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
if (!menuMusic)
|
||||
{
|
||||
var query = beatmaps.Query<BeatmapSetInfo>().Where(b => !b.DeletePending);
|
||||
int count = query.Count();
|
||||
if (count > 0)
|
||||
setInfo = query.ElementAt(RNG.Next(0, count - 1));
|
||||
var sets = beatmaps.GetAllUsableBeatmapSets(false);
|
||||
if (sets.Count > 0)
|
||||
setInfo = beatmaps.QueryBeatmapSet(s => s.ID == sets[RNG.Next(0, sets.Count - 1)].ID);
|
||||
}
|
||||
|
||||
if (setInfo == null)
|
||||
{
|
||||
var query = beatmaps.Query<BeatmapSetInfo>().Where(b => b.Hash == MENU_MUSIC_BEATMAP_HASH);
|
||||
|
||||
setInfo = query.FirstOrDefault();
|
||||
setInfo = beatmaps.QueryBeatmapSet(b => b.Hash == menu_music_beatmap_hash);
|
||||
|
||||
if (setInfo == null)
|
||||
{
|
||||
// we need to import the default menu background beatmap
|
||||
beatmaps.Import(new OszArchiveReader(game.Resources.GetStream(@"Tracks/circles.osz")));
|
||||
setInfo = beatmaps.Import(new OszArchiveReader(game.Resources.GetStream(@"Tracks/circles.osz")));
|
||||
|
||||
setInfo = query.First();
|
||||
|
||||
setInfo.DeletePending = true;
|
||||
beatmaps.Update(setInfo, false);
|
||||
setInfo.Protected = true;
|
||||
beatmaps.Delete(setInfo);
|
||||
}
|
||||
}
|
||||
|
||||
beatmaps.GetChildren(setInfo);
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
|
||||
|
||||
track = Beatmap.Value.Track;
|
||||
|
@ -10,8 +10,8 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
@ -4,8 +4,8 @@
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
|
||||
namespace osu.Game.Screens.Multiplayer
|
||||
|
@ -13,8 +13,8 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
@ -6,11 +6,11 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using OpenTK;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Screens
|
||||
{
|
||||
|
@ -13,7 +13,6 @@ using osu.Framework.Logging;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
|
@ -7,7 +7,6 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user