fix paths/clean up code/use best practices

develop
Myk 2022-09-14 10:33:27 -07:00 committed by GitHub
parent 7ccacd7875
commit d68c17d070
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 65 additions and 73 deletions

@ -336,7 +336,7 @@ structure that looks like this::
raw/init.d/example-mod.lua raw/init.d/example-mod.lua
raw/objects/... raw/objects/...
raw/scripts/example-mod/main.lua raw/scripts/example-mod.lua
raw/scripts/example-mod/... raw/scripts/example-mod/...
README.md README.md
@ -346,9 +346,9 @@ Let's go through that line by line.
loaded. loaded.
* Modifications to the game raws (potentially with custom raw tokens) go in * Modifications to the game raws (potentially with custom raw tokens) go in
``raw/objects/``. ``raw/objects/``.
* A subfolder for your mod under ``raw/scripts/`` will contain all the scripts used by * A control script in ``raw/scripts/`` that handles enabling and disabling your mod.
your mod, including the main initialization code in ``main.lua`` which registers all * A subfolder for your mod under ``raw/scripts/`` will contain all the internal scripts
your timer and event callbacks. used by your mod.
It is a good idea to use a version control system to organize changes to your mod code. It is a good idea to use a version control system to organize changes to your mod code.
You can create a separate Git repository for each of your mods. The ``README.md`` file You can create a separate Git repository for each of your mods. The ``README.md`` file
@ -361,107 +361,99 @@ script paths in ``dfhack-config/script-paths.txt``::
+/path/to/mymods/example-mod/raw/scripts +/path/to/mymods/example-mod/raw/scripts
Ok, you're all set up! Now, let's take a look at an example Ok, you're all set up! Now, let's take a look at an example
``raw/scripts/example-mod/main.lua`` file:: ``raw/scripts/example-mod.lua`` file::
-- main setup and teardown for example-mod
-- this next line indicates that the script supports the "enable" API so you can start
-- it by running "enable example-mod" and stop it by running "disable example-mod"
--@ enable = true
local usage = [[
Usage
-----
enable example-mod
disable example-mod
]]
local repeatUtil = require('repeat-util') local repeatUtil = require('repeat-util')
local eventful = require('plugins.eventful') local eventful = require('plugins.eventful')
local modId = 'example-mod' -- you can reference global values or functions declared in any of your internal scripts
local args = {...} local moduleA = reqscript('example-mod/module-a')
local moduleB = reqscript('example-mod/module-b')
if args[1] == "enable" then local moduleC = reqscript('example-mod/module-c')
-- The modules and what they link into the environment with local moduleD = reqscript('example-mod/module-d')
-- Each module exports functions named the way they are to be used
local moduleA = dfhack.reqscript("example-mod/module-a") -- on load,
-- every tick
local moduleB = dfhack.reqscript("example-mod/module-b") -- on load,
-- on unload, onReactionComplete
local moduleC = dfhack.reqscript("example-mod/module-c")
-- onReactionComplete
local moduleD = dfhack.reqscript("example-mod/module-d") -- every 100
-- frames, onProjItemCheckMovement, onProjUnitCheckMovement
-- Set up the modules
-- Order: on load, repeat-util ticks (from smallest interval to
-- largest), days, months, years, and frames, then eventful callbacks in
-- the same order as the first modules to use them
moduleA.onLoad()
moduleB.onLoad()
repeatUtil.scheduleEvery(modId .. " 1 ticks", 1, "ticks", function() enabled = enabled or false
moduleA.every1Tick() local modId = 'example-mod'
end)
repeatUtil.scheduleEvery(modID .. " 100 frames", 1, "frames", function() if not dfhack_flags.enable then
moduleD.every100Frames() print(usage)
print()
print(('Example mod is currently '):format(enabled and 'enabled' or 'disabled'))
return
end end
eventful.onReactionComplete[modId] = function(...) if dfhack_flags.enable_state then
-- Pass the event's parameters to the listeners, whatever they are -- do any initialization your internal scripts might require
moduleB.onReactionComplete(...) moduleA.onLoad()
moduleC.onReactionComplete(...) moduleB.onLoad()
end
eventful.onProjItemCheckMovement[modId] = function(...) -- register your callbacks
moduleD.onProjItemCheckMovement(...) repeatUtil.scheduleEvery(modId .. ' every tick', 1, 'ticks', moduleA.every1Tick)
end repeatUtil.scheduleEvery(modId .. ' 100 frames', 1, 'frames', moduleD.every100Frames)
eventful.onProjUnitCheckMovement[modId] = function(...) eventful.onReactionComplete[modId] = function(reaction, reaction_product, unit, input_items, input_reagents, output_items)
moduleD.onProjUnitCheckMovement(...) -- pass the event's parameters to the listeners
moduleB.onReactionComplete(reaction, reaction_product, unit, input_items, input_reagents, output_items)
moduleC.onReactionComplete(reaction, reaction_product, unit, input_items, input_reagents, output_items)
end end
print("Example mod enabled") eventful.onProjItemCheckMovement[modId] = moduleD.onProjItemCheckMovement
elseif args[1] == "disable" then eventful.onProjUnitCheckMovement[modId] = moduleD.onProjUnitCheckMovement
-- Order: on unload, then cancel the callbacks in the same order as
-- above
print('Example mod enabled')
enabled = true
else
-- call any shutdown functions your internal scripts might require
moduleA.onUnload() moduleA.onUnload()
repeatUtil.cancel(modId .. " 1 ticks") repeatUtil.cancel(modId .. ' every ticks')
repeatUtil.cancel(modId .. " 100 frames") repeatUtil.cancel(modId .. ' 100 frames')
eventful.onReactionComplete[modId] = nil eventful.onReactionComplete[modId] = nil
eventful.onProjItemCheckMovement[modId] = nil eventful.onProjItemCheckMovement[modId] = nil
eventful.onProjUnitCheckMovement[modId] = nil eventful.onProjUnitCheckMovement[modId] = nil
print("Example mod disabled") print('Example mod disabled')
elseif not args[1] then enabled = false
dfhack.printerr("No argument given to example-mod/main")
else
dfhack.printerr("Unknown argument \"" .. args[1] ..
"\" to example-mod/main")
end end
You can see there are four cases depending on arguments. Set up the callbacks You can call ``enable example-mod`` and ``disable example-mod`` yourself while
and call on load functions if enabled, dismantle the callbacks and call on developing, but for end users you can start your mod automatically from
unload functions if disabled, no arguments given, and invalid argument(s) given. ``raw/init.d/example-mod.lua``::
Here is an example of an ``raw/init.d/`` file: ::
dfhack.run_command("example-mod/main enable") -- Very simple. Could be dfhack.run_command('enable example-mod')
-- called "init-example-mod.lua"
Here is what ``raw/scripts/module-a.lua`` would look like: :: Inside ``raw/scripts/example-mod/module-a.lua`` you could have code like this::
--@ module = true --@ module = true
-- The above line is required for dfhack.reqscript to work -- The above line is required for reqscript to work
function onLoad() -- global variables are exported function onLoad() -- global variables are exported
-- blah -- do initialization here
end end
local function usedByOnTick() -- local variables are not exported local function usedByOnTick(unit) -- local variables are not exported
-- blah -- this is an internal function: local functions/variables are not exported
end end
function onTick() -- exported function onTick() -- exported
for blah in ipairs(blah) do for _,unit in ipairs(df.global.world.units.all) do
usedByOnTick() usedByOnTick(unit)
end end
end end
It is recommended to check `reqscript <reqscript>`'s documentation. The `reqscript` function reloads scripts that have changed, so you can modify your
``reqscript`` caches scripts but will reload scripts that have changed (it scripts while DF is running and just disable/enable your mod to load the changes into
checks the file's last modification date) so you can do live editing *and* have your ongoing game!
common tables et cetera between scripts that require the same module.