2024-04-17 22:54:09 -06:00
---@class TimerPrivateProps
---@field initialTime number the initial duration of the timer.
---@field async? boolean wether the timer should run asynchronously or not
---@field startTime number the gametimer stamp of when the timer starts. changes when paused and played
---@field triggerOnEnd boolean set in the forceEnd method using the optional param. wether or not the onEnd function is triggered when force ending the timer early
---@field currentTimeLeft number current timer length
---@field paused boolean the pause state of the timer
---@class OxTimer : OxClass
2024-04-20 06:55:56 +10:00
---@field private private TimerPrivateProps
2024-04-17 22:54:09 -06:00
---@field start fun(self: self, async?: boolean) starts the timer
2025-01-28 06:47:48 +11:00
---@field onEnd? fun() cb function triggered when the timer finishes
2024-04-17 22:54:09 -06:00
---@field forceEnd fun(self: self, triggerOnEnd: boolean) end timer early and optionally trigger the onEnd function still
---@field isPaused fun(self: self): boolean returns wether the timer is paused or not
---@field pause fun(self: self) pauses the timer until play method is called
---@field play fun(self: self) resumes the timer if paused
---@field getTimeLeft fun(self: self, format?: 'ms' | 's' | 'm' | 'h'): number | table returns the time left on the timer with the specified format rounded to 2 decimal places (miliseconds, seconds, minutes, hours). returns a table of all if not specified.
local timer = lib.class ( ' OxTimer ' )
2024-04-20 06:55:56 +10:00
---@private
---@param time number
---@param onEnd fun(self: OxTimer)
---@param async? boolean
2024-04-17 22:54:09 -06:00
function timer : constructor ( time , onEnd , async )
assert ( type ( time ) == " number " and time > 0 , " Time must be a positive number " )
assert ( onEnd == nil or type ( onEnd ) == " function " , " onEnd must be a function or nil " )
assert ( type ( async ) == " boolean " or async == nil , " async must be a boolean or nil " )
2025-01-28 06:47:48 +11:00
self.onEnd = onEnd
2024-04-17 22:54:09 -06:00
self.private . initialTime = time
self.private . currentTimeLeft = time
self.private . startTime = 0
self.private . paused = false
2025-01-28 06:47:48 +11:00
self.private . triggerOnEnd = true
2024-04-17 22:54:09 -06:00
self : start ( async )
end
2025-01-26 05:20:23 +11:00
---@protected
function timer : run ( )
while self : isPaused ( ) or self : getTimeLeft ( ' ms ' ) > 0 do
Wait ( 0 )
end
2024-04-17 22:54:09 -06:00
2025-01-26 05:20:23 +11:00
if self.private . triggerOnEnd then
self : onEnd ( )
end
2024-04-17 22:54:09 -06:00
2025-01-26 05:20:23 +11:00
self.private . triggerOnEnd = true
end
2025-01-20 02:23:50 +11:00
2025-01-26 05:20:23 +11:00
function timer : start ( async )
if self.private . startTime > 0 then error ( ' Cannot start a timer that is already running ' ) end
2025-01-20 02:23:50 +11:00
2025-01-26 05:20:23 +11:00
self.private . startTime = GetGameTimer ( )
2024-04-17 22:54:09 -06:00
2025-01-26 05:20:23 +11:00
if not async then return self : run ( ) end
2025-01-20 02:23:50 +11:00
Citizen.CreateThreadNow ( function ( )
2025-01-26 05:20:23 +11:00
self : run ( )
2025-01-20 02:23:50 +11:00
end )
2024-04-17 22:54:09 -06:00
end
function timer : forceEnd ( triggerOnEnd )
if self : getTimeLeft ( ' ms ' ) <= 0 then return end
2025-01-20 02:23:50 +11:00
2024-04-17 22:54:09 -06:00
self.private . paused = false
self.private . currentTimeLeft = 0
2025-01-20 02:23:50 +11:00
self.private . triggerOnEnd = triggerOnEnd
2024-04-17 22:54:09 -06:00
Wait ( 0 )
end
function timer : pause ( )
if self.private . paused then return end
2025-01-20 02:23:50 +11:00
2024-04-17 22:54:09 -06:00
self.private . currentTimeLeft = self : getTimeLeft ( ' ms ' ) --[[@as number]]
self.private . paused = true
end
function timer : play ( )
if not self.private . paused then return end
self.private . startTime = GetGameTimer ( )
self.private . paused = false
end
function timer : isPaused ( )
return self.private . paused
end
2024-05-02 01:06:12 -05:00
function timer : restart ( async )
2024-04-17 22:54:09 -06:00
self : forceEnd ( false )
Wait ( 0 )
self.private . currentTimeLeft = self.private . initialTime
self.private . startTime = 0
2024-05-02 01:06:12 -05:00
self : start ( async )
2024-04-17 22:54:09 -06:00
end
function timer : getTimeLeft ( format )
local ms = self.private . currentTimeLeft - ( GetGameTimer ( ) - self.private . startTime )
local roundedfloat = function ( value )
return tonumber ( string.format ( ' %.2f ' , value ) )
end
if format == ' ms ' then
return roundedfloat ( ms )
end
local s = ms / 1000
if format == ' s ' then
return roundedfloat ( s )
end
local m = s / 60
if format == ' m ' then
return roundedfloat ( m )
end
local h = m / 60
if format == ' h ' then
return roundedfloat ( h )
end
return {
ms = roundedfloat ( ms ) ,
s = roundedfloat ( s ) ,
m = roundedfloat ( m ) ,
h = roundedfloat ( h )
}
end
2024-04-20 06:55:56 +10:00
---@param time number
---@param onEnd fun(self: OxTimer)
---@param async? boolean
function lib . timer ( time , onEnd , async )
return timer : new ( time , onEnd , async )
end
2024-04-17 22:54:09 -06:00
2024-04-20 06:55:56 +10:00
return lib.timer