Reloads and failures
What a reload resets, how to carry state across one, and what a failed call does.
While the game runs, modlock dev reloads your mod with the new build each time you save. A reload starts the mod fresh: its variables reset, and the host removes everything it placed.
Failed calls
A call that fails logs the reason and returns false or undefined, and your mod keeps running. Everything your mod places is removed when the world changes. Stopping or reloading the mod removes it too, and releases the heroes it froze, the modifier states it held and the input it blocked.
In Go, each call returns an error instead, and your mod can ignore the error and keep playing.
Slow and stopped mods
An event's processor time includes the game calls its handler makes, but not a stall where the server waits, such as paging on a machine short of memory.
| An event that | Does |
|---|---|
| runs past 500 ms of processor time | Still finishes. The host logs where its time went, warns the players in chat, and for five minutes lets any player restart the mod with /restartmod. |
| runs past five seconds | Stops the mod, as a crash does. |
When a mod stops, the host removes what it placed and the interfaces it showed,
and the mod stays stopped. The host warns in chat each minute until a player types /restartmod or a reload replaces it.
A restart starts the same build in a new instance, as a reload does.
Hold a reload
When a new build would lose work in progress, such as a timed run, call holdReload(true) at the start and holdReload(false) when it ends. A reload that arrives while the hold is on waits, and the newest build replaces the running one on the next frame after you release the hold. A mod that stops also releases its hold.
import { holdReload } from 'modlock'
function startRun() {
holdReload(true)
}
function endRun() {
holdReload(false)
}local function startRun()
modlock.holdReload(true)
end
local function endRun()
modlock.holdReload(false)
enddef start_run() -> None:
modlock.hold_reload(True)
def end_run() -> None:
modlock.hold_reload(False)func startRun() { _ = mod.HoldReload(true) }
func endRun() { _ = mod.HoldReload(false) }Hand state to the next build
Some state should survive a reload, such as the round the game is on or the panels each player has open. Hand that state to the next build as handoff state:
import { handedOff, handoff } from 'modlock'
// Pick up the round the last build was on.
let round = Number(handedOff() ?? 1)
function nextRound() {
round += 1
handoff(String(round))
}-- Pick up the round the last build was on.
local round = tonumber(modlock.handedOff()) or 1
local function nextRound()
round += 1
modlock.handoff(tostring(round))
end# Pick up the round the last build was on.
round_number = int(modlock.handed_off() or 1)
def next_round() -> None:
global round_number
round_number += 1
modlock.handoff(str(round_number))var round = 1
func init() {
// Pick up the round the last build was on.
mod.OnStart(func([]string) {
if text, err := mod.HandedOff(); err == nil {
if n, err := strconv.Atoi(text); err == nil {
round = n
}
}
})
}
func nextRound() {
round++
_ = mod.Handoff(strconv.Itoa(round))
}| Call | Does | Ends when |
|---|---|---|
handoff(text), handedOff() | Write the game's state, and read it on load. | The mod stops or the server restarts. |
player.handoff(text), player.handedOff() | Write one player's state, and read it on load. | That player leaves. A bot has none. |
Handoff state lasts only through a reload in the same game. The host keeps it only in memory, up to 64 KiB per call, and handing off an empty text clears it.