Skip to content

Commit

Permalink
Update documentation [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
pardeike-bot committed Dec 30, 2021
1 parent 5d99dcd commit eff433e
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 45 deletions.
10 changes: 7 additions & 3 deletions docs/articles/annotations.html
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ <h1 id="annotations">Annotations</h1>
<pre><code class="lang-csharp" name="example">using HarmonyLib;

[HarmonyPatch(typeof(SomeTypeHere))]
[HarmonyPatch(&quot;SomeMethodName&quot;)]
[HarmonyPatch(&quot;SomeMethodName&quot;)] // if possible use nameof() here
class MyPatches
{
static void Postfix(/*...*/)
Expand Down Expand Up @@ -192,9 +192,13 @@ <h4 id="patching-multiple-methods">Patching multiple methods</h4>
}

// prefix all methods in someAssembly with a non-void return type and beginning with &quot;Player&quot;
static void Prefix(MethodBase __originalMethod)
static void Prefix(object[] __args, MethodBase __originalMethod)
{
// use __originalMethod to decide what to do
// use dynamic code to handle all method calls
var parameters = __originalMethod.GetParameters();
FileLog.Log($&quot;Method {__originalMethod.FullDescription()}:&quot;);
for (var i = 0; i &lt; __args.Length; i++)
FileLog.Log($&quot;{parameters[i].Name} of type {parameters[i].ParameterType} is {__args[i]}&quot;);
}
}
</code></pre><h3 id="combining-annotations">Combining annotations</h3>
Expand Down
1 change: 1 addition & 0 deletions docs/articles/basics.html
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ <h3 id="debug-log">Debug Log</h3>
<h3 id="manual-patching">Manual patching</h3>
<p>For more control, you use <code>Patch()</code>. It takes an original and a combination of Prefix, Postfix or Transpiler methods, which are optional HarmonyMethod objects (pass null to <code>Patch()</code> to skip one type of patch):</p>
<pre><code class="lang-csharp" name="example">// add null checks to the following lines, they are omitted for clarity
// when possible, don't use string and instead use nameof(...)
var original = typeof(TheClass).GetMethod(&quot;TheMethod&quot;);
var prefix = typeof(MyPatchClass1).GetMethod(&quot;SomeMethod&quot;);
var postfix = typeof(MyPatchClass2).GetMethod(&quot;SomeMethod&quot;);
Expand Down
4 changes: 2 additions & 2 deletions docs/articles/intro.html
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ <h2 id="hello-world-example">Hello World Example</h2>
}

[HarmonyPatch(typeof(SomeGameClass))]
[HarmonyPatch(&quot;DoSomething&quot;)]
[HarmonyPatch(&quot;DoSomething&quot;)] // if possible use nameof() here
class Patch01
{
static AccessTools.FieldRef&lt;SomeGameClass, bool&gt; isRunningRef =
Expand Down Expand Up @@ -203,7 +203,7 @@ <h2 id="hello-world-example">Hello World Example</h2>
{
var harmony = new Harmony(&quot;com.example.patch&quot;);

var mOriginal = AccessTools.Method(typeof(SomeGameClass), &quot;DoSomething&quot;);
var mOriginal = AccessTools.Method(typeof(SomeGameClass), &quot;DoSomething&quot;); // if possible use nameof() here
var mPrefix = SymbolExtensions.GetMethodInfo(() =&gt; MyPrefix());
var mPostfix = SymbolExtensions.GetMethodInfo(() =&gt; MyPostfix());
// in general, add null checks here (new HarmonyMethod() does it for you too)
Expand Down
26 changes: 25 additions & 1 deletion docs/articles/patching-auxilary.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,29 @@ <h2 id="auxilary-patch-methods">Auxilary patch methods</h2>
<li><code>Harmony harmony</code> - the current Harmony instance</li>
<li><code>Exception ex</code> - only valid in <code>Cleanup</code> and receives a possible exception</li>
</ul>
<h3 id="prepare">Prepare</h3>
<p>Here is a simple example that patches a method inside a private type:</p>
<pre><code class="lang-csharp" name="example">[HarmonyPatch] // at least one Harmony annotation makes Harmony not skip this patch class when calling PatchAll()
class MyPatch
{
// here, inside the patch class, you can place the auxilary patch methods
// for example TargetMethod:

public MethodBase TargetMethod()
{
// use normal reflection or helper methods in &lt;AccessTools&gt; to find the method/constructor
// you want to patch and return its MethodInfo/ConstructorInfo
//
var type = AccessTools.FirstInner(typeof(TheClass), t =&gt; t.Name.Contains(&quot;Stuff&quot;));
return AccessTools.FirstMethod(type, method =&gt; method.Name.Contains(&quot;SomeMethod&quot;));
}

// your patches
public void Prefix()
{
// ...
}
}
</code></pre><h3 id="prepare">Prepare</h3>
<p>Before the patching, Harmony gives you a chance to prepare your state. For this, Harmony searches for a method called</p>
<pre><code class="lang-csharp">static void Prepare(...)
static void Prepare(MethodBase original, ...)
Expand Down Expand Up @@ -107,8 +129,10 @@ <h3 id="targetmethods">TargetMethods</h3>
<p>A typical implementation would <code>yield</code> the results like this:</p>
<pre><code class="lang-csharp" name="example">static IEnumerable&lt;MethodBase&gt; TargetMethods()
{
// if possible use nameof() or SymbolExtensions.GetMethodInfo() here
yield return AccessTools.Method(typeof(Foo), &quot;Method1&quot;);
yield return AccessTools.Method(typeof(Bar), &quot;Method2&quot;);

// you could also iterate using reflections over many methods
}
</code></pre><h3 id="cleanup">Cleanup</h3>
Expand Down
48 changes: 27 additions & 21 deletions docs/articles/patching-injections.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,29 +70,35 @@
<h1 id="patching">Patching</h1>

<h2 id="common-injected-values">Common injected values</h2>
<p>Each patch method (except a transpiler) can get all the arguments of the original method as well as the instance if the original method is not static and the return value. Patches only need to define the parameters they want to access.</p>
<h3 id="instance">Instance</h3>
<p>Patches can use an argument named <code>__instance</code> to access the instance value if original method is not static. This is similar to the C# keyword <code>this</code> when used in the original method.</p>
<h3 id="result">Result</h3>
<p>Patches can use an argument named <code>__result</code> to access the returned value. The type <code>T</code> of argument must match the return type of the original or be assignable from it. For prefixes, as the original method hasn't run yet, the value of <code>__result</code> is default(T). For most reference types, that would be <code>null</code>. If you wish to alter the <code>__result</code>, you need to define it by reference like <code>ref string name</code>.</p>
<h3 id="state">State</h3>
<p>Patches can use an argument named <code>__state</code> to store information in the prefix method that can be accessed again in the postfix method. Think of it as a local variable. It can be any type and you are responsible to initialize its value in the prefix. It only works if both patches are defined in the same class.</p>
<h3 id="private-fields">(Private) Fields</h3>
<p>Argument names starting with three underscores, for example <code>___someField</code>, can be used to read and (with <code>ref</code>) write private fields on the instance that has the corresponding name (minus the underscores).</p>
<h3 id="original-method-argument-matching">Original Method Argument Matching</h3>
<p>In order for the original method arguments to be properly matched to the patched method, some restrictions are placed on the types and names of arguments in the patched method:</p>
<h4 id="--argument-types">- Argument Types</h4>
<p>The type of a given argument (that is to be matched to the argument of the original method) must either be the same type or be <code>object</code>.</p>
<h4 id="--argument-names">- Argument Names</h4>
<p>The name of a given argument (that is to be matched to the argument of the original method) must either be the same name or of the form <code>__n</code>, where <code>n</code> is the zero-based index of the argument in the orignal method (you can use argument annotations to map to custom names).</p>
<h3 id="--the-original">- The original</h3>
<p>To allow patches to identify on which method they are attachted you can inject the original methods MethodBase by using an argument named <code>__originalMethod</code>.</p>
<p>Each patch method (except a transpiler) can get all the arguments of the original method as well as the instance if the original method is not static and the return value.</p>
<p>You only need to define the parameters you want to access.</p>
<h3 id="__instance">__instance</h3>
<p>Patches can use an argument called <strong><code>__instance</code></strong> to access the instance value if original method is not static. This is similar to the C# keyword <code>this</code> when used in the original method.</p>
<h3 id="__result">__result</h3>
<p>Patches can use an argument called <strong><code>__result</code></strong> to access the returned value. The type must match the return type of the original or be assignable from it. For prefixes, as the original method hasn't run yet, the value of <code>__result</code> is the default for that type. For most reference types, that would be <code>null</code>. If you wish to <strong>alter</strong> the <code>__result</code>, you need to define it <strong>by reference</strong> like <code>ref string name</code>.</p>
<h3 id="__state">__state</h3>
<p>Patches can use an argument called <strong><code>__state</code></strong> to store information in the prefix method that can be accessed again in the postfix method. Think of it as a local variable. It can be any type and you are responsible to initialize its value in the prefix. <strong>Note:</strong> It only works if both patches are defined in the same class.</p>
<h3 id="___fields">___fields</h3>
<p>Argument names starting with <strong>three</strong> underscores like <strong><code>___someField</code></strong> can be used to read/write private fields that have that name minus the underscores. To write to field you need to use the <strong><code>ref</code></strong> keyword like <code>ref string ___name</code>.</p>
<h3 id="__args">__args</h3>
<p>To access all arguments at once, you can let Harmony inject <strong><code>object[] __args</code></strong> that will contain all arguments in the order they appear. Editing the contents of that array (no ref needed) will automatically update the values of the corresponding arguments.</p>
<p><strong>Note:</strong> This way of manipulation comes with some small overhead so if possible use normal argument injection</p>
<h3 id="method-arguments">method arguments</h3>
<p>To access or change one or several of the original methods arguments, simply repeat them with the same name in your patch. Some restrictions are placed on the types and names of arguments in the patched method:</p>
<ul>
<li>The type of an injected argument must be assignable from the original argument (or just use <code>object</code>)</li>
<li>The name of a given argument (that is to be matched to the argument of the original method) must either be the same name or of the form <strong><code>__n</code></strong>, where <code>n</code> is the zero-based index of the argument in the orignal method (you can also use argument annotations to map to custom names).</li>
</ul>
<h3 id="__originalmethod">__originalMethod</h3>
<p>To allow patches to identify on which method they are attachted you can inject the original methods MethodBase by using an argument called <strong><code>__originalMethod</code></strong>.</p>
<p><img src="https://raw.githubusercontent.com/pardeike/Harmony/master/Harmony/Documentation/images/note.png" alt="note"> <strong>You cannot call the original method with that</strong>. The value is only for conditional code in your patch that can selectively run if the patch is applied to multiple methods. The original does not exist after patching and this will point to the patched version.</p>
<h3 id="--special-arguments">- Special arguments</h3>
<h3 id="__runoriginal">__runOriginal</h3>
<p>To learn if the original is/was skipped you can inject <strong><code>bool __runOriginal</code></strong>. This is a readonly injection to understand if the original will be run (in a Prefix) or was run (in a Postfix).</p>
<h3 id="transpilers">Transpilers</h3>
<p>In transpilers, arguments are only matched by their type so you can choose any argument name you like.</p>
<p>An argument of type <code>IEnumerable&lt;CodeInstruction&gt;</code> is required and will be used to pass the IL codes to the transpiler
An argument of type <code>ILGenerator</code> will be set to the current IL code generator
An argument of type <code>MethodBase</code> will be set to the current original method being patched</p>
<p>An argument of type <strong><code>IEnumerable&lt;CodeInstruction&gt;</code></strong> is required and will be used to pass the IL codes to the transpiler
An argument of type <strong><code>ILGenerator</code></strong> will be set to the current IL code generator
An argument of type <strong><code>MethodBase</code></strong> will be set to the current original method being patched</p>
</article>
</div>

Expand Down
8 changes: 4 additions & 4 deletions docs/articles/patching-postfix.html
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ <h3 id="reading-or-changing-the-result">Reading or changing the result</h3>
}
}

[HarmonyPatch(typeof(OriginalCode), &quot;GetName&quot;)]
[HarmonyPatch(typeof(OriginalCode), nameof(OriginalCode.GetName))]
class Patch
{
static void Postfix(ref string __result)
Expand All @@ -114,7 +114,7 @@ <h3 id="reading-or-changing-the-result">Reading or changing the result</h3>
}
}

[HarmonyPatch(typeof(OriginalCode), &quot;GetName&quot;)]
[HarmonyPatch(typeof(OriginalCode), nameof(OriginalCode.GetName))]
class Patch1
{
static string Postfix(string name)
Expand All @@ -123,7 +123,7 @@ <h3 id="reading-or-changing-the-result">Reading or changing the result</h3>
}
}

[HarmonyPatch(typeof(OriginalCode), &quot;GetNumbers&quot;)]
[HarmonyPatch(typeof(OriginalCode), nameof(OriginalCode.GetNumbers))]
class Patch2
{
static IEnumerable&lt;int&gt; Postfix(IEnumerable&lt;int&gt; values)
Expand All @@ -147,7 +147,7 @@ <h3 id="reading-or-changing-the-result">Reading or changing the result</h3>
}
}

[HarmonyPatch(typeof(OriginalCode), &quot;Test&quot;)]
[HarmonyPatch(typeof(OriginalCode), nameof(OriginalCode.Test))]
class Patch
{
static void Prefix(int counter)
Expand Down
8 changes: 4 additions & 4 deletions docs/articles/patching-prefix.html
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ <h3 id="reading-and-changing-arguments">Reading and changing arguments</h3>
}
}

[HarmonyPatch(typeof(OriginalCode), &quot;Test&quot;)]
[HarmonyPatch(typeof(OriginalCode), nameof(OriginalCode.Test))]
class Patch
{
static void Prefix(int counter, ref string name)
Expand All @@ -108,7 +108,7 @@ <h3 id="reading-and-changing-arguments">Reading and changing arguments</h3>
}
}

[HarmonyPatch(typeof(OriginalCode), &quot;GetName&quot;)]
[HarmonyPatch(typeof(OriginalCode), nameof(OriginalCode.GetName))]
class Patch
{
static bool Prefix(ref string __result)
Expand All @@ -127,7 +127,7 @@ <h3 id="reading-and-changing-arguments">Reading and changing arguments</h3>
}
}

[HarmonyPatch(typeof(OriginalCode), &quot;IsFullAfterTakingIn&quot;)]
[HarmonyPatch(typeof(OriginalCode), nameof(OriginalCode.IsFullAfterTakingIn))]
class Patch
{
static bool Prefix(ref bool __result, int i)
Expand All @@ -151,7 +151,7 @@ <h3 id="reading-and-changing-arguments">Reading and changing arguments</h3>
}
}

[HarmonyPatch(typeof(OriginalCode), &quot;Test&quot;)]
[HarmonyPatch(typeof(OriginalCode), nameof(OriginalCode.Test))]
class Patch
{
// this example uses a Stopwatch type to measure
Expand Down
4 changes: 2 additions & 2 deletions docs/articles/patching-transpiler.html
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ <h2 id="transpiler">Transpiler</h2>
MethodBase original // [OPTIONAL]
</code></pre>
<p>A typical transpiler looks like this:</p>
<pre><code class="lang-csharp" name="example">static FieldInfo f_someField = AccessTools.Field(typeof(SomeType), &quot;someField&quot;);
<pre><code class="lang-csharp" name="example">static FieldInfo f_someField = AccessTools.Field(typeof(SomeType), nameof(SomeType.someField));
static MethodInfo m_MyExtraMethod = SymbolExtensions.GetMethodInfo(() =&gt; Tools.MyExtraMethod());

// looks for STDFLD someField and inserts CALL MyExtraMethod before it
Expand Down Expand Up @@ -259,7 +259,7 @@ <h2 id="basic-transpiler-tutorial">Basic Transpiler Tutorial</h2>
<p><strong>11) The execution</strong></p>
<p>Strategy: <em>Search for RET codes. For every code found, search until the next RET and look for the usage of the string &quot;TooBigCaravanMassUsage&quot;. If found, continue to find the following RET and remove everything from right after the first RET to including the second RET</em>:</p>
<pre><code class="lang-csharp" name="example">[HarmonyPatch(typeof(Dialog_FormCaravan))]
[HarmonyPatch(&quot;CheckForErrors&quot;)]
[HarmonyPatch(nameof(Dialog_FormCaravan.CheckForErrors))]
public static class Dialog_FormCaravan_CheckForErrors_Patch
{
static IEnumerable&lt;CodeInstruction&gt; Transpiler(IEnumerable&lt;CodeInstruction&gt; instructions)
Expand Down
16 changes: 8 additions & 8 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@
"output": {
".html": {
"relative_path": "articles/annotations.html",
"hash": "cb9xyQ4JEdmeI69EbT3t2yjfKxpubI46dNrFYx7mW+o="
"hash": "qPxnLPo1JnmvmRRPlqEa1NGByKyNlxxqAgIHIwXZDOc="
}
},
"is_incremental": false,
Expand All @@ -777,7 +777,7 @@
"output": {
".html": {
"relative_path": "articles/basics.html",
"hash": "hqe4hYiGZDMv+M+3v9qtKUrkU6LHNDRdsDyTCQW/1lE="
"hash": "LzGOvKHjm60rOciG6Aalo//fimNpifblhpZDM/1j0zY="
}
},
"is_incremental": false,
Expand All @@ -801,7 +801,7 @@
"output": {
".html": {
"relative_path": "articles/intro.html",
"hash": "d9XhrmoH/020jxqei5oVZy88FgQmocXAD7EHYgyn4Ec="
"hash": "BNBKp9rS8Q8YWtFePsL3cxkXRwAS+lHyV8cZENR6BSo="
}
},
"is_incremental": false,
Expand All @@ -825,7 +825,7 @@
"output": {
".html": {
"relative_path": "articles/patching-auxilary.html",
"hash": "Db86a2ij4RvDdryNsg7UWVXJOJ7H76RcGswJ0RZfxK0="
"hash": "itFMxuvZ6pkq7p1wf4aBfP1pNSfe46zYkQVGblVMAWI="
}
},
"is_incremental": false,
Expand Down Expand Up @@ -861,7 +861,7 @@
"output": {
".html": {
"relative_path": "articles/patching-injections.html",
"hash": "z8k3di28o9P3ksXmfhzTALn0yvzE2QQ9yMELCLN+1PM="
"hash": "hg/Y+tyTNRuwq0ZN9V8HgBMGQqRdOHd3X4ip3kVL+g0="
}
},
"is_incremental": false,
Expand All @@ -873,7 +873,7 @@
"output": {
".html": {
"relative_path": "articles/patching-postfix.html",
"hash": "EMqnVw0UhzrH2uHzkDMbIEpzZF/a6q7z4w1g4EUuAKo="
"hash": "OMIezCWvqQTgJUfC0F6anfu/7FX/iZjEh38xCjzNZ1g="
}
},
"is_incremental": false,
Expand All @@ -885,7 +885,7 @@
"output": {
".html": {
"relative_path": "articles/patching-prefix.html",
"hash": "FU13McuExihrqoeqcc/XE1so+UyIlxdrZ87Nvh7GUso="
"hash": "Cr7cb37TGb2fW+pu64pap4uNg4peyGg3soDnbYekEoE="
}
},
"is_incremental": false,
Expand All @@ -909,7 +909,7 @@
"output": {
".html": {
"relative_path": "articles/patching-transpiler.html",
"hash": "SvD/f+TUOYCoTFWtlQk6P2ir1y1gCWKebl46OzsuECE="
"hash": "hGLOJJbyCUyYIQtvKhWkD/01JcQXYfG7gaCfvCjVEfY="
}
},
"is_incremental": false,
Expand Down

0 comments on commit eff433e

Please sign in to comment.