The reason that Dark BASIC Professional (and Dark BASIC) both had a Timer Call based upon System Uptime (i.e. from when the OS was last booted) is because that's how Windows itself handles the System Timer.
This isn't actually how most Modern OS work... as I recall there is no way (without creating a Service Runtime to track it) to find out the current "Uptime" of most OS.
It's typically not even useful info to know.
As consider that with System Time from Boot., it's entirely possible to easily hit the "Maximum" of the 32bit Value.
I mean it resets every ~1,193hrs (49 Days 17 Hrs) ... which given that most people put their Computers into "Sleep" or "Hibernation" Mode instead of actually turning them Off., means that should you track this information; likelihood of actually hitting the "Maximum" is higher than you might think; which for Applications that don't account for this, means you're going to get some interesting "Quirks" occur at said point.
Conversely speaking however., you're VERY unlikely to hit this for when an Individual Application is being run; as you're typically not always going to have them Open / Running.
So it's better to have a "New" Timer specifically for the Application.
•
Actually, what I find weird is that AppGameKit still uses a Single Application Timer... rather providing a Timer Framework that allows you to create Multiple Timers.
I mean I've done that myself:
// Region: Copied from Common.agc
#Constant True -1
#Constant False 0
#Constant KEY_ESCAPE 27
// EndRegion
Type Timer_t
Old As Float
New As Float
Delta As Float
Period As Float
Count As Float
Reset As Integer
EndType
Global AppTimers As Timer_t[]
// Create Main Logic Timer
Global MainLogic As Integer
MainLogic = CreateTimer( 60.0 )
// Example Code::
Do
UpdateTimer( 0 )
// 60Hz Main Logic
If AppTimers[MainLogic].Reset = True
If GetRawKeyPressed( KEY_ESCAPE )
// Note: Perform Garbage Collection Here
// ReleaseTimers() // This keeps crashing Windows?! Might need to figure out why :)
Exit
EndIf
// Default AGK Output
Print( ScreenFPS() )
// ToDo: Change to a "Full" Approach over All-in-One Sync()
Sync()
EndIf
Loop
// Example Code
// Please Note: Currently there is no way to Delete / Release an Individual Timer
// Create (Add) Timer to Stack
Function CreateTimer( ResetPeriod As Float )
// Make Sure the ResetPeriod (in Hz) is Positive
If ResetPeriod < 0
//ErrorThrow( ERROR_FUNC_IO, "Timer: Negative Reset Period" ) // ToDo: Add Debug/Error Functions
ExitFunction False
EndIf
Local Period As Float : Period = (1000.0 / ResetPeriod) : Period = Period * 0.001
Local Element As Integer : Element = AppTimers.length + 1 // Insert a new Array Element
// Resize the Array, then Populate
AppTimers.length = Element
AppTimers[Element].New = Timer()
AppTimers[Element].Period = Period
AppTimers[Element].Old = AppTimers[Element].New
// Finally we Return the Timer ID
EndFunction Element
// Update Timer(s) Function
Function UpdateTimer( TimerID As Integer )
// Store Timer() to Synchronise all Timers
Local Current As Float : Current = Timer()
Local Max, Min As Integer
// Check if we're updating an Individual or All Timers
If TimerID = Not False
Min = TimerID
Max = TimerID
Else
Min = 0
Max = AppTimers.length
EndIf
// Update Timer(s)
For Index = Min To Max
// Has the Period been Triggered?
If AppTimers[Index].Reset = True
AppTimers[Index].Reset = False // If so, we Reset the Period
EndIf
// Update Logic
AppTimers[Index].Old = AppTimers[Index].New
AppTimers[Index].New = Current
AppTimers[Index].Delta = AppTimers[Index].New - AppTimers[Index].Old // Difference between Timer Calls
Inc AppTimers[Index].Count, AppTimers[Index].Delta // Increase the Count Period
// Check to see if we've achieved the Trigger Period
If AppTimers[Index].Count >= AppTimers[Index].Period
AppTimers[Index].Reset = True
AppTimers[Index].Count = 0.0
EndIf
Next
EndFunction
But, yeah... interesting how such an approach isn't "Built-In"
Mind... I've always been curious as to why "True" and "False" aren't Default Values as they are in most other Languages.
•
Now assuming that you don't actually want to create a Plug-In... provided you're on Windows, you can do this:
Cmd = RunApp("cmd", "/C WMIC path Win32_OperatingSystem get LastBootUpTime >> "+ ROOT_DIR +"time.txt")
/*
Repeat
// We're just killing time while CMD does it's thing
Until GetFileExists( "time.txt" )
*/
Sleep(1000) // Hack to allow Cmd to Complete, given AGK doesn't want to believe the dang file exists
// Note: If you Terminate Cmd BEFORE this it doesn't write the txt file.
// We ran it with /C, which means "Close after Complete" but let's just make sure
If GetAppRunning( Cmd )
TerminateApp( Cmd )
EndIf
Type WindowsDate
Year As Integer
Month As Integer
Day As Integer
Hour As Integer
Minutes As Integer
Seconds As Integer
Milliseconds As Integer
GMT As Integer
EndType
LastBootUpTime As WindowsDate
FileExists As Integer
FileExists = GetFileExists( ROOT_DIR + "time.txt")
TimeFile As Integer
If FileExists
Time As String
TimeFile = OpenToRead( ROOT_DIR + "time.txt" )
Time = ReadString( TimeFile )
Time = ReadString( TimeFile )
CloseFile( TimeFile )
LastBootUpTime.Year = Val(Left(Time, 4))
LastBootUpTime.Month = Val(Right(Left(Time, 6), 2))
LastBootUpTime.Day = Val(Right(Left(Time, 8), 2))
LastBootUpTime.Hour = Val(Right(Left(Time, 10), 2))
LastBootUpTime.Minutes = Val(Right(Left(Time, 12), 2))
LastBootUpTime.Seconds = Val(Right(Left(Time, 14), 2))
LastBootupTime.Milliseconds = Val(Left(GetStringToken(Time,".",2),5))
LastBootUpTime.GMT = Val(Right(Time, 5))
EndIf
Do
Print(GetWritePath())
Print("Does File Exist: " + Str(FileExists))
Print("Raw: " + Time$)
Sync()
If GetRawKeyPressed(27) Then Exit
Loop
Now as a note... I don't get along with the File Commands in AGK.
No idea WTF I'm doing wrong with them., but regardless... the file does exist; and if you follow the filepath in the app you can verify it's existence and that it's just a standard text file.
Why AppGameKit doesn't believe that - frankly I gave up trying to figure out.
Still it should provide you with what you want.