Decompiled source of RustyHeathensMessenger v1.0.0

plugins/RustyHeathensMessenger/RustyHeathensMessenger.dll

Decompiled a week ago
using 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.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Steamworks;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("RustyLaserGaming")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Fantasy rune Viking character customization for Valheim.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RustyHeathensMessenger")]
[assembly: AssemblyTitle("RustyHeathensMessenger")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace RustyHeathensMessenger;

[HarmonyPatch(typeof(Character), "OnDeath")]
public static class RustyHeathensMessengerBossKillMessagesPatch
{
	private const string RpcReportBossKillName = "RustyHeathensMessenger_ReportBossKill";

	private static readonly HashSet<int> _announcedBosses = new HashSet<int>();

	private static ZRoutedRpc _registeredRpcInstance;

	private static string _lastBossKey = string.Empty;

	private static float _lastBossMessageTime;

	public static void EnsureRegistered()
	{
		if (ZRoutedRpc.instance != null && _registeredRpcInstance != ZRoutedRpc.instance)
		{
			_registeredRpcInstance = ZRoutedRpc.instance;
			ZRoutedRpc.instance.Register<string>("RustyHeathensMessenger_ReportBossKill", (Action<long, string>)RPC_ReportBossKill);
		}
	}

	private static void Postfix(Character __instance)
	{
		if ((Object)(object)__instance == (Object)null || !__instance.IsBoss())
		{
			return;
		}
		EnsureRegistered();
		string bossDisplayName = GetBossDisplayName(((Object)(object)((Component)__instance).gameObject != (Object)null) ? ((Object)((Component)__instance).gameObject).name : null);
		if (string.IsNullOrEmpty(bossDisplayName))
		{
			return;
		}
		int num = (((Object)(object)((Component)__instance).gameObject != (Object)null) ? ((Object)((Component)__instance).gameObject).GetInstanceID() : 0);
		if (num != 0)
		{
			if (_announcedBosses.Contains(num))
			{
				return;
			}
			_announcedBosses.Add(num);
		}
		if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer())
		{
			AnnounceBossKillFromServer(bossDisplayName);
		}
		else if (ZRoutedRpc.instance != null)
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(GetServerPeerId(), "RustyHeathensMessenger_ReportBossKill", new object[1] { bossDisplayName });
		}
	}

	private static void RPC_ReportBossKill(long sender, string bossDisplayName)
	{
		if (!((Object)(object)ZNet.instance != (Object)null) || ZNet.instance.IsServer())
		{
			AnnounceBossKillFromServer(bossDisplayName);
		}
	}

	private static void AnnounceBossKillFromServer(string bossDisplayName)
	{
		if (!string.IsNullOrWhiteSpace(bossDisplayName) && RustyHeathensMessengerServerConfigSync.BossKillMessagesEnabled())
		{
			string text = bossDisplayName.ToLowerInvariant();
			if (!(_lastBossKey == text) || !(Time.time - _lastBossMessageTime < 8f))
			{
				_lastBossKey = text;
				_lastBossMessageTime = Time.time;
				RustyHeathensMessengerMessageBroadcast.BroadcastCenter("The Rusty Heathens defeated " + bossDisplayName + "!\nValhalla heard the victory roar.");
			}
		}
	}

	private static string GetBossDisplayName(string prefabName)
	{
		if (string.IsNullOrEmpty(prefabName))
		{
			return string.Empty;
		}
		if (prefabName.EndsWith("(Clone)", StringComparison.Ordinal))
		{
			prefabName = prefabName.Substring(0, prefabName.Length - "(Clone)".Length);
		}
		return prefabName switch
		{
			"Eikthyr" => "Eikthyr", 
			"gd_king" => "The Elder", 
			"Bonemass" => "Bonemass", 
			"Dragon" => "Moder", 
			"GoblinKing" => "Yagluth", 
			"SeekerQueen" => "The Queen", 
			"Fader" => "Fader", 
			_ => string.Empty, 
		};
	}

	private static long GetServerPeerId()
	{
		try
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return 0L;
			}
			MethodInfo method = typeof(ZNet).GetMethod("GetServerPeer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return 0L;
			}
			object obj = method.Invoke(ZNet.instance, null);
			if (obj == null)
			{
				return 0L;
			}
			FieldInfo field = obj.GetType().GetField("m_uid", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				return 0L;
			}
			if (field.GetValue(obj) is long result)
			{
				return result;
			}
		}
		catch
		{
		}
		return 0L;
	}
}
[HarmonyPatch(typeof(Chat), "SendText")]
public static class RustyHeathensMessengerChatCommands
{
	private static int _funnyPickCounter = -1;

	private const string RpcProtectedCommandRequestName = "RustyHeathensMessenger_ProtectedCommandRequest";

	private static ZRoutedRpc _registeredRpcInstance;

	public static void EnsureRegistered()
	{
		if (ZRoutedRpc.instance != null && _registeredRpcInstance != ZRoutedRpc.instance)
		{
			_registeredRpcInstance = ZRoutedRpc.instance;
			ZRoutedRpc.instance.Register<string, string>("RustyHeathensMessenger_ProtectedCommandRequest", (Action<long, string, string>)RPC_ProtectedCommandRequest);
		}
	}

	private static void RequestProtectedCommandFromServer(string command)
	{
		EnsureRegistered();
		string localSteamIdForCommandRequest = GetLocalSteamIdForCommandRequest();
		if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
		{
			if (!ServerSteamIdIsAllowed(localSteamIdForCommandRequest))
			{
				RustyHeathensMessengerMessageBroadcast.BroadcastCenter("COMMAND LOCKED\n\nOnly approved server admins can use this command.");
			}
			else if (IsRhmdiagCommand(command))
			{
				RustyHeathensMessengerMessageBroadcast.BroadcastCenter(BuildServerDiagnosticsMessage());
			}
			else if (IsOlresultsCommand(command))
			{
				RustyHeathensMessengerOneLifeCheck.ShowLastResultsLocal();
			}
			else
			{
				HandleCommand(command);
			}
		}
		else if (ZRoutedRpc.instance == null)
		{
			RustyHeathensMessengerMessageBroadcast.ShowLocalCenter("COMMAND WAITING\n\nServer permissions are not ready yet.");
		}
		else
		{
			long serverPeerIdForProtectedCommands = GetServerPeerIdForProtectedCommands();
			ZRoutedRpc.instance.InvokeRoutedRPC(serverPeerIdForProtectedCommands, "RustyHeathensMessenger_ProtectedCommandRequest", new object[2] { command, localSteamIdForCommandRequest });
		}
	}

	private static void RPC_ProtectedCommandRequest(long sender, string command, string steamId)
	{
		if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || string.IsNullOrWhiteSpace(command))
		{
			return;
		}
		command = command.Trim().ToLowerInvariant();
		if (IsRhmCommand(command) && !IsAlwaysAllowedCommand(command))
		{
			if (!ServerSteamIdIsAllowed(steamId))
			{
				RustyHeathensMessengerMessageBroadcast.BroadcastCenter("COMMAND LOCKED\n\nOnly approved server admins can use this command.");
			}
			else if (IsRhmdiagCommand(command))
			{
				RustyHeathensMessengerMessageBroadcast.BroadcastCenter(BuildServerDiagnosticsMessage());
			}
			else if (IsOlresultsCommand(command))
			{
				RustyHeathensMessengerOneLifeCheck.SendLastResultsToPeer(sender);
			}
			else
			{
				HandleCommand(command);
			}
		}
	}

	private static string GetLocalSteamIdForCommandRequest()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			return SteamUser.GetSteamID().m_SteamID.ToString();
		}
		catch
		{
		}
		if ((Object)(object)Player.m_localPlayer != (Object)null)
		{
			return Player.m_localPlayer.GetPlayerID().ToString();
		}
		return string.Empty;
	}

	private static long GetServerPeerIdForProtectedCommands()
	{
		try
		{
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				MethodInfo method = typeof(ZNet).GetMethod("GetServerPeer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method != null)
				{
					object obj = method.Invoke(ZNet.instance, null);
					if (obj != null)
					{
						FieldInfo field = obj.GetType().GetField("m_uid", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						if (field != null && field.GetValue(obj) is long num && num != 0L)
						{
							return num;
						}
					}
				}
			}
		}
		catch
		{
		}
		return 0L;
	}

	private static bool ServerSteamIdIsAllowed(string steamId)
	{
		if (string.IsNullOrWhiteSpace(steamId))
		{
			return false;
		}
		if (string.Equals((RustyHeathensMessengerPlugin.CommandPermissionModeEntry != null) ? RustyHeathensMessengerPlugin.CommandPermissionModeEntry.Value : "SteamIds", "Everyone", StringComparison.OrdinalIgnoreCase))
		{
			return true;
		}
		string text = ((RustyHeathensMessengerPlugin.CommandAllowedSteamIdsEntry != null) ? RustyHeathensMessengerPlugin.CommandAllowedSteamIdsEntry.Value : string.Empty);
		if (string.IsNullOrWhiteSpace(text))
		{
			return false;
		}
		string[] array = text.Split(new char[4] { ',', ';', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
		for (int i = 0; i < array.Length; i++)
		{
			if (string.Equals(array[i].Trim(), steamId.Trim(), StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
		}
		return false;
	}

	private static bool IsRhmdiagCommand(string command)
	{
		if (!string.Equals(command, "!rhmdiag", StringComparison.OrdinalIgnoreCase))
		{
			return string.Equals(command, "/rhm rhmdiag", StringComparison.OrdinalIgnoreCase);
		}
		return true;
	}

	private static bool IsOlresultsCommand(string command)
	{
		if (!string.Equals(command, "!olresults", StringComparison.OrdinalIgnoreCase))
		{
			return string.Equals(command, "/rhm olresults", StringComparison.OrdinalIgnoreCase);
		}
		return true;
	}

	private static string BuildServerDiagnosticsMessage()
	{
		bool flag = RustyHeathensMessengerPlugin.ChatCommandsEnabledEntry == null || RustyHeathensMessengerPlugin.ChatCommandsEnabledEntry.Value;
		bool flag2 = RustyHeathensMessengerPlugin.DeathLedgerEnabledEntry == null || RustyHeathensMessengerPlugin.DeathLedgerEnabledEntry.Value;
		bool flag3 = RustyHeathensMessengerPlugin.PlayerJoinMessagesEnabledEntry == null || RustyHeathensMessengerPlugin.PlayerJoinMessagesEnabledEntry.Value;
		bool flag4 = RustyHeathensMessengerPlugin.StreamModeEnabledEntry == null || RustyHeathensMessengerPlugin.StreamModeEnabledEntry.Value;
		string text = ((RustyHeathensMessengerPlugin.CommandPermissionModeEntry != null) ? RustyHeathensMessengerPlugin.CommandPermissionModeEntry.Value : "Unknown");
		return "RUSTY HEATHENS DIAGNOSTICS\n\nVersion: 1.0.0\nCommands: " + (flag ? "Enabled" : "Disabled") + "\nDeath Ledger: " + (flag2 ? "Enabled" : "Disabled") + "\nJoin Messages: " + (flag3 ? "Enabled" : "Disabled") + "\nStream Mode: " + (flag4 ? "Enabled" : "Disabled") + "\nPermissions: Server checked\nMode: " + text;
	}

	private static bool Prefix(Type type, string text)
	{
		if (string.IsNullOrWhiteSpace(text))
		{
			return true;
		}
		string command = text.Trim().ToLowerInvariant();
		if (!IsRhmCommand(command))
		{
			return true;
		}
		if (!RustyHeathensMessengerServerConfigSync.ChatCommandsEnabled())
		{
			return true;
		}
		if (!IsAlwaysAllowedCommand(command))
		{
			RequestProtectedCommandFromServer(command);
			return false;
		}
		HandleCommand(command);
		return false;
	}

	private static bool IsRhmCommand(string command)
	{
		switch (command)
		{
		default:
			return command == "!olresults";
		case "/rhm":
		case "/rhm help":
		case "!help":
		case "/rhm testbroadcast":
		case "!testbroadcast":
		case "/rhm whoami":
		case "!whoami":
		case "/rhm rhmdiag":
		case "!rhmdiag":
		case "/rhm deaths":
		case "!deaths":
		case "/rhm mydeaths":
		case "!mydeaths":
		case "/rhm deathclear confirm":
		case "!deathclear confirm":
		case "/rhm streammode":
		case "/rhm streammode on":
		case "/rhm streammode off":
		case "!streammode":
		case "!streammode on":
		case "!streammode off":
		case "/rhm stream":
		case "!stream":
		case "/rhm boss":
		case "!boss":
		case "/rhm base":
		case "!base":
		case "/rhm discord":
		case "!discord":
		case "/rhm ending":
		case "/rhm end":
		case "/rhm stream ending":
		case "!ending":
		case "!end":
		case "!streamending":
		case "/rhm body":
		case "!body":
		case "!version":
		case "/rhm version":
		case "/rhm raid":
		case "!raid":
		case "/rhm olcheck":
		case "!olcheck":
		case "/rhm olresults":
			return true;
		}
	}

	private static bool IsAlwaysAllowedCommand(string command)
	{
		switch (command)
		{
		default:
			return command == "!whoami";
		case "!help":
		case "/rhm":
		case "/rhm help":
		case "/rhm deaths":
		case "!deaths":
		case "/rhm mydeaths":
		case "!mydeaths":
		case "!version":
		case "/rhm version":
		case "/rhm whoami":
			return true;
		}
	}

	private static bool PlayerCanUseCommands()
	{
		string a = ((RustyHeathensMessengerPlugin.CommandPermissionModeEntry != null) ? RustyHeathensMessengerPlugin.CommandPermissionModeEntry.Value : "Everyone");
		if (string.Equals(a, "Everyone", StringComparison.OrdinalIgnoreCase))
		{
			return true;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return false;
		}
		if (string.Equals(a, "HostOnly", StringComparison.OrdinalIgnoreCase))
		{
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				return ZNet.instance.IsServer();
			}
			return false;
		}
		if (string.Equals(a, "NamedPlayers", StringComparison.OrdinalIgnoreCase))
		{
			return PlayerNameIsAllowed(localPlayer);
		}
		if (string.Equals(a, "SteamIds", StringComparison.OrdinalIgnoreCase))
		{
			return PlayerSteamIdIsAllowed(localPlayer);
		}
		if (string.Equals(a, "NamedPlayersOrSteamIds", StringComparison.OrdinalIgnoreCase))
		{
			if (!PlayerNameIsAllowed(localPlayer))
			{
				return PlayerSteamIdIsAllowed(localPlayer);
			}
			return true;
		}
		if (string.Equals(a, "ServerAdminList", StringComparison.OrdinalIgnoreCase))
		{
			if (!PlayerIsServerAdmin(localPlayer))
			{
				return PlayerSteamIdIsAllowed(localPlayer);
			}
			return true;
		}
		return true;
	}

	private static bool PlayerIsServerAdmin(Player player)
	{
		//IL_005b: 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)
		if ((Object)(object)ZNet.instance == (Object)null)
		{
			return false;
		}
		if (ZNet.instance.IsServer())
		{
			return true;
		}
		List<string> list = new List<string>();
		if ((Object)(object)player != (Object)null)
		{
			list.Add(player.GetPlayerID().ToString());
		}
		try
		{
			list.Add(ZNet.GetUID().ToString());
		}
		catch
		{
		}
		try
		{
			list.Add(SteamUser.GetSteamID().m_SteamID.ToString());
		}
		catch
		{
		}
		foreach (string item in list)
		{
			if (!string.IsNullOrWhiteSpace(item) && ZNetIsAdmin(item.Trim()))
			{
				return true;
			}
		}
		return false;
	}

	private static bool ZNetIsAdmin(string id)
	{
		try
		{
			MethodInfo[] methods = typeof(ZNet).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != "IsAdmin")
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length != 1)
				{
					continue;
				}
				object obj = null;
				if (parameters[0].ParameterType == typeof(string))
				{
					obj = methodInfo.Invoke(ZNet.instance, new object[1] { id });
				}
				else if (parameters[0].ParameterType == typeof(long))
				{
					if (!long.TryParse(id, out var result))
					{
						continue;
					}
					obj = methodInfo.Invoke(ZNet.instance, new object[1] { result });
				}
				if (obj is bool && (bool)obj)
				{
					return true;
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private static bool PlayerNameIsAllowed(Player player)
	{
		string obj = ((RustyHeathensMessengerPlugin.CommandAllowedPlayerNamesEntry != null) ? RustyHeathensMessengerPlugin.CommandAllowedPlayerNamesEntry.Value : string.Empty);
		string playerName = player.GetPlayerName();
		string[] array = obj.Split(new char[1] { ',' });
		for (int i = 0; i < array.Length; i++)
		{
			if (string.Equals(array[i].Trim(), playerName, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
		}
		return false;
	}

	private static bool PlayerSteamIdIsAllowed(Player player)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		string text = ((RustyHeathensMessengerPlugin.CommandAllowedSteamIdsEntry != null) ? RustyHeathensMessengerPlugin.CommandAllowedSteamIdsEntry.Value : string.Empty);
		if (string.IsNullOrWhiteSpace(text))
		{
			return false;
		}
		List<string> list = new List<string>();
		try
		{
			list.Add(SteamUser.GetSteamID().m_SteamID.ToString());
		}
		catch
		{
		}
		try
		{
			list.Add(ZNet.GetUID().ToString());
		}
		catch
		{
		}
		if ((Object)(object)player != (Object)null)
		{
			list.Add(player.GetPlayerID().ToString());
		}
		string[] array = text.Split(new char[4] { ',', ';', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
		for (int i = 0; i < array.Length; i++)
		{
			string text2 = array[i].Trim();
			if (string.IsNullOrWhiteSpace(text2))
			{
				continue;
			}
			foreach (string item in list)
			{
				string b = item.Trim();
				if (string.Equals(text2, b, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
		}
		return false;
	}

	private static string BuildVersionMessage()
	{
		return "RUSTY HEATHENS MESSENGER\n\nVersion: 1.0.0\nPermissions: Server-side\nMode: Messaging only\n\n";
	}

	private static void HandleCommand(string command)
	{
		switch (command)
		{
		case "!version":
		case "/rhm version":
			RustyHeathensMessengerMessageBroadcast.ShowLocalCenter(BuildVersionMessage());
			break;
		case "!help":
		case "/rhm":
		case "/rhm help":
			RustyHeathensMessengerMessageBroadcast.ShowLocalCenter("RUSTY HEATHENS MESSENGER\n\nOpen Commands:\n!help - Show this help\n!version - Show mod version\n!whoami - Show your player info\n!deaths - Show death ledger\n!mydeaths - Show your death count\n\nProtected Commands:\n!stream - Stream starting soon\n!boss - Boss fight starting soon\n!base - Return to base\n!discord - Discord reminder\n!ending - Stream ending\n!body - Heathen down\n!raid - Incoming raid\n!testbroadcast - Test server broadcast\n!rhmdiag - Server diagnostics\n!olcheck - One Life character check\n!olresults - Reopen last One Life check results\n!deathclear confirm - Clear death ledger");
			break;
		case "/rhm testbroadcast":
		case "!testbroadcast":
			ShowCenter("BROADCAST TEST\n\nIf you can see this, Rusty Heathens Messenger broadcasts are working.");
			break;
		case "/rhm olcheck":
		case "!olcheck":
			RustyHeathensMessengerOneLifeCheck.RequestCheck();
			break;
		case "/rhm whoami":
		case "!whoami":
			RustyHeathensMessengerMessageBroadcast.ShowLocalCenter(BuildWhoAmIMessage());
			break;
		case "/rhm rhmdiag":
		case "!rhmdiag":
			RustyHeathensMessengerMessageBroadcast.ShowLocalCenter(BuildDiagnosticsMessage());
			break;
		case "/rhm deaths":
		case "!deaths":
			RustyHeathensMessengerDeathLedger.RequestLedgerBroadcast();
			break;
		case "/rhm mydeaths":
		case "!mydeaths":
			RustyHeathensMessengerDeathLedger.RequestMyDeaths(Player.m_localPlayer);
			break;
		case "/rhm deathclear confirm":
		case "!deathclear confirm":
			RustyHeathensMessengerDeathLedger.ClearLedgerBroadcast();
			break;
		case "/rhm streammode":
		case "/rhm streammode on":
		case "/rhm streammode off":
		case "!streammode":
		case "!streammode on":
		case "!streammode off":
			HandleStreamModeCommand(command);
			break;
		case "/rhm stream":
		case "!stream":
			ShowConfiguredMessage(RustyHeathensMessengerPlugin.StreamTitleEntry, RustyHeathensMessengerPlugin.StreamBodyEntry, RustyHeathensMessengerPlugin.StreamStyleEntry, "STREAM STARTING SOON", "The Rusty Heathens are gathering.\nGrab your gear, check your food, and prepare for chaos.");
			break;
		case "/rhm boss":
		case "!boss":
			ShowConfiguredMessage(RustyHeathensMessengerPlugin.BossStartTitleEntry, RustyHeathensMessengerPlugin.BossStartBodyEntry, RustyHeathensMessengerPlugin.BossStartStyleEntry, "BOSS FIGHT STARTING SOON", "Return to base, repair your gear, grab food, and wait for the group.");
			break;
		case "/rhm base":
		case "!base":
			ShowConfiguredMessage(RustyHeathensMessengerPlugin.BaseTitleEntry, RustyHeathensMessengerPlugin.BaseBodyEntry, RustyHeathensMessengerPlugin.BaseStyleEntry, "RETURN TO BASE", "Everyone head back to base.\nRegroup before the chaos gets worse.");
			break;
		case "/rhm discord":
		case "!discord":
			ShowConfiguredMessage(RustyHeathensMessengerPlugin.DiscordTitleEntry, RustyHeathensMessengerPlugin.DiscordBodyEntry, RustyHeathensMessengerPlugin.DiscordStyleEntry, "DISCORD REMINDER", "Use Discord for rules, event plans, updates, and stream info.\nMessage RustyLaser if you need help.");
			break;
		case "/rhm ending":
		case "/rhm end":
		case "/rhm stream ending":
		case "!ending":
		case "!end":
		case "!streamending":
			ShowConfiguredMessage(RustyHeathensMessengerPlugin.EndingTitleEntry, RustyHeathensMessengerPlugin.EndingBodyEntry, RustyHeathensMessengerPlugin.EndingStyleEntry, "STREAM IS ENDING", "The stream is ending.\nIf you want to say bye to chat, return to the wall.");
			break;
		case "/rhm body":
		case "!body":
			ShowConfiguredMessage(RustyHeathensMessengerPlugin.BodyTitleEntry, RustyHeathensMessengerPlugin.BodyBodyEntry, RustyHeathensMessengerPlugin.BodyStyleEntry, "HEATHEN DOWN", "Head back to base and regroup.\nA Heathen needs help recovering their kit.");
			break;
		case "/rhm raid":
		case "!raid":
			ShowConfiguredMessage(RustyHeathensMessengerPlugin.RaidCommandTitleEntry, RustyHeathensMessengerPlugin.RaidCommandBodyEntry, RustyHeathensMessengerPlugin.RaidCommandStyleEntry, "INCOMING RAID", "Head back to base.\nHelp keep the Rusty Heathens safe.");
			break;
		}
	}

	private static string BuildWhoAmIMessage()
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		string text = "Unknown";
		string text2 = "Unavailable";
		if ((Object)(object)localPlayer != (Object)null)
		{
			text = localPlayer.GetPlayerName();
		}
		try
		{
			text2 = SteamUser.GetSteamID().m_SteamID.ToString();
		}
		catch
		{
		}
		return "PLAYER INFO\n\nName: " + text + "\nSteam ID: " + text2 + "\nVersion: 1.0.0\nPermissions: Server checked\nHelp: !help";
	}

	private static string BuildDiagnosticsMessage()
	{
		return BuildServerDiagnosticsMessage();
	}

	private static void HandleStreamModeCommand(string command)
	{
		if (RustyHeathensMessengerPlugin.StreamModeEnabledEntry != null && !RustyHeathensMessengerPlugin.StreamModeEnabledEntry.Value)
		{
			ShowCenter("STREAM MODE DISABLED\n\nStream Mode commands are disabled in the config.");
			return;
		}
		switch (command)
		{
		case "/rhm streammode on":
		case "!streammode on":
		{
			RustyHeathensMessengerPlugin.StreamModeActive = true;
			string configText4 = GetConfigText(RustyHeathensMessengerPlugin.StreamModeOnTitleEntry, "STREAM MODE ENABLED");
			string configText5 = GetConfigText(RustyHeathensMessengerPlugin.StreamModeOnBodyEntry, "Chat is watching.\nKeep it fun, keep it moving, and prepare for Rusty Heathens chaos.");
			ShowCenter(configText4 + "\n\n" + configText5);
			break;
		}
		case "/rhm streammode off":
		case "!streammode off":
		{
			RustyHeathensMessengerPlugin.StreamModeActive = false;
			string configText2 = GetConfigText(RustyHeathensMessengerPlugin.StreamModeOffTitleEntry, "STREAM MODE DISABLED");
			string configText3 = GetConfigText(RustyHeathensMessengerPlugin.StreamModeOffBodyEntry, "Chat has been released.\nYou may now return to unsupervised bad decisions.");
			ShowCenter(configText2 + "\n\n" + configText3);
			break;
		}
		default:
		{
			string configText = GetConfigText(RustyHeathensMessengerPlugin.StreamModeStatusTitleEntry, "STREAM MODE STATUS");
			string text = (RustyHeathensMessengerPlugin.StreamModeActive ? GetConfigText(RustyHeathensMessengerPlugin.StreamModeStatusOnBodyEntry, "Stream Mode is ON.\nChat is watching the chaos unfold.") : GetConfigText(RustyHeathensMessengerPlugin.StreamModeStatusOffBodyEntry, "Stream Mode is OFF.\nThe Heathens are currently causing chaos off-camera."));
			ShowCenter(configText + "\n\n" + text);
			break;
		}
		}
	}

	private static void ShowConfiguredMessage(ConfigEntry<string> titleEntry, ConfigEntry<string> bodyEntry, ConfigEntry<string> styleEntry, string defaultTitle, string defaultBody)
	{
		string configText = GetConfigText(titleEntry, defaultTitle);
		string configText2 = GetConfigText(bodyEntry, defaultBody);
		string configText3 = GetConfigText(styleEntry, "Normal");
		string text = ApplyMessageStyle(configText, configText2, configText3);
		if (RustyHeathensMessengerPlugin.StreamModeActive)
		{
			string configText4 = GetConfigText(RustyHeathensMessengerPlugin.StreamModeFooterEntry, "LIVE STREAM MODE: Chat is watching.");
			if (!string.IsNullOrWhiteSpace(configText4))
			{
				text = text + "\n\n" + configText4;
			}
		}
		ShowCenter(text);
	}

	private static string ApplyMessageStyle(string title, string body, string style)
	{
		style = (string.IsNullOrWhiteSpace(style) ? "Normal" : style.Trim());
		if (string.Equals(style, "Epic", StringComparison.OrdinalIgnoreCase))
		{
			return "=== " + title.ToUpperInvariant() + " ===\n\n" + body;
		}
		if (string.Equals(style, "Funny", StringComparison.OrdinalIgnoreCase))
		{
			return GetFunnyFooter(title) + "\n\n" + title.ToUpperInvariant() + "\n\n" + body;
		}
		if (string.Equals(style, "Emergency", StringComparison.OrdinalIgnoreCase))
		{
			return "!!! " + title.ToUpperInvariant() + " !!!\n\n" + body;
		}
		return title + "\n\n" + body;
	}

	private static string GetFunnyHeader(string title)
	{
		string text = title.ToLowerInvariant();
		if (text.Contains("stream starting"))
		{
			return "CHAT'S WATCHING: " + title.ToUpperInvariant();
		}
		if (text.Contains("boss"))
		{
			return "BAD IDEA LOADING: " + title.ToUpperInvariant();
		}
		if (text.Contains("return to base"))
		{
			return "PANIC WALK ENGAGED: " + title.ToUpperInvariant();
		}
		if (text.Contains("discord"))
		{
			return "READ THE RUNES: " + title.ToUpperInvariant();
		}
		if (text.Contains("ending"))
		{
			return "LAST CALL HEATHENS: " + title.ToUpperInvariant();
		}
		if (text.Contains("heathen down"))
		{
			return "CORPSE RUN O'CLOCK: " + title.ToUpperInvariant();
		}
		if (text.Contains("raid"))
		{
			return "PANIC PROFESSIONALLY: " + title.ToUpperInvariant();
		}
		return "RUSTY HEATHENS PSA: " + title.ToUpperInvariant();
	}

	private static string GetFunnyFooter(string title)
	{
		string text = title.ToLowerInvariant();
		if (text.Contains("stream starting"))
		{
			return Pick(new string[5] { "Try to look busy. Chat is watching.", "The mead is warm, the gear is broken, and somehow we are live.", "Everybody act professional. Or at least Viking-adjacent.", "Rusty hit the button. There is no going back now.", "Panda the Chaos Bringer has entered the chat. Prepare accordingly." });
		}
		if (text.Contains("boss"))
		{
			return Pick(new string[5] { "Bring food, bring courage, and maybe bring a backup plan.", "If you forgot rested buff, Odin already judged you.", "This is the part where confidence becomes a corpse run.", "Check your gear now. Regret waits at the boss altar.", "Panda called it a plan. The rest of us call it evidence." });
		}
		if (text.Contains("return to base"))
		{
			return Pick(new string[5] { "If you are lost, follow the screaming.", "Return to base before the base becomes a memory.", "The longship of poor decisions is heading home.", "Regroup now. Wander dramatically later.", "Someone check on Seppy before he finds another creative way to die." });
		}
		if (text.Contains("discord"))
		{
			return Pick(new string[5] { "Yes, this is your reminder before someone says they did not know.", "The runes were posted in Discord. Probably.", "Check Discord before asking Rusty for the third time.", "Important things happen there. Sometimes even plans.", "Discord has the rules. Panda has the chaos. Try not to confuse them." });
		}
		if (text.Contains("ending"))
		{
			return Pick(new string[5] { "Last chance to wave before Rusty hits the button.", "Say bye to chat before Valhalla claims the outro.", "Return to the wall. The ceremonial goodbye awkwardness begins.", "The stream is ending, but the chaos will remember us.", "One final wave before Panda starts another problem." });
		}
		if (text.Contains("heathen down"))
		{
			return Pick(new string[5] { "A kit has fallen. Again. Nobody act surprised.", "Someone has donated gear to the wilderness.", "Corpse run time. Try not to create a second one.", "A Heathen is down. Somebody get Witchy before this becomes a ritual.", "Witchy saw the body and said, 'That looks like a learning experience.'" });
		}
		if (text.Contains("raid"))
		{
			return Pick(new string[5] { "Heathens to the walls. Panic professionally.", "The base is under attack. Try not to decorate the floor with your corpse.", "This is not a drill. Unless it is a troll. Then it is worse.", "Protect the base, the mead, and whatever Seppy is standing near.", "Panda the Chaos Bringer says this is fine. It is not fine." });
		}
		return Pick(new string[5] { "This is probably fine.", "Odin has questions.", "The Rusty Heathens have made another decision.", "Somebody write this down as a lesson.", "Chaos has entered the server." });
	}

	private static string Pick(string[] lines)
	{
		if (lines == null || lines.Length == 0)
		{
			return "This is probably fine.";
		}
		if (lines.Length == 1)
		{
			return lines[0];
		}
		_funnyPickCounter++;
		if (_funnyPickCounter >= lines.Length)
		{
			_funnyPickCounter = 0;
		}
		return lines[_funnyPickCounter];
	}

	private static string GetConfigText(ConfigEntry<string> entry, string fallback)
	{
		if (entry == null)
		{
			return fallback;
		}
		if (string.IsNullOrWhiteSpace(entry.Value))
		{
			return fallback;
		}
		return entry.Value.Replace("\\n", "\n");
	}

	private static void ShowCenter(string message)
	{
		RustyHeathensMessengerMessageBroadcast.BroadcastCenter(message);
	}
}
[HarmonyPatch(typeof(Player), "Awake")]
public static class RustyHeathensMessengerDeathCounterPlayerAwakePatch
{
	private static void Postfix(Player __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && (Object)(object)((Component)__instance).GetComponent<RustyHeathensMessengerDeathCounter>() == (Object)null)
		{
			((Component)__instance).gameObject.AddComponent<RustyHeathensMessengerDeathCounter>();
		}
	}
}
public class RustyHeathensMessengerDeathCounter : MonoBehaviour
{
	private const string DeathCountKey = "RustyHeathensMessenger.DeathCount";

	private Player _player;

	private bool _wasDead;

	private bool _deathAlreadyCounted;

	private bool _hasBeenAlive;

	private static DateTime _lastLocalDeathReportTime = DateTime.MinValue;

	private const double LocalDeathDuplicateWindowSeconds = 10.0;

	private static int _lastFunnyDeathMessageIndex = -1;

	private void Awake()
	{
		_player = ((Component)this).GetComponent<Player>();
	}

	private void Update()
	{
		if ((Object)(object)_player == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)_player != (Object)(object)Player.m_localPlayer)
		{
			return;
		}
		bool flag = ((Character)_player).IsDead();
		if (!flag)
		{
			_hasBeenAlive = true;
			_deathAlreadyCounted = false;
			_wasDead = false;
			return;
		}
		if (!_hasBeenAlive)
		{
			_wasDead = flag;
			return;
		}
		if (flag && !_wasDead && !_deathAlreadyCounted && CanReportLocalDeath())
		{
			_deathAlreadyCounted = true;
			RegisterDeath(_player);
		}
		_wasDead = flag;
	}

	private static bool CanReportLocalDeath()
	{
		DateTime utcNow = DateTime.UtcNow;
		if ((utcNow - _lastLocalDeathReportTime).TotalSeconds < 10.0)
		{
			return false;
		}
		_lastLocalDeathReportTime = utcNow;
		return true;
	}

	public static void ClearLocalDeathCount()
	{
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null) && localPlayer.m_customData != null && localPlayer.m_customData.ContainsKey("RustyHeathensMessenger.DeathCount"))
		{
			localPlayer.m_customData.Remove("RustyHeathensMessenger.DeathCount");
		}
	}

	private static void RegisterDeath(Player player)
	{
		if ((Object)(object)player == (Object)null || player.m_customData == null)
		{
			return;
		}
		int deathCount = GetDeathCount(player) + 1;
		player.m_customData["RustyHeathensMessenger.DeathCount"] = deathCount.ToString();
		RustyHeathensMessengerPlayerJoinMessages.SuppressNextJoinMessageForDeath(player);
		RustyHeathensMessengerDeathLedger.ReportLocalDeath(player);
		if (RustyHeathensMessengerServerConfigSync.DeathMessagesEnabled())
		{
			string funnyDeathMessage = GetFunnyDeathMessage(deathCount);
			if (!string.Equals(RustyHeathensMessengerServerConfigSync.DeathMessageVisibility(), "Public", StringComparison.OrdinalIgnoreCase))
			{
				((Character)player).Message((MessageType)2, "Death #" + deathCount + "\n" + funnyDeathMessage, 0, (Sprite)null, false);
			}
		}
	}

	private static int GetDeathCount(Player player)
	{
		if (player.m_customData == null)
		{
			return 0;
		}
		if (!player.m_customData.ContainsKey("RustyHeathensMessenger.DeathCount"))
		{
			return 0;
		}
		if (!int.TryParse(player.m_customData["RustyHeathensMessenger.DeathCount"], out var result))
		{
			return 0;
		}
		return result;
	}

	private static string GetFunnyDeathMessage(int deathCount)
	{
		switch (deathCount)
		{
		case 1:
			return "First blood. Odin noticed.";
		case 2:
			return "The corpse run begins.";
		case 3:
			return "Three deaths in. Confidence remains dangerously high.";
		case 4:
			return "Four deaths. The gods are starting to recognize you.";
		case 5:
			return "Five deaths. That is a strategy now.";
		case 7:
			return "Seven deaths. Lucky number. Unlucky heathen.";
		case 10:
			return "Ten deaths. Valhalla has a reserved seat.";
		case 13:
			return "Thirteen deaths. Even the greydwarfs are concerned.";
		case 15:
			return "Fifteen deaths. The corpse run has become cardio.";
		case 20:
			return "Twenty deaths. Your tombstone needs its own map marker.";
		case 25:
			return "Twenty-five deaths. The ground knows your name.";
		case 30:
			return "Thirty deaths. At this point, death is part of the build plan.";
		case 40:
			return "Forty deaths. The saga is mostly screaming now.";
		case 50:
			return "Fifty deaths. The saga is mostly tombstones.";
		case 69:
			return "Sixty-nine deaths. Nice. Terrible, but nice.";
		case 75:
			return "Seventy-five deaths. Valheim has issued a warning label.";
		case 100:
			return "One hundred deaths. Seppy would be proud.";
		default:
		{
			string[] array = new string[40]
			{
				"Another glorious disaster.", "The Rusty Heathens felt that one.", "Your corpse is now part of the landscape.", "That was less of a fight and more of a donation.", "Valheim remains undefeated.", "The gods laughed. Respectfully.", "That death had confidence behind it.", "Bold choice. Bad outcome.", "You have once again become a cautionary tale.", "The mead did not save you.",
				"The food timer was probably involved.", "A tactical retreat would have been nice about ten seconds ago.", "Your tombstone has entered the chat.", "Somewhere in Valhalla, paperwork was filed.", "The plan was brave. The result was not.", "That was not a death. That was a learning experience.", "The Rusty Heathens will pretend they did not see that.", "You died doing what you loved: making questionable choices.", "A new tombstone has joined the server.", "The gods have reviewed the footage and declined to comment.",
				"You brought courage. Valheim brought consequences.", "That one looked personal.", "The death counter appreciates your commitment.", "Your survival plan has been rejected.", "That was a full-send into bad news.", "The saga continues, mostly because you keep respawning.", "Someone mark the map. Again.", "The health bar disappeared faster than the plan.", "A fine example of what not to do.", "The ancestors are clapping slowly.",
				"The body recovery team has been notified.", "Your gear is now having an adventure without you.", "That was a bold attempt at becoming a legend.", "You are not dead. You are temporarily loot-shaped.", "The server felt that one.", "The gods admire your dedication to testing gravity.", "Your confidence has been returned to spawn.", "That death was sponsored by poor timing.", "You have unlocked: another corpse run.", "The bad idea has been completed successfully."
			};
			int num = Random.Range(0, array.Length);
			if (array.Length > 1 && num == _lastFunnyDeathMessageIndex)
			{
				num = (num + 1) % array.Length;
			}
			_lastFunnyDeathMessageIndex = num;
			return array[num];
		}
		}
	}
}
public static class RustyHeathensMessengerDeathLedger
{
	private class DeathLedgerEntry
	{
		public string SteamId;

		public string DisplayName;

		public int Deaths;
	}

	private const string RpcReportDeathName = "RustyHeathensMessenger_ReportDeath";

	private const string RpcRequestLedgerName = "RustyHeathensMessenger_RequestDeathLedger";

	private const string RpcRequestMyDeathsName = "RustyHeathensMessenger_RequestMyDeaths";

	private const string RpcShowMyDeathsName = "RustyHeathensMessenger_ShowMyDeaths";

	private const string RpcClearLedgerName = "RustyHeathensMessenger_ClearDeathLedger";

	private const string RpcClearLocalDeathCountName = "RustyHeathensMessenger_ClearLocalDeathCount";

	private static readonly Dictionary<string, DeathLedgerEntry> Ledger = new Dictionary<string, DeathLedgerEntry>();

	private static readonly Dictionary<string, DateTime> RecentDeathReports = new Dictionary<string, DateTime>();

	private const double DuplicateDeathWindowSeconds = 5.0;

	private static DateTime _lastLedgerBroadcastRequestTime = DateTime.MinValue;

	private const double LedgerBroadcastDuplicateWindowSeconds = 2.0;

	private static ZRoutedRpc _registeredRpcInstance;

	private static bool _loaded;

	private static int _lastPublicDeathMessageIndex = -1;

	public static void EnsureRegistered()
	{
		if (ZRoutedRpc.instance != null && _registeredRpcInstance != ZRoutedRpc.instance)
		{
			_registeredRpcInstance = ZRoutedRpc.instance;
			ZRoutedRpc.instance.Register<string, string>("RustyHeathensMessenger_ReportDeath", (Action<long, string, string>)RPC_ReportDeath);
			ZRoutedRpc.instance.Register<string>("RustyHeathensMessenger_RequestDeathLedger", (Action<long, string>)RPC_RequestLedger);
			ZRoutedRpc.instance.Register<string, string>("RustyHeathensMessenger_RequestMyDeaths", (Action<long, string, string>)RPC_RequestMyDeaths);
			ZRoutedRpc.instance.Register<string>("RustyHeathensMessenger_ShowMyDeaths", (Action<long, string>)RPC_ShowMyDeaths);
			ZRoutedRpc.instance.Register<string>("RustyHeathensMessenger_ClearDeathLedger", (Action<long, string>)RPC_ClearLedger);
			ZRoutedRpc.instance.Register<string>("RustyHeathensMessenger_ClearLocalDeathCount", (Action<long, string>)RPC_ClearLocalDeathCount);
		}
	}

	private static void RPC_ClearLocalDeathCount(long sender, string request)
	{
		if (string.Equals(request, "confirm", StringComparison.OrdinalIgnoreCase))
		{
			RustyHeathensMessengerDeathCounter.ClearLocalDeathCount();
		}
	}

	public static void ReportLocalDeath(Player player)
	{
		if (IsEnabled() && !((Object)(object)player == (Object)null))
		{
			EnsureRegistered();
			string text = GetLocalSteamId();
			if (string.IsNullOrWhiteSpace(text))
			{
				text = player.GetPlayerID().ToString();
			}
			string playerName = player.GetPlayerName();
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				AddDeath(text, playerName);
				return;
			}
			if (ZRoutedRpc.instance == null)
			{
				AddDeath(text, playerName);
				return;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(GetServerPeerId(), "RustyHeathensMessenger_ReportDeath", new object[2] { text, playerName });
		}
	}

	public static void RequestLedgerBroadcast()
	{
		if (!IsEnabled())
		{
			RustyHeathensMessengerMessageBroadcast.ShowLocalCenter("DEATH LEDGER DISABLED\n\nDeath ledger tracking is disabled in the config.");
			return;
		}
		EnsureRegistered();
		if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
		{
			BroadcastLedger();
			return;
		}
		if (ZRoutedRpc.instance == null)
		{
			RustyHeathensMessengerMessageBroadcast.ShowLocalCenter(BuildLedgerMessage());
			return;
		}
		long serverPeerId = GetServerPeerId();
		ZRoutedRpc.instance.InvokeRoutedRPC(serverPeerId, "RustyHeathensMessenger_RequestDeathLedger", new object[1] { "request" });
		if (serverPeerId != 0L)
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, "RustyHeathensMessenger_RequestDeathLedger", new object[1] { "request" });
		}
	}

	public static void RequestMyDeaths(Player player)
	{
		if (!IsEnabled())
		{
			RustyHeathensMessengerMessageBroadcast.ShowLocalCenter("DEATH LEDGER DISABLED\n\nDeath ledger tracking is disabled in the config.");
		}
		else if (!((Object)(object)player == (Object)null))
		{
			EnsureRegistered();
			string text = GetLocalSteamId();
			if (string.IsNullOrWhiteSpace(text))
			{
				text = player.GetPlayerID().ToString();
			}
			string playerName = player.GetPlayerName();
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				RustyHeathensMessengerMessageBroadcast.ShowLocalCenter(BuildMyDeathsMessage(text, playerName));
				return;
			}
			if (ZRoutedRpc.instance == null)
			{
				RustyHeathensMessengerMessageBroadcast.ShowLocalCenter(BuildMyDeathsMessage(text, playerName));
				return;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(GetServerPeerId(), "RustyHeathensMessenger_RequestMyDeaths", new object[2] { text, playerName });
		}
	}

	public static void ClearLedgerBroadcast()
	{
		if (!IsEnabled())
		{
			RustyHeathensMessengerMessageBroadcast.ShowLocalCenter("DEATH LEDGER DISABLED\n\nDeath ledger tracking is disabled in the config.");
			return;
		}
		EnsureRegistered();
		if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
		{
			ClearLedgerNow();
			return;
		}
		if (ZRoutedRpc.instance == null)
		{
			ClearLedgerNow();
			return;
		}
		ZRoutedRpc.instance.InvokeRoutedRPC(GetServerPeerId(), "RustyHeathensMessenger_ClearDeathLedger", new object[1] { "confirm" });
	}

	private static void RPC_RequestMyDeaths(long sender, string steamId, string playerName)
	{
		if (IsEnabled() && (!((Object)(object)ZNet.instance != (Object)null) || ZNet.instance.IsServer()))
		{
			string text = BuildMyDeathsMessage(steamId, playerName);
			if (ZRoutedRpc.instance == null)
			{
				RustyHeathensMessengerMessageBroadcast.ShowLocalCenter(text);
				return;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "RustyHeathensMessenger_ShowMyDeaths", new object[1] { text });
		}
	}

	private static void RPC_ShowMyDeaths(long sender, string message)
	{
		RustyHeathensMessengerMessageBroadcast.ShowLocalCenter(message);
	}

	private static void RPC_ClearLedger(long sender, string request)
	{
		if (IsEnabled() && (!((Object)(object)ZNet.instance != (Object)null) || ZNet.instance.IsServer()) && string.Equals(request, "confirm", StringComparison.OrdinalIgnoreCase))
		{
			ClearLedgerNow();
		}
	}

	private static void ClearLedgerNow()
	{
		LoadLedger();
		Ledger.Clear();
		SaveLedger();
		RustyHeathensMessengerDeathCounter.ClearLocalDeathCount();
		if (ZRoutedRpc.instance != null)
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, "RustyHeathensMessenger_ClearLocalDeathCount", new object[1] { "confirm" });
		}
		RustyHeathensMessengerMessageBroadcast.BroadcastCenter("DEATH LEDGER CLEARED\n\nAll death counts have been reset.");
	}

	private static string BuildMyDeathsMessage(string steamId, string playerName)
	{
		LoadLedger();
		DeathLedgerEntry value = null;
		if (!string.IsNullOrWhiteSpace(steamId))
		{
			Ledger.TryGetValue(steamId.Trim(), out value);
		}
		if (value == null && !string.IsNullOrWhiteSpace(playerName))
		{
			foreach (DeathLedgerEntry value2 in Ledger.Values)
			{
				if (string.Equals(value2.DisplayName, playerName, StringComparison.OrdinalIgnoreCase))
				{
					value = value2;
					break;
				}
			}
		}
		string text = ((!string.IsNullOrWhiteSpace(playerName)) ? playerName : "You");
		int num = 0;
		if (value != null)
		{
			text = value.DisplayName;
			num = value.Deaths;
		}
		return "MY DEATHS\n\n" + text + " - " + num + ((num == 1) ? " death" : " deaths");
	}

	private static void RPC_ReportDeath(long sender, string steamId, string playerName)
	{
		if (IsEnabled() && (!((Object)(object)ZNet.instance != (Object)null) || ZNet.instance.IsServer()))
		{
			AddDeath(steamId, playerName);
		}
	}

	private static void RPC_RequestLedger(long sender, string request)
	{
		if (IsEnabled() && (!((Object)(object)ZNet.instance != (Object)null) || ZNet.instance.IsServer()))
		{
			DateTime utcNow = DateTime.UtcNow;
			if (!((utcNow - _lastLedgerBroadcastRequestTime).TotalSeconds < 2.0))
			{
				_lastLedgerBroadcastRequestTime = utcNow;
				BroadcastLedger();
			}
		}
	}

	private static bool PublicDeathMessagesEnabled()
	{
		if (!RustyHeathensMessengerServerConfigSync.DeathMessagesEnabled())
		{
			return false;
		}
		return string.Equals(RustyHeathensMessengerServerConfigSync.DeathMessageVisibility(), "Public", StringComparison.OrdinalIgnoreCase);
	}

	private static void TryBroadcastPublicDeathMessage(string playerName, int deathCount)
	{
		if (PublicDeathMessagesEnabled())
		{
			RustyHeathensMessengerMessageBroadcast.BroadcastCenter(PickPublicDeathMessage(string.IsNullOrWhiteSpace(playerName) ? "A heathen" : playerName.Trim(), deathCount));
		}
	}

	private static string PickPublicDeathMessage(string playerName, int deathCount)
	{
		string text = deathCount.ToString();
		string[] array = new string[7]
		{
			"HEATHEN DOWN\n\n" + playerName + " has fallen. The ledger demands another tally. Death #" + text + ".",
			"THE GODS ARE LAUGHING\n\n" + playerName + " has died again. Death #" + text + " enters the saga.",
			"ANOTHER ONE FOR THE LEDGER\n\n" + playerName + " met Valheim the hard way. Death #" + text + ".",
			"VALHALLA CALLED\n\n" + playerName + " answered immediately. Death #" + text + ".",
			"HEATHEN STATUS: HORIZONTAL\n\n" + playerName + " has been added to the death ledger. Death #" + text + ".",
			"SAGA INTERRUPTION\n\n" + playerName + " has temporarily stopped living. Death #" + text + ".",
			"THE DEATH COUNTER GROWS\n\n" + playerName + " just fed the ledger. Death #" + text + "."
		};
		int num = Random.Range(0, array.Length);
		if (array.Length > 1 && num == _lastPublicDeathMessageIndex)
		{
			num = (num + 1) % array.Length;
		}
		_lastPublicDeathMessageIndex = num;
		return array[num];
	}

	private static void AddDeath(string steamId, string playerName)
	{
		if (string.IsNullOrWhiteSpace(steamId))
		{
			return;
		}
		string text = steamId.Trim();
		if (!IsDuplicateDeathReport(text))
		{
			LoadLedger();
			if (!Ledger.TryGetValue(text, out var value))
			{
				value = new DeathLedgerEntry
				{
					SteamId = text,
					DisplayName = CleanField(playerName),
					Deaths = 0
				};
				Ledger[text] = value;
			}
			if (!string.IsNullOrWhiteSpace(playerName))
			{
				value.DisplayName = CleanField(playerName);
			}
			value.Deaths++;
			SaveLedger();
			TryBroadcastPublicDeathMessage(playerName, value.Deaths);
		}
	}

	private static bool IsDuplicateDeathReport(string key)
	{
		DateTime utcNow = DateTime.UtcNow;
		if (RecentDeathReports.TryGetValue(key, out var value) && (utcNow - value).TotalSeconds < 5.0)
		{
			return true;
		}
		RecentDeathReports[key] = utcNow;
		return false;
	}

	private static void BroadcastLedger()
	{
		RustyHeathensMessengerMessageBroadcast.BroadcastCenter(BuildLedgerMessage());
	}

	private static string BuildLedgerMessage()
	{
		LoadLedger();
		string configText = GetConfigText(RustyHeathensMessengerPlugin.DeathLedgerTitleEntry, "DEATH LEDGER");
		if (Ledger.Count == 0)
		{
			string configText2 = GetConfigText(RustyHeathensMessengerPlugin.DeathLedgerNoDeathsMessageEntry, "No deaths recorded yet.");
			return configText + "\n\n" + configText2;
		}
		int num = 10;
		if (RustyHeathensMessengerPlugin.DeathLedgerTopCountEntry != null)
		{
			num = Math.Max(1, RustyHeathensMessengerPlugin.DeathLedgerTopCountEntry.Value);
		}
		List<DeathLedgerEntry> list = new List<DeathLedgerEntry>(Ledger.Values);
		list.Sort((DeathLedgerEntry a, DeathLedgerEntry b) => b.Deaths.CompareTo(a.Deaths));
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendLine(configText);
		stringBuilder.AppendLine();
		int num2 = 0;
		for (int num3 = 0; num3 < list.Count; num3++)
		{
			if (num2 >= num)
			{
				break;
			}
			DeathLedgerEntry deathLedgerEntry = list[num3];
			num2++;
			stringBuilder.AppendLine(num2 + ". " + deathLedgerEntry.DisplayName + " - " + deathLedgerEntry.Deaths + ((deathLedgerEntry.Deaths == 1) ? " death" : " deaths"));
		}
		return stringBuilder.ToString().TrimEnd(Array.Empty<char>());
	}

	private static void LoadLedger()
	{
		if (_loaded)
		{
			return;
		}
		_loaded = true;
		Ledger.Clear();
		string ledgerPath = GetLedgerPath();
		if (!File.Exists(ledgerPath))
		{
			return;
		}
		string[] array = File.ReadAllLines(ledgerPath);
		foreach (string text in array)
		{
			if (string.IsNullOrWhiteSpace(text))
			{
				continue;
			}
			string[] array2 = text.Split(new char[1] { '|' });
			if (array2.Length >= 3)
			{
				string text2 = array2[0].Trim();
				string displayName = array2[1].Trim();
				if (int.TryParse(array2[2].Trim(), out var result) && !string.IsNullOrWhiteSpace(text2))
				{
					Ledger[text2] = new DeathLedgerEntry
					{
						SteamId = text2,
						DisplayName = displayName,
						Deaths = result
					};
				}
			}
		}
	}

	private static void SaveLedger()
	{
		string ledgerPath = GetLedgerPath();
		string directoryName = Path.GetDirectoryName(ledgerPath);
		if (!Directory.Exists(directoryName))
		{
			Directory.CreateDirectory(directoryName);
		}
		List<string> list = new List<string>();
		foreach (DeathLedgerEntry value in Ledger.Values)
		{
			list.Add(CleanField(value.SteamId) + "|" + CleanField(value.DisplayName) + "|" + value.Deaths);
		}
		File.WriteAllLines(ledgerPath, list.ToArray());
	}

	private static string GetLedgerPath()
	{
		string path = "RustyHeathensMessenger_DeathLedger.txt";
		if (RustyHeathensMessengerPlugin.DeathLedgerFileNameEntry != null && !string.IsNullOrWhiteSpace(RustyHeathensMessengerPlugin.DeathLedgerFileNameEntry.Value))
		{
			path = RustyHeathensMessengerPlugin.DeathLedgerFileNameEntry.Value;
		}
		path = Path.GetFileName(path);
		return Path.Combine(Paths.ConfigPath, path);
	}

	private static long GetServerPeerId()
	{
		try
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return 0L;
			}
			MethodInfo method = typeof(ZNet).GetMethod("GetServerPeer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return 0L;
			}
			object obj = method.Invoke(ZNet.instance, null);
			if (obj == null)
			{
				return 0L;
			}
			FieldInfo field = obj.GetType().GetField("m_uid", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				return 0L;
			}
			if (field.GetValue(obj) is long result)
			{
				return result;
			}
		}
		catch
		{
		}
		return 0L;
	}

	private static string GetLocalSteamId()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			return SteamUser.GetSteamID().m_SteamID.ToString();
		}
		catch
		{
			return string.Empty;
		}
	}

	private static bool IsEnabled()
	{
		return RustyHeathensMessengerServerConfigSync.DeathLedgerEnabled();
	}

	private static string GetConfigText(ConfigEntry<string> entry, string fallback)
	{
		if (entry == null)
		{
			return fallback;
		}
		if (string.IsNullOrWhiteSpace(entry.Value))
		{
			return fallback;
		}
		return entry.Value.Replace("\\n", "\n");
	}

	private static string CleanField(string value)
	{
		if (string.IsNullOrWhiteSpace(value))
		{
			return string.Empty;
		}
		return value.Replace("|", "/").Trim();
	}
}
public static class RustyHeathensMessengerMessageBroadcast
{
	private const string RpcName = "RustyHeathensMessenger_ShowCenterMessage";

	private static ZRoutedRpc _registeredRpcInstance;

	public static void EnsureRegistered()
	{
		if (ZRoutedRpc.instance != null && _registeredRpcInstance != ZRoutedRpc.instance)
		{
			_registeredRpcInstance = ZRoutedRpc.instance;
			ZRoutedRpc.instance.Register<string>("RustyHeathensMessenger_ShowCenterMessage", (Action<long, string>)RPC_ShowCenterMessage);
		}
	}

	public static void BroadcastCenter(string message)
	{
		EnsureRegistered();
		if (ZRoutedRpc.instance == null)
		{
			ShowLocalCenter(message);
			return;
		}
		ZRoutedRpc.instance.InvokeRoutedRPC(0L, "RustyHeathensMessenger_ShowCenterMessage", new object[1] { message });
	}

	public static void ShowLocalCenter(string message)
	{
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null))
		{
			((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false);
		}
	}

	private static void RPC_ShowCenterMessage(long sender, string message)
	{
		if (!string.IsNullOrWhiteSpace(message))
		{
			if (message.StartsWith("DEATH LEDGER CLEARED", StringComparison.OrdinalIgnoreCase))
			{
				RustyHeathensMessengerDeathCounter.ClearLocalDeathCount();
			}
			ShowLocalCenter(message);
		}
	}
}
public static class RustyHeathensMessengerOneLifeCheck
{
	private const string RpcStartCheckName = "RustyHeathensMessenger_StartOneLifeCheck";

	private const string RpcRequestCheckName = "RustyHeathensMessenger_RequestOneLifeCheck";

	private const string RpcReportCheckName = "RustyHeathensMessenger_ReportOneLifeCheck";

	private const string RpcShowAdminResultsName = "RustyHeathensMessenger_ShowOneLifeAdminResults";

	private static ZRoutedRpc _registeredRpcInstance;

	private static bool _checkActive;

	private static string _activeCheckId = string.Empty;

	private static float _broadcastResultsAt;

	private static readonly Dictionary<string, string> Reports = new Dictionary<string, string>();

	private static readonly Dictionary<string, long> AdminPeers = new Dictionary<string, long>();

	private static string _lastAdminResultsMessage = string.Empty;

	public static void Update()
	{
		EnsureRegistered();
		if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && _checkActive && !(Time.time < _broadcastResultsAt))
		{
			BroadcastResults();
		}
	}

	public static void EnsureRegistered()
	{
		if (ZRoutedRpc.instance != null && _registeredRpcInstance != ZRoutedRpc.instance)
		{
			_registeredRpcInstance = ZRoutedRpc.instance;
			ZRoutedRpc.instance.Register<string>("RustyHeathensMessenger_StartOneLifeCheck", (Action<long, string>)RPC_StartCheck);
			ZRoutedRpc.instance.Register<string>("RustyHeathensMessenger_RequestOneLifeCheck", (Action<long, string>)RPC_RequestCheck);
			ZRoutedRpc.instance.Register<string>("RustyHeathensMessenger_ReportOneLifeCheck", (Action<long, string>)RPC_ReportCheck);
			ZRoutedRpc.instance.Register<string>("RustyHeathensMessenger_ShowOneLifeAdminResults", (Action<long, string>)RPC_ShowAdminResults);
		}
	}

	public static void RequestCheck()
	{
		EnsureRegistered();
		if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
		{
			StartCheckFromServer();
			return;
		}
		if (ZRoutedRpc.instance == null)
		{
			RustyHeathensMessengerMessageBroadcast.ShowLocalCenter("ONE LIFE CHECK FAILED\n\nServer RPC was not ready.");
			return;
		}
		ZRoutedRpc.instance.InvokeRoutedRPC(GetServerPeerId(), "RustyHeathensMessenger_StartOneLifeCheck", new object[1] { "request" });
	}

	private static void RPC_StartCheck(long sender, string request)
	{
		if (!((Object)(object)ZNet.instance != (Object)null) || ZNet.instance.IsServer())
		{
			StartCheckFromServer();
		}
	}

	private static void StartCheckFromServer()
	{
		EnsureRegistered();
		if (!IsEnabled())
		{
			RustyHeathensMessengerMessageBroadcast.BroadcastCenter("ONE LIFE CHECK DISABLED\n\nThe One Life check command is disabled in the server config.");
		}
		else if (ZRoutedRpc.instance != null)
		{
			Reports.Clear();
			AdminPeers.Clear();
			_checkActive = true;
			_activeCheckId = Guid.NewGuid().ToString("N");
			_broadcastResultsAt = Time.time + 6f;
			RustyHeathensMessengerMessageBroadcast.BroadcastCenter("ONE LIFE CHECK STARTED\n\nChecking all players for inventory, equipped items, food, and skills.");
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, "RustyHeathensMessenger_RequestOneLifeCheck", new object[1] { _activeCheckId });
		}
	}

	private static void RPC_RequestCheck(long sender, string checkId)
	{
		if (!string.IsNullOrWhiteSpace(checkId))
		{
			ReportLocalPlayer(checkId);
		}
	}

	private static void ReportLocalPlayer(string checkId)
	{
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null))
		{
			string text = BuildReportPayload(checkId, localPlayer);
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				ProcessReport(text, 0L);
			}
			else if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(GetServerPeerId(), "RustyHeathensMessenger_ReportOneLifeCheck", new object[1] { text });
			}
		}
	}

	private static void RPC_ReportCheck(long sender, string payload)
	{
		if (!((Object)(object)ZNet.instance != (Object)null) || ZNet.instance.IsServer())
		{
			ProcessReport(payload, sender);
		}
	}

	private static void ProcessReport(string payload, long senderPeerId)
	{
		if (string.IsNullOrWhiteSpace(payload))
		{
			return;
		}
		string[] array = payload.Split(new char[1] { '|' });
		if (array.Length >= 9 && string.Equals(array[0], _activeCheckId, StringComparison.OrdinalIgnoreCase))
		{
			string text = DecodeText(array[1], "unknown");
			string text2 = DecodeText(array[2], "Unknown");
			string text3 = array[3];
			string text4 = DecodeText(array[8], "");
			string key = ((!string.IsNullOrWhiteSpace(text)) ? text.Trim() : text2.Trim());
			Reports[key] = text3 + "|" + text2 + "|" + text4;
			if (IsAdminPlayer(text, text2) && senderPeerId != 0L)
			{
				AdminPeers[key] = senderPeerId;
			}
		}
	}

	private static string BuildReportPayload(string checkId, Player player)
	{
		string value = GetLocalSteamId();
		if (string.IsNullOrWhiteSpace(value))
		{
			value = player.GetPlayerID().ToString();
		}
		string playerName = player.GetPlayerName();
		int inventoryItemCount = GetInventoryItemCount(player);
		int equippedItemCount = GetEquippedItemCount(player);
		int collectionCount = GetCollectionCount(player, "m_foods");
		int skillsAboveZeroCount = GetSkillsAboveZeroCount(player);
		string status = GetStatus(inventoryItemCount, equippedItemCount, collectionCount, skillsAboveZeroCount);
		string text = ((skillsAboveZeroCount >= 0) ? skillsAboveZeroCount.ToString() : "unknown");
		string value2 = "Items: " + inventoryItemCount + " / Equipped: " + equippedItemCount + " / Food: " + collectionCount + " / Skills: " + text;
		return checkId + "|" + EncodeText(value) + "|" + EncodeText(playerName) + "|" + status + "|" + inventoryItemCount + "|" + equippedItemCount + "|" + collectionCount + "|" + text + "|" + EncodeText(value2);
	}

	private static string GetStatus(int inventoryItems, int equippedItems, int foodCount, int skillsAboveZero)
	{
		if (inventoryItems > 0 || equippedItems > 0 || foodCount > 0)
		{
			return "FAIL";
		}
		if (skillsAboveZero < 0 || skillsAboveZero > 0)
		{
			return "WARNING";
		}
		return "PASS";
	}

	private static void BroadcastResults()
	{
		_checkActive = false;
		if (Reports.Count == 0)
		{
			_lastAdminResultsMessage = "ONE LIFE ADMIN CHECK\n\nNo player reports received.";
			RustyHeathensMessengerMessageBroadcast.BroadcastCenter("ONE LIFE CHECK COMPLETE\n\nNo player reports received.");
			return;
		}
		List<string> list = new List<string>();
		List<string> list2 = new List<string>();
		List<string> list3 = new List<string>();
		foreach (string value in Reports.Values)
		{
			string[] array = value.Split(new char[1] { '|' });
			if (array.Length >= 3)
			{
				string a = array[0];
				string text = array[1];
				string text2 = array[2];
				string item = text + " - " + text2;
				if (string.Equals(a, "PASS", StringComparison.OrdinalIgnoreCase))
				{
					list.Add(item);
				}
				else if (string.Equals(a, "WARNING", StringComparison.OrdinalIgnoreCase))
				{
					list2.Add(item);
				}
				else
				{
					list3.Add(item);
				}
			}
		}
		list.Sort();
		list2.Sort();
		list3.Sort();
		string message = ((list2.Count != 0 || list3.Count != 0) ? ("ONE LIFE CHECK COMPLETE\n\nPASS: " + list.Count + "\nWARNING: " + list2.Count + "\nFAIL: " + list3.Count + "\n\nAdmins received the details.") : ("ONE LIFE CHECK COMPLETE\n\nALL CLEAR\n" + list.Count + " player" + ((list.Count == 1) ? "" : "s") + " passed.\n\nAdmins received the details."));
		RustyHeathensMessengerMessageBroadcast.BroadcastCenter(message);
		_lastAdminResultsMessage = BuildAdminResultsMessage(list, list2, list3);
		SendAdminResults(_lastAdminResultsMessage);
	}

	private static string BuildAdminResultsMessage(List<string> passLines, List<string> warningLines, List<string> failLines)
	{
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendLine("ONE LIFE ADMIN CHECK");
		stringBuilder.AppendLine();
		AppendGroup(stringBuilder, "FAIL", failLines);
		AppendGroup(stringBuilder, "WARNING", warningLines);
		AppendGroup(stringBuilder, "PASS", passLines);
		return stringBuilder.ToString().TrimEnd(Array.Empty<char>());
	}

	private static void AppendGroup(StringBuilder builder, string title, List<string> lines)
	{
		builder.AppendLine(title + " (" + lines.Count + ")");
		if (lines.Count == 0)
		{
			builder.AppendLine("None");
			builder.AppendLine();
			return;
		}
		foreach (string line in lines)
		{
			builder.AppendLine(line);
		}
		builder.AppendLine();
	}

	private static void SendAdminResults(string message)
	{
		if (ZRoutedRpc.instance == null || string.IsNullOrWhiteSpace(message))
		{
			return;
		}
		foreach (long value in AdminPeers.Values)
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(value, "RustyHeathensMessenger_ShowOneLifeAdminResults", new object[1] { message });
		}
	}

	private static void RPC_ShowAdminResults(long sender, string message)
	{
		RustyHeathensMessengerMessageBroadcast.ShowLocalCenter(message);
	}

	public static void ShowLastResultsLocal()
	{
		if (string.IsNullOrWhiteSpace(_lastAdminResultsMessage))
		{
			RustyHeathensMessengerMessageBroadcast.ShowLocalCenter("ONE LIFE ADMIN CHECK\n\nNo saved One Life check results yet.\nRun !olcheck first.");
		}
		else
		{
			RustyHeathensMessengerMessageBroadcast.ShowLocalCenter(_lastAdminResultsMessage);
		}
	}

	public static void SendLastResultsToPeer(long peerId)
	{
		EnsureRegistered();
		if (ZRoutedRpc.instance != null)
		{
			string text = (string.IsNullOrWhiteSpace(_lastAdminResultsMessage) ? "ONE LIFE ADMIN CHECK\n\nNo saved One Life check results yet.\nRun !olcheck first." : _lastAdminResultsMessage);
			ZRoutedRpc.instance.InvokeRoutedRPC(peerId, "RustyHeathensMessenger_ShowOneLifeAdminResults", new object[1] { text });
		}
	}

	private static bool IsAdminPlayer(string steamId, string playerName)
	{
		if (!string.IsNullOrWhiteSpace(steamId))
		{
			string[] array = ((RustyHeathensMessengerPlugin.CommandAllowedSteamIdsEntry != null) ? RustyHeathensMessengerPlugin.CommandAllowedSteamIdsEntry.Value : string.Empty).Split(new char[4] { ',', ';', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				if (string.Equals(array[i].Trim(), steamId.Trim(), StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
		}
		if (!string.IsNullOrWhiteSpace(playerName))
		{
			string[] array = ((RustyHeathensMessengerPlugin.CommandAllowedPlayerNamesEntry != null) ? RustyHeathensMessengerPlugin.CommandAllowedPlayerNamesEntry.Value : string.Empty).Split(new char[4] { ',', ';', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				if (string.Equals(array[i].Trim(), playerName.Trim(), StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
		}
		return false;
	}

	private static bool IsEnabled()
	{
		if (RustyHeathensMessengerPlugin.OneLifeCheckEnabledEntry != null)
		{
			return RustyHeathensMessengerPlugin.OneLifeCheckEnabledEntry.Value;
		}
		return true;
	}

	private static int GetInventoryItemCount(Player player)
	{
		try
		{
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return 0;
			}
			return inventory.GetAllItems()?.Count ?? 0;
		}
		catch
		{
			return 0;
		}
	}

	private static int GetEquippedItemCount(Player player)
	{
		try
		{
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return 0;
			}
			List<ItemData> allItems = inventory.GetAllItems();
			if (allItems == null)
			{
				return 0;
			}
			int num = 0;
			foreach (ItemData item in allItems)
			{
				if (item != null && item.m_equipped)
				{
					num++;
				}
			}
			return num;
		}
		catch
		{
			return 0;
		}
	}

	private static int GetCollectionCount(object target, string fieldName)
	{
		try
		{
			object fieldValue = GetFieldValue(target, fieldName);
			if (fieldValue == null)
			{
				return 0;
			}
			if (!(fieldValue is ICollection { Count: var count }))
			{
				if (!(fieldValue is IEnumerable enumerable))
				{
					return 0;
				}
				int num = 0;
				foreach (object item in enumerable)
				{
					_ = item;
					num++;
				}
				return num;
			}
			return count;
		}
		catch
		{
			return 0;
		}
	}

	private static int GetSkillsAboveZeroCount(Player player)
	{
		try
		{
			object fieldValue = GetFieldValue(player, "m_skills");
			if (fieldValue == null)
			{
				return -1;
			}
			if (!(GetFieldValue(fieldValue, "m_skillData") is IEnumerable enumerable))
			{
				return -1;
			}
			int num = 0;
			foreach (object item in enumerable)
			{
				object propertyValue = GetPropertyValue(item, "Value");
				if (propertyValue != null)
				{
					object fieldValue2 = GetFieldValue(propertyValue, "m_level");
					if (fieldValue2 is float && (float)fieldValue2 > 0.01f)
					{
						num++;
					}
				}
			}
			return num;
		}
		catch
		{
			return -1;
		}
	}

	private static object GetFieldValue(object target, string fieldName)
	{
		if (target == null)
		{
			return null;
		}
		FieldInfo field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (!(field != null))
		{
			return null;
		}
		return field.GetValue(target);
	}

	private static object GetPropertyValue(object target, string propertyName)
	{
		if (target == null)
		{
			return null;
		}
		PropertyInfo property = target.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (!(property != null))
		{
			return null;
		}
		return property.GetValue(target, null);
	}

	private static string EncodeText(string value)
	{
		if (value == null)
		{
			value = string.Empty;
		}
		return Convert.ToBase64String(Encoding.UTF8.GetBytes(value));
	}

	private static string DecodeText(string value, string fallback)
	{
		if (string.IsNullOrWhiteSpace(value))
		{
			return fallback;
		}
		try
		{
			byte[] bytes = Convert.FromBase64String(value);
			return Encoding.UTF8.GetString(bytes);
		}
		catch
		{
			return fallback;
		}
	}

	private static string GetLocalSteamId()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			return SteamUser.GetSteamID().m_SteamID.ToString();
		}
		catch
		{
			return string.Empty;
		}
	}

	private static long GetServerPeerId()
	{
		try
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return 0L;
			}
			MethodInfo method = typeof(ZNet).GetMethod("GetServerPeer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return 0L;
			}
			object obj = method.Invoke(ZNet.instance, null);
			if (obj == null)
			{
				return 0L;
			}
			FieldInfo field = obj.GetType().GetField("m_uid", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				return 0L;
			}
			if (field.GetValue(obj) is long result)
			{
				return result;
			}
		}
		catch
		{
		}
		return 0L;
	}
}
[HarmonyPatch(typeof(Player), "Awake")]
public static class RustyHeathensMessengerPlayerJoinMessagesPlayerAwakePatch
{
	private static void Postfix(Player __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && (Object)(object)((Component)__instance).GetComponent<RustyHeathensMessengerPlayerJoinMessages>() == (Object)null)
		{
			((Component)__instance).gameObject.AddComponent<RustyHeathensMessengerPlayerJoinMessages>();
		}
	}
}
public class RustyHeathensMessengerPlayerJoinMessages : MonoBehaviour
{
	private const string RpcReportJoinName = "RustyHeathensMessenger_ReportPlayerJoin";

	private static readonly Dictionary<string, DateTime> RecentJoinReports = new Dictionary<string, DateTime>();

	private static readonly HashSet<string> SuppressNextJoinReportAfterDeath = new HashSet<string>();

	private const double DuplicateJoinWindowSeconds = 30.0;

	private static ZRoutedRpc _registeredRpcInstance;

	private static int _lastGeneralJoinMessageIndex = -1;

	private Player _player;

	private bool _reported;

	private float _reportAt;

	public static void EnsureRegistered()
	{
		if (ZRoutedRpc.instance != null && _registeredRpcInstance != ZRoutedRpc.instance)
		{
			_registeredRpcInstance = ZRoutedRpc.instance;
			ZRoutedRpc.instance.Register<string, string>("RustyHeathensMessenger_ReportPlayerJoin", (Action<long, string, string>)RPC_ReportPlayerJoin);
		}
	}

	public static void SuppressNextJoinMessageForDeath(Player player)
	{
		if (!((Object)(object)player == (Object)null))
		{
			string text = GetLocalSteamId();
			if (string.IsNullOrWhiteSpace(text))
			{
				text = player.GetPlayerID().ToString();
			}
			if (!string.IsNullOrWhiteSpace(text))
			{
				SuppressNextJoinReportAfterDeath.Add(text.Trim());
			}
		}
	}

	private void Awake()
	{
		_player = ((Component)this).GetComponent<Player>();
		float num = 3f;
		if (RustyHeathensMessengerPlugin.PlayerJoinMessageDelaySecondsEntry != null)
		{
			num = Mathf.Max(0f, RustyHeathensMessengerPlugin.PlayerJoinMessageDelaySecondsEntry.Value);
		}
		_reportAt = Time.time + num;
	}

	private void Update()
	{
		if (!_reported && RustyHeathensMessengerServerConfigSync.PlayerJoinMessagesEnabled() && !((Object)(object)_player == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)_player != (Object)(object)Player.m_localPlayer) && !(Time.time < _reportAt))
		{
			_reported = true;
			ReportLocalJoin(_player);
		}
	}

	private static void ReportLocalJoin(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return;
		}
		EnsureRegistered();
		string text = GetLocalSteamId();
		if (string.IsNullOrWhiteSpace(text))
		{
			text = player.GetPlayerID().ToString();
		}
		string playerName = player.GetPlayerName();
		if (!ShouldSuppressBecauseOfRecentDeath(text))
		{
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				TryBroadcastJoinMessageFromServer(text, playerName);
				return;
			}
			if (ZRoutedRpc.instance == null)
			{
				TryBroadcastJoinMessageFromServer(text, playerName);
				return;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(GetServerPeerId(), "RustyHeathensMessenger_ReportPlayerJoin", new object[2] { text, playerName });
		}
	}

	private static void RPC_ReportPlayerJoin(long sender, string steamId, string playerName)
	{
		if (RustyHeathensMessengerServerConfigSync.PlayerJoinMessagesEnabled() && (!((Object)(object)ZNet.instance != (Object)null) || ZNet.instance.IsServer()))
		{
			TryBroadcastJoinMessageFromServer(steamId, playerName);
		}
	}

	private static void BroadcastGeneralJoinMessage(string steamId, string playerName)
	{
		string text = ((!string.IsNullOrWhiteSpace(steamId)) ? steamId.Trim() : ((!string.IsNullOrWhiteSpace(playerName)) ? playerName.Trim() : "unknown"));
		if (string.IsNullOrWhiteSpace(text))
		{
			text = "unknown";
		}
		if (!IsDuplicateJoinReport("general|" + text))
		{
			RustyHeathensMessengerMessageBroadcast.BroadcastCenter(PickGeneralJoinMessage(string.IsNullOrWhiteSpace(playerName) ? "A new heathen" : playerName.Trim()));
		}
	}

	private static string PickGeneralJoinMessage(string playerName)
	{
		string[] array = new string[7]
		{
			"A NEW HEATHEN HAS ARRIVED\n\n" + playerName + " wandered into the saga. Hide the good mead.",
			"HEATHEN DETECTED\n\n" + playerName + " has joined. Confidence is high. Survival is unlikely.",
			"FRESH MEAT HAS ENTERED\n\n" + playerName + " has arrived. The gods have sent another volunteer.",
			"ANOTHER ONE JOINS THE CHAOS\n\n" + playerName + " is here. They read the server rules, right?",
			"A NEW SOUL ENTERS VALHEIM\n\n" + playerName + " has joined. Blame them for the next raid.",
			"THE SAGA GAINS ANOTHER\n\n" + playerName + " has arrived. May their axe be sharp and their death count stay low.",
			"NEW HEATHEN ONLINE\n\n" + playerName + " has joined. Somebody show them the emergency portal."
		};
		int num = Random.Range(0, array.Length);
		if (array.Length > 1 && num == _lastGeneralJoinMessageIndex)
		{
			num = (num + 1) % array.Length;
		}
		_lastGeneralJoinMessageIndex = num;
		return array[num];
	}

	private static void TryBroadcastJoinMessageFromServer(string steamId, string playerName)
	{
		string text = ((RustyHeathensMessengerPlugin.PlayerJoinMessagesEntry != null) ? RustyHeathensMessengerPlugin.PlayerJoinMessagesEntry.Value : string.Empty);
		if (string.IsNullOrWhiteSpace(text))
		{
			BroadcastGeneralJoinMessage(steamId, playerName);
			return;
		}
		string[] array = text.Split(new char[1] { ';' });
		foreach (string text2 in array)
		{
			if (string.IsNullOrWhiteSpace(text2))
			{
				continue;
			}
			string[] array2 = text2.Split(new char[1] { '|' });
			if (array2.Length < 4)
			{
				continue;
			}
			string text3 = array2[0].Trim();
			string text4 = array2[1].Trim();
			string text5 = array2[2].Trim();
			string text6 = array2[3].Trim();
			bool num = !string.IsNullOrWhiteSpace(text3) && !string.IsNullOrWhiteSpace(steamId) && string.Equals(text3, steamId, StringComparison.OrdinalIgnoreCase);
			bool flag = !string.IsNullOrWhiteSpace(text4) && !string.IsNullOrWhiteSpace(playerName) && string.Equals(text4, playerName, StringComparison.OrdinalIgnoreCase);
			if (!num && !flag)
			{
				continue;
			}
			if (!IsDuplicateJoinReport((!string.IsNullOrWhiteSpace(text3)) ? ("steam:" + text3) : ("name:" + text4.ToLowerInvariant())))
			{
				if (string.IsNullOrWhiteSpace(text5))
				{
					text5 = text4 + " HAS ARRIVED";
				}
				text6 = text6.Replace("\\n", "\n");
				RustyHeathensMessengerMessageBroadcast.BroadcastCenter(text5 + "\n\n" + text6);
			}
			return;
		}
		BroadcastGeneralJoinMessage(steamId, playerName);
	}

	private static bool IsDuplicateJoinReport(string key)
	{
		DateTime utcNow = DateTime.UtcNow;
		if (RecentJoinReports.TryGetValue(key, out var value) && (utcNow - value).TotalSeconds < 30.0)
		{
			return true;
		}
		RecentJoinReports[key] = utcNow;
		return false;
	}

	private static bool ShouldSuppressBecauseOfRecentDeath(string steamId)
	{
		if (string.IsNullOrWhiteSpace(steamId))
		{
			return false;
		}
		string item = steamId.Trim();
		if (!SuppressNextJoinReportAfterDeath.Contains(item))
		{
			return false;
		}
		SuppressNextJoinReportAfterDeath.Remove(item);
		return true;
	}

	private static long GetServerPeerId()
	{
		try
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return 0L;
			}
			MethodInfo method = typeof(ZNet).GetMethod("GetServerPeer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return 0L;
			}
			object obj = method.Invoke(ZNet.instance, null);
			if (obj == null)
			{
				return 0L;
			}
			FieldInfo field = obj.GetType().GetField("m_uid", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				return 0L;
			}
			if (field.GetValue(obj) is long result)
			{
				return result;
			}
		}
		catch
		{
		}
		return 0L;
	}

	private static string GetLocalSteamId()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			return SteamUser.GetSteamID().m_SteamID.ToString();
		}
		catch
		{
			return string.Empty;
		}
	}
}
[BepInPlugin("com.rustylasergaming.heathensmessenger", "Rusty Heathens Messenger", "1.0.0")]
public sealed class RustyHeathensMessengerPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "com.rustylasergaming.heathensmessenger";

	public const string PluginName = "Rusty Heathens Messenger";

	public const string PluginVersion = "1.0.0";

	internal static ConfigEntry<bool> ServerReminderEnabledEntry;

	internal static ConfigEntry<bool> RaidWarningsEnabledEntry;

	internal static ConfigEntry<bool> WelcomeMessageEnabledEntry;

	internal static ConfigEntry<bool> BossKillMessagesEnabledEntry;

	internal static ConfigEntry<bool> DeathMessagesEnabledEntry;

	internal static ConfigEntry<string> DeathMessageVisibilityEntry;

	internal static ConfigEntry<bool> ChatCommandsEnabledEntry;

	internal static ConfigEntry<string> CommandPermissionModeEntry;

	internal static ConfigEntry<string> CommandAllowedPlayerNamesEntry;

	internal static ConfigEntry<string> CommandAllowedSteamIdsEntry;

	internal static ConfigEntry<string> WelcomeTitleEntry;

	internal static ConfigEntry<string> WelcomeBodyEntry;

	internal static ConfigEntry<string> ServerReminderTitleEntry;

	internal static ConfigEntry<string> ServerReminderBodyEntry;

	internal static ConfigEntry<string> StreamTitleEntry;

	internal static ConfigEntry<string> StreamBodyEntry;

	internal static ConfigEntry<string> BossStartTitleEntry;

	internal static ConfigEntry<string> BossStartBodyEntry;

	internal static ConfigEntry<string> BaseTitleEntry;

	internal static ConfigEntry<string> BaseBodyEntry;

	internal static ConfigEntry<string> DiscordTitleEntry;

	internal static ConfigEntry<string> DiscordBodyEntry;

	internal static ConfigEntry<string> EndingTitleEntry;

	internal static ConfigEntry<string> EndingBodyEntry;

	internal static ConfigEntry<string> BodyTitleEntry;

	internal static ConfigEntry<string> BodyBodyEntry;

	internal static ConfigEntry<string> RaidCommandTitleEntry;

	internal static ConfigEntry<string> RaidCommandBodyEntry;

	internal static ConfigEntry<string> StreamStyleEntry;

	internal static ConfigEntry<string> BossStartStyleEntry;

	internal static ConfigEntry<string> BaseStyleEntry;

	internal static ConfigEntry<string> DiscordStyleEntry;

	internal static ConfigEntry<string> EndingStyleEntry;

	internal static ConfigEntry<string> BodyStyleEntry;

	internal static ConfigEntry<string> RaidCommandStyleEntry;

	internal static ConfigEntry<bool> StreamModeEnabledEntry;

	internal static ConfigEntry<bool> StreamModeStartsEnabledEntry;

	internal static ConfigEntry<string> StreamModeOnTitleEntry;

	internal static ConfigEntry<string> StreamModeOnBodyEntry;

	internal static ConfigEntry<string> StreamModeOffTitleEntry;

	internal static ConfigEntry<string> StreamModeOffBodyEntry;

	internal static ConfigEntry<string> StreamModeStatusTitleEntry;

	internal static ConfigEntry<string> StreamModeStatusOnBodyEntry;

	internal static ConfigEntry<string> StreamModeStatusOffBodyEntry;

	internal static ConfigEntry<string> StreamModeFooterEntry;

	internal static ConfigEntry<bool> PlayerJoinMessagesEnabledEntry;

	internal static ConfigEntry<float> PlayerJoinMessageDelaySecondsEntry;

	internal static ConfigEntry<string> PlayerJoinMessagesEntry;

	internal static ConfigEntry<bool> DeathLedgerEnabledEntry;

	internal static ConfigEntry<int> DeathLedgerTopCountEntry;

	internal static ConfigEntry<string> DeathLedgerTitleEntry;

	internal static ConfigEntry<string> DeathLedgerNoDeathsMessageEntry;

	internal static ConfigEntry<string> DeathLedgerFileNameEntry;

	internal static ConfigEntry<bool> OneLifeCheckEnabledEntry;

	internal static bool StreamModeActive;

	private Harmony _harmony;

	internal static RustyHeathensMessengerPlugin Instance { get; private set; }

	private void Awake()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		Instance = this;
		BindConfig();
		_harmony = new Harmony("com.rustylasergaming.heathensmessenger");
		_harmony.PatchAll(Assembly.GetExecutingAssembly());
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Rusty Heathens Messenger 1.0.0 loaded.");
	}

	private void Update()
	{
		RustyHeathensMessengerMessageBroadcast.EnsureRegistered();
		RustyHeathensMessengerDeathLedger.EnsureRegistered();
		RustyHeathensMessengerPlayerJoinMessages.EnsureRegistered();
		RustyHeathensMessengerChatCommands.EnsureRegistered();
		RustyHeathensMessengerBossKillMessagesPatch.EnsureRegistered();
		RustyHeathensMessengerOneLifeCheck.Update();
		RustyHeathensMessengerServerConfigSync.Update();
	}

	private void BindConfig()
	{
		WelcomeMessageEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - Features", "EnableWelcomeMessage", true, "Show the welcome message when joining a world.");
		ServerReminderEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - Features", "EnableServerReminder", true, "Show the server reminder message after joining.");
		RaidWarningsEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - Features", "EnableRaidWarnings", true, "Show raid warning messages.");
		BossKillMessagesEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - Features", "EnableBossKillMessages", true, "Show boss kill messages.");
		DeathMessageVisibilityEntry = ((BaseUnityPlugin)this).Config.Bind<string>("01 - Features", "DeathMessageVisibility", "Private", "Controls who sees death messages. Options: Private, Public.");
		DeathMessagesEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - Features", "EnableDeathMessages", true, "Show death counter and funny death messages.");
		ChatCommandsEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - Features", "EnableChatCommands", true, "Enable Rusty Heathens Messenger chat commands.");
		CommandPermissionModeEntry = ((BaseUnityPlugin)this).Config.Bind<string>("02 - Command Permissions", "CommandPermissionMode", "SteamIds", "Controls who can use protected commands. For dedicated servers such as DatHost, SteamIds is recommended. Protected commands are checked by the server config.");
		CommandAllowedSteamIdsEntry = ((BaseUnityPlugin)this).Config.Bind<string>("02 - Command Permissions", "CommandAllowedSteamIds", "", "Comma-separated Steam64 IDs allowed to use protected commands when CommandPermissionMode is SteamIds or NamedPlayersOrSteamIds.");
		CommandAllowedPlayerNamesEntry = ((BaseUnityPlugin)this).Config.Bind<string>("02 - Command Permissions", "CommandAllowedPlayerNames", "", "Comma-separated player names allowed to use protected commands when CommandPermissionMode is NamedPlayers or NamedPlayersOrSteamIds. SteamIds is recommended for dedicated servers.");
		WelcomeTitleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("03 - Welcome Message", "WelcomeTitle", "Welcome to the Rusty Heathens", "Title shown in the welcome message.");
		WelcomeBodyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("03 - Welcome Message", "WelcomeBody", "Survive the chaos. Earn Valhalla.", "Body shown in the welcome message.");
		ServerReminderTitleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("04 - Server Reminder", "ServerReminderTitle", "RUSTY HEATHENS SERVER", "Title shown in the server reminder.");
		ServerReminderBodyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("04 - Server Reminder", "ServerReminderBody", "Respect the crew.\nNo stealing.\nNo boss fights without the group.\nHelp with body recovery when you can.\nJoin Discord for rules, events, and stream info.", "Body shown in the server reminder.");
		StreamTitleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "StreamTitle", "STREAM STARTING SOON", "Title for stream starting command.");
		StreamBodyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "StreamBody", "The Rusty Heathens are gathering.\nGrab your gear, check your food, and prepare for chaos.", "Body for stream starting command.");
		BossStartTitleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "BossStartTitle", "BOSS FIGHT STARTING SOON", "Title for boss fight starting command.");
		BossStartBodyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "BossStartBody", "Return to base, repair your gear, grab food, and wait for the group.", "Body for boss fight starting command.");
		BaseTitleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "BaseTitle", "RETURN TO BASE", "Title for return to base command.");
		BaseBodyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "BaseBody", "Everyone head back to base.\nRegroup before the chaos gets worse.", "Body for return to base command.");
		DiscordTitleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "DiscordTitle", "DISCORD REMINDER", "Title for Discord reminder command.");
		DiscordBodyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "DiscordBody", "Use Discord for rules, event plans, updates, and stream info.\nMessage RustyLaser if you need help.", "Body for Discord reminder command.");
		EndingTitleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "EndingTitle", "STREAM IS ENDING", "Title for stream ending command.");
		EndingBodyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "EndingBody", "The stream is ending.\nIf you want to say bye to chat, return to the wall.", "Body for stream ending command.");
		BodyTitleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "BodyTitle", "HEATHEN DOWN", "Title for body recovery command.");
		BodyBodyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "BodyBody", "Head back to base and regroup.\nA Heathen needs help recovering their kit.", "Body for body recovery command.");
		RaidCommandTitleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "RaidTitle", "INCOMING RAID", "Title for incoming raid command.");
		RaidCommandBodyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("05 - Chat Commands", "RaidBody", "Head back to base.\nHelp keep the Rusty Heathens safe.", "Body for incoming raid command.");
		StreamStyleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("06 - Message Styles", "StreamStyle", "Normal", "Style for stream starting command. Options: Normal, Epic, Funny, Emergency.");
		BossStartStyleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("06 - Message Styles", "BossStartStyle", "Epic", "Style for boss fight starting command. Options: Normal, Epic, Funny, Emergency.");
		BaseStyleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("06 - Message Styles", "BaseStyle", "Normal", "Style for return to base command. Options: Normal, Epic, Funny, Emergency.");
		DiscordStyleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("06 - Message Styles", "DiscordStyle", "Normal", "Style for Discord reminder command. Options: Normal, Epic, Funny, Emergency.");
		EndingStyleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("06 - Message Styles", "EndingStyle", "Normal", "Style for stream ending command. Options: Normal, Epic, Funny, Emergency.");
		BodyStyleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("06 - Message Styles", "BodyStyle", "Epic", "Style for body recovery command. Options: Normal, Epic, Funny, Emergency.");
		RaidCommandStyleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("06 - Message Styles", "RaidStyle", "Emergency", "Style for incoming raid command. Options: Normal, Epic, Funny, Emergency.");
		StreamModeEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("07 - Stream Mode", "EnableStreamMode", true, "Enable or disable Stream Mode commands and stream mode footer messages.");
		StreamModeStartsEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("07 - Stream Mode", "StreamModeStartsEnabled", false, "If true, Stream Mode starts enabled when the world loads.");
		StreamModeOnTitleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("07 - Stream Mode", "StreamModeOnTitle", "STREAM MODE ENABLED", "Title shown when Stream Mode is turned on.");
		StreamModeOnBodyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("07 - Stream Mode", "StreamModeOnBody", "Chat is watching.\nKeep it fun, keep it moving, and prepare for Rusty Heathens chaos.", "Body shown when Stream Mode is turned on.");
		StreamModeOffTitleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("07 - Stream Mode", "StreamModeOffTitle", "STREAM MODE DISABLED", "Title shown when Stream Mode is turned off.");
		StreamModeOffBodyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("07 - Stream Mode", "StreamModeOffBody", "Chat has been released.\nYou may now return to unsupervised bad decisions.", "Body shown when Stream Mode is turned off.");
		StreamModeStatusTitleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("07 - Stream Mode", "StreamModeStatusTitle", "STREAM MODE STATUS", "Title shown when checking Stream Mode status.");
		StreamModeStatusOnBodyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("07 - Stream Mode", "StreamModeStatusOnBody", "Stream Mode is ON.\nChat is watching the chaos unfold.", "Body shown when Stream Mode is currently on.");
		StreamModeStatusOffBodyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("07 - Stream Mode", "StreamModeStatusOffBody", "Stream Mode is OFF.\nThe Heathens are currently causing chaos off-camera.", "Body shown when Stream Mode is currently off.");
		StreamModeFooterEntry = ((BaseUnityPlugin)this).Config.Bind<string>("07 - Stream Mode", "StreamModeFooter", "LIVE STREAM MODE: Chat is watching.", "Footer added to broadcast command messages while Stream Mode is on.");
		PlayerJoinMessagesEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("08 - Player Join Messages", "EnablePlayerJoinMessages", true, "Enable or disable player-specific join messages.");
		PlayerJoinMessageDelaySecondsEntry = ((BaseUnityPlugin)this).Config.Bind<float>("08 - Player Join Messages", "PlayerJoinMessageDelaySeconds", 3f, "Delay in seconds before showing a player join message after the player loads in.");
		string text = "|RustyLaser|RUSTYLASER HAS ARRIVED|The longship has a captain.\\nChaos now has supervision.;|Panda|PANDA HAS ARRIVED|The Chaos Bringer is here.\\nHide the important stuff.;|Witchy|WITCHY HAS ARRIVED|The ritual can begin.\\nSomebody check the cauldron.;|Seppy|SEPPY HAS ARRIVED|The tiny tank has entered the saga.\\nSomebody keep an eye on him.;|Phuture|PHUTURE HAS ARRIVED|First to retreat, last to fall.\\nThe storm has entered the saga.;|Pinklady|PINKLADY HAS ARRIVED|The builder is here.\\nMaybe the base will survive after all.;|Mama Laser|MAMA LASER HAS ARRIVED|The oracle is here.\\nTrolls have been warned.;|Saelion|SAELION HAS ARRIVED|The blade joins the saga.\\nSomething is about to become a problem.";
		PlayerJoinMessagesEntry = ((BaseUnityPlugin)this).Config.Bind<string>("08 - Player Join Messages", "PlayerJoinMessages", text, "Player join messages. Format: SteamID|DisplayName|Title|Message. Separate multiple players with semicolons. SteamID can be blank to match by player name.");
		DeathLedgerEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("09 - Death Ledger", "EnableDeathLedger", true, "Enable or disable server-wide death ledger tracking.");
		DeathLedgerTopCountEntry = ((BaseUnityPlugin)this).Config.Bind<int>("09 - Death Ledger", "DeathLedgerTopCount", 10, "How many players to show when using !deaths or /rhm deaths.");
		DeathLedgerTitleEntry = ((BaseUnityPlugin)this).Config.Bind<string>("09 - Death Ledger", "DeathLedgerTitle", "DEATH LEDGER", "Title shown for the death ledger message.");
		DeathLedgerNoDeathsMessageEntry = ((BaseUnityPlugin)this).Config.Bind<string>("09 - Death Ledger", "DeathLedgerNoDeathsMessage", "No deaths recorded yet.", "Message shown when the death ledger is empty.");
		DeathLedgerFileNameEntry = ((BaseUnityPlugin)this).Config.Bind<string>("09 - Death Ledger", "DeathLedgerFileName", "RustyHeathensMessenger_DeathLedger.txt", "File name used to save server-wide death counts.");
		OneLifeCheckEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("10 - One Life Check", "EnableOneLifeCheck", true, "Enable or disable the One Life character/inventory check command.");
		StreamModeActive = StreamModeEnabledEntry.Value && StreamModeStartsEnabledEntry.Value;
		ApplyMessagingSettingsToRuntime();
	}

	internal static void ApplyMessagingSettingsToRuntime()
	{
		if (ServerReminderEnabledEntry != null)
		{
			RustyHeathensMessengerServerReminder.ServerReminderEnabled = ServerReminderEnabledEntry.Value;
		}
		if (RaidWarningsEnabledEntry != null)
		{
			RustyHeathensMessengerRaidWarnings.RaidWarningsEnabled = RaidWarningsEnabledEntry.Value;
		}
	}
}
public sealed class RustyHeathensMessengerRaidWarnings : MonoBehaviour
{
	private Player _player;

	private string _activeRaid = string.Empty;

	private float _nextCheck;

	private float _nextRepeatMessage;

	public static bool RaidWarningsEnabled = true;

	private void Awake()
	{
		_player = ((Component)this).GetComponent<Player>();
	}

	private void Update()
	{
		if (!((Object)(object)_player == (Object)null) && !((Object)(object)Player.m_localPlayer != (Object)(object)_player) && RustyHeathensMessengerServerConfigSync.HasServerConfig() && RustyHeathensMessengerServerConfigSync.RaidWarningsEnabled() && !(Time.time < _nextCheck))
		{
			_nextCheck = Time.time + 1f;
			string currentRaidDisplayName = GetCurrentRaidDisplayName();
			if (!string.IsNullOrEmpty(currentRaidDisplayName) && string.IsNullOrEmpty(_activeRaid))
			{
				_activeRaid = currentRaidDisplayName;
				_nextRepeatMessage = Time.time + 45f;
				ShowCenter("RAID WARNING\n" + currentRaidDisplayName + "\nThe Rusty Heathens are under attack!");
			}
			else if (!string.IsNullOrEmpty(currentRaidDisplayName) && currentRaidDisplayName == _activeRaid && Time.time >= _nextRepeatMessage)
			{
				_nextRepeatMessage = Time.time + 45f;
				ShowCenter("RAID STILL ACTIVE\n" + currentRaidDisplayName + "\nHold the line, Heathens!");
			}
			else if (string.IsNullOrEmpty(currentRaidDisplayName) && !string.IsNullOrEmpty(_activeRaid))
			{
				ShowCenter("RAID CLEARED\nThe Heathens still stand.");
				_activeRaid = string.Empty;
				_nextRepeatMessage = 0f;
			}
		}
	}

	public static string GetCurrentRaidDisplayName()
	{
		object currentRandomEventObject = GetCurrentRandomEventObject();
		if (currentRandomEventObject == null)
		{
			return string.Empty;
		}
		string text = GetStringField(currentRandomEventObject, "m_name");
		if (string.IsNullOrEmpty(text))
		{
			text = currentRandomEventObject.ToString();
		}
		return MakeRaidNameFriendly(text);
	}

	private static object GetCurrentRandomEventObject()
	{
		try
		{
			Type type = Type.GetType("RandEventSystem, Assembly-CSharp");
			if (type == null)
			{
				return null;
			}
			object obj = GetStaticField(type, "instance") ?? GetStaticField(type, "m_instance");
			if (obj == null)
			{
				Object val = Object.FindFirstObjectByType(type);
				if (val != (Object)null)
				{
					obj = val;
				}
			}
			if (obj == null)
			{
				return null;
			}
			object result;
			if ((result = GetInstanceField(obj, "m_randomEvent")) == null)
			{
				result = GetInstanceField(obj, "m_currentRandomEvent") ?? GetInstanceField(obj, "m_event");
			}
			return result;
		}
		catch
		{
			return null;
		}
	}

	private static object GetStaticField(Type type, string fieldName)
	{
		FieldInfo field = type.GetField(fieldName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		if (!(field != null))
		{
			return null;
		}
		return field.GetValue(null);
	}

	private static object GetInstanceField(object target, string fieldName)
	{
		if (target == null)
		{
			return null;
		}
		FieldInfo field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (!(field != null))
		{
			return null;
		}
		return field.GetValue(target);
	}

	private static string GetStringField(object target, string fieldName)
	{
		object instanceField = GetInstanceField(target, fieldName);
		if (instanceField == null)
		{
			return string.Empty;
		}
		return instanceField.ToString();
	}

	private static string MakeRaidNameFriendly(string rawName)
	{
		if (string.IsNullOrEmpty(rawName))
		{
			return "Unknown Raid";
		}
		string text = rawName.ToLowerInvariant();
		if (text.Contains("army_eikthyr"))
		{
			return "Eikthyr's Herd";
		}
		if (text.Contains("army_theelder") || text.Contains("foresttrolls"))
		{
			return "The Forest Moves";
		}
		if (text.Contains("army_bonemass") || text.Contains("skeletons"))
		{
			return "Bonemass' Dead";
		}
		if (text.Contains("army_moder") || text.Contains("wolves"))
		{
			return "The Mountain Hunt";
		}
		if (text.Contains("army_goblin") || text.Contains("goblin"))
		{
			return "The Plains Warband";
		}
		if (text.Contains("army_gjall") || text.Contains("gjall"))
		{
			return "Mistlands Terror";
		}
		if (text.Contains("army_charred") || text.Contains("charred"))
		{
			return "Ashlands Siege";
		}
		return CleanName(rawName);
	}

	private static string CleanName(string rawName)
	{
		string text = rawName.Replace("$event_", string.Empty).Replace("event_", string.Empty).Replace("army_", string.Empty)
			.Replace("_", " ")
			.Trim();
		if (string.IsNullOrEmpty(text))
		{
			return "Unknown Raid";
		}
		StringBuilder stringBuilder = new StringBuilder(text.Length);
		bool flag = true;
		string text2 = text;
		foreach (char c in text2)
		{
			if (char.IsWhiteSpace(c))
			{
				stringBuilder.Append(c);
				flag = true;
			}
			else if (flag)
			{
				stringBuilder.Append(char.ToUpperInvariant(c));
				flag = false;
			}
			else
			{
				stringBuilder.Append(c);
			}
		}
		return stringBuilder.ToString();
	}

	private void ShowCenter(string text)
	{
		if ((Object)(object)_player == (Object)null)
		{
			return;
		}
		try
		{
			((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
		}
		catch
		{
		}
	}
}
[HarmonyPatch(typeof(Player), "Awake")]
public static class RustyHeathensMessengerRaidWarningsPlayerAwakePatch
{
	private static void Postfix(Player __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && (Object)(object)((Component)__instance).GetComponent<RustyHeathensMessengerRaidWarnings>() == (Object)null)
		{
			((Component)__instance).gameObject.AddComponent<RustyHeathensMessengerRaidWarnings>();
		}
	}
}
public static class RustyHeathensMessengerServerConfigSync
{
	private const string RpcRequestConfigName = "RustyHeathensMessenger_RequestServerConfig";

	private const string RpcReceiveConfigName = "RustyHeathensMessenger_ReceiveServerConfig";

	private static ZRoutedRpc _registeredRpcInstance;

	private static float _nextRequestTime;

	private static bool _hasServerConfig;

	private static bool _welcomeMessageEnabled = true;

	private static bool _serverReminderEnabled = true;

	private static bool _raidWarningsEnabled = true;

	private static bool _bossKillMessagesEnabled = true;

	private static bool _deathMessagesEnabled = true;

	private static bool _deathLedgerEnabled = true;

	private static bool _playerJoinMessagesEnabled = true;

	private static bool _chatCommandsEnabled = true;

	private static string _deathMessageVisibility = "Private";

	private static string _welcomeTitle = "Welcome to the Rusty Heathens";

	private static string _welcomeBody = "Survive the chaos. Earn Valhalla.";

	private static string _serverReminderTitle = "RUSTY HEATHENS SERVER";

	private static string _serverReminderBody = "Respect the crew.\nNo stealing.\nNo boss fights without the group.\nHelp with body recovery when you can.\nJoin Discord for rules, events, and stream info.";

	public static void Update()
	{
		EnsureRegistered();
		if (ZRoutedRpc.instance != null && !((Object)(object)ZNet.instance == (Object)null))
		{
			if (ZNet.instance.IsServer())
			{
				ApplyLocalServerConfig();
			}
			else if (!_hasServerConfig && !(Time.time < _nextRequestTime))
			{
				_nextRequestTime = Time.time + 5f;
				RequestServerConfig();
			}
		}
	}

	public static void EnsureRegistered()
	{
		if (ZRoutedRpc.instance != null && _registeredRpcInstance != ZRoutedRpc.instance)
		{
			_registeredRpcInstance = ZRoutedRpc.instance;
			ZRoutedRpc.instance.Register<string>("RustyHeathensMessenger_RequestServerConfig", (Action<long, string>)RPC_RequestServerConfig);
			ZRoutedRpc.instance.Register<string>("RustyHeathensMessenger_ReceiveServerConfig", (Action<long, string>)RPC_ReceiveServerConfig);
		}
	}

	private static void RequestServerConfig()
	{
		ZRoutedRp