Code archives/Miscellaneous/Millisecond timer without integer wrap problems

This code has been declared by its author to be Public Domain code.

Download source code

Millisecond timer without integer wrap problems by BlitzSupport2009
MilliSecs () can wrap from the highest integer value possible, 2147483647, to the lowest integer value, -2147483648, at any time, up to a maximum of 49 days, potentially causing weird effects in game timing, and potentially disastrous effects for long-running applications/server processes, etc.

This means that if your end user's PC has been running without a reboot for that long, your program may find MilliSecs () suddenly switches from a positive value to a negative value. This system means you don't have to worry about the result wrapping around, unless you expect your program to be running in 200 million years. Perhaps if it's a Unix app, though...

To use GameTime, call ResetGameTime () at the start of your code (this is mandatory) and simply use GameTime () as a direct replacement for MilliSecs ().

Important! Any direct comparisons with GameTime's result should use Long values, otherwise you may run into MilliSecs-type wrap effects, missing the point completely!

For more details, proof-of-concept demo and alternative community solutions to MilliSecs () integer wrapping, see this thread.
SuperStrict ' You can remove this if you don't want it!

' -----------------------------------------------------------------------------
' These globals MUST be included in your code!
' -----------------------------------------------------------------------------

Global GT_Start:Long	' Start of game time
Global GT_Last:Int		' Last INTEGER value of MilliSecs ()
Global GT_Current:Long	' LONG value updated by MilliSecs ()

' -----------------------------------------------------------------------------
' ResetGameTime MUST be called at the start of your game, or at least
' before you first try to use the GameTime function...
' -----------------------------------------------------------------------------

' You can also call this to reset GameTime on reaching a new level, starting
' a new game after the player dies, etc...

Function ResetGameTime:Int ()
	GT_Current	= 0
	GT_Start		= Long (MilliSecs ())
	GT_Last		= GT_Start
End Function

' -----------------------------------------------------------------------------
' Returns milliseconds from when ResetGameTime was called...
' -----------------------------------------------------------------------------

Function GameTime:Long ()

	Local msi:Int = MilliSecs ()

	GT_Current = GT_Current + (msi - GT_Last)
	GT_Last = msi

	Return GT_Current

End Function

' -----------------------------------------------------------------------------
' D E M O . . .
' -----------------------------------------------------------------------------

AppTitle = "Click mouse to reset game time!"

Graphics 640, 480

ResetGameTime ()

Local iticks:Int = MilliSecs ()
Local isecs:Int

Local lticks:Long = GameTime ()
Local lsecs:Long

Repeat

	If MouseHit (1)

		ResetGameTime ()

		iticks = MilliSecs ()
		isecs = 0
		
		lticks = GameTime ()
		lsecs = 0

	EndIf
	
	Cls
	
	If GameTime () => lticks + 1000
		lsecs = lsecs + 1
		lticks = GameTime ()
	EndIf
	
	DrawText "GameTime: " + lsecs + " [" + GameTime () + "]", 20, 20

	If MilliSecs () => iticks + 1000
		isecs = isecs + 1
		iticks = MilliSecs ()
	EndIf
	
	DrawText "MilliSecs: " + isecs + " [" + MilliSecs () + "]", 20, 40

	Flip
	
Until KeyHit (KEY_ESCAPE)

End

Comments

Nate the Great2009
hey thats great but is it really important for a simple short game or is it only if you want to make an application that runs for days at a time?


Jesse2009
I would think that it's for any game that's run on a computer that's been on long enough and not necessarily the game. The need is definite.


BlitzSupport2009
What Jesse said. It's not whether your game runs for 49 days, but whether the end user's OS has been running for almost that long and then your game is launched. The end user's MilliSecs () value would be reaching the limits of what an integer variable can hold, then it wraps to a negative number.


Code Archives Forum