mirror of
https://github.com/ppy/osu.git
synced 2025-02-06 22:33:13 +08:00
Add "freeplay" button to multiplayer song select
This commit is contained in:
parent
9abb92a8d6
commit
0fb75233ff
94
osu.Game/Screens/OnlinePlay/FooterButtonFreePlay.cs
Normal file
94
osu.Game/Screens/OnlinePlay/FooterButtonFreePlay.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -41,10 +41,12 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
protected override UserActivity InitialActivity => new UserActivity.InLobby(room);
|
protected override UserActivity InitialActivity => new UserActivity.InLobby(room);
|
||||||
|
|
||||||
protected readonly Bindable<IReadOnlyList<Mod>> FreeMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
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 Room room;
|
||||||
private readonly PlaylistItem? initialItem;
|
private readonly PlaylistItem? initialItem;
|
||||||
private readonly FreeModSelectOverlay freeModSelectOverlay;
|
private readonly FreeModSelectOverlay freeModSelect;
|
||||||
|
private FooterButton freeModsFooterButton = null!;
|
||||||
|
|
||||||
private IDisposable? freeModSelectOverlayRegistration;
|
private IDisposable? freeModSelectOverlayRegistration;
|
||||||
|
|
||||||
@ -61,7 +63,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
|
|
||||||
Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING };
|
Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING };
|
||||||
|
|
||||||
freeModSelectOverlay = new FreeModSelectOverlay
|
freeModSelect = new FreeModSelectOverlay
|
||||||
{
|
{
|
||||||
SelectedMods = { BindTarget = FreeMods },
|
SelectedMods = { BindTarget = FreeMods },
|
||||||
IsValidMod = IsValidFreeMod,
|
IsValidMod = IsValidFreeMod,
|
||||||
@ -72,7 +74,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
LeftArea.Padding = new MarginPadding { Top = Header.HEIGHT };
|
LeftArea.Padding = new MarginPadding { Top = Header.HEIGHT };
|
||||||
LoadComponent(freeModSelectOverlay);
|
LoadComponent(freeModSelect);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -108,12 +110,36 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
Mods.Value = initialItem.RequiredMods.Select(m => m.ToMod(rulesetInstance)).ToArray();
|
Mods.Value = initialItem.RequiredMods.Select(m => m.ToMod(rulesetInstance)).ToArray();
|
||||||
FreeMods.Value = initialItem.AllowedMods.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);
|
Mods.BindValueChanged(onModsChanged);
|
||||||
Ruleset.BindValueChanged(onRulesetChanged);
|
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)
|
private void onModsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)
|
||||||
@ -121,7 +147,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
FreeMods.Value = FreeMods.Value.Where(checkCompatibleFreeMod).ToList();
|
FreeMods.Value = FreeMods.Value.Where(checkCompatibleFreeMod).ToList();
|
||||||
|
|
||||||
// Reset the validity delegate to update the overlay's display.
|
// Reset the validity delegate to update the overlay's display.
|
||||||
freeModSelectOverlay.IsValidMod = IsValidFreeMod;
|
freeModSelect.IsValidMod = IsValidFreeMod;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onRulesetChanged(ValueChangedEvent<RulesetInfo> ruleset)
|
private void onRulesetChanged(ValueChangedEvent<RulesetInfo> ruleset)
|
||||||
@ -135,7 +161,8 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
{
|
{
|
||||||
RulesetID = Ruleset.Value.OnlineID,
|
RulesetID = Ruleset.Value.OnlineID,
|
||||||
RequiredMods = Mods.Value.Select(m => new APIMod(m)).ToArray(),
|
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);
|
return SelectItem(item);
|
||||||
@ -150,9 +177,9 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
|
|
||||||
public override bool OnBackButton()
|
public override bool OnBackButton()
|
||||||
{
|
{
|
||||||
if (freeModSelectOverlay.State.Value == Visibility.Visible)
|
if (freeModSelect.State.Value == Visibility.Visible)
|
||||||
{
|
{
|
||||||
freeModSelectOverlay.Hide();
|
freeModSelect.Hide();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +188,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
|
|
||||||
public override bool OnExiting(ScreenExitEvent e)
|
public override bool OnExiting(ScreenExitEvent e)
|
||||||
{
|
{
|
||||||
freeModSelectOverlay.Hide();
|
freeModSelect.Hide();
|
||||||
return base.OnExiting(e);
|
return base.OnExiting(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,9 +200,15 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
protected override IEnumerable<(FooterButton, OverlayContainer?)> CreateSongSelectFooterButtons()
|
protected override IEnumerable<(FooterButton, OverlayContainer?)> CreateSongSelectFooterButtons()
|
||||||
{
|
{
|
||||||
var baseButtons = base.CreateSongSelectFooterButtons().ToList();
|
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;
|
return baseButtons;
|
||||||
}
|
}
|
||||||
|
@ -37,9 +37,10 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
private PlaylistItem createNewItem() => new PlaylistItem(Beatmap.Value.BeatmapInfo)
|
private PlaylistItem createNewItem() => new PlaylistItem(Beatmap.Value.BeatmapInfo)
|
||||||
{
|
{
|
||||||
ID = room.Playlist.Count == 0 ? 0 : room.Playlist.Max(p => p.ID) + 1,
|
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,
|
RulesetID = Ruleset.Value.OnlineID,
|
||||||
RequiredMods = Mods.Value.Select(m => new APIMod(m)).ToArray(),
|
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(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,11 @@ namespace osu.Game.Screens.Select
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected Container FooterPanels { get; private set; } = null!;
|
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>
|
/// <summary>
|
||||||
/// Whether entering editor mode should be allowed.
|
/// Whether entering editor mode should be allowed.
|
||||||
/// </summary>
|
/// </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>
|
/// <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?)[]
|
protected virtual IEnumerable<(FooterButton, OverlayContainer?)> CreateSongSelectFooterButtons() => new (FooterButton, OverlayContainer?)[]
|
||||||
{
|
{
|
||||||
(new FooterButtonMods { Current = Mods }, ModSelect),
|
(ModsFooterButton = new FooterButtonMods { Current = Mods }, ModSelect),
|
||||||
(new FooterButtonRandom
|
(new FooterButtonRandom
|
||||||
{
|
{
|
||||||
NextRandom = () => Carousel.SelectNextRandom(),
|
NextRandom = () => Carousel.SelectNextRandom(),
|
||||||
|
Loading…
Reference in New Issue
Block a user