1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-21 07:49:52 +08:00

Merge pull request #32669 from smoogipoo/refactor-match-subscreen

Rewrite match subscreen to remove bindables
This commit is contained in:
Bartłomiej Dach
2025-04-08 12:51:36 +02:00
committed by GitHub
Unverified
9 changed files with 871 additions and 869 deletions
@@ -105,7 +105,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(otherBeatmap = beatmap()));
AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen);
AddUntilStep("selected item is new beatmap", () => (CurrentSubScreen as MultiplayerMatchSubScreen)?.SelectedItem.Value?.Beatmap.OnlineID == otherBeatmap.OnlineID);
AddUntilStep("selected item is new beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == otherBeatmap.OnlineID);
}
private void addItem(Func<BeatmapInfo> beatmap)
@@ -443,7 +443,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("Enter song select", () =>
{
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(item);
((MultiplayerMatchSubScreen)currentSubScreen).ShowSongSelect(item);
});
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
@@ -484,7 +484,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("Enter song select", () =>
{
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(item);
((MultiplayerMatchSubScreen)currentSubScreen).ShowSongSelect(item);
});
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
@@ -525,7 +525,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("Enter song select", () =>
{
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(item);
((MultiplayerMatchSubScreen)currentSubScreen).ShowSongSelect(item);
});
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
@@ -657,7 +657,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("invoke on back button", () => multiplayerComponents.OnBackButton());
AddAssert("mod overlay is hidden", () => this.ChildrenOfType<RoomSubScreen>().Single().UserModsSelectOverlay.State.Value == Visibility.Hidden);
AddAssert("mod overlay is hidden", () => this.ChildrenOfType<MultiplayerUserModSelectOverlay>().Single().State.Value == Visibility.Hidden);
AddAssert("dialog overlay is hidden", () => DialogOverlay.State.Value == Visibility.Hidden);
@@ -828,11 +828,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
AddUntilStep("wait for join", () => multiplayerClient.RoomJoined);
AddAssert("local room has correct settings", () =>
{
var localRoom = this.ChildrenOfType<MultiplayerMatchSubScreen>().Single().Room;
return localRoom.Name == multiplayerClient.ServerSideRooms[0].Name && localRoom.Playlist.Single().ID == 2;
});
AddAssert("local room has correct name", () => this.ChildrenOfType<MultiplayerRoomPanel>().Single().Room.Name, () => Is.EqualTo(multiplayerClient.ServerSideRooms[0].Name));
AddAssert("local room has correct playlist", () => this.ChildrenOfType<MultiplayerQueueList>().Single().Items.Single().ID, () => Is.EqualTo(2));
}
[Test]
@@ -8,6 +8,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Extensions;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
@@ -186,7 +187,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("mod select contents loaded",
() => this.ChildrenOfType<ModColumn>().Any() && this.ChildrenOfType<ModColumn>().All(col => col.IsLoaded && col.ItemsLoaded));
AddUntilStep("mod select contains only double time mod",
() => this.ChildrenOfType<RoomSubScreen>().Single().UserModsSelectOverlay
() => this.ChildrenOfType<MultiplayerUserModSelectOverlay>().Single()
.ChildrenOfType<ModPanel>()
.SingleOrDefault(panel => panel.Visible)?.Mod is OsuModDoubleTime);
}
@@ -212,7 +213,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("press toggle mod select key", () => InputManager.Key(Key.F1));
AddUntilStep("mod select shown", () => this.ChildrenOfType<RoomSubScreen>().Single().UserModsSelectOverlay.State.Value == Visibility.Visible);
AddUntilStep("mod select shown", () => this.ChildrenOfType<MultiplayerUserModSelectOverlay>().Single().State.Value == Visibility.Visible);
}
[Test]
@@ -235,7 +236,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("press toggle mod select key", () => InputManager.Key(Key.F1));
AddWaitStep("wait some", 3);
AddAssert("mod select not shown", () => this.ChildrenOfType<RoomSubScreen>().Single().UserModsSelectOverlay.State.Value == Visibility.Hidden);
AddAssert("mod select not shown", () => this.ChildrenOfType<MultiplayerUserModSelectOverlay>().Single().State.Value == Visibility.Hidden);
}
[Test]
@@ -307,10 +308,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("mod select shows unranked", () => this.ChildrenOfType<RankingInformationDisplay>().Single().Ranked.Value == false);
AddAssert("score multiplier = 1.20", () => this.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value, () => Is.EqualTo(1.2).Within(0.01));
AddStep("select flashlight", () => screen.UserModsSelectOverlay.ChildrenOfType<ModPanel>().Single(m => m.Mod is ModFlashlight).TriggerClick());
AddStep("select flashlight", () => this.ChildrenOfType<MultiplayerUserModSelectOverlay>().Single().ChildrenOfType<ModPanel>().Single(m => m.Mod is ModFlashlight).TriggerClick());
AddAssert("score multiplier = 1.35", () => this.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value, () => Is.EqualTo(1.35).Within(0.01));
AddStep("change flashlight setting", () => ((OsuModFlashlight)screen.UserModsSelectOverlay.SelectedMods.Value.Single()).FollowDelay.Value = 1200);
AddStep("change flashlight setting", () => ((OsuModFlashlight)this.ChildrenOfType<MultiplayerUserModSelectOverlay>().Single().SelectedMods.Value.Single()).FollowDelay.Value = 1200);
AddAssert("score multiplier = 1.20", () => this.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value, () => Is.EqualTo(1.2).Within(0.01));
}
@@ -392,6 +393,39 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("flashlight mod panel not activated", () => !this.ChildrenOfType<ModPanel>().Single(p => p.Mod is OsuModFlashlight).Active.Value);
}
[Test]
public void TestStartCountdown()
{
AddStep("set playlist", () =>
{
room.Playlist =
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First()).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
];
});
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
AddUntilStep("wait for room join", () => RoomJoined);
AddStep("click countdown button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<MultiplayerCountdownButton>().Single());
InputManager.Click(MouseButton.Left);
});
AddStep("start a countdown", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<Popover>().Single().ChildrenOfType<Button>().First());
InputManager.Click(MouseButton.Left);
});
AddUntilStep("countdown started", () => MultiplayerClient.ServerRoom!.ActiveCountdowns.Any());
}
private partial class TestMultiplayerMatchSubScreen : MultiplayerMatchSubScreen
{
[Resolved(canBeNull: true)]
@@ -36,6 +36,21 @@ namespace osu.Game.Online.Multiplayer
/// </summary>
public virtual event Action? RoomUpdated;
/// <summary>
/// Invoked when a user's local style is changed.
/// </summary>
public event Action<MultiplayerRoomUser>? UserStyleChanged;
/// <summary>
/// Invoked when a user's local mods are changed.
/// </summary>
public event Action<MultiplayerRoomUser>? UserModsChanged;
/// <summary>
/// Invoked when the room's settings are changed.
/// </summary>
public event Action<MultiplayerRoomSettings>? SettingsChanged;
/// <summary>
/// Invoked when a new user joins the room.
/// </summary>
@@ -710,7 +725,7 @@ namespace osu.Game.Online.Multiplayer
return Task.CompletedTask;
}
public Task UserStyleChanged(int userId, int? beatmapId, int? rulesetId)
Task IMultiplayerClient.UserStyleChanged(int userId, int? beatmapId, int? rulesetId)
{
Scheduler.Add(() =>
{
@@ -723,13 +738,14 @@ namespace osu.Game.Online.Multiplayer
user.BeatmapId = beatmapId;
user.RulesetId = rulesetId;
UserStyleChanged?.Invoke(user);
RoomUpdated?.Invoke();
}, false);
return Task.CompletedTask;
}
public Task UserModsChanged(int userId, IEnumerable<APIMod> mods)
Task IMultiplayerClient.UserModsChanged(int userId, IEnumerable<APIMod> mods)
{
Scheduler.Add(() =>
{
@@ -741,6 +757,7 @@ namespace osu.Game.Online.Multiplayer
user.Mods = mods;
UserModsChanged?.Invoke(user);
RoomUpdated?.Invoke();
}, false);
@@ -907,6 +924,7 @@ namespace osu.Game.Online.Multiplayer
APIRoom.CurrentPlaylistItem = APIRoom.Playlist.Single(item => item.ID == settings.PlaylistItemId);
APIRoom.AutoSkip = Room.Settings.AutoSkip;
SettingsChanged?.Invoke(settings);
RoomUpdated?.Invoke();
}
@@ -1,544 +0,0 @@
// 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;
using System.ComponentModel;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Cursor;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Overlays;
using osu.Game.Overlays.Mods;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Menu;
using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
using osu.Game.Utils;
using Container = osu.Framework.Graphics.Containers.Container;
namespace osu.Game.Screens.OnlinePlay.Match
{
[Cached(typeof(IPreviewTrackOwner))]
public abstract partial class RoomSubScreen : OnlinePlaySubScreen, IPreviewTrackOwner
{
public readonly Bindable<PlaylistItem?> SelectedItem = new Bindable<PlaylistItem?>();
public override bool? ApplyModTrackAdjustments => true;
protected override BackgroundScreen CreateBackground() => new MultiplayerRoomBackgroundScreen();
public override bool DisallowExternalBeatmapRulesetChanges => true;
/// <summary>
/// A container that provides controls for selection of user mods.
/// This will be shown/hidden automatically when applicable.
/// </summary>
protected Drawable UserModsSection = null!;
/// <summary>
/// A container that provides controls for selection of the user style.
/// This will be shown/hidden automatically when applicable.
/// </summary>
protected Drawable UserStyleSection = null!;
/// <summary>
/// A container that will display the user's style.
/// </summary>
protected Container<DrawableRoomPlaylistItem> UserStyleDisplayContainer = null!;
private Sample? sampleStart;
[Resolved(CanBeNull = true)]
private IOverlayManager? overlayManager { get; set; }
[Resolved]
private MusicController music { get; set; } = null!;
[Resolved]
private BeatmapManager beatmapManager { get; set; } = null!;
[Resolved]
protected RulesetStore Rulesets { get; private set; } = null!;
[Resolved]
protected IAPIProvider API { get; private set; } = null!;
[Resolved(canBeNull: true)]
protected OnlinePlayScreen? ParentScreen { get; private set; }
[Resolved]
private PreviewTrackManager previewTrackManager { get; set; } = null!;
[Resolved(canBeNull: true)]
protected IDialogOverlay? DialogOverlay { get; private set; }
[Cached(typeof(OnlinePlayBeatmapAvailabilityTracker))]
private readonly MultiplayerBeatmapAvailabilityTracker beatmapAvailabilityTracker = new MultiplayerBeatmapAvailabilityTracker();
protected IBindable<BeatmapAvailability> BeatmapAvailability => beatmapAvailabilityTracker.Availability;
public readonly Room Room;
internal ModSelectOverlay UserModsSelectOverlay { get; private set; } = null!;
private IDisposable? userModsSelectOverlayRegistration;
private RoomSettingsOverlay settingsOverlay = null!;
private Drawable mainContent = null!;
/// <summary>
/// Creates a new <see cref="RoomSubScreen"/>.
/// </summary>
/// <param name="room">The <see cref="Room"/>.</param>
protected RoomSubScreen(Room room)
{
Room = room;
Padding = new MarginPadding { Top = Header.HEIGHT };
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
sampleStart = audio.Samples.Get(@"SongSelect/confirm-selection");
InternalChild = new PopoverContainer
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
beatmapAvailabilityTracker,
new MultiplayerRoomSounds(),
new GridContainer
{
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.Absolute, 50)
},
Content = new[]
{
// Padded main content (drawable room + main content)
new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding
{
Horizontal = WaveOverlayContainer.WIDTH_PADDING,
Bottom = 30
},
Children = new[]
{
mainContent = new GridContainer
{
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize),
new Dimension(GridSizeMode.Absolute, 10)
},
Content = new[]
{
new Drawable[]
{
new OsuContextMenuContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = new MultiplayerRoomPanel(Room)
{
OnEdit = () => settingsOverlay.Show(),
}
}
},
null,
new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Children = new[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 10,
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex(@"3e3a44") // Temporary.
},
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(20),
Child = CreateMainContent(),
},
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
},
}
}
}
}
},
new Container
{
RelativeSizeAxes = Axes.Both,
// Resolves 1px masking errors between the settings overlay and the room panel.
Padding = new MarginPadding(-1),
Child = settingsOverlay = CreateRoomSettingsOverlay(Room)
}
},
},
},
// Footer
new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex(@"28242d") // Temporary.
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(5),
Child = CreateFooter()
},
}
}
}
}
}
}
};
LoadComponent(UserModsSelectOverlay = new MultiplayerUserModSelectOverlay());
}
protected override void LoadComplete()
{
base.LoadComplete();
SelectedItem.BindValueChanged(_ => updateSpecifics());
beatmapAvailabilityTracker.Availability.BindValueChanged(_ => updateSpecifics());
userModsSelectOverlayRegistration = overlayManager?.RegisterBlockingOverlay(UserModsSelectOverlay);
Room.PropertyChanged += onRoomPropertyChanged;
updateSetupState();
}
private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Room.RoomID))
updateSetupState();
}
private void updateSetupState()
{
if (Room.RoomID == null)
{
// A new room is being created.
// The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed.
mainContent.Hide();
settingsOverlay.Show();
}
else
{
mainContent.Show();
settingsOverlay.Hide();
}
}
protected virtual bool IsConnected => API.State.Value == APIState.Online;
public override bool OnBackButton()
{
if (Room.RoomID == null)
{
if (!ensureExitConfirmed())
return true;
settingsOverlay.Hide();
return base.OnBackButton();
}
if (UserModsSelectOverlay.State.Value == Visibility.Visible)
{
UserModsSelectOverlay.Hide();
return true;
}
if (settingsOverlay.State.Value == Visibility.Visible)
{
settingsOverlay.Hide();
return true;
}
return base.OnBackButton();
}
protected void ShowUserModSelect() => UserModsSelectOverlay.Show();
public override void OnEntering(ScreenTransitionEvent e)
{
base.OnEntering(e);
beginHandlingTrack();
}
public override void OnSuspending(ScreenTransitionEvent e)
{
// Should be a noop in most cases, but let's ensure beyond doubt that the beatmap is in a correct state.
updateSpecifics();
onLeaving();
base.OnSuspending(e);
}
public override void OnResuming(ScreenTransitionEvent e)
{
base.OnResuming(e);
updateSpecifics();
beginHandlingTrack();
}
protected bool ExitConfirmed { get; private set; }
public override bool OnExiting(ScreenExitEvent e)
{
if (!ensureExitConfirmed())
return true;
if (Room.RoomID != null)
PartRoom();
Mods.Value = Array.Empty<Mod>();
onLeaving();
return base.OnExiting(e);
}
/// <summary>
/// Parts from the current room.
/// </summary>
protected abstract void PartRoom();
private bool ensureExitConfirmed()
{
if (ExitConfirmed)
return true;
if (!IsConnected)
return true;
bool hasUnsavedChanges = Room.RoomID == null && Room.Playlist.Count > 0;
if (DialogOverlay == null || !hasUnsavedChanges)
return true;
// if the dialog is already displayed, block exiting until the user explicitly makes a decision.
if (DialogOverlay.CurrentDialog is ConfirmDiscardChangesDialog discardChangesDialog)
{
discardChangesDialog.Flash();
return false;
}
DialogOverlay.Push(new ConfirmDiscardChangesDialog(() =>
{
ExitConfirmed = true;
settingsOverlay.Hide();
this.Exit();
}));
return false;
}
protected void StartPlay()
{
if (SelectedItem.Value is not PlaylistItem item)
return;
item = item.With(
ruleset: GetGameplayRuleset().OnlineID,
beatmap: new Optional<IBeatmapInfo>(GetGameplayBeatmap()));
// User may be at song select or otherwise when the host starts gameplay.
// Ensure that they first return to this screen, else global bindables (beatmap etc.) may be in a bad state.
if (!this.IsCurrentScreen())
{
this.MakeCurrent();
Schedule(StartPlay);
return;
}
sampleStart?.Play();
// fallback is to allow this class to operate when there is no parent OnlineScreen (testing purposes).
var targetScreen = (Screen?)ParentScreen ?? this;
targetScreen.Push(CreateGameplayScreen(item));
}
/// <summary>
/// Creates the gameplay screen to be entered.
/// </summary>
/// <param name="selectedItem">The playlist item about to be played.</param>
/// <returns>The screen to enter.</returns>
protected abstract Screen CreateGameplayScreen(PlaylistItem selectedItem);
private void updateSpecifics()
{
if (!this.IsCurrentScreen() || SelectedItem.Value is not PlaylistItem item)
return;
var rulesetInstance = GetGameplayRuleset().CreateInstance();
Mod[] allowedMods = item.Freestyle
? rulesetInstance.AllMods.OfType<Mod>().Where(m => ModUtils.IsValidFreeModForMatchType(m, Room.Type)).ToArray()
: item.AllowedMods.Select(m => m.ToMod(rulesetInstance)).ToArray();
// Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
int beatmapId = GetGameplayBeatmap().OnlineID;
var localBeatmap = beatmapManager.QueryBeatmap($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", beatmapId);
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
UserModsSelectOverlay.Beatmap.Value = Beatmap.Value;
Mods.Value = GetGameplayMods().Select(m => m.ToMod(rulesetInstance)).ToArray();
Ruleset.Value = GetGameplayRuleset();
if (allowedMods.Length > 0)
UserModsSection.Show();
else
{
UserModsSection.Hide();
UserModsSelectOverlay.Hide();
}
if (item.Freestyle)
{
UserStyleSection.Show();
PlaylistItem gameplayItem = SelectedItem.Value.With(ruleset: GetGameplayRuleset().OnlineID, beatmap: new Optional<IBeatmapInfo>(GetGameplayBeatmap()));
PlaylistItem? currentItem = UserStyleDisplayContainer.SingleOrDefault()?.Item;
if (gameplayItem.Equals(currentItem))
return;
UserStyleDisplayContainer.Child = new DrawableRoomPlaylistItem(gameplayItem, true)
{
AllowReordering = false,
AllowEditing = true,
RequestEdit = _ => OpenStyleSelection()
};
}
else
UserStyleSection.Hide();
}
protected virtual APIMod[] GetGameplayMods() => SelectedItem.Value!.RequiredMods;
protected virtual RulesetInfo GetGameplayRuleset() => Rulesets.GetRuleset(SelectedItem.Value!.RulesetID)!;
protected virtual IBeatmapInfo GetGameplayBeatmap() => SelectedItem.Value!.Beatmap;
protected abstract void OpenStyleSelection();
private void beginHandlingTrack()
{
Beatmap.BindValueChanged(applyLoopingToTrack, true);
}
private void onLeaving()
{
UserModsSelectOverlay.Hide();
endHandlingTrack();
previewTrackManager.StopAnyPlaying(this);
}
private void endHandlingTrack()
{
Beatmap.ValueChanged -= applyLoopingToTrack;
cancelTrackLooping();
}
private void applyLoopingToTrack(ValueChangedEvent<WorkingBeatmap>? _ = null)
{
if (!this.IsCurrentScreen())
return;
var track = Beatmap.Value?.Track;
if (track != null)
{
Beatmap.Value!.PrepareTrackForPreview(true);
music.EnsurePlayingSomething();
}
}
private void cancelTrackLooping()
{
var track = Beatmap.Value?.Track;
if (track != null)
track.Looping = false;
}
/// <summary>
/// Creates the main centred content.
/// </summary>
protected abstract Drawable CreateMainContent();
/// <summary>
/// Creates the footer content.
/// </summary>
protected abstract Drawable CreateFooter();
/// <summary>
/// Creates the room settings overlay.
/// </summary>
/// <param name="room">The room to change the settings of.</param>
protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(Room room);
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
userModsSelectOverlayRegistration?.Dispose();
Room.PropertyChanged -= onRoomPropertyChanged;
}
}
}
@@ -12,7 +12,6 @@ using osu.Framework.Extensions.ExceptionExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
@@ -35,7 +34,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
[Resolved]
private OngoingOperationTracker ongoingOperationTracker { get; set; } = null!;
private readonly BindableWithCurrent<PlaylistItem?> selectedItem = new BindableWithCurrent<PlaylistItem?>();
private MatchSettings settings = null!;
public MultiplayerMatchSettingsOverlay(Room room)
@@ -274,11 +272,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
RelativeSizeAxes = Axes.X,
Height = 40,
Text = "Select beatmap",
Action = () =>
{
if (matchSubScreen.IsCurrentScreen())
matchSubScreen.Push(new MultiplayerMatchSongSelect(matchSubScreen.Room));
}
Action = () => matchSubScreen.ShowSongSelect()
}
}
}
File diff suppressed because it is too large Load Diff
@@ -15,6 +15,7 @@ using osu.Game.Online;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.Countdown;
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Mods;
@@ -70,6 +71,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
private MultiplayerPlaylistItem? currentItem => ServerRoom?.Playlist[currentIndex];
private int currentIndex;
private long lastPlaylistItemId;
private int lastCountdownId;
private readonly TestRoomRequestsHandler apiRequestHandler;
@@ -393,7 +395,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
switch (request)
{
case ChangeTeamRequest changeTeam:
TeamVersusRoomState roomState = (TeamVersusRoomState)ServerRoom.MatchState!;
TeamVersusUserState userState = (TeamVersusUserState)LocalUser.MatchState!;
@@ -402,11 +403,25 @@ namespace osu.Game.Tests.Visual.Multiplayer
if (targetTeam != null)
{
userState.TeamID = targetTeam.ID;
await ((IMultiplayerClient)this).MatchUserStateChanged(clone(LocalUser.UserID), clone(userState)).ConfigureAwait(false);
}
break;
case StartMatchCountdownRequest startCountdown:
ServerRoom.ActiveCountdowns.Add(new MatchStartCountdown
{
ID = ++lastCountdownId,
TimeRemaining = startCountdown.Duration
});
await ((IMultiplayerClient)this).MatchEvent(clone(new CountdownStartedEvent(ServerRoom.ActiveCountdowns[^1]))).ConfigureAwait(false);
break;
case StopCountdownRequest stopCountdown:
ServerRoom.ActiveCountdowns.Remove(ServerRoom.ActiveCountdowns.First(c => c.ID == stopCountdown.ID));
await ((IMultiplayerClient)this).MatchEvent(clone(new CountdownStoppedEvent(stopCountdown.ID))).ConfigureAwait(false);
break;
}
}
+7
View File
@@ -6,6 +6,7 @@ using MessagePack;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Online;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Scoring;
@@ -271,6 +272,12 @@ namespace osu.Game.Users
RoomName = room.Name;
}
public InLobby(MultiplayerRoom room)
{
RoomID = room.RoomID;
RoomName = room.Settings.Name;
}
[SerializationConstructor]
public InLobby() { }