2022-10-02 16:22:05 +00:00
const RingBuffer = require ( './RingBuffer' ) ;
2022-09-20 15:50:01 +00:00
window . UPSYNC _MSG _ACT _HB _PING = 1 ;
window . UPSYNC _MSG _ACT _PLAYER _CMD = 2 ;
window . UPSYNC _MSG _ACT _PLAYER _COLLIDER _ACK = 3 ;
2022-10-01 15:54:48 +00:00
window . DOWNSYNC _MSG _ACT _PLAYER _ADDED _AND _ACKED = - 98 ;
window . DOWNSYNC _MSG _ACT _PLAYER _READDED _AND _ACKED = - 97 ;
window . DOWNSYNC _MSG _ACT _BATTLE _READY _TO _START = - 1 ;
window . DOWNSYNC _MSG _ACT _BATTLE _START = 0 ;
2022-09-20 15:50:01 +00:00
window . DOWNSYNC _MSG _ACT _HB _REQ = 1 ;
window . DOWNSYNC _MSG _ACT _INPUT _BATCH = 2 ;
2022-10-02 16:22:05 +00:00
window . DOWNSYNC _MSG _ACT _BATTLE _STOPPED = 3 ;
2022-10-01 07:14:05 +00:00
window . DOWNSYNC _MSG _ACT _FORCED _RESYNC = 4 ;
2022-09-20 15:50:01 +00:00
2022-10-01 15:54:48 +00:00
2022-09-20 15:50:01 +00:00
window . sendSafely = function ( msgStr ) {
/ * *
* - "If the data can't be sent (for example, because it needs to be buffered but the buffer is full), the socket is closed automatically."
*
* from https : //developer.mozilla.org/en-US/docs/Web/API/WebSocket/send.
* /
if ( null == window . clientSession || window . clientSession . readyState != WebSocket . OPEN ) return false ;
window . clientSession . send ( msgStr ) ;
}
window . sendUint8AsBase64Safely = function ( msgUint8Arr ) {
if ( null == window . clientSession || window . clientSession . readyState != WebSocket . OPEN ) return false ;
window . clientSession . send ( _uint8ToBase64 ( msgUint8Arr ) ) ;
}
window . closeWSConnection = function ( ) {
if ( null == window . clientSession || window . clientSession . readyState != WebSocket . OPEN ) return ;
console . log ( ` Closing "window.clientSession" from the client-side. ` ) ;
window . clientSession . close ( ) ;
}
window . getBoundRoomIdFromPersistentStorage = function ( ) {
const boundRoomIdExpiresAt = parseInt ( cc . sys . localStorage . getItem ( "boundRoomIdExpiresAt" ) ) ;
if ( ! boundRoomIdExpiresAt || Date . now ( ) >= boundRoomIdExpiresAt ) {
window . clearBoundRoomIdInBothVolatileAndPersistentStorage ( ) ;
return null ;
}
return cc . sys . localStorage . getItem ( "boundRoomId" ) ;
} ;
window . clearBoundRoomIdInBothVolatileAndPersistentStorage = function ( ) {
window . boundRoomId = null ;
cc . sys . localStorage . removeItem ( "boundRoomId" ) ;
cc . sys . localStorage . removeItem ( "boundRoomIdExpiresAt" ) ;
} ;
window . clearSelfPlayer = function ( ) {
cc . sys . localStorage . removeItem ( "selfPlayer" ) ;
} ;
window . boundRoomId = getBoundRoomIdFromPersistentStorage ( ) ;
window . handleHbRequirements = function ( resp ) {
if ( constants . RET _CODE . OK != resp . ret ) return ;
if ( null == window . boundRoomId ) {
window . boundRoomId = resp . bciFrame . boundRoomId ;
cc . sys . localStorage . setItem ( 'boundRoomId' , window . boundRoomId ) ;
cc . sys . localStorage . setItem ( 'boundRoomIdExpiresAt' , Date . now ( ) + 10 * 60 * 1000 ) ; // Temporarily hardcoded, for `boundRoomId` only.
}
if ( window . handleBattleColliderInfo ) {
window . handleBattleColliderInfo ( resp . bciFrame ) ;
}
} ;
function _uint8ToBase64 ( uint8Arr ) {
return window . btoa ( uint8Arr ) ;
}
function _base64ToUint8Array ( base64 ) {
var origBytes = null ;
if ( null != window . atob ) {
var origBinaryStr = window . atob ( base64 ) ;
var origLen = origBinaryStr . length ;
origBytes = new Uint8Array ( origLen ) ;
for ( var i = 0 ; i < origLen ; i ++ ) {
origBytes [ i ] = origBinaryStr . charCodeAt ( i ) ;
}
return origBytes ;
} else {
return null ;
}
}
function _base64ToArrayBuffer ( base64 ) {
return _base64ToUint8Array ( base64 ) . buffer ;
}
window . getExpectedRoomIdSync = function ( ) {
2022-09-24 04:01:50 +00:00
const qDict = window . getQueryParamDict ( ) ;
if ( qDict ) {
return qDict [ "expectedRoomId" ] ;
2022-09-20 15:50:01 +00:00
} else {
2022-09-24 04:01:50 +00:00
if ( window . history && window . history . state ) {
return window . history . state . expectedRoomId ;
2022-09-20 15:50:01 +00:00
}
}
return null ;
} ;
window . unsetClientSessionCloseOrErrorFlag = function ( ) {
cc . sys . localStorage . removeItem ( "ClientSessionCloseOrErrorFlag" ) ;
return ;
}
window . setClientSessionCloseOrErrorFlag = function ( ) {
const oldVal = cc . sys . localStorage . getItem ( "ClientSessionCloseOrErrorFlag" ) ;
if ( true == oldVal ) return false ;
cc . sys . localStorage . setItem ( "ClientSessionCloseOrErrorFlag" , true ) ;
return true ;
}
window . initPersistentSessionClient = function ( onopenCb , expectedRoomId ) {
if ( window . clientSession && window . clientSession . readyState == WebSocket . OPEN ) {
if ( null != onopenCb ) {
onopenCb ( ) ;
}
return ;
}
const intAuthToken = cc . sys . localStorage . getItem ( "selfPlayer" ) ? JSON . parse ( cc . sys . localStorage . getItem ( 'selfPlayer' ) ) . intAuthToken : "" ;
let urlToConnect = backendAddress . PROTOCOL . replace ( 'http' , 'ws' ) + '://' + backendAddress . HOST + ":" + backendAddress . PORT + backendAddress . WS _PATH _PREFIX + "?intAuthToken=" + intAuthToken ;
if ( null != expectedRoomId ) {
console . log ( "initPersistentSessionClient with expectedRoomId == " + expectedRoomId ) ;
urlToConnect = urlToConnect + "&expectedRoomId=" + expectedRoomId ;
} else {
window . boundRoomId = getBoundRoomIdFromPersistentStorage ( ) ;
if ( null != window . boundRoomId ) {
console . log ( "initPersistentSessionClient with boundRoomId == " + boundRoomId ) ;
urlToConnect = urlToConnect + "&boundRoomId=" + window . boundRoomId ;
}
}
const currentHistoryState = window . history && window . history . state ? window . history . state : { } ;
const clientSession = new WebSocket ( urlToConnect ) ;
clientSession . binaryType = 'arraybuffer' ; // Make 'event.data' of 'onmessage' an "ArrayBuffer" instead of a "Blob"
clientSession . onopen = function ( event ) {
console . log ( "The WS clientSession is opened." ) ;
window . clientSession = clientSession ;
if ( null == onopenCb ) return ;
onopenCb ( ) ;
} ;
clientSession . onmessage = function ( event ) {
if ( null == event || null == event . data ) {
return ;
}
try {
const resp = window . WsResp . decode ( new Uint8Array ( event . data ) ) ;
switch ( resp . act ) {
case window . DOWNSYNC _MSG _ACT _HB _REQ :
window . handleHbRequirements ( resp ) ; // 获取boundRoomId并存储到localStorage
break ;
2022-10-01 15:54:48 +00:00
case window . DOWNSYNC _MSG _ACT _PLAYER _ADDED _AND _ACKED :
2022-10-02 16:22:05 +00:00
mapIns . onPlayerAdded ( resp . rdf ) ;
2022-10-01 15:54:48 +00:00
break ;
case window . DOWNSYNC _MSG _ACT _PLAYER _READDED _AND _ACKED :
// Deliberately left blank for now
2022-10-04 03:24:47 +00:00
mapIns . hideFindingPlayersGUI ( ) ;
2022-10-01 15:54:48 +00:00
break ;
case window . DOWNSYNC _MSG _ACT _BATTLE _READY _TO _START :
2022-10-04 03:24:47 +00:00
mapIns . onBattleReadyToStart ( resp . rdf . playerMetas ) ;
2022-10-02 16:22:05 +00:00
break ;
2022-10-01 15:54:48 +00:00
case window . DOWNSYNC _MSG _ACT _BATTLE _START :
2022-10-03 03:42:19 +00:00
mapIns . onRoomDownsyncFrame ( resp . rdf ) ;
2022-10-02 16:22:05 +00:00
break ;
case window . DOWNSYNC _MSG _ACT _BATTLE _STOPPED :
mapIns . onBattleStopped ( ) ;
2022-09-20 15:50:01 +00:00
break ;
case window . DOWNSYNC _MSG _ACT _INPUT _BATCH :
2022-10-02 16:22:05 +00:00
mapIns . onInputFrameDownsyncBatch ( resp . inputFrameDownsyncBatch ) ;
2022-09-20 15:50:01 +00:00
break ;
2022-10-01 07:14:05 +00:00
case window . DOWNSYNC _MSG _ACT _FORCED _RESYNC :
2022-10-04 03:24:47 +00:00
if ( null == resp . inputFrameDownsyncBatch || 0 >= resp . inputFrameDownsyncBatch . length ) {
console . error ( "Got empty inputFrameDownsyncBatch upon resync@localRenderFrameId=" , mapIns . renderFrameId , ", @lastAllConfirmedRenderFrameId=" , mapIns . lastAllConfirmedRenderFrameId , "@lastAllConfirmedInputFrameId=" , mapIns . lastAllConfirmedInputFrameId , ", @localRecentInputCache=" , mapIns . _stringifyRecentInputCache ( false ) , ", the incoming resp=\n" , JSON . stringify ( resp , null , 2 ) ) ;
return ;
}
// Unless upon ws session lost and reconnected, it's maintained true that "inputFrameDownsyncBatch[0].inputFrameId == frontend.lastAllConfirmedInputFrameId+1", and in this case we should try to keep frontend moving only by "frontend.recentInputCache" to avoid jiggling of synced positions
const inputFrameIdConsecutive = ( resp . inputFrameDownsyncBatch [ 0 ] . inputFrameId == mapIns . lastAllConfirmedInputFrameId + 1 ) ;
const renderFrameIdConsecutive = ( resp . rdf . id <= mapIns . renderFrameId + mapIns . renderFrameIdLagTolerance ) ;
if ( inputFrameIdConsecutive && renderFrameIdConsecutive ) {
console . log ( "Got consecutive resync@localRenderFrameId=" , mapIns . renderFrameId , ", @lastAllConfirmedRenderFrameId=" , mapIns . lastAllConfirmedRenderFrameId , "@lastAllConfirmedInputFrameId=" , mapIns . lastAllConfirmedInputFrameId , ", @localRecentInputCache=" , mapIns . _stringifyRecentInputCache ( false ) , ", the incoming resp=\n" , JSON . stringify ( resp ) ) ;
mapIns . onInputFrameDownsyncBatch ( resp . inputFrameDownsyncBatch ) ;
} else {
console . warn ( "Got forced resync@localRenderFrameId=" , mapIns . renderFrameId , ", @lastAllConfirmedRenderFrameId=" , mapIns . lastAllConfirmedRenderFrameId , "@lastAllConfirmedInputFrameId=" , mapIns . lastAllConfirmedInputFrameId , ", @localRecentInputCache=" , mapIns . _stringifyRecentInputCache ( false ) , ", the incoming resp=\n" , JSON . stringify ( resp , null , 2 ) ) ;
// The following order of execution is important
const dumpRenderCacheRet = mapIns . onRoomDownsyncFrame ( resp . rdf ) ;
mapIns . onInputFrameDownsyncBatch ( resp . inputFrameDownsyncBatch , dumpRenderCacheRet ) ;
}
2022-10-01 07:14:05 +00:00
break ;
2022-09-20 15:50:01 +00:00
default :
break ;
}
} catch ( e ) {
console . error ( "Unexpected error when parsing data of:" , event . data , e ) ;
}
} ;
clientSession . onerror = function ( event ) {
if ( ! window . setClientSessionCloseOrErrorFlag ( ) ) {
return ;
}
console . error ( "Error caught on the WS clientSession: " , event ) ;
if ( window . clientSessionPingInterval ) {
clearInterval ( window . clientSessionPingInterval ) ;
}
if ( window . handleClientSessionCloseOrError ) {
window . handleClientSessionCloseOrError ( ) ;
}
window . unsetClientSessionCloseOrErrorFlag ( ) ;
} ;
clientSession . onclose = function ( event ) {
if ( ! window . setClientSessionCloseOrErrorFlag ( ) ) {
return ;
}
console . warn ( "The WS clientSession is closed: " , event ) ;
if ( window . clientSessionPingInterval ) {
clearInterval ( window . clientSessionPingInterval ) ;
}
if ( false == event . wasClean ) {
// Chrome doesn't allow the use of "CustomCloseCode"s (yet) and will callback with a "WebsocketStdCloseCode 1006" and "false == event.wasClean" here. See https://tools.ietf.org/html/rfc6455#section-7.4 for more information.
if ( window . handleClientSessionCloseOrError ) {
window . handleClientSessionCloseOrError ( ) ;
}
} else {
switch ( event . code ) {
case constants . RET _CODE . PLAYER _NOT _FOUND :
case constants . RET _CODE . PLAYER _CHEATING :
window . clearBoundRoomIdInBothVolatileAndPersistentStorage ( ) ;
break ;
default :
break ;
}
if ( window . handleClientSessionCloseOrError ) {
window . handleClientSessionCloseOrError ( ) ;
}
}
window . unsetClientSessionCloseOrErrorFlag ( ) ;
} ;
} ;
window . clearLocalStorageAndBackToLoginScene = function ( shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage ) {
console . warn ( "+++++++ Calling `clearLocalStorageAndBackToLoginScene`" ) ;
if ( window . mapIns && window . mapIns . musicEffectManagerScriptIns ) {
window . mapIns . musicEffectManagerScriptIns . stopAllMusic ( ) ;
}
/ * *
* Here I deliberately removed the callback in the "common `handleClientSessionCloseOrError` callback"
* within which another invocation to ` clearLocalStorageAndBackToLoginScene ` will be made .
*
* It ' ll be re - assigned to the common one upon reentrance of ` Map.onLoad ` .
*
* -- YFLu 2019 - 04 - 06
* /
window . handleClientSessionCloseOrError = ( ) => {
console . warn ( "+++++++ Special handleClientSessionCloseOrError() assigned within `clearLocalStorageAndBackToLoginScene`" ) ;
// TBD.
window . handleClientSessionCloseOrError = null ; // To ensure that it's called at most once.
} ;
window . closeWSConnection ( ) ;
window . clearSelfPlayer ( ) ;
if ( true != shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage ) {
window . clearBoundRoomIdInBothVolatileAndPersistentStorage ( ) ;
}
2022-09-24 04:01:50 +00:00
cc . director . loadScene ( 'login' ) ;
2022-09-20 15:50:01 +00:00
} ;