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

Add "freeplay" button to multiplayer song select

This commit is contained in:
Dan Balasescu 2024-12-10 23:02:26 +09:00
parent 9abb92a8d6
commit 0fb75233ff
No known key found for this signature in database
4 changed files with 146 additions and 13 deletions

View File

@ -0,0 +1,94 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Screens.Select;
namespace osu.Game.Screens.OnlinePlay
{
public class FooterButtonFreePlay : FooterButton, IHasCurrentValue<bool>
{
private readonly BindableWithCurrent<bool> current = new BindableWithCurrent<bool>();
public Bindable<bool> Current
{
get => current.Current;
set => current.Current = value;
}
private OsuSpriteText text = null!;
private Circle circle = null!;
[Resolved]
private OsuColour colours { get; set; } = null!;
[BackgroundDependencyLoader]
private void load()
{
ButtonContentContainer.AddRange(new[]
{
new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
circle = new Circle
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Colour = colours.YellowDark,
RelativeSizeAxes = Axes.Both,
},
text = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Padding = new MarginPadding(5),
UseFullGlyphHeight = false,
}
}
}
});
SelectedColour = colours.Yellow;
DeselectedColour = SelectedColour.Opacity(0.5f);
Text = @"freeplay";
}
protected override void LoadComplete()
{
base.LoadComplete();
Current.BindValueChanged(_ => updateDisplay(), true);
// Overwrite any external behaviour as we delegate the main toggle action to a sub-button.
Action = () => current.Value = !current.Value;
}
private void updateDisplay()
{
if (current.Value)
{
text.Text = "on";
text.FadeColour(colours.Gray2, 200, Easing.OutQuint);
circle.FadeColour(colours.Yellow, 200, Easing.OutQuint);
}
else
{
text.Text = "off";
text.FadeColour(colours.GrayF, 200, Easing.OutQuint);
circle.FadeColour(colours.Gray4, 200, Easing.OutQuint);
}
}
}
}

View File

@ -41,10 +41,12 @@ namespace osu.Game.Screens.OnlinePlay
protected override UserActivity InitialActivity => new UserActivity.InLobby(room);
protected readonly Bindable<IReadOnlyList<Mod>> FreeMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
protected readonly Bindable<bool> FreePlay = new Bindable<bool>();
private readonly Room room;
private readonly PlaylistItem? initialItem;
private readonly FreeModSelectOverlay freeModSelectOverlay;
private readonly FreeModSelectOverlay freeModSelect;
private FooterButton freeModsFooterButton = null!;
private IDisposable? freeModSelectOverlayRegistration;
@ -61,7 +63,7 @@ namespace osu.Game.Screens.OnlinePlay
Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING };
freeModSelectOverlay = new FreeModSelectOverlay
freeModSelect = new FreeModSelectOverlay
{
SelectedMods = { BindTarget = FreeMods },
IsValidMod = IsValidFreeMod,
@ -72,7 +74,7 @@ namespace osu.Game.Screens.OnlinePlay
private void load()
{
LeftArea.Padding = new MarginPadding { Top = Header.HEIGHT };
LoadComponent(freeModSelectOverlay);
LoadComponent(freeModSelect);
}
protected override void LoadComplete()
@ -108,12 +110,36 @@ namespace osu.Game.Screens.OnlinePlay
Mods.Value = initialItem.RequiredMods.Select(m => m.ToMod(rulesetInstance)).ToArray();
FreeMods.Value = initialItem.AllowedMods.Select(m => m.ToMod(rulesetInstance)).ToArray();
}
if (initialItem.BeatmapSetId != null)
FreePlay.Value = true;
}
Mods.BindValueChanged(onModsChanged);
Ruleset.BindValueChanged(onRulesetChanged);
FreePlay.BindValueChanged(onFreePlayChanged, true);
freeModSelectOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(freeModSelectOverlay);
freeModSelectOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(freeModSelect);
}
private void onFreePlayChanged(ValueChangedEvent<bool> enabled)
{
if (enabled.NewValue)
{
freeModsFooterButton.Enabled.Value = false;
ModsFooterButton.Enabled.Value = false;
ModSelect.Hide();
freeModSelect.Hide();
Mods.Value = [];
FreeMods.Value = [];
}
else
{
freeModsFooterButton.Enabled.Value = true;
ModsFooterButton.Enabled.Value = true;
}
}
private void onModsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)
@ -121,7 +147,7 @@ namespace osu.Game.Screens.OnlinePlay
FreeMods.Value = FreeMods.Value.Where(checkCompatibleFreeMod).ToList();
// Reset the validity delegate to update the overlay's display.
freeModSelectOverlay.IsValidMod = IsValidFreeMod;
freeModSelect.IsValidMod = IsValidFreeMod;
}
private void onRulesetChanged(ValueChangedEvent<RulesetInfo> ruleset)
@ -135,7 +161,8 @@ namespace osu.Game.Screens.OnlinePlay
{
RulesetID = Ruleset.Value.OnlineID,
RequiredMods = Mods.Value.Select(m => new APIMod(m)).ToArray(),
AllowedMods = FreeMods.Value.Select(m => new APIMod(m)).ToArray()
AllowedMods = FreeMods.Value.Select(m => new APIMod(m)).ToArray(),
BeatmapSetId = FreePlay.Value ? Beatmap.Value.BeatmapSetInfo.OnlineID : null
};
return SelectItem(item);
@ -150,9 +177,9 @@ namespace osu.Game.Screens.OnlinePlay
public override bool OnBackButton()
{
if (freeModSelectOverlay.State.Value == Visibility.Visible)
if (freeModSelect.State.Value == Visibility.Visible)
{
freeModSelectOverlay.Hide();
freeModSelect.Hide();
return true;
}
@ -161,7 +188,7 @@ namespace osu.Game.Screens.OnlinePlay
public override bool OnExiting(ScreenExitEvent e)
{
freeModSelectOverlay.Hide();
freeModSelect.Hide();
return base.OnExiting(e);
}
@ -173,9 +200,15 @@ namespace osu.Game.Screens.OnlinePlay
protected override IEnumerable<(FooterButton, OverlayContainer?)> CreateSongSelectFooterButtons()
{
var baseButtons = base.CreateSongSelectFooterButtons().ToList();
var freeModsButton = new FooterButtonFreeMods(freeModSelectOverlay) { Current = FreeMods };
baseButtons.Insert(baseButtons.FindIndex(b => b.Item1 is FooterButtonMods) + 1, (freeModsButton, freeModSelectOverlay));
freeModsFooterButton = new FooterButtonFreeMods(freeModSelect) { Current = FreeMods };
var freePlayButton = new FooterButtonFreePlay { Current = FreePlay };
baseButtons.InsertRange(baseButtons.FindIndex(b => b.Item1 is FooterButtonMods) + 1, new (FooterButton, OverlayContainer?)[]
{
(freeModsFooterButton, freeModSelect),
(freePlayButton, null)
});
return baseButtons;
}

View File

@ -37,9 +37,10 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
private PlaylistItem createNewItem() => new PlaylistItem(Beatmap.Value.BeatmapInfo)
{
ID = room.Playlist.Count == 0 ? 0 : room.Playlist.Max(p => p.ID) + 1,
BeatmapSetId = FreePlay.Value ? Beatmap.Value.BeatmapSetInfo.OnlineID : null,
RulesetID = Ruleset.Value.OnlineID,
RequiredMods = Mods.Value.Select(m => new APIMod(m)).ToArray(),
AllowedMods = FreeMods.Value.Select(m => new APIMod(m)).ToArray()
AllowedMods = FreeMods.Value.Select(m => new APIMod(m)).ToArray(),
};
}
}

View File

@ -82,6 +82,11 @@ namespace osu.Game.Screens.Select
/// </summary>
protected Container FooterPanels { get; private set; } = null!;
/// <summary>
/// The <see cref="FooterButton"/> that opens the mod select dialog.
/// </summary>
protected FooterButton ModsFooterButton { get; private set; } = null!;
/// <summary>
/// Whether entering editor mode should be allowed.
/// </summary>
@ -407,7 +412,7 @@ namespace osu.Game.Screens.Select
/// <returns>A set of <see cref="FooterButton"/> and an optional <see cref="OverlayContainer"/> which the button opens when pressed.</returns>
protected virtual IEnumerable<(FooterButton, OverlayContainer?)> CreateSongSelectFooterButtons() => new (FooterButton, OverlayContainer?)[]
{
(new FooterButtonMods { Current = Mods }, ModSelect),
(ModsFooterButton = new FooterButtonMods { Current = Mods }, ModSelect),
(new FooterButtonRandom
{
NextRandom = () => Carousel.SelectNextRandom(),