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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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() { }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user