Changes

Line 1: Line 1:  
←[[Modding:Index|Index]]
 
←[[Modding:Index|Index]]
   −
{{SMAPI upcoming|3.6}}
+
{{Modder compatibility header}}
   −
'''This page is for modders. Players: see [[Modding:Mod compatibility]] instead.'''
+
SMAPI 3.12 updates from Harmony 1.2.0.1 to Harmony 2.1. That only affects mods which use Harmony directly; that's [[Modding:Modder Guide/APIs/Harmony|discouraged in most cases]], isn't officially part of SMAPI's public API, and isn't subject to SMAPI's normal versioning policy. If you use Harmony in your mods, this page explains how the update affects them.
 
  −
This page explains how to update your mod code for Harmony 2.0. This only applies to mods which use Harmony directly; [[Modding:Modder Guide/APIs/Harmony|that's discouraged]] in most cases, isn't officially part of SMAPI's public API, and isn't subject to SMAPI's normal versioning policy.
      
__TOC__
 
__TOC__
 
==Overview==
 
==Overview==
 
===What's changing?===
 
===What's changing?===
[https://github.com/pardeike/Harmony/releases/tag/v2.0.0 Harmony 2.0] has many changes that benefit SMAPI and mods. Some notable changes:
+
[https://github.com/pardeike/Harmony/releases/tag/v2.0.0 Harmony 2.0] and [https://github.com/pardeike/Harmony/releases/tag/v2.1.0.0 2.1] have many changes that benefit SMAPI and mods. Some notable changes:
 
* Added [https://harmony.pardeike.net/articles/patching-finalizer.html finalizers] and [https://harmony.pardeike.net/articles/reverse-patching.html reverse patches].
 
* Added [https://harmony.pardeike.net/articles/patching-finalizer.html finalizers] and [https://harmony.pardeike.net/articles/reverse-patching.html reverse patches].
* Added <tt>CodeInstruction</tt> extensions, <tt>Manipulator</tt> utility, and other improvements for transpilers.
+
* Added [https://harmony.pardeike.net/articles/patching-postfix.html pass-through postfixes].
* Transpilers can now default to the original input by returning <tt>null</tt>.
+
* Added [https://harmony.pardeike.net/api/HarmonyLib.Transpilers.html <samp>Manipulator</samp>] utility, <samp>CodeInstruction</samp> extensions, and other improvements for transpilers.
* Better compatibility with Android modding.
+
* Added more <samp>AccessTools.Is*</samp> methods.
* Better exception messages.
+
* Added support for .NET 5.
* Better validation for invalid patches.
+
* Transpilers can now default to the original input by returning <samp>null</samp>.
 +
* Improved compatibility with Android modding.
 +
* Improved exception messages.
 +
* Improved validation for invalid patches.
 
* Fixed cases where methods were inlined and unpatchable on Linux/Mac.
 
* Fixed cases where methods were inlined and unpatchable on Linux/Mac.
 
* Fixed methods with struct return types being unpatchable.
 
* Fixed methods with struct return types being unpatchable.
* Various other improvements and fixes; see the [https://github.com/pardeike/Harmony/releases/tag/v2.0.0 Harmony 2.0 release notes] and [https://harmony.pardeike.net Harmony 2.0 documentation] for more info.
+
* Various other improvements and fixes; see the [https://github.com/pardeike/Harmony/releases/tag/v2.0.0 Harmony 2.0 release notes], [https://github.com/pardeike/Harmony/releases/tag/v2.1.0.0 Harmony 2.1 release notes], and [https://harmony.pardeike.net new Harmony documentation] for more info.
   −
After waiting ≈four months to make sure the release is stable, SMAPI 3.6 will transition to Harmony 2.0.
+
After waiting over a year to make sure the release is stable, SMAPI is transitioning to Harmony 2.1.
    
===Is this the modapocalypse?===
 
===Is this the modapocalypse?===
 
Nope. Although this is a major change, significant efforts were undertaken to minimise the impact:
 
Nope. Although this is a major change, significant efforts were undertaken to minimise the impact:
* Mods which don't use Harmony directly are not affected.
+
* mods which don't use Harmony directly aren't affected;
* SMAPI automatically rewrites most Harmony 1.''x'' code for compatibility so many mods can work without an update;
+
* most mods are rewritten automatically for compatibility, so they'll work without an update;
* pull requests will be submitted to update affected open-source mods;
+
* pull requests were submitted to update affected open-source mods;
* unofficial updates will be created for mods which haven't updated officially by the time SMAPI 3.6 is released;
+
* unofficial updates were created as needed for mods which hadn't updated officially;
* the changes will be actively communicated and documented to modders.
+
* the changes were actively communicated and documented to modders.
   −
In addition, the current target is ''at least'' 90% compatibility for open-source mods before SMAPI 3.6 is released. All of this means that the 3.6 release should have minimal impact on mod compatibility, despite the scope of the changes.
+
In addition, the target was ''at least'' 90% compatibility for open-source mods before SMAPI migrates. All of this means that the release should have minimal impact on mod compatibility, despite the scope of the changes.
    
===How to update your mod===
 
===How to update your mod===
Line 45: Line 46:     
===Stricter validation===
 
===Stricter validation===
Harmony 2.0 has stricter validation in general, so invalid patches that would previously work (e.g. setting <tt>__result</tt> to the wrong type) will now cause errors. See the exception messages for help fixing these.
+
Harmony 2.x has stricter validation in general, so invalid patches that would previously somewhat work (''e.g.,'' setting <samp>__result</samp> to the wrong type) will now cause errors. See the exception messages for help fixing these.
    
===Patching static constructors===
 
===Patching static constructors===
The <tt>AccessTools</tt> methods for constructors (<tt>DeclaredConstructor</tt>, <tt>Constructor</tt>, and <tt>GetDeclaredConstructors</tt>) no longer match static constructors by default. Pass <tt>searchForStatic: true</tt> to the methods if needed.
+
The <samp>AccessTools</samp> methods for constructors (<samp>Constructor</samp>, <samp>DeclaredConstructor</samp>, and <samp>GetDeclaredConstructors</samp>) no longer match static constructors by default. Use the new <samp>searchForStatic</samp> argument if you need to match them:
 +
 
 +
<syntaxhighlight lang="c#">
 +
// match static constructors only
 +
var method = AccessTools.Constructor(typeof(ExampleType), searchForStatic: true);
 +
 
 +
// match static *or* instance constructors
 +
var method =
 +
  AccessTools.Constructor(typeof(ExampleType), searchForStatic: true)
 +
  ?? AccessTools.Constructor(typeof(ExampleType));
 +
</syntaxhighlight>
 +
 
 +
Note that Harmony no longer matches static constructors for a good reason — they're only called once for the type, so often static constructor patches won't work correctly.
    
===Patching virtual methods===
 
===Patching virtual methods===
You can no longer patch a non-implemented virtual method; doing so results in the error "''You can only patch implemented methods/constructors''".
+
When patching a virtual method, you must now patch the specific type which implements it. Patching the wrong type now results in the error "''You can only patch implemented methods/constructors''".
    
For example, consider this code:
 
For example, consider this code:
<source lang="C#">
+
<syntaxhighlight lang="c#">
 
public class GameLocation
 
public class GameLocation
 
{
 
{
Line 61: Line 74:     
public class Farm : GameLocation {}
 
public class Farm : GameLocation {}
</source>
+
</syntaxhighlight>
 +
 
 +
<samp>Farm.cleanupBeforePlayerExit</samp> doesn't exist, so it's inherited from <samp>GameLocation</samp>. Harmony 1.x would let you patch <samp>Farm.cleanupBeforePlayerExit</samp>, but in Harmony 2.x you must target the actual method (<samp>GameLocation.cleanupBeforePlayerExit</samp> in this example).
 +
 
 +
===<samp>HarmonyMethod</samp> no longer allows null===
 +
Harmony 1.x allowed <code>new HarmonyMethod(null)</code>, so you could safely use it with methods that might not exist. Harmony 2.x now throws an exception in that case, so you should check if you're not sure it exists:
 +
<syntaxhighlight lang="c#">
 +
MethodInfo prefix = AccessTools.Method(this.GetType(), "Prefix");
 +
if (prefix != null)
 +
  harmony.Patch(original, new HarmonyMethod(prefix));
 +
</syntaxhighlight>
   −
<tt>Farm.cleanupBeforePlayerExit</tt> doesn't exist, so it's inherited from <tt>GameLocation</tt>. Harmony 1.x would let you patch <tt>Farm.cleanupBeforePlayerExit</tt>, but in Harmony 2.x you must target the actual method (<tt>GameLocation.cleanupBeforePlayerExit</tt> in this example).
+
===Transpiler changes===
 +
Harmony 2.x uses a new engine ({{github|MonoMod/MonoMod|MonoMod}}) under the hood, so there may be unexpected changes in the way transpiler patches work. For example, short-form branches may become long-form. If your mod uses transpilers, you should test each one to make sure it's working as you expect.
    
[[Category:Modding]]
 
[[Category:Modding]]
translators
8,437

edits