Changes

wikify
Line 1: Line 1: −
<pre>
+
← [[Modding:Index|Index]]
---
  −
layout: default
  −
title: Updating a SMAPI mod
  −
intro: >
  −
  In rare cases, SMAPI needs to change the interfaces it exposes to mods. (This
  −
  doesn't happen often, because SMAPI strives to expose abstract interfaces that
  −
  aren't tightly coupled to changes in the game.) When an interface does need to
  −
  change, the old interface is
  −
  <a href="https://en.wikipedia.org/wiki/Deprecation">deprecated</a> and supported
  −
  long enough to let mods update at their own pace.
  −
permalink: /for-devs/updating-a-smapi-mod
  −
redirect_from:
  −
    - /guides/updating-a-smapi-mod
  −
---
     −
## How to update your mod
+
In rare cases, SMAPI needs to change the interfaces it exposes to mods. (This doesn't happen often, because SMAPI strives to expose abstract interfaces that aren't tightly coupled to changes in the game.) When an interface does need to change, the old interface is [[wikipedia:Deprecation|deprecated]] and supported long enough to let mods update at their own pace.
 +
 
 +
==How to update your mod==
 
You don't need to comb through your code; SMAPI can tell you if you're using a deprecated interface:
 
You don't need to comb through your code; SMAPI can tell you if you're using a deprecated interface:
   −
1. Use the latest [SMAPI for developers](https://github.com/Pathoschild/SMAPI/releases) download.
+
# Use the latest [https://github.com/Pathoschild/SMAPI/releases SMAPI for developers] download. This will show all deprecation messages in the console:<br />[[File:Modding - updating deprecated SMAPI code - deprecation warnings.png]]
  This will show all deprecation messages in the console:
+
# 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]]
 +
# Optionally, you can refer to the following sections on how to replace specific interfaces.
   −
  > ![console message for a deprecated interface](images/updating-a-smapi-mod/deprecated-console.png)
+
==How deprecated interfaces are phased out==
 +
Deprecated interfaces are fully supported until their removal. They'll slowly move through these phases:
   −
2. When you look at the code, you'll see a deprecation warning with a hint of how to fix it:
+
{| class="wikitable"
 
+
|-
  > ![intellisense for an obsolete property](images/updating-a-smapi-mod/deprecated-intellisense.png)
+
! severity !! description
 
+
|-
3. Optionally, you can refer to the following sections on how to replace specific interfaces.
+
| ''notice'' || The interface is deprecated, but mod authors have time to update their mods. Nothing is reported to the console, though deprecation messages are shown in the log file.
 
+
|-
## How deprecated interfaces are phased out
+
| ''info'' || Mods should no longer use the interface. Debug-level deprecation messages are shown in the console.
Deprecated interfaces are fully supported until their removal. They'll slowly move through these
+
|-
phases:
+
| ''pending removal'' || Mods should no longer use the interface. Warning-level deprecation messages in the console indicate the mod will break soon if it doesn't update.
 
+
|}
severity         | description
  −
:---------------- | :----------
  −
_notice_          | The interface is deprecated, but mod authors have time to update their mods. Nothing is reported to the console, though deprecation messages are shown in the log file.
  −
_info_            | Mods should no longer use the interface. Debug-level deprecation messages are shown in the console.
  −
_pending removal_ | Mods should no longer use the interface. Warning-level deprecation messages in the console indicate the mod will break soon if it doesn't update.
      
The interface will then be removed entirely.
 
The interface will then be removed entirely.
   −
## Deprecated interfaces
+
==Deprecated interfaces==
 
  −
### Overview
   
These are currently deprecated:
 
These are currently deprecated:
   −
since | interfaces               | severity | replacement
+
{| class="wikitable"
:----- | :------------------------ | :------- | :----------
+
|-
1.0   | `Config` class           | _info_ | see _[mod configuration](#mod-configuration)_.
+
! since
1.0   | `Mod.BaseConfigPath`      | _info_ | see _[mod configuration](#mod-configuration)_.
+
! interfaces
1.0   | `Mod.PathOnDisk`          | _info_ | see _[mod configuration](#mod-configuration)_ or use `this.Helper.DirectoryPath`.
+
! severity
1.0   | `Mod.PerSaveConfigFolder` | _info_ | use [per-save JSON files](/for-devs/creating-a-smapi-mod-advanced-config) instead.
+
! replacement
1.0   | `Mod.PerSaveConfigPath| _info_ | use [per-save JSON files](/for-devs/creating-a-smapi-mod-advanced-config) instead.
+
|-
1.0   | `Mod.Entry(object[])`    | _info_ | see _[mod entry method](#mod-entry-method)_.
+
| 1.0
1.1   | `Log` class               | _info_ | use the `this.Monitor.Log` mod method.
+
| <tt>Config</tt> class
1.6   | `PlayerEvents.FarmerChanged` | _info_ | serves no purpose.
+
| ''info''
1.6   | `PlayerEvents.LoadedGame` | _info_ | use `SaveEvents.AfterLoad`.
+
| see [[#Mod configuration|mod configuration]].
1.6   | `TimeEvents.OnNewDay`    | _info_ | unreliable and doesn't do what you think; use `TimeEvents.DayOfMonthChanged` to detect a day change, and `SaveEvents.BeforeSave` + `SaveEvents.AfterSave` to detect saves.
+
|-
1.9   | `Command` class           | _info_ | use `this.Helper.ConsoleCommands`.
+
| 1.0
1.10   | `GameEvents.Initialize` | _info_ | move any code into your `Entry` method.
+
| <tt>Mod.BaseConfigPath</tt>
1.10   | `GameEvents.LoadContent` | _info_ | move any code into your `Entry` method.
+
| ''info''
 +
| see [[#Mod configuration|mod configuration]].
 +
|-
 +
| 1.0
 +
| <tt>Mod.PathOnDisk</tt>
 +
| ''info''
 +
| see [[#Mod configuration|mod configuration]] or use <tt>this.Helper.DirectoryPath</tt>.
 +
|-
 +
| 1.0
 +
| <tt>Mod.PerSaveConfigFolder</tt>
 +
| ''info''
 +
| use [[Modding:Creating a SMAPI mod#Configuration|per-save JSON files]] instead.
 +
|-
 +
| 1.0
 +
| <tt>Mod.PerSaveConfigPath</tt>
 +
| ''info''
 +
| use [[Modding:Creating a SMAPI mod#Configuration|per-save JSON files]] instead.
 +
|-
 +
| 1.0
 +
| <tt>Mod.Entry(object[])</tt>
 +
| ''info''
 +
| see [[#Mod entry method|mod entry method]].
 +
|-
 +
| 1.1
 +
| <tt>Log</tt> class
 +
| ''info''
 +
| use the <tt>this.Monitor.Log</tt> mod method.
 +
|-
 +
| 1.6
 +
| <tt>PlayerEvents.FarmerChanged</tt>
 +
| ''info''
 +
| serves no purpose.
 +
|-
 +
| 1.6
 +
| <tt>PlayerEvents.LoadedGame</tt>
 +
| ''info''
 +
| use <tt>SaveEvents.AfterLoad</tt>.
 +
|-
 +
| 1.6
 +
| <tt>TimeEvents.OnNewDay</tt>
 +
| ''info''
 +
| unreliable and doesn't do what you think; use <tt>TimeEvents.DayOfMonthChanged</tt> to detect a day change, and <tt>SaveEvents.BeforeSave</tt> + <tt>SaveEvents.AfterSave</tt> to detect saves.
 +
|-
 +
| 1.9
 +
| <tt>Command</tt> class
 +
| ''info''
 +
| use <tt>this.Helper.ConsoleCommands</tt>.
 +
|-
 +
| 1.10
 +
| <tt>GameEvents.Initialize</tt>
 +
| ''info''
 +
| move any code into your <tt>Entry</tt> method.
 +
|-
 +
| 1.10
 +
| <tt>GameEvents.LoadContent</tt>
 +
| ''info''
 +
| move any code into your <tt>Entry</tt> method.
 +
|}
    
These have been removed:
 
These have been removed:
   −
deprecated | removed | interfaces | replacement
+
{| class="wikitable"
:--------- | :------ | :--------- | :----------
+
|-
0.39.3     | 1.9¹   | `SObject` class | reimplement if needed.
+
! deprecated
0.39.3     | 1.9¹   | `Extensions.ToSingular(…)` | use `string.Join`.
+
! removed
1.0       | 1.9¹   | `Authour` in `manifest.json` | use `Author`.
+
! interfaces
1.0       | 1.9¹   | `Extensions` class | reimplement if needed, or use an extensions library.
+
! replacement
1.0       | 1.9¹   | `LogWriter` class | use `this.Monitor.Log`.
+
|-
1.0       | 1.9¹   | `SPlayer` class | use `Game1.player`.
+
| 0.39.3
1.1       | 1.9¹   | `Command.CallCommand(string)` | use `this.Helper.ConsoleCommands`.
+
| 1.9¹
1.1       | 1.9¹   | `Mod.Entry(ModHelper)` | change `ModHelper` to `IModHelper`.
+
| <tt>SObject</tt> class
1.5       | 1.9¹   | `Version` class | use `SemanticVersion`.
+
| reimplement if needed.
1.5       | 1.9¹   | `Mod.Manifest` | use `Mod.ModManifest` <small>(changes type from `Manifest` to `IManifest`)</small>.
+
|-
1.5       | 1.9¹   | `Constants.Version` | use `Constants.ApiVersion` <small>(changes type from `Version` to `ISemanticVersion`)</small>.
+
| 0.39.3
1.0<br /><small><em>experimental API</em></small> | 1.9¹ | `IConfigFile` and `ConfigFile` | reimplement if needed.
+
| 1.9¹
 +
| <tt>Extensions.ToSingular(…)</tt>
 +
| use <tt>string.Join</tt>.
 +
|-
 +
| 1.0
 +
| 1.9¹
 +
| <tt>Authour</tt> in <tt>manifest.json</tt>
 +
| use <tt>Author</tt>.
 +
|-
 +
| 1.0
 +
| 1.9¹
 +
| <tt>Extensions</tt> class
 +
| reimplement if needed, or use an extensions library.
 +
|-
 +
| 1.0
 +
| 1.9¹
 +
| <tt>LogWriter</tt> class
 +
| use <tt>this.Monitor.Log</tt>.
 +
|-
 +
| 1.0
 +
| 1.9¹
 +
| <tt>SPlayer</tt> class
 +
| use <tt>Game1.player</tt>.
 +
|-
 +
| 1.1
 +
| 1.9¹
 +
| <tt>Command.CallCommand(string)</tt>
 +
| use <tt>this.Helper.ConsoleCommands</tt>.
 +
|-
 +
| 1.1
 +
| 1.9¹
 +
| <tt>Mod.Entry(ModHelper)</tt>
 +
| change <tt>ModHelper</tt> to <tt>IModHelper</tt>.
 +
|-
 +
| 1.5
 +
| 1.9¹
 +
| <tt>Version</tt> class
 +
| use <tt>SemanticVersion</tt>.
 +
|-
 +
| 1.5
 +
| 1.9¹
 +
| <tt>Mod.Manifest</tt>
 +
| use <tt>Mod.ModManifest</tt> <small>(changes type from <tt>Manifest</tt> to <tt>IManifest</tt>)</small>.
 +
|-
 +
| 1.5
 +
| 1.9¹
 +
| <tt>Constants.Version</tt>
 +
| use <tt>Constants.ApiVersion</tt> <small>(changes type from <tt>Version</tt> to <tt>ISemanticVersion</tt>)</small>.
 +
|-
 +
| 1.0<br /><small><em>experimental API</em></small>
 +
| 1.9¹
 +
| <tt>IConfigFile</tt> and <tt>ConfigFile</tt>
 +
| reimplement if needed.
 +
|}
    
<small>¹ Stardew Valley 1.2 broke many existing mods, so SMAPI 1.9 used the opportunity to remove the most rarely-used deprecated APIs.</small>
 
<small>¹ Stardew Valley 1.2 broke many existing mods, so SMAPI 1.9 used the opportunity to remove the most rarely-used deprecated APIs.</small>
   −
### Migration guides
+
==Migration guides==
 
This section provides more information for some migrations mentioned in the previous section.
 
This section provides more information for some migrations mentioned in the previous section.
   −
#### Mod entry method
+
===Mod entry method===
_For the latest documentation, see [creating a SMAPI mod: writing your mod code](/for-devs/creating-a-smapi-mod#writing-your-mod-code)._
+
''For the latest documentation, see [[Modding:Creating a SMAPI mod#Writing your mod code]].''
    
Change your mod's entry class from this:
 
Change your mod's entry class from this:
   −
```c#
+
<source lang="c#">
 
/// <summary>Initialise the mod.</summary>
 
/// <summary>Initialise the mod.</summary>
 
public override void Entry(params object[] objects)
 
public override void Entry(params object[] objects)
Line 95: Line 188:  
     // your code
 
     // your code
 
}
 
}
```
+
</source>
    
to this:
 
to this:
   −
```c#
+
<source lang="c#">
/// <summary>Initialise the mod.</summary>
+
/// <summary>The mod entry point, called after the mod is first loaded.</summary>
/// <param name="helper">Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files.</param>
+
/// <param name="helper">Provides simplified APIs for writing mods.</param>
 
public override void Entry(IModHelper helper)
 
public override void Entry(IModHelper helper)
 
{
 
{
 
     // your code
 
     // your code
 
}
 
}
```
+
</source>
   −
#### Mod configuration
+
===Mod configuration===
_For the latest documentation, see [creating a SMAPI mod: configuration](/for-devs/creating-a-smapi-mod#configuration)._
+
''For the latest documentation, see [[Modding:Creating a SMAPI mod#Configuration]].''
   −
If you use `config.json`, it's much easier in 1.0.
+
If you use <tt>config.json</tt>, it's much easier in 1.0.
   −
1. Find your subclass of `StardewModdingAPI.Config`, which probably looks something like this:
+
<ol>
 +
<li>Find your subclass of <tt>StardewModdingAPI.Config</tt>, which probably looks something like this:
   −
  ```c#
+
<source lang="c#">
  class SampleConfig : StardewModdingAPI.Config
+
class SampleConfig : StardewModdingAPI.Config
 +
{
 +
  public bool ExampleBoolean { get; set; }
 +
  public float ExampleFloat { get; set; }
 +
 
 +
  public override T GenerateDefaultConfig<T>()
 
   {
 
   {
       public bool ExampleBoolean { get; set; }
+
       this.ExampleBoolean = true;
       public float ExampleFloat { get; set; }
+
       this.ExampleFloat = 0.5;
 +
      return this as T;
 +
  }
 +
}
 +
</source></li>
   −
      public override T GenerateDefaultConfig<T>()
+
<li>Edit this class as follows:
      {
+
* Move default values into the constructor or property setters.
        this.ExampleBoolean = true;
+
* Remove <tt>StardewModdingAPI.Config</tt>.
        this.ExampleFloat = 0.5;
+
* Remove all <tt>override</tt> methods.
        return this as T;
+
</li>
      }
  −
  }
  −
  ```
     −
2. Edit this class as follows:
+
<li>Your class should now look something like this:
  * Move default values into the constructor or property setters.
  −
  * Remove `StardewModdingAPI.Config`.
  −
  * Remove all `override` methods.
     −
3. Your class should now look something like this:
+
<source lang="c#">
 +
class SampleConfig
 +
{
 +
  public bool ExampleBoolean { get; set; } = true;
 +
  public float ExampleFloat { get; set; } = 0.5;
 +
}
 +
</source>
   −
  ```c#
+
or like this if you used a constructor:
  class SampleConfig
  −
  {
  −
      public bool ExampleBoolean { get; set; } = true;
  −
      public float ExampleFloat { get; set; } = 0.5;
  −
  }
  −
  ```
     −
   or like this if you used a constructor:
+
<source lang="c#">
 +
class SampleConfig
 +
{
 +
   public bool ExampleBoolean { get; set; }
 +
  public float ExampleFloat { get; set; }
   −
   ```c#
+
   public SampleConfig()
  class SampleConfig
   
   {
 
   {
       public bool ExampleBoolean { get; set; }
+
       this.ExampleBoolean = true;
       public float ExampleFloat { get; set; }
+
       this.ExampleFloat = 0.5;
 +
  }
 +
}
 +
</source></li>
   −
      public SampleConfig()
+
<li>In your <tt>Mod</tt> class, change anything that looks like this:
      {
  −
        this.ExampleBoolean = true;
  −
        this.ExampleFloat = 0.5;
  −
      }
  −
  }
  −
  ```
  −
4. In your `Mod` class, change anything that looks like this:
     −
  ```
+
<source lang="c#">
  var config = new SampleConfig().InitializeConfig(this.BaseConfigPath);
+
var config = new SampleConfig().InitializeConfig(this.BaseConfigPath);
  ```
+
</source>
   −
  to this:
+
to this:
   −
  ```
+
<source lang="c#">
  var config = helper.ReadConfig<SampleConfig>();
+
var config = helper.ReadConfig<SampleConfig>();
  ```
+
</source></li>
   −
5. If you use other methods, here's how to migrate them:
+
<li>If you use other methods, here's how to migrate them:
   −
  before 1.0 | after 1.0
+
{| class="wikitable"
  :--------- | :--------
+
|-
  `new SampleConfig().GenerateDefaultConfig()`<br />`new SampleConfig().Instance()` | `new SampleConfig()`
+
! before 1.0
  `new SampleConfig().InitializeConfig(this.BaseConfigPath)`<br />`config.UpdateConfig()`<br />`config.LoadConfig(this.BaseConfigPath)`<br />`config.ReloadConfig()` | `helper.ReadConfig<SampleConfig>()`
+
! after 1.0
  `config.WriteConfig()| `helper.WriteConfig(config)`
+
|-
 +
| <tt>new SampleConfig().GenerateDefaultConfig()</tt><br /><tt>new SampleConfig().Instance()</tt>
 +
| <tt>new SampleConfig()</tt>
 +
|-
 +
| <tt>new SampleConfig().InitializeConfig(this.BaseConfigPath)</tt><br /><tt>config.UpdateConfig()</tt><br /><tt>config.LoadConfig(this.BaseConfigPath)</tt><br /><tt>config.ReloadConfig()</tt>
 +
| <tt>helper.ReadConfig<SampleConfig>()</tt>
 +
|-
 +
| <tt>config.WriteConfig()</tt>
 +
| <tt>helper.WriteConfig(config)</tt>
 +
|}
 +
</li>
 +
</ol>
   −
For more information, see [creating a SMAPI mod: configuration](/for-devs/creating-a-smapi-mod#configuration).
+
For more information, see [[Modding:Creating a SMAPI mod#Configuration]].
For help with more advanced configuration (including custom JSON files and per-save configuration),
  −
see [advanced SMAPI mod configuration](/for-devs/creating-a-smapi-mod-advanced-config).
  −
</pre>
      
[[Category:Modding]]
 
[[Category:Modding]]
translators
8,437

edits