Content Patcher is a Stardew Valley mod which loads content packs that change the game's images and data without replacing XNB files.
This documentation is for modders. If you're a player, see the Nexus page instead.
- Install the latest version of SMAPI.
- Install this mod from Nexus mods.
- Unzip any Content Patcher content packs into
Mods
to install them. - Run the game using SMAPI.
Content Patcher lets you create a standard content pack
which changes the game's data and images, no programming needed. Players can install it by
unzipping it into Mods
, just like a SMAPI mod.
Just by editing a JSON file, you can make very simple changes to the game (like replace one image file), or more interesting changes (like things that look different in each season), or very specific changes (like coffee is more expensive in winter when it's snowing on the weekend).
If you're familiar with creating XNB mods, Content Patcher supports everything XNB mods supported. Here's a quick comparison:
XNB mod | Content Patcher | |
---|---|---|
easy to create | ✘ need to unpack/repack files | ✓ edit JSON files |
easy to install | ✘ different for every mod | ✓ drop into Mods |
easy to uninstall | ✘ manually restore files | ✓ remove from Mods |
update checks | ✘ no | ✓ yes (via SMAPI) |
compatibility checks | ✘ no | ✓ yes (via SMAPI DB) |
mod compatibility | ✘ very poor (each file can only be changed by one mod) |
✓ high (mods only conflict if they edit the same part of a file) |
game compatibility | ✘ break in most updates | ✓ only affected if the part they edited changes |
easy to troubleshoot | ✘ no record of changes | ✓ SMAPI log + Content Patcher validation |
Content Patcher supports all game assets with some very powerful features, but it's a generalist framework. More specialised frameworks might be better for specific things. You should consider whether one of these would work for you:
- Advanced Location Loader to add and edit maps.
- Custom Farming Redux to add machines.
- Custom Furniture to add furniture.
- CustomNPC to add NPCs.
- Custom Shirts to add shirts.
- Json Assets to add items and fruit trees.
TODO: conditional maps
A content pack is a folder with these files:
- a
manifest.json
for SMAPI to read (see content packs on the wiki); - a
content.json
which describes the changes you want to make; - and any images or files you want to use.
The content.json
file has three main fields:
field | purpose |
---|---|
Format |
The format version (just use 1.4 ). |
Changes |
The changes you want to make. Each entry is called a patch, and describes a specific action to perform: replace this file, copy this image into the file, etc. You can list any number of patches. |
ConfigSchema |
(optional) Defines the config.json format, to support more complex mods. See player configuration. |
Here's a quick example of each possible patch type (explanations below):
{
"Format": "1.4",
"Changes": [
// replace an entire file
{
"Action": "Load",
"Target": "Animals/Dinosaur",
"FromFile": "assets/dinosaur.png"
},
// edit part of an image
{
"Action": "EditImage",
"Target": "Maps/springobjects",
"FromFile": "assets/fish-object.png",
"FromArea": { "X": 0, "Y": 0, "Width": 16, "Height": 16 }, // optional, defaults to entire FromFile
"ToArea": { "X": 256, "Y": 96, "Width": 16, "Height": 16 } // optional, defaults to source size from top-left
},
// edit fields for existing entries in a data file (zero-indexed)
{
"Action": "EditData",
"Target": "Data/ObjectInformation",
"Fields": {
"70": {
0: "Jade",
5: "A pale green ornamental stone."
}
}
},
// add or replace entries in a data file
{
"Action": "EditData",
"Target": "Data/ObjectInformation",
"Entries": {
"70": "Jade/200/-300/Minerals -2/Jade/A pale green ornamental stone.",
"72": "Diamond/750/-300/Minerals -2/Diamond/A rare and valuable gem."
}
}
]
}
All patches support these common fields:
field | purpose |
---|---|
Action |
The kind of change to make (Load , EditImage , or EditData ); explained in the next section. |
Target |
The game asset you want to patch. This is the file path inside your game's Content folder, without the file extension or language. For example: use Animals/Dinosaur to edit Content/Animals/Dinosaur.xnb . Capitalisation doesn't matter. Your changes are applied in all languages unless you specify a language condition. |
LogName |
(optional) A name for this patch shown in log messages. This is very useful for understanding errors; if not specified, will default to a name like entry #14 (EditImage Animals/Dinosaurs) . |
Enabled |
(optional) Whether to apply this patch. Default true. |
When |
(optional) Only apply the patch if the given conditions match (see conditions). |
-
Replace an entire file (
"Action": "Load"
).
When the game loads the file, it'll receive your file instead. This is useful for mods which change everything (like pet replacement mods).Avoid this if you don't need to change the whole file though — each file can only be replaced once, so your content pack won't be compatible with other content packs that replace the same file. (It'll work fine with content packs that only edit the file, though.)
field purpose See common fields above. FromFile
The relative file path in your content pack folder to load instead (like assets/dinosaur.png
). This can be a.png
,.tbin
, or.xnb
file. Capitalisation doesn't matter. -
Edit an image (
"Action": "EditImage"
).
Instead of replacing an entire spritesheet, you can replace just the part you need. For example, you can change an item image by changing only its sprite in the spritesheet. Any number of content packs can edit the same file.You can extend an image downwards by just patching past the bottom. Content Patcher will automatically expand the image to fit.
field purpose See common fields above. FromFile
The relative path to the image in your content pack folder to patch into the target (like assets/dinosaur.png
). This can be a.png
or.xnb
file. Capitalisation doesn't matter.FromArea
(optional) The part of the source image to copy. Defaults to the whole source image. This is specified as an object with the X and Y pixel coordinates of the top-left corner, and the pixel width and height of the area. See example in overview. ToArea
(optional) The part of the target image to replace. Defaults to the FromArea
size starting from the top-left corner. This is specified as an object with the X and Y pixel coordinates of the top-left corner, and the pixel width and height of the area. See example in overview.PatchMode
(optional) How to apply FromArea
toToArea
. Defaults toReplace
. Possible values:Replace
: replace the target area with your source image.Overlay
: draw your source image over the target, so the original image shows through transparent pixels. Note that semi-transparent pixels will replace the underlying pixels, they won't be combined.
-
Edit a data file (
"Action": "EditData"
).
Instead of replacing an entire data file, you can edit the individual entries or even fields you need.field purpose See common fields above. Fields
(optional) The individual fields you want to change for existing entries. See example in overview. Entries
(optional) The entries in the data file you want to add, replace, or (if set to null
) delete. If you only want to change a few fields, useFields
instead for best compatibility with other mods. See example in overview.
Caution: some XNB files have extra fields at the end for translations; when adding or replacing an entry for all locales, make sure you include the extra field(s) to avoid errors for non-English players.
You can make a patch conditional by adding a When
field. The patch will be applied when all
conditions match, and removed when they no longer match. Conditions are not case-sensitive, and you
can specify multiple values as a comma-delimited list. You don't need to specify all conditions.
For example, this changes the house texture only in Spring or Summer.
{
"Action": "EditImage",
"Target": "Building/houses",
"FromFile": "assets/green_house.png",
"When": {
"Season": "spring, summer"
}
}
These conditions can be used as conditions and tokens for any patch:
condition | purpose | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Day | The day of month. Possible values: any integer from 1 through 28. | ||||||||||||||||
DayOfWeek |
The day of week. Possible values: |
||||||||||||||||
Language |
The game's current language. Possible values:
|
||||||||||||||||
Season |
The season name. Possible values: |
||||||||||||||||
Weather |
The weather name. Possible values: |
These conditions cannot be used as tokens or by an "Action": "Load"
patch (but can
be used as a condition for any other patch type):
condition | purpose | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
DayEvent |
The festival or wedding happening today. Possible values:
|
||||||||||||||||||||||||||||||||
HasFlag |
The letter IDs received by the player. The game also uses this to store some useful flags. For example:
|
||||||||||||||||||||||||||||||||
HasMod |
The installed mod IDs (matching the |
||||||||||||||||||||||||||||||||
HasSeenEvent |
The event IDs the player has seen, matching IDs in the |
||||||||||||||||||||||||||||||||
Hearts |
The player's heart level with a given NPC. You must specify the character name as part of the key (using their English name regardless of translations), like this: "When": {
"Hearts:Abigail": "10, 11, 12, 13"
} |
||||||||||||||||||||||||||||||||
Relationship |
The player's relationship with a given NPC or player. You must specify the character name as part of the key (using their English name regardless of translations), like this: "When": {
"Relationship:Abigail": "Married"
} The valid relationship types are...
|
||||||||||||||||||||||||||||||||
Spouse | The current player's spouse name (using their English name regardless of translations). |
Special note about "Action": "Load"
:
Each file can only be loaded by one patch. Content Patcher will allow multiple loaders, so
long as their conditions can never overlap. If they can overlap, it will refuse to add the second
one. For example:
loader A | loader B | result |
---|---|---|
season: "Spring" |
season: "Summer" |
both are loaded correctly (seasons never overlap). |
day: 1 |
dayOfWeek: "Tuesday" |
both are loaded correctly (1st day of month is never Tuesday). |
day: 1 |
weather: "Sun" |
error: sun could happen on the first of a month. |
You can let players configure your mod using a config.json
file. This requires a bit more upfront
setup for the mod author, but once that's done it'll behave just like a SMAPI config.json
for
players. Content Patcher will automatically create and load the file, and you can use the config
values in the When
field. Config fields are not case-sensitive, and can only
contain string values.
For example: this content.json
defines a Material
config field and uses it to change which
patch is applied. See below for more details.
{
"Format": "1.4",
"ConfigSchema": {
"Material": {
"AllowValues": "Wood, Metal"
}
},
"Changes": [
{
"Action": "Load",
"Target": "LooseSprites/Billboard",
"FromFile": "assets/material_wood.png",
"When": {
"Material": "Wood"
}
},
{
"Action": "Load",
"Target": "LooseSprites/Billboard",
"FromFile": "assets/material_metal.png",
"When": {
"Material": "Metal"
}
}
]
}
Here's how to do it:
-
Add a
ConfigSchema
section to thecontent.json
(like above), which defines your config fields and how to validate them. Available fields for each one:field meaning AllowValues
Required. The values the player can provide, as a comma-delimited string.
Tip: for a boolean flag, use"true, false"
.AllowBlank
(optional) Whether the field can be left blank. Behaviour: - If false (default): missing and blank fields are filled in with the default value.
- If true: missing fields are filled in with the default value; blank fields are left as-is.
AllowMultiple
(optional) Whether the player can specify multiple comma-delimited values. Default false. Default
(optional) The default values when the field is missing. Can contain multiple comma-delimited values if AllowMultiple
is true. If not set, defaults to the first value inAllowValues
. -
Use the config fields as
When
conditions. The field names and values are not case-sensitive.
That's it! Content Patcher will automatically create the config.json
when you run the game.
You can use conditions and config values in the FromFile
,
Target
, and Enabled
fields in content.json
. Just put the name of the condition or config
field in two curly brackets, and Content Patcher will automatically fill in the value.
For example, this gives the farmhouse a different appearance in each season:
{
"Format": "1.4",
"Changes": [
{
"Action": "EditImage",
"Target": "Buildings/houses",
"FromFile": "assets/{{season}}.png" // assets/spring.png, assets/summer.png, etc
}
]
}
You can use multiple tokens and conditions for more dynamic changes:
{
"Format": "1.4",
"Changes": [
{
"Action": "EditImage",
"Target": "Buildings/houses",
"FromFile": "assets/{{season}}_{{weather}}.png", // assets/spring_rain.png, etc
"When": {
"Weather": "sun, rain"
}
}
]
}
Tokens are subject to some restrictions:
Enabled
:- Max one token per field.
- Config fields can't have
"AllowMultiple": true
. - Config fields must have
"AllowValues": "true, false"
.
FromFile
:- Config fields can't have
"AllowMultiple": true
. - All possible files must exist, subject to any conditions you set. In the first example above,
you'll need four files (one per season). If you add a
"Season": "spring, summer"
condition, you'll only need two files.
- Config fields can't have
Target
:- Config fields can't have
"AllowMultiple": true
.
- Config fields can't have
See content packs on the wiki for general info. Suggestions:
- Add specific install steps in your mod description to help players:
[size=5]Install[/size] [list=1] [*][url=https://smapi.io]Install the latest version of SMAPI[/url]. [*][url=https://www.nexusmods.com/stardewvalley/mods/1915]Install Content Patcher[/url]. [*]Download this mod and unzip it into [font=Courier New]Stardew Valley/Mods[/font]. [*]Run the game using SMAPI. [/list]
- When editing the Nexus page, add Content Patcher under 'Requirements'. Besides reminding players to install it first, it'll also add your content pack to the list on the Content Patcher page.
- Including
config.json
(if created) in your release download is not recommended. That will cause players to lose their settings every time they update. Instead leave it out and it'll generate when the game is launched, just like a SMAPI mod'scontent.json
.
Content Patcher adds two patch commands for testing and troubleshooting.
-
patch summary
lists all the loaded patches, their current values, and (if applicable) the reasons they weren't applied.Example output:
Current conditions: Day: 5 DayOfWeek: friday Language: en Season: spring Weather: sun Patches by content pack ([X] means applied): Sample Content Pack: [X] Palm Trees | Load TerrainFeatures/tree_palm [X] Bushes | Load TileSheets/bushes [ ] Maple Trees | Load TerrainFeatures/tree2_{{season}} | failed conditions: Season (summer, fall, winter) [ ] Oak Trees | Load TerrainFeatures/tree1_{{season}} | failed conditions: Season (summer, fall, winter) [X] World Map | EditImage LooseSprites/map
-
patch update
immediately updates Content Patcher's condition context and rechecks all patches. This is mainly useful if you change conditions through the console (like the date), and want to update patches without going to bed.
Content Patcher has a 'debug mode' which lets you view loaded textures directly in-game with any
current changes. To enable it, open the mod's config.json
file in a text editor and enable
EnableDebugFeatures
.
Once enabled, press F3
to display textures and left/right CTRL
to cycle textures. Close and
reopen the debug UI to refresh the texture list.
Content Patcher doesn't log much info. You can change that by opening the mod's config.json
file
in a text editor and enable VerboseLog
. This may significantly slow down loading, and should
normally be left disabled unless you need it.
Once enabled, it will log significantly more information at three points:
- when loading patches (e.g. whether each patch was enabled and which files were preloaded);
- when SMAPI checks if Content Patcher can load/edit an asset;
- and when the context changes (anytime the conditions change: different day, season, weather, etc).
If your changes aren't appearing in game, make sure you set a LogName
(see common fields)
and then search the SMAPI log file for that name. Particular questions to ask:
- Did Content Patcher load the patch?
If it doesn't appear, check that yourcontent.json
is correct. If it says 'skipped', check yourEnabled
value orconfig.json
. - When the context is updated, is the box ticked next to the patch name?
If not, checked yourWhen
field. - When SMAPI checks if it can load/edit the asset name, is the box ticked?
If not, check yourWhen
andTarget
fields.
Content Patcher is compatible with Stardew Valley 1.3+ on Linux/Mac/Windows, both single-player and multiplayer.
Content Patcher works fine in multiplayer. It's best if all players have the same content packs, but not required. Here are the effects if some players don't have a content pack installed:
patch type | effect |
---|---|
visual | Only visible to players that have it installed. |
maps | Only visible to players that have it installed. Players without the custom map will see the normal map and will be subject to the normal bounds (e.g. they may see other players walk through walls, but they won't be able to follow). |
data | Only directly affects players that have it installed, but can indirectly affect other players. For example, if a content pack changes Data/ObjectInformation and you create a new object, other player will see that object's custom values even if their Data/ObjectInformation doesn't have those changes. |
Your content.json
can have multiple patches for the same file. Action: Load
always happens
before other action types, but otherwise each patch is applied in the order you list them. This
patch order within a content pack is by design and unlikely to change.
The patch order between different content packs is currently undocumented and not guaranteed.
The only guarantee is that Action: Load
will happen before other patch types (even across content
packs). Otherwise don't depend on your patches being applied in a certain order relative to those
in a different content pack.
Some game assets have special logic. This isn't specific to Content Patcher, but they're documented here for convenience.
asset | notes |
---|---|
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. |