Changes

m
Text replacement - "tt>" to "samp>"
Line 1: Line 1:  
←[[Modding:Index|Index]]
 
←[[Modding:Index|Index]]
   −
'''This page is for modders. Players: see [[Modding:Mod compatibility]] instead.'''
+
{{Modder compatibility header}}
 
   
This page explains how to update your SMAPI mod code for compatibility with SMAPI 1.9 (released alongside Stardew Valley 1.2 in April 2017) and 2.0 (released in October 2017).
 
This page explains how to update your SMAPI mod code for compatibility with SMAPI 1.9 (released alongside Stardew Valley 1.2 in April 2017) and 2.0 (released in October 2017).
   Line 9: Line 8:  
[[File:SMAPI compatibility.png|thumb|SMAPI compatibility over time. The SMAPI 2.0 release in October 2017 appears as a small bump.]]
 
[[File:SMAPI compatibility.png|thumb|SMAPI compatibility over time. The SMAPI 2.0 release in October 2017 appears as a small bump.]]
   −
The last major breaking change was in SMAPI 0.40 (April 2016). Since then 23 SMAPI releases were published with almost full backwards compatibility. SMAPI has matured significantly since version 0.40, and its APIs have converged towards better consistency. Older APIs have been [[wikipedia:Deprecation|deprecated]] with full support, but this introduces significant maintenance overhead. A few rarely-used APIs were dropped in SMAPI 1.9 (when Stardew Valley 1.2 broke many mods),and SMAPI 2.0 is the release which finally drops support for these old APIs.
+
The last major breaking change was in SMAPI 0.40 (April 2016). Since then 23 SMAPI releases were published with almost full backwards compatibility. SMAPI has matured significantly since version 0.40, and its APIs have converged towards better consistency. Older APIs have been [[wikipedia:Deprecation|deprecated]] with full support, but this introduces significant maintenance overhead. A few rarely-used APIs were dropped in SMAPI 1.9 (when Stardew Valley 1.2 broke many mods), and SMAPI 2.0 is the release which finally drops support for these old APIs.
    
Although this is a major change, significant effort was undertaken to minimise the impact on mods: (a) the APIs were supported for a long time with increasingly prominent warnings in the SMAPI console about their deprecation and removal; (b) dozens of pull requests were submitted to update affected mods; (c) unofficial updates were created for mods which haven't updated officially yet; and (d) the changes were actively communicated and documented to modders. This means that SMAPI 2.0 has a minimal impact on mod compatibility (see chart on the right).
 
Although this is a major change, significant effort was undertaken to minimise the impact on mods: (a) the APIs were supported for a long time with increasingly prominent warnings in the SMAPI console about their deprecation and removal; (b) dozens of pull requests were submitted to update affected mods; (c) unofficial updates were created for mods which haven't updated officially yet; and (d) the changes were actively communicated and documented to modders. This means that SMAPI 2.0 has a minimal impact on mod compatibility (see chart on the right).
Line 33: Line 32:  
| 0.39.3
 
| 0.39.3
 
| 1.9¹
 
| 1.9¹
| <tt>SObject</tt> class
+
| <samp>SObject</samp> class
 
| reimplement if needed.
 
| reimplement if needed.
 
|-
 
|-
 
| 0.39.3
 
| 0.39.3
 
| 1.9¹
 
| 1.9¹
| <tt>Extensions.ToSingular(…)</tt>
+
| <samp>Extensions.ToSingular(…)</samp>
| use <tt>string.Join</tt>.
+
| use <samp>string.Join</samp>.
 
|-
 
|-
 
| 1.0
 
| 1.0
 
| 1.9¹
 
| 1.9¹
| <tt>Authour</tt> in <tt>manifest.json</tt>
+
| <samp>Authour</samp> in <samp>manifest.json</samp>
| use <tt>Author</tt>.
+
| use <samp>Author</samp>.
 
|-
 
|-
 
| 1.0
 
| 1.0
 
| 1.9¹
 
| 1.9¹
| <tt>Extensions</tt> class
+
| <samp>Extensions</samp> class
 
| reimplement if needed, or use an extensions library.
 
| reimplement if needed, or use an extensions library.
 
|-
 
|-
 
| 1.0
 
| 1.0
 
| 1.9¹
 
| 1.9¹
| <tt>LogWriter</tt> class
+
| <samp>LogWriter</samp> class
| use <tt>this.Monitor.Log</tt>.
+
| use <samp>this.Monitor.Log</samp>.
 
|-
 
|-
 
| 1.0
 
| 1.0
 
| 1.9¹
 
| 1.9¹
| <tt>SPlayer</tt> class
+
| <samp>SPlayer</samp> class
| use <tt>Game1.player</tt>.
+
| use <samp>Game1.player</samp>.
 
|-
 
|-
 
| 1.0<br /><small><em>experimental API</em></small>
 
| 1.0<br /><small><em>experimental API</em></small>
 
| 1.9¹
 
| 1.9¹
| <tt>IConfigFile</tt> and <tt>ConfigFile</tt>
+
| <samp>IConfigFile</samp> and <samp>ConfigFile</samp>
 
| reimplement if needed.
 
| reimplement if needed.
 
|-
 
|-
 
| 1.1
 
| 1.1
 
| 1.9¹
 
| 1.9¹
| <tt>Command.CallCommand(string)</tt>
+
| <samp>Command.CallCommand(string)</samp>
| use <tt>this.Helper.ConsoleCommands</tt>.
+
| use <samp>this.Helper.ConsoleCommands</samp>.
 
|-
 
|-
 
| 1.1
 
| 1.1
 
| 1.9¹
 
| 1.9¹
| <tt>Mod.Entry(ModHelper)</tt>
+
| <samp>Mod.Entry(ModHelper)</samp>
| change <tt>ModHelper</tt> to <tt>IModHelper</tt>.
+
| change <samp>ModHelper</samp> to <samp>IModHelper</samp>.
 
|-
 
|-
 
| 1.5
 
| 1.5
 
| 1.9¹
 
| 1.9¹
| <tt>Version</tt> class
+
| <samp>Version</samp> class
| use <tt>SemanticVersion</tt>.
+
| use <samp>SemanticVersion</samp>.
 
|-
 
|-
 
| 1.5
 
| 1.5
 
| 1.9¹
 
| 1.9¹
| <tt>Mod.Manifest</tt>
+
| <samp>Mod.Manifest</samp>
| use <tt>Mod.ModManifest</tt> <small>(changes type from <tt>Manifest</tt> to <tt>IManifest</tt>)</small>.
+
| use <samp>Mod.ModManifest</samp> <small>(changes type from <samp>Manifest</samp> to <samp>IManifest</samp>)</small>.
 
|-
 
|-
 
| 1.5
 
| 1.5
 
| 1.9¹
 
| 1.9¹
| <tt>Constants.Version</tt>
+
| <samp>Constants.Version</samp>
| use <tt>Constants.ApiVersion</tt> <small>(changes type from <tt>Version</tt> to <tt>ISemanticVersion</tt>)</small>.
+
| use <samp>Constants.ApiVersion</samp> <small>(changes type from <samp>Version</samp> to <samp>ISemanticVersion</samp>)</small>.
 
|-
 
|-
 
| 1.0
 
| 1.0
 
| 2.0
 
| 2.0
| <tt>Config</tt> class
+
| <samp>Config</samp> class
 
| see [[#Mod configuration|mod configuration]].
 
| see [[#Mod configuration|mod configuration]].
 
|-
 
|-
 
| 1.0
 
| 1.0
 
| 2.0
 
| 2.0
| <tt>Mod.BaseConfigPath</tt>
+
| <samp>Mod.BaseConfigPath</samp>
 
| see [[#Mod configuration|mod configuration]].
 
| see [[#Mod configuration|mod configuration]].
 
|-
 
|-
 
| 1.0
 
| 1.0
 
| 2.0
 
| 2.0
| <tt>Mod.PathOnDisk</tt>
+
| <samp>Mod.PathOnDisk</samp>
| see [[#Mod configuration|mod configuration]] or use <tt>this.Helper.DirectoryPath</tt>.
+
| see [[#Mod configuration|mod configuration]] or use <samp>this.Helper.DirectoryPath</samp>.
 
|-
 
|-
 
| 1.0
 
| 1.0
 
| 2.0
 
| 2.0
| <tt>Mod.PerSaveConfigFolder</tt>
+
| <samp>Mod.PerSaveConfigFolder</samp>
 
| use [[Modding:Modder Guide/APIs/Config|per-save JSON files]] instead.
 
| use [[Modding:Modder Guide/APIs/Config|per-save JSON files]] instead.
 
|-
 
|-
 
| 1.0
 
| 1.0
 
| 2.0
 
| 2.0
| <tt>Mod.PerSaveConfigPath</tt>
+
| <samp>Mod.PerSaveConfigPath</samp>
 
| use [[Modding:Modder Guide/APIs/Config|per-save JSON files]] instead.
 
| use [[Modding:Modder Guide/APIs/Config|per-save JSON files]] instead.
 
|-
 
|-
 
| 1.0
 
| 1.0
 
| 2.0
 
| 2.0
| <tt>Mod.Entry(object[])</tt>
+
| <samp>Mod.Entry(object[])</samp>
 
| see [[#Mod entry method|mod entry method]].
 
| see [[#Mod entry method|mod entry method]].
 
|-
 
|-
 
| 1.1
 
| 1.1
 
| 2.0
 
| 2.0
| <tt>Log</tt> class
+
| <samp>Log</samp> class
| use the <tt>this.Monitor.Log</tt> mod method.
+
| use the <samp>this.Monitor.Log</samp> mod method.
 
|-
 
|-
 
| 1.6
 
| 1.6
 
| 2.0
 
| 2.0
| <tt>PlayerEvents.FarmerChanged</tt>
+
| <samp>PlayerEvents.FarmerChanged</samp>
 
| serves no purpose.
 
| serves no purpose.
 
|-
 
|-
 
| 1.6
 
| 1.6
 
| 2.0
 
| 2.0
| <tt>PlayerEvents.LoadedGame</tt>
+
| <samp>PlayerEvents.LoadedGame</samp>
| use <tt>SaveEvents.AfterLoad</tt>.
+
| use <samp>SaveEvents.AfterLoad</samp>.
 
|-
 
|-
 
| 1.6
 
| 1.6
 
| 2.0
 
| 2.0
| <tt>TimeEvents.OnNewDay</tt>
+
| <samp>TimeEvents.OnNewDay</samp>
| unreliable and don't do what you think; use <tt>TimeEvents.AfterDayChanged</tt> or <tt>SaveEvents.BeforeSave</tt> instead.
+
| unreliable and don't do what you think; use <samp>TimeEvents.AfterDayChanged</samp> or <samp>SaveEvents.BeforeSave</samp> instead.
 
|-
 
|-
 
| 1.9
 
| 1.9
 
| 2.0
 
| 2.0
| <tt>Command</tt> class
+
| <samp>Command</samp> class
| use <tt>this.Helper.ConsoleCommands</tt>.
+
| use <samp>this.Helper.ConsoleCommands</samp>.
 
|-
 
|-
 
| 1.10
 
| 1.10
 
| 2.0
 
| 2.0
| <tt>GameEvents.Initialize</tt><br /><tt>GameEvents.LoadContent</tt>
+
| <samp>GameEvents.Initialize</samp><br /><samp>GameEvents.LoadContent</samp>
| move any code into your <tt>Entry</tt> method.
+
| move any code into your <samp>Entry</samp> method.
 
|-
 
|-
 
| 1.13
 
| 1.13
 
| 2.0
 
| 2.0
| <tt>GameEvents.GameLoaded</tt>
+
| <samp>GameEvents.GameLoaded</samp>
| move any code into your <tt>Entry</tt> method.
+
| move any code into your <samp>Entry</samp> method.
 
|-
 
|-
 
| 1.14
 
| 1.14
 
| 2.0
 
| 2.0
| <tt>TimeEvents.DayOfMonthChanged</tt><br /><tt>TimeEvents.SeasonOfYearChanged</tt><br /><tt>TimeEvents.YearOfGameChanged</tt>
+
| <samp>TimeEvents.DayOfMonthChanged</samp><br /><samp>TimeEvents.SeasonOfYearChanged</samp><br /><samp>TimeEvents.YearOfGameChanged</samp>
| unreliable and don't do what you think; use <tt>TimeEvents.AfterDayChanged</tt> or <tt>SaveEvents.BeforeSave</tt> instead.
+
| unreliable and don't do what you think; use <samp>TimeEvents.AfterDayChanged</samp> or <samp>SaveEvents.BeforeSave</samp> instead.
 
|}
 
|}
   Line 169: Line 168:  
Change your mod's entry class from this:
 
Change your mod's entry class from this:
   −
<source lang="c#">
+
<syntaxhighlight 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 175: Line 174:  
     // your code
 
     // your code
 
}
 
}
</source>
+
</syntaxhighlight>
    
to this:
 
to this:
   −
<source lang="c#">
+
<syntaxhighlight lang="c#">
 
/// <summary>The mod entry point, called after the mod is first loaded.</summary>
 
/// <summary>The mod entry point, called after the mod is first loaded.</summary>
 
/// <param name="helper">Provides simplified APIs for writing mods.</param>
 
/// <param name="helper">Provides simplified APIs for writing mods.</param>
Line 186: Line 185:  
     // your code
 
     // your code
 
}
 
}
</source>
+
</syntaxhighlight>
    
===Mod configuration===
 
===Mod configuration===
 
''For the latest documentation, see [[Modding:Modder Guide/APIs/Config]].''
 
''For the latest documentation, see [[Modding:Modder Guide/APIs/Config]].''
   −
If you use <tt>config.json</tt>, it's much easier in 1.0.
+
If you use <samp>config.json</samp>, it's much easier in 1.0.
    
<ol>
 
<ol>
<li>Find your subclass of <tt>StardewModdingAPI.Config</tt>, which probably looks something like this:
+
<li>Find your subclass of <samp>StardewModdingAPI.Config</samp>, which probably looks something like this:
   −
<source lang="c#">
+
<syntaxhighlight lang="c#">
 
class SampleConfig : StardewModdingAPI.Config
 
class SampleConfig : StardewModdingAPI.Config
 
{
 
{
Line 209: Line 208:  
   }
 
   }
 
}
 
}
</source></li>
+
</syntaxhighlight></li>
    
<li>Edit this class as follows:
 
<li>Edit this class as follows:
 
* Move default values into the constructor or property setters.
 
* Move default values into the constructor or property setters.
* Remove <tt>StardewModdingAPI.Config</tt>.
+
* Remove <samp>StardewModdingAPI.Config</samp>.
* Remove all <tt>override</tt> methods.
+
* Remove all <samp>override</samp> methods.
 
</li>
 
</li>
    
<li>Your class should now look something like this:
 
<li>Your class should now look something like this:
   −
<source lang="c#">
+
<syntaxhighlight lang="c#">
 
class SampleConfig
 
class SampleConfig
 
{
 
{
Line 225: Line 224:  
   public float ExampleFloat { get; set; } = 0.5;
 
   public float ExampleFloat { get; set; } = 0.5;
 
}
 
}
</source>
+
</syntaxhighlight>
    
or like this if you used a constructor:
 
or like this if you used a constructor:
   −
<source lang="c#">
+
<syntaxhighlight lang="c#">
 
class SampleConfig
 
class SampleConfig
 
{
 
{
Line 241: Line 240:  
   }
 
   }
 
}
 
}
</source></li>
+
</syntaxhighlight></li>
   −
<li>In your <tt>Mod</tt> class, change anything that looks like this:
+
<li>In your <samp>Mod</samp> class, change anything that looks like this:
   −
<source lang="c#">
+
<syntaxhighlight lang="c#">
 
var config = new SampleConfig().InitializeConfig(this.BaseConfigPath);
 
var config = new SampleConfig().InitializeConfig(this.BaseConfigPath);
</source>
+
</syntaxhighlight>
    
to this:
 
to this:
   −
<source lang="c#">
+
<syntaxhighlight lang="c#">
 
var config = helper.ReadConfig<SampleConfig>();
 
var config = helper.ReadConfig<SampleConfig>();
</source></li>
+
</syntaxhighlight></li>
    
<li>If you use other methods, here's how to migrate them:
 
<li>If you use other methods, here's how to migrate them:
Line 262: Line 261:  
! after 1.0
 
! after 1.0
 
|-
 
|-
| <tt>new SampleConfig().GenerateDefaultConfig()</tt><br /><tt>new SampleConfig().Instance()</tt>
+
| <samp>new SampleConfig().GenerateDefaultConfig()</samp><br /><samp>new SampleConfig().Instance()</samp>
| <tt>new SampleConfig()</tt>
+
| <samp>new SampleConfig()</samp>
 
|-
 
|-
| <tt>new SampleConfig().InitializeConfig(this.BaseConfigPath)</tt><br /><tt>config.UpdateConfig()</tt><br /><tt>config.LoadConfig(this.BaseConfigPath)</tt><br /><tt>config.ReloadConfig()</tt>
+
| <samp>new SampleConfig().InitializeConfig(this.BaseConfigPath)</samp><br /><samp>config.UpdateConfig()</samp><br /><samp>config.LoadConfig(this.BaseConfigPath)</samp><br /><samp>config.ReloadConfig()</samp>
| <tt>helper.ReadConfig<SampleConfig>()</tt>
+
| <samp>helper.ReadConfig<SampleConfig>()</samp>
 
|-
 
|-
| <tt>config.WriteConfig()</tt>
+
| <samp>config.WriteConfig()</samp>
| <tt>helper.WriteConfig(config)</tt>
+
| <samp>helper.WriteConfig(config)</samp>
 
|}
 
|}
 
</li>
 
</li>
105,853

edits