Modding:Migrate to Stardew Valley 1.7: Difference between revisions
imported>Pathoschild →Event changes: expand fork deprecation, + deprecated commands |
imported>Pathoschild →Multilingual events: clarify wording and potential issues |
||
| Line 60: | Line 60: | ||
===[[Modding:Event data|Event]] changes=== | ===[[Modding:Event data|Event]] changes=== | ||
====Multilingual events==== | ====Multilingual events==== | ||
All vanilla events are now multilingual, with a single copy of | All vanilla events are now multilingual, with a single copy of each event script which uses translation keys. Translations from the old per-language event files were moved into a per-language <samp>Strings/Events</samp> file. | ||
For example: | |||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
| Line 86: | Line 87: | ||
|} | |} | ||
[[Modding:Content Patcher|Content Patcher]] content packs should generally be unaffected, since their edits were applied to the active version of the file automatically (which will just become the base file in all languages). In rare cases, | [[Modding:Content Patcher|Content Patcher]] content packs should generally be unaffected, since their edits were applied to the active version of the file automatically (which will just become the base file in all languages). | ||
In rare cases, a mod which directly targets a specific localized asset name like <code>Data/Events/Beach.fr-FR</code> may no longer work or break vanilla events (depending on how it edits them). That should be a very rare case, since the APIs for both Content Patcher and SMAPI were designed to discourage doing that. | |||
====Forking deprecated==== | ====Forking deprecated==== | ||
Revision as of 16:05, 29 April 2025
This page is for mod authors. Players: see the mod compatibility list instead.
This page describes changes accumulated in the game's pre-alpha development branch. There's no estimated release date or even assigned version number for these changes yet. Things will change before it's released!
This page helps mod authors prepare their mods for the next game version (tentatively Stardew Valley 1.6.16), and documents some of the changes and new functionality.
FAQs

What's changing?
So far, Stardew Valley 1.6.16 only has small changes for mods following the major 1.6 and 1.6.9 updates.
Is this the modapocalypse?
No, the current impact on mods is expected to be minimal. A few mods which use Harmony or reflection to hook deeply into game internals might be affected by any game update, but otherwise no change in mod compatibility is expected.
How to update your mod
Here's a suggested 'quick start' guide to update a mod for Stardew Valley 1.6.16.
- For C# mods:
-
- Update for Stardew Valley 1.6.9 if you haven't already.
- Rebuild the solution.
- Fix any build errors and review any build warnings. You can search this page and previous migration guides for relevant info as needed.
- Increment your mod version in manifest.json.
(Some mods may be added to SMAPI's compatibility blacklist due to runtime errors. Incrementing the mod version will fix that if so.) - Test to make sure the mod works.
- Skim through this page, and check any section that might be relevant to the mod.
- For Content Patcher packs:
-
- Update for Stardew Valley 1.6.9 if you haven't already.
- Skim through this page, and check any section that might be relevant to the mod.
- For content packs which use another framework:
- See the documentation for the framework mod. Often you won't need to update the content pack if the framework mod itself was updated.
Changes for all mod authors
New context tags
| context tag | effect |
|---|---|
| fish_skip_minigame | If the player catches this item while fishing, it'll be caught directly without the fishing minigame. This matches the behavior when catching junk items like seaweed (which now have the context tag where needed). |
Debug command changes
Improved existing commands:
| command | description |
|---|---|
| perfection | Fixed error when run on a save which already has some requirements partly met. |
Event changes
Multilingual events
All vanilla events are now multilingual, with a single copy of each event script which uses translation keys. Translations from the old per-language event files were moved into a per-language Strings/Events file.
For example:
| files in 1.6.15 | files in 1.6.16 |
|---|---|
Data/Events/Beach Data/Events/Beach.de-DE Data/Events/Beach.es-ES Data/Events/Beach.fr-FR Data/Events/Beach.hu-HU Data/Events/Beach.it-IT Data/Events/Beach.ja-JP Data/Events/Beach.ko-KR Data/Events/Beach.pt-BR Data/Events/Beach.ru-RU Data/Events/Beach.tr-TR Data/Events/Beach.zh-CN |
Data/Events/Beach |
Content Patcher content packs should generally be unaffected, since their edits were applied to the active version of the file automatically (which will just become the base file in all languages).
In rare cases, a mod which directly targets a specific localized asset name like Data/Events/Beach.fr-FR may no longer work or break vanilla events (depending on how it edits them). That should be a very rare case, since the APIs for both Content Patcher and SMAPI were designed to discourage doing that.
Forking deprecated
All vanilla events which used forking now use goto labels instead.
Forking still works as-is for backwards compatibility, but mod events should prefer goto labels since...
- they work more consistently and intuitively with other features like skip labels;
- it's the approach that the game will be applying and developing in future versions;
- deprecated commands will be reported as an error if you use the EventValidator;
- and there's no guarantee forking will always work in future versions.
The fork-related event commands are deprecated.
New event commands
| command | description | ||||||||
|---|---|---|---|---|---|---|---|---|---|
addActor <x> <y> <direction>
|
Add a character or player to the event. This is mostly equivalent to adding them through the character positions field, but can be done at any point in the script (e.g. for use with goto for event variations). | ||||||||
choose <question> [<answer> <go to label>]+
|
Show a dialogue box to choose from a list of responses, then optionally skip to a label based on the selected answer.
Arguments:
For example, here's a simple choice which doesn't affect anything: choose "Do you like apples?" "I love them." _ "I hate them." _/ Or you can change the course of the event based on the choice: speak Abigail "Do you... like me?$l"/ choose null "Yes!" happy "No." heartbroken/ label heartbroken/ speak Abigail "Oh. I understand.$s"/ faceDirection Abigail left/ pause 3000/ end/ label happy/ speak Abigail "We should explore the mines together next time!$h"/ ... | ||||||||
goto [<target> [condition]]+
|
Skip forward or backward to a specific position in the event script. Each <target> can be:
You can list any number of label/condition pairs, and it will go to the first label with a matching condition. If a condition is omitted, it defaults to always true. If none of the conditions match, it continues to the next command normally. For example, this event script uses goto to repeat a question until a specific answer is selected: "
continue/64 15/farmer 64 16 2 Abigail 64 18 0/pause 1500/
label question/speak Abigail \"Hey! Did you have your eye on someone?\"/quickQuestion #Abigail.#Penny.#Alex.(break)goto correct(break)goto hmm(break)goto hmm/
label hmm/speak Abigail \"Oh?$u\"/pause 500/goto question/
label correct/speak Abigail \"I thought so!$l\"/pause 500/end
"
You can make goto conditional using game state queries. For example, this will go to the divorced label if you divorced Abigail, and continue to the next command if not: " .../ goto divorced \"PLAYER_NPC_RELATIONSHIP Current Abigail Divorced\"/ " | ||||||||
label <label>
|
Set a named position in the event script, which you can go to using the goto command.
Note: you can't use end as a label name, since that automatically matches the end event command. |
Improved existing commands
| command | description |
|---|---|
| gainSkill | Added argument validation. |
| skippable | Added an optional [skip to label] argument. If set, the event will jump to that label when the player clicks the skip button (see goto for more info). The last skippable command run before the player skips is applied.
This is meant to clean up or grant unlocks before the event ends. For example: ".../skippable beforeEnd/.../label beforeEnd/gainSkill Fishing 1/addItem (T)TrainingRod/end" Technically you can jump to any point in the event (e.g. to cancel the skip). However, the skip action will still cancel any ongoing event behavior like ongoing player/NPC movements, so you should be careful doing this. |
| spriteText | The [text] argument can now be a translation key to get the text from.
|
Deprecated commands
These event commands are deprecated. They still work as before, but they'll be reported as an error if you use the EventValidator.
| event command | migration |
|---|---|
| fork | Use the choose or goto commands instead. If you used dialogue containing the %fork token, it should be removed and replaced with equivalent event commands. |
| question forkX | Use the choose command instead, and replace the event fork with a label.
For example, this script: // main event question fork1 "#I believe in you!#Wow, you're really arrogant."/ fork arrogant/ speak Alex "Thanks, @. I'll remember that."/ ... // 'arrogant' event emote Alex 12/ speak Alex "Hmmph... I think someone's a little jealous.$a"/ Becomes this script: choose _ "I believe in you!" believe "Wow, you're really arrogant." arrogant/ label believe/ speak Alex "Thanks, @. I'll remember that."/ ... label arrogant/ emote Alex 12/ speak Alex "Hmmph... I think someone's a little jealous.$a"/ ... Forks often duplicated the end of the script. In that case, you can have both variants just goto the common ending instead. |
| question null | Use choose with _ labels instead. (Setting a label argument to _ means it'll just continue to the next command instead.)
For example, this command: question null "But what am I going to say to Vincent?#It's best to be honest with kids.#You did the right thing. Kids should have hope."/ Would become this command: choose "But what am I going to say to Vincent?" "It's best to be honest with kids." _ "You did the right thing. Kids should have hope." _/ |
| quickQuestion | Use the choose command instead. The <question> and <answerX> have matching choose arguments, while the <answerX script> arguments become labels.
For example, this command: quickQuestion #I'd like to help#Nah, I'll pass...(break)emote Willy 32\speak Willy "Aye... I thought you would.$h#$b#I'll leave this door unlocked for ya... you can come drop off the materials whenever you like."(break)emote Willy 28\speak Willy "Alright, suit yourself...$s#$b#If you have a change of heart, you can always come back and help out. I'll leave this door unlocked, anyhow."/ Becomes this script: choose _ "I'd like to help" accept "Nah, I'll pass..." refuse/ label accept/ emote Willy 32/ speak Willy "Aye... I thought you would.$h#$b#I'll leave this door unlocked for ya... you can come drop off the materials whenever you like."/ goto resume/ label refuse/ emote Willy 28/ speak Willy "Alright, suit yourself...$s#$b#If you have a change of heart, you can always come back and help out. I'll leave this door unlocked, anyhow."/ label resume/ |
| cutscene bandfork elliottBookTalk question haleyDarkRoom question shaneCliffs question shaneLoan |
These commands are deleted and will no longer work. They're unlikely to be used by mod events, but see their relevant events for the new equivalents if needed. |
Other changes
- Moved all vanilla events' on-skip behavior into their event scripts (except the pet adoption logic).
- Moved summit events into a new Data/Events/Summit file.
Lost items shop changes
In Data/LostItemsShop, added one new field:
| field | effect |
|---|---|
| RequireCondition | (Optional) The game state queries which must match to add this item. The Target player is the one being checked.
This field should generally only be used with deterministic game state queries. |
If you specify multiple criteria fields, only one is applied in this order: RequireMailReceived, then RequireEventSeen, then RequireCondition.
Special order changes
- In Data/SpecialOrders, added one new field:
field effect CanBeCancelled (Optional) Whether the special order can be cancelled. In multiplayer, any player cancelling the special order will remove it for all players. Default false. And improved one field:
field effect Duration This can now be set to "Indefinite" for a special order with no expiry. It will remain active until it's completed or cancelled. Consider enabling CanBeCancelled if applicable.
Other changes
- Added validation for schedule offset command in end-of-route animations.
- Fixed FarmHouseFurniture map property only allowing numeric item IDs.
- Fixed crash when loading a save with missing building interiors.
- Fixed intermittent crash when an item delivery quest for a non-Wizard NPC requests a cooking-type item.
- Fixed RejectItem_* dialogue disabling the NPC's normal dialogue after it's shown.
Changes for C# mod authors
Instance statics no longer affect mod assemblies
In multiplayer, split-screen mode works by swapping the values of static fields for each screen (called instanced statics). In previous versions, Stardew Valley would scan all loaded assemblies for static fields marked with [InstancedStatic] attributes except a few ignored assemblies like MonoGame.
In Stardew Valley 1.6.16, the game now only does this for the main game assembly to improve performance. If a mod was using [InstancedStatic], it should use SMAPI's built-in per-screen data utility instead.
AssetNameUtility
The new AssetNameUtility class has methods for working with asset names:
| method | usage |
|---|---|
| Normalize | A low-level method which normalizes path separators in an asset name. For example:
string assetName = AssetNameUtility.Normalize("Characters/\\/Abigail"); // produces "Characters/Abigail"
Consider using SMAPI's PathUtilities.NormalizeAssetName instead, which is more thorough. |
| TryParseTranslationKey | Parses a translation key into its component parts. For example:
if (AssetNameUtility.TryParseTranslationKey("Strings/UI:Confirm", out string assetName, out string fieldKey, out string error))
...; // assetName: Strings/UI, fieldKey: Confirm, error: null
This doesn't check whether the asset or key exists; see Game1.content.IsValidTranslationKey to do that. |
EventValidator
Overview
The new EventValidator class analyses event scripts to detect issues like...
- command names which don't match a registered command or alias;
- command arguments which don't match those expected by the command;
- and custom rule violations based on the EventValidator.CommandValidators field (e.g. a default validator checks that goto commands match a valid label).
This is mainly meant to implement unit tests for events. For example, to validate all events in a data asset:
string assetName = "Data/Events/Farm";
var events = Game1.content.Load<Dictionary<string, string>>(assetName);
var validator = new EventValidator();
foreach ((string key, string script) in events)
{
foreach (var issue in validator.Validator(assetName, key, script))
Assert.Fail($"Validation failed for event '{key}' > command '{issue.CommandText}': {issue.SuggestedError}.");
}
Command argument validation
Argument validation is enabled if the command's handler method has an EventArguments attribute, which defines the argument pattern using a special syntax. Each command can list multiple patterns, and it'll be considered valid if any of them matches. If the pattern is an empty string, the validator will ensure no arguments are provided.
For example, the default showFrame command is defined like this:
[EventArguments("int", "actor int bool?")]
public static void ShowFrame(Event @event, string[] args, EventContext context)
An argument pattern consists of space-delimited tokens, where each token defines the format for an argument. For example, actor int bool? has three tokens representing three arguments: an actor name, a positive integer, and an optional boolean.
These are the tokens recognized by the validator:
| token | meaning |
|---|---|
| generic argument types | |
| bool | A boolean value (true or false). |
| float | A positive number with optional decimal point (like 5 or 0.5). |
| -float | A number with optional decimal point and optional negative sign (like 5, -5, or -0.5). |
| int | A positive integer (like 5). |
| -int | An integer with optional negative sign (like 5 or -5). |
| string | A quoted sequence of arbitrary text like "some words here". If the argument has no quotes, this is equivalent to the word token. |
| word | A simple sequence of letters, numbers, periods, and/or underscores (usually an ID or similar value). While the command will accept quotes, they're redundant and will be rejected by the validator. |
| remainder | One or more arguments of any type. |
| specific string formats | |
| actor | An actor name in the event format (like Abigail or Kent?). |
| assetName | An asset name like Data/Achievements. |
| direction | A direction which can be specified as either a number (like 0) or name (like up). |
| goToLabel | An event label (see the goto and label event commands). This is equivalent to word, but is used by EventValidator to validate label references. |
| itemId | An item ID which can be qualified or unqualified (like (O)MossySoup or MossySoup). |
| translationKey | A translation key like Strings/Locations:SomeKey. |
| custom formats | |
| '...' | The literal text or regex pattern to match, like 'continue' or '[\w-]+'.
|
In addition, you can extend tokens with these indicators:
- Suffix with + for repeating argument of that type. For example, int+ would allow both 5 and 5 6 7.
- Suffix with ? for an optional argument which can be omitted. All tokens after this token must also be optional. (You can have optional repeating arguments like int+?.)
- Infix with | for a parameter which can be one of multiple types. For example int|bool will allow either integer or boolean values.
Other breaking API changes
(This section is meant as a quick reference if you have build errors; there's no need to read through it otherwise.)
These class members changed in 1.6.16:
| type | member | migration |
|---|---|---|
| FishingRod | lastCatchWasJunk | Renamed to lastCatchSkippedMinigame to more accurately convey what it does. |
Other changes
- Map tilesheets are now normalized to forward slashes on all platforms (like Maps/Town instead of Maps\Town).
- Fixed
item.CopyFieldsFrom(other)always setting the stack size for the copy to 1. - Fixed
Event.TryGetEventCommandHandlernot loading commands if it's called before any other methods. - Fixed machine auto-load leaving empty slots in chests when taking a secondary ingredient.
Name translation changes for wiki maintainers
Some in-game item and monster names were retranslated in some languages for clarity or correctness.
This list is mostly provided to help wiki maintainers update pages, so it doesn't include names which only changed capitalization, changed ' (straight apostrophe) to ’ (curly) in French, or aren't visible to vanilla players (like mine rocks).
Furniture
- Hungarian
item old name new name Artist Bookcase Művészi könyvespolc Művészi könyvszekrény Birch Double Bed Birs dupla ágy Nyírfa dupla ágy Dark Bookcase Sötét könyvespolc Sötét könyvszekrény Gray Joja Bookcase Szürke Joja könyvespolc Szürke Joja könyvszekrény Joja Bookcase Joja könyvespolc Joja könyvszekrény Junimo Bookcase Junimo könyvespolc Junimo könyvszekrény Large Wizard Bookcase Nagy varázsló könyvespolc Nagy varázsló könyvszekrény Luxury Bookcase Luxus könyvespolc Luxus könyvszekrény Modern Bookcase Modern könyvespolc Modern könyvszekrény Retro Bookcase Retro könyvespolc Retro könyvszekrény Short Bookcase Kicsi könyvespolc Kicsi könyvszekrény Short Wizard Bookcase Alacsony varázsló könyvespolc Alacsony varázsló könyvszekrény Small Wizard Bookcase Kicsi varázsló könyvespolc Kicsi varázsló könyvszekrény Wizard Bookcase Varázsló könyvespolc Varázsló könyvszekrény
- Russian
item old name new name Pierre's Sign Знак Пьера Вывеска Пьера
Hats
- Russian
item old name new name Blobfish Mask Маска рыбы-пузыря Маска рыбы-капли
Weapons
- Russian
item old name new name Dark Sword Темный Меч Темный клинок Dragontooth Club Драконозубья дубинка Дубина из драконьего зуба Dragontooth Cutlass Драконозубья сабля Сабля из драконьего зуба Dragontooth Shiv Драконозубья заточка Заточка из драконьего зуба Dwarf Dagger Кинжал Дварфов Дварфийский кинжал Dwarf Hammer Молот Дварфов Дварфийский молот Dwarf Sword Меч Дварфов Дварфийский меч Insect Head Жучья Голова Жучиная голова Leah's Whittler Точилка Леи Резец Леи Seb's Lost Mace Потерянная палица Себа Потерянная булава Себа Wind Spire Башня Ветров Пика ветров
Monsters
- Hungarian
monster old name new name Truffle Crab Kőrák Szarvasgombarák