A stable modding interface between Techblox and mods https://mod.exmods.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
6.1KB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using HarmonyLib;
  5. using RobocraftX;
  6. using RobocraftX.Services;
  7. using Svelto.Context;
  8. using Svelto.Tasks;
  9. using TechbloxModdingAPI.App;
  10. using TechbloxModdingAPI.Blocks;
  11. using TechbloxModdingAPI.Tasks;
  12. using TechbloxModdingAPI.Utility;
  13. namespace TechbloxModdingAPI
  14. {
  15. /// <summary>
  16. /// The main class of the TechbloxModdingAPI.
  17. /// Use this to initialize the API before calling it.
  18. /// </summary>
  19. public static class Main
  20. {
  21. private static Harmony harmony;
  22. public static bool IsInitialized {
  23. get { return harmony != null; }
  24. }
  25. private static int referenceCount = 0;
  26. /// <summary>
  27. /// Initializes the TechbloxModdingAPI.
  28. /// Call this as soon as possible after Techblox starts up.
  29. /// Ideally, this should be called from your main Plugin class's OnApplicationStart() method.
  30. /// </summary>
  31. public static void Init()
  32. {
  33. referenceCount++;
  34. if (referenceCount > 1) { return; }
  35. if (IsInitialized)
  36. {
  37. Logging.LogWarning("TechbloxModdingAPI.Main.Init() called but API is already initialized!");
  38. return;
  39. }
  40. Logging.MetaDebugLog($"Patching Techblox");
  41. var currentAssembly = Assembly.GetExecutingAssembly();
  42. harmony = new Harmony(currentAssembly.GetName().Name);
  43. try
  44. {
  45. harmony.PatchAll(currentAssembly);
  46. }
  47. catch (Exception e)
  48. { //Can't use ErrorBuilder or Logging.LogException (which eventually uses ErrorBuilder) yet
  49. Logging.Log(e.ToString());
  50. Logging.LogWarning("Failed to patch Techblox. Attempting to patch to display error...");
  51. harmony.Patch(AccessTools.Method(typeof(FullGameCompositionRoot), "OnContextInitialized")
  52. .MakeGenericMethod(typeof(UnityContext<FullGameCompositionRoot>)),
  53. new HarmonyMethod(((Action) OnPatchError).Method)); //Can't use lambdas here :(
  54. return;
  55. }
  56. // init utility
  57. Logging.MetaDebugLog($"Initializing Utility");
  58. Utility.GameState.Init();
  59. // init block implementors
  60. Logging.MetaDebugLog($"Initializing Blocks");
  61. // init input
  62. Input.FakeInput.Init();
  63. // init object-oriented classes
  64. Player.Init();
  65. Block.Init();
  66. BlockGroup.Init();
  67. Wire.Init();
  68. Logging.MetaDebugLog($"Initializing Client");
  69. Client.Init();
  70. Game.Init();
  71. // init UI
  72. Interface.IMGUI.Constants.Init();
  73. Interface.IMGUI.IMGUIManager.Init();
  74. Logging.MetaDebugLog("Initializing anti-anticheat");
  75. var type = AccessTools.TypeByName("Techblox.Services.Eos.Anticheat.Client.Services.AnticheatClientService");
  76. harmony.Patch(type.GetConstructors()[0], new HarmonyMethod(((Func<bool>) AntiAntiCheat).Method));
  77. harmony.Patch(AccessTools.Method(type, "Shutdown"), new HarmonyMethod(((Func<bool>) AntiAntiCheat).Method));
  78. harmony.Patch(AccessTools.Method(type, "StartProtectedSession"), new HarmonyMethod(((AntiAnticheatDelegate) AntiAntiCheat).Method));
  79. harmony.Patch(AccessTools.Method(type, "StopProtectedSession"), new HarmonyMethod(((AntiAnticheatDelegateBool) AntiAntiCheat).Method));
  80. harmony.Patch(AccessTools.Method("Techblox.Services.Eos.Anticheat.Client.EosGetPendingMessagesToSendServiceRequest:Execute"), new HarmonyMethod(((AntiAnticheatDelegateTask)AntiAntiCheatTask).Method));
  81. Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized");
  82. }
  83. public delegate bool AntiAnticheatDelegate(ref object __result);
  84. public delegate bool AntiAnticheatDelegateBool(ref bool __result);
  85. public delegate bool AntiAnticheatDelegateTask(ref IEnumerator<TaskContract> __result);
  86. /// <summary>
  87. /// Shuts down & cleans up the TechbloxModdingAPI.
  88. /// Call this as late as possible before Techblox quits.
  89. /// Ideally, this should be called from your main Plugin class's OnApplicationQuit() method.
  90. /// </summary>
  91. public static void Shutdown()
  92. {
  93. if (referenceCount > 0) { referenceCount--; }
  94. if (referenceCount == 0)
  95. {
  96. if (!IsInitialized)
  97. {
  98. Logging.LogWarning("TechbloxModdingAPI.Main.Shutdown() called but API is not initialized!");
  99. return;
  100. }
  101. Scheduler.Dispose();
  102. var currentAssembly = Assembly.GetExecutingAssembly();
  103. harmony.UnpatchAll(currentAssembly.GetName().Name);
  104. harmony = null;
  105. Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} shutdown");
  106. }
  107. }
  108. private static void OnPatchError()
  109. {
  110. ErrorBuilder.DisplayMustQuitError("Failed to patch Techblox!\n" +
  111. "Make sure you're using the latest version of TechbloxModdingAPI or disable mods if the API isn't released yet.");
  112. }
  113. private static bool AntiAntiCheat() => false;
  114. private static bool AntiAntiCheat(ref object __result)
  115. {
  116. var targetType =
  117. AccessTools.TypeByName("Techblox.Services.Eos.Anticheat.Client.Services.StartProtectedSessionResult");
  118. var target = Activator.CreateInstance(targetType);
  119. targetType.GetField("Success").SetValue(target, true);
  120. __result = target;
  121. return false;
  122. }
  123. private static bool AntiAntiCheat(ref bool __result)
  124. {
  125. __result = true;
  126. return false;
  127. }
  128. private static bool AntiAntiCheatTask(ref IEnumerator<TaskContract> __result)
  129. {
  130. IEnumerator<TaskContract> Func()
  131. {
  132. yield return Yield.It;
  133. }
  134. __result = Func();
  135. return false;
  136. }
  137. }
  138. }