Missions, integrations and overlays¶
The mission folder holds the Central Economy files and init.c. dzo treats it
with care: the live mission is never wiped or recreated.
The game world (the persistence, storage_1) is not in the mission folder.
dzo starts the server with -storage=/dayz/storage, and /dayz/storage is
<instances>/<name>/storage/<map> on the host. The server then writes
storage_<instanceId> there and nothing into the mission, so the mission folder
only holds files dzo and the mods manage. Keeping the world per map means that
changing the map starts a fresh world instead of loading the old map’s
persistence; the old one stays in its directory. Mods that use the $storage:
placeholder get the same directory.
Pristine and live¶
Each instance has two copies:
servermpmissions/— the pristine missionA checkout of the instance’s mission repository at the configured
ref.dzo mission update <name>fetches a new version. Nothing else changes it.mpmissions/<map>/— the live missionWhat the server runs. It is created once from the pristine mission (
dzo instance createordzo mission init) and then only updated in place.
Which files dzo manages¶
dzo keeps a manifest of the files it owns in the live mission:
- Managed files
Every file that comes from the pristine mission. dzo updates them on every render.
- Generated files
Folders dzo creates itself:
mod_<id>/for mod CE data,custom_<name>/for overlays, andEditorFiles/.- Foreign files
Everything else:
storage_*, files mods write at runtime, files you placed by hand. dzo never changes or deletes them. Paths listed inmission.unmanagedare treated as foreign even if the mission repository ships them.
If a managed file was changed in the live mission (by a mod or by hand), dzo
warns, copies the changed file to filehistory/ and overwrites it
(drift: warn-backup-overwrite). Recurring drift on the same file usually
means it belongs in mission.unmanaged.
The render¶
Before every start dzo builds the mission in a staging area:
start from the pristine mission;
add each mod’s integration files, in the order of the
modslist;add overlays (shared ones first, then the instance’s own);
validate everything: XML and JSON must parse, every referenced file and every CE folder must exist;
only if everything is valid: take a snapshot if one is due, write the changes into the live mission atomically, update the manifest.
If validation fails, the start is aborted and the live mission is untouched.
Preview a render at any time:
dzo instance render deerisle --dry-run
dzo instance render <name> (without --dry-run) is the same render, applied.
It is what the unit runs before every start. The first render into an empty
mpmissions/<map> is the one-time initialisation from the pristine mission;
every later render only touches files dzo manages (in the manifest, or new in
the pristine mission). storage_* and everything matching
mission.unmanaged is never written.
The render also prepares what the server needs besides the mission: the signature
keys (runtime/keys: the server build’s and those of every client mod, copied
because the container cannot follow links into the cache, plus your own: *.bikey files in keys/ of the site
repository, in instances/<name>/keys/ and at the top of the instance’s overlays), runtime/serverDZ.cfg
from the site repository’s instances/<name>/serverDZ.cfg, and the BattlEye
config with the RCon port and a password that dzo generates once and keeps below
paths.secrets. In serverDZ.cfg dzo sets Missions/DayZ/template to the
instance’s map and steamQueryPort to ports.query; everything else stays
as you wrote it. A missing or unparsable serverDZ.cfg fails the render before
the live mission is touched, also with --dry-run.
The pristine mission is fetched from mission_source the first time it is missing, and never again on its own, so a start
does not need the network. --update-pristine fetches it again; the live
mission follows on that same render. A base file the map lacks (for example
cfgweather.xml) is taken from fallback_mission in the installed server
build, when a build is installed.
The default source is Bohemia Interactive’s Central Economy repository: an instance without
mission_source uses the folder named like its map (dayzOffline.chernarusplus,
dayzOffline.enoch, dayzOffline.sakhal) at master, not the files that ship
inside the server build. ref and path alone change that default, for example
mission_source: {ref: DZ_1.29} pins a tag. A map the repository does not have (a
modded map) needs a mission_source of its own (git/ref/path, or a
preset). dzo instance render <name> --update-pristine fetches the repository
again; the live mission follows, with the usual drift handling.
How mod files are merged¶
integrations/mods/<modid>/integration.yaml says which files a mod
contributes and where they come from:
mod: 2291785308 # required: the workshop id
name: DayZExpansionCore # required: a label for reports
aliases: [2291785437] # default: none; further workshop ids that use this integration
normalize: [xml-decl] # default: none; eventposdef-root | wrap-root | xml-decl
files: # default: none; the key is the file name
types.xml: {source: local, path: files/types.xml}
cfgspawnabletypes.xml: {source: url, url: https://…, sha256: …}
cfgeventspawns.xml: {source: local, path: files/cfgeventspawns.xml,
maps: [dayzOffline.chernarusplus]}
events.xml: {source: mod, path: ./info/events.xml}
hooks:
post_merge: [hooks/remove-static-trains.sh] # default: none
mod and name are required; mod is the workshop id the integration is for, and
aliases lists further workshop ids that use the same integration. Each entry of files has a source, which is local (in the site repository,
needs path, relative to the integration’s folder), url (downloaded, cached, needs
url; sha256 pins it by hash and is verified) or mod (a file shipped inside the mod,
needs path). maps restricts an entry to the listed maps (the map of the instance); the
same file name may then appear for several maps. normalize is explained at the end of
the merge. hooks.post_merge is a list of scripts, see Hooks below.
dzo never changes the downloaded mod itself.
An instance can replace an integration for itself with instances/<name>/integrations/<modid>/
(same file, same keys); it takes the place of the shared one as a whole, key by key not merged.
A map preset, integrations/maps/<name>.yaml, is a mission source an instance refers to
with mission_source: {preset: <name>}. All three keys are required; ref and path
of the instance’s mission_source replace them:
git: https://<git host>/<owner>/DeerIsle-mission.git # the repository
ref: main # a branch, tag or commit
path: empty.deerisle # the mission folder in the repository
Each file type has a fixed merge strategy:
Files |
Strategy |
|---|---|
|
copied to |
|
XML elements appended to the mission file |
|
deep merge; known lists (object spawners, spawn gear presets, restricted areas) are appended without duplicates |
|
arrays concatenated |
|
replaced |
|
patched |
anything else |
copied to |
When two mods define the same thing, the one later in the mods list wins and
the render report lists the conflict.
Overlays¶
An overlay is a folder of mission files: your own tweaks, loadouts, object
spawners. Shared overlays live in site/overlays/, instance overlays in
instances/<name>/overlays/. They use the same merge strategies as mods.
EditorFiles¶
Files in instances/<name>/EditorFiles/ (*.dze for the DayZ Editor Loader
servermod) are copied to EditorFiles/ in the live mission on every render.
They are generated files: dzo owns them. A file you remove from the site is
removed from the mission at the next render (a copy goes to the file history
first, and a folder that ends up empty is removed). Only files dzo wrote are
removed; a file you put there yourself stays.
MapStreamDZE¶
Files in instances/<name>/MapStreamDZE/ (*.dze, subfolders allowed) are
mirrored to profiles/dzo/mapstream/DZE/ of the instance, where the
dzo_mapstream servermod reads them. It is not part of the mission: the sync
runs on every render (so at every start), after the mission is applied. dzo
owns that target folder: files are written when they differ, and files and
folders that are not in the site any more are removed. The render prints the
number of files written and removed when it changed anything.
An instance without a MapStreamDZE folder is not touched, so files the mod
wrote itself stay. Git does not keep an empty folder: to remove the last file,
delete it and keep a placeholder such as .gitkeep in the folder (it is
copied too, which is harmless). Symlinks and other non-regular files in the
folder fail the render. There is no config.yaml, site.yaml or
instance.yaml key for it.
An overlay.yaml can declare files that cfggameplay.json must reference.
dzo then adds the references with the right path:
object_spawners: ["*.json"] # default: none; file name patterns, in the overlay
spawn_gear_presets: ["loadout-*.json"] # default: none
restricted_areas: ["areas-*.json"] # default: none
Each key lists patterns of file names of the overlay that go into the list of that name in
cfggameplay.json: object_spawners (objectSpawnersArr), spawn_gear_presets
(spawnGearPresetFiles) and restricted_areas (playerRestrictedAreaFiles).
Hooks¶
For anything the strategies cannot express, a hook runs a script. A hook is an
executable (a path relative to instances/<name>/ in the site repository, or to the
integration’s folder for an integration’s post_merge) that gets a JSON context on stdin
and these variables: DZO_INSTANCE, DZO_HOOK_POINT, DZO_MAP,
DZO_LIVE_MISSION and, for post_merge, DZO_STAGING. One script runs for at most
10 minutes.
Hook |
When |
A failing script |
|---|---|---|
|
in the staging area: an integration’s own |
fails the render, the live mission stays as it was |
|
after the live mission was updated, at the end of |
fails the render (and so the start) |
|
before the server starts ( |
fails the start |
|
after the container is gone ( |
is printed, nothing else |
|
in a restart that deploys pending mod or build generations, before the snapshot |
aborts the restart, the server starts again as it was |
|
after those generations were deployed |
is printed |
|
after a new generation of a mod was installed, for every instance that uses it |
is printed |
|
after a snapshot, see Backups and restores |
is printed |
dzo instance hook <name> <point> runs the scripts of one point by hand.
The merge itself¶
The staging area is the pristine mission, then the instance’s messages.xml (always empty: dzo serve sends the messages, see Configuration), then the
mods in list order, then the overlays in list order. After the merge every file it wrote must
parse, and every <ce folder> must exist with the files it names, or the render stops before
the live mission is touched. Notes on what is built:
init.cof an integration is a unified diff, applied withpatchto the mission’sinit.c; a diff that does not apply fails the render.messages.xmlis always written empty by dzo; themessages.xmlof a mod integration or an overlay is accepted but replaced by the empty one, becausedzo servesends the server messages itself.globals.xmlis not a Central Economy file type, so it is not registered: its<var>elements are merged bynameintodb/globals.xml(the later contributor wins a variable).Two contributors that replace the same file (
cfgweather.xml,messages.xml) are reported as a conflict; the later one wins. Elements of the XML files that are merged bynameare replaced silently; inmapgrouppos.xmla group is identified bynameandpos, because the file has many groups of one name (one per position).normalize:in an integration repairs the quirks of mod files before they are merged:eventposdef-rootrenames the root<events>ofcfgeventspawns.xmlto<eventposdef>,wrap-rootwraps a file that is a bare list of elements into the root element of its kind (the name of the file says which), andxml-decladds the XML declaration. A JSON file is left alone.A
urlsource is downloaded once and kept inpaths.cache: by itssha256when it has one (and verified), else by its URL (and never fetched again).
Mission history and reset¶
dzo mission rollback <name> [<time>]restores managed files fromfilehistory/.dzo mission reinit <name>recreates the live mission from pristine. This is the only destructive mission command: it asks for confirmation and always takes a snapshot first.