Modding

Supporting multiple game versions

Folder

A mod folder can hold a subfolder per game version. The root info.json lists them in versions, each entry a path and a match expression on the game version. At startup, the game reads this list, selects the first matching entry and loads the mod from that subfolder.

folder
DayAndNightSolar/
    info.json
    0.22.2/
        info.json
        init.lua
    0.22.1/
        info.json
        init.lua
info.json json
{
    "name": "DayAndNightSolar",
    "versions": [
        { "path": "0.22.2", "match": ">=0.22.2" },
        { "path": "0.22.1", "match": "<=0.22.1" }
    ]
}

Each subfolder is a whole mod: its own info.json, init.lua, Loc and Paks. The root file is read for versions; the manifest of the mod comes from the matched folder.

Matching

FieldMeaning
path Subfolder containing a complete mod and its info.json.
match Game version constraints. Every constraint must be satisfied.
  • The version matched against is the build string up to the first -: a game that reports 0.22.2-1 matches as 0.22.2.
  • A match is one or more conditions, each an operator and a version: >=, <=, =, >, <. Every condition must be satisfied. For example, >=0.22.0 <0.23.0 includes versions from 0.22.0 up to, but not including, 0.23.0.
  • Versions compare number by number, and a version with fewer numbers is the lower one: 0.22 is lower than 0.22.0. Use all three components for exact matches: =0.22 does not match 0.22.0.
  • Entries are checked from top to bottom. Put an exact version match before any broader range that includes it.

The matched folder

Everything the game reads for the mod comes from the matched folder: the manifest, init.lua and the modules require reaches from it, the strings in Loc/<language>/, and the paks in Paks/<Platform>/.

0.22.2/info.json json
{
    "name": "DayAndNightSolar",
    "version": "1.1",
    "title": "Day & Night Solar",
    "author": "evospace",
    "evospace_version": "0.22.2",
    "dependencies": ["Vanilla>=0.22.0", "VanillaLib>=0.22.0"],
    "description": "Solar panels produce at full output throughout the day and night."
}
  • Use the same name in every version folder. Only one version is loaded at startup.
  • dependencies are per folder. The example's 0.22.2 folder reads vlib and declares VanillaLib; its 0.22.1 folder iterates over the prototypes directly and depends only on Vanilla.
  • evospace_version is the build the folder was written for.

Log

The game names the version it matches against, and the entry each versioned mod matched. The log is written at startup.

log
Game version for mod matching: 0.22.2
Versioned mod DayAndNightSolar: matched >=0.22.2 -> 0.22.2

When no entry matches, the mod is not loaded:

log
Versioned mod DayAndNightSolar has no match for game version 0.22.2

A matched path without an info.json is an error as well, and no other entry is tried:

log
Versioned mod DayAndNightSolar: path 0.22.2 has no info.json

A folder that declares an evospace_version above the running build still loads, with a warning:

log
DayAndNightSolar declares evospace_version 0.22.4 but the game is 0.22.2: it was built against an api this build does not have

One folder

A mod that differs between builds in a value, not in the API it calls, needs no second folder: game.build_string is the build it runs on, suffix included — 0.22.2-1. It is a field of Game.

Installation and publishing

The mod folder goes to Content/Mods of the game, or to the Workshop from the main menu as in Publishing: the form points at the mod folder and Steam takes its whole tree, subfolders included, so one Workshop item serves every build the versions list covers. A subscriber's game picks its folder at startup, and the mod list shows the title and version of the folder it picked.