Updated documentation.

This commit is contained in:
genxium
2022-10-03 11:42:19 +08:00
parent 9d9bea21ef
commit 09b12c5b16
11 changed files with 180 additions and 177 deletions

View File

@@ -547,20 +547,23 @@ cc.Class({
this._inputControlEnabled = false;
},
onBattleStartedOrResynced(rdf) {
onRoomDownsyncFrame(rdf) {
// This function is also applicable to "re-joining".
const self = window.mapIns;
if (rdf.id < self.lastAllConfirmedRenderFrameId) {
return window.RING_BUFF_FAILED_TO_SET;
}
const dumpRenderCacheRet = self.dumpToRenderCache(rdf);
if (window.RING_BUFF_FAILED_TO_SET == dumpRenderCacheRet) {
console.error("Something is wrong while setting the RingBuffer by frameId!");
return dumpRenderCacheRet;
}
if (window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.BATTLE_START < rdf.id && window.RING_BUFF_CONSECUTIVE_SET == dumpRenderCacheRet) {
if (rdf.id < self.chaserRenderFrameId) {
// This "rdf.id = backend.refRenderFrameId" could be small, see comments around "room.go".
self.chaserRenderFrameId = rdf.id;
}
// In this case, we'll also got proper all-confirmed inputFrames for advancing the renderFrames in the coming "update(dt)"
/*
Don't change
- lastAllConfirmedRenderFrameId, it's updated only in "rollbackAndChase > _createRoomDownsyncFrameLocally" (except for when RING_BUFF_NON_CONSECUTIVE_SET)
- chaserRenderFrameId, it's updated only in "onInputFrameDownsyncBatch" (except for when RING_BUFF_NON_CONSECUTIVE_SET)
*/
return dumpRenderCacheRet;
}
@@ -569,6 +572,7 @@ cc.Class({
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;
@@ -623,6 +627,9 @@ cc.Class({
for (let k in batch) {
const inputFrameDownsync = batch[k];
const inputFrameDownsyncId = inputFrameDownsync.inputFrameId;
if (inputFrameDownsyncId < self.lastAllConfirmedInputFrameId) {
continue;
}
if (window.RING_BUFF_NON_CONSECUTIVE_SET == dumpRenderCacheRet) {
// Deliberately left blank, in this case "chaserRenderFrameId" is already reset to proper value.
} else {
@@ -767,8 +774,9 @@ cc.Class({
// Use "fractional-frame-chasing" to guarantee that "self.update(dt)" is not jammed by a "large range of frame-chasing". See `<proj-root>/ConcerningEdgeCases.md` for the motivation.
const prevChaserRenderFrameId = self.chaserRenderFrameId;
let nextChaserRenderFrameId = (prevChaserRenderFrameId + self.maxChasingRenderFramesPerUpdate);
if (nextChaserRenderFrameId > self.renderFrameId)
if (nextChaserRenderFrameId > self.renderFrameId) {
nextChaserRenderFrameId = self.renderFrameId;
}
self.rollbackAndChase(prevChaserRenderFrameId, nextChaserRenderFrameId, self.chaserCollisionSys, self.chaserCollisionSysMap);
self.chaserRenderFrameId = nextChaserRenderFrameId; // Move the cursor "self.chaserRenderFrameId", keep in mind that "self.chaserRenderFrameId" is not monotonic!
let t2 = performance.now();
@@ -975,29 +983,27 @@ cc.Class({
},
rollbackAndChase(renderFrameIdSt, renderFrameIdEd, collisionSys, collisionSysMap) {
if (renderFrameIdSt >= renderFrameIdEd) {
return;
}
const self = this;
const renderFrameSt = self.recentRenderCache.getByFrameId(renderFrameIdSt); // typed "RoomDownsyncFrame"
if (null == renderFrameSt) {
let latestRdf = self.recentRenderCache.getByFrameId(renderFrameIdSt); // typed "RoomDownsyncFrame"
if (null == latestRdf) {
console.error("Couldn't find renderFrameId=", renderFrameIdSt, " to rollback, lastAllConfirmedRenderFrameId=", self.lastAllConfirmedRenderFrameId, ", lastAllConfirmedInputFrameId=", self.lastAllConfirmedInputFrameId, ", recentRenderCache=", self._stringifyRecentRenderCache(false), ", recentInputCache=", self._stringifyRecentInputCache(false));
}
if (renderFrameIdSt >= renderFrameIdEd) {
return latestRdf;
}
/*
Reset "position" of players in "collisionSys" according to "renderFrameSt". The easy part is that we don't have path-dependent-integrals to worry about like that of thermal dynamics.
Reset "position" of players in "collisionSys" according to "renderFrameIdSt". The easy part is that we don't have path-dependent-integrals to worry about like that of thermal dynamics.
*/
self.playerRichInfoDict.forEach((playerRichInfo, playerId) => {
const joinIndex = playerRichInfo.joinIndex;
const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex;
const playerCollider = collisionSysMap.get(collisionPlayerIndex);
const player = renderFrameSt.players[playerId];
const player = latestRdf.players[playerId];
playerCollider.x = player.x;
playerCollider.y = player.y;
});
// [WARNING] Traverse in the order of joinIndices to guarantee determinism.
/*
This function eventually calculates a "RoomDownsyncFrame" where "RoomDownsyncFrame.id == renderFrameIdEd".
*/
@@ -1009,6 +1015,7 @@ cc.Class({
console.error("Failed to get cached inputFrameDownsync for renderFrameId=", i, ", inputFrameId=", j, "lastAllConfirmedRenderFrameId=", self.lastAllConfirmedRenderFrameId, ", lastAllConfirmedInputFrameId=", self.lastAllConfirmedInputFrameId, ", recentRenderCache=", self._stringifyRecentRenderCache(false), ", recentInputCache=", self._stringifyRecentInputCache(false));
}
const inputList = inputFrameDownsync.inputList;
// [WARNING] Traverse in the order of joinIndices to guarantee determinism.
for (let j in self.playerRichInfoArr) {
const joinIndex = parseInt(j) + 1;
const playerId = self.playerRichInfoArr[j].id;
@@ -1038,9 +1045,11 @@ cc.Class({
playerCollider.y -= result.overlap * result.overlap_y;
}
}
latestRdf = self._createRoomDownsyncFrameLocally(i+1, collisionSys, collisionSysMap);
}
return self._createRoomDownsyncFrameLocally(renderFrameIdEd, collisionSys, collisionSysMap);
return latestRdf;
},
_initPlayerRichInfoDict(players, playerMetas) {

View File

@@ -68,7 +68,7 @@ RingBuffer.prototype.getByFrameId = function(frameId) {
// [WARNING] During a battle, frontend could receive non-consecutive frames (either renderFrame or inputFrame) due to resync, the buffer should handle these frames properly.
RingBuffer.prototype.setByFrameId = function(item, frameId) {
if (frameId < this.stFrameId) {
console.error("Invalid putByFrameId#1: stFrameId=", stFrameId, ", edFrameId=", edFrameId, ", incoming item=", item);
console.error("Invalid putByFrameId#1: stFrameId=", this.stFrameId, ", edFrameId=", this.edFrameId, ", incoming item=", item);
return window.RING_BUFF_FAILED_TO_SET;
}
const arrIdx = this.getArrIdxByOffset(frameId - this.stFrameId);

View File

@@ -171,7 +171,7 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
mapIns.onBattleReadyToStart(resp.rdf.playerMetas, false);
break;
case window.DOWNSYNC_MSG_ACT_BATTLE_START:
mapIns.onBattleStartedOrResynced(resp.rdf);
mapIns.onRoomDownsyncFrame(resp.rdf);
break;
case window.DOWNSYNC_MSG_ACT_BATTLE_STOPPED:
mapIns.onBattleStopped();
@@ -180,9 +180,9 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
mapIns.onInputFrameDownsyncBatch(resp.inputFrameDownsyncBatch);
break;
case window.DOWNSYNC_MSG_ACT_FORCED_RESYNC:
console.warn("Got forced resync:", JSON.stringify(resp), " @localRenderFrameId=", mapIns.renderFrameId, ", @localRecentInputCache=", mapIns._stringifyRecentInputCache(false));
console.warn("Got forced resync@localRenderFrameId=", mapIns.renderFrameId, ", @lastAllConfirmedRenderFrameId=", mapIns.lastAllConfirmedRenderFrameId, "@lastAllConfirmedInputFrameId=", mapIns.lastAllConfirmedInputFrameId, ", @localRecentInputCache=", mapIns._stringifyRecentInputCache(false), ", the incoming resp=\n", JSON.stringify(resp));
// The following order of execution is important, because "onInputFrameDownsyncBatch" is only available when state is IN_BATTLE
const dumpRenderCacheRet = mapIns.onBattleStartedOrResynced(resp.rdf);
const dumpRenderCacheRet = mapIns.onRoomDownsyncFrame(resp.rdf);
mapIns.onInputFrameDownsyncBatch(resp.inputFrameDownsyncBatch, dumpRenderCacheRet);
break;
default: