1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-05 09:42:54 +08:00

Compare commits

...

13 Commits

Author SHA1 Message Date
Huo Yaoyuan
7a98e191a2
Merge 938428d264 into aa0ee5cf3a 2024-12-04 10:23:34 -05:00
Salman Alshamrani
aa0ee5cf3a
Merge pull request #30970 from peppy/results-screen-quick-retry-transition
Fix quick retry transition from results screen
2024-12-04 07:12:38 -05:00
Salman Alshamrani
a7586c52d0
Merge branch 'master' into results-screen-quick-retry-transition 2024-12-04 06:31:14 -05:00
Dean Herbert
e555131b39
Merge pull request #30971 from smoogipoo/improve-multi-search
Improve multiplayer listing search by making it fuzzy
2024-12-04 00:11:32 -08:00
Dan Balasescu
ad4df82593
Improve multiplayer listing search by making it fuzzy 2024-12-04 16:26:36 +09:00
Dan Balasescu
a8963cf317
Merge pull request #30969 from peppy/buttons-search-term
Add "buttons" as a search term for key bindings
2024-12-04 15:52:12 +09:00
Dean Herbert
a4d58648e2
Fix quick retry transition from results screen 2024-12-04 14:31:39 +09:00
Dean Herbert
296fa69edd
Add "buttons" as a search term for key bindings 2024-12-04 14:30:59 +09:00
Huo Yaoyuan
938428d264 Resolve new nullability warnings 2024-11-27 21:37:25 +08:00
Huo Yaoyuan
dd045f851f Merge branch 'master' 2024-11-27 21:10:26 +08:00
Huo Yaoyuan
f5e6da7f88 Remaining cases of bindable nullability 2023-05-28 01:00:45 +08:00
Huo Yaoyuan
cb0a7d9bc1 Pass time to Section.CreatePoint 2023-05-28 00:30:20 +08:00
Huo Yaoyuan
cd50c42608 Game side bindable nullablity for easy cases 2023-05-28 00:20:33 +08:00
19 changed files with 69 additions and 41 deletions

View File

@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
{
public partial class LegacyTaikoScroller : CompositeDrawable
{
public Bindable<JudgementResult> LastResult = new Bindable<JudgementResult>();
public Bindable<JudgementResult?> LastResult = new Bindable<JudgementResult?>();
public LegacyTaikoScroller()
{

View File

@ -37,7 +37,7 @@ namespace osu.Game.Graphics.UserInterface
private partial class ToggleTextContainer : TextContainer
{
private readonly StatefulMenuItem menuItem;
private readonly Bindable<object> state;
private readonly Bindable<object?> state;
private readonly SpriteIcon stateIcon;
public ToggleTextContainer(StatefulMenuItem menuItem)
@ -61,7 +61,7 @@ namespace osu.Game.Graphics.UserInterface
state.BindValueChanged(updateState, true);
}
private void updateState(ValueChangedEvent<object> state)
private void updateState(ValueChangedEvent<object?> state)
{
var icon = menuItem.GetIconForState(state.NewValue);

View File

@ -2,7 +2,9 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Diagnostics;
using osu.Framework.Bindables;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
@ -16,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface
/// <summary>
/// The current state that should be displayed.
/// </summary>
public readonly Bindable<object> State = new Bindable<object>();
public readonly Bindable<object?> State = new Bindable<object?>();
/// <summary>
/// Creates a new <see cref="StatefulMenuItem"/>.
@ -24,7 +26,7 @@ namespace osu.Game.Graphics.UserInterface
/// <param name="text">The text to display.</param>
/// <param name="changeStateFunc">A function that mutates a state to another state after this <see cref="StatefulMenuItem"/> is pressed.</param>
/// <param name="type">The type of action which this <see cref="StatefulMenuItem"/> performs.</param>
protected StatefulMenuItem(LocalisableString text, Func<object, object> changeStateFunc, MenuItemType type = MenuItemType.Standard)
protected StatefulMenuItem(LocalisableString text, Func<object?, object?> changeStateFunc, MenuItemType type = MenuItemType.Standard)
: this(text, changeStateFunc, type, null)
{
}
@ -36,7 +38,7 @@ namespace osu.Game.Graphics.UserInterface
/// <param name="changeStateFunc">A function that mutates a state to another state after this <see cref="StatefulMenuItem"/> is pressed.</param>
/// <param name="type">The type of action which this <see cref="StatefulMenuItem"/> performs.</param>
/// <param name="action">A delegate to be invoked when this <see cref="StatefulMenuItem"/> is pressed.</param>
protected StatefulMenuItem(LocalisableString text, Func<object, object>? changeStateFunc, MenuItemType type, Action<object>? action)
protected StatefulMenuItem(LocalisableString text, Func<object?, object?>? changeStateFunc, MenuItemType type, Action<object?>? action)
: base(text, type)
{
Action.Value = () =>
@ -51,7 +53,7 @@ namespace osu.Game.Graphics.UserInterface
/// </summary>
/// <param name="state">The state to retrieve the relevant icon for.</param>
/// <returns>The icon to be displayed for <paramref name="state"/>.</returns>
public abstract IconUsage? GetIconForState(object state);
public abstract IconUsage? GetIconForState(object? state);
}
public abstract class StatefulMenuItem<T> : StatefulMenuItem
@ -81,20 +83,21 @@ namespace osu.Game.Graphics.UserInterface
/// <param name="type">The type of action which this <see cref="StatefulMenuItem"/> performs.</param>
/// <param name="action">A delegate to be invoked when this <see cref="StatefulMenuItem"/> is pressed.</param>
protected StatefulMenuItem(LocalisableString text, Func<T, T>? changeStateFunc, MenuItemType type, Action<T>? action)
: base(text, o => changeStateFunc?.Invoke((T)o) ?? o, type, o => action?.Invoke((T)o))
: base(text, o => changeStateFunc?.Invoke((T)o.AsNonNull()) ?? o, type, o => action?.Invoke((T)o.AsNonNull()))
{
base.State.BindValueChanged(state =>
{
if (state.NewValue == null)
base.State.Value = default(T);
Debug.Assert(base.State.Value != null);
State.Value = (T)base.State.Value;
}, true);
State.BindValueChanged(state => base.State.Value = state.NewValue);
}
public sealed override IconUsage? GetIconForState(object state) => GetIconForState((T)state);
public sealed override IconUsage? GetIconForState(object? state) => GetIconForState((T)state!);
/// <summary>
/// Retrieves the icon to be displayed for a state.

View File

@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Chat
public void TextBoxKillFocus() => chatTextBox.KillFocus();
[Resolved]
private Bindable<Channel> currentChannel { get; set; } = null!;
private Bindable<Channel?> currentChannel { get; set; } = null!;
private Container chattingTextContainer = null!;
private OsuSpriteText chattingText = null!;
@ -138,7 +138,7 @@ namespace osu.Game.Overlays.Chat
currentChannel.BindValueChanged(change =>
{
Channel newChannel = change.NewValue;
Channel? newChannel = change.NewValue;
switch (newChannel?.Type)
{

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using osu.Framework;
@ -200,11 +201,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
currentDisplay.BindValueChanged(display => Schedule(() =>
{
if (display.NewValue == null)
{
resolutions.Clear();
return;
}
Debug.Assert(display.NewValue != null);
resolutions.ReplaceRange(1, resolutions.Count - 1, display.NewValue.DisplayModes
.Where(m => m.Size.Width >= 800 && m.Size.Height >= 600)

View File

@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
{
protected override LocalisableString Header => BindingSettingsStrings.ShortcutAndGameplayBindings;
public override IEnumerable<LocalisableString> FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { @"keybindings", @"controls", @"keyboard", @"keys" });
public override IEnumerable<LocalisableString> FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { @"keybindings", @"controls", @"keyboard", @"keys", @"buttons" });
public BindingSettings(KeyBindingPanel keyConfig)
{

View File

@ -18,7 +18,7 @@ namespace osu.Game.Screens.Edit.Components
protected readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
protected readonly IBindable<Track> Track = new Bindable<Track>();
protected readonly IBindable<Track?> Track = new Bindable<Track?>();
public readonly Drawable Background;
private readonly Container content;

View File

@ -66,7 +66,7 @@ namespace osu.Game.Screens.Edit.Setup
syncingColours = true;
comboColours.Colours.Clear();
comboColours.Colours.AddRange(Beatmap.BeatmapSkin?.ComboColours);
comboColours.Colours.AddRange(Beatmap.BeatmapSkin?.ComboColours ?? []);
syncingColours = false;
});

View File

@ -81,9 +81,9 @@ namespace osu.Game.Screens.Edit.Timing
effectPoint.ScrollSpeedBindable.Value = scrollSpeed.NewValue;
}
protected override EffectControlPoint CreatePoint()
protected override EffectControlPoint CreatePointFrom(double time)
{
var reference = Beatmap.ControlPointInfo.EffectPointAt(SelectedGroup.Value.Time);
var reference = Beatmap.ControlPointInfo.EffectPointAt(time);
return new EffectControlPoint
{

View File

@ -21,7 +21,7 @@ namespace osu.Game.Screens.Edit.Timing
private OsuButton button = null!;
[Resolved]
protected Bindable<ControlPointGroup> SelectedGroup { get; private set; } = null!;
protected Bindable<ControlPointGroup?> SelectedGroup { get; private set; } = null!;
[Resolved]
protected EditorBeatmap Beatmap { get; private set; } = null!;

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@ -30,7 +31,7 @@ namespace osu.Game.Screens.Edit.Timing
protected EditorBeatmap Beatmap { get; private set; } = null!;
[Resolved]
protected Bindable<ControlPointGroup> SelectedGroup { get; private set; } = null!;
protected Bindable<ControlPointGroup?> SelectedGroup { get; private set; } = null!;
[Resolved]
protected IEditorChangeHandler? ChangeHandler { get; private set; }
@ -103,12 +104,13 @@ namespace osu.Game.Screens.Edit.Timing
}
if (ControlPoint.Value == null)
SelectedGroup.Value.Add(ControlPoint.Value = CreatePoint());
SelectedGroup.Value.Add(ControlPoint.Value = CreatePointFrom(SelectedGroup.Value.Time));
}
else
{
if (ControlPoint.Value != null)
{
Debug.Assert(SelectedGroup.Value != null);
SelectedGroup.Value.Remove(ControlPoint.Value);
ControlPoint.Value = null;
}
@ -128,6 +130,6 @@ namespace osu.Game.Screens.Edit.Timing
protected abstract void OnControlPointChanged(ValueChangedEvent<T?> point);
protected abstract T CreatePoint();
protected abstract T CreatePointFrom(double time);
}
}

View File

@ -31,7 +31,7 @@ namespace osu.Game.Screens.Edit.Timing
private OsuConfigManager configManager { get; set; } = null!;
[Resolved]
private Bindable<ControlPointGroup> selectedGroup { get; set; } = null!;
private Bindable<ControlPointGroup?> selectedGroup { get; set; } = null!;
private readonly BindableBool isHandlingTapping = new BindableBool();

View File

@ -83,9 +83,9 @@ namespace osu.Game.Screens.Edit.Timing
}
}
protected override TimingControlPoint CreatePoint()
protected override TimingControlPoint CreatePointFrom(double time)
{
var reference = Beatmap.ControlPointInfo.TimingPointAt(SelectedGroup.Value.Time);
var reference = Beatmap.ControlPointInfo.TimingPointAt(time);
return new TimingControlPoint
{

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@ -80,19 +81,34 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
bool matchingFilter = true;
matchingFilter &= criteria.Ruleset == null || r.Room.PlaylistItemStats?.RulesetIDs.Any(id => id == criteria.Ruleset.OnlineID) != false;
if (!string.IsNullOrEmpty(criteria.SearchString))
{
// Room name isn't translatable, so ToString() is used here for simplicity.
matchingFilter &= r.FilterTerms.Any(term => term.ToString().Contains(criteria.SearchString, StringComparison.InvariantCultureIgnoreCase));
}
matchingFilter &= matchPermissions(r, criteria.Permissions);
// Room name isn't translatable, so ToString() is used here for simplicity.
string[] filterTerms = r.FilterTerms.Select(t => t.ToString()).ToArray();
string[] searchTerms = criteria.SearchString.Split(' ', StringSplitOptions.RemoveEmptyEntries);
matchingFilter &= searchTerms.All(searchTerm => filterTerms.Any(filterTerm => checkTerm(filterTerm, searchTerm)));
r.MatchingFilter = matchingFilter;
}
});
// Lifted from SearchContainer.
static bool checkTerm(string haystack, string needle)
{
int index = 0;
for (int i = 0; i < needle.Length; i++)
{
int found = CultureInfo.InvariantCulture.CompareInfo.IndexOf(haystack, needle[i], index, CompareOptions.OrdinalIgnoreCase);
if (found < 0)
return false;
index = found + 1;
}
return true;
}
static bool matchPermissions(DrawableLoungeRoom room, RoomPermissionsFilter accessType)
{
switch (accessType)

View File

@ -3,6 +3,7 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -38,6 +39,10 @@ namespace osu.Game.Screens.OnlinePlay.Match
{
this.allowEdit = allowEdit;
// Roslyn sees required non-nullable property as nullable in constructor,
// as it can't see the implementation provides a fallback.
Debug.Assert(SelectedItem != null);
base.SelectedItem.BindTo(SelectedItem);
}

View File

@ -55,6 +55,8 @@ namespace osu.Game.Screens.Ranking
[Resolved]
private Player? player { get; set; }
private bool skipExitTransition;
[Resolved]
private IAPIProvider api { get; set; } = null!;
@ -203,6 +205,7 @@ namespace osu.Game.Screens.Ranking
{
if (!this.IsCurrentScreen()) return;
skipExitTransition = true;
player?.Restart(true);
},
});
@ -313,7 +316,8 @@ namespace osu.Game.Screens.Ranking
// HitObject references from HitEvent.
Score?.HitEvents.Clear();
this.FadeOut(100);
if (!skipExitTransition)
this.FadeOut(100);
return false;
}

View File

@ -68,7 +68,7 @@ namespace osu.Game.Screens.Select.Leaderboards
}
[Resolved]
private IBindable<RulesetInfo> ruleset { get; set; } = null!;
private IBindable<RulesetInfo?> ruleset { get; set; } = null!;
[Resolved]
private IBindable<IReadOnlyList<Mod>> mods { get; set; } = null!;
@ -186,6 +186,7 @@ namespace osu.Game.Screens.Select.Leaderboards
scoreSubscription?.Dispose();
scoreSubscription = null;
Debug.Assert(ruleset.Value != null);
scoreSubscription = realm.RegisterForNotifications(r =>
r.All<ScoreInfo>().Filter($"{nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $0"
+ $" AND {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.BeatmapHash)}"

View File

@ -135,7 +135,7 @@ namespace osu.Game.Screens.Select
private FooterButtonOptions beatmapOptionsButton = null!;
private readonly Bindable<RulesetInfo> decoupledRuleset = new Bindable<RulesetInfo>();
private readonly Bindable<RulesetInfo?> decoupledRuleset = new Bindable<RulesetInfo?>();
private double audioFeedbackLastPlaybackTime;
@ -426,7 +426,7 @@ namespace osu.Game.Screens.Select
dependencies.CacheAs(this);
dependencies.CacheAs(decoupledRuleset);
dependencies.CacheAs<IBindable<RulesetInfo>>(decoupledRuleset);
dependencies.CacheAs<IBindable<RulesetInfo?>>(decoupledRuleset);
return dependencies;
}
@ -994,7 +994,7 @@ namespace osu.Game.Screens.Select
selectedMods.BindValueChanged(_ =>
{
if (decoupledRuleset.Value.Equals(rulesetNoDebounce))
if (decoupledRuleset.Value?.Equals(rulesetNoDebounce) ?? false)
advancedStats.Mods.Value = selectedMods.Value;
}, true);

View File

@ -49,7 +49,7 @@ namespace osu.Game.Skinning
SpriteName.BindValueChanged(name =>
{
((SpriteComponentLookup)ComponentLookup).LookupName = name.NewValue ?? string.Empty;
((SpriteComponentLookup)ComponentLookup).LookupName = name.NewValue;
if (IsLoaded)
SkinChanged(CurrentSkin);
});