Added inactive watchdog hint in frontend.

This commit is contained in:
genxium 2022-12-20 16:01:44 +08:00
parent 9eb6ad26ef
commit 727e66787f
8 changed files with 130 additions and 136 deletions

View File

@ -1,28 +1,28 @@
{ {
"RET_CODE": { "RET_CODE": {
"__comment__":"基础", "__comment__": "Websocket",
"OK": 9000, "OK": 3000,
"UNKNOWN_ERROR": 9001, "UNKNOWN_ERROR": 3001,
"INVALID_REQUEST_PARAM": 9002, "INVALID_REQUEST_PARAM": 3002,
"IS_TEST_ACC": 9003, "IS_TEST_ACC": 3003,
"MYSQL_ERROR": 9004, "MYSQL_ERROR": 3004,
"NONEXISTENT_ACT": 9005, "NONEXISTENT_ACT": 3005,
"LACK_OF_DIAMOND": 9006, "LACK_OF_DIAMOND": 3006,
"LACK_OF_GOLD": 9007, "LACK_OF_GOLD": 3007,
"LACK_OF_ENERGY": 9008, "LACK_OF_ENERGY": 3008,
"NONEXISTENT_ACT_HANDLER": 9009, "NONEXISTENT_ACT_HANDLER": 3009,
"LOCALLY_NO_AVAILABLE_ROOM": 9010, "LOCALLY_NO_AVAILABLE_ROOM": 3010,
"LOCALLY_NO_SPECIFIED_ROOM": 9011, "LOCALLY_NO_SPECIFIED_ROOM": 3011,
"PLAYER_NOT_ADDABLE_TO_ROOM": 9012, "PLAYER_NOT_ADDABLE_TO_ROOM": 3012,
"PLAYER_NOT_READDABLE_TO_ROOM": 9013, "PLAYER_NOT_READDABLE_TO_ROOM": 3013,
"PLAYER_NOT_FOUND": 9014, "PLAYER_NOT_FOUND": 3014,
"PLAYER_CHEATING": 9015, "PLAYER_CHEATING": 3015,
"WECHAT_SERVER_ERROR": 9016, "WECHAT_SERVER_ERROR": 3016,
"IS_BOT_ACC": 9017, "IS_BOT_ACC": 3017,
"ACTIVE_WATCHDOG": 3018,
"BATTLE_STOPPED": 3019,
"__comment__":"SMS", "__comment__": "OTHERS",
"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY": 5001,
"SMS_CAPTCHA_NOT_MATCH": 5002,
"INVALID_TOKEN": 2001, "INVALID_TOKEN": 2001,
"DUPLICATED": 2002, "DUPLICATED": 2002,
@ -39,12 +39,15 @@
"FAILED_TO_DELETE": 2015, "FAILED_TO_DELETE": 2015,
"FAILED_TO_CREATE": 2016, "FAILED_TO_CREATE": 2016,
"INCORRECT_PHONE_NUMBER": 2018, "INCORRECT_PHONE_NUMBER": 2018,
"INSUFFICIENT_MEM_TO_ALLOCATE_CONNECTION": 3001, "INSUFFICIENT_MEM_TO_ALLOCATE_CONNECTION": 2019,
"PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY": 4000, "PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY": 2020,
"TRADE_CREATION_TOO_FREQUENTLY": 4002, "TRADE_CREATION_TOO_FREQUENTLY": 2021,
"MAP_NOT_UNLOCKED": 4003, "MAP_NOT_UNLOCKED": 2022,
"GET_SMS_CAPTCHA_RESP_ERROR_CODE": 2023,
"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY": 2024,
"SMS_CAPTCHA_NOT_MATCH": 2025,
"GET_SMS_CAPTCHA_RESP_ERROR_CODE": 5003,
"NOT_IMPLEMENTED_YET": 65535 "NOT_IMPLEMENTED_YET": 65535
}, },
"AUTH_CHANNEL": { "AUTH_CHANNEL": {
@ -62,6 +65,6 @@
}, },
"WS": { "WS": {
"INTERVAL_TO_PING": 2000, "INTERVAL_TO_PING": 2000,
"WILL_KICK_IF_INACTIVE_FOR": 6000 "WILL_KICK_IF_INACTIVE_FOR": 4000
} }
} }

View File

@ -15,10 +15,13 @@ type constants struct {
SmsValidResendPeriodSeconds int `json:"SMS_VALID_RESEND_PERIOD_SECONDS"` SmsValidResendPeriodSeconds int `json:"SMS_VALID_RESEND_PERIOD_SECONDS"`
} `json:"PLAYER"` } `json:"PLAYER"`
RetCode struct { RetCode struct {
ActiveWatchdog int `json:"ACTIVE_WATCHDOG"`
BattleStopped int `json:"BATTLE_STOPPED"`
Duplicated int `json:"DUPLICATED"` Duplicated int `json:"DUPLICATED"`
FailedToCreate int `json:"FAILED_TO_CREATE"` FailedToCreate int `json:"FAILED_TO_CREATE"`
FailedToDelete int `json:"FAILED_TO_DELETE"` FailedToDelete int `json:"FAILED_TO_DELETE"`
FailedToUpdate int `json:"FAILED_TO_UPDATE"` FailedToUpdate int `json:"FAILED_TO_UPDATE"`
GetSmsCaptchaRespErrorCode int `json:"GET_SMS_CAPTCHA_RESP_ERROR_CODE"`
IncorrectCaptcha int `json:"INCORRECT_CAPTCHA"` IncorrectCaptcha int `json:"INCORRECT_CAPTCHA"`
IncorrectHandle int `json:"INCORRECT_HANDLE"` IncorrectHandle int `json:"INCORRECT_HANDLE"`
IncorrectPassword int `json:"INCORRECT_PASSWORD"` IncorrectPassword int `json:"INCORRECT_PASSWORD"`
@ -28,27 +31,26 @@ type constants struct {
InvalidEmailLiteral int `json:"INVALID_EMAIL_LITERAL"` InvalidEmailLiteral int `json:"INVALID_EMAIL_LITERAL"`
InvalidRequestParam int `json:"INVALID_REQUEST_PARAM"` InvalidRequestParam int `json:"INVALID_REQUEST_PARAM"`
InvalidToken int `json:"INVALID_TOKEN"` InvalidToken int `json:"INVALID_TOKEN"`
IsTestAcc int `json:"IS_TEST_ACC"`
IsBotAcc int `json:"IS_BOT_ACC"` IsBotAcc int `json:"IS_BOT_ACC"`
IsTestAcc int `json:"IS_TEST_ACC"`
LackOfDiamond int `json:"LACK_OF_DIAMOND"` LackOfDiamond int `json:"LACK_OF_DIAMOND"`
LackOfEnergy int `json:"LACK_OF_ENERGY"` LackOfEnergy int `json:"LACK_OF_ENERGY"`
LackOfGold int `json:"LACK_OF_GOLD"` LackOfGold int `json:"LACK_OF_GOLD"`
LocallyNoAvailableRoom int `json:"LOCALLY_NO_AVAILABLE_ROOM"`
LocallyNoSpecifiedRoom int `json:"LOCALLY_NO_SPECIFIED_ROOM"`
MapNotUnlocked int `json:"MAP_NOT_UNLOCKED"` MapNotUnlocked int `json:"MAP_NOT_UNLOCKED"`
MysqlError int `json:"MYSQL_ERROR"` MysqlError int `json:"MYSQL_ERROR"`
GetSmsCaptchaRespErrorCode int `json:"GET_SMS_CAPTCHA_RESP_ERROR_CODE"`
NewHandleConflict int `json:"NEW_HANDLE_CONFLICT"` NewHandleConflict int `json:"NEW_HANDLE_CONFLICT"`
NonexistentAct int `json:"NONEXISTENT_ACT"` NonexistentAct int `json:"NONEXISTENT_ACT"`
NonexistentActHandler int `json:"NONEXISTENT_ACT_HANDLER"` NonexistentActHandler int `json:"NONEXISTENT_ACT_HANDLER"`
LocallyNoAvailableRoom int `json:"LOCALLY_NO_AVAILABLE_ROOM"`
LocallyNoSpecifiedRoom int `json:"LOCALLY_NO_SPECIFIED_ROOM"`
PlayerNotAddableToRoom int `json:"PLAYER_NOT_ADDABLE_TO_ROOM"`
PlayerNotReAddableToRoom int `json:"PLAYER_NOT_READDABLE_TO_ROOM"`
PlayerNotFound int `json:"PLAYER_NOT_FOUND"`
PlayerCheating int `json:"PLAYER_CHEATING"`
NotImplementedYet int `json:"NOT_IMPLEMENTED_YET"` NotImplementedYet int `json:"NOT_IMPLEMENTED_YET"`
NoAssociatedEmail int `json:"NO_ASSOCIATED_EMAIL"` NoAssociatedEmail int `json:"NO_ASSOCIATED_EMAIL"`
Ok int `json:"OK"` Ok int `json:"OK"`
PasswordResetCodeGenerationPerEmailTooFrequently int `json:"PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY"` PasswordResetCodeGenerationPerEmailTooFrequently int `json:"PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY"`
PlayerCheating int `json:"PLAYER_CHEATING"`
PlayerNotAddableToRoom int `json:"PLAYER_NOT_ADDABLE_TO_ROOM"`
PlayerNotFound int `json:"PLAYER_NOT_FOUND"`
PlayerNotReaddableToRoom int `json:"PLAYER_NOT_READDABLE_TO_ROOM"`
SendEmailTimeout int `json:"SEND_EMAIL_TIMEOUT"` SendEmailTimeout int `json:"SEND_EMAIL_TIMEOUT"`
SmsCaptchaNotMatch int `json:"SMS_CAPTCHA_NOT_MATCH"` SmsCaptchaNotMatch int `json:"SMS_CAPTCHA_NOT_MATCH"`
SmsCaptchaRequestedTooFrequently int `json:"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY"` SmsCaptchaRequestedTooFrequently int `json:"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY"`

View File

@ -170,9 +170,10 @@ type Room struct {
LastAllConfirmedInputList []uint64 LastAllConfirmedInputList []uint64
JoinIndexBooleanArr []bool JoinIndexBooleanArr []bool
BackendDynamicsEnabled bool BackendDynamicsEnabled bool
LastRenderFrameIdTriggeredAt int64 ForceAllResyncOnAnyActiveSlowTicker bool
PlayerDefaultSpeed int32 LastRenderFrameIdTriggeredAt int64
PlayerDefaultSpeed int32
BulletBattleLocalIdCounter int32 BulletBattleLocalIdCounter int32
dilutedRollbackEstimatedDtNanos int64 dilutedRollbackEstimatedDtNanos int64
@ -210,7 +211,7 @@ func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, session *websocke
pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer
newWatchdog := NewWatchdog(ConstVals.Ws.WillKickIfInactiveFor, func() { newWatchdog := NewWatchdog(ConstVals.Ws.WillKickIfInactiveFor, func() {
Logger.Warn("Conn inactive watchdog triggered#1:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount)) Logger.Warn("Conn inactive watchdog triggered#1:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount))
signalToCloseConnOfThisPlayer(Constants.RetCode.UnknownError, "") signalToCloseConnOfThisPlayer(Constants.RetCode.ActiveWatchdog, "")
}) })
newWatchdog.Stop() newWatchdog.Stop()
pR.PlayerActiveWatchdogDict[playerId] = newWatchdog pR.PlayerActiveWatchdogDict[playerId] = newWatchdog
@ -247,7 +248,7 @@ func (pR *Room) ReAddPlayerIfPossible(pTmpPlayerInstance *Player, session *webso
pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer
pR.PlayerActiveWatchdogDict[playerId] = NewWatchdog(ConstVals.Ws.WillKickIfInactiveFor, func() { pR.PlayerActiveWatchdogDict[playerId] = NewWatchdog(ConstVals.Ws.WillKickIfInactiveFor, func() {
Logger.Warn("Conn inactive watchdog triggered#2:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount)) Logger.Warn("Conn inactive watchdog triggered#2:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount))
signalToCloseConnOfThisPlayer(Constants.RetCode.UnknownError, "") signalToCloseConnOfThisPlayer(Constants.RetCode.ActiveWatchdog, "")
}) // For ReAdded player the new watchdog starts immediately }) // For ReAdded player the new watchdog starts immediately
Logger.Warn("ReAddPlayerIfPossible finished.", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("joinIndex", pEffectiveInRoomPlayerInstance.JoinIndex), zap.Any("playerBattleState", pEffectiveInRoomPlayerInstance.BattleState), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount), zap.Any("AckingFrameId", pEffectiveInRoomPlayerInstance.AckingFrameId), zap.Any("AckingInputFrameId", pEffectiveInRoomPlayerInstance.AckingInputFrameId), zap.Any("LastSentInputFrameId", pEffectiveInRoomPlayerInstance.LastSentInputFrameId)) Logger.Warn("ReAddPlayerIfPossible finished.", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("joinIndex", pEffectiveInRoomPlayerInstance.JoinIndex), zap.Any("playerBattleState", pEffectiveInRoomPlayerInstance.BattleState), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount), zap.Any("AckingFrameId", pEffectiveInRoomPlayerInstance.AckingFrameId), zap.Any("AckingInputFrameId", pEffectiveInRoomPlayerInstance.AckingInputFrameId), zap.Any("LastSentInputFrameId", pEffectiveInRoomPlayerInstance.LastSentInputFrameId))
@ -776,7 +777,8 @@ func (pR *Room) OnDismissed() {
pR.InputFrameUpsyncDelayTolerance = (pR.NstDelayFrames >> pR.InputScaleFrames) - 1 // this value should be strictly smaller than (NstDelayFrames >> InputScaleFrames), otherwise "type#1 forceConfirmation" might become a lag avalanche pR.InputFrameUpsyncDelayTolerance = (pR.NstDelayFrames >> pR.InputScaleFrames) - 1 // this value should be strictly smaller than (NstDelayFrames >> InputScaleFrames), otherwise "type#1 forceConfirmation" might become a lag avalanche
pR.MaxChasingRenderFramesPerUpdate = 12 // Don't set this value too high to avoid exhausting frontend CPU within a single frame pR.MaxChasingRenderFramesPerUpdate = 12 // Don't set this value too high to avoid exhausting frontend CPU within a single frame
pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work! pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work!
pR.ForceAllResyncOnAnyActiveSlowTicker = false // See tradeoff discussion in "downsyncToAllPlayers"
punchSkillId := int32(1) punchSkillId := int32(1)
pR.MeleeSkillConfig = make(map[int32]*MeleeBullet, 0) pR.MeleeSkillConfig = make(map[int32]*MeleeBullet, 0)
pR.MeleeSkillConfig[punchSkillId] = &MeleeBullet{ pR.MeleeSkillConfig[punchSkillId] = &MeleeBullet{
@ -1769,7 +1771,7 @@ func (pR *Room) downsyncToAllPlayers(inputsBufferSnapshot *InputsBufferSnapshot)
break break
} }
/* /*
[WARNING] There's a tradeoff here, if the `ACTIVE SLOW TICKER` doesn't resume for a long period of time, the current approach is to kick it out by "connWatchdog" instead of forcing resync of all players in the same battle all the way along. [WARNING] There's a tradeoff for setting/unsetting "ForceAllResyncOnAnyActiveSlowTicker" here, if the `ACTIVE SLOW TICKER` doesn't resume for a long period of time, the current approach is to kick it out by "connWatchdog" instead of forcing resync of all players in the same battle all the way along.
[FIXME] [FIXME]
In practice, I tested in internet environment by toggling player#1 "CPU throttling: 1x -> 4x -> 1x -> 6x -> 1x" and checked the logs of all players which showed that "all received inputFrameIds are consecutive for all players", yet not forcing resync of all players here still result in occasional inconsistent graphics for the `ACTIVE NORMAL TICKER`s. In practice, I tested in internet environment by toggling player#1 "CPU throttling: 1x -> 4x -> 1x -> 6x -> 1x" and checked the logs of all players which showed that "all received inputFrameIds are consecutive for all players", yet not forcing resync of all players here still result in occasional inconsistent graphics for the `ACTIVE NORMAL TICKER`s.
@ -1778,7 +1780,7 @@ func (pR *Room) downsyncToAllPlayers(inputsBufferSnapshot *InputsBufferSnapshot)
*/ */
thatPlayerJoinMask := uint64(1 << uint32(player.JoinIndex-1)) thatPlayerJoinMask := uint64(1 << uint32(player.JoinIndex-1))
isActiveSlowTicker := (0 < (thatPlayerJoinMask & inputsBufferSnapshot.UnconfirmedMask)) && (PlayerBattleStateIns.ACTIVE == playerBattleState) isActiveSlowTicker := (0 < (thatPlayerJoinMask & inputsBufferSnapshot.UnconfirmedMask)) && (PlayerBattleStateIns.ACTIVE == playerBattleState)
if isActiveSlowTicker { if pR.ForceAllResyncOnAnyActiveSlowTicker && isActiveSlowTicker {
inputsBufferSnapshot.ShouldForceResync = true inputsBufferSnapshot.ShouldForceResync = true
break break
} }

View File

@ -373,7 +373,7 @@ func Serve(c *gin.Context) {
// TODO: Is there any potential edge-trigger improvement like the epoll approach mentioned above for the following statement? See discussion in https://github.com/gorilla/websocket/issues/122 // TODO: Is there any potential edge-trigger improvement like the epoll approach mentioned above for the following statement? See discussion in https://github.com/gorilla/websocket/issues/122
_, bytes, err := conn.ReadMessage() _, bytes, err := conn.ReadMessage()
if nil != err { if nil != err {
Logger.Error("About to `signalToCloseConnOfThisPlayer`", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Error(err)) Logger.Error("About to `signalToCloseConnOfThisPlayer` due to conn.ReadMessage err", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Error(err))
signalToCloseConnOfThisPlayer(Constants.RetCode.UnknownError, "") signalToCloseConnOfThisPlayer(Constants.RetCode.UnknownError, "")
return nil return nil
} }

View File

@ -23,8 +23,8 @@ var constants = {
FILE_NAME: { FILE_NAME: {
TREASURE_PICKEDUP: "TreasurePicked", TREASURE_PICKEDUP: "TreasurePicked",
CRASHED_BY_TRAP_BULLET: "CrashedByTrapBullet", CRASHED_BY_TRAP_BULLET: "CrashedByTrapBullet",
HIGH_SCORE_TREASURE_PICKED:"HighScoreTreasurePicked", HIGH_SCORE_TREASURE_PICKED: "HighScoreTreasurePicked",
COUNT_DOWN_10SEC_TO_END:"countDown10SecToEnd", COUNT_DOWN_10SEC_TO_END: "countDown10SecToEnd",
BGM: "BGM" BGM: "BGM"
} }
}, },
@ -55,39 +55,40 @@ var constants = {
}, },
RET_CODE: { RET_CODE: {
/** /**
* NOTE: The "RET_CODE"s from 1000-1015 are reserved for the websocket "WebsocketStdCloseCode"s. * NOTE: The "RET_CODE"s from 1000-1015 are reserved for the websocket "WebsocketStdCloseCode"s, custom codes should be between 3000-4999
* *
* References * References
* - https://tools.ietf.org/html/rfc6455#section-7.4 * - https://tools.ietf.org/html/rfc6455#section-7.4
* - https://godoc.org/github.com/gorilla/websocket#pkg-constants. * - https://godoc.org/github.com/gorilla/websocket#pkg-constants.
*/ */
"__comment__": "基础", "__comment__": "Websocket",
"OK": 9000, "OK": 3000,
"UNKNOWN_ERROR": 9001, "UNKNOWN_ERROR": 3001,
"INVALID_REQUEST_PARAM": 9002, "INVALID_REQUEST_PARAM": 3002,
"IS_TEST_ACC": 9003, "IS_TEST_ACC": 3003,
"MYSQL_ERROR": 9004, "MYSQL_ERROR": 3004,
"NONEXISTENT_ACT": 9005, "NONEXISTENT_ACT": 3005,
"LACK_OF_DIAMOND": 9006, "LACK_OF_DIAMOND": 3006,
"LACK_OF_GOLD": 9007, "LACK_OF_GOLD": 3007,
"LACK_OF_ENERGY": 9008, "LACK_OF_ENERGY": 3008,
"NONEXISTENT_ACT_HANDLER": 9009, "NONEXISTENT_ACT_HANDLER": 3009,
"LOCALLY_NO_AVAILABLE_ROOM": 9010, "LOCALLY_NO_AVAILABLE_ROOM": 3010,
"LOCALLY_NO_SPECIFIED_ROOM": 9011, "LOCALLY_NO_SPECIFIED_ROOM": 3011,
"PLAYER_NOT_ADDABLE_TO_ROOM": 9012, "PLAYER_NOT_ADDABLE_TO_ROOM": 3012,
"PLAYER_NOT_READDABLE_TO_ROOM": 9013, "PLAYER_NOT_READDABLE_TO_ROOM": 3013,
"PLAYER_NOT_FOUND": 9014, "PLAYER_NOT_FOUND": 3014,
"PLAYER_CHEATING": 9015, "PLAYER_CHEATING": 3015,
"WECHAT_SERVER_ERROR": 3016,
"IS_BOT_ACC": 3017,
"ACTIVE_WATCHDOG": 3018,
"BATTLE_STOPPED": 3019,
"__comment__": "OTHERS",
"__comment__": "SMS",
"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY": 5001,
"SMS_CAPTCHA_NOT_MATCH": 5002,
"INVALID_TOKEN": 2001, "INVALID_TOKEN": 2001,
"DUPLICATED": 2002, "DUPLICATED": 2002,
"INCORRECT_HANDLE": 2004, "INCORRECT_HANDLE": 2004,
"NONEXISTENT_HANDLE": 2005,
"INCORRECT_PASSWORD": 2006, "INCORRECT_PASSWORD": 2006,
"INCORRECT_CAPTCHA": 2007, "INCORRECT_CAPTCHA": 2007,
"INVALID_EMAIL_LITERAL": 2008, "INVALID_EMAIL_LITERAL": 2008,
@ -99,9 +100,14 @@ var constants = {
"FAILED_TO_DELETE": 2015, "FAILED_TO_DELETE": 2015,
"FAILED_TO_CREATE": 2016, "FAILED_TO_CREATE": 2016,
"INCORRECT_PHONE_NUMBER": 2018, "INCORRECT_PHONE_NUMBER": 2018,
"PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY": 4000, "INSUFFICIENT_MEM_TO_ALLOCATE_CONNECTION": 2019,
"TRADE_CREATION_TOO_FREQUENTLY": 4002, "PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY": 2020,
"MAP_NOT_UNLOCKED": 4003, "TRADE_CREATION_TOO_FREQUENTLY": 2021,
"MAP_NOT_UNLOCKED": 2022,
"GET_SMS_CAPTCHA_RESP_ERROR_CODE": 2023,
"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY": 2024,
"SMS_CAPTCHA_NOT_MATCH": 2025,
"NOT_IMPLEMENTED_YET": 65535 "NOT_IMPLEMENTED_YET": 65535
}, },

View File

@ -440,7 +440,7 @@
"array": [ "array": [
0, 0,
0, 0,
216.50635094610968, 215.95961841836203,
0, 0,
0, 0,
0, 0,

View File

@ -11,6 +11,7 @@ window.ALL_MAP_STATES = {
}; };
window.ALL_BATTLE_STATES = { window.ALL_BATTLE_STATES = {
NONE: -1,
WAITING: 0, WAITING: 0,
IN_BATTLE: 1, IN_BATTLE: 1,
IN_SETTLEMENT: 2, IN_SETTLEMENT: 2,
@ -222,15 +223,19 @@ cc.Class({
onDestroy() { onDestroy() {
const self = this; const self = this;
console.warn("+++++++ Map onDestroy()"); console.warn("+++++++ Map onDestroy()");
if (null == self.battleState || ALL_BATTLE_STATES.WAITING == self.battleState) { if (null == self.battleState || ALL_BATTLE_STATES.IN_BATTLE != self.battleState) {
window.clearBoundRoomIdInBothVolatileAndPersistentStorage(); window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
} }
if (null != window.handleBattleColliderInfo) { if (null != window.handleBattleColliderInfo) {
window.handleBattleColliderInfo = null; window.handleBattleColliderInfo = null;
} }
if (null != window.handleClientSessionError) { },
window.handleClientSessionError = null;
} onManualRejoinRequired(labelString) {
const self = this;
self.battleState = ALL_BATTLE_STATES.NONE; // Effectively stops "update(dt)"
self.showPopupInCanvas(self.gameRuleNode);
self.popupSimplePressToGo(labelString, false);
}, },
popupSimplePressToGo(labelString, hideYesButton) { popupSimplePressToGo(labelString, hideYesButton) {
@ -334,16 +339,6 @@ cc.Class({
self.showCriticalCoordinateLabels = false; self.showCriticalCoordinateLabels = false;
console.warn("+++++++ Map onLoad()"); console.warn("+++++++ Map onLoad()");
window.handleClientSessionError = function() {
console.warn('+++++++ Common handleClientSessionError()');
if (ALL_BATTLE_STATES.IN_SETTLEMENT == self.battleState) {
console.log("Battled ended by settlement");
} else {
console.warn("Connection lost, going back to login page");
window.clearLocalStorageAndBackToLoginScene(true);
}
};
const mapNode = self.node; const mapNode = self.node;
const canvasNode = mapNode.parent; const canvasNode = mapNode.parent;
@ -759,6 +754,8 @@ cc.Class({
if (ALL_BATTLE_STATES.IN_BATTLE != self.battleState) { if (ALL_BATTLE_STATES.IN_BATTLE != self.battleState) {
return; return;
} }
window.closeWSConnection(constants.RET_CODE.BATTLE_STOPPED);
self.battleState = ALL_BATTLE_STATES.IN_SETTLEMENT;
self.countdownNanos = null; self.countdownNanos = null;
self.logBattleStats(); self.logBattleStats();
if (self.musicEffectManagerScriptIns) { if (self.musicEffectManagerScriptIns) {
@ -769,7 +766,6 @@ cc.Class({
const resultPanelScriptIns = resultPanelNode.getComponent("ResultPanel"); const resultPanelScriptIns = resultPanelNode.getComponent("ResultPanel");
resultPanelScriptIns.showPlayerInfo(self.playerRichInfoDict); resultPanelScriptIns.showPlayerInfo(self.playerRichInfoDict);
window.clearBoundRoomIdInBothVolatileAndPersistentStorage(); window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
self.battleState = ALL_BATTLE_STATES.IN_SETTLEMENT;
self.showPopupInCanvas(resultPanelNode); self.showPopupInCanvas(resultPanelNode);
// Clear player info // Clear player info
@ -945,6 +941,7 @@ cc.Class({
showPopupInCanvas(toShowNode) { showPopupInCanvas(toShowNode) {
const self = this; const self = this;
toShowNode.active = true;
self.disableInputControls(); self.disableInputControls();
self.transitToState(ALL_MAP_STATES.SHOWING_MODAL_POPUP); self.transitToState(ALL_MAP_STATES.SHOWING_MODAL_POPUP);
safelyAddChild(self.widgetsAboveAllNode, toShowNode); safelyAddChild(self.widgetsAboveAllNode, toShowNode);

View File

@ -12,7 +12,6 @@ window.DOWNSYNC_MSG_ACT_INPUT_BATCH = 2;
window.DOWNSYNC_MSG_ACT_BATTLE_STOPPED = 3; window.DOWNSYNC_MSG_ACT_BATTLE_STOPPED = 3;
window.DOWNSYNC_MSG_ACT_FORCED_RESYNC = 4; window.DOWNSYNC_MSG_ACT_FORCED_RESYNC = 4;
window.sendSafely = function(msgStr) { 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." * - "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."
@ -28,10 +27,13 @@ window.sendUint8AsBase64Safely = function(msgUint8Arr) {
window.clientSession.send(_uint8ToBase64(msgUint8Arr)); window.clientSession.send(_uint8ToBase64(msgUint8Arr));
} }
window.closeWSConnection = function() { window.closeWSConnection = function(code, reason) {
if (null == window.clientSession || window.clientSession.readyState != WebSocket.OPEN) return; if (null == window.clientSession || window.clientSession.readyState != WebSocket.OPEN) {
console.log(`"window.clientSession" is already closed or destroyed.`);
return;
}
console.log(`Closing "window.clientSession" from the client-side.`); console.log(`Closing "window.clientSession" from the client-side.`);
window.clientSession.close(); window.clientSession.close(code, reason);
} }
window.getBoundRoomIdFromPersistentStorage = function() { window.getBoundRoomIdFromPersistentStorage = function() {
@ -184,39 +186,33 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
clientSession.onerror = function(evt) { clientSession.onerror = function(evt) {
console.error("Error caught on the WS clientSession: ", evt); console.error("Error caught on the WS clientSession: ", evt);
if (window.handleClientSessionError) { window.clearLocalStorageAndBackToLoginScene(true);
window.handleClientSessionError();
}
}; };
clientSession.onclose = function(evt) { clientSession.onclose = function(evt) {
// [WARNING] The callback "onclose" might be called AFTER the webpage is refreshed with "1001 == evt.code". // [WARNING] The callback "onclose" might be called AFTER the webpage is refreshed with "1001 == evt.code".
console.warn("The WS clientSession is closed: ", evt, clientSession); console.warn(`The WS clientSession is closed: evt=${JSON.stringify(evt)}, evt.code=${evt.code}`);
if (false == evt.wasClean) { switch (evt.code) {
/* case constants.RET_CODE.BATTLE_STOPPED:
Chrome doesn't allow the use of "CustomCloseCode"s (yet) and will callback with a "WebsocketStdCloseCode 1006" and "false == evt.wasClean" here. See https://tools.ietf.org/html/rfc6455#section-7.4 for more information. // deliberately do nothing
*/ break;
if (window.handleClientSessionError) { case constants.RET_CODE.PLAYER_NOT_ADDABLE_TO_ROOM:
window.handleClientSessionError(); case constants.RET_CODE.PLAYER_NOT_READDABLE_TO_ROOM:
} window.clearBoundRoomIdInBothVolatileAndPersistentStorage(); // To favor the player to join other rooms
} else { mapIns.onManualRejoinRequired("Couldn't join any room at the moment, please retry");
switch (evt.code) { break;
case constants.RET_CODE.PLAYER_NOT_ADDABLE_TO_ROOM: case constants.RET_CODE.ACTIVE_WATCHDOG:
case constants.RET_CODE.PLAYER_NOT_READDABLE_TO_ROOM: mapIns.onManualRejoinRequired("Disconnected due to long-time inactivity, please rejoin");
window.clearBoundRoomIdInBothVolatileAndPersistentStorage(); break;
break; case constants.RET_CODE.UNKNOWN_ERROR:
case constants.RET_CODE.UNKNOWN_ERROR: case constants.RET_CODE.MYSQL_ERROR:
case constants.RET_CODE.MYSQL_ERROR: case constants.RET_CODE.PLAYER_NOT_FOUND:
case constants.RET_CODE.PLAYER_NOT_FOUND: case constants.RET_CODE.PLAYER_CHEATING:
case constants.RET_CODE.PLAYER_CHEATING: case 1006: // Peer(i.e. the backend) gone unexpectedly
case 1006: // Peer(i.e. the backend) gone unexpectedly window.clearLocalStorageAndBackToLoginScene(true);
if (window.handleClientSessionError) { break;
window.handleClientSessionError(); default:
} break;
break;
default:
break;
}
} }
}; };
}; };
@ -227,19 +223,7 @@ window.clearLocalStorageAndBackToLoginScene = function(shouldRetainBoundRoomIdIn
if (window.mapIns && window.mapIns.musicEffectManagerScriptIns) { if (window.mapIns && window.mapIns.musicEffectManagerScriptIns) {
window.mapIns.musicEffectManagerScriptIns.stopAllMusic(); window.mapIns.musicEffectManagerScriptIns.stopAllMusic();
} }
/**
* Here I deliberately removed the callback in the "common `handleClientSessionError` 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.handleClientSessionError = () => {
console.warn("+++++++ Special handleClientSessionError() assigned within `clearLocalStorageAndBackToLoginScene`");
// TBD.
window.handleClientSessionError = null; // To ensure that it's called at most once.
};
window.closeWSConnection(); window.closeWSConnection();
window.clearSelfPlayer(); window.clearSelfPlayer();
if (true != shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) { if (true != shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) {