Decompiled source of ThuliumAPI v1.1.0

ThuliumAPI.dll

Decompiled 6 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ThuliumAPI")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ThuliumAPI")]
[assembly: AssemblyTitle("ThuliumAPI")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ThuliumAPI;

[BepInPlugin("com.ngeorge.thuliumapi", "Thulium API", "1.1.0")]
public class ThuliumAPI : BaseUnityPlugin
{
	public static ManualLogSource Log;

	public static Harmony Harmony;

	public static bool EnableAssemblyDump { get; private set; }

	public static bool DumpClassesOnly { get; private set; }

	public static string AssemblyDumpPath => Path.Combine(Path.GetTempPath(), "ThuliumAPI_AssemblyDump.txt");

	private void Awake()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Harmony = new Harmony("com.ngeorge.thuliumapi");
		Log.LogMessage((object)"Thulium API loading...");
		ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableAssemblyDump", false, "Enable assembly dump to console (logs all classes and methods)");
		EnableAssemblyDump = val.Value;
		ConfigEntry<bool> val2 = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DumpClassesOnly", false, "If enabled, only dump class names without methods");
		DumpClassesOnly = val2.Value;
		try
		{
			Hooks.Init();
			GameAPI.Init();
			ContentRegistry.Init();
			if (EnableAssemblyDump || DumpClassesOnly)
			{
				Log.LogMessage((object)("Assembly dump enabled. Writing to: " + AssemblyDumpPath));
				DumpAssembly();
			}
			Log.LogMessage((object)"Thulium API loaded successfully.");
		}
		catch (Exception arg)
		{
			Log.LogError((object)$"API INIT FAILED: {arg}");
		}
	}

	private void DumpAssembly()
	{
		try
		{
			Log.LogMessage((object)"=== ASSEMBLY DUMP START ===");
			Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "Assembly-CSharp");
			if (assembly == null)
			{
				Log.LogWarning((object)"Assembly-CSharp not found!");
				return;
			}
			List<Type> list = (from t in assembly.GetTypes()
				orderby t.Name
				select t).ToList();
			Log.LogMessage((object)$"Total Classes: {list.Count}");
			Log.LogMessage((object)"");
			foreach (Type item in list)
			{
				if (DumpClassesOnly)
				{
					Log.LogMessage((object)("[" + item.Name + "]"));
					continue;
				}
				List<MethodInfo> declaredMethods = AccessTools.GetDeclaredMethods(item);
				if (!declaredMethods.Any())
				{
					continue;
				}
				Log.LogMessage((object)("┌─ [" + item.Name + "]"));
				foreach (MethodInfo item2 in declaredMethods.OrderBy((MethodInfo m) => m.Name))
				{
					string text = string.Join(", ", from p in item2.GetParameters()
						select p.ParameterType.Name);
					Log.LogMessage((object)("  ├─ " + item2.ReturnType.Name + " " + item2.Name + "(" + text + ")"));
				}
				Log.LogMessage((object)"└──");
			}
			Log.LogMessage((object)"=== ASSEMBLY DUMP COMPLETE ===");
		}
		catch (Exception arg)
		{
			Log.LogError((object)$"Assembly dump failed: {arg}");
		}
	}
}
public static class Hooks
{
	public static event Action OnGameStart;

	public static event Action OnGameUpdate;

	public static event Action<string> OnSceneLoaded;

	public static event Action<KeyCode> OnKeyPressed;

	public static event Action<int> OnDifficultyChanged;

	public static event Action<UnitPropertyProxy> OnEnemySpawn;

	public static event Action<UnitPropertyProxy> OnEnemyDeath;

	public static event Action<DamageProxy> OnPlayerDamaged;

	public static event Action<DamageProxy> OnEnemyDamaged;

	public static event Func<DamageProxy, bool> OnBeforePlayerDamage;

	public static event Func<DamageProxy, bool> OnBeforeEnemyDamage;

	public static event Func<SpawnRequestProxy, bool> OnBeforeEnemySpawn;

	public static event Action<UnitPropertyProxy, float> OnPlayerHealed;

	public static void Init()
	{
		Harmony harmony = ThuliumAPI.Harmony;
		ThuliumAPI.Log.LogMessage((object)"Patching GameMgr.Start...");
		Patch(harmony, "GameMgr", "Start", null, "GameStart_Postfix");
		ThuliumAPI.Log.LogMessage((object)"Patching GameMgr.Update...");
		Patch(harmony, "GameMgr", "Update", null, "GameUpdate_Postfix");
		ThuliumAPI.Log.LogMessage((object)"Patching DataMgr.SaveSelectedWorldData...");
		Patch(harmony, "DataMgr", "SaveSelectedWorldData", null, "DifficultyChanged_Postfix");
		ThuliumAPI.Log.LogMessage((object)"Patching UnitProperty.TakeDamage...");
		Type type = AccessTools.TypeByName("UnitProperty");
		PatchMethod(harmony, type, "TakeDamage", new Type[3]
		{
			typeof(float),
			AccessTools.TypeByName("AttackerType"),
			AccessTools.TypeByName("TakeDamageInfo")
		}, "TakeDamage_Prefix", "TakeDamage_Postfix");
		ThuliumAPI.Log.LogMessage((object)"Patching UnitProperty.HPRecovery...");
		PatchMethod(harmony, type, "HPRecovery", null, null, "HPRecovery_Postfix");
		ThuliumAPI.Log.LogMessage((object)"Patching UnitProperty.AnnouncedDeath...");
		PatchMethod(harmony, type, "AnnouncedDeath", null, null, "AnnouncedDeath_Postfix");
		ThuliumAPI.Log.LogMessage((object)"Patching BattleMgr.SpawnUnit...");
		PatchByName(harmony, "BattleMgr", "SpawnUnit", "SpawnUnit_Prefix", "SpawnUnit_Postfix");
		ThuliumAPI.Log.LogMessage((object)"Patching SceneManager.Internal_SceneLoaded...");
		MethodInfo methodInfo = AccessTools.Method("UnityEngine.SceneManagement.SceneManager:Internal_SceneLoaded", (Type[])null, (Type[])null);
		if (methodInfo != null)
		{
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, HM("SceneLoaded_Postfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
		ThuliumAPI.Log.LogMessage((object)"✓ All hooks initialized successfully!");
	}

	private static void Patch(Harmony h, string type, string method, string prefix = null, string postfix = null)
	{
		MethodInfo methodInfo = AccessTools.Method(type + ":" + method, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			ThuliumAPI.Log.LogWarning((object)("Hook target not found: " + type + "." + method));
		}
		else
		{
			h.Patch((MethodBase)methodInfo, (prefix != null) ? HM(prefix) : null, (postfix != null) ? HM(postfix) : null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
	}

	private static void PatchMethod(Harmony h, Type type, string method, Type[] args, string prefix = null, string postfix = null)
	{
		MethodInfo methodInfo = ((args != null) ? AccessTools.Method(type, method, args, (Type[])null) : AccessTools.Method(type, method, (Type[])null, (Type[])null));
		if (methodInfo == null)
		{
			ThuliumAPI.Log.LogWarning((object)("Hook target not found: " + type?.Name + "." + method));
		}
		else
		{
			h.Patch((MethodBase)methodInfo, (prefix != null) ? HM(prefix) : null, (postfix != null) ? HM(postfix) : null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
	}

	private static void PatchByName(Harmony h, string type, string method, string prefix = null, string postfix = null)
	{
		Type type2 = AccessTools.TypeByName(type);
		if (type2 == null)
		{
			ThuliumAPI.Log.LogWarning((object)("Type not found: " + type));
			return;
		}
		foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type2))
		{
			if (!(declaredMethod.Name != method))
			{
				h.Patch((MethodBase)declaredMethod, (prefix != null) ? HM(prefix) : null, (postfix != null) ? HM(postfix) : null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}
	}

	private static HarmonyMethod HM(string name)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Expected O, but got Unknown
		return new HarmonyMethod(typeof(Hooks), name, (Type[])null);
	}

	private static void GameStart_Postfix()
	{
		Hooks.OnGameStart?.Invoke();
	}

	private static void GameUpdate_Postfix()
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		Hooks.OnGameUpdate?.Invoke();
		foreach (KeyCode value in Enum.GetValues(typeof(KeyCode)))
		{
			if (Input.GetKeyDown(value))
			{
				Hooks.OnKeyPressed?.Invoke(value);
			}
		}
	}

	private static void DifficultyChanged_Postfix()
	{
		try
		{
			Hooks.OnDifficultyChanged?.Invoke(GameAPI.GetDifficulty());
		}
		catch
		{
		}
	}

	private static void SceneLoaded_Postfix(Scene scene)
	{
		Hooks.OnSceneLoaded?.Invoke(((Scene)(ref scene)).name);
	}

	private static bool TakeDamage_Prefix(object __instance, ref float damage, object info)
	{
		DamageProxy damageProxy = new DamageProxy(__instance, damage, info);
		Component val = (Component)((__instance is Component) ? __instance : null);
		Func<DamageProxy, bool> func = (((Object)(object)val != (Object)null && val.CompareTag("Player")) ? Hooks.OnBeforePlayerDamage : Hooks.OnBeforeEnemyDamage);
		if (func != null)
		{
			Delegate[] invocationList = func.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Func<DamageProxy, bool> func2 = (Func<DamageProxy, bool>)invocationList[i];
				if (!func2(damageProxy))
				{
					return false;
				}
			}
			damage = damageProxy.Damage;
		}
		return true;
	}

	private static void TakeDamage_Postfix(object __instance, float damage, object info)
	{
		DamageProxy obj = new DamageProxy(__instance, damage, info);
		Component val = (Component)((__instance is Component) ? __instance : null);
		if ((Object)(object)val != (Object)null && val.CompareTag("Player"))
		{
			Hooks.OnPlayerDamaged?.Invoke(obj);
		}
		else
		{
			Hooks.OnEnemyDamaged?.Invoke(obj);
		}
	}

	private static void HPRecovery_Postfix(object __instance, float hp)
	{
		UnitPropertyProxy arg = new UnitPropertyProxy(__instance);
		Hooks.OnPlayerHealed?.Invoke(arg, hp);
	}

	private static void AnnouncedDeath_Postfix(object __instance)
	{
		object obj = ((__instance is Component) ? __instance : null);
		GameObject val = ((obj != null) ? ((Component)obj).gameObject : null);
		if ((Object)(object)val != (Object)null && !val.CompareTag("Player"))
		{
			Hooks.OnEnemyDeath?.Invoke(new UnitPropertyProxy(__instance));
		}
	}

	private static bool SpawnUnit_Prefix(object __instance, ref object unitConfig, ref Vector3 pos)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		SpawnRequestProxy spawnRequestProxy = new SpawnRequestProxy(unitConfig, pos);
		if (Hooks.OnBeforeEnemySpawn != null)
		{
			Delegate[] invocationList = Hooks.OnBeforeEnemySpawn.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Func<SpawnRequestProxy, bool> func = (Func<SpawnRequestProxy, bool>)invocationList[i];
				if (!func(spawnRequestProxy))
				{
					return false;
				}
			}
			pos = spawnRequestProxy.Position;
		}
		return true;
	}

	private static void SpawnUnit_Postfix(object __instance, GameObject __result)
	{
		if ((Object)(object)__result != (Object)null)
		{
			Hooks.OnEnemySpawn?.Invoke(new UnitPropertyProxy(__result.GetComponent<Component>()));
		}
	}
}
public sealed class UnitPropertyProxy
{
	private static readonly FieldInfo _f_currentHP = AccessTools.Field(AccessTools.TypeByName("UnitProperty"), "currentHP");

	private static readonly FieldInfo _f_maxHP = AccessTools.Field(AccessTools.TypeByName("UnitConfig"), "maxHP");

	private static readonly PropertyInfo _p_isUnitDead = AccessTools.Property(AccessTools.TypeByName("UnitProperty"), "isUnitDead");

	private static readonly PropertyInfo _p_isInvincible = AccessTools.Property(AccessTools.TypeByName("UnitProperty"), "IsInvincible");

	private static readonly PropertyInfo _p_unitCfg = AccessTools.Property(AccessTools.TypeByName("UnitProperty"), "UnitCfg");

	private static readonly FieldInfo _f_invincibleCtr = AccessTools.Field(AccessTools.TypeByName("UnitProperty"), "invincibleCounter");

	private readonly object _raw;

	public float CurrentHP
	{
		get
		{
			return (_raw != null) ? ((float)(_f_currentHP?.GetValue(_raw) ?? ((object)0f))) : 0f;
		}
		set
		{
			_f_currentHP?.SetValue(_raw, value);
		}
	}

	public float MaxHP
	{
		get
		{
			object obj = _p_unitCfg?.GetValue(_raw);
			return (obj != null) ? ((float)(_f_maxHP?.GetValue(obj) ?? ((object)0f))) : 0f;
		}
	}

	public bool IsDead => (bool)(_p_isUnitDead?.GetValue(_raw) ?? ((object)true));

	public bool IsInvincible => (bool)(_p_isInvincible?.GetValue(_raw) ?? ((object)false));

	public GameObject GameObject
	{
		get
		{
			object raw = _raw;
			object obj = ((raw is Component) ? raw : null);
			return (obj != null) ? ((Component)obj).gameObject : null;
		}
	}

	public Transform Transform
	{
		get
		{
			object raw = _raw;
			object obj = ((raw is Component) ? raw : null);
			return (obj != null) ? ((Component)obj).transform : null;
		}
	}

	public UnitPropertyProxy(object rawUnitProperty)
	{
		_raw = rawUnitProperty;
	}

	public void SetInvincible(bool on)
	{
		int num = (int)(_f_invincibleCtr?.GetValue(_raw) ?? ((object)0));
		_f_invincibleCtr?.SetValue(_raw, on ? Mathf.Max(1, num) : 0);
	}

	public override string ToString()
	{
		return $"UnitPropertyProxy(HP={CurrentHP}/{MaxHP}, dead={IsDead})";
	}
}
public sealed class DamageProxy
{
	private static readonly Type _t = AccessTools.TypeByName("TakeDamageInfo");

	private static readonly FieldInfo _f_damage = AccessTools.Field(_t, "damage");

	private static readonly FieldInfo _f_isCrit = AccessTools.Field(_t, "isCriticalDamage");

	private static readonly FieldInfo _f_immune = AccessTools.Field(_t, "immuneDamage");

	private static readonly FieldInfo _f_isPerc = AccessTools.Field(_t, "isPercentageDamage");

	private static readonly FieldInfo _f_trap = AccessTools.Field(_t, "isTrapDamage");

	private static readonly FieldInfo _f_kb = AccessTools.Field(_t, "knockbackForce");

	private static readonly FieldInfo _f_attPpt = AccessTools.Field(_t, "attackerPpt");

	private static readonly FieldInfo _f_hitPpt = AccessTools.Field(_t, "beHitPpt");

	private readonly object _info;

	public UnitPropertyProxy Victim { get; }

	public float Damage
	{
		get
		{
			return (_info != null) ? ((float)(_f_damage?.GetValue(_info) ?? ((object)0f))) : 0f;
		}
		set
		{
			if (_info != null)
			{
				_f_damage?.SetValue(_info, value);
			}
		}
	}

	public bool IsCritical
	{
		get
		{
			return _info != null && (bool)(_f_isCrit?.GetValue(_info) ?? ((object)false));
		}
		set
		{
			if (_info != null)
			{
				_f_isCrit?.SetValue(_info, value);
			}
		}
	}

	public bool ImmuneToThisHit
	{
		get
		{
			return _info != null && (bool)(_f_immune?.GetValue(_info) ?? ((object)false));
		}
		set
		{
			if (_info != null)
			{
				_f_immune?.SetValue(_info, value);
			}
		}
	}

	public bool IsPercentageDamage => _info != null && (bool)(_f_isPerc?.GetValue(_info) ?? ((object)false));

	public bool IsTrapDamage => _info != null && (bool)(_f_trap?.GetValue(_info) ?? ((object)false));

	public Vector3 KnockbackForce
	{
		get
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			return (Vector3)((_info != null) ? ((Vector3)(_f_kb?.GetValue(_info) ?? ((object)Vector3.zero))) : Vector3.zero);
		}
		set
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (_info != null)
			{
				_f_kb?.SetValue(_info, value);
			}
		}
	}

	public DamageProxy(object rawUnitProperty, float damage, object rawInfo)
	{
		Victim = new UnitPropertyProxy(rawUnitProperty);
		_info = rawInfo;
		if (rawInfo != null && _f_damage != null)
		{
			_f_damage.SetValue(rawInfo, damage);
		}
	}

	public void SuppressKnockback()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		KnockbackForce = Vector3.zero;
	}

	public override string ToString()
	{
		return $"DamageProxy(dmg={Damage}, crit={IsCritical}, immune={ImmuneToThisHit})";
	}
}
public sealed class SpawnRequestProxy
{
	private static readonly FieldInfo _f_id = AccessTools.Field(AccessTools.TypeByName("UnitConfig"), "id");

	private readonly object _unitCfg;

	public int UnitID => (_unitCfg != null) ? ((int)(_f_id?.GetValue(_unitCfg) ?? ((object)(-1)))) : (-1);

	public Vector3 Position { get; set; }

	public SpawnRequestProxy(object unitConfig, Vector3 pos)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		_unitCfg = unitConfig;
		Position = pos;
	}

	public override string ToString()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		return $"SpawnRequest(id={UnitID}, pos={Position})";
	}
}
public static class GameAPI
{
	private static Type _tDataMgr;

	private static Type _tWorldData;

	private static Type _tUnitProperty;

	private static Type _tBattleMgr;

	private static Type _tPlayerMgr;

	private static FieldInfo _f_selectedWorldData;

	private static FieldInfo _f_selectedDifficulty;

	private static PropertyInfo _p_battleMgrInst;

	private static PropertyInfo _p_playerMgrInst;

	private static PropertyInfo _p_gameMgrInst;

	private static MethodInfo _m_hpRecovery;

	private static MethodInfo _m_announcedDeath;

	private static GameObject _playerCache;

	public static object BattleMgr => _p_battleMgrInst?.GetValue(null);

	public static object PlayerMgr => _p_playerMgrInst?.GetValue(null);

	public static object GameMgr => _p_gameMgrInst?.GetValue(null);

	public static void Init()
	{
		_tDataMgr = AccessTools.TypeByName("DataMgr");
		_tWorldData = AccessTools.TypeByName("WorldData");
		_tUnitProperty = AccessTools.TypeByName("UnitProperty");
		_tBattleMgr = AccessTools.TypeByName("BattleMgr");
		_tPlayerMgr = AccessTools.TypeByName("PlayerMgr");
		_f_selectedWorldData = AccessTools.Field(_tDataMgr, "selectedWorldData");
		_f_selectedDifficulty = AccessTools.Field(_tWorldData, "selectedDifficulty");
		_p_battleMgrInst = AccessTools.Property(_tBattleMgr, "Inst");
		_p_playerMgrInst = AccessTools.Property(_tPlayerMgr, "Inst");
		_p_gameMgrInst = AccessTools.Property(AccessTools.TypeByName("GameMgr"), "Inst");
		_m_hpRecovery = AccessTools.Method(_tUnitProperty, "HPRecovery", (Type[])null, (Type[])null);
		_m_announcedDeath = AccessTools.Method(_tUnitProperty, "AnnouncedDeath", (Type[])null, (Type[])null);
		ThuliumAPI.Log.LogMessage((object)"GameAPI ready.");
	}

	public static object GetWorldData()
	{
		return _f_selectedWorldData?.GetValue(null);
	}

	public static int GetDifficulty()
	{
		object worldData = GetWorldData();
		return (worldData != null) ? ((int)(_f_selectedDifficulty?.GetValue(worldData) ?? ((object)0))) : 0;
	}

	public static void SetDifficulty(int difficulty)
	{
		object worldData = GetWorldData();
		if (worldData != null)
		{
			_f_selectedDifficulty?.SetValue(worldData, difficulty);
		}
	}

	public static GameObject GetPlayer()
	{
		if ((Object)(object)_playerCache == (Object)null)
		{
			_playerCache = GameObject.FindWithTag("Player");
		}
		return _playerCache;
	}

	public static void InvalidatePlayerCache()
	{
		_playerCache = null;
	}

	public static UnitPropertyProxy GetPlayerProperty()
	{
		GameObject player = GetPlayer();
		Component val = ((player != null) ? player.GetComponent(AccessTools.TypeByName("UnitProperty")) : null);
		return ((Object)(object)val != (Object)null) ? new UnitPropertyProxy(val) : null;
	}

	public static Vector3 GetPlayerPosition()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		GameObject player = GetPlayer();
		return (player != null) ? player.transform.position : Vector3.zero;
	}

	public static void TeleportPlayer(Vector3 pos)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		GameObject player = GetPlayer();
		if ((Object)(object)player != (Object)null)
		{
			player.transform.position = pos;
		}
	}

	public static void HealPlayer(float amount)
	{
		Component playerComponent = GetPlayerComponent();
		if ((Object)(object)playerComponent != (Object)null)
		{
			_m_hpRecovery?.Invoke(playerComponent, new object[2] { amount, true });
		}
	}

	public static void SetPlayerHP(float hp)
	{
		UnitPropertyProxy playerProperty = GetPlayerProperty();
		if (playerProperty != null)
		{
			playerProperty.CurrentHP = hp;
		}
	}

	public static void KillPlayer()
	{
		Component playerComponent = GetPlayerComponent();
		if ((Object)(object)playerComponent != (Object)null)
		{
			_m_announcedDeath?.Invoke(playerComponent, new object[2] { null, true });
		}
	}

	private static Component GetPlayerComponent()
	{
		GameObject player = GetPlayer();
		if ((Object)(object)player == (Object)null)
		{
			return null;
		}
		return player.GetComponent(_tUnitProperty);
	}

	public static GameObject[] GetAllEnemies()
	{
		return GameObject.FindGameObjectsWithTag("Enemy");
	}

	public static UnitPropertyProxy[] GetAllEnemyProperties()
	{
		GameObject[] allEnemies = GetAllEnemies();
		UnitPropertyProxy[] array = new UnitPropertyProxy[allEnemies.Length];
		for (int i = 0; i < allEnemies.Length; i++)
		{
			Component component = allEnemies[i].GetComponent(_tUnitProperty);
			array[i] = new UnitPropertyProxy(component);
		}
		return array;
	}

	public static void KillAllEnemies()
	{
		GameObject[] allEnemies = GetAllEnemies();
		foreach (GameObject val in allEnemies)
		{
			Object.Destroy((Object)(object)val);
		}
	}

	public static void KillAllEnemiesViaGame()
	{
		UnitPropertyProxy[] allEnemyProperties = GetAllEnemyProperties();
		foreach (UnitPropertyProxy unitPropertyProxy in allEnemyProperties)
		{
			GameObject gameObject = unitPropertyProxy.GameObject;
			Component val = ((gameObject != null) ? gameObject.GetComponent(_tUnitProperty) : null);
			if ((Object)(object)val != (Object)null)
			{
				_m_announcedDeath?.Invoke(val, new object[2] { null, true });
			}
		}
	}
}
public static class ContentRegistry
{
	public delegate float DamageModifier(DamageProxy dmg);

	public delegate bool SpawnFilter(SpawnRequestProxy req);

	private static readonly List<DamageModifier> _playerDamageMods = new List<DamageModifier>();

	private static readonly List<DamageModifier> _enemyDamageMods = new List<DamageModifier>();

	private static readonly List<SpawnFilter> _spawnFilters = new List<SpawnFilter>();

	private static readonly Dictionary<int, List<Action<UnitPropertyProxy>>> _deathCallbacks = new Dictionary<int, List<Action<UnitPropertyProxy>>>();

	private static readonly Dictionary<string, GameObject> _customPrefabs = new Dictionary<string, GameObject>();

	public static void Init()
	{
		Hooks.OnBeforePlayerDamage += delegate(DamageProxy proxy)
		{
			foreach (DamageModifier playerDamageMod in _playerDamageMods)
			{
				proxy.Damage = playerDamageMod(proxy);
			}
			return true;
		};
		Hooks.OnBeforeEnemyDamage += delegate(DamageProxy proxy)
		{
			foreach (DamageModifier enemyDamageMod in _enemyDamageMods)
			{
				proxy.Damage = enemyDamageMod(proxy);
			}
			return true;
		};
		Hooks.OnBeforeEnemySpawn += delegate(SpawnRequestProxy proxy)
		{
			foreach (SpawnFilter spawnFilter in _spawnFilters)
			{
				if (!spawnFilter(proxy))
				{
					return false;
				}
			}
			return true;
		};
		Hooks.OnEnemyDeath += delegate(UnitPropertyProxy ppt)
		{
			if (_deathCallbacks.TryGetValue(ppt.GetInstanceID_Safe(), out var value))
			{
				foreach (Action<UnitPropertyProxy> item in value)
				{
					item(ppt);
				}
			}
		};
		ThuliumAPI.Log.LogMessage((object)"ContentRegistry ready.");
	}

	public static void RegisterPlayerDamageModifier(DamageModifier mod)
	{
		_playerDamageMods.Add(mod);
	}

	public static void RegisterEnemyDamageModifier(DamageModifier mod)
	{
		_enemyDamageMods.Add(mod);
	}

	public static void RegisterSpawnFilter(SpawnFilter filter)
	{
		_spawnFilters.Add(filter);
	}

	public static void OnUnitDeath(int unitID, Action<UnitPropertyProxy> cb)
	{
		if (!_deathCallbacks.ContainsKey(unitID))
		{
			_deathCallbacks[unitID] = new List<Action<UnitPropertyProxy>>();
		}
		_deathCallbacks[unitID].Add(cb);
	}

	public static void RegisterPrefab(string key, GameObject prefab)
	{
		if ((Object)(object)prefab == (Object)null)
		{
			throw new ArgumentNullException("prefab");
		}
		_customPrefabs[key] = prefab;
		ThuliumAPI.Log.LogMessage((object)("[ContentRegistry] Registered prefab '" + key + "'"));
	}

	public static GameObject SpawnRegisteredPrefab(string key, Vector3 position, Quaternion? rotation = null)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		if (!_customPrefabs.TryGetValue(key, out var value))
		{
			ThuliumAPI.Log.LogWarning((object)("[ContentRegistry] No prefab registered with key '" + key + "'"));
			return null;
		}
		return Object.Instantiate<GameObject>(value, position, (Quaternion)(((??)rotation) ?? Quaternion.identity));
	}

	public static bool HasPrefab(string key)
	{
		return _customPrefabs.ContainsKey(key);
	}
}
public static class Utils
{
	public static void Print(object msg)
	{
		ThuliumAPI.Log.LogMessage(msg);
	}

	public static void Warn(object msg)
	{
		ThuliumAPI.Log.LogWarning(msg);
	}

	public static void Error(object msg)
	{
		ThuliumAPI.Log.LogError(msg);
	}

	public static T GetField<T>(object obj, string field)
	{
		FieldInfo fieldInfo = AccessTools.Field(obj.GetType(), field);
		return (fieldInfo != null) ? ((T)fieldInfo.GetValue(obj)) : default(T);
	}

	public static void SetField(object obj, string field, object value)
	{
		AccessTools.Field(obj.GetType(), field)?.SetValue(obj, value);
	}

	public static object Call(object obj, string method, params object[] args)
	{
		return AccessTools.Method(obj.GetType(), method, (Type[])null, (Type[])null)?.Invoke(obj, args);
	}

	public static void SetTimeScale(float scale)
	{
		Time.timeScale = scale;
	}

	public static void PauseGame()
	{
		Time.timeScale = 0f;
	}

	public static void ResumeGame()
	{
		Time.timeScale = 1f;
	}

	public static GameObject SpawnPrefab(GameObject prefab, Vector3 pos, Quaternion? rot = null)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		return Object.Instantiate<GameObject>(prefab, pos, (Quaternion)(((??)rot) ?? Quaternion.identity));
	}

	public static GameObject[] GetAllEnemies()
	{
		return GameObject.FindGameObjectsWithTag("Enemy");
	}

	public static Component GetMainCanvas()
	{
		Type type = AccessTools.TypeByName("UnityEngine.Canvas");
		return (Component)((type != null) ? /*isinst with value type is only supported in some contexts*/: null);
	}
}
internal static class UnitPropertyProxyExtensions
{
	public static int GetInstanceID_Safe(this UnitPropertyProxy proxy)
	{
		GameObject val = proxy?.GameObject;
		return ((Object)(object)val != (Object)null) ? ((Object)val).GetInstanceID() : (-1);
	}
}