Changes

Jump to navigation Jump to search
m
→‎When to use Harmony: clarify version compatibility note
Line 10: Line 10:  
* It's very easy to cause crashes, errors, or subtle bugs, including difficult-to-diagnose memory corruption errors.
 
* It's very easy to cause crashes, errors, or subtle bugs, including difficult-to-diagnose memory corruption errors.
 
* SMAPI often can't detect incompatible Harmony code.
 
* SMAPI often can't detect incompatible Harmony code.
* Crossplatform compatibility isn't guaranteed.
+
* SMAPI often can't rewrite Harmony patches for compatibility, so the mod may break on other platforms (e.g. Android) or in future game updates.
 
* Patches may conflict with other Harmony mods, sometimes in ways that are difficult to troubleshoot.
 
* Patches may conflict with other Harmony mods, sometimes in ways that are difficult to troubleshoot.
 
* Patches may have unpredictable effects on other mods that aren't using Harmony. That may also irritate other modders, if players often report bugs to other mods due to your patches.
 
* Patches may have unpredictable effects on other mods that aren't using Harmony. That may also irritate other modders, if players often report bugs to other mods due to your patches.
Line 22: Line 22:  
'''Harmony should be a last resort''' (see the previous section).
 
'''Harmony should be a last resort''' (see the previous section).
 
<ol>
 
<ol>
<li>Edit your mod's <tt>.csproj</tt> project file, and add this to the first <tt>&lt;PropertyGroup&gt;</tt> section:
+
<li>Edit your mod's <samp>.csproj</samp> project file, and add this to the first <samp>&lt;PropertyGroup&gt;</samp> section:
<source lang="xml">
+
<syntaxhighlight lang="xml">
 
<EnableHarmony>true</EnableHarmony>
 
<EnableHarmony>true</EnableHarmony>
</source></li>
+
</syntaxhighlight></li>
<li>In your mod's <tt>Entry</tt> method, use Harmony's code API to register patches:
+
<li>In your mod's <samp>Entry</samp> method, use Harmony's code API to register patches:
<source lang="c#">
+
<syntaxhighlight lang="c#">
var harmony = HarmonyInstance.Create(this.ModManifest.UniqueID);
+
var harmony = new Harmony(this.ModManifest.UniqueID);
    
// example patch, you'll need to edit this for your patch
 
// example patch, you'll need to edit this for your patch
Line 35: Line 35:  
   prefix: new HarmonyMethod(typeof(ObjectPatches), nameof(ObjectPatches.CanBePlacedHere_Prefix))
 
   prefix: new HarmonyMethod(typeof(ObjectPatches), nameof(ObjectPatches.CanBePlacedHere_Prefix))
 
);
 
);
</source></li>
+
</syntaxhighlight></li>
<li>See the {{github|pardeike/Harmony/wiki|Harmony wiki}} for tutorials and documentation.</li>
+
<li>See the [https://harmony.pardeike.net/ Harmony tutorials and documentation].</li>
 
</ol>
 
</ol>
   Line 43: Line 43:  
<li>See [[#When to use Harmony|when to use Harmony]].</li>
 
<li>See [[#When to use Harmony|when to use Harmony]].</li>
 
<li>Unhandled errors in a patch can be hard to troubleshoot, which often leads to players asking for help on the SMAPI page instead of your mod. '''Please''' handle errors, log them, and default to the original code. For example:
 
<li>Unhandled errors in a patch can be hard to troubleshoot, which often leads to players asking for help on the SMAPI page instead of your mod. '''Please''' handle errors, log them, and default to the original code. For example:
<source lang="C#">
+
<syntaxhighlight lang="C#">
public class ObjectPatches
+
internal class ObjectPatches
 
{
 
{
 
     private static IMonitor Monitor;
 
     private static IMonitor Monitor;
    
     // call this method from your Entry class
 
     // call this method from your Entry class
     public static void Initialize(IMonitor monitor)
+
     internal static void Initialize(IMonitor monitor)
 
     {
 
     {
 
         Monitor = monitor;
 
         Monitor = monitor;
 
     }
 
     }
   −
     public static bool CanBePlacedHere_Prefix(SObject __instance, GameLocation location, Vector2 tile, ref bool __result)
+
     // patches need to be static!
 +
    internal static bool CanBePlacedHere_Prefix(StardewValley.Object __instance, GameLocation location, Vector2 tile, ref bool __result)
 
     {
 
     {
 
         try
 
         try
Line 68: Line 69:  
     }
 
     }
 
}
 
}
</source>
+
</syntaxhighlight>
 
</li>
 
</li>
 
<li>Use postfixes when possible for best compatibility and stability.</li>
 
<li>Use postfixes when possible for best compatibility and stability.</li>
 
<li>Don't use transpile patches unless you have no choice and you know what you're doing. This has a much higher chance of causing issues, is more fragile and likely to break in game updates, and makes it much less likely that other modders can help if you need it.</li>
 
<li>Don't use transpile patches unless you have no choice and you know what you're doing. This has a much higher chance of causing issues, is more fragile and likely to break in game updates, and makes it much less likely that other modders can help if you need it.</li>
 +
<li>[[#How to use it|Use the code API]] instead of annotations like <samp>[HarmonyPatch]</samp> (see ''[[#Why should I avoid Harmony annotations and PatchAll?|Why should I avoid Harmony annotations and <samp>PatchAll</samp>?]]'').</li>
 
</ol>
 
</ol>
 +
 +
==FAQs==
 +
===Which version of Harmony should I use?===
 +
The Harmony version is managed by SMAPI (currently 2.1.''x''). If you [[#How to use it|use the <samp>EnableHarmony</samp> option]], you'll use the version bundled with SMAPI automatically.
 +
 +
===Why should I avoid Harmony annotations and <samp>PatchAll</samp>?===
 +
There are two ways to add patches:
 +
* [[#How to use it|Use the code API]] (recommended).
 +
* Use annotations like <samp>[HarmonyPatch]</samp> on static classes, then call Harmony's <samp>PatchAll</samp> to dynamically scan the assembly for those annotations. This is fragile and discouraged.
 +
 +
For context, SMAPI automatically rewrites mods when needed for compatibility. That's used to keep mods working when there are breaking changes in the game/SMAPI/Harmony, or to handle crossplatform differences (e.g. using PC mods on Android). For example, the Stardew Valley 1.5.5 update broke most C# mods, but nearly all of them were fixed automatically by SMAPI's rewriting.
 +
 +
However annotations work differently in the compiled code, so SMAPI can't rewrite them. That means mods which use annotations are more fragile; they may break without warning in future game/SMAPI/Harmony updates, and may not work on some platforms.
 +
 +
===What is inlining and why does it matter?===
 +
 +
[https://en.wikipedia.org/wiki/Inline_expansion Inlining] is when the JIT takes a method call and sticks the body of the method called instead of emitting an actual call. If this happens, a harmony patch applied to the callee will not take effect.
 +
 +
The heuristics the JIT uses to decide whether or not to inline a method are not documented and are subject to change, but [https://stackoverflow.com/a/31467000/19366602 small, simple methods that do not throw exceptions] are the most likely to be inlined. Additionally, the heuristic seems to change between platform and platform, with mac being more aggressive than Windows.
translators
8,403

edits

Navigation menu