Dynamically Reloading Lua Files

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
benhumphreys
Prole
Posts: 31
Joined: Thu Sep 13, 2012 2:10 am

Dynamically Reloading Lua Files

Post by benhumphreys » Wed Oct 03, 2012 2:31 pm

I read this post by the Legend of Grimrock guys on dynamically loading Lua to speed up their code, build, test iteration cycle.

It got me thinking, if this is possible within a C++ environment that runs Lua, is it possible in a Lua-only environment like a Löve game?
Ideally it'd be great to be able to change some entity definitions in my game, and then have my code re-load that on the fly.

Has anyone tried this already?

User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Dynamically Reloading Lua Files

Post by Robin » Wed Oct 03, 2012 3:09 pm

Yeah, I think people have tried it, though I can't remember specific examples.

You can do it pretty easily if you design your data structures right. Then you can reload your game on the fly without crashing or resetting the game.

... someone with actual experience with this care to comment? :P
Help us help you: attach a .love.

User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: Dynamically Reloading Lua Files

Post by bartbes » Wed Oct 03, 2012 3:10 pm

Yeah, there's been a couple of these things, like LICK.
Personally, I've used some bash scripts hooked up to inotify to restart love when a file is modified.

User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Dynamically Reloading Lua Files

Post by Robin » Wed Oct 03, 2012 3:27 pm

bartbes wrote:Personally, I've used some bash scripts hooked up to inotify to restart love when a file is modified.
That's simple and doesn't require any changes to the game itself, nice.

Those don't preserve state, though. If you can manage that, it'll be epic. Can we intercept signals? If so, your bash script could send a signal and the game would intercept that and store the state in the savedir.
Help us help you: attach a .love.

jonbro
Prole
Posts: 8
Joined: Tue Oct 02, 2012 10:18 am

Re: Dynamically Reloading Lua Files

Post by jonbro » Wed Oct 03, 2012 6:29 pm

I am not doing this in love2d, but in my other lua project, I use sockets to send the data over the network and then execute. I have some code that runs on the command line looking for file changes.

It lets me preserve state, which is nice.

jonbro
Prole
Posts: 8
Joined: Tue Oct 02, 2012 10:18 am

Re: Dynamically Reloading Lua Files

Post by jonbro » Wed Oct 03, 2012 8:03 pm

Hey (sorry for the double posting), but I just went ahead and wrote a pure lua thing that watches the file system and loads in lua files that change. It preserves state, so you can just go along editing things.

just use it like this:

Code: Select all

local fw = love.filesystem.load("fileWatch.lua")()
fw:start()
function love.update(dt)
	fw:update()
end
I don't think that it works on windows (I am unsure on how to do directory separators in a crossplatform way), and it dumps out errors to the console that opened it, rather than blue screening.

Hope that someone finds this useful, let me know if there are any changes that you want.
Attachments
filewatch.zip
(1.35 KiB) Downloaded 189 times

benhumphreys
Prole
Posts: 31
Joined: Thu Sep 13, 2012 2:10 am

Re: Dynamically Reloading Lua Files

Post by benhumphreys » Thu Oct 04, 2012 1:21 am

jonbro that looks super-useful! Thanks for posting it!

I'm wondering how I could build this into a larger system.
Calling require() again on a file that's already been require'd won't do anything?

I guess if the files you are watching and reloading are functions and class data, you could find the matching existing instance(s), and replace their properties to point to the modified functions and class data. You'd have to preserve instance data though...

Something like this:

Code: Select all

modifiedStuff -- our asynchronously loaded table
for _, entity in ipairs(entities) do
  foreach key, val in pairs(modifiedStuff) do
    entity[key] = val
  end
end
I'm not sure how to do this cleanly yet using MiddleClass. Hmm.

User avatar
klembot
Prole
Posts: 30
Joined: Tue Apr 24, 2012 12:41 am

Re: Dynamically Reloading Lua Files

Post by klembot » Thu Oct 04, 2012 4:22 am

I have some code to do this in Zoetrope. The approach it takes is different and more basic. When it initially loads, it takes a snapshot of _G (the table where all globals live) and packages.loaded (which tracks what's already been loaded). To reload, it resets _G and packages.loaded to their previous values and restarts things by requiring main.lua, then calling love.load().

The code that takes the snapshot is here, and here is how I do the reloading.

User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: Dynamically Reloading Lua Files

Post by Inny » Thu Oct 04, 2012 5:00 am

I've taken on a pattern (I think kikito may have suggested it, but I could be wrong) where I do the primary list of library loading out of love.load, which makes sure to clear out package.loaded. Then I rig a quick reset button (like F9) to the love.load call. Here's some sample code:

Code: Select all

libraries = {
  "class", "graphics", "color", "input", "util", "statemachine"
}

function loadLibraries()
  for _, lib in ipairs( libraries ) do
    package.loaded[lib] = nil
  end
  for _, lib in ipairs( libraries ) do
    require(lib)
  end
end

function love.load()
  loadLibraries()
end

User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: Dynamically Reloading Lua Files

Post by bartbes » Thu Oct 04, 2012 5:16 pm

benhumphreys wrote: Calling require() again on a file that's already been require'd won't do anything?
Correct, but the easy workaround is something like this:

Code: Select all

function rerequire(module)
    package.loaded[module] = nil
    return require(module)
end

Post Reply

Who is online

Users browsing this forum: No registered users and 37 guests