DelayNoMore/frontend/assets/scripts/NetworkDoctor.js

122 lines
5.2 KiB
JavaScript
Raw Normal View History

2023-01-21 14:53:41 +00:00
const RingBuffer = require('./RingBuffer');
var NetworkDoctor = function(capacity) {
this.reset(capacity);
};
NetworkDoctor.prototype.reset = function(capacity) {
2023-02-13 02:34:56 +00:00
this.inputFrameIdFront = 0;
2023-01-21 14:53:41 +00:00
this.sendingQ = new RingBuffer(capacity);
this.inputFrameDownsyncQ = new RingBuffer(capacity);
this.peerInputFrameUpsyncQ = new RingBuffer(capacity);
this.peerInputFrameUpsyncCnt = 0;
this.immediateRollbackFrames = 0;
2023-01-22 03:34:02 +00:00
this.skippedRenderFrameCnt = 0;
this.inputRateThreshold = gopkgs.ConvertToNoDelayInputFrameId(60);
this.peerUpsyncThreshold = 8;
this.rollbackFramesThreshold = 8; // Roughly the minimum "TurnAroundFramesToRecover".
2023-01-21 14:53:41 +00:00
};
2023-02-13 02:34:56 +00:00
NetworkDoctor.prototype.logInputFrameIdFront = function(inputFrameId) {
this.inputFrameIdFront = inputFrameId;
};
2023-01-21 14:53:41 +00:00
NetworkDoctor.prototype.logSending = function(stFrameId, edFrameId) {
this.sendingQ.put({
i: stFrameId,
j: edFrameId,
t: Date.now()
});
};
NetworkDoctor.prototype.logInputFrameDownsync = function(stFrameId, edFrameId) {
this.inputFrameDownsyncQ.put({
i: stFrameId,
j: edFrameId,
t: Date.now()
});
};
NetworkDoctor.prototype.logPeerInputFrameUpsync = function(stFrameId, edFrameId) {
const firstPopped = this.peerInputFrameUpsyncQ.put({
i: stFrameId,
j: edFrameId,
t: Date.now()
});
if (null != firstPopped) {
this.peerInputFrameUpsyncCnt -= (firstPopped.j - firstPopped.i + 1);
}
this.peerInputFrameUpsyncCnt += (edFrameId - stFrameId + 1);
};
2023-01-22 03:34:02 +00:00
NetworkDoctor.prototype.logRollbackFrames = function(x) {
this.immediateRollbackFrames = x;
2023-01-21 14:53:41 +00:00
};
2023-01-22 03:34:02 +00:00
NetworkDoctor.prototype.stats = function() {
2023-02-13 03:52:47 +00:00
let inputFrameIdFront = this.inputFrameIdFront,
sendingFps = 0,
2023-01-22 03:34:02 +00:00
srvDownsyncFps = 0,
peerUpsyncFps = 0,
rollbackFrames = this.immediateRollbackFrames;
if (1 < this.sendingQ.cnt) {
const st = this.sendingQ.getByFrameId(this.sendingQ.stFrameId);
const ed = this.sendingQ.getByFrameId(this.sendingQ.edFrameId - 1);
const elapsedMillis = ed.t - st.t;
sendingFps = Math.round((ed.j - st.i) * 1000 / elapsedMillis);
}
if (1 < this.inputFrameDownsyncQ.cnt) {
const st = this.inputFrameDownsyncQ.getByFrameId(this.inputFrameDownsyncQ.stFrameId);
const ed = this.inputFrameDownsyncQ.getByFrameId(this.inputFrameDownsyncQ.edFrameId - 1);
const elapsedMillis = ed.t - st.t;
srvDownsyncFps = Math.round((ed.j - st.i) * 1000 / elapsedMillis);
}
if (1 < this.peerInputFrameUpsyncQ.cnt) {
const st = this.peerInputFrameUpsyncQ.getByFrameId(this.peerInputFrameUpsyncQ.stFrameId);
const ed = this.peerInputFrameUpsyncQ.getByFrameId(this.peerInputFrameUpsyncQ.edFrameId - 1);
const elapsedMillis = ed.t - st.t;
peerUpsyncFps = Math.round(this.peerInputFrameUpsyncCnt * 1000 / elapsedMillis);
}
2023-02-13 03:52:47 +00:00
return [inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, this.skippedRenderFrameCnt];
2023-01-21 14:53:41 +00:00
};
2023-01-22 03:34:02 +00:00
NetworkDoctor.prototype.logSkippedRenderFrameCnt = function() {
this.skippedRenderFrameCnt += 1;
}
2023-01-21 14:53:41 +00:00
2023-02-01 13:35:00 +00:00
NetworkDoctor.prototype.isTooFast = function(mapIns) {
2023-02-13 03:52:47 +00:00
const [inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt] = this.stats();
2023-02-01 13:35:00 +00:00
if (sendingFps >= this.inputRateThreshold + 3) {
2023-01-22 15:05:32 +00:00
// Don't send too fast
2023-02-13 07:37:13 +00:00
if (CC_DEBUG) {
// Printing of this message might induce a performance impact.
2023-02-18 04:07:56 +00:00
// console.log(`Sending too fast, sendingFps=${sendingFps}`);
2023-02-13 07:37:13 +00:00
}
2023-02-13 03:52:47 +00:00
return [true, inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt];
2023-02-01 13:35:00 +00:00
} else {
const sendingFpsNormal = (sendingFps >= this.inputRateThreshold);
2023-01-24 02:08:34 +00:00
// An outstanding lag within the "inputFrameDownsyncQ" will reduce "srvDownsyncFps", HOWEVER, a constant lag wouldn't impact "srvDownsyncFps"! In native platforms we might use PING value might help as a supplement information to confirm that the "selfPlayer" is not lagged within the time accounted by "inputFrameDownsyncQ".
2023-02-01 13:35:00 +00:00
const recvFpsNormal = (srvDownsyncFps >= this.inputRateThreshold || peerUpsyncFps >= this.inputRateThreshold * (window.boundRoomCapacity - 1));
if (sendingFpsNormal && recvFpsNormal) {
let minInputFrameIdFront = Number.MAX_VALUE;
for (let k = 0; k < window.boundRoomCapacity; ++k) {
if (k + 1 == mapIns.selfPlayerInfo.JoinIndex) continue;
if (mapIns.lastIndividuallyConfirmedInputFrameId[k] >= minInputFrameIdFront) continue;
minInputFrameIdFront = mapIns.lastIndividuallyConfirmedInputFrameId[k];
}
2023-02-13 07:37:13 +00:00
if ((inputFrameIdFront > minInputFrameIdFront) && ((inputFrameIdFront - minInputFrameIdFront) > (mapIns.inputFrameUpsyncDelayTolerance + 1))) {
2023-02-01 13:35:00 +00:00
// first comparison condition is to avoid numeric overflow
2023-02-13 07:37:13 +00:00
if (CC_DEBUG) {
// Printing of this message might induce a performance impact.
2023-02-18 04:07:56 +00:00
// console.log(`Game logic ticking too fast, selfInputFrameIdFront=${inputFrameIdFront}, minInputFrameIdFront=${minInputFrameIdFront}, inputFrameUpsyncDelayTolerance=${mapIns.inputFrameUpsyncDelayTolerance}`);
2023-02-13 07:37:13 +00:00
}
2023-02-13 03:52:47 +00:00
return [true, inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt];
2023-02-01 13:35:00 +00:00
}
2023-01-22 03:34:02 +00:00
}
}
2023-02-13 03:52:47 +00:00
return [false, inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt];
2023-01-21 14:53:41 +00:00
};
module.exports = NetworkDoctor;