1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-16 05:03:02 +08:00

Merge pull request #16626 from peppy/fix-skin-section-realm-usage

Refactor `SkinSection` to avoid unnecessary realm queries
This commit is contained in:
Dan Balasescu 2022-01-26 19:01:15 +09:00 committed by GitHub
commit b1a23486c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 48 deletions

View File

@ -216,12 +216,6 @@ namespace osu.Game.Database
return new RealmLiveUnmanaged<T>(realmObject); return new RealmLiveUnmanaged<T>(realmObject);
} }
public static List<Live<T>> ToLive<T>(this IEnumerable<T> realmList, RealmAccess realm)
where T : RealmObject, IHasGuidPrimaryKey
{
return realmList.Select(l => new RealmLive<T>(l, realm)).Cast<Live<T>>().ToList();
}
public static Live<T> ToLive<T>(this T realmObject, RealmAccess realm) public static Live<T> ToLive<T>(this T realmObject, RealmAccess realm)
where T : RealmObject, IHasGuidPrimaryKey where T : RealmObject, IHasGuidPrimaryKey
{ {

View File

@ -18,6 +18,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation; using osu.Game.Localisation;
using osu.Game.Skinning; using osu.Game.Skinning;
using osu.Game.Skinning.Editor; using osu.Game.Skinning.Editor;
using Realms;
namespace osu.Game.Overlays.Settings.Sections namespace osu.Game.Overlays.Settings.Sections
{ {
@ -41,7 +42,7 @@ namespace osu.Game.Overlays.Settings.Sections
Name = "<Random Skin>", Name = "<Random Skin>",
}.ToLiveUnmanaged(); }.ToLiveUnmanaged();
private List<Live<SkinInfo>> skinItems; private readonly List<Live<SkinInfo>> dropdownItems = new List<Live<SkinInfo>>();
[Resolved] [Resolved]
private SkinManager skins { get; set; } private SkinManager skins { get; set; }
@ -51,12 +52,6 @@ namespace osu.Game.Overlays.Settings.Sections
private IDisposable realmSubscription; private IDisposable realmSubscription;
private IQueryable<SkinInfo> queryRealmSkins() =>
realm.Realm.All<SkinInfo>()
.Where(s => !s.DeletePending)
.OrderByDescending(s => s.Protected) // protected skins should be at the top.
.ThenBy(s => s.Name, StringComparer.OrdinalIgnoreCase);
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuConfigManager config, [CanBeNull] SkinEditorOverlay skinEditor) private void load(OsuConfigManager config, [CanBeNull] SkinEditorOverlay skinEditor)
{ {
@ -83,20 +78,21 @@ namespace osu.Game.Overlays.Settings.Sections
skinDropdown.Current = dropdownBindable; skinDropdown.Current = dropdownBindable;
realmSubscription = realm.RegisterForNotifications(r => queryRealmSkins(), (sender, changes, error) => realmSubscription = realm.RegisterForNotifications(r => realm.Realm.All<SkinInfo>()
{ .Where(s => !s.DeletePending)
// The first fire of this is a bit redundant due to the call below, .OrderByDescending(s => s.Protected) // protected skins should be at the top.
// but this is safest in case the subscription is restored after a context recycle. .ThenBy(s => s.Name, StringComparer.OrdinalIgnoreCase), skinsChanged);
updateItems();
});
updateItems();
configBindable.BindValueChanged(id => Scheduler.AddOnce(updateSelectedSkinFromConfig)); configBindable.BindValueChanged(id => Scheduler.AddOnce(updateSelectedSkinFromConfig));
updateSelectedSkinFromConfig();
dropdownBindable.BindValueChanged(skin => dropdownBindable.BindValueChanged(dropdownSelectionChanged);
}
private void dropdownSelectionChanged(ValueChangedEvent<Live<SkinInfo>> skin)
{ {
// Only handle cases where it's clear the user has intent to change skins.
if (skin.OldValue == null) return;
if (skin.NewValue.Equals(random_skin_info)) if (skin.NewValue.Equals(random_skin_info))
{ {
var skinBefore = skins.CurrentSkinInfo.Value; var skinBefore = skins.CurrentSkinInfo.Value;
@ -113,7 +109,27 @@ namespace osu.Game.Overlays.Settings.Sections
} }
configBindable.Value = skin.NewValue.ID.ToString(); configBindable.Value = skin.NewValue.ID.ToString();
}); }
private void skinsChanged(IRealmCollection<SkinInfo> sender, ChangeSet changes, Exception error)
{
// This can only mean that realm is recycling, else we would see the protected skins.
// Because we are using `Live<>` in this class, we don't need to worry about this scenario too much.
if (!sender.Any())
return;
int protectedCount = sender.Count(s => s.Protected);
// For simplicity repopulate the full list.
// In the future we should change this to properly handle ChangeSet events.
dropdownItems.Clear();
foreach (var skin in sender)
dropdownItems.Add(skin.ToLive(realm));
dropdownItems.Insert(protectedCount, random_skin_info);
skinDropdown.Items = dropdownItems;
updateSelectedSkinFromConfig();
} }
private void updateSelectedSkinFromConfig() private void updateSelectedSkinFromConfig()
@ -126,17 +142,6 @@ namespace osu.Game.Overlays.Settings.Sections
dropdownBindable.Value = skin ?? skinDropdown.Items.First(); dropdownBindable.Value = skin ?? skinDropdown.Items.First();
} }
private void updateItems()
{
int protectedCount = queryRealmSkins().Count(s => s.Protected);
skinItems = queryRealmSkins().ToLive(realm);
skinItems.Insert(protectedCount, random_skin_info);
skinDropdown.Items = skinItems;
}
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);