Difference between revisions of "Modding:Migrate to Stardew Valley 1.3"

From Stardew Valley Wiki
Jump to navigation Jump to search
(→‎Major changes: + Game1.currentLocation can be null)
(→‎Major changes: + Reserved key bindings)
Line 64: Line 64:
 
* Custom map tilesheets no longer need hacks to avoid the game's seasonal logic. Tilesheets which don't start with a season name and underscore won't be seasonalised.
 
* Custom map tilesheets no longer need hacks to avoid the game's seasonal logic. Tilesheets which don't start with a season name and underscore won't be seasonalised.
 
* Several changes to support upcoming SMAPI features and fixes.
 
* Several changes to support upcoming SMAPI features and fixes.
 +
 +
===Reserved key bindings===
 +
Mods won't receive input sent to the chatbox, and they won't receive the toggle-chatbox key ({{key|T}} by default).
  
 
==Fix common compiler warnings==
 
==Fix common compiler warnings==

Revision as of 18:48, 22 April 2018

Index

This page is for modders. Players: see Modding:SMAPI compatibility instead. For updating Content Patcher or XNB mods, see Migrate XNB changes to Stardew Valley 1.3.

This page explains how to update your SMAPI mod code for compatibility with Stardew Valley 1.3.

Overview

Single player

At a high level, here's how to update a SMAPI mod:

  1. Update the mod build NuGet package to 2.1-beta. (You may need to enable the 'include prerelease' checkbox to see the beta.)
    This adds support for Stardew Valley 1.3, and adds code analysis which will report common problems in Stardew Valley 1.3 as compiler warnings.
  2. Restart Visual Studio to fully install the package.
  3. Rebuild your solution.
  4. Fix any compiler errors and warnings you see in the Error List pane in Visual Studio (or equivalent for other editors).
  5. See below for help with specific changes and warnings.
  6. Test all mod features to make sure they work.

If you need help updating your code, feel free to ask questions on the Stardew Valley Discord.

Multiplayer

The instructions for single player apply for multiplayer too. Stardew Valley 1.3 automatically synchronises most world changes to other players (see net fields), so many mods will work in multiplayer too. Some mods may need further changes, but that can only be decided case-by-case.

There are three common approaches to multiplayer compatibility:

  • Let anyone install the mod. If your mod makes changes to the world, make sure it'll work fine if different players have different versions or configuration, or only some of the players have it installed.
  • Only let the main player install the mod, which avoids complications from other players changing the same data. To do this, check SMAPI's Context.IsMainPlayer in your code.
  • Only enable in single-player mode. This eliminates all multiplayer and sync complications, though players may be disappointed. To do this, check SMAPI's Context.IsMultiplayer in your code.

Common issues:

  • If your mod adds custom buildings or items, the game may crash trying to sync them to other players.

Major changes

Net fields

A 'net type' is any of several new classes which Stardew Valley 1.3 uses to sync data between players, named for the Net prefix in their name. A net type can represent a simple value like NetBool, or complex values like NetFieldDictionary. Many existing fields have been converted to net types (called 'net fields'), each wrapping the underlying value:

NetString str = new NetString("bar");
if (str.Value == "bar") // true

Impact on mods:

  • The game will regularly collect all the net fields reachable from Game1.netWorldState and sync them with other players. That means that many mod changes will be synchronised automatically in multiplayer.
  • Net fields can implicitly convert to their equivalent normal values (like bool x = new NetBool(true)), but their conversion rules can be counterintuitive and error-prone. For example, item?.category == null && item?.category != null can both be true at once. Always avoid implicit casts to minimise bugs.

Suggested fix:

  • With the latest mod build package installed, rebuild your project. The package will detect net field references you need to update, and show an appropriate warning. See fix common warnings below.

WorldDate

Game1.WorldDate is a new field which provides a more useful way to check the date. This combines the day, season, and year with useful logic like day-of-week and date comparisons. This incorporates many of the features from SMAPI's SDate class.

Game1.player.friendships is obsolete

The Game1.player.friendships field is always null in Stardew Valley 1.3. Use the new Game1.player.friendshipData field instead, which wraps the raw data with a more useful model and more data.

Game1.currentLocation can be null

The Game1.currentLocation field is intermittently null for secondary players in multiplayer mode (e.g. when they transition between locations). Make sure any references to that field can handle it being null.

Texture constructor arguments

Many constructors which previously accepted Texture2D texture arguments now take a string textureName argument instead. It's usually better to use SMAPI's content API to override textures instead. You can change the cached texture after the object is constructed (may need reflection), but don't change the texture name to avoid multiplayer sync issues.

Changes to help modders

Stardew Valley 1.3 includes several changes intended to benefit modders. Some of the most relevant are...

  • Many more methods and properties are now virtual.
  • Many type checks now allow subclasses (like item.GetType() == typeof(Axe)item is Axe).
  • Any GameLocation can now set IsGreenhouse = true, and crops will grow there all year.
  • Any NPC can now set IsSocial to determine whether they appear in the social menu.
  • Bee houses now find nearby flowers in any location, not only when placed on the farm.
  • Custom map tilesheets no longer need hacks to avoid the game's seasonal logic. Tilesheets which don't start with a season name and underscore won't be seasonalised.
  • Several changes to support upcoming SMAPI features and fixes.

Reserved key bindings

Mods won't receive input sent to the chatbox, and they won't receive the toggle-chatbox key (T by default).

Fix common compiler warnings

Make sure you check your Error List pane in Visual Studio (or equivalent in other IDEs) and fix any warnings. Here are some common ones:

Mismatch between the processor architecture...

Sample warning: "There was a mismatch between the processor architecture of the project being built "{0}" and the processor architecture of the reference "{1}". This mismatch may cause runtime failures."

That warning is normal. The error is saying that your build is set to 'Any CPU', but Stardew Valley is x86-only so it'll only work in x86 anyway. You can either ignore it, or change your platform target to x86.

This implicitly converts...

Sample warning: "This implicitly converts '{0}' from Net{1} to {2}, but Net{1} has unintuitive implicit conversion rules. Consider comparing against the actual value instead to avoid bugs. See https://smapi.io/buildmsg/avoid-implicit-net-field-cast for details."

Your code is referencing a net field, which can cause subtle bugs. The field you're referencing has an equivalent non-net property, like monster.Health (int) instead of monster.health (NetBool). Change your code to use the suggested property instead.

FieldName is a Net* field...

Sample warning: "'{0}' is a Net{1} field; consider using the {2} property instead. See https://smapi.io/buildmsg/avoid-net-field for details."

Your code is referencing a net field, which can cause subtle bugs. You should access the underlying value instead:

  • For a reference type (i.e. one that can contain null), you can use the .Value property (or .FieldDict for a NetDictionary):
    if (building.indoors.Value == null)
    

    Or convert the value before comparison:

    GameLocation indoors = building.indoors.Value;
    if(indoors == null)
       // ...
    
  • For a value type (i.e. one that can't contain null), check if the parent is null (if needed) and compare with .Value:
    if (item != null && item.category.Value == 0)
    

The FieldName field is obsolete...

Sample warning: "The 'Character.friendships' field is obsolete and should be replaced with 'friendshipData'. See https://smapi.io/buildmsg/avoid-obsolete-field for details."

You're referencing a field which should no longer be used. Use the suggested field name instead to fix it.

Testing in multiplayer

You can test mods in multiplayer on the same computer, by launching two instances of the game. This needs a few extra steps.

  1. Prepare player one:
    1. Launch SMAPI like usual.
    2. From the title screen: click co-op, then host.
    3. Start a new save slot (unless you've already created one). Make sure to set 'starting cabins' to at least one (you'll need one cabin per extra player).
  2. Prepare player two:
    1. Launch SMAPI from a terminal or command prompt like this:
      • Windows: StardewModdingAPI.exe --log-path "SMAPI-latest-player2.txt"
      • Linux or Mac: StardewValley --log-path "SMAPI-latest-player2.txt"
    2. From the title screen: click co-op, then join LAN game.
    3. Leave the 'Enter IP...' box empty and click OK.