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.

128 lines
5.5KB

  1. using System;
  2. using System.Reflection;
  3. using HarmonyLib;
  4. using RobocraftX;
  5. using RobocraftX.Schedulers;
  6. using RobocraftX.Services;
  7. using Svelto.Context;
  8. using Svelto.Tasks.ExtraLean;
  9. using GamecraftModdingAPI.Blocks;
  10. using GamecraftModdingAPI.Utility;
  11. using GamecraftModdingAPI.Events;
  12. using GamecraftModdingAPI.Tasks;
  13. namespace GamecraftModdingAPI
  14. {
  15. /// <summary>
  16. /// The main class of the GamecraftModdingAPI.
  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 GamecraftModdingAPI.
  28. /// Call this as soon as possible after Gamecraft 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("GamecraftModdingAPI.Main.Init() called but API is already initialized!");
  38. return;
  39. }
  40. Logging.MetaDebugLog($"Patching Gamecraft");
  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 Gamecraft. 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. #pragma warning disable 0612,0618
  59. Utility.GameState.Init();
  60. Utility.VersionTracking.Init();
  61. // create default event emitters
  62. Logging.MetaDebugLog($"Initializing Events");
  63. EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.ApplicationInitialized, "GamecraftModdingAPIApplicationInitializedEventEmitter", false));
  64. EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.Menu, "GamecraftModdingAPIMenuActivatedEventEmitter", false));
  65. EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.MenuSwitchedTo, "GamecraftModdingAPIMenuSwitchedToEventEmitter", false));
  66. EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.Game, "GamecraftModdingAPIGameActivatedEventEmitter", false));
  67. EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameReloaded, "GamecraftModdingAPIGameReloadedEventEmitter", false));
  68. EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameSwitchedTo, "GamecraftModdingAPIGameSwitchedToEventEmitter", false));
  69. EventManager.AddEventEmitter(GameHostTransitionDeterministicGroupEnginePatch.buildEngine);
  70. EventManager.AddEventEmitter(GameHostTransitionDeterministicGroupEnginePatch.simEngine);
  71. #pragma warning restore 0612,0618
  72. // init block implementors
  73. Logging.MetaDebugLog($"Initializing Blocks");
  74. // init inventory
  75. Inventory.Hotbar.Init();
  76. // init input
  77. Input.FakeInput.Init();
  78. // init object-oriented classes
  79. Player.Init();
  80. Block.Init();
  81. BlockGroup.Init();
  82. Wire.Init();
  83. GameClient.Init();
  84. AsyncUtils.Init();
  85. GamecraftModdingAPI.App.Client.Init();
  86. GamecraftModdingAPI.App.Game.Init();
  87. CustomBlock.Prepare().RunOn(ExtraLean.UIScheduler);
  88. Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized");
  89. }
  90. /// <summary>
  91. /// Shuts down & cleans up the GamecraftModdingAPI.
  92. /// Call this as late as possible before Gamecraft quits.
  93. /// Ideally, this should be called from your main Plugin class's OnApplicationQuit() method.
  94. /// </summary>
  95. public static void Shutdown()
  96. {
  97. if (referenceCount > 0) { referenceCount--; }
  98. if (referenceCount == 0)
  99. {
  100. if (!IsInitialized)
  101. {
  102. Logging.LogWarning("GamecraftModdingAPI.Main.Shutdown() called but API is not initialized!");
  103. return;
  104. }
  105. Scheduler.Dispose();
  106. var currentAssembly = Assembly.GetExecutingAssembly();
  107. harmony.UnpatchAll(currentAssembly.GetName().Name);
  108. harmony = null;
  109. Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} shutdown");
  110. }
  111. }
  112. private static void OnPatchError()
  113. {
  114. ErrorBuilder.DisplayMustQuitError("Failed to patch Gamecraft!\n" +
  115. "Make sure you're using the latest version of GamecraftModdingAPI or disable mods if the API isn't released yet.");
  116. }
  117. }
  118. }