2023-01-21 14:53:41 +00:00
const RingBuffer = require ( './RingBuffer' ) ;
var NetworkDoctor = function ( capacity ) {
this . reset ( capacity ) ;
} ;
NetworkDoctor . prototype . reset = function ( capacity ) {
2023-02-13 02:34:56 +00:00
this . inputFrameIdFront = 0 ;
2023-01-21 14:53:41 +00:00
this . sendingQ = new RingBuffer ( capacity ) ;
this . inputFrameDownsyncQ = new RingBuffer ( capacity ) ;
this . peerInputFrameUpsyncQ = new RingBuffer ( capacity ) ;
this . peerInputFrameUpsyncCnt = 0 ;
this . immediateRollbackFrames = 0 ;
2023-01-22 03:34:02 +00:00
this . skippedRenderFrameCnt = 0 ;
this . inputRateThreshold = gopkgs . ConvertToNoDelayInputFrameId ( 60 ) ;
this . peerUpsyncThreshold = 8 ;
2023-01-23 06:17:52 +00:00
this . rollbackFramesThreshold = 8 ; // Roughly the minimum "TurnAroundFramesToRecover".
2023-01-21 14:53:41 +00:00
} ;
2023-02-13 02:34:56 +00:00
NetworkDoctor . prototype . logInputFrameIdFront = function ( inputFrameId ) {
this . inputFrameIdFront = inputFrameId ;
} ;
2023-01-21 14:53:41 +00:00
NetworkDoctor . prototype . logSending = function ( stFrameId , edFrameId ) {
this . sendingQ . put ( {
i : stFrameId ,
j : edFrameId ,
t : Date . now ( )
} ) ;
} ;
NetworkDoctor . prototype . logInputFrameDownsync = function ( stFrameId , edFrameId ) {
this . inputFrameDownsyncQ . put ( {
i : stFrameId ,
j : edFrameId ,
t : Date . now ( )
} ) ;
} ;
NetworkDoctor . prototype . logPeerInputFrameUpsync = function ( stFrameId , edFrameId ) {
const firstPopped = this . peerInputFrameUpsyncQ . put ( {
i : stFrameId ,
j : edFrameId ,
t : Date . now ( )
} ) ;
if ( null != firstPopped ) {
this . peerInputFrameUpsyncCnt -= ( firstPopped . j - firstPopped . i + 1 ) ;
}
this . peerInputFrameUpsyncCnt += ( edFrameId - stFrameId + 1 ) ;
} ;
2023-01-22 03:34:02 +00:00
NetworkDoctor . prototype . logRollbackFrames = function ( x ) {
this . immediateRollbackFrames = x ;
2023-01-21 14:53:41 +00:00
} ;
2023-01-22 03:34:02 +00:00
NetworkDoctor . prototype . stats = function ( ) {
2023-02-13 03:52:47 +00:00
let inputFrameIdFront = this . inputFrameIdFront ,
sendingFps = 0 ,
2023-01-22 03:34:02 +00:00
srvDownsyncFps = 0 ,
peerUpsyncFps = 0 ,
rollbackFrames = this . immediateRollbackFrames ;
if ( 1 < this . sendingQ . cnt ) {
const st = this . sendingQ . getByFrameId ( this . sendingQ . stFrameId ) ;
const ed = this . sendingQ . getByFrameId ( this . sendingQ . edFrameId - 1 ) ;
const elapsedMillis = ed . t - st . t ;
sendingFps = Math . round ( ( ed . j - st . i ) * 1000 / elapsedMillis ) ;
}
if ( 1 < this . inputFrameDownsyncQ . cnt ) {
const st = this . inputFrameDownsyncQ . getByFrameId ( this . inputFrameDownsyncQ . stFrameId ) ;
const ed = this . inputFrameDownsyncQ . getByFrameId ( this . inputFrameDownsyncQ . edFrameId - 1 ) ;
const elapsedMillis = ed . t - st . t ;
srvDownsyncFps = Math . round ( ( ed . j - st . i ) * 1000 / elapsedMillis ) ;
}
if ( 1 < this . peerInputFrameUpsyncQ . cnt ) {
const st = this . peerInputFrameUpsyncQ . getByFrameId ( this . peerInputFrameUpsyncQ . stFrameId ) ;
const ed = this . peerInputFrameUpsyncQ . getByFrameId ( this . peerInputFrameUpsyncQ . edFrameId - 1 ) ;
const elapsedMillis = ed . t - st . t ;
peerUpsyncFps = Math . round ( this . peerInputFrameUpsyncCnt * 1000 / elapsedMillis ) ;
}
2023-02-13 03:52:47 +00:00
return [ inputFrameIdFront , sendingFps , srvDownsyncFps , peerUpsyncFps , rollbackFrames , this . skippedRenderFrameCnt ] ;
2023-01-21 14:53:41 +00:00
} ;
2023-01-22 03:34:02 +00:00
NetworkDoctor . prototype . logSkippedRenderFrameCnt = function ( ) {
this . skippedRenderFrameCnt += 1 ;
}
2023-01-21 14:53:41 +00:00
2023-02-01 13:35:00 +00:00
NetworkDoctor . prototype . isTooFast = function ( mapIns ) {
2023-02-13 03:52:47 +00:00
const [ inputFrameIdFront , sendingFps , srvDownsyncFps , peerUpsyncFps , rollbackFrames , skippedRenderFrameCnt ] = this . stats ( ) ;
2023-02-01 13:35:00 +00:00
if ( sendingFps >= this . inputRateThreshold + 3 ) {
2023-01-22 15:05:32 +00:00
// Don't send too fast
2023-02-13 07:37:13 +00:00
if ( CC _DEBUG ) {
// Printing of this message might induce a performance impact.
2023-02-18 04:07:56 +00:00
// console.log(`Sending too fast, sendingFps=${sendingFps}`);
2023-02-13 07:37:13 +00:00
}
2023-02-13 03:52:47 +00:00
return [ true , inputFrameIdFront , sendingFps , srvDownsyncFps , peerUpsyncFps , rollbackFrames , skippedRenderFrameCnt ] ;
2023-02-01 13:35:00 +00:00
} else {
const sendingFpsNormal = ( sendingFps >= this . inputRateThreshold ) ;
2023-01-24 02:08:34 +00:00
// An outstanding lag within the "inputFrameDownsyncQ" will reduce "srvDownsyncFps", HOWEVER, a constant lag wouldn't impact "srvDownsyncFps"! In native platforms we might use PING value might help as a supplement information to confirm that the "selfPlayer" is not lagged within the time accounted by "inputFrameDownsyncQ".
2023-02-01 13:35:00 +00:00
const recvFpsNormal = ( srvDownsyncFps >= this . inputRateThreshold || peerUpsyncFps >= this . inputRateThreshold * ( window . boundRoomCapacity - 1 ) ) ;
if ( sendingFpsNormal && recvFpsNormal ) {
let minInputFrameIdFront = Number . MAX _VALUE ;
for ( let k = 0 ; k < window . boundRoomCapacity ; ++ k ) {
if ( k + 1 == mapIns . selfPlayerInfo . JoinIndex ) continue ;
if ( mapIns . lastIndividuallyConfirmedInputFrameId [ k ] >= minInputFrameIdFront ) continue ;
minInputFrameIdFront = mapIns . lastIndividuallyConfirmedInputFrameId [ k ] ;
}
2023-02-13 07:37:13 +00:00
if ( ( inputFrameIdFront > minInputFrameIdFront ) && ( ( inputFrameIdFront - minInputFrameIdFront ) > ( mapIns . inputFrameUpsyncDelayTolerance + 1 ) ) ) {
2023-02-01 13:35:00 +00:00
// first comparison condition is to avoid numeric overflow
2023-02-13 07:37:13 +00:00
if ( CC _DEBUG ) {
// Printing of this message might induce a performance impact.
2023-02-18 04:07:56 +00:00
// console.log(`Game logic ticking too fast, selfInputFrameIdFront=${inputFrameIdFront}, minInputFrameIdFront=${minInputFrameIdFront}, inputFrameUpsyncDelayTolerance=${mapIns.inputFrameUpsyncDelayTolerance}`);
2023-02-13 07:37:13 +00:00
}
2023-02-13 03:52:47 +00:00
return [ true , inputFrameIdFront , sendingFps , srvDownsyncFps , peerUpsyncFps , rollbackFrames , skippedRenderFrameCnt ] ;
2023-02-01 13:35:00 +00:00
}
2023-01-22 03:34:02 +00:00
}
}
2023-02-13 03:52:47 +00:00
return [ false , inputFrameIdFront , sendingFps , srvDownsyncFps , peerUpsyncFps , rollbackFrames , skippedRenderFrameCnt ] ;
2023-01-21 14:53:41 +00:00
} ;
module . exports = NetworkDoctor ;