mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 12:57:36 +08:00
Fix song select running updates when screen is not active
Who would have guessed that `Schedule` calls were there for a reason! I've tidied things up. Most of the changes I've made here are not required – the schedule is the main thing here. The reason the sound was playing is because one-too-many schedules was removed causing beatmap updates to update carousel specifics while still at the player loader screen. Note that the selection sound still plays on returning to song select, but this is not a regression. I'm looking at fixing this in a separate PR because I'm in a good place as far as understanding the logic right now and it would be a waste to leave it broken. Closes https://github.com/ppy/osu/issues/25875.
This commit is contained in:
parent
831c273b45
commit
64f62e7d90
@ -301,6 +301,9 @@ namespace osu.Game.Screens.Select
|
|||||||
if (loadedTestBeatmaps)
|
if (loadedTestBeatmaps)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var setsRequiringUpdate = new HashSet<BeatmapSetInfo>();
|
||||||
|
var setsRequiringRemoval = new HashSet<Guid>();
|
||||||
|
|
||||||
if (changes == null)
|
if (changes == null)
|
||||||
{
|
{
|
||||||
// During initial population, we must manually account for the fact that our original query was done on an async thread.
|
// During initial population, we must manually account for the fact that our original query was done on an async thread.
|
||||||
@ -314,67 +317,80 @@ namespace osu.Game.Screens.Select
|
|||||||
foreach (var id in realmSets)
|
foreach (var id in realmSets)
|
||||||
{
|
{
|
||||||
if (!root.BeatmapSetsByID.ContainsKey(id))
|
if (!root.BeatmapSetsByID.ContainsKey(id))
|
||||||
updateBeatmapSet(realm.Realm.Find<BeatmapSetInfo>(id)!.Detach());
|
setsRequiringUpdate.Add(realm.Realm.Find<BeatmapSetInfo>(id)!.Detach());
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var id in root.BeatmapSetsByID.Keys)
|
foreach (var id in root.BeatmapSetsByID.Keys)
|
||||||
{
|
{
|
||||||
if (!realmSets.Contains(id))
|
if (!realmSets.Contains(id))
|
||||||
removeBeatmapSet(id);
|
setsRequiringRemoval.Add(id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (int i in changes.NewModifiedIndices)
|
||||||
|
setsRequiringUpdate.Add(sender[i].Detach());
|
||||||
|
|
||||||
invalidateAfterChange();
|
foreach (int i in changes.InsertedIndices)
|
||||||
BeatmapSetsLoaded = true;
|
setsRequiringUpdate.Add(sender[i].Detach());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (int i in changes.NewModifiedIndices)
|
// All local operations must be scheduled.
|
||||||
updateBeatmapSet(sender[i].Detach());
|
//
|
||||||
|
// If we don't schedule, beatmaps getting changed while song select is suspended (ie. last played being updated)
|
||||||
foreach (int i in changes.InsertedIndices)
|
// will cause unexpected sounds and operations to occur in the background.
|
||||||
updateBeatmapSet(sender[i].Detach());
|
Schedule(() =>
|
||||||
|
|
||||||
if (changes.DeletedIndices.Length > 0 && SelectedBeatmapInfo != null)
|
|
||||||
{
|
{
|
||||||
// If SelectedBeatmapInfo is non-null, the set should also be non-null.
|
try
|
||||||
Debug.Assert(SelectedBeatmapSet != null);
|
|
||||||
|
|
||||||
// To handle the beatmap update flow, attempt to track selection changes across delete-insert transactions.
|
|
||||||
// When an update occurs, the previous beatmap set is either soft or hard deleted.
|
|
||||||
// Check if the current selection was potentially deleted by re-querying its validity.
|
|
||||||
bool selectedSetMarkedDeleted = sender.Realm.Find<BeatmapSetInfo>(SelectedBeatmapSet.ID)?.DeletePending != false;
|
|
||||||
|
|
||||||
int[] modifiedAndInserted = changes.NewModifiedIndices.Concat(changes.InsertedIndices).ToArray();
|
|
||||||
|
|
||||||
if (selectedSetMarkedDeleted && modifiedAndInserted.Any())
|
|
||||||
{
|
{
|
||||||
// If it is no longer valid, make the bold assumption that an updated version will be available in the modified/inserted indices.
|
foreach (var set in setsRequiringRemoval)
|
||||||
// This relies on the full update operation being in a single transaction, so please don't change that.
|
removeBeatmapSet(set);
|
||||||
foreach (int i in modifiedAndInserted)
|
|
||||||
|
foreach (var set in setsRequiringUpdate)
|
||||||
|
updateBeatmapSet(set);
|
||||||
|
|
||||||
|
if (changes?.DeletedIndices.Length > 0 && SelectedBeatmapInfo != null)
|
||||||
{
|
{
|
||||||
var beatmapSetInfo = sender[i];
|
// If SelectedBeatmapInfo is non-null, the set should also be non-null.
|
||||||
|
Debug.Assert(SelectedBeatmapSet != null);
|
||||||
|
|
||||||
foreach (var beatmapInfo in beatmapSetInfo.Beatmaps)
|
// To handle the beatmap update flow, attempt to track selection changes across delete-insert transactions.
|
||||||
|
// When an update occurs, the previous beatmap set is either soft or hard deleted.
|
||||||
|
// Check if the current selection was potentially deleted by re-querying its validity.
|
||||||
|
bool selectedSetMarkedDeleted = realm.Run(r => r.Find<BeatmapSetInfo>(SelectedBeatmapSet.ID)?.DeletePending != false);
|
||||||
|
|
||||||
|
if (selectedSetMarkedDeleted && setsRequiringUpdate.Any())
|
||||||
{
|
{
|
||||||
if (!((IBeatmapMetadataInfo)beatmapInfo.Metadata).Equals(SelectedBeatmapInfo.Metadata))
|
// If it is no longer valid, make the bold assumption that an updated version will be available in the modified/inserted indices.
|
||||||
continue;
|
// This relies on the full update operation being in a single transaction, so please don't change that.
|
||||||
|
foreach (var set in setsRequiringUpdate)
|
||||||
// Best effort matching. We can't use ID because in the update flow a new version will get its own GUID.
|
|
||||||
if (beatmapInfo.DifficultyName == SelectedBeatmapInfo.DifficultyName)
|
|
||||||
{
|
{
|
||||||
SelectBeatmap(beatmapInfo);
|
foreach (var beatmapInfo in set.Beatmaps)
|
||||||
return;
|
{
|
||||||
|
if (!((IBeatmapMetadataInfo)beatmapInfo.Metadata).Equals(SelectedBeatmapInfo.Metadata))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Best effort matching. We can't use ID because in the update flow a new version will get its own GUID.
|
||||||
|
if (beatmapInfo.DifficultyName == SelectedBeatmapInfo.DifficultyName)
|
||||||
|
{
|
||||||
|
SelectBeatmap(beatmapInfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a direct selection couldn't be made, it's feasible that the difficulty name (or beatmap metadata) changed.
|
||||||
|
// Let's attempt to follow set-level selection anyway.
|
||||||
|
SelectBeatmap(setsRequiringUpdate.First().Beatmaps.First());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a direct selection couldn't be made, it's feasible that the difficulty name (or beatmap metadata) changed.
|
|
||||||
// Let's attempt to follow set-level selection anyway.
|
|
||||||
SelectBeatmap(sender[modifiedAndInserted.First()].Beatmaps.First());
|
|
||||||
}
|
}
|
||||||
}
|
finally
|
||||||
|
{
|
||||||
invalidateAfterChange();
|
BeatmapSetsLoaded = true;
|
||||||
|
invalidateAfterChange();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beatmapsChanged(IRealmCollection<BeatmapInfo> sender, ChangeSet? changes)
|
private void beatmapsChanged(IRealmCollection<BeatmapInfo> sender, ChangeSet? changes)
|
||||||
|
Loading…
Reference in New Issue
Block a user