Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SimpleDeathCounter v0.2.0
SimpleDeathCounter.dll
Decompiled 8 months agousing System; using System.Collections; 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 UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = "")] [assembly: AssemblyCompany("SimpleDeathCounter")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("A BepInEx of my Simple Death Counter mod originally made with MelonLoader")] [assembly: AssemblyTitle("SimpleDeathCounter")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 SimpleDeathCounter { [BepInPlugin("Nordbo.SimpleDeathCounter", "Simple Death Counter", "0.2.0")] public class Plugin : BaseUnityPlugin { [CompilerGenerated] private sealed class <AttachToPlayer>d__44 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; private Type <heroControllerType>5__1; private Object[] <heroObjects>5__2; private Object[] <>s__3; private int <>s__4; private Object <obj>5__5; private EventInfo <onDeathEvent>5__6; private Action <callback>5__7; private Exception <e>5__8; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <AttachToPlayer>d__44(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <heroControllerType>5__1 = null; <heroObjects>5__2 = null; <>s__3 = null; <obj>5__5 = null; <onDeathEvent>5__6 = null; <callback>5__7 = null; <e>5__8 = null; <>1__state = -2; } private bool MoveNext() { //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } try { <heroControllerType>5__1 = AccessTools.TypeByName("HeroController"); if (<heroControllerType>5__1 != null) { <heroObjects>5__2 = Object.FindObjectsOfType(<heroControllerType>5__1); <>s__3 = <heroObjects>5__2; for (<>s__4 = 0; <>s__4 < <>s__3.Length; <>s__4++) { <obj>5__5 = <>s__3[<>s__4]; if (!(<obj>5__5 == (Object)null) && !attachedHeroes.Contains(<obj>5__5)) { <onDeathEvent>5__6 = <heroControllerType>5__1.GetEvent("OnDeath"); if (<onDeathEvent>5__6 != null) { <callback>5__7 = delegate { IncrementDeathCount(); }; try { <onDeathEvent>5__6.RemoveEventHandler(<obj>5__5, <callback>5__7); } catch { } <onDeathEvent>5__6.AddEventHandler(<obj>5__5, <callback>5__7); attachedHeroes.Add(<obj>5__5); ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"\ud83d\udd39 Attached OnDeath event to HeroController instance."); } <callback>5__7 = null; } <onDeathEvent>5__6 = null; <obj>5__5 = null; } } <>s__3 = null; <heroObjects>5__2 = null; } <heroControllerType>5__1 = null; } catch (Exception ex) { <e>5__8 = ex; ManualLogSource log2 = Log; if (log2 != null) { log2.LogDebug((object)("AttachToPlayer tick error: " + <e>5__8.Message)); } } <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <ReloadConfigRoutine>d__41 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Plugin <>4__this; private int <i>5__1; private bool <retry>5__2; private Exception <ex>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ReloadConfigRoutine>d__41(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <ex>5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.05f); <>1__state = 1; return true; case 1: <>1__state = -1; <i>5__1 = 0; break; case 2: <>1__state = -1; <i>5__1++; break; } if (<i>5__1 < 3) { <retry>5__2 = false; try { ((BaseUnityPlugin)<>4__this).Config.Reload(); deathCount = cfgDeathCount.Value; UpdateCounterUI(); Log.LogInfo((object)"♻\ufe0f Config reloaded from disk."); return false; } catch (IOException) { <retry>5__2 = true; } catch (Exception ex2) { <ex>5__3 = ex2; Log.LogWarning((object)("Config reload error: " + <ex>5__3.Message)); return false; } if (<retry>5__2) { <>2__current = (object)new WaitForSeconds(0.4f); <>1__state = 2; return true; } } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } internal static ManualLogSource Log; private static readonly HashSet<object> attachedHeroes = new HashSet<object>(); public static int deathCount = 0; private static float lastDeathRegisterTime = -999f; private static GameObject counterCanvasGO; private static Text counterUIText; private static Outline counterOutline; private static ConfigEntry<float> cfgPosX; private static ConfigEntry<float> cfgPosY; private static ConfigEntry<int> cfgFontSize; private static ConfigEntry<bool> cfgAutoFontSize; private static ConfigEntry<bool> cfgEnableDeathAnimation; private static ConfigEntry<int> cfgDeathCount; private static bool deathAnimation = false; private static float animationTimer = 0f; private const float animationDuration = 0.28f; private const int fontSizeIncrease = 7; private FileSystemWatcher _cfgWatcher; private static bool _configReloadPending = false; private static float _configReloadRequestTime = 0f; private string _configFilePath; private static Vector2 CounterPosition => new Vector2(cfgPosX.Value, cfgPosY.Value); private static int FontSize => cfgFontSize.Value; private static bool AutoFontSize => cfgAutoFontSize.Value; private static bool EnableDeathAnim => cfgEnableDeathAnimation.Value; private void Awake() { //IL_0214: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"Simple Death Counter loading..."); cfgPosX = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "PosX", 24f, "Horizontal position (pixels) from left."); cfgPosY = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "PosY", -72f, "Vertical position (pixels). Negative means from bottom."); cfgFontSize = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "FontSize", 26, "Font size if AutoFontSize is false."); cfgAutoFontSize = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "AutoFontSize", true, "Auto-scale font relative to screen height."); cfgEnableDeathAnimation = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "EnableDeathAnimation", true, "Animate text briefly on death."); cfgDeathCount = ((BaseUnityPlugin)this).Config.Bind<int>("Data", "DeathCount", 0, "Total number of deaths (persisted)."); cfgDeathCount.SettingChanged += delegate { deathCount = cfgDeathCount.Value; UpdateCounterUI(); }; cfgPosX.SettingChanged += delegate { UpdateCounterUI(); }; cfgPosY.SettingChanged += delegate { UpdateCounterUI(); }; cfgFontSize.SettingChanged += delegate { UpdateCounterUI(); }; cfgAutoFontSize.SettingChanged += delegate { UpdateCounterUI(); }; cfgEnableDeathAnimation.SettingChanged += delegate { }; deathCount = cfgDeathCount.Value; Log.LogInfo((object)$"\ud83d\udce5 Loaded deaths from config: {deathCount}"); new Harmony("Nordbo.SimpleDeathCounter").PatchAll(); try { CreateCounterUI(); UpdateCounterUI(); } catch (Exception ex) { Log.LogWarning((object)("Could not create initial UI: " + ex.Message)); } ((MonoBehaviour)this).StartCoroutine(AttachToPlayer()); _configFilePath = Path.Combine(Paths.ConfigPath, ((BaseUnityPlugin)this).Info.Metadata.GUID + ".cfg"); SetupConfigWatcher(); } private void OnDestroy() { try { if (_cfgWatcher != null) { _cfgWatcher.EnableRaisingEvents = false; _cfgWatcher.Dispose(); _cfgWatcher = null; } } catch { } } private void Update() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) if (_configReloadPending && Time.realtimeSinceStartup - _configReloadRequestTime > 0.25f) { _configReloadPending = false; TryReloadConfig(); } if ((Object)(object)counterUIText == (Object)null) { return; } int num = (AutoFontSize ? Mathf.RoundToInt((float)Screen.height * 0.03f) : FontSize); int num2 = num; Color val = Color.white; if (EnableDeathAnim && deathAnimation) { animationTimer += Time.deltaTime; float num3 = Mathf.Clamp01(animationTimer / 0.28f); float num4 = 1f - Mathf.Pow(1f - num3, 2f); num2 = Mathf.RoundToInt((float)num + 7f * (1f - num4)); val = Color.Lerp(Color.red, Color.white, num3); if (animationTimer >= 0.28f) { deathAnimation = false; animationTimer = 0f; val = Color.white; } } RectTransform rectTransform = ((Graphic)counterUIText).rectTransform; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(CounterPosition.x, (CounterPosition.y >= 0f) ? CounterPosition.y : (0f - CounterPosition.y)); if (counterUIText.fontSize != num2) { counterUIText.fontSize = num2; } if (((Graphic)counterUIText).color != val) { ((Graphic)counterUIText).color = val; } if (rectTransform.anchoredPosition != val2) { rectTransform.anchoredPosition = val2; } } private void OnGUI() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) GameManager instance = GameManager.instance; if ((Object)(object)instance == (Object)null || (int)instance.GameState != 4 || (Object)(object)counterUIText != (Object)null) { return; } GUIStyle label = GUI.skin.label; label.alignment = (TextAnchor)6; label.font = Resources.Load<Font>("Perpetua") ?? Resources.GetBuiltinResource<Font>("Arial.ttf"); int num = (AutoFontSize ? Mathf.RoundToInt((float)Screen.height * 0.03f) : FontSize); if (EnableDeathAnim && deathAnimation) { animationTimer += Time.deltaTime; float num2 = Mathf.Clamp01(animationTimer / 0.28f); float num3 = 1f - Mathf.Pow(1f - num2, 2f); num = Mathf.RoundToInt((float)num + 7f * (1f - num3)); label.normal.textColor = Color.Lerp(Color.red, Color.white, num2); if (animationTimer >= 0.28f) { deathAnimation = false; animationTimer = 0f; label.normal.textColor = Color.white; } } label.fontSize = num; float x = CounterPosition.x; float num4 = ((CounterPosition.y >= 0f) ? CounterPosition.y : ((float)Screen.height + CounterPosition.y)); string text = $"Deaths: {deathCount}"; Color color = GUI.color; GUI.color = new Color(0f, 0f, 0f, 0.9f); GUI.Label(new Rect(x + 3f, num4 + 3f, 800f, 72f), text, label); GUI.color = Color.white; GUI.Label(new Rect(x, num4, 800f, 72f), text, label); GUI.color = color; } public static void IncrementDeathCount() { float realtimeSinceStartup = Time.realtimeSinceStartup; if (!(realtimeSinceStartup - lastDeathRegisterTime < 0.4f)) { lastDeathRegisterTime = realtimeSinceStartup; deathCount++; ManualLogSource log = Log; if (log != null) { log.LogInfo((object)$"\ud83d\udc80 Death registered. Total: {deathCount}"); } PersistDeathCount(); if (EnableDeathAnim) { deathAnimation = true; animationTimer = 0f; } UpdateCounterUI(); } } public static int GetHeroDeathCount() { return deathCount; } public static void SetHeroDeathCount(int value) { deathCount = value; PersistDeathCount(); UpdateCounterUI(); } private static void PersistDeathCount() { try { cfgDeathCount.Value = deathCount; Plugin plugin = Object.FindObjectOfType<Plugin>(); if (plugin != null) { ((BaseUnityPlugin)plugin).Config.Save(); } ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"\ud83d\udcbe Death count saved to config."); } } catch (Exception ex) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogError((object)("❌ Failed to save death count: " + ex.Message)); } } } private void SetupConfigWatcher() { try { string directoryName = Path.GetDirectoryName(_configFilePath); string fileName = Path.GetFileName(_configFilePath); _cfgWatcher = new FileSystemWatcher(directoryName, fileName) { NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Attributes | NotifyFilters.Size | NotifyFilters.LastWrite) }; _cfgWatcher.Changed += OnConfigFileTouched; _cfgWatcher.Created += OnConfigFileTouched; _cfgWatcher.Renamed += OnConfigFileRenamed; _cfgWatcher.EnableRaisingEvents = true; Log.LogInfo((object)("\ud83c\udf00 Config hot-reload watching: " + _configFilePath)); } catch (Exception ex) { Log.LogWarning((object)("Config watcher failed to start: " + ex.Message)); } } private void OnConfigFileTouched(object sender, FileSystemEventArgs e) { _configReloadPending = true; _configReloadRequestTime = Time.realtimeSinceStartup; } private void OnConfigFileRenamed(object sender, RenamedEventArgs e) { _configReloadPending = true; _configReloadRequestTime = Time.realtimeSinceStartup; } private void TryReloadConfig() { try { ((MonoBehaviour)this).StartCoroutine(ReloadConfigRoutine()); } catch (Exception ex) { Log.LogWarning((object)("Config reload scheduling failed: " + ex.Message)); } } [IteratorStateMachine(typeof(<ReloadConfigRoutine>d__41))] private IEnumerator ReloadConfigRoutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ReloadConfigRoutine>d__41(0) { <>4__this = this }; } private static void CreateCounterUI() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)counterCanvasGO != (Object)null)) { counterCanvasGO = new GameObject("DeathCounterCanvas", new Type[3] { typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster) }); Object.DontDestroyOnLoad((Object)(object)counterCanvasGO); Canvas component = counterCanvasGO.GetComponent<Canvas>(); component.renderMode = (RenderMode)0; component.sortingOrder = 9999; CanvasScaler component2 = counterCanvasGO.GetComponent<CanvasScaler>(); component2.uiScaleMode = (ScaleMode)1; component2.referenceResolution = new Vector2(1920f, 1080f); GameObject val = new GameObject("DeathCounterText", new Type[3] { typeof(RectTransform), typeof(Text), typeof(Outline) }); val.transform.SetParent(counterCanvasGO.transform, false); RectTransform component3 = val.GetComponent<RectTransform>(); component3.anchorMin = new Vector2(0f, 0f); component3.anchorMax = new Vector2(0f, 0f); component3.pivot = new Vector2(0f, 0f); component3.anchoredPosition = new Vector2(24f, 24f); component3.sizeDelta = new Vector2(800f, 72f); counterUIText = val.GetComponent<Text>(); counterUIText.alignment = (TextAnchor)6; ((Graphic)counterUIText).color = Color.white; counterUIText.font = Resources.Load<Font>("Perpetua") ?? Resources.GetBuiltinResource<Font>("Arial.ttf"); counterUIText.fontSize = Mathf.RoundToInt((float)Screen.height * 0.03f); counterOutline = val.GetComponent<Outline>(); ((Shadow)counterOutline).effectColor = new Color(0f, 0f, 0f, 0.9f); ((Shadow)counterOutline).effectDistance = new Vector2(2f, -2f); } } private static void UpdateCounterUI() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)counterUIText == (Object)null)) { counterUIText.text = $"Deaths: {deathCount}"; RectTransform rectTransform = ((Graphic)counterUIText).rectTransform; float x = CounterPosition.x; float num = ((CounterPosition.y >= 0f) ? CounterPosition.y : (0f - CounterPosition.y)); if (num < 0f) { num = 0f; } rectTransform.anchoredPosition = new Vector2(x, num); counterUIText.fontSize = (AutoFontSize ? Mathf.RoundToInt((float)Screen.height * 0.03f) : FontSize); } } [IteratorStateMachine(typeof(<AttachToPlayer>d__44))] private static IEnumerator AttachToPlayer() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <AttachToPlayer>d__44(0); } } [HarmonyPatch] public static class HeroControllerPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("HeroController"); return AccessTools.Method(type, "Awake", (Type[])null, (Type[])null); } private static void Postfix(object __instance) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"\ud83d\udd39 HeroController.Awake called. Checking for OnDeath event..."); } EventInfo @event = __instance.GetType().GetEvent("OnDeath", BindingFlags.Instance | BindingFlags.Public); if (@event != null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)"ℹ\ufe0f OnDeath event present (subscription handled elsewhere)."); } } else { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)"❌ Could not find OnDeath event in HeroController!"); } } } } [HarmonyPatch(typeof(GameManager), "PlayerDead")] internal static class GameManagerPlayerDeadPatch { private static void Postfix(GameManager __instance) { Plugin.IncrementDeathCount(); } } [HarmonyPatch(typeof(GameManager), "PlayerDeadFromHazard")] internal static class GameManagerPlayerDeadFromHazardPatch { private static void Postfix(GameManager __instance) { } } public static class MyPluginInfo { public const string PLUGIN_GUID = "SimpleDeathCounter"; public const string PLUGIN_NAME = "A BepInEx of my Simple Death Counter mod originally made with MelonLoader"; public const string PLUGIN_VERSION = "1.0.0"; } }