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 Denis UI Killfeed v1.1.1
plugins/DenisUIKillFeed/DenisUIKillFeed.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; 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.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("DenisUIKillFeed")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+0d77aba4ef99a87d6be4daeb81b0de1f2e0c0dca")] [assembly: AssemblyProduct("DenisUIKillFeed")] [assembly: AssemblyTitle("DenisUIKillFeed")] [assembly: AssemblyVersion("1.0.0.0")] [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 DenisUIKillFeed { internal static class EnemyFeedTracker { internal static Enemy GetEnemyFromParent(EnemyParent enemyParent) { try { object? obj = Plugin.EnemyParentEnemyField?.GetValue(enemyParent); return (Enemy)((obj is Enemy) ? obj : null); } catch { return null; } } internal static bool GetParentSpawned(EnemyParent enemyParent) { try { object obj = Plugin.EnemyParentSpawnedField?.GetValue(enemyParent); if (obj is bool) { bool result = (bool)obj; if (true) { return result; } } } catch { } return true; } internal static bool GetEnemyHasHealth(Enemy enemy) { try { if ((Object)(object)enemy == (Object)null) { return false; } object obj = Plugin.EnemyHasHealthField?.GetValue(enemy); if (obj is bool) { bool result = (bool)obj; if (true) { return result; } } } catch { } return false; } internal static EnemyHealth GetEnemyHealth(Enemy enemy) { try { object? obj = Plugin.EnemyHealthRefField?.GetValue(enemy); return (EnemyHealth)((obj is EnemyHealth) ? obj : null); } catch { return null; } } internal static int GetEnemyHealthCurrent(EnemyHealth health) { try { if ((Object)(object)health == (Object)null) { return 0; } object obj = Plugin.EnemyHealthCurrentField?.GetValue(health); if (obj is int) { int result = (int)obj; if (true) { return result; } } } catch { } return 0; } internal static bool GetEnemyHealthDead(EnemyHealth health) { try { if ((Object)(object)health == (Object)null) { return false; } object obj = Plugin.EnemyHealthDeadField?.GetValue(health); if (obj is bool) { bool result = (bool)obj; if (true) { return result; } } } catch { } return false; } internal static float GetMapValueTotal() { return 0f; } internal static bool EnemyShouldRequireOrbConfirmation(string enemyName) { return !Plugin.NoOrbEnemyNames.Contains(enemyName); } internal static void SeedSeenValuables() { ValuableObject[] array = Object.FindObjectsOfType<ValuableObject>(); if (array == null) { return; } ValuableObject[] array2 = array; foreach (ValuableObject val in array2) { if ((Object)(object)val != (Object)null) { Plugin.SeenValuableIds.Add(((Object)((Component)val).gameObject).GetInstanceID()); } } } internal static bool ObserveNewEnemyOrbFor(string enemyName, float mapValueBeforeDeath) { ValuableObject[] array = Object.FindObjectsOfType<ValuableObject>(); if (array == null) { return false; } bool flag = EnemyShouldRequireOrbConfirmation(enemyName); float mapValueTotal = GetMapValueTotal(); ValuableObject[] array2 = array; foreach (ValuableObject val in array2) { if ((Object)(object)val == (Object)null) { continue; } int instanceID = ((Object)((Component)val).gameObject).GetInstanceID(); if (!Plugin.SeenValuableIds.Contains(instanceID)) { Plugin.SeenValuableIds.Add(instanceID); string text = ((Object)((Component)val).gameObject).name ?? string.Empty; if (text.IndexOf("Enemy Valuable", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } return !flag && mapValueTotal > mapValueBeforeDeath; } internal static void ObserveEnemiesFromDirector() { //IL_0667: Unknown result type (might be due to invalid IL or missing references) //IL_0494: Unknown result type (might be due to invalid IL or missing references) HashSet<int> seen = new HashSet<int>(); try { EnemyDirector instance = EnemyDirector.instance; if ((Object)(object)instance == (Object)null || instance.enemiesSpawned == null) { return; } foreach (EnemyParent item in instance.enemiesSpawned) { if ((Object)(object)item == (Object)null) { continue; } int instanceID = ((Object)item).GetInstanceID(); seen.Add(instanceID); string text = (string.IsNullOrWhiteSpace(item.enemyName) ? "Enemy" : item.enemyName); Enemy enemyFromParent = GetEnemyFromParent(item); bool parentSpawned = GetParentSpawned(item); EnemyHealth enemyHealth = GetEnemyHealth(enemyFromParent); bool flag = (Object)(object)enemyHealth != (Object)null && GetEnemyHasHealth(enemyFromParent); int num = (flag ? GetEnemyHealthCurrent(enemyHealth) : 0); bool flag2 = flag && (GetEnemyHealthDead(enemyHealth) || num <= 0); bool flag3 = flag2 || !parentSpawned; if (!Plugin.EnemyStates.TryGetValue(instanceID, out var value)) { Plugin.EnemyStates[instanceID] = new ObservedEnemyState { EnemyParent = item, Name = text, WasDead = flag3, LastHealth = num, FirstSeenAt = Time.time, AliveSince = ((!flag3 && parentSpawned) ? Time.time : (-1f)), PendingDeathSince = (flag3 ? Time.time : (-1f)), DeathAnnounced = false, Spawned = parentSpawned, HasEnteredStableAlivePhase = false, HadAliveHealthSample = (!flag3 && num > 0), HadDamageEvidence = false }; continue; } value.EnemyParent = item; value.Name = text; value.Spawned = parentSpawned; bool flag4 = Time.time - value.FirstSeenAt >= 1f; bool flag5 = Time.time - value.FirstSeenAt < 1f; if (!flag3 && parentSpawned) { if (value.AliveSince < 0f) { value.AliveSince = Time.time; } if (num > 0) { value.HadAliveHealthSample = true; } if (value.LastHealth > 0 && num > 0 && num < value.LastHealth) { value.HadDamageEvidence = true; } if (!value.HasEnteredStableAlivePhase && value.AliveSince >= 0f && Time.time - value.AliveSince >= 0.35f) { value.HasEnteredStableAlivePhase = true; } } bool flag6 = EnemyShouldRequireOrbConfirmation(text); bool flag7 = !flag6 && value.HadAliveHealthSample && (flag2 || value.HadDamageEvidence || (value.LastHealth > 0 && num <= 0)); if (!value.WasDead && flag3) { if (flag4 && !flag5 && value.HasEnteredStableAlivePhase && (flag6 || flag7)) { value.PendingDeathSince = Time.time; value.MapValueBeforeDeath = GetMapValueTotal(); value.OrbConfirmed = false; } else { value.PendingDeathSince = -1f; value.OrbConfirmed = false; } } else if (!flag3) { value.PendingDeathSince = -1f; value.DeathAnnounced = false; value.OrbConfirmed = false; } if (!value.DeathAnnounced && flag4 && flag3 && value.PendingDeathSince >= 0f && Time.time - value.PendingDeathSince >= 0.2f) { if (!value.OrbConfirmed) { value.OrbConfirmed = ObserveNewEnemyOrbFor(text, value.MapValueBeforeDeath); } bool flag8 = !flag6 && flag7; bool flag9 = value.LastAnnouncementAt <= 0f || Time.time - value.LastAnnouncementAt >= 6f; if ((value.OrbConfirmed || flag8) && flag9) { if (Plugin.ShowEnemyKillsConfig.Value && Time.time - Plugin.LevelStartTime >= 1f) { Plugin.AddEntry(text + " killed", new Color(0.96f, 0.82f, 0.28f, 1f)); } value.DeathAnnounced = true; value.LastAnnouncementAt = Time.time; } } value.WasDead = flag3; value.LastHealth = num; } } catch (Exception arg) { Debug.LogError((object)$"[DenisUIKillFeed] ObserveEnemiesFromDirector error: {arg}"); } List<int> list = Plugin.EnemyStates.Keys.Where((int id) => !seen.Contains(id)).ToList(); foreach (int item2 in list) { ObservedEnemyState observedEnemyState = Plugin.EnemyStates[item2]; bool flag10 = Time.time - observedEnemyState.FirstSeenAt >= 1f; if (!observedEnemyState.DeathAnnounced && flag10 && observedEnemyState.PendingDeathSince >= 0f) { if (!observedEnemyState.OrbConfirmed) { observedEnemyState.OrbConfirmed = ObserveNewEnemyOrbFor(observedEnemyState.Name, observedEnemyState.MapValueBeforeDeath); } bool flag11 = !EnemyShouldRequireOrbConfirmation(observedEnemyState.Name) && observedEnemyState.HadAliveHealthSample && observedEnemyState.HadDamageEvidence; bool flag12 = observedEnemyState.LastAnnouncementAt <= 0f || Time.time - observedEnemyState.LastAnnouncementAt >= 6f; if ((observedEnemyState.OrbConfirmed || flag11) && flag12) { if (Plugin.ShowEnemyKillsConfig.Value && Time.time - Plugin.LevelStartTime >= 1f) { Plugin.AddEntry(observedEnemyState.Name + " killed", new Color(0.96f, 0.82f, 0.28f, 1f)); } observedEnemyState.LastAnnouncementAt = Time.time; } } Plugin.EnemyStates.Remove(item2); } } } [HarmonyPatch(typeof(RoundDirector))] internal static class KillFeedHud { [HarmonyPatch("Update")] [HarmonyPostfix] private static void Update_Postfix() { bool flag = SemiFunc.RunIsLevel(); if (flag) { Plugin.LastLevelActiveAt = Time.time; } if (!EnsureHud()) { return; } if (!flag) { if (Time.time - Plugin.LastLevelActiveAt <= 8f) { UpdateKillFeedHud(); return; } SetInactive(); Plugin.ResetObservedState(); } else { PlayerFeedTracker.ObservePlayers(); EnemyFeedTracker.ObserveEnemiesFromDirector(); UpdateKillFeedHud(); } } internal static bool EnsureHud() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown //IL_0119: 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_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.Find("Game Hud"); GameObject val2 = GameObject.Find("Tax Haul"); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return false; } TMP_Text component = val2.GetComponent<TMP_Text>(); TMP_FontAsset val3 = ((component != null) ? component.font : null); if ((Object)(object)val3 == (Object)null) { return false; } if ((Object)(object)Plugin.FeedInstance == (Object)null) { Plugin.FeedInstance = new GameObject("Denis UI Killfeed HUD"); Plugin.FeedInstance.SetActive(false); Plugin.FeedInstance.transform.SetParent(val.transform, false); Plugin.FeedText = Plugin.FeedInstance.AddComponent<TextMeshProUGUI>(); ((TMP_Text)Plugin.FeedText).font = val3; ((TMP_Text)Plugin.FeedText).fontSize = 24f; ((TMP_Text)Plugin.FeedText).enableWordWrapping = false; ((TMP_Text)Plugin.FeedText).alignment = (TextAlignmentOptions)260; ((TMP_Text)Plugin.FeedText).horizontalAlignment = (HorizontalAlignmentOptions)4; ((TMP_Text)Plugin.FeedText).verticalAlignment = (VerticalAlignmentOptions)256; ((Graphic)Plugin.FeedText).raycastTarget = false; ((TMP_Text)Plugin.FeedText).margin = Vector4.zero; ((TMP_Text)Plugin.FeedText).characterSpacing = 0f; ((TMP_Text)Plugin.FeedText).wordSpacing = 0f; ((TMP_Text)Plugin.FeedText).fontStyle = (FontStyles)0; ContentSizeFitter val4 = Plugin.FeedInstance.AddComponent<ContentSizeFitter>(); val4.verticalFit = (FitMode)2; val4.horizontalFit = (FitMode)0; RectTransform component2 = Plugin.FeedInstance.GetComponent<RectTransform>(); component2.pivot = new Vector2(1f, 1f); component2.anchorMin = new Vector2(1f, 1f); component2.anchorMax = new Vector2(1f, 1f); component2.sizeDelta = new Vector2(520f, 220f); component2.anchoredPosition = new Vector2(-10f, -250f); } else if ((Object)(object)Plugin.FeedText != (Object)null && (Object)(object)((TMP_Text)Plugin.FeedText).transform.parent != (Object)(object)val.transform) { ((TMP_Text)Plugin.FeedText).transform.SetParent(val.transform, false); } return true; } internal static void UpdateKillFeedHud() { //IL_0101: Unknown result type (might be due to invalid IL or missing references) Plugin.Entries.RemoveAll((KillFeedEntry e) => Time.time > e.ExpiresAt); if (Plugin.Entries.Count == 0) { Plugin.FeedInstance.SetActive(false); Plugin.LastRenderedFeedText = string.Empty; Plugin.LastRenderedFontSize = -1f; Plugin.HudShowStartedAt = -100000f; return; } bool activeSelf = Plugin.FeedInstance.activeSelf; Plugin.FeedInstance.SetActive(true); if (!activeSelf) { Plugin.HudShowStartedAt = Time.time; } RectTransform component = Plugin.FeedInstance.GetComponent<RectTransform>(); float num = Mathf.Max(0f, Time.time - Plugin.HudShowStartedAt); float num2 = Mathf.Clamp01(num / 0.18f); float num3 = 1f - Mathf.Pow(1f - num2, 3f); float num4 = Mathf.Lerp(24f, 0f, num3); component.anchoredPosition = new Vector2(-10f + num4, -250f); int num5 = Plugin.Entries.Max((KillFeedEntry e) => e.Text.Length); int num6 = Mathf.Clamp((num5 - 1) / 46, 0, 3); float num7 = Mathf.Clamp(Plugin.TextScaleConfig?.Value ?? 1f, 0.7f, 1f); float num8 = Plugin.MobHudSizes[num6] * num7; if (!Mathf.Approximately(Plugin.LastRenderedFontSize, num8)) { ((TMP_Text)Plugin.FeedText).fontSize = num8; ((TMP_Text)Plugin.FeedText).lineSpacing = (0f - num8) * 1.05f; Plugin.LastRenderedFontSize = num8; } StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < Plugin.Entries.Count; i++) { KillFeedEntry killFeedEntry = Plugin.Entries[i]; if (i > 0) { stringBuilder.Append('\n'); } float num9 = Mathf.Max(0f, Time.time - killFeedEntry.CreatedAt); float num10 = Mathf.Max(0f, killFeedEntry.ExpiresAt - Time.time); float num11 = Mathf.Clamp01(num9 / 0.16f); float num12 = Mathf.Clamp01(num10 / 0.24f); float num13 = Mathf.Min(num11, num12); string value = Mathf.Clamp(Mathf.RoundToInt(num13 * 255f), 0, 255).ToString("X2"); stringBuilder.Append("<color=#").Append(killFeedEntry.Color).Append(value) .Append('>') .Append(killFeedEntry.Text) .Append("</color>"); } string text = stringBuilder.ToString(); if (text != Plugin.LastRenderedFeedText) { ((TMP_Text)Plugin.FeedText).text = text; Plugin.LastRenderedFeedText = text; } } internal static void SetInactive() { if ((Object)(object)Plugin.FeedInstance != (Object)null) { Plugin.FeedInstance.SetActive(false); } } } internal sealed class KillFeedEntry { public string Text; public string Color; public float ExpiresAt; public float CreatedAt; } internal sealed class ObservedPlayerState { public PlayerAvatar Avatar; public string Name; public bool WasDead; public float LastDeathAt; } internal sealed class PendingDisconnectState { public string Name; public float MissingSince; public bool HadRecentDeath; } internal sealed class ObservedEnemyState { public EnemyParent EnemyParent; public string Name; public bool WasDead; public int LastHealth; public float FirstSeenAt; public float PendingDeathSince; public bool DeathAnnounced; public bool Spawned; public float MapValueBeforeDeath; public bool OrbConfirmed; public float AliveSince; public bool HasEnteredStableAlivePhase; public bool HadAliveHealthSample; public bool HadDamageEvidence; public float LastAnnouncementAt; } internal static class PlayerFeedTracker { [HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathRPC")] internal static class PlayerAvatarDeathPatch { [HarmonyPostfix] private static void Postfix(PlayerAvatar __instance) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) string text = ResolvePlayerName(__instance); string item = SanitizeDisplayName(text); if (!Plugin.PlayersWithDisconnectFeed.Contains(item) && Plugin.ShowPlayerDeathsConfig.Value && Time.time - Plugin.LevelStartTime >= 1f) { Plugin.AddEntry(text + " died", new Color(0.7f, 0.23f, 0.23f, 1f)); } int num = (((Object)(object)__instance != (Object)null) ? ((Object)__instance).GetInstanceID() : 0); if (num != 0 && Plugin.PlayerStates.TryGetValue(num, out var value)) { value.WasDead = true; value.LastDeathAt = Time.time; } } } internal static string ResolvePlayerName(PlayerAvatar avatar) { if ((Object)(object)avatar == (Object)null) { return "Player"; } try { string raw = Plugin.PlayerNameField?.GetValue(avatar) as string; raw = SanitizeDisplayName(raw); if (!string.IsNullOrWhiteSpace(raw)) { return raw; } } catch { } return SanitizeDisplayName((!string.IsNullOrWhiteSpace(((Object)avatar).name)) ? ((Object)avatar).name : "Player"); } internal static string SanitizeDisplayName(string raw) { if (string.IsNullOrEmpty(raw)) { return raw; } StringBuilder stringBuilder = new StringBuilder(raw.Length); foreach (char c in raw) { if (!char.IsControl(c)) { UnicodeCategory unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c); if (unicodeCategory != UnicodeCategory.Format) { stringBuilder.Append(c); } } } return stringBuilder.ToString().Trim(); } internal static bool IsPlayerDead(PlayerAvatar avatar) { if ((Object)(object)avatar == (Object)null) { return false; } try { object obj = Plugin.PlayerDeadSetField?.GetValue(avatar); if (obj is bool) { bool result = (bool)obj; if (true) { return result; } } } catch { } return false; } internal static void ObservePlayers() { //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) HashSet<int> seen = new HashSet<int>(); try { List<PlayerAvatar> list = SemiFunc.PlayerGetAll(); if (list == null) { return; } foreach (PlayerAvatar item2 in list) { if ((Object)(object)item2 == (Object)null) { continue; } int instanceID = ((Object)item2).GetInstanceID(); seen.Add(instanceID); string text = ResolvePlayerName(item2); bool flag = IsPlayerDead(item2); if (!Plugin.PlayerStates.TryGetValue(instanceID, out var value)) { value = new ObservedPlayerState { Avatar = item2, Name = text, WasDead = flag }; Plugin.PlayerStates[instanceID] = value; } else { value.Avatar = item2; value.Name = text; } Plugin.PlayerStatesByName[text] = value; Plugin.PendingDisconnects.Remove(text); if (!value.WasDead && flag) { string item = SanitizeDisplayName(text); if (!Plugin.PlayersWithDisconnectFeed.Contains(item) && Plugin.ShowPlayerDeathsConfig.Value && Time.time - Plugin.LevelStartTime >= 1f) { Plugin.AddEntry(text + " died", new Color(0.7f, 0.23f, 0.23f, 1f)); } value.LastDeathAt = Time.time; } value.WasDead = flag; } } catch (Exception arg) { Debug.LogError((object)$"[DenisUIKillFeed] ObservePlayers error: {arg}"); } List<int> list2 = Plugin.PlayerStates.Keys.Where((int id) => !seen.Contains(id)).ToList(); foreach (int item3 in list2) { ObservedPlayerState observedPlayerState = Plugin.PlayerStates[item3]; if (observedPlayerState != null && !string.IsNullOrWhiteSpace(observedPlayerState.Name) && !Plugin.SceneResetInProgress) { bool hadRecentDeath = observedPlayerState.LastDeathAt > 0f && Time.time - observedPlayerState.LastDeathAt <= 2.5f; string text2 = SanitizeDisplayName(observedPlayerState.Name); if (!string.IsNullOrWhiteSpace(text2) && !Plugin.PendingDisconnects.ContainsKey(text2)) { Plugin.PendingDisconnects[text2] = new PendingDisconnectState { Name = text2, MissingSince = Time.time, HadRecentDeath = hadRecentDeath }; } } if (observedPlayerState != null && !string.IsNullOrWhiteSpace(observedPlayerState.Name)) { Plugin.PlayerStatesByName.Remove(observedPlayerState.Name); } Plugin.PlayerStates.Remove(item3); } List<string> list3 = Plugin.PendingDisconnects.Keys.ToList(); foreach (string item4 in list3) { if (Plugin.PlayerStatesByName.ContainsKey(item4)) { Plugin.PendingDisconnects.Remove(item4); } else { if (Time.time - Plugin.LevelStartTime < 4f) { continue; } PendingDisconnectState pendingDisconnectState = Plugin.PendingDisconnects[item4]; if (Time.time - pendingDisconnectState.MissingSince < 1.25f) { continue; } if (Plugin.RecentlyDisconnectedPlayers.Add(pendingDisconnectState.Name)) { if (Plugin.ShowDisconnectsConfig.Value) { Plugin.AddEntry(pendingDisconnectState.Name + " disconnected", new Color(0.58f, 0.58f, 0.62f, 1f)); } Plugin.PlayersWithDisconnectFeed.Add(pendingDisconnectState.Name); } Plugin.PendingDisconnects.Remove(item4); } } if (Plugin.SceneResetInProgress && seen.Count > 0) { Plugin.SceneResetInProgress = false; } } } [BepInPlugin("denis.repo.denisuikillfeed", "Denis UI Killfeed", "1.1.0")] public class Plugin : BaseUnityPlugin { internal static GameObject FeedInstance; internal static TextMeshProUGUI FeedText; internal static readonly List<KillFeedEntry> Entries = new List<KillFeedEntry>(); internal static readonly Dictionary<int, ObservedPlayerState> PlayerStates = new Dictionary<int, ObservedPlayerState>(); internal static readonly Dictionary<string, ObservedPlayerState> PlayerStatesByName = new Dictionary<string, ObservedPlayerState>(StringComparer.OrdinalIgnoreCase); internal static readonly HashSet<string> RecentlyDisconnectedPlayers = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static readonly HashSet<string> PlayersWithDisconnectFeed = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static readonly Dictionary<string, PendingDisconnectState> PendingDisconnects = new Dictionary<string, PendingDisconnectState>(StringComparer.OrdinalIgnoreCase); internal static readonly Dictionary<int, ObservedEnemyState> EnemyStates = new Dictionary<int, ObservedEnemyState>(); internal static readonly HashSet<int> SeenValuableIds = new HashSet<int>(); internal static readonly HashSet<string> NoOrbEnemyNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Gnome", "Banger", "Tick" }; internal static readonly float[] MobHudSizes = new float[4] { 24f, 18f, 14f, 11f }; internal static bool SceneResetInProgress; internal static float LastLevelActiveAt; internal static float LevelStartTime; internal static float HudShowStartedAt = -100000f; internal static string LastRenderedFeedText = string.Empty; internal static float LastRenderedFontSize = -1f; internal static readonly FieldInfo PlayerNameField = typeof(PlayerAvatar).GetField("playerName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static readonly FieldInfo PlayerDeadSetField = typeof(PlayerAvatar).GetField("deadSet", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static readonly FieldInfo EnemyParentEnemyField = typeof(EnemyParent).GetField("Enemy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(EnemyParent).GetField("enemy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static readonly FieldInfo EnemyParentSpawnedField = typeof(EnemyParent).GetField("Spawned", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(EnemyParent).GetField("spawned", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static readonly FieldInfo EnemyHasHealthField = typeof(Enemy).GetField("HasHealth", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(Enemy).GetField("hasHealth", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static readonly FieldInfo EnemyHealthRefField = typeof(Enemy).GetField("Health", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(Enemy).GetField("health", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static readonly FieldInfo EnemyHealthCurrentField = typeof(EnemyHealth).GetField("healthCurrent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static readonly FieldInfo EnemyHealthDeadField = typeof(EnemyHealth).GetField("dead", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static ConfigEntry<bool> ShowEnemyKillsConfig; internal static ConfigEntry<bool> ShowPlayerDeathsConfig; internal static ConfigEntry<bool> ShowDisconnectsConfig; internal static ConfigEntry<float> TextScaleConfig; internal const float HudGraceAfterLevelEnds = 8f; internal const float DisconnectConfirmSeconds = 1.25f; internal const float DisconnectStartupGuardSeconds = 4f; internal const float SpawnGraceSeconds = 1f; internal const float AliveStableSeconds = 0.35f; internal const float EnemyAnnouncementCooldownSeconds = 6f; internal const float HudSlideSeconds = 0.18f; internal const float EntryFadeInSeconds = 0.16f; internal const float EntryFadeOutSeconds = 0.24f; internal static Plugin Instance { get; private set; } internal Harmony Harmony { get; private set; } private void Awake() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown Instance = this; ((Component)this).transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; TextScaleConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Killfeed Activity", "Text Scale", 1f, new ConfigDescription("Scales the killfeed text size.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.7f, 1f), Array.Empty<object>())); ShowEnemyKillsConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Killfeed Activity", "Enemy deaths", true, "Show enemy death events in the killfeed."); ShowPlayerDeathsConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Killfeed Activity", "Player deaths", true, "Show player death events in the killfeed."); ShowDisconnectsConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Killfeed Activity", "Player disconnects", true, "Show player disconnect events in the killfeed."); Harmony = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Denis UI Killfeed loaded"); } private void OnDestroy() { Harmony harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } internal static void AddEntry(string text, Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) string text2 = ColorUtility.ToHtmlStringRGB(color); if (Entries.Count > 0) { KillFeedEntry killFeedEntry = Entries[0]; if (killFeedEntry.Text == text && killFeedEntry.Color == text2 && Time.time - killFeedEntry.CreatedAt <= 0.35f) { killFeedEntry.ExpiresAt = Time.time + 7f; return; } } Entries.Insert(0, new KillFeedEntry { Text = text, Color = text2, ExpiresAt = Time.time + 7f, CreatedAt = Time.time }); if (Entries.Count > 5) { Entries.RemoveRange(5, Entries.Count - 5); } } internal static void ResetObservedState() { PlayerStates.Clear(); PlayerStatesByName.Clear(); EnemyStates.Clear(); SeenValuableIds.Clear(); RecentlyDisconnectedPlayers.Clear(); PlayersWithDisconnectFeed.Clear(); PendingDisconnects.Clear(); SceneResetInProgress = true; LevelStartTime = Time.time; HudShowStartedAt = -100000f; LastRenderedFeedText = string.Empty; LastRenderedFontSize = -1f; } } }