diff --git a/docs/modders/il2cppdifferences.md b/docs/modders/il2cppdifferences.md
index 61fdaed..d3895a3 100644
--- a/docs/modders/il2cppdifferences.md
+++ b/docs/modders/il2cppdifferences.md
@@ -4,11 +4,11 @@ MelonLoader have some "small" things that doesn't work the exact same as if you
> If you find something that doesn't seems natural with Il2Cpp and that isn't listed here, please ping _loukylor#0001_ on the [MelonLoader Discord](https://discord.gg/2Wn3N2P).
-### Il2cppInterop Generated Names
+### Il2CppInterop Generated Names
?> You may ignore this section if your game is not obfuscated
-Il2cppInterop is what is used to generate proxy mono assemblies from Il2Cpp code. It will automatically assign auto-generated to obfuscated names.
+Il2CppInterop is what is used to generate proxy mono assemblies from Il2Cpp code. It will automatically assign auto-generated to obfuscated names.
The names are generated following certain rules:
For fields and properties:
@@ -46,7 +46,7 @@ Note that `MelonLoader.RegisterTypeInIl2Cpp` will register all parent types if a
Here is a very basic example:
```cs
-// You must reference `Il2cppInterop.Runtime.dll` for this to work
+// You must reference `Il2CppInterop.Runtime.dll` for this to work
using Il2CppInterop.Runtime;
[RegisterTypeInIl2Cpp]
@@ -124,7 +124,7 @@ MelonCoroutines.Stop(routine);
In case you want to run an Il2Cpp method taking a type, you may want to use `.GetType()`.
`.GetType()` would actually returns the Mono type, and not the original Il2Cpp type. To do so, we need to replace it with `Il2CppInterop.Runtime.Il2CppType.Of()`.
```cs
-// You must reference `Il2cppInterop.Runtime.dll` for this.
+// You must reference `Il2CppInterop.Runtime.dll` for this.
using Il2CppInterop.Runtime;
Resources.FindObjectsOfTypeAll(Il2CppType.Of());
diff --git a/docs/modders/patching.md b/docs/modders/patching.md
index 8820fb3..a4f4069 100644
--- a/docs/modders/patching.md
+++ b/docs/modders/patching.md
@@ -46,7 +46,9 @@ public class Example
This will mostly be a repeat of what the [Harmony Docs](https://harmony.pardeike.net/articles/patching.html) say. But here we go!
For this example, I will be patching `Example.PrivateMethod(int param1)`.
-Harmony is included in `MelonLoader.dll`, so there's no need to download the nuget package or reference the dll.
+With MelonLoader 0.6.0+, Harmony is included in the `MelonLoader\net6` folder for Il2Cpp and `MelonLoader\net35` for Mono, named `0Harmony.dll`.
+With MelonLoader 0.5.4-0.5.7, Harmony is included directly under the `MelonLoader` folder for both Il2Cpp and Mono, also named `0Harmony.dll`.
+On previous versions, it is directly embedded into `MelonLoader.dll`.
Let's create a new class. It can be named anything and have any access modifiers, however, we must add the `HarmonyPatch` attribute for it to be picked up by Harmony.
In the attribute, we specify what method we would like to patch. This is similar to [getting a method using Reflection](modders/reflection?id=calling-a-method-using-reflection).
@@ -150,50 +152,46 @@ Here's the code that we're going to be using, its a simple patch of the getter f
then we return a string of our choice. Will probably break some things in a game if they rely on the name but this is just for fun
```cs
-//delegate for our patch, same number of parameters as our patch method
+// Delegate for our patch, same number of parameters as our patch method
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate IntPtr GetNameDelegate(
IntPtr instance,
IntPtr methodInfo
);
-//two static fields with our delegate type
+// Two static fields with our delegate type
private static NativeHook Hook;
private static GetNameDelegate _patchDelegate;
-//the patch method, dealing with unmanaged to managed then back to unmanaged so pointers galore
+// The patch method, dealing with unmanaged to managed then back to unmanaged, so pointers galore
public static unsafe IntPtr GetName(IntPtr instance, IntPtr methodInfo)
{
IntPtr result = hook.Trampoline(instance, methodName);
string name = IL2CPP.PointerToValueGeneric (result, false, false);
- Logger.Msg(name);
+ Melon.Logger.Msg(name);
return IL2CPP.ManagedStringToIl2Cpp("MelonLoader");
}
-//logging instance
-public static MelonLogger.Instance Logger;
-//our mods initialize method, prefer OnLateInitializeMelon to make sure everything is loaded and available
+// Our mod's initialize method, prefer OnLateInitializeMelon to make sure everything is loaded and available
public override unsafe void OnLateInitializeMelon()
{
- Logger=LoggerInstance;
-
- //getting the IntPtr for our target method with GetIl2CppMethodInfoPointerFieldForGeneratedMethod
+ // Getting the IntPtr for our target method with GetIl2CppMethodInfoPointerFieldForGeneratedMethod
IntPtr originalMethod = *(IntPtr*) (IntPtr) Il2CppInteropUtils.
- GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(UnityEngine.Object).GetMethod("get_name").GetValue(null);
+ GetIl2CppMethodInfoPointerFieldForGeneratedMethod(typeof(UnityEngine.Object).GetMethod("get_name").GetValue(null));
- //storing our patch method in one of the delegate fields
+ // Storing our patch method in one of the delegate fields
_patchDelegate = GetName;
- //getting the IntPtr from _patchDelegate
+ // Getting the IntPtr from _patchDelegate
IntPtr delegatePointer = Marshal.GetFunctionPointerForDelegate(_patchDelegate);
- //creating the NativeHook with our target method' IntPtr and patch delegate' IntPtr
+ // Creating the NativeHook with our target method' IntPtr and patch delegate' IntPtr
NativeHook hook = new NativeHook (originalMethod, delegatePointer);
- //very important part, actually telling it to attach and hook into the target method
+ // Very important part, actually telling it to attach and hook into the target method
hook.Attach();
- //storing the hook so we can use the trampoline in it to run the original method in our patch
+ // Storing the hook so we can use the trampoline in it to run the original method in our patch
Hook = hook.Trampoline;
}
```
diff --git a/docs/modders/preferences.md b/docs/modders/preferences.md
index 1ea0439..7114517 100644
--- a/docs/modders/preferences.md
+++ b/docs/modders/preferences.md
@@ -14,7 +14,7 @@ namespace MyProject
{
public override void OnUpdate()
{
- if(Input.GetKeyDown(KeyCode.T))
+ if (Input.GetKeyDown(KeyCode.T))
{
LoggerInstance.Log("You just pressed T");
}
diff --git a/docs/modders/quickstart.md b/docs/modders/quickstart.md
index 3519a86..34c6b06 100644
--- a/docs/modders/quickstart.md
+++ b/docs/modders/quickstart.md
@@ -2,6 +2,21 @@
!> This tutorial assumes that you have a fair grasp of the C# programming language and basic knowledge of Visual Studio and Unity Engine.
+### Visual Studio Template
+An automated Visual Studio 2022 template for creating MelonLoader mods and plugins is available.
+It handles the creation of the required boilerplate (the `MelonMod`/`MelonPlugin` class, `MelonInfo`, and `MelonGame`) as well as referencing the required assemblies for mod development, mainly MelonLoader, Harmony, and for Il2Cpp, proxy assemblies and the unhollower (Il2CppAssemblyUnhollower or Il2CppInterop). It also handles variation between MelonLoader or Unity versions, such as framework versions or override changes.
+
+0. Download MelonLoader to your game and run it once before continuing.
+1. Download the VSIX from the [GitHub repo](https://github.com/TrevTV/MelonLoader.VSWizard/releases).
+2. Close all instances of Visual Studio and run the VSIX installer (double-clicking it should open it).
+3. Open Visual Studio and create a new project.
+4. Search for `MelonLoader` and click on either Mod or Plugin.
+5. Enter the project info and press Create.
+6. Select the EXE of the game you are modding and press Open.
+7. Wait for the project creation and it should open a Visual Studio window with a working project.
+
+You may want to change the author in the `MelonInfo` attribute. It defaults to your computer's username.
+
### Basic mod setup
First, you will need to create a new project. Unity versions require different project templates:
@@ -185,8 +200,9 @@ For games using the IL2CPP runtime, all the game/Unity assemblies can be found i
Since IL2CPP converts all game assemblies to C++, MelonLoader is using [Il2CppInterop](https://github.com/BepInEx/Il2CppInterop), an IL2CPP proxy assembly generator which allows us to use IL2CPP assemblies from C#.
Before we can use any assemblies generated by the Unhollower, it's required to reference the following assemblies first:
-- `il2cppmscorlib`
-- `Il2cppInterop`
+- `Il2Cppmscorlib.dll`
+- `Il2CppInterop.Common.dll`
+- `Il2CppInterop.Runtime.dll`
At this point, you're ready to make your first functional Melon.
@@ -205,8 +221,6 @@ namespace TimeFreezer
{
public class TimeFreezerMod : MelonMod
{
- public static TimeFreezerMod instance;
-
private static KeyCode freezeToggleKey;
private static bool frozen;
@@ -214,7 +228,6 @@ namespace TimeFreezer
public override void OnEarlyInitializeMelon()
{
- instance = this;
freezeToggleKey = KeyCode.Space;
}
@@ -237,7 +250,7 @@ namespace TimeFreezer
if (frozen)
{
- instance.LoggerInstance.Msg("Freezing");
+ Melon.Logger.Msg("Freezing");
MelonEvents.OnGUI.Subscribe(DrawFrozenText, 100); // Register the 'Frozen' label
baseTimeScale = Time.timeScale; // Save the original time scale before freezing
@@ -245,7 +258,7 @@ namespace TimeFreezer
}
else
{
- instance.LoggerInstance.Msg("Unfreezing");
+ Melon.Logger.Msg("Unfreezing");
MelonEvents.OnGUI.Unsubscribe(DrawFrozenText); // Unregister the 'Frozen' label
Time.timeScale = baseTimeScale; // Reset the time scale to what it was before we froze the time