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.

141 lines
5.4KB

  1. using System;
  2. using System.Reflection;
  3. using HarmonyLib;
  4. using RobocraftX;
  5. using RobocraftX.Services;
  6. using Svelto.Context;
  7. using TechbloxModdingAPI.App;
  8. using TechbloxModdingAPI.Blocks;
  9. using TechbloxModdingAPI.Tasks;
  10. using TechbloxModdingAPI.Utility;
  11. namespace TechbloxModdingAPI
  12. {
  13. /// <summary>
  14. /// The main class of the TechbloxModdingAPI.
  15. /// Use this to initialize the API before calling it.
  16. /// </summary>
  17. public static class Main
  18. {
  19. private static Harmony harmony;
  20. public static bool IsInitialized {
  21. get { return harmony != null; }
  22. }
  23. private static int referenceCount = 0;
  24. /// <summary>
  25. /// Initializes the TechbloxModdingAPI.
  26. /// Call this as soon as possible after Techblox starts up.
  27. /// Ideally, this should be called from your main Plugin class's OnApplicationStart() method.
  28. /// </summary>
  29. public static void Init()
  30. {
  31. referenceCount++;
  32. if (referenceCount > 1) { return; }
  33. if (IsInitialized)
  34. {
  35. Logging.LogWarning("TechbloxModdingAPI.Main.Init() called but API is already initialized!");
  36. return;
  37. }
  38. Logging.MetaDebugLog($"Patching Techblox");
  39. var currentAssembly = Assembly.GetExecutingAssembly();
  40. harmony = new Harmony(currentAssembly.GetName().Name);
  41. try
  42. {
  43. harmony.PatchAll(currentAssembly);
  44. }
  45. catch (Exception e)
  46. {
  47. HandleError(e, "Failed to patch Techblox. Attempting to patch to display error...", OnPatchError);
  48. return;
  49. }
  50. try
  51. {
  52. // init utility
  53. Logging.MetaDebugLog($"Initializing Utility");
  54. Utility.GameState.Init();
  55. // init block implementors
  56. Logging.MetaDebugLog($"Initializing Blocks");
  57. // init input
  58. Input.FakeInput.Init();
  59. // init object-oriented classes
  60. Player.Init();
  61. Block.Init();
  62. BlockGroup.Init();
  63. Wire.Init();
  64. // init client
  65. Logging.MetaDebugLog($"Initializing Client");
  66. Client.Init();
  67. Game.Init();
  68. // init UI
  69. Logging.MetaDebugLog($"Initializing UI");
  70. Interface.IMGUI.Constants.Init();
  71. Interface.IMGUI.IMGUIManager.Init();
  72. // init anti-anticheat
  73. Logging.MetaDebugLog("Initializing anti-anticheat");
  74. AntiAntiCheatPatch.Init(harmony);
  75. Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized");
  76. }
  77. catch (Exception e)
  78. {
  79. HandleError(e, "Failed to initialize the API! Attempting to patch to display error...", OnInitError);
  80. }
  81. }
  82. /// <summary>
  83. /// Shuts down & cleans up the TechbloxModdingAPI.
  84. /// Call this as late as possible before Techblox quits.
  85. /// Ideally, this should be called from your main Plugin class's OnApplicationQuit() method.
  86. /// </summary>
  87. public static void Shutdown()
  88. {
  89. if (referenceCount > 0) { referenceCount--; }
  90. if (referenceCount == 0)
  91. {
  92. if (!IsInitialized)
  93. {
  94. Logging.LogWarning("TechbloxModdingAPI.Main.Shutdown() called but API is not initialized!");
  95. return;
  96. }
  97. Scheduler.Dispose();
  98. var currentAssembly = Assembly.GetExecutingAssembly();
  99. harmony.UnpatchSelf();
  100. harmony = null;
  101. Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} shutdown");
  102. }
  103. }
  104. private static void OnPatchError()
  105. {
  106. ErrorBuilder.DisplayMustQuitError("Failed to patch Techblox!\n" +
  107. "Make sure you're using the latest version of TechbloxModdingAPI or disable mods if the API isn't released yet.");
  108. }
  109. private static void OnInitError()
  110. {
  111. ErrorBuilder.DisplayMustQuitError("Failed to initialize the modding API!\n" +
  112. "Make sure you're using the latest version. If you are, please report the error.");
  113. }
  114. /// <summary>
  115. /// Handles an init error. Logs the exception, a log message, and allows displaying an error in-game.
  116. /// </summary>
  117. /// <param name="e">The exception</param>
  118. /// <param name="logMsg">The log message</param>
  119. /// <param name="onInit">The action to run when the game is ready to display error messages</param>
  120. private static void HandleError(Exception e, string logMsg, Action onInit)
  121. { //Can't use ErrorBuilder or Logging.LogException (which eventually uses ErrorBuilder) yet
  122. Logging.Log(e.ToString());
  123. Logging.LogWarning(logMsg);
  124. harmony.Patch(AccessTools.Method(typeof(FullGameCompositionRoot), "OnContextInitialized")
  125. .MakeGenericMethod(typeof(UnityContext<FullGameCompositionRoot>)),
  126. new HarmonyMethod(onInit.Method)); //Can't use lambdas here :(
  127. }
  128. }
  129. }