|
|
|
@@ -128,7 +128,7 @@ type Room struct {
|
|
|
|
|
EffectivePlayerCount int32
|
|
|
|
|
DismissalWaitGroup sync.WaitGroup
|
|
|
|
|
InputsBuffer *battle.RingBuffer // Indices are STRICTLY consecutive
|
|
|
|
|
InputsBufferLock sync.Mutex // Guards [InputsBuffer, LatestPlayerUpsyncedInputFrameId, LastAllConfirmedInputFrameId, LastAllConfirmedInputList, LastAllConfirmedInputFrameIdWithChange]
|
|
|
|
|
InputsBufferLock sync.Mutex // Guards [InputsBuffer, LatestPlayerUpsyncedInputFrameId, LastAllConfirmedInputFrameId, LastAllConfirmedInputList, LastAllConfirmedInputFrameIdWithChange, LastIndividuallyConfirmedInputList, player.LastReceivedInputFrameId]
|
|
|
|
|
RenderFrameBuffer *battle.RingBuffer // Indices are STRICTLY consecutive
|
|
|
|
|
LatestPlayerUpsyncedInputFrameId int32
|
|
|
|
|
LastAllConfirmedInputFrameId int32
|
|
|
|
@@ -148,7 +148,8 @@ type Room struct {
|
|
|
|
|
TmxPointsMap StrToVec2DListMap
|
|
|
|
|
TmxPolygonsMap StrToPolygon2DListMap
|
|
|
|
|
|
|
|
|
|
rdfIdToActuallyUsedInput map[int32]*pb.InputFrameDownsync
|
|
|
|
|
rdfIdToActuallyUsedInput map[int32]*pb.InputFrameDownsync
|
|
|
|
|
LastIndividuallyConfirmedInputList []uint64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (pR *Room) updateScore() {
|
|
|
|
@@ -172,6 +173,7 @@ func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, session *websocke
|
|
|
|
|
pPlayerFromDbInit.AckingFrameId = -1
|
|
|
|
|
pPlayerFromDbInit.AckingInputFrameId = -1
|
|
|
|
|
pPlayerFromDbInit.LastSentInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED
|
|
|
|
|
pPlayerFromDbInit.LastReceivedInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED
|
|
|
|
|
pPlayerFromDbInit.BattleState = PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK
|
|
|
|
|
|
|
|
|
|
pPlayerFromDbInit.ColliderRadius = DEFAULT_PLAYER_RADIUS // Hardcoded
|
|
|
|
@@ -740,6 +742,7 @@ func (pR *Room) OnDismissed() {
|
|
|
|
|
pR.RenderFrameBuffer = battle.NewRingBuffer(pR.RenderCacheSize)
|
|
|
|
|
pR.InputsBuffer = battle.NewRingBuffer((pR.RenderCacheSize >> 1) + 1)
|
|
|
|
|
pR.rdfIdToActuallyUsedInput = make(map[int32]*pb.InputFrameDownsync)
|
|
|
|
|
pR.LastIndividuallyConfirmedInputList = make([]uint64, pR.Capacity)
|
|
|
|
|
|
|
|
|
|
pR.LatestPlayerUpsyncedInputFrameId = -1
|
|
|
|
|
pR.LastAllConfirmedInputFrameId = -1
|
|
|
|
@@ -1016,12 +1019,7 @@ func (pR *Room) sendSafely(roomDownsyncFrame *pb.RoomDownsyncFrame, toSendInputF
|
|
|
|
|
func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *battle.InputFrameDownsync {
|
|
|
|
|
/*
|
|
|
|
|
[WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked.
|
|
|
|
|
|
|
|
|
|
Kindly note that on backend the prefab is much simpler than its frontend counterpart, because frontend will upsync its latest command immediately if there's any change w.r.t. its own prev cmd, thus if no upsync received from a frontend,
|
|
|
|
|
- EITHER it's due to local lag and bad network,
|
|
|
|
|
- OR there's no change w.r.t. to its prev cmd.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var currInputFrameDownsync *battle.InputFrameDownsync = nil
|
|
|
|
|
tmp1 := pR.InputsBuffer.GetByFrameId(inputFrameId) // Would be nil if "pR.InputsBuffer.EdFrameId <= inputFrameId", else if "pR.InputsBuffer.EdFrameId > inputFrameId" is already met, then by now we can just return "tmp1.(*InputFrameDownsync)"
|
|
|
|
|
if nil == tmp1 {
|
|
|
|
@@ -1033,18 +1031,26 @@ func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *battle.InputF
|
|
|
|
|
ConfirmedList: uint64(0),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
j2 := j - 1
|
|
|
|
|
tmp2 := pR.InputsBuffer.GetByFrameId(j2)
|
|
|
|
|
if nil != tmp2 {
|
|
|
|
|
prevInputFrameDownsync := tmp2.(*battle.InputFrameDownsync)
|
|
|
|
|
for i, _ := range currInputFrameDownsync.InputList {
|
|
|
|
|
currInputFrameDownsync.InputList[i] = prevInputFrameDownsync.InputList[i]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
[WARNING] Don't reference "pR.InputsBuffer.GetByFrameId(j-1)" to prefab here!
|
|
|
|
|
|
|
|
|
|
Otherwise if an ActiveSlowTicker got a forced confirmation sequence like
|
|
|
|
|
```
|
|
|
|
|
inputFrame#42 {dx: -2} upsynced;
|
|
|
|
|
inputFrame#43-50 {dx: +2} ignored by [type#1 forceConfirmation];
|
|
|
|
|
inputFrame#51 {dx: +2} upsynced;
|
|
|
|
|
inputFrame#52-60 {dx: +2} ignored by [type#1 forceConfirmation];
|
|
|
|
|
inputFrame#61 {dx: +2} upsynced;
|
|
|
|
|
|
|
|
|
|
...there would be more [type#1 forceConfirmation]s for this ActiveSlowTicker if it doesn't catch up the upsync pace...
|
|
|
|
|
```
|
|
|
|
|
, the backend might've been prefabbing TOO QUICKLY and thus still replicating "inputFrame#42" by now for this ActiveSlowTicker, making its graphics inconsistent upon "[type#1 forceConfirmation] at inputFrame#52-60", i.e. as if always dragged to the left while having been controlled to the right for a few frames -- what's worse, the same graphical inconsistence could even impact later "[type#1 forceConfirmation]s" if this ActiveSlowTicker doesn't catch up with the upsync pace!
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for i, _ := range currInputFrameDownsync.InputList {
|
|
|
|
|
// [WARNING] The use of "InputsBufferLock" guarantees that by now "inputFrameId >= pR.InputsBuffer.EdFrameId >= pR.LatestPlayerUpsyncedInputFrameId", thus it's safe to use "pR.LastIndividuallyConfirmedInputList" for prediction.
|
|
|
|
|
// Don't predict "btnA & btnB"!
|
|
|
|
|
currInputFrameDownsync.InputList[i] = (currInputFrameDownsync.InputList[i] & uint64(15))
|
|
|
|
|
currInputFrameDownsync.InputList[i] = (pR.LastIndividuallyConfirmedInputList[i] & uint64(15))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pR.InputsBuffer.Put(currInputFrameDownsync)
|
|
|
|
@@ -1066,8 +1072,8 @@ func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*pb.InputFr
|
|
|
|
|
Logger.Debug(fmt.Sprintf("Omitting obsolete inputFrameUpsync#1: roomId=%v, playerId=%v, clientInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.InputsBufferString(false)))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if clientInputFrameId < pR.LastAllConfirmedInputFrameId {
|
|
|
|
|
Logger.Debug(fmt.Sprintf("Omitting obsolete inputFrameUpsync#2: roomId=%v, playerId=%v, clientInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.InputsBufferString(false)))
|
|
|
|
|
if clientInputFrameId < player.LastReceivedInputFrameId {
|
|
|
|
|
Logger.Debug(fmt.Sprintf("Omitting obsolete inputFrameUpsync#2: roomId=%v, playerId=%v, clientInputFrameId=%v, playerLastReceivedInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, player.LastReceivedInputFrameId, pR.InputsBufferString(false)))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if clientInputFrameId > pR.InputsBuffer.EdFrameId {
|
|
|
|
@@ -1079,6 +1085,9 @@ func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*pb.InputFr
|
|
|
|
|
targetInputFrameDownsync.InputList[player.JoinIndex-1] = inputFrameUpsync.Encoded
|
|
|
|
|
targetInputFrameDownsync.ConfirmedList |= uint64(1 << uint32(player.JoinIndex-1))
|
|
|
|
|
|
|
|
|
|
player.LastReceivedInputFrameId = clientInputFrameId
|
|
|
|
|
pR.LastIndividuallyConfirmedInputList[player.JoinIndex-1] = inputFrameUpsync.Encoded
|
|
|
|
|
|
|
|
|
|
if clientInputFrameId > pR.LatestPlayerUpsyncedInputFrameId {
|
|
|
|
|
pR.LatestPlayerUpsyncedInputFrameId = clientInputFrameId
|
|
|
|
|
}
|
|
|
|
|