diff --git a/creating-a-mod/creating-your-first-mod.md b/creating-a-mod/creating-your-first-mod.md index 7c2ecf1edf6cb6afbdcb6956d439e1676007205d..d37a4eaadacaabaf4fc9c7b318a3ac65a63ac914 100644 --- a/creating-a-mod/creating-your-first-mod.md +++ b/creating-a-mod/creating-your-first-mod.md @@ -50,15 +50,15 @@ I haven't gone through this code in detail because this is something people with public override void ModLoaded() { //This is an event the VTOLAPI calls when the game is done loading a scene - VTOLAPI.SceneLoaded += SceneLoaded; + VTOLAPI.SceneLoaded += SceneLoaded; base.ModLoaded(); - Log("HELLO WORLD!!!!!!"); + Log("HELLO WORLD!!!!!!"); // If Log isn't working you can also try Debug.Log, but it's likely your class doesn't inherit from either VTOLMOD or Monobehaviour } ``` # Building the .dll file -Now we have our mod create, we need to create the .dll file. Thankfully this is simple, right clicking on the project and pressing Build. +Now we have our mod create, we need to create the .dll file. Thankfully this is simple, right clicking on the project and pressing Build, or pressing ctrl + shift + b. ![](/images/creating-a-mod/Build-Button.PNG) diff --git a/creating-a-mod/setup.md b/creating-a-mod/setup.md index 2bd11ac4e7a6e668552a8ddab8e007b6da215b50..39277f1272e42f0fa4ab188ed8b525f5dce68add 100644 --- a/creating-a-mod/setup.md +++ b/creating-a-mod/setup.md @@ -17,3 +17,7 @@ You don't need Unity, however, if you want to start importing your own assets in ![](/images/creating-a-mod/unity.PNG) Once these are installed, we can next move onto creating a basic mod in Visual Studio. + +# dnSpy (Optional) + +dnSpy is what allows you to look at decompiled code and look at what everything does. It's downloadable [here](https://github.com/dnSpy/dnSpy/releases). \ No newline at end of file diff --git a/creating-a-mod/step2.md b/creating-a-mod/step2.md deleted file mode 100644 index 796c906eb6bf1483321eca1792b527c41e7f6920..0000000000000000000000000000000000000000 --- a/creating-a-mod/step2.md +++ /dev/null @@ -1 +0,0 @@ -This is step 2 \ No newline at end of file diff --git a/creating-a-mod/waiting-for-flight-scene.md b/creating-a-mod/waiting-for-flight-scene.md new file mode 100644 index 0000000000000000000000000000000000000000..3d4dc8ad4596a10238682bc60694c8a8329543ff --- /dev/null +++ b/creating-a-mod/waiting-for-flight-scene.md @@ -0,0 +1,27 @@ +# What is the Flight Scene? +The flight scene is the scene where you can fly your airplane, typically the AV-42C, F/A-26B, or the F45A. It's useful to wait for this scene if you want to only run code when the scene is Active. There are 3 scenes that constitute as a "flight" scene, Akutan, CustomMapBase, and OverCloud_CustomMapBase. + +# How to wait for the flight scene +The first thing you want to do is write a scene loaded function. The SceneLoaded function should look something like this, +```cs + private void SceneChanged(VTOLScenes scenes) // You can name it anything, naming it SceneLoaded will cause unity to call it and could break some things + { + if (scenes == VTOLScenes.Akutan || scenes == VTOLScenes.CustomMapBase || scenes == VTOLScenes.CustomMapBase_OverCloud) // If inside of a scene that you can fly in + { + // Your code here. + } + } +``` +This code will cause whatever is inside of the if statement to be ran when a flightscene starts, however this can also cause code to run before objects (like the player's vehicle) are loaded in, to combat this we need to write a [coroutine]("https://docs.unity3d.com/Manual/Coroutines.html") to make sure we don't run code before the scene is loaded. +```cs +private IEnumerator waitForLoad() + { + while (VTMapManager.fetch == null || !VTMapManager.fetch.scenarioReady || FlightSceneManager.instance.switchingScene) + { + yield return null; // tells the routine to wait a frame before resuming + } + // your code here + yield break; // stops the routine, this is required at the end of the routine if you don't yield anywhere else, but at that point it might be better to make the return type something else + } +``` +Now all that's left to do is link everything together, in your modloaded function if you place the code `VTOLAPI.SceneLoaded += yourSceneLoadedFunction;`, then whenever the scene is changed your function will be caused, and putting `StartCoroutine(waitFroLoad())` inside the if statement of SceneChanged will cause waitForLoad() to run, now you can run code when the flight scene has loaded. Note that if you want the code to rerun when you will also have to add `VTOLAPI.MissionReloaded += waitForLoead`. \ No newline at end of file diff --git a/creating-a-mod/writing-jsons.md b/creating-a-mod/writing-jsons.md new file mode 100644 index 0000000000000000000000000000000000000000..6bcd634e22116b3fb67f83e0cd1fd5ede7ca0841 --- /dev/null +++ b/creating-a-mod/writing-jsons.md @@ -0,0 +1,18 @@ +# JSON Files +Json files follow a format that goes `"Key" : "Value",`, the ModLoader reads these files in order to know how to interpret the mod and for easy modification of descriptions. This is all supported in the ModLoader's mod creator section, but if you want to manually edit the files you can also do it. + +Let's look at an example, from the mod All Equips All Time. +![](/images/creating-a-mod/json-example.png) + +Not all values shown here were written by its creator, but rather by the website after uploading it. There are only a couple values that matter in the JSON, the website will write the rest for you. + +# description +This is self explanatory, what your mod does. +# dll_file +This is what the ModLoader will inject, if you have multiple dll files this is the file that contains your `VTOLMOD` class. +# name +This is the name of your mod. +# version +This is the version of your mod. + +Note that most of these fields will be created and editable in the ModLoader by using Create A Project. If you want an image to be present in your mod, drop it into the mod folder and name it "preview". It's recommended that the file isn't too big, or the mod might take longer to load. \ No newline at end of file diff --git a/creating-a-skin/toc.yml b/creating-a-skin/toc.yml index 9bce036f0103df11f4a949d8a990cc8034b5880e..f7264ae0376e3bcfbb7139201dca9955693baf8e 100644 --- a/creating-a-skin/toc.yml +++ b/creating-a-skin/toc.yml @@ -1,2 +1,2 @@ - name: Getting Started - href: index.md \ No newline at end of file + href: index.md diff --git a/documentation/api/index.md b/documentation/api/index.md index a3c3a6d07a9cf1534e41475d91f778e53594db3c..aef3c52673f5fde0e730fd83c0d8397aff2435dd 100644 --- a/documentation/api/index.md +++ b/documentation/api/index.md @@ -4,7 +4,7 @@ This is the documentation for the mod loaders API >[!CAUTION] > This is rarely used any more -To find the API all you need to do is get the instance variable from the static class then store that in a variable. Later on, all you have to call is "api" if you want to use a function from the API. +To find the API all you need to do is get the instance variable from the static class then store that in a variable. Later on, all you have to call is "api" if you want to use a function from the API. ```cs private VTOLAPI api; diff --git a/documentation/api/waiting-for-mission-to-be-reloaded.md b/documentation/api/waiting-for-mission-to-be-reloaded.md index 88e5932c2cb3dfb4f8a32fb4392276231df063d2..d38960b8c4d8db3b8109d706817698e042b3fe6f 100644 --- a/documentation/api/waiting-for-mission-to-be-reloaded.md +++ b/documentation/api/waiting-for-mission-to-be-reloaded.md @@ -10,4 +10,9 @@ private void MissionReloaded() { //My Amazing Code to run when the user reloads the mission } -``` \ No newline at end of file +``` +You should also consider waiting for the flightscene to be ready, the following code in an IEnumerator will do that. +```cs +while (VTMapManager.fetch == null || !VTMapManager.fetch.scenarioReady || FlightSceneManager.instance.switchingScene) + yield return null; +``` diff --git a/documentation/api/waiting-for-scenario-to-finish-loading.md b/documentation/api/waiting-for-scenario-to-finish-loading.md index 751c8323c3f1b2b62ca0196cdaa410eaa24c45f6..cdd7ba93a8aedefb071529c3f9b31b6f02a07b98 100644 --- a/documentation/api/waiting-for-scenario-to-finish-loading.md +++ b/documentation/api/waiting-for-scenario-to-finish-loading.md @@ -20,4 +20,9 @@ private void SceneLoaded(VTOLScenes scene) break; } } -``` \ No newline at end of file +``` +If you want to wait for the flightscene to be ready, consider adding the following code to an IEnumerator. +```cs +while (VTMapManager.fetch == null || !VTMapManager.fetch.scenarioReady || FlightSceneManager.instance.switchingScene) + yield return null; +``` diff --git a/documentation/harmony/Traverse-private-fields.md b/documentation/harmony/Traverse-private-fields.md new file mode 100644 index 0000000000000000000000000000000000000000..814aae6a1eb72330405bca84c18db59bb6c8fc63 --- /dev/null +++ b/documentation/harmony/Traverse-private-fields.md @@ -0,0 +1,6 @@ +# Traverse +Traverse is the class in Harmony that is used to get private variables or functions, a traverse is created as follows. +```cs +Traverse traverse = Traverse.Create(object: objectToTraverse); +``` +After making your traverse, you can read private fields by calling `Traverse.Field("yourField").GetValue()`, and you can call private functions by doing `Traverse.Method("yourmethod").GetValue()`, note the return on get value is of type object so you will need to cast it correctly. diff --git a/documentation/harmony/changing-private-variables.md b/documentation/harmony/changing-private-variables.md deleted file mode 100644 index 57e136dbd88604b0701beaa50e550aecf7aab1b8..0000000000000000000000000000000000000000 --- a/documentation/harmony/changing-private-variables.md +++ /dev/null @@ -1,5 +0,0 @@ -Use this snippet to get and set private variables. -```cs -var foo = FindObjectOfType(); -Traverse.Create(foo).Field("privateVariableName").SetValue("world"); -``` \ No newline at end of file diff --git a/documentation/harmony/patching-methods.md b/documentation/harmony/patching-methods.md deleted file mode 100644 index 770ab9f220de4d68b8f016aa3d6a3580ca3d0f35..0000000000000000000000000000000000000000 --- a/documentation/harmony/patching-methods.md +++ /dev/null @@ -1,8 +0,0 @@ -Run this to patch your methods! https://github.com/pardeike/Harmony/wiki/Bootstrapping -```cs -private void Start() -{ - HarmonyInstance instance = HarmonyInstance.Create("me.mymod"); - instance.PatchAll(Assembly.GetExecutingAssembly()); -} -``` \ No newline at end of file diff --git a/documentation/harmony/patching.md b/documentation/harmony/patching.md new file mode 100644 index 0000000000000000000000000000000000000000..e6c15ac2fa810fbd4da8abdab495fdeead108ca1 --- /dev/null +++ b/documentation/harmony/patching.md @@ -0,0 +1,94 @@ +# What is Patching? +Patching is the process of running code before or after a function, and sometimes even modifying it. Patching is useful to execute your code after a function, or before one if your mod breaks it entirely. Patching can even stop the original method from executing. + +# Setup +In your ModLoaded function we will add the following code, if you aren't patching and functions this is unnecessary. +```cs +HarmonyInstance harmonyInstance = HarmonyInstance.Create("YourName.YourMod"); +harmonyInstance.PatchAll(Assembly.GetExecutingAssembly()); +``` +This will tell harmony to use our patches that we have created., after this code has been added we can begin to write our patches. All patches have to happen either before or after a function has executed in harmony. + +# Prefix +Prefix happens before a function is called, let's take the example code here. +```cs +public class Bar +{ + public void Foo() + { + Console.WriteLine("Bar") + } +} +``` +This code will print Bar to the console, however lets say we want it to print out Foobar before hand, we can accomplish that with the following code. +```cs +[HarmonyPatch(typeof(Bar), "Foo")] // the first argument is the class type, and the second is the name of the function, note that using nameof(class.function) would also work +public class Patch_Foo // the name can be anything you want it to be, but it's better to be descriptive +{ + [HarmonyPrefix] // this isn't needed if the function name is Prefix + public static bool Prefix() // if your function is named Prefix harmony will interpret it as such, if not you need the aformentioned tag. Prefix can also have a return type of void + { + Console.WriteLine("Foobar"); + return true; + } +} +``` +With our new patch in place Foobar is printed then Bar is printed, however if we didn't want Bar to be printed we could return false and harmony wouldn't run the patched function, only our code. + +# Postfix +Postfix happens after a function is called, let's take the example code from Prefix, but now we want Foobar to be printed after Foo. That'd be done with the following code. +```cs +[HarmonyPatch(typeof(Bar), "Foo")] // the first argument is the class type, and the second is the name of the function, note that using nameof(class.function) would also work +public class Patch_Foo // the name can be anything you want it to be, but it's better to be descriptive +{ + [HarmonyPostfix] // this isn't needed if the function name is Postfix + public static void Postfix() + { + Console.WriteLine("Foobar"); + } +} +``` +This will cause Foobar to be printed after Bar is printed. + +# Modifying or reading a return value +Modifying the return value can be done in both Prefix and Postfix, take this code for example. +```cs +public class MyClass +{ + public static int myMethod(int myInt) + { + return myInt; + } +} +``` +If we wanted myMethod to return a different value we could do so by adding the parameter ref __result to our patch, the type of result has to match the return value of the class and must contain ref if you want to modify it, if you simply wish to read it then ref isn't necessary. +```cs +[HarmonyPatch(typeof(MyClass), "myMethod")] +public class Patch_MyClass +{ + public static void Postfix(ref int __result) + { + __result = 3; + } +} +``` +With this code, we now return 3. Keep in mind that this code works with prefix as well, however if the original function is ran then the return could be modified. + +# Modifying or reading parameters +Remember the code from the last section, but let's say that we want to read myInt, or modify it, that can be accomplished by adding that as a parameter to our patch. +```cs +[HarmonyPatch(typeof(MyClass), "myMethod")] +public class Patch_MyClass +{ + public static void Postfix(ref int myInt) // ref is required if we want to modify it + { + myInt = 4; + System.out.println(myInt); + } +} +``` + + +# Miscellaneous parameters for patching +__instance can be used in the parameters of your patch to grab the instance of the class that called the function. +__state can be used to pass a variable between Prefix and Postfix between the same patched function. \ No newline at end of file diff --git a/documentation/harmony/replacing-methods.md b/documentation/harmony/replacing-methods.md deleted file mode 100644 index 692de3536b7a2ad720e50f37ac2fb804f36ddf0e..0000000000000000000000000000000000000000 --- a/documentation/harmony/replacing-methods.md +++ /dev/null @@ -1,13 +0,0 @@ -Use this to replace a method. The return false stops the original method. -```cs -[HarmonyPatch(typeof(ClassName))] -[HarmonyPatch("MethodName")] -public class Patch0 -{ - public static bool Prefix() - { - //Your Custom Code - return false; - } -} -``` \ No newline at end of file diff --git a/documentation/toc.yml b/documentation/toc.yml index 7085145420464cdcce58e72136cf842be85f64da..58b57a28cf2e3ff701467152df3f2735e8cf87c1 100644 --- a/documentation/toc.yml +++ b/documentation/toc.yml @@ -17,14 +17,12 @@ href: api\waiting-for-mission-to-be-reloaded.md - name: Get Users Mods href: api\get-users-mods.md -- name: Harmony Examples +- name: Harmony items: - name: Patching Methods - href: harmony\patching-methods.md - - name: Replacig Methods - href: harmony\replacing-methods.md + href: harmony\patching.md - name: Getting and Setting Private Variables - href: harmony\changing-private-variables.md + href: harmony\Traverse-private-fields.md - name: VTOL VR items: - name: Debug Camera Controls diff --git a/documentation/vtolvr/debug-camera.md b/documentation/vtolvr/debug-camera.md index 3be65bfb694367a460d39c4e1e92eb664d8e2fa5..eaba4b0081182fec13865cc5cd7d651b85de14bb 100644 --- a/documentation/vtolvr/debug-camera.md +++ b/documentation/vtolvr/debug-camera.md @@ -18,6 +18,6 @@ The game has a debug camera which the developer uses to view around the differen > > h - Enables Head debug (Doesn't seem to work) > -> v - Does a toggle mod (Doesn't seem to work) +> v - Switches camera mode from free to chase and vice versa > > t - Does something called tgtMode (Doesn't seem to do anything) \ No newline at end of file diff --git a/images/creating-a-mod/json-example.png b/images/creating-a-mod/json-example.png new file mode 100644 index 0000000000000000000000000000000000000000..84c60865e5bce015c54505f3f5fa44e8f19b690b Binary files /dev/null and b/images/creating-a-mod/json-example.png differ