Decompiled source of Carnometer v2.1.0

BepInEx/plugins/Carnometer.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Pigeon.Movement;
using Sparroh.UI;
using TMPro;
using UnityEngine;

[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("Sparroh")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.1.0")]
[assembly: AssemblyInformationalVersion("2.0.1")]
[assembly: AssemblyProduct("Carnometer")]
[assembly: AssemblyTitle("Carnometer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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;
		}
	}
}
public class CarnometerMod
{
	private HudHandle damageHud;

	public Queue<(float time, float damage)> damageQueue = new Queue<(float, float)>();

	private HudHandle killHud;

	public float missionStartTime;

	public int totalCoresKilled;

	public float totalDamage;

	public int totalKills;

	public static CarnometerMod Instance { get; private set; }

	public CarnometerMod()
	{
		Instance = this;
		missionStartTime = Time.time;
	}

	public void OnConfigChanged()
	{
		if (!ConfigManager.EnableDamageHUD.Value && HudHandle.IsValid(damageHud))
		{
			DestroyHud(ref damageHud);
		}
		if (!ConfigManager.EnableKillHUD.Value && HudHandle.IsValid(killHud))
		{
			DestroyHud(ref killHud);
		}
		UpdateHudVisibility();
	}

	public void UpdateHudVisibility()
	{
		if (HudHandle.IsValid(damageHud))
		{
			damageHud.SetActive(ConfigManager.EnableDamageHUD.Value);
		}
		if (HudHandle.IsValid(killHud))
		{
			killHud.SetActive(ConfigManager.EnableKillHUD.Value);
		}
	}

	private void CreateDamageHud()
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		if (damageHud != null && !damageHud.IsAlive)
		{
			damageHud = null;
		}
		if (!HudHandle.IsValid(damageHud))
		{
			damageHud = HudBuilder.Create("CarnometerDamageHUD").ParentToReticle(true).Anchor(ConfigManager.DamageAnchors.XValue, ConfigManager.DamageAnchors.YValue)
				.Pivot(new Vector2(0f, 1f))
				.Size(320f, 50f, true)
				.AddLines(2, -1f, (TextAlignmentOptions)513)
				.Build();
			if (HudHandle.IsValid(damageHud))
			{
				damageHud.EnableReposition("sparroh.carnometer.damage", "Damage HUD", ConfigManager.DamageAnchors);
				UpdateHudVisibility();
			}
		}
	}

	private void CreateKillHud()
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		if (killHud != null && !killHud.IsAlive)
		{
			killHud = null;
		}
		if (!HudHandle.IsValid(killHud))
		{
			killHud = HudBuilder.Create("CarnometerKillHUD").ParentToReticle(true).Anchor(ConfigManager.KillAnchors.XValue, ConfigManager.KillAnchors.YValue)
				.Pivot(new Vector2(0f, 1f))
				.Size(320f, 50f, true)
				.AddLines(2, -1f, (TextAlignmentOptions)513)
				.Build();
			if (HudHandle.IsValid(killHud))
			{
				killHud.EnableReposition("sparroh.carnometer.kill", "Kill HUD", ConfigManager.KillAnchors);
				UpdateHudVisibility();
			}
		}
	}

	private static void DestroyHud(ref HudHandle hud)
	{
		if (hud != null)
		{
			if (hud.IsAlive)
			{
				hud.Destroy();
			}
			hud = null;
		}
	}

	public void Update()
	{
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_025d: Unknown result type (might be due to invalid IL or missing references)
		//IL_028a: Unknown result type (might be due to invalid IL or missing references)
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		bool value = ConfigManager.EnableDamageHUD.Value;
		bool value2 = ConfigManager.EnableKillHUD.Value;
		if ((!value && !value2) || (Object)(object)Player.LocalPlayer == (Object)null)
		{
			return;
		}
		if (value && !HudHandle.IsValid(damageHud))
		{
			CreateDamageHud();
		}
		if (value2 && !HudHandle.IsValid(killHud))
		{
			CreateKillHud();
		}
		float time = Time.time;
		float value3 = ConfigManager.DpsWindowSeconds.Value;
		float num = time - missionStartTime;
		if (value && HudHandle.IsValid(damageHud) && damageHud.Lines != null && damageHud.Lines.Length >= 2)
		{
			while (damageQueue.Count > 0 && damageQueue.Peek().time < time - value3)
			{
				damageQueue.Dequeue();
			}
			float num2 = 0f;
			foreach (var item in damageQueue)
			{
				num2 += item.damage;
			}
			float num3 = ((damageQueue.Count > 0) ? (num2 / value3) : 0f);
			float num4 = ((num > 0f) ? (totalDamage / num) : 0f);
			Color value4 = ConfigManager.DamageColor.Value;
			damageHud.Lines[0].SetRichWithRate("Total Damage", totalDamage, num4, value4, "F0", "F1");
			damageHud.Lines[1].Text = RichText.LabeledWithRate($"Last {value3:F0}sec Damage", num2, num3, value4, "F0", "F1");
		}
		if (value2 && HudHandle.IsValid(killHud) && killHud.Lines != null && killHud.Lines.Length >= 2)
		{
			float num5 = ((num > 0f) ? ((float)totalKills / num) : 0f);
			float num6 = ((num > 0f) ? ((float)totalCoresKilled / num) : 0f);
			Color value5 = ConfigManager.KillColor.Value;
			killHud.Lines[0].SetRichWithRate("Targets Killed", (float)totalKills, num5, value5, "F0", "F1");
			killHud.Lines[1].SetRichWithRate("Cores Killed", (float)totalCoresKilled, num6, value5, "F0", "F1");
		}
	}

	public void OnDestroy()
	{
		DestroyHud(ref damageHud);
		DestroyHud(ref killHud);
	}
}
public static class ConfigManager
{
	private const float DebounceSeconds = 0.25f;

	private static ConfigFile config;

	private static ManualLogSource logger;

	private static FileSystemWatcher configWatcher;

	private static volatile bool pendingRefresh;

	private static volatile bool reloadPending;

	private static float lastReloadTime;

	public static ConfigEntry<bool> EnableDamageHUD { get; private set; }

	public static ConfigEntry<bool> EnableKillHUD { get; private set; }

	public static ConfigEntry<float> DpsWindowSeconds { get; private set; }

	public static HudAnchors DamageAnchors { get; private set; }

	public static HudAnchors KillAnchors { get; private set; }

	public static ConfigColor DamageColor { get; private set; }

	public static ConfigColor KillColor { get; private set; }

	public static void Initialize(ConfigFile configFile, ManualLogSource log)
	{
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		config = configFile;
		logger = log;
		EnableDamageHUD = config.Bind<bool>("General", "Enable Damage HUD", true, "Enable or disable the damage meter HUD.");
		EnableKillHUD = config.Bind<bool>("General", "Enable Kill HUD", true, "Enable or disable the kill tracker HUD.");
		DpsWindowSeconds = config.Bind<float>("General", "DPS Window", 5f, "Time window (in seconds) for calculating DPS. Higher values smooth out spikes.");
		DamageAnchors = HudAnchors.Bind(config, "DamageHUD", 0.294803f, 0.285045f, "HUD Positioning");
		KillAnchors = HudAnchors.Bind(config, "KillHUD", 0.294803f, 0.225045f, "HUD Positioning");
		DamageColor = ConfigColor.Bind(config, "Colors", "Damage HUD Color", UIColors.Rose, "Rich-text value color for the damage meter (hex RRGGBB or #RRGGBB).");
		KillColor = ConfigColor.Bind(config, "Colors", "Kill HUD Color", UIColors.Rose, "Rich-text value color for the kill tracker (hex RRGGBB or #RRGGBB).");
		EnableDamageHUD.SettingChanged += OnSettingChanged;
		EnableKillHUD.SettingChanged += OnSettingChanged;
		try
		{
			SetupFileWatcher();
		}
		catch (Exception ex)
		{
			logger.LogError((object)("Error setting up config file watcher: " + ex.Message));
		}
	}

	public static void Tick()
	{
		if (!reloadPending || Time.unscaledTime - lastReloadTime < 0.25f)
		{
			return;
		}
		reloadPending = false;
		lastReloadTime = Time.unscaledTime;
		try
		{
			config.Reload();
			pendingRefresh = true;
			logger.LogInfo((object)"Config reloaded from disk.");
		}
		catch (Exception ex)
		{
			logger.LogError((object)("Error reloading config: " + ex.Message));
		}
	}

	public static bool ConsumePendingRefresh()
	{
		if (!pendingRefresh)
		{
			return false;
		}
		pendingRefresh = false;
		return true;
	}

	public static void Dispose()
	{
		if (EnableDamageHUD != null)
		{
			EnableDamageHUD.SettingChanged -= OnSettingChanged;
		}
		if (EnableKillHUD != null)
		{
			EnableKillHUD.SettingChanged -= OnSettingChanged;
		}
		if (configWatcher != null)
		{
			configWatcher.EnableRaisingEvents = false;
			configWatcher.Changed -= OnConfigFileChanged;
			configWatcher.Created -= OnConfigFileChanged;
			configWatcher.Renamed -= OnConfigFileChanged;
			configWatcher.Dispose();
			configWatcher = null;
		}
	}

	private static void SetupFileWatcher()
	{
		configWatcher = new FileSystemWatcher(Paths.ConfigPath, "sparroh.carnometer.cfg");
		configWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite;
		configWatcher.Changed += OnConfigFileChanged;
		configWatcher.Created += OnConfigFileChanged;
		configWatcher.Renamed += OnConfigFileChanged;
		configWatcher.EnableRaisingEvents = true;
	}

	private static void OnConfigFileChanged(object sender, FileSystemEventArgs e)
	{
		reloadPending = true;
	}

	private static void OnSettingChanged(object sender, EventArgs e)
	{
		pendingRefresh = true;
	}
}
[HarmonyPatch]
public static class DPSPatches
{
	[HarmonyPrefix]
	[HarmonyPatch(typeof(PlayerData), "OnLocalPlayerDamageTarget")]
	private static bool PrefixDamage(in DamageCallbackData data)
	{
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: 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_004d: Unknown result type (might be due to invalid IL or missing references)
		if (CarnometerMod.Instance == null)
		{
			return true;
		}
		if (data.damageData.damage > 0f)
		{
			CarnometerMod.Instance.totalDamage += data.damageData.damage;
			TargetType type = ((IFollowable)data.target).Type;
			if ((type & 1) != 0 || (type & 2) != 0)
			{
				CarnometerMod.Instance.damageQueue.Enqueue((Time.time, data.damageData.damage));
			}
			if (((DamageCallbackData)(ref data)).KilledTarget)
			{
				CarnometerMod.Instance.totalKills++;
				if (typeof(EnemyCore).IsAssignableFrom(((object)data.target).GetType()))
				{
					CarnometerMod.Instance.totalCoresKilled++;
				}
			}
		}
		return true;
	}
}
[HarmonyPatch]
public static class MissionPatches
{
	[HarmonyPrefix]
	[HarmonyPatch(typeof(MissionManager), "SpawnHUD")]
	private static void MissionStart()
	{
		if (CarnometerMod.Instance != null)
		{
			CarnometerMod.Instance.totalDamage = 0f;
			CarnometerMod.Instance.totalKills = 0;
			CarnometerMod.Instance.totalCoresKilled = 0;
			CarnometerMod.Instance.damageQueue.Clear();
			CarnometerMod.Instance.missionStartTime = Time.time;
		}
	}
}
[BepInPlugin("sparroh.carnometer", "Carnometer", "2.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[MycoMod(/*Could not decode attribute arguments.*/)]
public class SparrohPlugin : BaseUnityPlugin
{
	public const string PluginGUID = "sparroh.carnometer";

	public const string PluginName = "Carnometer";

	public const string PluginVersion = "2.1.0";

	internal static ManualLogSource Logger;

	private CarnometerMod carnometer;

	private Harmony harmony;

	private void Awake()
	{
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Expected O, but got Unknown
		Logger = ((BaseUnityPlugin)this).Logger;
		try
		{
			ConfigManager.Initialize(((BaseUnityPlugin)this).Config, Logger);
		}
		catch (Exception ex)
		{
			Logger.LogError((object)("Failed to initialize config: " + ex.Message));
			return;
		}
		try
		{
			harmony = new Harmony("sparroh.carnometer");
		}
		catch (Exception ex2)
		{
			Logger.LogError((object)("Failed to create Harmony instance: " + ex2.Message));
			return;
		}
		try
		{
			carnometer = new CarnometerMod();
		}
		catch (Exception ex3)
		{
			Logger.LogError((object)("Failed to initialize Carnometer: " + ex3.Message));
		}
		try
		{
			harmony.PatchAll();
		}
		catch (Exception ex4)
		{
			Logger.LogError((object)("Failed to apply Harmony patches: " + ex4.Message));
		}
		Logger.LogInfo((object)"Carnometer loaded successfully.");
	}

	private void Update()
	{
		try
		{
			ConfigManager.Tick();
			if (ConfigManager.ConsumePendingRefresh() && carnometer != null)
			{
				carnometer.OnConfigChanged();
			}
			if (carnometer != null)
			{
				carnometer.UpdateHudVisibility();
			}
			if (carnometer != null)
			{
				carnometer.Update();
			}
		}
		catch (Exception ex)
		{
			Logger.LogError((object)("Error in Carnometer.Update(): " + ex.Message));
		}
	}

	private void OnDestroy()
	{
		try
		{
			if (carnometer != null)
			{
				carnometer.OnDestroy();
			}
		}
		catch (Exception ex)
		{
			Logger.LogError((object)("Error in Carnometer.OnDestroy(): " + ex.Message));
		}
		try
		{
			ConfigManager.Dispose();
		}
		catch (Exception ex2)
		{
			Logger.LogError((object)("Error disposing config: " + ex2.Message));
		}
		try
		{
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
		catch (Exception ex3)
		{
			Logger.LogError((object)("Error unpatching Harmony: " + ex3.Message));
		}
	}
}
namespace Carnometer
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Carnometer";

		public const string PLUGIN_NAME = "Carnometer";

		public const string PLUGIN_VERSION = "2.0.1";
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}