Looking for advice on library module design

I’ve been working on reusable lua modules a lot lately, but I have a problem making them both A) as flexible and easy-to-use as I want, and B) work with Defold’s library dependency system. The problem is, library files are refreshed every time you open the editor, so I can’t require the user to change anything in the module itself, or in any accompanying files. So . . . how do I make a library that can be configured in different ways?

For example, I’m working on a GUI library. I have most of the code in one module, but I’ve separated all the visual stuff (for button press, release, hover, etc.) in a separate “theme” module so it can be more easily customized. You could easily make a new theme module outside the library folder, but you’d still have to change the require line in the main module, which would be un-done when the editor refreshes the library.

The options I’ve thought about so far are:

  1. I could pass in data from a script, but that would have to be done before any other scripts try to use the library, which is a pain in the butt.
  2. I could require a file that is outside the library folder. This might be the best option, but it does add more setup work for the user and means the library wouldn’t work “out of the box”.
  3. I could just forget about the Libraries system and make the module however I want. This is easy, but makes setting up the library way more work. Download, unzip, cut, paste, etc., rather than just: copy-paste line to game.project, click “fetch”. And it means you wouldn’t get automatic updates. (which isn’t necessarily a bad thing.)

So I’m looking for other people’s thoughts on this. Both on how to solve it, and how you like to use external libraries, if you care about the library dependency thing or not, etc. Thanks!

1 Like

If you compartmentalize the settings can’t you have a set of defaults so everything works out of the box? If a user wants to override settings, they can do something like:

ross_mod = require("path/to/ross_cool_module")
mod_settings = require("my_settings")
-- or
mod_settings = { some_setting = 4711, ... }

-- and then
ross_mod.settings(mod_settings)
...
2 Likes

Why not have an init(config) function of some kind in your Lua module and let the user provide configuration/setup via that function?

4 Likes

@britzl Well, that would be option 1. I was hoping to avoid having to set things at run time from a script, since that means you need a script that runs before everything else. I mean, it’s probably a good idea to design your game so there’s one script that runs first, but I’d rather not force that on people.

@sicher That’s a very good point. See my response to Britzl above, but, you made me realize that I can wrap a require in pcall() and get the defaults if that fails.

-- in ross_cool_module
local settings = pcall(require, "main.user_settings") or require("path/to/ross_cool_settings")

That would still need a fixed location for a user settings file, so it’s not perfect I guess. Maybe I’ll just use both: the above and also allow changing settings via a function call. That should cover all the bases.

Another option would be to try and load additional configs from an embedded .json file using sys.load_resource().

1 Like

I have similar question, for libraries like DirtyLarry and other libraries that uses an atlas/sprites/guis. Is there a way to design the library so you can inject your own atlas?

2 Likes

My solution to this is somewhat influenced by subclassing in oop. I have a gui helper library that works out of the box, but when I want to config stuff I do it by creating another module that requires the first and monkey patch stuff and then I require that module instead:

-- gui_helper.lua

local _M={
       texture="buttons.png",
}

_M.register_button=function(text)
...
end

return _M

-- new_gui_helper.lua
local _M=require("gui_helper.lua")

_M.texture="nicer_buttons.png"
_M.register_button=function(text, image)

end

return _M

I then can require the new_gui_helper.lua instead.

Don’t know if that is more or less cumbersome than what you have now…

4 Likes

That’s a pretty cool idea. I always forget that you can change stuff like that. Thanks!

1 Like