0
0
Fork
You've already forked loreload
0
loreload is a hotreload library for LÖVE and LÖVR
  • Lua 100%
2026年07月05日 10:22:46 +02:00
.gitignore chore: add .gitignore 2026年06月22日 23:53:09 +02:00
LICENSE docs: add LICENSE 2026年06月22日 23:53:22 +02:00
loreload-scm-0.rockspec spec: fix download link 2026年06月26日 08:00:52 +02:00
loreload.lua chore: make refresh rate less aggressive 2026年07月04日 12:16:19 +02:00
README.md docs: fix syntax in README.md 2026年07月05日 10:22:46 +02:00

loreload

loreload is a hot-reloading library for LÖVE and LÖVR. It watches for file changes and reloads the game if it detects a change.

Installation

Either install via luarocks (currently dev version only):

> luarocks install loreload --lua-version=5.1 --dev

or download the Lua source file directly into your game-project/modules directory

wget https://codeberg.org/sewbacca/loreload/raw/branch/main/loreload.lua

Then simply pop require 'loreload' as the first(!) import into your main.lua and enjoy hotreloading <3

Important Remarks

Beware: loreload assumes all already loaded modules before itself are static-modules, that is they will never be reloaded (i.e. loreload itself). If you find that some modules are not reloaded this is probably why. Watch the console log closely to see if the offending file is actually detected.

You can specify more static-modules via loreload.markstatic 'module.name'. These won't be reloaded during subsequent loads. You can undo this by marking them dynamic via loreload.markdynamic 'module.name'.

During startup a custom (love|lovr).run is set. If a watched file changes loreload restarts the main loop from the beginning to display the newest changes. If an error occurs the error message is displayed using (love|lovr).(errhand|errhandler) and loreload continues to watch for file changes.

If you have a custom run() function, just be sure to call loreload.setuprun() after it has been declared but before (love|lovr).run() is called. loreload will then be able to watch for file changes while respecting your main loop.

At startup require, dofile and loadfile will be patched to start watchers automatically. If you need additional files to be watched, then for simple functions where the corresponding filepath is passed directly, run love.*.* = loreload.wrap(love.*.*, n). It will return a patched function which will automatically watch the n'th (default: 1) parameter:

-- already implemented in loreload:
loadfile = loreload.wrap(loadfile, 1)

For more complex functions call loreload.watch(filepath) with the filepath directly.

If you want state to persist between reloads then you have a few choices:

  1. The global table is not touched during reload (aside from package.loaded), thus it is perfectly suited to store data that helps to restore your game state to a particular point that you are working on:
-- lazy
current_level = current_level or 'start-level'
  1. loreload does call love.load() and love.quit() during reloads, so if you save your latest UI state to disk anyway, you are perfectly set up to open love/lovr in your desired state.
  2. Set a callback at loreload.onreload or loreload.onreloaded.

If you find the log output of loreload a bit noisy, or you want to direct it into your custom ingame log, overwrite loreload.onlog:

-- i.e. this will silence reload notifications in the console log.
loreload.onlog = function() end

Known Limitations

File changes that occur below the modification-date-resolution won't be registered. iNotify (or the Windows equivalent) is planned in the future to lift this limitation.

If an error occurs during the first startup of LÖVE or LÖVR, loreload will be unable to reload the application.

Unfortunately I have found no way to reload C-modules. There's probably a way using jit's ffi, however this would require cross-platform specifics and also you'd need to convince Lua to garbage collect the C-module. If you managed to do that (or found an easier way), a PR would be appretiated.

API Reference

Configuration

loreload.setuprun()

Resets (love|lovr).run while remembering the current set (love|lovr).run if it is not already the hotreloader. Always call this after you have declared your custom (love|lovr).run.

loreload.onlog(msg: string)

A logging callback to be overridden by the user. Defaults to io.write(msg, '\n').

lorelad.refreshinterval: number (default: 0)

Time interval until files are checked for changes again (in seconds).

loreload.onreload If a callback is set, it is executed right before all state is unloaded. It is called before (love|lovr).quit is called.

loreload.onreloaded If a callback is set, it is executed right after the game has been reloaded, but before any updates occur. It is called after (love|lovr).load().

Watch API

loreload.watch(file: string)

Watches given file for changes, may trigger a reload upon the next update.

loreload.unwatch(file: string)

Stops watching given file for changes.

loreload.wrap(f: function, n: integer? (default: 1)): function

Wraps a function equivalent to the following code:

return function(...)
 loreload.watch(select(n, ...))
 return f(...)
end

loreload.markstatic(modname)

Marks a module as static, will never be reloaded unless marked dynamic again. (default behavior for modules required before require 'loreload')

loreload.markdynamic(modname)

Marks a module as dynamic, thus it may cause reloads (default behavior for modules required after require 'loreload')

loreload.files(): string[]

Returns an array of currently watched files.

loreload.addfiles(files: string[])

Adds specified files to be watched.

loreload.dropfiles()

Drops all watched files.

Reload control

loreload.restart()

Explicitly order a restart upon the next loop iteration.

loreload.filechanged()

Scans for any file that may would cause a restart.

Any Problems?

File an issue! Already have a solution? PRs are welcome.