Skip to content

Instantly share code, notes, and snippets.

@gilzoide
Last active July 27, 2020 03:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gilzoide/7545553b03ed0de2c79b5ba1ae674183 to your computer and use it in GitHub Desktop.
Save gilzoide/7545553b03ed0de2c79b5ba1ae674183 to your computer and use it in GitHub Desktop.
A module for detecting updated files in a LÖVE game
-- Detecting updated files for hot reloading in a LÖVE game
local hotreload = {}
-- Monitor the "src" and "assets" paths, can be changed to any existing folders in your project, separated by spaces
local monitor_path = "src assets"
-- External command for monitoring the filesystem
-- Needs fswatch available for execution in PATH (no errors will be thrown, but reload will not work)
-- https://github.com/emcrisostomo/fswatch
local fswatch_cmd = "fswatch --recursive --event Updated " .. monitor_path
function hotreload.load()
hotreload.channel = love.thread.newChannel()
-- This may be used to retrieve the relative file paths from fswatch's output
hotreload.source = love.filesystem.getSource()
-- Reading a subprocess output is a blocking operation, so it must run in a separate thread
local thread = love.thread.newThread([[
local channel, fswatch_cmd = ...
local fswatch = io.popen(fswatch_cmd)
-- `io.popen` returns an open file even if the command failed
-- This `if` is not mandatory, but this will make the thread finish instead of being blocked forever for nothing
if fswatch:read(0) then
for line in fswatch:lines() do
channel:push(line)
end
else
print(string.format('HOTRELOAD failed running %q and is disabled', fswatch_cmd))
end
]])
thread:start(hotreload.channel, fswatch_cmd)
end
function hotreload.update()
-- Note: if no files are updated or if the fswatch command failed, nothing happens =]
while hotreload.channel:getCount() > 0 do
local filename = hotreload.channel:pop()
-- Note: fswatch returns full file paths.
-- You can get the relative path by trimming the project source path with the following line
-- `+2` is for skipping the trailing "/" or "\"
filename = filename:sub(#hotreload.source + 2)
print('UPDATED', filename)
-- Example: reload image assets into global table
local imagename = filename:match("([^/\\]+)%.png$")
if imagename then
print(string.format('Reloading image %q into global table', imagename))
_G[imagename] = love.graphics.newImage(filename)
end
end
end
return hotreload
local hotreload = require 'hotreload'
function love.load()
-- do your usual loading here
hotreload.load()
end
function love.update(dt)
-- hotreloading stuff in the beginning of the update means the new stuff is readily available in your update cycle
hotreload.update()
-- your usual update here
end
function love.draw()
-- your usual draw here, no drawing is needed for hotreload
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment