File layout and discovery

A patch only runs if the game can find it. This page covers where patch files go and the two globals that tell your script who it belongs to.

What a mod is

If you have not packaged a mod before, here is the short version. A mod is a folder the game loads at startup. Inside it is a swinfo.json manifest that gives the mod an id, a name, and a version. (It is a file from SpaceWarp, the modding platform Redux is built on.) Your patches are just .lua files sitting inside that folder.

Mods live in the game's mods folder, the same place every Redux and SpaceWarp mod is installed. The in-game mod list has an "Open Mods Folder" button that opens it, which is the easiest way to find it. At startup PatchManager looks through the mods there and discovers the .lua files inside each one.

Shipping patches covers the manifest in detail. For now you only need the picture: a mod is a folder with a manifest and your .lua files.

Where patch files live

There are two ways a .lua patch gets discovered.

Inside a mod

The normal case. Your mod is a folder with a swinfo.json manifest. Every .lua file anywhere under that folder is discovered and run as a patch, at any depth. You can organize patches into subfolders however you like:

MyMod/
  swinfo.json
  patches/
    parts.lua
    planets/
      reentry.lua
      dust-colors.lua

All three .lua files will be discovered and run.

There is one rule: a file whose name starts with an underscore is skipped. A file like _shared.lua is not run as a patch. This is how you keep helper libraries that other patch files pull in with require from being executed on their own. See Sharing Lua with require.

As a standalone drop-in

A single .lua file dropped directly into the game's mods folder, with no swinfo.json around it, is treated as a tiny mod of its own. Its mod id becomes the file name without the extension. This is convenient for a one-file tweak you do not want to package, but for anything you share, it is recommended to ship it as a packaged mod.

ModId

ModId is a global string holding the id of the mod your script belongs to. For a packaged mod it is the ModID from swinfo.json. For a standalone drop-in it is the file name sans extension.

You will use it when you want a name that is unique across all mods. Patch names, for instance, are automatically prefixed with your ModId behind the scenes, which is why two mods can both have a patch called Fixes without clashing. As such you will rarely need to read ModId directly.

Location

Location is a global string holding the full path to the folder your script was found in. It is useful when a patch needs to load a file you shipped alongside it: instead of hard-coding a path, you build one relative to Location. This matters because the modloader lets a mod sit at any depth in the file tree, so there is no fixed path you could assume. Location always points at your own mod's folder, wherever it ended up.

Location is nil only in unusual setups where a script was not loaded from a folder on disk. That does not happen by accident, so unless you have deliberately arranged it, you do not need to guard against the nil case.

When patches run

Discovery happens once, at game startup, before assets load. All discovered scripts run to register their patches first. This includes the scripts of mods that are not yet on in a campaign. Then PatchManager loads the assets and runs the registered patches on them:

  • One time for the feature set of the main menu, at startup.

  • One more time for the set of each campaign, when that campaign loads.

Each run uses only the patches that the set allows. This split is important. The body of a Do callback runs later than the PM.Parts:Patch(...) call that registered it. The callback can run more than one time, one time for each set. You cannot register a new patch from inside a Do callback, because registration is already over by then.

Next

Once your patches work locally, shipping patches covers packaging them for other people.