timer⚓︎
The timer library provides helper functions for creating delayed executors.
Timers get canceled when loading saves.
All active timers will be canceled right before the loaded
event triggers.
Properties⚓︎
timer.active
⚓︎
Constant to represent a timer that is actively running.
timer.expired
⚓︎
Constant to represent a timer that has completed.
timer.game
⚓︎
Constant to represent timers that run based on in-world time. Their clock is measured in game-scale hours.
timer.paused
⚓︎
Constant to represent a timer that is paused.
timer.real
⚓︎
Constant to represent timers that run in real-time. Their time is measured in seconds.
timer.simulate
⚓︎
Constant to represent timers that run when the game isn't paused - the game's menus are closed. It matches the simulate
event's timing. If the game is simulating, simulate events and simulate timers progress. Duration is measured in seconds.
Functions⚓︎
timer.delayOneFrame
⚓︎
Creates a timer that will finish the next frame. It defaults to the next simulation frame.
Tip
It's recommended to study the Object Lifetimes guide. It describes how to safely use tes3reference objects inside timer callbacks.
local timer = timer.delayOneFrame(callback, type)
Parameters:
callback
(fun(e: mwseTimerCallbackData)): The callback function that will execute when the timer expires.type
(integer): Default:timer.simulate
. Type of the timer. This value can betimer.simulate
,timer.game
ortimer.real
.
Returns:
timer
(mwseTimer)
timer.frame.delayOneFrame
⚓︎
Creates a timer that will finish the next frame.
Tip
It's recommended to study the Object Lifetimes guide. It describes how to safely use tes3reference objects inside timer callbacks.
local timer = timer.frame.delayOneFrame(callback)
Parameters:
callback
(fun(e: mwseTimerCallbackData)): The callback function that will execute when the timer expires.
Returns:
timer
(mwseTimer)
timer.register
⚓︎
Registers a named timer with a callback to persist between game sessions. Bear in mind that nothing in MWSE is sandboxed, so all the registered timers are in the global namespace. Consider prefixing your timer with mod name or something else to avoid name collisions. For instance, iceCreamMod:myTimer
.
Tip
It's recommended to study the Object Lifetimes guide. It describes how to safely use tes3reference objects inside timer callbacks.
timer.register(name, fn)
Parameters:
name
(string): Name of the registered timer.fn
(fun(e: mwseTimerCallbackData)): A callback function for the timer.
Example: Persistent timers tutorial with .data
usage
The timer registered in the example is registered and persistent. That renders starting the timer on every loaded event unnecessary. Its state is saved, and it continues where it stopped after loading a save.
---@param e mwseTimerCallbackData
local function showMessage(e)
local timer = e.timer
local data = timer.data
local currentTimestamp = tes3.getSimulationTimestamp()
-- We are sure that the timer.data ~= nil since we
-- created that table in timer.start function.
-- So, lets disable the warnings for a bit.
---@diagnostic disable:need-check-nil
tes3.messageBox(data.message:format(
data.startTimestamp,
data.lastIterationTimestamp,
currentTimestamp
))
---@diagnostic enable:need-check-nil
-- Save this to the data table on the timer
data.lastIterationTimestamp = currentTimestamp
end
timer.register("testExample:OneDayTimer", showMessage)
timer.start({
type = timer.game,
persist = true,
iterations = -1,
duration = 24,
-- Notice that the callback isn't a function, but
-- a string passed to the timer.register function
callback = "testExample:OneDayTimer",
data = {
startTimestamp = tes3.getSimulationTimestamp(),
lastIterationTimestamp = tes3.getSimulationTimestamp(),
message = [[One day later...
timer's starting timestamp %s
the timestamp of last iteration %s
current timestamp %s
]]
}
})
timer.start
⚓︎
Creates a timer.
Timers get canceled when loading saves.
All active timers will be canceled right before the loaded
event triggers.
Tip
It's recommended to study the Object Lifetimes guide. It describes how to safely use tes3reference objects inside timer callbacks.
local timer = timer.start({ type = ..., duration = ..., callback = ..., iterations = ..., persist = ..., data = ... })
Parameters:
params
(table)type
(integer): Default:timer.simulate
. Type of the timer. This value can betimer.simulate
,timer.game
ortimer.real
.duration
(number): Duration of the timer. The method of time passing depends on the timer type.callback
(fun(e: mwseTimerCallbackData), string): The callback function that will execute when the timer expires. If starting a registered timer, this needs to be thename
string passed totimer.register
.iterations
(integer): Default:1
. The number of iterations to run. Use-1
for infinite looping.persist
(boolean): Default:true
. Registering a timer with persist flag set totrue
will serialize the callback string in the save to persist between sessions. Only a registered timer will persist between sessions. Seetimer.register()
.data
(table, nil): Default:nil
. Data to be attached to the timer. If this is a persistent timer, the data must be json-serializable, matching the same limitations as data stored on references.
Returns:
timer
(mwseTimer)
Example: Show a Countdown Message
In this example, whenever the player activates an item they will be shown a 10 second countdown. Because it is a simulation timer, it will not tick down while the menu is open, nor is it sensitive to the game timescale/clock.
local timeLeft = 0;
local function onTimerExpired()
timeLeft = timeLeft - 1
tes3.messageBox("%d seconds left", timeLeft)
end
local function onActivate(eventData)
if (eventData.activator == tes3.player) then
timeLeft = 10
timer.start{ duration = 1, iterations = 10, type = timer.simulate, callback = onTimerExpired }
end
end
event.register(tes3.event.activate, onActivate)