← README
This document helps mod authors create a content pack for Content Patcher.
See the main README for other info.
Content Patcher lets you change the game content using only JSON files. JSON is just a text format, so no programming experience is needed.
You can make a wide range of changes to the game:
- change images, dialogue, maps, etc;
- add custom items, fruit trees, locations, etc;
- change shop inventory;
- and much more.
You can also make very dynamic changes to the game. For example, raise the price of coffee on winter weekend evenings when it's snowing unless the player married Abigail.
The modding documentation on the wiki is often written for Content Patcher pack authors, so you can find many specific examples there.
A content pack is just a folder with two text files in it: manifest.json
(which has info like
your mod name) and content.json
(which tells Content Patcher what you want to change). Your
folder might also have images or other files, which are usually in an assets
subfolder by
convention:
📁 Mods/
📁 [CP] YourModName/
🗎 content.json
🗎 manifest.json
📁 assets/
🗎 example.png
For example, here's a content.json
which replaces Abigail's portraits with your own image:
{
"Format": "2.4.0",
"Changes": [
{
"Action": "Load",
"Target": "Portraits/Abigail",
"FromFile": "assets/abigail.png"
}
]
}
You can do much more with Content Patcher using features like actions, tokens, conditions, and more. This guide goes into more detail below.
An asset is an image, data model, or map which the game loads from its Content
folder (or from
mods). These are what Content Patcher lets you change.
The asset name never includes "Content", the language code,
or the file extension. For example, both Content/Maps/spring_beach.xnb
and
Content/Maps/spring_beach.fr-FR.xnb
are the same Maps/spring_beach
asset.
You can unpack the game's content files
to see what they contain. Here's what Portraits/Abigail
contains:
So if you wanted to change Abigail's portraits, you would use Content Patcher to load or edit
Portraits/Abigail
and change that image like in the previous example code.
- Install SMAPI and Content Patcher.
- Create an empty folder in your
Mods
folder, and name it[CP] YourModName
. ReplaceYourModName
with a unique name for your mod. - Create a
manifest.json
file with this content:{ "Name": "Your Mod Name", "Author": "Your Name", "Version": "1.0.0", "Description": "One or two sentences about the mod.", "UniqueID": "YourName.YourModName", "UpdateKeys": [], // when you release the mod, see https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Update_checks "ContentPackFor": { "UniqueID": "Pathoschild.ContentPatcher" } }
- Change the
Name
,Author
,Description
, andUniqueID
values to describe your mod. (Don't change theUniqueID
underContentPackFor
!) - Create a
content.json
file with this content:{ "Format": "2.4.0", "Changes": [ // your changes will go here ] }
That's it! You now have a working Content Patcher pack, though it doesn't do anything yet.
That Format
field is the version of Content Patcher for which you designed the content pack. This
is used to keep your content pack compatible with future versions.
You should always use the latest format version (currently 2.4.0
) to enable the latest features,
avoid obsolete behavior, and reduce startup time.
The Changes
field describes what you want to change in the game. Each entry in the list is called
a patch, and describes a specific action to perform: edit this image, change this dialogue, etc.
You can list any number of patches, and you can apply multiple patches to the same file (they'll be
applied one after another in the order listed).
Note: these are ordered by how often content packs use them. You don't need to know or use all of these features.
Every patch has an Action
field, which is the type of change you want to make. See the
documentation page for each action (linked below) for more info on each one.
action | overview |
---|---|
Load |
For example, if you have an {
"Format": "2.4.0",
"Changes": [
{
"Action": "Load",
"Target": "Portraits/Abigail",
"FromFile": "assets/abigail.png"
}
]
} This isn't recommended if you can use one of the See the |
EditData |
This lets you...
For example, this doubles the price of moss soup (see object fields): {
"Format": "2.4.0",
"Changes": [
{
"Action": "EditData",
"Target": "Data/Objects",
"Fields": {
"MossSoup": {
"Price": 80
}
}
}
]
} You can do much more using |
EditImage |
This lets you...
For example, if your content pack has an {
"Format": "2.4.0",
"Changes": [
{
"Action": "EditImage",
"Target": "Maps/springobjects",
"FromFile": "assets/fish-object.png",
"ToArea": { "X": 160, "Y": 80, "Width": 16, "Height": 16 }
}
]
} See the |
EditMap |
This lets you...
For example, this replaces the town square with a custom version in your content folder: {
"Format": "2.4.0",
"Changes": [
{
"Action": "EditMap",
"Target": "Maps/Town",
"FromFile": "assets/town.tmx",
"ToArea": { "X": 22, "Y": 61, "Width": 16, "Height": 13 }
}
]
} See the |
Include |
For example, you can combine this with tokens and condition to load a dynamic file: {
"Format": "2.4.0",
"Changes": [
{
"Action": "Include",
"FromFile": "assets/john_{{season}}.json"
}
]
} See the |
The CustomLocations
feature lets you add new in-game locations, complete with their own maps and
warps. Content Patcher automatically handles NPC pathfinding, object persistence, etc.
See the custom location documentation for more info.
The previous sections explain how to make static changes, but you can use tokens & conditions to make dynamic changes.
For example, you can...
- change patches based on wide range of factors like the season, answered dialogue questions, in-game progress, etc.
- use randomization, arithmetic, and dynamic queries;
- and more.
For example, this gives Abigail a different portrait for each season:
{
"Format": "2.4.0",
"Changes": [
{
"Action": "Load",
"Target": "Portraits/Abigail",
"FromFile": "assets/abigail-{{season}}.png"
}
]
}
Or this gives her different seasonal portraits if you're married to her:
{
"Format": "2.4.0",
"Changes": [
{
"Action": "Load",
"Target": "Portraits/Abigail",
"FromFile": "assets/abigail-married.png",
"When": {
"Spouse": "Abigail"
}
}
]
}
See the conditions & tokens guide for more info.
You can let players configure your mod using a config.json
file. If the player has Generic Mod
Config Menu installed, they'll also be able to
configure the mod through an in-game options menu.
For example, you can use config values as tokens and conditions:
{
"Format": "2.4.0",
"ConfigSchema": {
"EnableJohn": {
"AllowValues": "true, false",
"Default": true
}
},
"Changes": [
{
"Action": "Include",
"FromFile": "assets/john.json",
"When": {
"EnableJohn": true
}
}
]
}
See the player config documentation for more info.
You can add translation files to your mod and access them through the i18n
token. Content Patcher
will automatically handle showing the default text if something isn't translated into the current
language.
For example, if your i18n
files contain a translation with the key rainy-day
, you can access it
in any Content Patcher field that allows tokens:
{
"Format": "2.4.0",
"Changes": [
{
"Action": "EditData",
"Target": "Characters/Dialogue/MarriageDialogueAbigail",
"Entries": {
"Rainy_Day_4": "{{i18n: rainy-day}}"
}
}
]
}
See the translation documentation for more info.
Text operations let you change a text field based on its current value, instead of just setting the new value. For example, you can append or prepend text to the current value.
For example, this adds pufferfish as a universally loved gift:
{
"Action": "EditData",
"Target": "Data/NPCGiftTastes",
"TextOperations": [
{
"Operation": "Append",
"Target": ["Entries", "Universal_Love"],
"Value": "127",
"Delimiter": " "
}
]
}
See the text operations documentation for more info.
Content Patcher adds custom trigger actions for specialized cases like updating pre-existing saves for renamed content IDs.
See Content Patcher's trigger action documentation for more info.
See the troubleshooting guide for more info.
Your patches are applied to data assets every time the asset is loaded, but they update their fields when the day starts by default. For example, let's say you have this patch:
{
"Action": "EditMap",
"Target": "Maps/Town",
"SetProperties": {
"CurrentTime": "{{Time}}"
}
}
When the day starts, Content Patcher updates the patch so it contains "CurrentTime": "600"
. It
doesn't matter if you reload the map it's applied to later in the day, the patch still contains
"CurrentTime": "600"
until its fields are updated.
You can add the Update
field to update more often if needed. The possible values are:
update rate | effect |
---|---|
OnDayStart |
(default) Update when the in-game day starts. This is always enabled even if you omit it. |
OnLocationChange |
update when the player warps to a new location. |
OnTimeChange |
Update when the in-game clock changes. |
multiple | You can specify multiple values separated by commas, like "Update": "OnLocationChange, OnTimeChange" . |
For example, this will update and reapply the patch when the in-game time changes:
{
"Action": "EditMap",
"Target": "Maps/Town",
"SetProperties": {
"CurrentTime": "{{Time}}"
},
"Update": "OnTimeChange"
}
Yep. See the author migration guide for more info.
Your patches affect every language by default.
The asset name in the Target
field doesn't include the language. For example,
"Target": "Dialogue/Abigail"
(the asset name) will change the content loaded from
Content/Dialogue/Abigail.de-DE.xnb
(the file path) when playing in German. If you want
to make the same change in every language, you don't need to do anything else.
To target a specific language, you can add a language condition:
{
"Action": "EditImage",
"Target": "LooseSprites/Cursors",
"FromFile": "assets/cursors.de.png",
"When": {
"Language": "de"
}
}
You can also load the translated version automatically if it exists. That way you can just add translated files to your content pack, and it'll default to the untranslated version if no translation exists:
// use translated version if it exists in the content pack
{
"Action": "EditImage",
"Target": "LooseSprites/Cursors",
"FromFile": "assets/cursors.{{language}}.png",
"When": {
"HasFile:{{FromFile}}": true
}
},
// otherwise use untranslated version
{
"Action": "EditImage",
"Target": "LooseSprites/Cursors",
"FromFile": "assets/cursors.png",
"When": {
"HasFile: assets/cursors.{{language}}.png": false
}
},
Any number of patches can be applied to the same file. Action: Load
always happens before other
action types, but otherwise each patch is applied sequentially. After each patch is done, the next
patch will see the combined asset as the input.
Within one content pack, patches are applied in the order they're listed in content.json
. When
you have multiple content packs, each one is applied in the order they're loaded by SMAPI; if you
need to explicitly patch after another content pack, see manifest dependencies.
Some game assets have special logic. This isn't specific to Content Patcher, but they're documented here for convenience.
asset | notes |
---|---|
Characters/Dialogue/* |
Dialogue is set when the day starts, so setting a custom update rate won't affect dialogue after the day starts. (You can use location-specific dialogue keys to circumvent that though.) |
Characters/Farmer/accessories |
The number of accessories is hardcoded, so custom accessories need to replace an existing one. |
Characters/Farmer/skinColors |
The number of skin colors is hardcoded, so custom colors need to replace an existing one. |
Data/SpecialOrders |
The game caches a copy of this asset before the game saves, and loads a separate copy the first time you open the special orders board for the session. Be very careful adding/removing special orders conditionally, which may cause a crash when the player tries to accepts a special order from the new list which doesn't exist in the cached one. |
Maps/* |
See Modding:Maps#Potential issues on the wiki. |
- README for other info
- Ask for help