Minor fix.

This commit is contained in:
genxium 2023-02-01 07:27:10 +08:00
parent 2fb6fd6bea
commit 851678e2f3
3 changed files with 42 additions and 16 deletions

View File

@ -547,7 +547,7 @@
"array": [ "array": [
0, 0,
0, 0,
209.73151519075364, 209.57814771583418,
0, 0,
0, 0,
0, 0,

View File

@ -43,10 +43,10 @@ window.onUdpMessage = (args) => {
//cc.log(`#2 Js called back by CPP for upsync: onUdpMessage: ${JSON.stringify(req)}`); //cc.log(`#2 Js called back by CPP for upsync: onUdpMessage: ${JSON.stringify(req)}`);
if (req.act && window.UPSYNC_MSG_ACT_PLAYER_CMD == req.act) { if (req.act && window.UPSYNC_MSG_ACT_PLAYER_CMD == req.act) {
let effCnt = 0; let effCnt = 0;
const renderedInputFrameIdUpper = gopkgs.ConvertToDelayedInputFrameId(self.renderFrameId);
const peerJoinIndex = req.joinIndex; const peerJoinIndex = req.joinIndex;
if (peerJoinIndex == self.selfPlayerInfo.JoinIndex) return;
const batch = req.inputFrameUpsyncBatch; const batch = req.inputFrameUpsyncBatch;
self.onPeerInputFrameUpsync(peerJoinIndex, batch, true); //self.onPeerInputFrameUpsync(peerJoinIndex, batch, true); // By now calling "self.onPeerInputFrameUpsync" from "onUdpMessage" seems to be overriding local inputs unexpectedly -- even after the local input has already arrived at the peer side via backend udp tunnel! Root cause remains to be investigated.
} }
} }
}; };
@ -144,7 +144,7 @@ cc.Class({
return (confirmedList + 1) == (1 << this.playerRichInfoDict.size); return (confirmedList + 1) == (1 << this.playerRichInfoDict.size);
}, },
getOrPrefabInputFrameUpsync(inputFrameId) { getOrPrefabInputFrameUpsync(inputFrameId, canConfirmSelf) {
// TODO: find some kind of synchronization mechanism against "onInputFrameDownsyncBatch"! // TODO: find some kind of synchronization mechanism against "onInputFrameDownsyncBatch"!
const self = this; const self = this;
if ( if (
@ -157,10 +157,15 @@ cc.Class({
let previousSelfInput = null, let previousSelfInput = null,
currSelfInput = null; currSelfInput = null;
const joinIndex = self.selfPlayerInfo.JoinIndex; const joinIndex = self.selfPlayerInfo.JoinIndex;
const selfJoinIndexMask = (1 << (joinIndex - 1));
const existingInputFrame = self.recentInputCache.GetByFrameId(inputFrameId); const existingInputFrame = self.recentInputCache.GetByFrameId(inputFrameId);
const previousInputFrameDownsync = self.recentInputCache.GetByFrameId(inputFrameId - 1); const previousInputFrameDownsync = self.recentInputCache.GetByFrameId(inputFrameId - 1);
previousSelfInput = (null == previousInputFrameDownsync ? null : previousInputFrameDownsync.InputList[joinIndex - 1]); previousSelfInput = (null == previousInputFrameDownsync ? null : previousInputFrameDownsync.InputList[joinIndex - 1]);
if (null != existingInputFrame) { if (
null != existingInputFrame
&&
(true != canConfirmSelf)
) {
// This could happen upon either [type#1] or [type#2] forceConfirmation, where "refRenderFrame" is accompanied by some "inputFrameDownsyncs". The check here also guarantees that we don't override history // This could happen upon either [type#1] or [type#2] forceConfirmation, where "refRenderFrame" is accompanied by some "inputFrameDownsyncs". The check here also guarantees that we don't override history
//console.log(`noDelayInputFrameId=${inputFrameId} already exists in recentInputCache: recentInputCache=${self._stringifyRecentInputCache(false)}`); //console.log(`noDelayInputFrameId=${inputFrameId} already exists in recentInputCache: recentInputCache=${self._stringifyRecentInputCache(false)}`);
return [previousSelfInput, existingInputFrame.InputList[joinIndex - 1]]; return [previousSelfInput, existingInputFrame.InputList[joinIndex - 1]];
@ -169,15 +174,31 @@ cc.Class({
const prefabbedInputList = new Array(self.playerRichInfoDict.size).fill(0); const prefabbedInputList = new Array(self.playerRichInfoDict.size).fill(0);
// the returned "gopkgs.NewInputFrameDownsync.InputList" is immutable, thus we can only modify the values in "prefabbedInputList" // the returned "gopkgs.NewInputFrameDownsync.InputList" is immutable, thus we can only modify the values in "prefabbedInputList"
for (let k in prefabbedInputList) { for (let k in prefabbedInputList) {
prefabbedInputList[k] = self.lastIndividuallyConfirmedInputList[k]; if (null != existingInputFrame) {
// Don't predict "btnA & btnB"! // When "null != existingInputFrame", it implies that "true == canConfirmSelf" here, we just have to assign "prefabbedInputList[(joinIndex-1)]" specifically and copy all others
prefabbedInputList[k] = (prefabbedInputList[k] & 15); prefabbedInputList[k] = existingInputFrame.InputList[k];
} else if (self.lastIndividuallyConfirmedInputFrameId[k] <= inputFrameId) {
prefabbedInputList[k] = self.lastIndividuallyConfirmedInputList[k];
// Don't predict "btnA & btnB"!
prefabbedInputList[k] = (prefabbedInputList[k] & 15);
} else if (null != previousInputFrameDownsync) {
// When "self.lastIndividuallyConfirmedInputFrameId[k] > inputFrameId", don't use it to predict a historical input!
prefabbedInputList[k] = previousInputFrameDownsync.InputList[k];
// Don't predict "btnA & btnB"!
prefabbedInputList[k] = (prefabbedInputList[k] & 15);
}
}
let initConfirmedList = 0;
if (null != existingInputFrame) {
// When "null != existingInputFrame", it implies that "true == canConfirmSelf" here
initConfirmedList = (existingInputFrame.ConfirmedList | selfJoinIndexMask);
} }
currSelfInput = self.ctrl.getEncodedInput(); // When "null == existingInputFrame", it'd be safe to say that the realtime "self.ctrl.getEncodedInput()" is for the requested "inputFrameId" currSelfInput = self.ctrl.getEncodedInput(); // When "null == existingInputFrame", it'd be safe to say that the realtime "self.ctrl.getEncodedInput()" is for the requested "inputFrameId"
prefabbedInputList[(joinIndex - 1)] = currSelfInput; prefabbedInputList[(joinIndex - 1)] = currSelfInput;
while (self.recentInputCache.EdFrameId <= inputFrameId) { while (self.recentInputCache.EdFrameId <= inputFrameId) {
// Fill the gap // Fill the gap
const prefabbedInputFrameDownsync = gopkgs.NewInputFrameDownsync(self.recentInputCache.EdFrameId, prefabbedInputList.slice(), (1 << (joinIndex - 1))); // [WARNING] Do not blindly use "selfJoinIndexMask" here, as the "actuallyUsedInput for self" couldn't be confirmed while prefabbing, otherwise we'd have confirmed a wrong self input by "_markConfirmationIfApplicable()"!
const prefabbedInputFrameDownsync = gopkgs.NewInputFrameDownsync(self.recentInputCache.EdFrameId, prefabbedInputList.slice(), initConfirmedList);
// console.log(`Prefabbed inputFrameId=${prefabbedInputFrameDownsync.InputFrameId}`); // console.log(`Prefabbed inputFrameId=${prefabbedInputFrameDownsync.InputFrameId}`);
self.recentInputCache.Put(prefabbedInputFrameDownsync); self.recentInputCache.Put(prefabbedInputFrameDownsync);
} }
@ -812,12 +833,15 @@ cc.Class({
_markConfirmationIfApplicable() { _markConfirmationIfApplicable() {
const self = this; const self = this;
let newAllConfirmedCnt = 0;
while (self.recentInputCache.StFrameId <= self.lastAllConfirmedInputFrameId && self.lastAllConfirmedInputFrameId < self.recentInputCache.EdFrameId) { while (self.recentInputCache.StFrameId <= self.lastAllConfirmedInputFrameId && self.lastAllConfirmedInputFrameId < self.recentInputCache.EdFrameId) {
const inputFrameDownsync = self.recentInputCache.GetByFrameId(self.lastAllConfirmedInputFrameId); const inputFrameDownsync = self.recentInputCache.GetByFrameId(self.lastAllConfirmedInputFrameId);
if (null == inputFrameDownsync) break; if (null == inputFrameDownsync) break;
if (self._allConfirmed(inputFrameDownsync.ConfirmedList)) break; if (self._allConfirmed(inputFrameDownsync.ConfirmedList)) break;
++self.lastAllConfirmedInputFrameId; ++self.lastAllConfirmedInputFrameId;
++newAllConfirmedCnt;
} }
return newAllConfirmedCnt;
}, },
onInputFrameDownsyncBatch(batch /* []*pb.InputFrameDownsync */ ) { onInputFrameDownsyncBatch(batch /* []*pb.InputFrameDownsync */ ) {
@ -841,6 +865,9 @@ cc.Class({
if (inputFrameDownsyncId <= self.lastAllConfirmedInputFrameId) { if (inputFrameDownsyncId <= self.lastAllConfirmedInputFrameId) {
continue; continue;
} }
// [WARNING] Now that "inputFrameDownsyncId > self.lastAllConfirmedInputFrameId", we should make an update immediately because unlike its backend counterpart "Room.LastAllConfirmedInputFrameId", the frontend "mapIns.lastAllConfirmedInputFrameId" might inevitably get gaps among discrete values due to "either type#1 or type#2 forceConfirmation" -- and only "onInputFrameDownsyncBatch" can catch this!
self.lastAllConfirmedInputFrameId = inputFrameDownsyncId;
const localInputFrame = self.recentInputCache.GetByFrameId(inputFrameDownsyncId); const localInputFrame = self.recentInputCache.GetByFrameId(inputFrameDownsyncId);
if (null != localInputFrame if (null != localInputFrame
&& &&
@ -866,7 +893,7 @@ cc.Class({
throw `Failed to dump input cache (maybe recentInputCache too small)! inputFrameDownsync.inputFrameId=${inputFrameDownsync.inputFrameId}, lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}; recentRenderCache=${self._stringifyRecentRenderCache(false)}, recentInputCache=${self._stringifyRecentInputCache(false)}`; throw `Failed to dump input cache (maybe recentInputCache too small)! inputFrameDownsync.inputFrameId=${inputFrameDownsync.inputFrameId}, lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}; recentRenderCache=${self._stringifyRecentRenderCache(false)}, recentInputCache=${self._stringifyRecentInputCache(false)}`;
} }
} }
self._markConfirmationIfApplicable(); //self._markConfirmationIfApplicable();
if (null == firstPredictedYetIncorrectInputFrameId) return; if (null == firstPredictedYetIncorrectInputFrameId) return;
const renderFrameId1 = gopkgs.ConvertToFirstUsedRenderFrameId(firstPredictedYetIncorrectInputFrameId) - 1; const renderFrameId1 = gopkgs.ConvertToFirstUsedRenderFrameId(firstPredictedYetIncorrectInputFrameId) - 1;
@ -920,8 +947,7 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
// [WARNING] Don't reject it by "inputFrameId <= self.lastIndividuallyConfirmedInputFrameId[peerJoinIndex-1]", the arrival of UDP packets might not reserve their sending order! // [WARNING] Don't reject it by "inputFrameId <= self.lastIndividuallyConfirmedInputFrameId[peerJoinIndex-1]", the arrival of UDP packets might not reserve their sending order!
continue; continue;
} }
self.getOrPrefabInputFrameUpsync(inputFrameId); // Make sure that inputFrame exists locally const existingInputFrame = self.getOrPrefabInputFrameUpsync(inputFrameId, false); // Make sure that inputFrame exists locally
const existingInputFrame = self.recentInputCache.GetByFrameId(inputFrameId);
if (0 < (existingInputFrame.ConfirmedList & (1 << (peerJoinIndex - 1)))) { if (0 < (existingInputFrame.ConfirmedList & (1 << (peerJoinIndex - 1)))) {
continue; continue;
} }
@ -942,7 +968,7 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
self.recentInputCache.SetByFrameId(newInputFrameDownsyncLocal, inputFrameId); self.recentInputCache.SetByFrameId(newInputFrameDownsyncLocal, inputFrameId);
} }
if (0 < effCnt) { if (0 < effCnt) {
self._markConfirmationIfApplicable(); //self._markConfirmationIfApplicable();
self.networkDoctor.logPeerInputFrameUpsync(batch[0].inputFrameId, batch[batch.length - 1].inputFrameId); self.networkDoctor.logPeerInputFrameUpsync(batch[0].inputFrameId, batch[batch.length - 1].inputFrameId);
} }
}, },
@ -1029,13 +1055,13 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
let prevSelfInput = null, let prevSelfInput = null,
currSelfInput = null; currSelfInput = null;
if (gopkgs.ShouldGenerateInputFrameUpsync(self.renderFrameId)) { if (gopkgs.ShouldGenerateInputFrameUpsync(self.renderFrameId)) {
[prevSelfInput, currSelfInput] = self.getOrPrefabInputFrameUpsync(noDelayInputFrameId); [prevSelfInput, currSelfInput] = self.getOrPrefabInputFrameUpsync(noDelayInputFrameId, true);
} }
const delayedInputFrameId = gopkgs.ConvertToDelayedInputFrameId(self.renderFrameId); const delayedInputFrameId = gopkgs.ConvertToDelayedInputFrameId(self.renderFrameId);
if (null == self.recentInputCache.GetByFrameId(delayedInputFrameId)) { if (null == self.recentInputCache.GetByFrameId(delayedInputFrameId)) {
// Possible edge case after resync, kindly note that it's OK to prefab a "future inputFrame" here, because "sendInputFrameUpsyncBatch" would be capped by "noDelayInputFrameId from self.renderFrameId". // Possible edge case after resync, kindly note that it's OK to prefab a "future inputFrame" here, because "sendInputFrameUpsyncBatch" would be capped by "noDelayInputFrameId from self.renderFrameId".
self.getOrPrefabInputFrameUpsync(delayedInputFrameId); self.getOrPrefabInputFrameUpsync(delayedInputFrameId, false);
} }
let t0 = performance.now(); let t0 = performance.now();

View File

@ -189,7 +189,7 @@ cc.Class({
currSelfInput = null; currSelfInput = null;
const noDelayInputFrameId = gopkgs.ConvertToNoDelayInputFrameId(self.renderFrameId); // It's important that "inputDelayFrames == 0" here const noDelayInputFrameId = gopkgs.ConvertToNoDelayInputFrameId(self.renderFrameId); // It's important that "inputDelayFrames == 0" here
if (gopkgs.ShouldGenerateInputFrameUpsync(self.renderFrameId)) { if (gopkgs.ShouldGenerateInputFrameUpsync(self.renderFrameId)) {
const prevAndCurrInputs = self.getOrPrefabInputFrameUpsync(noDelayInputFrameId); const prevAndCurrInputs = self.getOrPrefabInputFrameUpsync(noDelayInputFrameId, true);
prevSelfInput = prevAndCurrInputs[0]; prevSelfInput = prevAndCurrInputs[0];
currSelfInput = prevAndCurrInputs[1]; currSelfInput = prevAndCurrInputs[1];
} }