mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 10:12:54 +08:00
Merge branch 'master' into realm-integration/stable-export-flow
This commit is contained in:
commit
d3a4890c31
@ -1050,7 +1050,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
|
|
||||||
private static void checkSingleReferencedFileCount(OsuGameBase osu, int expected)
|
private static void checkSingleReferencedFileCount(OsuGameBase osu, int expected)
|
||||||
{
|
{
|
||||||
Assert.AreEqual(expected, osu.Dependencies.Get<FileStore>().QueryFiles(f => f.ReferenceCount == 1).Count());
|
Assert.AreEqual(expected, osu.Dependencies.Get<DatabaseContextFactory>().Get().FileInfo.Count(f => f.ReferenceCount == 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ensureLoaded(OsuGameBase osu, int timeout = 60000)
|
private static void ensureLoaded(OsuGameBase osu, int timeout = 60000)
|
||||||
|
@ -572,7 +572,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddStep("add mixed ruleset beatmapset", () =>
|
AddStep("add mixed ruleset beatmapset", () =>
|
||||||
{
|
{
|
||||||
testMixed = TestResources.CreateTestBeatmapSetInfo();
|
testMixed = TestResources.CreateTestBeatmapSetInfo(3);
|
||||||
|
|
||||||
for (int i = 0; i <= 2; i++)
|
for (int i = 0; i <= 2; i++)
|
||||||
{
|
{
|
||||||
@ -595,7 +595,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
BeatmapSetInfo testSingle = null;
|
BeatmapSetInfo testSingle = null;
|
||||||
AddStep("add single ruleset beatmapset", () =>
|
AddStep("add single ruleset beatmapset", () =>
|
||||||
{
|
{
|
||||||
testSingle = TestResources.CreateTestBeatmapSetInfo();
|
testSingle = TestResources.CreateTestBeatmapSetInfo(3);
|
||||||
testSingle.Beatmaps.ForEach(b =>
|
testSingle.Beatmaps.ForEach(b =>
|
||||||
{
|
{
|
||||||
b.Ruleset = rulesets.AvailableRulesets.ElementAt(1);
|
b.Ruleset = rulesets.AvailableRulesets.ElementAt(1);
|
||||||
@ -615,7 +615,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
List<BeatmapSetInfo> manySets = new List<BeatmapSetInfo>();
|
List<BeatmapSetInfo> manySets = new List<BeatmapSetInfo>();
|
||||||
|
|
||||||
for (int i = 1; i <= 50; i++)
|
for (int i = 1; i <= 50; i++)
|
||||||
manySets.Add(TestResources.CreateTestBeatmapSetInfo(i));
|
manySets.Add(TestResources.CreateTestBeatmapSetInfo(3));
|
||||||
|
|
||||||
loadBeatmaps(manySets);
|
loadBeatmaps(manySets);
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Database
|
|||||||
/// <param name="obj">The object to use as a reference when negotiating a local instance.</param>
|
/// <param name="obj">The object to use as a reference when negotiating a local instance.</param>
|
||||||
/// <param name="lookupSource">An optional lookup source which will be used to query and populate a freshly retrieved replacement. If not provided, the refreshed object will still be returned but will not have any includes.</param>
|
/// <param name="lookupSource">An optional lookup source which will be used to query and populate a freshly retrieved replacement. If not provided, the refreshed object will still be returned but will not have any includes.</param>
|
||||||
/// <typeparam name="T">A valid EF-stored type.</typeparam>
|
/// <typeparam name="T">A valid EF-stored type.</typeparam>
|
||||||
protected virtual void Refresh<T>(ref T obj, IQueryable<T> lookupSource = null) where T : class, IHasPrimaryKey
|
protected void Refresh<T>(ref T obj, IQueryable<T> lookupSource = null) where T : class, IHasPrimaryKey
|
||||||
{
|
{
|
||||||
using (var usage = ContextFactory.GetForWrite())
|
using (var usage = ContextFactory.GetForWrite())
|
||||||
{
|
{
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Database
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles migration of legacy user data from osu-stable.
|
/// Handles migration of legacy user data from osu-stable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LeagcyImportManager : Component
|
public class LegacyImportManager : Component
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private SkinManager skins { get; set; }
|
private SkinManager skins { get; set; }
|
@ -1,3 +1,6 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Database
|
||||||
@ -11,4 +14,4 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ using osu.Framework.Statistics;
|
|||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Models;
|
using osu.Game.Models;
|
||||||
|
using osu.Game.Stores;
|
||||||
using Realms;
|
using Realms;
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
@ -121,6 +122,10 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clean up files after dropping any pending deletions.
|
||||||
|
// in the future we may want to only do this when the game is idle, rather than on every startup.
|
||||||
|
new RealmFileStore(this, storage).Cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -2,11 +2,8 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
@ -31,13 +28,6 @@ namespace osu.Game.IO
|
|||||||
Store = new StorageBackedResourceStore(Storage);
|
Store = new StorageBackedResourceStore(Storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Perform a lookup query on available <see cref="FileInfo"/>s.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="query">The query.</param>
|
|
||||||
/// <returns>Results from the provided query.</returns>
|
|
||||||
public IEnumerable<FileInfo> QueryFiles(Expression<Func<FileInfo, bool>> query) => ContextFactory.Get().Set<FileInfo>().AsNoTracking().Where(f => f.ReferenceCount > 0).Where(query);
|
|
||||||
|
|
||||||
public FileInfo Add(Stream data, bool reference = true)
|
public FileInfo Add(Stream data, bool reference = true)
|
||||||
{
|
{
|
||||||
using (var usage = ContextFactory.GetForWrite())
|
using (var usage = ContextFactory.GetForWrite())
|
||||||
|
@ -116,7 +116,7 @@ namespace osu.Game
|
|||||||
private readonly DifficultyRecommender difficultyRecommender = new DifficultyRecommender();
|
private readonly DifficultyRecommender difficultyRecommender = new DifficultyRecommender();
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
private readonly LeagcyImportManager leagcyImportManager = new LeagcyImportManager();
|
private readonly LegacyImportManager legacyImportManager = new LegacyImportManager();
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
private readonly ScreenshotManager screenshotManager = new ScreenshotManager();
|
private readonly ScreenshotManager screenshotManager = new ScreenshotManager();
|
||||||
@ -782,7 +782,7 @@ namespace osu.Game
|
|||||||
PostNotification = n => Notifications.Post(n),
|
PostNotification = n => Notifications.Post(n),
|
||||||
}, Add, true);
|
}, Add, true);
|
||||||
|
|
||||||
loadComponentSingleFile(leagcyImportManager, Add);
|
loadComponentSingleFile(legacyImportManager, Add);
|
||||||
|
|
||||||
loadComponentSingleFile(screenshotManager, Add);
|
loadComponentSingleFile(screenshotManager, Add);
|
||||||
|
|
||||||
|
@ -31,9 +31,9 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
private SettingsButton undeleteButton;
|
private SettingsButton undeleteButton;
|
||||||
|
|
||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] LeagcyImportManager leagcyImportManager, DialogOverlay dialogOverlay)
|
private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] LegacyImportManager legacyImportManager, DialogOverlay dialogOverlay)
|
||||||
{
|
{
|
||||||
if (leagcyImportManager?.SupportsImportFromStable == true)
|
if (legacyImportManager?.SupportsImportFromStable == true)
|
||||||
{
|
{
|
||||||
Add(importBeatmapsButton = new SettingsButton
|
Add(importBeatmapsButton = new SettingsButton
|
||||||
{
|
{
|
||||||
@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
Action = () =>
|
Action = () =>
|
||||||
{
|
{
|
||||||
importBeatmapsButton.Enabled.Value = false;
|
importBeatmapsButton.Enabled.Value = false;
|
||||||
leagcyImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true));
|
legacyImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -59,7 +59,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (leagcyImportManager?.SupportsImportFromStable == true)
|
if (legacyImportManager?.SupportsImportFromStable == true)
|
||||||
{
|
{
|
||||||
Add(importScoresButton = new SettingsButton
|
Add(importScoresButton = new SettingsButton
|
||||||
{
|
{
|
||||||
@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
Action = () =>
|
Action = () =>
|
||||||
{
|
{
|
||||||
importScoresButton.Enabled.Value = false;
|
importScoresButton.Enabled.Value = false;
|
||||||
leagcyImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true));
|
legacyImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -85,7 +85,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (leagcyImportManager?.SupportsImportFromStable == true)
|
if (legacyImportManager?.SupportsImportFromStable == true)
|
||||||
{
|
{
|
||||||
Add(importSkinsButton = new SettingsButton
|
Add(importSkinsButton = new SettingsButton
|
||||||
{
|
{
|
||||||
@ -93,7 +93,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
Action = () =>
|
Action = () =>
|
||||||
{
|
{
|
||||||
importSkinsButton.Enabled.Value = false;
|
importSkinsButton.Enabled.Value = false;
|
||||||
leagcyImportManager.ImportFromStableAsync(StableContent.Skins).ContinueWith(t => Schedule(() => importSkinsButton.Enabled.Value = true));
|
legacyImportManager.ImportFromStableAsync(StableContent.Skins).ContinueWith(t => Schedule(() => importSkinsButton.Enabled.Value = true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
|
|
||||||
if (collectionManager != null)
|
if (collectionManager != null)
|
||||||
{
|
{
|
||||||
if (leagcyImportManager?.SupportsImportFromStable == true)
|
if (legacyImportManager?.SupportsImportFromStable == true)
|
||||||
{
|
{
|
||||||
Add(importCollectionsButton = new SettingsButton
|
Add(importCollectionsButton = new SettingsButton
|
||||||
{
|
{
|
||||||
@ -121,7 +121,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
Action = () =>
|
Action = () =>
|
||||||
{
|
{
|
||||||
importCollectionsButton.Enabled.Value = false;
|
importCollectionsButton.Enabled.Value = false;
|
||||||
leagcyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true));
|
legacyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ using osu.Game.Rulesets.Scoring;
|
|||||||
|
|
||||||
namespace osu.Game.Scoring
|
namespace osu.Game.Scoring
|
||||||
{
|
{
|
||||||
public class ScoreManager : IModelManager<ScoreInfo>, IModelImporter<ScoreInfo>, IModelFileManager<ScoreInfo, ScoreFileInfo>, IModelDownloader<IScoreInfo>
|
public class ScoreManager : IModelManager<ScoreInfo>, IModelImporter<ScoreInfo>, IModelDownloader<IScoreInfo>
|
||||||
{
|
{
|
||||||
private readonly Scheduler scheduler;
|
private readonly Scheduler scheduler;
|
||||||
private readonly Func<BeatmapDifficultyCache> difficulties;
|
private readonly Func<BeatmapDifficultyCache> difficulties;
|
||||||
@ -326,25 +326,6 @@ namespace osu.Game.Scoring
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Implementation of IModelFileManager<in ScoreInfo,in ScoreFileInfo>
|
|
||||||
|
|
||||||
public void ReplaceFile(ScoreInfo model, ScoreFileInfo file, Stream contents, string filename = null)
|
|
||||||
{
|
|
||||||
scoreModelManager.ReplaceFile(model, file, contents, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DeleteFile(ScoreInfo model, ScoreFileInfo file)
|
|
||||||
{
|
|
||||||
scoreModelManager.DeleteFile(model, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddFile(ScoreInfo model, Stream contents, string filename)
|
|
||||||
{
|
|
||||||
scoreModelManager.AddFile(model, contents, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Implementation of IModelDownloader<IScoreInfo>
|
#region Implementation of IModelDownloader<IScoreInfo>
|
||||||
|
|
||||||
public event Action<ArchiveDownloadRequest<IScoreInfo>> DownloadBegan
|
public event Action<ArchiveDownloadRequest<IScoreInfo>> DownloadBegan
|
||||||
|
@ -51,7 +51,7 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
protected virtual bool ShowFooter => true;
|
protected virtual bool ShowFooter => true;
|
||||||
|
|
||||||
protected virtual bool DisplayStableImportPrompt => leagcyImportManager?.SupportsImportFromStable == true;
|
protected virtual bool DisplayStableImportPrompt => legacyImportManager?.SupportsImportFromStable == true;
|
||||||
|
|
||||||
public override bool? AllowTrackAdjustments => true;
|
public override bool? AllowTrackAdjustments => true;
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ namespace osu.Game.Screens.Select
|
|||||||
private BeatmapManager beatmaps { get; set; }
|
private BeatmapManager beatmaps { get; set; }
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private LeagcyImportManager leagcyImportManager { get; set; }
|
private LegacyImportManager legacyImportManager { get; set; }
|
||||||
|
|
||||||
protected ModSelectOverlay ModSelect { get; private set; }
|
protected ModSelectOverlay ModSelect { get; private set; }
|
||||||
|
|
||||||
@ -297,7 +297,7 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
dialogOverlay.Push(new ImportFromStablePopup(() =>
|
dialogOverlay.Push(new ImportFromStablePopup(() =>
|
||||||
{
|
{
|
||||||
Task.Run(() => leagcyImportManager.ImportFromStableAsync(StableContent.All));
|
Task.Run(() => legacyImportManager.ImportFromStableAsync(StableContent.All));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -86,9 +86,13 @@ namespace osu.Game.Stores
|
|||||||
|
|
||||||
public void Cleanup()
|
public void Cleanup()
|
||||||
{
|
{
|
||||||
var realm = realmFactory.Context;
|
Logger.Log(@"Beginning realm file store cleanup");
|
||||||
|
|
||||||
|
int totalFiles = 0;
|
||||||
|
int removedFiles = 0;
|
||||||
|
|
||||||
// can potentially be run asynchronously, although we will need to consider operation order for disk deletion vs realm removal.
|
// can potentially be run asynchronously, although we will need to consider operation order for disk deletion vs realm removal.
|
||||||
|
using (var realm = realmFactory.CreateContext())
|
||||||
using (var transaction = realm.BeginWrite())
|
using (var transaction = realm.BeginWrite())
|
||||||
{
|
{
|
||||||
// TODO: consider using a realm native query to avoid iterating all files (https://github.com/realm/realm-dotnet/issues/2659#issuecomment-927823707)
|
// TODO: consider using a realm native query to avoid iterating all files (https://github.com/realm/realm-dotnet/issues/2659#issuecomment-927823707)
|
||||||
@ -96,11 +100,14 @@ namespace osu.Game.Stores
|
|||||||
|
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
|
totalFiles++;
|
||||||
|
|
||||||
if (file.BacklinksCount > 0)
|
if (file.BacklinksCount > 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
removedFiles++;
|
||||||
Storage.Delete(file.GetStoragePath());
|
Storage.Delete(file.GetStoragePath());
|
||||||
realm.Remove(file);
|
realm.Remove(file);
|
||||||
}
|
}
|
||||||
@ -112,6 +119,8 @@ namespace osu.Game.Stores
|
|||||||
|
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Log($@"Finished realm file store cleanup ({removedFiles} of {totalFiles} deleted)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user