Decompiled source of Crossover v2.0.0

plugins/Crossover.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Notiffy.API;
using NukeLib.Utils;
using TMPro;
using ThornClient.Core;
using ThornClient.Core.ConfigurableElements;
using ThornClient.Core.DataTypes;
using ThornClient.System;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Crossover")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+b65397996146739093dea5046ddab675ac854ce5")]
[assembly: AssemblyProduct("Crossover")]
[assembly: AssemblyTitle("Crossover")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Crossover
{
	public class CrossBehavior : EnemyTrackingBehavior
	{
		private enum State
		{
			Hidden,
			Marking
		}

		public bool startMarkImmediately = true;

		public float markLifetime = 0.5333f;

		public float scalingDelay;

		public float scalingDuration = 0.1333f;

		public float startScale = 1f;

		public float endScale = 0.2f;

		public Tuple<float, Color>[] colorSteps = Array.Empty<Tuple<float, Color>>();

		private RectTransform rectTransform;

		private CanvasGroup canvasGroup;

		private Image frontLayerImage;

		private Image backLayerImage;

		private State state;

		private float startMarkTime;

		private float scaleDiff => startScale - endScale;

		public Tuple<float, Color>[] GetUpdatedColorSteps()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			Color item = Utils.Transparentize(((Graphic)backLayerImage).color);
			return new Tuple<float, Color>[8]
			{
				Tuple.Create<float, Color>(0f, Color.white),
				Tuple.Create<float, Color>(0.0333f, Color.black),
				Tuple.Create<float, Color>(0.0667f, Color.white),
				Tuple.Create<float, Color>(0.1333f, Color.black),
				Tuple.Create<float, Color>(0.2f, ((Graphic)backLayerImage).color),
				Tuple.Create<float, Color>(0.4f, item),
				Tuple.Create<float, Color>(0.4667f, ((Graphic)backLayerImage).color),
				Tuple.Create<float, Color>(0.5333f, item)
			};
		}

		private void Awake()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			frontLayerImage = ((Component)((Component)this).transform.Find("DeathCrossFrontLayer")).gameObject.GetComponent<Image>();
			backLayerImage = ((Component)this).gameObject.GetComponent<Image>();
			((Graphic)backLayerImage).color = CrossoverConfig.AccentColor.Value;
			colorSteps = GetUpdatedColorSteps();
			startScale = CrossoverConfig.StartScale.Value;
			endScale = CrossoverConfig.EndScale.Value;
			scalingDuration = CrossoverConfig.ScalingDuration.Value;
			scalingDelay = CrossoverConfig.ScalingDelay.Value;
			markLifetime = CrossoverConfig.VisibleDuration.Value;
			canvasGroup = ((Component)this).GetComponent<CanvasGroup>();
			canvasGroup.alpha = CrossoverConfig.CrossMarkOpacity.Value;
			if (canvasGroup.alpha < 1f)
			{
				((Graphic)backLayerImage).color = Utils.Transparentize(((Graphic)backLayerImage).color);
			}
		}

		protected override void Start()
		{
			ref RectTransform reference = ref rectTransform;
			Transform transform = ((Component)this).transform;
			reference = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			base.Start();
		}

		private float Curve(float x)
		{
			float num = Math.Clamp(x, 0f, 1f);
			float num2 = 1f - num;
			return 1f - num2 * num2 * num2;
		}

		private void UpdateColor(float elapsedTime)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			int i = 0;
			if (!(elapsedTime < 0f))
			{
				for (; i < colorSteps.Length && elapsedTime >= colorSteps[i].Item1; i++)
				{
				}
				((Graphic)frontLayerImage).color = colorSteps[i - 1].Item2;
			}
		}

		private void SetScale(float newScale)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			((Transform)rectTransform).localScale = new Vector3(newScale, newScale, newScale);
		}

		private void UpdateScale(float percentage)
		{
			float scale = startScale - Curve(percentage) * scaleDiff;
			SetScale(scale);
		}

		protected override void Update()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			if (state == State.Hidden && (startMarkImmediately || (Object)(object)enemy == (Object)null || enemy.health <= 0f))
			{
				state = State.Marking;
				startMarkTime = Time.time;
			}
			if (state != State.Hidden)
			{
				float num = Time.time - startMarkTime;
				UpdateColor(num);
				UpdateScale((num - scalingDelay) / scalingDuration);
				base.Update();
				((Transform)rectTransform).position = canvasPoint;
				if (Time.time - startMarkTime >= markLifetime)
				{
					Object.Destroy((Object)(object)((Component)this).gameObject);
				}
			}
		}
	}
	public class CrossoverConfig : Module
	{
		public static CrossoverConfig Instance;

		public static Setting<bool> EnableCrosses;

		public static Setting<Color> AccentColor;

		public static Setting<float> StartScale;

		public static Setting<float> EndScale;

		public static Setting<float> EnemyHealthThreshold;

		public static Setting<float> CrossMarkOpacity;

		public static Setting<float> ScalingDelay;

		public static Setting<float> ScalingDuration;

		public static Setting<float> VisibleDuration;

		public static Setting<bool> EnableTrackers;

		public static Setting<int> TrackerThreshold;

		public static Setting<EnemyList> ForceTrackEnemies;

		public static Setting<bool> TrackerIgnorePuppets;

		public static Setting<bool> TrackerUseSpecificEnemyIcons;

		public static Setting<bool> TrackerShowEnemyNames;

		public static Setting<Color> TrackerColor;

		public static Setting<float> TrackerScale;

		public static Setting<float> TrackerMarkOpacity;

		public static Setting<string> LastVersion;

		public override Sprite Icon => FileAssetUtils.LoadNewSprite(Plugin.PluginSymbolicIconPath, 100f, (SpriteMeshType)1);

		public override string[] Tags => new string[4] { "mark", "death", "indicator", "tracker" };

		public CrossoverConfig()
			: base("crossover.config", "Crossover", "Configuration for cross marks and enemy indicators", (ModuleCategory)1, (KeyCode)0, (KeyCode)0, false, false)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Expected O, but got Unknown
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Expected O, but got Unknown
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Expected O, but got Unknown
			Instance = this;
			((Configurable)this).CreateHeader("deathCrossesHeader", "Death Crosses", "", (HeaderType)0, (SettingGroup)null);
			EnableCrosses = ((Configurable)this).CreateSetting<bool>("crossEnabled", "Enable death crosses", "Whether to show death cross marks on killed enemies", true, (SettingGroup)null);
			AccentColor = ((Configurable)this).CreateSetting<Color>("accentColor", "Cross accent color", "The primary accent color for death cross marks", ColorUtils.ToColor(14360121), (SettingGroup)null);
			SettingGroup val = ((Configurable)this).CreateGroup("crossAdvanced", "Advanced", "Advanced visual options for cross marks", (SettingGroup)null);
			StartScale = ((Configurable)this).CreateSetting<float>("crossStartScale", "Cross starting scale", "Initial scale on appearance", 2f, (SettingGroup)null);
			EndScale = ((Configurable)this).CreateSetting<float>("crossEndScale", "Cross ending scale", "Final scale before disappearing", 0.35f, val);
			EnemyHealthThreshold = ((Configurable)this).CreateSetting<float>("crossEnemyHealthThreshold", "Cross enemy health threshold", "At what health amount should the cross trigger", 0f, val);
			((Setting)EnemyHealthThreshold).Hints = new InterfaceHints
			{
				Hidden = true
			};
			CrossMarkOpacity = ((Configurable)this).CreateSetting<float>("crossMarkOpacity", "Cross mark opacity", "Opacity level of the cross mark", 1f, val);
			((Setting)CrossMarkOpacity).Hints = new InterfaceHints
			{
				Range = Tuple.Create(0f, 1f)
			};
			ScalingDelay = ((Configurable)this).CreateSetting<float>("crossScalingDelay", "Scaling delay", "Delay before scale transformation begins", 0f, val);
			ScalingDuration = ((Configurable)this).CreateSetting<float>("crossScalingDuration", "Scaling duration", "Time duration for scale transition", 0.1333f, val);
			VisibleDuration = ((Configurable)this).CreateSetting<float>("crossVisibleDuration", "Visible duration", "Total time the cross remains visible", 0.5333f, val);
			((Configurable)this).CreateHeader("trackersHeader", "Enemy Trackers", "", (HeaderType)0, (SettingGroup)null);
			EnableTrackers = ((Configurable)this).CreateSetting<bool>("trackerEnabled", "Enable tracker icons", "Shows icons at enemy locations", false, (SettingGroup)null);
			TrackerThreshold = ((Configurable)this).CreateSetting<int>("trackerThreshold", "Reveal last x enemies", "Show trackers for all enemies when there are at most x remaining, where x=", 5, (SettingGroup)null);
			ForceTrackEnemies = ((Configurable)this).CreateSetting<EnemyList>("trackerForceEnemies", "Force track enemies", "These enemies will always be tracked regardless of the global enemy count. Tip: especially useful for Mindflayers and Powers since they teleport a lot and require special attention", new EnemyList(), (SettingGroup)null);
			TrackerShowEnemyNames = ((Configurable)this).CreateSetting<bool>("trackerShowEnemyNames", "Show enemy names", "Display text labels of enemy names next to their tracker", true, (SettingGroup)null);
			TrackerColor = ((Configurable)this).CreateSetting<Color>("trackerColor", "Tracker accent color", "The accent color used for enemy indicator marks", ColorUtils.ToColor(15840787), (SettingGroup)null);
			SettingGroup val2 = ((Configurable)this).CreateGroup("crossAdvanced", "Advanced", "Advanced visual options for cross marks", (SettingGroup)null);
			TrackerUseSpecificEnemyIcons = ((Configurable)this).CreateSetting<bool>("trackerUseSpecificEnemyIcons", "Use specific enemy type icons", "Render distinct icons based on enemy type instead of generic icons", true, val2);
			TrackerIgnorePuppets = ((Configurable)this).CreateSetting<bool>("trackerIgnorePuppets", "Ignore puppets (blood bois)", "Do not display trackers for violence tree or Deathcatcher-spawned enemies", true, val2);
			TrackerScale = ((Configurable)this).CreateSetting<float>("trackerScale", "Tracker mark scale", "Visual scale multiplier for tracker indicators", 1f, val2);
			TrackerMarkOpacity = ((Configurable)this).CreateSetting<float>("trackerMarkOpacity", "Tracker mark opacity", "Opacity level for tracker marks", 0.7f, val2);
			((Setting)TrackerMarkOpacity).Hints = new InterfaceHints
			{
				Range = Tuple.Create(0f, 1f)
			};
			SettingGroup val3 = ((Configurable)this).CreateGroup("devGroup", "Developer", "Developer options", (SettingGroup)null);
			LastVersion = ((Configurable)this).CreateSetting<string>("lastVersion", "Last version", "Internal version tracking", "0.0.0", val3);
		}

		public static bool IsEnemyForceTracked(EnemyType type)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			return ForceTrackEnemies.Value.Includes(type);
		}
	}
	public class EnemyIndicatorController : EnemyTrackingBehavior
	{
		private bool _show;

		private bool _cleanedUp;

		private RectTransform rectTransform;

		private CanvasGroup canvasGroup;

		private GameObject? indicatorObject;

		private Image frontLayerImage;

		private Image backLayerImage;

		private TMP_Text frontLayerText;

		private TMP_Text backLayerText;

		private static readonly string DEFAULT_ICON = "dot_circle";

		private string _enemyName = "Enemy";

		private bool enemyCountBelowThreshold
		{
			get
			{
				EnemyTracker instance = MonoSingleton<EnemyTracker>.Instance;
				return ((instance != null) ? (from e in instance.GetCurrentEnemies()
					where !e.puppet
					select e).Count() : 0) <= CrossoverConfig.TrackerThreshold.Value;
			}
		}

		private void SetText(string text)
		{
			if (!((Object)(object)frontLayerText == (Object)null) && !((Object)(object)backLayerText == (Object)null))
			{
				frontLayerText.text = text;
				backLayerText.text = text;
			}
		}

		private void SetAccentColor(Color color)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)frontLayerImage == (Object)null) && !((Object)(object)frontLayerText == (Object)null))
			{
				if (((Object)frontLayerImage.sprite).name != DEFAULT_ICON)
				{
					color = Color.white;
				}
				((Graphic)frontLayerImage).color = color;
				((Graphic)frontLayerText).color = color;
			}
		}

		private void SetBackgroundColor(Color color)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)backLayerImage == (Object)null) && !((Object)(object)backLayerText == (Object)null))
			{
				((Graphic)backLayerImage).color = color;
				((Graphic)backLayerText).color = color;
			}
		}

		private void SetScale(float scale)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rectTransform == (Object)null))
			{
				((Transform)rectTransform).localScale = new Vector3(scale, scale, scale);
				Rect rect = rectTransform.rect;
				float width = ((Rect)(ref rect)).width;
				rect = rectTransform.rect;
				clampPadding = Math.Max(width, ((Rect)(ref rect)).height);
			}
		}

		private void SetAlpha(float alpha)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)canvasGroup == (Object)null))
			{
				canvasGroup.alpha = alpha;
				if (canvasGroup.alpha < 1f)
				{
					SetBackgroundColor(Utils.Transparentize(((Graphic)backLayerImage).color));
				}
				else
				{
					SetBackgroundColor(Utils.Opacitize(((Graphic)backLayerImage).color));
				}
			}
		}

		private void SetActive(bool active)
		{
			if (!((Object)(object)indicatorObject == (Object)null))
			{
				indicatorObject.SetActive(active);
			}
		}

		private void SetNameActive(bool active)
		{
			if ((Object)(object)frontLayerText != (Object)null)
			{
				((Component)frontLayerText).gameObject.SetActive(active);
			}
			if ((Object)(object)backLayerText != (Object)null)
			{
				((Component)backLayerText).gameObject.SetActive(active);
			}
		}

		private void SetEnemyIcon(bool useSpecificEnemyIcon)
		{
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			string input = ((object)Unsafe.As<EnemyType, EnemyType>(ref enemy.enemyType)/*cast due to .constrained prefix*/).ToString();
			string key = DEFAULT_ICON;
			if (useSpecificEnemyIcon)
			{
				string text = input.ToSnakeCase();
				if (Plugin.EnemyIcons.ContainsKey(text))
				{
					key = text;
				}
				else
				{
					switch (enemy.FullName.ToLower())
					{
					case "earthmover mortar":
						text = "centaur_mortar";
						break;
					case "earthmover rocket launcher":
						text = "centaur_rocket";
						break;
					case "earthmover tower":
						text = "centaur_orb";
						break;
					case "cancerous rodent":
						text = "cancerous_rodent";
						break;
					case "very cancerous rodent":
						text = "very_cancerous_rodent";
						break;
					case "big johninator":
						text = "big_johninator";
						break;
					}
					if (Plugin.EnemyIcons.ContainsKey(text))
					{
						key = text;
					}
				}
			}
			if (Plugin.EnemyIcons.TryGetValue(key, out Sprite value))
			{
				frontLayerImage.sprite = value;
				backLayerImage.sprite = value;
				SetAccentColor(CrossoverConfig.TrackerColor.Value);
			}
		}

		private void UpdateAppearance()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)indicatorObject == (Object)null))
			{
				SetAccentColor(CrossoverConfig.TrackerColor.Value);
				SetScale(CrossoverConfig.TrackerScale.Value);
				SetAlpha(CrossoverConfig.TrackerMarkOpacity.Value);
				SetNameActive(CrossoverConfig.TrackerShowEnemyNames.Value);
				SetEnemyIcon(CrossoverConfig.TrackerUseSpecificEnemyIcons.Value);
				indicatorObject.SetActive(CrossoverConfig.EnableTrackers.Value);
			}
		}

		private void UpdateShow()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (!enemyCountBelowThreshold && !CrossoverConfig.IsEnemyForceTracked(enemy.enemyType))
			{
				_show = false;
				if ((Object)(object)indicatorObject != (Object)null)
				{
					indicatorObject.SetActive(false);
				}
				return;
			}
			if ((Object)(object)indicatorObject == (Object)null)
			{
				indicatorObject = Object.Instantiate<GameObject>(Plugin.EnemyIndicatorPrefab, Plugin.CrossoverCanvas.transform);
				rectTransform = indicatorObject.GetComponent<RectTransform>();
				canvasGroup = indicatorObject.GetComponent<CanvasGroup>();
				frontLayerImage = ((Component)indicatorObject.transform.Find("EnemyTrackerFrontLayer")).GetComponent<Image>();
				backLayerImage = indicatorObject.GetComponent<Image>();
				frontLayerText = ((Component)indicatorObject.transform.Find("EnemyTrackerFrontLayer/FrontEnemyName")).GetComponent<TMP_Text>();
				backLayerText = ((Component)indicatorObject.transform.Find("EnemyName")).GetComponent<TMP_Text>();
			}
			SetText(_enemyName);
			UpdateAppearance();
			_show = true;
		}

		private void HookStuff()
		{
			Setting<bool> enableTrackers = CrossoverConfig.EnableTrackers;
			enableTrackers.OnValueChanged = (Action<bool>)Delegate.Combine(enableTrackers.OnValueChanged, new Action<bool>(SetActive));
			Setting<bool> trackerUseSpecificEnemyIcons = CrossoverConfig.TrackerUseSpecificEnemyIcons;
			trackerUseSpecificEnemyIcons.OnValueChanged = (Action<bool>)Delegate.Combine(trackerUseSpecificEnemyIcons.OnValueChanged, new Action<bool>(SetEnemyIcon));
			Setting<bool> trackerShowEnemyNames = CrossoverConfig.TrackerShowEnemyNames;
			trackerShowEnemyNames.OnValueChanged = (Action<bool>)Delegate.Combine(trackerShowEnemyNames.OnValueChanged, new Action<bool>(SetNameActive));
			Setting<Color> trackerColor = CrossoverConfig.TrackerColor;
			trackerColor.OnValueChanged = (Action<Color>)Delegate.Combine(trackerColor.OnValueChanged, new Action<Color>(SetAccentColor));
			Setting<float> trackerScale = CrossoverConfig.TrackerScale;
			trackerScale.OnValueChanged = (Action<float>)Delegate.Combine(trackerScale.OnValueChanged, new Action<float>(SetScale));
			Setting<float> trackerMarkOpacity = CrossoverConfig.TrackerMarkOpacity;
			trackerMarkOpacity.OnValueChanged = (Action<float>)Delegate.Combine(trackerMarkOpacity.OnValueChanged, new Action<float>(SetAlpha));
			EnemyListener.EnemyCountChanged += UpdateShow;
			enemy.destroyOnDeath.Add(indicatorObject);
		}

		private void UnhookStuff()
		{
			EnemyListener.EnemyCountChanged -= UpdateShow;
			Setting<bool> enableTrackers = CrossoverConfig.EnableTrackers;
			enableTrackers.OnValueChanged = (Action<bool>)Delegate.Remove(enableTrackers.OnValueChanged, new Action<bool>(SetActive));
			Setting<bool> trackerUseSpecificEnemyIcons = CrossoverConfig.TrackerUseSpecificEnemyIcons;
			trackerUseSpecificEnemyIcons.OnValueChanged = (Action<bool>)Delegate.Remove(trackerUseSpecificEnemyIcons.OnValueChanged, new Action<bool>(SetEnemyIcon));
			Setting<bool> trackerShowEnemyNames = CrossoverConfig.TrackerShowEnemyNames;
			trackerShowEnemyNames.OnValueChanged = (Action<bool>)Delegate.Remove(trackerShowEnemyNames.OnValueChanged, new Action<bool>(SetNameActive));
			Setting<Color> trackerColor = CrossoverConfig.TrackerColor;
			trackerColor.OnValueChanged = (Action<Color>)Delegate.Remove(trackerColor.OnValueChanged, new Action<Color>(SetAccentColor));
			Setting<float> trackerScale = CrossoverConfig.TrackerScale;
			trackerScale.OnValueChanged = (Action<float>)Delegate.Remove(trackerScale.OnValueChanged, new Action<float>(SetScale));
			Setting<float> trackerMarkOpacity = CrossoverConfig.TrackerMarkOpacity;
			trackerMarkOpacity.OnValueChanged = (Action<float>)Delegate.Remove(trackerMarkOpacity.OnValueChanged, new Action<float>(SetAlpha));
		}

		private void Awake()
		{
			clampToScreen = true;
		}

		protected override void Start()
		{
			base.Start();
			TextInfo textInfo = CultureInfo.CurrentCulture.TextInfo;
			EnemyIdentifier obj = enemy;
			_enemyName = textInfo.ToTitleCase(((obj != null) ? obj.FullName.ToLower() : null) ?? "Enemy");
			UpdateShow();
			HookStuff();
		}

		internal void PrintDebugInfo()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			EnemyIdentifier obj = enemy;
			string text = ((obj != null) ? ((object)((Component)obj).transform).ToString() : null) ?? "NULL TRANSFORM";
			EnemyIdentifier obj2 = enemy;
			Vector3? obj3;
			if (obj2 == null)
			{
				obj3 = null;
			}
			else
			{
				Transform transform = ((Component)obj2).transform;
				obj3 = ((transform != null) ? new Vector3?(transform.position) : ((Vector3?)null));
			}
			string text2 = ((object)(Vector3)(((??)obj3) ?? (Vector3.one * -1f))/*cast due to .constrained prefix*/).ToString() ?? "";
			string text3 = $"{enemy?.health ?? (-1f)}";
			GameObject? obj4 = indicatorObject;
			string text4 = ((obj4 != null) ? ((object)obj4.transform.position/*cast due to .constrained prefix*/).ToString() : null) ?? "NULL POS";
			Plugin.Log.LogInfo((object)$"--- Enemy {_enemyName} | transform: {text} | pos: {text2} | hp: {text3} | indicatorObject: {indicatorObject} | indicatorObjPos: {text4}");
		}

		private void OnDisable()
		{
			RemoveIndicatorAndStop();
		}

		protected override void Update()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)enemy == (Object)null || enemy.dead || enemy.health <= 0f || (Object)(object)((Component)enemy).transform == (Object)null || (Object)(object)((Component)this).gameObject == (Object)null || !((Component)this).gameObject.activeSelf)
			{
				RemoveIndicatorAndStop();
			}
			else if (_show)
			{
				base.Update();
				((Transform)rectTransform).position = canvasPoint;
			}
		}

		public void RemoveIndicatorAndStop()
		{
			if (!_cleanedUp)
			{
				_cleanedUp = true;
				_show = false;
				if ((Object)(object)indicatorObject != (Object)null)
				{
					Object.Destroy((Object)(object)indicatorObject);
				}
				UnhookStuff();
				Object.Destroy((Object)(object)this);
			}
		}

		private void OnDestroy()
		{
			UnhookStuff();
			if ((Object)(object)indicatorObject != (Object)null)
			{
				Object.Destroy((Object)(object)indicatorObject);
			}
		}
	}
	public static class EnemyListener
	{
		public delegate void OnSomeEnemyDied();

		public static event OnSomeEnemyDied EnemyCountChanged;

		internal static void NotifyChange()
		{
			EnemyListener.EnemyCountChanged?.Invoke();
		}
	}
	public class EnemyTrackingBehavior : MonoBehaviour
	{
		public Vector3 canvasPoint;

		protected Vector3 lastEnemyPosition = Vector3.zero;

		public EnemyIdentifier enemy;

		protected float enemyHeight;

		public bool clampToScreen;

		public float clampPadding;

		public void SetEnemy(EnemyIdentifier enemy)
		{
			this.enemy = enemy;
		}

		protected Vector3 GetEnemyPosition()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)enemy != (Object)null && (Object)(object)((Component)enemy).transform != (Object)null)
			{
				lastEnemyPosition = ((Component)enemy).transform.position;
			}
			return lastEnemyPosition + enemyHeight / 2f * Vector3.up;
		}

		private void UpdateCanvasPoint()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = MonoSingleton<CameraController>.Instance.cam.WorldToScreenPoint(GetEnemyPosition());
			bool num = val.z < 0f;
			int privateField = MonoSingleton<PostProcessV2_Handler>.Instance.GetPrivateField<int>("width");
			int privateField2 = MonoSingleton<PostProcessV2_Handler>.Instance.GetPrivateField<int>("height");
			val.x *= Screen.width;
			val.y *= Screen.height;
			val.x /= privateField;
			val.y /= privateField2;
			if (num)
			{
				float num2 = (float)privateField / 2f;
				float num3 = (float)privateField - val.x - num2;
				if (Mathf.Approximately(num3, 0f))
				{
					num3 = -1f;
				}
				val.x = num2 + num3 / Math.Abs(num3) * (float)Screen.width / 2f;
			}
			if (clampToScreen)
			{
				val.x = Mathf.Clamp(val.x, clampPadding, (float)privateField - clampPadding);
				val.y = Mathf.Clamp(val.y, clampPadding, (float)privateField2 - clampPadding);
			}
			canvasPoint = val;
		}

		protected virtual void Start()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)enemy == (Object)null))
			{
				Collider component = ((Component)enemy).GetComponent<Collider>();
				if (!((Object)(object)component == (Object)null))
				{
					Bounds bounds = component.bounds;
					float y = (((Bounds)(ref bounds)).center - ((Component)enemy).transform.position).y;
					bounds = component.bounds;
					enemyHeight = y + ((Bounds)(ref bounds)).extents.y;
				}
			}
		}

		protected virtual void Update()
		{
			UpdateCanvasPoint();
		}
	}
	[BepInPlugin("com.github.end-4.crossover", "Crossover", "2.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		public static string workingPath = Assembly.GetExecutingAssembly().Location;

		public static string workingDir = Path.GetDirectoryName(workingPath);

		public const string PluginGUID = "com.github.end-4.crossover";

		public const string PluginName = "Crossover";

		public const string PluginVersion = "2.0.0";

		internal static GameObject DeathCrossPrefab;

		internal static GameObject EnemyIndicatorPrefab;

		internal static GameObject CrossoverCanvasPrefab;

		internal static GameObject CrossoverCanvas;

		internal static Dictionary<string, Sprite> EnemyIcons = new Dictionary<string, Sprite>();

		private static readonly string BundlePath = Path.Combine(workingDir, "assets", "crossover.bundle");

		internal static string[] IconNames = new string[41]
		{
			"dot_circle", "big_johninator", "cancerous_rodent", "centaur_mortar", "centaur_orb", "centaur_rocket", "cerberus", "deathcatcher", "drone", "ferryman",
			"filth", "flesh_panopticon", "flesh_prison", "gabriel", "gabriel_second", "gutterman", "guttertank", "hideous_mass", "idol", "malicious_face",
			"mandalore", "mindflayer", "minos_prime", "minotaur", "mirror_reaper", "power", "providence", "puppet", "schism", "sisyphus",
			"sisyphus_prime", "soldier", "stalker", "stray", "mannequin", "streetcleaner", "swordsmachine", "turret", "v2", "very_cancerous_rodent",
			"virtue"
		};

		public static string PluginIconPath => Path.Combine(workingDir, "icon.png");

		public static string PluginSymbolicIconPath => Path.Combine(workingDir, "icon_clickgui.png");

		private void LoadObjects()
		{
			AssetBundle val = AssetBundle.LoadFromFile(BundlePath);
			if ((Object)(object)val == (Object)null)
			{
				Log.LogError((object)"Couldn't load asset bundle");
			}
			DeathCrossPrefab = val.LoadAsset<GameObject>("DeathCross");
			EnemyIndicatorPrefab = val.LoadAsset<GameObject>("EnemyIndicator");
			CrossoverCanvasPrefab = val.LoadAsset<GameObject>("CrossoverCanvas");
			CrossoverCanvas = Object.Instantiate<GameObject>(CrossoverCanvasPrefab);
			Object.DontDestroyOnLoad((Object)(object)CrossoverCanvas);
			((Object)CrossoverCanvas).hideFlags = (HideFlags)61;
			for (int i = 0; i < IconNames.Length; i++)
			{
				string text = IconNames[i];
				Sprite value = val.LoadAsset<Sprite>(text);
				EnemyIcons.Add(text, value);
			}
		}

		private void Awake()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			LoadObjects();
			new Harmony("Crossover").PatchAll();
			UserHints.Initialize();
			Log.LogInfo((object)"Crossover loaded!");
		}
	}
	public static class UserHints
	{
		public static void IssueUpdateNoticeIfNecessary()
		{
			string text = CrossoverConfig.LastVersion.Value ?? "999.999.999";
			Version value = new Version(text);
			if (new Version("2.0.0").CompareTo(value) == 1)
			{
				bool num = text != "0.0.0";
				string text2 = (num ? "updated" : "installed");
				string text3 = (num ? "<b>2.0.0</b>: Configuration is now in Thorn" : "Configuration is available in Thorn");
				string text4 = "Press " + ThornModule.Instance.OpenClickGUI.Value.ToString(true) + " then search \"crossover\"";
				NotificationSystem.NotifySend("<color=#db1e39>Crossover</color> " + text2, text3 + ". " + text4, (Sprite)null, Path.Combine(Plugin.workingDir, "icon.png"), (Urgency)1, "NotifySend", 0u, (Dictionary<string, string>)null, 10000);
				CrossoverConfig.LastVersion.Value = "2.0.0";
			}
			SceneManager.sceneLoaded -= IssueUpdateNoticeIfNecessary;
		}

		public static void IssueUpdateNoticeIfNecessary(Scene _, LoadSceneMode __)
		{
			IssueUpdateNoticeIfNecessary();
		}

		public static void Initialize()
		{
		}

		static UserHints()
		{
			SceneUtils.SafeSceneLoaded += IssueUpdateNoticeIfNecessary;
		}
	}
	internal static class Utils
	{
		internal static T GetPrivateField<T>(this object obj, string field)
		{
			Type type = obj.GetType();
			if (type.GetField(field, BindingFlags.Instance | BindingFlags.NonPublic) == null)
			{
				throw new ArgumentException("The field " + field + " does not exist in target class " + type.Name + "!");
			}
			return (T)type.GetField(field, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj);
		}

		internal static Color Transparentize(Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			return new Color(color.r, color.g, color.b, 0f);
		}

		internal static Color Opacitize(Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			return new Color(color.r, color.g, color.b, 1f);
		}

		internal static string ToSnakeCase(this string input)
		{
			if (string.IsNullOrEmpty(input))
			{
				return input;
			}
			return Regex.Replace(input, "(?<!^)(?=[A-Z][a-z])|(?<=[a-z0-9])(?=[A-Z])", "_").ToLowerInvariant();
		}
	}
}
namespace Crossover.Patches
{
	[HarmonyPatch(typeof(EnemyIdentifier))]
	internal class EnemyPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("ProcessDeath")]
		private static void EnemyDied(EnemyIdentifier __instance)
		{
			if (CrossoverConfig.EnableCrosses.Value && !(__instance.health < CrossoverConfig.EnemyHealthThreshold.Value))
			{
				GameObject obj = Object.Instantiate<GameObject>(Plugin.DeathCrossPrefab, Plugin.CrossoverCanvas.transform);
				obj.AddComponent<CrossBehavior>().SetEnemy(__instance);
				obj.SetActive(true);
				EnemyListener.NotifyChange();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void EnemySpawned(EnemyIdentifier __instance)
		{
			if (CrossoverConfig.EnableTrackers.Value && (!__instance.puppet || !CrossoverConfig.TrackerIgnorePuppets.Value) && !((Object)(object)((Component)__instance).gameObject.GetComponent<EnemyIndicatorController>() != (Object)null))
			{
				((Component)__instance).gameObject.AddComponent<EnemyIndicatorController>().SetEnemy(__instance);
				EnemyListener.NotifyChange();
			}
		}
	}
}