mirror of
				https://github.com/genxium/DelayNoMore
				synced 2025-10-31 19:37:00 +00:00 
			
		
		
		
	Added backend dynamics toggle.
This commit is contained in:
		| @@ -188,6 +188,7 @@ type Room struct { | ||||
| 	StageTileH                     int32 | ||||
| 	RawBattleStrToVec2DListMap     StrToVec2DListMap | ||||
| 	RawBattleStrToPolygon2DListMap StrToPolygon2DListMap | ||||
|     BackendDynamicsEnabled         bool | ||||
| } | ||||
|  | ||||
| const ( | ||||
| @@ -459,17 +460,12 @@ func (pR *Room) StartBattle() { | ||||
| 			} | ||||
|  | ||||
| 			// Force setting all-confirmed of buffered inputFrames periodically | ||||
| 			unconfirmedMask := pR.forceConfirmationIfApplicable() | ||||
|  | ||||
| 			dynamicsDuration := int64(0) | ||||
| 			if 0 <= pR.LastAllConfirmedInputFrameId { | ||||
| 				dynamicsStartedAt := utils.UnixtimeNano() | ||||
| 				// Apply "all-confirmed inputFrames" to move forward "pR.CurDynamicsRenderFrameId" | ||||
| 				nextDynamicsRenderFrameId := pR.ConvertToLastUsedRenderFrameId(pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames) | ||||
| 				Logger.Debug(fmt.Sprintf("roomId=%v, room.RenderFrameId=%v, LastAllConfirmedInputFrameId=%v, InputDelayFrames=%v, nextDynamicsRenderFrameId=%v", pR.Id, pR.RenderFrameId, pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames, nextDynamicsRenderFrameId)) | ||||
| 				pR.applyInputFrameDownsyncDynamics(pR.CurDynamicsRenderFrameId, nextDynamicsRenderFrameId) | ||||
| 				dynamicsDuration = utils.UnixtimeNano() - dynamicsStartedAt | ||||
| 			} | ||||
| 			unconfirmedMask := uint64(0) | ||||
|             if pR.BackendDynamicsEnabled { | ||||
|                unconfirmedMask = pR.forceConfirmationIfApplicable() | ||||
|             } else { | ||||
|                pR.markConfirmationIfApplicable() | ||||
|             } | ||||
|  | ||||
| 			upperToSendInputFrameId := atomic.LoadInt32(&(pR.LastAllConfirmedInputFrameId)) | ||||
| 			/* | ||||
| @@ -481,13 +477,26 @@ func (pR *Room) StartBattle() { | ||||
| 			   Hence even upon resync, it's still possible that "refRenderFrameId < frontend.chaserRenderFrameId". | ||||
| 			*/ | ||||
| 			refRenderFrameId := pR.ConvertToGeneratingRenderFrameId(upperToSendInputFrameId) + (1 << pR.InputScaleFrames) - 1 | ||||
| 			// [WARNING] The following inequalities 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 { | ||||
| 				refRenderFrameId = pR.RenderFrameId | ||||
| 			} | ||||
| 			if refRenderFrameId > pR.CurDynamicsRenderFrameId { | ||||
| 				refRenderFrameId = pR.CurDynamicsRenderFrameId | ||||
| 			} | ||||
|  | ||||
|             dynamicsDuration := int64(0) | ||||
|             if pR.BackendDynamicsEnabled { | ||||
|                 if 0 <= pR.LastAllConfirmedInputFrameId { | ||||
|                     dynamicsStartedAt := utils.UnixtimeNano() | ||||
|                     // Apply "all-confirmed inputFrames" to move forward "pR.CurDynamicsRenderFrameId" | ||||
|                     nextDynamicsRenderFrameId := pR.ConvertToLastUsedRenderFrameId(pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames) | ||||
|                     Logger.Debug(fmt.Sprintf("roomId=%v, room.RenderFrameId=%v, LastAllConfirmedInputFrameId=%v, InputDelayFrames=%v, nextDynamicsRenderFrameId=%v", pR.Id, pR.RenderFrameId, pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames, nextDynamicsRenderFrameId)) | ||||
|                     pR.applyInputFrameDownsyncDynamics(pR.CurDynamicsRenderFrameId, nextDynamicsRenderFrameId) | ||||
|                     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.CurDynamicsRenderFrameId { | ||||
|                     refRenderFrameId = pR.CurDynamicsRenderFrameId | ||||
|                 } | ||||
|             }   | ||||
| 			for playerId, player := range pR.Players { | ||||
| 				if swapped := atomic.CompareAndSwapInt32(&player.BattleState, PlayerBattleStateIns.ACTIVE, PlayerBattleStateIns.ACTIVE); !swapped { | ||||
| 					// [WARNING] DON'T send anything if the player is disconnected, because it could jam the channel and cause significant delay upon "battle recovery for reconnected player". | ||||
| @@ -537,7 +546,7 @@ func (pR *Room) StartBattle() { | ||||
|  | ||||
| 					indiceInJoinIndexBooleanArr := uint32(player.JoinIndex - 1) | ||||
| 					var joinMask uint64 = (1 << indiceInJoinIndexBooleanArr) | ||||
| 					if MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED == player.LastSentInputFrameId || 0 < (unconfirmedMask&joinMask) { | ||||
| 					if pR.BackendDynamicsEnabled && (MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED == player.LastSentInputFrameId || 0 < (unconfirmedMask&joinMask)) { | ||||
| 						// [WARNING] Even upon "MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED", it could be true that "0 == (unconfirmedMask & joinMask)"! | ||||
| 						tmp := pR.RenderFrameBuffer.GetByFrameId(refRenderFrameId) | ||||
| 						if nil == tmp { | ||||
| @@ -801,6 +810,8 @@ func (pR *Room) OnDismissed() { | ||||
| 	pR.InputFrameUpsyncDelayTolerance = 2 | ||||
| 	pR.MaxChasingRenderFramesPerUpdate = 10 | ||||
|  | ||||
|     pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work! | ||||
|  | ||||
| 	pR.ChooseStage() | ||||
| 	pR.EffectivePlayerCount = 0 | ||||
|  | ||||
| @@ -1068,6 +1079,43 @@ func (pR *Room) prefabInputFrameDownsync(inputFrameId int32) *pb.InputFrameDowns | ||||
| 	return currInputFrameDownsync | ||||
| } | ||||
|  | ||||
| func (pR *Room) markConfirmationIfApplicable() { | ||||
| 	inputFrameId1 := pR.LastAllConfirmedInputFrameId+1 | ||||
|     gap := int32(4) // This value is hardcoded and doesn't need be much bigger, because the backend side is supposed to never lag when "false == BackendDynamicsEnabled".  | ||||
| 	inputFrameId2 := inputFrameId1+gap  | ||||
|     if inputFrameId2 > pR.InputsBuffer.EdFrameId { | ||||
|         inputFrameId2 = pR.InputsBuffer.EdFrameId | ||||
|     } | ||||
|  | ||||
|     totPlayerCnt := uint32(pR.Capacity) | ||||
|     allConfirmedMask := uint64((1 << totPlayerCnt) - 1) | ||||
|     for inputFrameId := inputFrameId1; inputFrameId < inputFrameId2; inputFrameId++ { | ||||
|         tmp := pR.InputsBuffer.GetByFrameId(inputFrameId) | ||||
|         if nil == tmp { | ||||
|             panic(fmt.Sprintf("inputFrameId=%v doesn't exist for roomId=%v, this is abnormal because the server should prefab inputFrameDownsync in a most advanced pace, check the prefab logic! InputsBuffer=%v", inputFrameId, pR.Id, pR.InputsBufferString(false))) | ||||
|         } | ||||
|         inputFrameDownsync := tmp.(*pb.InputFrameDownsync) | ||||
|         for _, player := range pR.Players { | ||||
|             bufIndex := pR.toDiscreteInputsBufferIndex(inputFrameId, player.JoinIndex) | ||||
|             tmp, loaded := pR.DiscreteInputsBuffer.LoadAndDelete(bufIndex) // It's safe to "LoadAndDelete" here because the "inputFrameUpsync" of this player is already remembered by the corresponding "inputFrameDown".  | ||||
|             if !loaded { | ||||
|                 continue | ||||
|             } | ||||
|             inputFrameUpsync := tmp.(*pb.InputFrameUpsync) | ||||
|             indiceInJoinIndexBooleanArr := uint32(player.JoinIndex - 1) | ||||
|             inputFrameDownsync.InputList[indiceInJoinIndexBooleanArr] = pR.EncodeUpsyncCmd(inputFrameUpsync) | ||||
|             inputFrameDownsync.ConfirmedList |= (1 << indiceInJoinIndexBooleanArr) | ||||
|         } | ||||
|  | ||||
|         // Force confirmation of "inputFrame2" | ||||
|         if allConfirmedMask == inputFrameDownsync.ConfirmedList {      | ||||
|             pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, -1) | ||||
|         } else { | ||||
|             break | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| func (pR *Room) forceConfirmationIfApplicable() uint64 { | ||||
| 	// Force confirmation of non-all-confirmed inputFrame EXACTLY ONE AT A TIME, returns the non-confirmed mask of players, e.g. in a 4-player-battle returning 1001 means that players with JoinIndex=1 and JoinIndex=4 are non-confirmed for inputFrameId2 | ||||
| 	renderFrameId1 := (pR.RenderFrameId - pR.NstDelayFrames) // the renderFrameId which should've been rendered on frontend | ||||
|   | ||||
		Reference in New Issue
	
	Block a user