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(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("Carnometer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Carnometer")] [assembly: AssemblyTitle("Carnometer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.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 { internal 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 (Instance == null) { return true; } if (data.damageData.damage > 0f) { Instance.totalDamage += data.damageData.damage; TargetType type = ((IFollowable)data.target).Type; if ((type & 1) != 0 || (type & 2) != 0) { Instance.damageQueue.Enqueue((Time.time, data.damageData.damage)); } if (((DamageCallbackData)(ref data)).KilledTarget) { Instance.totalKills++; if (typeof(EnemyCore).IsAssignableFrom(((object)data.target).GetType())) { Instance.totalCoresKilled++; } } } return true; } } internal class MissionPatches { [HarmonyPrefix] [HarmonyPatch(typeof(MissionManager), "SpawnHUD")] private static void MissionStart() { if (Instance != null) { Instance.totalDamage = 0f; Instance.totalKills = 0; Instance.totalCoresKilled = 0; Instance.damageQueue.Clear(); Instance.missionStartTime = Time.time; } } } private ConfigEntry enableDamageMeterHUD; private ConfigEntry dpsWindowSeconds; private ConfigEntry carnometerAnchorX; private ConfigEntry carnometerAnchorY; private ConfigColor valueColor; private HudHandle hud; public Queue<(float time, float damage)> damageQueue = new Queue<(float, float)>(); public float totalDamage; public int totalKills; public int totalCoresKilled; public float missionStartTime; private readonly ConfigFile configFile; private readonly Harmony harmony; public static CarnometerMod Instance { get; private set; } public bool IsActive { get { if (hud != null) { return hud.IsActive; } return false; } } public Vector2 GetSize { get { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) HudHandle obj = hud; if (obj == null) { return Vector2.zero; } return obj.Size; } } public CarnometerMod(ConfigFile configFile, Harmony harmony) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) this.configFile = configFile; this.harmony = harmony; Instance = this; enableDamageMeterHUD = configFile.Bind("General", "EnableDamageMeterHUD", true, "Enable or disable the damage meter functionality."); enableDamageMeterHUD.SettingChanged += OnEnableDamageMeterHUDChanged; dpsWindowSeconds = configFile.Bind("General", "DPSWindowSeconds", 5f, "Time window (in seconds) for calculating DPS. Higher values smooth out spikes."); carnometerAnchorX = configFile.Bind("HUD Positioning", "CarnometerAnchorX", 0.294803f, "X anchor position for Carnometer (0-1)."); carnometerAnchorY = configFile.Bind("HUD Positioning", "CarnometerAnchorY", 0.285045f, "Y anchor position for Carnometer (0-1)."); carnometerAnchorX.SettingChanged += OnAnchorChanged; carnometerAnchorY.SettingChanged += OnAnchorChanged; valueColor = ConfigColor.Bind(configFile, "Colors", "ValueColor", UIColors.Rose, "Rich-text value color for damage/kill meters (hex RRGGBB or #RRGGBB)."); harmony.PatchAll(typeof(DPSPatches)); harmony.PatchAll(typeof(MissionPatches)); missionStartTime = Time.time; } public void UpdateHudVisibility() { if (hud != null) { hud.SetActive(enableDamageMeterHUD.Value); } } private void OnEnableDamageMeterHUDChanged(object sender, EventArgs e) { if (!enableDamageMeterHUD.Value && hud != null) { DestroyHud(); } UpdateHudVisibility(); } private void OnAnchorChanged(object sender, EventArgs e) { UpdateAnchors(); } private void UpdateAnchors() { if (hud != null) { hud.SetAnchor(carnometerAnchorX.Value, carnometerAnchorY.Value); } } private void CreateDamageMeterHUD() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (hud == null) { hud = HudBuilder.Create("DamageMeterHUD").ParentToReticle(true).Anchor(carnometerAnchorX.Value, carnometerAnchorY.Value) .Pivot(new Vector2(0f, 1f)) .Size(320f, 100f, true) .AddLines(4, -1f, (TextAlignmentOptions)513) .Build(); if (hud != null) { HudRepositionClient.Register("sparroh.carnometer", "Carnometer", hud.Rect, carnometerAnchorX, carnometerAnchorY); UpdateHudVisibility(); } } } private void DestroyHud() { HudRepositionClient.Unregister("sparroh.carnometer"); if (hud != null) { hud.Destroy(); hud = null; } } public void Update() { //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) if (!enableDamageMeterHUD.Value || (Object)(object)Player.LocalPlayer == (Object)null) { return; } if (hud == null) { CreateDamageMeterHUD(); } else { if (hud.Lines == null || hud.Lines.Length < 4) { return; } float time = Time.time; float value = dpsWindowSeconds.Value; while (damageQueue.Count > 0 && damageQueue.Peek().time < time - value) { damageQueue.Dequeue(); } float num = 0f; foreach (var item in damageQueue) { num += item.damage; } float num2 = ((damageQueue.Count > 0) ? (num / value) : 0f); float num3 = Time.time - missionStartTime; float num4 = ((num3 > 0f) ? (totalDamage / num3) : 0f); float num5 = ((num3 > 0f) ? ((float)totalKills / num3) : 0f); float num6 = ((num3 > 0f) ? ((float)totalCoresKilled / num3) : 0f); Color value2 = valueColor.Value; hud.Lines[0].SetRichWithRate("Total Damage", totalDamage, num4, value2, "F0", "F1"); hud.Lines[1].Text = RichText.LabeledWithRate($"Last {value:F0}sec Damage", num, num2, value2, "F0", "F1"); hud.Lines[2].SetRichWithRate("Targets Killed", (float)totalKills, num5, value2, "F0", "F1"); hud.Lines[3].SetRichWithRate("Cores Killed", (float)totalCoresKilled, num6, value2, "F0", "F1"); } } public void OnDestroy() { DestroyHud(); } } public static class HudRepositionClient { private const string ApiTypeName = "HudRepositionAPI"; private static Type _apiType; private static MethodInfo _register; private static MethodInfo _unregister; private static bool _available; public static bool IsAvailable { get { EnsureResolved(); return _available; } } public static void Register(string id, string displayName, RectTransform rect, ConfigEntry anchorX, ConfigEntry anchorY) { if (!_available) { EnsureResolved(force: true); } if (!_available || (Object)(object)rect == (Object)null || anchorX == null || anchorY == null) { return; } try { _register.Invoke(null, new object[5] { id, displayName, rect, anchorX, anchorY }); } catch (Exception ex) { Debug.LogWarning((object)("[HudRepositionClient] Register failed: " + (ex.InnerException?.Message ?? ex.Message))); } } public static void Unregister(string id) { if (!_available) { EnsureResolved(force: true); } if (!_available || string.IsNullOrEmpty(id)) { return; } try { _unregister.Invoke(null, new object[1] { id }); } catch (Exception) { } } private static void EnsureResolved(bool force = false) { if (_available && !force) { return; } _apiType = null; _register = null; _unregister = null; _available = false; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type type = assembly.GetType("HudRepositionAPI", throwOnError: false); if (type != null) { _apiType = type; break; } } catch { } } if (_apiType == null) { return; } MethodInfo[] methods = _apiType.GetMethods(BindingFlags.Static | BindingFlags.Public); foreach (MethodInfo methodInfo in methods) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (methodInfo.Name == "Register" && parameters.Length == 5 && parameters[0].ParameterType == typeof(string) && parameters[1].ParameterType == typeof(string) && typeof(RectTransform).IsAssignableFrom(parameters[2].ParameterType)) { _register = methodInfo; } else if (methodInfo.Name == "Unregister" && parameters.Length == 1 && parameters[0].ParameterType == typeof(string)) { _unregister = methodInfo; } } _available = _register != null && _unregister != null; } } [BepInPlugin("sparroh.carnometer", "Carnometer", "2.0.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.0.0"; internal static ManualLogSource Logger; private Harmony harmony; private CarnometerMod carnometer; private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; try { harmony = new Harmony("sparroh.carnometer"); } catch (Exception ex) { Logger.LogError((object)("Failed to create Harmony instance: " + ex.Message)); return; } ConfigFile configFile = ((BaseUnityPlugin)this).Config; try { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, "sparroh.carnometer.cfg"); fileSystemWatcher.Changed += delegate { configFile.Reload(); }; fileSystemWatcher.EnableRaisingEvents = true; } catch (Exception ex2) { Logger.LogWarning((object)("Failed to set up config watcher: " + ex2.Message)); } try { carnometer = new CarnometerMod(configFile, harmony); } 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 { if (carnometer != null) { carnometer.UpdateHudVisibility(); } } catch (Exception ex) { Logger.LogError((object)("Error in Carnometer.UpdateHudVisibility(): " + ex.Message)); } try { if (carnometer != null) { carnometer.Update(); } } catch (Exception ex2) { Logger.LogError((object)("Error in Carnometer.Update(): " + ex2.Message)); } } private void OnDestroy() { try { if (carnometer != null) { carnometer.OnDestroy(); } } catch (Exception ex) { Logger.LogError((object)("Error in Carnometer.OnDestroy(): " + ex.Message)); } try { if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex2) { Logger.LogError((object)("Error unpatching Harmony: " + ex2.Message)); } } } namespace Carnometer { public static class MyPluginInfo { public const string PLUGIN_GUID = "Carnometer"; public const string PLUGIN_NAME = "Carnometer"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }