Start here
How data packs work
The rules on this page hold for every kind of content. The pages for each content type only add what is particular to it.
The folder#
A pack is one folder with a mod.json at its top. Everything else is optional:
- Each content type is read from fixed places, such as
data/tours.jsonand the folderdata/tours/. A path that ends in/is a folder: every.jsonfile in it, and in folders inside it, is read in name order. Every content type’s places. - A file somewhere else is not read.
data/player/fordata/players/is simply ignored. - Files are UTF-8 JSON. Comments and trailing commas are not allowed.
- Use forward slashes in every path a pack writes, on every platform.
mod.json#
The manifest says who the pack is and what it needs:
{
"id": "acme.county-legends",
"name": "County Legends",
"version": "1.2.0",
"gameVersion": ">=0.50.15",
"authors": ["Acme"],
"description": "Thirty players of the county circuit, with their rivalries.",
"dependencies": { "acme.county-venues": "^1.0.0" },
"loadAfter": ["someone.else.pub-tours"],
"tags": ["players", "county"],
"icon": "assets/icon.png",
"banner": "assets/banner.webp",
"screenshots": ["assets/shots/rankings.png"]
}| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
$schema | text | Editor hint: where mod.schema.json is (ignored) | ||
id | text | Yes | Pattern: ^[a-z0-9][a-z0-9-]*(\.[a-z0-9][a-z0-9-]*)*$ | |
name | text | Yes | ||
version | text | Yes | Pattern: ^\d+\.\d+\.\d+(-[\w.]+)?$ | |
gameVersion | text | "*" | Semver range of game versions, e.g. ">=0.5.0 <2.0.0" | |
authors | list | [] | ||
description | text | "" | ||
dependencies | map (key: value) | {} | ||
loadAfter | list | [] | ||
provides | list | [] | ||
entry | text | Script run in the sandbox (Scripts), e.g. "scripts/main.js" (used by default when present) | ||
tags | list | [] | ||
replaces | list | [] | Kinds of the base game’s data this pack takes out before adding its own, e.g. ["players"]: only the base game’s records go, never another pack’s, so packs for different countries add up. An entry can be { "kind": "players", "nations": ["ENG", "SCO"] } to take out only those nations’ records | |
replaces[] | one of several shapes | Yes | ||
| Shape 1: text | ||||
Shape 2 (with kind) | ||||
replaces[].kind | text | Yes | ||
replaces[].nations | list, at least 1 item | Nation codes: only the base game’s records from these nations are taken out (players, roster and venues) | ||
icon | text | Square image shown on the Mods screen: an asset path relative to the mod, e.g. "assets/icon.png" (png, jpg, webp, gif, avif or svg; 1 MB at most; 256×256 looks best) | ||
banner | text | Wide image across the top of the mod’s card and details: an asset path, e.g. "assets/banner.webp" (about 3:1, e.g. 1200×400; 4 MB at most) | ||
screenshots | list, up to 8 items | [] | Up to 8 images shown in the mod’s details (asset paths; 4 MB each at most) | |
scriptBudgetMs | number | No longer read: a script has no time limit, only a step limit for a stuck call (Scripts). A mod that still sets it loads with a warning | ||
Versions and ranges#
version is major.minor.patch, such as 1.2.0, with an optional tag (1.2.0-beta.1). gameVersion and the values in dependencies are ranges:
| Range | Means |
|---|---|
* | any version (the default) |
0.50.15 or =0.50.15 | exactly that version |
>=0.50.15, >, <, <= | at least, above, below, at most |
^1.2.0 | 1.2.0 or later, below 2.0.0 (for 0.x versions: the same minor version) |
~1.2.0 | 1.2.0 or later, below 1.3.0 |
>=0.50.0 <0.60.0 | both at once (separated by a space) |
^1.0.0 || ^2.0.0 | either |
A pack whose gameVersion the game does not meet does not load (“Needs game version …; this is …”). So does a pack whose dependency is missing, switched off or the wrong version.
Records and ids#
Most content files are a JSON list of records, and every record has an id. Ids are lower-case words separated by dots, with dashes inside words: acme.county-legends.player.big-dave.
- A new record’s id starts with your pack’s id and a dot. That keeps packs from treading on each other. The rest of the id is yours: the base game uses
core.<kind>.<name>, such ascore.player.dani-okafororcore.venue.irwell-dome, and that is a good habit. - A record with an id that already exists replaces that record, field for field: yours is used and the other is gone. The Mods screen shows a warning naming whose record you replaced, so that two packs replacing the same thing are easy to spot.
- The same id twice in your own pack is an error.
- Other records name records by id: a player’s
rivalIds, an event’svenueIdandtourId, a story’s follow-ups. Each field’s notes in the reference say what it names.
Replacing the base game’s data#
A pack’s records go in beside the base game’s. To use your own world instead (real players, say), name in mod.json the kinds of data whose base-game records should go first:
{
"id": "acme.real-uk",
"replaces": ["players", { "kind": "venues", "nations": ["ENG", "SCO", "WAL", "NIR"] }]
}- A kind is the content type’s name on the content types page:
players,roster(the Exhibition quick-match players),tours,events,venues,sponsorsand so on. Settings files such astuningcannot be replaced: change their values by id. - Only the base game’s records go, never another pack’s. Two packs that each replace
players, one per country, both keep their players. nationsnarrows it to the base game’s records from those nations (playersandrosterbynationality,venuesbycountry). Other nations keep theirs.- Your pack can still change a base record by its id: that record stays.
- Records that named something taken out are dropped with a warning, as usual (an event at a removed venue, say). Tours and events are tied to the base game’s career rules, nation scenes and organisations, so a pack that replaces them needs those to follow.
- Give the same real person the same id in every pack (agree it with other makers), so a player in two packs is one record and the later one wins.
- A kind the game does not know, a settings kind, or
nationson a kind without a nation is an error, and the pack does not load. - The Data packs page shows what a pack replaces, and warns when the same person (first name, last name and nationality) is in two packs, or when a pack’s
replacesleaves a nation with no named players from any pack (the game still makes up players from its name pools there).
Careers and your pack’s updates#
A career keeps the pack data it started with, and New Career lets the player pick which packs a career starts with. When you release a new version, tell careers what changed with a text per change, named after your pack and the new version:
[
{ "id": "acme.real-uk.text.data-update.acme.real-uk.4.1.0.new-players", "text": "Twelve Challenge Tour players join" }
]- Put it in
data/texts/. The part afterdata-update.is your pack’s id, the version and a short name. - A career that uses your pack is then offered the update when it is loaded. Taking it brings in your new version’s event templates, venues, sponsors, kit, commentary and stories, and your new named players.
- Players already in the career, their rankings, money and results are never changed.
- A version with no such text offers nothing, and a pack can only announce its own changes.
- Deleting a pack that careers use warns the player and names those careers: they keep playing on the data they have, but lose the pack’s pictures and its own texts.
Settings files#
Some content is a set of numbers rather than a list of things: the career rules, training, injuries, travel load, the living world, legacy, population, the card settings, the kit settings, travel fares and the tuning values. Their file holds one object (a list of them also works):
{
"id": "acme.county-legends.training",
"rate": 0.036
}- Every field but
idis optional. Give only what you want to change; the rest keeps the game’s value. - Several packs can each ship one. They apply in load order, and later fields win.
- Inside a field, most objects merge key by key and a list you give replaces the whole list, but each kind of settings has its own rules: its guide says how its fields combine.
Patches#
A patch changes a few fields of a record from another pack (the base game, usually) and leaves the rest as it is. That is kinder than replacing the whole record: if the base game later improves the record, your pack keeps the improvements and still makes its own change.
Patches go in data/patches/, in files ending .patch.json. A file holds one patch or a list of them:
[
{ "target": "player:core.player.dani-okafor", "patch": { "nickname": "The Quicksilver Kid", "attributes": { "finishing": 95 } } },
{ "target": "tour:core.tour.challenge", "patch": { "rules": { "cardsAwarded": 3 } } },
{ "target": "sponsor:core.sponsor.barrelcraft", "patch": { "logo": null } }
]targetis the record’s kind, a colon and its id. The kind is the content type’s patch key (player,tour,event,venue,sponsor,text,tuning, …), listed for every type on the content types page.- A patch follows JSON Merge Patch: objects merge field by field, any other value (a list included) replaces what was there, and
nullremoves a field. - Patches apply after every pack’s records are in, in load order. A patch still works when another pack has replaced the record.
- A picture path in a patch is read from the patching pack’s folder.
- A patch whose target does not exist (the other pack is not installed, say) is a warning, not an error. So is a patch that would leave the record broken: it is skipped.
Load order#
- The base game (
core) always loads first. - Packs that come with the game load next, in name order.
- Then your installed packs, in the order on the Mods screen (Load earlier and Load later in a pack’s details). A new pack goes in alphabetical order after those already placed.
- A pack always loads after the packs in its
dependenciesandloadAfter, whatever the order on the screen. Packs that name each other in a loop do not load.
When two packs give the same record, the later one wins. Settings and tuning apply in the same order, later values winning.
Errors and warnings#
- An error disables the whole pack. Bad JSON, a field the type does not have, a value out of range, a new id without your prefix, a missing dependency: the pack shows Not loaded and none of it is used, so a pack is never half installed.
- A warning lets the pack load. A picture that is missing or cannot be read (the game draws its own art instead), a record that replaces another pack’s, a patch with no target.
- Cross-checks run once every pack is in: an event at a venue that does not exist, a rival who is not a player, a story that follows up a story nobody has. The record that cannot work is dropped, with a warning saying why, and the rest of the pack loads.
Every problem is listed in the pack’s details on the Mods screen with its file, line, record and field. The Mod Studio shows them as you type.
Packs and careers#
A career takes a copy of the content when it starts, and the career is played from that copy. Installing, changing, switching off or removing a pack therefore changes new careers first. Some content then follows the installed packs into careers under way, the next time each career is loaded:
| Follows the installed packs into careers under way | Stays as the career began |
|---|---|
|
|
The interface and the look of the game (interface strings, themes, the main menu’s backdrop) come from the installed packs whenever the game runs.
When a new version of the game changes the base game’s data, a career under way is offered an update the next time it is loaded, with a list of the changes and a backup of the save. That update is for the base game’s data only: a new version of your pack reaches new careers, plus whatever follows the installed packs, above.
A career remembers the packs it began with. If you load a career whose packs are no longer installed or have changed, the Load screen says so; the career still plays, from its own copy.
The base game as your reference#
The base game’s pack is the best reference there is: every content type, set out the way the game expects, with its pictures. On Windows it is in the folder where the game is installed, at DartsPlayerSimulator_Data\StreamingAssets\core. Read it and copy from it, but do not change it: a game update replaces it, and your changes belong in a pack of your own.
To use one of the base game’s pictures in your pack, give its full address, such as dtj-asset://core/assets/venues/core.venue.irwell-dome.webp. See Images, sound and models.