A temp update.

This commit is contained in:
genxium 2022-09-22 12:45:17 +08:00
parent c7d4e387c9
commit f0e624aa85
2 changed files with 54 additions and 69 deletions

View File

@ -440,7 +440,7 @@
"array": [ "array": [
0, 0,
0, 0,
209.73151519075364, 216.05530045313827,
0, 0,
0, 0,
0, 0,

View File

@ -138,25 +138,18 @@ cc.Class({
_dumpToFullFrameCache: function(fullFrame) { _dumpToFullFrameCache: function(fullFrame) {
const self = this; const self = this;
while (self.recentFrameCacheCurrentSize >= self.recentFrameCacheMaxCount) { while (self.recentFrameCacheEd - self.recentFrameCacheSt >= self.recentFrameCacheMaxCount) {
const toDelFrameId = Object.keys(self.recentFrameCache)[0]; delete self.recentFrameCache[self.recentFrameCacheSt++];
delete self.recentFrameCache[toDelFrameId];
--self.recentFrameCacheCurrentSize;
} }
self.recentFrameCache[fullFrame.id] = fullFrame; self.recentFrameCache[self.recentFrameCacheEd++] = fullFrame;
++self.recentFrameCacheCurrentSize;
}, },
_dumpToInputCache: function(inputFrameDownsync) { _dumpToInputCache: function(inputFrameDownsync) {
const self = this; const self = this;
while (self.recentInputCacheCurrentSize >= self.recentInputCacheMaxCount) { while (self.recentInputCacheEd - self.recentInputCacheSt >= self.recentInputCacheMaxCount) {
const toDelFrameId = Object.keys(self.recentInputCache)[0]; delete self.recentInputCache[self.recentInputCacheSt++];
// console.log("Deleting toDelFrameId=", toDelFrameId, " from recentInputCache");
delete self.recentInputCache[toDelFrameId];
--self.recentInputCacheCurrentSize;
} }
self.recentInputCache[inputFrameDownsync.inputFrameId] = inputFrameDownsync; self.recentInputCache[self.recentInputCacheEd++] = inputFrameDownsync;
++self.recentInputCacheCurrentSize;
}, },
_convertToInputFrameId(renderFrameId, inputDelayFrames) { _convertToInputFrameId(renderFrameId, inputDelayFrames) {
@ -184,14 +177,14 @@ cc.Class({
const discreteDir = instance.ctrl.getDiscretizedDirection(); const discreteDir = instance.ctrl.getDiscretizedDirection();
let prefabbedInputList = null; let prefabbedInputList = null;
let selfPlayerLastInputFrameInput = 0; let selfPlayerLastInputFrameInput = 0;
if (0 == instance.lastLocalInputFrameId) { if (0 == instance.recentInputCacheEd) {
prefabbedInputList = new Array(Object.keys(instance.playersNode).length).fill(0); prefabbedInputList = new Array(instance.playerRichInfoDict.size).fill(0);
} else { } else {
if (null == instance.recentInputCache || null == instance.recentInputCache[instance.lastLocalInputFrameId-1]) { if (null == instance.recentInputCache || null == instance.recentInputCache[instance.recentInputCacheEd-1]) {
console.warn("_generateInputFrameUpsync: recentInputCache is NOT having inputFrameId=", instance.lastLocalInputFrameId-1, "; recentInputCache=", instance._stringifyRecentInputCache(false)); console.warn("_generateInputFrameUpsync: recentInputCache is NOT having inputFrameId=", instance.recentInputCacheEd-1, "; recentInputCache=", instance._stringifyRecentInputCache(false));
prefabbedInputList = new Array(Object.keys(instance.playersNode).length).fill(0); prefabbedInputList = new Array(instance.playerRichInfoDict.size).fill(0);
} else { } else {
prefabbedInputList = Array.from(instance.recentInputCache[instance.lastLocalInputFrameId-1].inputList); prefabbedInputList = Array.from(instance.recentInputCache[instance.recentInputCacheEd-1].inputList);
selfPlayerLastInputFrameInput = prefabbedInputList[(instance.selfPlayerInfo.joinIndex-1)]; // it's an integer, thus making a copy here, not impacted by later assignments selfPlayerLastInputFrameInput = prefabbedInputList[(instance.selfPlayerInfo.joinIndex-1)]; // it's an integer, thus making a copy here, not impacted by later assignments
} }
} }
@ -322,32 +315,34 @@ cc.Class({
self.countdownNanos = null; self.countdownNanos = null;
// Clearing previous info of all players. [BEGINS] // Clearing previous info of all players. [BEGINS]
for (let joinIndex in self.playersNode) { if (null != self.playerRichInfoDict) {
const node = self.playersNode[joinIndex]; self.playerRichInfoDict.forEach((playerRichInfo, playerId) => {
if (node.parent) { if (playerRichInfo.node.parent) {
node.parent.removeChild(node); playerRichInfo.node.parent.removeChild(playerRichInfo.node);
} }
});
} }
self.playerRichInfoDict = {}; self.playerRichInfoDict = new Map();
// Clearing previous info of all players. [ENDS] // Clearing previous info of all players. [ENDS]
self.lastRoomDownsyncFrameId = 0; self.lastRoomDownsyncFrameId = 0;
self.renderFrameId = 0; // After battle started self.renderFrameId = 0; // After battle started
self.inputDelayFrames = 8; self.inputDelayFrames = 8;
self.inputScaleFrames = 3; self.inputScaleFrames = 3;
self.lastLocalInputFrameId = 0;
self.lastDownsyncInputFrameId = -1; self.lastDownsyncInputFrameId = -1;
self.lastAllConfirmedInputFrameId = -1; self.lastAllConfirmedInputFrameId = -1;
self.lastUpsyncInputFrameId = -1; self.lastUpsyncInputFrameId = -1;
self.inputFrameUpsyncDelayTolerance = 3; self.inputFrameUpsyncDelayTolerance = 3;
self.recentFrameCache = {}; self.recentFrameCache = {};
self.recentFrameCacheCurrentSize = 0; self.recentFrameCacheSt = 0; // closed index
self.recentFrameCacheEd = 0; // open index
self.recentFrameCacheMaxCount = 1024; self.recentFrameCacheMaxCount = 1024;
self.selfPlayerInfo = null; // This field is kept for distinguishing "self" and "others". self.selfPlayerInfo = null; // This field is kept for distinguishing "self" and "others".
self.recentInputCache = {}; // TODO: Use a ringbuf instead self.recentInputCache = {}; // TODO: Use a ringbuf instead
self.recentInputCacheCurrentSize = 0; self.recentInputCacheSt = 0; // closed index
self.recentInputCacheEd = 0; // open index
self.recentInputCacheMaxCount = 1024; self.recentInputCacheMaxCount = 1024;
self.toRollbackRenderFrameId1 = null; self.toRollbackRenderFrameId1 = null;
self.toRollbackInputFrameId1 = null; self.toRollbackInputFrameId1 = null;
@ -435,16 +430,6 @@ cc.Class({
self.widgetsAboveAllNode = self.mainCameraNode.getChildByName("WidgetsAboveAll"); self.widgetsAboveAllNode = self.mainCameraNode.getChildByName("WidgetsAboveAll");
self.mainCameraNode.setPosition(cc.v2()); self.mainCameraNode.setPosition(cc.v2());
self.playersNode = {};
const player1Node = cc.instantiate(self.player1Prefab);
const player2Node = cc.instantiate(self.player2Prefab);
Object.assign(self.playersNode, {
1: player1Node
});
Object.assign(self.playersNode, {
2: player2Node
});
/** Init required prefab ended. */ /** Init required prefab ended. */
self.clientUpsyncFps = 60; self.clientUpsyncFps = 60;
@ -758,7 +743,7 @@ cc.Class({
spawnPlayerNode(joinIndex, x, y) { spawnPlayerNode(joinIndex, x, y) {
const instance = this; const instance = this;
const newPlayerNode = instance.playersNode[joinIndex]; const newPlayerNode = 1 == joinIndex ? cc.instantiate(instance.player1Prefab) : cc.instantiate(instance.player2Prefab); // hardcoded for now, car color determined solely by joinIndex
newPlayerNode.setPosition(cc.v2(x, y)); newPlayerNode.setPosition(cc.v2(x, y));
newPlayerNode.getComponent("SelfPlayer").mapNode = instance.node; newPlayerNode.getComponent("SelfPlayer").mapNode = instance.node;
@ -775,10 +760,6 @@ cc.Class({
update(dt) { update(dt) {
const self = this; const self = this;
try { try {
let inputs = new Array(Object.keys(self.playersNode).length).fill({
dx: 0,
dy: 0
});
if (ALL_BATTLE_STATES.IN_BATTLE == self.battleState) { if (ALL_BATTLE_STATES.IN_BATTLE == self.battleState) {
let prevSelfInput = null, currSelfInput = null; let prevSelfInput = null, currSelfInput = null;
const noDelayInputFrameId = self._convertToInputFrameId(self.renderFrameId, 0); // It's important that "inputDelayFrames == 0" here const noDelayInputFrameId = self._convertToInputFrameId(self.renderFrameId, 0); // It's important that "inputDelayFrames == 0" here
@ -797,15 +778,13 @@ cc.Class({
if (null != self.toRollbackRenderFrameId1) { if (null != self.toRollbackRenderFrameId1) {
// Rollback-and-replay if necessary, prior to applying the latest dynamics // Rollback-and-replay if necessary, prior to applying the latest dynamics
const anotherJoinIndex = 3-self.selfPlayerInfo.joinIndex; const anotherJoinIndex = 3-self.selfPlayerInfo.joinIndex;
console.log("BEFORE rollback, the other player's position: ", JSON.stringify(self.playersNode[anotherJoinIndex].position));
self._rollbackAndReplay(self.toRollbackInputFrameId1, self.toRollbackRenderFrameId1, delayedInputFrameId, self.renderFrameId); self._rollbackAndReplay(self.toRollbackInputFrameId1, self.toRollbackRenderFrameId1, delayedInputFrameId, self.renderFrameId);
console.log("AFTER rollback, the other player's position: ", JSON.stringify(self.playersNode[anotherJoinIndex].position));
self.toRollbackRenderFrameId1 = null; self.toRollbackRenderFrameId1 = null;
self.toRollbackRenderFrameId2 = null; self.toRollbackRenderFrameId2 = null;
} }
} }
const delayedInputFrameDownsync = self.recentInputCache[delayedInputFrameId]; const delayedInputFrameDownsync = self.assembleInputFrameDownsync(delayedInputFrameId);
if (null == delayedInputFrameDownsync) { if (null == delayedInputFrameDownsync) {
console.warn("update(dt): recentInputCache is NOT having inputFrameId=", delayedInputFrameId, "; recentInputCache=", instance._stringifyRecentInputCache(false)); console.warn("update(dt): recentInputCache is NOT having inputFrameId=", delayedInputFrameId, "; recentInputCache=", instance._stringifyRecentInputCache(false));
} else { } else {
@ -949,9 +928,7 @@ cc.Class({
players: {}, players: {},
countdownNanos: self.countdownNanos countdownNanos: self.countdownNanos
}; };
self.playerRichInfoDict.forEach((playerRichInfo, playerId) => {
for (let playerId in self.playerRichInfoDict) {
const playerRichInfo = self.playerRichInfoDict[playerId];
const joinIndex = playerRichInfo.joinIndex; const joinIndex = playerRichInfo.joinIndex;
const playerNode = playerRichInfo.node; const playerNode = playerRichInfo.node;
const playerScriptIns = playerRichInfo.scriptIns; const playerScriptIns = playerRichInfo.scriptIns;
@ -963,20 +940,33 @@ cc.Class({
speed: playerScriptIns.speed, speed: playerScriptIns.speed,
joinIndex: joinIndex joinIndex: joinIndex
}; };
} });
return rdf; return rdf;
}, },
_applyRoomDownsyncFrameDynamics(rdf) { _applyRoomDownsyncFrameDynamics(rdf) {
const self = this; const self = this;
for (let playerId in self.playerRichInfoDict) { self.playerRichInfoDict.forEach((playerRichInfo, playerId) => {
const playerRichInfo = self.playerRichInfoDict[playerId];
const immediatePlayerInfo = rdf.players[playerId]; const immediatePlayerInfo = rdf.players[playerId];
playerRichInfo.node.setPosition(immediatePlayerInfo.x, immediatePlayerInfo.y); playerRichInfo.node.setPosition(immediatePlayerInfo.x, immediatePlayerInfo.y);
playerRichInfo.scriptIns.scheduleNewDirection(immediatePlayerInfo.dir, true); playerRichInfo.scriptIns.scheduleNewDirection(immediatePlayerInfo.dir, true);
playerRichInfo.scriptIns.updateSpeed(immediatePlayerInfo.speed); playerRichInfo.scriptIns.updateSpeed(immediatePlayerInfo.speed);
});
},
assembleInputFrameDownsync(inputFrameId) {
const self = this;
let inputFrameDownsync = self.recentInputCache[inputFrameId];
if (-1 != self.lastAllConfirmedInputFrameId && inputFrameId > self.lastAllConfirmedInputFrameId) {
const lastAllConfirmedInputFrame = self.recentInputCache[self.lastAllConfirmedInputFrameId];
for (let i = 0; i < inputFrameDownsync.inputList.length; ++i) {
if (i == self.selfPlayerInfo.joinIndex-1) continue;
inputFrameDownsync.inputList[i] = lastAllConfirmedInputFrame.inputList[i];
} }
}
return inputFrameDownsync;
}, },
_applyInputFrameDownsyncDynamics(inputFrameDownsync, invokeUpdateToo) { _applyInputFrameDownsyncDynamics(inputFrameDownsync, invokeUpdateToo) {
@ -984,8 +974,7 @@ cc.Class({
const self = this; const self = this;
const inputs = inputFrameDownsync.inputList; const inputs = inputFrameDownsync.inputList;
// Update controlled player nodes // Update controlled player nodes
for (let playerId in self.playerRichInfoDict) { self.playerRichInfoDict.forEach((playerRichInfo, playerId) => {
const playerRichInfo = self.playerRichInfoDict[playerId];
const joinIndex = playerRichInfo.joinIndex; const joinIndex = playerRichInfo.joinIndex;
const playerScriptIns = playerRichInfo.scriptIns; const playerScriptIns = playerRichInfo.scriptIns;
const decodedInput = self.ctrl.decodeDirection(inputs[joinIndex-1]); const decodedInput = self.ctrl.decodeDirection(inputs[joinIndex-1]);
@ -993,7 +982,7 @@ cc.Class({
if (invokeUpdateToo) { if (invokeUpdateToo) {
playerScriptIns.update(self.rollbackEstimatedDt); playerScriptIns.update(self.rollbackEstimatedDt);
} }
} });
if (invokeUpdateToo) { if (invokeUpdateToo) {
// [WARNING] CocosCreator v2.2.1 uses a singleton "CCDirector" to schedule "tree descendent updates" and "collision detections" in different timers, thus the following manual trigger of collision detection might not produce the same outcome for the "selfPlayer" as the other peers. Moreover, the aforementioned use of different timers is an intrinsic source of error! // [WARNING] CocosCreator v2.2.1 uses a singleton "CCDirector" to schedule "tree descendent updates" and "collision detections" in different timers, thus the following manual trigger of collision detection might not produce the same outcome for the "selfPlayer" as the other peers. Moreover, the aforementioned use of different timers is an intrinsic source of error!
@ -1006,7 +995,6 @@ cc.Class({
const self = this; const self = this;
const rdf1 = self.recentFrameCache[renderFrameId1]; const rdf1 = self.recentFrameCache[renderFrameId1];
if (null == rdf1) { if (null == rdf1) {
const recentFrameCacheKeys = Object.keys(self.recentFrameCache);
console.error("renderFrameId1=", renderFrameId1, "doesn't exist in recentFrameCache ", self._stringifyRecentFrameCache(false), ": COULDN'T ROLLBACK!"); console.error("renderFrameId1=", renderFrameId1, "doesn't exist in recentFrameCache ", self._stringifyRecentFrameCache(false), ": COULDN'T ROLLBACK!");
return; return;
} }
@ -1016,7 +1004,7 @@ cc.Class({
// DON'T apply inputFrameDownsync dynamics for exactly "renderFrameId2", see the comment around the invocation of "_rollbackAndReplay". // DON'T apply inputFrameDownsync dynamics for exactly "renderFrameId2", see the comment around the invocation of "_rollbackAndReplay".
for (let renderFrameId = renderFrameId1; renderFrameId < renderFrameId2; ++renderFrameId) { for (let renderFrameId = renderFrameId1; renderFrameId < renderFrameId2; ++renderFrameId) {
const delayedInputFrameId = self._convertToInputFrameId(renderFrameId, self.inputDelayFrames); const delayedInputFrameId = self._convertToInputFrameId(renderFrameId, self.inputDelayFrames);
const delayedInputFrameDownsync = self.recentInputCache[delayedInputFrameId]; const delayedInputFrameDownsync = self.assembleInputFrameDownsync(delayedInputFrameId);
self._applyInputFrameDownsyncDynamics(delayedInputFrameDownsync, true); self._applyInputFrameDownsyncDynamics(delayedInputFrameDownsync, true);
// console.log("_rollbackAndReplay, AFTER:", self._stringifyRollbackResult(renderFrameId, delayedInputFrameDownsync)); // console.log("_rollbackAndReplay, AFTER:", self._stringifyRollbackResult(renderFrameId, delayedInputFrameDownsync));
} }
@ -1028,13 +1016,13 @@ cc.Class({
const self = this; const self = this;
for (let k in players) { for (let k in players) {
const playerId = parseInt(k); const playerId = parseInt(k);
if (self.playerRichInfoDict.hasOwnProperty(playerId)) continue; if (self.playerRichInfoDict.has(playerId)) continue; // Skip already put keys
const immediatePlayerInfo = players[playerId]; const immediatePlayerInfo = players[playerId];
const immediatePlayerMeta = playerMetas[playerId]; const immediatePlayerMeta = playerMetas[playerId];
const nodeAndScriptIns = self.spawnPlayerNode(immediatePlayerInfo.joinIndex, immediatePlayerInfo.x, immediatePlayerInfo.y); const nodeAndScriptIns = self.spawnPlayerNode(immediatePlayerInfo.joinIndex, immediatePlayerInfo.x, immediatePlayerInfo.y);
self.playerRichInfoDict[playerId] = immediatePlayerInfo; self.playerRichInfoDict.set(playerId, immediatePlayerInfo);
Object.assign(self.playerRichInfoDict[playerId], { Object.assign(self.playerRichInfoDict.get(playerId), {
node: nodeAndScriptIns[0], node: nodeAndScriptIns[0],
scriptIns: nodeAndScriptIns[1] scriptIns: nodeAndScriptIns[1]
}); });
@ -1057,16 +1045,14 @@ cc.Class({
return s.join('\n'); return s.join('\n');
} }
const keys = Object.keys(this.recentFrameCache); return "[stRenderFrameId=" + self.recentFrameCacheSt + ", edRenderFrameId=" + self.recentFrameCacheEd + ")";
return "[stRenderFrameId=" + keys[0] + ", edRenderFrameId=" + keys[keys.length-1] + "]";
}, },
_stringifyRecentInputCache(usefullOutput) { _stringifyRecentInputCache(usefullOutput) {
if (true == usefullOutput) { if (true == usefullOutput) {
return JSON.stringify(this.recentInputCache); return JSON.stringify(this.recentInputCache);
} }
const keys = Object.keys(this.recentInputCache); return "[stInputFrameId=" + self.recentInputCacheSt + ", edInputFrameId=" + self.recentInputCacheEd + ")";
return "[stInputFrameId=" + keys[0] + ", edInputFrameId=" + keys[keys.length-1] + "]";
}, },
_stringifyRollbackResult(renderFrameId, delayedInputFrameDownsync) { _stringifyRollbackResult(renderFrameId, delayedInputFrameDownsync) {
@ -1087,8 +1073,7 @@ cc.Class({
} }
); );
let players = {}; let players = {};
for (let playerId in self.playerRichInfoDict) { self.playerRichInfoDict.forEach((playerRichInfo, playerId) => {
const playerRichInfo = self.playerRichInfoDict[playerId];
const joinIndex = playerRichInfo.joinIndex; const joinIndex = playerRichInfo.joinIndex;
const playerNode = playerRichInfo.node; const playerNode = playerRichInfo.node;
const playerScriptIns = playerRichInfo.scriptIns; const playerScriptIns = playerRichInfo.scriptIns;
@ -1097,7 +1082,7 @@ cc.Class({
x: playerNode.position.x, x: playerNode.position.x,
y: playerNode.position.y, y: playerNode.position.y,
}; };
} });
return JSON.stringify(s); return JSON.stringify(s);
}, },