A patch with "Action": "EditData" edits fields and entries inside a data asset. Any number of
content packs can edit the same asset.
A data asset contains information loaded by the game: events, dialogue, item info, etc. The format for many assets is documented on the wiki.
There are three types of asset:
| asset type | usage |
|---|---|
| dictionary |
A dictionary is a list of key/value pairs, where the key is unique within the list. The key is always an integer or string, but the value can be any data type. For example, {
// "key": value
"504": "Sneakers/A little flimsy... but fashionable!/50/1/0/0/Sneakers",
"505": "Rubber Boots/Protection from the elements./50/0/1/1/Rubber Boots",
"506": "Leather Boots/The leather is very supple./50/1/1/2/Leather Boots"
} |
| list |
A list is a non-unique set of values which don't have an explicit key. These are surrounded by
For example, [
{
"ID": 0,
"Name": "Cotton Candy",
"DisplayName": "Cotton Candy",
"Description": "A large pink cloud of spun sugar.",
"Price": 50,
"ItemTags": [ "Sweet", "Candy" ]
},
// other entries omitted for brevity
]Although lists don't have keys, Content Patcher often assigns one field as a unique identifer which can be used as the key (see edit a list). |
| model |
A model is a predefined data structure. For content packs, it's essentially identical to a dictionary except that you can't add new entries (only edit existing ones). |
An entry is a key/value pair in a dictionary, or a value in a list. The key is always a number or string.
For example, each line in Data/Boots is an entry (where the number before the colon is the key,
and the string after it is the value):
{
"504": "Sneakers/A little flimsy... but fashionable!/50/1/0/0/Sneakers",
"505": "Rubber Boots/Protection from the elements./50/0/1/1/Rubber Boots"
}That also applies to data models. For example, this is one entry from Data/Movies:
"fall_movie_0": {
"ID": null,
"SheetIndex": 1,
"Title": "Mysterium",
"Description": "Peer behind the midnight veil... You must experience to believe!",
"Tags": [ "horror", "art" ],
"Scenes": [ /* omitted for brevity */ ]
}A field is just an entry directly within an entry. In the previous example, "SheetIndex": 1 is
a field.
An EditData patch consists of a model under Changes (see examples below) with these fields:
- Required fields:
-
You must specify both of these fields:
field purpose ActionThe kind of change to make. Set to EditDatafor this action type.TargetThe game asset name to replace (or multiple comma-delimited asset names), like Characters/Dialogue/Abigail. This field supports tokens, and capitalisation doesn't matter.And at least one of these:
field purpose FieldsThe individual fields you want to change for existing entries. This field supports tokens in field keys and values. The key for each field is the field index (starting at zero) for a slash-delimited string, or the field name for an object. EntriesThe entries in the data file you want to add/replace/delete, indexed by ID. If you only want to change a few fields, use Fieldsinstead for best compatibility with other mods. To add an entry, just specify a key that doesn't exist; to delete an entry, set the value tonull(like"some key": null). This field supports tokens in entry keys and values.
For list values, see alsoMoveEntries.MoveEntries(List assets only) Change the entry order in a list asset like Data/MoviesReactions. (Using this with a non-list asset will cause an error, since those have no order.)TextOperationsChange the value of an existing string entry or field; see text operations for more info.
To change an entry, use the format
["Entries", "entry key"]and replace"entry key"with the key you'd specify forEntriesabove. If the entry doesn't exist, it'll be created and the text operation will be applied as if it was an empty string.To change a field, use the format
["Fields", "entry key", "field key"]and replace"entry key"and"field key"with the keys you'd specify forFieldsabove. If the entry doesn't exist, the operation will fail with an error message. If the field doesn't exist, it'll be created if the entry is an object, or fail with an error if the entry is a delimited string. Currently you can only target top-level fields. - Optional fields:
-
field purpose TargetFieldWhen targeting a list or dictionary, the field within the value to set as the root scope; see target field below. This field supports tokens. When(optional) Only apply the patch if the given conditions match. LogName(optional) A name for this patch to show in log messages. This is useful for understanding errors; if not specified, it'll default to a name like entry #14 (EditImage Animals/Dinosaurs).Update(optional) How often the patch fields should be updated for token changes. See update rate for more info.
The simplest edit for a dictionary is to create or overwrite an entry. For
example, this adds an item to Data/ObjectInformation (with the key 900):
{
"Format": "1.27.0",
"Changes": [
{
"Action": "EditData",
"Target": "Data/ObjectInformation",
"Entries": {
"900": "Pufferchick/1200/100/Seeds -74/Pufferchick/An example object."
}
},
]
}You can also edit a field within the entry. When the entry's value is a string, the value is assumed to be a slash-delimited list of fields (each assigned a number starting at zero); otherwise fields are entries directly within the given entry. For example, this edits the description field for an item:
{
"Format": "1.27.0",
"Changes": [
{
"Action": "EditData",
"Target": "Data/ObjectInformation",
"Fields": {
"128": { // entry 128 (pufferfish)
5: "Weirdly similar to a pufferchick." // field 5 (description)
}
}
},
]
}You can also delete an entry by setting its value to null. For example, this deletes an event to
recreate it with different conditions:
{
"Format": "1.27.0",
"Changes": [
{
"Action": "EditData",
"Target": "Data/Events/Beach",
"Entries": {
"733330/f Sam 750/w sunny/t 700 1500/z winter/y 1": null,
"733330/f Sam 750/w sunny/t 700 1500/z winter": "event script would go here"
}
}
]
}When the value has nested entries, you can use TargetField to edit a specific
one.
You can edit a list the same way too, with a few caveats.
Although there's no unique key, you can still use the Entries field to target a specific entry as
if it did. Content Patcher will find the entry based on a unique value in the data model:
| asset | field used as the key |
|---|---|
| default | ID if it exists. |
Data/ConcessionTastes |
Name |
Data/FishPondData |
The RequiredTags field with comma-separated tags (like fish_ocean,fish_crab_pot). The key is space-sensitive. |
Data/MoviesReactions |
NPCName |
Data/RandomBundles |
AreaName |
Data/TailoringRecipes |
FirstItemTags and SecondItemTags, with comma-separated tags and a pipe between them (like item_cloth|category_fish,fish_semi_rare). The key is space-sensitive. |
The order is often important for list assets (e.g. the game will use the first entry in
Data\MoviesReactions that matches the NPC it's checking). You can change the order using the
MoveEntries field. For example, this moves the Abigail entry using each possible operation:
{
"Format": "1.27.0",
"Changes": [
{
"Action": "EditData",
"Target": "Data/MoviesReactions",
"MoveEntries": [
{ "ID": "Abigail", "BeforeID": "Leah" }, // move entry so it's right before Leah
{ "ID": "Abigail", "AfterID": "Leah" }, // move entry so it's right after Leah
{ "ID": "Abigail", "ToPosition": "Top" }, // move entry to the top of the list
{ "ID": "Abigail", "ToPosition": "Bottom" }, // move entry to the bottom of the list
]
},
]
}New entries are added at the bottom of the list by default.
A model is a predefined data structure. For content packs, it's essentially identical to a dictionary except that you can't add new entries (only edit existing ones).
You can perform any number of edit operations within the same patch. For example, you can add a new
entry and then move it into the right order at the same time. They'll be applied in this order:
Entries, Fields, MoveEntries, and TextOperations.
Your changes normally apply to the top-level entries, but TargetField lets you apply changes to a
nested subset of the entry instead. For example, you can change one field within a field within the
entry.
This affects all of the change fields (e.g. Fields, Entries, TextOperations, etc).
TargetField describes a path to 'drill into' relative to the entire data asset.
For example, "TargetField": [ "Crafts Room", "BundleSets", "#0", "Bundles", "#0" ] will...
- select the
Crafts Roomentry; - select the
BundleSetsfield on that entry; - select the first bundle set in that
BundleSetsfield; - select the
Bundlesfield on that bundle set; - and select the first value in that
Bundlesarray.
At that point any changes will be applied within the selected value, instead of the entire model.
Each value in the list can be one of these:
| type | effect |
|---|---|
| ID | A dictionary key or list key within a dictionary/list (e.g. "Crafts Room" in the example below). |
| field name | The name of a field on the data model (e.g. "BundleSets" and "Bundles" in the example below). |
| array index | The position of a value within the list (e.g. #0 in the example below). This must be prefixed with #, otherwise it'll be treated as an ID instead. |
The Data/RandomBundles asset has entries like this:
[
{
"AreaName": "Crafts Room",
"Keys": "13 14 15 16 17 19",
"BundleSets": [
{
"Bundles": [
{
"Name": "Spring Foraging",
"Index": 0,
"Sprite": "13",
"Color": "Green",
"Items": "1 Wild Horseradish, 1 Daffodil, 1 Leek, 1 Dandelion, 1 Spring Onion",
"Pick": 4,
"RequiredItems": -1,
"Reward": "30 Spring Seeds"
},
...
]
}
],
...
}
]Using TargetField, you can edit the bundle reward within the entry without needing to redefine
the entire entry:
{
"Format": "1.27.0",
"Changes": [
{
"Action": "EditData",
"Target": "Data/RandomBundles",
"TargetField": [ "Crafts Room", "BundleSets", "#0", "Bundles", "#0" ],
"Entries": {
"Reward": "60 Spring Seeds" // double normal reward
}
},
]
}The TargetField sets the selected value as the scope, so the rest of the fields work as if the
entire data asset looked like this:
{
"Name": "Spring Foraging",
"Index": 0,
"Sprite": "13",
"Color": "Green",
"Items": "1 Wild Horseradish, 1 Daffodil, 1 Leek, 1 Dandelion, 1 Spring Onion",
"Pick": 4,
"RequiredItems": -1,
"Reward": "30 Spring Seeds"
}- Author guide for other actions and options
- Documentation for data asset formats on the wiki