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.

139 lines
5.3KB

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