Is this the proper way to do a mod's auto-run module? Are there best practices that I'm not following?
Let me see if I can do code review in this format. Hopefully it will be easy enough to follow.
First of all, "internal" modules refer to modules that are internal relative to your mod. They are explicitly ignored by the DFHack mod scanning. The script should go in
lighter_green_glass (100)/scripts_modactive
in order to get picked up and loaded.
This *does* allow your script to be shown in
gui/launcher as a runnable script, but that's not a bad thing. That gives you a mechanism to show your help text, reminding the user what the mod does and telling them how to control it (if/when you implement adjustable controls).
Incidentally, this file needs help text : ) The format is documented here:
https://docs.dfhack.org/en/latest/docs/dev/Documentation.html#external-scripts-and-pluginslocal function mod_is_loaded()
-- df.global.world.object_loader.object_loader_order_id[] is an array of strings.
-- search it for the ID of our mod. if it exists, the mod is loaded.
return(utils.linear_index(df.global.world.object_loader.object_load_order_id, mod_ID, 'value') ~= nil)
end
You don't need this part. Once your script is in the correct location, it will load if and only if it is active for the current world.
if dfhack_flags.module then
dfhack.onStateChange[GLOBAL_KEY] = function(event)
if event == SC_WORLD_LOADED and mod_is_loaded() then
activate_mod_raws_changes()
elseif event == SC_WORLD_UNLOADED and mod_is_loaded() then
deactivate_mod_raws_changes()
end
end
end
You don't need to check for dfhack_flags.module since you've already filtered out the cases where that variable is not true. Also, as mentioned above, you don't need to check if the mod is loaded since being in the correct path will do that for you.
Also, be sure to completely remove your state change handler on world unload, otherwise your handler will still run in a later-loaded world where the mod is not active. I just recently realized this was a problem and updated the
example in the modding guide. If a world with your mod active is loaded a second time, the script will be reloaded as a module before the world loaded event and will have an opportunity to reattach the handler.
Suggested replacement code:
dfhack.onStateChange[GLOBAL_KEY] = function(event)
if event == SC_WORLD_LOADED then
activate_mod_raws_changes()
elseif event == SC_WORLD_UNLOADED then
deactivate_mod_raws_changes()
dfhack.onStateChange[GLOBAL_KEY] = nil
end
end
It is not required, but if you implement the enabled API, it would:
1. feature your mod in the DFHack control panel (in the "Fort" tab), including a link to show your help text
2. allow players to use the enable and disable commands to dynamically control your mod
Implementing the enabled API just means adding a
--@enable=true tag at the top of the file, implementing an
isEnabled() function, and handling the
dfhack_flags.enable_state flag. The example in the modding guide does this.
I have to say, this is a beautifully simple mod. Do you mind if I use it as an example in the modding guide?