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

From Stardew Valley Wiki
Jump to navigation Jump to search
(split Content Patcher and XNB updates to Modding:Migrate XNB changes to Stardew Valley 1.3)
(expand and update)
Line 5: Line 5:
 
This page explains how to update your SMAPI mod code for compatibility with Stardew Valley 1.3.
 
This page explains how to update your SMAPI mod code for compatibility with Stardew Valley 1.3.
  
==SMAPI mods==
+
==Overview==
===Overview===
 
 
At a high level, here's how to update a SMAPI mod:
 
At a high level, here's how to update a SMAPI mod:
 
# Update the [https://www.nuget.org/packages/Pathoschild.Stardew.ModBuildConfig mod build NuGet package] to 2.1-beta. (You may need to enable the 'include prerelease' checkbox to see the beta.)<br />''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.''
 
# Update the [https://www.nuget.org/packages/Pathoschild.Stardew.ModBuildConfig mod build NuGet package] to 2.1-beta. (You may need to enable the 'include prerelease' checkbox to see the beta.)<br />''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.''
 +
# '''Restart Visual Studio''' to fully install the package.
 
# Rebuild your solution.
 
# Rebuild your solution.
 
# Fix any compiler errors and warnings you see in the ''Error List'' pane in Visual Studio (or equivalent for other editors).
 
# Fix any compiler errors and warnings you see in the ''Error List'' pane in Visual Studio (or equivalent for other editors).
Line 18: Line 18:
 
If you need help updating your code, feel free to ask questions [[Modding:Community#Discord|on the Stardew Valley Discord]].
 
If you need help updating your code, feel free to ask questions [[Modding:Community#Discord|on the Stardew Valley Discord]].
  
===Net types===
+
==Major changes==
Stardew Valley 1.3 uses net types (like <tt>NetBool</tt> and <tt>NetInt</tt>) to handle multiplayer sync. These types can implicitly convert to their equivalent normal values (like <code>bool x = new NetBool()</code>), but their conversion rules are unintuitive and error-prone. For example, <code>item?.category == null && item?.category != null</code> can both be true at once, and <code>building.indoors != null</code> will be true for a null value in some cases. With the mod build config package installed, rebuild the project and look for warnings in the Error List pane like this:
+
===Net fields===
<blockquote>''&apos;&#123;&#123;expression&#125;&#125;&apos; is a &#123;&#123;net type&#125;&#125; field; consider using the &#123;&#123;property name&#125;&#125; property instead. See https://smapi.io/buildmsg/smapi002 for details.''</blockquote>
+
A 'net type' is any of several new classes which Stardew Valley 1.3 uses to sync data between players, named for the <code>Net</code> prefix in their name. A net type can represent a simple value like <tt>NetBool</tt>, or complex values like <tt>NetFieldDictionary</tt>. Many existing fields have been converted to net types (called 'net fields'), each wrapping the underlying value:
<blockquote>''This implicitly converts &apos;&#123;&#123;expression&#125;&#125;&apos; from &#123;&#123;net type&#125;&#125; to &#123;&#123;other type&#125;&#125;, but &#123;&#123;net type&#125;&#125; has unintuitive implicit conversion rules. Consider comparing against the actual value instead to avoid bugs. See https://smapi.io/buildmsg/smapi001 for details.''</blockquote>
+
: <source lang="C#">
 +
NetString str = new NetString("bar");
 +
if (str.Value == "bar") // true
 +
</source>
 +
 
 +
Impact on mods:
 +
* The game will regularly collect all the net fields reachable from <tt>Game1.netWorldState</tt> 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 <code>bool x = new NetBool(true)</code>), but their conversion rules can be counterintuitive and error-prone. For example, <code>item?.category == null && item?.category != null</code> can both be true at once. '''Always avoid implicit casts to minimise bugs.'''
  
 
Suggested fix:
 
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|''fix common warnings'']] below.
 +
 +
===<tt>Game1.player.friendships</tt>===
 +
This field is always null in Stardew Valley 1.3. Use the new <tt>Game1.player.friendshipData</tt> field instead, which wraps the raw data with a model.
 +
 +
===Texture constructor arguments===
 +
Many constructors which previously accepted <tt>Texture2D texture</tt> arguments now take a <tt>string textureName</tt> 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 [[Modding:SMAPI APIs#Reflection|reflection]]), but don't change the texture name to avoid multiplayer sync issues.
 +
 +
==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 [https://msdn.microsoft.com/en-us/library/ms185328.aspx change your platform target] to x86.
 +
 +
===This implicitly converts...===
 +
Sample warning: "''This implicitly converts '{0}' from {1} to {2}, but {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 fields|net field]], which can cause subtle bugs. The field you're referencing has an equivalent non-net property, like <tt>monster.Health</tt> (<tt>int</tt>) instead of <tt>monster.health</tt> (<tt>NetBool</tt>). Change your code to use the suggested property instead.
 +
 +
===FieldName is a Net* field...===
 +
Sample warning: "'''{0}' is a {1} field; consider using the {2} property instead. See https://smapi.io/buildmsg/avoid-net-field for details.''"
 +
 +
Your code is referencing a [[#Net fields|net field]], which can cause subtle bugs. You should access the underlying value instead:
 
<ul>
 
<ul>
<li>Some net fields have an equivalent non-net property, like <tt>monster.Health</tt> (<tt>int</tt>) instead of <tt>monster.health</tt> (<tt>NetBool</tt>). The mod build package will add a [https://smapi.io/buildmsg/smapi002 SMAPI002 warning] which says which property to use instead.</li>
 
 
<li>For a reference type (i.e. one that can contain <tt>null</tt>), you can use the <tt>.Value</tt> property (or <tt>.FieldDict</tt> for a <tt>NetDictionary</tt>):
 
<li>For a reference type (i.e. one that can contain <tt>null</tt>), you can use the <tt>.Value</tt> property (or <tt>.FieldDict</tt> for a <tt>NetDictionary</tt>):
 
<source lang="c#">
 
<source lang="c#">
Line 33: Line 64:
 
Or convert the value before comparison:
 
Or convert the value before comparison:
 
<source lang="c#">
 
<source lang="c#">
GameLocation indoors = building.indoors;
+
GameLocation indoors = building.indoors.Value;
 
if(indoors == null)
 
if(indoors == null)
 
   // ...
 
   // ...
 
</source></li>
 
</source></li>
<li>For a value type (i.e. one that can't contain <tt>null</tt>), check if the object is null (if applicable) and compare with <tt>.Value</tt>:
+
<li>For a value type (i.e. one that can't contain <tt>null</tt>), check if the parent is null (if needed) and compare with <tt>.Value</tt>:
 
<source lang="c#">
 
<source lang="c#">
 
if (item != null && item.category.Value == 0)
 
if (item != null && item.category.Value == 0)
Line 43: Line 74:
 
</ul>
 
</ul>
  
===<tt>Game1.player.friendships</tt>===
+
===The FieldName field is obsolete...===
This field is always null in Stardew Valley 1.3. Use the new <tt>Game1.player.friendshipData</tt> field instead, which wraps the raw data with a model.
+
Sample warning: "''The 'Character.friendships' field is obsolete and should be replaced with 'friendshipData'. See https://smapi.io/buildmsg/smapi003 for details.''"
 
 
===Texture constructor arguments===
 
Many constructors which previously accepted <tt>Texture2D texture</tt> arguments now take a <tt>string textureName</tt> 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 [[Modding:SMAPI APIs#Reflection|reflection]]), but don't change the texture name to avoid multiplayer sync issues.
 
 
 
===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:
 
 
 
* "''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.''"<br />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 [https://msdn.microsoft.com/en-us/library/ms185328.aspx change your platform target] to x86.
 
 
 
* "''This implicitly converts '{0}' from {1} to {2}, but {1} has unintuitive implicit conversion rules. Consider comparing against the actual value instead to avoid bugs. See https://smapi.io/buildmsg/smapi001 for details.''"<br />See [[#Net types]].
 
 
 
* "'''{0}' is a {1} field; consider using the {2} property instead. See https://smapi.io/buildmsg/smapi002 for details.''"<br />See [[#Net types]].
 
  
* "''The '{0}' field is obsolete and should be replaced with '{1}'. See https://smapi.io/buildmsg/smapi003 for details.''"<br />You're referencing a field which should no longer be used. Just use the suggested field name instead to fix it.
+
You're referencing a field which should no longer be used. Use the suggested field name instead to fix it.
  
 
[[Category:Modding]]
 
[[Category:Modding]]

Revision as of 03:45, 20 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

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.

That should take care of compatibility in single-player mode. The game will automatically synchronise most world changes to other players, but you might need further changes to work in multiplayer mode. Questions to consider: will your mod cause any problems if two players both have it installed? Do you have any custom objects/buildings/etc that might get synchronised to other players, and will that synchronisation work correctly? What if they have different configuration? Maybe it should only work for the main player? You can use SMAPI's Context.IsSinglePlayer and Context.IsMainPlayer flags in your logic to avoid conflicts.

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

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.

Game1.player.friendships

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

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.

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 {1} to {2}, but {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 {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/smapi003 for details."

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