using System; using System.Collections.Generic; using System.Reflection; using HarmonyLib; using RobocraftX; using RobocraftX.Services; using Svelto.Context; using Svelto.Tasks; using TechbloxModdingAPI.App; using TechbloxModdingAPI.Blocks; using TechbloxModdingAPI.Tasks; using TechbloxModdingAPI.Utility; namespace TechbloxModdingAPI { /// /// The main class of the TechbloxModdingAPI. /// Use this to initialize the API before calling it. /// public static class Main { private static Harmony harmony; public static bool IsInitialized { get { return harmony != null; } } private static int referenceCount = 0; /// /// Initializes the TechbloxModdingAPI. /// Call this as soon as possible after Techblox starts up. /// Ideally, this should be called from your main Plugin class's OnApplicationStart() method. /// public static void Init() { referenceCount++; if (referenceCount > 1) { return; } if (IsInitialized) { Logging.LogWarning("TechbloxModdingAPI.Main.Init() called but API is already initialized!"); return; } Logging.MetaDebugLog($"Patching Techblox"); var currentAssembly = Assembly.GetExecutingAssembly(); harmony = new Harmony(currentAssembly.GetName().Name); try { harmony.PatchAll(currentAssembly); } catch (Exception e) { //Can't use ErrorBuilder or Logging.LogException (which eventually uses ErrorBuilder) yet Logging.Log(e.ToString()); Logging.LogWarning("Failed to patch Techblox. Attempting to patch to display error..."); harmony.Patch(AccessTools.Method(typeof(FullGameCompositionRoot), "OnContextInitialized") .MakeGenericMethod(typeof(UnityContext)), new HarmonyMethod(((Action) OnPatchError).Method)); //Can't use lambdas here :( return; } // init utility Logging.MetaDebugLog($"Initializing Utility"); Utility.GameState.Init(); // init block implementors Logging.MetaDebugLog($"Initializing Blocks"); // init input Input.FakeInput.Init(); // init object-oriented classes Player.Init(); Block.Init(); BlockGroup.Init(); Wire.Init(); Logging.MetaDebugLog($"Initializing Client"); Client.Init(); Game.Init(); // init UI Interface.IMGUI.Constants.Init(); Interface.IMGUI.IMGUIManager.Init(); Logging.MetaDebugLog("Initializing anti-anticheat"); var type = AccessTools.TypeByName("Techblox.Services.Eos.Anticheat.Client.Services.AnticheatClientService"); harmony.Patch(type.GetConstructors()[0], new HarmonyMethod(((Func) AntiAntiCheat).Method)); harmony.Patch(AccessTools.Method(type, "Shutdown"), new HarmonyMethod(((Func) AntiAntiCheat).Method)); harmony.Patch(AccessTools.Method(type, "StartProtectedSession"), new HarmonyMethod(((AntiAnticheatDelegate) AntiAntiCheat).Method)); harmony.Patch(AccessTools.Method(type, "StopProtectedSession"), new HarmonyMethod(((AntiAnticheatDelegateBool) AntiAntiCheat).Method)); harmony.Patch(AccessTools.Method("Techblox.Services.Eos.Anticheat.Client.EosGetPendingMessagesToSendServiceRequest:Execute"), new HarmonyMethod(((AntiAnticheatDelegateTask)AntiAntiCheatTask).Method)); Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized"); } public delegate bool AntiAnticheatDelegate(ref object __result); public delegate bool AntiAnticheatDelegateBool(ref bool __result); public delegate bool AntiAnticheatDelegateTask(ref IEnumerator __result); /// /// Shuts down & cleans up the TechbloxModdingAPI. /// Call this as late as possible before Techblox quits. /// Ideally, this should be called from your main Plugin class's OnApplicationQuit() method. /// public static void Shutdown() { if (referenceCount > 0) { referenceCount--; } if (referenceCount == 0) { if (!IsInitialized) { Logging.LogWarning("TechbloxModdingAPI.Main.Shutdown() called but API is not initialized!"); return; } Scheduler.Dispose(); var currentAssembly = Assembly.GetExecutingAssembly(); harmony.UnpatchAll(currentAssembly.GetName().Name); harmony = null; Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} shutdown"); } } private static void OnPatchError() { ErrorBuilder.DisplayMustQuitError("Failed to patch Techblox!\n" + "Make sure you're using the latest version of TechbloxModdingAPI or disable mods if the API isn't released yet."); } private static bool AntiAntiCheat() => false; private static bool AntiAntiCheat(ref object __result) { var targetType = AccessTools.TypeByName("Techblox.Services.Eos.Anticheat.Client.Services.StartProtectedSessionResult"); var target = Activator.CreateInstance(targetType); targetType.GetField("Success").SetValue(target, true); __result = target; return false; } private static bool AntiAntiCheat(ref bool __result) { __result = true; return false; } private static bool AntiAntiCheatTask(ref IEnumerator __result) { IEnumerator Func() { yield return Yield.It; } __result = Func(); return false; } } }