Fixes for frontend rollback field access.

This commit is contained in:
genxium 2022-12-26 12:27:05 +08:00
parent a85c6f9ad8
commit bc8eab8115
3 changed files with 38 additions and 13 deletions

View File

@ -10,9 +10,12 @@ func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame
return nil return nil
} }
ret := &pb.RoomDownsyncFrame{ ret := &pb.RoomDownsyncFrame{
Id: rdf.Id, Id: rdf.Id,
PlayersArr: make([]*pb.PlayerDownsync, len(rdf.PlayersArr), len(rdf.PlayersArr)), PlayersArr: make([]*pb.PlayerDownsync, len(rdf.PlayersArr), len(rdf.PlayersArr)),
MeleeBullets: make([]*pb.MeleeBullet, len(rdf.MeleeBullets), len(rdf.MeleeBullets)), MeleeBullets: make([]*pb.MeleeBullet, len(rdf.MeleeBullets), len(rdf.MeleeBullets)),
CountdownNanos: rdf.CountdownNanos,
BackendUnconfirmedMask: rdf.BackendUnconfirmedMask,
ShouldForceResync: rdf.ShouldForceResync,
} }
for i, last := range rdf.PlayersArr { for i, last := range rdf.PlayersArr {

View File

@ -1160,7 +1160,7 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) uint64 {
pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, -1) pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, -1)
} }
if 0 < unconfirmedMask { if 0 < unconfirmedMask {
Logger.Debug(fmt.Sprintf("[type#1 forceConfirmation] For roomId=%d@renderFrameId=%d, curDynamicsRenderFrameId=%d, LatestPlayerUpsyncedInputFrameId:%d, LastAllConfirmedInputFrameId:%d, (pR.NstDelayFrames >> pR.InputScaleFrames):%d, InputFrameUpsyncDelayTolerance:%d, unconfirmedMask=%d; there's a slow ticker suspect, forcing all-confirmation", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LatestPlayerUpsyncedInputFrameId, oldLastAllConfirmedInputFrameId, (pR.NstDelayFrames >> pR.InputScaleFrames), pR.InputFrameUpsyncDelayTolerance, unconfirmedMask)) Logger.Info(fmt.Sprintf("[type#1 forceConfirmation] For roomId=%d@renderFrameId=%d, curDynamicsRenderFrameId=%d, LatestPlayerUpsyncedInputFrameId:%d, oldLastAllConfirmedInputFrameId:%d, newLastAllConfirmedInputFrameId:%d, (pR.NstDelayFrames >> pR.InputScaleFrames):%d, InputFrameUpsyncDelayTolerance:%d, unconfirmedMask=%d; there's a slow ticker suspect, forcing all-confirmation", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LatestPlayerUpsyncedInputFrameId, oldLastAllConfirmedInputFrameId, pR.LastAllConfirmedInputFrameId, (pR.NstDelayFrames >> pR.InputScaleFrames), pR.InputFrameUpsyncDelayTolerance, unconfirmedMask))
} }
} else { } else {
// Type#2 helps resolve the edge case when all players are disconnected temporarily // Type#2 helps resolve the edge case when all players are disconnected temporarily

View File

@ -605,7 +605,7 @@ cc.Class({
} }
const shouldForceDumping1 = (window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.BATTLE_START == rdf.Id); const shouldForceDumping1 = (window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.BATTLE_START == rdf.Id);
let shouldForceDumping2 = (rdf.Id >= self.renderFrameId + self.renderFrameIdLagTolerance); let shouldForceDumping2 = (rdf.Id >= self.renderFrameId + self.renderFrameIdLagTolerance);
let shouldForceResync = rdf.ShouldForceResync; let shouldForceResync = pbRdf.ShouldForceResync;
const notSelfUnconfirmed = (0 == (rdf.BackendUnconfirmedMask & (1 << (self.selfPlayerInfo.joinIndex - 1)))); const notSelfUnconfirmed = (0 == (rdf.BackendUnconfirmedMask & (1 << (self.selfPlayerInfo.joinIndex - 1))));
if (notSelfUnconfirmed) { if (notSelfUnconfirmed) {
shouldForceDumping2 = false; shouldForceDumping2 = false;
@ -618,7 +618,7 @@ cc.Class({
If "BackendUnconfirmedMask" is non-all-1 and contains the current player, show a label/button to hint manual reconnection. Note that the continuity of "recentInputCache" is not a good indicator, because due to network delay upon a [type#1 forceConfirmation] a player might just lag in upsync networking and have all consecutive inputFrameIds locally. If "BackendUnconfirmedMask" is non-all-1 and contains the current player, show a label/button to hint manual reconnection. Note that the continuity of "recentInputCache" is not a good indicator, because due to network delay upon a [type#1 forceConfirmation] a player might just lag in upsync networking and have all consecutive inputFrameIds locally.
*/ */
const [dumpRenderCacheRet, oldStRenderFrameId, oldEdRenderFrameId] = (shouldForceDumping1 || shouldForceDumping2 || shouldForceResync) ? self.recentRenderCache.setByFrameId(rdf, rdf.id) : [window.RING_BUFF_CONSECUTIVE_SET, null, null]; const [dumpRenderCacheRet, oldStRenderFrameId, oldEdRenderFrameId] = (shouldForceDumping1 || shouldForceDumping2 || shouldForceResync) ? self.recentRenderCache.setByFrameId(rdf, rdf.Id) : [window.RING_BUFF_CONSECUTIVE_SET, null, null];
if (window.RING_BUFF_FAILED_TO_SET == dumpRenderCacheRet) { if (window.RING_BUFF_FAILED_TO_SET == dumpRenderCacheRet) {
throw `Failed to dump render cache#1 (maybe recentRenderCache too small)! rdf.id=${rdf.id}, lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}; recentRenderCache=${self._stringifyRecentRenderCache(false)}, recentInputCache=${self._stringifyRecentInputCache(false)}`; throw `Failed to dump render cache#1 (maybe recentRenderCache too small)! rdf.id=${rdf.id}, lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}; recentRenderCache=${self._stringifyRecentRenderCache(false)}, recentInputCache=${self._stringifyRecentInputCache(false)}`;
} }
@ -646,6 +646,8 @@ cc.Class({
if (window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.BATTLE_START == rdf.Id) { if (window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.BATTLE_START == rdf.Id) {
console.log('On battle started! renderFrameId=', rdf.Id); console.log('On battle started! renderFrameId=', rdf.Id);
} else {
console.log('On battle resynced! renderFrameId=', rdf.Id);
} }
self.renderFrameId = rdf.Id; self.renderFrameId = rdf.Id;
self.lastRenderFrameIdTriggeredAt = performance.now(); self.lastRenderFrameIdTriggeredAt = performance.now();
@ -720,6 +722,9 @@ cc.Class({
onInputFrameDownsyncBatch(batch) { onInputFrameDownsyncBatch(batch) {
// TODO: find some kind of synchronization mechanism against "getOrPrefabInputFrameUpsync"! // TODO: find some kind of synchronization mechanism against "getOrPrefabInputFrameUpsync"!
if (null == batch) {
return;
}
const self = this; const self = this;
if (!self.recentInputCache) { if (!self.recentInputCache) {
return; return;
@ -773,7 +778,9 @@ cc.Class({
*/ */
// The actual rollback-and-chase would later be executed in update(dt). // The actual rollback-and-chase would later be executed in update(dt).
console.warn(`Mismatched input detected, resetting chaserRenderFrameId: ${self.chaserRenderFrameId}->${renderFrameId1} by firstPredictedYetIncorrectInputFrameId: ${inputFrameId1} console.warn(`Mismatched input detected, resetting chaserRenderFrameId: ${self.chaserRenderFrameId}->${renderFrameId1} by firstPredictedYetIncorrectInputFrameId: ${inputFrameId1}
lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}`); lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}
recentInputCache=${self._stringifyRecentInputCache(false)}
batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inputFrameId}]`);
self.chaserRenderFrameId = renderFrameId1; self.chaserRenderFrameId = renderFrameId1;
}, },
@ -1104,11 +1111,11 @@ ${self._stringifyRecentInputAndRenderCacheCorrespondingly()}`);
if (true == isChasing) { if (true == isChasing) {
// [WARNING] Move the cursor "self.chaserRenderFrameId" when "true == isChasing", keep in mind that "self.chaserRenderFrameId" is not monotonic! // [WARNING] Move the cursor "self.chaserRenderFrameId" when "true == isChasing", keep in mind that "self.chaserRenderFrameId" is not monotonic!
self.chaserRenderFrameId = nextRdf.id; self.chaserRenderFrameId = nextRdf.Id;
} else if (nextRdf.id == self.chaserRenderFrameId + 1) { } else if (nextRdf.Id == self.chaserRenderFrameId + 1) {
self.chaserRenderFrameId = nextRdf.id; // To avoid redundant calculation self.chaserRenderFrameId = nextRdf.Id; // To avoid redundant calculation
} }
self.recentRenderCache.setByFrameId(nextRdf, nextRdf.id); self.recentRenderCache.setByFrameId(nextRdf, nextRdf.Id);
prevLatestRdf = currRdf; prevLatestRdf = currRdf;
latestRdf = nextRdf; latestRdf = nextRdf;
} }
@ -1158,15 +1165,30 @@ ${self._stringifyRecentInputAndRenderCacheCorrespondingly()}`);
return `[stInputFrameId=${self.recentInputCache.stFrameId}, edInputFrameId=${self.recentInputCache.edFrameId})`; return `[stInputFrameId=${self.recentInputCache.stFrameId}, edInputFrameId=${self.recentInputCache.edFrameId})`;
}, },
_stringifyGopkgRoomDownsyncFrame(rdf) {
let s = [];
s.push(`{`);
s.push(` id: ${rdf.Id}`);
s.push(` players: [`);
for (let k in rdf.PlayersArr) {
const player = rdf.PlayersArr[k];
s.push(` {joinIndex: ${player.JoinIndex}, id: ${player.Id}, vx: ${player.VirtualGridX}, vy: ${player.VirtualGridY}, velX: ${player.VelX}, velY: ${player.VelY}}`);
}
s.push(` ]`);
s.push(`}`);
return s.join("\n");
},
_stringifyRecentRenderCache(usefullOutput) { _stringifyRecentRenderCache(usefullOutput) {
const self = this; const self = this;
if (true == usefullOutput) { if (true == usefullOutput) {
let s = []; let s = [];
for (let i = self.recentRenderCache.stFrameId; i < self.recentRenderCache.edFrameId; ++i) { for (let i = self.recentRenderCache.stFrameId; i < self.recentRenderCache.edFrameId; ++i) {
s.push(JSON.stringify(self.recentRenderCache.getByFrameId(i))); const rdf = self.recentRenderCache.getByFrameId(i);
s.push(self._stringifyGopkgRoomDownsyncFrame(rdf));
} }
return s.join('\n'); return s.join("\n");
} }
return `[stRenderFrameId=${self.recentRenderCache.stFrameId}, edRenderFrameId=${self.recentRenderCache.edFrameId})`; return `[stRenderFrameId=${self.recentRenderCache.stFrameId}, edRenderFrameId=${self.recentRenderCache.edFrameId})`;
}, },