mirror of
https://github.com/genxium/DelayNoMore
synced 2024-12-25 11:18:55 +00:00
Improved stability.
This commit is contained in:
parent
b9beee549f
commit
ea14ced958
@ -156,10 +156,9 @@ type Room struct {
|
|||||||
TmxPointsMap StrToVec2DListMap
|
TmxPointsMap StrToVec2DListMap
|
||||||
TmxPolygonsMap StrToPolygon2DListMap
|
TmxPolygonsMap StrToPolygon2DListMap
|
||||||
|
|
||||||
rdfIdToActuallyUsedInput map[int32]*pb.InputFrameDownsync
|
rdfIdToActuallyUsedInput map[int32]*pb.InputFrameDownsync
|
||||||
allowUpdateInputFrameInPlaceUponDynamics bool
|
LastIndividuallyConfirmedInputFrameId []int32
|
||||||
LastIndividuallyConfirmedInputFrameId []int32
|
LastIndividuallyConfirmedInputList []uint64
|
||||||
LastIndividuallyConfirmedInputList []uint64
|
|
||||||
|
|
||||||
BattleUdpTunnelLock sync.Mutex
|
BattleUdpTunnelLock sync.Mutex
|
||||||
BattleUdpTunnelAddr *pb.PeerUdpAddr
|
BattleUdpTunnelAddr *pb.PeerUdpAddr
|
||||||
@ -808,7 +807,6 @@ func (pR *Room) OnDismissed() {
|
|||||||
pR.RenderFrameBuffer = resolv.NewRingBuffer(pR.RenderCacheSize)
|
pR.RenderFrameBuffer = resolv.NewRingBuffer(pR.RenderCacheSize)
|
||||||
pR.InputsBuffer = resolv.NewRingBuffer((pR.RenderCacheSize >> 1) + 1)
|
pR.InputsBuffer = resolv.NewRingBuffer((pR.RenderCacheSize >> 1) + 1)
|
||||||
pR.rdfIdToActuallyUsedInput = make(map[int32]*pb.InputFrameDownsync)
|
pR.rdfIdToActuallyUsedInput = make(map[int32]*pb.InputFrameDownsync)
|
||||||
pR.allowUpdateInputFrameInPlaceUponDynamics = true
|
|
||||||
pR.LastIndividuallyConfirmedInputFrameId = make([]int32, pR.Capacity)
|
pR.LastIndividuallyConfirmedInputFrameId = make([]int32, pR.Capacity)
|
||||||
for i := 0; i < pR.Capacity; i++ {
|
for i := 0; i < pR.Capacity; i++ {
|
||||||
pR.LastIndividuallyConfirmedInputFrameId[i] = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED
|
pR.LastIndividuallyConfirmedInputFrameId[i] = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED
|
||||||
@ -847,7 +845,7 @@ func (pR *Room) OnDismissed() {
|
|||||||
pR.RollbackEstimatedDtNanos = 16666666 // A little smaller than the actual per frame time, just for logging FAST FRAME
|
pR.RollbackEstimatedDtNanos = 16666666 // A little smaller than the actual per frame time, just for logging FAST FRAME
|
||||||
dilutedServerFps := float64(58.0) // Don't set this value too small, otherwise we might miss force confirmation needs for slow tickers!
|
dilutedServerFps := float64(58.0) // Don't set this value too small, otherwise we might miss force confirmation needs for slow tickers!
|
||||||
pR.dilutedRollbackEstimatedDtNanos = int64(float64(pR.RollbackEstimatedDtNanos) * float64(serverFps) / dilutedServerFps)
|
pR.dilutedRollbackEstimatedDtNanos = int64(float64(pR.RollbackEstimatedDtNanos) * float64(serverFps) / dilutedServerFps)
|
||||||
pR.BattleDurationFrames = int32(60 * serverFps)
|
pR.BattleDurationFrames = int32(20 * serverFps)
|
||||||
//pR.BattleDurationFrames = int32(20 * serverFps)
|
//pR.BattleDurationFrames = int32(20 * serverFps)
|
||||||
pR.BattleDurationNanos = int64(pR.BattleDurationFrames) * (pR.RollbackEstimatedDtNanos + 1)
|
pR.BattleDurationNanos = int64(pR.BattleDurationFrames) * (pR.RollbackEstimatedDtNanos + 1)
|
||||||
pR.InputFrameUpsyncDelayTolerance = battle.ConvertToNoDelayInputFrameId(pR.NstDelayFrames) - 1 // this value should be strictly smaller than (NstDelayFrames >> InputScaleFrames), otherwise "type#1 forceConfirmation" might become a lag avalanche
|
pR.InputFrameUpsyncDelayTolerance = battle.ConvertToNoDelayInputFrameId(pR.NstDelayFrames) - 1 // this value should be strictly smaller than (NstDelayFrames >> InputScaleFrames), otherwise "type#1 forceConfirmation" might become a lag avalanche
|
||||||
@ -856,7 +854,7 @@ func (pR *Room) OnDismissed() {
|
|||||||
pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work!
|
pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work!
|
||||||
pR.ForceAllResyncOnAnyActiveSlowTicker = true // See tradeoff discussion in "downsyncToAllPlayers"
|
pR.ForceAllResyncOnAnyActiveSlowTicker = true // See tradeoff discussion in "downsyncToAllPlayers"
|
||||||
|
|
||||||
pR.FrameDataLoggingEnabled = false // [WARNING] DON'T ENABLE ON LONG BATTLE DURATION! It consumes A LOT OF MEMORY!
|
pR.FrameDataLoggingEnabled = true // [WARNING] DON'T ENABLE ON LONG BATTLE DURATION! It consumes A LOT OF MEMORY!
|
||||||
pR.BattleUdpTunnelLock.Lock()
|
pR.BattleUdpTunnelLock.Lock()
|
||||||
pR.BattleUdpTunnel = nil
|
pR.BattleUdpTunnel = nil
|
||||||
pR.BattleUdpTunnelAddr = nil
|
pR.BattleUdpTunnelAddr = nil
|
||||||
@ -1309,9 +1307,6 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) uint64 {
|
|||||||
panic(fmt.Sprintf("inputFrameId=%v doesn't exist for roomId=%v! InputsBuffer=%v", j, pR.Id, pR.InputsBufferString(false)))
|
panic(fmt.Sprintf("inputFrameId=%v doesn't exist for roomId=%v! InputsBuffer=%v", j, pR.Id, pR.InputsBufferString(false)))
|
||||||
}
|
}
|
||||||
inputFrameDownsync := tmp.(*battle.InputFrameDownsync)
|
inputFrameDownsync := tmp.(*battle.InputFrameDownsync)
|
||||||
if pR.allowUpdateInputFrameInPlaceUponDynamics {
|
|
||||||
battle.UpdateInputFrameInPlaceUponDynamics(j, pR.Capacity, inputFrameDownsync.ConfirmedList, inputFrameDownsync.InputList, pR.LastIndividuallyConfirmedInputFrameId, pR.LastIndividuallyConfirmedInputList, int32(MAGIC_JOIN_INDEX_INVALID))
|
|
||||||
}
|
|
||||||
unconfirmedMask |= (allConfirmedMask ^ inputFrameDownsync.ConfirmedList)
|
unconfirmedMask |= (allConfirmedMask ^ inputFrameDownsync.ConfirmedList)
|
||||||
inputFrameDownsync.ConfirmedList = allConfirmedMask
|
inputFrameDownsync.ConfirmedList = allConfirmedMask
|
||||||
pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, -1)
|
pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, -1)
|
||||||
@ -1392,7 +1387,7 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
battle.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(pR.InputsBuffer, currRenderFrame.Id, pR.Space, pR.CollisionSysMap, pR.SpaceOffsetX, pR.SpaceOffsetY, pR.CharacterConfigsArr, pR.RenderFrameBuffer, pR.collisionHolder, pR.effPushbacks, pR.hardPushbackNormsArr, pR.jumpedOrNotList, pR.dynamicRectangleColliders, pR.LastIndividuallyConfirmedInputFrameId, pR.LastIndividuallyConfirmedInputList, false, MAGIC_JOIN_INDEX_INVALID) // "allowUpdateInputFrameInPlaceUponDynamics" is instead used in "forceConfirmationIfApplicable"
|
battle.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(pR.InputsBuffer, currRenderFrame.Id, pR.Space, pR.CollisionSysMap, pR.SpaceOffsetX, pR.SpaceOffsetY, pR.CharacterConfigsArr, pR.RenderFrameBuffer, pR.collisionHolder, pR.effPushbacks, pR.hardPushbackNormsArr, pR.jumpedOrNotList, pR.dynamicRectangleColliders, pR.LastIndividuallyConfirmedInputFrameId, pR.LastIndividuallyConfirmedInputList, false, MAGIC_JOIN_INDEX_INVALID) // DON'T mutate inputs upon dynamics on backend to avoid complicating the edge cases
|
||||||
pR.CurDynamicsRenderFrameId++
|
pR.CurDynamicsRenderFrameId++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,7 +461,7 @@
|
|||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
210.4441731196186,
|
209.57814771583418,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -713,9 +713,9 @@ cc.Class({
|
|||||||
if (notSelfUnconfirmed) {
|
if (notSelfUnconfirmed) {
|
||||||
shouldForceDumping2 = false;
|
shouldForceDumping2 = false;
|
||||||
shouldForceResync = false;
|
shouldForceResync = false;
|
||||||
self.othersForcedDownsyncRenderFrameDict.set(rdfId, rdf);
|
self.othersForcedDownsyncRenderFrameDict.set(rdfId, [pbRdf, rdf]);
|
||||||
if (CC_DEBUG) {
|
if (CC_DEBUG) {
|
||||||
console.warn(`Someone else is forced to resync! renderFrameId=${rdf.GetId()}
|
console.warn(`Someone else is forced to resync! renderFrameId=${rdfId}
|
||||||
backendUnconfirmedMask=${pbRdf.backendUnconfirmedMask}
|
backendUnconfirmedMask=${pbRdf.backendUnconfirmedMask}
|
||||||
accompaniedInputFrameDownsyncBatchRange=[${null == accompaniedInputFrameDownsyncBatch ? null : accompaniedInputFrameDownsyncBatch[0].inputFrameId}, ${null == accompaniedInputFrameDownsyncBatch ? null : accompaniedInputFrameDownsyncBatch[accompaniedInputFrameDownsyncBatch.length - 1].inputFrameId}]`);
|
accompaniedInputFrameDownsyncBatchRange=[${null == accompaniedInputFrameDownsyncBatch ? null : accompaniedInputFrameDownsyncBatch[0].inputFrameId}, ${null == accompaniedInputFrameDownsyncBatch ? null : accompaniedInputFrameDownsyncBatch[accompaniedInputFrameDownsyncBatch.length - 1].inputFrameId}]`);
|
||||||
}
|
}
|
||||||
@ -947,7 +947,7 @@ accompaniedInputFrameDownsyncBatchRange=[${accompaniedInputFrameDownsyncBatch[0]
|
|||||||
_handleIncorrectlyRenderedPrediction(firstPredictedYetIncorrectInputFrameId, batch, fromUDP) {
|
_handleIncorrectlyRenderedPrediction(firstPredictedYetIncorrectInputFrameId, batch, fromUDP) {
|
||||||
if (null == firstPredictedYetIncorrectInputFrameId) return;
|
if (null == firstPredictedYetIncorrectInputFrameId) return;
|
||||||
const self = this;
|
const self = this;
|
||||||
const renderFrameId1 = gopkgs.ConvertToFirstUsedRenderFrameId(firstPredictedYetIncorrectInputFrameId) - 1;
|
const renderFrameId1 = gopkgs.ConvertToFirstUsedRenderFrameId(firstPredictedYetIncorrectInputFrameId);
|
||||||
if (renderFrameId1 >= self.chaserRenderFrameId) return;
|
if (renderFrameId1 >= self.chaserRenderFrameId) return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1164,25 +1164,25 @@ fromUDP=${fromUDP}`);
|
|||||||
rollbackFrames = 0;
|
rollbackFrames = 0;
|
||||||
}
|
}
|
||||||
self.networkDoctor.logRollbackFrames(rollbackFrames);
|
self.networkDoctor.logRollbackFrames(rollbackFrames);
|
||||||
let prevRdf = latestRdfResults[0],
|
let prevRdf = latestRdfResults[0], // Having "prevRdf.Id == self.renderFrameId"
|
||||||
rdf = latestRdfResults[1];
|
rdf = latestRdfResults[1]; // Having "rdf.Id == self.renderFrameId+1"
|
||||||
/*
|
/*
|
||||||
const nonTrivialChaseEnded = (prevChaserRenderFrameId < nextChaserRenderFrameId && nextChaserRenderFrameId == self.renderFrameId);
|
const nonTrivialChaseEnded = (prevChaserRenderFrameId < nextChaserRenderFrameId && nextChaserRenderFrameId == self.renderFrameId);
|
||||||
if (nonTrivialChaseEnded) {
|
if (nonTrivialChaseEnded) {
|
||||||
console.debug("Non-trivial chase ended, prevChaserRenderFrameId=" + prevChaserRenderFrameId + ", nextChaserRenderFrameId=" + nextChaserRenderFrameId);
|
console.debug("Non-trivial chase ended, prevChaserRenderFrameId=" + prevChaserRenderFrameId + ", nextChaserRenderFrameId=" + nextChaserRenderFrameId);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
// [WARNING] Don't try to get "prevRdf(i.e. renderFrameId == latest-1)" by "self.recentRenderCache.GetByFrameId(...)" here, as the cache might have been updated by asynchronous "onRoomDownsyncFrame(...)" calls!
|
|
||||||
if (self.othersForcedDownsyncRenderFrameDict.has(rdf.GetId())) {
|
if (self.othersForcedDownsyncRenderFrameDict.has(rdf.GetId())) {
|
||||||
const delayedInputFrameId = gopkgs.ConvertToDelayedInputFrameId(rdf.GetId());
|
const [pbOthersForcedDownsyncRenderFrame, othersForcedDownsyncRenderFrame] = self.othersForcedDownsyncRenderFrameDict.get(rdf.GetId());
|
||||||
const othersForcedDownsyncRenderFrame = self.othersForcedDownsyncRenderFrameDict.get(rdf.GetId());
|
|
||||||
if (self.lastAllConfirmedInputFrameId >= delayedInputFrameId && !self.equalRoomDownsyncFrames(othersForcedDownsyncRenderFrame, rdf)) {
|
if (self.lastAllConfirmedInputFrameId >= delayedInputFrameId && !self.equalRoomDownsyncFrames(othersForcedDownsyncRenderFrame, rdf)) {
|
||||||
if (CC_DEBUG) {
|
if (CC_DEBUG) {
|
||||||
console.warn(`Mismatched render frame@rdf.id=${rdf.GetId()} w/ inputFrameId=${delayedInputFrameId}:
|
console.warn(`Mismatched render frame@rdf.id=${rdf.GetId()} w/ inputFrameId=${delayedInputFrameId}:
|
||||||
rdf=${self._stringifyGopkgRdfForFrameDataLogging(rdf)}
|
rdf=${self._stringifyGopkgRdfForFrameDataLogging(rdf)}
|
||||||
othersForcedDownsyncRenderFrame=${self._stringifyGopkgRdfForFrameDataLogging(othersForcedDownsyncRenderFrame)}`);
|
othersForcedDownsyncRenderFrame=${self._stringifyGopkgRdfForFrameDataLogging(othersForcedDownsyncRenderFrame)}`);
|
||||||
}
|
}
|
||||||
rdf = othersForcedDownsyncRenderFrame;
|
// [WARNING] When this happens, something is intrinsically wrong -- to avoid having an inconsistent history in the "recentRenderCache", thus a wrong prediction all the way from here on, clear the history!
|
||||||
|
pbOthersForcedDownsyncRenderFrame.backendUnconfirmedMask = ((1 << window.boundRoomCapacity) - 1);
|
||||||
|
self.onRoomDownsyncFrame(pbOthersForcedDownsyncRenderFrame, null);
|
||||||
self.othersForcedDownsyncRenderFrameDict.delete(rdf.GetId());
|
self.othersForcedDownsyncRenderFrameDict.delete(rdf.GetId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1438,19 +1438,11 @@ othersForcedDownsyncRenderFrame=${self._stringifyGopkgRdfForFrameDataLogging(oth
|
|||||||
const j = gopkgs.ConvertToDelayedInputFrameId(i);
|
const j = gopkgs.ConvertToDelayedInputFrameId(i);
|
||||||
const delayedInputFrame = gopkgs.GetInputFrameDownsync(self.recentInputCache, j);
|
const delayedInputFrame = gopkgs.GetInputFrameDownsync(self.recentInputCache, j);
|
||||||
|
|
||||||
const allowUpdateInputFrameInPlaceUponDynamics = (!isChasing);
|
const allowUpdateInputFrameInPlaceUponDynamics = (!isChasing); // [WARNING] Input mutation could trigger chasing on frontend, thus don't trigger mutation when chasing to avoid confusing recursion.
|
||||||
const hasInputFrameUpdatedOnDynamics = gopkgs.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrameJs(self.recentInputCache, i, collisionSys, collisionSysMap, self.spaceOffsetX, self.spaceOffsetY, self.chConfigsOrderedByJoinIndex, self.recentRenderCache, self.collisionHolder, self.effPushbacks, self.hardPushbackNormsArr, self.jumpedOrNotList, self.dynamicRectangleColliders, self.lastIndividuallyConfirmedInputFrameId, self.lastIndividuallyConfirmedInputList, allowUpdateInputFrameInPlaceUponDynamics, self.selfPlayerInfo.joinIndex);
|
const hasInputFrameUpdatedOnDynamics = gopkgs.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrameJs(self.recentInputCache, i, collisionSys, collisionSysMap, self.spaceOffsetX, self.spaceOffsetY, self.chConfigsOrderedByJoinIndex, self.recentRenderCache, self.collisionHolder, self.effPushbacks, self.hardPushbackNormsArr, self.jumpedOrNotList, self.dynamicRectangleColliders, self.lastIndividuallyConfirmedInputFrameId, self.lastIndividuallyConfirmedInputList, allowUpdateInputFrameInPlaceUponDynamics, self.selfPlayerInfo.joinIndex);
|
||||||
if (hasInputFrameUpdatedOnDynamics) {
|
if (hasInputFrameUpdatedOnDynamics) {
|
||||||
const ii = gopkgs.ConvertToFirstUsedRenderFrameId(j);
|
const ii = gopkgs.ConvertToFirstUsedRenderFrameId(j);
|
||||||
if (ii < i) {
|
if (ii < i) {
|
||||||
/*
|
|
||||||
[WARNING]
|
|
||||||
If we don't rollback at this spot, when the mutated "delayedInputFrame.inputList" a.k.a. "inputFrame#j" matches the later downsynced version, rollback WOULDN'T be triggered for the incorrectly rendered "renderFrame#(ii+1)", and it would STAY IN HISTORY FOREVER -- as the history becomes incorrect, EVERY LATEST renderFrame since "inputFrame#j" was mutated would be ALWAYS incorrectly rendering too!
|
|
||||||
|
|
||||||
The backend counterpart doesn't need this rollback because
|
|
||||||
1. Backend only applies all-confirmed inputFrames to calc dynamics.
|
|
||||||
2. Backend applies an all-confirmed inputFrame to all applicable render frames at once.
|
|
||||||
*/
|
|
||||||
self._handleIncorrectlyRenderedPrediction(j, null, false);
|
self._handleIncorrectlyRenderedPrediction(j, null, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -372,7 +372,7 @@ bool DelayNoMore::UdpSession::pollUdpRecvRingBuff() {
|
|||||||
// This function is called by GameThread 60 fps.
|
// This function is called by GameThread 60 fps.
|
||||||
|
|
||||||
//uv_mutex_lock(&recvRingBuffLock);
|
//uv_mutex_lock(&recvRingBuffLock);
|
||||||
while (true) {
|
while (true && NULL != recvLoop) {
|
||||||
RecvWork f;
|
RecvWork f;
|
||||||
bool res = recvRingBuff->pop(&f);
|
bool res = recvRingBuff->pop(&f);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
|
@ -76,7 +76,7 @@
|
|||||||
"shelter_z_reducer",
|
"shelter_z_reducer",
|
||||||
"shelter"
|
"shelter"
|
||||||
],
|
],
|
||||||
"last-module-event-record-time": 1677337364473,
|
"last-module-event-record-time": 1678432182471,
|
||||||
"simulator-orientation": false,
|
"simulator-orientation": false,
|
||||||
"simulator-resolution": {
|
"simulator-resolution": {
|
||||||
"height": 640,
|
"height": 640,
|
||||||
|
Loading…
Reference in New Issue
Block a user