Skip to content

timer⚓︎

The timer library provides helper functions for creating delayed executors.

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 be timer.simulate, timer.game or timer.real.

Returns:


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.

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 be timer.simulate, timer.game or timer.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 the name string passed to timer.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 to true will serialize the callback string in the save to persist between sessions. Only a registered timer will persist between sessions. See timer.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:

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)