diff --git a/README.md b/README.md index f2575cd..541d729 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,18 @@ Proof of concept mod and reference implementation ## Installation -1. Patch Gamecraft with [IPA](https://github.com/Eusth/IPA). -You will need to build it yourself; the latest release does not work (in the future the latest build will be available for download) -2. Build TestMod solution and copy `obj\Debug\net45\TestMod.dll` into Gamecraft's `Plugins\` folder (IPA should have created this automatically in the previous step) +1. Patch Gamecraft with [GCIPA](https://git.exmods.org/modtainers/GCIPA). +You should download the latest release and extract it to the Gamecraft folder. +To patch, drag `Gamecraft.exe` onto `IPA.exe`. You will need to redo this step whenever Gamecraft is updated. +2. Extract the TestMod zip into Gamecraft's `Plugins\` folder (GCIPA should have created this automatically in the previous step). You should see `0Harmony.dll` and `TestMod.dll` in the `Plugins\` folder. If those files are in another folder in `Plugins\` it will not work. 3. Launch Gamecraft. -You can check the log file `%APPDATA%\..\LocalLow\FreeJam\RobocraftX\Player.log` to confirm +You can check the log file `%APPDATA%\..\LocalLow\FreeJam\RobocraftX\Player.log` to confirm. +You should be able to see a message near the top showing how many plugins (should be 1) have been loaded and their names (should be TestPlugin v0.0.0a). ## Development Interested in making your own mod? Clone this repository and modify the Plugin class in `TestMod\TestPlugin.cs`. +Patch Gamecraft with [GCIPA](#installation) +Build the solution and copy `bin\Debug\net45\TestMod.dll` and `bin\Debug\net45\0Harmony.dll` into Gamecraft's `Plugins\` folder. More information about the IPlugin and IEnhancedPlugin interface can be found [on the IPA repository](https://github.com/Eusth/IPA) diff --git a/TestMod/TeleportEnginePatch.cs b/TestMod/TeleportEnginePatch.cs index fd31ec6..f4c2346 100644 --- a/TestMod/TeleportEnginePatch.cs +++ b/TestMod/TeleportEnginePatch.cs @@ -13,9 +13,17 @@ namespace TestMod.Waypoints { static TeleportCharacterCommandEngine Instance {get; private set;} - static void Postfix(TeleportCharacterCommandEngine __result) + static void Postfix(TeleportCharacterCommandEngine __result, TeleportCharacterCommandEngine __instance) { - Instance = __result; + // this works because this class should be a singleton; only one copy of it should exist at a time + if (__instance != null) + { + Instance = __instance; + Debug.Log("Instance caught from constructor"); + } else { + Instance = __result; + Debug.Log("Result caught from constructor") + } Debug.Log("Caught TeleportCharacterCommandEngine"); } } diff --git a/TestMod/TeleportPatch.cs b/TestMod/TeleportPatch.cs index f782f92..20ef009 100644 --- a/TestMod/TeleportPatch.cs +++ b/TestMod/TeleportPatch.cs @@ -3,14 +3,20 @@ using System.Dictionary.Generic; using Harmony; using UnityEngine; using Unity.Mathematics; +using RobocraftX.Character; +using RobocraftX.StateSync; using RobocraftX.GUI.CommandLine; using uREPL; namespace TestMod.Waypoints { - [HarmonyPatch] + [HarmonyPatch(typeof(uREPL.RuntimeCommands))] + [HarmonyPatch("Register")] + [HarmonyPatch(new Type[] { typeof(string), typeof(Action), typeof(string) })] class TeleportPatch { + // TeleportPatch intercepts all Register(string, Action string) method calls + // which allows it to catch Teleport Actions as they're registered as CLI commands static Action TeleportAbsolute {get; private set;} static Action TeleportRelative {get; private set;} @@ -19,7 +25,7 @@ namespace TestMod.Waypoints static void Prefix(string name, Action func, string description) { - Debug.Log("Caught Register for "+name); + Debug.Log("Caught Register method call for "+name); if (name.Equals("TeleportPlayerAbsolute")) { TeleportAbsolute = func; @@ -31,13 +37,7 @@ namespace TestMod.Waypoints } } - static MethodBase TargetMethod(HarmonyInstance instance) - { - Type CLUtility = AccessTools.TypeByName("RobocraftX.GUI.CommandLine.CommandLineUtility"); - return Harmony.AccessTools.Method(CLUtility, "Register", new Type[]{ typeof(string), typeof(Action), typeof(string) }, new Type[]{ typeof(float), typeof(float), typeof(float) }); - } - - static void WaypointCommand(object name) + static void WaypointHereCommand(object name) { // hopefully entitiesDB does not become private in the future... if (TeleportEnginePatch.Instance == null) @@ -45,16 +45,16 @@ namespace TestMod.Waypoints uREPL.Log.Error("Teleport command object missing!"); return; } - ref RigidBodyEntityStruct reference = ref TeleportEnginePatch.Instance.entitiesDB.QueryEntity(0u, CharacterExclusiveGroups.CharacterGroup); if (_waypoints.ContainsKey(name)) { _waypoints.Remove(name); } + ref RigidBodyEntityStruct reference = ref TeleportEnginePatch.Instance.entitiesDB.QueryEntity(0u, CharacterExclusiveGroups.CharacterGroup); _waypoints.Add(new float[3]{reference.x, reference.y, reference.z}); uREPL.Log.Output("Saved "+name.ToString()); } - static void TeleportWaypointCommand(object name) + static void TeleportToWaypointCommand(object name) { if (!_waypoints.ContainsKey(name)) { @@ -66,7 +66,7 @@ namespace TestMod.Waypoints uREPL.Log.Error("TeleportPlayerAbsolute command missing!"); return; } - TeleportAbsolute(_waypoints[name]); + TeleportAbsolute(_waypoints[name][0], _waypoints[name][1], _waypoints[name][2]); uREPL.Log.Output("Teleported player to "+name.ToString()); } } diff --git a/TestMod/TestPlugin.cs b/TestMod/TestPlugin.cs index 2e1828b..bc22d05 100644 --- a/TestMod/TestPlugin.cs +++ b/TestMod/TestPlugin.cs @@ -37,6 +37,11 @@ namespace TestMod commandHelp.Invoke(null, new string[] { "Echo", "Write a message to the command line" }); uREPL.RuntimeCommands.Register("Exit", QuitCommand, "Close Gamecraft"); commandHelp.Invoke(null, new string[] { "Exit", "Forcefully exit Gamecraft immediately" }); + // waypoint commands + uREPL.RuntimeCommands.Register("WaypointHere", Waypoints.WaypointHereCommand, "/shrug"); + commandHelp.Invoke(null, new string[] { "WaypointHere", "Create a named waypoint in your current location" }); + uREPL.RuntimeCommands.Register("TeleportToWaypoint", Waypoints.TeleportToWaypoint, "Blame Josh"); + commandHelp.Invoke(null, new string[] { "TeleportToWaypoint", "Teleport to a waypoint by name" }); Debug.Log("TestPlugin startup complete"); }