DelayNoMore/frontend/assets/scripts/WsSessionMgr.js

243 lines
9.7 KiB
JavaScript
Raw Normal View History

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_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;
window.DOWNSYNC_MSG_ACT_FORCED_RESYNC = 4;
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(code, reason) {
if (null == window.clientSession || window.clientSession.readyState != WebSocket.OPEN) {
console.log(`"window.clientSession" is already closed or destroyed.`);
return;
}
2022-09-20 15:50:01 +00:00
console.log(`Closing "window.clientSession" from the client-side.`);
window.clientSession.close(code, reason);
2022-09-20 15:50:01 +00:00
}
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() {
const qDict = window.getQueryParamDict();
if (qDict) {
return qDict["expectedRoomId"];
2022-09-20 15:50:01 +00:00
} else {
if (window.history && window.history.state) {
return window.history.state.expectedRoomId;
2022-09-20 15:50:01 +00:00
}
}
return null;
};
window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
if (window.clientSession && window.clientSession.readyState == WebSocket.OPEN) {
if (null != onopenCb) {
onopenCb();
}
return;
}
2022-10-25 15:36:55 +00:00
2022-10-24 16:05:38 +00:00
const selfPlayerStr = cc.sys.localStorage.getItem("selfPlayer");
2022-10-25 15:36:55 +00:00
const selfPlayer = null == selfPlayerStr ? null : JSON.parse(selfPlayerStr);
2022-10-24 16:05:38 +00:00
const intAuthToken = null == selfPlayer ? "" : selfPlayer.intAuthToken;
2022-09-20 15:50:01 +00:00
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(evt) {
2022-12-01 03:35:56 +00:00
console.log("The WS clientSession is opened.");
2022-09-20 15:50:01 +00:00
window.clientSession = clientSession;
if (null == onopenCb) return;
onopenCb();
};
clientSession.onmessage = function(evt) {
if (null == evt || null == evt.data) {
2022-09-20 15:50:01 +00:00
return;
}
// FIXME: In practice, it seems like the thread invoking "onmessage" could be different from "Map.update(dt)", which makes it necessary to guard "recentRenderCache & recentInputCache" for "getOrPrefabInputFrameUpsync & rollbackAndChase & onRoomDownsyncFrame & onInputFrameDownsyncBatch" to avoid mysterious RAM contamination, but there's no explicit mutex in JavaScript for browsers -- this issue is found in Firefox (108.0.1, 64-bit, Windows 11), but not in Chrome (108.0.5359.125, Official Build, 64-bit, Windows 11) -- just breakpoint in "Map.rollbackAndChase" then see whether the logs of "onmessage" can still be printed and whether the values of "recentRenderCache & recentInputCache" change in console).
2022-09-20 15:50:01 +00:00
try {
const resp = window.pb.protos.WsResp.decode(new Uint8Array(evt.data));
//console.log(`Got non-empty onmessage decoded: resp.act=${resp.act}`);
2022-09-20 15:50:01 +00:00
switch (resp.act) {
case window.DOWNSYNC_MSG_ACT_HB_REQ:
window.handleHbRequirements(resp);
2022-09-20 15:50:01 +00:00
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_BATTLE_READY_TO_START:
mapIns.onBattleReadyToStart(resp.rdf);
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;
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}, @chaserRenderFrameId=${mapIns.chaserRenderFrameId}, @localRecentInputCache=${mapIns._stringifyRecentInputCache(false)}, the incoming resp=${JSON.stringify(resp, null, 2)}`);
2022-10-04 03:24:47 +00:00
return;
}
mapIns.onRoomDownsyncFrame(resp.rdf, resp.inputFrameDownsyncBatch);
break;
2022-09-20 15:50:01 +00:00
default:
break;
}
} catch (e) {
console.error("Unexpected error when parsing data of:", evt.data, e);
2022-09-20 15:50:01 +00:00
}
};
clientSession.onerror = function(evt) {
console.error("Error caught on the WS clientSession: ", evt);
window.clearLocalStorageAndBackToLoginScene(true);
2022-09-20 15:50:01 +00:00
};
clientSession.onclose = function(evt) {
// [WARNING] The callback "onclose" might be called AFTER the webpage is refreshed with "1001 == evt.code".
console.warn(`The WS clientSession is closed: evt=${JSON.stringify(evt)}, evt.code=${evt.code}`);
switch (evt.code) {
2022-12-22 03:35:18 +00:00
case constants.RET_CODE.CLIENT_MISMATCHED_RENDER_FRAME:
break;
case constants.RET_CODE.BATTLE_STOPPED:
// deliberately do nothing
2022-12-27 02:09:53 +00:00
if (mapIns.frameDataLoggingEnabled) {
console.warn(`${mapIns._stringifyRdfIdToActuallyUsedInput()}`);
}
break;
case constants.RET_CODE.PLAYER_NOT_ADDABLE_TO_ROOM:
case constants.RET_CODE.PLAYER_NOT_READDABLE_TO_ROOM:
window.clearBoundRoomIdInBothVolatileAndPersistentStorage(); // To favor the player to join other rooms
mapIns.onManualRejoinRequired("Couldn't join any room at the moment, please retry");
break;
case constants.RET_CODE.ACTIVE_WATCHDOG:
mapIns.onManualRejoinRequired("Disconnected due to long-time inactivity, please rejoin");
break;
case constants.RET_CODE.UNKNOWN_ERROR:
case constants.RET_CODE.MYSQL_ERROR:
case constants.RET_CODE.PLAYER_NOT_FOUND:
case constants.RET_CODE.PLAYER_CHEATING:
case 1006: // Peer(i.e. the backend) gone unexpectedly
2022-12-27 02:09:53 +00:00
if (mapIns.frameDataLoggingEnabled) {
console.warn(`${mapIns._stringifyRdfIdToActuallyUsedInput()}`);
}
window.clearLocalStorageAndBackToLoginScene(true);
break;
default:
break;
2022-09-20 15:50:01 +00:00
}
};
};
window.clearLocalStorageAndBackToLoginScene = function(shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) {
console.warn("+++++++ Calling `clearLocalStorageAndBackToLoginScene`");
if (window.mapIns && window.mapIns.musicEffectManagerScriptIns) {
window.mapIns.musicEffectManagerScriptIns.stopAllMusic();
}
2022-09-20 15:50:01 +00:00
window.closeWSConnection();
window.clearSelfPlayer();
if (true != shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) {
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
}
cc.director.loadScene('login');
2022-09-20 15:50:01 +00:00
};