From 59567993c225bf928e764939560c2a08e258f4e4 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 20 Dec 2020 23:40:11 +0900 Subject: [PATCH] clock: Bug fix: High TPS didn't work well due to the timer precision When the TPS is high (e.g., 300), the count might be unreliable since the timer might not be precise on some machines. In this case, calculate the factor and multiply the count by it. Fixes #1444 --- internal/clock/clock.go | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/internal/clock/clock.go b/internal/clock/clock.go index cecddf3f1..18f749ef4 100644 --- a/internal/clock/clock.go +++ b/internal/clock/clock.go @@ -29,6 +29,8 @@ var ( currentFPS float64 currentTPS float64 + lastTPS int64 + tpsCalcErr int64 lastUpdated int64 fpsCount = 0 tpsCount = 0 @@ -64,6 +66,28 @@ func min(a, b int64) int64 { return b } +// calcTPSFactor calculates the TPS that is used for the timer and the factor for the count. +// If tps is under the baseTPS, use tps as newTPS. The factor is 1. The timer precision should be enough. +// If not, use baseTPS as newTPS and factor that can be more than 1. +func calcTPSFactor(tps, baseTPS int64) (newTPS int64, factor int) { + if tps <= baseTPS { + return tps, 1 + } + + if lastTPS != tps { + tpsCalcErr = 0 + } + lastTPS = tps + + factor = int(tps / baseTPS) + tpsCalcErr += tps - baseTPS*int64(factor) + + factor += int(tpsCalcErr / baseTPS) + tpsCalcErr %= baseTPS + + return baseTPS, factor +} + func calcCountFromTPS(tps int64, now int64) int { if tps == 0 { return 0 @@ -80,10 +104,12 @@ func calcCountFromTPS(tps int64, now int64) int { count := 0 syncWithSystemClock := false - // When TPS is big (e.g. 300), the time gap can be small and diff might always exceeds the gap. - // To avoid this, prepare another gap assuming TPS was 60 and use the bigger one (#1443). - tooBigGap := int64(time.Second) * 5 / min(int64(tps), 60) - if diff > tooBigGap { + // When TPS is big (e.g. 300), the timer precision is no longer reliable. + // Multiply the factor later instead (#1444). + var tpsFactor int + tps, tpsFactor = calcTPSFactor(tps, 60) // TODO: 60 should be the current display's FPS. + + if diff > int64(time.Second)*5/tps { // The previous time is too old. // Let's force to sync the game time with the system clock. syncWithSystemClock = true @@ -107,7 +133,7 @@ func calcCountFromTPS(tps int64, now int64) int { lastSystemTime += int64(count) * int64(time.Second) / tps } - return count + return count * tpsFactor } func updateFPSAndTPS(now int64, count int) {