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) {