mirror of
https://github.com/genxium/DelayNoMore
synced 2024-12-26 03:39:00 +00:00
Working on reduction of resync received in frontend.
This commit is contained in:
parent
9469b27348
commit
080a384ade
@ -154,7 +154,7 @@ type Room struct {
|
|||||||
State int32
|
State int32
|
||||||
Index int
|
Index int
|
||||||
RenderFrameId int32
|
RenderFrameId int32
|
||||||
CurDynamicsRenderFrameId int32 // [WARNING] The dynamics of backend is ALWAYS MOVING FORWARD BY ALL-CONFIRMED INPUTFRAMES (either by upsync or forced), i.e. no rollback
|
CurDynamicsRenderFrameId int32 // [WARNING] The dynamics of backend is ALWAYS MOVING FORWARD BY ALL-CONFIRMED INPUTFRAMES (either by upsync or forced), i.e. no rollback; Moreover when "true == BackendDynamicsEnabled" we always have "Room.CurDynamicsRenderFrameId >= Room.RenderFrameId" because each "all-confirmed inputFrame" is applied on "all applicable renderFrames" in one-go hence often sees a future "renderFrame" earlier
|
||||||
EffectivePlayerCount int32
|
EffectivePlayerCount int32
|
||||||
DismissalWaitGroup sync.WaitGroup
|
DismissalWaitGroup sync.WaitGroup
|
||||||
Barriers map[int32]*Barrier
|
Barriers map[int32]*Barrier
|
||||||
@ -166,9 +166,10 @@ type Room struct {
|
|||||||
LastAllConfirmedInputList []uint64
|
LastAllConfirmedInputList []uint64
|
||||||
JoinIndexBooleanArr []bool
|
JoinIndexBooleanArr []bool
|
||||||
|
|
||||||
BackendDynamicsEnabled bool
|
BackendDynamicsEnabled bool
|
||||||
LastRenderFrameIdTriggeredAt int64
|
BackendDynamicsForceConfirmationEnabled bool
|
||||||
PlayerDefaultSpeed int32
|
LastRenderFrameIdTriggeredAt int64
|
||||||
|
PlayerDefaultSpeed int32
|
||||||
|
|
||||||
BulletBattleLocalIdCounter int32
|
BulletBattleLocalIdCounter int32
|
||||||
dilutedRollbackEstimatedDtNanos int64
|
dilutedRollbackEstimatedDtNanos int64
|
||||||
@ -334,6 +335,10 @@ func (pR *Room) ConvertToGeneratingRenderFrameId(inputFrameId int32) int32 {
|
|||||||
return (inputFrameId << pR.InputScaleFrames)
|
return (inputFrameId << pR.InputScaleFrames)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pR *Room) ConvertToJustBeforeNextGeneratingRenderFrameId(inputFrameId int32) int32 {
|
||||||
|
return (inputFrameId << pR.InputScaleFrames) + (1 << pR.InputScaleFrames) - 1
|
||||||
|
}
|
||||||
|
|
||||||
func (pR *Room) ConvertToFirstUsedRenderFrameId(inputFrameId int32, inputDelayFrames int32) int32 {
|
func (pR *Room) ConvertToFirstUsedRenderFrameId(inputFrameId int32, inputDelayFrames int32) int32 {
|
||||||
return ((inputFrameId << pR.InputScaleFrames) + inputDelayFrames)
|
return ((inputFrameId << pR.InputScaleFrames) + inputDelayFrames)
|
||||||
}
|
}
|
||||||
@ -408,6 +413,7 @@ func (pR *Room) StartBattle() {
|
|||||||
pR.onBattleStoppedForSettlement()
|
pR.onBattleStoppedForSettlement()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
battleStartedAtNanos := utils.UnixtimeNano()
|
||||||
pR.LastRenderFrameIdTriggeredAt = utils.UnixtimeNano()
|
pR.LastRenderFrameIdTriggeredAt = utils.UnixtimeNano()
|
||||||
|
|
||||||
Logger.Info("The `battleMainLoop` is started for:", zap.Any("roomId", pR.Id))
|
Logger.Info("The `battleMainLoop` is started for:", zap.Any("roomId", pR.Id))
|
||||||
@ -416,7 +422,10 @@ func (pR *Room) StartBattle() {
|
|||||||
|
|
||||||
elapsedNanosSinceLastFrameIdTriggered := stCalculation - pR.LastRenderFrameIdTriggeredAt
|
elapsedNanosSinceLastFrameIdTriggered := stCalculation - pR.LastRenderFrameIdTriggeredAt
|
||||||
if elapsedNanosSinceLastFrameIdTriggered < pR.dilutedRollbackEstimatedDtNanos {
|
if elapsedNanosSinceLastFrameIdTriggered < pR.dilutedRollbackEstimatedDtNanos {
|
||||||
Logger.Debug(fmt.Sprintf("Avoiding too fast frame@roomId=%v, renderFrameId=%v: elapsedNanosSinceLastFrameIdTriggered=%v", pR.Id, pR.RenderFrameId, elapsedNanosSinceLastFrameIdTriggered))
|
totalElapsedNanos := (stCalculation - battleStartedAtNanos)
|
||||||
|
serverFpsByFar := float64(pR.RenderFrameId) * float64(1000000000) / float64(totalElapsedNanos)
|
||||||
|
Logger.Info(fmt.Sprintf("Avoiding too fast frame@roomId=%v, renderFrameId=%v, totalElapsedNanos=%v, serverFpsByFar=%v: elapsedNanosSinceLastFrameIdTriggered=%v", pR.Id, pR.RenderFrameId, totalElapsedNanos, serverFpsByFar, elapsedNanosSinceLastFrameIdTriggered))
|
||||||
|
time.Sleep(time.Duration(pR.dilutedRollbackEstimatedDtNanos - elapsedNanosSinceLastFrameIdTriggered))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,7 +447,7 @@ func (pR *Room) StartBattle() {
|
|||||||
|
|
||||||
pR.markConfirmationIfApplicable()
|
pR.markConfirmationIfApplicable()
|
||||||
unconfirmedMask := uint64(0)
|
unconfirmedMask := uint64(0)
|
||||||
if pR.BackendDynamicsEnabled {
|
if pR.BackendDynamicsForceConfirmationEnabled {
|
||||||
// Force setting all-confirmed of buffered inputFrames periodically
|
// Force setting all-confirmed of buffered inputFrames periodically
|
||||||
unconfirmedMask = pR.forceConfirmationIfApplicable()
|
unconfirmedMask = pR.forceConfirmationIfApplicable()
|
||||||
}
|
}
|
||||||
@ -452,10 +461,7 @@ func (pR *Room) StartBattle() {
|
|||||||
|
|
||||||
Upon resync, it's still possible that "refRenderFrameId < frontend.chaserRenderFrameId" -- and this is allowed.
|
Upon resync, it's still possible that "refRenderFrameId < frontend.chaserRenderFrameId" -- and this is allowed.
|
||||||
*/
|
*/
|
||||||
refRenderFrameId := pR.ConvertToGeneratingRenderFrameId(upperToSendInputFrameId) + (1 << pR.InputScaleFrames) - 1
|
refRenderFrameId := pR.ConvertToJustBeforeNextGeneratingRenderFrameId(upperToSendInputFrameId)
|
||||||
if refRenderFrameId > pR.RenderFrameId {
|
|
||||||
refRenderFrameId = pR.RenderFrameId
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamicsDuration := int64(0)
|
dynamicsDuration := int64(0)
|
||||||
if pR.BackendDynamicsEnabled {
|
if pR.BackendDynamicsEnabled {
|
||||||
@ -467,11 +473,10 @@ func (pR *Room) StartBattle() {
|
|||||||
pR.applyInputFrameDownsyncDynamics(pR.CurDynamicsRenderFrameId, nextDynamicsRenderFrameId, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY)
|
pR.applyInputFrameDownsyncDynamics(pR.CurDynamicsRenderFrameId, nextDynamicsRenderFrameId, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY)
|
||||||
dynamicsDuration = utils.UnixtimeNano() - dynamicsStartedAt
|
dynamicsDuration = utils.UnixtimeNano() - dynamicsStartedAt
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// [WARNING] The following inequality are seldom true, but just to avoid that in good network condition the frontend resyncs itself to a "too advanced frontend.renderFrameId", and then starts upsyncing "too advanced inputFrameId".
|
if refRenderFrameId > pR.RenderFrameId {
|
||||||
if refRenderFrameId > pR.CurDynamicsRenderFrameId {
|
refRenderFrameId = pR.RenderFrameId
|
||||||
refRenderFrameId = pR.CurDynamicsRenderFrameId
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for playerId, player := range pR.Players {
|
for playerId, player := range pR.Players {
|
||||||
@ -576,7 +581,8 @@ func (pR *Room) StartBattle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pR.RenderFrameId++
|
pR.RenderFrameId++
|
||||||
elapsedInCalculation := (utils.UnixtimeNano() - stCalculation)
|
pR.LastRenderFrameIdTriggeredAt = utils.UnixtimeNano()
|
||||||
|
elapsedInCalculation := (pR.LastRenderFrameIdTriggeredAt - stCalculation)
|
||||||
if elapsedInCalculation > pR.dilutedRollbackEstimatedDtNanos {
|
if elapsedInCalculation > pR.dilutedRollbackEstimatedDtNanos {
|
||||||
Logger.Warn(fmt.Sprintf("SLOW FRAME! Elapsed time statistics: roomId=%v, room.RenderFrameId=%v, elapsedInCalculation=%v ns, dynamicsDuration=%v ns, dilutedRollbackEstimatedDtNanos=%v", pR.Id, pR.RenderFrameId, elapsedInCalculation, dynamicsDuration, pR.dilutedRollbackEstimatedDtNanos))
|
Logger.Warn(fmt.Sprintf("SLOW FRAME! Elapsed time statistics: roomId=%v, room.RenderFrameId=%v, elapsedInCalculation=%v ns, dynamicsDuration=%v ns, dilutedRollbackEstimatedDtNanos=%v", pR.Id, pR.RenderFrameId, elapsedInCalculation, dynamicsDuration, pR.dilutedRollbackEstimatedDtNanos))
|
||||||
}
|
}
|
||||||
@ -792,7 +798,7 @@ func (pR *Room) OnDismissed() {
|
|||||||
pR.RenderFrameId = 0
|
pR.RenderFrameId = 0
|
||||||
pR.CurDynamicsRenderFrameId = 0
|
pR.CurDynamicsRenderFrameId = 0
|
||||||
pR.InputDelayFrames = 8
|
pR.InputDelayFrames = 8
|
||||||
pR.NstDelayFrames = 4
|
pR.NstDelayFrames = pR.InputDelayFrames
|
||||||
pR.InputScaleFrames = uint32(2)
|
pR.InputScaleFrames = uint32(2)
|
||||||
pR.ServerFps = 60
|
pR.ServerFps = 60
|
||||||
pR.RollbackEstimatedDtMillis = 16.667 // Use fixed-and-low-precision to mitigate the inconsistent floating-point-number issue between Golang and JavaScript
|
pR.RollbackEstimatedDtMillis = 16.667 // Use fixed-and-low-precision to mitigate the inconsistent floating-point-number issue between Golang and JavaScript
|
||||||
@ -805,6 +811,7 @@ func (pR *Room) OnDismissed() {
|
|||||||
pR.MaxChasingRenderFramesPerUpdate = 5
|
pR.MaxChasingRenderFramesPerUpdate = 5
|
||||||
|
|
||||||
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.BackendDynamicsForceConfirmationEnabled = (pR.BackendDynamicsEnabled && true)
|
||||||
punchSkillId := int32(1)
|
punchSkillId := int32(1)
|
||||||
pR.MeleeSkillConfig = make(map[int32]*MeleeBullet, 0)
|
pR.MeleeSkillConfig = make(map[int32]*MeleeBullet, 0)
|
||||||
pR.MeleeSkillConfig[punchSkillId] = &MeleeBullet{
|
pR.MeleeSkillConfig[punchSkillId] = &MeleeBullet{
|
||||||
|
@ -440,7 +440,7 @@
|
|||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
210.5241291124452,
|
342.9460598986377,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -454,7 +454,7 @@
|
|||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
210.5241291124452,
|
342.9460598986377,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -82,21 +82,21 @@ cc.Class({
|
|||||||
// It turns out that "prevRdfPlayer.characterState" is not useful in this function :)
|
// It turns out that "prevRdfPlayer.characterState" is not useful in this function :)
|
||||||
if (newAnimName == playingAnimName && window.ATK_CHARACTER_STATE_INTERRUPT_WAIVE_SET.has(newCharacterState)) {
|
if (newAnimName == playingAnimName && window.ATK_CHARACTER_STATE_INTERRUPT_WAIVE_SET.has(newCharacterState)) {
|
||||||
// No need to interrupt
|
// No need to interrupt
|
||||||
// console.warn(`JoinIndex=${rdfPlayer.joinIndex}, not interrupting ${newAnimName} while the playing anim is also ${playingAnimName}, player rdf changed from: ${null == prevRdfPlayer ? null : JSON.stringify(prevRdfPlayer)}, , to: ${JSON.stringify(rdfPlayer)}`);
|
// console.warn(`JoinIndex=${rdfPlayer.joinIndex}, not interrupting ${newAnimName} while the playing anim is also ${playingAnimName}, player rdf changed from: ${null == prevRdfPlayer ? null : JSON.stringify(prevRdfPlayer)}, to: ${JSON.stringify(rdfPlayer)}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.animComp instanceof dragonBones.ArmatureDisplay) {
|
if (this.animComp instanceof dragonBones.ArmatureDisplay) {
|
||||||
this._interruptPlayingAnimAndPlayNewAnimDragonBones(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName, underlyingAnimationCtrl);
|
this._interruptPlayingAnimAndPlayNewAnimDragonBones(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName, underlyingAnimationCtrl, playingAnimName);
|
||||||
} else {
|
} else {
|
||||||
this._interruptPlayingAnimAndPlayNewAnimFrameAnim(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName);
|
this._interruptPlayingAnimAndPlayNewAnimFrameAnim(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName, playingAnimName);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_interruptPlayingAnimAndPlayNewAnimDragonBones(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName, underlyingAnimationCtrl) {
|
_interruptPlayingAnimAndPlayNewAnimDragonBones(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName, underlyingAnimationCtrl, playingAnimName) {
|
||||||
if (ATK_CHARACTER_STATE.Idle1[0] == newCharacterState || ATK_CHARACTER_STATE.Walking[0] == newCharacterState) {
|
if (window.ATK_CHARACTER_STATE_INTERRUPT_WAIVE_SET.has(newCharacterState)) {
|
||||||
// No "framesToRecover"
|
// No "framesToRecover"
|
||||||
// console.warn(`JoinIndex=${rdfPlayer.joinIndex}, playing new ${newAnimName} from the beginning: while the playing anim is ${playAnimation}, player rdf changed from: ${null == prevRdfPlayer ? null : JSON.stringify(prevRdfPlayer)}, , to: ${JSON.stringify(rdfPlayer)}`);
|
console.warn(`#DragonBones JoinIndex=${rdfPlayer.joinIndex}, playing new ${newAnimName} from the beginning: while the playing anim is ${playingAnimName}, player rdf changed from: ${null == prevRdfPlayer ? null : JSON.stringify(prevRdfPlayer)}, to: ${JSON.stringify(rdfPlayer)}`);
|
||||||
underlyingAnimationCtrl.gotoAndPlayByFrame(newAnimName, 0, -1);
|
underlyingAnimationCtrl.gotoAndPlayByFrame(newAnimName, 0, -1);
|
||||||
} else {
|
} else {
|
||||||
const animationData = underlyingAnimationCtrl._animations[newAnimName];
|
const animationData = underlyingAnimationCtrl._animations[newAnimName];
|
||||||
@ -109,10 +109,10 @@ cc.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_interruptPlayingAnimAndPlayNewAnimFrameAnim(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName) {
|
_interruptPlayingAnimAndPlayNewAnimFrameAnim(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName, playingAnimName) {
|
||||||
if (window.ATK_CHARACTER_STATE_INTERRUPT_WAIVE_SET.has(newCharacterState)) {
|
if (window.ATK_CHARACTER_STATE_INTERRUPT_WAIVE_SET.has(newCharacterState)) {
|
||||||
// No "framesToRecover"
|
// No "framesToRecover"
|
||||||
// console.warn(`JoinIndex=${rdfPlayer.joinIndex}, playing new ${newAnimName} from the beginning: while the playing anim is ${playAnimation}, player rdf changed from: ${null == prevRdfPlayer ? null : JSON.stringify(prevRdfPlayer)}, , to: ${JSON.stringify(rdfPlayer)}`);
|
console.warn(`#FrameAnim JoinIndex=${rdfPlayer.joinIndex}, playing new ${newAnimName} from the beginning: while the playing anim is ${playingAnimName}, player rdf changed from: ${null == prevRdfPlayer ? null : JSON.stringify(prevRdfPlayer)}, to: ${JSON.stringify(rdfPlayer)}`);
|
||||||
this.animComp.play(newAnimName, 0);
|
this.animComp.play(newAnimName, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user