1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-12 19:42:55 +08:00

Ensure online IDs are validated for imports that don't have an associated archive too

This commit is contained in:
Dean Herbert 2018-07-19 13:41:09 +09:00
parent e3fb781a5a
commit 68614f1512

View File

@ -89,34 +89,46 @@ namespace osu.Game.Beatmaps
this.audioManager = audioManager; this.audioManager = audioManager;
} }
protected override void Populate(BeatmapSetInfo model, ArchiveReader archive) protected override void Populate(BeatmapSetInfo beatmapSet, ArchiveReader archive)
{ {
if (archive != null) if (archive != null)
model.Beatmaps = createBeatmapDifficulties(archive); beatmapSet.Beatmaps = createBeatmapDifficulties(archive);
foreach (BeatmapInfo b in model.Beatmaps) foreach (BeatmapInfo b in beatmapSet.Beatmaps)
{ {
// remove metadata from difficulties where it matches the set // remove metadata from difficulties where it matches the set
if (model.Metadata.Equals(b.Metadata)) if (beatmapSet.Metadata.Equals(b.Metadata))
b.Metadata = null; b.Metadata = null;
// by setting the model here, we can update the noline set id below. b.BeatmapSet = beatmapSet;
b.BeatmapSet = model;
fetchAndPopulateOnlineIDs(b, model.Beatmaps);
} }
// check if a set already exists with the same online id, delete if it does. // check if a set already exists with the same online id, delete if it does.
if (model.OnlineBeatmapSetID != null) if (beatmapSet.OnlineBeatmapSetID != null)
{ {
var existingOnlineId = beatmaps.ConsumableItems.FirstOrDefault(b => b.OnlineBeatmapSetID == model.OnlineBeatmapSetID); var existingOnlineId = beatmaps.ConsumableItems.FirstOrDefault(b => b.OnlineBeatmapSetID == beatmapSet.OnlineBeatmapSetID);
if (existingOnlineId != null) if (existingOnlineId != null)
{ {
Delete(existingOnlineId); Delete(existingOnlineId);
beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID); beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID);
Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({model.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database); Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({beatmapSet.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database);
} }
} }
validateOnlineIds(beatmapSet.Beatmaps);
foreach (BeatmapInfo b in beatmapSet.Beatmaps)
fetchAndPopulateOnlineIDs(b, beatmapSet.Beatmaps);
}
private void validateOnlineIds(List<BeatmapInfo> beatmaps)
{
var beatmapIds = beatmaps.Where(b => b.OnlineBeatmapID.HasValue).Select(b => b.OnlineBeatmapID);
// ensure all IDs are unique in this set and none match existing IDs in the local beatmap store.
if (beatmapIds.GroupBy(b => b).Any(g => g.Count() > 1) || QueryBeatmaps(b => beatmapIds.Contains(b.OnlineBeatmapID)).Any())
// remove all online IDs if any problems were found.
beatmaps.ForEach(b => b.OnlineBeatmapID = null);
} }
protected override BeatmapSetInfo CheckForExisting(BeatmapSetInfo model) protected override BeatmapSetInfo CheckForExisting(BeatmapSetInfo model)
@ -297,7 +309,7 @@ namespace osu.Game.Beatmaps
/// </summary> /// </summary>
/// <param name="query">The query.</param> /// <param name="query">The query.</param>
/// <returns>Results from the provided query.</returns> /// <returns>Results from the provided query.</returns>
public IEnumerable<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>> query) => beatmaps.Beatmaps.AsNoTracking().Where(query); public IQueryable<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>> query) => beatmaps.Beatmaps.AsNoTracking().Where(query);
/// <summary> /// <summary>
/// Denotes whether an osu-stable installation is present to perform automated imports from. /// Denotes whether an osu-stable installation is present to perform automated imports from.
@ -360,8 +372,6 @@ namespace osu.Game.Beatmaps
{ {
var beatmapInfos = new List<BeatmapInfo>(); var beatmapInfos = new List<BeatmapInfo>();
bool invalidateOnlineIDs = false;
foreach (var name in reader.Filenames.Where(f => f.EndsWith(".osu"))) foreach (var name in reader.Filenames.Where(f => f.EndsWith(".osu")))
{ {
using (var raw = reader.GetStream(name)) using (var raw = reader.GetStream(name))
@ -378,38 +388,15 @@ namespace osu.Game.Beatmaps
beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash(); beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash();
beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash(); beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash();
if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue) var ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID);
{
var ourId = beatmap.BeatmapInfo.OnlineBeatmapID;
// check that no existing beatmap in database exists that is imported with the same online beatmap ID. if so, give it precedence.
if (QueryBeatmap(b => b.OnlineBeatmapID.Value == ourId) != null)
beatmap.BeatmapInfo.OnlineBeatmapID = null;
// check that no other beatmap in this imported set has a conflicting online beatmap ID. If so, presume *all* are incorrect.
if (beatmapInfos.Any(b => b.OnlineBeatmapID == ourId))
invalidateOnlineIDs = true;
}
RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID);
beatmap.BeatmapInfo.Ruleset = ruleset; beatmap.BeatmapInfo.Ruleset = ruleset;
// TODO: this should be done in a better place once we actually need to dynamically update it.
if (ruleset != null) beatmap.BeatmapInfo.StarDifficulty = ruleset?.CreateInstance().CreateDifficultyCalculator(new DummyConversionBeatmap(beatmap)).Calculate().StarRating ?? 0;
{
// TODO: this should be done in a better place once we actually need to dynamically update it.
beatmap.BeatmapInfo.StarDifficulty = ruleset.CreateInstance().CreateDifficultyCalculator(new DummyConversionBeatmap(beatmap)).Calculate().StarRating;
}
else
beatmap.BeatmapInfo.StarDifficulty = 0;
beatmapInfos.Add(beatmap.BeatmapInfo); beatmapInfos.Add(beatmap.BeatmapInfo);
} }
} }
if (invalidateOnlineIDs)
beatmapInfos.ForEach(b => b.OnlineBeatmapID = null);
return beatmapInfos; return beatmapInfos;
} }
@ -422,12 +409,12 @@ namespace osu.Game.Beatmaps
/// <returns>True if population was successful.</returns> /// <returns>True if population was successful.</returns>
private bool fetchAndPopulateOnlineIDs(BeatmapInfo beatmap, IEnumerable<BeatmapInfo> otherBeatmaps, bool force = false) private bool fetchAndPopulateOnlineIDs(BeatmapInfo beatmap, IEnumerable<BeatmapInfo> otherBeatmaps, bool force = false)
{ {
if (api?.State != APIState.Online)
return false;
if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null) if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null)
return true; return true;
if (api.State != APIState.Online)
return false;
Logger.Log("Attempting online lookup for IDs...", LoggingTarget.Database); Logger.Log("Attempting online lookup for IDs...", LoggingTarget.Database);
try try