diff --git a/battle_srv/models/room.go b/battle_srv/models/room.go index 2b0142f..2b65d7f 100644 --- a/battle_srv/models/room.go +++ b/battle_srv/models/room.go @@ -348,7 +348,7 @@ func (pR *Room) EncodeUpsyncCmd(upsyncCmd *pb.InputFrameUpsync) uint64 { func (pR *Room) AllPlayerInputsBufferString() string { s := make([]string, 0) - s = append(s, fmt.Sprintf("{lastAllConfirmedInputFrameId: %v, lastAllConfirmedInputFrameIdWithChange: %v}", pR.LastAllConfirmedInputFrameId, pR.LastAllConfirmedInputFrameIdWithChange)) + s = append(s, fmt.Sprintf("\n{stInputFrameId: %v, edInputFrameId: %v, lastAllConfirmedInputFrameIdWithChange: %v, lastAllConfirmedInputFrameId: %v}", pR.AllPlayerInputsBuffer.StFrameId, pR.AllPlayerInputsBuffer.EdFrameId, pR.LastAllConfirmedInputFrameIdWithChange, pR.LastAllConfirmedInputFrameId)) for playerId, player := range pR.Players { s = append(s, fmt.Sprintf("{playerId: %v, ackingFrameId: %v, ackingInputFrameId: %v, lastSentInputFrameId: %v}", playerId, player.AckingFrameId, player.AckingInputFrameId, player.LastSentInputFrameId)) } @@ -456,7 +456,7 @@ func (pR *Room) StartBattle() { toSendInputFrames := make([]*pb.InputFrameDownsync, 0, pR.AllPlayerInputsBuffer.Cnt) candidateToSendInputFrameId := atomic.LoadInt32(&(pR.Players[playerId].LastSentInputFrameId)) + 1 if candidateToSendInputFrameId < pR.AllPlayerInputsBuffer.StFrameId { - Logger.Warn("LastSentInputFrameId already popped:", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("lastSentInputFrameId", candidateToSendInputFrameId-1), zap.Any("playerAckingInputFrameId", player.AckingInputFrameId), zap.Any("AllPlayerInputsBuffer", pR.AllPlayerInputsBufferString())) + Logger.Warn(fmt.Sprintf("LastSentInputFrameId already popped: roomId=%v, playerId=%v, lastSentInputFrameId=%v, playerAckingInputFrameId=%v, AllPlayerInputsBuffer=%v", pR.Id, playerId, candidateToSendInputFrameId-1, player.AckingInputFrameId, pR.AllPlayerInputsBufferString())) candidateToSendInputFrameId = pR.AllPlayerInputsBuffer.StFrameId } @@ -534,7 +534,7 @@ func (pR *Room) OnBattleCmdReceived(pReq *pb.WsReq) { ackingInputFrameId := pReq.AckingInputFrameId if _, existent := pR.Players[playerId]; !existent { - Logger.Warn("upcmd player doesn't exist:", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId)) + Logger.Warn(fmt.Sprintf("upcmd player doesn't exist: roomId=%v, playerId=%v", pR.Id, playerId)) return } @@ -549,7 +549,7 @@ func (pR *Room) OnBattleCmdReceived(pReq *pb.WsReq) { for _, inputFrameUpsync := range inputFrameUpsyncBatch { clientInputFrameId := inputFrameUpsync.InputFrameId if clientInputFrameId < pR.AllPlayerInputsBuffer.StFrameId { - Logger.Warn("Obsolete inputFrameUpsync:", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("clientInputFrameId", clientInputFrameId), zap.Any("StFrameId", pR.AllPlayerInputsBuffer.StFrameId), zap.Any("EdFrameId", pR.AllPlayerInputsBuffer.EdFrameId)) + Logger.Warn(fmt.Sprintf("Obsolete inputFrameUpsync: roomId=%v, playerId=%v, clientInputFrameId=%v, AllPlayerInputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.AllPlayerInputsBufferString())) return } @@ -557,36 +557,36 @@ func (pR *Room) OnBattleCmdReceived(pReq *pb.WsReq) { encodedInput := pR.EncodeUpsyncCmd(inputFrameUpsync) if clientInputFrameId >= pR.AllPlayerInputsBuffer.EdFrameId { - Logger.Warn("inputFrame too advanced! is the player cheating?", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("inputFrameId", clientInputFrameId), zap.Any("EdFrameId", pR.AllPlayerInputsBuffer.EdFrameId)) + Logger.Warn(fmt.Sprintf("inputFrame too advanced! is the player cheating?: roomId=%v, playerId=%v, clientInputFrameId=%v, AllPlayerInputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.AllPlayerInputsBufferString())) return } tmp2 := pR.AllPlayerInputsBuffer.GetByFrameId(clientInputFrameId) if nil == tmp2 { // This shouldn't happen due to the previous 2 checks - Logger.Warn("Mysterious error getting an input frame:", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("clientInputFrameId", clientInputFrameId), zap.Any("StFrameId", pR.AllPlayerInputsBuffer.StFrameId), zap.Any("EdFrameId", pR.AllPlayerInputsBuffer.EdFrameId)) + Logger.Warn(fmt.Sprintf("Mysterious error getting an input frame: roomId=%v, playerId=%v, clientInputFrameId=%v, AllPlayerInputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.AllPlayerInputsBufferString())) return } inputFrameDownsync := tmp2.(*pb.InputFrameDownsync) oldConfirmedList := atomic.LoadUint64(&(inputFrameDownsync.ConfirmedList)) if (oldConfirmedList & joinMask) > 0 { - Logger.Warn("Cmd already confirmed but getting set attempt, omitting this upsync cmd:", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("clientInputFrameId", clientInputFrameId), zap.Any("StFrameId", pR.AllPlayerInputsBuffer.StFrameId), zap.Any("EdFrameId", pR.AllPlayerInputsBuffer.EdFrameId)) + Logger.Warn(fmt.Sprintf("Cmd already confirmed but getting set attempt, omitting this upsync cmd: roomId=%v, playerId=%v, clientInputFrameId=%v, AllPlayerInputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.AllPlayerInputsBufferString())) return } // In Golang 1.12, there's no "compare-and-swap primitive" on a custom struct (or it's pointer, unless it's an unsafe pointer https://pkg.go.dev/sync/atomic@go1.12#CompareAndSwapPointer). Although CAS on custom struct is possible in Golang 1.19 https://pkg.go.dev/sync/atomic@go1.19.1#Value.CompareAndSwap, using a single word is still faster whenever possible. if swapped := atomic.CompareAndSwapUint64(&inputFrameDownsync.InputList[indiceInJoinIndexBooleanArr], uint64(0), encodedInput); !swapped { - Logger.Warn("Failed input CAS:", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("clientInputFrameId", clientInputFrameId)) + Logger.Warn(fmt.Sprintf("Failed input CAS: roomId=%v, playerId=%v, clientInputFrameId=%v", pR.Id, playerId, clientInputFrameId)) return } newConfirmedList := (oldConfirmedList | joinMask) if swapped := atomic.CompareAndSwapUint64(&(inputFrameDownsync.ConfirmedList), oldConfirmedList, newConfirmedList); !swapped { // [WARNING] Upon this error, the actual input has already been updated, which is an expected result if it caused by the force confirmation from "battleMainLoop". - Logger.Warn("Failed confirm CAS:", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("clientInputFrameId", clientInputFrameId)) + Logger.Warn(fmt.Sprintf("Failed confirm CAS: roomId=%v, playerId=%v, clientInputFrameId=%v", pR.Id, playerId, clientInputFrameId)) return } - totPlayerCnt := uint32(len(pR.Players)) + totPlayerCnt := uint32(pR.Capacity) allConfirmedMask := uint64((1 << totPlayerCnt) - 1) if allConfirmedMask == newConfirmedList { pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, playerId) @@ -598,7 +598,7 @@ func (pR *Room) onInputFrameDownsyncAllConfirmed(inputFrameDownsync *pb.InputFra clientInputFrameId := inputFrameDownsync.InputFrameId if false == pR.equalInputLists(inputFrameDownsync.InputList, pR.LastAllConfirmedInputList) { atomic.StoreInt32(&(pR.LastAllConfirmedInputFrameIdWithChange), clientInputFrameId) // [WARNING] Different from the CAS in "battleMainLoop", it's safe to just update "pR.LastAllConfirmedInputFrameIdWithChange" here, because only monotonic increment is possible here! - Logger.Info("Key inputFrame change", zap.Any("roomId", pR.Id), zap.Any("inputFrameId", clientInputFrameId), zap.Any("lastInputFrameId", pR.LastAllConfirmedInputFrameId), zap.Any("AllPlayerInputsBuffer", pR.AllPlayerInputsBufferString()), zap.Any("newInputList", inputFrameDownsync.InputList), zap.Any("lastInputList", pR.LastAllConfirmedInputList)) + Logger.Info(fmt.Sprintf("Key inputFrame change: roomId=%v, playerId=%v, clientInputFrameId=%v, lastInputFrameId=%v, newInputList=%v, lastInputList=%v, AllPlayerInputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.LastAllConfirmedInputFrameId, inputFrameDownsync.InputList, pR.LastAllConfirmedInputList, pR.AllPlayerInputsBufferString())) } atomic.StoreInt32(&(pR.LastAllConfirmedInputFrameId), clientInputFrameId) // [WARNING] It's IMPORTANT that "pR.LastAllConfirmedInputFrameId" is NOT NECESSARILY CONSECUTIVE, i.e. if one of the players disconnects and reconnects within a considerable amount of frame delays! for i, v := range inputFrameDownsync.InputList { @@ -606,7 +606,7 @@ func (pR *Room) onInputFrameDownsyncAllConfirmed(inputFrameDownsync *pb.InputFra pR.LastAllConfirmedInputList[i] = v } if pR.inputFrameIdDebuggable(clientInputFrameId) { - Logger.Info("inputFrame lifecycle#2[allconfirmed]", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("inputFrameId", clientInputFrameId), zap.Any("AllPlayerInputsBuffer", pR.AllPlayerInputsBufferString())) + Logger.Info(fmt.Sprintf("inputFrame lifecycle#2[allconfirmed]: roomId=%v, playerId=%v, clientInputFrameId=%v, AllPlayerInputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.LastAllConfirmedInputFrameId, pR.AllPlayerInputsBufferString())) } } @@ -1074,7 +1074,7 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende if nil == tmp { panic(fmt.Sprintf("delayedInputFrameId=%v doesn't exist for roomId=%v, this is abnormal because it's to be used for applying dynamics to [fromRenderFrameId:%v, toRenderFrameId:%v) @ collisionSysRenderFrameId=%v! AllPlayerInputsBuffer=%v", delayedInputFrameId, pR.Id, fromRenderFrameId, toRenderFrameId, collisionSysRenderFrameId, pR.AllPlayerInputsBufferString())) } - delayedInputFrame := tmp.(pb.InputFrameDownsync) + delayedInputFrame := tmp.(*pb.InputFrameDownsync) if swapped := atomic.CompareAndSwapUint64(&(delayedInputFrame.ConfirmedList), allConfirmedMask, allConfirmedMask); !swapped { panic(fmt.Sprintf("delayedInputFrameId=%v is not yet all-confirmed for roomId=%v, this is abnormal because it's to be used for applying dynamics to [fromRenderFrameId:%v, toRenderFrameId:%v) @ collisionSysRenderFrameId=%v! AllPlayerInputsBuffer=%v", delayedInputFrameId, pR.Id, fromRenderFrameId, toRenderFrameId, collisionSysRenderFrameId, pR.AllPlayerInputsBufferString())) } diff --git a/battle_srv/models/tiled_map.go b/battle_srv/models/tiled_map.go index aeb5f00..a483211 100644 --- a/battle_srv/models/tiled_map.go +++ b/battle_srv/models/tiled_map.go @@ -6,8 +6,6 @@ import ( "encoding/base64" "encoding/xml" "errors" - "fmt" - "github.com/ByteArena/box2d" "go.uber.org/zap" "io/ioutil" "math" @@ -181,17 +179,12 @@ type Polygon2DList []*Polygon2D type StrToVec2DListMap map[string]*Vec2DList // Note that it's deliberately NOT using "map[string]Vec2DList", for the easy of passing return value to "models/room.go". type StrToPolygon2DListMap map[string]*Polygon2DList // Note that it's deliberately NOT using "map[string]Polygon2DList", for the easy of passing return value to "models/room.go". -func TmxPolylineToPolygon2DInB2World(pTmxMapIns *TmxMap, singleObjInTmxFile *TmxOrTsxObject, targetPolyline *TmxOrTsxPolyline) (*Polygon2D, error) { +func tmxPolylineToPolygon2D(pTmxMapIns *TmxMap, singleObjInTmxFile *TmxOrTsxObject, targetPolyline *TmxOrTsxPolyline) (*Polygon2D, error) { if nil == targetPolyline { return nil, nil } singleValueArray := strings.Split(targetPolyline.Points, " ") - pointsCount := len(singleValueArray) - - if pointsCount >= box2d.B2_maxPolygonVertices { - return nil, errors.New(fmt.Sprintf("During `TmxPolylineToPolygon2DInB2World`, you have a polygon with pointsCount == %v, exceeding or equal to box2d.B2_maxPolygonVertices == %v, of polyines [%v]", pointsCount, box2d.B2_maxPolygonVertices, singleValueArray)) - } theUntransformedAnchor := &Vec2D{ X: singleObjInTmxFile.X, @@ -217,7 +210,6 @@ func TmxPolylineToPolygon2DInB2World(pTmxMapIns *TmxMap, singleObjInTmxFile *Tmx } } - // Transform to B2World space coordinate. tmp := &Vec2D{ X: thePolygon2DFromPolyline.Points[k].X, Y: thePolygon2DFromPolyline.Points[k].Y, @@ -230,7 +222,7 @@ func TmxPolylineToPolygon2DInB2World(pTmxMapIns *TmxMap, singleObjInTmxFile *Tmx return thePolygon2DFromPolyline, nil } -func TsxPolylineToOffsetsWrtTileCenterInB2World(pTmxMapIns *TmxMap, singleObjInTsxFile *TmxOrTsxObject, targetPolyline *TmxOrTsxPolyline, pTsxIns *Tsx) (*Polygon2D, error) { +func tsxPolylineToOffsetsWrtTileCenter(pTmxMapIns *TmxMap, singleObjInTsxFile *TmxOrTsxObject, targetPolyline *TmxOrTsxPolyline, pTsxIns *Tsx) (*Polygon2D, error) { if nil == targetPolyline { return nil, nil } @@ -241,10 +233,6 @@ func TsxPolylineToOffsetsWrtTileCenterInB2World(pTmxMapIns *TmxMap, singleObjInT singleValueArray := strings.Split(targetPolyline.Points, " ") pointsCount := len(singleValueArray) - if pointsCount >= box2d.B2_maxPolygonVertices { - return nil, errors.New(fmt.Sprintf("During `TsxPolylineToOffsetsWrtTileCenterInB2World`, you have a polygon with pointsCount == %v, exceeding or equal to box2d.B2_maxPolygonVertices == %v", pointsCount, box2d.B2_maxPolygonVertices)) - } - thePolygon2DFromPolyline := &Polygon2D{ Anchor: nil, Points: make([]*Vec2D, pointsCount), @@ -253,7 +241,7 @@ func TsxPolylineToOffsetsWrtTileCenterInB2World(pTmxMapIns *TmxMap, singleObjInT } /* - [WARNING] In this case, the "Treasure"s and "GuardTower"s are put into Tmx file as "ImageObject"s, of each the "ProportionalAnchor" is (0.5, 0). Therefore we calculate that "thePolygon2DFromPolyline.Points" are "offsets(in B2World) w.r.t. the BottomCenter". See https://shimo.im/docs/SmLJJhXm2C8XMzZT for details. + [WARNING] In this case, the "Treasure"s and "GuardTower"s are put into Tmx file as "ImageObject"s, of each the "ProportionalAnchor" is (0.5, 0). Therefore the "thePolygon2DFromPolyline.Points" are "offsets w.r.t. the BottomCenter". See https://shimo.im/docs/SmLJJhXm2C8XMzZT for details. */ for k, value := range singleValueArray { @@ -271,14 +259,12 @@ func TsxPolylineToOffsetsWrtTileCenterInB2World(pTmxMapIns *TmxMap, singleObjInT thePolygon2DFromPolyline.Points[k].Y = float64(pTsxIns.TileHeight) - (coordinateValue + offsetFromTopLeftInTileLocalCoordY) } } - - // No need to transform for B2World space coordinate because the marks in a Tsx file is already rectilinear. } return thePolygon2DFromPolyline, nil } -func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, firstGid int, gidBoundariesMapInB2World map[int]StrToPolygon2DListMap) error { +func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, firstGid int, gidBoundariesMap map[int]StrToPolygon2DListMap) error { pTsxIns := &Tsx{} err := xml.Unmarshal(byteArrOfTsxFile, pTsxIns) if nil != err { @@ -312,7 +298,7 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f ``` , we currently REQUIRE that "`an object of a tile` with ONE OR MORE polylines must come with a single corresponding '', and viceversa". - Refer to https://shimo.im/docs/SmLJJhXm2C8XMzZT for how we theoretically fit a "Polyline in Tsx" into a "Polygon2D" and then into the corresponding "B2BodyDef & B2Body in the `world of colliding bodies`". + Refer to https://shimo.im/docs/SmLJJhXm2C8XMzZT for how we theoretically fit a "Polyline in Tsx" into a "Polygon2D". */ theObjGroup := tile.ObjectGroup @@ -331,11 +317,11 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f key := singleObj.Properties.Property[0].Value var theStrToPolygon2DListMap StrToPolygon2DListMap - if existingStrToPolygon2DListMap, ok := gidBoundariesMapInB2World[globalGid]; ok { + if existingStrToPolygon2DListMap, ok := gidBoundariesMap[globalGid]; ok { theStrToPolygon2DListMap = existingStrToPolygon2DListMap } else { - gidBoundariesMapInB2World[globalGid] = make(StrToPolygon2DListMap, 0) - theStrToPolygon2DListMap = gidBoundariesMapInB2World[globalGid] + gidBoundariesMap[globalGid] = make(StrToPolygon2DListMap, 0) + theStrToPolygon2DListMap = gidBoundariesMap[globalGid] } var pThePolygon2DList *Polygon2DList @@ -347,7 +333,7 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f pThePolygon2DList = theStrToPolygon2DListMap[key] } - thePolygon2DFromPolyline, err := TsxPolylineToOffsetsWrtTileCenterInB2World(pTmxMapIns, singleObj, singleObj.Polyline, pTsxIns) + thePolygon2DFromPolyline, err := tsxPolylineToOffsetsWrtTileCenter(pTmxMapIns, singleObj, singleObj.Polyline, pTsxIns) if nil != err { panic(err) } @@ -357,16 +343,9 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f return nil } -func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMapInB2World map[int]StrToPolygon2DListMap) (int32, int32, int32, int32, StrToVec2DListMap, StrToPolygon2DListMap, error) { +func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMap map[int]StrToPolygon2DListMap) (int32, int32, int32, int32, StrToVec2DListMap, StrToPolygon2DListMap, error) { toRetStrToVec2DListMap := make(StrToVec2DListMap, 0) toRetStrToPolygon2DListMap := make(StrToPolygon2DListMap, 0) - /* - Note that both - - "Vec2D"s of "toRetStrToVec2DListMap", and - - "Polygon2D"s of "toRetStrToPolygon2DListMap" - - are already transformed into the "coordinate of B2World". - */ for _, objGroup := range pTmxMapIns.ObjectGroups { switch objGroup.Name { @@ -376,10 +355,8 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMapInB2World map[i if false == ok { theVec2DListToCache := make(Vec2DList, 0) toRetStrToVec2DListMap[objGroup.Name] = &theVec2DListToCache - pTheVec2DListToCache = toRetStrToVec2DListMap[objGroup.Name] - } else { - pTheVec2DListToCache = toRetStrToVec2DListMap[objGroup.Name] - } + } + pTheVec2DListToCache = toRetStrToVec2DListMap[objGroup.Name] for _, singleObjInTmxFile := range objGroup.Objects { theUntransformedPos := &Vec2D{ X: singleObjInTmxFile.X, @@ -389,16 +366,14 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMapInB2World map[i *pTheVec2DListToCache = append(*pTheVec2DListToCache, &thePosInWorld) } case "Barrier": - // Note that in this case, the "Polygon2D.Anchor" of each "TmxOrTsxObject" is exactly overlapping with "Polygon2D.Points[0]" w.r.t. B2World. + // Note that in this case, the "Polygon2D.Anchor" of each "TmxOrTsxObject" is exactly overlapping with "Polygon2D.Points[0]". var pThePolygon2DListToCache *Polygon2DList _, ok := toRetStrToPolygon2DListMap[objGroup.Name] if false == ok { thePolygon2DListToCache := make(Polygon2DList, 0) toRetStrToPolygon2DListMap[objGroup.Name] = &thePolygon2DListToCache - pThePolygon2DListToCache = toRetStrToPolygon2DListMap[objGroup.Name] - } else { - pThePolygon2DListToCache = toRetStrToPolygon2DListMap[objGroup.Name] } + pThePolygon2DListToCache = toRetStrToPolygon2DListMap[objGroup.Name] for _, singleObjInTmxFile := range objGroup.Objects { if nil == singleObjInTmxFile.Polyline { @@ -408,7 +383,7 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMapInB2World map[i continue } - thePolygon2DInWorld, err := TmxPolylineToPolygon2DInB2World(pTmxMapIns, singleObjInTmxFile, singleObjInTmxFile.Polyline) + thePolygon2DInWorld, err := tmxPolylineToPolygon2D(pTmxMapIns, singleObjInTmxFile, singleObjInTmxFile.Polyline) if nil != err { panic(err) } diff --git a/frontend/assets/scenes/login.fire b/frontend/assets/scenes/login.fire index 020e9a8..31ccba3 100644 --- a/frontend/assets/scenes/login.fire +++ b/frontend/assets/scenes/login.fire @@ -440,7 +440,7 @@ "array": [ 0, 0, - 216.05530045313827, + 209.73151519075364, 0, 0, 0, diff --git a/frontend/assets/scripts/Map.js b/frontend/assets/scripts/Map.js index 87bf748..c670e39 100644 --- a/frontend/assets/scripts/Map.js +++ b/frontend/assets/scripts/Map.js @@ -1047,6 +1047,7 @@ cc.Class({ const inputList = self.getCachedInputFrameDownsyncWithPrediction(j).inputList; for (let j in self.playerRichInfoArr) { const joinIndex = parseInt(j) + 1; + const playerId = self.playerRichInfoArr[j].id; const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; const playerCollider = collisionSysMap.get(collisionPlayerIndex); const player = renderFrame.players[playerId]; diff --git a/frontend/assets/scripts/WsSessionMgr.js b/frontend/assets/scripts/WsSessionMgr.js index 7069cf8..5cf08e9 100644 --- a/frontend/assets/scripts/WsSessionMgr.js +++ b/frontend/assets/scripts/WsSessionMgr.js @@ -166,6 +166,7 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) { break; case window.DOWNSYNC_MSG_ACT_FORCED_RESYNC: if (window.handleInputFrameDownsyncBatch && window.handleRoomDownsyncFrame) { + console.warn("GOT forced resync:", resp); // The following order of execution is important, because "handleInputFrameDownsyncBatch" is only available when state is IN_BATTLE window.handleRoomDownsyncFrame(resp.rdf); window.handleInputFrameDownsyncBatch(resp.inputFrameDownsyncBatch);