I wrote a little script to support hot reloading of lua modules.
The example code below shows how it could be used
local hotr = require('scripts.hotr')
local Game = hotr.MakeReloadable('Game')
function Game.New()
local o = {}
setmetatable(o, self.__mt)
-- This just ensures that you can set values after reloading, and it will save it to
-- o instead of the new class returned by hotr.MakeReloadable
-- (I could bake this into MakeReloadable)
self.__mt.__new_index = function(obj, key, value)
rawset(obj, key, value)
end
return o
end
function Game:LogStatus()
-- print('Game status ...') -- Uncomment after reloading
end
This allows you to change the code for a class, which will be reflected in all active objects.
It uses a proxy metatable that allows you to reload a module, create a new class entirely, and then hook that onto the proxy metatable held by the objects.
This is the hotr
module.
-- hotr.lua
----------
local M = {}
-- Named map of metatables, e.g. 'game.player'.
local metatable_map = {}
function M.Reload(modname)
if not package.loaded[modname] then
print(string.format('%s not loaded anyway ...', modname))
end
package.loaded[modname] = nil
if package.loaded[modname] then
print(string.format('Huh ... %s should not be loaded right now', modname))
end
local succ, vals = pcall(function() require(modname) end)
if succ then
return vals
end
print(string.format("### ERROR: Failed to load %s\n---\n%s\n===", modname, vals))
end
-- Registers metatable the first time, returns afterwards.
---@param class_name string
function M.GetMt(class_name)
if metatable_map[class_name] == nil then
metatable_map[class_name] = {}
end
local clz = metatable_map[class_name]
return clz
end
function M.GetClass(class_name)
return getmetatable(M.GetMt(class_name))
end
function M.MakeReloadable(class_name, prototype)
local class = { __mt = M.GetMt(class_name) }
-- The prototype can be referenced in the object constructor.
if prototype ~= nil then
class.__prototype = prototype
end
setmetatable(class.__mt, class)
class.__mt.__index = class
return class
end
return M