Modding:Migrate to Stardew Valley 1.6

From Stardew Valley Wiki
Revision as of 01:43, 27 January 2022 by Pathoschild (talk | contribs) (→‎Custom shops: + new Action OpenShop tile property)
Jump to navigation Jump to search

Index

This page is for mod authors. Players: see Modding:Mod compatibility instead.

The following describes the upcoming SMAPI 4.0.0, and may change before release.

This page explains how to update your mods for compatibility with the next major game version (tentatively Stardew Valley 1.6.0), and documents some of the changes and new functionality.

This describes an unreleased alpha version of the game. Things will change before it's released!

FAQs

What's changing?

Stardew Valley 1.6 makes fundamental changes to the game code to make it more extensible for mods.

Is this the modapocalypse?

Yes. The update includes major changes to fundamental parts of the game, and SMAPI and Content Patcher can't feasibly rewrite older mods for compatibility with these changes. This will break a large proportion of existing mods until they're updated for the changes. However, per discussion between the game developers and modding community, we've agreed that this short-term pain is more than offset by the huge long-term improvements to modding.

Which changes are likely to break mods?

How to update your mod

  1. Update your mod code and assets for any breaking changes listed below.
  2. If SMAPI still says your mod is incompatible, check the TRACE messages in the log file for the reason why.
    If the logs say "marked 'assume broken' in SMAPI's internal compatibility list", you can increase the Version in your content pack's manifest.json file to bypass it.
  3. Test the mod in-game and make any other changes needed.

Buff overhaul

1.6 rewrites buffs to work more consistently and be more extensible:

  • Buff logic is unified into Game1.player.buffs, which is the single source of truth for buff data. This replaces the previous player.added* and player.appliedBuffs fields, BuffsDisplay logic, enchantment stat bonuses, and boots/ring attribute changes on (un)equip.
  • This also removes limitations on buff types (e.g. buffs can add weapon bonuses and weapons can add attribute buffs) and buffable equipment (e.g. equipped tools can have buffs too).
  • Buff effects are now fully recalculated when they change, to fix a range of longstanding bugs like attribute drift and double-debuffs. Just like before, the buffs are managed locally; only the buff IDs and aggregate attribute effects are synced.

For C# mods:

  • Each buff now has a unique string ID. You can apply a new buff with the same ID to replace it (so you no longer need to manually find and remove previous instances of the buff).
  • You can add standard buff effects to any equipment by overriding Item.AddEquipmentEffects, or add custom behaviour/buffs by overriding Item.onEquip and Item.onUnequip.
  • You can add custom food or drink buffs by overriding Item.GetFoodOrDrinkBuffs().
  • The Buff constructor now supports a custom icon texture, sprite index, display name, description, and millisecond duration to fully support custom buffs.
  • You can change how buff attributes are displayed (or add new attributes) by extending the BuffsDisplay.displayAttributes list.

For example, here's how to add a custom buff which adds +3 speed:

Buff buff = new Buff(
    buff_id: "Example.ModId/ZoomZoom",
    display_name: "Zoom Zoom", // can optionally specify description text too
    icon_texture: this.Helper.Content.Load<Texture2D>("assets/zoom.png"),
    icon_sheet_index: 0,
    duration: 30_000, // 30 seconds
    buff_effects: new BuffEffects()
    {
        speed = { 10 } // shortcut for buff.speed.Value = 10
    }
);
Game1.player.applyBuff(buff);

You can also implement your own custom effects in code by checking if the buff is active, like Game1.player.hasBuff("Example.ModId/ZoomZoom").

Custom items

Overview

Stardew Valley 1.6 makes three major changes to how items work in the game:

  1. Each item type now has an ItemDataDefinition class which tells the game how to handle it. SMAPI mods can add custom item type definitions or patch the vanilla logic. Each definition has a unique prefix (like (O) for objects) which is used in qualified item IDs. The vanilla types are bigcraftables ((BC)), boots ((B)), furniture ((F)), hats ((H)), objects ((O)), pants ((P)), shirts ((S)), tools ((T)), and weapons ((W)).
  2. Each item now has a locally unique string ID (ItemID) and a globally unique string ID (QualifiedItemID). The ItemID is assumed to only contain alphanumeric/underscore/dot characters so they can be used in fields delimited with spaces/slashes/commas, in filenames, etc. The QualifiedItemID is auto-generated by prefixing the ItemID with the item type identifier.

    For legacy reasons, the ItemID for vanilla item isn't globally unique. For example, Pufferfish (object 128) and Mushroom Box (bigcraftable 128) both have ItemID: 128. They can be distinguished by their QualifiedItemID, which is (O)128 and (BC)128 respectively.

    For mod items, both IDs should be globally unique. By convention the ItemID should include your mod ID or author name, like Example.ModId_ItemName.

  3. Custom items can now provide their own item texture, specified in a new field in the item data assets (see below). The item's ParentSheetIndex field is the index within that texture.

In other words, the three important fields for items are:

name type description
ItemID string An item key which is only unique within its item type, like 128 (vanilla item) or Example.ModId_Watermelon (custom item).
QualifiedItemID string A globally unique item key, like (O)128 (vanilla item) or (O)Example.ModId_Watermelon (custom item).
ParentSheetIndex int The item's image sprite within its spritesheet (whether it's a vanilla spritesheet or custom one).

Item references

Item references throughout the game code now use the ItemID instead of the ParentSheetIndex. Since the ItemID is identical to the index for existing vanilla items, most data assets are unaffected by this change. For example, here's from Data/NPCDispositions with one custom item:

"Universal_Like": "-2 -7 -26 -75 -80 72 395 613 634 635 636 637 638 724 459 Example.ModID_watermelon"

Unless otherwise noted, unqualified item IDs will produce objects. Some assets let you override that by specifying a QualifiedItemID value instead. For example, you can add (O)128 to the gift taste list to explicitly add for an object. Here's a partial list of data assets and their supported item ID formats:

data asset item ID format
Data/CraftingRecipes
Data/CookingRecipes
  • Ingredients: both supported.
  • Output: set field 2 to the unqualified item ID, and field 3 to one of true (bigcraftable) or false (object) or an item type identifier like BC.
Data/fruitTrees
  • Fruit: both supported.
  • Sapling: unqualified only.
Data/NPCGiftTastes Both supported, but only (O) items can be gifted.

Define a custom item

Overview

You can define custom items for most vanilla item types using only Content Patcher or SMAPI's content API. The data asset for each item type has two new fields:

field effect
texture name The asset name for the texture under the game's Content folder. Use \ (or \\ in JSON) to separate name segments if needed. For example, objects use Maps\springobjects by default.
sprite index The index of the sprite within the above texture, starting at 0 for the top-left sprite.

Supported item types:

item type data asset sprite index index texture name index default texture name
big craftables Data/BigCraftablesInformation 10 11 TileSheets/Craftables
boots Data/Boots item sprite: 8
shoe color: 5
item sprite: 9
shoe color: 7
item sprite: Maps/springobjects
shoe color: Characters/Farmer/shoeColors
crops Data/Crops 2 9 TileSheets/crops
furniture Data/Furniture 8 9 TileSheets/furniture
fruit trees Data/FruitTrees 0 4 TileSheets/fruitTrees
hats Data/Hats 6 7 Characters/Farmer/hats
objects Data/ObjectInformation 9 10 Maps/springobjects
pants & shirts Data/ClothingInformation male: 3
female: 4
10 Characters/Farmer/pants
Characters/Farmer/shirts
tools Data/ToolData 3 4 TileSheets/Tools
weapons Data/Weapons 15 16 TileSheets/weapons

For example, this content pack adds a new Pufferchick item with a custom image, custom gift tastes, and a custom crop that produces it. Note that item references in other data assets like Data/Crops and Data/NPCGiftTastes use the item ID.

{
    "Format": "2.0.0",
    "Changes": [
        // add item
        {
            "Action": "EditData",
            "Target": "Data/ObjectInformation",
            "Entries": {
                "Example.ModId_Pufferchick": "Pufferchick/1200/100/Seeds -74/Pufferchick/An example object.////0/Mods\\Example.ModId\\Objects"
            }
        },

        // add gift tastes
        {
            "Action": "EditData",
            "Target": "Data/NPCGiftTastes",
            "TextOperations": [
                {
                    "Operation": "Append",
                    "Target": ["Entries", "Universal_Love"],
                    "Value": "Example.ModId_Pufferchick",
                    "Delimiter": " " // if there are already values, add a space between them and the new one
                }
            ]
        },

        // add crop (Pufferchick is both seed and produce, like coffee beans)
        {
            "Action": "EditData",
            "Target": "Data/Crops",
            "Entries": {
                "Example.ModId_Pufferchick": "1 1 1 1 1/spring summer fall/0/Example.ModId_Pufferchick/-1/0/false/false/false/Mods\\Example.ModId\\Crops"
            }
        },

        // add item + crop images
        {
            "Action": "Load",
            "Target": "Mods/Example.ModId/Crops, Mods/Example.ModId/Objects",
            "FromFile": "assets/{{TargetWithoutPath}}.png" // assets/Crops.png, assets/Objects.png
        },
    ]
}

Most item data assets work just like Data/ObjectInformation. For fruit trees, see custom fruit trees.

Tools

Tools are defined in the new Data/ToolData asset using this field format:

index field purpose
0 Class The name of the class in the StardewValley.Tools namespace. The class must have a constructor with no arguments. For example, given a value of Axe, the game will create StardewValley.Tools.Axe instances.
1
2
Name key
Description key
The string key to load for the tool's in-game display name and description, in the form <asset name>:<key> (e.g., Strings\StringsFromCSFiles:Axe.cs.1). In JSON, use \\ for any asset path slashes.
3 Parent sheet index The index of the tool's sprite in its spritesheet. Tool upgrades are handled by adding an offset to this index (e.g., basic axe = index, copper axe = index + 1, steel axe = index + 2, etc).
4 Texture (Optional) The asset name for the item's spritesheet.

Error items

In-game items with no underlying data (e.g. because you removed the mod which adds them) would previously cause issues like invisible items, errors, and crashes. This was partly mitigated by the bundled ErrorHandler mod.

Stardew Valley 1.6 adds comprehensive handling for such items. They'll be shown with a 🛇 sprite in inventory UIs and in-game, with the name Error Item and a description which indicates the missing item ID for troubleshooting.

For C# mods

Compare items
Since Item.QualifiedItemID is globally unique, it can be used to simplify comparing items. For example:
old code new code
item.ParentSheetIndex == 848 item.QualifiedItemID == "(O)848"
IsNormalObjectAtParentSheetIndex(item, 74) item.QualifiedItemID == "(O)74"
!item.bigCraftable && item.ParentSheetIndex == 128 item.QualifiedItemID == "(O)128"
item is Boots && item.ParentSheetIndex == 505 item.QualifiedItemID == "(B)505"

Caveat: flavored item don't have their own ID. For example, Blueberry Wine and Wine are both (O)348. This affects flavored jellies, juices, pickles, and wines. In those cases you should still compare their separate fields like preservedParentSheetIndex (which actually contains the preserved item's ItemID, not its ParentSheetIndex).

Construct items
Creating items works just like before, except that you now specify the item's ItemID (_not_ QualifiedItemID) instead of its ParentSheetIndex. For example:
new Object("634", 1);                      // vanilla item
new Object("Example.ModId_Watermelon", 1); // custom item

You can use a new utility method to construct items from their QualifiedItemID:

Item item = Utility.CreateItemByID("(B)505"); // Rubber Boots
Define custom item types
You can subclass ItemDataDefinition for your own item type, and add an instance to the ItemDataDefinition.ItemTypes and IdentifierLookup lists. This provides all the logic needed by the game to handle the item type: where to get item data, how to draw them, etc. This is extremely specialized, and multiplayer compatibility is unknown. Most mods should add custom items within the existing types instead.
New Is* methods
1.6 adds some StardewValley.Object methods to handle custom items in a generic way (and to let mods patch the logic):
method effect
object.IsTeaSapling() Whether the item is a Tea Sapling.
object.IsFruitTreeSapling() Whether the item is a fruit tree sapling. This checks the Data\fruitTrees keys, so it works with custom fruit trees too.
object.IsTapper() Whether the item is a Tapper or Heavy Tapper.
object.IsBar() Whether the item is a Copper Bar, Iron Bar, Gold Bar, Iridium Bar, or Radioactive Bar.

Custom buildings

You can now add custom buildings by editing the Data/BuildingsData asset. This consists of a string → model lookup, where the key is a unique building ID, and the value is a model with these fields:

field effect
required fields
ID A key which uniquely identifies this building. This should match the asset key. The ID should only contain alphanumeric/underscore/dot characters, and should ideally be prefixed with your mod ID like Example.ModId_BuildingName.
Name
Description
A tokenizable string for the display name and description (e.g. shown in the construction menu).
Texture The asset name for the texture under the game's Content folder.
BuildMaterials The materials you must provide to start construction, as a list of models with these fields:
field effect
ItemID The required item ID (qualified or unqualified).
Amount The number of the item required.

This field is required, but you can leave it empty (i.e. "BuildMaterials": {}) if the building doesn't need any resources.

construction
BuildCost (Optional) The gold cost to construct the building. Defaults to 0g.
BuildDays (Optional) The number of days needed to complete construction (e.g. 1 for a building completed the next day). If set to 0, construction finishes instantly. Defaults to 0.
BuildCondition (Optional) A game state query which indicates whether the building should be available in Robin's construction menu. Defaults to always available.
building exterior
Size (Optional) The building's width and height when constructed, measured in tiles. Defaults to a 1 x 1 area.
SourceRect (Optional) The building's pixel area within the Texture, in the form "<x> <y> <width> <height>" (like "0 0 112 128"). Defaults to the entire texture.
SortTileOffset (Optional) A Y tile offset applied when figuring out render layering. For example, a value of 2.5 will treat the building as if it was 2.5 tiles further up the screen for the purposes of layering. Default 0.
CollisionMap (Optional) An ASCII text block which indicates which of the building's tiles the players can walk onto, where each character can be X (blocked) or O (passable). Defaults to all tiles blocked.

For example, a stable covers a 2x4 tile area with the front two tiles passable:

XXXX
XOOX

When the collision map is parsed, leading/trailing whitespace is trimmed (both for the entire map and for each line). In JSON, you can specify it in two forms:

// single line with \n line breaks
"CollisionMap": "XXXX\nXOOX"

// multi-line with optional indentation
"CollisionMap": "
    XXXX
    XOOX
"
HumanDoor (Optional) The position of the door that can be clicked to warp into the building interior. This is measured in tiles relative to the top-left corner tile. Defaults to disabled.
AnimalDoor (Optional) The position of the door that animals use to enter/exit the building, if the building interior is an animal location. This is measured in tiles relative to the top-left corner tile. Defaults to disabled.
AnimalDoorOpenDuration
AnimalDoorCloseDuration
(Optional) The duration of the open/close animation for the animal door, measured in milliseconds. If omitted, the door switches to the open/closed state instantly.
AnimalDoorOpenSound
AnimalDoorCloseSound
(Optional) The sound which is played once each time the animal door is opened/closed. Disabled by default.
DrawLayers (Optional) A list of overlays to draw over the building, with support for conditions and animations. This consists of a list of models with these fields:
field effect
SourceRect The pixel area within the building's texture asset name to draw, formatted like "<x> <y> <width> <height>". If the overlay is animated via FrameCount, this is the area of the first frame.
DrawPosition The tile position at which to draw the top-left corner of the texture, relative to the building's top-left corner tile.
SortTileOffset (Optional) A Y tile offset applied when figuring out render layering. For example, a value of 2.5 will treat the texture as if it was 2.5 tiles further up the screen for the purposes of layering. Default 0.
OnlyDrawIfChestHasContents (Optional) The name of a chest defined in the Chests field which must contain items. If it's empty, this overlay won't be rendered. Defaults to none.
FrameCount
FramesPerRow
FrameDuration
(Optional) If FrameCount is more than one, the building overlay will be animated automatically. For each frame, the SourceRect will be offset by its Width to the right up to FramesPerRow - 1 times, and then down by its Height. Each frame will be rendered on-screen for FrameDuration milliseconds before switching to the next frame.

For example, if you set FrameCount to 6 and FramesPerRow to 3, the building will expect the frames to be laid out like this in the spritesheet (where frame 1 matches SourceRect):

┌───┬───┬───┐
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
└───┴───┴───┘
AnimalDoorOffset (Optional) A pixel offset applied to the draw layer when the animal door is open. While the door is opening, the percentage open is applied to the offset (e.g. 50% open = 50% offset).
DrawShadow (Optional) Whether to draw an automatic shadow along the bottom edge of the building's sprite. Default true.
building interior
IndoorMap (Optional) The name of the map asset under Maps to load for the building interior. For example, "Shed" will load the shed's Maps/Shed map.
IndoorMapType (Optional) The building class which will manage the building's interior location. This must be one of the vanilla types in the game's StardewValley.Locations. namespace. There are too many to list here, but the most useful types are likely Cabin, Cellar, DecoratableLocation, FarmCave, FarmHouse, and Shed. Defaults to the generic GameLocation class.

Note: AnimalHouse and SlimeHutch are in a different namespace, so can't be used currently.

MaxOccupants (Optional) The maximum number of animals who can live in this building.

Note: this currently has no effect, since the IndoorMapType can't be set to AnimalHouse.

item processing
ItemConversions (Optional) The item processing rules which take input items and convert them into output items using the inventories defined by Chests. This consists of a list of models with these fields:
field effect
RequiredTags A list of context tags to match against an input item. An item must have all of these tags to be accepted.
SourceChest The name of the inventory defined in Chests from which to take input items.
DestinationChest The name of the inventory defined in Chests in which to store output items.
ProducedItems The output items produced when an input item is converted. This consists of a list of models with these fields:
field effect
ItemID The qualified item ID.
MinCount
MaxCount
The minimum/maximum number of the item to produce.
Chance (Optional) The probability that the item will be produced, as a value between 0 (never drops) and 1 (always drops). This has no effect on other output items (e.g. if there are ten outputs with 100% chance, all ten will be produced). Default 1 (100% chance).
Condition (Optional) If set, the output is only available if the given game state query is true.
RequiredCount (Optional) The number of the input item to consume. Default 1.
MaxDailyConversions (Optional) The maximum number of the input item which can be processed each day. Each conversion rule has its own separate maximum (e.g. if you have two rules each with a max of 1, then you can convert one of each daily). Set to -1 to allow unlimited conversions. Default 1.
Chests (Optional) The input/output inventories that can be accessed from a tile on the building exterior. The allowed items are defined by the separate ItemConversions field. This is a list of models with these fields:
field effect
Name A name for this chest, referenced from the ItemConversions field. Each chest must have a unique name within one building's chest list (but they don't need to be globally unique).
Type The inventory type. This must be one of:
  • Chest: show a normal chest UI on click.
  • Collect: provides items for the player to collect. Clicking the tile will do nothing (if empty), grab the item directly (if it only contains one item), else show a grab-only inventory UI.
  • Load: lets the player add items for the building to process.
Sound (Optional) The sound to play once when the player clicks the chest.
InvalidItemMessage
InvalidCountMessage
ChestFullMessage
(Optional) A tokenizable string to show when the player tries to add an item to the chest when...
  • it isn't a supported item;
  • it's supported but they don't have enough in their inventory;
  • the chest has no more room to accept it.

If omitted, the player interaction is ignored with no message shown.

DisplayTile (Optional) The chest's position on the building exterior, measured in tiles from the top-left corner of the building. This affects the position of the 'item ready to collect' bubble. If omitted, the bubble is disabled.
tile interactions
ActionTiles (Optional) A list of tiles which the player can click to trigger an Action map tile property. This consists of a list of models with these fields:
field effect
Tile The tile position, relative to the building's top-left corner tile.
Action The tokenizable string for the action to perform, excluding the Action prefix. For example, "Dialogue Hi there @!" to show a messagebox like "Hi there <player name>!". The tokenizable string is expected before the action is raised. See the list of tile properties for useful Action values.
DefaultAction (Optional) The default tile action if the clicked tile isn't in ActionTiles. Defaults to none.
TileProperties (Optional) The map tile properties to set. This consists of a list of models with these fields:
field effect
LayerName The name of the map layer whose tiles to change.
Tiles The tile properties to set on the layer, as a list of models with these fields:
field effect
Tile The tile position, relative to the building's top-left corner tile.
Key
Value
The tile property name/value to set.
unused
Builder Unused.
ValidBuildLocations Unused.

Custom map areas

The valley map, with one map area highlighted.

You can now add/edit areas on the game menu's map UI, or even replace the entire map for a different world region, by editing the new Data/InGameMap asset. For example, this is used to show a different farm on the map depending on the current farm type.

Concepts

The game divides the map into three concepts:

  • A map is one full world area rendered in one image, like the entire image shown at right.
  • A map area is a smaller section of the map which is linked to one or more in-game areas. The map area might be edited/swapped depending on the context, have its own tooltip(s), or have its own player marker positions. For example, the highlighted area on the image shown at right is swapped depending on the current farm type.
  • A group name is a unique key shared between all the map areas that are rendered on the same map. For example, if there was a separate map for Ginger Island, all the map areas in the valley group would be hidden.

Format

The Data/InGameMap data asset consists of a string → model lookup, where the key is a unique identifier for the map area, and the value is a model with these fields:

field effect
AreaID A unique identifier for the area. This should match the key.
Group A unique group key shared between all areas drawn on the same map (see concepts). When the player is in an area for one group, all map areas with a different group key are hidden automatically. The base valley map added by the base game has the group key SDV.
Texture The asset name for the texture to draw when the area is applied to the map.

If set to the exact string "MOD_FARM", the game will apply the texture for the current farm type, regardless of whether it's a vanilla or mod farm type. (The vanilla DestRect for the farm area is "0 43 131 61".)

Note: this field is required. To add an invisible area, you can set this to a valid texture (e.g. "LooseSprites\\map") and omit SourceRect instead.

SourceRect The pixel area within the Texture to draw, formatted like "<x> <y> <width> <height>". Omit this field to make the area invisible (e.g. to add zones or tooltips without changing the map).
DestRect The pixel area within the map which is covered by this area, formatted like "<x> <y> <width> <height>".
Zones The in-game locations to match with the map. Each zone can provide one or more of the following:
  • match an in-game location to the world map area (via ValidAreas);
  • match an in-game tile position to the world map pixel position (via MapTileCorners and MapImageCorners);
  • add tooltips and scroll text for different portions of the world map (via DisplayName).

This consists of a list models with these fields:

field effect
ValidAreas A list of location names. Each location can be one of...
  • An internal location name (as shown by the Debug Mode mod). Any location within the mines and the Skull Cavern will be Mines and SkullCave respectively, and festivals use the map asset name (e.g. Town-EggFestival). For example, the vanilla desert uses "ValidAreas": [ "Desert", "SkullCave", "SandyHouse", "SandyShop", "Club" ].
  • CONTEXT_Default for any location in the valley.
  • CONTEXT_Island for any location on Ginger Island.
MapTileCorners
MapImageCorners
(Optional) The corner coordinates for the in-game location measured in tiles, and the equivalent map image area measured in pixels. Both use the form "<top-left x> <top-left y> <bottom-right x> <bottom-right y>".

These are used to calculate the position of a player within the map view, given their real position in-game. For example, let's say an area has tile positions (0, 0) through (10, 20), and map pixel positions (200, 200) through (300, 400). If the player is standing on tile (5, 10) in-game (in the exact middle of the location), the game would place their marker at pixel (250, 300) on the map (in the exact middle of the map area).

If these are omitted, the player marker is simply placed in the center of the parent map area.

DisplayName (Optional) A tokenizable string for the scroll text (shown at the bottom of the map when the player is in this area). Defaults to the parent area's DisplayName. If this is the exact string FarmName, it shows the farm name instead.
DisplayName (Optional) A tokenizable string for the tooltip (shown when the mouse is over the area) and scroll (shown at the bottom of the map when the player is in the location). If omitted or empty, the tooltip/scroll isn't shown. Defaults to empty.
Condition (Optional) A game state query which checks whether the area should be applied (if the group is visible). Defaults to always applied.
DisplayAsUnknown (Optional) Whether to replace the tooltip for the area with ??? if the Condition isn't met. Default false.
IncludeInGroupDetection (Optional) Whether to use this area when the game is scanning areas to see which group the player is in. If this is false, it will be ignored even if the player is in the area. Default true.

Example

This Content Patcher content pack adds a full world map for Ginger Island, complete with tooltips and player marker positioning. If the player unlocked the beach resort, it applies the beach resort texture on top of the base map.

{
    "Format": "2.0.0",
    "Changes": [
        // add world map edits
        {
            "Action": "EditData",
            "Target": "Data/IngameMap",
            "Entries": {
                // the base world map image with tooltips/positioning
                "GingerIsland_BaseMap": {
                    "Group": "GingerIsland",
                    "AreaID": "GingerIsland_BaseMap",
                    "Texture": "Mods/Example.ModId/GingerIsland",
                    "SourceRect": "0 0 300 180",
                    "DestRect": "0 0 300 180",
                    "Zones": [
                        {
                            "ValidAreas": [ "IslandSouth" ],
                            "MapTileCorners": "0 0 42 45",
                            "MapImageCorners": "105 105 231 240",
                            "DisplayName": "{{i18n: map-names.island-south}}"
                        },
                        // ... list each map area here
                    ]
                },

                // add beach resort if unlocked
                "GingerIsland_Resort": {
                    "Group": "GingerIsland",
                    "AreaID": "GingerIsland_Resort",
                    "Texture": "Mods/Example.ModId/GingerIsland_Resort",
                    "SourceRect": "0 0 300 180",
                    "DestRect": "0 0 300 180",
                    "Condition": "PLAYER_HAS_FLAG Any Island_Resort"
                }
            }
        },

        // load textures
        {
            "Action": "Load",
            "Target": "Mods/Example.ModId/GingerIsland",
            "FromFile": "assets/ginger-island.png"
        }
    ]
}

Custom shops

Format

You can now create and edit shops via the new Data/Shops asset. This consists of a list of models with these fields:

field effect
ID A unique ID for the shop. The current vanilla shop IDs are Marnie (Marnie's Ranch), Marlon (Adventurer's Guild), and Pierre (Pierre's General Store). For a custom shop, you should use a globally unique ID which includes your mod ID like ExampleMod.Id_ShopName.
ItemGroups The items to list in the shop inventory. This consists of a list of models with these fields:
field effect
Items The items to add to the shop inventory if the Condition matches. This costs of a list of values with these fields:
field effect
ItemID One of the qualified item ID (like (O)128 for a pufferfish), or SEEDSHOP_RANDOM_WALLPAPERS (random wallpapers), or SEEDSHOP_PLAYER_ITEMS (items the player has recently sold to Pierre's store).
IsRecipe (Optional) Whether to add the crafting/cooking recipe for the item, instead of the item itself. Default false.
Price (Optional) The price to purchase the item from the shop. Defaults to the item's normal price.
IgnorePriceMultiplier (Optional) Whether to ignore the PriceMultiplier value set for the shop. Default false.
Stock (Optional) The maximum number of the item which can be purchased in one day. Default unlimited.
Condition (Optional) A game state query which indicates whether the item should be added. If omitted, the item is always added.

Special case: if the player found Pierre's Missing Stocklist, season conditions are ignored in Pierre's General Store.

ShopOwner (Optional) The name of the NPC whose portrait to show in the shop UI.
Dialogues (Optional) A list of possible dialogues; each day one dialogue will be randomly chosen to show in the shop UI. Each dialogue consists of a model with these fields:
field effect
Dialogue The dialogue text to show, as a tokenizable string. The resulting text is parsed using the dialogue format.
Condition (Optional) A game state query which indicates whether the dialogue should be available. If omitted, the dialogue is always available.
PriceMultiplier (Optional) A multiplier applied to the price when buying items from the shop, like 1.5 for a 50% markup. Defaults to 1.

Note: this is only applied to items in ItemGroups which explicitly set a price.

Open a custom shop

You can place an Action OpenShop tile property on the map, which will open the given shop ID when the player clicks it.

In C# code, you can get the inventory for a custom shop using Utility.GetShopStock("shop id here"), or open a shop menu using Game1.activeClickableMenu = new ShopMenu(new(), who: "shop id here").

Custom fruit trees

You can now add custom fruit trees by editing the modified Data/fruitTrees asset. This consists of a stringstring lookup, where the key is the sapling item ID and the value is a slash (/)-delimited list of these fields:

index field effect
0 tree ID A key which uniquely identifies this tree. For vanilla trees, this matches the spritesheet index. For custom trees, the ID should only contain alphanumeric/underscore/dot characters.
1 season The season in which the fruit tree bears fruit.
2 fruit The unqualified object ID for the fruit it produces.
3 sapling price Unused.
4 sprite index The tree's row index in the spritesheet (e.g. 0 for the first tree, 1 for the second tree, etc). If omitted, the game will try to parse the item ID as an index.
5 texture The asset name for the texture under the game's Content folder. Use \ (or \\ in JSON) to separate name segments if needed. For example, fruit trees use TileSheets\fruitTrees by default.

For example, this content pack adds a custom fruit tree, including custom items for the sapling and fruit:

{
    "Format": "2.0.0",
    "Changes": [
        // add fruit + sapling items
        // note: sapling must have an edibility under 0 (usually -300) to be plantable
        {
            "Action": "EditData",
            "Target": "Data/ObjectInformation",
            "Entries": {
                "Example.ModId_Pufferfruit": "Pufferfruit/1200/100/Basic -6/Pufferfruit/An example fruit item.////1/Mods\\Example.ModId\\Objects",
                "Example.ModId_Puffersapling": "Puffersapling/1200/-300/Basic -74/Puffersapling/An example tree sapling.////2/Mods\\Example.ModId\\Objects"
            }
        },

        // add fruit tree
        {
            "Action": "EditData",
            "Target": "Data/FruitTrees",
            "Entries": {
                "Example.ModId_Puffersapling": "Example.ModId_Puffertree/spring/Example.ModId_Pufferfruit/1000/0/Mods\\Example.ModId\\FruitTrees"
            }
        },

        // add images
        {
            "Action": "Load",
            "Target": "Mods/Example.ModId/FruitTrees, Mods/Example.ModId/Objects",
            "FromFile": "assets/{{TargetWithoutPath}}.png" // assets/FruitTrees.png, assets/Objects.png
        },
    ]
}

The fruit trees can then be added to the game by giving the player a sapling item in the usual ways (e.g. from a shop).

Custom wild trees

You can now create/edit wild trees by editing the Data/WildTrees asset. This consists of a string => model lookup, where the asset key is the wild tree ID: one of 1 (oak), 2 (maple), 3 (pine), 6 (palm), 7 (mushroom), 8 (mahogany), or a custom string ID defined by a mod. The asset value is a model with these fields:

field effect
TreeType The tree ID; this should match the asset key.
Textures The tree textures to show in game. This can be a list containing either a single asset name, or four asset names (for spring, summer, fall, and winter in that order).
SeedItemID The qualified item ID for the seed item.
SeedPlantable (Optional) Whether the seed can be planted by the player. If this is false, it can only be spawned automatically via map properties. Default true.
GrowthChance (Optional) The probability each day that the tree will grow to the next stage without tree fertilizer, expressed as a value from 0 (will never grow) to 1 (will grow every day). Defaults to 0.2 (20% chance).
FertilizedGrowthChance (Optional) Equivalent to GrowthChance, but with tree fertilizer. Defaults to 1 (100% chance).
SeedChance (Optional) The probability each day that the tree will produce a seed that will drop when the tree is shaken. Default 0.05 (5% chance).
SeedOnChopChance (Optional) The probability that a seed will drop when the player chops down the tree. Default 0.75 (75% chance).
DropWoodOnChop (Optional) Whether to drop wood when the player chops down the tree. Default true.
DropHardwoodOnLumberChop (Optional) Whether to drop hardwood when the player chops down the tree, if they have the Lumberjack profession. Default true.
IsLeafy (Optional) Whether shaking or chopping the tree causes cosmetic leaves to drop from tree and produces a leaf rustle sound. When a leaf drops, the game will use one of the four leaf sprites in the tree's spritesheet in the slot left of the stump sprite. Default true.
IsLeafyInWinter (Optional) Whether IsLeafy also applies in winter. Default false.
GrowsInWinter (Optional) Whether the tree can grow in winter (subject to GrowthChance and FertilizedGrowthChance). Default false.
IsStumpDuringWinter (Optional) Whether the tree is reduced to a stump in winter and regrows in spring, like the vanilla mushroom tree. Default false.
AllowWoodpeckers (Optional) Whether woodpeckers can spawn on the tree. Default true.
UseAlternateSeedSprite (Optional) Whether to render a different tree sprite when it has a seed ready. If true, the tree spritesheet should be double-width with the alternate textures on the right. Default false.
DebrisColor (Optional) The color of the cosmetic wood chips when chopping the tree. The valid values are 12 (brown/woody), 100001 (light green), 100002 (light blue), 100003 (red), 100004 (yellow), 100005 (black), 100006 (gray), 100007 (charcoal / dim gray), or any other value for white. Defaults to brown/woody.
AdditionalChopDrops
BushChopDrops
StumpChopDrops
(Optional) The additional items to drop when the tree is chopped. One field applies depending on the tree's current state: AdditionalChopDrops for a full-grown tree, BushChopDrops for a bush (one step below full-grown), and StumpChopDrops for the stump left behind after chopping a full-grown tree. This consists of a list of models with these fields:
field effect
ItemID The qualified item ID.
MinCount
MaxCount
The minimum/maximum number of the item to drop.
Chance (Optional) The probability that the item will drop, as a value between 0 (never drops) and 1 (always drops). This has no effect on other drops (e.g. if there are ten drops with 100% chance, all ten will drop). Default 1 (100% chance).
Condition (Optional) If set, the drop is only available if the given game state query is true.
SpringTapItems
SummerTapItems
FallTapItems
WinterTapItems
The items produced by tapping the tree in each season, as a list of models with these fields. If multiple items can be produced, the first available one is selected.
field effect
PossibleItems The possible items to produce, as a list of models with these fields. If there are multiple items listed, one will be chosen at random each time.
field effect
ItemID The qualified item ID.
MinCount
MaxCount
The minimum/maximum number of the item to produce when the tapper is emptied.
DaysUntilReady The number of days before the tapper is ready to empty.
IsInitialTap (Optional) Whether this group only applies the first time a tree is tapped. Default false.
PreviousItemID (Optional) If set, the group only applies if the previous item produced by the tapper matches the given unqualified item ID.
Condition (Optional) If set, the group only applies if the given game state query is true.

Trees can then be added to the game by...

  • spawning them on map tiles by adding Paths index 34 to the Paths layer, with a TreeType tile property with the tree ID;
  • or giving the player a seed item in the usual ways (e.g. from a shop, mail letter, etc).

Standardized data fields

1.6 standardizes the number of fields in data assets, and fixes inconsistencies between English and localized files. This is a major breaking change for content packs, and for C# mods which edit data assets.

Three examples illustrate the standardization:

  • Data/CookingRecipes had four fields in English, and a fifth field in other languages for the display name. The display name field is now required in English too.
  • Data/BigCraftables had an optional 9th field which indicates whether it's a lamp, and a 10th field for the display name. Even if it's empty, the 9th field is now required (note the extra / before the last field):
    // before
    "151": "Marble Brazier/500/-300/Crafting -9/Provides a moderate amount of light./true/true/0/Marble Brazier", // 9 fields
    
    // after
    "151": "Marble Brazier/500/-300/Crafting -9/Provides a moderate amount of light./true/true/0//Marble Brazier" // 10 fields
    
  • Data/ObjectInformation had several optional fields at the end. These are now required even if empty:
    // before
    "0": "Weeds/0/-1/Basic/Weeds/A bunch of obnoxious weeds."
    
    // after
    "0": "Weeds/0/-1/Basic/Weeds/A bunch of obnoxious weeds.///"
    

Existing mods which add entries without the now-required fields may cause errors and crashes. XNB mods which change data are likely universally broken.

The exception is fields which only exist for modding, like the texture + index overrides for custom items. These can typically be omitted.

String event IDs

Events now use string IDs, so mods can use a unique key like Example.ModId_EventName (instead of hoping no other mod uses the same number). Prefixing the mod ID to event keys is recommended to simplify troubleshooting and avoid conflicts. For best compatibility, custom IDs should only contain alphanumeric/underscore/dot characters.

If an event has no preconditions, you must keep the trailing slash (i.e. have an empty preconditions field) to distinguish it from an event fork:

"Example.ModId_EventName/": "...", // event: loaded automatically by the game
"SomeFork": "..."                  // event fork: ignored unless it's loaded through an event script

New C# utility methods

1.6 adds a new set of utilities (GetDataAtIndex, GetIntAtIndex, and GetFloatAtIndex) to replace common logic for parsing the game's data assets while accounting for optional field indexes.

For example, code like this:

string[] rawEffects = fields.Length > Object.objectInfoBuffTypesIndex && fields[Object.objectInfoBuffTypesIndex].Length > 0
    ? fields[Object.objectInfoBuffTypesIndex].Split(' ')
    : new string[0];

int farming = rawEffects.Length > Buffs.farming && int.TryParse(rawEffects[Buffs.farming], out int _farming)
    ? _farming
    : 0;
int fishing = rawEffects.Length > Buffs.fishing && int.TryParse(rawEffects[Buffs.fishing], out int _fishing)
    ? _fishing
    : 0;

Can now be rewritten like this:

string[] rawEffects = Utility.GetDataAtIndex(fields, Object.objectInfoBuffTypesIndex, "").Split(' ');
int farming = Utility.GetIntAtIndex(rawEffects, Buffs.farming);
int fishing = Utility.GetIntAtIndex(rawEffects, Buffs.fishing);

Game state queries

A game state query is a vanilla way to specify conditions for some content like shop data, inspired by Content Patcher's conditions. A query consists of a comma-delimited list of conditions in the form <type> [arguments], where <type> is case-sensitive. The type can be prefixed with ! to negate it. The query is true if it's null/blank, or if every listed condition exists and is true. For example, !SEASON Spring, WEATHER Here sunny is true on sunny non-spring days.

Conditions

World
Condition effect
DAY_OF_MONTH <day> Check the day of month.
DAY_OF_WEEK <day> Check the day of week, formatted as an integer between 0 (Sunday) through 6 (Saturday).
FARM_CAVE <type> The current farm cave (one of Bats, Mushrooms, or None).
FARM_NAME <name> Check the name of the farm.

Note: this only works for farm names that don't contain spaces.

FARM_TYPE <type> Check the farm type. The <type> is one of 1 (standard), 2 (riverland), 3 (forest), 4 (hilltop), 4 (combat), 5 (four corners), 6 (beach), or the ID for a custom farm type.
IS_HOST Check whether the current player is the main/host player.
IS_CUSTOM_FARM_TYPE Check whether the farm type is a custom one created by a mod. (This returns false for mods which edit/replace a vanilla farm type.)
SEASON <season> Check the season (one of spring, summer, fall, or winter).
LOCATION_ACCESSIBLE <name> Check whether the given location is accessible (one of CommunityCenter, JojaMart, or Railroad). Returns true for any other name, regardless of whether it's accessible.
WEATHER <location> <weather> Check whether the weather in the given location (one of Here or an internal location name) is Rainy or Sunny.
WORLD_STATE <id> Check whether any world state flag with the given <id> is set.
YEAR Check if the year is equal or more than the given value. For example, YEAR 2 is true in year 2 and all later years.
Player info & progress
Condition effect
PLAYER_COMBAT_LEVEL <player> <level>
PLAYER_FARMING_LEVEL <player> <level>
PLAYER_FISHING_LEVEL <player> <level>
PLAYER_FORAGING_LEVEL <player> <level>
PLAYER_MINING_LEVEL <player> <level>
Check the skill levels for the specified player(s).
PLAYER_CURRENT_MONEY <player> <amount> Check whether the specified player(s) currently have at least <amount> gold.
PLAYER_FARMHOUSE_UPGRADE <player> <level> Check whether the specified player(s) have upgraded their farmhouse or cabin to at least the given level (see possible levels).
PLAYER_GENDER <player> <gender> Check whether the specified player(s) are Male or Female.
PLAYER_HAS_CAUGHT_FISH <player> <id> Check whether the specified player(s) have caught at least one fish with the given ID.
PLAYER_HAS_CONVERSATION_TOPIC <player> <id> Check whether the specified player(s) have a conversation topic with the ID <id> active.
PLAYER_HAS_CRAFTING_RECIPE <player> <recipe name>
PLAYER_HAS_COOKING_RECIPE <player> <recipe name>
Check whether the specified player(s) know the crafting/cooking recipe identified by its internal name (spaces allowed). For example, PLAYER_HAS_CRAFTING_RECIPE CURRENT Field Snack.
PLAYER_HAS_DIALOGUE_ANSWER <player> <id> Check whether the specified player(s) have chosen the given dialogue answer in a previous dialogue.
PLAYER_HAS_FLAG <player> <id> Check whether the specified player(s) have the given mail flag set (with spaces allowed in the <id>).
PLAYER_HAS_ITEM <player> <item> Check whether the specified player(s) have at least one of a normal item (not bigcraftable, furniture, etc) in their inventory. The <item> can be 858 (Qi Gems), 73 (Walnuts), or the unqualified item ID.
PLAYER_HAS_ITEM_NAMED <player> <item name> Check whether the specified player(s) have at least one item in their inventory with the given <item name> (spaces allowed).
PLAYER_HAS_READ_LETTER <player> <id> Check whether the specified player(s) have read a letter, where <id> is the internal mail ID (spaces allowed). For example, PLAYER_HAS_READ_LETTER Any Visited_Island.
PLAYER_HAS_SECRET_NOTE <player> <id> Check whether the specified player(s) have read a secret note, where <id> is the secret note's integer ID.
PLAYER_HAS_SEEN_EVENT <player> <id> Check whether the specified player(s) have seen the event with given <id>.
PLAYER_MOD_DATA <player> <key> <value> Check whether the specified player(s) have a player.modData entry added by a mod with the given <key> and <value>.
PLAYER_MONEY_EARNED <player> <amount> Check whether the specified player(s) have earned at least <amount> gold.
Player relationships
Condition effect
PLAYER_HAS_CHILDREN <player> <count> Check whether the specified player(s) have least <count> children.
PLAYER_HAS_PET <player> Check whether the specified player(s) have a pet.
PLAYER_HEARTS <player> <npc> <heart level> Check whether the specified player(s) have a friend with at least <heart level> hearts of friendship. The <npc> can be an NPC's internal name, Any (check every NPC), or AnyDateable (check every romanceable NPC).
PLAYER_HAS_MET <player> <npc> Check whether the specified player(s) have talked to an NPC at least once. The <npc> is an NPC's internal name.
PLAYER_IS_DATING <player> <npc> Check whether the specified player(s) have given a bouquet to an NPC. The <npc> can be an NPC's internal name, or Any (check every romanceable NPC).
PLAYER_IS_DIVORCED <player> <npc> Check whether the specified player(s) are divorced. The <npc> can be an NPC's internal name or Any (with any NPC).
PLAYER_IS_ENGAGED <player> <target> Check whether the specified player(s) are engaged. The <target> can be an NPC's internal name, Any (with any NPC), or Player (with any player).
PLAYER_IS_MARRIED <player> <target> Check whether the specified player(s) are married. The <target> can be an NPC's internal name, Any (to any NPC), or Player (to any player).
PLAYER_IS_ROOMMATE <player> <target> Check whether the specified player(s) have a roommate. The <target> can be an NPC's internal name, Any (with any NPC), or Player (always false).
PLAYER_PREFERRED_PET <player> <pet> Check whether the preferred pet for the specified player(s) is Cat or Dog.
Save stats
Condition effect
DAYS_PLAYED <count> Check if at least <count> days have been played in the current save (including the current one).
MINE_LOWEST_LEVEL_REACHED <level> Check if any player has reached at least level <level> in the mines.
Randomization
Condition effect
RANDOM <value> Perform a random probability check. For example, RANDOM 0.4 is true 40% of the time. This recalculates the result each time it's called.
PICKED_VALUE_TICK <min> <min> <value> [seed offset]
PICKED_VALUE_DAYS <min> <max> <value> [seed offset]
Chooses a random value between <min> and <max>, and checks if it's equal to <value>. For example, PICKED_VALUE_TICK 1 10 2 has a 10% chance (check if 2 is equal to a random number between 1 and 10).

This always choose the same value for the current tick (if PICKED_VALUE_TICK) or in-game day (if PICKED_VALUE_DAYS). To have a different synchronized value, specify [seed offset] with an offset number (e.g. three options in a list would use offset 0, 1, and 2).

PICKED_VALUE <min> <max> <value> Not recommended for content packs, except in shop dialogues.
Equivalent to PICKED_VALUE_TICK, but checks the value selected by calling the GameStateQuery.PickRandomValue(random) method in code. The game only calls this method when opening a shop menu for shop data with dialogue.

Player ID

Some conditions have a <player> argument. This can be one of...

value result
Any At least one player must match the condition, regardless of whether they're online.
All Every player must match the condition, regardless of whether they're online.
Current The local player.
Host The main player.
Target In Data/WildTrees for the AdditionalChopDrops field only, the last player who chopped the tree. Otherwise equivalent to Current.
any other The unique multiplayer ID for the player to check.

Using queries elsewhere

C# code can use the GameStateQuery class to work with queries, like GameStateQuery.CheckConditions(query).

You can also use game state queries in event preconditions using the new G condition flag, like some_event_id/G !SEASON Spring, WEATHER Here sunny.

Extensibility

C# mods can define custom conditions by calling GameStateQuery.RegisterQueryType("condition name", (string[] fields) => ...). To avoid conflicts, prefixing custom condition names with your mod ID (like Example.ModId_SomeCondition) is strongly recommended.

Tokenizable string format

Stardew Valley 1.6 adds support for literal strings that contain tokens (currently only supported for custom map areas and custom shops).

Literal text

Previously you often needed to load text from a string key in data assets. With this new format, you can use the literal text directly in the asset instead (including Content Patcher tokens):

// before
"Dialogue": "Strings\\StringsFromCSFiles:ShopMenu.cs.11488",

// after: literal text supported
"Dialogue": "Welcome to Pierre's!",

// after: literal text with Content Patcher tokens
"Dialogue": "Welcome to Pierre's, {{PlayerName}}! {{i18n: translatable-text}}",

Tokens

You can inject tokens using square brackets. For example, "[LocalizedText Strings\StringsFromCSFiles:ShopMenu.cs.11488] This is raw text" will show something like "Welcome to Pierre's! This is raw text". Here are the supported tokens:

token format output
[ArticleFor <word>] The grammatical article (a or an) for the given word when playing in English, else blank. For example, [ArticleFor apple] apple will output an apple.
[FarmName] The farm name for the current save (without the injected "Farm" text).
[LocalizedText <string key>] Translation text loaded from the given string key. If the translation has placeholder tokens like {0}, you can add the values after the string key.
[PositiveAdjective] A random adjective from the Strings\Lexicon data asset's RandomPositiveAdjective_PlaceOrEvent entry.
[SuggestedItem] (For shops only.) The name of a random item currently available in the shop stock.

When passing an input argument for tokens like ArticleFor, the input can contain its own nested tokens. For example, "[ArticleFor [SuggestedItem]] [SuggestedItem]" would output something like an Apple.

If you're using Content Patcher, you can use its tokens anywhere in the string (including within square brackets); they'll be expanded before the game parses the string. For example, "{{Spouse}} would love [ArticleFor [SuggestedItem]] [SuggestedItem]!" would output something like "Alexa would love an Apple!".

Map/tile property changes

  • Added new Action tile properties:
    layer property explanation
    Buildings Action BuildingToggleAnimalDoor Opens/closes the animal door for the building which covers the tile.
    Buildings Action ObeliskWarp <location name> <x> <y> [whether to dismount] Warps the player to the specified location name and position with the Obelisk animation/sound effects.
    Buildings Action OpenShop <shop id> [from direction] [open time] [close time] [owner tile area] Open the shop with the given <shop id>. All arguments besides the ID are optional:
    • [from direction]: if specified, the player must be standing in this direction relative to the shop (one of down, up, left, right, or none). Setting this to none disables the requirement. The default for most vanilla shops is down.
    • [open time] and [close time]: the start & end times in 26-hour format when the shop is available. Interacting with the tile outside those times does nothing.
    • [owner tile area]: if specified, the tile area which must contain one of the shop owners for the shop to be available. For a custom shop, these are defined by its ValidNPCs field. This can be specified in two forms: <x> <y> for a single tile, or <top-left x> <top-left y> <bottom-right x> <bottom-right y> for a multi-tile area.
  • Dropped support for non-string map & tile properties. Properties set to bool, int, or float will be converted to string when the game loads them.

Other changes

  • Added a display name field in English too for Data/Boots, Data/CookingRecipes, Data/CraftingRecipes, and Data/Furniture.
  • Added optional Conditions game state query field to Data/SpecialOrders.

XNB impact

Here's a summary of the XNB files which changed in Stardew Valley 1.6.

This doesn't include...

  • changes in non-English files;
  • new fields when the vanilla entries didn't change (e.g. optional custom item fields).

Shorthand:

  • 'broken' means removing new content or potentially important changes, or potentially causing significant display bugs. This is a broad category — the game may work fine without it or crash, depending how it uses that specific content.
  • 'mostly unaffected' means mods will only be affected if they edit specific entries or fields.
  • Blank means no expected impact for the vast majority of mods.

XNB mods are disproportionately affected since (a) they replace the entire file and (b) they're loaded through the MonoGame content pipeline which is less tolerant of format changes.

content file changes XNB Content Patcher
Data/AquariumFish changed key type ✘ broken
Data/BigCraftablesInformation changed key type, standardized fields ✘ broken ✘ likely broken
Data/Boots changed key type, added display name ✘ broken ✘ likely broken
Data/ClothingInformation changed key type, standardized fields ✘ broken ✘ likely broken
Data/CookingRecipes added display name ✘ broken ✘ likely broken
Data/CraftingRecipes added display name ✘ broken ✘ likely broken
Data/Crops changed key type ✘ broken
Data/Events/IslandSouth fixed typo ✘ will remove changes ✓ mostly unaffected
Data/Fish changed key type ✘ broken
Data/FishPondData changed ItemID field type ✘ broken
Data/fruitTrees changed key type ✘ broken
Data/Furniture changed key type, standardized fields, added display name ✘ broken ✘ likely broken
Data/hats changed key type, standardized fields, added display name ✘ broken ✘ likely broken
Data/IngameMap new
Data/ObjectInformation changed key type, standardized fields ✘ broken ✘ likely broken
Data/Shops new
Data/ToolData new
Data/weapons changed key type, added display name ✘ broken ✘ likely broken
Data/WildTrees new
Maps/AbandonedJojaMart
Maps/Backwoods
Maps/Backwoods_GraveSite
Maps/Backwoods_Staircase
Maps/Barn
Maps/Barn2
Maps/Barn3
Maps/BoatTunnel
Maps/Cabin
Maps/Cabin1
Maps/Cabin1_marriage
Maps/Cabin2
Maps/Cabin2_marriage
Maps/Coop
Maps/Coop2
Maps/Coop3
Maps/Farm
Maps/Farm_Combat
Maps/Farm_Fishing
Maps/Farm_Foraging
Maps/Farm_FourCorners
Maps/Farm_Greenhouse_Dirt
Maps/Farm_Greenhouse_Dirt_FourCorners
Maps/Farm_Island
Maps/Farm_Mining
Maps/FarmHouse
Maps/FarmHouse_Bedroom_Normal
Maps/FarmHouse_Bedroom_Open
Maps/FarmHouse_Cellar
Maps/FarmHouse_ChildBed_0
Maps/FarmHouse_ChildBed_1
Maps/FarmHouse_CornerRoom_Add
Maps/FarmHouse_CornerRoom_Remove
Maps/FarmHouse_SouthernRoom_Add
Maps/FarmHouse_SouthernRoom_Remove
Maps/FarmHouse1
Maps/FarmHouse1_marriage
Maps/FarmHouse2
Maps/FarmHouse2_marriage
Maps/Greenhouse
Maps/IslandFarmHouse
Maps/MarnieBarn
Maps/Mine
Maps/Mountain
Maps/MovieTheater
Maps/MovieTheaterScreen
Maps/spousePatios
Maps/Sunroom
Maps/Mines/Volcano_SetPieces_32
changed map & tile properties to string
Maps/paths added icon for custom wild tree spawn

See also