Changes

m
Line 2: Line 2:     
{{Modder compatibility header}}
 
{{Modder compatibility header}}
{{SMAPI upcoming|4.0.0}}
     −
This page explains how to update your mod code for compatibility with SMAPI 4.0.0. See also [[Modding:Migrate to Stardew Valley 1.6|''Migrate to Stardew Valley 1.6'']].
+
This page explains how to update your C# mod code for compatibility with SMAPI 4.0.0. (Content packs aren't affected.) You can update mods now, there's no need to wait for the 4.0 release itself.
    
==Overview==
 
==Overview==
Line 10: Line 9:  
[[File:SMAPI compatibility.png|thumb|SMAPI compatibility over time. The SMAPI 2.0 release appears as a small bump in October 2017, and SMAPI 3.0 was released alongside Stardew Valley 1.4.]]
 
[[File:SMAPI compatibility.png|thumb|SMAPI compatibility over time. The SMAPI 2.0 release appears as a small bump in October 2017, and SMAPI 3.0 was released alongside Stardew Valley 1.4.]]
   −
The [[Modding:Modder Guide/APIs/Content|content interception API]] (''i.e.'' <samp>IAssetLoader</samp> and <samp>IAssetEditor</samp>) was introduced five years ago in [https://github.com/Pathoschild/SMAPI/blob/develop/docs/release-notes-archived.md#20 SMAPI 2.0.0]. Since then it's become one of the most important parts of SMAPI; for example, it's the basis for Content Patcher which is now the backbone for 39.7% of all mods. However, the API has remained essentially unchanged since its introduction and it doesn't account for all the use cases that apply today.
+
The [[Modding:Modder Guide/APIs/Content|content interception API]] (''i.e.'' <samp>IAssetLoader</samp> and <samp>IAssetEditor</samp>) was introduced five years ago in [https://github.com/Pathoschild/SMAPI/blob/develop/docs/release-notes-archived.md#20 SMAPI 2.0.0]. Since then it's become one of the most important parts of SMAPI; for example, it's the basis for Content Patcher which is now the backbone for 41.1% of all mods. However, the API has remained essentially unchanged since its introduction and it doesn't account for all the use cases that apply today.
    
SMAPI 4.0.0 is the release that fixes that. This completely redesigns the content API:
 
SMAPI 4.0.0 is the release that fixes that. This completely redesigns the content API:
Line 31: Line 30:     
===How to update your mod===
 
===How to update your mod===
You don't need to comb through your code manually. SMAPI can tell you if you're using a deprecated interface:
+
You don't need to comb through your code manually. SMAPI can tell you if you're using a deprecated API:
   −
# Use the latest [https://smapi.io/ SMAPI for developers] download. This will show deprecation messages in the console:<br />[[File:Modding - updating deprecated SMAPI code - deprecation warnings.png]]
+
# SMAPI will show deprecation messages in the console window (the exact format changes depending on the deprecation level, but you can just search for your mod name):<br />[[File:Modding - updating deprecated SMAPI code - deprecation warnings.png]]
# When you look at the code, you'll see a deprecation warning with a hint of how to fix it:<br />[[File:Modding - updating deprecated SMAPI code - deprecation intellisense.png]]
+
# When you look at the code in Visual Studio, you'll see build warnings with hints on how to fix them:<br />[[File:Modding - updating deprecated SMAPI code - deprecation intellisense.png]]
# You can refer to the following sections on how to replace specific interfaces.
+
# You can refer to the following sections on how to replace specific APIs.
   −
==Changes==
+
==Breaking changes==
 
===Content interception API===
 
===Content interception API===
 
The <samp>IAssetLoader</samp> and <samp>IAssetEditor</samp> interfaces no longer exist. Both have been replaced by the [[Modding:Modder Guide/APIs/Events#Content.AssetRequested|<samp>AssetRequested</samp> event]], which is used like this:
 
The <samp>IAssetLoader</samp> and <samp>IAssetEditor</samp> interfaces no longer exist. Both have been replaced by the [[Modding:Modder Guide/APIs/Events#Content.AssetRequested|<samp>AssetRequested</samp> event]], which is used like this:
Line 61: Line 60:  
         }
 
         }
 
     }
 
     }
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
   Line 68: Line 68:  
* When loading an asset, you must now specify an <samp>AssetLoadPriority</samp> which decides what happens if two loads apply to the same asset. <samp>AssetLoadPriority.Exclusive</samp> matches the previous behavior, but may reduce mod compatibility. See the IntelliSense documentation for more info.
 
* When loading an asset, you must now specify an <samp>AssetLoadPriority</samp> which decides what happens if two loads apply to the same asset. <samp>AssetLoadPriority.Exclusive</samp> matches the previous behavior, but may reduce mod compatibility. See the IntelliSense documentation for more info.
   −
See the [[Modding:Modder Guide/APIs/Events#Content|content event docs]] for more info on how to use them.
+
See the [[Modding:Modder Guide/APIs/Events#Content|content events]] and [[Modding:Modder Guide/APIs/Content|content API]] docs for more info on how to use them.
    
===Content loading API===
 
===Content loading API===
Line 108: Line 108:  
| <samp>helper.Content.Load</samp>
 
| <samp>helper.Content.Load</samp>
 
| Use <samp>helper.GameContent</samp> or <samp>helper.ModContent</samp>, and remove the <samp>ContentSource</samp> parameter.
 
| Use <samp>helper.GameContent</samp> or <samp>helper.ModContent</samp>, and remove the <samp>ContentSource</samp> parameter.
 +
 +
Migration notes:
 +
* When loading assets from <samp>helper.GameContent</samp>, don't add a <samp>.xnb</samp> file extension (''e.g.'' use <code>"Portraits/Abigail"</code> instead of <code>"Portraits/Abigail.xnb"</code>). You're requesting an [[Modding:Modder Guide/APIs/Content#What's an 'asset name'?|asset name]], not a file path.
 +
* When loading XNB files from <samp>helper.ModContent</samp>, ''do'' add the <samp>.xnb</samp> file extension. It's no longer added automatically if needed.
 
|-
 
|-
 
| <samp>helper.Content.NormalizeAssetName</samp>
 
| <samp>helper.Content.NormalizeAssetName</samp>
Line 142: Line 146:  
| <samp>PerScreen&lt;T&gt;(null)</samp>
 
| <samp>PerScreen&lt;T&gt;(null)</samp>
 
| Passing null into the constructor is deprecated. You should call <code>PerScreen&lt;T&gt;()</code> to use the default value.
 
| Passing null into the constructor is deprecated. You should call <code>PerScreen&lt;T&gt;()</code> to use the default value.
 +
|-
 +
| <samp>SDate.Season</samp>
 +
| <samp>SDate.Season</samp> is now the <samp>Season</samp> enum, to match the game. Use <samp>SDate.SeasonKey</samp> if you absolutely need the string form.
 
|}
 
|}
   Line 181: Line 188:  
</syntaxhighlight>
 
</syntaxhighlight>
 
|}
 
|}
 +
 +
===Removed dependencies===
 +
SMAPI 4.0.0 no longer uses these dependencies, so they won't be loaded automatically anymore. If you manually referenced one of them, either copy it into your mod's release folder or see the suggested migration below.
 +
 +
{| class="wikitable"
 +
|-
 +
! dependency
 +
! suggested migration
 +
|-
 +
| <samp>System.Configuration.ConfigurationManager.dll</samp>
 +
| Use the [[Modding:Modder Guide/APIs/Config|standard config API]] instead.
 +
|-
 +
| <samp>System.Runtime.Caching.dll</samp>
 +
| Avoid <samp>MemoryCache</samp> or <samp>ObjectCache</samp> from this DLL, which can negatively impact performance for players. If you need cache expiry, consider the faster (but still heavy) [https://docs.microsoft.com/en-us/dotnet/core/extensions/caching <samp>Microsoft.Extensions.Caching.Memory</samp>] package instead. Otherwise consider using a plain <samp>Dictionary&lt;TKey, TValue&gt;</samp> field instead.
 +
|-
 +
| <samp>System.Security.Permissions.dll</samp>
 +
| This is usually only needed for <samp>System.Configuration.ConfigurationManager.dll</samp> or <samp>System.Runtime.Caching.dll</samp>, and can probably be removed.
 +
|}
 +
 +
==Other changes==
 +
===Raw texture data===
 +
Creating <samp>Texture2D</samp> instances is expensive and involves calls to the graphics card. When you don't need a full texture, you can now load it as <samp>IRawTextureData</samp> instead, and then pass that into SMAPI APIs that accept textures.
 +
 +
For example, you no longer need to create a <samp>Texture2D</samp> instance to apply an image overlay:
 +
<syntaxhighlight lang="c#">
 +
private void OnAssetRequested(object? sender, AssetRequestedEventArgs e)
 +
{
 +
    if (e.Name.IsEquivalentTo("Portraits/Abigail"))
 +
    {
 +
        e.Edit(asset =>
 +
        {
 +
            IRawTextureData ribbon = this.Helper.ModContent.Load<IRawTextureData>("assets/ribbon.png");
 +
            asset.AsImage().PatchImage(source: ribbon);
 +
        });
 +
    }
 +
}
 +
</syntaxhighlight>
    
[[Category:Modding]]
 
[[Category:Modding]]
528

edits