2020-12-20 23:04:06 +08:00
// 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.
2021-02-01 16:54:56 +08:00
using System.Collections.Generic ;
2020-12-24 09:38:53 +08:00
using System.Diagnostics ;
2020-12-20 23:04:06 +08:00
using System.Linq ;
using osu.Framework.Allocation ;
2020-12-23 14:58:50 +08:00
using osu.Framework.Bindables ;
2024-11-12 00:38:31 +08:00
using osu.Framework.Extensions.ObjectExtensions ;
2020-12-20 23:04:06 +08:00
using osu.Framework.Graphics ;
using osu.Framework.Graphics.Containers ;
2021-12-21 13:37:23 +08:00
using osu.Framework.Logging ;
2020-12-20 23:04:06 +08:00
using osu.Framework.Screens ;
2021-02-10 18:56:59 +08:00
using osu.Framework.Threading ;
2021-03-03 13:04:00 +08:00
using osu.Game.Beatmaps ;
2021-02-10 18:56:59 +08:00
using osu.Game.Configuration ;
2022-07-08 06:42:11 +08:00
using osu.Game.Graphics.Cursor ;
2021-05-11 18:22:09 +08:00
using osu.Game.Online ;
2024-12-25 21:24:21 +08:00
using osu.Game.Online.API ;
using osu.Game.Online.API.Requests.Responses ;
2020-12-20 23:04:06 +08:00
using osu.Game.Online.Multiplayer ;
2020-12-25 12:38:11 +08:00
using osu.Game.Online.Rooms ;
2021-03-03 13:50:54 +08:00
using osu.Game.Overlays ;
using osu.Game.Overlays.Dialog ;
2021-03-03 13:04:00 +08:00
using osu.Game.Rulesets ;
2021-02-01 16:54:56 +08:00
using osu.Game.Rulesets.Mods ;
2020-12-25 23:50:00 +08:00
using osu.Game.Screens.OnlinePlay.Components ;
using osu.Game.Screens.OnlinePlay.Match ;
using osu.Game.Screens.OnlinePlay.Match.Components ;
using osu.Game.Screens.OnlinePlay.Multiplayer.Match ;
2021-12-01 18:54:48 +08:00
using osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist ;
2020-12-25 23:50:00 +08:00
using osu.Game.Screens.OnlinePlay.Multiplayer.Participants ;
2021-04-09 20:03:45 +08:00
using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate ;
2021-02-01 12:40:59 +08:00
using osu.Game.Screens.Play.HUD ;
2020-12-20 23:04:06 +08:00
using osu.Game.Users ;
2021-02-01 12:40:59 +08:00
using osuTK ;
2020-12-25 23:50:00 +08:00
using ParticipantsList = osu . Game . Screens . OnlinePlay . Multiplayer . Participants . ParticipantsList ;
2020-12-20 23:04:06 +08:00
2020-12-25 23:50:00 +08:00
namespace osu.Game.Screens.OnlinePlay.Multiplayer
2020-12-20 23:04:06 +08:00
{
[Cached]
2022-11-24 13:32:20 +08:00
public partial class MultiplayerMatchSubScreen : RoomSubScreen , IHandlePresentBeatmap
2020-12-20 23:04:06 +08:00
{
public override string Title { get ; }
2020-12-24 23:10:29 +08:00
public override string ShortTitle = > "room" ;
2020-12-20 23:04:06 +08:00
[Resolved]
2024-11-12 00:38:31 +08:00
private MultiplayerClient client { get ; set ; } = null ! ;
2020-12-20 23:04:06 +08:00
2023-06-21 23:01:48 +08:00
[Resolved(canBeNull: true)]
2024-11-12 00:38:31 +08:00
private OsuGame ? game { get ; set ; }
2023-06-20 17:23:59 +08:00
2024-11-12 00:38:31 +08:00
private AddItemButton addItemButton = null ! ;
2021-12-10 00:15:15 +08:00
2020-12-25 12:38:11 +08:00
public MultiplayerMatchSubScreen ( Room room )
2021-08-17 16:05:20 +08:00
: base ( room )
2020-12-20 23:04:06 +08:00
{
2024-11-13 15:55:18 +08:00
Title = room . RoomID = = null ? "New room" : room . Name ;
2020-12-20 23:04:06 +08:00
Activity . Value = new UserActivity . InLobby ( room ) ;
}
protected override void LoadComplete ( )
{
base . LoadComplete ( ) ;
2021-01-18 22:23:51 +08:00
BeatmapAvailability . BindValueChanged ( updateBeatmapAvailability , true ) ;
2021-02-16 13:42:31 +08:00
UserMods . BindValueChanged ( onUserModsChanged ) ;
2020-12-20 23:04:06 +08:00
client . LoadRequested + = onLoadRequested ;
2021-02-11 14:55:08 +08:00
client . RoomUpdated + = onRoomUpdated ;
2020-12-23 14:58:50 +08:00
2022-07-17 17:23:15 +08:00
if ( ! client . IsConnected . Value )
handleRoomLost ( ) ;
2020-12-20 23:04:06 +08:00
}
2023-07-19 18:36:51 +08:00
protected override bool IsConnected = > base . IsConnected & & client . IsConnected . Value ;
2021-10-15 19:18:25 +08:00
protected override Drawable CreateMainContent ( ) = > new Container
2021-08-17 16:05:20 +08:00
{
RelativeSizeAxes = Axes . Both ,
2021-10-15 19:18:25 +08:00
Padding = new MarginPadding { Horizontal = 5 , Vertical = 10 } ,
2022-07-08 06:42:11 +08:00
Child = new OsuContextMenuContainer
2021-08-17 16:05:20 +08:00
{
2021-10-15 19:18:25 +08:00
RelativeSizeAxes = Axes . Both ,
2022-07-08 06:42:11 +08:00
Child = new GridContainer
2021-08-17 16:05:20 +08:00
{
2022-07-08 06:42:11 +08:00
RelativeSizeAxes = Axes . Both ,
ColumnDimensions = new [ ]
{
new Dimension ( ) ,
new Dimension ( GridSizeMode . Absolute , 10 ) ,
new Dimension ( ) ,
new Dimension ( GridSizeMode . Absolute , 10 ) ,
new Dimension ( ) ,
} ,
Content = new [ ]
2021-08-17 16:05:20 +08:00
{
2024-11-12 00:38:31 +08:00
new Drawable ? [ ]
2021-08-17 16:05:20 +08:00
{
2022-07-08 06:42:11 +08:00
new GridContainer
2021-08-18 14:54:33 +08:00
{
2022-07-08 06:42:11 +08:00
RelativeSizeAxes = Axes . Both ,
RowDimensions = new [ ]
2021-08-17 16:05:20 +08:00
{
2022-07-08 06:42:11 +08:00
new Dimension ( GridSizeMode . AutoSize )
} ,
Content = new [ ]
{
new Drawable [ ] { new ParticipantsListHeader ( ) } ,
new Drawable [ ]
2021-08-17 16:05:20 +08:00
{
2022-07-08 06:42:11 +08:00
new ParticipantsList
{
RelativeSizeAxes = Axes . Both
} ,
}
2021-10-15 19:18:25 +08:00
}
2022-07-08 06:42:11 +08:00
} ,
null ,
new GridContainer
2021-10-15 19:18:25 +08:00
{
2022-07-08 06:42:11 +08:00
RelativeSizeAxes = Axes . Both ,
2025-02-12 16:31:55 +08:00
RowDimensions = new [ ]
{
new Dimension ( GridSizeMode . AutoSize ) ,
new Dimension ( GridSizeMode . AutoSize ) ,
new Dimension ( GridSizeMode . Absolute , 5 ) ,
new Dimension ( ) ,
new Dimension ( GridSizeMode . AutoSize ) ,
new Dimension ( GridSizeMode . AutoSize ) ,
} ,
2022-07-08 06:42:11 +08:00
Content = new [ ]
2021-10-22 18:41:36 +08:00
{
2025-02-12 16:31:55 +08:00
new Drawable [ ] { new OverlinedHeader ( "Beatmap queue" ) } ,
2022-07-08 06:42:11 +08:00
new Drawable [ ]
2021-10-22 18:41:36 +08:00
{
2022-07-08 06:42:11 +08:00
addItemButton = new AddItemButton
{
RelativeSizeAxes = Axes . X ,
Height = 40 ,
Text = "Add item" ,
Action = ( ) = > OpenSongSelection ( )
} ,
2021-10-22 21:17:26 +08:00
} ,
2022-07-08 06:42:11 +08:00
null ,
new Drawable [ ]
2021-10-22 21:17:26 +08:00
{
2024-11-14 16:57:32 +08:00
new MultiplayerPlaylist ( Room )
2022-07-08 06:42:11 +08:00
{
RelativeSizeAxes = Axes . Both ,
2024-11-12 00:38:31 +08:00
RequestEdit = OpenSongSelection ,
SelectedItem = SelectedItem
2022-07-08 06:42:11 +08:00
}
} ,
2025-02-06 12:29:16 +08:00
new [ ]
2021-08-18 14:54:33 +08:00
{
2025-02-06 12:29:16 +08:00
UserModsSection = new FillFlowContainer
2021-08-18 14:54:33 +08:00
{
2022-07-08 06:42:11 +08:00
RelativeSizeAxes = Axes . X ,
AutoSizeAxes = Axes . Y ,
Margin = new MarginPadding { Top = 10 } ,
2025-02-06 12:29:16 +08:00
Alpha = 0 ,
Children = new Drawable [ ]
2021-08-18 14:54:33 +08:00
{
2025-02-06 12:29:16 +08:00
new OverlinedHeader ( "Extra mods" ) ,
new FillFlowContainer
2021-08-18 14:54:33 +08:00
{
2025-02-06 12:29:16 +08:00
AutoSizeAxes = Axes . Both ,
Direction = FillDirection . Horizontal ,
Spacing = new Vector2 ( 10 , 0 ) ,
2022-07-08 06:42:11 +08:00
Children = new Drawable [ ]
2021-10-15 19:18:25 +08:00
{
2025-02-06 12:29:16 +08:00
new UserModSelectButton
2022-07-08 06:42:11 +08:00
{
2025-02-06 12:29:16 +08:00
Anchor = Anchor . CentreLeft ,
Origin = Anchor . CentreLeft ,
Width = 90 ,
2025-02-12 16:43:49 +08:00
Height = 30 ,
2025-02-06 12:29:16 +08:00
Text = "Select" ,
Action = ShowUserModSelect ,
2022-07-08 06:42:11 +08:00
} ,
2025-02-06 12:29:16 +08:00
new ModDisplay
2022-07-08 06:42:11 +08:00
{
2025-02-06 12:29:16 +08:00
Anchor = Anchor . CentreLeft ,
Origin = Anchor . CentreLeft ,
Current = UserMods ,
Scale = new Vector2 ( 0.8f ) ,
} ,
2022-07-08 06:42:11 +08:00
}
} ,
}
2024-12-23 19:12:25 +08:00
}
2021-08-19 18:02:31 +08:00
} ,
2025-02-06 12:29:16 +08:00
new [ ]
{
UserStyleSection = new FillFlowContainer
{
RelativeSizeAxes = Axes . X ,
AutoSizeAxes = Axes . Y ,
Margin = new MarginPadding { Top = 10 } ,
Alpha = 0 ,
Children = new Drawable [ ]
{
new OverlinedHeader ( "Difficulty" ) ,
UserStyleDisplayContainer = new Container < DrawableRoomPlaylistItem >
{
RelativeSizeAxes = Axes . X ,
AutoSizeAxes = Axes . Y
}
}
} ,
} ,
2021-10-15 19:18:25 +08:00
} ,
} ,
2022-07-08 06:42:11 +08:00
null ,
new GridContainer
2021-10-15 19:18:25 +08:00
{
2022-07-08 06:42:11 +08:00
RelativeSizeAxes = Axes . Both ,
Content = new [ ]
{
new Drawable [ ] { new OverlinedHeader ( "Chat" ) } ,
new Drawable [ ] { new MatchChatDisplay ( Room ) { RelativeSizeAxes = Axes . Both } }
} ,
RowDimensions = new [ ]
{
new Dimension ( GridSizeMode . AutoSize ) ,
new Dimension ( ) ,
}
2021-10-15 19:25:32 +08:00
} ,
2022-07-08 06:42:11 +08:00
}
2021-08-17 16:05:20 +08:00
}
2021-10-15 19:18:25 +08:00
}
}
2021-08-17 16:05:20 +08:00
} ;
2021-12-10 13:14:22 +08:00
/// <summary>
/// Opens the song selection screen to add or edit an item.
/// </summary>
/// <param name="itemToEdit">An optional playlist item to edit. If null, a new item will be added instead.</param>
2024-11-12 00:38:31 +08:00
internal void OpenSongSelection ( PlaylistItem ? itemToEdit = null )
2021-12-06 13:03:24 +08:00
{
if ( ! this . IsCurrentScreen ( ) )
return ;
2022-09-07 19:01:17 +08:00
this . Push ( new MultiplayerMatchSongSelect ( Room , itemToEdit ) ) ;
2021-12-06 13:03:24 +08:00
}
2024-12-25 21:24:21 +08:00
protected override void OpenStyleSelection ( )
{
if ( ! this . IsCurrentScreen ( ) | | SelectedItem . Value is not PlaylistItem item )
return ;
2025-02-03 18:21:21 +08:00
this . Push ( new MultiplayerMatchFreestyleSelect ( Room , item ) ) ;
2024-12-25 21:24:21 +08:00
}
2024-11-12 00:38:31 +08:00
protected override Drawable CreateFooter ( ) = > new MultiplayerMatchFooter
{
SelectedItem = SelectedItem
} ;
2021-08-17 16:05:20 +08:00
2024-11-12 00:38:31 +08:00
protected override RoomSettingsOverlay CreateRoomSettingsOverlay ( Room room ) = > new MultiplayerMatchSettingsOverlay ( room )
{
SelectedItem = SelectedItem
} ;
2021-08-17 17:24:04 +08:00
2024-12-25 21:24:21 +08:00
protected override APIMod [ ] GetGameplayMods ( )
2021-08-18 19:21:29 +08:00
{
2024-12-25 21:24:21 +08:00
// Using the room's reported status makes the server authoritative.
2025-01-08 17:57:22 +08:00
return client . LocalUser ? . Mods ! = null ? client . LocalUser . Mods . Concat ( SelectedItem . Value ! . RequiredMods ) . ToArray ( ) : base . GetGameplayMods ( ) ;
2024-12-25 21:24:21 +08:00
}
2021-08-18 19:21:29 +08:00
2024-12-25 21:24:21 +08:00
protected override RulesetInfo GetGameplayRuleset ( )
{
// Using the room's reported status makes the server authoritative.
return client . LocalUser ? . RulesetId ! = null ? Rulesets . GetRuleset ( client . LocalUser . RulesetId . Value ) ! : base . GetGameplayRuleset ( ) ;
}
protected override IBeatmapInfo GetGameplayBeatmap ( )
{
// Using the room's reported status makes the server authoritative.
return client . LocalUser ? . BeatmapId ! = null ? new APIBeatmap { OnlineID = client . LocalUser . BeatmapId . Value } : base . GetGameplayBeatmap ( ) ;
2021-08-18 19:21:29 +08:00
}
2021-03-03 14:24:55 +08:00
[Resolved(canBeNull: true)]
2024-11-12 00:38:31 +08:00
private IDialogOverlay ? dialogOverlay { get ; set ; }
2021-03-03 13:50:54 +08:00
2024-01-22 22:35:03 +08:00
private bool exitConfirmed ;
2022-04-21 23:52:44 +08:00
public override bool OnExiting ( ScreenExitEvent e )
2021-06-22 11:22:18 +08:00
{
2023-07-19 18:36:51 +08:00
// room has not been created yet or we're offline; exit immediately.
if ( client . Room = = null | | ! IsConnected )
2022-04-21 23:52:44 +08:00
return base . OnExiting ( e ) ;
2021-06-22 11:22:18 +08:00
2024-01-22 22:35:03 +08:00
if ( ! exitConfirmed & & dialogOverlay ! = null )
2021-03-03 13:50:54 +08:00
{
2021-06-22 11:23:11 +08:00
if ( dialogOverlay . CurrentDialog is ConfirmDialog confirmDialog )
confirmDialog . PerformOkAction ( ) ;
else
2021-03-03 13:50:54 +08:00
{
2021-06-22 11:23:11 +08:00
dialogOverlay . Push ( new ConfirmDialog ( "Are you sure you want to leave this multiplayer match?" , ( ) = >
{
2024-01-22 22:35:03 +08:00
exitConfirmed = true ;
2023-07-30 21:50:10 +08:00
if ( this . IsCurrentScreen ( ) )
this . Exit ( ) ;
2021-06-22 11:23:11 +08:00
} ) ) ;
}
2021-03-03 13:50:54 +08:00
return true ;
}
2022-04-21 23:52:44 +08:00
return base . OnExiting ( e ) ;
2020-12-20 23:04:06 +08:00
}
2024-11-12 00:38:31 +08:00
private ModSettingChangeTracker ? modSettingChangeTracker ;
private ScheduledDelegate ? debouncedModSettingsUpdate ;
2021-02-10 18:56:59 +08:00
2021-02-01 16:57:32 +08:00
private void onUserModsChanged ( ValueChangedEvent < IReadOnlyList < Mod > > mods )
2021-02-01 16:54:56 +08:00
{
2021-02-10 18:56:59 +08:00
modSettingChangeTracker ? . Dispose ( ) ;
2021-02-01 16:54:56 +08:00
if ( client . Room = = null )
return ;
2022-03-30 22:58:30 +08:00
client . ChangeUserMods ( mods . NewValue ) . FireAndForget ( ) ;
2021-02-10 18:56:59 +08:00
modSettingChangeTracker = new ModSettingChangeTracker ( mods . NewValue ) ;
modSettingChangeTracker . SettingChanged + = onModSettingsChanged ;
}
private void onModSettingsChanged ( Mod mod )
{
// Debounce changes to mod settings so as to not thrash the network.
debouncedModSettingsUpdate ? . Cancel ( ) ;
2021-02-10 19:16:26 +08:00
debouncedModSettingsUpdate = Scheduler . AddDelayed ( ( ) = >
{
if ( client . Room = = null )
return ;
2022-03-30 22:58:30 +08:00
client . ChangeUserMods ( UserMods . Value ) . FireAndForget ( ) ;
2021-02-10 19:16:26 +08:00
} , 500 ) ;
2021-02-01 16:54:56 +08:00
}
2020-12-20 23:04:06 +08:00
2021-02-05 15:17:02 +08:00
private void updateBeatmapAvailability ( ValueChangedEvent < BeatmapAvailability > availability )
2021-01-18 15:49:38 +08:00
{
2021-01-18 22:23:51 +08:00
if ( client . Room = = null )
return ;
2022-03-30 22:58:30 +08:00
client . ChangeBeatmapAvailability ( availability . NewValue ) . FireAndForget ( ) ;
2021-02-05 15:19:45 +08:00
2023-06-28 13:51:19 +08:00
switch ( availability . NewValue . State )
2021-05-11 18:22:09 +08:00
{
2023-06-28 13:51:19 +08:00
case DownloadState . LocallyAvailable :
if ( client . LocalUser ? . State = = MultiplayerUserState . Spectating
& & ( client . Room ? . State = = MultiplayerRoomState . WaitingForLoad | | client . Room ? . State = = MultiplayerRoomState . Playing ) )
{
onLoadRequested ( ) ;
}
break ;
case DownloadState . Unknown :
// Don't do anything rash in an unknown state.
break ;
default :
// while this flow is handled server-side, this covers the edge case of the local user being in a ready state and then deleting the current beatmap.
if ( client . LocalUser ? . State = = MultiplayerUserState . Ready )
client . ChangeState ( MultiplayerUserState . Idle ) ;
break ;
2021-05-11 18:22:09 +08:00
}
2021-01-18 15:49:38 +08:00
}
2021-04-26 20:55:38 +08:00
private void onRoomUpdated ( )
2021-02-11 14:55:08 +08:00
{
2021-08-11 18:56:25 +08:00
// may happen if the client is kicked or otherwise removed from the room.
if ( client . Room = = null )
{
2021-08-13 13:37:43 +08:00
handleRoomLost ( ) ;
2021-08-11 18:56:25 +08:00
return ;
}
2025-01-29 18:06:14 +08:00
SelectedItem . Value = Room . Playlist . SingleOrDefault ( i = > i . ID = = client . Room . Settings . PlaylistItemId ) ;
2021-12-10 19:08:59 +08:00
2023-06-20 17:27:19 +08:00
addItemButton . Alpha = localUserCanAddItem ? 1 : 0 ;
2021-10-22 18:41:36 +08:00
2024-01-03 01:38:25 +08:00
Activity . Value = new UserActivity . InLobby ( Room ) ;
2021-04-26 20:55:38 +08:00
}
2021-04-09 20:03:45 +08:00
2024-11-13 17:57:51 +08:00
private bool localUserCanAddItem = > client . IsHost | | Room . QueueMode ! = QueueMode . HostOnly ;
2023-06-20 17:27:19 +08:00
2021-08-13 13:37:43 +08:00
private void handleRoomLost ( ) = > Schedule ( ( ) = >
{
2021-12-21 14:07:06 +08:00
Logger . Log ( $"{this} exiting due to loss of room or connection" ) ;
2021-12-21 13:37:23 +08:00
2021-08-13 13:37:43 +08:00
if ( this . IsCurrentScreen ( ) )
this . Exit ( ) ;
else
ValidForResume = false ;
} ) ;
2021-04-26 20:55:38 +08:00
private void onLoadRequested ( )
{
2021-05-03 13:01:10 +08:00
// In the case of spectating, IMultiplayerClient.LoadRequested can be fired while the game is still spectating a previous session.
// For now, we want to game to switch to the new game so need to request exiting from the play screen.
2021-04-26 20:55:38 +08:00
if ( ! ParentScreen . IsCurrentScreen ( ) )
2021-04-09 20:03:45 +08:00
{
2021-04-26 20:55:38 +08:00
ParentScreen . MakeCurrent ( ) ;
2021-04-13 22:21:35 +08:00
2021-04-26 20:55:38 +08:00
Schedule ( onLoadRequested ) ;
return ;
2021-04-09 20:03:45 +08:00
}
2021-02-11 14:55:08 +08:00
2022-02-03 22:22:08 +08:00
// The beatmap is queried asynchronously when the selected item changes.
// This is an issue with MultiSpectatorScreen which is effectively in an always "ready" state and receives LoadRequested() callbacks
// even when it is not truly ready (i.e. the beatmap hasn't been selected by the client yet). For the time being, a simple fix to this is to ignore the callback.
// Note that spectator will be entered automatically when the client is capable of doing so via beatmap availability callbacks (see: updateBeatmapAvailability()).
2022-02-04 16:53:30 +08:00
if ( client . LocalUser ? . State = = MultiplayerUserState . Spectating & & ( SelectedItem . Value = = null | | Beatmap . IsDefault ) )
2022-02-03 22:22:08 +08:00
return ;
2023-08-01 18:08:26 +08:00
if ( BeatmapAvailability . Value . State ! = DownloadState . LocallyAvailable )
return ;
2021-04-22 22:37:33 +08:00
StartPlay ( ) ;
2020-12-24 09:38:53 +08:00
}
2020-12-20 23:04:06 +08:00
2024-11-21 19:26:44 +08:00
protected override Screen CreateGameplayScreen ( PlaylistItem selectedItem )
2021-04-22 22:37:33 +08:00
{
Debug . Assert ( client . LocalUser ! = null ) ;
2021-08-10 17:39:20 +08:00
Debug . Assert ( client . Room ! = null ) ;
2021-04-22 22:37:33 +08:00
2021-05-03 13:04:20 +08:00
int [ ] userIds = client . CurrentMatchPlayingUserIds . ToArray ( ) ;
2021-08-10 17:39:20 +08:00
MultiplayerRoomUser [ ] users = userIds . Select ( id = > client . Room . Users . First ( u = > u . UserID = = id ) ) . ToArray ( ) ;
2021-04-22 22:37:33 +08:00
2021-05-03 13:04:20 +08:00
switch ( client . LocalUser . State )
{
case MultiplayerUserState . Spectating :
2022-02-25 15:03:28 +08:00
return new MultiSpectatorScreen ( Room , users . Take ( PlayerGrid . MAX_PLAYERS ) . ToArray ( ) ) ;
2021-05-03 13:04:20 +08:00
default :
2024-11-21 19:26:44 +08:00
return new MultiplayerPlayerLoader ( ( ) = > new MultiplayerPlayer ( Room , selectedItem , users ) ) ;
2021-05-03 13:04:20 +08:00
}
2021-04-22 22:37:33 +08:00
}
2021-03-03 13:04:00 +08:00
public void PresentBeatmap ( WorkingBeatmap beatmap , RulesetInfo ruleset )
{
if ( ! this . IsCurrentScreen ( ) )
return ;
2023-06-20 17:27:19 +08:00
if ( ! localUserCanAddItem )
return ;
2023-06-21 23:02:02 +08:00
// If there's only one playlist item and we are the host, assume we want to change it. Else add a new one.
2024-11-12 00:38:31 +08:00
PlaylistItem ? itemToEdit = client . IsHost & & Room . Playlist . Count = = 1 ? Room . Playlist . Single ( ) : null ;
2021-12-10 19:08:59 +08:00
2023-06-20 17:23:59 +08:00
OpenSongSelection ( itemToEdit ) ;
2021-03-03 13:53:47 +08:00
2023-06-20 17:23:59 +08:00
// Re-run PresentBeatmap now that we've pushed a song select that can handle it.
game ? . PresentBeatmap ( beatmap . BeatmapSetInfo , b = > b . ID = = beatmap . BeatmapInfo . ID ) ;
2021-03-03 13:04:00 +08:00
}
2021-08-18 14:54:33 +08:00
protected override void Dispose ( bool isDisposing )
{
base . Dispose ( isDisposing ) ;
2024-11-12 00:38:31 +08:00
if ( client . IsNotNull ( ) )
2021-08-18 14:54:33 +08:00
{
client . RoomUpdated - = onRoomUpdated ;
client . LoadRequested - = onLoadRequested ;
}
modSettingChangeTracker ? . Dispose ( ) ;
}
2021-12-10 00:15:15 +08:00
2022-11-26 23:19:36 +08:00
public partial class AddItemButton : PurpleRoundedButton
2021-12-10 00:15:15 +08:00
{
}
2020-12-20 23:04:06 +08:00
}
}