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;
}
}
}