Added backend collider initialization codes.

This commit is contained in:
genxium 2022-10-01 15:14:05 +08:00
parent 527cc94242
commit a2a8be9068
5 changed files with 73 additions and 61 deletions

View File

@ -1,12 +1,5 @@
package models package models
import (
"github.com/ByteArena/box2d"
)
type Barrier struct { type Barrier struct {
X float64
Y float64
Boundary *Polygon2D Boundary *Polygon2D
CollidableBody *box2d.B2Body
} }

View File

@ -3,7 +3,6 @@ package models
import ( import (
"database/sql" "database/sql"
"fmt" "fmt"
"github.com/ByteArena/box2d"
sq "github.com/Masterminds/squirrel" sq "github.com/Masterminds/squirrel"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
) )
@ -54,7 +53,6 @@ type Player struct {
UpdatedAt int64 `json:"-" db:"updated_at"` UpdatedAt int64 `json:"-" db:"updated_at"`
DeletedAt NullInt64 `json:"-" db:"deleted_at"` DeletedAt NullInt64 `json:"-" db:"deleted_at"`
TutorialStage int `json:"-" db:"tutorial_stage"` TutorialStage int `json:"-" db:"tutorial_stage"`
CollidableBody *box2d.B2Body `json:"-"`
AckingFrameId int32 `json:"ackingFrameId"` AckingFrameId int32 `json:"ackingFrameId"`
AckingInputFrameId int32 `json:"-"` AckingInputFrameId int32 `json:"-"`
LastSentInputFrameId int32 `json:"-"` LastSentInputFrameId int32 `json:"-"`

View File

@ -9,6 +9,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"io/ioutil" "io/ioutil"
"math/rand" "math/rand"
"math"
"os" "os"
"path/filepath" "path/filepath"
. "server/common" . "server/common"
@ -28,6 +29,7 @@ const (
DOWNSYNC_MSG_ACT_HB_REQ = int32(1) DOWNSYNC_MSG_ACT_HB_REQ = int32(1)
DOWNSYNC_MSG_ACT_INPUT_BATCH = int32(2) DOWNSYNC_MSG_ACT_INPUT_BATCH = int32(2)
DOWNSYNC_MSG_ACT_ROOM_FRAME = int32(3) DOWNSYNC_MSG_ACT_ROOM_FRAME = int32(3)
DOWNSYNC_MSG_ACT_FORCED_RESYNC = int32(4)
) )
const ( const (
@ -315,8 +317,6 @@ func (pR *Room) ChooseStage() error {
Logger.Info("ChooseStage printing polygon2D for barrierPolygon2DList", zap.Any("barrierLocalIdInBattle", barrierLocalIdInBattle), zap.Any("polygon2D.Anchor", polygon2D.Anchor), zap.Any("polygon2D.Points", polygon2D.Points)) Logger.Info("ChooseStage printing polygon2D for barrierPolygon2DList", zap.Any("barrierLocalIdInBattle", barrierLocalIdInBattle), zap.Any("polygon2D.Anchor", polygon2D.Anchor), zap.Any("polygon2D.Points", polygon2D.Points))
*/ */
pR.Barriers[barrierLocalIdInBattle] = &Barrier{ pR.Barriers[barrierLocalIdInBattle] = &Barrier{
X: polygon2D.Anchor.X,
Y: polygon2D.Anchor.Y,
Boundary: polygon2D, Boundary: polygon2D,
} }
@ -416,7 +416,7 @@ func (pR *Room) StartBattle() {
*/ */
continue continue
} }
pR.sendSafely(kickoffFrame, playerId) pR.sendSafely(&kickoffFrame, nil, DOWNSYNC_MSG_ACT_ROOM_FRAME, playerId)
} }
} }
@ -481,19 +481,12 @@ func (pR *Room) StartBattle() {
var joinMask uint64 = (1 << indiceInJoinIndexBooleanArr) var joinMask uint64 = (1 << indiceInJoinIndexBooleanArr)
if 0 < (unconfirmedMask & joinMask) { if 0 < (unconfirmedMask & joinMask) {
refRenderFrame := pR.RenderFrameBuffer.GetByFrameId(pR.CurDynamicsRenderFrameId).(*pb.RoomDownsyncFrame) refRenderFrame := pR.RenderFrameBuffer.GetByFrameId(pR.CurDynamicsRenderFrameId).(*pb.RoomDownsyncFrame)
resp := pb.WsResp { pR.sendSafely(refRenderFrame, toSendInputFrames, DOWNSYNC_MSG_ACT_FORCED_RESYNC, playerId)
Ret: int32(Constants.RetCode.Ok),
EchoedMsgId: int32(0),
Act: DOWNSYNC_MSG_ACT_ROOM_FRAME,
InputFrameDownsyncBatch: toSendInputFrames,
Rdf: refRenderFrame,
}
pR.sendSafely(resp, playerId)
} else { } else {
if 0 >= len(toSendInputFrames) { if 0 >= len(toSendInputFrames) {
continue continue
} }
pR.sendSafely(toSendInputFrames, playerId) pR.sendSafely(nil, toSendInputFrames, DOWNSYNC_MSG_ACT_INPUT_BATCH, playerId)
atomic.StoreInt32(&(pR.Players[playerId].LastSentInputFrameId), candidateToSendInputFrameId-1) atomic.StoreInt32(&(pR.Players[playerId].LastSentInputFrameId), candidateToSendInputFrameId-1)
if -1 != debugSendingInputFrameId { if -1 != debugSendingInputFrameId {
Logger.Info("inputFrame lifecycle#4[sent]:", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("playerAckingInputFrameId", player.AckingInputFrameId), zap.Any("inputFrameId", debugSendingInputFrameId), zap.Any("AllPlayerInputsBuffer", pR.AllPlayerInputsBufferString())) Logger.Info("inputFrame lifecycle#4[sent]:", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("playerAckingInputFrameId", player.AckingInputFrameId), zap.Any("inputFrameId", debugSendingInputFrameId), zap.Any("AllPlayerInputsBuffer", pR.AllPlayerInputsBufferString()))
@ -644,7 +637,7 @@ func (pR *Room) StopBattleForSettlement() {
SentAt: utils.UnixtimeMilli(), SentAt: utils.UnixtimeMilli(),
CountdownNanos: -1, // TODO: Replace this magic constant! CountdownNanos: -1, // TODO: Replace this magic constant!
} }
pR.sendSafely(assembledFrame, playerId) pR.sendSafely(&assembledFrame, nil, DOWNSYNC_MSG_ACT_ROOM_FRAME, playerId)
} }
// Note that `pR.onBattleStoppedForSettlement` will be called by `battleMainLoop`. // Note that `pR.onBattleStoppedForSettlement` will be called by `battleMainLoop`.
} }
@ -687,7 +680,7 @@ func (pR *Room) onBattlePrepare(cb BattleStartCbType) {
Logger.Info("Sending out frame for RoomBattleState.PREPARE ", zap.Any("battleReadyToStartFrame", battleReadyToStartFrame)) Logger.Info("Sending out frame for RoomBattleState.PREPARE ", zap.Any("battleReadyToStartFrame", battleReadyToStartFrame))
for _, player := range pR.Players { for _, player := range pR.Players {
pR.sendSafely(battleReadyToStartFrame, player.Id) pR.sendSafely(&battleReadyToStartFrame, nil, DOWNSYNC_MSG_ACT_ROOM_FRAME, player.Id)
} }
battlePreparationNanos := int64(6000000000) battlePreparationNanos := int64(6000000000)
@ -950,7 +943,7 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
By making use of the sequential nature of each ws session, all later "RoomDownsyncFrame"s generated after `pRoom.StartBattle()` will be put behind this `playerAckedFrame`. By making use of the sequential nature of each ws session, all later "RoomDownsyncFrame"s generated after `pRoom.StartBattle()` will be put behind this `playerAckedFrame`.
*/ */
pR.sendSafely(playerAckedFrame, player.Id) pR.sendSafely(&playerAckedFrame, nil, DOWNSYNC_MSG_ACT_ROOM_FRAME, player.Id)
} }
pPlayer.BattleState = PlayerBattleStateIns.ACTIVE pPlayer.BattleState = PlayerBattleStateIns.ACTIVE
@ -974,38 +967,19 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
return true return true
} }
func (pR *Room) sendSafely(s interface{}, playerId int32) { func (pR *Room) sendSafely(roomDownsyncFrame *pb.RoomDownsyncFrame, toSendFrames []*pb.InputFrameDownsync, act int32, playerId int32) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
pR.PlayerSignalToCloseDict[playerId](Constants.RetCode.UnknownError, fmt.Sprintf("%v", r)) pR.PlayerSignalToCloseDict[playerId](Constants.RetCode.UnknownError, fmt.Sprintf("%v", r))
} }
}() }()
var pResp *pb.WsResp = nil pResp := &pb.WsResp{
switch v := s.(type) {
case pb.WsResp:
resp := s.(pb.WsResp)
pResp = &resp
case pb.RoomDownsyncFrame:
roomDownsyncFrame := s.(pb.RoomDownsyncFrame)
pResp = &pb.WsResp{
Ret: int32(Constants.RetCode.Ok), Ret: int32(Constants.RetCode.Ok),
EchoedMsgId: int32(0), Act: act,
Act: DOWNSYNC_MSG_ACT_ROOM_FRAME, Rdf: roomDownsyncFrame,
Rdf: &roomDownsyncFrame,
}
case []*pb.InputFrameDownsync:
toSendFrames := s.([]*pb.InputFrameDownsync)
pResp = &pb.WsResp{
Ret: int32(Constants.RetCode.Ok),
EchoedMsgId: int32(0),
Act: DOWNSYNC_MSG_ACT_INPUT_BATCH,
InputFrameDownsyncBatch: toSendFrames, InputFrameDownsyncBatch: toSendFrames,
} }
default:
panic(fmt.Sprintf("Unknown downsync message type, roomId=%v, playerId=%v, roomState=%v, v=%v", pR.Id, playerId, v))
}
theBytes, marshalErr := proto.Marshal(pResp) theBytes, marshalErr := proto.Marshal(pResp)
if nil != marshalErr { if nil != marshalErr {
@ -1151,8 +1125,44 @@ func (pR *Room) inputFrameIdDebuggable(inputFrameId int32) bool {
} }
func (pR *Room) refreshColliders() { func (pR *Room) refreshColliders() {
// Kindly note that by now, we've already got all the shapes in the tmx file into "pR.(Players | Barriers)" from "ParseTmxLayersAndGroups"
space := resolv.NewSpace(int(pR.StageDiscreteW), int(pR.StageDiscreteH), int(pR.StageTileW), int(pR.StageTileH)) // allocate a new collision space everytime after a battle is settled
for _, player := range pR.Players { for _, player := range pR.Players {
playerCollider := resolv.NewObject(player.X, player.Y, 12, 12) // Radius=12 is hardcoded
playerColliderShape := resolv.NewCircle(player.X, player.Y, 12)
playerCollider.SetShape(playerColliderShape)
space.Add(playerCollider)
// Keep track of the collider in "pR.CollisionSysMap"
joinIndex := player.JoinIndex joinIndex := player.JoinIndex
pR.PlayersArr[joinIndex-1] = player pR.PlayersArr[joinIndex-1] = player
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
pR.CollisionSysMap[collisionPlayerIndex] = playerCollider
}
for _, barrier := range pR.Barriers {
var w float64 = 0
var h float64 = 0
for i, pi := range barrier.Boundary.Points {
for j, pj := range barrier.Boundary.Points {
if i == j {
continue
}
if math.Abs(pj.X - pi.X) > w {
w = math.Abs(pj.X - pi.X)
}
if math.Abs(pj.Y - pi.Y) > h {
h = math.Abs(pj.Y - pi.Y)
}
}
}
barrierColliderShape := resolv.NewConvexPolygon()
for _, p := range barrier.Boundary.Points {
barrierColliderShape.AddPoints(p.X+barrier.Boundary.Anchor.X, p.Y+barrier.Boundary.Anchor.Y)
}
barrierCollider := resolv.NewObject(barrier.Boundary.Anchor.X, barrier.Boundary.Anchor.Y, w, h, "Barrier")
barrierCollider.SetShape(barrierColliderShape)
space.Add(barrierCollider)
} }
} }

View File

@ -222,11 +222,14 @@ cc.Class({
shouldSendInputFrameUpsyncBatch(prevSelfInput, currSelfInput, lastUpsyncInputFrameId, currInputFrameId) { shouldSendInputFrameUpsyncBatch(prevSelfInput, currSelfInput, lastUpsyncInputFrameId, currInputFrameId) {
/* /*
For a 2-player-battle, this "shouldUpsyncForEarlyAllConfirmedOnServer" can be omitted, however for more players in a same battle, to avoid a "long time non-moving player" jamming the downsync of other moving players, we should use this flag. For a 2-player-battle, this "shouldUpsyncForEarlyAllConfirmedOnBackend" can be omitted, however for more players in a same battle, to avoid a "long time non-moving player" jamming the downsync of other moving players, we should use this flag.
When backend implements the "force confirmation" feature, we can have "false == shouldUpsyncForEarlyAllConfirmedOnBackend" all the time as well!
*/ */
if (null == currSelfInput) return false; if (null == currSelfInput) return false;
const shouldUpsyncForEarlyAllConfirmedOnServer = (currInputFrameId - lastUpsyncInputFrameId >= this.inputFrameUpsyncDelayTolerance);
return shouldUpsyncForEarlyAllConfirmedOnServer || (prevSelfInput != currSelfInput); const shouldUpsyncForEarlyAllConfirmedOnBackend = (currInputFrameId - lastUpsyncInputFrameId >= this.inputFrameUpsyncDelayTolerance);
return shouldUpsyncForEarlyAllConfirmedOnBackend || (prevSelfInput != currSelfInput);
}, },
sendInputFrameUpsyncBatch(inputFrameId) { sendInputFrameUpsyncBatch(inputFrameId) {
@ -562,14 +565,11 @@ cc.Class({
self.onBattleReadyToStart(rdf.playerMetas, false); self.onBattleReadyToStart(rdf.playerMetas, false);
return; return;
case window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.BATTLE_START: case window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.BATTLE_START:
self.onBattleStarted(rdf); self.onBattleStartedOrResynced(rdf);
return; return;
case window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.PLAYER_READDED_AND_ACKED: case window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.PLAYER_READDED_AND_ACKED:
// [WARNING] The "frameId" from server could be quite fast-forwarding, don't assign it in other cases.
self.renderFrameId = frameId;
self.lastAllConfirmedRenderFrameId = frameId;
self.onBattleReadyToStart(rdf.playerMetas, true); self.onBattleReadyToStart(rdf.playerMetas, true);
self.onBattleStarted(rdf); self.onBattleStartedOrResynced(rdf);
return; return;
} }
@ -689,10 +689,14 @@ cc.Class({
this._inputControlEnabled = false; this._inputControlEnabled = false;
}, },
onBattleStarted(rdf) { onBattleStartedOrResynced(rdf) {
// This function is also applicable to "re-joining". // This function is also applicable to "re-joining".
console.log('On battle started!'); console.log('On battle started or resynced! renderFrameId=', rdf.id);
const self = window.mapIns; const self = window.mapIns;
self.renderFrameId = rdf.id;
self.lastAllConfirmedRenderFrameId = rdf.id;
self.chaserRenderFrameId = rdf.id;
const players = rdf.players; const players = rdf.players;
const playerMetas = rdf.playerMetas; const playerMetas = rdf.playerMetas;
self._initPlayerRichInfoDict(players, playerMetas); self._initPlayerRichInfoDict(players, playerMetas);
@ -717,7 +721,6 @@ cc.Class({
self.countdownToBeginGameNode.parent.removeChild(self.countdownToBeginGameNode); self.countdownToBeginGameNode.parent.removeChild(self.countdownToBeginGameNode);
} }
self.transitToState(ALL_MAP_STATES.VISUAL); self.transitToState(ALL_MAP_STATES.VISUAL);
self.chaserRenderFrameId = rdf.id;
self.applyRoomDownsyncFrameDynamics(rdf); self.applyRoomDownsyncFrameDynamics(rdf);
self._dumpToRenderCache(rdf); self._dumpToRenderCache(rdf);
self.battleState = ALL_BATTLE_STATES.IN_BATTLE; // Starts the increment of "self.renderFrameId" in "self.update(dt)" self.battleState = ALL_BATTLE_STATES.IN_BATTLE; // Starts the increment of "self.renderFrameId" in "self.update(dt)"

View File

@ -5,6 +5,7 @@ window.UPSYNC_MSG_ACT_PLAYER_COLLIDER_ACK = 3;
window.DOWNSYNC_MSG_ACT_HB_REQ = 1; window.DOWNSYNC_MSG_ACT_HB_REQ = 1;
window.DOWNSYNC_MSG_ACT_INPUT_BATCH = 2; window.DOWNSYNC_MSG_ACT_INPUT_BATCH = 2;
window.DOWNSYNC_MSG_ACT_ROOM_FRAME = 3; window.DOWNSYNC_MSG_ACT_ROOM_FRAME = 3;
window.DOWNSYNC_MSG_ACT_FORCED_RESYNC = 4;
window.sendSafely = function(msgStr) { window.sendSafely = function(msgStr) {
/** /**
@ -163,6 +164,13 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
window.handleInputFrameDownsyncBatch(resp.inputFrameDownsyncBatch); window.handleInputFrameDownsyncBatch(resp.inputFrameDownsyncBatch);
} }
break; break;
case window.DOWNSYNC_MSG_ACT_FORCED_RESYNC:
if (window.handleInputFrameDownsyncBatch && window.handleRoomDownsyncFrame) {
// 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);
}
break;
default: default:
break; break;
} }