Getting low-delay OS notifications of file updates

Issue #1079 wontfix
coffeecat
created an issue

This is for development purposes. Without this, hot-reloading (e.g. lurker) would have a big delay without eating too much CPU.

This can also be done via FFI or (luasocket+an external program), but it would be nice to have LOVE support it by default.

I haven't researched about implementation. There could be a cross-platform library for this.

The API could be as simple as

-- in conf.lua
function love.conf(t)
    t.modules.watchfile = true
end

-- whenever a file in source directory is modified/created/deleted/moved,
-- the following callback is called
function love.fileupdated(filename)
    -- check the filename, and do the work
end

Comments (29)

  1. Alex Szpakowski

    PhysFS doesn't support this on its own, although it would be possible to have separate backend code for OS X / Windows / Linux for this (I haven't looked into Windows and Linux implementations though.)

    On the other hand, in the past I've just periodically checked love.filesystem.getLastModified for the files I want to monitor, and it worked fine. You could also run the check in a loop in a background thread if you wanted, to avoid CPU usage on the main thread.

  2. coffeecat reporter

    I would guess there exists some cross-platform library for this. Separate backend code seems to be too much work.

    On the other hand, in the past I've just periodically checked love.filesystem.getLastModified for the files I want to monitor, and it worked fine. You could also run the check in a loop in a background thread if you wanted, to avoid CPU usage on the main thread.

    Yeah.. but I want an ideal solution.

  3. Kyle McLamb

    I've looked into it a bit for myself: there seem to be a few filesystem event APIs, but nothing reasonably independent enough that it could just be added to love.

    Here's a proof of concept that uses inotify() directly through the FFI, no C code required: https://github.com/Alloyed/love-watch

    Using this I've noticed it's not particularly easy to get a good view of what a user is doing through their filesystem events: each text-editor/IDE will generate a different set of events, so the best you can do is tell "something changed with this file". This should be fine for hot-reloading purposes but it's not really something I'd add to the larger project.

  4. Bart van Strien

    Thanks for the info @Kyle McLamb . I don't think there's an easy path towards supporting this, especially because it has to transparently follow physfs. Even a naive inotify (thus linux-only) would probably watch the path that a file currently resolves to, which may not be accurate if a file with the same name gets created in a mounted location with a higher priority (like the save dir). And, of course, it's a relatively niche feature.

    EDIT: If you really want it, you could also try opening a feature request on physfs, if physfs supports it there's no reason love wouldn't.

  5. coffeecat reporter

    I agree this feature could be tricky to implement. If this feature is ever supported, it must be reliable.

    I intend to look into this when I have some time.

  6. Yucheng Zhang

    Hi. Now I finally have got some free time, and would like to make some contributions. :)

    I think this issue is related to #885. It is a fundamental building block for implementing a quick development-test cycle, and I'd like to see LOVE have this built in.

    I don't think physfs would ever support this, as it seems to be out of the scope of their project. Also unfortunately, years passed and there still isn't a simple cross-platform library for this, so we have to do this ourselves. I intend to start actual code writing, if the following proposal is sound to you.

    The API looks like:

    -- in conf.lua
    function love.conf(t)
        t.modules.watchsource = true
        t.watchsource.debounce = 10 -- in ms; 0 stands for no debouncing
    end
    
    -- whenever a file in source directory is modified/created/deleted/moved,
    -- the following callback is called
    function love.sourceupdated(pathlist)
        -- check the path list, and do the work
    end
    

    Details:

    1. This feature is designed only for development purposes. It is unusual to watch for file updates after the game is shipped, and only supporting for development greatly reduces the complexity of implementing this feature.
    2. Only unarchived .love source directory in non-fused mode is supported. Only Windows/MaxOS/Linux are supported. Other situations (archived .love, fused mode, save directory, SourceBaseDirectory, iOS/Android) seem unnecessary for quick-cycle iterative development. I will start with Linux, and move to MacOS and Windows later.
    3. PhysFS mounts are irrelevant, because love.filesystem.mount does not allow mounting archive/folder in source directory in non-fused mode.
    4. We only report to game applications which file has been operated (i.e. modified/created/removed/etc), but no actual operation. Game applications may have better knowledge when handling these events, and a filename is often sufficient. When the actual operation is needed, the game application can find out itself, in which case this API provides the game application an efficient low-latency event trigger.
    5. We will debounce the file system events for a configurable amount of time, in case some editors may trigger multiple consecutive events of a single file.
    6. We will define a sensible default love.sourceupdated handler, where everything is reloaded.
  7. coffeecat reporter

    I'll reopen this issue for better visibility, since I am not sure whether people can read my proposal in a closed issue.

    I have to acknowledge that the proposal isn't perfect, and the problem is hard. But I believe it's worth all the troubles, if we take interactive or short-cycle iterative development seriously.

    In case you haven't heard about it, Bret Victor's Inventing on Principle showed how fun interactive development can be. Inspired by it, I created lovecat some time ago (which is a bit outdated, and I intend to update in the near future), which enables some fun development experiences without editor support.

    Much part of realizing interactive development is independent of LOVE, but source file update events is one area that LOVE can help. If this proposal gets rejected, I would be off using linotify in my current game project, which is perfectly fine for me. However, I really hope to see LOVE move in this direction, and benefit all users.

    I hope all these make sense.

  8. Bart van Strien

    I'd probably not design it so.. specific. I'd suggest adding a function (or two) to love.filesystem to add a file/directory to watch, and then have filemodified and directorymodified callbacks. That way you don't tie it to just monitoring lua files and it's opt-in on a more granular level. You could even check if the file/directory is watchable at the time, though I guess that means you can't watch for a file that doesn't exist yet that way.

  9. Gabe Stilez

    Since the "official" way to do FS stuff in löve is with PhysFS, getLastModified (maybe combined with a lua table holding initial values for files we want tracked) should be sufficient enough for what this issue wanted to accomplish, namely file update notifications; the fact that they'd work in a pull/poll fashion instead of a push/hook/interrupt one, or that they're not "low level" enough should be a moot point in my opinion.

    For lua's own io, which could still be used, writing a libraryless solution with popen calling cmdline/terminal functions would work... if their OS/build supports popen, that is.

    Since users can choose which one they want to use, i don't think a love.handler should be added in by default, rather it should remain on the user-side, or again, wrap both up in a library, if one wants to.

    Bonus thought: The FFI also allows one to circumvent löve's two-directory limit, effectively allowing read/write* access throughout the whole real filesystem too, so one should be aware of that little tidbit as well. (*: permissions depending)

    By the way, nothing's wrong with ways to accomplish this that aren't pushed into löve proper; while we're at it, we could also create an issue that löve doesn't include a code editor, for even more short-cycle development. :P

  10. coffeecat reporter

    Thanks for the feedback! :D

    I realized that this feature is also useful for hot reloading player mods. I did some design iterations in my mind, and now I propose a new revision based on the feedback.

    love.filesystem.setWatchEnabled(root, enabled, debounce)
    -- root must be one of: 'source', 'sourcebase', 'save'
    -- enabled must be one of: true, false
    -- debounce is in seconds, and defaults to 0.01; debounce == 0 stands for no debouncing
    -- if the game application wants to watch an unwatchable root, we'll raise an error
    
    function love.pathupdated(root, pathlist)
        -- root is one of 'source', 'sourcebase', 'save'
        -- pathlist is a table of path strings, which is the relative path to root
    end
    

    I explain the design in detail as follows:

    1. The API now covers everything that is accessible via love.filesystem, and fits well with the rest of love.filesystem.
    2. You may think abstracting root away with the virtual physfs filesystem is more elegant, but now I realize that this is not always preferable. For a hot reloading library, it can't be sure whether the updated file is from the source directory or save directory, and can't reliably trigger a hot reload.
    3. I don't think more granularity would bring much value. (1) It is easy to filter out interesting events based on path strings. (2) The update events are usually sparse, pushing all of them to the game application shouldn't hurt the performance. (3) For development purposes, almost every update event from the source directory is interesting, if the running game wants to reflect the new version on disk.
    4. love.filemodified and love.directorymodified are more aesthetically appealing to me, but the two callback are usually closely related, and the game application can always do a love.filesystem.isDirectory. For my own game, I would call a common function from both callbacks.
    5. Every file in the root directory is watched, and asset files could be reloaded on the fly by the game application or a development library it uses.
    6. 'source' and 'save' root directory is sufficient for any use case I can think of, but I added 'sourcebase' for generality.

    I am open to more feedback, and I understand it's a nontrivial API modification to LOVE.

  11. coffeecat reporter

    Most of @Gabe Stilez 's comments are irrelevant now, since I realized that this feature is also useful for hot reloading player mods. But I'd still like to point out a few things.

    Since users can choose which one they want to use, i don't think a love.handler should be added in by default, rather it should remain on the user-side, or again, wrap both up in a library, if one wants to.

    This is actually a bad thing. People will use different and incompatible ways for the same functionality. This might lead to a splitting in the LOVE ecosystem, and having a standardized way is better.

    By the way, nothing's wrong with ways to accomplish this that aren't pushed into löve proper; while we're at it, we could also create an issue that löve doesn't include a code editor, for even more short-cycle development. :P

    Actually I see this as a real issue. I am not starting a huge-IDE vs lightweight-framework war, but from my understandings one advantage of IDEs is that they usually provide better interactivity. This is a real shortcoming for us, and I believe it's well worth efforts to make it up. It's a difficult problem, and developing a new editor is obviously not a sane way to address the issue -_-b I believe lovecat is a nice way to introduce interactivity to LOVE game development, and I use it in my own game. The only other thing I can think of for now is to provide a Lua REPL from a TCP socket, so that editor plugins could inject or execute any Lua code in the running game. This is a third approach to realize interactive development, besides hot reloading updated files and lovecat. This can be done easily from user side via luasocket, and but including it in LOVE may have benefits such like standardization.

  12. coffeecat reporter

    Actually, there are at least two more ways to help with interactive development:

    1. lovebird lets you execute any Lua code in a browser, and inspect global variables, etc. Lovecat took inspiration from it, and was thus named similarly.
    2. In-game development UI. From this perspective, #1238 is helpful. I'm not sure whether it'll be useful for end-user UI in most games, but as a development tool, it is nice to have.
  13. Gabe Stilez

    @coffeecat care to point out which parts are irrelevant? Also, the integrated code editor part was sarcasm, and poorly veiled at that, it seems. :3

    This is actually a bad thing. People will use different and incompatible ways for the same functionality. This might lead to a splitting in the LOVE ecosystem, and having a standardized way is better.

    I tend to disagree, since lua itself has a philosophy of allowing people to do things in more than one way; Löve's file system solution is there for most basic use-cases; you got a virtual file system with a source directory with all code and assets you included in a build, and a save directory where the user can do whatever they want, basically. But; if someone wants to write something with löve, for whatever reason, and they do need to access other places on the computer (again, OS protection schemes notwithstanding, otherwise e.g. file managers wouldn't exist either) then they can use lua's own io library to do so. The fact that i mentioned one can "jury-rig" the PhysFS inside löve as well, so they can play ball with all the new* Object constructor functions too is just something that's again not sanctioned, but not impossible to do; i should know, i tried it and it worked, for me that is. Now, i'm not saying that absolutely every solution should be supported by any and all things that may be orthogonal to other stuff, but one should consider whether it's worth to only support one part.

    Also, kind of off topic though, but as for the IDE thing, i'm not completely against it, but again, that's tons of added code to bloat file sizes for people who don't really want such functionality to exist in löve in the first place (*including love-nuklear, since #1238 was mentioned), as a standardized yet standalone project, i'd say i'm all for it (regardless of its implementation using sockets, threads, or what have you), but i'd rather not see it in the executive environment by default. (Also, relevant xkcd strip number 927)

  14. coffeecat reporter

    @Gabe Stilez

    Hi, after rereading your last comment, I find I had some misunderstandings about your comment. Most part of your comment is still valid, even when I found another use case for this. I am sorry about that.

    I fully got the sarcasm, and just wanted to take the chance to elaborate some thoughts on this topic. I was probably too rational when writing those thoughts, and didn't express well that I understood the sarcasm. (also probably due to that I am not a native speaker)

    lua itself has a philosophy of allowing people to do things in more than one way

    It's just a philosophy. There isn't a philosophy that is absolutely correct, and every philosophy has its downside. Lack of standardization is one downside for something like Lua. Let me mention that how many class systems Lua have, and how incompatible they are. When you write a library in OOP-style Lua code, how confident you are that your library will be compatible with other OOP libraries? People just work around the problem, and don't write libraries in OOP. (I am not advocating for OOP. OOP is overrated.)

    Don't get me wrong, I used to like minimalism and simplicity very very much, and I still like them. I think in the end, it's just various design trade-offs. For Lua, lack of standardization doesn't hurt much, because it is mainly intended to be embedded in a host program, and lack of ecosystem isn't a big problem. For a wider picture, battery-included solutions always win.

    For this specific feature that I am proposing to add to LOVE, yes, it can be accomplished with existing API, but not in an efficient manner. Note that this is also a commonly used feature, I have seen several development libraries watch file updates, and they are all doing this with the suboptimal love.filesystem.getLastModified approach. I hope OS can do some caching, and prevent this kind of stupid code from harming my non-SSD harddisk.

    that's tons of added code to bloat file sizes for people who don't really want such functionality to exist in löve in the first place

    I understand that you don't want a bloated LOVE, and I don't either. However, let me first point out that, no matter how hard we try, LOVE will always have an opinionated set of features, unless LOVE decides to take the absolute minimum of everything, and be a SDL for Lua. Take love.physics for an example. People may have not thought like this, but physics can mean different things in gamedev, e.g. real-world physics, or platformer physics. Why don't we include an API like bump in LOVE, while including Box2D which is significantly harder to use than the rest of LOVE? A simpler platfomer physics system may fit LOVE better.

    I am tired to see people arguing about whether a particular feature should be included in LOVE. It's a waste of time for everyone involved, and it's just different opinions. Even one's own opinion might change over time. I actually didn't like the idea of #1238, but when I realized that a built-in GUI library can help with interactive development, I changed my mind.

    A real solution is that we include everything that can be done good enough, given the constraint of manpower of the LOVE development team. Note that "good enough" means many things which I'm not going to elabarate here. LOVE already has an opt-in mechanism to let you choose which LOVE modules you want, and the extra functionalities that you don't need is in a separate namespace, and in the end of day it will harm nobody. As for executable size, I don't exactly understand why people are obsessed with it. The only benefit of small executable might be that it gives people a sense of lightweight. However, LOVE will always be actually lightweight, if each of its opt-in modules is lightweight. A real downside of more features for LOVE is that it will be harder to port to different platforms, namely game consoles. This is where I see custom build to opt-in only needed modules is helpful.

    As for the IDE thing, I can't see how this can be done properly for LOVE. IDEs usually make assumptions about how you develop your game, and these assumptions make them better in some aspects, but might get in your way if you want to do something different. LOVE on the other hand makes few assumptions, but some things will be harder to do generally, e.g. interactive development. It's a different tradeoff, but it is still possible to make up our shortcomings to some extent.

    Sorry for this much of off topic, but I believe my ideas deserve to be heard. Correct me if I am wrong.

  15. Gabe Stilez

    @coffeecat First, i'm not a native speaker either, so don't worry about that.

    I agree that standardization has its upsides; i know how many class systems have been written (some by people using löve) (30log, MiddleClass, SECL, hump.class, Slither, ...) but again, most of those implement things differently, because the needs indeed have differed between the individuals. But yes, it's absolutely about trade-offs.

    For this specific feature that I am proposing to add to LOVE, yes, it can be accomplished with existing API, but not in an efficient manner. Note that this is also a commonly used feature, I have seen several development libraries watch file updates, and they are all doing this with the suboptimal love.filesystem.getLastModified approach. I hope OS can do some caching, and prevent this kind of stupid code from harming my non-SSD harddisk.

    I mean, i really am/was under the impression, that this was efficient enough for most use-cases (people shouldn't poll file changes every 1 ms anyway, 1/4 of a second is plenty, or just doing it on an event like mouseclick or button press); or at the very least, that it couldn't "harm" your HDD... if anything, i'd think it would have a bigger risk on an SSD, but it just reads from a peripheral, it doesn't write to it.

    I understand that you don't want a bloated LOVE, and I don't either. However,...

    I agree that the feature set will always depend on the devs themselves; i believe the reason why Box2D is implemented in löve and a more "game-istic" "physics" libs isn't is because the latter can be more easily written in lua than Box2D's rigid body realistic physics could, with the same efficiency, i mean.

    That said, Box2D still lacks continuous collision detection (although i read that it was in the plans for 2.0) so one could have reasoned to include the Bullet physics library instead (3D usage notwithstanding, or at least it's not a reason for not using it) of Box2D... and i think that neither of these two support soft-bodies either (not out-of-the-box, at least), but people can write libs using these to simulate soft-body physics (e.g. https://github.com/exezin/loveblobs)

    I am tired to see people arguing about whether a particular feature should be included in LOVE. It's a waste of time for everyone involved, and it's just different opinions. Even one's own opinion might change over time. I actually didn't like the idea of #1238, but when I realized that a built-in GUI library can help with interactive development, I changed my mind.

    I used to think that what one specific user here did, namely calling out all naming conventions, and then some, was a waste of time, then i reconsidered after realizing that he made an effort to normalize a lot of names; and some of the issues were indeed resolved, the naming changed; not all, but some.

    I believe banter is good though, as long as it remains more or less civilized, and people can still argue for or against inclusion of features.

    A real solution is that we include everything that can be done good enough, given the constraint of manpower of the LOVE development team. Note that "good enough" means many things which I'm not going to elaborate here. ...

    Given that that manpower is quite small, that's not much, although fyi a pretty big thing that got added not too long ago (audio effects and queueable sources) was actually done as a pull request, made by an "external" person, as in, not part of the dev team. TBH the executable's filesize doesn't bother me either, at least on desktops, and people can still whine about having all those dll-s around anyway :3

    No comment on the IDE stuff, ZeroBrane already exists as one for lua, and it can also handle Löve, so that may be sufficient for people wanting to use one.

    Also, as i said above, i think talking stuff out is beneficial. That said, (to get back on topic) if it's possible to have a more efficient file change tracking mechanism, then by all means, i'm for it; originally i only mentioned that if possible (i.e. depending on the implementation) it could work with both PhysFS and lua's io, but that may take more time and it may be that much more pointless; i don't know.

  16. coffeecat reporter

    @Gabe Stilez Glad to see your reply. :)

    I mean, i really am/was under the impression, that this was efficient enough for most use-cases (people shouldn't poll file changes every 1 ms anyway, 1/4 of a second is plenty, or just doing it on an event like mouseclick or button press); or at the very least, that it couldn't "harm" your HDD... if anything, i'd think it would have a bigger risk on an SSD, but it just reads from a peripheral, it doesn't write to it.

    What hot-reload need is an instant update of the running game whenever a source file is saved. The shorter the delay is, the better. I am polling at the frequency of every 0.1s.

    I have to acknowledge that I am not exactly sure whether polling is an unacceptable solution. It might be that I find polling emotionally unacceptable or I just want perfection. However, every commonly used OS provides an API specifically for this purpose (see here for details), and it's obviously the best way to go.

    That said, Box2D still lacks continuous collision detection (although i read that it was in the plans for 2.0) so one could have reasoned to include the Bullet physics library instead (3D usage notwithstanding, or at least it's not a reason for not using it) of Box2D... and i think that neither of these two support soft-bodies either (not out-of-the-box, at least), but people can write libs using these to simulate soft-body physics (e.g. https://github.com/exezin/loveblobs)

    You might be interested in LiquidFun for soft-bodies. I once mentioned it here in one of LOVE issues.

    I used to think that what one specific user here did, namely calling out all naming conventions, and then some, was a waste of time, then i reconsidered after realizing that he made an effort to normalize a lot of names; and some of the issues were indeed resolved, the naming changed; not all, but some.

    That is about consistency. I also value consistency much. It's an important goal in designing, and it means the user is required to remember less amount of information. It's an artificial example, but try to remember the following:

    the-FirstThIng
    the_seCond_thing__
    theTHIRDthING
    

    vs.

    the-first-thing
    the-second-thing
    the-third-thing
    

    Given that that manpower is quite small

    I can see it from the commit history. I hope I can help.

    TBH the executable's filesize doesn't bother me either, at least on desktops, and people can still whine about having all those dll-s around anyway :3

    DLLs are probably about LGPL dependencies. Permissively licensed libraries can be statically linked, and won't produce a DLL.

    No comment on the IDE stuff, ZeroBrane already exists as one for lua, and it can also handle Löve, so that may be sufficient for people wanting to use one.

    I just checked out on ZeroBrane. It has a shining feature called "live coding", but otherwise seems to be just a normal editor tailered to Lua. Live coding is very close to what I have been talking here by "interactive development". I could be wrong, but live coding is probably implemented by a Lua REPL exposed via network, as I mentioned above. It's not a perfect solution: it probably won't work well in more complicated cases, and you still can't manipulate game objects directly inside the game screen. I believe by combining different mechanisms, each game project can find a way best suited to it for interactive development.

    if it's possible to have a more efficient file change tracking mechanism, then by all means, i'm for it

    Thanks :)

  17. coffeecat reporter

    Now I have a (partially) working implementation for Linux here: https://bitbucket.org/coffeecat/love/commits/139aaaad2726392e78c13a219ac8621011871bba.

    It works smoothly, and doesn't incur any overhead if this feature is never used. It uses blocking inotify in a separate worker thread. I have a good feeling about this feature, and now a simple hot-reload can be implemented as simple as:

    function love.load()
      love.filesystem.setWatchEnabled('source')
    end
    
    function love.pathupdated()
      love.event.quit('restart')
    end
    

    However unfortunately I have just found that inotify doesn't provide a simple way to recursively watch a directory, and we have to manually add all sub-directories to watch. Furthermore, to ensure file modification via hard-links work correctly, we have to additionally add all files to watch. It is a further difficulty to respect love.filesystem.setSymlinksEnabled. There's also some limitations of inotify which doesn't notify events in some uncommon cases.

    I'll address these issues later, and hopefully we can get an implementation that is reliable enough.

  18. Mi 28

    Since this is for development purposes, I believe it would be simpler to use some basic Lua-side library than have LÖVE implement it. Keep in mind that each piece of code added is a piece of code LÖVE has to maintain. If it serves no substantial purpose, it probably shouldn't be there.

  19. coffeecat reporter

    @Mi 28

    You are absolutely right that any feature added into LOVE should gain a level of adoption. For this specific functionality, there're already several libraries for this, which indicates that there is a need. However they are all inefficient, polling all files every 0.x second. This proposal can be seen as a performance improvement of a functionally (which is important in my opinion) that people are already using.

    I am well aware of the maintenance cost, and I intend to maintain at least this feature.

    Note that this feature is also useful for detecting player mod changes.

  20. coffeecat reporter

    Please note that I don't need file updates in real time. The file update events are sparse, what I need is that I can immediately get notified of them. I believe this also applies to other people who follow the same development practice.

    Detecting player mod changes is at least useful in the level loading screen. It's also useful if the game wants to support better mod development.

  21. Mi 28

    I don't know what development practice are you even referring to. If you mean automatically restarting the game when you update a file, then that's pretty moot: you can simply restart the game manually to accomplish the same task. Or you can append your launch script to kill a running instance before launching a new one. And games that support mods check the files at startup, they don't receive notifications in real time. At this point the whole endeavor strikes me as pointless, a lot of effort to solve a petty non-issue. The 0.0001% development man-hours saved on removing a single button press will never pay off for the time spent developing this sort of feature, especially since it can be otherwise solved to the same effect but in only few seconds spent, without touching the framework or incurring performance penalties.

    It had never bothered me to restart the game manually after I tweak the code. But that sort of changes alter the program behavior significantly, sometimes radically, it entirely warrants manual cycle. I don't, however, restart the game because I edited some magic numbers - I edit them in-game without even stopping it. So to me this sort of feature is entirely moot.

  22. coffeecat reporter

    If you mean automatically restarting the game when you update a file, then ...

    One can do much more advanced things than this. See my previous forum post for what I am doing in my game project: https://love2d.org/forums/viewtopic.php?f=3&t=84815&start=40#p218268

    Another example is that you can detect texture file changes, and update the texture in the running game.

    And games that support mods check the files at startup, they don't receive notifications in real time. At this point the whole endeavor strikes me as pointless, a lot of effort to solve a petty non-issue. The 0.0001% development man-hours saved on removing a single button press will never pay off for the time spent developing this sort of feature, especially since it can be otherwise solved to the same effect but in only few seconds spent, without touching the framework or incurring performance penalties.

    Are you suggesting that we should use a 'refresh' button for player mod updates? You may argue that a 'refresh' is acceptable, but I believe in better user experiences. A LOVE game developer gets this better user experience for free if this proposal gets accepted in LOVE.

  23. coffeecat reporter

    I don't, however, restart the game because I edited some magic numbers - I edit them in-game without even stopping it.

    I suggest that you take a look at my library lovecat for tweaking numbers.

  24. Mi 28

    I'm not aware of any games with mod support that detect new mods on the fly, they either do it on startup only or have "refresh" button.

  25. coffeecat reporter

    Sorry to disappoint. Recently I have been migrating my game to a Lisp-based framework. I don't know when I can continue to work on this at the moment, so I am closing this.

  26. Log in to comment