@@ -55,7 +55,7 @@ import Player from '#/engine/entity/Player.js';
5555import EntityLifeCycle from '#/engine/entity/EntityLifeCycle.js' ;
5656import { NpcList , PlayerList } from '#/engine/entity/EntityList.js' ;
5757import { isClientConnected , NetworkPlayer } from '#/engine/entity/NetworkPlayer.js' ;
58- import { EntityQueueState } from '#/engine/entity/EntityQueueRequest.js' ;
58+ import { EntityQueueState , PlayerQueueType } from '#/engine/entity/EntityQueueRequest.js' ;
5959import { PlayerTimerType } from '#/engine/entity/EntityTimer.js' ;
6060
6161import UpdateRebootTimer from '#/network/server/model/UpdateRebootTimer.js' ;
@@ -122,8 +122,8 @@ class World {
122122 private static readonly PLAYER_SAVERATE : number = 500 ; // 5m
123123 private static readonly PLAYER_COORDLOGRATE : number = 50 ; // 30s
124124
125- private static readonly TIMEOUT_SOCKET_IDLE : number = Environment . NODE_DEBUG_SOCKET ? 60000 : 50 ; // 30s with no data- disconnect client
126- private static readonly TIMEOUT_SOCKET_LOGOUT : number = Environment . NODE_DEBUG_SOCKET ? 60000 : 100 ; // 60s with no client- remove player from processing
125+ private static readonly TIMEOUT_NO_CONNECTION : number = Environment . NODE_DEBUG_SOCKET ? 60000 : 50 ; // 30s with no connection (16 ticks in osrs)
126+ private static readonly TIMEOUT_NO_RESPONSE : number = Environment . NODE_DEBUG_SOCKET ? 60000 : 100 ; // 60s without any response
127127
128128 // the game/zones map
129129 readonly gameMap : GameMap ;
@@ -712,14 +712,6 @@ class World {
712712 }
713713 }
714714
715- if ( this . currentTick - player . lastResponse >= World . TIMEOUT_SOCKET_LOGOUT ) {
716- // x-logged / timed out for 60s: logout
717- player . loggedOut = true ;
718- } else if ( this . currentTick - player . lastResponse >= World . TIMEOUT_SOCKET_IDLE ) {
719- // x-logged / timed out for 30s: attempt logout
720- player . tryLogout = true ;
721- }
722-
723715 // - client input tracking
724716 player . processInputTracking ( ) ;
725717
@@ -728,7 +720,10 @@ class World {
728720 }
729721 } catch ( err ) {
730722 console . error ( err ) ;
731- this . removePlayer ( player ) ;
723+ if ( isClientConnected ( player ) ) {
724+ player . logout ( ) ;
725+ player . client . close ( ) ;
726+ }
732727 }
733728 }
734729
@@ -841,7 +836,7 @@ class World {
841836 // - primary queue
842837 // - weak queue
843838 player . processQueues ( ) ;
844- if ( ! player . loggedOut ) {
839+ if ( ! player . loggingOut ) {
845840 // - timers
846841 player . processTimers ( PlayerTimerType . NORMAL ) ;
847842 // - soft timers
@@ -861,7 +856,10 @@ class World {
861856 }
862857 } catch ( err ) {
863858 console . error ( err ) ;
864- this . removePlayer ( player ) ;
859+ if ( isClientConnected ( player ) ) {
860+ player . logout ( ) ;
861+ player . client . close ( ) ;
862+ }
865863 }
866864 }
867865
@@ -872,33 +870,54 @@ class World {
872870 const start : number = Date . now ( ) ;
873871
874872 for ( const player of this . players ) {
875- if ( player . loggedOut ) {
876- player . tryLogout = true ;
877- player . clearInteraction ( ) ;
878- }
879-
880- if ( ! player . tryLogout ) {
881- continue ;
873+ let force = false ;
874+ if ( this . shutdown || this . currentTick - player . lastResponse >= World . TIMEOUT_NO_RESPONSE ) {
875+ // world shutdown or x-logged / timed out for 60s: force logout
876+ player . loggingOut = true ;
877+ force = true ;
878+ } else if ( this . currentTick - player . lastConnected >= World . TIMEOUT_NO_CONNECTION ) {
879+ // connection lost for 30s: request idle logout
880+ player . requestIdleLogout = true ;
881+ }
882+
883+ if ( player . requestLogout || player . requestIdleLogout ) {
884+ if ( this . currentTick >= player . preventLogoutUntil ) {
885+ player . loggingOut = true ;
886+ } else if ( player . requestLogout && player . preventLogoutMessage !== null ) {
887+ player . messageGame ( player . preventLogoutMessage ) ; // engine message type in osrs
888+ player . preventLogoutMessage = null ;
889+ }
890+ player . requestLogout = false ;
891+ player . requestIdleLogout = false ;
882892 }
883893
884- player . closeModal ( ) ;
894+ if ( player . loggingOut && ( force || this . currentTick >= player . preventLogoutUntil ) ) {
895+ player . closeModal ( ) ;
885896
886- if ( player . canAccess ( ) && player . queue . head ( ) === null && player . engineQueue . head ( ) === null ) {
887- const script = ScriptProvider . getByTriggerSpecific ( ServerTriggerType . LOGOUT , - 1 , - 1 ) ;
888- if ( ! script ) {
889- printError ( 'LOGOUT TRIGGER IS BROKEN!' ) ;
890- continue ;
897+ let queueDiscardable = true ;
898+ for ( let request = player . queue . head ( ) ; request !== null ; request = player . queue . next ( ) ) {
899+ if ( request . type === PlayerQueueType . LONG ) {
900+ const logoutAction = request . args [ 0 ] ;
901+ if ( logoutAction === 1 ) {
902+ // ^discard
903+ continue ;
904+ }
905+ }
906+ queueDiscardable = false ;
907+ break ;
891908 }
892-
893- const state = ScriptRunner . init ( script , player ) ;
894- state . pointerAdd ( ScriptPointer . ProtectedActivePlayer ) ;
895- ScriptRunner . execute ( state ) ;
896-
897- const result = state . popInt ( ) ;
898- if ( result === 1 ) {
909+ if ( player . canAccess ( ) && player . engineQueue . head ( ) === null && queueDiscardable ) {
910+ const script = ScriptProvider . getByTriggerSpecific ( ServerTriggerType . LOGOUT , - 1 , - 1 ) ;
911+ if ( ! script ) {
912+ printError ( 'LOGOUT TRIGGER IS BROKEN!' ) ;
913+ continue ;
914+ }
915+
916+ const state = ScriptRunner . init ( script , player ) ;
917+ state . pointerAdd ( ScriptPointer . ProtectedActivePlayer ) ;
918+ ScriptRunner . execute ( state ) ;
919+
899920 this . removePlayer ( player ) ;
900- } else {
901- player . tryLogout = false ;
902921 }
903922 }
904923 }
@@ -1112,7 +1131,10 @@ class World {
11121131 player . encodeOut ( ) ;
11131132 } catch ( err ) {
11141133 console . error ( err ) ;
1115- this . removePlayer ( player ) ;
1134+ if ( isClientConnected ( player ) ) {
1135+ player . logout ( ) ;
1136+ player . client . close ( ) ;
1137+ }
11161138 }
11171139 }
11181140 this . cycleStats [ WorldStat . CLIENT_OUT ] = Date . now ( ) - start ;
@@ -1199,23 +1221,23 @@ class World {
11991221 }
12001222
12011223 private processShutdown ( ) : void {
1224+ for ( const player of this . players ) {
1225+ if ( isClientConnected ( player ) ) {
1226+ player . logout ( ) ;
1227+ player . client . close ( ) ;
1228+ }
1229+ }
1230+
12021231 const duration = this . currentTick - this . shutdownTick ;
12031232 if ( duration >= 1024 ) {
12041233 // force remove all players, they had their chances to finish processing
12051234 for ( const player of this . players ) {
1235+ player . addSessionLog ( LoggerEventType . ENGINE , 'Player force removed!' ) ;
1236+ printError ( `Player '${ player . username } ' force removed!` ) ;
12061237 this . removePlayer ( player ) ;
12071238 }
12081239 }
12091240
1210- for ( const player of this . players ) {
1211- player . loggedOut = true ;
1212-
1213- if ( isClientConnected ( player ) ) {
1214- player . logout ( ) ; // see ya
1215- player . client . close ( ) ;
1216- }
1217- }
1218-
12191241 const online = this . getTotalPlayers ( ) ;
12201242 if ( online === 0 && this . logoutRequests . size === 0 ) {
12211243 printInfo ( 'Server shutdown complete' ) ;
@@ -1592,11 +1614,6 @@ class World {
15921614 return null ;
15931615 }
15941616
1595- if ( player . loggedOut ) {
1596- // todo: proper?
1597- return null ;
1598- }
1599-
16001617 return player ;
16011618 }
16021619
0 commit comments