Decompiled source of PvP Kill Feed v1.1.0

PvPKillFeed.dll

Decompiled 8 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using RdMods.PvpKillFeed.Patches;
using TMPro;
using UnityEngine;
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("PvPKillFeed")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("PvP Kill Feed")]
[assembly: AssemblyTitle("PvPKillFeed")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
namespace RdMods.PvpKillFeed
{
	public static class ChatCommands
	{
		[HarmonyPatch(typeof(Chat), "InputText")]
		private static class ChatInputPatch
		{
			private static bool Prefix(Chat __instance)
			{
				if ((Object)(object)__instance == (Object)null || (Object)(object)((Terminal)__instance).m_input == (Object)null)
				{
					return true;
				}
				return !TryHandleChat(((TMP_InputField)((Terminal)__instance).m_input).text);
			}
		}

		private class DelegateCommand : ConsoleCommand
		{
			private readonly string _name;

			private readonly string _help;

			private readonly Action<string[]> _run;

			public override string Name => _name;

			public override string Help => _help;

			public override bool IsCheat => false;

			public DelegateCommand(string name, string help, Action<string[]> run)
			{
				_name = name;
				_help = help;
				_run = run;
			}

			public override void Run(string[] args)
			{
				_run(args);
			}
		}

		public static void Register()
		{
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new DelegateCommand("disablekillfeed", "Hide the kill feed on this client for the current session.", delegate
			{
				SetFeedHidden(hidden: true);
			}));
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new DelegateCommand("enablekillfeed", "Show the kill feed on this client. Rejoin also re-enables it.", delegate
			{
				SetFeedHidden(hidden: false);
			}));
		}

		public static bool TryHandleChat(string raw)
		{
			if (string.IsNullOrEmpty(raw) || raw[0] != '/')
			{
				return false;
			}
			string text = raw.Trim();
			int num = text.IndexOf(' ');
			if (num > 0)
			{
				text = text.Substring(0, num);
			}
			if (text.Equals("/disablekillfeed", StringComparison.OrdinalIgnoreCase))
			{
				SetFeedHidden(hidden: true);
				return true;
			}
			if (text.Equals("/enablekillfeed", StringComparison.OrdinalIgnoreCase))
			{
				SetFeedHidden(hidden: false);
				return true;
			}
			return false;
		}

		private static void SetFeedHidden(bool hidden)
		{
			if ((Object)(object)Plugin.Instance == (Object)null || (Object)(object)Plugin.Instance.Hud == (Object)null)
			{
				Tell("Kill feed is not ready.");
				return;
			}
			if (Plugin.Instance.Hud.LocalHidden == hidden)
			{
				Tell(hidden ? "Kill feed is already hidden." : "Kill feed is already shown.");
				return;
			}
			Plugin.Instance.Hud.SetLocalHidden(hidden);
			Tell(hidden ? "Kill feed hidden. Other players still see your kills. /enablekillfeed to show." : "Kill feed shown.");
		}

		private static void Tell(string message)
		{
			if ((Object)(object)Chat.instance != (Object)null)
			{
				((Terminal)Chat.instance).AddString(message);
			}
		}
	}
	public static class GuildColor
	{
		public const string GuildsPluginGuid = "org.bepinex.plugins.guilds";

		public static readonly Color White = Color.white;

		public static readonly int WhiteRgb = PvpKillEvent.Pack(Color.white);

		private static bool _initialized;

		private static bool _available;

		private static MethodInfo _getPlayerGuild;

		private static MethodInfo _getGuilds;

		private static FieldInfo _generalField;

		private static FieldInfo _colorField;

		private static FieldInfo _membersField;

		public static bool IsAvailable
		{
			get
			{
				Init();
				return _available;
			}
		}

		public static void Init()
		{
			if (_initialized)
			{
				return;
			}
			_initialized = true;
			if (!Chainloader.PluginInfos.ContainsKey("org.bepinex.plugins.guilds"))
			{
				Plugin.Log.LogInfo((object)"Guilds is not loaded. Names will render white.");
				return;
			}
			Type type = FindType("Guilds.API");
			Type type2 = FindType("Guilds.Guild");
			Type type3 = FindType("Guilds.GuildGeneral");
			if (type == null || type2 == null || type3 == null)
			{
				Plugin.Log.LogWarning((object)"Guilds is present but its API types could not be resolved.");
				return;
			}
			_getPlayerGuild = type.GetMethod("GetPlayerGuild", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Player) }, null);
			_getGuilds = type.GetMethod("GetGuilds", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null);
			_generalField = type2.GetField("General", BindingFlags.Instance | BindingFlags.Public);
			_membersField = type2.GetField("Members", BindingFlags.Instance | BindingFlags.Public);
			_colorField = type3.GetField("color", BindingFlags.Instance | BindingFlags.Public);
			_available = _getPlayerGuild != null && _generalField != null && _colorField != null;
			Plugin.Log.LogInfo((object)(_available ? "Bound to Guilds.API for live guild RGB colors." : "Failed to bind Guilds.API. Names will render white."));
		}

		public static int RgbFor(Player player)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return ColorToRgb(ColorFor(player));
		}

		public static int RgbForName(string playerName)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return ColorToRgb(ColorForName(playerName));
		}

		public static Color ColorFor(Player player)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Init();
			if (!_available || (Object)(object)player == (Object)null || _getPlayerGuild == null)
			{
				return White;
			}
			try
			{
				return ReadGuildColor(_getPlayerGuild.Invoke(null, new object[1] { player }));
			}
			catch
			{
				return White;
			}
		}

		public static Color ColorForName(string playerName)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			Init();
			if (string.IsNullOrEmpty(playerName))
			{
				return White;
			}
			Player val = FindLivePlayer(playerName);
			if ((Object)(object)val != (Object)null)
			{
				return ColorFor(val);
			}
			return ColorFromGuildScan(playerName);
		}

		public static int ColorToRgb(Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return PvpKillEvent.Pack(color);
		}

		private static Color ColorFromGuildScan(string playerName)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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_007c: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			if (_getGuilds == null)
			{
				return White;
			}
			try
			{
				if (!(_getGuilds.Invoke(null, null) is IEnumerable enumerable))
				{
					return White;
				}
				foreach (object item in enumerable)
				{
					if (GuildContainsPlayer(item, playerName))
					{
						return ReadGuildColor(item);
					}
				}
			}
			catch
			{
			}
			return White;
		}

		private static Color ReadGuildColor(object guild)
		{
			//IL_001d: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			if (guild == null || _generalField == null || _colorField == null)
			{
				return White;
			}
			object value = _generalField.GetValue(guild);
			if (value == null)
			{
				return White;
			}
			return ParseHtml(_colorField.GetValue(value) as string);
		}

		private static bool GuildContainsPlayer(object guild, string playerName)
		{
			if (guild == null || _membersField == null)
			{
				return false;
			}
			if (!(_membersField.GetValue(guild) is IDictionary dictionary))
			{
				return false;
			}
			foreach (object key in dictionary.Keys)
			{
				if (key != null)
				{
					FieldInfo field = key.GetType().GetField("name", BindingFlags.Instance | BindingFlags.Public);
					if (string.Equals((field != null) ? (field.GetValue(key) as string) : null, playerName, StringComparison.OrdinalIgnoreCase))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static Player FindLivePlayer(string playerName)
		{
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if ((Object)(object)allPlayer != (Object)null && string.Equals(NameResolver.OfPlayer(allPlayer), playerName, StringComparison.OrdinalIgnoreCase))
				{
					return allPlayer;
				}
			}
			return null;
		}

		private static Type FindType(string fullName)
		{
			Type type = Type.GetType(fullName + ", Guilds");
			if (type != null)
			{
				return type;
			}
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				if (assembly.GetName().Name == "Guilds")
				{
					return assembly.GetType(fullName);
				}
			}
			return null;
		}

		private static Color ParseHtml(string html)
		{
			//IL_0008: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(html))
			{
				return White;
			}
			string text = html.Trim();
			if (text[0] != '#')
			{
				text = "#" + text;
			}
			Color result = default(Color);
			if (!ColorUtility.TryParseHtmlString(text, ref result))
			{
				return White;
			}
			result.a = 1f;
			return result;
		}
	}
	public enum HudAnchor
	{
		TopLeft,
		TopCenter,
		TopRight,
		BottomLeft,
		BottomCenter,
		BottomRight
	}
	public static class KillFeedAssets
	{
		private const string SwordResource = "kill_icon_sword.png";

		private static Sprite _sword;

		public static Sprite Sword => _sword;

		public static void Load()
		{
			_sword = ToSprite(LoadTexture("kill_icon_sword.png"));
			if ((Object)(object)_sword == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Failed to load crossed-swords kill icon.");
			}
		}

		private static Texture2D LoadTexture(string fileName)
		{
			try
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				string text = executingAssembly.GetManifestResourceNames().FirstOrDefault((string n) => n.EndsWith(fileName, StringComparison.OrdinalIgnoreCase));
				if (text == null)
				{
					return null;
				}
				using Stream stream = executingAssembly.GetManifestResourceStream(text);
				if (stream == null)
				{
					return null;
				}
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				Texture2D val = AssetUtils.LoadImage(memoryStream.ToArray());
				if ((Object)(object)val != (Object)null)
				{
					((Object)val).name = fileName;
					((Texture)val).filterMode = (FilterMode)1;
					((Texture)val).wrapMode = (TextureWrapMode)1;
				}
				return val;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Kill icon load failed: " + ex.Message));
				return null;
			}
		}

		private static Sprite ToSprite(Texture2D texture)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)texture == (Object)null)
			{
				return null;
			}
			return Sprite.Create(texture, new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), new Vector2(0.5f, 0.5f), 100f);
		}
	}
	public class KillFeedConfig
	{
		public ConfigEntry<HudAnchor> Position;

		public ConfigEntry<int> OffsetX;

		public ConfigEntry<int> OffsetY;

		public ConfigEntry<bool> NewestOnTop;

		public ConfigEntry<float> EntryDurationSeconds;

		public ConfigEntry<float> FadeOutSeconds;

		public ConfigEntry<int> MaxEntries;

		public ConfigEntry<int> FontSize;

		public ConfigEntry<int> IconSize;

		public ConfigEntry<int> EntrySpacing;

		public ConfigEntry<float> BackgroundAlpha;

		public ConfigEntry<int> BackgroundPadX;

		public ConfigEntry<int> BackgroundPadY;

		public KillFeedConfig(ConfigFile cfg)
		{
			Position = ConfigFileExtensions.BindConfig<HudAnchor>(cfg, "HUD", "Position", HudAnchor.TopCenter, "HUD anchor.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			OffsetX = ConfigFileExtensions.BindConfig<int>(cfg, "HUD", "OffsetX", 0, "Horizontal inset (px).", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			OffsetY = ConfigFileExtensions.BindConfig<int>(cfg, "HUD", "OffsetY", 36, "Vertical inset (px).", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			NewestOnTop = ConfigFileExtensions.BindConfig<bool>(cfg, "HUD", "NewestOnTop", true, "New kills appear at the top.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			EntryDurationSeconds = ConfigFileExtensions.BindConfig<float>(cfg, "HUD", "EntryDurationSeconds", 7f, "Seconds fully visible.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			FadeOutSeconds = ConfigFileExtensions.BindConfig<float>(cfg, "HUD", "FadeOutSeconds", 2f, "Fade-out seconds.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			MaxEntries = ConfigFileExtensions.BindConfig<int>(cfg, "HUD", "MaxEntries", 3, "Max lines on screen.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			FontSize = ConfigFileExtensions.BindConfig<int>(cfg, "HUD", "FontSize", 15, "Name font size.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			IconSize = ConfigFileExtensions.BindConfig<int>(cfg, "HUD", "IconSize", 20, "Sword icon size (px).", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			EntrySpacing = ConfigFileExtensions.BindConfig<int>(cfg, "HUD", "EntrySpacing", 4, "Gap between lines (px).", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			BackgroundAlpha = ConfigFileExtensions.BindConfig<float>(cfg, "HUD", "BackgroundAlpha", 0.55f, "Bar opacity 0-1.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			BackgroundPadX = ConfigFileExtensions.BindConfig<int>(cfg, "HUD", "BackgroundPadX", 5, "Bar padding X (px).", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			BackgroundPadY = ConfigFileExtensions.BindConfig<int>(cfg, "HUD", "BackgroundPadY", 1, "Bar padding Y (px).", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
		}
	}
	public class KillFeedHud : MonoBehaviour
	{
		private class EntryView
		{
			public GameObject Root;

			public RectTransform Motion;

			public CanvasGroup Group;
		}

		private class PendingKill
		{
			public string Killer;

			public string Victim;

			public Color KillerColor;

			public Color VictimColor;
		}

		private const float SlideInSeconds = 0.2f;

		private KillFeedConfig _cfg;

		private RectTransform _root;

		private VerticalLayoutGroup _stack;

		private Sprite _barSprite;

		private readonly List<EntryView> _entries = new List<EntryView>();

		private readonly Queue<PendingKill> _queued = new Queue<PendingKill>();

		private bool _guiBound;

		public bool LocalHidden { get; private set; }

		public void Configure(KillFeedConfig cfg)
		{
			_cfg = cfg;
		}

		public void BindGui()
		{
			if (!_guiBound)
			{
				_guiBound = true;
				GUIManager.OnCustomGUIAvailable += RebuildRoot;
				if ((Object)(object)GUIManager.CustomGUIFront != (Object)null)
				{
					RebuildRoot();
				}
			}
		}

		public void UnbindGui()
		{
			if (_guiBound)
			{
				_guiBound = false;
				GUIManager.OnCustomGUIAvailable -= RebuildRoot;
			}
		}

		public void SetLocalHidden(bool hidden)
		{
			LocalHidden = hidden;
			ApplyVisibility();
		}

		public void ResetSession()
		{
			LocalHidden = false;
			ApplyVisibility();
		}

		public void RefreshLayout()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			ApplyAnchor();
			ApplySpacing();
			if ((Object)(object)_stack != (Object)null)
			{
				((LayoutGroup)_stack).childAlignment = ChildAlignmentForAnchor();
			}
		}

		public void Push(PvpKillEvent ev)
		{
			//IL_0048: 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)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if (LocalHidden)
			{
				return;
			}
			string text = NameResolver.Sanitize(ev.Killer);
			string text2 = NameResolver.Sanitize(ev.Victim);
			if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(text2))
			{
				PendingKill pendingKill = new PendingKill
				{
					Killer = text,
					Victim = text2,
					KillerColor = ev.KillerColor,
					VictimColor = ev.VictimColor
				};
				if ((Object)(object)_stack == (Object)null)
				{
					_queued.Enqueue(pendingKill);
				}
				else
				{
					Spawn(pendingKill);
				}
			}
		}

		private void RebuildRoot()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_00a9: 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_00f7: Expected O, but got Unknown
			try
			{
				_entries.Clear();
				_root = null;
				_stack = null;
				GameObject customGUIFront = GUIManager.CustomGUIFront;
				if (!((Object)(object)customGUIFront == (Object)null))
				{
					EnsureBarSprite();
					GameObject val = new GameObject("PvPKillFeed_Root", new Type[3]
					{
						typeof(RectTransform),
						typeof(VerticalLayoutGroup),
						typeof(ContentSizeFitter)
					});
					val.layer = 5;
					val.transform.SetParent(customGUIFront.transform, false);
					_root = val.GetComponent<RectTransform>();
					ApplyAnchor();
					_stack = val.GetComponent<VerticalLayoutGroup>();
					((LayoutGroup)_stack).childAlignment = ChildAlignmentForAnchor();
					((HorizontalOrVerticalLayoutGroup)_stack).childControlWidth = true;
					((HorizontalOrVerticalLayoutGroup)_stack).childControlHeight = true;
					((HorizontalOrVerticalLayoutGroup)_stack).childForceExpandWidth = true;
					((HorizontalOrVerticalLayoutGroup)_stack).childForceExpandHeight = false;
					((LayoutGroup)_stack).padding = new RectOffset(0, 0, 0, 0);
					ApplySpacing();
					ContentSizeFitter component = val.GetComponent<ContentSizeFitter>();
					component.horizontalFit = (FitMode)2;
					component.verticalFit = (FitMode)2;
					ApplyVisibility();
					while (_queued.Count > 0)
					{
						Spawn(_queued.Dequeue());
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Kill feed GUI rebuild failed: " + ex.Message));
			}
		}

		private void ApplyAnchor()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_0114: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_root == (Object)null) && _cfg != null)
			{
				HudAnchor value = _cfg.Position.Value;
				bool flag = IsCenter(value);
				bool flag2 = IsRight(value);
				bool flag3 = IsBottom(value);
				float num = (flag ? 0.5f : (flag2 ? 1f : 0f));
				float num2 = (flag3 ? 0f : 1f);
				_root.anchorMin = new Vector2(num, num2);
				_root.anchorMax = new Vector2(num, num2);
				_root.pivot = new Vector2(num, num2);
				float num3 = _cfg.OffsetX.Value;
				float num4 = Math.Max(0, _cfg.OffsetY.Value);
				float num5 = (flag ? num3 : (flag2 ? (0f - Math.Max(0f, num3)) : Math.Max(0f, num3)));
				_root.anchoredPosition = new Vector2(num5, flag3 ? num4 : (0f - num4));
				_root.sizeDelta = Vector2.zero;
			}
		}

		private void ApplySpacing()
		{
			if (!((Object)(object)_stack == (Object)null) && _cfg != null)
			{
				((HorizontalOrVerticalLayoutGroup)_stack).spacing = Mathf.Max(0, _cfg.EntrySpacing.Value);
			}
		}

		private TextAnchor ChildAlignmentForAnchor()
		{
			if (_cfg == null)
			{
				return (TextAnchor)1;
			}
			return (TextAnchor)(_cfg.Position.Value switch
			{
				HudAnchor.TopLeft => 0, 
				HudAnchor.TopCenter => 1, 
				HudAnchor.BottomLeft => 6, 
				HudAnchor.BottomCenter => 7, 
				HudAnchor.BottomRight => 8, 
				_ => 2, 
			});
		}

		private static bool IsCenter(HudAnchor anchor)
		{
			if (anchor != HudAnchor.TopCenter)
			{
				return anchor == HudAnchor.BottomCenter;
			}
			return true;
		}

		private static bool IsRight(HudAnchor anchor)
		{
			if (anchor != HudAnchor.TopRight)
			{
				return anchor == HudAnchor.BottomRight;
			}
			return true;
		}

		private static bool IsBottom(HudAnchor anchor)
		{
			if (anchor != HudAnchor.BottomLeft && anchor != HudAnchor.BottomCenter)
			{
				return anchor == HudAnchor.BottomRight;
			}
			return true;
		}

		private Vector2 InnerPivot()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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)
			if (_cfg == null || IsCenter(_cfg.Position.Value))
			{
				return new Vector2(0.5f, 0.5f);
			}
			if (!IsRight(_cfg.Position.Value))
			{
				return new Vector2(0f, 0.5f);
			}
			return new Vector2(1f, 0.5f);
		}

		private Vector2 SlideOffset()
		{
			//IL_0063: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			HudAnchor value = _cfg.Position.Value;
			if (IsCenter(value))
			{
				if (!IsBottom(value))
				{
					return new Vector2(0f, 18f);
				}
				return new Vector2(0f, -18f);
			}
			if (!IsRight(value))
			{
				return new Vector2(-24f, 0f);
			}
			return new Vector2(24f, 0f);
		}

		private void Spawn(PendingKill pending)
		{
			if ((Object)(object)_stack == (Object)null || _cfg == null || LocalHidden)
			{
				return;
			}
			ApplyAnchor();
			ApplySpacing();
			TrimToMax();
			EntryView entryView = BuildRow(pending);
			if (entryView != null && !((Object)(object)entryView.Root == (Object)null))
			{
				if (_cfg.NewestOnTop.Value)
				{
					entryView.Root.transform.SetAsFirstSibling();
				}
				_entries.Add(entryView);
				LayoutRebuilder.ForceRebuildLayoutImmediate(_root);
				((MonoBehaviour)this).StartCoroutine(SafeRunEntry(entryView));
			}
		}

		private void TrimToMax()
		{
			int num = Math.Max(1, _cfg.MaxEntries.Value);
			while (_entries.Count >= num)
			{
				EntryView entryView = _entries[0];
				_entries.RemoveAt(0);
				if (entryView != null && (Object)(object)entryView.Root != (Object)null)
				{
					Object.Destroy((Object)(object)entryView.Root);
				}
			}
			_entries.RemoveAll((EntryView e) => e == null || (Object)(object)e.Root == (Object)null);
		}

		private EntryView BuildRow(PendingKill pending)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Expected O, but got Unknown
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			int num = Math.Max(8, _cfg.IconSize.Value);
			int num2 = Mathf.Clamp(_cfg.BackgroundPadX.Value, 0, 32);
			int num3 = Mathf.Clamp(_cfg.BackgroundPadY.Value, 0, 32);
			GameObject val = new GameObject("KillLine", new Type[2]
			{
				typeof(RectTransform),
				typeof(LayoutElement)
			});
			val.layer = 5;
			val.transform.SetParent(((Component)_stack).transform, false);
			LayoutElement component = val.GetComponent<LayoutElement>();
			component.flexibleWidth = 1f;
			GameObject val2 = new GameObject("Content", new Type[5]
			{
				typeof(RectTransform),
				typeof(CanvasGroup),
				typeof(HorizontalLayoutGroup),
				typeof(ContentSizeFitter),
				typeof(Image)
			});
			val2.layer = 5;
			val2.transform.SetParent(val.transform, false);
			RectTransform component2 = val2.GetComponent<RectTransform>();
			Vector2 pivot = (component2.anchorMax = (component2.anchorMin = InnerPivot()));
			component2.pivot = pivot;
			component2.anchoredPosition = Vector2.zero;
			HorizontalLayoutGroup component3 = val2.GetComponent<HorizontalLayoutGroup>();
			((LayoutGroup)component3).childAlignment = (TextAnchor)4;
			((HorizontalOrVerticalLayoutGroup)component3).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)component3).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)component3).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)component3).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)component3).spacing = 8f;
			((LayoutGroup)component3).padding = new RectOffset(num2, num2, num3, num3);
			ContentSizeFitter component4 = val2.GetComponent<ContentSizeFitter>();
			component4.horizontalFit = (FitMode)2;
			component4.verticalFit = (FitMode)2;
			Image component5 = val2.GetComponent<Image>();
			component5.sprite = _barSprite;
			component5.type = (Type)0;
			((Graphic)component5).color = new Color(0f, 0f, 0f, Mathf.Clamp01(_cfg.BackgroundAlpha.Value));
			((Graphic)component5).raycastTarget = false;
			TextMeshProUGUI killer = CreateName(val2.transform, pending.Killer, pending.KillerColor);
			CreateIcon(val2.transform, num);
			TextMeshProUGUI victim = CreateName(val2.transform, pending.Victim, pending.VictimColor);
			float num4 = (component.preferredHeight = (component.minHeight = MeasureRowHeight(killer, victim, num, num3)));
			component.flexibleHeight = 0f;
			LayoutRebuilder.ForceRebuildLayoutImmediate(component2);
			Rect rect = component2.rect;
			float height = ((Rect)(ref rect)).height;
			if (height > num4)
			{
				component.minHeight = height;
				component.preferredHeight = height;
			}
			CanvasGroup component6 = val2.GetComponent<CanvasGroup>();
			component6.alpha = 0f;
			component6.blocksRaycasts = false;
			component6.interactable = false;
			return new EntryView
			{
				Root = val,
				Motion = component2,
				Group = component6
			};
		}

		private TextMeshProUGUI CreateName(Transform parent, string name, Color color)
		{
			//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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_0103: 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)
			GameObject val = new GameObject("Name", new Type[4]
			{
				typeof(RectTransform),
				typeof(TextMeshProUGUI),
				typeof(ContentSizeFitter),
				typeof(Outline)
			})
			{
				layer = 5
			};
			val.transform.SetParent(parent, false);
			TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
			((Graphic)component).raycastTarget = false;
			((TMP_Text)component).text = name;
			((Graphic)component).color = color;
			((TMP_Text)component).fontSize = Math.Max(8, _cfg.FontSize.Value);
			((TMP_Text)component).fontStyle = (FontStyles)1;
			((TMP_Text)component).characterSpacing = -1.2f;
			((TMP_Text)component).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)component).overflowMode = (TextOverflowModes)0;
			((TMP_Text)component).alignment = (TextAlignmentOptions)4097;
			((TMP_Text)component).enableAutoSizing = false;
			TMP_FontAsset val2 = ((GUIManager.Instance != null) ? GUIManager.Instance.TMP_AveriaSansLibre : null);
			if ((Object)(object)val2 != (Object)null)
			{
				((TMP_Text)component).font = val2;
			}
			Outline component2 = val.GetComponent<Outline>();
			((Shadow)component2).effectColor = new Color(0f, 0f, 0f, 0.92f);
			((Shadow)component2).effectDistance = new Vector2(1f, -1f);
			((Shadow)component2).useGraphicAlpha = true;
			ContentSizeFitter component3 = val.GetComponent<ContentSizeFitter>();
			component3.horizontalFit = (FitMode)2;
			component3.verticalFit = (FitMode)2;
			return component;
		}

		private static float MeasureRowHeight(TextMeshProUGUI killer, TextMeshProUGUI victim, int iconSize, int padY)
		{
			float num = Mathf.Max(MeasureNameHeight(killer), MeasureNameHeight(victim));
			return Mathf.Max((float)iconSize, num) + (float)padY * 2f;
		}

		private static float MeasureNameHeight(TextMeshProUGUI tmp)
		{
			if ((Object)(object)tmp == (Object)null)
			{
				return 0f;
			}
			((TMP_Text)tmp).ForceMeshUpdate(true, false);
			return Mathf.Max(((TMP_Text)tmp).preferredHeight, ((TMP_Text)tmp).fontSize);
		}

		private Image CreateIcon(Transform parent, int size)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("KillIcon", new Type[3]
			{
				typeof(RectTransform),
				typeof(LayoutElement),
				typeof(Image)
			})
			{
				layer = 5
			};
			val.transform.SetParent(parent, false);
			LayoutElement component = val.GetComponent<LayoutElement>();
			component.preferredWidth = size;
			component.preferredHeight = size;
			component.minWidth = size;
			component.minHeight = size;
			val.GetComponent<RectTransform>().sizeDelta = new Vector2((float)size, (float)size);
			Image component2 = val.GetComponent<Image>();
			((Graphic)component2).raycastTarget = false;
			component2.preserveAspect = true;
			((Graphic)component2).color = Color.white;
			component2.sprite = KillFeedAssets.Sword;
			return component2;
		}

		private void EnsureBarSprite()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_001c: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_barSprite != (Object)null))
			{
				Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false);
				val.SetPixel(0, 0, Color.white);
				((Texture)val).wrapMode = (TextureWrapMode)1;
				((Texture)val).filterMode = (FilterMode)0;
				val.Apply();
				_barSprite = Sprite.Create(val, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f), 1f);
			}
		}

		private IEnumerator SafeRunEntry(EntryView view)
		{
			IEnumerator routine;
			try
			{
				routine = AnimateEntry(view);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Kill feed animation failed to start: " + ex.Message));
				yield break;
			}
			while (true)
			{
				bool flag;
				try
				{
					flag = routine.MoveNext();
				}
				catch (Exception ex2)
				{
					Plugin.Log.LogWarning((object)("Kill feed animation error: " + ex2.Message));
					break;
				}
				if (flag)
				{
					yield return routine.Current;
					continue;
				}
				break;
			}
		}

		private IEnumerator AnimateEntry(EntryView view)
		{
			if (view == null || (Object)(object)view.Motion == (Object)null || (Object)(object)view.Group == (Object)null)
			{
				yield break;
			}
			Vector2 slide = SlideOffset();
			view.Motion.anchoredPosition = slide;
			float t = 0f;
			while (t < 0.2f)
			{
				if ((Object)(object)view.Root == (Object)null || (Object)(object)view.Motion == (Object)null)
				{
					yield break;
				}
				t += Time.unscaledDeltaTime;
				float num = Mathf.Clamp01(t / 0.2f);
				float num2 = 1f - (1f - num) * (1f - num);
				view.Group.alpha = num2;
				view.Motion.anchoredPosition = Vector2.Lerp(slide, Vector2.zero, num2);
				yield return null;
			}
			if ((Object)(object)view.Root == (Object)null || (Object)(object)view.Motion == (Object)null)
			{
				yield break;
			}
			view.Group.alpha = 1f;
			view.Motion.anchoredPosition = Vector2.zero;
			float num3 = Math.Max(0.1f, _cfg.EntryDurationSeconds.Value);
			yield return (object)new WaitForSecondsRealtime(num3);
			float fade = Math.Max(0.05f, _cfg.FadeOutSeconds.Value);
			t = 0f;
			while (t < fade)
			{
				if ((Object)(object)view.Root == (Object)null || (Object)(object)view.Group == (Object)null)
				{
					yield break;
				}
				t += Time.unscaledDeltaTime;
				view.Group.alpha = 1f - Mathf.Clamp01(t / fade);
				yield return null;
			}
			_entries.Remove(view);
			if ((Object)(object)view.Root != (Object)null)
			{
				Object.Destroy((Object)(object)view.Root);
			}
		}

		private void ApplyVisibility()
		{
			if (!((Object)(object)_root == (Object)null))
			{
				bool flag = (Object)(object)Player.m_localPlayer != (Object)null && ((Object)(object)Hud.instance == (Object)null || Hud.instance.IsVisible());
				bool flag2 = !LocalHidden && flag;
				if (((Component)_root).gameObject.activeSelf != flag2)
				{
					((Component)_root).gameObject.SetActive(flag2);
				}
			}
		}

		private void Update()
		{
			try
			{
				ApplyVisibility();
			}
			catch
			{
			}
		}
	}
	public static class NameResolver
	{
		public static string OfPlayer(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return "";
			}
			string playerName = player.GetPlayerName();
			if (!string.IsNullOrEmpty(playerName) && playerName != "...")
			{
				return Sanitize(playerName);
			}
			string hoverName = ((Character)player).GetHoverName();
			if (!string.IsNullOrEmpty(hoverName) && hoverName != "...")
			{
				return Sanitize(hoverName);
			}
			return "";
		}

		public static string Sanitize(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return "";
			}
			return name.Replace("<", "").Replace(">", "").Trim();
		}
	}
	public static class Network
	{
		[HarmonyPatch(typeof(Game), "Start")]
		private static class GameStartPatch
		{
			private static void Postfix()
			{
				if ((Object)(object)Plugin.Instance != (Object)null && (Object)(object)Plugin.Instance.Hud != (Object)null)
				{
					Plugin.Instance.Hud.ResetSession();
				}
				ResetSession();
				TryRegister();
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnDestroy")]
		private static class ZNetDestroyPatch
		{
			private static void Prefix()
			{
				_registeredRpc = null;
				ResetSession();
			}
		}

		public const string RpcName = "PKF";

		private const float DedupSeconds = 2.5f;

		private const int MaxCache = 8;

		private static ZRoutedRpc _registeredRpc;

		private static readonly Dictionary<long, float> _recentVictims = new Dictionary<long, float>(8);

		private static readonly List<long> _stale = new List<long>(8);

		public static void Broadcast(PvpKillEvent ev)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			if (ZRoutedRpc.instance != null)
			{
				ZPackage val = new ZPackage();
				ev.Write(val);
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "PKF", new object[1] { val });
			}
		}

		public static void OnRpc(long sender, ZPackage pkg)
		{
			if (pkg != null && !((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)Plugin.Instance == (Object)null))
			{
				PvpKillEvent ev;
				try
				{
					ev = PvpKillEvent.Read(pkg);
				}
				catch
				{
					return;
				}
				if (!IsDuplicate(ev.VictimId))
				{
					Plugin.Instance.OnPvpKillReceived(ev);
				}
			}
		}

		public static void ResetSession()
		{
			_recentVictims.Clear();
			_stale.Clear();
			PlayerDeathPatch.ResetDebounce();
			CharacterDamagePatch.ClearCredit();
		}

		private static bool IsDuplicate(long victimId)
		{
			float unscaledTime = Time.unscaledTime;
			Prune(unscaledTime);
			if (_recentVictims.TryGetValue(victimId, out var value) && unscaledTime - value < 2.5f)
			{
				return true;
			}
			_recentVictims[victimId] = unscaledTime;
			return false;
		}

		private static void Prune(float now)
		{
			if (_recentVictims.Count == 0)
			{
				return;
			}
			_stale.Clear();
			foreach (KeyValuePair<long, float> recentVictim in _recentVictims)
			{
				if (now - recentVictim.Value >= 2.5f)
				{
					_stale.Add(recentVictim.Key);
				}
			}
			for (int i = 0; i < _stale.Count; i++)
			{
				_recentVictims.Remove(_stale[i]);
			}
			_stale.Clear();
			if (_recentVictims.Count > 8)
			{
				_recentVictims.Clear();
			}
		}

		private static void TryRegister()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null && _registeredRpc != instance)
			{
				instance.Register<ZPackage>("PKF", (Action<long, ZPackage>)OnRpc);
				_registeredRpc = instance;
			}
		}
	}
	[BepInPlugin("com.rdmods.pvpkillfeed", "PvP Kill Feed", "1.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.rdmods.pvpkillfeed";

		public const string PluginName = "PvP Kill Feed";

		public const string PluginVersion = "1.1.0";

		private Harmony _harmony;

		private ConfigFileWatcher _configWatcher;

		public static Plugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		public KillFeedConfig FeedConfig { get; private set; }

		public KillFeedHud Hud { get; private set; }

		private void Awake()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			FeedConfig = new KillFeedConfig(((BaseUnityPlugin)this).Config);
			KillFeedAssets.Load();
			GuildColor.Init();
			Hud = ((Component)this).gameObject.AddComponent<KillFeedHud>();
			Hud.Configure(FeedConfig);
			Hud.BindGui();
			ChatCommands.Register();
			_configWatcher = new ConfigFileWatcher(((BaseUnityPlugin)this).Config, 1000L);
			_configWatcher.OnConfigFileReloaded += OnConfigReloaded;
			SynchronizationManager.OnConfigurationSynchronized += OnConfigSynced;
			_harmony = new Harmony("com.rdmods.pvpkillfeed");
			_harmony.PatchAll();
			Log.LogInfo((object)"PvP Kill Feed v1.1.0 loaded.");
		}

		private void OnDestroy()
		{
			SynchronizationManager.OnConfigurationSynchronized -= OnConfigSynced;
			if (_configWatcher != null)
			{
				_configWatcher.OnConfigFileReloaded -= OnConfigReloaded;
			}
			if ((Object)(object)Hud != (Object)null)
			{
				Hud.UnbindGui();
			}
			Network.ResetSession();
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}

		public void OnPvpKillReceived(PvpKillEvent ev)
		{
			if (!((Object)(object)Hud == (Object)null) && !Hud.LocalHidden)
			{
				Hud.Push(ev);
			}
		}

		private void OnConfigReloaded()
		{
			RefreshHud();
		}

		private static void OnConfigSynced(object sender, ConfigurationSynchronizationEventArgs args)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				Instance.RefreshHud();
			}
		}

		private void RefreshHud()
		{
			if ((Object)(object)Hud != (Object)null)
			{
				Hud.RefreshLayout();
			}
		}
	}
	public struct PvpKillEvent
	{
		public const int MaxNameChars = 32;

		public string Killer;

		public string Victim;

		public long VictimId;

		public int KillerRgb;

		public int VictimRgb;

		public Color KillerColor => Unpack(KillerRgb);

		public Color VictimColor => Unpack(VictimRgb);

		public void Write(ZPackage pkg)
		{
			WriteName(pkg, Killer);
			WriteName(pkg, Victim);
			pkg.Write(VictimId);
			pkg.Write(KillerRgb);
			pkg.Write(VictimRgb);
		}

		public static PvpKillEvent Read(ZPackage pkg)
		{
			return new PvpKillEvent
			{
				Killer = pkg.ReadString(),
				Victim = pkg.ReadString(),
				VictimId = pkg.ReadLong(),
				KillerRgb = pkg.ReadInt(),
				VictimRgb = pkg.ReadInt()
			};
		}

		public static int Pack(Color c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			int num = Mathf.Clamp(Mathf.RoundToInt(c.r * 255f), 0, 255);
			int num2 = Mathf.Clamp(Mathf.RoundToInt(c.g * 255f), 0, 255);
			int num3 = Mathf.Clamp(Mathf.RoundToInt(c.b * 255f), 0, 255);
			return (num << 16) | (num2 << 8) | num3;
		}

		public static Color Unpack(int rgb)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			return new Color((float)((rgb >> 16) & 0xFF) / 255f, (float)((rgb >> 8) & 0xFF) / 255f, (float)(rgb & 0xFF) / 255f, 1f);
		}

		private static void WriteName(ZPackage pkg, string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				pkg.Write("");
			}
			else
			{
				pkg.Write((name.Length > 32) ? name.Substring(0, 32) : name);
			}
		}
	}
}
namespace RdMods.PvpKillFeed.Patches
{
	[HarmonyPatch(typeof(Character), "Damage")]
	public static class CharacterDamagePatch
	{
		internal static bool HasConfirmedKiller;

		internal static string ConfirmedKillerName;

		internal static int ConfirmedKillerRgb;

		private static void Prefix(Character __instance, HitData hit, out bool __state)
		{
			__state = false;
			if (!((Object)(object)__instance == (Object)null) && hit != null && __instance.IsPlayer() && !((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !HasConfirmedKiller && !(__instance.GetHealth() <= 0f))
			{
				Character attacker = hit.GetAttacker();
				Player val = (Player)(object)((attacker is Player) ? attacker : null);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)__instance))
				{
					__state = true;
				}
			}
		}

		private static void Postfix(Character __instance, HitData hit, bool __state)
		{
			if (!__state || HasConfirmedKiller || (Object)(object)__instance == (Object)null || hit == null || __instance.GetHealth() > 0f)
			{
				return;
			}
			Character attacker = hit.GetAttacker();
			Player val = (Player)(object)((attacker is Player) ? attacker : null);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)__instance))
			{
				string text = NameResolver.OfPlayer(val);
				if (!string.IsNullOrEmpty(text))
				{
					HasConfirmedKiller = true;
					ConfirmedKillerName = text;
					ConfirmedKillerRgb = GuildColor.RgbFor(val);
				}
			}
		}

		internal static void ClearCredit()
		{
			HasConfirmedKiller = false;
			ConfirmedKillerName = null;
			ConfirmedKillerRgb = GuildColor.WhiteRgb;
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	public static class PlayerSpawnedCreditReset
	{
		private static void Postfix(Player __instance)
		{
			if ((Object)(object)__instance != (Object)null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				CharacterDamagePatch.ClearCredit();
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnDeath")]
	public static class PlayerDeathPatch
	{
		private const float BroadcastCooldown = 2f;

		private static float _lastBroadcastTime = -999f;

		private static void Prefix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			if (!CharacterDamagePatch.HasConfirmedKiller || string.IsNullOrEmpty(CharacterDamagePatch.ConfirmedKillerName))
			{
				CharacterDamagePatch.ClearCredit();
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime - _lastBroadcastTime < 2f)
			{
				CharacterDamagePatch.ClearCredit();
				return;
			}
			string text = NameResolver.OfPlayer(__instance);
			if (string.IsNullOrEmpty(text))
			{
				CharacterDamagePatch.ClearCredit();
				return;
			}
			_lastBroadcastTime = unscaledTime;
			Network.Broadcast(new PvpKillEvent
			{
				Killer = CharacterDamagePatch.ConfirmedKillerName,
				Victim = text,
				VictimId = __instance.GetPlayerID(),
				KillerRgb = CharacterDamagePatch.ConfirmedKillerRgb,
				VictimRgb = GuildColor.RgbFor(__instance)
			});
			CharacterDamagePatch.ClearCredit();
		}

		internal static void ResetDebounce()
		{
			_lastBroadcastTime = -999f;
		}
	}
}