WENOPAL

How to port a Project Zomboid mod from B41 to B42

A list of everything that changed for modders between Build 41 and Build 42 (folders, items, recipes, translations, Lua) and how to update your mod step by step.

Level intermediate Β· Updated

Thousands of Build 41 mods don't work in Build 42, and many of their authors have moved on. The good news is that most of the changes are mechanical: you can fix them with find and replace, as long as you know what to look for. This guide collects everything we had to change in our own mods, checked against the game's own files (B42.21).

1. The folder structure

In B41 the files went straight into the mod folder. In B42 they go inside a folder named after the version:

text
B41                                   B42
Contents/mods/MiMod/                  Contents/mods/MiMod/
β”œβ”€β”€ mod.info                          β”œβ”€β”€ 42/
β”œβ”€β”€ poster.png                        β”‚   β”œβ”€β”€ mod.info
└── media/                            β”‚   β”œβ”€β”€ poster.png
                                      β”‚   └── media/
                                      └── common/        (optional)
  • Move mod.info, the images and media/ into 42/.
  • common/ is for files that work on any version. It's optional.
  • In mod.info, add versionMin=42.0.0, or whatever version you actually need.

2. Items: Type becomes ItemType

In B42 no vanilla item uses Type =: they all use ItemType with a base: prefix.

B41B42
Type = Food,ItemType = base:food,
Type = Weapon,ItemType = base:weapon,
Type = Clothing,ItemType = base:clothing,
Type = Normal,ItemType = base:normal,
Type = Drainable,ItemType = base:drainable,

The 15 types that exist in B42 are: base:normal, base:food, base:weapon, base:clothing, base:drainable, base:container, base:literature, base:moveable, base:radio, base:key, base:map, base:weaponpart, base:alarmclock, base:alarmclockclothing and base:animal. For examples of each, look up a similar item in the item reference.

3. Tags, BodyLocations and categories take base:

WhatB41B42
TagsTags = Hammer,Tags = base:hammer,
Where clothing is wornBodyLocation = Shoes,BodyLocation = base:shoes,
Weapon categoryCategories = SmallBlunt,Categories = base:smallblunt,

The exact values are in the tag reference and the BodyLocations reference. Watch out: some names aren't just "add base:" (for example, there's base:tshirt, base:shortsleeveshirt, base:zeddmg). Copy them from the reference.

4. Recipes: recipe becomes craftRecipe

B42 doesn't have a single recipe in the old format: there are almost a thousand craftRecipe and zero recipe. The format is completely different:

text
craftRecipe MakeCompletoItaliano
{
    timedAction = Making,
    time = 60,
    Tags = InHandCraft;Cooking,
    category = Cooking,
    inputs
    {
        item 1 [CompleteItaliano.PanCompleto;Base.BunsHotdog_single] flags[InheritFoodAge],
        item 1 tags[base:screwdriver] mode:keep,
    }
    outputs
    {
        item 1 CompleteItaliano.CompletoItaliano,
    }
}
  • Old recipes don't convert themselves: you have to rewrite them. See the items and recipes guide.
  • Every item from your mod needs the module in front (MiMod.Item). If it's missing, the game won't load the save ("World loading could not proceed, there are script load errors").
  • The recipe's display name goes in Recipes.json (see section 5).

5. Translations: JSON only

B42 only reads .json files. B41's .txt files are silently ignored: the key shows up on screen instead of the text.

text
B41: media/lua/shared/Translate/ES/ItemName_ES.txt
     ItemName_ES = {
         ItemName_MiMod.Sopaipilla = "Sopaipilla",
     }

B42: media/lua/shared/Translate/ES/ItemName.json
     {
         "MiMod.Sopaipilla": "Sopaipilla"
     }
  • Notice that the key changes: in B42 it's Module.Item, without the ItemName_ in front.
  • The same goes for Tooltip, Recipes, IG_UI, Sandbox: one .json per type and per language (the example above is the Spanish ES folder; English lives in EN). Details in Translations.

6. Loot: nearly the same, but check the names

The system is still ProceduralDistributions with Events.OnPostDistributionMerge, so B41 loot code usually works. But many lists were changed or left empty: for example, GunStoreShelf exists but is marked as deprecated and has no items. If your item "doesn't spawn", check every name in the loot list reference.

Always use the pattern that checks the list exists, explained in Loot.

7. Lua changes that break mods

BeforeIn B42
getProperties():Is(IsoFlagType.water)getProperties():has(IsoFlagType.water), lowercase. The game doesn't use :Is( anywhere.
getCell():getVehicles():get(i)getVehicles() is now a Set, with no :get(i). To loop over objects, use getCell():getObjectListForLua().
HaloTextHelper.addText(player, texto, color)Use addGoodText (green), addBadText (red) or addText(player, texto).
table.insert(PrintMediaDefinitions.Fliers, ...)That table no longer exists: fliers are now a registry (Registries.FLIER).
BodyLocations as strings: getOrCreateLocation("Hat")The game uses the ItemBodyLocation.HAT enum. Check media/lua/shared/NPCs/BodyLocations.lua.
Timed actions in client/Put them in shared/: in B42 multiplayer the server also creates them by name.

The typical symptom of these changes is a tried to call nil error that shows up when the save loads. The full list of B42 events is in the Lua events reference.

8. Servers: Mods= takes a backslash

If your mod gets used on servers, mention on its page that in B42 the line is Mods=\MiMod (with a \ before each ID). More in the dedicated server guide.

Checklist

  • Files moved into 42/ and versionMin set in mod.info.
  • Every Type = changed to ItemType = base:....
  • Tags, BodyLocations and categories with base:, copied from the reference.
  • Recipes rewritten as craftRecipe, with your mod's items prefixed by the module.
  • Translations moved to .json, with the new keys.
  • Loot lists checked one by one.
  • No :Is(, getVehicles():get( or PrintMediaDefinitions.Fliers left in the Lua.
  • Tested with -debug on a new save: no errors in console.txt. See Common errors.