diff --git a/battle_srv/models/room.go b/battle_srv/models/room.go index e6cb36a..6388512 100644 --- a/battle_srv/models/room.go +++ b/battle_srv/models/room.go @@ -1251,9 +1251,11 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende } } + pbPlayers := toPbPlayers(pR.Players) + newRenderFrame := RoomDownsyncFrame{ Id: collisionSysRenderFrameId + 1, - Players: toPbPlayers(pR.Players), + Players: pbPlayers, CountdownNanos: (pR.BattleDurationNanos - int64(collisionSysRenderFrameId)*pR.RollbackEstimatedDtNanos), } pR.RenderFrameBuffer.Put(&newRenderFrame) @@ -1292,10 +1294,10 @@ func (pR *Room) printBarrier(barrierCollider *resolv.Object) { Logger.Info(fmt.Sprintf("Barrier in roomId=%v: w=%v, h=%v, shape=%v", pR.Id, barrierCollider.W, barrierCollider.H, barrierCollider.Shape)) } -func (pR *Room) worldToVirtualGridPos(x, y float64) (int32, int32) { +func (pR *Room) worldToVirtualGridPos(wx, wy float64) (int32, int32) { // In JavaScript floating numbers suffer from seemingly non-deterministic arithmetics, and even if certain libs solved this issue by approaches such as fixed-point-number, they might not be used in other libs -- e.g. the "collision libs" we're interested in -- thus couldn't kill all pains. - var virtualGridX int32 = int32(x * pR.WorldToVirtualGridRatio) - var virtualGridY int32 = int32(y * pR.WorldToVirtualGridRatio) + var virtualGridX int32 = int32(wx * pR.WorldToVirtualGridRatio) + var virtualGridY int32 = int32(wy * pR.WorldToVirtualGridRatio) return virtualGridX, virtualGridY } diff --git a/frontend/assets/scenes/login.fire b/frontend/assets/scenes/login.fire index a527072..0becc89 100644 --- a/frontend/assets/scenes/login.fire +++ b/frontend/assets/scenes/login.fire @@ -440,7 +440,7 @@ "array": [ 0, 0, - 377.5870760500153, + 216.67592045656244, 0, 0, 0, diff --git a/frontend/assets/scripts/Login.js b/frontend/assets/scripts/Login.js index 1390183..936453e 100644 --- a/frontend/assets/scripts/Login.js +++ b/frontend/assets/scripts/Login.js @@ -1,6 +1,8 @@ const i18n = require('LanguageData'); i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field +window.pb = require("./modules/room_downsync_frame_proto_bundle.forcemsg"); + cc.Class({ extends: cc.Component, @@ -96,30 +98,6 @@ cc.Class({ if (null != qDict && qDict["expectedRoomId"]) { window.clearBoundRoomIdInBothVolatileAndPersistentStorage(); } - - cc.loader.loadRes("pbfiles/room_downsync_frame", function(err, textAsset /* cc.TextAsset */ ) { - if (err) { - cc.error(err.message || err); - return; - } - // Otherwise, `window.RoomDownsyncFrame` is already assigned. - let protoRoot = new protobuf.Root; - window.protobuf.parse(textAsset.text, protoRoot); - window.RoomDownsyncFrame = protoRoot.lookupType("treasurehunterx.RoomDownsyncFrame"); - window.BattleColliderInfo = protoRoot.lookupType("treasurehunterx.BattleColliderInfo"); - window.WsReq = protoRoot.lookupType("treasurehunterx.WsReq"); - window.WsResp = protoRoot.lookupType("treasurehunterx.WsResp"); - self.checkIntAuthTokenExpire().then( - (intAuthToken) => { - console.log("Successfully found `intAuthToken` in local cache"); - self.useTokenLogin(intAuthToken); - }, - () => { - console.warn("Failed to find `intAuthToken` in local cache"); - window.clearBoundRoomIdInBothVolatileAndPersistentStorage(); - } - ); - }); }, getRetCodeList() { diff --git a/frontend/assets/scripts/Map.js b/frontend/assets/scripts/Map.js index 4449e46..0af26a0 100644 --- a/frontend/assets/scripts/Map.js +++ b/frontend/assets/scripts/Map.js @@ -223,7 +223,7 @@ cc.Class({ inputFrameUpsyncBatch.push(inputFrameUpsync); } } - const reqData = window.WsReq.encode({ + const reqData = window.pb.protos.WsReq.encode({ msgId: Date.now(), playerId: self.selfPlayerInfo.id, act: window.UPSYNC_MSG_ACT_PLAYER_CMD, @@ -502,7 +502,7 @@ cc.Class({ self.backgroundMapTiledIns.node.setContentSize(newBackgroundMapSize.width * newBackgroundMapTileSize.width, newBackgroundMapSize.height * newBackgroundMapTileSize.height); self.backgroundMapTiledIns.node.setPosition(cc.v2(0, 0)); - const reqData = window.WsReq.encode({ + const reqData = window.pb.protos.WsReq.encode({ msgId: Date.now(), act: window.UPSYNC_MSG_ACT_PLAYER_COLLIDER_ACK, }).finish(); @@ -598,12 +598,6 @@ cc.Class({ console.log('On battle resynced! renderFrameId=', rdf.id); } - self.renderFrameId = rdf.id; - self.lastRenderFrameIdTriggeredAt = performance.now(); - // In this case it must be true that "rdf.id > chaserRenderFrameId >= lastAllConfirmedRenderFrameId". - self.lastAllConfirmedRenderFrameId = rdf.id; - self.chaserRenderFrameId = rdf.id; - const players = rdf.players; const playerMetas = rdf.playerMetas; self._initPlayerRichInfoDict(players, playerMetas); @@ -615,6 +609,12 @@ cc.Class({ playersInfoScriptIns.updateData(playerMeta); } + self.renderFrameId = rdf.id; + self.lastRenderFrameIdTriggeredAt = performance.now(); + // In this case it must be true that "rdf.id > chaserRenderFrameId >= lastAllConfirmedRenderFrameId". + self.lastAllConfirmedRenderFrameId = rdf.id; + self.chaserRenderFrameId = rdf.id; + if (null != rdf.countdownNanos) { self.countdownNanos = rdf.countdownNanos; } @@ -741,17 +741,16 @@ cc.Class({ self.playersInfoNode.getComponent("PlayersInfo").clearInfo(); }, - spawnPlayerNode(joinIndex, x, y) { + spawnPlayerNode(joinIndex, vx, vy, playerRichInfo) { const self = this; const newPlayerNode = 1 == joinIndex ? cc.instantiate(self.player1Prefab) : cc.instantiate(self.player2Prefab); // hardcoded for now, car color determined solely by joinIndex - newPlayerNode.setPosition(cc.v2(x, y)); + const wpos = self.virtualGridToWorldPos(vx, vy); + + newPlayerNode.setPosition(cc.v2(wpos[0], wpos[1])); newPlayerNode.getComponent("SelfPlayer").mapNode = self.node; - const currentSelfColliderCircle = newPlayerNode.getComponent(cc.CircleCollider); - const r = currentSelfColliderCircle.radius, - d = 2 * r; - // The collision box of an individual player is a polygon instead of a circle, because the backend collision engine doesn't handle circle alignment well. - const x0 = x - r, - y0 = y - r; + const cpos = self.virtualGridToPlayerColliderPos(vx, vy, playerRichInfo); + const d = playerRichInfo.colliderRadius*2, x0 = cpos[0], + y0 = cpos[1]; let pts = [[0, 0], [d, 0], [d, d], [0, d]]; const newPlayerColliderLatest = self.latestCollisionSys.createPolygon(x0, y0, pts); @@ -919,9 +918,19 @@ cc.Class({ self.findingPlayerNode.parent.removeChild(self.findingPlayerNode); }, - onBattleReadyToStart(playerMetas) { - console.log("Calling `onBattleReadyToStart` with:", playerMetas); + onBattleReadyToStart(rdf) { const self = this; + const players = rdf.players; + const playerMetas = rdf.playerMetas; + self._initPlayerRichInfoDict(players, playerMetas); + + // Show the top status indicators for IN_BATTLE + const playersInfoScriptIns = self.playersInfoNode.getComponent("PlayersInfo"); + for (let i in playerMetas) { + const playerMeta = playerMetas[i]; + playersInfoScriptIns.updateData(playerMeta); + } + console.log("Calling `onBattleReadyToStart` with:", playerMetas); const findingPlayerScriptIns = self.findingPlayerNode.getComponent("FindingPlayer"); findingPlayerScriptIns.hideExitButton(); findingPlayerScriptIns.updatePlayersInfo(playerMetas); @@ -965,9 +974,7 @@ cc.Class({ const joinIndex = playerRichInfo.joinIndex; const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; const playerCollider = collisionSysMap.get(collisionPlayerIndex); - const currentSelfColliderCircle = playerRichInfo.node.getComponent(cc.CircleCollider); const vpos = self.playerColliderAnchorToVirtualGridPos(playerCollider.x, playerCollider.y, playerRichInfo); - const r = currentSelfColliderCircle.radius; rdf.players[playerRichInfo.id] = { id: playerRichInfo.id, virtualGridX: vpos[0], @@ -1044,7 +1051,7 @@ cc.Class({ const playerCollider = collisionSysMap.get(collisionPlayerIndex); const player = latestRdf.players[playerId]; - const cpos = self.worldToVirtualGridPos(player.virtualGridX, player.virtualGridY); + const cpos = self.virtualGridToPlayerColliderPos(player.virtualGridX, player.virtualGridY, playerRichInfo); playerCollider.x = cpos[0]; playerCollider.y = cpos[1]; }); @@ -1069,7 +1076,7 @@ cc.Class({ const player = renderFrame.players[playerId]; const encodedInput = inputList[joinIndex - 1]; const decodedInput = self.ctrl.decodeDirection(encodedInput); - const baseChange = player.speed * decodedInput.speedFactor; + const baseChange = player.speed * self.virtualGridToWorldRatio * decodedInput.speedFactor; playerCollider.x += baseChange * decodedInput.dx; playerCollider.y += baseChange * decodedInput.dy; } @@ -1104,16 +1111,16 @@ cc.Class({ if (self.playerRichInfoDict.has(playerId)) continue; // Skip already put keys const immediatePlayerInfo = players[playerId]; const immediatePlayerMeta = playerMetas[playerId]; - const nodeAndScriptIns = self.spawnPlayerNode(immediatePlayerInfo.joinIndex, immediatePlayerInfo.x, immediatePlayerInfo.y); self.playerRichInfoDict.set(playerId, immediatePlayerInfo); + Object.assign(self.playerRichInfoDict.get(playerId), immediatePlayerMeta); + + const nodeAndScriptIns = self.spawnPlayerNode(immediatePlayerInfo.joinIndex, immediatePlayerInfo.virtualGridX, immediatePlayerInfo.virtualGridY, self.playerRichInfoDict.get(playerId)); Object.assign(self.playerRichInfoDict.get(playerId), { node: nodeAndScriptIns[0], scriptIns: nodeAndScriptIns[1] }); - Object.assign(self.playerRichInfoDict.get(playerId), immediatePlayerMeta); - if (self.selfPlayerInfo.id == playerId) { self.selfPlayerInfo = Object.assign(self.selfPlayerInfo, immediatePlayerInfo); nodeAndScriptIns[1].showArrowTipNode(); @@ -1177,12 +1184,12 @@ cc.Class({ playerColliderAnchorToVirtualGridPos(cx, cy, playerRichInfo) { const self = this; const wpos = self.playerColliderAnchorToWorldPos(cx, cy, playerRichInfo); - return pR.worldToVirtualGridPos(wpos[0], wpos[1]) + return self.worldToVirtualGridPos(wpos[0], wpos[1]) }, virtualGridToPlayerColliderPos(vx, vy, playerRichInfo) { const self = this; const wpos = self.virtualGridToWorldPos(vx, vy); - return playerWorldToCollisionPos(wpos[0], wpos[1], playerRichInfo) + return self.playerWorldToCollisionPos(wpos[0], wpos[1], playerRichInfo) }, }); diff --git a/frontend/assets/scripts/WsSessionMgr.js b/frontend/assets/scripts/WsSessionMgr.js index ac10b7d..1204219 100644 --- a/frontend/assets/scripts/WsSessionMgr.js +++ b/frontend/assets/scripts/WsSessionMgr.js @@ -146,7 +146,7 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) { return; } try { - const resp = window.WsResp.decode(new Uint8Array(evt.data)); + const resp = window.pb.protos.WsResp.decode(new Uint8Array(evt.data)); switch (resp.act) { case window.DOWNSYNC_MSG_ACT_HB_REQ: window.handleHbRequirements(resp); // 获取boundRoomId并存储到localStorage @@ -159,7 +159,7 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) { mapIns.hideFindingPlayersGUI(); break; case window.DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START: - mapIns.onBattleReadyToStart(resp.rdf.playerMetas); + mapIns.onBattleReadyToStart(resp.rdf); break; case window.DOWNSYNC_MSG_ACT_BATTLE_START: mapIns.onRoomDownsyncFrame(resp.rdf);