diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index c4cbce6430..8728d776d0 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -63,6 +63,8 @@ namespace osu.Game.Beatmaps
public override string[] HandledExtensions => new[] { ".osz" };
+ protected override string[] HashableFileTypes => new[] { ".osu" };
+
protected override string ImportFromStablePath => "Songs";
private readonly RulesetStore rulesets;
@@ -129,9 +131,6 @@ namespace osu.Game.Beatmaps
beatmaps.ForEach(b => b.OnlineBeatmapID = null);
}
- protected override BeatmapSetInfo CheckForExisting(BeatmapSetInfo model) =>
- beatmaps.ConsumableItems.FirstOrDefault(b => b.Hash == model.Hash);
-
///
/// Downloads a beatmap.
/// This will post notifications tracking progress.
@@ -307,20 +306,6 @@ namespace osu.Game.Beatmaps
/// Results from the provided query.
public IQueryable QueryBeatmaps(Expression> query) => beatmaps.Beatmaps.AsNoTracking().Where(query);
- ///
- /// Create a SHA-2 hash from the provided archive based on contained beatmap (.osu) file content.
- ///
- private string computeBeatmapSetHash(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);
-
- return hashable.ComputeSHA2Hash();
- }
-
protected override BeatmapSetInfo CreateModel(ArchiveReader reader)
{
// let's make sure there are actually .osu files to import.
@@ -339,7 +324,6 @@ namespace osu.Game.Beatmaps
{
OnlineBeatmapSetID = beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID,
Beatmaps = new List(),
- Hash = computeBeatmapSetHash(reader),
Metadata = beatmap.Metadata,
};
}
diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs
index 2d5cbac8f1..e2157f5fb3 100644
--- a/osu.Game/Database/ArchiveModelManager.cs
+++ b/osu.Game/Database/ArchiveModelManager.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
+using osu.Framework.Extensions;
using osu.Framework.IO.File;
using osu.Framework.Logging;
using osu.Framework.Platform;
@@ -203,7 +204,12 @@ namespace osu.Game.Database
try
{
var model = CreateModel(archive);
- return model == null ? null : Import(model, archive);
+
+ if (model == null) return null;
+
+ model.Hash = computeBeatmapSetHash(archive);
+
+ return Import(model, archive);
}
catch (Exception e)
{
@@ -212,6 +218,27 @@ namespace osu.Game.Database
}
}
+ ///
+ /// Any file extensions which should be included in hash creation.
+ /// Generally should include all file types which determine the file's uniqueness.
+ /// Large files should be avoided if possible.
+ ///
+ protected abstract string[] HashableFileTypes { get; }
+
+ ///
+ /// Create a SHA-2 hash from the provided archive based on contained beatmap (.osu) file content.
+ ///
+ private string computeBeatmapSetHash(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);
+
+ return hashable.ComputeSHA2Hash();
+ }
+
///
/// Import an item from a .
///
@@ -477,7 +504,7 @@ namespace osu.Game.Database
///
/// The new model proposed for import. Note that has not yet been run on this model.
/// An existing model which matches the criteria to skip importing, else null.
- protected virtual TModel CheckForExisting(TModel model) => null;
+ protected virtual TModel CheckForExisting(TModel model) => ModelStore.ConsumableItems.FirstOrDefault(b => b.Hash == model.Hash);
private DbSet queryModel() => ContextFactory.Get().Set();
diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs
index b41b424661..ce179d43ef 100644
--- a/osu.Game/Skinning/SkinManager.cs
+++ b/osu.Game/Skinning/SkinManager.cs
@@ -26,6 +26,8 @@ namespace osu.Game.Skinning
public override string[] HandledExtensions => new[] { ".osk" };
+ protected override string[] HashableFileTypes => new[] { ".ini" };
+
protected override string ImportFromStablePath => "Skins";
public SkinManager(Storage storage, DatabaseContextFactory contextFactory, IIpcHost importHost, AudioManager audio)
@@ -67,9 +69,6 @@ namespace osu.Game.Skinning
/// A list of available .
public List GetAllUserSkins() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList();
- protected override SkinInfo CheckForExisting(SkinInfo model)
- => ModelStore.ConsumableItems.FirstOrDefault(s => s.Name == model.Name && s.Creator == model.Creator);
-
protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name };
protected override void Populate(SkinInfo model, ArchiveReader archive)