Fix `OnlinePlayBeatmapAvailabilityTracker` potentially in incorrect state

Adter an import of a modified version of a beatmap (that was already
present in the local database), it's feasible that one of these trackers
would not see the state change due to the nuances of the import process.
This commit is contained in:
Dean Herbert 2021-12-14 19:11:56 +09:00
parent 3bc2de4889
commit 453ecd21b3
1 changed files with 42 additions and 3 deletions

View File

@ -40,6 +40,11 @@ public sealed class OnlinePlayBeatmapAvailabilityTracker : CompositeDrawable
private BeatmapDownloadTracker downloadTracker; private BeatmapDownloadTracker downloadTracker;
/// <summary>
/// The beatmap matching the required hash (and providing a final <see cref="BeatmapAvailability.LocallyAvailable"/> state).
/// </summary>
private BeatmapInfo matchingHash;
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
@ -71,13 +76,34 @@ protected override void LoadComplete()
progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500); progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500);
}, true); }, true);
}, true); }, true);
// These events are needed for a fringe case where a modified/altered beatmap is imported with matching OnlineIDs.
// During the import process this will cause the existing beatmap set to be silently deleted and replaced with the new one.
// This is not exposed to us via `BeatmapDownloadTracker` so we have to take it into our own hands (as we care about the hash matching).
beatmapManager.ItemUpdated += itemUpdated;
beatmapManager.ItemRemoved += itemRemoved;
} }
private void itemUpdated(BeatmapSetInfo item) => Schedule(() =>
{
if (matchingHash?.BeatmapSet.ID == item.ID || SelectedItem.Value?.Beatmap.Value.BeatmapSet?.OnlineID == item.OnlineID)
updateAvailability();
});
private void itemRemoved(BeatmapSetInfo item) => Schedule(() =>
{
if (matchingHash?.BeatmapSet.ID == item.ID)
updateAvailability();
});
private void updateAvailability() private void updateAvailability()
{ {
if (downloadTracker == null) if (downloadTracker == null)
return; return;
// will be repopulated below if still valid.
matchingHash = null;
switch (downloadTracker.State.Value) switch (downloadTracker.State.Value)
{ {
case DownloadState.NotDownloaded: case DownloadState.NotDownloaded:
@ -93,7 +119,9 @@ private void updateAvailability()
break; break;
case DownloadState.LocallyAvailable: case DownloadState.LocallyAvailable:
bool hashMatches = checkHashValidity(); matchingHash = findMatchingHash();
bool hashMatches = matchingHash != null;
availability.Value = hashMatches ? BeatmapAvailability.LocallyAvailable() : BeatmapAvailability.NotDownloaded(); availability.Value = hashMatches ? BeatmapAvailability.LocallyAvailable() : BeatmapAvailability.NotDownloaded();
@ -108,12 +136,23 @@ private void updateAvailability()
} }
} }
private bool checkHashValidity() private BeatmapInfo findMatchingHash()
{ {
int onlineId = SelectedItem.Value.Beatmap.Value.OnlineID; int onlineId = SelectedItem.Value.Beatmap.Value.OnlineID;
string checksum = SelectedItem.Value.Beatmap.Value.MD5Hash; string checksum = SelectedItem.Value.Beatmap.Value.MD5Hash;
return beatmapManager.QueryBeatmap(b => b.OnlineID == onlineId && b.MD5Hash == checksum && !b.BeatmapSet.DeletePending) != null; return beatmapManager.QueryBeatmap(b => b.OnlineID == onlineId && b.MD5Hash == checksum && !b.BeatmapSet.DeletePending);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (beatmapManager != null)
{
beatmapManager.ItemUpdated -= itemUpdated;
beatmapManager.ItemRemoved -= itemRemoved;
}
} }
} }
} }