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