mirror of
https://github.com/ppy/osu.git
synced 2026-05-13 19:54:15 +08:00
Fix dragging difficulty filter slider on a very large collection causing lag (#37701)
The delayed collection evaluation (making it async) is the main fix, but the debounce seems like good to have from a sanity angle. Alternative would be `Scheduler.AddOnce` to avoid multiple input events per frame being handled. Closes https://github.com/ppy/osu/issues/37615.
This commit is contained in:
committed by
GitHub
Unverified
parent
c84777d7bf
commit
6fab856b45
@@ -144,7 +144,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddUntilStep("4 rooms visible", () => container.DrawableRooms.Count(r => r.IsPresent) == 4);
|
||||
|
||||
AddStep("filter one room", () => container.Filter.Value = new FilterCriteria { SearchString = rooms.First().Name });
|
||||
AddStep("filter one room", () => container.Filter.Value = new LoungeFilterCriteria { SearchString = rooms.First().Name });
|
||||
|
||||
AddUntilStep("1 rooms visible", () => container.DrawableRooms.Count(r => r.IsPresent) == 1);
|
||||
|
||||
@@ -160,13 +160,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddStep("add rooms", () => rooms.AddRange(GenerateRooms(3, new CatchRuleset().RulesetInfo)));
|
||||
|
||||
// Todo: What even is this case...?
|
||||
AddStep("set empty filter criteria", () => container.Filter.Value = new FilterCriteria());
|
||||
AddStep("set empty filter criteria", () => container.Filter.Value = new LoungeFilterCriteria());
|
||||
AddUntilStep("5 rooms visible", () => container.DrawableRooms.Count(r => r.IsPresent) == 5);
|
||||
|
||||
AddStep("filter osu! rooms", () => container.Filter.Value = new FilterCriteria { Ruleset = new OsuRuleset().RulesetInfo });
|
||||
AddStep("filter osu! rooms", () => container.Filter.Value = new LoungeFilterCriteria { Ruleset = new OsuRuleset().RulesetInfo });
|
||||
AddUntilStep("2 rooms visible", () => container.DrawableRooms.Count(r => r.IsPresent) == 2);
|
||||
|
||||
AddStep("filter catch rooms", () => container.Filter.Value = new FilterCriteria { Ruleset = new CatchRuleset().RulesetInfo });
|
||||
AddStep("filter catch rooms", () => container.Filter.Value = new LoungeFilterCriteria { Ruleset = new CatchRuleset().RulesetInfo });
|
||||
AddUntilStep("3 rooms visible", () => container.DrawableRooms.Count(r => r.IsPresent) == 3);
|
||||
}
|
||||
|
||||
@@ -183,11 +183,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddUntilStep("both rooms visible", () => container.DrawableRooms.Count(r => r.IsPresent) == 2);
|
||||
|
||||
AddStep("filter public rooms", () => container.Filter.Value = new FilterCriteria { Permissions = RoomPermissionsFilter.Public });
|
||||
AddStep("filter public rooms", () => container.Filter.Value = new LoungeFilterCriteria { Permissions = RoomPermissionsFilter.Public });
|
||||
|
||||
AddUntilStep("private room hidden", () => container.DrawableRooms.All(r => !r.Room.HasPassword));
|
||||
|
||||
AddStep("filter private rooms", () => container.Filter.Value = new FilterCriteria { Permissions = RoomPermissionsFilter.Private });
|
||||
AddStep("filter private rooms", () => container.Filter.Value = new LoungeFilterCriteria { Permissions = RoomPermissionsFilter.Private });
|
||||
|
||||
AddUntilStep("public room hidden", () => container.DrawableRooms.All(r => r.Room.HasPassword));
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace osu.Game.Online.Rooms
|
||||
private readonly RoomStatusFilter? status;
|
||||
private readonly string category;
|
||||
|
||||
public GetRoomsRequest(FilterCriteria filterCriteria)
|
||||
public GetRoomsRequest(LoungeFilterCriteria filterCriteria)
|
||||
{
|
||||
mode = filterCriteria.Mode;
|
||||
category = filterCriteria.Category;
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||
{
|
||||
public class FilterCriteria
|
||||
public class LoungeFilterCriteria
|
||||
{
|
||||
public string SearchString = string.Empty;
|
||||
public RoomModeFilter Mode;
|
||||
@@ -31,7 +31,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||
/// <summary>
|
||||
/// The current filter criteria. Should be managed externally.
|
||||
/// </summary>
|
||||
public readonly Bindable<FilterCriteria?> Filter = new Bindable<FilterCriteria?>();
|
||||
public readonly Bindable<LoungeFilterCriteria?> Filter = new Bindable<LoungeFilterCriteria?>();
|
||||
|
||||
/// <summary>
|
||||
/// The currently user-selected room.
|
||||
@@ -87,7 +87,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||
Filter.BindValueChanged(criteria => applyFilterCriteria(criteria.NewValue), true);
|
||||
}
|
||||
|
||||
private void applyFilterCriteria(FilterCriteria? criteria)
|
||||
private void applyFilterCriteria(LoungeFilterCriteria? criteria)
|
||||
{
|
||||
roomFlow.Children.ForEach(r =>
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
||||
private IAPIProvider api { get; set; } = null!;
|
||||
|
||||
public required Action<Room[]> RoomsReceived { get; init; }
|
||||
public readonly IBindable<FilterCriteria?> Filter = new Bindable<FilterCriteria?>();
|
||||
public readonly IBindable<LoungeFilterCriteria?> Filter = new Bindable<LoungeFilterCriteria?>();
|
||||
|
||||
private GetRoomsRequest? lastPollRequest;
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
||||
|
||||
private IDisposable? joiningRoomOperation;
|
||||
|
||||
private readonly Bindable<FilterCriteria?> filter = new Bindable<FilterCriteria?>();
|
||||
private readonly Bindable<LoungeFilterCriteria?> filter = new Bindable<LoungeFilterCriteria?>();
|
||||
private readonly Bindable<bool> hasListingResults = new Bindable<bool>();
|
||||
private readonly IBindable<bool> operationInProgress = new Bindable<bool>();
|
||||
private readonly IBindable<bool> isIdle = new BindableBool();
|
||||
@@ -262,7 +262,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
||||
filter.Value = CreateFilterCriteria();
|
||||
}
|
||||
|
||||
protected virtual FilterCriteria CreateFilterCriteria() => new FilterCriteria
|
||||
protected virtual LoungeFilterCriteria CreateFilterCriteria() => new LoungeFilterCriteria
|
||||
{
|
||||
SearchString = searchTextBox.Current.Value,
|
||||
Ruleset = ruleset.Value,
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
StatusDropdown.Current.BindValueChanged(_ => showInProgress.Alpha = StatusDropdown.Current.Value == RoomModeFilter.Open ? 1 : 0, true);
|
||||
}
|
||||
|
||||
protected override FilterCriteria CreateFilterCriteria()
|
||||
protected override LoungeFilterCriteria CreateFilterCriteria()
|
||||
{
|
||||
var criteria = base.CreateFilterCriteria();
|
||||
criteria.Category = @"realtime";
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
return base.CreateFilterControls().Append(categoryDropdown);
|
||||
}
|
||||
|
||||
protected override FilterCriteria CreateFilterCriteria()
|
||||
protected override LoungeFilterCriteria CreateFilterCriteria()
|
||||
{
|
||||
var criteria = base.CreateFilterCriteria();
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider, OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
SliderContainer.AddRange(new Drawable[]
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
@@ -13,6 +12,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Collections;
|
||||
using osu.Game.Configuration;
|
||||
@@ -244,8 +244,20 @@ namespace osu.Game.Screens.Select
|
||||
});
|
||||
|
||||
searchTextBox.Current.BindValueChanged(_ => updateCriteria());
|
||||
difficultyRangeSlider.LowerBound.BindValueChanged(_ => updateCriteria());
|
||||
difficultyRangeSlider.UpperBound.BindValueChanged(_ => updateCriteria());
|
||||
|
||||
ScheduledDelegate? sliderDebounce = null;
|
||||
|
||||
// For slider dragging (where input events can arrive very often), even creating criteria can have
|
||||
// overhead, especially when a collection is selected (see ToImmutableHashSet() call).
|
||||
void debouncedUpdateCriteria()
|
||||
{
|
||||
sliderDebounce?.Cancel();
|
||||
sliderDebounce = Scheduler.AddDelayed(() => updateCriteria(), 50);
|
||||
}
|
||||
|
||||
difficultyRangeSlider.LowerBound.BindValueChanged(_ => debouncedUpdateCriteria());
|
||||
difficultyRangeSlider.UpperBound.BindValueChanged(_ => debouncedUpdateCriteria());
|
||||
|
||||
showConvertedBeatmapsButton.Active.BindValueChanged(_ => updateCriteria());
|
||||
sortDropdown.Current.BindValueChanged(_ => updateCriteria());
|
||||
groupDropdown.Current.BindValueChanged(_ => updateCriteria());
|
||||
@@ -258,7 +270,7 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
updateCriteria();
|
||||
});
|
||||
collectionsSubscription = realm.RegisterForNotifications(r => r.All<BeatmapCollection>(), (collections, changeSet) =>
|
||||
collectionsSubscription = realm.RegisterForNotifications(r => r.All<BeatmapCollection>(), (_, changeSet) =>
|
||||
{
|
||||
if (changeSet != null && groupDropdown.Current.Value.Value == GroupMode.Collections)
|
||||
updateCriteria();
|
||||
@@ -293,7 +305,7 @@ namespace osu.Game.Screens.Select
|
||||
AllowConvertedBeatmaps = showConvertedBeatmapsButton.Active.Value,
|
||||
Ruleset = ruleset.Value,
|
||||
Mods = mods.Value,
|
||||
CollectionBeatmapMD5Hashes = collectionDropdown.Current.Value?.Collection?.PerformRead(c => c.BeatmapMD5Hashes).ToImmutableHashSet(),
|
||||
Collection = collectionDropdown.Current.Value?.Collection,
|
||||
LocalUserId = isValidUser ? localUser.Value.Id : null,
|
||||
LocalUserUsername = isValidUser ? localUser.Value.Username : null,
|
||||
};
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Collections;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Filter;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@@ -111,10 +113,24 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
}
|
||||
|
||||
private ImmutableHashSet<string>? collectionBeatmapMD5Hashes;
|
||||
private Live<BeatmapCollection>? collection;
|
||||
|
||||
/// <summary>
|
||||
/// Hashes from the <see cref="BeatmapCollection"/> to filter to.
|
||||
/// </summary>
|
||||
public IEnumerable<string>? CollectionBeatmapMD5Hashes { get; set; }
|
||||
public IEnumerable<string>? CollectionBeatmapMD5Hashes =>
|
||||
collectionBeatmapMD5Hashes ??= Collection?.PerformRead(c => c.BeatmapMD5Hashes.ToImmutableHashSet());
|
||||
|
||||
public Live<BeatmapCollection>? Collection
|
||||
{
|
||||
get => collection;
|
||||
set
|
||||
{
|
||||
collection = value;
|
||||
collectionBeatmapMD5Hashes = null;
|
||||
}
|
||||
}
|
||||
|
||||
public IRulesetFilterCriteria? RulesetCriteria { get; set; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user