@@ -22,7 +22,7 @@ public sealed class LobbyScene(PlayerMode mode) : Scene
2222 PlayerMode mode = mode ;
2323
2424 readonly TimeSpan refreshInterval = TimeSpan . FromSeconds ( 2 ) ;
25- readonly TimeSpan pingInterval = TimeSpan . FromMilliseconds ( 300 ) ;
25+ readonly TimeSpan handShakeInterval = TimeSpan . FromMilliseconds ( 300 ) ;
2626 readonly KeyboardController keyboard = new ( ) ;
2727 readonly CancellationTokenSource cts = new ( ) ;
2828
@@ -33,8 +33,7 @@ public override void Initialize()
3333 lobbyUdpClient = new ( Config . LocalPort , Config . ServerUrl , Config . ServerUdpPort ) ;
3434 keyboard . Update ( ) ;
3535
36- StartPingTimer ( ) ;
37- StartLobbyRefreshTimer ( ) ;
36+ _ = StartTimers ( ) ;
3837 }
3938
4039 public override void Update ( GameTime gameTime )
@@ -59,7 +58,7 @@ async Task ToggleReady()
5958 {
6059 if ( ! AllReachable ( ) ) return ;
6160
62- await client . ToggleReady ( ) ;
61+ await client . ToggleReady ( cts . Token ) ;
6362 ready = true ;
6463 }
6564
@@ -295,7 +294,7 @@ void DrawError(SpriteBatch spriteBatch)
295294
296295 async Task RequestLobby ( )
297296 {
298- user = await client . EnterLobby ( Config . LobbyName , Config . Username , mode ) ;
297+ user = await client . EnterLobby ( Config . LobbyName , Config . Username , mode , cts . Token ) ;
299298 await RefreshLobby ( ) ;
300299
301300 if ( Array . Exists ( lobbyInfo . Spectators , s => s . PeerId == user . PeerId ) )
@@ -306,13 +305,20 @@ async Task RequestLobby()
306305
307306 async Task RefreshLobby ( )
308307 {
309- lobbyInfo = await client . GetLobby ( ) ;
308+ if ( await client . GetLobby ( cts . Token ) is not { } lobby )
309+ {
310+ SetError ( "Can't find Lobby..." ) ;
311+ await Task . Delay ( TimeSpan . FromSeconds ( 1.5 ) ) ;
312+ lobbyInfo = null ;
313+ LoadScene ( new ChooseLobbyScene ( ) ) ;
314+ return ;
315+ }
310316
317+ lobbyInfo = lobby ;
311318 await lobbyUdpClient . HandShake ( user ) ;
312319
313320 if ( connected ) return ;
314- connected = lobbyInfo . Players . SingleOrDefault ( x => x . PeerId == user . PeerId ) is
315- { Connected : true } ;
321+ connected = lobbyInfo . Players . SingleOrDefault ( x => x . PeerId == user . PeerId ) is { Connected : true } ;
316322 }
317323
318324 void CheckPlayersReady ( )
@@ -416,90 +422,63 @@ NetcodeSessionBuilder<PlayerInputs> NetcodeSessionBuilder() =>
416422
417423 bool PendingNetworkCall ( )
418424 {
419- if ( networkCall is null )
420- return false ;
421-
422- if ( ! networkCall . IsCompleted )
423- return true ;
424-
425- if ( networkCall . IsFaulted )
426- SetError ( networkCall . Exception ) ;
425+ if ( networkCall is null ) return false ;
426+ if ( ! networkCall . IsCompleted ) return true ;
427+ if ( networkCall is { IsFaulted : true , Exception . InnerException : not TaskCanceledException } )
428+ SetError ( networkCall . Exception . InnerException ) ;
427429
428430 networkCall = null ;
429431 return true ;
430432 }
431433
432- void SetError ( Exception ex )
434+ void SetError ( Exception ex ) => SetError ( ex . ToString ( ) ) ;
435+
436+ void SetError ( string message )
433437 {
434438 currentState = LobbyState . Error ;
435- errorMessage =
436- ex ? . InnerException ? . Message
437- ?? networkCall . Exception ? . Message ;
439+ errorMessage = message ;
438440 }
439441
440- public void StartPingTimer ( ) => Task . Run ( async ( ) =>
442+ async Task StartTimers ( )
441443 {
442- using PeriodicTimer timer = new ( pingInterval ) ;
443-
444- try
445- {
446- while ( await timer . WaitForNextTickAsync ( cts . Token ) )
444+ var handShakeTimer = AsyncTimer . Create ( handShakeInterval , async ( ) =>
447445 {
448- if ( lobbyInfo is null || lobbyInfo . Ready ) continue ;
449- await Task . WhenAll (
450- lobbyUdpClient . Ping ( user , lobbyInfo . Players , cts . Token ) ,
451- lobbyUdpClient . Ping ( user , lobbyInfo . Spectators , cts . Token )
452- ) ;
453- }
454- }
455- catch ( OperationCanceledException )
456- {
457- // skip
458- }
459- catch ( Exception ex )
460- {
461- SetError ( ex ) ;
462- }
463- } ) ;
446+ if ( lobbyInfo is not null && ! lobbyInfo . Ready )
447+ await Task . WhenAll (
448+ lobbyUdpClient . HandShake ( user , lobbyInfo . Players , cts . Token ) ,
449+ lobbyUdpClient . HandShake ( user , lobbyInfo . Spectators , cts . Token )
450+ ) ;
451+ } ,
452+ SetError , cts . Token ) ;
453+
454+ var refreshTimer = AsyncTimer . Create ( refreshInterval , async ( ) =>
455+ {
456+ if ( currentState is LobbyState . Waiting )
457+ await RefreshLobby ( ) ;
458+ } ,
459+ SetError , cts . Token ) ;
464460
465- public void StartLobbyRefreshTimer ( ) => Task . Run ( async ( ) =>
466- {
467- using PeriodicTimer timer = new ( refreshInterval ) ;
468461
469- try
470- {
471- while ( await timer . WaitForNextTickAsync ( cts . Token ) )
472- {
473- if ( currentState is not LobbyState . Waiting ) continue ;
474- await RefreshLobby ( ) ;
475- }
476- }
477- catch ( OperationCanceledException )
478- {
479- // skip
480- }
481- catch ( Exception ex )
482- {
483- SetError ( ex ) ;
484- }
485- } ) ;
462+ await Task . Run ( ( ) => Task . WhenAll ( handShakeTimer , refreshTimer ) , cts . Token ) ;
463+ }
486464
487465 protected override void Dispose ( bool disposing )
488466 {
489467 try
490468 {
469+ if ( user is not null && lobbyInfo is { Ready : false } )
470+ client . LeaveLobby ( cts . Token ) . GetAwaiter ( ) . GetResult ( ) ;
471+
491472 cts . Dispose ( ) ;
492473 lobbyUdpClient . Dispose ( ) ;
493- if ( user is not null && lobbyInfo is { Ready : false } )
494- client . LeaveLobby ( ) . GetAwaiter ( ) . GetResult ( ) ;
495474 }
496475 catch ( Exception e )
497476 {
498477 Console . WriteLine ( $ "Error leaving lobby: { e } ") ;
499478 }
500479 }
501480
502- public enum LobbyState
481+ enum LobbyState
503482 {
504483 Loading ,
505484 Waiting ,
0 commit comments